fix vhost migration issues, and qxl locking for spice

This commit is contained in:
Justin M. Forbes 2011-03-16 15:31:55 -05:00
parent bc9e714751
commit da929861c3
50 changed files with 897 additions and 8202 deletions

View File

@ -1,259 +0,0 @@
From 09992bc6b432987ed3871dd7e4327ab6a589b865 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 14 Jun 2010 09:54:27 +0200
Subject: [PATCH 01/39] add pflib: PixelFormat conversion library.
---
Makefile.objs | 1 +
pflib.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pflib.h | 6 ++
3 files changed, 220 insertions(+), 0 deletions(-)
create mode 100644 pflib.c
create mode 100644 pflib.h
diff --git a/Makefile.objs b/Makefile.objs
index dbee210..147051f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -84,6 +84,7 @@ common-obj-y += qemu-char.o savevm.o #aio.o
common-obj-y += msmouse.o ps2.o
common-obj-y += qdev.o qdev-properties.o
common-obj-y += block-migration.o
+common-obj-y += pflib.o
common-obj-$(CONFIG_BRLAPI) += baum.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
diff --git a/pflib.c b/pflib.c
new file mode 100644
index 0000000..1154d0c
--- /dev/null
+++ b/pflib.c
@@ -0,0 +1,213 @@
+/*
+ * PixelFormat conversion library.
+ *
+ * Author: Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu-common.h"
+#include "console.h"
+#include "pflib.h"
+
+typedef struct QemuPixel QemuPixel;
+
+typedef void (*pf_convert)(QemuPfConv *conv,
+ void *dst, void *src, uint32_t cnt);
+typedef void (*pf_convert_from)(PixelFormat *pf,
+ QemuPixel *dst, void *src, uint32_t cnt);
+typedef void (*pf_convert_to)(PixelFormat *pf,
+ void *dst, QemuPixel *src, uint32_t cnt);
+
+struct QemuPfConv {
+ pf_convert convert;
+ PixelFormat src;
+ PixelFormat dst;
+
+ /* for copy_generic() */
+ pf_convert_from conv_from;
+ pf_convert_to conv_to;
+ QemuPixel *conv_buf;
+ uint32_t conv_cnt;
+};
+
+struct QemuPixel {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+ uint8_t alpha;
+};
+
+/* ----------------------------------------------------------------------- */
+/* PixelFormat -> QemuPixel conversions */
+
+static void conv_16_to_pixel(PixelFormat *pf,
+ QemuPixel *dst, void *src, uint32_t cnt)
+{
+ uint16_t *src16 = src;
+
+ while (cnt > 0) {
+ dst->red = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
+ dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
+ dst->blue = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
+ dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits);
+ dst++, src16++, cnt--;
+ }
+}
+
+/* assumes pf->{r,g,b,a}bits == 8 */
+static void conv_32_to_pixel_fast(PixelFormat *pf,
+ QemuPixel *dst, void *src, uint32_t cnt)
+{
+ uint32_t *src32 = src;
+
+ while (cnt > 0) {
+ dst->red = (*src32 & pf->rmask) >> pf->rshift;
+ dst->green = (*src32 & pf->gmask) >> pf->gshift;
+ dst->blue = (*src32 & pf->bmask) >> pf->bshift;
+ dst->alpha = (*src32 & pf->amask) >> pf->ashift;
+ dst++, src32++, cnt--;
+ }
+}
+
+static void conv_32_to_pixel_generic(PixelFormat *pf,
+ QemuPixel *dst, void *src, uint32_t cnt)
+{
+ uint32_t *src32 = src;
+
+ while (cnt > 0) {
+ if (pf->rbits < 8) {
+ dst->red = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
+ } else {
+ dst->red = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8);
+ }
+ if (pf->gbits < 8) {
+ dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
+ } else {
+ dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8);
+ }
+ if (pf->bbits < 8) {
+ dst->blue = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
+ } else {
+ dst->blue = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8);
+ }
+ if (pf->abits < 8) {
+ dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits);
+ } else {
+ dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8);
+ }
+ dst++, src32++, cnt--;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+/* QemuPixel -> PixelFormat conversions */
+
+static void conv_pixel_to_16(PixelFormat *pf,
+ void *dst, QemuPixel *src, uint32_t cnt)
+{
+ uint16_t *dst16 = dst;
+
+ while (cnt > 0) {
+ *dst16 = ((uint16_t)src->red >> (8 - pf->rbits)) << pf->rshift;
+ *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift;
+ *dst16 |= ((uint16_t)src->blue >> (8 - pf->bbits)) << pf->bshift;
+ *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
+ dst16++, src++, cnt--;
+ }
+}
+
+static void conv_pixel_to_32(PixelFormat *pf,
+ void *dst, QemuPixel *src, uint32_t cnt)
+{
+ uint32_t *dst32 = dst;
+
+ while (cnt > 0) {
+ *dst32 = ((uint32_t)src->red >> (8 - pf->rbits)) << pf->rshift;
+ *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift;
+ *dst32 |= ((uint32_t)src->blue >> (8 - pf->bbits)) << pf->bshift;
+ *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
+ dst32++, src++, cnt--;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+/* PixelFormat -> PixelFormat conversions */
+
+static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+ uint32_t bytes = cnt * conv->src.bytes_per_pixel;
+ memcpy(dst, src, bytes);
+}
+
+static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+ if (conv->conv_cnt < cnt) {
+ conv->conv_cnt = cnt;
+ conv->conv_buf = qemu_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt);
+ }
+ conv->conv_from(&conv->src, conv->conv_buf, src, cnt);
+ conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt);
+}
+
+/* ----------------------------------------------------------------------- */
+/* public interface */
+
+QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src)
+{
+ QemuPfConv *conv = qemu_mallocz(sizeof(QemuPfConv));
+
+ conv->src = *src;
+ conv->dst = *dst;
+
+ if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) {
+ /* formats identical, can simply copy */
+ conv->convert = convert_copy;
+ } else {
+ /* generic two-step conversion: src -> QemuPixel -> dst */
+ switch (conv->src.bytes_per_pixel) {
+ case 2:
+ conv->conv_from = conv_16_to_pixel;
+ break;
+ case 4:
+ if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) {
+ conv->conv_from = conv_32_to_pixel_fast;
+ } else {
+ conv->conv_from = conv_32_to_pixel_generic;
+ }
+ break;
+ default:
+ goto err;
+ }
+ switch (conv->dst.bytes_per_pixel) {
+ case 2:
+ conv->conv_to = conv_pixel_to_16;
+ break;
+ case 4:
+ conv->conv_to = conv_pixel_to_32;
+ break;
+ default:
+ goto err;
+ }
+ conv->convert = convert_generic;
+ }
+ return conv;
+
+err:
+ qemu_free(conv);
+ return NULL;
+}
+
+void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+ conv->convert(conv, dst, src, cnt);
+}
+
+void qemu_pf_conv_put(QemuPfConv *conv)
+{
+ if (conv) {
+ qemu_free(conv->conv_buf);
+ qemu_free(conv);
+ }
+}
diff --git a/pflib.h b/pflib.h
new file mode 100644
index 0000000..8d73fdd
--- /dev/null
+++ b/pflib.h
@@ -0,0 +1,6 @@
+/* public */
+typedef struct QemuPfConv QemuPfConv;
+
+QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src);
+void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt);
+void qemu_pf_conv_put(QemuPfConv *conv);
--
1.7.2.3

View File

@ -0,0 +1,143 @@
>From fd04276a00b172e6fbba3e3c72b1d13a0f179414 Mon Sep 17 00:00:00 2001
From: Alon Levy <alevy@redhat.com>
Date: Wed, 16 Mar 2011 15:21:03 +0100
Subject: [PATCH 1/4] qxl/spice-display: move pipe to ssd
This moves the int pipe[2] and pthread_t main data from the
PCIQXLDevice struct to the SimpleSpiceDisplay. This will let us
reuse it in the next patch for both -spice with no -qxl usage and
for vga mode from qxl.
Also move the pipe creation function (which is effectively completely rewritten
by this patch anyways) from hw/qxl.c to ui/spice-display.c, since
spice-display will depend on it after the next patch and qemu can be build
with ui/spice-display.c in combination with no hw/qxl.c.
---
hw/qxl.c | 22 +++++-----------------
hw/qxl.h | 4 ----
ui/spice-display.c | 21 +++++++++++++++++++++
ui/spice-display.h | 8 ++++++++
4 files changed, 34 insertions(+), 21 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index fe4212b..201698f 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1062,7 +1062,7 @@ static void pipe_read(void *opaque)
int len;
do {
- len = read(d->pipe[0], &dummy, sizeof(dummy));
+ len = read(d->ssd.pipe[0], &dummy, sizeof(dummy));
} while (len == sizeof(dummy));
qxl_set_irq(d);
}
@@ -1078,10 +1078,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
if ((old_pending & le_events) == le_events) {
return;
}
- if (pthread_self() == d->main) {
+ if (pthread_self() == d->ssd.main) {
+ /* running in io_thread thread */
qxl_set_irq(d);
} else {
- if (write(d->pipe[1], d, 1) != 1) {
+ if (write(d->ssd.pipe[1], d, 1) != 1) {
dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
}
}
@@ -1089,20 +1090,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
static void init_pipe_signaling(PCIQXLDevice *d)
{
- if (pipe(d->pipe) < 0) {
- dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
- return;
- }
-#ifdef CONFIG_IOTHREAD
- fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
-#else
- fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
-#endif
- fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
- fcntl(d->pipe[0], F_SETOWN, getpid());
-
- d->main = pthread_self();
- qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
+ qxl_create_server_to_iothread_pipe(&d->ssd, pipe_read);
}
/* graphics console */
diff --git a/hw/qxl.h b/hw/qxl.h
index f6c450d..701245f 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -55,10 +55,6 @@ typedef struct PCIQXLDevice {
} guest_surfaces;
QXLPHYSICAL guest_cursor;
- /* thread signaling */
- pthread_t main;
- int pipe[2];
-
/* ram pci bar */
QXLRam *ram;
VGACommonState vga;
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 020b423..ec6e0cb 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -394,6 +394,27 @@ static DisplayChangeListener display_listener = {
.dpy_refresh = display_refresh,
};
+void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
+ IOHandler *pipe_read)
+{
+ if (pipe(ssd->pipe) < 0) {
+ fprintf(stderr, "%s: pipe creation failed\n", __FUNCTION__);
+ return;
+ }
+
+#ifdef CONFIG_IOTHREAD
+ fcntl(ssd->pipe[0], F_SETFL, O_NONBLOCK);
+#else
+ fcntl(ssd->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
+#endif
+ fcntl(ssd->pipe[1], F_SETFL, O_NONBLOCK);
+
+ fcntl(ssd->pipe[0], F_SETOWN, getpid());
+
+ qemu_set_fd_handler(ssd->pipe[0], pipe_read, NULL, ssd);
+ ssd->main = pthread_self();
+}
+
void qemu_spice_display_init(DisplayState *ds)
{
assert(sdpy.ds == NULL);
diff --git a/ui/spice-display.h b/ui/spice-display.h
index aef0464..3e6cf7c 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -43,6 +43,11 @@ typedef struct SimpleSpiceDisplay {
QXLRect dirty;
int notify;
int running;
+
+ /* thread signaling - used both in qxl (in vga mode
+ * and in native mode) and without qxl */
+ pthread_t main;
+ int pipe[2]; /* to iothread */
} SimpleSpiceDisplay;
typedef struct SimpleSpiceUpdate {
@@ -66,3 +71,6 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
int x, int y, int w, int h);
void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
+/* used by both qxl and spice-display */
+void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
+ IOHandler *pipe_read);
--
1.7.3.2

View File

@ -1,39 +0,0 @@
From 89df4f8cf7ecde07e3dc5e2ea3c19cbcd02165d0 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 23 Apr 2010 13:44:10 +0200
Subject: [PATCH 02/39] configure: add logging
Write compile commands and messages to config.log.
Useful for debugging configure.
---
configure | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/configure b/configure
index b85590f..e09c442 100755
--- a/configure
+++ b/configure
@@ -16,15 +16,18 @@ TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
trap "rm -f $TMPC $TMPO $TMPE ; exit" EXIT INT QUIT TERM
+rm -f config.log
compile_object() {
- $cc $QEMU_CFLAGS -c -o $TMPO $TMPC > /dev/null 2> /dev/null
+ echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log
+ $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1
}
compile_prog() {
local_cflags="$1"
local_ldflags="$2"
- $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags > /dev/null 2> /dev/null
+ echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log
+ $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1
}
# check whether a command is available to this shell (may be either an
--
1.7.2.3

View File

@ -0,0 +1,312 @@
>From 97e291086fef45762e0278e85ab1d231a9902bbb Mon Sep 17 00:00:00 2001
From: Uri Lublin <uril@redhat.com>
Date: Wed, 16 Mar 2011 15:43:45 +0100
Subject: [PATCH 2/4] qxl: implement get_command in vga mode without locks
This patch and the next drop the requirement to lose the global qemu
mutex during dispatcher calls. This patch enables it, the next drops
the unlock/lock pairs around dispatcher calls.
The current solution of dropping the locks is buggy:
* it allows multiple dispatcher calls from two vcpu threads, the
dispatcher doesn't handle that by design (single fd, not locked, can't
handle writes from two threads)
* it requires us to keep track of cpu_single_env, which is magic.
The solution implemented in this patch and the next (the next just
drops the locks, this patch allows that to work):
* the only operation that needed locking was qemu_create_simple_update,
* it required locking because it was called from the spice-server thread.
* do it in the iothread by reusing the existing pipe used for set_irq.
The current flow implemented is now:
spice-server thread:
qxl.c:interface_get_command (called either by polling or from wakeup)
if update!=NULL:
waiting_for_update=0
update=NULL
return update
else:
if not waiting_for_update:
waiting_for_update=1
write to pipe, which is read by iothread (main thread)
iothread:
wakeup from select,
qxl.c:pipe_read
update=qemu_create_simple_update()
wakeup spice-server thread by calling d.worker->wakeup(d.worker)
---
hw/qxl.c | 81 +++++++++++++++++++++++++++++++++++++++------------
ui/spice-display.c | 75 +++++++++++++++++++++++++++++++++++++++++++----
ui/spice-display.h | 16 ++++++++++
3 files changed, 146 insertions(+), 26 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 201698f..64580f1 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -340,7 +340,6 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
{
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
- SimpleSpiceUpdate *update;
QXLCommandRing *ring;
QXLCommand *cmd;
int notify;
@@ -348,16 +347,25 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
switch (qxl->mode) {
case QXL_MODE_VGA:
dprint(qxl, 2, "%s: vga\n", __FUNCTION__);
- update = qemu_spice_create_update(&qxl->ssd);
- if (update == NULL) {
- return false;
+ if (qxl_vga_mode_get_command(&qxl->ssd, ext)) {
+ qxl_log_command(qxl, "vga", ext);
+ return true;
}
- *ext = update->ext;
- qxl_log_command(qxl, "vga", ext);
- return true;
+ return false;
case QXL_MODE_COMPAT:
case QXL_MODE_NATIVE:
case QXL_MODE_UNDEFINED:
+ /* flush any existing updates that we didn't send to the guest.
+ * since update != NULL it means the server didn't get it, and
+ * because we changed mode to != QXL_MODE_VGA, it won't. */
+ if (qxl->ssd.update != NULL) {
+ if (qxl->ssd.update != QXL_EMPTY_UPDATE) {
+ qemu_spice_destroy_update(&qxl->ssd, qxl->ssd.update);
+ }
+ qxl->ssd.update = NULL;
+ qxl->ssd.waiting_for_update = 0;
+ }
+ /* */
dprint(qxl, 2, "%s: %s\n", __FUNCTION__,
qxl->cmdflags ? "compat" : "native");
ring = &qxl->ram->cmd_ring;
@@ -1057,17 +1065,50 @@ static void qxl_map(PCIDevice *pci, int region_num,
static void pipe_read(void *opaque)
{
- PCIQXLDevice *d = opaque;
- char dummy;
- int len;
-
- do {
- len = read(d->ssd.pipe[0], &dummy, sizeof(dummy));
- } while (len == sizeof(dummy));
- qxl_set_irq(d);
+ SimpleSpiceDisplay *ssd = opaque;
+ unsigned char cmd;
+ int len, set_irq = 0;
+ int create_update = 0;
+
+ while (1) {
+ cmd = 0;
+ len = read(ssd->pipe[0], &cmd, sizeof(cmd));
+ if (len < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN) {
+ break;
+ }
+ perror("qxl: pipe_read: read failed");
+ break;
+ }
+ switch (cmd) {
+ case QXL_SERVER_SET_IRQ:
+ set_irq = 1;
+ break;
+ case QXL_SERVER_CREATE_UPDATE:
+ create_update = 1;
+ break;
+ default:
+ fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
+ abort();
+ }
+ }
+ /* no need to do either operation more than once */
+ if (create_update) {
+ assert(ssd->update == NULL);
+ ssd->update = qemu_spice_create_update(ssd);
+ if (ssd->update == NULL) {
+ ssd->update = QXL_EMPTY_UPDATE;
+ }
+ ssd->worker->wakeup(ssd->worker);
+ }
+ if (set_irq) {
+ qxl_set_irq(container_of(ssd, PCIQXLDevice, ssd));
+ }
}
-/* called from spice server thread context only */
static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
{
uint32_t old_pending;
@@ -1082,9 +1123,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
/* running in io_thread thread */
qxl_set_irq(d);
} else {
- if (write(d->ssd.pipe[1], d, 1) != 1) {
- dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
- }
+ /* called from spice-server thread */
+ int ret;
+ unsigned char ack = QXL_SERVER_SET_IRQ;
+ ret = write(d->ssd.pipe[1], &ack, 1);
+ assert(ret == 1);
}
}
diff --git a/ui/spice-display.c b/ui/spice-display.c
index ec6e0cb..bdd14b8 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -294,18 +294,39 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
info->n_surfaces = NUM_SURFACES;
}
+/* Called from spice server thread context (via interface_get_command) */
+int qxl_vga_mode_get_command(
+ SimpleSpiceDisplay *ssd, struct QXLCommandExt *ext)
+{
+ SimpleSpiceUpdate *update;
+ unsigned char req;
+ int r;
+
+ update = ssd->update;
+ if (update != NULL) {
+ ssd->waiting_for_update = 0;
+ ssd->update = NULL;
+ if (update != QXL_EMPTY_UPDATE) {
+ *ext = update->ext;
+ return true;
+ }
+ } else {
+ if (!ssd->waiting_for_update) {
+ ssd->waiting_for_update = 1;
+ req = QXL_SERVER_CREATE_UPDATE;
+ r = write(ssd->pipe[1], &req , 1);
+ assert(r == 1);
+ }
+ }
+ return false;
+}
+
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
{
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
- SimpleSpiceUpdate *update;
dprint(3, "%s:\n", __FUNCTION__);
- update = qemu_spice_create_update(ssd);
- if (update == NULL) {
- return false;
- }
- *ext = update->ext;
- return true;
+ return qxl_vga_mode_get_command(ssd, ext);
}
static int interface_req_cmd_notification(QXLInstance *sin)
@@ -394,6 +415,45 @@ static DisplayChangeListener display_listener = {
.dpy_refresh = display_refresh,
};
+static void pipe_read(void *opaque)
+{
+ SimpleSpiceDisplay *ssd = opaque;
+ unsigned char cmd;
+ int len, create_update = 0;
+
+ while (1) {
+ cmd = 0;
+ len = read(ssd->pipe[0], &cmd, sizeof(cmd));
+ if (len < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN) {
+ break;
+ }
+ perror("qxl: pipe_read: read failed");
+ break;
+ }
+ switch (cmd) {
+ case QXL_SERVER_CREATE_UPDATE:
+ create_update = 1;
+ break;
+ default:
+ fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
+ abort();
+ }
+ }
+ /* no need to do this more than once */
+ if (create_update) {
+ assert(ssd->update == NULL);
+ ssd->update = qemu_spice_create_update(ssd);
+ if (ssd->update == NULL) {
+ ssd->update = QXL_EMPTY_UPDATE;
+ }
+ ssd->worker->wakeup(ssd->worker);
+ }
+}
+
void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
IOHandler *pipe_read)
{
@@ -427,6 +487,7 @@ void qemu_spice_display_init(DisplayState *ds)
qemu_spice_add_interface(&sdpy.qxl.base);
assert(sdpy.worker);
+ qxl_create_server_to_iothread_pipe(&sdpy, pipe_read);
qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy);
qemu_spice_create_host_memslot(&sdpy);
qemu_spice_create_host_primary(&sdpy);
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 3e6cf7c..2be6a34 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -31,6 +31,15 @@
#define NUM_SURFACES 1024
+/* For commands/requests from server thread to iothread */
+#define QXL_EMPTY_UPDATE ((void *)-1)
+enum {
+ QXL_SERVER_SET_IRQ = 1,
+ QXL_SERVER_CREATE_UPDATE,
+};
+
+struct SimpleSpiceUpdate;
+
typedef struct SimpleSpiceDisplay {
DisplayState *ds;
void *buf;
@@ -48,6 +57,10 @@ typedef struct SimpleSpiceDisplay {
* and in native mode) and without qxl */
pthread_t main;
int pipe[2]; /* to iothread */
+
+ /* ssd updates (one request/command at a time) */
+ struct SimpleSpiceUpdate *update;
+ int waiting_for_update;
} SimpleSpiceDisplay;
typedef struct SimpleSpiceUpdate {
@@ -71,6 +84,9 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
int x, int y, int w, int h);
void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
+/* shared with qxl.c in vga mode and ui/spice-display (no qxl mode) */
+int qxl_vga_mode_get_command(
+ SimpleSpiceDisplay *ssd, struct QXLCommandExt *ext);
/* used by both qxl and spice-display */
void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
IOHandler *pipe_read);
--
1.7.3.2

View File

@ -1,94 +0,0 @@
From 0034da7fb15d1225e0fd725009743d48511a90b7 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 24 Mar 2010 10:26:51 +0100
Subject: [PATCH 03/39] add spice into the configure file
---
configure | 36 ++++++++++++++++++++++++++++++++++++
1 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/configure b/configure
index e09c442..2aaa6d7 100755
--- a/configure
+++ b/configure
@@ -331,6 +331,7 @@ cpu_emulation="yes"
check_utests="no"
user_pie="no"
zero_malloc=""
+spice=""
# OS specific
if check_define __linux__ ; then
@@ -647,6 +648,10 @@ for opt do
;;
--enable-kvm-device-assignment) kvm_cap_device_assignment="yes"
;;
+ --disable-spice) spice="no"
+ ;;
+ --enable-spice) spice="yes"
+ ;;
--enable-profiler) profiler="yes"
;;
--enable-cocoa)
@@ -933,6 +938,8 @@ echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable vhost-net acceleration support"
+echo " --disable-spice disable spice"
+echo " --enable-spice enable spice"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@@ -2184,6 +2191,30 @@ if compile_prog "" ""; then
gcc_attribute_warn_unused_result=yes
fi
+# spice probe
+if test "$spice" != "no" ; then
+ cat > $TMPC << EOF
+#include <spice.h>
+int main(void) { spice_server_new(); return 0; }
+EOF
+ spice_proto_ver=$($pkgconfig --modversion spice-protocol 2>/dev/null)
+ spice_server_ver=$($pkgconfig --modversion spice-server 2>/dev/null)
+ spice_cflags=$($pkgconfig --cflags spice-protocol spice-server 2>/dev/null)
+ spice_libs=$($pkgconfig --libs spice-protocol spice-server 2>/dev/null)
+ if compile_prog "$spice_cflags" "$spice_libs" ; then
+ spice="yes"
+ libs_softmmu="$libs_softmmu $spice_libs"
+ QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
+ else
+ if test "$spice" = "yes" ; then
+ feature_not_found "spice"
+ fi
+ spice="no"
+ fi
+fi
+
+##########################################
+
##########################################
# check if we have fdatasync
@@ -2329,6 +2360,7 @@ echo "preadv support $preadv"
echo "fdatasync $fdatasync"
echo "uuid support $uuid"
echo "vhost-net support $vhost_net"
+echo "spice support $spice"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2574,6 +2606,10 @@ else
echo "CONFIG_NO_CPU_EMULATION=y" >> $config_host_mak
fi
+if test "$spice" = "yes" ; then
+ echo "CONFIG_SPICE=y" >> $config_host_mak
+fi
+
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "CONFIG_BSD=y" >> $config_host_mak
--
1.7.2.3

View File

@ -0,0 +1,148 @@
>From d413b3c36cbd9820c5b9492b52caa421abccf745 Mon Sep 17 00:00:00 2001
From: Alon Levy <alevy@redhat.com>
Date: Wed, 16 Mar 2011 15:46:22 +0100
Subject: [PATCH 3/4] qxl/spice: remove qemu_mutex_{un,}lock_iothread around dispatcher
with the previous patch making sure get_command no longer needs to lock,
there is no reason to drop the qemu iothread mutex in qxl.c and in
ui/spice-display.c
The only location where the lock remains are the cursor related callbacks,
that path is currently broken. It is only triggered if running spice and sdl,
which is broken already before that.
---
hw/qxl.c | 8 --------
ui/spice-display.c | 19 +++----------------
2 files changed, 3 insertions(+), 24 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 64580f1..cf3c938 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -670,10 +670,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
dprint(d, 1, "%s: start%s\n", __FUNCTION__,
loadvm ? " (loadvm)" : "");
- qemu_mutex_unlock_iothread();
d->ssd.worker->reset_cursor(d->ssd.worker);
d->ssd.worker->reset_image_cache(d->ssd.worker);
- qemu_mutex_lock_iothread();
qxl_reset_surfaces(d);
qxl_reset_memslots(d);
@@ -803,9 +801,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
{
dprint(d, 1, "%s:\n", __FUNCTION__);
d->mode = QXL_MODE_UNDEFINED;
- qemu_mutex_unlock_iothread();
d->ssd.worker->destroy_surfaces(d->ssd.worker);
- qemu_mutex_lock_iothread();
memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
}
@@ -874,9 +870,7 @@ static void qxl_destroy_primary(PCIQXLDevice *d)
dprint(d, 1, "%s\n", __FUNCTION__);
d->mode = QXL_MODE_UNDEFINED;
- qemu_mutex_unlock_iothread();
d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
- qemu_mutex_lock_iothread();
}
static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
@@ -946,10 +940,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
case QXL_IO_UPDATE_AREA:
{
QXLRect update = d->ram->update_area;
- qemu_mutex_unlock_iothread();
d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
&update, NULL, 0, 0);
- qemu_mutex_lock_iothread();
break;
}
case QXL_IO_NOTIFY_CMD:
diff --git a/ui/spice-display.c b/ui/spice-display.c
index bdd14b8..ecb22cc 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -62,13 +62,7 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
dest->right = MAX(dest->right, r->right);
}
-/*
- * Called from spice server thread context (via interface_get_command).
- *
- * We must aquire the global qemu mutex here to make sure the
- * DisplayState (+DisplaySurface) we are accessing doesn't change
- * underneath us.
- */
+/* Called from io-thread context (via pipe_read) */
SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
{
SimpleSpiceUpdate *update;
@@ -78,9 +72,7 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
uint8_t *src, *dst;
int by, bw, bh;
- qemu_mutex_lock_iothread();
if (qemu_spice_rect_is_empty(&ssd->dirty)) {
- qemu_mutex_unlock_iothread();
return NULL;
};
@@ -141,7 +133,6 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
cmd->data = (intptr_t)drawable;
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
- qemu_mutex_unlock_iothread();
return update;
}
@@ -169,6 +160,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
ssd->worker->add_memslot(ssd->worker, &memslot);
}
+/* called from iothread (main) or a vcpu-thread */
void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
{
QXLDevSurfaceCreate surface;
@@ -186,18 +178,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
surface.mem = (intptr_t)ssd->buf;
surface.group_id = MEMSLOT_GROUP_HOST;
- qemu_mutex_unlock_iothread();
ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
- qemu_mutex_lock_iothread();
}
void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
{
dprint(1, "%s:\n", __FUNCTION__);
- qemu_mutex_unlock_iothread();
ssd->worker->destroy_primary_surface(ssd->worker, 0);
- qemu_mutex_lock_iothread();
}
void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
@@ -207,9 +195,7 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
if (running) {
ssd->worker->start(ssd->worker);
} else {
- qemu_mutex_unlock_iothread();
ssd->worker->stop(ssd->worker);
- qemu_mutex_lock_iothread();
}
ssd->running = running;
}
@@ -233,6 +219,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
qemu_spice_rect_union(&ssd->dirty, &update_area);
}
+/* called only from iothread (main) */
void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
{
dprint(1, "%s:\n", __FUNCTION__);
--
1.7.3.2

View File

@ -0,0 +1,249 @@
>From 1a33e5f2fa6de800047517a6f3251dc7191c97b5 Mon Sep 17 00:00:00 2001
From: Alon Levy <alevy@redhat.com>
Date: Wed, 16 Mar 2011 16:02:16 +0100
Subject: [PATCH 4/4] hw/qxl-render: drop cursor locks, replace with pipe
Switching locking protection of ds->cursor_set/cursor_move to moving
every call to these functions into the iothread and using the ssd->pipe
to transfer that, adding QXL_SERVER_CURSOR_SET, QXL_SERVER_CURSOR_MOVE.
This is tested with both -vnc :0 -spice and -sdl -spice.
---
hw/qxl-render.c | 25 +++++++++-----
hw/qxl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/qxl.h | 4 ++
ui/spice-display.h | 13 +++++++-
4 files changed, 122 insertions(+), 10 deletions(-)
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 58965e0..6759edb 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -178,7 +178,6 @@ fail:
return NULL;
}
-
/* called from spice server thread context only */
void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
{
@@ -209,18 +208,26 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
if (c == NULL) {
c = cursor_builtin_left_ptr();
}
- qemu_mutex_lock_iothread();
- qxl->ssd.ds->cursor_define(c);
- qxl->ssd.ds->mouse_set(x, y, 1);
- qemu_mutex_unlock_iothread();
- cursor_put(c);
+ qxl_server_request_cursor_set(qxl, c, x, y);
break;
case QXL_CURSOR_MOVE:
x = cmd->u.position.x;
y = cmd->u.position.y;
- qemu_mutex_lock_iothread();
- qxl->ssd.ds->mouse_set(x, y, 1);
- qemu_mutex_unlock_iothread();
+ qxl_server_request_cursor_move(qxl, x, y);
break;
}
}
+
+/* called from iothread only (via qxl.c:pipe_read) */
+void qxl_render_cursor_set(SimpleSpiceDisplay *ssd, QEMUCursor *c, int x, int y)
+{
+ ssd->ds->cursor_define(c);
+ ssd->ds->mouse_set(x, y, 1);
+ cursor_put(c);
+}
+
+/* called from iothread only (via qxl.c:pipe_read) */
+void qxl_render_cursor_move(SimpleSpiceDisplay *ssd, int x, int y)
+{
+ ssd->ds->mouse_set(x, y, 1);
+}
diff --git a/hw/qxl.c b/hw/qxl.c
index cf3c938..4c27deb 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -117,6 +117,27 @@ static QXLMode qxl_modes[] = {
#endif
};
+typedef struct __attribute__ ((__packed__)) {
+ QEMUCursor *c;
+ int x;
+ int y;
+} QXLServerCursorSet;
+
+typedef struct __attribute__ ((__packed__)) {
+ int x;
+ int y;
+} QXLServerCursorMove;
+
+typedef struct __attribute__ ((__packed__)) {
+ unsigned char req;
+ QXLServerCursorMove data;
+} QXLServerCursorMoveRequest;
+
+typedef struct __attribute__ ((__packed__)) {
+ unsigned char req;
+ QXLServerCursorSet data;
+} QXLServerCursorSetRequest;
+
static PCIQXLDevice *qxl0;
static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
@@ -337,6 +358,33 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
}
/* called from spice server thread context only */
+void qxl_server_request_cursor_set(PCIQXLDevice *qxl, QEMUCursor *c, int x, int y)
+{
+ QXLServerCursorSetRequest req;
+ int r;
+
+ req.req = QXL_SERVER_CURSOR_SET;
+ req.data.c = c;
+ req.data.x = x;
+ req.data.y = y;
+ r = write(qxl->ssd.pipe[1], &req, sizeof(req));
+ assert(r == sizeof(req));
+}
+
+/* called from spice server thread context only */
+void qxl_server_request_cursor_move(PCIQXLDevice *qxl, int x, int y)
+{
+ QXLServerCursorMoveRequest req;
+ int r;
+
+ req.req = QXL_SERVER_CURSOR_MOVE;
+ req.data.x = x;
+ req.data.y = y;
+ r = write(qxl->ssd.pipe[1], &req, sizeof(req));
+ assert(r == sizeof(req));
+}
+
+/* called from spice server thread context only */
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
{
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
@@ -1055,12 +1103,37 @@ static void qxl_map(PCIDevice *pci, int region_num,
}
}
+static void read_bytes(int fd, void *buf, int len_requested)
+{
+ int len;
+ int total_len = 0;
+
+ do {
+ len = read(fd, buf, len_requested - total_len);
+ if (len < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ perror("qxl: pipe_read: read failed");
+ /* will abort once it's out of the while loop */
+ break;
+ }
+ total_len += len;
+ buf = (uint8_t *)buf + len;
+ } while (total_len < len_requested);
+ assert(total_len == len_requested);
+}
+
static void pipe_read(void *opaque)
{
SimpleSpiceDisplay *ssd = opaque;
unsigned char cmd;
int len, set_irq = 0;
int create_update = 0;
+ int cursor_set = 0;
+ int cursor_move = 0;
+ QXLServerCursorSet cursor_set_data;
+ QXLServerCursorMove cursor_move_data;
while (1) {
cmd = 0;
@@ -1082,6 +1155,17 @@ static void pipe_read(void *opaque)
case QXL_SERVER_CREATE_UPDATE:
create_update = 1;
break;
+ case QXL_SERVER_CURSOR_SET:
+ if (cursor_set == 1) {
+ cursor_put(cursor_set_data.c);
+ }
+ cursor_set = 1;
+ read_bytes(ssd->pipe[0], &cursor_set_data, sizeof(cursor_set_data));
+ break;
+ case QXL_SERVER_CURSOR_MOVE:
+ cursor_move = 1;
+ read_bytes(ssd->pipe[0], &cursor_move_data, sizeof(cursor_move_data));
+ break;
default:
fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
abort();
@@ -1099,6 +1183,12 @@ static void pipe_read(void *opaque)
if (set_irq) {
qxl_set_irq(container_of(ssd, PCIQXLDevice, ssd));
}
+ if (cursor_move) {
+ qxl_render_cursor_move(ssd, cursor_move_data.x, cursor_move_data.y);
+ }
+ if (cursor_set) {
+ qxl_render_cursor_set(ssd, cursor_set_data.c, cursor_set_data.x, cursor_set_data.y);
+ }
}
static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
diff --git a/hw/qxl.h b/hw/qxl.h
index 701245f..f4f99ec 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -93,6 +93,8 @@ typedef struct PCIQXLDevice {
/* qxl.c */
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+void qxl_server_request_cursor_set(PCIQXLDevice *qxl, QEMUCursor *c, int x, int y);
+void qxl_server_request_cursor_move(PCIQXLDevice *qxl, int x, int y);
/* qxl-logger.c */
void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
@@ -102,3 +104,5 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
void qxl_render_resize(PCIQXLDevice *qxl);
void qxl_render_update(PCIQXLDevice *qxl);
void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
+void qxl_render_cursor_set(SimpleSpiceDisplay *ssd, QEMUCursor *c, int x, int y);
+void qxl_render_cursor_move(SimpleSpiceDisplay *ssd, int x, int y);
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 2be6a34..bbfd689 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -31,11 +31,22 @@
#define NUM_SURFACES 1024
-/* For commands/requests from server thread to iothread */
+/*
+ * Commands/requests from server thread to iothread.
+ * Note that CREATE_UPDATE is used both with qxl and without it (spice-display)
+ * the others are only used with the qxl device.
+ *
+ * SET_IRQ - just the request is sent (1 byte)
+ * CREATE_UPDATE - jus the request is sent (1 byte)
+ * CURSOR_SET - send QXLServerRequestCursorSet
+ * CURSOR_MOVE - send QXLServerRequestCursorMove
+ */
#define QXL_EMPTY_UPDATE ((void *)-1)
enum {
QXL_SERVER_SET_IRQ = 1,
QXL_SERVER_CREATE_UPDATE,
+ QXL_SERVER_CURSOR_SET,
+ QXL_SERVER_CURSOR_MOVE
};
struct SimpleSpiceUpdate;
--
1.7.3.2

View File

@ -1,333 +0,0 @@
From 67361a4ad5c99c5dfecdb9d2fc1ba794c38c44ff Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 11 Mar 2010 11:13:27 -0300
Subject: [PATCH 04/39] spice: core bits
Add -spice command line switch. Has support setting passwd and port for
now. With this patch applied the spice client can successfully connect
to qemu. You can't do anything useful yet though.
---
Makefile.objs | 2 +
qemu-config.c | 23 ++++++++
qemu-config.h | 1 +
qemu-options.hx | 8 +++
qemu-spice.h | 22 ++++++++
spice.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
vl.c | 15 ++++++
7 files changed, 222 insertions(+), 0 deletions(-)
create mode 100644 qemu-spice.h
create mode 100644 spice.c
diff --git a/Makefile.objs b/Makefile.objs
index 147051f..569b458 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -89,6 +89,8 @@ common-obj-y += pflib.o
common-obj-$(CONFIG_BRLAPI) += baum.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
+common-obj-$(CONFIG_SPICE) += spice.o
+
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
audio-obj-$(CONFIG_OSS) += ossaudio.o
diff --git a/qemu-config.c b/qemu-config.c
index 08ee553..8a894cf 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -346,6 +346,26 @@ QemuOptsList qemu_cpudef_opts = {
},
};
+#ifdef CONFIG_SPICE
+QemuOptsList qemu_spice_opts = {
+ .name = "spice",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
+ .desc = {
+ {
+ .name = "port",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "password",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "disable-ticketing",
+ .type = QEMU_OPT_BOOL,
+ },
+ { /* end if list */ }
+ },
+};
+#endif
+
static QemuOptsList *vm_config_groups[] = {
&qemu_drive_opts,
&qemu_chardev_opts,
@@ -356,6 +376,9 @@ static QemuOptsList *vm_config_groups[] = {
&qemu_global_opts,
&qemu_mon_opts,
&qemu_cpudef_opts,
+#ifdef CONFIG_SPICE
+ &qemu_spice_opts,
+#endif
NULL,
};
diff --git a/qemu-config.h b/qemu-config.h
index dca69d4..3a90213 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -14,6 +14,7 @@ extern QemuOptsList qemu_rtc_opts;
extern QemuOptsList qemu_global_opts;
extern QemuOptsList qemu_mon_opts;
extern QemuOptsList qemu_cpudef_opts;
+extern QemuOptsList qemu_spice_opts;
QemuOptsList *qemu_find_opts(const char *group);
int qemu_set_option(const char *str);
diff --git a/qemu-options.hx b/qemu-options.hx
index 66c84a0..85551cc 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -676,6 +676,14 @@ STEXI
Enable SDL.
ETEXI
+#ifdef CONFIG_SPICE
+DEF("spice", HAS_ARG, QEMU_OPTION_spice,
+ "-spice <args> use spice\n", QEMU_ARCH_ALL)
+STEXI
+Use Spice.
+ETEXI
+#endif
+
DEF("portrait", 0, QEMU_OPTION_portrait,
"-portrait rotate graphical output 90 deg left (only PXA LCD)\n",
QEMU_ARCH_ALL)
diff --git a/qemu-spice.h b/qemu-spice.h
new file mode 100644
index 0000000..5597576
--- /dev/null
+++ b/qemu-spice.h
@@ -0,0 +1,22 @@
+#ifndef QEMU_SPICE_H
+#define QEMU_SPICE_H
+
+#ifdef CONFIG_SPICE
+
+#include <spice.h>
+
+#include "qemu-option.h"
+#include "qemu-config.h"
+
+extern SpiceServer *spice_server;
+extern int using_spice;
+
+void qemu_spice_init(void);
+
+#else /* CONFIG_SPICE */
+
+#define using_spice 0
+
+#endif /* CONFIG_SPICE */
+
+#endif /* QEMU_SPICE_H */
diff --git a/spice.c b/spice.c
new file mode 100644
index 0000000..50fa5ca
--- /dev/null
+++ b/spice.c
@@ -0,0 +1,151 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <spice.h>
+#include <spice-experimental.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "monitor.h"
+
+/* core bits */
+
+SpiceServer *spice_server;
+int using_spice = 0;
+
+struct SpiceTimer {
+ QEMUTimer *timer;
+ QTAILQ_ENTRY(SpiceTimer) next;
+};
+static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers);
+
+static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
+{
+ SpiceTimer *timer;
+
+ timer = qemu_mallocz(sizeof(*timer));
+ timer->timer = qemu_new_timer(rt_clock, func, opaque);
+ QTAILQ_INSERT_TAIL(&timers, timer, next);
+ return timer;
+}
+
+static void timer_start(SpiceTimer *timer, uint32_t ms)
+{
+ qemu_mod_timer(timer->timer, qemu_get_clock(rt_clock) + ms);
+}
+
+static void timer_cancel(SpiceTimer *timer)
+{
+ qemu_del_timer(timer->timer);
+}
+
+static void timer_remove(SpiceTimer *timer)
+{
+ qemu_del_timer(timer->timer);
+ qemu_free_timer(timer->timer);
+ QTAILQ_REMOVE(&timers, timer, next);
+ free(timer);
+}
+
+struct SpiceWatch {
+ int fd;
+ int event_mask;
+ SpiceWatchFunc func;
+ void *opaque;
+ QTAILQ_ENTRY(SpiceWatch) next;
+};
+static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches);
+
+static void watch_read(void *opaque)
+{
+ SpiceWatch *watch = opaque;
+ watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
+}
+
+static void watch_write(void *opaque)
+{
+ SpiceWatch *watch = opaque;
+ watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
+}
+
+static void watch_update_mask(SpiceWatch *watch, int event_mask)
+{
+ IOHandler *on_read = NULL;
+ IOHandler *on_write = NULL;
+
+ watch->event_mask = event_mask;
+ if (watch->event_mask & SPICE_WATCH_EVENT_READ)
+ on_read = watch_read;
+ if (watch->event_mask & SPICE_WATCH_EVENT_WRITE)
+ on_read = watch_write;
+ qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
+}
+
+static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+{
+ SpiceWatch *watch;
+
+ watch = qemu_mallocz(sizeof(*watch));
+ watch->fd = fd;
+ watch->func = func;
+ watch->opaque = opaque;
+ QTAILQ_INSERT_TAIL(&watches, watch, next);
+
+ watch_update_mask(watch, event_mask);
+ return watch;
+}
+
+static void watch_remove(SpiceWatch *watch)
+{
+ watch_update_mask(watch, 0);
+ QTAILQ_REMOVE(&watches, watch, next);
+ qemu_free(watch);
+}
+
+static SpiceCoreInterface core_interface = {
+ .base.type = SPICE_INTERFACE_CORE,
+ .base.description = "qemu core services",
+ .base.major_version = SPICE_INTERFACE_CORE_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_CORE_MINOR,
+
+ .timer_add = timer_add,
+ .timer_start = timer_start,
+ .timer_cancel = timer_cancel,
+ .timer_remove = timer_remove,
+
+ .watch_add = watch_add,
+ .watch_update_mask = watch_update_mask,
+ .watch_remove = watch_remove,
+};
+
+/* functions for the rest of qemu */
+
+void qemu_spice_init(void)
+{
+ QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+ const char *password;
+ int port;
+
+ if (!opts)
+ return;
+ port = qemu_opt_get_number(opts, "port", 0);
+ if (!port)
+ return;
+ password = qemu_opt_get(opts, "password");
+
+ spice_server = spice_server_new();
+ spice_server_set_port(spice_server, port);
+ if (password)
+ spice_server_set_ticket(spice_server, password, 0, 0, 0);
+ if (qemu_opt_get_bool(opts, "disable-ticketing", 0))
+ spice_server_set_noauth(spice_server);
+
+ /* TODO: make configurable via cmdline */
+ spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
+
+ spice_server_init(spice_server, &core_interface);
+ using_spice = 1;
+}
diff --git a/vl.c b/vl.c
index de8bad1..97897e0 100644
--- a/vl.c
+++ b/vl.c
@@ -162,6 +162,8 @@ int main(int argc, char **argv)
#include "cpus.h"
#include "arch_init.h"
+#include "qemu-spice.h"
+
//#define DEBUG_NET
//#define DEBUG_SLIRP
@@ -2677,6 +2679,15 @@ int main(int argc, char **argv, char **envp)
}
break;
}
+#ifdef CONFIG_SPICE
+ case QEMU_OPTION_spice:
+ opts = qemu_opts_parse(&qemu_spice_opts, optarg, 0);
+ if (!opts) {
+ fprintf(stderr, "parse error: %s\n", optarg);
+ exit(1);
+ }
+ break;
+#endif
case QEMU_OPTION_writeconfig:
{
FILE *fp;
@@ -2951,6 +2962,10 @@ int main(int argc, char **argv, char **envp)
}
qemu_add_globals();
+#ifdef CONFIG_SPICE
+ qemu_spice_init();
+#endif
+
machine->init(ram_size, boot_devices,
kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
--
1.7.2.3

View File

@ -1,118 +0,0 @@
From 90f6ec84332857752c252b1c3b89d86eb9714b0e Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 11 Mar 2010 11:13:28 -0300
Subject: [PATCH 05/39] spice: add keyboard
Open keyboard channel. Now you can type into the spice client and the
keyboard events are sent to your guest. You'll need some other display
like vnc to actually see the guest responding to them though.
---
Makefile.objs | 2 +-
qemu-spice.h | 1 +
spice-input.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
spice.c | 2 ++
4 files changed, 61 insertions(+), 1 deletions(-)
create mode 100644 spice-input.c
diff --git a/Makefile.objs b/Makefile.objs
index 569b458..023a0dc 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -89,7 +89,7 @@ common-obj-y += pflib.o
common-obj-$(CONFIG_BRLAPI) += baum.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
-common-obj-$(CONFIG_SPICE) += spice.o
+common-obj-$(CONFIG_SPICE) += spice.o spice-input.o
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
diff --git a/qemu-spice.h b/qemu-spice.h
index 5597576..ceb3db2 100644
--- a/qemu-spice.h
+++ b/qemu-spice.h
@@ -12,6 +12,7 @@ extern SpiceServer *spice_server;
extern int using_spice;
void qemu_spice_init(void);
+void qemu_spice_input_init(void);
#else /* CONFIG_SPICE */
diff --git a/spice-input.c b/spice-input.c
new file mode 100644
index 0000000..e1014d7
--- /dev/null
+++ b/spice-input.c
@@ -0,0 +1,57 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <spice.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "console.h"
+
+/* keyboard bits */
+
+typedef struct QemuSpiceKbd {
+ SpiceKbdInstance sin;
+ int ledstate;
+} QemuSpiceKbd;
+
+static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
+static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
+static void kbd_leds(void *opaque, int l);
+
+static const SpiceKbdInterface kbd_interface = {
+ .base.type = SPICE_INTERFACE_KEYBOARD,
+ .base.description = "qemu keyboard",
+ .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
+ .push_scan_freg = kbd_push_key,
+ .get_leds = kbd_get_leds,
+};
+
+static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
+{
+ kbd_put_keycode(frag);
+}
+
+static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
+{
+ QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
+ return kbd->ledstate;
+}
+
+static void kbd_leds(void *opaque, int ledstate)
+{
+ QemuSpiceKbd *kbd = opaque;
+ kbd->ledstate = ledstate;
+ spice_server_kbd_leds(&kbd->sin, ledstate);
+}
+
+void qemu_spice_input_init(void)
+{
+ QemuSpiceKbd *kbd;
+
+ kbd = qemu_mallocz(sizeof(*kbd));
+ kbd->sin.base.sif = &kbd_interface.base;
+ spice_server_add_interface(spice_server, &kbd->sin.base);
+ qemu_add_led_event_handler(kbd_leds, kbd);
+}
diff --git a/spice.c b/spice.c
index 50fa5ca..c763d52 100644
--- a/spice.c
+++ b/spice.c
@@ -148,4 +148,6 @@ void qemu_spice_init(void)
spice_server_init(spice_server, &core_interface);
using_spice = 1;
+
+ qemu_spice_input_init();
}
--
1.7.2.3

View File

@ -1,62 +0,0 @@
From e18846175191cbc590ac46fa3820726aeebd6d48 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 11 Mar 2010 11:13:29 -0300
Subject: [PATCH 06/39] spice: add mouse
Open mouse channel. Now you can move the guests mouse pointer.
No tablet / absolute positioning (yet) though.
---
spice-input.c | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/spice-input.c b/spice-input.c
index e1014d7..8f3deb4 100644
--- a/spice-input.c
+++ b/spice-input.c
@@ -46,12 +46,43 @@ static void kbd_leds(void *opaque, int ledstate)
spice_server_kbd_leds(&kbd->sin, ledstate);
}
+/* mouse bits */
+
+typedef struct QemuSpiceMouse {
+ SpiceMouseInstance sin;
+} QemuSpiceMouse;
+
+static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
+ uint32_t buttons_state)
+{
+ kbd_mouse_event(dx, dy, dz, buttons_state);
+}
+
+static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
+{
+ kbd_mouse_event(0, 0, 0, buttons_state);
+}
+
+static const SpiceMouseInterface mouse_interface = {
+ .base.type = SPICE_INTERFACE_MOUSE,
+ .base.description = "mouse",
+ .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
+ .motion = mouse_motion,
+ .buttons = mouse_buttons,
+};
+
void qemu_spice_input_init(void)
{
QemuSpiceKbd *kbd;
+ QemuSpiceMouse *mouse;
kbd = qemu_mallocz(sizeof(*kbd));
kbd->sin.base.sif = &kbd_interface.base;
spice_server_add_interface(spice_server, &kbd->sin.base);
qemu_add_led_event_handler(kbd_leds, kbd);
+
+ mouse = qemu_mallocz(sizeof(*mouse));
+ mouse->sin.base.sif = &mouse_interface.base;
+ spice_server_add_interface(spice_server, &mouse->sin.base);
}
--
1.7.2.3

View File

@ -1,532 +0,0 @@
From 0143117eb5e6233fdeff3b679492b51148cc8f85 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 24 Mar 2010 15:47:18 +0100
Subject: [PATCH 07/39] spice: simple display
With that patch applied you'll actually see the guests screen in the
spice client. This does *not* bring qxl and full spice support though.
This is basically the qxl vga mode made more generic, so it plays
together with any qemu-emulated gfx card. You can display stdvga or
cirrus via spice client. You can have both vnc and spice enabled and
clients connected at the same time.
---
Makefile.objs | 2 +-
qemu-spice.h | 1 +
spice-display.c | 394 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
spice-display.h | 52 ++++++++
vl.c | 7 +-
5 files changed, 454 insertions(+), 2 deletions(-)
create mode 100644 spice-display.c
create mode 100644 spice-display.h
diff --git a/Makefile.objs b/Makefile.objs
index 023a0dc..d05643f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -89,7 +89,7 @@ common-obj-y += pflib.o
common-obj-$(CONFIG_BRLAPI) += baum.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
-common-obj-$(CONFIG_SPICE) += spice.o spice-input.o
+common-obj-$(CONFIG_SPICE) += spice.o spice-input.o spice-display.o
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
diff --git a/qemu-spice.h b/qemu-spice.h
index ceb3db2..f061004 100644
--- a/qemu-spice.h
+++ b/qemu-spice.h
@@ -13,6 +13,7 @@ extern int using_spice;
void qemu_spice_init(void);
void qemu_spice_input_init(void);
+void qemu_spice_display_init(DisplayState *ds);
#else /* CONFIG_SPICE */
diff --git a/spice-display.c b/spice-display.c
new file mode 100644
index 0000000..13a620e
--- /dev/null
+++ b/spice-display.c
@@ -0,0 +1,394 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+
+#include "spice-display.h"
+
+static int debug = 1;
+
+int qemu_spice_rect_is_empty(const QXLRect* r)
+{
+ return r->top == r->bottom || r->left == r->right;
+}
+
+void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
+{
+ if (qemu_spice_rect_is_empty(r)) {
+ return;
+ }
+
+ if (qemu_spice_rect_is_empty(dest)) {
+ *dest = *r;
+ return;
+ }
+
+ dest->top = MIN(dest->top, r->top);
+ dest->left = MIN(dest->left, r->left);
+ dest->bottom = MAX(dest->bottom, r->bottom);
+ dest->right = MAX(dest->right, r->right);
+}
+
+SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+{
+ SimpleSpiceUpdate *update;
+ QXLDrawable *drawable;
+ QXLImage *image;
+ QXLCommand *cmd;
+ uint8_t *src, *dst;
+ int by, bw, bh;
+
+ if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+ return NULL;
+ };
+
+ pthread_mutex_lock(&ssd->lock);
+ if (debug > 1)
+ fprintf(stderr, "%s: lr %d -> %d, tb -> %d -> %d\n", __FUNCTION__,
+ ssd->dirty.left, ssd->dirty.right,
+ ssd->dirty.top, ssd->dirty.bottom);
+
+ update = qemu_mallocz(sizeof(*update));
+ drawable = &update->drawable;
+ image = &update->image;
+ cmd = &update->ext.cmd;
+
+ bw = ssd->dirty.right - ssd->dirty.left;
+ bh = ssd->dirty.bottom - ssd->dirty.top;
+ update->bitmap = qemu_malloc(bw * bh * 4);
+
+ drawable->bbox = ssd->dirty;
+ drawable->clip.type = SPICE_CLIP_TYPE_NONE;
+ drawable->effect = QXL_EFFECT_OPAQUE;
+ drawable->release_info.id = (intptr_t)update;
+ drawable->type = QXL_DRAW_COPY;
+
+ drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
+ drawable->u.copy.src_bitmap = (intptr_t)image;
+ drawable->u.copy.src_area.right = bw;
+ drawable->u.copy.src_area.bottom = bh;
+
+ QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++);
+ image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
+ image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
+ image->bitmap.stride = bw * 4;
+ image->descriptor.width = image->bitmap.x = bw;
+ image->descriptor.height = image->bitmap.y = bh;
+ image->bitmap.data = (intptr_t)(update->bitmap);
+ image->bitmap.palette = 0;
+ image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+
+ if (ssd->conv == NULL) {
+ PixelFormat dst = qemu_default_pixelformat(32);
+ ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf);
+ assert(ssd->conv);
+ }
+
+ src = ds_get_data(ssd->ds) +
+ ssd->dirty.top * ds_get_linesize(ssd->ds) +
+ ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds);
+ dst = update->bitmap;
+ for (by = 0; by < bh; by++) {
+ qemu_pf_conv_run(ssd->conv, dst, src, bw);
+ src += ds_get_linesize(ssd->ds);
+ dst += image->bitmap.stride;
+ }
+
+ cmd->type = QXL_CMD_DRAW;
+ cmd->data = (intptr_t)drawable;
+
+ memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+ pthread_mutex_unlock(&ssd->lock);
+ return update;
+}
+
+void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
+{
+ qemu_free(update->bitmap);
+ qemu_free(update);
+}
+
+void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
+{
+ QXLDevMemSlot memslot;
+
+ if (debug)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+
+ memset(&memslot, 0, sizeof(memslot));
+ memslot.slot_group_id = MEMSLOT_GROUP_HOST;
+ memslot.virt_end = ~0;
+ ssd->worker->add_memslot(ssd->worker, &memslot);
+}
+
+void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+{
+ QXLDevSurfaceCreate surface;
+
+ if (debug)
+ fprintf(stderr, "%s: %dx%d\n", __FUNCTION__,
+ ds_get_width(ssd->ds), ds_get_height(ssd->ds));
+
+ surface.format = SPICE_SURFACE_FMT_32_xRGB;
+ surface.width = ds_get_width(ssd->ds);
+ surface.height = ds_get_height(ssd->ds);
+ surface.stride = -surface.width * 4;
+ surface.mouse_mode = 0;
+ surface.flags = 0;
+ surface.type = 0;
+ surface.mem = (intptr_t)ssd->buf;
+ surface.group_id = MEMSLOT_GROUP_HOST;
+ ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
+}
+
+void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
+{
+ if (debug)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+
+ ssd->worker->destroy_primary_surface(ssd->worker, 0);
+}
+
+void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+{
+ SimpleSpiceDisplay *ssd = opaque;
+
+ if (running) {
+ ssd->worker->start(ssd->worker);
+ } else {
+ ssd->worker->stop(ssd->worker);
+ }
+ ssd->running = running;
+}
+
+/* display listener callbacks */
+
+void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+ int x, int y, int w, int h)
+{
+ QXLRect update_area;
+
+ if (debug > 1)
+ fprintf(stderr, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h);
+ update_area.left = x,
+ update_area.right = x + w;
+ update_area.top = y;
+ update_area.bottom = y + h;
+
+ pthread_mutex_lock(&ssd->lock);
+ if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+ ssd->notify++;
+ }
+ qemu_spice_rect_union(&ssd->dirty, &update_area);
+ pthread_mutex_unlock(&ssd->lock);
+}
+
+void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
+{
+ if (debug)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+
+ pthread_mutex_lock(&ssd->lock);
+ memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+ pthread_mutex_unlock(&ssd->lock);
+
+ qemu_spice_destroy_host_primary(ssd);
+ qemu_spice_create_host_primary(ssd);
+ qemu_pf_conv_put(ssd->conv);
+ ssd->conv = NULL;
+
+ pthread_mutex_lock(&ssd->lock);
+ ssd->dirty.left = 0;
+ ssd->dirty.right = ds_get_width(ssd->ds);
+ ssd->dirty.top = 0;
+ ssd->dirty.bottom = ds_get_height(ssd->ds);
+ ssd->notify++;
+ pthread_mutex_unlock(&ssd->lock);
+}
+
+void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
+{
+ if (debug > 2)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ vga_hw_update();
+ if (ssd->notify) {
+ ssd->notify = 0;
+ ssd->worker->wakeup(ssd->worker);
+ if (debug > 1)
+ fprintf(stderr, "%s: notify\n", __FUNCTION__);
+ }
+}
+
+/* spice display interface callbacks */
+
+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
+{
+ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+
+ if (debug)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ ssd->worker = qxl_worker;
+}
+
+static void interface_set_compression_level(QXLInstance *sin, int level)
+{
+ if (debug)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ /* nothing to do */
+}
+
+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
+{
+ if (debug > 2)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ /* nothing to do */
+}
+
+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+{
+ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+
+ info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
+ info->memslot_id_bits = MEMSLOT_SLOT_BITS;
+ info->num_memslots = NUM_MEMSLOTS;
+ info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
+ info->internal_groupslot_id = 0;
+ info->qxl_ram_size = ssd->bufsize;
+ info->n_surfaces = NUM_SURFACES;
+}
+
+static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+ SimpleSpiceUpdate *update;
+
+ if (debug > 2)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ update = qemu_spice_create_update(ssd);
+ if (update == NULL) {
+ return false;
+ }
+ *ext = update->ext;
+ return true;
+}
+
+static int interface_req_cmd_notification(QXLInstance *sin)
+{
+ if (debug)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ return 1;
+}
+
+static void interface_release_resource(QXLInstance *sin,
+ struct QXLReleaseInfoExt ext)
+{
+ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+ uintptr_t id;
+
+ if (debug > 1)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ id = ext.info->id;
+ qemu_spice_destroy_update(ssd, (void*)id);
+}
+
+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+ if (debug > 2)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ return false;
+}
+
+static int interface_req_cursor_notification(QXLInstance *sin)
+{
+ if (debug)
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ return 1;
+}
+
+static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
+{
+ fprintf(stderr, "%s: abort()\n", __FUNCTION__);
+ abort();
+}
+
+static int interface_flush_resources(QXLInstance *sin)
+{
+ fprintf(stderr, "%s: abort()\n", __FUNCTION__);
+ abort();
+ return 0;
+}
+
+static const QXLInterface dpy_interface = {
+ .base.type = SPICE_INTERFACE_QXL,
+ .base.description = "qemu simple display",
+ .base.major_version = SPICE_INTERFACE_QXL_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_QXL_MINOR,
+
+ .pci_vendor = REDHAT_PCI_VENDOR_ID,
+ .pci_id = QXL_DEVICE_ID,
+ .pci_revision = QXL_REVISION,
+
+ .attache_worker = interface_attach_worker,
+ .set_compression_level = interface_set_compression_level,
+ .set_mm_time = interface_set_mm_time,
+
+ .get_init_info = interface_get_init_info,
+ .get_command = interface_get_command,
+ .req_cmd_notification = interface_req_cmd_notification,
+ .release_resource = interface_release_resource,
+ .get_cursor_command = interface_get_cursor_command,
+ .req_cursor_notification = interface_req_cursor_notification,
+ .notify_update = interface_notify_update,
+ .flush_resources = interface_flush_resources,
+};
+
+static SimpleSpiceDisplay sdpy;
+
+static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
+{
+ qemu_spice_display_update(&sdpy, x, y, w, h);
+}
+
+static void display_resize(struct DisplayState *ds)
+{
+ qemu_spice_display_resize(&sdpy);
+}
+
+static void display_refresh(struct DisplayState *ds)
+{
+ qemu_spice_display_refresh(&sdpy);
+}
+
+static DisplayChangeListener display_listener = {
+ .dpy_update = display_update,
+ .dpy_resize = display_resize,
+ .dpy_refresh = display_refresh,
+};
+
+void qemu_spice_display_init(DisplayState *ds)
+{
+ assert(sdpy.ds == NULL);
+ sdpy.ds = ds;
+ sdpy.bufsize = (16 * 1024 * 1024);
+ sdpy.buf = qemu_malloc(sdpy.bufsize);
+ pthread_mutex_init(&sdpy.lock, NULL);
+ register_displaychangelistener(ds, &display_listener);
+
+ sdpy.qxl.base.sif = &dpy_interface.base;
+ spice_server_add_interface(spice_server, &sdpy.qxl.base);
+ assert(sdpy.worker);
+
+ qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy);
+ qemu_spice_create_host_memslot(&sdpy);
+ qemu_spice_create_host_primary(&sdpy);
+}
diff --git a/spice-display.h b/spice-display.h
new file mode 100644
index 0000000..70a7be4
--- /dev/null
+++ b/spice-display.h
@@ -0,0 +1,52 @@
+#include <spice/ipc_ring.h>
+#include <spice/draw.h>
+#include <spice/qxl_dev.h>
+
+#include "pflib.h"
+
+#define NUM_MEMSLOTS 8
+#define MEMSLOT_GENERATION_BITS 8
+#define MEMSLOT_SLOT_BITS 8
+
+#define MEMSLOT_GROUP_HOST 0
+#define MEMSLOT_GROUP_GUEST 1
+#define NUM_MEMSLOTS_GROUPS 2
+
+#define NUM_SURFACES 1024
+
+typedef struct SimpleSpiceDisplay {
+ DisplayState *ds;
+ void *buf;
+ int bufsize;
+ QXLWorker *worker;
+ QXLInstance qxl;
+ uint32_t unique;
+ QemuPfConv *conv;
+
+ pthread_mutex_t lock;
+ QXLRect dirty;
+ int notify;
+ int running;
+} SimpleSpiceDisplay;
+
+typedef struct SimpleSpiceUpdate {
+ QXLDrawable drawable;
+ QXLImage image;
+ QXLCommandExt ext;
+ uint8_t *bitmap;
+} SimpleSpiceUpdate;
+
+int qemu_spice_rect_is_empty(const QXLRect* r);
+void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
+
+SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *sdpy);
+void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update);
+void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
+void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
+void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
+void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
+
+void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+ int x, int y, int w, int h);
+void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
+void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
diff --git a/vl.c b/vl.c
index 97897e0..2ccebc8 100644
--- a/vl.c
+++ b/vl.c
@@ -2993,7 +2993,7 @@ int main(int argc, char **argv, char **envp)
/* just use the first displaystate for the moment */
ds = get_displaystate();
- if (display_type == DT_DEFAULT) {
+ if (display_type == DT_DEFAULT && !using_spice) {
#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
display_type = DT_SDL;
#else
@@ -3033,6 +3033,11 @@ int main(int argc, char **argv, char **envp)
default:
break;
}
+#ifdef CONFIG_SPICE
+ if (using_spice) {
+ qemu_spice_display_init(ds);
+ }
+#endif
dpy_resize(ds);
dcl = ds->listeners;
--
1.7.2.3

View File

@ -1,160 +0,0 @@
From e3c6e18e27f0d598b37e9be1795dbcb42f740071 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 13 Apr 2010 09:05:03 +0200
Subject: [PATCH 08/39] spice: add tablet support
Add support for the spice tablet interface. The tablet interface will
be registered (and then used by the spice client) as soon as a absolute
pointing device is available and used by the guest, i.e. you'll have to
configure your guest with '-usbdevice tablet'.
---
spice-display.c | 2 +-
spice-input.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 93 insertions(+), 8 deletions(-)
diff --git a/spice-display.c b/spice-display.c
index 13a620e..a749e64 100644
--- a/spice-display.c
+++ b/spice-display.c
@@ -143,7 +143,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
surface.width = ds_get_width(ssd->ds);
surface.height = ds_get_height(ssd->ds);
surface.stride = -surface.width * 4;
- surface.mouse_mode = 0;
+ surface.mouse_mode = true;
surface.flags = 0;
surface.type = 0;
surface.mem = (intptr_t)ssd->buf;
diff --git a/spice-input.c b/spice-input.c
index 8f3deb4..5646ff9 100644
--- a/spice-input.c
+++ b/spice-input.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdbool.h>
#include <string.h>
#include <spice.h>
@@ -48,9 +49,13 @@ static void kbd_leds(void *opaque, int ledstate)
/* mouse bits */
-typedef struct QemuSpiceMouse {
- SpiceMouseInstance sin;
-} QemuSpiceMouse;
+typedef struct QemuSpicePointer {
+ SpiceMouseInstance mouse;
+ SpiceTabletInstance tablet;
+ int width, height, x, y;
+ Notifier mouse_mode;
+ bool absolute;
+} QemuSpicePointer;
static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
uint32_t buttons_state)
@@ -72,17 +77,97 @@ static const SpiceMouseInterface mouse_interface = {
.buttons = mouse_buttons,
};
+static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
+{
+ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+ fprintf(stderr, "%s: %dx%d\n", __FUNCTION__, width, height);
+ if (height < 16)
+ height = 16;
+ if (width < 16)
+ width = 16;
+ pointer->width = width;
+ pointer->height = height;
+}
+
+static void tablet_position(SpiceTabletInstance* sin, int x, int y,
+ uint32_t buttons_state)
+{
+ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+ pointer->x = x * 0x7FFF / (pointer->width - 1);
+ pointer->y = y * 0x7FFF / (pointer->height - 1);
+ kbd_mouse_event(pointer->x, pointer->y, 0, buttons_state);
+}
+
+
+static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
+ uint32_t buttons_state)
+{
+ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+ kbd_mouse_event(pointer->x, pointer->y, wheel, buttons_state);
+}
+
+static void tablet_buttons(SpiceTabletInstance *sin,
+ uint32_t buttons_state)
+{
+ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+ kbd_mouse_event(pointer->x, pointer->y, 0, buttons_state);
+}
+
+static const SpiceTabletInterface tablet_interface = {
+ .base.type = SPICE_INTERFACE_TABLET,
+ .base.description = "tablet",
+ .base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
+ .set_logical_size = tablet_set_logical_size,
+ .position = tablet_position,
+ .wheel = tablet_wheel,
+ .buttons = tablet_buttons,
+};
+
+static void mouse_mode_notifier(Notifier *notifier)
+{
+ QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
+ bool is_absolute = kbd_mouse_is_absolute();
+ bool has_absolute = kbd_mouse_has_absolute();
+
+ fprintf(stderr, "%s: absolute pointer: %s%s\n", __FUNCTION__,
+ has_absolute ? "present" : "not available",
+ is_absolute ? "+active" : "");
+
+ if (pointer->absolute == is_absolute)
+ return;
+
+ if (is_absolute) {
+ fprintf(stderr, "%s: using absolute pointer (client mode)\n", __FUNCTION__);
+ spice_server_add_interface(spice_server, &pointer->tablet.base);
+ } else {
+ fprintf(stderr, "%s: using relative pointer (server mode)\n", __FUNCTION__);
+ spice_server_remove_interface(&pointer->tablet.base);
+ }
+ pointer->absolute = is_absolute;
+}
+
void qemu_spice_input_init(void)
{
QemuSpiceKbd *kbd;
- QemuSpiceMouse *mouse;
+ QemuSpicePointer *pointer;
kbd = qemu_mallocz(sizeof(*kbd));
kbd->sin.base.sif = &kbd_interface.base;
spice_server_add_interface(spice_server, &kbd->sin.base);
qemu_add_led_event_handler(kbd_leds, kbd);
- mouse = qemu_mallocz(sizeof(*mouse));
- mouse->sin.base.sif = &mouse_interface.base;
- spice_server_add_interface(spice_server, &mouse->sin.base);
+ pointer = qemu_mallocz(sizeof(*pointer));
+ pointer->mouse.base.sif = &mouse_interface.base;
+ pointer->tablet.base.sif = &tablet_interface.base;
+ spice_server_add_interface(spice_server, &pointer->mouse.base);
+
+ pointer->absolute = false;
+ pointer->mouse_mode.notify = mouse_mode_notifier;
+ qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
+ mouse_mode_notifier(&pointer->mouse_mode);
}
--
1.7.2.3

View File

@ -1,28 +0,0 @@
From 0920337756cdf82dcd585efb23ae18f8086696c8 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 24 Mar 2010 11:16:54 +0100
Subject: [PATCH 09/39] vgabios update to 0.6c + pcibios patches.
---
Makefile | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 3cd07e0..e40c9a2 100644
--- a/Makefile
+++ b/Makefile
@@ -154,8 +154,9 @@ ar de en-us fi fr-be hr it lv nl pl ru th \
common de-ch es fo fr-ca hu ja mk nl-be pt sl tr
ifdef INSTALL_BLOBS
-BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
-video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
+BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
+vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-qxldev.bin \
+ppc_rom.bin video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
gpxe-eepro100-80861209.rom \
gpxe-eepro100-80861229.rom \
pxe-e1000.bin \
--
1.7.2.3

View File

@ -1,31 +0,0 @@
From 6ac04dff1ee3932d2ef94c1e42f4e8208fbf92bf Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 6 May 2010 11:13:11 +0200
Subject: [PATCH 10/39] switch stdvga to pci vgabios
---
hw/vga-pci.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 3907871..8e1ed35 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -105,11 +105,10 @@ static int pci_vga_initfn(PCIDevice *dev)
bios_total_size <<= 1;
pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+ } else {
+ if (dev->romfile == NULL)
+ dev->romfile = qemu_strdup("vgabios-stdvga.bin");
}
-
- vga_init_vbe(s);
- /* ROM BIOS */
- rom_add_vga(VGABIOS_FILENAME);
return 0;
}
--
1.7.2.3

View File

@ -1,50 +0,0 @@
From 07cdc867f1e12a4e8b4096e7f1f3ffda2f4e7d02 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 6 May 2010 11:14:11 +0200
Subject: [PATCH 11/39] switch vmware_vga to pci vgabios
---
hw/vmware_vga.c | 7 +------
1 files changed, 1 insertions(+), 6 deletions(-)
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 12bff48..682f287 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -114,14 +114,12 @@ struct pci_vmsvga_state_s {
# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
# define SVGA_IO_MUL 1
# define SVGA_FIFO_SIZE 0x10000
-# define SVGA_MEM_BASE 0xe0000000
# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2
#else
# define SVGA_ID SVGA_ID_1
# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
# define SVGA_IO_MUL 4
# define SVGA_FIFO_SIZE 0x10000
-# define SVGA_MEM_BASE 0xe0000000
# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA
#endif
@@ -1171,10 +1169,6 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
vga_init(&s->vga);
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
- vga_init_vbe(&s->vga);
-
- rom_add_vga(VGABIOS_FILENAME);
-
vmsvga_reset(s);
}
@@ -1272,6 +1266,7 @@ static PCIDeviceInfo vmsvga_info = {
.qdev.size = sizeof(struct pci_vmsvga_state_s),
.qdev.vmsd = &vmstate_vmware_vga,
.init = pci_vmsvga_initfn,
+ .romfile = "vgabios-vmware.bin",
};
static void vmsvga_register(void)
--
1.7.2.3

View File

@ -1,61 +0,0 @@
From a659f6b472d95503657ac68a52242ce769006f17 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 11 May 2010 22:28:44 +0200
Subject: [PATCH 12/39] all vga: refuse hotplugging.
Try to pci hotplug a vga card, watch qemu die with hw_error().
This patch fixes it.
---
hw/cirrus_vga.c | 4 ++++
hw/vga-pci.c | 4 ++++
hw/vmware_vga.c | 4 ++++
3 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index efa7a42..dadaa80 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -3206,6 +3206,10 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
uint8_t *pci_conf = d->dev.config;
int device_id = CIRRUS_ID_CLGD5446;
+ if (dev->qdev.hotplugged) {
+ return -1;
+ }
+
/* setup VGA */
vga_common_init(&s->vga, VGA_RAM_SIZE);
cirrus_init_common(s, device_id, 1);
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 8e1ed35..4e673a5 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -81,6 +81,10 @@ static int pci_vga_initfn(PCIDevice *dev)
VGACommonState *s = &d->vga;
uint8_t *pci_conf = d->dev.config;
+ if (dev->qdev.hotplugged) {
+ return -1;
+ }
+
// vga + console init
vga_common_init(s, VGA_RAM_SIZE);
vga_init(s);
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 682f287..7ff89aa 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1232,6 +1232,10 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
struct pci_vmsvga_state_s *s =
DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
+ if (dev->qdev.hotplugged) {
+ return -1;
+ }
+
pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
pci_config_set_class(s->card.config, PCI_CLASS_DISPLAY_VGA);
--
1.7.2.3

View File

@ -1,168 +0,0 @@
From e0d06d42a83e7796b2c39ad6cab3630c0a8c2845 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 11 Mar 2010 11:13:32 -0300
Subject: [PATCH 13/39] spice: tls support
Add options to the -spice command line switch to setup tls:
tls-port
listening port
x509-dir
x509 file directory. Expects same filenames as
-vnc $display,x509=$dir
x509-key-file
x509-key-password
x509-cert-file
x509-cacert-file
x509-dh-key-file
x509 files can also be set individually.
tls-ciphers
which ciphers to use.
---
qemu-config.c | 24 ++++++++++++++++++++
spice.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 86 insertions(+), 4 deletions(-)
diff --git a/qemu-config.c b/qemu-config.c
index 8a894cf..74bfc62 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -355,11 +355,35 @@ QemuOptsList qemu_spice_opts = {
.name = "port",
.type = QEMU_OPT_NUMBER,
},{
+ .name = "tls-port",
+ .type = QEMU_OPT_NUMBER,
+ },{
.name = "password",
.type = QEMU_OPT_STRING,
},{
.name = "disable-ticketing",
.type = QEMU_OPT_BOOL,
+ },{
+ .name = "x509-dir",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-key-file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-key-password",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-cert-file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-cacert-file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509-dh-key-file",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "tls-ciphers",
+ .type = QEMU_OPT_STRING,
},
{ /* end if list */ }
},
diff --git a/spice.c b/spice.c
index c763d52..3fe76cd 100644
--- a/spice.c
+++ b/spice.c
@@ -9,6 +9,7 @@
#include "qemu-spice.h"
#include "qemu-timer.h"
#include "qemu-queue.h"
+#include "qemu-x509.h"
#include "monitor.h"
/* core bits */
@@ -126,18 +127,71 @@ static SpiceCoreInterface core_interface = {
void qemu_spice_init(void)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
- const char *password;
- int port;
+ const char *password, *str, *x509_dir,
+ *x509_key_password = NULL,
+ *x509_dh_file = NULL,
+ *tls_ciphers = NULL;
+ char *x509_key_file = NULL,
+ *x509_cert_file = NULL,
+ *x509_cacert_file = NULL;
+ int port, tls_port, len;
if (!opts)
return;
port = qemu_opt_get_number(opts, "port", 0);
- if (!port)
+ tls_port = qemu_opt_get_number(opts, "tls-port", 0);
+ if (!port && !tls_port)
return;
password = qemu_opt_get(opts, "password");
+ if (tls_port) {
+ x509_dir = qemu_opt_get(opts, "x509-dir");
+ if (NULL == x509_dir)
+ x509_dir = ".";
+ len = strlen(x509_dir) + 32;
+
+ str = qemu_opt_get(opts, "x509-key-file");
+ if (str) {
+ x509_key_file = qemu_strdup(str);
+ } else {
+ x509_key_file = qemu_malloc(len);
+ snprintf(x509_key_file, len, "%s/%s", x509_dir, X509_SERVER_KEY_FILE);
+ }
+
+ str = qemu_opt_get(opts, "x509-cert-file");
+ if (str) {
+ x509_cert_file = qemu_strdup(str);
+ } else {
+ x509_cert_file = qemu_malloc(len);
+ snprintf(x509_cert_file, len, "%s/%s", x509_dir, X509_SERVER_CERT_FILE);
+ }
+
+ str = qemu_opt_get(opts, "x509-cacert-file");
+ if (str) {
+ x509_cacert_file = qemu_strdup(str);
+ } else {
+ x509_cacert_file = qemu_malloc(len);
+ snprintf(x509_cacert_file, len, "%s/%s", x509_dir, X509_CA_CERT_FILE);
+ }
+
+ x509_key_password = qemu_opt_get(opts, "x509-key-password");
+ x509_dh_file = qemu_opt_get(opts, "x509-dh-file");
+ tls_ciphers = qemu_opt_get(opts, "tls-ciphers");
+ }
+
spice_server = spice_server_new();
- spice_server_set_port(spice_server, port);
+ if (port) {
+ spice_server_set_port(spice_server, port);
+ }
+ if (tls_port) {
+ spice_server_set_tls(spice_server, tls_port,
+ x509_cacert_file,
+ x509_cert_file,
+ x509_key_file,
+ x509_key_password,
+ x509_dh_file,
+ tls_ciphers);
+ }
if (password)
spice_server_set_ticket(spice_server, password, 0, 0, 0);
if (qemu_opt_get_bool(opts, "disable-ticketing", 0))
@@ -150,4 +204,8 @@ void qemu_spice_init(void)
using_spice = 1;
qemu_spice_input_init();
+
+ qemu_free(x509_key_file);
+ qemu_free(x509_cert_file);
+ qemu_free(x509_cacert_file);
}
--
1.7.2.3

File diff suppressed because it is too large Load Diff

View File

@ -1,405 +0,0 @@
From f3e02bc08c4521dc53d858174612341462d588ce Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 13 Apr 2010 10:34:46 +0200
Subject: [PATCH 15/39] spice: add audio
Add support for the spice audio interface.
The driver is first in the driver list, but can_be_default is set only
in case spice is active. So if you are using spice the spice audio
driver is the default one, otherwise whatever comes first after spice in
the list. Overriding the default using QEMU_AUDIO_DRV works in any
case.
---
Makefile.objs | 1 +
audio/audio.c | 3 +
audio/audio_int.h | 1 +
audio/spiceaudio.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++++
qemu-spice.h | 1 +
spice.c | 1 +
6 files changed, 319 insertions(+), 0 deletions(-)
create mode 100644 audio/spiceaudio.c
diff --git a/Makefile.objs b/Makefile.objs
index d05643f..9a6b0f3 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -94,6 +94,7 @@ common-obj-$(CONFIG_SPICE) += spice.o spice-input.o spice-display.o
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
audio-obj-$(CONFIG_OSS) += ossaudio.o
+audio-obj-$(CONFIG_SPICE) += spiceaudio.o
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
audio-obj-$(CONFIG_ALSA) += alsaaudio.o
audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
diff --git a/audio/audio.c b/audio/audio.c
index ad51077..ade342e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -44,6 +44,9 @@
that we generate the list.
*/
static struct audio_driver *drvtab[] = {
+#ifdef CONFIG_SPICE
+ &spice_audio_driver,
+#endif
CONFIG_AUDIO_DRIVERS
&no_audio_driver,
&wav_audio_driver
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 06e313f..d1f6c2d 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern struct audio_driver esd_audio_driver;
extern struct audio_driver pa_audio_driver;
+extern struct audio_driver spice_audio_driver;
extern struct audio_driver winwave_audio_driver;
extern struct mixeng_volume nominal_volume;
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
new file mode 100644
index 0000000..8ae7499
--- /dev/null
+++ b/audio/spiceaudio.c
@@ -0,0 +1,312 @@
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "qemu-spice.h"
+
+#define AUDIO_CAP "spice"
+#include "audio.h"
+#include "audio_int.h"
+
+#define LINE_IN_SAMPLES 1024
+#define LINE_OUT_SAMPLES 1024
+
+typedef struct SpiceVoiceOut {
+ HWVoiceOut hw;
+ SpicePlaybackInstance sin;
+ int64_t prev_ticks;
+ int active;
+ uint32_t *frame;
+ uint32_t *fpos;
+ uint32_t fsize;
+} SpiceVoiceOut;
+
+typedef struct SpiceVoiceIn {
+ HWVoiceIn hw;
+ SpiceRecordInstance sin;
+ int64_t prev_ticks;
+ int active;
+ uint32_t samples[LINE_IN_SAMPLES];
+} SpiceVoiceIn;
+
+static const SpicePlaybackInterface playback_sif = {
+ .base.type = SPICE_INTERFACE_PLAYBACK,
+ .base.description = "playback",
+ .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
+};
+
+static const SpiceRecordInterface record_sif = {
+ .base.type = SPICE_INTERFACE_RECORD,
+ .base.description = "record",
+ .base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
+};
+
+static void *spice_audio_init(void)
+{
+ if (!using_spice) {
+ return NULL;
+ }
+ return &spice_audio_init;
+}
+
+static void spice_audio_fini(void *opaque)
+{
+ /* nothing */
+}
+
+static int calculate_samples(struct audio_pcm_info *info, int64_t *old_ticks)
+{
+ int64_t now;
+ int64_t ticks;
+ int64_t bytes;
+ int samples;
+
+ now = qemu_get_clock (vm_clock);
+ ticks = now - *old_ticks;
+ *old_ticks = now;
+ bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
+ bytes = audio_MIN (bytes, INT_MAX);
+ samples = bytes >> info->shift;
+ return samples;
+}
+
+/* playback */
+
+static int line_out_init(HWVoiceOut *hw, struct audsettings *as)
+{
+ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+ struct audsettings settings;
+
+ settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ;
+ settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN;
+ settings.fmt = AUD_FMT_S16;
+ settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+ audio_pcm_init_info(&hw->info, &settings);
+ hw->samples = LINE_OUT_SAMPLES;
+ out->active = 0;
+
+ out->sin.base.sif = &playback_sif.base;
+ spice_server_add_interface(spice_server, &out->sin.base);
+ return 0;
+}
+
+static void line_out_fini(HWVoiceOut *hw)
+{
+ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+
+ spice_server_remove_interface(&out->sin.base);
+}
+
+static int line_out_run(HWVoiceOut *hw, int live)
+{
+ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+ int rpos, decr;
+ int samples;
+
+ if (!live) {
+ return 0;
+ }
+
+ decr = calculate_samples(&hw->info, &out->prev_ticks);
+ decr = audio_MIN(live, decr);
+
+ samples = decr;
+ rpos = hw->rpos;
+ while (samples) {
+ int left_till_end_samples = hw->samples - rpos;
+ int len = audio_MIN(samples, left_till_end_samples);
+
+ if (!out->frame) {
+ spice_server_playback_get_buffer(&out->sin, &out->frame, &out->fsize);
+ out->fpos = out->frame;
+ }
+ if (out->frame) {
+ len = audio_MIN(len, out->fsize);
+ hw->clip(out->fpos, hw->mix_buf + rpos, len);
+ out->fsize -= len;
+ out->fpos += len;
+ if (out->fsize == 0) {
+ spice_server_playback_put_samples(&out->sin, out->frame);
+ out->frame = out->fpos = NULL;
+ }
+ }
+ rpos = (rpos + len) % hw->samples;
+ samples -= len;
+ }
+ hw->rpos = rpos;
+ return decr;
+}
+
+static int line_out_write(SWVoiceOut *sw, void *buf, int len)
+{
+ return audio_pcm_sw_write(sw, buf, len);
+}
+
+static int line_out_ctl(HWVoiceOut *hw, int cmd, ...)
+{
+ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ if (out->active) {
+ break;
+ }
+ out->active = 1;
+ out->prev_ticks = qemu_get_clock (vm_clock);
+ spice_server_playback_start(&out->sin);
+ break;
+ case VOICE_DISABLE:
+ if (!out->active) {
+ break;
+ }
+ out->active = 0;
+ if (out->frame) {
+ memset(out->fpos, 0, out->fsize << 2);
+ spice_server_playback_put_samples(&out->sin, out->frame);
+ out->frame = out->fpos = NULL;
+ }
+ spice_server_playback_stop(&out->sin);
+ break;
+ }
+ return 0;
+}
+
+/* record */
+
+static int line_in_init(HWVoiceIn *hw, struct audsettings *as)
+{
+ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+ struct audsettings settings;
+
+ settings.freq = SPICE_INTERFACE_RECORD_FREQ;
+ settings.nchannels = SPICE_INTERFACE_RECORD_CHAN;
+ settings.fmt = AUD_FMT_S16;
+ settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+ audio_pcm_init_info(&hw->info, &settings);
+ hw->samples = LINE_IN_SAMPLES;
+ in->active = 0;
+
+ in->sin.base.sif = &record_sif.base;
+ spice_server_add_interface(spice_server, &in->sin.base);
+ return 0;
+}
+
+static void line_in_fini(HWVoiceIn *hw)
+{
+ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+
+ spice_server_remove_interface(&in->sin.base);
+}
+
+static int line_in_run(HWVoiceIn *hw)
+{
+ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+ int num_samples;
+ int ready;
+ int len[2];
+ uint64_t delta_samp;
+ uint32_t *samples;
+
+ if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in(hw))) {
+ return 0;
+ }
+
+ delta_samp = calculate_samples(&hw->info, &in->prev_ticks);
+ num_samples = audio_MIN(num_samples, delta_samp);
+
+ ready = spice_server_record_get_samples(&in->sin, in->samples, num_samples);
+ samples = in->samples;
+ if (ready == 0) {
+ static uint32_t silence[LINE_IN_SAMPLES];
+ samples = silence;
+ ready = LINE_IN_SAMPLES;
+ }
+
+ num_samples = audio_MIN(ready, num_samples);
+
+ if (hw->wpos + num_samples > hw->samples) {
+ len[0] = hw->samples - hw->wpos;
+ len[1] = num_samples - len[0];
+ } else {
+ len[0] = num_samples;
+ len[1] = 0;
+ }
+
+ hw->conv(hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume);
+
+ if (len[1]) {
+ hw->conv(hw->conv_buf, samples + len[0], len[1],
+ &nominal_volume);
+ }
+
+ hw->wpos = (hw->wpos + num_samples) % hw->samples;
+
+ return num_samples;
+}
+
+static int line_in_read(SWVoiceIn *sw, void *buf, int size)
+{
+ return audio_pcm_sw_read(sw, buf, size);
+}
+
+static int line_in_ctl(HWVoiceIn *hw, int cmd, ...)
+{
+ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ if (in->active) {
+ break;
+ }
+ in->active = 1;
+ in->prev_ticks = qemu_get_clock (vm_clock);
+ spice_server_record_start(&in->sin);
+ break;
+ case VOICE_DISABLE:
+ if (!in->active) {
+ break;
+ }
+ in->active = 0;
+ spice_server_record_stop(&in->sin);
+ break;
+ }
+ return 0;
+}
+
+static struct audio_option audio_options[] = {
+ { /* end of list */ },
+};
+
+static struct audio_pcm_ops audio_callbacks = {
+ .init_out = line_out_init,
+ .fini_out = line_out_fini,
+ .run_out = line_out_run,
+ .write = line_out_write,
+ .ctl_out = line_out_ctl,
+
+ .init_in = line_in_init,
+ .fini_in = line_in_fini,
+ .run_in = line_in_run,
+ .read = line_in_read,
+ .ctl_in = line_in_ctl,
+};
+
+struct audio_driver spice_audio_driver = {
+ .name = "spice",
+ .descr = "spice audio driver",
+ .options = audio_options,
+ .init = spice_audio_init,
+ .fini = spice_audio_fini,
+ .pcm_ops = &audio_callbacks,
+ .max_voices_out = 1,
+ .max_voices_in = 1,
+ .voice_size_out = sizeof(SpiceVoiceOut),
+ .voice_size_in = sizeof(SpiceVoiceIn),
+};
+
+void qemu_spice_audio_init(void)
+{
+ spice_audio_driver.can_be_default = 1;
+}
diff --git a/qemu-spice.h b/qemu-spice.h
index f061004..6f19ba7 100644
--- a/qemu-spice.h
+++ b/qemu-spice.h
@@ -13,6 +13,7 @@ extern int using_spice;
void qemu_spice_init(void);
void qemu_spice_input_init(void);
+void qemu_spice_audio_init(void);
void qemu_spice_display_init(DisplayState *ds);
#else /* CONFIG_SPICE */
diff --git a/spice.c b/spice.c
index 3fe76cd..fc76ef7 100644
--- a/spice.c
+++ b/spice.c
@@ -204,6 +204,7 @@ void qemu_spice_init(void)
using_spice = 1;
qemu_spice_input_init();
+ qemu_spice_audio_init();
qemu_free(x509_key_file);
qemu_free(x509_cert_file);
--
1.7.2.3

View File

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

View File

@ -1,592 +0,0 @@
From ee782dec6adaced9c5bb99d02253505fb635fa12 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 12 Mar 2010 16:26:18 +0100
Subject: [PATCH 17/39] spice: add pci vdi port backend (obsolete).
This is *not* intended to be merged upstream. It is just here
because the virtio-serial windows guest drivers are not ready,
so you can't go with the new spice-vmc yet.
---
Makefile.target | 2 +-
hw/spice-vdi.c | 556 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 557 insertions(+), 1 deletions(-)
create mode 100644 hw/spice-vdi.c
diff --git a/Makefile.target b/Makefile.target
index 90544c5..025bdb8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -217,7 +217,7 @@ obj-i386-y += pc_piix.o
obj-i386-y += testdev.o
obj-i386-y += acpi.o acpi_piix4.o
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
-obj-i386-$(CONFIG_SPICE) += spice-vmc.o
+obj-i386-$(CONFIG_SPICE) += spice-vmc.o spice-vdi.o
obj-i386-y += pcspk.o i8254.o
obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
diff --git a/hw/spice-vdi.c b/hw/spice-vdi.c
new file mode 100644
index 0000000..23cbbe1
--- /dev/null
+++ b/hw/spice-vdi.c
@@ -0,0 +1,556 @@
+#include <pthread.h>
+#include <signal.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/pci.h"
+#include "console.h"
+#include "hw/vga_int.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "console.h"
+#include "pci.h"
+#include "hw.h"
+#include "cpu-common.h"
+
+#include <spice.h>
+#include <spice-experimental.h>
+#include <spice/ipc_ring.h>
+#include <spice/barrier.h>
+
+#undef SPICE_RING_PROD_ITEM
+#define SPICE_RING_PROD_ITEM(r, ret) { \
+ typeof(r) start = r; \
+ typeof(r) end = r + 1; \
+ uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \
+ typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \
+ if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
+ abort(); \
+ } \
+ ret = &m_item->el; \
+ }
+
+#undef SPICE_RING_CONS_ITEM
+#define SPICE_RING_CONS_ITEM(r, ret) { \
+ typeof(r) start = r; \
+ typeof(r) end = r + 1; \
+ uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \
+ typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \
+ if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
+ abort(); \
+ } \
+ ret = &m_item->el; \
+ }
+
+
+#undef ALIGN
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+
+#define REDHAT_PCI_VENDOR_ID 0x1b36
+#define VDI_PORT_DEVICE_ID 0x0105
+#define VDI_PORT_REVISION 0x01
+
+#define VDI_PORT_INTERRUPT (1 << 0)
+
+#define VDI_PORT_MAGIC (*(uint32_t*)"VDIP")
+
+#define VDI_PORT_DEV_NAME "vdi_port"
+#define VDI_PORT_SAVE_VERSION 20
+
+#include <spice/start-packed.h>
+
+typedef struct SPICE_ATTR_PACKED VDIPortPacket {
+ uint32_t gen;
+ uint32_t size;
+ uint8_t data[512 - 2 * sizeof(uint32_t)];
+} VDIPortPacket;
+
+SPICE_RING_DECLARE(VDIPortRing, VDIPortPacket, 32);
+
+enum {
+ VDI_PORT_IO_RANGE_INDEX,
+ VDI_PORT_RAM_RANGE_INDEX,
+};
+
+enum {
+ VDI_PORT_IO_CONNECTION,
+ VDI_PORT_IO_NOTIFY = 4,
+ VDI_PORT_IO_UPDATE_IRQ = 8,
+
+ VDI_PORT_IO_RANGE_SIZE = 12
+};
+
+typedef struct SPICE_ATTR_PACKED VDIPortRam {
+ uint32_t magic;
+ uint32_t generation;
+ uint32_t int_pending;
+ uint32_t int_mask;
+ VDIPortRing input;
+ VDIPortRing output;
+ uint32_t reserv[32];
+} VDIPortRam;
+
+#include <spice/end-packed.h>
+
+typedef struct PCIVDIPortDevice {
+ PCIDevice pci_dev;
+ uint32_t io_base;
+ uint64_t ram_offset;
+ uint32_t ram_size;
+ VDIPortRam *ram;
+ uint32_t connected;
+ int running;
+ int new_gen_on_resume;
+ int active_interface;
+ SpiceVDIPortInstance sin;
+ int plug_read_pos;
+} PCIVDIPortDevice;
+
+static int debug = 1;
+
+static inline uint32_t msb_mask(uint32_t val)
+{
+ uint32_t mask;
+
+ do {
+ mask = ~(val - 1) & val;
+ val &= ~mask;
+ } while (mask < val);
+
+ return mask;
+}
+
+static inline void atomic_or(uint32_t *var, uint32_t add)
+{
+ __asm__ __volatile__ ("lock; orl %1, %0" : "+m" (*var) : "r" (add) : "memory");
+}
+
+static inline uint32_t atomic_exchange(uint32_t val, uint32_t *ptr)
+{
+ __asm__ __volatile__("xchgl %0, %1" : "+q"(val), "+m" (*ptr) : : "memory");
+ return val;
+}
+
+static void set_dirty(void *base, ram_addr_t offset, void *start, uint32_t length)
+{
+ assert(start >= base);
+
+ ram_addr_t addr = (ram_addr_t)((uint8_t*)start - (uint8_t*)base) + offset;
+ ram_addr_t end = ALIGN(addr + length, TARGET_PAGE_SIZE);
+
+ do {
+ cpu_physical_memory_set_dirty(addr);
+ addr += TARGET_PAGE_SIZE;
+ } while ( addr < end );
+}
+
+static inline void vdi_port_set_dirty(PCIVDIPortDevice *d, void *start, uint32_t length)
+{
+ set_dirty(d->ram, d->ram_offset, start, length);
+}
+
+static void vdi_port_new_gen(PCIVDIPortDevice *d)
+{
+ d->ram->generation = (d->ram->generation + 1 == 0) ? 1 : d->ram->generation + 1;
+ vdi_port_set_dirty(d, &d->ram->generation, sizeof(d->ram->generation));
+}
+
+static int vdi_port_irq_level(PCIVDIPortDevice *d)
+{
+ return !!(d->ram->int_pending & d->ram->int_mask);
+}
+
+static void vdi_port_notify_guest(PCIVDIPortDevice *d)
+{
+ uint32_t events = VDI_PORT_INTERRUPT;
+ uint32_t old_pending;
+
+ if (!d->connected) {
+ return;
+ }
+ old_pending = __sync_fetch_and_or(&d->ram->int_pending, events);
+ if ((old_pending & events) == events) {
+ return;
+ }
+ qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
+ vdi_port_set_dirty(d, &d->ram->int_pending, sizeof(d->ram->int_pending));
+}
+
+static int vdi_port_interface_write(SpiceVDIPortInstance *sin,
+ const uint8_t *buf, int len)
+{
+ PCIVDIPortDevice *d = container_of(sin, PCIVDIPortDevice, sin);
+ VDIPortRing *ring = &d->ram->output;
+ int do_notify = false;
+ int actual_write = 0;
+ int l = len;
+
+ if (!d->running) {
+ return 0;
+ }
+
+ while (len) {
+ VDIPortPacket *packet;
+ int notify;
+ int wait;
+
+ SPICE_RING_PROD_WAIT(ring, wait);
+ if (wait) {
+ break;
+ }
+
+ SPICE_RING_PROD_ITEM(ring, packet);
+ packet->gen = d->ram->generation;
+ packet->size = MIN(len, sizeof(packet->data));
+ memcpy(packet->data, buf, packet->size);
+ vdi_port_set_dirty(d, packet, sizeof(*packet) - (sizeof(packet->data) - packet->size));
+
+ SPICE_RING_PUSH(ring, notify);
+ do_notify = do_notify || notify;
+ len -= packet->size;
+ buf += packet->size;
+ actual_write += packet->size;
+ }
+ vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
+
+ if (do_notify) {
+ vdi_port_notify_guest(d);
+ }
+ if (debug > 1) {
+ fprintf(stderr, "%s: %d/%d\n", __FUNCTION__, actual_write, l);
+ }
+ return actual_write;
+}
+
+static int vdi_port_interface_read(SpiceVDIPortInstance *sin,
+ uint8_t *buf, int len)
+{
+ PCIVDIPortDevice *d = container_of(sin, PCIVDIPortDevice, sin);
+ VDIPortRing *ring = &d->ram->input;
+ uint32_t gen = d->ram->generation;
+ VDIPortPacket *packet;
+ int do_notify = false;
+ int actual_read = 0;
+ int l = len;
+
+ if (!d->running) {
+ return 0;
+ }
+
+ while (!SPICE_RING_IS_EMPTY(ring)) {
+ int notify;
+
+ SPICE_RING_CONS_ITEM(ring, packet);
+ if (packet->gen == gen) {
+ break;
+ }
+ SPICE_RING_POP(ring, notify);
+ do_notify = do_notify || notify;
+ }
+ while (len) {
+ VDIPortPacket *packet;
+ int wait;
+ int now;
+
+ SPICE_RING_CONS_WAIT(ring, wait);
+
+ if (wait) {
+ break;
+ }
+
+ SPICE_RING_CONS_ITEM(ring, packet);
+ if (packet->size > sizeof(packet->data)) {
+ vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
+ printf("%s: bad packet size\n", __FUNCTION__);
+ return 0;
+ }
+ now = MIN(len, packet->size - d->plug_read_pos);
+ memcpy(buf, packet->data + d->plug_read_pos, now);
+ len -= now;
+ buf += now;
+ actual_read += now;
+ if ((d->plug_read_pos += now) == packet->size) {
+ int notify;
+
+ d->plug_read_pos = 0;
+ SPICE_RING_POP(ring, notify);
+ do_notify = do_notify || notify;
+ }
+ }
+ vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
+
+ if (do_notify) {
+ vdi_port_notify_guest(d);
+ }
+ if (debug > 1) {
+ fprintf(stderr, "%s: %d/%d\n", __FUNCTION__, actual_read, l);
+ }
+ return actual_read;
+}
+
+static SpiceVDIPortInterface vdi_port_interface = {
+ .base.type = SPICE_INTERFACE_VDI_PORT,
+ .base.description = "vdi port",
+ .base.major_version = SPICE_INTERFACE_VDI_PORT_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_VDI_PORT_MINOR,
+
+ .write = vdi_port_interface_write,
+ .read = vdi_port_interface_read,
+};
+
+static void vdi_port_register_interface(PCIVDIPortDevice *d)
+{
+ if (d->active_interface ) {
+ return;
+ }
+
+ if (debug) {
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ }
+ d->sin.base.sif = &vdi_port_interface.base;
+ spice_server_add_interface(spice_server, &d->sin.base);
+ d->active_interface = true;
+}
+
+static void vdi_port_unregister_interface(PCIVDIPortDevice *d)
+{
+ if (!d->active_interface ) {
+ return;
+ }
+ if (debug) {
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ }
+ spice_server_remove_interface(&d->sin.base);
+ d->active_interface = false;
+}
+
+static uint32_t vdi_port_dev_connect(PCIVDIPortDevice *d)
+{
+ if (d->connected) {
+ if (debug) {
+ fprintf(stderr, "%s: already connected\n", __FUNCTION__);
+ }
+ return 0;
+ }
+ vdi_port_new_gen(d);
+ d->connected = true;
+ vdi_port_register_interface(d);
+ return d->ram->generation;
+}
+
+static void vdi_port_dev_disconnect(PCIVDIPortDevice *d)
+{
+ if (!d->connected) {
+ if (debug) {
+ fprintf(stderr, "%s: not connected\n", __FUNCTION__);
+ }
+ return;
+ }
+ d->connected = false;
+ vdi_port_unregister_interface(d);
+}
+
+static void vdi_port_dev_notify(PCIVDIPortDevice *d)
+{
+ spice_server_vdi_port_wakeup(&d->sin);
+}
+
+static void vdi_port_write_dword(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCIVDIPortDevice *d = opaque;
+ uint32_t io_port = addr - d->io_base;
+
+ if (debug > 1) {
+ fprintf(stderr, "%s: addr 0x%x val 0x%x\n", __FUNCTION__, addr, val);
+ }
+ switch (io_port) {
+ case VDI_PORT_IO_NOTIFY:
+ if (!d->connected) {
+ fprintf(stderr, "%s: not connected\n", __FUNCTION__);
+ return;
+ }
+ vdi_port_dev_notify(d);
+ break;
+ case VDI_PORT_IO_UPDATE_IRQ:
+ qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
+ break;
+ case VDI_PORT_IO_CONNECTION:
+ vdi_port_dev_disconnect(d);
+ break;
+ default:
+ if (debug) {
+ fprintf(stderr, "%s: unexpected addr 0x%x val 0x%x\n",
+ __FUNCTION__, addr, val);
+ }
+ };
+}
+
+static uint32_t vdi_port_read_dword(void *opaque, uint32_t addr)
+{
+ PCIVDIPortDevice *d = opaque;
+ uint32_t io_port = addr - d->io_base;
+
+ if (debug > 1) {
+ fprintf(stderr, "%s: addr 0x%x\n", __FUNCTION__, addr);
+ }
+ if (io_port == VDI_PORT_IO_CONNECTION) {
+ return vdi_port_dev_connect(d);
+ } else {
+ fprintf(stderr, "%s: unexpected addr 0x%x\n", __FUNCTION__, addr);
+ }
+ return 0xffffffff;
+}
+
+static void vdi_port_io_map(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev, pci_dev);
+
+ if (debug) {
+ fprintf(stderr, "%s: base 0x%lx size 0x%lx\n", __FUNCTION__, addr, size);
+ }
+ d->io_base = addr;
+ register_ioport_write(addr, size, 4, vdi_port_write_dword, pci_dev);
+ register_ioport_read(addr, size, 4, vdi_port_read_dword, pci_dev);
+}
+
+static void vdi_port_ram_map(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev, pci_dev);
+
+ if (debug) {
+ fprintf(stderr, "%s: addr 0x%lx size 0x%lx\n", __FUNCTION__, addr, size);
+ }
+
+ assert((addr & (size - 1)) == 0);
+ assert(size == d->ram_size);
+
+ cpu_register_physical_memory(addr, size, d->ram_offset | IO_MEM_RAM);
+}
+
+static void vdi_port_reset(PCIVDIPortDevice *d)
+{
+ memset(d->ram, 0, sizeof(*d->ram));
+ SPICE_RING_INIT(&d->ram->input);
+ SPICE_RING_INIT(&d->ram->output);
+ d->ram->magic = VDI_PORT_MAGIC;
+ d->ram->generation = 0;
+ d->ram->int_pending = 0;
+ d->ram->int_mask = 0;
+ d->connected = false;
+ d->plug_read_pos = 0;
+ vdi_port_set_dirty(d, d->ram, sizeof(*d->ram));
+}
+
+static void vdi_port_reset_handler(DeviceState *dev)
+{
+ PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev.qdev, dev);
+
+ if (d->connected) {
+ vdi_port_dev_disconnect(d);
+ }
+
+ vdi_port_reset(d);
+ qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
+}
+
+static int vdi_port_pre_load(void* opaque)
+{
+ PCIVDIPortDevice* d = opaque;
+
+ vdi_port_unregister_interface(d);
+ return 0;
+}
+
+static int vdi_port_post_load(void* opaque,int version_id)
+{
+ PCIVDIPortDevice* d = opaque;
+
+ if (d->connected) {
+ vdi_port_register_interface(d);
+ }
+ return 0;
+}
+
+static void vdi_port_vm_change_state_handler(void *opaque, int running, int reason)
+{
+ PCIVDIPortDevice* d = opaque;
+
+ if (running) {
+ d->running = true;
+ if (d->new_gen_on_resume) {
+ d->new_gen_on_resume = false;
+ vdi_port_new_gen(d);
+ vdi_port_notify_guest(d);
+ }
+ qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
+ vdi_port_dev_notify(d);
+ } else {
+ d->running = false;
+ }
+}
+
+static int vdi_port_init(PCIDevice *dev)
+{
+ PCIVDIPortDevice *vdi = (PCIVDIPortDevice *)dev;
+ uint8_t* config = vdi->pci_dev.config;
+ uint32_t ram_size = msb_mask(sizeof(VDIPortRam) * 2 - 1);
+
+ vdi->ram_offset = qemu_ram_alloc(&vdi->pci_dev.qdev, "bar1", ram_size);
+ vdi->ram = qemu_get_ram_ptr(vdi->ram_offset);
+ vdi_port_reset(vdi);
+ vdi->ram_size = ram_size;
+ vdi->new_gen_on_resume = false;
+ vdi->running = false;
+
+ pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID);
+ pci_config_set_device_id(config, VDI_PORT_DEVICE_ID);
+ pci_config_set_class(config, PCI_CLASS_COMMUNICATION_OTHER);
+ pci_set_byte(&config[PCI_REVISION_ID], VDI_PORT_REVISION);
+ pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
+
+ pci_register_bar(dev, VDI_PORT_IO_RANGE_INDEX,
+ msb_mask(VDI_PORT_IO_RANGE_SIZE * 2 - 1),
+ PCI_BASE_ADDRESS_SPACE_IO, vdi_port_io_map);
+
+ pci_register_bar(dev, VDI_PORT_RAM_RANGE_INDEX,
+ vdi->ram_size , PCI_BASE_ADDRESS_SPACE_MEMORY,
+ vdi_port_ram_map);
+
+ qemu_add_vm_change_state_handler(vdi_port_vm_change_state_handler, vdi);
+
+ return 0;
+}
+
+static VMStateDescription vdi_port_vmstate = {
+ .name = VDI_PORT_DEV_NAME,
+ .version_id = VDI_PORT_SAVE_VERSION,
+ .minimum_version_id = VDI_PORT_SAVE_VERSION,
+ .pre_load = vdi_port_pre_load,
+ .post_load = vdi_port_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_PCI_DEVICE(pci_dev, PCIVDIPortDevice),
+ VMSTATE_UINT32(connected, PCIVDIPortDevice),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static PCIDeviceInfo vdi_port_info = {
+ .qdev.name = VDI_PORT_DEV_NAME,
+ .qdev.desc = "spice virtual desktop port (obsolete)",
+ .qdev.size = sizeof(PCIVDIPortDevice),
+ .qdev.vmsd = &vdi_port_vmstate,
+ .qdev.reset = vdi_port_reset_handler,
+
+ .init = vdi_port_init,
+};
+
+static void vdi_port_register(void)
+{
+ pci_qdev_register(&vdi_port_info);
+}
+
+device_init(vdi_port_register);
--
1.7.2.3

View File

@ -1,29 +0,0 @@
From 898303cfd535d76ce971f3ac1310696937fbd286 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 14 Jun 2010 09:53:48 +0200
Subject: [PATCH 18/39] use memalign instead of posix_memalign
---
osdep.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/osdep.c b/osdep.c
index 2375a69..ed2fd40 100644
--- a/osdep.c
+++ b/osdep.c
@@ -100,7 +100,12 @@ void *qemu_memalign(size_t alignment, size_t size)
#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
int ret;
void *ptr;
+#if 0
ret = posix_memalign(&ptr, alignment, size);
+#else
+ ptr = memalign(alignment, size);
+ ret = (ptr == NULL) ? -1 : 0;
+#endif
if (ret != 0) {
fprintf(stderr, "Failed to allocate %zu B: %s\n",
size, strerror(ret));
--
1.7.2.3

View File

@ -1,179 +0,0 @@
From 80b1dac2be1487d31e6766abe2359fcff1bf0481 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 23 Apr 2010 13:28:21 +0200
Subject: [PATCH 19/39] spice: live migration (wip).
Handle spice client migration, i.e. inform a spice client connected
about the new host and connection parameters, so it can move over the
connection automatically.
---
monitor.c | 1 +
qemu-monitor.hx | 11 +++++++
qemu-spice.h | 2 +
spice.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 101 insertions(+), 0 deletions(-)
diff --git a/monitor.c b/monitor.c
index e51df62..6674a8c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -57,6 +57,7 @@
#include "osdep.h"
#include "exec-all.h"
#include "qemu-kvm.h"
+#include "qemu-spice.h"
//#define DEBUG
//#define DEBUG_COMPLETION
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index da7b796..c2570d9 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -2510,6 +2510,17 @@ ETEXI
HXCOMM DO NOT add new commands after 'info', move your addition before it!
+#if defined(CONFIG_SPICE)
+ {
+ .name = "spice_migrate_info",
+ .args_type = "hostname:s,port:i?,tls-port:i?,cert-subject:s?",
+ .params = "hostname port tls-port cert-subject",
+ .help = "send migration info to spice client",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = mon_spice_migrate,
+ },
+#endif
+
STEXI
@end table
ETEXI
diff --git a/qemu-spice.h b/qemu-spice.h
index 6f19ba7..3c8e959 100644
--- a/qemu-spice.h
+++ b/qemu-spice.h
@@ -16,6 +16,8 @@ void qemu_spice_input_init(void);
void qemu_spice_audio_init(void);
void qemu_spice_display_init(DisplayState *ds);
+int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
#else /* CONFIG_SPICE */
#define using_spice 0
diff --git a/spice.c b/spice.c
index fc76ef7..1109b4f 100644
--- a/spice.c
+++ b/spice.c
@@ -11,6 +11,7 @@
#include "qemu-queue.h"
#include "qemu-x509.h"
#include "monitor.h"
+#include "hw/hw.h"
/* core bits */
@@ -122,8 +123,90 @@ static SpiceCoreInterface core_interface = {
.watch_remove = watch_remove,
};
+/* handle client migration */
+
+static int spice_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
+{
+ static int last_stage;
+ static int migrate_client, client_connected;
+ int ret = 1;
+
+ if (last_stage != stage) {
+ last_stage = stage;
+ fprintf(stderr, "%s: stage %d\n", __FUNCTION__, stage);
+ } else {
+ fprintf(stderr, ".");
+ }
+
+ switch (stage) {
+ case 1:
+ migrate_client = 1;
+ client_connected = 0;
+ fprintf(stderr, "%s: start client migration\n", __FUNCTION__);
+ if (spice_server_migrate_start(spice_server) != 0) {
+ fprintf(stderr, "%s: fail -> no client migration\n", __FUNCTION__);
+ migrate_client = 0;
+ }
+ break;
+ case 2:
+ if (!migrate_client)
+ break;
+ switch (spice_server_migrate_client_state(spice_server)) {
+ case SPICE_MIGRATE_CLIENT_NONE:
+ fprintf(stderr, "%s: no client connected\n", __FUNCTION__);
+ migrate_client = 0;
+ break;
+ case SPICE_MIGRATE_CLIENT_WAITING:
+ ret = 0;
+ break;
+ case SPICE_MIGRATE_CLIENT_READY:
+ if (!client_connected) {
+ fprintf(stderr, "%s: client connected to target\n", __FUNCTION__);
+ client_connected = 1;
+ }
+ break;
+ }
+ break;
+ case 3:
+ if (migrate_client && client_connected) {
+ fprintf(stderr, "%s: finish client migration\n", __FUNCTION__);
+ spice_server_migrate_end(spice_server, 1);
+ }
+ break;
+ }
+ return ret;
+}
+
+static void spice_save(QEMUFile *f, void *opaque)
+{
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+}
+
+static int spice_load(QEMUFile *f, void *opaque, int version_id)
+{
+ fprintf(stderr, "%s:\n", __FUNCTION__);
+ return 0;
+}
+
/* functions for the rest of qemu */
+int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *hostname = qdict_get_str(qdict, "hostname");
+ const char *subject = qdict_get_try_str(qdict, "cert-subject");
+ int port = qdict_get_try_int(qdict, "port", -1);
+ int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
+
+ if (!spice_server) {
+ qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+ return -1;
+ }
+
+ /* TODO: Convert to QError */
+ return spice_server_migrate_info(spice_server, hostname,
+ port, tls_port, subject);
+}
+
void qemu_spice_init(void)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
@@ -206,6 +289,10 @@ void qemu_spice_init(void)
qemu_spice_input_init();
qemu_spice_audio_init();
+ register_savevm_live(NULL, "spice", -1, 1, NULL,
+ spice_live, spice_save, spice_load,
+ spice_server);
+
qemu_free(x509_key_file);
qemu_free(x509_cert_file);
qemu_free(x509_cacert_file);
--
1.7.2.3

View File

@ -1,23 +0,0 @@
From 7241cc479a0f4a148ae60336add6d7be80da9ff0 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 8 Jul 2010 14:11:18 +0200
Subject: [PATCH 20/39] spice-display: draw.h is internal now
---
spice-display.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/spice-display.h b/spice-display.h
index 70a7be4..b55e7ea 100644
--- a/spice-display.h
+++ b/spice-display.h
@@ -1,5 +1,5 @@
#include <spice/ipc_ring.h>
-#include <spice/draw.h>
+#include <spice/enums.h>
#include <spice/qxl_dev.h>
#include "pflib.h"
--
1.7.2.3

View File

@ -1,25 +0,0 @@
From c269c8b87769b25c9d69d40944de0e883458af86 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 8 Jul 2010 14:31:10 +0200
Subject: [PATCH 21/39] spice-display: disable debug
---
spice-display.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/spice-display.c b/spice-display.c
index a749e64..2291cc7 100644
--- a/spice-display.c
+++ b/spice-display.c
@@ -15,7 +15,7 @@
#include "spice-display.h"
-static int debug = 1;
+static int debug = 0;
int qemu_spice_rect_is_empty(const QXLRect* r)
{
--
1.7.2.3

View File

@ -1,27 +0,0 @@
From 2912f038b4bfddd4c3dacb3b0102e45553859632 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 8 Jul 2010 16:29:15 +0200
Subject: [PATCH 22/39] spice-display: pci rev fixups
---
spice-display.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/spice-display.c b/spice-display.c
index 2291cc7..87a71cd 100644
--- a/spice-display.c
+++ b/spice-display.c
@@ -334,10 +334,6 @@ static const QXLInterface dpy_interface = {
.base.major_version = SPICE_INTERFACE_QXL_MAJOR,
.base.minor_version = SPICE_INTERFACE_QXL_MINOR,
- .pci_vendor = REDHAT_PCI_VENDOR_ID,
- .pci_id = QXL_DEVICE_ID,
- .pci_revision = QXL_REVISION,
-
.attache_worker = interface_attach_worker,
.set_compression_level = interface_set_compression_level,
.set_mm_time = interface_set_mm_time,
--
1.7.2.3

View File

@ -1,52 +0,0 @@
From 727553e1a33dccab2b27ee5e184e003440765289 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 8 Jul 2010 16:29:27 +0200
Subject: [PATCH 23/39] qxl: pci rev fixups
---
hw/qxl.c | 20 ++++++++------------
1 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 475360c..2a0ea4e 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -511,10 +511,6 @@ static const QXLInterface qxl_interface = {
.base.major_version = SPICE_INTERFACE_QXL_MAJOR,
.base.minor_version = SPICE_INTERFACE_QXL_MINOR,
- .pci_vendor = REDHAT_PCI_VENDOR_ID,
- .pci_id = QXL_DEVICE_ID,
- .pci_revision = QXL_REVISION,
-
.attache_worker = interface_attach_worker,
.set_compression_level = interface_set_compression_level,
.set_mm_time = interface_set_mm_time,
@@ -1136,16 +1132,16 @@ static int qxl_init(PCIDevice *dev)
qxl->generation = 1;
switch (qxl->revision) {
- case 1: /* qxl-1 */
- pci_device_id = 0x0100;
- pci_device_rev = 1;
+ case 1: /* spice 0.4 -- qxl-1 */
+ pci_device_id = QXL_DEVICE_ID_STABLE;
+ pci_device_rev = QXL_REVISION_STABLE_V04;
break;
- case 2: /* qxl-2 */
- pci_device_id = 0x0100;
- pci_device_rev = 2;
+ case 2: /* spice 0.6 -- qxl-2 */
+ pci_device_id = QXL_DEVICE_ID_STABLE;
+ pci_device_rev = QXL_REVISION_STABLE_V06;
break;
- default: /* unstable */
- pci_device_id = 0x01ff;
+ default: /* experimental */
+ pci_device_id = QXL_DEVICE_ID_DEVEL;
pci_device_rev = 1;
break;
}
--
1.7.2.3

View File

@ -1,26 +0,0 @@
From c9f9044475d392e55de4dd6e343477ce1a57eabc Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 8 Jul 2010 17:51:09 +0200
Subject: [PATCH 24/39] qxl: support QXL_IO_DESTROY_ALL_SURFACES
---
hw/qxl.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 2a0ea4e..7bd4467 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -930,6 +930,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
case QXL_IO_DESTROY_SURFACE_WAIT:
d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
break;
+ case QXL_IO_DESTROY_ALL_SURFACES:
+ d->ssd.worker->destroy_surfaces(d->ssd.worker);
+ break;
default:
fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
abort();
--
1.7.2.3

View File

@ -1,57 +0,0 @@
From c8fa37e075cf59e8b21af9211f6a6348c92ed098 Mon Sep 17 00:00:00 2001
From: Alon Levy <alevy@redhat.com>
Date: Mon, 12 Jul 2010 22:48:59 +0300
Subject: [PATCH 25/39] spice-vmc: two bugfixes in vmc_read
* throttling with no discard means possible recursion, make
vmc_read handle that.
* zero datapos when data is done (from rhel6 version)
---
hw/spice-vmc.c | 13 ++++++++-----
1 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
index 3f6a2bb..06e30e6 100644
--- a/hw/spice-vmc.c
+++ b/hw/spice-vmc.c
@@ -45,7 +45,7 @@ static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
ssize_t out;
out = virtio_serial_write(&svc->port, buf, len);
- dprintf(svc, 2, "%s: %lu/%d\n", __func__, out, len);
+ dprintf(svc, 3, "%s: %lu/%d\n", __func__, out, len);
return out;
}
@@ -54,13 +54,16 @@ static int vmc_read(SpiceVDIPortInstance *sin, uint8_t *buf, int len)
SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
int bytes = MIN(len, svc->datalen);
- dprintf(svc, 2, "%s: %d/%zd\n", __func__, bytes, svc->datalen);
- if (bytes) {
+ dprintf(svc, 2, "%s: %p %d/%d/%zd\n", __func__, svc->datapos, len, bytes, svc->datalen);
+ if (bytes > 0) {
memcpy(buf, svc->datapos, bytes);
svc->datapos += bytes;
svc->datalen -= bytes;
- if (0 == svc->datalen) {
+ assert(svc->datalen >= 0);
+ if (svc->datalen == 0) {
+ svc->datapos = 0;
virtio_serial_throttle_port(&svc->port, false);
+ // ^^^ !!! may call vmc_have_data, so don't touch svc after it!
}
}
return bytes;
@@ -140,7 +143,7 @@ static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len
SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
dprintf(svc, 2, "%s: %zd\n", __func__, len);
- assert(svc->datapos == 0);
+ assert(svc->datalen == 0);
if (svc->bufsize < len) {
svc->bufsize = len;
svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
--
1.7.2.3

View File

@ -1,84 +0,0 @@
From 0045574847883167f5c2b569811e049616ee611d Mon Sep 17 00:00:00 2001
From: Yonit Halperin <yhalperi@redhat.com>
Date: Wed, 14 Jul 2010 13:26:34 +0300
Subject: [PATCH 26/39] spice: enabling/disabling jpeg and zlib-over-glz via spice command line args
---
qemu-config.c | 6 ++++++
spice.c | 29 +++++++++++++++++++++++++++++
2 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/qemu-config.c b/qemu-config.c
index 74bfc62..3e4fcf9 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -384,6 +384,12 @@ QemuOptsList qemu_spice_opts = {
},{
.name = "tls-ciphers",
.type = QEMU_OPT_STRING,
+ },{
+ .name = "jpeg",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "zlib-glz",
+ .type = QEMU_OPT_STRING,
},
{ /* end if list */ }
},
diff --git a/spice.c b/spice.c
index 1109b4f..201e53c 100644
--- a/spice.c
+++ b/spice.c
@@ -207,6 +207,23 @@ int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
port, tls_port, subject);
}
+static inline spice_wan_compression_t get_wan_compression_value(const char *str)
+{
+ if (!strcmp(str, "wan")) {
+ return SPICE_WAN_COMPRESSION_AUTO;
+ }
+
+ if (!strcmp(str, "never")) {
+ return SPICE_WAN_COMPRESSION_NEVER;
+ }
+
+ if (!strcmp(str, "always")) {
+ return SPICE_WAN_COMPRESSION_ALWAYS;
+ }
+
+ return SPICE_WAN_COMPRESSION_INVALID;
+}
+
void qemu_spice_init(void)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
@@ -218,6 +235,7 @@ void qemu_spice_init(void)
*x509_cert_file = NULL,
*x509_cacert_file = NULL;
int port, tls_port, len;
+ const char *jpeg, *zlib_glz;
if (!opts)
return;
@@ -283,6 +301,17 @@ void qemu_spice_init(void)
/* TODO: make configurable via cmdline */
spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
+ jpeg = qemu_opt_get(opts, "jpeg");
+ zlib_glz = qemu_opt_get(opts, "zlib-glz");
+
+ if (jpeg) {
+ spice_server_set_jpeg_compression(spice_server, get_wan_compression_value(jpeg));
+ }
+
+ if (zlib_glz) {
+ spice_server_set_zlib_glz_compression(spice_server, get_wan_compression_value(zlib_glz));
+ }
+
spice_server_init(spice_server, &core_interface);
using_spice = 1;
--
1.7.2.3

View File

@ -1,57 +0,0 @@
From 9200133d24ee5b5dab71ce922882c3534d9e8a5a Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 15 Jul 2010 09:01:28 +0200
Subject: [PATCH 27/39] ifdef new config options.
---
spice.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/spice.c b/spice.c
index 201e53c..76e6ac1 100644
--- a/spice.c
+++ b/spice.c
@@ -207,6 +207,7 @@ int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
port, tls_port, subject);
}
+#if defined(SPICE_SERVER_VERSION) && SPICE_SERVER_VERSION >= 0x000503
static inline spice_wan_compression_t get_wan_compression_value(const char *str)
{
if (!strcmp(str, "wan")) {
@@ -223,6 +224,7 @@ static inline spice_wan_compression_t get_wan_compression_value(const char *str)
return SPICE_WAN_COMPRESSION_INVALID;
}
+#endif
void qemu_spice_init(void)
{
@@ -235,7 +237,6 @@ void qemu_spice_init(void)
*x509_cert_file = NULL,
*x509_cacert_file = NULL;
int port, tls_port, len;
- const char *jpeg, *zlib_glz;
if (!opts)
return;
@@ -301,6 +302,8 @@ void qemu_spice_init(void)
/* TODO: make configurable via cmdline */
spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
+#if defined(SPICE_SERVER_VERSION) && SPICE_SERVER_VERSION >= 0x000503
+ const char *jpeg, *zlib_glz;
jpeg = qemu_opt_get(opts, "jpeg");
zlib_glz = qemu_opt_get(opts, "zlib-glz");
@@ -311,6 +314,7 @@ void qemu_spice_init(void)
if (zlib_glz) {
spice_server_set_zlib_glz_compression(spice_server, get_wan_compression_value(zlib_glz));
}
+#endif
spice_server_init(spice_server, &core_interface);
using_spice = 1;
--
1.7.2.3

View File

@ -1,27 +0,0 @@
From 2165916a311108d39c7aa45e5189af26712234b8 Mon Sep 17 00:00:00 2001
From: Alon Levy <alevy@redhat.com>
Date: Wed, 14 Jul 2010 16:30:35 +0300
Subject: [PATCH 28/39] spice-vmc: add counter to debug statements
---
hw/spice-vmc.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
index 06e30e6..041f243 100644
--- a/hw/spice-vmc.c
+++ b/hw/spice-vmc.c
@@ -23,8 +23,9 @@
#define dprintf(_svc, _level, _fmt, ...) \
do { \
+ static unsigned __dprintf_counter = 0; \
if (_svc->debug >= _level) { \
- fprintf(stderr, "svc: " _fmt, ## __VA_ARGS__); \
+ fprintf(stderr, "svc: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
} \
} while (0)
--
1.7.2.3

View File

@ -1,53 +0,0 @@
From f86c044ae075d142e658e866572eb0a37ecad2e1 Mon Sep 17 00:00:00 2001
From: Alon Levy <alevy@redhat.com>
Date: Thu, 22 Jul 2010 00:21:18 +0300
Subject: [PATCH 29/39] spice-vmc: split vmc_write to max sized virtio_serial_write calls
workaround for current windows driver limitation (RHBZ 617000)
---
hw/spice-vmc.c | 21 ++++++++++++++++++---
1 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
index 041f243..b9d64a2 100644
--- a/hw/spice-vmc.c
+++ b/hw/spice-vmc.c
@@ -21,6 +21,8 @@
#define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
#define VMC_DEVICE_NAME "spicevmc"
+#define VMC_MAX_HOST_WRITE 2048
+
#define dprintf(_svc, _level, _fmt, ...) \
do { \
static unsigned __dprintf_counter = 0; \
@@ -43,10 +45,23 @@ typedef struct SpiceVirtualChannel {
static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
{
SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
- ssize_t out;
+ ssize_t out = 0;
+ ssize_t last_out;
+ uint8_t* p = (uint8_t*)buf;
+
+ while (len > 0) {
+ last_out = virtio_serial_write(&svc->port, p,
+ MIN(len, VMC_MAX_HOST_WRITE));
+ if (last_out > 0) {
+ out += last_out;
+ len -= last_out;
+ p += last_out;
+ } else {
+ break;
+ }
+ }
- out = virtio_serial_write(&svc->port, buf, len);
- dprintf(svc, 3, "%s: %lu/%d\n", __func__, out, len);
+ dprintf(svc, 3, "%s: %lu/%zd\n", __func__, out, len + out);
return out;
}
--
1.7.2.3

View File

@ -1,24 +0,0 @@
From be78cc4a136f8ec63dc6d7efd8356625c639a877 Mon Sep 17 00:00:00 2001
From: Alon Levy <alevy@redhat.com>
Date: Tue, 3 Aug 2010 11:37:51 +0300
Subject: [PATCH 30/39] qxl: add 800x480 resolution to qxl_modes (n900 native)
---
hw/qxl.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 7bd4467..86c0e03 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -64,6 +64,7 @@
static QXLMode qxl_modes[] = {
QXL_MODE_EX(640, 480),
+ QXL_MODE_EX(800, 480),
QXL_MODE_EX(800, 600),
QXL_MODE_EX(832, 624),
QXL_MODE_EX(1024, 768),
--
1.7.2.3

View File

@ -1,259 +0,0 @@
From e55e5fd43113a5b266efa6d17e44f0e9231a98ed Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 25 Aug 2010 16:08:37 +0000
Subject: [PATCH 31/39] qxl: savevm fixes
---
hw/qxl.c | 125 +++++++++++++++++++++++++++++++++++++++++++++----------------
hw/qxl.h | 6 +++
2 files changed, 98 insertions(+), 33 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 86c0e03..4a15200 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1087,6 +1087,14 @@ static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
{
PCIQXLDevice *qxl = opaque;
qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
+
+ if (!running && qxl->mode == QXL_MODE_NATIVE) {
+ /* dirty all vram (which holds surfaces) to make sure it is saved */
+ /* FIXME #1: should go out during "live" stage */
+ /* FIXME #2: we only need to save the areas which are actually used */
+ ram_addr_t addr = qxl->vram_offset;
+ qxl_set_dirty(addr, addr + qxl->vram_size);
+ }
}
/* display change listener */
@@ -1134,6 +1142,8 @@ static int qxl_init(PCIDevice *dev)
qxl->id = device_id;
qxl->mode = QXL_MODE_UNDEFINED;
qxl->generation = 1;
+ qxl->num_memslots = NUM_MEMSLOTS;
+ qxl->num_surfaces = NUM_SURFACES;
switch (qxl->revision) {
case 1: /* spice 0.4 -- qxl-1 */
@@ -1183,7 +1193,8 @@ static int qxl_init(PCIDevice *dev)
if (ram_size < 16 * 1024 * 1024)
ram_size = 16 * 1024 * 1024;
qxl->vga.vram_size = ram_size;
- qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar0", qxl->vga.vram_size);
+ qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram",
+ qxl->vga.vram_size);
qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
pci_config_set_class(config, PCI_CLASS_DISPLAY_OTHER);
@@ -1195,14 +1206,14 @@ static int qxl_init(PCIDevice *dev)
pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
qxl->rom_size = qxl_rom_size();
- qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar2", qxl->rom_size);
+ qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size);
init_qxl_rom(qxl);
init_qxl_ram(qxl);
if (qxl->vram_size < 16 * 1024 * 1024)
qxl->vram_size = 16 * 1024 * 1024;
qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
- qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar1", qxl->vram_size);
+ qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);
pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
msb_mask(QXL_IO_RANGE_SIZE * 2 - 1),
@@ -1237,14 +1248,12 @@ static void qxl_pre_save(void *opaque)
uint8_t *ram_start = d->vga.vram_ptr;
dprintf(d, 1, "%s:\n", __FUNCTION__);
-#if 1 /* wanna zap this */
if (d->last_release == NULL) {
d->last_release_offset = 0;
} else {
d->last_release_offset = (uint8_t *)d->last_release - ram_start;
}
assert(d->last_release_offset < d->vga.vram_size);
-#endif
}
static int qxl_pre_load(void *opaque)
@@ -1306,29 +1315,55 @@ static int qxl_post_load(void *opaque, int version)
}
dprintf(d, 1, "%s: done\n", __FUNCTION__);
-#if 1 /* wanna zap this */
- if (d->last_release_offset >= d->vga.vram_size) {
- dprintf(d, 1, "%s: invalid last_release_offset %u, ram_size %u\n",
- __FUNCTION__, d->last_release_offset, d->vga.vram_size);
- exit(-1);
- }
-
+ assert(d->last_release_offset < d->vga.vram_size);
if (d->last_release_offset == 0) {
d->last_release = NULL;
} else {
d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
}
-#endif
+
+ /* spice 0.4 compatibility -- accept but ignore */
+ free(d->worker_data);
+ d->worker_data = NULL;
+ d->worker_data_size = 0;
return 0;
}
-#define QXL_VER 1
+#define QXL_SAVE_VERSION 20
+
+static bool qxl_test_worker_data(void *opaque, int version_id)
+{
+ PCIQXLDevice* d = opaque;
+
+ if (d->revision != 1) {
+ return false;
+ }
+ if (!d->worker_data_size) {
+ return false;
+ }
+ if (!d->worker_data) {
+ d->worker_data = qemu_malloc(d->worker_data_size);
+ }
+ return true;
+}
+
+static bool qxl_test_spice04(void *opaque, int version_id)
+{
+ PCIQXLDevice* d = opaque;
+ return d->revision == 1;
+}
+
+static bool qxl_test_spice06(void *opaque)
+{
+ PCIQXLDevice* d = opaque;
+ return d->revision > 1;
+}
static VMStateDescription qxl_memslot = {
.name = "qxl-memslot",
- .version_id = QXL_VER,
- .minimum_version_id = QXL_VER,
+ .version_id = QXL_SAVE_VERSION,
+ .minimum_version_id = QXL_SAVE_VERSION,
.fields = (VMStateField[]) {
VMSTATE_UINT64(slot.mem_start, struct guest_slots),
VMSTATE_UINT64(slot.mem_end, struct guest_slots),
@@ -1339,8 +1374,8 @@ static VMStateDescription qxl_memslot = {
static VMStateDescription qxl_surface = {
.name = "qxl-surface",
- .version_id = QXL_VER,
- .minimum_version_id = QXL_VER,
+ .version_id = QXL_SAVE_VERSION,
+ .minimum_version_id = QXL_SAVE_VERSION,
.fields = (VMStateField[]) {
VMSTATE_UINT32(width, QXLSurfaceCreate),
VMSTATE_UINT32(height, QXLSurfaceCreate),
@@ -1355,34 +1390,58 @@ static VMStateDescription qxl_surface = {
}
};
+static VMStateDescription qxl_vmstate_spice06 = {
+ .name = "qxl/spice06",
+ .version_id = QXL_SAVE_VERSION,
+ .minimum_version_id = QXL_SAVE_VERSION,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
+ VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
+ qxl_memslot, struct guest_slots),
+ VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
+ qxl_surface, QXLSurfaceCreate),
+ VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice),
+ VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0,
+ vmstate_info_uint64, uint64_t),
+ VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static VMStateDescription qxl_vmstate = {
.name = "qxl",
- .version_id = QXL_VER,
- .minimum_version_id = QXL_VER,
+ .version_id = QXL_SAVE_VERSION,
+ .minimum_version_id = QXL_SAVE_VERSION,
.pre_save = qxl_pre_save,
.pre_load = qxl_pre_load,
.post_load = qxl_post_load,
.fields = (VMStateField []) {
VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
- VMSTATE_STRUCT(vga, PCIQXLDevice, QXL_VER, vmstate_vga_common, VGACommonState),
+ VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
-#if 1 /* wanna zap this */
VMSTATE_UINT32(num_free_res, PCIQXLDevice),
VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
-#endif
VMSTATE_UINT32(mode, PCIQXLDevice),
VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
-#if 1 /* new stuff */
- VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, QXL_VER,
- qxl_memslot, struct guest_slots),
- VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, QXL_VER,
- qxl_surface, QXLSurfaceCreate),
- VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, QXL_VER,
- vmstate_info_uint64, uint64_t),
- VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
-#endif
+
+ /* spice 0.4 sends/expects them */
+ VMSTATE_VBUFFER_UINT32(vga.vram_ptr, PCIQXLDevice, 0, qxl_test_spice04, 0,
+ vga.vram_size),
+ VMSTATE_UINT32_TEST(worker_data_size, PCIQXLDevice, qxl_test_spice04),
+ VMSTATE_VBUFFER_UINT32(worker_data, PCIQXLDevice, 0, qxl_test_worker_data, 0,
+ worker_data_size),
+
VMSTATE_END_OF_LIST()
- }
+ },
+ .subsections = (VMStateSubsection[]) {
+ {
+ /* additional spice 0.6 state */
+ .vmsd = &qxl_vmstate_spice06,
+ .needed = qxl_test_spice06,
+ },{
+ /* end of list */
+ },
+ },
};
static PCIDeviceInfo qxl_info = {
diff --git a/hw/qxl.h b/hw/qxl.h
index 1216405..caf3684 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -24,6 +24,9 @@ typedef struct PCIQXLDevice {
int generation;
uint32_t revision;
+ int32_t num_memslots;
+ int32_t num_surfaces;
+
struct guest_slots {
QXLMemSlot slot;
void *ptr;
@@ -74,6 +77,9 @@ typedef struct PCIQXLDevice {
/* io bar */
uint32_t io_base;
+ /* spice 0.4 loadvm compatibility */
+ void *worker_data;
+ uint32_t worker_data_size;
} PCIQXLDevice;
#define PANIC_ON(x) if ((x)) { \
--
1.7.2.3

View File

@ -1,53 +0,0 @@
From f48f184b9d22bbd2e34fb4f3a7a760f0e98fae64 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 8 Sep 2010 11:45:30 +0200
Subject: [PATCH 32/39] Revert "spice-vmc: split vmc_write to max sized virtio_serial_write calls"
This reverts commit 380b75548db5116e538dc646e84bceb1c4b0e61b.
---
hw/spice-vmc.c | 21 +++------------------
1 files changed, 3 insertions(+), 18 deletions(-)
diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
index b9d64a2..041f243 100644
--- a/hw/spice-vmc.c
+++ b/hw/spice-vmc.c
@@ -21,8 +21,6 @@
#define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
#define VMC_DEVICE_NAME "spicevmc"
-#define VMC_MAX_HOST_WRITE 2048
-
#define dprintf(_svc, _level, _fmt, ...) \
do { \
static unsigned __dprintf_counter = 0; \
@@ -45,23 +43,10 @@ typedef struct SpiceVirtualChannel {
static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
{
SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
- ssize_t out = 0;
- ssize_t last_out;
- uint8_t* p = (uint8_t*)buf;
-
- while (len > 0) {
- last_out = virtio_serial_write(&svc->port, p,
- MIN(len, VMC_MAX_HOST_WRITE));
- if (last_out > 0) {
- out += last_out;
- len -= last_out;
- p += last_out;
- } else {
- break;
- }
- }
+ ssize_t out;
- dprintf(svc, 3, "%s: %lu/%zd\n", __func__, out, len + out);
+ out = virtio_serial_write(&svc->port, buf, len);
+ dprintf(svc, 3, "%s: %lu/%d\n", __func__, out, len);
return out;
}
--
1.7.2.3

View File

@ -1,28 +0,0 @@
From a5d6e7e76bf5f5fb0e2c8232ddca2b850bfc1afa Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 8 Sep 2010 11:45:49 +0200
Subject: [PATCH 33/39] Revert "spice-vmc: add counter to debug statements"
This reverts commit f3ab5192a20ee9dc7776b13ec0ba75030bb52a20.
---
hw/spice-vmc.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
index 041f243..06e30e6 100644
--- a/hw/spice-vmc.c
+++ b/hw/spice-vmc.c
@@ -23,9 +23,8 @@
#define dprintf(_svc, _level, _fmt, ...) \
do { \
- static unsigned __dprintf_counter = 0; \
if (_svc->debug >= _level) { \
- fprintf(stderr, "svc: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
+ fprintf(stderr, "svc: " _fmt, ## __VA_ARGS__); \
} \
} while (0)
--
1.7.2.3

View File

@ -1,55 +0,0 @@
From 84115ef1adf343c34eebfb1045cbc5c72892e3b2 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 8 Sep 2010 11:46:18 +0200
Subject: [PATCH 34/39] Revert "spice-vmc: two bugfixes in vmc_read"
This reverts commit 71983a37e30c68beab5e9056a4600d2958f77a04.
---
hw/spice-vmc.c | 13 +++++--------
1 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
index 06e30e6..3f6a2bb 100644
--- a/hw/spice-vmc.c
+++ b/hw/spice-vmc.c
@@ -45,7 +45,7 @@ static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
ssize_t out;
out = virtio_serial_write(&svc->port, buf, len);
- dprintf(svc, 3, "%s: %lu/%d\n", __func__, out, len);
+ dprintf(svc, 2, "%s: %lu/%d\n", __func__, out, len);
return out;
}
@@ -54,16 +54,13 @@ static int vmc_read(SpiceVDIPortInstance *sin, uint8_t *buf, int len)
SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
int bytes = MIN(len, svc->datalen);
- dprintf(svc, 2, "%s: %p %d/%d/%zd\n", __func__, svc->datapos, len, bytes, svc->datalen);
- if (bytes > 0) {
+ dprintf(svc, 2, "%s: %d/%zd\n", __func__, bytes, svc->datalen);
+ if (bytes) {
memcpy(buf, svc->datapos, bytes);
svc->datapos += bytes;
svc->datalen -= bytes;
- assert(svc->datalen >= 0);
- if (svc->datalen == 0) {
- svc->datapos = 0;
+ if (0 == svc->datalen) {
virtio_serial_throttle_port(&svc->port, false);
- // ^^^ !!! may call vmc_have_data, so don't touch svc after it!
}
}
return bytes;
@@ -143,7 +140,7 @@ static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len
SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
dprintf(svc, 2, "%s: %zd\n", __func__, len);
- assert(svc->datalen == 0);
+ assert(svc->datapos == 0);
if (svc->bufsize < len) {
svc->bufsize = len;
svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
--
1.7.2.3

View File

@ -1,181 +0,0 @@
From 3e0d1b6ed5f8e8b871803337008e104398e4db0a Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 8 Sep 2010 11:48:57 +0200
Subject: [PATCH 35/39] Revert "spice: live migration (wip)."
This reverts commit 85b9db9ba993af737c9c402cf2f67db7b1b3cbce.
Conflicts:
spice.c
---
monitor.c | 1 -
qemu-monitor.hx | 11 -------
qemu-spice.h | 2 -
spice.c | 87 -------------------------------------------------------
4 files changed, 0 insertions(+), 101 deletions(-)
diff --git a/monitor.c b/monitor.c
index 6674a8c..e51df62 100644
--- a/monitor.c
+++ b/monitor.c
@@ -57,7 +57,6 @@
#include "osdep.h"
#include "exec-all.h"
#include "qemu-kvm.h"
-#include "qemu-spice.h"
//#define DEBUG
//#define DEBUG_COMPLETION
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index c2570d9..da7b796 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -2510,17 +2510,6 @@ ETEXI
HXCOMM DO NOT add new commands after 'info', move your addition before it!
-#if defined(CONFIG_SPICE)
- {
- .name = "spice_migrate_info",
- .args_type = "hostname:s,port:i?,tls-port:i?,cert-subject:s?",
- .params = "hostname port tls-port cert-subject",
- .help = "send migration info to spice client",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = mon_spice_migrate,
- },
-#endif
-
STEXI
@end table
ETEXI
diff --git a/qemu-spice.h b/qemu-spice.h
index 3c8e959..6f19ba7 100644
--- a/qemu-spice.h
+++ b/qemu-spice.h
@@ -16,8 +16,6 @@ void qemu_spice_input_init(void);
void qemu_spice_audio_init(void);
void qemu_spice_display_init(DisplayState *ds);
-int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
-
#else /* CONFIG_SPICE */
#define using_spice 0
diff --git a/spice.c b/spice.c
index 76e6ac1..e6f047d 100644
--- a/spice.c
+++ b/spice.c
@@ -11,7 +11,6 @@
#include "qemu-queue.h"
#include "qemu-x509.h"
#include "monitor.h"
-#include "hw/hw.h"
/* core bits */
@@ -123,90 +122,8 @@ static SpiceCoreInterface core_interface = {
.watch_remove = watch_remove,
};
-/* handle client migration */
-
-static int spice_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
-{
- static int last_stage;
- static int migrate_client, client_connected;
- int ret = 1;
-
- if (last_stage != stage) {
- last_stage = stage;
- fprintf(stderr, "%s: stage %d\n", __FUNCTION__, stage);
- } else {
- fprintf(stderr, ".");
- }
-
- switch (stage) {
- case 1:
- migrate_client = 1;
- client_connected = 0;
- fprintf(stderr, "%s: start client migration\n", __FUNCTION__);
- if (spice_server_migrate_start(spice_server) != 0) {
- fprintf(stderr, "%s: fail -> no client migration\n", __FUNCTION__);
- migrate_client = 0;
- }
- break;
- case 2:
- if (!migrate_client)
- break;
- switch (spice_server_migrate_client_state(spice_server)) {
- case SPICE_MIGRATE_CLIENT_NONE:
- fprintf(stderr, "%s: no client connected\n", __FUNCTION__);
- migrate_client = 0;
- break;
- case SPICE_MIGRATE_CLIENT_WAITING:
- ret = 0;
- break;
- case SPICE_MIGRATE_CLIENT_READY:
- if (!client_connected) {
- fprintf(stderr, "%s: client connected to target\n", __FUNCTION__);
- client_connected = 1;
- }
- break;
- }
- break;
- case 3:
- if (migrate_client && client_connected) {
- fprintf(stderr, "%s: finish client migration\n", __FUNCTION__);
- spice_server_migrate_end(spice_server, 1);
- }
- break;
- }
- return ret;
-}
-
-static void spice_save(QEMUFile *f, void *opaque)
-{
- fprintf(stderr, "%s:\n", __FUNCTION__);
-}
-
-static int spice_load(QEMUFile *f, void *opaque, int version_id)
-{
- fprintf(stderr, "%s:\n", __FUNCTION__);
- return 0;
-}
-
/* functions for the rest of qemu */
-int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *hostname = qdict_get_str(qdict, "hostname");
- const char *subject = qdict_get_try_str(qdict, "cert-subject");
- int port = qdict_get_try_int(qdict, "port", -1);
- int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
-
- if (!spice_server) {
- qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
- return -1;
- }
-
- /* TODO: Convert to QError */
- return spice_server_migrate_info(spice_server, hostname,
- port, tls_port, subject);
-}
-
#if defined(SPICE_SERVER_VERSION) && SPICE_SERVER_VERSION >= 0x000503
static inline spice_wan_compression_t get_wan_compression_value(const char *str)
{
@@ -322,10 +239,6 @@ void qemu_spice_init(void)
qemu_spice_input_init();
qemu_spice_audio_init();
- register_savevm_live(NULL, "spice", -1, 1, NULL,
- spice_live, spice_save, spice_load,
- spice_server);
-
qemu_free(x509_key_file);
qemu_free(x509_cert_file);
qemu_free(x509_cacert_file);
--
1.7.2.3

View File

@ -1,590 +0,0 @@
From 7bad8970dd7db3e3e0e0b11626656c68f4238884 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 8 Sep 2010 11:49:22 +0200
Subject: [PATCH 36/39] Revert "spice: add pci vdi port backend (obsolete)."
This reverts commit b56a2ed131bdb4ce42db8f33f87603c416e7a60a.
---
Makefile.target | 2 +-
hw/spice-vdi.c | 556 -------------------------------------------------------
2 files changed, 1 insertions(+), 557 deletions(-)
delete mode 100644 hw/spice-vdi.c
diff --git a/Makefile.target b/Makefile.target
index 025bdb8..90544c5 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -217,7 +217,7 @@ obj-i386-y += pc_piix.o
obj-i386-y += testdev.o
obj-i386-y += acpi.o acpi_piix4.o
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
-obj-i386-$(CONFIG_SPICE) += spice-vmc.o spice-vdi.o
+obj-i386-$(CONFIG_SPICE) += spice-vmc.o
obj-i386-y += pcspk.o i8254.o
obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
diff --git a/hw/spice-vdi.c b/hw/spice-vdi.c
deleted file mode 100644
index 23cbbe1..0000000
--- a/hw/spice-vdi.c
+++ /dev/null
@@ -1,556 +0,0 @@
-#include <pthread.h>
-#include <signal.h>
-
-#include "qemu-common.h"
-#include "qemu-spice.h"
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/pci.h"
-#include "console.h"
-#include "hw/vga_int.h"
-#include "qemu-timer.h"
-#include "sysemu.h"
-#include "console.h"
-#include "pci.h"
-#include "hw.h"
-#include "cpu-common.h"
-
-#include <spice.h>
-#include <spice-experimental.h>
-#include <spice/ipc_ring.h>
-#include <spice/barrier.h>
-
-#undef SPICE_RING_PROD_ITEM
-#define SPICE_RING_PROD_ITEM(r, ret) { \
- typeof(r) start = r; \
- typeof(r) end = r + 1; \
- uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \
- typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \
- if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
- abort(); \
- } \
- ret = &m_item->el; \
- }
-
-#undef SPICE_RING_CONS_ITEM
-#define SPICE_RING_CONS_ITEM(r, ret) { \
- typeof(r) start = r; \
- typeof(r) end = r + 1; \
- uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \
- typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \
- if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
- abort(); \
- } \
- ret = &m_item->el; \
- }
-
-
-#undef ALIGN
-#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
-
-#define REDHAT_PCI_VENDOR_ID 0x1b36
-#define VDI_PORT_DEVICE_ID 0x0105
-#define VDI_PORT_REVISION 0x01
-
-#define VDI_PORT_INTERRUPT (1 << 0)
-
-#define VDI_PORT_MAGIC (*(uint32_t*)"VDIP")
-
-#define VDI_PORT_DEV_NAME "vdi_port"
-#define VDI_PORT_SAVE_VERSION 20
-
-#include <spice/start-packed.h>
-
-typedef struct SPICE_ATTR_PACKED VDIPortPacket {
- uint32_t gen;
- uint32_t size;
- uint8_t data[512 - 2 * sizeof(uint32_t)];
-} VDIPortPacket;
-
-SPICE_RING_DECLARE(VDIPortRing, VDIPortPacket, 32);
-
-enum {
- VDI_PORT_IO_RANGE_INDEX,
- VDI_PORT_RAM_RANGE_INDEX,
-};
-
-enum {
- VDI_PORT_IO_CONNECTION,
- VDI_PORT_IO_NOTIFY = 4,
- VDI_PORT_IO_UPDATE_IRQ = 8,
-
- VDI_PORT_IO_RANGE_SIZE = 12
-};
-
-typedef struct SPICE_ATTR_PACKED VDIPortRam {
- uint32_t magic;
- uint32_t generation;
- uint32_t int_pending;
- uint32_t int_mask;
- VDIPortRing input;
- VDIPortRing output;
- uint32_t reserv[32];
-} VDIPortRam;
-
-#include <spice/end-packed.h>
-
-typedef struct PCIVDIPortDevice {
- PCIDevice pci_dev;
- uint32_t io_base;
- uint64_t ram_offset;
- uint32_t ram_size;
- VDIPortRam *ram;
- uint32_t connected;
- int running;
- int new_gen_on_resume;
- int active_interface;
- SpiceVDIPortInstance sin;
- int plug_read_pos;
-} PCIVDIPortDevice;
-
-static int debug = 1;
-
-static inline uint32_t msb_mask(uint32_t val)
-{
- uint32_t mask;
-
- do {
- mask = ~(val - 1) & val;
- val &= ~mask;
- } while (mask < val);
-
- return mask;
-}
-
-static inline void atomic_or(uint32_t *var, uint32_t add)
-{
- __asm__ __volatile__ ("lock; orl %1, %0" : "+m" (*var) : "r" (add) : "memory");
-}
-
-static inline uint32_t atomic_exchange(uint32_t val, uint32_t *ptr)
-{
- __asm__ __volatile__("xchgl %0, %1" : "+q"(val), "+m" (*ptr) : : "memory");
- return val;
-}
-
-static void set_dirty(void *base, ram_addr_t offset, void *start, uint32_t length)
-{
- assert(start >= base);
-
- ram_addr_t addr = (ram_addr_t)((uint8_t*)start - (uint8_t*)base) + offset;
- ram_addr_t end = ALIGN(addr + length, TARGET_PAGE_SIZE);
-
- do {
- cpu_physical_memory_set_dirty(addr);
- addr += TARGET_PAGE_SIZE;
- } while ( addr < end );
-}
-
-static inline void vdi_port_set_dirty(PCIVDIPortDevice *d, void *start, uint32_t length)
-{
- set_dirty(d->ram, d->ram_offset, start, length);
-}
-
-static void vdi_port_new_gen(PCIVDIPortDevice *d)
-{
- d->ram->generation = (d->ram->generation + 1 == 0) ? 1 : d->ram->generation + 1;
- vdi_port_set_dirty(d, &d->ram->generation, sizeof(d->ram->generation));
-}
-
-static int vdi_port_irq_level(PCIVDIPortDevice *d)
-{
- return !!(d->ram->int_pending & d->ram->int_mask);
-}
-
-static void vdi_port_notify_guest(PCIVDIPortDevice *d)
-{
- uint32_t events = VDI_PORT_INTERRUPT;
- uint32_t old_pending;
-
- if (!d->connected) {
- return;
- }
- old_pending = __sync_fetch_and_or(&d->ram->int_pending, events);
- if ((old_pending & events) == events) {
- return;
- }
- qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
- vdi_port_set_dirty(d, &d->ram->int_pending, sizeof(d->ram->int_pending));
-}
-
-static int vdi_port_interface_write(SpiceVDIPortInstance *sin,
- const uint8_t *buf, int len)
-{
- PCIVDIPortDevice *d = container_of(sin, PCIVDIPortDevice, sin);
- VDIPortRing *ring = &d->ram->output;
- int do_notify = false;
- int actual_write = 0;
- int l = len;
-
- if (!d->running) {
- return 0;
- }
-
- while (len) {
- VDIPortPacket *packet;
- int notify;
- int wait;
-
- SPICE_RING_PROD_WAIT(ring, wait);
- if (wait) {
- break;
- }
-
- SPICE_RING_PROD_ITEM(ring, packet);
- packet->gen = d->ram->generation;
- packet->size = MIN(len, sizeof(packet->data));
- memcpy(packet->data, buf, packet->size);
- vdi_port_set_dirty(d, packet, sizeof(*packet) - (sizeof(packet->data) - packet->size));
-
- SPICE_RING_PUSH(ring, notify);
- do_notify = do_notify || notify;
- len -= packet->size;
- buf += packet->size;
- actual_write += packet->size;
- }
- vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
-
- if (do_notify) {
- vdi_port_notify_guest(d);
- }
- if (debug > 1) {
- fprintf(stderr, "%s: %d/%d\n", __FUNCTION__, actual_write, l);
- }
- return actual_write;
-}
-
-static int vdi_port_interface_read(SpiceVDIPortInstance *sin,
- uint8_t *buf, int len)
-{
- PCIVDIPortDevice *d = container_of(sin, PCIVDIPortDevice, sin);
- VDIPortRing *ring = &d->ram->input;
- uint32_t gen = d->ram->generation;
- VDIPortPacket *packet;
- int do_notify = false;
- int actual_read = 0;
- int l = len;
-
- if (!d->running) {
- return 0;
- }
-
- while (!SPICE_RING_IS_EMPTY(ring)) {
- int notify;
-
- SPICE_RING_CONS_ITEM(ring, packet);
- if (packet->gen == gen) {
- break;
- }
- SPICE_RING_POP(ring, notify);
- do_notify = do_notify || notify;
- }
- while (len) {
- VDIPortPacket *packet;
- int wait;
- int now;
-
- SPICE_RING_CONS_WAIT(ring, wait);
-
- if (wait) {
- break;
- }
-
- SPICE_RING_CONS_ITEM(ring, packet);
- if (packet->size > sizeof(packet->data)) {
- vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
- printf("%s: bad packet size\n", __FUNCTION__);
- return 0;
- }
- now = MIN(len, packet->size - d->plug_read_pos);
- memcpy(buf, packet->data + d->plug_read_pos, now);
- len -= now;
- buf += now;
- actual_read += now;
- if ((d->plug_read_pos += now) == packet->size) {
- int notify;
-
- d->plug_read_pos = 0;
- SPICE_RING_POP(ring, notify);
- do_notify = do_notify || notify;
- }
- }
- vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
-
- if (do_notify) {
- vdi_port_notify_guest(d);
- }
- if (debug > 1) {
- fprintf(stderr, "%s: %d/%d\n", __FUNCTION__, actual_read, l);
- }
- return actual_read;
-}
-
-static SpiceVDIPortInterface vdi_port_interface = {
- .base.type = SPICE_INTERFACE_VDI_PORT,
- .base.description = "vdi port",
- .base.major_version = SPICE_INTERFACE_VDI_PORT_MAJOR,
- .base.minor_version = SPICE_INTERFACE_VDI_PORT_MINOR,
-
- .write = vdi_port_interface_write,
- .read = vdi_port_interface_read,
-};
-
-static void vdi_port_register_interface(PCIVDIPortDevice *d)
-{
- if (d->active_interface ) {
- return;
- }
-
- if (debug) {
- fprintf(stderr, "%s\n", __FUNCTION__);
- }
- d->sin.base.sif = &vdi_port_interface.base;
- spice_server_add_interface(spice_server, &d->sin.base);
- d->active_interface = true;
-}
-
-static void vdi_port_unregister_interface(PCIVDIPortDevice *d)
-{
- if (!d->active_interface ) {
- return;
- }
- if (debug) {
- fprintf(stderr, "%s\n", __FUNCTION__);
- }
- spice_server_remove_interface(&d->sin.base);
- d->active_interface = false;
-}
-
-static uint32_t vdi_port_dev_connect(PCIVDIPortDevice *d)
-{
- if (d->connected) {
- if (debug) {
- fprintf(stderr, "%s: already connected\n", __FUNCTION__);
- }
- return 0;
- }
- vdi_port_new_gen(d);
- d->connected = true;
- vdi_port_register_interface(d);
- return d->ram->generation;
-}
-
-static void vdi_port_dev_disconnect(PCIVDIPortDevice *d)
-{
- if (!d->connected) {
- if (debug) {
- fprintf(stderr, "%s: not connected\n", __FUNCTION__);
- }
- return;
- }
- d->connected = false;
- vdi_port_unregister_interface(d);
-}
-
-static void vdi_port_dev_notify(PCIVDIPortDevice *d)
-{
- spice_server_vdi_port_wakeup(&d->sin);
-}
-
-static void vdi_port_write_dword(void *opaque, uint32_t addr, uint32_t val)
-{
- PCIVDIPortDevice *d = opaque;
- uint32_t io_port = addr - d->io_base;
-
- if (debug > 1) {
- fprintf(stderr, "%s: addr 0x%x val 0x%x\n", __FUNCTION__, addr, val);
- }
- switch (io_port) {
- case VDI_PORT_IO_NOTIFY:
- if (!d->connected) {
- fprintf(stderr, "%s: not connected\n", __FUNCTION__);
- return;
- }
- vdi_port_dev_notify(d);
- break;
- case VDI_PORT_IO_UPDATE_IRQ:
- qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
- break;
- case VDI_PORT_IO_CONNECTION:
- vdi_port_dev_disconnect(d);
- break;
- default:
- if (debug) {
- fprintf(stderr, "%s: unexpected addr 0x%x val 0x%x\n",
- __FUNCTION__, addr, val);
- }
- };
-}
-
-static uint32_t vdi_port_read_dword(void *opaque, uint32_t addr)
-{
- PCIVDIPortDevice *d = opaque;
- uint32_t io_port = addr - d->io_base;
-
- if (debug > 1) {
- fprintf(stderr, "%s: addr 0x%x\n", __FUNCTION__, addr);
- }
- if (io_port == VDI_PORT_IO_CONNECTION) {
- return vdi_port_dev_connect(d);
- } else {
- fprintf(stderr, "%s: unexpected addr 0x%x\n", __FUNCTION__, addr);
- }
- return 0xffffffff;
-}
-
-static void vdi_port_io_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev, pci_dev);
-
- if (debug) {
- fprintf(stderr, "%s: base 0x%lx size 0x%lx\n", __FUNCTION__, addr, size);
- }
- d->io_base = addr;
- register_ioport_write(addr, size, 4, vdi_port_write_dword, pci_dev);
- register_ioport_read(addr, size, 4, vdi_port_read_dword, pci_dev);
-}
-
-static void vdi_port_ram_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev, pci_dev);
-
- if (debug) {
- fprintf(stderr, "%s: addr 0x%lx size 0x%lx\n", __FUNCTION__, addr, size);
- }
-
- assert((addr & (size - 1)) == 0);
- assert(size == d->ram_size);
-
- cpu_register_physical_memory(addr, size, d->ram_offset | IO_MEM_RAM);
-}
-
-static void vdi_port_reset(PCIVDIPortDevice *d)
-{
- memset(d->ram, 0, sizeof(*d->ram));
- SPICE_RING_INIT(&d->ram->input);
- SPICE_RING_INIT(&d->ram->output);
- d->ram->magic = VDI_PORT_MAGIC;
- d->ram->generation = 0;
- d->ram->int_pending = 0;
- d->ram->int_mask = 0;
- d->connected = false;
- d->plug_read_pos = 0;
- vdi_port_set_dirty(d, d->ram, sizeof(*d->ram));
-}
-
-static void vdi_port_reset_handler(DeviceState *dev)
-{
- PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev.qdev, dev);
-
- if (d->connected) {
- vdi_port_dev_disconnect(d);
- }
-
- vdi_port_reset(d);
- qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
-}
-
-static int vdi_port_pre_load(void* opaque)
-{
- PCIVDIPortDevice* d = opaque;
-
- vdi_port_unregister_interface(d);
- return 0;
-}
-
-static int vdi_port_post_load(void* opaque,int version_id)
-{
- PCIVDIPortDevice* d = opaque;
-
- if (d->connected) {
- vdi_port_register_interface(d);
- }
- return 0;
-}
-
-static void vdi_port_vm_change_state_handler(void *opaque, int running, int reason)
-{
- PCIVDIPortDevice* d = opaque;
-
- if (running) {
- d->running = true;
- if (d->new_gen_on_resume) {
- d->new_gen_on_resume = false;
- vdi_port_new_gen(d);
- vdi_port_notify_guest(d);
- }
- qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
- vdi_port_dev_notify(d);
- } else {
- d->running = false;
- }
-}
-
-static int vdi_port_init(PCIDevice *dev)
-{
- PCIVDIPortDevice *vdi = (PCIVDIPortDevice *)dev;
- uint8_t* config = vdi->pci_dev.config;
- uint32_t ram_size = msb_mask(sizeof(VDIPortRam) * 2 - 1);
-
- vdi->ram_offset = qemu_ram_alloc(&vdi->pci_dev.qdev, "bar1", ram_size);
- vdi->ram = qemu_get_ram_ptr(vdi->ram_offset);
- vdi_port_reset(vdi);
- vdi->ram_size = ram_size;
- vdi->new_gen_on_resume = false;
- vdi->running = false;
-
- pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID);
- pci_config_set_device_id(config, VDI_PORT_DEVICE_ID);
- pci_config_set_class(config, PCI_CLASS_COMMUNICATION_OTHER);
- pci_set_byte(&config[PCI_REVISION_ID], VDI_PORT_REVISION);
- pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
-
- pci_register_bar(dev, VDI_PORT_IO_RANGE_INDEX,
- msb_mask(VDI_PORT_IO_RANGE_SIZE * 2 - 1),
- PCI_BASE_ADDRESS_SPACE_IO, vdi_port_io_map);
-
- pci_register_bar(dev, VDI_PORT_RAM_RANGE_INDEX,
- vdi->ram_size , PCI_BASE_ADDRESS_SPACE_MEMORY,
- vdi_port_ram_map);
-
- qemu_add_vm_change_state_handler(vdi_port_vm_change_state_handler, vdi);
-
- return 0;
-}
-
-static VMStateDescription vdi_port_vmstate = {
- .name = VDI_PORT_DEV_NAME,
- .version_id = VDI_PORT_SAVE_VERSION,
- .minimum_version_id = VDI_PORT_SAVE_VERSION,
- .pre_load = vdi_port_pre_load,
- .post_load = vdi_port_post_load,
- .fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(pci_dev, PCIVDIPortDevice),
- VMSTATE_UINT32(connected, PCIVDIPortDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static PCIDeviceInfo vdi_port_info = {
- .qdev.name = VDI_PORT_DEV_NAME,
- .qdev.desc = "spice virtual desktop port (obsolete)",
- .qdev.size = sizeof(PCIVDIPortDevice),
- .qdev.vmsd = &vdi_port_vmstate,
- .qdev.reset = vdi_port_reset_handler,
-
- .init = vdi_port_init,
-};
-
-static void vdi_port_register(void)
-{
- pci_qdev_register(&vdi_port_info);
-}
-
-device_init(vdi_port_register);
--
1.7.2.3

View File

@ -1,236 +0,0 @@
From bebcc44cfe5da8a4881292fa564869a481eea4ae Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 8 Sep 2010 11:49:40 +0200
Subject: [PATCH 37/39] Revert "spice: add virtio-serial based vdi port backend."
This reverts commit ef9e975b1d34c1426867cef832ba6238a401b740.
---
Makefile.target | 1 -
hw/spice-vmc.c | 203 -------------------------------------------------------
2 files changed, 0 insertions(+), 204 deletions(-)
delete mode 100644 hw/spice-vmc.c
diff --git a/Makefile.target b/Makefile.target
index 90544c5..4da33b5 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -217,7 +217,6 @@ obj-i386-y += pc_piix.o
obj-i386-y += testdev.o
obj-i386-y += acpi.o acpi_piix4.o
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
-obj-i386-$(CONFIG_SPICE) += spice-vmc.o
obj-i386-y += pcspk.o i8254.o
obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
deleted file mode 100644
index 3f6a2bb..0000000
--- a/hw/spice-vmc.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
-
- Spice Virtual Machine Channel (VMC).
-
- A virtio-serial port used for spice to guest communication, over
- which spice client and a daemon in the guest operating system
- communicate.
-
- Replaces the old vdi_port PCI device.
-
-*/
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <spice.h>
-#include <spice-experimental.h>
-
-#include "virtio-serial.h"
-#include "qemu-spice.h"
-
-#define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
-#define VMC_DEVICE_NAME "spicevmc"
-
-#define dprintf(_svc, _level, _fmt, ...) \
- do { \
- if (_svc->debug >= _level) { \
- fprintf(stderr, "svc: " _fmt, ## __VA_ARGS__); \
- } \
- } while (0)
-
-typedef struct SpiceVirtualChannel {
- VirtIOSerialPort port;
- VMChangeStateEntry *vmstate;
- SpiceVDIPortInstance sin;
- bool active;
- uint8_t *buffer;
- uint8_t *datapos;
- ssize_t bufsize, datalen;
- uint32_t debug;
-} SpiceVirtualChannel;
-
-static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
-{
- SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
- ssize_t out;
-
- out = virtio_serial_write(&svc->port, buf, len);
- dprintf(svc, 2, "%s: %lu/%d\n", __func__, out, len);
- return out;
-}
-
-static int vmc_read(SpiceVDIPortInstance *sin, uint8_t *buf, int len)
-{
- SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
- int bytes = MIN(len, svc->datalen);
-
- dprintf(svc, 2, "%s: %d/%zd\n", __func__, bytes, svc->datalen);
- if (bytes) {
- memcpy(buf, svc->datapos, bytes);
- svc->datapos += bytes;
- svc->datalen -= bytes;
- if (0 == svc->datalen) {
- virtio_serial_throttle_port(&svc->port, false);
- }
- }
- return bytes;
-}
-
-static SpiceVDIPortInterface vmc_interface = {
- .base.type = SPICE_INTERFACE_VDI_PORT,
- .base.description = "spice virtual channel vdi port",
- .base.major_version = SPICE_INTERFACE_VDI_PORT_MAJOR,
- .base.minor_version = SPICE_INTERFACE_VDI_PORT_MINOR,
- .write = vmc_write,
- .read = vmc_read,
-};
-
-static void vmc_register_interface(SpiceVirtualChannel *svc)
-{
- if (svc->active) {
- return;
- }
- dprintf(svc, 1, "%s\n", __func__);
- svc->sin.base.sif = &vmc_interface.base;
- spice_server_add_interface(spice_server, &svc->sin.base);
- svc->active = true;
-}
-
-static void vmc_unregister_interface(SpiceVirtualChannel *svc)
-{
- if (!svc->active) {
- return;
- }
- dprintf(svc, 1, "%s\n", __func__);
- spice_server_remove_interface(&svc->sin.base);
- svc->active = false;
-}
-
-
-static void vmc_change_state_handler(void *opaque, int running, int reason)
-{
- SpiceVirtualChannel *svc = opaque;
-
- if (running && svc->active) {
- spice_server_vdi_port_wakeup(&svc->sin);
- }
-}
-
-/*
- * virtio-serial callbacks
- */
-
-static void vmc_guest_open(VirtIOSerialPort *port)
-{
- SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
-
- dprintf(svc, 1, "%s\n", __func__);
- vmc_register_interface(svc);
-}
-
-static void vmc_guest_close(VirtIOSerialPort *port)
-{
- SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
-
- dprintf(svc, 1, "%s\n", __func__);
- vmc_unregister_interface(svc);
-}
-
-static void vmc_guest_ready(VirtIOSerialPort *port)
-{
- SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
-
- dprintf(svc, 1, "%s\n", __func__);
- if (svc->active)
- spice_server_vdi_port_wakeup(&svc->sin);
-}
-
-static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
-{
- SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
-
- dprintf(svc, 2, "%s: %zd\n", __func__, len);
- assert(svc->datapos == 0);
- if (svc->bufsize < len) {
- svc->bufsize = len;
- svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
- }
- memcpy(svc->buffer, buf, len);
- svc->datapos = svc->buffer;
- svc->datalen = len;
- virtio_serial_throttle_port(&svc->port, true);
- spice_server_vdi_port_wakeup(&svc->sin);
-}
-
-static int vmc_initfn(VirtIOSerialDevice *dev)
-{
- VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
- SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
-
- if (!using_spice)
- return -1;
-
- dprintf(svc, 1, "%s\n", __func__);
- port->name = qemu_strdup(VMC_GUEST_DEVICE_NAME);
- svc->vmstate = qemu_add_vm_change_state_handler(
- vmc_change_state_handler, svc);
- virtio_serial_open(port);
- return 0;
-}
-
-static int vmc_exitfn(VirtIOSerialDevice *dev)
-{
- VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
- SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
-
- dprintf(svc, 1, "%s\n", __func__);
- vmc_unregister_interface(svc);
- qemu_del_vm_change_state_handler(svc->vmstate);
- virtio_serial_close(port);
- return 0;
-}
-
-static VirtIOSerialPortInfo vmc_info = {
- .qdev.name = VMC_DEVICE_NAME,
- .qdev.size = sizeof(SpiceVirtualChannel),
- .init = vmc_initfn,
- .exit = vmc_exitfn,
- .guest_open = vmc_guest_open,
- .guest_close = vmc_guest_close,
- .guest_ready = vmc_guest_ready,
- .have_data = vmc_have_data,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("nr", SpiceVirtualChannel, port.id, VIRTIO_CONSOLE_BAD_ID),
- DEFINE_PROP_UINT32("debug", SpiceVirtualChannel, debug, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void vmc_register(void)
-{
- virtio_serial_port_qdev_register(&vmc_info);
-}
-device_init(vmc_register)
--
1.7.2.3

View File

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

View File

@ -1,30 +0,0 @@
From 9394cbaab7701fe421d5c0168854d39d6a8ecfc2 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 7 Sep 2010 16:45:27 +0200
Subject: [PATCH 39/39] qxl: fix release ring overrun
---
hw/qxl.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 4a15200..8448893 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -377,10 +377,10 @@ static inline void qxl_push_free_res(PCIQXLDevice *d)
QXLReleaseRing *ring = &d->ram->release_ring;
uint64_t *item;
-#define QXL_FREE_BUNCH_SIZE 10
+#define QXL_FREE_BUNCH_SIZE 32
- if (SPICE_RING_IS_EMPTY(ring) || (d->num_free_res == QXL_FREE_BUNCH_SIZE &&
- ring->prod - ring->cons + 1 != ring->num_items)) {
+ if (SPICE_RING_IS_EMPTY(ring) || (d->num_free_res >= QXL_FREE_BUNCH_SIZE &&
+ ring->prod - ring->cons + 2 != ring->num_items)) {
int notify;
SPICE_RING_PUSH(ring, notify);
--
1.7.2.3

View File

@ -1,25 +0,0 @@
From b0f3b268c79c532725ae23af56621ab2948ac480 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 16 Sep 2010 12:07:51 +0000
Subject: [PATCH 40/40] qxl: flip default to stable pci revision.
---
hw/qxl.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 8448893..d2a0c16 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1455,7 +1455,7 @@ static PCIDeviceInfo qxl_info = {
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 3),
+ DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
DEFINE_PROP_END_OF_LIST(),
--
1.7.2.3

View File

@ -1,116 +0,0 @@
From ff53b62094b009f34dd3312e32a637ca73c752e3 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 8 Oct 2010 00:30:13 +0000
Subject: [PATCH 41/42] vmmouse: adapt to mouse handler changes.
This patch updates the vmmouse handler registration and activation.
Old behavior:
vmmouse_read_id, vmmouse_request_relative and vmmouse_request_absolute
unregister the handler and re-register it.
New behavior:
vmmouse_request_relative and vmmouse_request_absolute will unregister
the handler in case the mode did change. Then register and active the
handler with current mode if needed.
Note that the old code never ever *activates* the handler, so the
vmmouse doesn't receive events. This trips up Fedora 14 for example:
Boot a default install without usb tablet, watch the X-Server activating
the vmmouse then, enjoy a non-functional mouse.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/vmmouse.c | 31 +++++++++++++++++++++----------
1 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index f359304..2097119 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -100,16 +100,29 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_
i8042_isa_mouse_fake_event(s->ps2_mouse);
}
-static void vmmouse_update_handler(VMMouseState *s)
+static void vmmouse_remove_handler(VMMouseState *s)
{
if (s->entry) {
qemu_remove_mouse_event_handler(s->entry);
s->entry = NULL;
}
- if (s->status == 0)
+}
+
+static void vmmouse_update_handler(VMMouseState *s, int absolute)
+{
+ if (s->status != 0) {
+ return;
+ }
+ if (s->absolute != absolute) {
+ s->absolute = absolute;
+ vmmouse_remove_handler(s);
+ }
+ if (s->entry == NULL) {
s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
s, s->absolute,
"vmmouse");
+ qemu_activate_mouse_event_handler(s->entry);
+ }
}
static void vmmouse_read_id(VMMouseState *s)
@@ -121,28 +134,25 @@ static void vmmouse_read_id(VMMouseState *s)
s->queue[s->nb_queue++] = VMMOUSE_VERSION;
s->status = 0;
- vmmouse_update_handler(s);
}
static void vmmouse_request_relative(VMMouseState *s)
{
DPRINTF("vmmouse_request_relative()\n");
- s->absolute = 0;
- vmmouse_update_handler(s);
+ vmmouse_update_handler(s, 0);
}
static void vmmouse_request_absolute(VMMouseState *s)
{
DPRINTF("vmmouse_request_absolute()\n");
- s->absolute = 1;
- vmmouse_update_handler(s);
+ vmmouse_update_handler(s, 1);
}
static void vmmouse_disable(VMMouseState *s)
{
DPRINTF("vmmouse_disable()\n");
s->status = 0xffff;
- vmmouse_update_handler(s);
+ vmmouse_remove_handler(s);
}
static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
@@ -154,7 +164,7 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
if (size == 0 || size > 6 || size > s->nb_queue) {
printf("vmmouse: driver requested too much data %d\n", size);
s->status = 0xffff;
- vmmouse_update_handler(s);
+ vmmouse_remove_handler(s);
return;
}
@@ -239,7 +249,8 @@ static int vmmouse_post_load(void *opaque, int version_id)
{
VMMouseState *s = opaque;
- vmmouse_update_handler(s);
+ vmmouse_remove_handler(s);
+ vmmouse_update_handler(s, s->absolute);
return 0;
}
--
1.7.2.3

View File

@ -1,316 +0,0 @@
From 2ed38f61f1054e188838bae9244fc1c327f8cda4 Mon Sep 17 00:00:00 2001
From: Marcelo Tosatti <mtosatti@redhat.com>
Date: Mon, 18 Oct 2010 16:17:00 -0200
Subject: [PATCH 42/42] vhost-net patches for qemu-0.13.0 tarball
Justin,
Attached are the patches to fix vhost-net on the 0.13.0 tarball.
Untested.
commit f76cfc6f0882f227101f21d5a5b80804710b88cb
Author: Michael S. Tsirkin <mst@redhat.com>
Date: Wed Oct 6 07:22:00 2010 +0200
vhost: fix up irqfd support
vhost irqfd support: case where many vqs are
mapped to a single msix vector is currently broken.
Fix it up.
Includes this patch from qemu.git:
virtio: change set guest notifier to per-device
When using irqfd with vhost-net to inject interrupts,
a single evenfd might inject multiple interrupts.
Implementing this is much easier with a single
per-device callback to set guest notifiers.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/msix.c | 82 +++++++++++++++++++++++++++++++-----------------------
hw/msix.h | 4 +-
hw/pci.h | 3 +-
hw/virtio-pci.c | 56 +++++++++++++++++++++++++++++++------
4 files changed, 97 insertions(+), 48 deletions(-)
diff --git a/hw/msix.c b/hw/msix.c
index 3dd0456..c0c6b50 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -300,10 +300,8 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
}
- if (was_masked != msix_is_masked(dev, vector) &&
- dev->msix_mask_notifier && dev->msix_mask_notifier_opaque[vector]) {
+ if (was_masked != msix_is_masked(dev, vector) && dev->msix_mask_notifier) {
int r = dev->msix_mask_notifier(dev, vector,
- dev->msix_mask_notifier_opaque[vector],
msix_is_masked(dev, vector));
assert(r >= 0);
}
@@ -351,9 +349,8 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
int was_masked = msix_is_masked(dev, vector);
dev->msix_table_page[offset] |= MSIX_VECTOR_MASK;
if (was_masked != msix_is_masked(dev, vector) &&
- dev->msix_mask_notifier && dev->msix_mask_notifier_opaque[vector]) {
+ dev->msix_mask_notifier) {
r = dev->msix_mask_notifier(dev, vector,
- dev->msix_mask_notifier_opaque[vector],
msix_is_masked(dev, vector));
assert(r >= 0);
}
@@ -379,8 +376,6 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
sizeof *dev->msix_irq_entries);
}
#endif
- dev->msix_mask_notifier_opaque =
- qemu_mallocz(nentries * sizeof *dev->msix_mask_notifier_opaque);
dev->msix_mask_notifier = NULL;
dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
sizeof *dev->msix_entry_used);
@@ -444,8 +439,6 @@ int msix_uninit(PCIDevice *dev)
dev->msix_entry_used = NULL;
qemu_free(dev->msix_irq_entries);
dev->msix_irq_entries = NULL;
- qemu_free(dev->msix_mask_notifier_opaque);
- dev->msix_mask_notifier_opaque = NULL;
dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
return 0;
}
@@ -590,46 +583,65 @@ void msix_unuse_all_vectors(PCIDevice *dev)
msix_free_irq_entries(dev);
}
-int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque)
+/* Invoke the notifier if vector entry is used and unmasked. */
+static int msix_notify_if_unmasked(PCIDevice *dev, unsigned vector, int masked)
{
- int r = 0;
- if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
+ assert(dev->msix_mask_notifier);
+ if (!dev->msix_entry_used[vector] || msix_is_masked(dev, vector)) {
return 0;
+ }
+ return dev->msix_mask_notifier(dev, vector, masked);
+}
- assert(dev->msix_mask_notifier);
- assert(opaque);
- assert(!dev->msix_mask_notifier_opaque[vector]);
+static int msix_set_mask_notifier_for_vector(PCIDevice *dev, unsigned vector)
+{
+ /* Notifier has been set. Invoke it on unmasked vectors. */
+ return msix_notify_if_unmasked(dev, vector, 0);
+}
+
+static int msix_unset_mask_notifier_for_vector(PCIDevice *dev, unsigned vector)
+{
+ /* Notifier will be unset. Invoke it to mask unmasked entries. */
+ return msix_notify_if_unmasked(dev, vector, 1);
+}
- /* Unmask the new notifier unless vector is masked. */
- if (!msix_is_masked(dev, vector)) {
- r = dev->msix_mask_notifier(dev, vector, opaque, false);
+int msix_set_mask_notifier(PCIDevice *dev, msix_mask_notifier_func f)
+{
+ int r, n;
+ assert(!dev->msix_mask_notifier);
+ dev->msix_mask_notifier = f;
+ for (n = 0; n < dev->msix_entries_nr; ++n) {
+ r = msix_set_mask_notifier_for_vector(dev, n);
if (r < 0) {
- return r;
+ goto undo;
}
}
- dev->msix_mask_notifier_opaque[vector] = opaque;
+ return 0;
+
+undo:
+ while (--n >= 0) {
+ msix_unset_mask_notifier_for_vector(dev, n);
+ }
+ dev->msix_mask_notifier = NULL;
return r;
}
-int msix_unset_mask_notifier(PCIDevice *dev, unsigned vector)
+int msix_unset_mask_notifier(PCIDevice *dev)
{
- int r = 0;
- void *opaque;
- if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
- return 0;
-
- opaque = dev->msix_mask_notifier_opaque[vector];
-
+ int r, n;
assert(dev->msix_mask_notifier);
- assert(opaque);
-
- /* Mask the old notifier unless it is already masked. */
- if (!msix_is_masked(dev, vector)) {
- r = dev->msix_mask_notifier(dev, vector, opaque, true);
+ for (n = 0; n < dev->msix_entries_nr; ++n) {
+ r = msix_unset_mask_notifier_for_vector(dev, n);
if (r < 0) {
- return r;
+ goto undo;
}
}
- dev->msix_mask_notifier_opaque[vector] = NULL;
+ dev->msix_mask_notifier = NULL;
+ return 0;
+
+undo:
+ while (--n >= 0) {
+ msix_set_mask_notifier_for_vector(dev, n);
+ }
return r;
}
diff --git a/hw/msix.h b/hw/msix.h
index 6b21ffb..5a81df5 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -33,6 +33,6 @@ void msix_reset(PCIDevice *dev);
extern int msix_supported;
-int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque);
-int msix_unset_mask_notifier(PCIDevice *dev, unsigned vector);
+int msix_set_mask_notifier(PCIDevice *dev, msix_mask_notifier_func);
+int msix_unset_mask_notifier(PCIDevice *dev);
#endif
diff --git a/hw/pci.h b/hw/pci.h
index ccb99d0..a40dc14 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -131,7 +131,7 @@ enum {
#define PCI_CAPABILITY_CONFIG_MSIX_LENGTH 0x10
typedef int (*msix_mask_notifier_func)(PCIDevice *, unsigned vector,
- void *opaque, int masked);
+ int masked);
struct PCIDevice {
DeviceState qdev;
@@ -198,7 +198,6 @@ struct PCIDevice {
struct kvm_irq_routing_entry *msix_irq_entries;
- void **msix_mask_notifier_opaque;
msix_mask_notifier_func msix_mask_notifier;
/* Device capability configuration space */
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 83b7871..72bc80e 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -427,11 +427,10 @@ static void virtio_pci_guest_notifier_read(void *opaque)
}
}
-static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector,
- void *opaque, int masked)
+static int virtio_pci_mask_vq(PCIDevice *dev, unsigned vector,
+ VirtQueue *vq, int masked)
{
#ifdef CONFIG_KVM
- VirtQueue *vq = opaque;
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
int r = kvm_set_irqfd(dev->msix_irq_entries[vector].gsi,
event_notifier_get_fd(notifier),
@@ -452,6 +451,34 @@ static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector,
#endif
}
+static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector,
+ int masked)
+{
+ VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
+ VirtIODevice *vdev = proxy->vdev;
+ int r, n;
+
+ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(vdev, n)) {
+ break;
+ }
+ if (virtio_queue_vector(vdev, n) != vector) {
+ continue;
+ }
+ r = virtio_pci_mask_vq(dev, vector, virtio_get_queue(vdev, n), masked);
+ if (r < 0) {
+ goto undo;
+ }
+ }
+ return 0;
+undo:
+ while (--n >= 0) {
+ virtio_pci_mask_vq(dev, vector, virtio_get_queue(vdev, n), !masked);
+ }
+ return r;
+}
+
+
static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
{
VirtIOPCIProxy *proxy = opaque;
@@ -465,11 +492,7 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
}
qemu_set_fd_handler(event_notifier_get_fd(notifier),
virtio_pci_guest_notifier_read, NULL, vq);
- msix_set_mask_notifier(&proxy->pci_dev,
- virtio_queue_vector(proxy->vdev, n), vq);
} else {
- msix_unset_mask_notifier(&proxy->pci_dev,
- virtio_queue_vector(proxy->vdev, n));
qemu_set_fd_handler(event_notifier_get_fd(notifier),
NULL, NULL, NULL);
/* Test and clear notifier before closing it,
@@ -487,6 +510,13 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
VirtIODevice *vdev = proxy->vdev;
int r, n;
+ /* Must unset mask notifier while guest notifier
+ * is still assigned */
+ if (!assign) {
+ r = msix_unset_mask_notifier(&proxy->pci_dev);
+ assert(r >= 0);
+ }
+
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
break;
@@ -498,6 +528,16 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
}
}
+ /* Must set mask notifier after guest notifier
+ * has been assigned */
+ if (assign) {
+ r = msix_set_mask_notifier(&proxy->pci_dev,
+ virtio_pci_mask_notifier);
+ if (r < 0) {
+ goto assign_error;
+ }
+ }
+
return 0;
assign_error:
@@ -583,8 +623,6 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
proxy->pci_dev.config_write = virtio_write_config;
- proxy->pci_dev.msix_mask_notifier = virtio_pci_mask_notifier;
-
size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
if (size & (size-1))
size = 1 << qemu_fls(size);
--
1.7.2.3

View File

@ -1,34 +0,0 @@
commit d35b261c7a94be9e2fcad5484343544d58ff99be
Author: Richard Henderson <rth@twiddle.net>
Date: Fri Jun 4 12:14:10 2010 -0700
s390x: Avoid _llseek.
There's no _llseek on s390x either. Replace the existing
test for __x86_64__ with a functional test for __NR_llseek.
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8222cb9..e94f1ee 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -208,7 +208,7 @@ _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count)
_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
#endif
_syscall2(int, sys_getpriority, int, which, int, who);
-#if defined(TARGET_NR__llseek) && !defined (__x86_64__)
+#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
#endif
@@ -5933,7 +5933,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR__llseek /* Not on alpha */
case TARGET_NR__llseek:
{
-#if defined (__x86_64__)
+#if !defined(__NR_llseek)
ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
if (put_user_s64(ret, arg4))
goto efault;

View File

@ -1,63 +0,0 @@
From e69a45b96be09d25429175fa8f0f85e3d7fab5a8 Mon Sep 17 00:00:00 2001
Message-Id: <e69a45b96be09d25429175fa8f0f85e3d7fab5a8.1277191832.git.amit.shah@redhat.com>
From: Kirill A. Shutemov <kirill@shutemov.name>
Date: Wed, 20 Jan 2010 00:56:14 +0100
Subject: [PATCH] block/vvfat.c: fix warnings with _FORTIFY_SOURCE
CC block/vvfat.o
cc1: warnings being treated as errors
block/vvfat.c: In function 'commit_one_file':
block/vvfat.c:2259: error: ignoring return value of 'ftruncate', declared with attribute warn_unused_result
make: *** [block/vvfat.o] Error 1
CC block/vvfat.o
In file included from /usr/include/stdio.h:912,
from ./qemu-common.h:19,
from block/vvfat.c:27:
In function 'snprintf',
inlined from 'init_directories' at block/vvfat.c:871,
inlined from 'vvfat_open' at block/vvfat.c:1068:
/usr/include/bits/stdio2.h:65: error: call to __builtin___snprintf_chk will always overflow destination buffer
make: *** [block/vvfat.o] Error 1
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
Signed-off-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 2dedf83ef0cc3463783d6b71bf1b25476f691f3a)
This fixes Fedora bug 605202.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
block/vvfat.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/block/vvfat.c b/block/vvfat.c
index c1acb35..592d6e6 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -868,7 +868,8 @@ static int init_directories(BDRVVVFATState* s,
{
direntry_t* entry=array_get_next(&(s->directory));
entry->attributes=0x28; /* archive | volume label */
- snprintf((char*)entry->name,11,"QEMU VVFAT");
+ memcpy(entry->name,"QEMU VVF",8);
+ memcpy(entry->extension,"AT ",3);
}
/* Now build FAT, and write back information into directory */
@@ -2256,7 +2257,11 @@ static int commit_one_file(BDRVVVFATState* s,
c = c1;
}
- ftruncate(fd, size);
+ if (ftruncate(fd, size)) {
+ perror("ftruncate()");
+ close(fd);
+ return -4;
+ }
close(fd);
return commit_mappings(s, first_cluster, dir_index);
--
1.7.0.1

View File

@ -0,0 +1,31 @@
vhost was passing a physical address to cpu_physical_memory_set_dirty,
which is wrong: we need to translate to ram address first.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Note: this lead to crashes during migration, so the patch
is needed on the stable branch too.
---
hw/vhost.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/hw/vhost.c b/hw/vhost.c
index aaa34e4..97a1299 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -49,8 +49,10 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
log = __sync_fetch_and_and(from, 0);
while ((bit = sizeof(log) > sizeof(int) ?
ffsll(log) : ffs(log))) {
+ ram_addr_t ram_addr;
bit -= 1;
- cpu_physical_memory_set_dirty(addr + bit * VHOST_LOG_PAGE);
+ ram_addr = cpu_get_physical_page_desc(addr + bit * VHOST_LOG_PAGE);
+ cpu_physical_memory_set_dirty(ram_addr);
log &= ~(0x1ull << bit);
}
addr += VHOST_LOG_CHUNK;
--
1.7.3.2.91.g446ac

View File

@ -1,7 +1,7 @@
Summary: QEMU is a FAST! processor emulator
Name: qemu
Version: 0.14.0
Release: 2%{?dist}
Release: 3%{?dist}
# Epoch because we pushed a qemu-1.0 package
Epoch: 2
License: GPLv2+ and LGPLv2+ and BSD
@ -37,7 +37,16 @@ Source8: ksmtuned.conf
# with F-13/
Patch00: pc-add-a-Fedora-13-machine-type-for-backward-compat.patch
# Patches from upstream:
Patch01: qemu-fix-non-PCI-target-build.patch
Patch02: qemu-vhost-fix-dirty-page-handling.patch
# Spice fixes
Patch20: 0001-qxl-spice-display-move-pipe-to-ssd.patch
Patch21: 0002-qxl-implement-get_command-in-vga-mode-without-locks.patch
Patch22: 0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch
Patch23: 0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel
@ -570,6 +579,10 @@ fi
%{_mandir}/man1/qemu-img.1*
%changelog
* Wed Mar 16 2011 Justin M. Forbes <jforbes@redhat.com> - 2:0.14.0-3
- Fix migration issue with vhost
- Fix qxl locking issues for spice
* Wed Mar 02 2011 Justin M. Forbes <jforbes@redhat.com> - 2:0.14.0-2
- Re-enable sparc and cris builds