From da929861c3e42e889f6635f4a459dd402d4d17fd Mon Sep 17 00:00:00 2001 From: Justin M. Forbes Date: Mar 16 2011 20:31:55 +0000 Subject: fix vhost migration issues, and qxl locking for spice --- diff --git a/0001-add-pflib-PixelFormat-conversion-library.patch b/0001-add-pflib-PixelFormat-conversion-library.patch deleted file mode 100644 index de9805e..0000000 --- a/0001-add-pflib-PixelFormat-conversion-library.patch +++ /dev/null @@ -1,259 +0,0 @@ -From 09992bc6b432987ed3871dd7e4327ab6a589b865 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 -+ * -+ * 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 - diff --git a/0001-qxl-spice-display-move-pipe-to-ssd.patch b/0001-qxl-spice-display-move-pipe-to-ssd.patch new file mode 100644 index 0000000..b542f54 --- /dev/null +++ b/0001-qxl-spice-display-move-pipe-to-ssd.patch @@ -0,0 +1,143 @@ +>From fd04276a00b172e6fbba3e3c72b1d13a0f179414 Mon Sep 17 00:00:00 2001 +From: Alon Levy +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 + diff --git a/0002-configure-add-logging.patch b/0002-configure-add-logging.patch deleted file mode 100644 index 34f374c..0000000 --- a/0002-configure-add-logging.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 89df4f8cf7ecde07e3dc5e2ea3c19cbcd02165d0 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0002-qxl-implement-get_command-in-vga-mode-without-locks.patch b/0002-qxl-implement-get_command-in-vga-mode-without-locks.patch new file mode 100644 index 0000000..d221d5f --- /dev/null +++ b/0002-qxl-implement-get_command-in-vga-mode-without-locks.patch @@ -0,0 +1,312 @@ +>From 97e291086fef45762e0278e85ab1d231a9902bbb Mon Sep 17 00:00:00 2001 +From: Uri Lublin +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 + diff --git a/0003-add-spice-into-the-configure-file.patch b/0003-add-spice-into-the-configure-file.patch deleted file mode 100644 index 3d4eb0a..0000000 --- a/0003-add-spice-into-the-configure-file.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0034da7fb15d1225e0fd725009743d48511a90b7 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 -+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 - diff --git a/0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch b/0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch new file mode 100644 index 0000000..92a148e --- /dev/null +++ b/0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch @@ -0,0 +1,148 @@ +>From d413b3c36cbd9820c5b9492b52caa421abccf745 Mon Sep 17 00:00:00 2001 +From: Alon Levy +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 + diff --git a/0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch b/0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch new file mode 100644 index 0000000..03daba4 --- /dev/null +++ b/0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch @@ -0,0 +1,249 @@ +>From 1a33e5f2fa6de800047517a6f3251dc7191c97b5 Mon Sep 17 00:00:00 2001 +From: Alon Levy +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 + diff --git a/0004-spice-core-bits.patch b/0004-spice-core-bits.patch deleted file mode 100644 index a4b156b..0000000 --- a/0004-spice-core-bits.patch +++ /dev/null @@ -1,333 +0,0 @@ -From 67361a4ad5c99c5dfecdb9d2fc1ba794c38c44ff Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 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 -+ -+#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 -+#include -+#include -+ -+#include -+#include -+ -+#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 - diff --git a/0005-spice-add-keyboard.patch b/0005-spice-add-keyboard.patch deleted file mode 100644 index 6394c15..0000000 --- a/0005-spice-add-keyboard.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 90f6ec84332857752c252b1c3b89d86eb9714b0e Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 -+#include -+#include -+ -+#include -+ -+#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 - diff --git a/0006-spice-add-mouse.patch b/0006-spice-add-mouse.patch deleted file mode 100644 index ea41880..0000000 --- a/0006-spice-add-mouse.patch +++ /dev/null @@ -1,62 +0,0 @@ -From e18846175191cbc590ac46fa3820726aeebd6d48 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0007-spice-simple-display.patch b/0007-spice-simple-display.patch deleted file mode 100644 index e59caa1..0000000 --- a/0007-spice-simple-display.patch +++ /dev/null @@ -1,532 +0,0 @@ -From 0143117eb5e6233fdeff3b679492b51148cc8f85 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 -+#include -+#include -+#include -+#include -+#include -+ -+#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 -+#include -+#include -+ -+#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 - diff --git a/0008-spice-add-tablet-support.patch b/0008-spice-add-tablet-support.patch deleted file mode 100644 index 6f37c81..0000000 --- a/0008-spice-add-tablet-support.patch +++ /dev/null @@ -1,160 +0,0 @@ -From e3c6e18e27f0d598b37e9be1795dbcb42f740071 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - #include -+#include - #include - - #include -@@ -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 - diff --git a/0009-vgabios-update-to-0.6c-pcibios-patches.patch b/0009-vgabios-update-to-0.6c-pcibios-patches.patch deleted file mode 100644 index 29ff6f4..0000000 --- a/0009-vgabios-update-to-0.6c-pcibios-patches.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0920337756cdf82dcd585efb23ae18f8086696c8 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0010-switch-stdvga-to-pci-vgabios.patch b/0010-switch-stdvga-to-pci-vgabios.patch deleted file mode 100644 index ccb71ac..0000000 --- a/0010-switch-stdvga-to-pci-vgabios.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 6ac04dff1ee3932d2ef94c1e42f4e8208fbf92bf Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0011-switch-vmware_vga-to-pci-vgabios.patch b/0011-switch-vmware_vga-to-pci-vgabios.patch deleted file mode 100644 index 30bfa9c..0000000 --- a/0011-switch-vmware_vga-to-pci-vgabios.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 07cdc867f1e12a4e8b4096e7f1f3ffda2f4e7d02 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0012-all-vga-refuse-hotplugging.patch b/0012-all-vga-refuse-hotplugging.patch deleted file mode 100644 index 393b1b2..0000000 --- a/0012-all-vga-refuse-hotplugging.patch +++ /dev/null @@ -1,61 +0,0 @@ -From a659f6b472d95503657ac68a52242ce769006f17 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0013-spice-tls-support.patch b/0013-spice-tls-support.patch deleted file mode 100644 index da247af..0000000 --- a/0013-spice-tls-support.patch +++ /dev/null @@ -1,168 +0,0 @@ -From e0d06d42a83e7796b2c39ad6cab3630c0a8c2845 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0014-spice-add-qxl-device.patch b/0014-spice-add-qxl-device.patch deleted file mode 100644 index 4ea90ba..0000000 --- a/0014-spice-add-qxl-device.patch +++ /dev/null @@ -1,2085 +0,0 @@ -From 4cd79eae3a476fda86b67a8075735a03c1254a08 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 27 Apr 2010 11:50:11 +0200 -Subject: [PATCH 14/39] spice: add qxl device - -qxl is a paravirtual graphics card. The qxl device is the bridge -between the guest and the spice server (aka libspice-server). The -spice server will send the rendering commands to the spice client, which -will actually render them. - -The spice server is also able to render locally, which is done in case -the guest wants read something from video memory. Local rendering is -also used to support display over vnc and sdl. - -qxl is activated using "-vga qxl". qxl supports multihead, additional -cards can be added via '-device qxl". ---- - Makefile.target | 1 + - hw/hw.h | 14 + - hw/pc.c | 8 + - hw/qxl-logger.c | 179 +++++++ - hw/qxl-render.c | 207 ++++++++ - hw/qxl.c | 1411 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ - hw/qxl.h | 102 ++++ - hw/vga_int.h | 2 +- - sysemu.h | 3 +- - vl.c | 4 +- - 10 files changed, 1928 insertions(+), 3 deletions(-) - create mode 100644 hw/qxl-logger.c - create mode 100644 hw/qxl-render.c - create mode 100644 hw/qxl.c - create mode 100644 hw/qxl.h - -diff --git a/Makefile.target b/Makefile.target -index 9e13d99..4da33b5 100644 ---- a/Makefile.target -+++ b/Makefile.target -@@ -216,6 +216,7 @@ obj-i386-y += debugcon.o multiboot.o - 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-y += pcspk.o i8254.o - obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o -diff --git a/hw/hw.h b/hw/hw.h -index ec6985d..044ebfb 100644 ---- a/hw/hw.h -+++ b/hw/hw.h -@@ -528,6 +528,17 @@ extern const VMStateInfo vmstate_info_unused_buffer; - .start = (_start), \ - } - -+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \ -+ .name = (stringify(_field)), \ -+ .version_id = (_version), \ -+ .field_exists = (_test), \ -+ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\ -+ .info = &vmstate_info_buffer, \ -+ .flags = VMS_VBUFFER|VMS_POINTER, \ -+ .offset = offsetof(_state, _field), \ -+ .start = (_start), \ -+} -+ - #define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \ - .name = (stringify(_field)), \ - .version_id = (_version), \ -@@ -742,6 +753,9 @@ extern const VMStateDescription vmstate_i2c_slave; - #define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \ - VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size) - -+#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size) \ -+ VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size) -+ - #define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \ - VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size) - -diff --git a/hw/pc.c b/hw/pc.c -index 77b1592..1f2df2f 100644 ---- a/hw/pc.c -+++ b/hw/pc.c -@@ -41,6 +41,7 @@ - #include "sysemu.h" - #include "device-assignment.h" - #include "kvm.h" -+#include "qemu-spice.h" - - /* output Bochs bios info messages */ - //#define DEBUG_BIOS -@@ -1002,6 +1003,13 @@ void pc_vga_init(PCIBus *pci_bus) - pci_vmsvga_init(pci_bus); - else - fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); -+#ifdef CONFIG_SPICE -+ } else if (qxl_enabled) { -+ if (pci_bus) -+ pci_create_simple(pci_bus, -1, "qxl"); -+ else -+ fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__); -+#endif - } else if (std_vga_enabled) { - if (pci_bus) { - pci_vga_init(pci_bus, 0, 0); -diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c -new file mode 100644 -index 0000000..d4a935a ---- /dev/null -+++ b/hw/qxl-logger.c -@@ -0,0 +1,179 @@ -+/* -+ * qxl command logging -- for debug purposes -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "qxl.h" -+ -+static const char *qxl_type[] = { -+ [ QXL_CMD_NOP ] = "nop", -+ [ QXL_CMD_DRAW ] = "draw", -+ [ QXL_CMD_UPDATE ] = "update", -+ [ QXL_CMD_CURSOR ] = "cursor", -+ [ QXL_CMD_MESSAGE ] = "message", -+ [ QXL_CMD_SURFACE ] = "surface", -+}; -+ -+static const char *qxl_draw_type[] = { -+ [ QXL_DRAW_NOP ] = "nop", -+ [ QXL_DRAW_FILL ] = "fill", -+ [ QXL_DRAW_OPAQUE ] = "opaque", -+ [ QXL_DRAW_COPY ] = "copy", -+ [ QXL_COPY_BITS ] = "copy-bits", -+ [ QXL_DRAW_BLEND ] = "blend", -+ [ QXL_DRAW_BLACKNESS ] = "blackness", -+ [ QXL_DRAW_WHITENESS ] = "whitemess", -+ [ QXL_DRAW_INVERS ] = "invers", -+ [ QXL_DRAW_ROP3 ] = "rop3", -+ [ QXL_DRAW_STROKE ] = "stroke", -+ [ QXL_DRAW_TEXT ] = "text", -+ [ QXL_DRAW_TRANSPARENT ] = "transparent", -+ [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend", -+}; -+ -+static const char *qxl_draw_effect[] = { -+ [ QXL_EFFECT_BLEND ] = "blend", -+ [ QXL_EFFECT_OPAQUE ] = "opaque", -+ [ QXL_EFFECT_REVERT_ON_DUP ] = "revert-on-dup", -+ [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup", -+ [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup", -+ [ QXL_EFFECT_NOP_ON_DUP ] = "nop-on-dup", -+ [ QXL_EFFECT_NOP ] = "nop", -+ [ QXL_EFFECT_OPAQUE_BRUSH ] = "opaque-brush", -+}; -+ -+static const char *qxl_surface_cmd[] = { -+ [ QXL_SURFACE_CMD_CREATE ] = "create", -+ [ QXL_SURFACE_CMD_DESTROY ] = "destroy", -+}; -+ -+static const char *spice_surface_fmt[] = { -+ [ SPICE_SURFACE_FMT_INVALID ] = "invalid", -+ [ SPICE_SURFACE_FMT_1_A ] = "alpha/1", -+ [ SPICE_SURFACE_FMT_8_A ] = "alpha/8", -+ [ SPICE_SURFACE_FMT_16_555 ] = "555/16", -+ [ SPICE_SURFACE_FMT_16_565 ] = "565/16", -+ [ SPICE_SURFACE_FMT_32_xRGB ] = "xRGB/32", -+ [ SPICE_SURFACE_FMT_32_ARGB ] = "ARGB/32", -+}; -+ -+static const char *qxl_cursor_cmd[] = { -+ [ QXL_CURSOR_SET ] = "set", -+ [ QXL_CURSOR_MOVE ] = "move", -+ [ QXL_CURSOR_HIDE ] = "hide", -+ [ QXL_CURSOR_TRAIL ] = "trail", -+}; -+ -+static const char *spice_cursor_type[] = { -+ [ SPICE_CURSOR_TYPE_ALPHA ] = "alpha", -+ [ SPICE_CURSOR_TYPE_MONO ] = "mono", -+ [ SPICE_CURSOR_TYPE_COLOR4 ] = "color4", -+ [ SPICE_CURSOR_TYPE_COLOR8 ] = "color8", -+ [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16", -+ [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24", -+ [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32", -+}; -+ -+static const char *qxl_v2n(const char *n[], size_t l, int v) -+{ -+ if (v >= l || !n[v]) -+ return "???"; -+ return n[v]; -+} -+#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value) -+ -+static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw) -+{ -+ fprintf(stderr, ": surface_id %d type %s effect %s", -+ draw->surface_id, -+ qxl_name(qxl_draw_type, draw->type), -+ qxl_name(qxl_draw_effect, draw->effect)); -+} -+ -+static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw) -+{ -+ fprintf(stderr, ": type %s effect %s", -+ qxl_name(qxl_draw_type, draw->type), -+ qxl_name(qxl_draw_effect, draw->effect)); -+} -+ -+static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd) -+{ -+ fprintf(stderr, ": %s id %d", -+ qxl_name(qxl_surface_cmd, cmd->type), -+ cmd->surface_id); -+ if (cmd->type == QXL_SURFACE_CMD_CREATE) { -+ fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)", -+ cmd->u.surface_create.width, -+ cmd->u.surface_create.height, -+ cmd->u.surface_create.stride, -+ qxl_name(spice_surface_fmt, cmd->u.surface_create.format), -+ qxl->guest_surfaces.count, qxl->guest_surfaces.max); -+ } -+ if (cmd->type == QXL_SURFACE_CMD_DESTROY) { -+ fprintf(stderr, " (count %d)", qxl->guest_surfaces.count); -+ } -+} -+ -+void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) -+{ -+ QXLCursor *cursor; -+ -+ fprintf(stderr, ": %s", -+ qxl_name(qxl_cursor_cmd, cmd->type)); -+ switch (cmd->type) { -+ case QXL_CURSOR_SET: -+ fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64, -+ cmd->u.set.position.x, -+ cmd->u.set.position.y, -+ cmd->u.set.visible ? "yes" : "no", -+ cmd->u.set.shape); -+ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); -+ fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d" -+ " unique 0x%" PRIx64 " data-size %d", -+ qxl_name(spice_cursor_type, cursor->header.type), -+ cursor->header.width, cursor->header.height, -+ cursor->header.hot_spot_x, cursor->header.hot_spot_y, -+ cursor->header.unique, cursor->data_size); -+ break; -+ case QXL_CURSOR_MOVE: -+ fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y); -+ break; -+ } -+} -+ -+void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) -+{ -+ bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; -+ void *data; -+ -+ if (!qxl->cmdlog) { -+ return; -+ } -+ fprintf(stderr, "qxl-%d/%s:", qxl->id, ring); -+ fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data, -+ qxl_name(qxl_type, ext->cmd.type), -+ compat ? "(compat)" : ""); -+ -+ data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); -+ switch (ext->cmd.type) { -+ case QXL_CMD_DRAW: -+ if (!compat) { -+ qxl_log_cmd_draw(qxl, data); -+ } else { -+ qxl_log_cmd_draw_compat(qxl, data); -+ } -+ break; -+ case QXL_CMD_SURFACE: -+ qxl_log_cmd_surface(qxl, data); -+ break; -+ case QXL_CMD_CURSOR: -+ qxl_log_cmd_cursor(qxl, data, ext->group_id); -+ break; -+ } -+ fprintf(stderr, "\n"); -+} -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -new file mode 100644 -index 0000000..d9ebca4 ---- /dev/null -+++ b/hw/qxl-render.c -@@ -0,0 +1,207 @@ -+/* -+ * qxl local rendering (aka display on sdl/vnc) -+ */ -+#include -+#include -+#include -+#include -+ -+#include "qxl.h" -+ -+static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) -+{ -+ uint8_t *src = qxl->guest_primary.data; -+ uint8_t *dst = qxl->guest_primary.flipped; -+ int len, i; -+ -+ src += (qxl->guest_primary.surface.height - rect->top - 1) * -+ qxl->guest_primary.stride; -+ dst += rect->top * qxl->guest_primary.stride; -+ src += rect->left * qxl->guest_primary.bytes_pp; -+ dst += rect->left * qxl->guest_primary.bytes_pp; -+ len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp; -+ -+ for (i = rect->top; i < rect->bottom; i++) { -+ memcpy(dst, src, len); -+ dst += qxl->guest_primary.stride; -+ src -= qxl->guest_primary.stride; -+ } -+} -+ -+void qxl_render_resize(PCIQXLDevice *qxl) -+{ -+ QXLSurfaceCreate *sc = &qxl->guest_primary.surface; -+ -+ qxl->guest_primary.stride = sc->stride; -+ qxl->guest_primary.resized++; -+ switch (sc->format) { -+ case SPICE_SURFACE_FMT_16_555: -+ qxl->guest_primary.bytes_pp = 2; -+ qxl->guest_primary.bits_pp = 15; -+ break; -+ case SPICE_SURFACE_FMT_16_565: -+ qxl->guest_primary.bytes_pp = 2; -+ qxl->guest_primary.bits_pp = 16; -+ break; -+ case SPICE_SURFACE_FMT_32_xRGB: -+ case SPICE_SURFACE_FMT_32_ARGB: -+ qxl->guest_primary.bytes_pp = 4; -+ qxl->guest_primary.bits_pp = 32; -+ break; -+ default: -+ fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__, -+ qxl->guest_primary.surface.format); -+ qxl->guest_primary.bytes_pp = 4; -+ qxl->guest_primary.bits_pp = 32; -+ break; -+ } -+} -+ -+void qxl_render_update(PCIQXLDevice *qxl) -+{ -+ VGACommonState *vga = &qxl->vga; -+ QXLRect dirty[32], update; -+ void *ptr; -+ int i; -+ -+ if (qxl->guest_primary.resized) { -+ qxl->guest_primary.resized = 0; -+ -+ if (qxl->guest_primary.flipped) { -+ qemu_free(qxl->guest_primary.flipped); -+ qxl->guest_primary.flipped = NULL; -+ } -+ qemu_free_displaysurface(vga->ds); -+ -+ qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset); -+ if (qxl->guest_primary.stride < 0) { -+ /* spice surface is upside down -> need extra buffer to flip */ -+ qxl->guest_primary.stride = -qxl->guest_primary.stride; -+ qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width * -+ qxl->guest_primary.stride); -+ ptr = qxl->guest_primary.flipped; -+ } else { -+ ptr = qxl->guest_primary.data; -+ } -+ fprintf(stderr, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n", -+ __FUNCTION__, -+ qxl->guest_primary.surface.width, -+ qxl->guest_primary.surface.height, -+ qxl->guest_primary.stride, -+ qxl->guest_primary.bytes_pp, -+ qxl->guest_primary.bits_pp, -+ qxl->guest_primary.flipped ? "yes" : "no"); -+ vga->ds->surface = -+ qemu_create_displaysurface_from(qxl->guest_primary.surface.width, -+ qxl->guest_primary.surface.height, -+ qxl->guest_primary.bits_pp, -+ qxl->guest_primary.stride, -+ ptr); -+ dpy_resize(vga->ds); -+ } -+ -+ if (!qxl->guest_primary.commands) -+ return; -+ qxl->guest_primary.commands = 0; -+ -+ update.left = 0; -+ update.right = qxl->guest_primary.surface.width; -+ update.top = 0; -+ update.bottom = qxl->guest_primary.surface.height; -+ -+ memset(dirty, 0, sizeof(dirty)); -+ qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update, -+ dirty, ARRAY_SIZE(dirty), 1); -+ -+ for (i = 0; i < ARRAY_SIZE(dirty); i++) { -+ if (qemu_spice_rect_is_empty(dirty+i)) -+ break; -+ if (qxl->guest_primary.flipped) { -+ qxl_flip(qxl, dirty+i); -+ } -+ dpy_update(vga->ds, -+ dirty[i].left, dirty[i].top, -+ dirty[i].right - dirty[i].left, -+ dirty[i].bottom - dirty[i].top); -+ } -+} -+ -+static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor) -+{ -+ QEMUCursor *c; -+ uint8_t *image, *mask; -+ int size; -+ -+ c = cursor_alloc(cursor->header.width, cursor->header.height); -+ c->hot_x = cursor->header.hot_spot_x; -+ c->hot_y = cursor->header.hot_spot_y; -+ switch (cursor->header.type) { -+ case SPICE_CURSOR_TYPE_ALPHA: -+ size = cursor->header.width * cursor->header.height * sizeof(uint32_t); -+ memcpy(c->data, cursor->chunk.data, size); -+ if (qxl->debug > 1) -+ cursor_print_ascii_art(c, "qxl/alpha"); -+ break; -+ case SPICE_CURSOR_TYPE_MONO: -+ mask = cursor->chunk.data; -+ image = mask + cursor_get_mono_bpl(c) * c->width; -+ cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask); -+ if (qxl->debug > 1) -+ cursor_print_ascii_art(c, "qxl/mono"); -+ break; -+ default: -+ fprintf(stderr, "%s: not implemented: type %d\n", -+ __FUNCTION__, cursor->header.type); -+ goto fail; -+ } -+ return c; -+ -+fail: -+ cursor_put(c); -+ return NULL; -+} -+ -+ -+void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) -+{ -+ QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); -+ QXLCursor *cursor; -+ QEMUCursor *c; -+ int x = -1, y = -1; -+ -+ if (!qxl->ssd.ds->mouse_set || -+ !qxl->ssd.ds->cursor_define) -+ return; -+ -+#if 1 -+ if (cmd->type != QXL_CURSOR_MOVE) { -+ fprintf(stderr, "%s", __FUNCTION__); -+ qxl_log_cmd_cursor(qxl, cmd, ext->group_id); -+ fprintf(stderr, "\n"); -+ } -+#endif -+ switch (cmd->type) { -+ case QXL_CURSOR_SET: -+ x = cmd->u.set.position.x; -+ y = cmd->u.set.position.y; -+ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); -+ if (cursor->chunk.data_size != cursor->data_size) { -+ fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__); -+ return; -+ } -+ c = qxl_cursor(qxl, cursor); -+ if (c == NULL) { -+ c = cursor_builtin_left_ptr(); -+ } -+ qxl->ssd.ds->cursor_define(c); -+ cursor_put(c); -+ break; -+ case QXL_CURSOR_MOVE: -+ x = cmd->u.position.x; -+ y = cmd->u.position.y; -+ break; -+ } -+ if (x != -1 && y != -1) { -+ qxl->ssd.ds->mouse_set(x, y, 1); -+ } -+} -diff --git a/hw/qxl.c b/hw/qxl.c -new file mode 100644 -index 0000000..475360c ---- /dev/null -+++ b/hw/qxl.c -@@ -0,0 +1,1411 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "qemu-common.h" -+#include "qemu-timer.h" -+#include "qemu-queue.h" -+#include "monitor.h" -+#include "sysemu.h" -+ -+#include "qxl.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 PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" -+ -+#define QXL_MODE(_x, _y, _b, _o) \ -+ { .x_res = _x, \ -+ .y_res = _y, \ -+ .bits = _b, \ -+ .stride = (_x) * (_b) / 8, \ -+ .x_mili = PIXEL_SIZE * (_x), \ -+ .y_mili = PIXEL_SIZE * (_y), \ -+ .orientation = _o, \ -+ } -+ -+#define QXL_MODE_16_32(x_res, y_res, orientation) \ -+ QXL_MODE(x_res, y_res, 16, orientation), \ -+ QXL_MODE(x_res, y_res, 32, orientation) -+ -+#define QXL_MODE_EX(x_res, y_res) \ -+ QXL_MODE_16_32(x_res, y_res, 0), \ -+ QXL_MODE_16_32(y_res, x_res, 1), \ -+ QXL_MODE_16_32(x_res, y_res, 2), \ -+ QXL_MODE_16_32(y_res, x_res, 3) -+ -+static QXLMode qxl_modes[] = { -+ QXL_MODE_EX(640, 480), -+ QXL_MODE_EX(800, 600), -+ QXL_MODE_EX(832, 624), -+ QXL_MODE_EX(1024, 768), -+ QXL_MODE_EX(1152, 864), -+ QXL_MODE_EX(1152, 870), -+ QXL_MODE_EX(1280, 720), -+ QXL_MODE_EX(1280, 768), -+ QXL_MODE_EX(1280, 800), -+ QXL_MODE_EX(1280, 960), -+ QXL_MODE_EX(1280, 1024), -+ QXL_MODE_EX(1360, 768), -+ QXL_MODE_EX(1366, 768), -+ QXL_MODE_EX(1400, 1050), -+ QXL_MODE_EX(1440, 900), -+ QXL_MODE_EX(1600, 900), -+ QXL_MODE_EX(1600, 1200), -+ QXL_MODE_EX(1680, 1050), -+ QXL_MODE_EX(1920, 1080), -+#ifdef QXL_HIRES_MODES -+ QXL_MODE_EX(1920, 1200), -+ QXL_MODE_EX(1920, 1440), -+ QXL_MODE_EX(2048, 1536), -+ QXL_MODE_EX(2560, 1600), -+ QXL_MODE_EX(2560, 2048), -+ QXL_MODE_EX(2800, 2100), -+ QXL_MODE_EX(3200, 2400), -+#endif -+}; -+ -+static int device_id = 0; -+static PCIQXLDevice *qxl0; -+ -+static void qxl_send_events(PCIQXLDevice *d, uint32_t events); -+static void qxl_destroy_primary(PCIQXLDevice *d); -+static void qxl_reset_memslots(PCIQXLDevice *d); -+static void qxl_reset_surfaces(PCIQXLDevice *d); -+static void qxl_ring_set_dirty(PCIQXLDevice *qxl); -+ -+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 ram_addr_t qxl_rom_size(void) -+{ -+ uint32_t rom_size = sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes); -+ rom_size = MAX(rom_size, TARGET_PAGE_SIZE); -+ rom_size = msb_mask(rom_size * 2 - 1); -+ return rom_size; -+} -+ -+static void init_qxl_rom(PCIQXLDevice *d) -+{ -+ QXLRom *rom = qemu_get_ram_ptr(d->rom_offset); -+ QXLModes *modes = (QXLModes *)(rom + 1); -+ uint32_t ram_header_size; -+ uint32_t surface0_area_size; -+ uint32_t num_pages; -+ uint32_t fb, maxfb = 0; -+ int i; -+ -+ memset(rom, 0, d->rom_size); -+ -+ rom->magic = cpu_to_le32(QXL_ROM_MAGIC); -+ rom->id = cpu_to_le32(d->id); -+ rom->modes_offset = cpu_to_le32(sizeof(QXLRom)); -+ -+ rom->slot_gen_bits = MEMSLOT_GENERATION_BITS; -+ rom->slot_id_bits = MEMSLOT_SLOT_BITS; -+ rom->slots_start = 1; -+ rom->slots_end = NUM_MEMSLOTS - 1; -+ rom->n_surfaces = cpu_to_le32(NUM_SURFACES); -+ -+ modes->n_modes = cpu_to_le32(ARRAY_SIZE(qxl_modes)); -+ for (i = 0; i < modes->n_modes; i++) { -+ fb = qxl_modes[i].y_res * qxl_modes[i].stride; -+ if (maxfb < fb) -+ maxfb = fb; -+ modes->modes[i].id = cpu_to_le32(i); -+ modes->modes[i].x_res = cpu_to_le32(qxl_modes[i].x_res); -+ modes->modes[i].y_res = cpu_to_le32(qxl_modes[i].y_res); -+ modes->modes[i].bits = cpu_to_le32(qxl_modes[i].bits); -+ modes->modes[i].stride = cpu_to_le32(qxl_modes[i].stride); -+ modes->modes[i].x_mili = cpu_to_le32(qxl_modes[i].x_mili); -+ modes->modes[i].y_mili = cpu_to_le32(qxl_modes[i].y_mili); -+ modes->modes[i].orientation = cpu_to_le32(qxl_modes[i].orientation); -+ } -+ if (maxfb < VGA_RAM_SIZE && d->id == 0) -+ maxfb = VGA_RAM_SIZE; -+ -+ ram_header_size = ALIGN(sizeof(QXLRam), 4096); -+ surface0_area_size = ALIGN(maxfb, 4096); -+ num_pages = d->vga.vram_size; -+ num_pages -= ram_header_size; -+ num_pages -= surface0_area_size; -+ num_pages = num_pages / TARGET_PAGE_SIZE; -+ -+ rom->draw_area_offset = cpu_to_le32(0); -+ rom->surface0_area_size = cpu_to_le32(surface0_area_size); -+ rom->pages_offset = cpu_to_le32(surface0_area_size); -+ rom->num_pages = cpu_to_le32(num_pages); -+ rom->ram_header_offset = cpu_to_le32(d->vga.vram_size - ram_header_size); -+ -+ d->shadow_rom = *rom; -+ d->rom = rom; -+ d->modes = modes; -+} -+ -+static void init_qxl_ram(PCIQXLDevice *d) -+{ -+ uint8_t *buf; -+ uint64_t *item; -+ -+ buf = d->vga.vram_ptr; -+ d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset)); -+ d->ram->magic = cpu_to_le32(QXL_RAM_MAGIC); -+ d->ram->int_pending = cpu_to_le32(0); -+ d->ram->int_mask = cpu_to_le32(0); -+ SPICE_RING_INIT(&d->ram->cmd_ring); -+ SPICE_RING_INIT(&d->ram->cursor_ring); -+ SPICE_RING_INIT(&d->ram->release_ring); -+ SPICE_RING_PROD_ITEM(&d->ram->release_ring, item); -+ *item = 0; -+ qxl_ring_set_dirty(d); -+} -+ -+static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end) -+{ -+ while (addr < end) { -+ cpu_physical_memory_set_dirty(addr); -+ addr += TARGET_PAGE_SIZE; -+ } -+} -+ -+static void qxl_rom_set_dirty(PCIQXLDevice *qxl) -+{ -+ ram_addr_t addr = qxl->rom_offset; -+ qxl_set_dirty(addr, addr + qxl->rom_size); -+} -+ -+static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr) -+{ -+ ram_addr_t addr = qxl->vga.vram_offset; -+ void *base = qxl->vga.vram_ptr; -+ intptr_t offset; -+ -+ offset = ptr - base; -+ offset &= ~(TARGET_PAGE_SIZE-1); -+ assert(offset < qxl->vga.vram_size); -+ qxl_set_dirty(addr + offset, addr + offset + TARGET_PAGE_SIZE); -+} -+ -+static void qxl_ring_set_dirty(PCIQXLDevice *qxl) -+{ -+ ram_addr_t addr = qxl->vga.vram_offset + qxl->shadow_rom.ram_header_offset; -+ ram_addr_t end = qxl->vga.vram_offset + qxl->vga.vram_size; -+ qxl_set_dirty(addr, end); -+} -+ -+/* -+ * keep track of some command state, for savevm/loadvm. -+ */ -+static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) -+{ -+ switch (le32_to_cpu(ext->cmd.type)) { -+ case QXL_CMD_SURFACE: -+ { -+ QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); -+ uint32_t id = le32_to_cpu(cmd->surface_id); -+ PANIC_ON(id >= NUM_SURFACES); -+ if (cmd->type == QXL_SURFACE_CMD_CREATE) { -+ qxl->guest_surfaces.cmds[id] = ext->cmd.data; -+ qxl->guest_surfaces.count++; -+ if (qxl->guest_surfaces.max < qxl->guest_surfaces.count) -+ qxl->guest_surfaces.max = qxl->guest_surfaces.count; -+ } -+ if (cmd->type == QXL_SURFACE_CMD_DESTROY) { -+ qxl->guest_surfaces.cmds[id] = 0; -+ qxl->guest_surfaces.count--; -+ } -+ break; -+ } -+ case QXL_CMD_CURSOR: -+ { -+ QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); -+ if (cmd->type == QXL_CURSOR_SET) { -+ qxl->guest_cursor = ext->cmd.data; -+ } -+ break; -+ } -+ } -+} -+ -+/* spice display interface callbacks */ -+ -+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ -+ dprintf(qxl, 1, "%s:\n", __FUNCTION__); -+ qxl->ssd.worker = qxl_worker; -+} -+ -+static void interface_set_compression_level(QXLInstance *sin, int level) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ -+ dprintf(qxl, 1, "%s: %d\n", __FUNCTION__, level); -+ qxl->shadow_rom.compression_level = cpu_to_le32(level); -+ qxl->rom->compression_level = cpu_to_le32(level); -+ qxl_rom_set_dirty(qxl); -+} -+ -+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ -+ qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time); -+ qxl->rom->mm_clock = cpu_to_le32(mm_time); -+ qxl_rom_set_dirty(qxl); -+} -+ -+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ -+ dprintf(qxl, 1, "%s:\n", __FUNCTION__); -+ 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 = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS; -+ info->n_surfaces = NUM_SURFACES; -+} -+ -+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; -+ -+ switch (qxl->mode) { -+ case QXL_MODE_VGA: -+ dprintf(qxl, 2, "%s: vga\n", __FUNCTION__); -+ update = qemu_spice_create_update(&qxl->ssd); -+ if (update == NULL) { -+ return false; -+ } -+ *ext = update->ext; -+ qxl_log_command(qxl, "vga", ext); -+ return true; -+ case QXL_MODE_COMPAT: -+ case QXL_MODE_NATIVE: -+ case QXL_MODE_UNDEFINED: -+ dprintf(qxl, 2, "%s: %s\n", __FUNCTION__, -+ qxl->cmdflags ? "compat" : "native"); -+ ring = &qxl->ram->cmd_ring; -+ if (SPICE_RING_IS_EMPTY(ring)) { -+ return false; -+ } -+ SPICE_RING_CONS_ITEM(ring, cmd); -+ ext->cmd = *cmd; -+ ext->group_id = MEMSLOT_GROUP_GUEST; -+ ext->flags = qxl->cmdflags; -+ SPICE_RING_POP(ring, notify); -+ qxl_ring_set_dirty(qxl); -+ if (notify) { -+ qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY); -+ } -+ qxl->guest_primary.commands++; -+ qxl_track_command(qxl, ext); -+ qxl_log_command(qxl, "cmd", ext); -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static int interface_req_cmd_notification(QXLInstance *sin) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ int wait = 1; -+ -+ switch (qxl->mode) { -+ case QXL_MODE_COMPAT: -+ case QXL_MODE_NATIVE: -+ case QXL_MODE_UNDEFINED: -+ SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait); -+ qxl_ring_set_dirty(qxl); -+ break; -+ default: -+ /* nothing */ -+ break; -+ } -+ return wait; -+} -+ -+static inline void qxl_push_free_res(PCIQXLDevice *d) -+{ -+ QXLReleaseRing *ring = &d->ram->release_ring; -+ uint64_t *item; -+ -+#define QXL_FREE_BUNCH_SIZE 10 -+ -+ if (SPICE_RING_IS_EMPTY(ring) || (d->num_free_res == QXL_FREE_BUNCH_SIZE && -+ ring->prod - ring->cons + 1 != ring->num_items)) { -+ int notify; -+ -+ SPICE_RING_PUSH(ring, notify); -+ if (notify) { -+ qxl_send_events(d, QXL_INTERRUPT_DISPLAY); -+ } -+ SPICE_RING_PROD_ITEM(ring, item); -+ *item = 0; -+ d->num_free_res = 0; -+ d->last_release = NULL; -+ qxl_ring_set_dirty(d); -+ } -+} -+ -+static void interface_release_resource(QXLInstance *sin, -+ struct QXLReleaseInfoExt ext) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ QXLReleaseRing *ring; -+ uint64_t *item, id; -+ -+ if (ext.group_id == MEMSLOT_GROUP_HOST) { -+ /* host group -> vga mode update request */ -+ qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id); -+ return; -+ } -+ -+ /* -+ * ext->info points into guest-visible memory -+ * pci bar 0, $command.release_info -+ */ -+ ring = &qxl->ram->release_ring; -+ SPICE_RING_PROD_ITEM(ring, item); -+ if (*item == 0) { -+ /* stick head into the ring */ -+ id = ext.info->id; -+ ext.info->next = 0; -+ qxl_ram_set_dirty(qxl, &ext.info->next); -+ *item = id; -+ qxl_ring_set_dirty(qxl); -+ } else { -+ /* append item to the list */ -+ qxl->last_release->next = ext.info->id; -+ qxl_ram_set_dirty(qxl, &qxl->last_release->next); -+ ext.info->next = 0; -+ qxl_ram_set_dirty(qxl, &ext.info->next); -+ } -+ qxl->last_release = ext.info; -+ qxl->num_free_res++; -+ qxl_push_free_res(qxl); -+} -+ -+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ QXLCursorRing *ring; -+ QXLCommand *cmd; -+ int notify; -+ -+ switch (qxl->mode) { -+ case QXL_MODE_COMPAT: -+ case QXL_MODE_NATIVE: -+ case QXL_MODE_UNDEFINED: -+ ring = &qxl->ram->cursor_ring; -+ if (SPICE_RING_IS_EMPTY(ring)) { -+ return false; -+ } -+ SPICE_RING_CONS_ITEM(ring, cmd); -+ ext->cmd = *cmd; -+ ext->group_id = MEMSLOT_GROUP_GUEST; -+ ext->flags = qxl->cmdflags; -+ SPICE_RING_POP(ring, notify); -+ qxl_ring_set_dirty(qxl); -+ if (notify) { -+ qxl_send_events(qxl, QXL_INTERRUPT_CURSOR); -+ } -+ qxl->guest_primary.commands++; -+ qxl_track_command(qxl, ext); -+ qxl_log_command(qxl, "csr", ext); -+ if (qxl->id == 0) { -+ qxl_render_cursor(qxl, ext); -+ } -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static int interface_req_cursor_notification(QXLInstance *sin) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ int wait = 1; -+ -+ switch (qxl->mode) { -+ case QXL_MODE_COMPAT: -+ case QXL_MODE_NATIVE: -+ case QXL_MODE_UNDEFINED: -+ SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait); -+ qxl_ring_set_dirty(qxl); -+ break; -+ default: -+ /* nothing */ -+ break; -+ } -+ return wait; -+} -+ -+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) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ int ret; -+ -+ ret = qxl->num_free_res; -+ if (ret) { -+ qxl_push_free_res(qxl); -+ } -+ return ret; -+} -+ -+static const QXLInterface qxl_interface = { -+ .base.type = SPICE_INTERFACE_QXL, -+ .base.description = "qxl gpu", -+ .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 void qxl_enter_vga_mode(PCIQXLDevice *d) -+{ -+ if (d->mode == QXL_MODE_VGA) { -+ return; -+ } -+ dprintf(d, 1, "%s\n", __FUNCTION__); -+ qemu_spice_create_host_primary(&d->ssd); -+ d->mode = QXL_MODE_VGA; -+ memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); -+} -+ -+static void qxl_exit_vga_mode(PCIQXLDevice *d) -+{ -+ if (d->mode != QXL_MODE_VGA) { -+ return; -+ } -+ dprintf(d, 1, "%s\n", __FUNCTION__); -+ qxl_destroy_primary(d); -+} -+ -+static void qxl_set_irq(PCIQXLDevice *d) -+{ -+ uint32_t pending = le32_to_cpu(d->ram->int_pending); -+ uint32_t mask = le32_to_cpu(d->ram->int_mask); -+ int level = !!(pending & mask); -+ qemu_set_irq(d->pci.irq[0], level); -+ qxl_ring_set_dirty(d); -+} -+ -+static void qxl_write_config(PCIDevice *d, uint32_t address, -+ uint32_t val, int len) -+{ -+ PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, d); -+ VGACommonState *vga = &qxl->vga; -+ -+ if (qxl->id == 0) { -+ vga_dirty_log_stop(vga); -+ } -+ pci_default_write_config(d, address, val, len); -+ if (qxl->id == 0) { -+ if (vga->map_addr && qxl->pci.io_regions[0].addr == -1) -+ vga->map_addr = 0; -+ vga_dirty_log_start(vga); -+ } -+} -+ -+static void qxl_check_state(PCIQXLDevice *d) -+{ -+ QXLRam *ram = d->ram; -+ -+ assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring)); -+ assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring)); -+} -+ -+static void qxl_reset_state(PCIQXLDevice *d) -+{ -+ QXLRam *ram = d->ram; -+ QXLRom *rom = d->rom; -+ -+ assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring)); -+ assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring)); -+ d->shadow_rom.update_id = cpu_to_le32(0); -+ *rom = d->shadow_rom; -+ qxl_rom_set_dirty(d); -+ init_qxl_ram(d); -+ d->num_free_res = 0; -+ d->last_release = NULL; -+ memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); -+} -+ -+static void qxl_soft_reset(PCIQXLDevice *d) -+{ -+ dprintf(d, 1, "%s:\n", __FUNCTION__); -+ qxl_check_state(d); -+ -+ if (d->id == 0) { -+ qxl_enter_vga_mode(d); -+ } else { -+ d->mode = QXL_MODE_UNDEFINED; -+ } -+} -+ -+static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) -+{ -+ dprintf(d, 1, "%s: start%s\n", __FUNCTION__, -+ loadvm ? " (loadvm)" : ""); -+ -+ d->ssd.worker->reset_cursor(d->ssd.worker); -+ d->ssd.worker->reset_image_cache(d->ssd.worker); -+ qxl_reset_surfaces(d); -+ qxl_reset_memslots(d); -+ -+ /* pre loadvm reset must not touch QXLRam. This lives in -+ * device memory, is migrated together with RAM and thus -+ * already loaded at this point */ -+ if (!loadvm) { -+ qxl_reset_state(d); -+ } -+ qemu_spice_create_host_memslot(&d->ssd); -+ qxl_soft_reset(d); -+ -+ dprintf(d, 1, "%s: done\n", __FUNCTION__); -+} -+ -+static void qxl_reset_handler(DeviceState *dev) -+{ -+ PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev); -+ qxl_hard_reset(d, 0); -+} -+ -+static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) -+{ -+ VGACommonState *vga = opaque; -+ PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga); -+ -+ if (qxl->mode != QXL_MODE_VGA) { -+ dprintf(qxl, 1, "%s\n", __FUNCTION__); -+ qxl_destroy_primary(qxl); -+ qxl_soft_reset(qxl); -+ } -+ vga_ioport_write(opaque, addr, val); -+} -+ -+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) -+{ -+ static const int regions[] = { -+ QXL_RAM_RANGE_INDEX, -+ QXL_VRAM_RANGE_INDEX, -+ }; -+ uint64_t guest_start; -+ uint64_t guest_end; -+ int pci_region; -+ pcibus_t pci_start; -+ pcibus_t pci_end; -+ intptr_t virt_start; -+ QXLDevMemSlot memslot; -+ int i; -+ -+ guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start); -+ guest_end = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end); -+ -+ dprintf(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n", -+ __FUNCTION__, slot_id, -+ guest_start, guest_end); -+ -+ PANIC_ON(slot_id >= NUM_MEMSLOTS); -+ PANIC_ON(guest_start > guest_end); -+ -+ for (i = 0; i < ARRAY_SIZE(regions); i++) { -+ pci_region = regions[i]; -+ pci_start = d->pci.io_regions[pci_region].addr; -+ pci_end = pci_start + d->pci.io_regions[pci_region].size; -+ /* mapped? */ -+ if (pci_start == -1) { -+ continue; -+ } -+ /* start address in range ? */ -+ if (guest_start < pci_start || guest_start > pci_end) { -+ continue; -+ } -+ /* end address in range ? */ -+ if (guest_end > pci_end) { -+ continue; -+ } -+ /* passed */ -+ break; -+ } -+ PANIC_ON(i == ARRAY_SIZE(regions)); /* finished loop without match */ -+ -+ switch (pci_region) { -+ case QXL_RAM_RANGE_INDEX: -+ virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset); -+ break; -+ case QXL_VRAM_RANGE_INDEX: -+ virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset); -+ break; -+ default: -+ /* should not happen */ -+ abort(); -+ } -+ -+ memslot.slot_id = slot_id; -+ memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */ -+ memslot.virt_start = virt_start + (guest_start - pci_start); -+ memslot.virt_end = virt_start + (guest_end - pci_start); -+ memslot.addr_delta = memslot.virt_start - delta; -+ memslot.generation = d->rom->slot_generation = 0; // FIXME d->generation++; -+ qxl_rom_set_dirty(d); -+ -+ dprintf(d, 1, "%s: slot %d: host virt 0x%" PRIx64 " - 0x%" PRIx64 "\n", -+ __FUNCTION__, memslot.slot_id, -+ memslot.virt_start, memslot.virt_end); -+ -+ d->ssd.worker->add_memslot(d->ssd.worker, &memslot); -+ d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; -+ d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; -+ d->guest_slots[slot_id].delta = delta; -+ d->guest_slots[slot_id].active = 1; -+} -+ -+static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) -+{ -+ dprintf(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id); -+ d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id); -+ d->guest_slots[slot_id].active = 0; -+} -+ -+static void qxl_reset_memslots(PCIQXLDevice *d) -+{ -+ dprintf(d, 1, "%s:\n", __FUNCTION__); -+ d->ssd.worker->reset_memslots(d->ssd.worker); -+ memset(&d->guest_slots, 0, sizeof(d->guest_slots)); -+} -+ -+static void qxl_reset_surfaces(PCIQXLDevice *d) -+{ -+ dprintf(d, 1, "%s:\n", __FUNCTION__); -+ d->mode = QXL_MODE_UNDEFINED; -+ d->ssd.worker->destroy_surfaces(d->ssd.worker); -+ memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); -+} -+ -+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) -+{ -+ uint64_t phys = le64_to_cpu(pqxl); -+ uint32_t slot = (phys >> (64 - 8)) & 0xff; -+ uint64_t offset = phys & 0xffffffffffff; -+ -+ switch (group_id) { -+ case MEMSLOT_GROUP_HOST: -+ return (void*)offset; -+ case MEMSLOT_GROUP_GUEST: -+ PANIC_ON(slot > NUM_MEMSLOTS); -+ PANIC_ON(!qxl->guest_slots[slot].active); -+ PANIC_ON(offset < qxl->guest_slots[slot].delta); -+ offset -= qxl->guest_slots[slot].delta; -+ PANIC_ON(offset > qxl->guest_slots[slot].size) -+ return qxl->guest_slots[slot].ptr + offset; -+ default: -+ PANIC_ON(1); -+ } -+} -+ -+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) -+{ -+ QXLDevSurfaceCreate surface; -+ QXLSurfaceCreate *sc = &qxl->guest_primary.surface; -+ -+ assert(qxl->mode != QXL_MODE_NATIVE); -+ qxl_exit_vga_mode(qxl); -+ -+ dprintf(qxl, 1, "%s: %dx%d\n", __FUNCTION__, -+ le32_to_cpu(sc->width), le32_to_cpu(sc->height)); -+ -+ surface.format = le32_to_cpu(sc->format); -+ surface.height = le32_to_cpu(sc->height); -+ surface.mem = le64_to_cpu(sc->mem); -+ surface.position = le32_to_cpu(sc->position); -+ surface.stride = le32_to_cpu(sc->stride); -+ surface.width = le32_to_cpu(sc->width); -+ surface.type = le32_to_cpu(sc->type); -+ surface.flags = le32_to_cpu(sc->flags); -+ -+ surface.mouse_mode = true; -+ surface.group_id = MEMSLOT_GROUP_GUEST; -+ if (loadvm) { -+ surface.flags |= QXL_SURF_FLAG_KEEP_DATA; -+ } -+ -+ qxl->mode = QXL_MODE_NATIVE; -+ qxl->cmdflags = 0; -+ qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface); -+ -+ /* for local rendering */ -+ qxl_render_resize(qxl); -+} -+ -+static void qxl_destroy_primary(PCIQXLDevice *d) -+{ -+ if (d->mode == QXL_MODE_UNDEFINED) { -+ return; -+ } -+ -+ dprintf(d, 1, "%s\n", __FUNCTION__); -+ -+ d->mode = QXL_MODE_UNDEFINED; -+ d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0); -+} -+ -+static void qxl_set_mode(PCIQXLDevice *d, int modenr) -+{ -+ pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr; -+ pcibus_t end = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start; -+ QXLMode *mode = d->modes->modes + modenr; -+ uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr; -+ QXLMemSlot slot = { -+ .mem_start = start, -+ .mem_end = end -+ }; -+ QXLSurfaceCreate surface = { -+ .width = mode->x_res, -+ .height = mode->y_res, -+ .stride = -mode->x_res * 4, -+ .format = SPICE_SURFACE_FMT_32_xRGB, -+ .mouse_mode = true, -+ .mem = devmem, -+ }; -+ -+ dprintf(d, 1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%lx ]\n", __FUNCTION__, -+ modenr, mode->x_res, mode->y_res, mode->bits, devmem); -+ qxl_hard_reset(d, 0); -+ -+ d->guest_slots[0].slot = slot; -+ qxl_add_memslot(d, 0, devmem); -+ -+ d->guest_primary.surface = surface; -+ qxl_create_guest_primary(d, 0); -+ -+ d->mode = QXL_MODE_COMPAT; -+ d->cmdflags = QXL_COMMAND_FLAG_COMPAT; -+ d->shadow_rom.mode = cpu_to_le32(modenr); -+ d->rom->mode = cpu_to_le32(modenr); -+ qxl_rom_set_dirty(d); -+} -+ -+static void ioport_write(void *opaque, uint32_t addr, uint32_t val) -+{ -+ PCIQXLDevice *d = opaque; -+ uint32_t io_port = addr - d->io_base; -+ -+ switch (io_port) { -+ case QXL_IO_RESET: -+ case QXL_IO_SET_MODE: -+ case QXL_IO_MEMSLOT_ADD: -+ case QXL_IO_MEMSLOT_DEL: -+ case QXL_IO_CREATE_PRIMARY: -+ break; -+ default: -+ if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT) -+ break; -+ dprintf(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port); -+ return; -+ } -+ -+ switch (io_port) { -+ case QXL_IO_UPDATE_AREA: -+ { -+ QXLRect update = d->ram->update_area; -+ d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface, -+ &update, NULL, 0, 0); -+ break; -+ } -+ case QXL_IO_NOTIFY_CMD: -+ d->ssd.worker->wakeup(d->ssd.worker); -+ break; -+ case QXL_IO_NOTIFY_CURSOR: -+ d->ssd.worker->wakeup(d->ssd.worker); -+ break; -+ case QXL_IO_UPDATE_IRQ: -+ qxl_set_irq(d); -+ break; -+ case QXL_IO_NOTIFY_OOM: -+ if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) { -+ break; -+ } -+ pthread_yield(); -+ if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) { -+ break; -+ } -+ d->ssd.worker->oom(d->ssd.worker); -+ break; -+ case QXL_IO_SET_MODE: -+ dprintf(d, 1, "QXL_SET_MODE %d\n", val); -+ qxl_set_mode(d, val); -+ break; -+ case QXL_IO_LOG: -+ dprintf(d, 1, "log %s", d->ram->log_buf); -+ break; -+ case QXL_IO_RESET: -+ dprintf(d, 1, "QXL_IO_RESET\n"); -+ qxl_hard_reset(d, 0); -+ break; -+ case QXL_IO_MEMSLOT_ADD: -+ PANIC_ON(val >= NUM_MEMSLOTS); -+ PANIC_ON(d->guest_slots[val].active); -+ d->guest_slots[val].slot = d->ram->mem_slot; -+ qxl_add_memslot(d, val, 0); -+ break; -+ case QXL_IO_MEMSLOT_DEL: -+ qxl_del_memslot(d, val); -+ break; -+ case QXL_IO_CREATE_PRIMARY: -+ PANIC_ON(val != 0); -+ dprintf(d, 1, "QXL_IO_CREATE_PRIMARY\n"); -+ d->guest_primary.surface = d->ram->create_surface; -+ qxl_create_guest_primary(d, 0); -+ break; -+ case QXL_IO_DESTROY_PRIMARY: -+ PANIC_ON(val != 0); -+ dprintf(d, 1, "QXL_IO_DESTROY_PRIMARY\n"); -+ qxl_destroy_primary(d); -+ break; -+ case QXL_IO_DESTROY_SURFACE_WAIT: -+ d->ssd.worker->destroy_surface_wait(d->ssd.worker, val); -+ break; -+ default: -+ fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); -+ abort(); -+ } -+} -+ -+static uint32_t ioport_read(void *opaque, uint32_t addr) -+{ -+ PCIQXLDevice *d = opaque; -+ -+ dprintf(d, 1, "%s: unexpected\n", __FUNCTION__); -+ return 0xff; -+} -+ -+static void qxl_map(PCIDevice *pci, int region_num, -+ pcibus_t addr, pcibus_t size, int type) -+{ -+ static const char *names[] = { -+ [ QXL_IO_RANGE_INDEX ] = "ioports", -+ [ QXL_RAM_RANGE_INDEX ] = "devram", -+ [ QXL_ROM_RANGE_INDEX ] = "rom", -+ [ QXL_VRAM_RANGE_INDEX ] = "vram", -+ }; -+ PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci); -+ -+ dprintf(qxl, 1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__, -+ region_num, names[region_num], addr, size); -+ -+ switch (region_num) { -+ case QXL_IO_RANGE_INDEX: -+ register_ioport_write(addr, size, 1, ioport_write, pci); -+ register_ioport_read(addr, size, 1, ioport_read, pci); -+ qxl->io_base = addr; -+ break; -+ case QXL_RAM_RANGE_INDEX: -+ cpu_register_physical_memory(addr, size, qxl->vga.vram_offset | IO_MEM_RAM); -+ qxl->vga.map_addr = addr; -+ qxl->vga.map_end = addr + size; -+ if (qxl->id == 0) { -+ vga_dirty_log_start(&qxl->vga); -+ } -+ break; -+ case QXL_ROM_RANGE_INDEX: -+ cpu_register_physical_memory(addr, size, qxl->rom_offset | IO_MEM_ROM); -+ break; -+ case QXL_VRAM_RANGE_INDEX: -+ cpu_register_physical_memory(addr, size, qxl->vram_offset | IO_MEM_RAM); -+ break; -+ } -+} -+ -+static void pipe_read(void *opaque) -+{ -+ PCIQXLDevice *d = opaque; -+ char dummy; -+ int len; -+ -+ do { -+ len = read(d->pipe[0], &dummy, sizeof(dummy)); -+ } while (len == sizeof(dummy)); -+ qxl_set_irq(d); -+} -+ -+static void qxl_send_events(PCIQXLDevice *d, uint32_t events) -+{ -+ uint32_t old_pending; -+ uint32_t le_events = cpu_to_le32(events); -+ -+ assert(d->ssd.running); -+ old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); -+ if ((old_pending & le_events) == le_events) { -+ return; -+ } -+ if (pthread_self() == d->main) { -+ qxl_set_irq(d); -+ } else { -+ if (write(d->pipe[1], d, 1) != 1) { -+ dprintf(d, 1, "%s: write to pipe failed\n", __FUNCTION__); -+ } -+ } -+} -+ -+static void init_pipe_signaling(PCIQXLDevice *d) -+{ -+ if (pipe(d->pipe) < 0) { -+ dprintf(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); -+} -+ -+/* graphics console */ -+ -+static void qxl_hw_update(void *opaque) -+{ -+ PCIQXLDevice *qxl = opaque; -+ VGACommonState *vga = &qxl->vga; -+ -+ switch (qxl->mode) { -+ case QXL_MODE_VGA: -+ vga->update(vga); -+ break; -+ case QXL_MODE_NATIVE: -+ qxl_render_update(qxl); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void qxl_hw_invalidate(void *opaque) -+{ -+ PCIQXLDevice *qxl = opaque; -+ VGACommonState *vga = &qxl->vga; -+ -+ vga->invalidate(vga); -+} -+ -+static void qxl_hw_screen_dump(void *opaque, const char *filename) -+{ -+ PCIQXLDevice *qxl = opaque; -+ VGACommonState *vga = &qxl->vga; -+ -+ if (qxl->mode == QXL_MODE_VGA) { -+ vga->screen_dump(vga, filename); -+ return; -+ } -+} -+ -+static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) -+{ -+ PCIQXLDevice *qxl = opaque; -+ VGACommonState *vga = &qxl->vga; -+ -+ if (qxl->mode == QXL_MODE_VGA) { -+ vga->text_update(vga, chardata); -+ return; -+ } -+} -+ -+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); -+} -+ -+/* display change listener */ -+ -+static void display_update(struct DisplayState *ds, int x, int y, int w, int h) -+{ -+ if (qxl0->mode == QXL_MODE_VGA) { -+ qemu_spice_display_update(&qxl0->ssd, x, y, w, h); -+ } -+} -+ -+static void display_resize(struct DisplayState *ds) -+{ -+ if (qxl0->mode == QXL_MODE_VGA) { -+ qemu_spice_display_resize(&qxl0->ssd); -+ } -+} -+ -+static void display_refresh(struct DisplayState *ds) -+{ -+ if (qxl0->mode == QXL_MODE_VGA) { -+ qemu_spice_display_refresh(&qxl0->ssd); -+ } -+} -+ -+static DisplayChangeListener display_listener = { -+ .dpy_update = display_update, -+ .dpy_resize = display_resize, -+ .dpy_refresh = display_refresh, -+}; -+ -+static int qxl_init(PCIDevice *dev) -+{ -+ PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); -+ VGACommonState *vga = &qxl->vga; -+ uint8_t* config = qxl->pci.config; -+ ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); -+ uint32_t pci_device_id; -+ uint32_t pci_device_rev; -+ -+ if (device_id == 0 && dev->qdev.hotplugged) { -+ device_id++; -+ } -+ -+ qxl->id = device_id; -+ qxl->mode = QXL_MODE_UNDEFINED; -+ qxl->generation = 1; -+ -+ switch (qxl->revision) { -+ case 1: /* qxl-1 */ -+ pci_device_id = 0x0100; -+ pci_device_rev = 1; -+ break; -+ case 2: /* qxl-2 */ -+ pci_device_id = 0x0100; -+ pci_device_rev = 2; -+ break; -+ default: /* unstable */ -+ pci_device_id = 0x01ff; -+ pci_device_rev = 1; -+ break; -+ } -+ -+ if (!qxl->id) { -+ if (ram_size < 32 * 1024 * 1024) -+ ram_size = 32 * 1024 * 1024; -+ vga_common_init(vga, ram_size); -+ vga_init(vga); -+ register_ioport_write(0x3c0, 16, 1, qxl_vga_ioport_write, vga); -+ register_ioport_write(0x3b4, 2, 1, qxl_vga_ioport_write, vga); -+ register_ioport_write(0x3d4, 2, 1, qxl_vga_ioport_write, vga); -+ register_ioport_write(0x3ba, 1, 1, qxl_vga_ioport_write, vga); -+ register_ioport_write(0x3da, 1, 1, qxl_vga_ioport_write, vga); -+ -+ vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, -+ qxl_hw_screen_dump, qxl_hw_text_update, qxl); -+ qxl->ssd.ds = vga->ds; -+ qxl->ssd.bufsize = (16 * 1024 * 1024); -+ qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize); -+ pthread_mutex_init(&qxl->ssd.lock, NULL); -+ -+ qxl0 = qxl; -+ register_displaychangelistener(vga->ds, &display_listener); -+ -+ if (qxl->pci.romfile == NULL) { -+ if (pci_device_id == 0x01ff) { -+ qxl->pci.romfile = qemu_strdup("vgabios-qxldev.bin"); -+ } else { -+ qxl->pci.romfile = qemu_strdup("vgabios-qxl.bin"); -+ } -+ } -+ pci_config_set_class(config, PCI_CLASS_DISPLAY_VGA); -+ } else { -+ 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_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset); -+ -+ pci_config_set_class(config, PCI_CLASS_DISPLAY_OTHER); -+ } -+ -+ pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID); -+ pci_config_set_device_id(config, pci_device_id); -+ pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); -+ 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); -+ 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); -+ -+ pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX, -+ msb_mask(QXL_IO_RANGE_SIZE * 2 - 1), -+ PCI_BASE_ADDRESS_SPACE_IO, qxl_map); -+ -+ pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX, -+ qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY, -+ qxl_map); -+ -+ pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX, -+ qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY, -+ qxl_map); -+ -+ pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size, -+ PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map); -+ -+ qxl->ssd.qxl.base.sif = &qxl_interface.base; -+ qxl->ssd.qxl.id = qxl->id; -+ spice_server_add_interface(spice_server, &qxl->ssd.qxl.base); -+ qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl); -+ -+ init_pipe_signaling(qxl); -+ qxl_reset_state(qxl); -+ -+ device_id++; -+ return 0; -+} -+ -+static void qxl_pre_save(void *opaque) -+{ -+ PCIQXLDevice* d = 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) -+{ -+ PCIQXLDevice* d = opaque; -+ -+ dprintf(d, 1, "%s: start\n", __FUNCTION__); -+ qxl_hard_reset(d, 1); -+ qxl_exit_vga_mode(d); -+ dprintf(d, 1, "%s: done\n", __FUNCTION__); -+ return 0; -+} -+ -+static int qxl_post_load(void *opaque, int version) -+{ -+ PCIQXLDevice* d = opaque; -+ uint8_t *ram_start = d->vga.vram_ptr; -+ QXLCommandExt *cmds; -+ int in, out, i, newmode; -+ -+ dprintf(d, 1, "%s: start\n", __FUNCTION__); -+ newmode = d->mode; -+ d->mode = QXL_MODE_UNDEFINED; -+ switch (newmode) { -+ case QXL_MODE_UNDEFINED: -+ break; -+ case QXL_MODE_VGA: -+ qxl_enter_vga_mode(d); -+ break; -+ case QXL_MODE_NATIVE: -+ for (i = 0; i < NUM_MEMSLOTS; i++) { -+ if (!d->guest_slots[i].active) -+ continue; -+ qxl_add_memslot(d, i, 0); -+ } -+ qxl_create_guest_primary(d, 1); -+ -+ /* replay surface-create and cursor-set commands */ -+ cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); -+ for (in = 0, out = 0; in < NUM_SURFACES; in++) { -+ if (d->guest_surfaces.cmds[in] == 0) -+ continue; -+ cmds[out].cmd.data = d->guest_surfaces.cmds[in]; -+ cmds[out].cmd.type = QXL_CMD_SURFACE; -+ cmds[out].group_id = MEMSLOT_GROUP_GUEST; -+ out++; -+ } -+ cmds[out].cmd.data = d->guest_cursor; -+ cmds[out].cmd.type = QXL_CMD_CURSOR; -+ cmds[out].group_id = MEMSLOT_GROUP_GUEST; -+ out++; -+ d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out); -+ qemu_free(cmds); -+ -+ break; -+ case QXL_MODE_COMPAT: -+ qxl_set_mode(d, d->shadow_rom.mode); -+ break; -+ } -+ 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); -+ } -+ -+ if (d->last_release_offset == 0) { -+ d->last_release = NULL; -+ } else { -+ d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset); -+ } -+#endif -+ -+ return 0; -+} -+ -+#define QXL_VER 1 -+ -+static VMStateDescription qxl_memslot = { -+ .name = "qxl-memslot", -+ .version_id = QXL_VER, -+ .minimum_version_id = QXL_VER, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64(slot.mem_start, struct guest_slots), -+ VMSTATE_UINT64(slot.mem_end, struct guest_slots), -+ VMSTATE_UINT32(active, struct guest_slots), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static VMStateDescription qxl_surface = { -+ .name = "qxl-surface", -+ .version_id = QXL_VER, -+ .minimum_version_id = QXL_VER, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT32(width, QXLSurfaceCreate), -+ VMSTATE_UINT32(height, QXLSurfaceCreate), -+ VMSTATE_INT32(stride, QXLSurfaceCreate), -+ VMSTATE_UINT32(format, QXLSurfaceCreate), -+ VMSTATE_UINT32(position, QXLSurfaceCreate), -+ VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate), -+ VMSTATE_UINT32(flags, QXLSurfaceCreate), -+ VMSTATE_UINT32(type, QXLSurfaceCreate), -+ VMSTATE_UINT64(mem, QXLSurfaceCreate), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static VMStateDescription qxl_vmstate = { -+ .name = "qxl", -+ .version_id = QXL_VER, -+ .minimum_version_id = QXL_VER, -+ .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_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 -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+static PCIDeviceInfo qxl_info = { -+ .qdev.name = "qxl", -+ .qdev.desc = "Spice QXL GPU", -+ .qdev.size = sizeof(PCIQXLDevice), -+ .qdev.reset = qxl_reset_handler, -+ .qdev.vmsd = &qxl_vmstate, -+ .init = qxl_init, -+ .config_write = qxl_write_config, -+ .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("debug", PCIQXLDevice, debug, 0), -+ DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), -+ DEFINE_PROP_END_OF_LIST(), -+ } -+}; -+ -+static void qxl_register(void) -+{ -+ pci_qdev_register(&qxl_info); -+} -+ -+device_init(qxl_register); -diff --git a/hw/qxl.h b/hw/qxl.h -new file mode 100644 -index 0000000..1216405 ---- /dev/null -+++ b/hw/qxl.h -@@ -0,0 +1,102 @@ -+#include "console.h" -+#include "hw.h" -+#include "pci.h" -+#include "vga_int.h" -+ -+#include "qemu-spice.h" -+#include "spice-display.h" -+ -+enum qxl_mode { -+ QXL_MODE_UNDEFINED, -+ QXL_MODE_VGA, -+ QXL_MODE_COMPAT, /* spice 0.4.x */ -+ QXL_MODE_NATIVE, -+}; -+ -+typedef struct PCIQXLDevice { -+ PCIDevice pci; -+ SimpleSpiceDisplay ssd; -+ int id; -+ uint32_t debug; -+ uint32_t cmdlog; -+ enum qxl_mode mode; -+ uint32_t cmdflags; -+ int generation; -+ uint32_t revision; -+ -+ struct guest_slots { -+ QXLMemSlot slot; -+ void *ptr; -+ uint64_t size; -+ uint64_t delta; -+ uint32_t active; -+ } guest_slots[NUM_MEMSLOTS]; -+ -+ struct guest_primary { -+ QXLSurfaceCreate surface; -+ uint32_t commands; -+ uint32_t resized; -+ int32_t stride; -+ uint32_t bits_pp; -+ uint32_t bytes_pp; -+ uint8_t *data, *flipped; -+ } guest_primary; -+ -+ struct surfaces { -+ QXLPHYSICAL cmds[NUM_SURFACES]; -+ uint32_t count; -+ uint32_t max; -+ } guest_surfaces; -+ QXLPHYSICAL guest_cursor; -+ -+ /* thread signaling */ -+ pthread_t main; -+ int pipe[2]; -+ -+ /* ram pci bar */ -+ QXLRam *ram; -+ VGACommonState vga; -+ uint32_t num_free_res; -+ QXLReleaseInfo *last_release; -+ uint32_t last_release_offset; -+ -+ /* rom pci bar */ -+ QXLRom shadow_rom; -+ QXLRom *rom; -+ QXLModes *modes; -+ uint32_t rom_size; -+ uint64_t rom_offset; -+ -+ /* vram pci bar */ -+ uint32_t vram_size; -+ uint64_t vram_offset; -+ -+ /* io bar */ -+ uint32_t io_base; -+ -+} PCIQXLDevice; -+ -+#define PANIC_ON(x) if ((x)) { \ -+ printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \ -+ exit(-1); \ -+} -+ -+#define dprintf(_qxl, _level, _fmt, ...) \ -+ do { \ -+ if (_qxl->debug >= _level) { \ -+ fprintf(stderr, "qxl-%d: ", _qxl->id); \ -+ fprintf(stderr, _fmt, ## __VA_ARGS__); \ -+ } \ -+ } while (0) -+ -+/* qxl.c */ -+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); -+ -+/* qxl-logger.c */ -+void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); -+void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); -+ -+/* qxl-render.c */ -+void qxl_render_resize(PCIQXLDevice *qxl); -+void qxl_render_update(PCIQXLDevice *qxl); -+void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); -diff --git a/hw/vga_int.h b/hw/vga_int.h -index 70e0f19..4a82683 100644 ---- a/hw/vga_int.h -+++ b/hw/vga_int.h -@@ -106,7 +106,7 @@ typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s); - typedef struct VGACommonState { - uint8_t *vram_ptr; - ram_addr_t vram_offset; -- unsigned int vram_size; -+ uint32_t vram_size; - uint32_t lfb_addr; - uint32_t lfb_end; - uint32_t map_addr; -diff --git a/sysemu.h b/sysemu.h -index bf1d68a..ea3634d 100644 ---- a/sysemu.h -+++ b/sysemu.h -@@ -103,7 +103,7 @@ extern int autostart; - extern int bios_size; - - typedef enum { -- VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB -+ VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL, - } VGAInterfaceType; - - extern int vga_interface_type; -@@ -111,6 +111,7 @@ extern int vga_interface_type; - #define std_vga_enabled (vga_interface_type == VGA_STD) - #define xenfb_enabled (vga_interface_type == VGA_XENFB) - #define vmsvga_enabled (vga_interface_type == VGA_VMWARE) -+#define qxl_enabled (vga_interface_type == VGA_QXL) - - extern int graphic_width; - extern int graphic_height; -diff --git a/vl.c b/vl.c -index 2ccebc8..eb630bd 100644 ---- a/vl.c -+++ b/vl.c -@@ -1459,6 +1459,8 @@ static void select_vgahw (const char *p) - vga_interface_type = VGA_VMWARE; - } else if (strstart(p, "xenfb", &opts)) { - vga_interface_type = VGA_XENFB; -+ } else if (strstart(p, "qxl", &opts)) { -+ vga_interface_type = VGA_QXL; - } else if (!strstart(p, "none", &opts)) { - invalid_vga: - fprintf(stderr, "Unknown vga type: %s\n", p); -@@ -3034,7 +3036,7 @@ int main(int argc, char **argv, char **envp) - break; - } - #ifdef CONFIG_SPICE -- if (using_spice) { -+ if (using_spice && !qxl_enabled) { - qemu_spice_display_init(ds); - } - #endif --- -1.7.2.3 - diff --git a/0015-spice-add-audio.patch b/0015-spice-add-audio.patch deleted file mode 100644 index 6725ffe..0000000 --- a/0015-spice-add-audio.patch +++ /dev/null @@ -1,405 +0,0 @@ -From f3e02bc08c4521dc53d858174612341462d588ce Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0016-spice-add-virtio-serial-based-vdi-port-backend.patch b/0016-spice-add-virtio-serial-based-vdi-port-backend.patch deleted file mode 100644 index 91528c9..0000000 --- a/0016-spice-add-virtio-serial-based-vdi-port-backend.patch +++ /dev/null @@ -1,238 +0,0 @@ -From ebf4cebd082442ed2bc11475fde301c18648298d Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 -+#include -+#include -+#include -+ -+#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 - diff --git a/0017-spice-add-pci-vdi-port-backend-obsolete.patch b/0017-spice-add-pci-vdi-port-backend-obsolete.patch deleted file mode 100644 index 6505bb7..0000000 --- a/0017-spice-add-pci-vdi-port-backend-obsolete.patch +++ /dev/null @@ -1,592 +0,0 @@ -From ee782dec6adaced9c5bb99d02253505fb635fa12 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 -+#include -+ -+#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 -+#include -+#include -+#include -+ -+#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 -+ -+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 -+ -+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 - diff --git a/0018-use-memalign-instead-of-posix_memalign.patch b/0018-use-memalign-instead-of-posix_memalign.patch deleted file mode 100644 index d7264c4..0000000 --- a/0018-use-memalign-instead-of-posix_memalign.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 898303cfd535d76ce971f3ac1310696937fbd286 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0019-spice-live-migration-wip.patch b/0019-spice-live-migration-wip.patch deleted file mode 100644 index 4e6ef6b..0000000 --- a/0019-spice-live-migration-wip.patch +++ /dev/null @@ -1,179 +0,0 @@ -From 80b1dac2be1487d31e6766abe2359fcff1bf0481 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0020-spice-display-draw.h-is-internal-now.patch b/0020-spice-display-draw.h-is-internal-now.patch deleted file mode 100644 index e734447..0000000 --- a/0020-spice-display-draw.h-is-internal-now.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 7241cc479a0f4a148ae60336add6d7be80da9ff0 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 --#include -+#include - #include - - #include "pflib.h" --- -1.7.2.3 - diff --git a/0021-spice-display-disable-debug.patch b/0021-spice-display-disable-debug.patch deleted file mode 100644 index bdaee85..0000000 --- a/0021-spice-display-disable-debug.patch +++ /dev/null @@ -1,25 +0,0 @@ -From c269c8b87769b25c9d69d40944de0e883458af86 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0022-spice-display-pci-rev-fixups.patch b/0022-spice-display-pci-rev-fixups.patch deleted file mode 100644 index 87534af..0000000 --- a/0022-spice-display-pci-rev-fixups.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 2912f038b4bfddd4c3dacb3b0102e45553859632 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0023-qxl-pci-rev-fixups.patch b/0023-qxl-pci-rev-fixups.patch deleted file mode 100644 index 5a9fc24..0000000 --- a/0023-qxl-pci-rev-fixups.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 727553e1a33dccab2b27ee5e184e003440765289 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch b/0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch deleted file mode 100644 index 07882f3..0000000 --- a/0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch +++ /dev/null @@ -1,26 +0,0 @@ -From c9f9044475d392e55de4dd6e343477ce1a57eabc Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0025-spice-vmc-two-bugfixes-in-vmc_read.patch b/0025-spice-vmc-two-bugfixes-in-vmc_read.patch deleted file mode 100644 index 3b4178b..0000000 --- a/0025-spice-vmc-two-bugfixes-in-vmc_read.patch +++ /dev/null @@ -1,57 +0,0 @@ -From c8fa37e075cf59e8b21af9211f6a6348c92ed098 Mon Sep 17 00:00:00 2001 -From: Alon Levy -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 - diff --git a/0026-spice-enabling-disabling-jpeg-and-zlib-over-glz-via-.patch b/0026-spice-enabling-disabling-jpeg-and-zlib-over-glz-via-.patch deleted file mode 100644 index 0af9bae..0000000 --- a/0026-spice-enabling-disabling-jpeg-and-zlib-over-glz-via-.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0045574847883167f5c2b569811e049616ee611d Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -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 - diff --git a/0027-ifdef-new-config-options.patch b/0027-ifdef-new-config-options.patch deleted file mode 100644 index 9b185eb..0000000 --- a/0027-ifdef-new-config-options.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 9200133d24ee5b5dab71ce922882c3534d9e8a5a Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0028-spice-vmc-add-counter-to-debug-statements.patch b/0028-spice-vmc-add-counter-to-debug-statements.patch deleted file mode 100644 index 2a3b23c..0000000 --- a/0028-spice-vmc-add-counter-to-debug-statements.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 2165916a311108d39c7aa45e5189af26712234b8 Mon Sep 17 00:00:00 2001 -From: Alon Levy -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 - diff --git a/0029-spice-vmc-split-vmc_write-to-max-sized-virtio_serial.patch b/0029-spice-vmc-split-vmc_write-to-max-sized-virtio_serial.patch deleted file mode 100644 index 0378f1c..0000000 --- a/0029-spice-vmc-split-vmc_write-to-max-sized-virtio_serial.patch +++ /dev/null @@ -1,53 +0,0 @@ -From f86c044ae075d142e658e866572eb0a37ecad2e1 Mon Sep 17 00:00:00 2001 -From: Alon Levy -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 - diff --git a/0030-qxl-add-800x480-resolution-to-qxl_modes-n900-native.patch b/0030-qxl-add-800x480-resolution-to-qxl_modes-n900-native.patch deleted file mode 100644 index 4eb6f8c..0000000 --- a/0030-qxl-add-800x480-resolution-to-qxl_modes-n900-native.patch +++ /dev/null @@ -1,24 +0,0 @@ -From be78cc4a136f8ec63dc6d7efd8356625c639a877 Mon Sep 17 00:00:00 2001 -From: Alon Levy -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 - diff --git a/0031-qxl-savevm-fixes.patch b/0031-qxl-savevm-fixes.patch deleted file mode 100644 index 93054e8..0000000 --- a/0031-qxl-savevm-fixes.patch +++ /dev/null @@ -1,259 +0,0 @@ -From e55e5fd43113a5b266efa6d17e44f0e9231a98ed Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0032-Revert-spice-vmc-split-vmc_write-to-max-sized-virtio.patch b/0032-Revert-spice-vmc-split-vmc_write-to-max-sized-virtio.patch deleted file mode 100644 index 54b7715..0000000 --- a/0032-Revert-spice-vmc-split-vmc_write-to-max-sized-virtio.patch +++ /dev/null @@ -1,53 +0,0 @@ -From f48f184b9d22bbd2e34fb4f3a7a760f0e98fae64 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0033-Revert-spice-vmc-add-counter-to-debug-statements.patch b/0033-Revert-spice-vmc-add-counter-to-debug-statements.patch deleted file mode 100644 index 6ff14e4..0000000 --- a/0033-Revert-spice-vmc-add-counter-to-debug-statements.patch +++ /dev/null @@ -1,28 +0,0 @@ -From a5d6e7e76bf5f5fb0e2c8232ddca2b850bfc1afa Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0034-Revert-spice-vmc-two-bugfixes-in-vmc_read.patch b/0034-Revert-spice-vmc-two-bugfixes-in-vmc_read.patch deleted file mode 100644 index ce11f48..0000000 --- a/0034-Revert-spice-vmc-two-bugfixes-in-vmc_read.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 84115ef1adf343c34eebfb1045cbc5c72892e3b2 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0035-Revert-spice-live-migration-wip.patch b/0035-Revert-spice-live-migration-wip.patch deleted file mode 100644 index ace3f27..0000000 --- a/0035-Revert-spice-live-migration-wip.patch +++ /dev/null @@ -1,181 +0,0 @@ -From 3e0d1b6ed5f8e8b871803337008e104398e4db0a Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0036-Revert-spice-add-pci-vdi-port-backend-obsolete.patch b/0036-Revert-spice-add-pci-vdi-port-backend-obsolete.patch deleted file mode 100644 index fcf7d08..0000000 --- a/0036-Revert-spice-add-pci-vdi-port-backend-obsolete.patch +++ /dev/null @@ -1,590 +0,0 @@ -From 7bad8970dd7db3e3e0e0b11626656c68f4238884 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 --#include -- --#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 --#include --#include --#include -- --#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 -- --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 -- --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 - diff --git a/0037-Revert-spice-add-virtio-serial-based-vdi-port-backen.patch b/0037-Revert-spice-add-virtio-serial-based-vdi-port-backen.patch deleted file mode 100644 index 654ddc5..0000000 --- a/0037-Revert-spice-add-virtio-serial-based-vdi-port-backen.patch +++ /dev/null @@ -1,236 +0,0 @@ -From bebcc44cfe5da8a4881292fa564869a481eea4ae Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 --#include --#include --#include -- --#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 - diff --git a/0038-spice-add-virtio-serial-based-spice-vmchannel-backen.patch b/0038-spice-add-virtio-serial-based-spice-vmchannel-backen.patch deleted file mode 100644 index 2423deb..0000000 --- a/0038-spice-add-virtio-serial-based-spice-vmchannel-backen.patch +++ /dev/null @@ -1,297 +0,0 @@ -From 5bdc01e675a51a123a813d62a8ae837db9360b7f Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 -+#include -+#include -+#include -+ -+#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 - diff --git a/0039-qxl-fix-release-ring-overrun.patch b/0039-qxl-fix-release-ring-overrun.patch deleted file mode 100644 index a8d041a..0000000 --- a/0039-qxl-fix-release-ring-overrun.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 9394cbaab7701fe421d5c0168854d39d6a8ecfc2 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0040-qxl-flip-default-to-stable-pci-revision.patch b/0040-qxl-flip-default-to-stable-pci-revision.patch deleted file mode 100644 index 2fe6928..0000000 --- a/0040-qxl-flip-default-to-stable-pci-revision.patch +++ /dev/null @@ -1,25 +0,0 @@ -From b0f3b268c79c532725ae23af56621ab2948ac480 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 - diff --git a/0041-vmmouse-adapt-to-mouse-handler-changes.patch b/0041-vmmouse-adapt-to-mouse-handler-changes.patch deleted file mode 100644 index 8914831..0000000 --- a/0041-vmmouse-adapt-to-mouse-handler-changes.patch +++ /dev/null @@ -1,116 +0,0 @@ -From ff53b62094b009f34dd3312e32a637ca73c752e3 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -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 ---- - 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 - diff --git a/0042-vhost-net-patches-for-qemu-0.13.0-tarball.patch b/0042-vhost-net-patches-for-qemu-0.13.0-tarball.patch deleted file mode 100644 index d8478d7..0000000 --- a/0042-vhost-net-patches-for-qemu-0.13.0-tarball.patch +++ /dev/null @@ -1,316 +0,0 @@ -From 2ed38f61f1054e188838bae9244fc1c327f8cda4 Mon Sep 17 00:00:00 2001 -From: Marcelo Tosatti -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 -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 ---- - 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 - diff --git a/avoid-llseek.patch b/avoid-llseek.patch deleted file mode 100644 index 18c4e8b..0000000 --- a/avoid-llseek.patch +++ /dev/null @@ -1,34 +0,0 @@ -commit d35b261c7a94be9e2fcad5484343544d58ff99be -Author: Richard Henderson -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 - Signed-off-by: Aurelien Jarno - -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; diff --git a/block-vvfat.c-fix-warnings-with-_FORTIFY_SOURCE.patch b/block-vvfat.c-fix-warnings-with-_FORTIFY_SOURCE.patch deleted file mode 100644 index d3cdf2e..0000000 --- a/block-vvfat.c-fix-warnings-with-_FORTIFY_SOURCE.patch +++ /dev/null @@ -1,63 +0,0 @@ -From e69a45b96be09d25429175fa8f0f85e3d7fab5a8 Mon Sep 17 00:00:00 2001 -Message-Id: -From: Kirill A. Shutemov -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 -Signed-off-by: Juan Quintela -Signed-off-by: Anthony Liguori -(cherry picked from commit 2dedf83ef0cc3463783d6b71bf1b25476f691f3a) - -This fixes Fedora bug 605202. - -Signed-off-by: Amit Shah ---- - 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 - diff --git a/qemu-vhost-fix-dirty-page-handling.patch b/qemu-vhost-fix-dirty-page-handling.patch new file mode 100644 index 0000000..e3fabb7 --- /dev/null +++ b/qemu-vhost-fix-dirty-page-handling.patch @@ -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 + +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 + diff --git a/qemu.spec b/qemu.spec index 98c115b..630116b 100644 --- a/qemu.spec +++ b/qemu.spec @@ -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 - 2:0.14.0-3 +- Fix migration issue with vhost +- Fix qxl locking issues for spice + * Wed Mar 02 2011 Justin M. Forbes - 2:0.14.0-2 - Re-enable sparc and cris builds