[qemu/f14/master] Updates from upstream to support spice 0.6.0

Justin M. Forbes jforbes at fedoraproject.org
Tue Sep 14 19:27:10 UTC 2010


commit a81953e7105b07201caf3d19d5b17e9089be00e5
Author: Justin M. Forbes <jforbes at redhat.com>
Date:   Tue Sep 14 14:26:08 2010 -0500

    Updates from upstream to support spice 0.6.0

 .gitignore                                         |    1 +
 ...-add-pflib-PixelFormat-conversion-library.patch |  259 +++
 0002-configure-add-logging.patch                   |   39 +
 0003-add-spice-into-the-configure-file.patch       |   94 +
 0004-spice-core-bits.patch                         |  333 ++++
 0005-spice-add-keyboard.patch                      |  118 ++
 0006-spice-add-mouse.patch                         |   62 +
 0007-spice-simple-display.patch                    |  532 +++++
 0008-spice-add-tablet-support.patch                |  160 ++
 0009-vgabios-update-to-0.6c-pcibios-patches.patch  |   28 +
 0010-switch-stdvga-to-pci-vgabios.patch            |   31 +
 0011-switch-vmware_vga-to-pci-vgabios.patch        |   50 +
 0012-all-vga-refuse-hotplugging.patch              |   61 +
 0013-spice-tls-support.patch                       |  168 ++
 0014-spice-add-qxl-device.patch                    | 2085 ++++++++++++++++++++
 0015-spice-add-audio.patch                         |  405 ++++
 ...-add-virtio-serial-based-vdi-port-backend.patch |  238 +++
 0017-spice-add-pci-vdi-port-backend-obsolete.patch |  592 ++++++
 0018-use-memalign-instead-of-posix_memalign.patch  |   29 +
 0019-spice-live-migration-wip.patch                |  179 ++
 0020-spice-display-draw.h-is-internal-now.patch    |   23 +
 0021-spice-display-disable-debug.patch             |   25 +
 0022-spice-display-pci-rev-fixups.patch            |   27 +
 0023-qxl-pci-rev-fixups.patch                      |   52 +
 0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch |   26 +
 0025-spice-vmc-two-bugfixes-in-vmc_read.patch      |   57 +
 ...ing-disabling-jpeg-and-zlib-over-glz-via-.patch |   84 +
 0027-ifdef-new-config-options.patch                |   57 +
 ...spice-vmc-add-counter-to-debug-statements.patch |   27 +
 ...plit-vmc_write-to-max-sized-virtio_serial.patch |   53 +
 ...0x480-resolution-to-qxl_modes-n900-native.patch |   24 +
 0031-qxl-savevm-fixes.patch                        |  259 +++
 ...e-vmc-split-vmc_write-to-max-sized-virtio.patch |   53 +
 ...spice-vmc-add-counter-to-debug-statements.patch |   28 +
 ...Revert-spice-vmc-two-bugfixes-in-vmc_read.patch |   55 +
 0035-Revert-spice-live-migration-wip.patch         |  181 ++
 ...t-spice-add-pci-vdi-port-backend-obsolete.patch |  590 ++++++
 ...e-add-virtio-serial-based-vdi-port-backen.patch |  236 +++
 ...irtio-serial-based-spice-vmchannel-backen.patch |  297 +++
 0039-qxl-fix-release-ring-overrun.patch            |   30 +
 ...edora-13-machine-type-for-backward-compat.patch |   37 +
 qemu.spec                                          |  105 +-
 sources                                            |    2 +-
 43 files changed, 7781 insertions(+), 11 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index f939288..07e3a9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 qemu-kvm-0.13.0-b81fe95.tar.gz
 qemu-kvm-0.13.0-25fdf4a.tar.gz
+/qemu-kvm-0.13.0-rc1.tar.gz
diff --git a/0001-add-pflib-PixelFormat-conversion-library.patch b/0001-add-pflib-PixelFormat-conversion-library.patch
new file mode 100644
index 0000000..de9805e
--- /dev/null
+++ b/0001-add-pflib-PixelFormat-conversion-library.patch
@@ -0,0 +1,259 @@
+From 09992bc6b432987ed3871dd7e4327ab6a589b865 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Mon, 14 Jun 2010 09:54:27 +0200
+Subject: [PATCH 01/39] add pflib: PixelFormat conversion library.
+
+---
+ Makefile.objs |    1 +
+ pflib.c       |  213 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ pflib.h       |    6 ++
+ 3 files changed, 220 insertions(+), 0 deletions(-)
+ create mode 100644 pflib.c
+ create mode 100644 pflib.h
+
+diff --git a/Makefile.objs b/Makefile.objs
+index dbee210..147051f 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -84,6 +84,7 @@ common-obj-y += qemu-char.o savevm.o #aio.o
+ common-obj-y += msmouse.o ps2.o
+ common-obj-y += qdev.o qdev-properties.o
+ common-obj-y += block-migration.o
++common-obj-y += pflib.o
+
+ common-obj-$(CONFIG_BRLAPI) += baum.o
+ common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
+diff --git a/pflib.c b/pflib.c
+new file mode 100644
+index 0000000..1154d0c
+--- /dev/null
++++ b/pflib.c
+@@ -0,0 +1,213 @@
++/*
++ * PixelFormat conversion library.
++ *
++ * Author: Gerd Hoffmann <kraxel at redhat.com>
++ *
++ * This work is licensed under the terms of the GNU GPL, version 2.  See
++ * the COPYING file in the top-level directory.
++ *
++ */
++#include "qemu-common.h"
++#include "console.h"
++#include "pflib.h"
++
++typedef struct QemuPixel QemuPixel;
++
++typedef void (*pf_convert)(QemuPfConv *conv,
++                           void *dst, void *src, uint32_t cnt);
++typedef void (*pf_convert_from)(PixelFormat *pf,
++                                QemuPixel *dst, void *src, uint32_t cnt);
++typedef void (*pf_convert_to)(PixelFormat *pf,
++                              void *dst, QemuPixel *src, uint32_t cnt);
++
++struct QemuPfConv {
++    pf_convert        convert;
++    PixelFormat       src;
++    PixelFormat       dst;
++
++    /* for copy_generic() */
++    pf_convert_from   conv_from;
++    pf_convert_to     conv_to;
++    QemuPixel         *conv_buf;
++    uint32_t          conv_cnt;
++};
++
++struct QemuPixel {
++    uint8_t red;
++    uint8_t green;
++    uint8_t blue;
++    uint8_t alpha;
++};
++
++/* ----------------------------------------------------------------------- */
++/* PixelFormat -> QemuPixel conversions                                    */
++
++static void conv_16_to_pixel(PixelFormat *pf,
++                             QemuPixel *dst, void *src, uint32_t cnt)
++{
++    uint16_t *src16 = src;
++
++    while (cnt > 0) {
++        dst->red   = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
++        dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
++        dst->blue  = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
++        dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits);
++        dst++, src16++, cnt--;
++    }
++}
++
++/* assumes pf->{r,g,b,a}bits == 8 */
++static void conv_32_to_pixel_fast(PixelFormat *pf,
++                                  QemuPixel *dst, void *src, uint32_t cnt)
++{
++    uint32_t *src32 = src;
++
++    while (cnt > 0) {
++        dst->red   = (*src32 & pf->rmask) >> pf->rshift;
++        dst->green = (*src32 & pf->gmask) >> pf->gshift;
++        dst->blue  = (*src32 & pf->bmask) >> pf->bshift;
++        dst->alpha = (*src32 & pf->amask) >> pf->ashift;
++        dst++, src32++, cnt--;
++    }
++}
++
++static void conv_32_to_pixel_generic(PixelFormat *pf,
++                                     QemuPixel *dst, void *src, uint32_t cnt)
++{
++    uint32_t *src32 = src;
++
++    while (cnt > 0) {
++        if (pf->rbits < 8) {
++            dst->red   = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
++        } else {
++            dst->red   = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8);
++        }
++        if (pf->gbits < 8) {
++            dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
++        } else {
++            dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8);
++        }
++        if (pf->bbits < 8) {
++            dst->blue  = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
++        } else {
++            dst->blue  = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8);
++        }
++        if (pf->abits < 8) {
++            dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits);
++        } else {
++            dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8);
++        }
++        dst++, src32++, cnt--;
++    }
++}
++
++/* ----------------------------------------------------------------------- */
++/* QemuPixel -> PixelFormat conversions                                    */
++
++static void conv_pixel_to_16(PixelFormat *pf,
++                             void *dst, QemuPixel *src, uint32_t cnt)
++{
++    uint16_t *dst16 = dst;
++
++    while (cnt > 0) {
++        *dst16  = ((uint16_t)src->red   >> (8 - pf->rbits)) << pf->rshift;
++        *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift;
++        *dst16 |= ((uint16_t)src->blue  >> (8 - pf->bbits)) << pf->bshift;
++        *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
++        dst16++, src++, cnt--;
++    }
++}
++
++static void conv_pixel_to_32(PixelFormat *pf,
++                             void *dst, QemuPixel *src, uint32_t cnt)
++{
++    uint32_t *dst32 = dst;
++
++    while (cnt > 0) {
++        *dst32  = ((uint32_t)src->red   >> (8 - pf->rbits)) << pf->rshift;
++        *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift;
++        *dst32 |= ((uint32_t)src->blue  >> (8 - pf->bbits)) << pf->bshift;
++        *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
++        dst32++, src++, cnt--;
++    }
++}
++
++/* ----------------------------------------------------------------------- */
++/* PixelFormat -> PixelFormat conversions                                  */
++
++static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
++{
++    uint32_t bytes = cnt * conv->src.bytes_per_pixel;
++    memcpy(dst, src, bytes);
++}
++
++static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
++{
++    if (conv->conv_cnt < cnt) {
++        conv->conv_cnt = cnt;
++        conv->conv_buf = qemu_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt);
++    }
++    conv->conv_from(&conv->src, conv->conv_buf, src, cnt);
++    conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt);
++}
++
++/* ----------------------------------------------------------------------- */
++/* public interface                                                        */
++
++QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src)
++{
++    QemuPfConv *conv = qemu_mallocz(sizeof(QemuPfConv));
++
++    conv->src = *src;
++    conv->dst = *dst;
++
++    if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) {
++        /* formats identical, can simply copy */
++        conv->convert = convert_copy;
++    } else {
++        /* generic two-step conversion: src -> QemuPixel -> dst  */
++        switch (conv->src.bytes_per_pixel) {
++        case 2:
++            conv->conv_from = conv_16_to_pixel;
++            break;
++        case 4:
++            if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) {
++                conv->conv_from = conv_32_to_pixel_fast;
++            } else {
++                conv->conv_from = conv_32_to_pixel_generic;
++            }
++            break;
++        default:
++            goto err;
++        }
++        switch (conv->dst.bytes_per_pixel) {
++        case 2:
++            conv->conv_to = conv_pixel_to_16;
++            break;
++        case 4:
++            conv->conv_to = conv_pixel_to_32;
++            break;
++        default:
++            goto err;
++        }
++        conv->convert = convert_generic;
++    }
++    return conv;
++
++err:
++    qemu_free(conv);
++    return NULL;
++}
++
++void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
++{
++    conv->convert(conv, dst, src, cnt);
++}
++
++void qemu_pf_conv_put(QemuPfConv *conv)
++{
++    if (conv) {
++        qemu_free(conv->conv_buf);
++        qemu_free(conv);
++    }
++}
+diff --git a/pflib.h b/pflib.h
+new file mode 100644
+index 0000000..8d73fdd
+--- /dev/null
++++ b/pflib.h
+@@ -0,0 +1,6 @@
++/* public */
++typedef struct QemuPfConv QemuPfConv;
++
++QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src);
++void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt);
++void qemu_pf_conv_put(QemuPfConv *conv);
+-- 
+1.7.2.3
+
diff --git a/0002-configure-add-logging.patch b/0002-configure-add-logging.patch
new file mode 100644
index 0000000..34f374c
--- /dev/null
+++ b/0002-configure-add-logging.patch
@@ -0,0 +1,39 @@
+From 89df4f8cf7ecde07e3dc5e2ea3c19cbcd02165d0 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Fri, 23 Apr 2010 13:44:10 +0200
+Subject: [PATCH 02/39] configure: add logging
+
+Write compile commands and messages to config.log.
+Useful for debugging configure.
+---
+ configure |    7 +++++--
+ 1 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/configure b/configure
+index b85590f..e09c442 100755
+--- a/configure
++++ b/configure
+@@ -16,15 +16,18 @@ TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
+ TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
+
+ trap "rm -f $TMPC $TMPO $TMPE ; exit" EXIT INT QUIT TERM
++rm -f config.log
+
+ compile_object() {
+-  $cc $QEMU_CFLAGS -c -o $TMPO $TMPC > /dev/null 2> /dev/null
++  echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log
++  $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1
+ }
+
+ compile_prog() {
+   local_cflags="$1"
+   local_ldflags="$2"
+-  $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags > /dev/null 2> /dev/null
++  echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log
++  $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1
+ }
+
+ # check whether a command is available to this shell (may be either an
+-- 
+1.7.2.3
+
diff --git a/0003-add-spice-into-the-configure-file.patch b/0003-add-spice-into-the-configure-file.patch
new file mode 100644
index 0000000..3d4eb0a
--- /dev/null
+++ b/0003-add-spice-into-the-configure-file.patch
@@ -0,0 +1,94 @@
+From 0034da7fb15d1225e0fd725009743d48511a90b7 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 24 Mar 2010 10:26:51 +0100
+Subject: [PATCH 03/39] add spice into the configure file
+
+---
+ configure |   36 ++++++++++++++++++++++++++++++++++++
+ 1 files changed, 36 insertions(+), 0 deletions(-)
+
+diff --git a/configure b/configure
+index e09c442..2aaa6d7 100755
+--- a/configure
++++ b/configure
+@@ -331,6 +331,7 @@ cpu_emulation="yes"
+ check_utests="no"
+ user_pie="no"
+ zero_malloc=""
++spice=""
+
+ # OS specific
+ if check_define __linux__ ; then
+@@ -647,6 +648,10 @@ for opt do
+   ;;
+   --enable-kvm-device-assignment) kvm_cap_device_assignment="yes"
+   ;;
++  --disable-spice) spice="no"
++  ;;
++  --enable-spice) spice="yes"
++  ;;
+   --enable-profiler) profiler="yes"
+   ;;
+   --enable-cocoa)
+@@ -933,6 +938,8 @@ echo "  --enable-docs            enable documentation build"
+ echo "  --disable-docs           disable documentation build"
+ echo "  --disable-vhost-net      disable vhost-net acceleration support"
+ echo "  --enable-vhost-net       enable vhost-net acceleration support"
++echo "  --disable-spice          disable spice"
++echo "  --enable-spice           enable spice"
+ echo ""
+ echo "NOTE: The object files are built at the place where configure is launched"
+ exit 1
+@@ -2184,6 +2191,30 @@ if compile_prog "" ""; then
+     gcc_attribute_warn_unused_result=yes
+ fi
+
++# spice probe
++if test "$spice" != "no" ; then
++  cat > $TMPC << EOF
++#include <spice.h>
++int main(void) { spice_server_new(); return 0; }
++EOF
++  spice_proto_ver=$($pkgconfig --modversion spice-protocol 2>/dev/null)
++  spice_server_ver=$($pkgconfig --modversion spice-server 2>/dev/null)
++  spice_cflags=$($pkgconfig --cflags spice-protocol spice-server 2>/dev/null)
++  spice_libs=$($pkgconfig --libs spice-protocol spice-server 2>/dev/null)
++  if compile_prog "$spice_cflags" "$spice_libs" ; then
++    spice="yes"
++    libs_softmmu="$libs_softmmu $spice_libs"
++    QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
++  else
++    if test "$spice" = "yes" ; then
++      feature_not_found "spice"
++    fi
++    spice="no"
++  fi
++fi
++
++##########################################
++
+ ##########################################
+ # check if we have fdatasync
+
+@@ -2329,6 +2360,7 @@ echo "preadv support    $preadv"
+ echo "fdatasync         $fdatasync"
+ echo "uuid support      $uuid"
+ echo "vhost-net support $vhost_net"
++echo "spice support     $spice"
+
+ if test $sdl_too_old = "yes"; then
+ echo "-> Your SDL version is too old - please upgrade to have SDL support"
+@@ -2574,6 +2606,10 @@ else
+   echo "CONFIG_NO_CPU_EMULATION=y" >> $config_host_mak
+ fi
+
++if test "$spice" = "yes" ; then
++  echo "CONFIG_SPICE=y" >> $config_host_mak
++fi
++
+ # XXX: suppress that
+ if [ "$bsd" = "yes" ] ; then
+   echo "CONFIG_BSD=y" >> $config_host_mak
+-- 
+1.7.2.3
+
diff --git a/0004-spice-core-bits.patch b/0004-spice-core-bits.patch
new file mode 100644
index 0000000..a4b156b
--- /dev/null
+++ b/0004-spice-core-bits.patch
@@ -0,0 +1,333 @@
+From 67361a4ad5c99c5dfecdb9d2fc1ba794c38c44ff Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 11 Mar 2010 11:13:27 -0300
+Subject: [PATCH 04/39] spice: core bits
+
+Add -spice command line switch.  Has support setting passwd and port for
+now.  With this patch applied the spice client can successfully connect
+to qemu.  You can't do anything useful yet though.
+---
+ Makefile.objs   |    2 +
+ qemu-config.c   |   23 ++++++++
+ qemu-config.h   |    1 +
+ qemu-options.hx |    8 +++
+ qemu-spice.h    |   22 ++++++++
+ spice.c         |  151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ vl.c            |   15 ++++++
+ 7 files changed, 222 insertions(+), 0 deletions(-)
+ create mode 100644 qemu-spice.h
+ create mode 100644 spice.c
+
+diff --git a/Makefile.objs b/Makefile.objs
+index 147051f..569b458 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -89,6 +89,8 @@ common-obj-y += pflib.o
+ common-obj-$(CONFIG_BRLAPI) += baum.o
+ common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
+
++common-obj-$(CONFIG_SPICE) += spice.o
++
+ audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
+ audio-obj-$(CONFIG_SDL) += sdlaudio.o
+ audio-obj-$(CONFIG_OSS) += ossaudio.o
+diff --git a/qemu-config.c b/qemu-config.c
+index 08ee553..8a894cf 100644
+--- a/qemu-config.c
++++ b/qemu-config.c
+@@ -346,6 +346,26 @@ QemuOptsList qemu_cpudef_opts = {
+     },
+ };
+
++#ifdef CONFIG_SPICE
++QemuOptsList qemu_spice_opts = {
++    .name = "spice",
++    .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
++    .desc = {
++        {
++            .name = "port",
++            .type = QEMU_OPT_NUMBER,
++        },{
++            .name = "password",
++            .type = QEMU_OPT_STRING,
++        },{
++            .name = "disable-ticketing",
++            .type = QEMU_OPT_BOOL,
++        },
++        { /* end if list */ }
++    },
++};
++#endif
++
+ static QemuOptsList *vm_config_groups[] = {
+     &qemu_drive_opts,
+     &qemu_chardev_opts,
+@@ -356,6 +376,9 @@ static QemuOptsList *vm_config_groups[] = {
+     &qemu_global_opts,
+     &qemu_mon_opts,
+     &qemu_cpudef_opts,
++#ifdef CONFIG_SPICE
++    &qemu_spice_opts,
++#endif
+     NULL,
+ };
+
+diff --git a/qemu-config.h b/qemu-config.h
+index dca69d4..3a90213 100644
+--- a/qemu-config.h
++++ b/qemu-config.h
+@@ -14,6 +14,7 @@ extern QemuOptsList qemu_rtc_opts;
+ extern QemuOptsList qemu_global_opts;
+ extern QemuOptsList qemu_mon_opts;
+ extern QemuOptsList qemu_cpudef_opts;
++extern QemuOptsList qemu_spice_opts;
+
+ QemuOptsList *qemu_find_opts(const char *group);
+ int qemu_set_option(const char *str);
+diff --git a/qemu-options.hx b/qemu-options.hx
+index 66c84a0..85551cc 100644
+--- a/qemu-options.hx
++++ b/qemu-options.hx
+@@ -676,6 +676,14 @@ STEXI
+ Enable SDL.
+ ETEXI
+
++#ifdef CONFIG_SPICE
++DEF("spice", HAS_ARG, QEMU_OPTION_spice,
++    "-spice <args>   use spice\n", QEMU_ARCH_ALL)
++STEXI
++Use Spice.
++ETEXI
++#endif
++
+ DEF("portrait", 0, QEMU_OPTION_portrait,
+     "-portrait       rotate graphical output 90 deg left (only PXA LCD)\n",
+     QEMU_ARCH_ALL)
+diff --git a/qemu-spice.h b/qemu-spice.h
+new file mode 100644
+index 0000000..5597576
+--- /dev/null
++++ b/qemu-spice.h
+@@ -0,0 +1,22 @@
++#ifndef QEMU_SPICE_H
++#define QEMU_SPICE_H
++
++#ifdef CONFIG_SPICE
++
++#include <spice.h>
++
++#include "qemu-option.h"
++#include "qemu-config.h"
++
++extern SpiceServer *spice_server;
++extern int using_spice;
++
++void qemu_spice_init(void);
++
++#else  /* CONFIG_SPICE */
++
++#define using_spice 0
++
++#endif /* CONFIG_SPICE */
++
++#endif /* QEMU_SPICE_H */
+diff --git a/spice.c b/spice.c
+new file mode 100644
+index 0000000..50fa5ca
+--- /dev/null
++++ b/spice.c
+@@ -0,0 +1,151 @@
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++
++#include <spice.h>
++#include <spice-experimental.h>
++
++#include "qemu-common.h"
++#include "qemu-spice.h"
++#include "qemu-timer.h"
++#include "qemu-queue.h"
++#include "monitor.h"
++
++/* core bits */
++
++SpiceServer *spice_server;
++int using_spice = 0;
++
++struct SpiceTimer {
++    QEMUTimer *timer;
++    QTAILQ_ENTRY(SpiceTimer) next;
++};
++static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers);
++
++static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
++{
++    SpiceTimer *timer;
++
++    timer = qemu_mallocz(sizeof(*timer));
++    timer->timer = qemu_new_timer(rt_clock, func, opaque);
++    QTAILQ_INSERT_TAIL(&timers, timer, next);
++    return timer;
++}
++
++static void timer_start(SpiceTimer *timer, uint32_t ms)
++{
++    qemu_mod_timer(timer->timer, qemu_get_clock(rt_clock) + ms);
++}
++
++static void timer_cancel(SpiceTimer *timer)
++{
++    qemu_del_timer(timer->timer);
++}
++
++static void timer_remove(SpiceTimer *timer)
++{
++    qemu_del_timer(timer->timer);
++    qemu_free_timer(timer->timer);
++    QTAILQ_REMOVE(&timers, timer, next);
++    free(timer);
++}
++
++struct SpiceWatch {
++    int fd;
++    int event_mask;
++    SpiceWatchFunc func;
++    void *opaque;
++    QTAILQ_ENTRY(SpiceWatch) next;
++};
++static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches);
++
++static void watch_read(void *opaque)
++{
++    SpiceWatch *watch = opaque;
++    watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
++}
++
++static void watch_write(void *opaque)
++{
++    SpiceWatch *watch = opaque;
++    watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
++}
++
++static void watch_update_mask(SpiceWatch *watch, int event_mask)
++{
++    IOHandler *on_read = NULL;
++    IOHandler *on_write = NULL;
++
++    watch->event_mask = event_mask;
++    if (watch->event_mask & SPICE_WATCH_EVENT_READ)
++        on_read = watch_read;
++    if (watch->event_mask & SPICE_WATCH_EVENT_WRITE)
++        on_read = watch_write;
++    qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
++}
++
++static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
++{
++    SpiceWatch *watch;
++
++    watch = qemu_mallocz(sizeof(*watch));
++    watch->fd     = fd;
++    watch->func   = func;
++    watch->opaque = opaque;
++    QTAILQ_INSERT_TAIL(&watches, watch, next);
++
++    watch_update_mask(watch, event_mask);
++    return watch;
++}
++
++static void watch_remove(SpiceWatch *watch)
++{
++    watch_update_mask(watch, 0);
++    QTAILQ_REMOVE(&watches, watch, next);
++    qemu_free(watch);
++}
++
++static SpiceCoreInterface core_interface = {
++    .base.type          = SPICE_INTERFACE_CORE,
++    .base.description   = "qemu core services",
++    .base.major_version = SPICE_INTERFACE_CORE_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_CORE_MINOR,
++
++    .timer_add          = timer_add,
++    .timer_start        = timer_start,
++    .timer_cancel       = timer_cancel,
++    .timer_remove       = timer_remove,
++
++    .watch_add          = watch_add,
++    .watch_update_mask  = watch_update_mask,
++    .watch_remove       = watch_remove,
++};
++
++/* functions for the rest of qemu */
++
++void qemu_spice_init(void)
++{
++    QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
++    const char *password;
++    int port;
++
++    if (!opts)
++        return;
++    port = qemu_opt_get_number(opts, "port", 0);
++    if (!port)
++        return;
++    password = qemu_opt_get(opts, "password");
++
++    spice_server = spice_server_new();
++    spice_server_set_port(spice_server, port);
++    if (password)
++        spice_server_set_ticket(spice_server, password, 0, 0, 0);
++    if (qemu_opt_get_bool(opts, "disable-ticketing", 0))
++        spice_server_set_noauth(spice_server);
++
++    /* TODO: make configurable via cmdline */
++    spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
++
++    spice_server_init(spice_server, &core_interface);
++    using_spice = 1;
++}
+diff --git a/vl.c b/vl.c
+index de8bad1..97897e0 100644
+--- a/vl.c
++++ b/vl.c
+@@ -162,6 +162,8 @@ int main(int argc, char **argv)
+ #include "cpus.h"
+ #include "arch_init.h"
+
++#include "qemu-spice.h"
++
+ //#define DEBUG_NET
+ //#define DEBUG_SLIRP
+
+@@ -2677,6 +2679,15 @@ int main(int argc, char **argv, char **envp)
+                     }
+                     break;
+                 }
++#ifdef CONFIG_SPICE
++            case QEMU_OPTION_spice:
++                opts = qemu_opts_parse(&qemu_spice_opts, optarg, 0);
++                if (!opts) {
++                    fprintf(stderr, "parse error: %s\n", optarg);
++                    exit(1);
++                }
++                break;
++#endif
+             case QEMU_OPTION_writeconfig:
+                 {
+                     FILE *fp;
+@@ -2951,6 +2962,10 @@ int main(int argc, char **argv, char **envp)
+     }
+     qemu_add_globals();
+
++#ifdef CONFIG_SPICE
++    qemu_spice_init();
++#endif
++
+     machine->init(ram_size, boot_devices,
+                   kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
+
+-- 
+1.7.2.3
+
diff --git a/0005-spice-add-keyboard.patch b/0005-spice-add-keyboard.patch
new file mode 100644
index 0000000..6394c15
--- /dev/null
+++ b/0005-spice-add-keyboard.patch
@@ -0,0 +1,118 @@
+From 90f6ec84332857752c252b1c3b89d86eb9714b0e Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 11 Mar 2010 11:13:28 -0300
+Subject: [PATCH 05/39] spice: add keyboard
+
+Open keyboard channel.  Now you can type into the spice client and the
+keyboard events are sent to your guest.  You'll need some other display
+like vnc to actually see the guest responding to them though.
+---
+ Makefile.objs |    2 +-
+ qemu-spice.h  |    1 +
+ spice-input.c |   57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ spice.c       |    2 ++
+ 4 files changed, 61 insertions(+), 1 deletions(-)
+ create mode 100644 spice-input.c
+
+diff --git a/Makefile.objs b/Makefile.objs
+index 569b458..023a0dc 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -89,7 +89,7 @@ common-obj-y += pflib.o
+ common-obj-$(CONFIG_BRLAPI) += baum.o
+ common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
+
+-common-obj-$(CONFIG_SPICE) += spice.o
++common-obj-$(CONFIG_SPICE) += spice.o spice-input.o
+
+ audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
+ audio-obj-$(CONFIG_SDL) += sdlaudio.o
+diff --git a/qemu-spice.h b/qemu-spice.h
+index 5597576..ceb3db2 100644
+--- a/qemu-spice.h
++++ b/qemu-spice.h
+@@ -12,6 +12,7 @@ extern SpiceServer *spice_server;
+ extern int using_spice;
+
+ void qemu_spice_init(void);
++void qemu_spice_input_init(void);
+
+ #else  /* CONFIG_SPICE */
+
+diff --git a/spice-input.c b/spice-input.c
+new file mode 100644
+index 0000000..e1014d7
+--- /dev/null
++++ b/spice-input.c
+@@ -0,0 +1,57 @@
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++
++#include <spice.h>
++
++#include "qemu-common.h"
++#include "qemu-spice.h"
++#include "console.h"
++
++/* keyboard bits */
++
++typedef struct QemuSpiceKbd {
++    SpiceKbdInstance sin;
++    int ledstate;
++} QemuSpiceKbd;
++
++static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
++static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
++static void kbd_leds(void *opaque, int l);
++
++static const SpiceKbdInterface kbd_interface = {
++    .base.type          = SPICE_INTERFACE_KEYBOARD,
++    .base.description   = "qemu keyboard",
++    .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
++    .push_scan_freg     = kbd_push_key,
++    .get_leds           = kbd_get_leds,
++};
++
++static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
++{
++    kbd_put_keycode(frag);
++}
++
++static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
++{
++    QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
++    return kbd->ledstate;
++}
++
++static void kbd_leds(void *opaque, int ledstate)
++{
++    QemuSpiceKbd *kbd = opaque;
++    kbd->ledstate = ledstate;
++    spice_server_kbd_leds(&kbd->sin, ledstate);
++}
++
++void qemu_spice_input_init(void)
++{
++    QemuSpiceKbd *kbd;
++
++    kbd = qemu_mallocz(sizeof(*kbd));
++    kbd->sin.base.sif = &kbd_interface.base;
++    spice_server_add_interface(spice_server, &kbd->sin.base);
++    qemu_add_led_event_handler(kbd_leds, kbd);
++}
+diff --git a/spice.c b/spice.c
+index 50fa5ca..c763d52 100644
+--- a/spice.c
++++ b/spice.c
+@@ -148,4 +148,6 @@ void qemu_spice_init(void)
+
+     spice_server_init(spice_server, &core_interface);
+     using_spice = 1;
++
++    qemu_spice_input_init();
+ }
+-- 
+1.7.2.3
+
diff --git a/0006-spice-add-mouse.patch b/0006-spice-add-mouse.patch
new file mode 100644
index 0000000..ea41880
--- /dev/null
+++ b/0006-spice-add-mouse.patch
@@ -0,0 +1,62 @@
+From e18846175191cbc590ac46fa3820726aeebd6d48 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 11 Mar 2010 11:13:29 -0300
+Subject: [PATCH 06/39] spice: add mouse
+
+Open mouse channel.  Now you can move the guests mouse pointer.
+No tablet / absolute positioning (yet) though.
+---
+ spice-input.c |   31 +++++++++++++++++++++++++++++++
+ 1 files changed, 31 insertions(+), 0 deletions(-)
+
+diff --git a/spice-input.c b/spice-input.c
+index e1014d7..8f3deb4 100644
+--- a/spice-input.c
++++ b/spice-input.c
+@@ -46,12 +46,43 @@ static void kbd_leds(void *opaque, int ledstate)
+     spice_server_kbd_leds(&kbd->sin, ledstate);
+ }
+
++/* mouse bits */
++
++typedef struct QemuSpiceMouse {
++    SpiceMouseInstance sin;
++} QemuSpiceMouse;
++
++static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
++                         uint32_t buttons_state)
++{
++    kbd_mouse_event(dx, dy, dz, buttons_state);
++}
++
++static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
++{
++    kbd_mouse_event(0, 0, 0, buttons_state);
++}
++
++static const SpiceMouseInterface mouse_interface = {
++    .base.type          = SPICE_INTERFACE_MOUSE,
++    .base.description   = "mouse",
++    .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
++    .motion             = mouse_motion,
++    .buttons            = mouse_buttons,
++};
++
+ void qemu_spice_input_init(void)
+ {
+     QemuSpiceKbd *kbd;
++    QemuSpiceMouse *mouse;
+
+     kbd = qemu_mallocz(sizeof(*kbd));
+     kbd->sin.base.sif = &kbd_interface.base;
+     spice_server_add_interface(spice_server, &kbd->sin.base);
+     qemu_add_led_event_handler(kbd_leds, kbd);
++
++    mouse = qemu_mallocz(sizeof(*mouse));
++    mouse->sin.base.sif = &mouse_interface.base;
++    spice_server_add_interface(spice_server, &mouse->sin.base);
+ }
+-- 
+1.7.2.3
+
diff --git a/0007-spice-simple-display.patch b/0007-spice-simple-display.patch
new file mode 100644
index 0000000..e59caa1
--- /dev/null
+++ b/0007-spice-simple-display.patch
@@ -0,0 +1,532 @@
+From 0143117eb5e6233fdeff3b679492b51148cc8f85 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 24 Mar 2010 15:47:18 +0100
+Subject: [PATCH 07/39] spice: simple display
+
+With that patch applied you'll actually see the guests screen in the
+spice client.  This does *not* bring qxl and full spice support though.
+This is basically the qxl vga mode made more generic, so it plays
+together with any qemu-emulated gfx card.  You can display stdvga or
+cirrus via spice client.  You can have both vnc and spice enabled and
+clients connected at the same time.
+---
+ Makefile.objs   |    2 +-
+ qemu-spice.h    |    1 +
+ spice-display.c |  394 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ spice-display.h |   52 ++++++++
+ vl.c            |    7 +-
+ 5 files changed, 454 insertions(+), 2 deletions(-)
+ create mode 100644 spice-display.c
+ create mode 100644 spice-display.h
+
+diff --git a/Makefile.objs b/Makefile.objs
+index 023a0dc..d05643f 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -89,7 +89,7 @@ common-obj-y += pflib.o
+ common-obj-$(CONFIG_BRLAPI) += baum.o
+ common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
+
+-common-obj-$(CONFIG_SPICE) += spice.o spice-input.o
++common-obj-$(CONFIG_SPICE) += spice.o spice-input.o spice-display.o
+
+ audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
+ audio-obj-$(CONFIG_SDL) += sdlaudio.o
+diff --git a/qemu-spice.h b/qemu-spice.h
+index ceb3db2..f061004 100644
+--- a/qemu-spice.h
++++ b/qemu-spice.h
+@@ -13,6 +13,7 @@ extern int using_spice;
+
+ void qemu_spice_init(void);
+ void qemu_spice_input_init(void);
++void qemu_spice_display_init(DisplayState *ds);
+
+ #else  /* CONFIG_SPICE */
+
+diff --git a/spice-display.c b/spice-display.c
+new file mode 100644
+index 0000000..13a620e
+--- /dev/null
++++ b/spice-display.c
+@@ -0,0 +1,394 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <string.h>
++#include <pthread.h>
++
++#include "qemu-common.h"
++#include "qemu-spice.h"
++#include "qemu-timer.h"
++#include "qemu-queue.h"
++#include "monitor.h"
++#include "console.h"
++#include "sysemu.h"
++
++#include "spice-display.h"
++
++static int debug = 1;
++
++int qemu_spice_rect_is_empty(const QXLRect* r)
++{
++    return r->top == r->bottom || r->left == r->right;
++}
++
++void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
++{
++    if (qemu_spice_rect_is_empty(r)) {
++        return;
++    }
++
++    if (qemu_spice_rect_is_empty(dest)) {
++        *dest = *r;
++        return;
++    }
++
++    dest->top = MIN(dest->top, r->top);
++    dest->left = MIN(dest->left, r->left);
++    dest->bottom = MAX(dest->bottom, r->bottom);
++    dest->right = MAX(dest->right, r->right);
++}
++
++SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
++{
++    SimpleSpiceUpdate *update;
++    QXLDrawable *drawable;
++    QXLImage *image;
++    QXLCommand *cmd;
++    uint8_t *src, *dst;
++    int by, bw, bh;
++
++    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
++        return NULL;
++    };
++
++    pthread_mutex_lock(&ssd->lock);
++    if (debug > 1)
++        fprintf(stderr, "%s: lr %d -> %d,  tb -> %d -> %d\n", __FUNCTION__,
++                ssd->dirty.left, ssd->dirty.right,
++                ssd->dirty.top, ssd->dirty.bottom);
++
++    update   = qemu_mallocz(sizeof(*update));
++    drawable = &update->drawable;
++    image    = &update->image;
++    cmd      = &update->ext.cmd;
++
++    bw       = ssd->dirty.right - ssd->dirty.left;
++    bh       = ssd->dirty.bottom - ssd->dirty.top;
++    update->bitmap = qemu_malloc(bw * bh * 4);
++
++    drawable->bbox            = ssd->dirty;
++    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
++    drawable->effect          = QXL_EFFECT_OPAQUE;
++    drawable->release_info.id = (intptr_t)update;
++    drawable->type            = QXL_DRAW_COPY;
++
++    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
++    drawable->u.copy.src_bitmap      = (intptr_t)image;
++    drawable->u.copy.src_area.right  = bw;
++    drawable->u.copy.src_area.bottom = bh;
++
++    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++);
++    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
++    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
++    image->bitmap.stride     = bw * 4;
++    image->descriptor.width  = image->bitmap.x = bw;
++    image->descriptor.height = image->bitmap.y = bh;
++    image->bitmap.data = (intptr_t)(update->bitmap);
++    image->bitmap.palette = 0;
++    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
++
++    if (ssd->conv == NULL) {
++        PixelFormat dst = qemu_default_pixelformat(32);
++        ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf);
++        assert(ssd->conv);
++    }
++
++    src = ds_get_data(ssd->ds) +
++        ssd->dirty.top * ds_get_linesize(ssd->ds) +
++        ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds);
++    dst = update->bitmap;
++    for (by = 0; by < bh; by++) {
++        qemu_pf_conv_run(ssd->conv, dst, src, bw);
++        src += ds_get_linesize(ssd->ds);
++        dst += image->bitmap.stride;
++    }
++
++    cmd->type = QXL_CMD_DRAW;
++    cmd->data = (intptr_t)drawable;
++
++    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
++    pthread_mutex_unlock(&ssd->lock);
++    return update;
++}
++
++void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
++{
++    qemu_free(update->bitmap);
++    qemu_free(update);
++}
++
++void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
++{
++    QXLDevMemSlot memslot;
++
++    if (debug)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++
++    memset(&memslot, 0, sizeof(memslot));
++    memslot.slot_group_id = MEMSLOT_GROUP_HOST;
++    memslot.virt_end = ~0;
++    ssd->worker->add_memslot(ssd->worker, &memslot);
++}
++
++void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
++{
++    QXLDevSurfaceCreate surface;
++
++    if (debug)
++        fprintf(stderr, "%s: %dx%d\n", __FUNCTION__,
++                ds_get_width(ssd->ds), ds_get_height(ssd->ds));
++
++    surface.format     = SPICE_SURFACE_FMT_32_xRGB;
++    surface.width      = ds_get_width(ssd->ds);
++    surface.height     = ds_get_height(ssd->ds);
++    surface.stride     = -surface.width * 4;
++    surface.mouse_mode = 0;
++    surface.flags      = 0;
++    surface.type       = 0;
++    surface.mem        = (intptr_t)ssd->buf;
++    surface.group_id   = MEMSLOT_GROUP_HOST;
++    ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
++}
++
++void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
++{
++    if (debug)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++
++    ssd->worker->destroy_primary_surface(ssd->worker, 0);
++}
++
++void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
++{
++    SimpleSpiceDisplay *ssd = opaque;
++
++    if (running) {
++        ssd->worker->start(ssd->worker);
++    } else {
++        ssd->worker->stop(ssd->worker);
++    }
++    ssd->running = running;
++}
++
++/* display listener callbacks */
++
++void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
++                               int x, int y, int w, int h)
++{
++    QXLRect update_area;
++
++    if (debug > 1)
++        fprintf(stderr, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h);
++    update_area.left = x,
++    update_area.right = x + w;
++    update_area.top = y;
++    update_area.bottom = y + h;
++
++    pthread_mutex_lock(&ssd->lock);
++    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
++        ssd->notify++;
++    }
++    qemu_spice_rect_union(&ssd->dirty, &update_area);
++    pthread_mutex_unlock(&ssd->lock);
++}
++
++void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
++{
++    if (debug)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++
++    pthread_mutex_lock(&ssd->lock);
++    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
++    pthread_mutex_unlock(&ssd->lock);
++
++    qemu_spice_destroy_host_primary(ssd);
++    qemu_spice_create_host_primary(ssd);
++    qemu_pf_conv_put(ssd->conv);
++    ssd->conv = NULL;
++
++    pthread_mutex_lock(&ssd->lock);
++    ssd->dirty.left   = 0;
++    ssd->dirty.right  = ds_get_width(ssd->ds);
++    ssd->dirty.top    = 0;
++    ssd->dirty.bottom = ds_get_height(ssd->ds);
++    ssd->notify++;
++    pthread_mutex_unlock(&ssd->lock);
++}
++
++void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
++{
++    if (debug > 2)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    vga_hw_update();
++    if (ssd->notify) {
++        ssd->notify = 0;
++        ssd->worker->wakeup(ssd->worker);
++        if (debug > 1)
++            fprintf(stderr, "%s: notify\n", __FUNCTION__);
++    }
++}
++
++/* spice display interface callbacks */
++
++static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
++{
++    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
++
++    if (debug)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    ssd->worker = qxl_worker;
++}
++
++static void interface_set_compression_level(QXLInstance *sin, int level)
++{
++    if (debug)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    /* nothing to do */
++}
++
++static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
++{
++    if (debug > 2)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    /* nothing to do */
++}
++
++static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
++{
++    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
++
++    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
++    info->memslot_id_bits  = MEMSLOT_SLOT_BITS;
++    info->num_memslots = NUM_MEMSLOTS;
++    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
++    info->internal_groupslot_id = 0;
++    info->qxl_ram_size = ssd->bufsize;
++    info->n_surfaces = NUM_SURFACES;
++}
++
++static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
++{
++    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
++    SimpleSpiceUpdate *update;
++
++    if (debug > 2)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    update = qemu_spice_create_update(ssd);
++    if (update == NULL) {
++        return false;
++    }
++    *ext = update->ext;
++    return true;
++}
++
++static int interface_req_cmd_notification(QXLInstance *sin)
++{
++    if (debug)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    return 1;
++}
++
++static void interface_release_resource(QXLInstance *sin,
++                                       struct QXLReleaseInfoExt ext)
++{
++    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
++    uintptr_t id;
++
++    if (debug > 1)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    id = ext.info->id;
++    qemu_spice_destroy_update(ssd, (void*)id);
++}
++
++static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
++{
++    if (debug > 2)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    return false;
++}
++
++static int interface_req_cursor_notification(QXLInstance *sin)
++{
++    if (debug)
++        fprintf(stderr, "%s:\n", __FUNCTION__);
++    return 1;
++}
++
++static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
++{
++    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
++    abort();
++}
++
++static int interface_flush_resources(QXLInstance *sin)
++{
++    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
++    abort();
++    return 0;
++}
++
++static const QXLInterface dpy_interface = {
++    .base.type               = SPICE_INTERFACE_QXL,
++    .base.description        = "qemu simple display",
++    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
++    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
++
++    .pci_vendor              = REDHAT_PCI_VENDOR_ID,
++    .pci_id                  = QXL_DEVICE_ID,
++    .pci_revision            = QXL_REVISION,
++
++    .attache_worker          = interface_attach_worker,
++    .set_compression_level   = interface_set_compression_level,
++    .set_mm_time             = interface_set_mm_time,
++
++    .get_init_info           = interface_get_init_info,
++    .get_command             = interface_get_command,
++    .req_cmd_notification    = interface_req_cmd_notification,
++    .release_resource        = interface_release_resource,
++    .get_cursor_command      = interface_get_cursor_command,
++    .req_cursor_notification = interface_req_cursor_notification,
++    .notify_update           = interface_notify_update,
++    .flush_resources         = interface_flush_resources,
++};
++
++static SimpleSpiceDisplay sdpy;
++
++static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
++{
++    qemu_spice_display_update(&sdpy, x, y, w, h);
++}
++
++static void display_resize(struct DisplayState *ds)
++{
++    qemu_spice_display_resize(&sdpy);
++}
++
++static void display_refresh(struct DisplayState *ds)
++{
++    qemu_spice_display_refresh(&sdpy);
++}
++
++static DisplayChangeListener display_listener = {
++    .dpy_update  = display_update,
++    .dpy_resize  = display_resize,
++    .dpy_refresh = display_refresh,
++};
++
++void qemu_spice_display_init(DisplayState *ds)
++{
++    assert(sdpy.ds == NULL);
++    sdpy.ds = ds;
++    sdpy.bufsize = (16 * 1024 * 1024);
++    sdpy.buf = qemu_malloc(sdpy.bufsize);
++    pthread_mutex_init(&sdpy.lock, NULL);
++    register_displaychangelistener(ds, &display_listener);
++
++    sdpy.qxl.base.sif = &dpy_interface.base;
++    spice_server_add_interface(spice_server, &sdpy.qxl.base);
++    assert(sdpy.worker);
++
++    qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy);
++    qemu_spice_create_host_memslot(&sdpy);
++    qemu_spice_create_host_primary(&sdpy);
++}
+diff --git a/spice-display.h b/spice-display.h
+new file mode 100644
+index 0000000..70a7be4
+--- /dev/null
++++ b/spice-display.h
+@@ -0,0 +1,52 @@
++#include <spice/ipc_ring.h>
++#include <spice/draw.h>
++#include <spice/qxl_dev.h>
++
++#include "pflib.h"
++
++#define NUM_MEMSLOTS 8
++#define MEMSLOT_GENERATION_BITS 8
++#define MEMSLOT_SLOT_BITS 8
++
++#define MEMSLOT_GROUP_HOST  0
++#define MEMSLOT_GROUP_GUEST 1
++#define NUM_MEMSLOTS_GROUPS 2
++
++#define NUM_SURFACES 1024
++
++typedef struct SimpleSpiceDisplay {
++    DisplayState *ds;
++    void *buf;
++    int bufsize;
++    QXLWorker *worker;
++    QXLInstance qxl;
++    uint32_t unique;
++    QemuPfConv *conv;
++
++    pthread_mutex_t lock;
++    QXLRect dirty;
++    int notify;
++    int running;
++} SimpleSpiceDisplay;
++
++typedef struct SimpleSpiceUpdate {
++    QXLDrawable drawable;
++    QXLImage image;
++    QXLCommandExt ext;
++    uint8_t *bitmap;
++} SimpleSpiceUpdate;
++
++int qemu_spice_rect_is_empty(const QXLRect* r);
++void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
++
++SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *sdpy);
++void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update);
++void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
++void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
++void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
++void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
++
++void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
++                               int x, int y, int w, int h);
++void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
++void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
+diff --git a/vl.c b/vl.c
+index 97897e0..2ccebc8 100644
+--- a/vl.c
++++ b/vl.c
+@@ -2993,7 +2993,7 @@ int main(int argc, char **argv, char **envp)
+     /* just use the first displaystate for the moment */
+     ds = get_displaystate();
+
+-    if (display_type == DT_DEFAULT) {
++    if (display_type == DT_DEFAULT && !using_spice) {
+ #if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+         display_type = DT_SDL;
+ #else
+@@ -3033,6 +3033,11 @@ int main(int argc, char **argv, char **envp)
+     default:
+         break;
+     }
++#ifdef CONFIG_SPICE
++    if (using_spice) {
++        qemu_spice_display_init(ds);
++    }
++#endif
+     dpy_resize(ds);
+
+     dcl = ds->listeners;
+-- 
+1.7.2.3
+
diff --git a/0008-spice-add-tablet-support.patch b/0008-spice-add-tablet-support.patch
new file mode 100644
index 0000000..6f37c81
--- /dev/null
+++ b/0008-spice-add-tablet-support.patch
@@ -0,0 +1,160 @@
+From e3c6e18e27f0d598b37e9be1795dbcb42f740071 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Tue, 13 Apr 2010 09:05:03 +0200
+Subject: [PATCH 08/39] spice: add tablet support
+
+Add support for the spice tablet interface.  The tablet interface will
+be registered (and then used by the spice client) as soon as a absolute
+pointing device is available and used by the guest, i.e. you'll have to
+configure your guest with '-usbdevice tablet'.
+---
+ spice-display.c |    2 +-
+ spice-input.c   |   99 +++++++++++++++++++++++++++++++++++++++++++++++++++----
+ 2 files changed, 93 insertions(+), 8 deletions(-)
+
+diff --git a/spice-display.c b/spice-display.c
+index 13a620e..a749e64 100644
+--- a/spice-display.c
++++ b/spice-display.c
+@@ -143,7 +143,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+     surface.width      = ds_get_width(ssd->ds);
+     surface.height     = ds_get_height(ssd->ds);
+     surface.stride     = -surface.width * 4;
+-    surface.mouse_mode = 0;
++    surface.mouse_mode = true;
+     surface.flags      = 0;
+     surface.type       = 0;
+     surface.mem        = (intptr_t)ssd->buf;
+diff --git a/spice-input.c b/spice-input.c
+index 8f3deb4..5646ff9 100644
+--- a/spice-input.c
++++ b/spice-input.c
+@@ -1,5 +1,6 @@
+ #include <stdlib.h>
+ #include <stdio.h>
++#include <stdbool.h>
+ #include <string.h>
+
+ #include <spice.h>
+@@ -48,9 +49,13 @@ static void kbd_leds(void *opaque, int ledstate)
+
+ /* mouse bits */
+
+-typedef struct QemuSpiceMouse {
+-    SpiceMouseInstance sin;
+-} QemuSpiceMouse;
++typedef struct QemuSpicePointer {
++    SpiceMouseInstance  mouse;
++    SpiceTabletInstance tablet;
++    int width, height, x, y;
++    Notifier mouse_mode;
++    bool absolute;
++} QemuSpicePointer;
+
+ static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
+                          uint32_t buttons_state)
+@@ -72,17 +77,97 @@ static const SpiceMouseInterface mouse_interface = {
+     .buttons            = mouse_buttons,
+ };
+
++static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
++{
++    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
++
++    fprintf(stderr, "%s: %dx%d\n", __FUNCTION__, width, height);
++    if (height < 16)
++        height = 16;
++    if (width < 16)
++        width = 16;
++    pointer->width  = width;
++    pointer->height = height;
++}
++
++static void tablet_position(SpiceTabletInstance* sin, int x, int y,
++                            uint32_t buttons_state)
++{
++    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
++
++    pointer->x = x * 0x7FFF / (pointer->width - 1);
++    pointer->y = y * 0x7FFF / (pointer->height - 1);
++    kbd_mouse_event(pointer->x, pointer->y, 0, buttons_state);
++}
++
++
++static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
++                         uint32_t buttons_state)
++{
++    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
++
++    kbd_mouse_event(pointer->x, pointer->y, wheel, buttons_state);
++}
++
++static void tablet_buttons(SpiceTabletInstance *sin,
++                           uint32_t buttons_state)
++{
++    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
++
++    kbd_mouse_event(pointer->x, pointer->y, 0, buttons_state);
++}
++
++static const SpiceTabletInterface tablet_interface = {
++    .base.type          = SPICE_INTERFACE_TABLET,
++    .base.description   = "tablet",
++    .base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
++    .set_logical_size   = tablet_set_logical_size,
++    .position           = tablet_position,
++    .wheel              = tablet_wheel,
++    .buttons            = tablet_buttons,
++};
++
++static void mouse_mode_notifier(Notifier *notifier)
++{
++    QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
++    bool is_absolute  = kbd_mouse_is_absolute();
++    bool has_absolute = kbd_mouse_has_absolute();
++
++    fprintf(stderr, "%s: absolute pointer: %s%s\n", __FUNCTION__,
++            has_absolute ? "present" : "not available",
++            is_absolute  ? "+active" : "");
++
++    if (pointer->absolute == is_absolute)
++        return;
++
++    if (is_absolute) {
++        fprintf(stderr, "%s: using absolute pointer (client mode)\n", __FUNCTION__);
++        spice_server_add_interface(spice_server, &pointer->tablet.base);
++    } else {
++        fprintf(stderr, "%s: using relative pointer (server mode)\n", __FUNCTION__);
++        spice_server_remove_interface(&pointer->tablet.base);
++    }
++    pointer->absolute = is_absolute;
++}
++
+ void qemu_spice_input_init(void)
+ {
+     QemuSpiceKbd *kbd;
+-    QemuSpiceMouse *mouse;
++    QemuSpicePointer *pointer;
+
+     kbd = qemu_mallocz(sizeof(*kbd));
+     kbd->sin.base.sif = &kbd_interface.base;
+     spice_server_add_interface(spice_server, &kbd->sin.base);
+     qemu_add_led_event_handler(kbd_leds, kbd);
+
+-    mouse = qemu_mallocz(sizeof(*mouse));
+-    mouse->sin.base.sif = &mouse_interface.base;
+-    spice_server_add_interface(spice_server, &mouse->sin.base);
++    pointer = qemu_mallocz(sizeof(*pointer));
++    pointer->mouse.base.sif  = &mouse_interface.base;
++    pointer->tablet.base.sif = &tablet_interface.base;
++    spice_server_add_interface(spice_server, &pointer->mouse.base);
++
++    pointer->absolute = false;
++    pointer->mouse_mode.notify = mouse_mode_notifier;
++    qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
++    mouse_mode_notifier(&pointer->mouse_mode);
+ }
+-- 
+1.7.2.3
+
diff --git a/0009-vgabios-update-to-0.6c-pcibios-patches.patch b/0009-vgabios-update-to-0.6c-pcibios-patches.patch
new file mode 100644
index 0000000..29ff6f4
--- /dev/null
+++ b/0009-vgabios-update-to-0.6c-pcibios-patches.patch
@@ -0,0 +1,28 @@
+From 0920337756cdf82dcd585efb23ae18f8086696c8 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 24 Mar 2010 11:16:54 +0100
+Subject: [PATCH 09/39] vgabios update to 0.6c + pcibios patches.
+
+---
+ Makefile |    5 +++--
+ 1 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 3cd07e0..e40c9a2 100644
+--- a/Makefile
++++ b/Makefile
+@@ -154,8 +154,9 @@ ar      de     en-us  fi  fr-be  hr     it  lv  nl         pl  ru     th \
+ common  de-ch  es     fo  fr-ca  hu     ja  mk  nl-be      pt  sl     tr
+
+ ifdef INSTALL_BLOBS
+-BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
+-video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
++BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
++vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-qxldev.bin \
++ppc_rom.bin video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
+ gpxe-eepro100-80861209.rom \
+ gpxe-eepro100-80861229.rom \
+ pxe-e1000.bin \
+-- 
+1.7.2.3
+
diff --git a/0010-switch-stdvga-to-pci-vgabios.patch b/0010-switch-stdvga-to-pci-vgabios.patch
new file mode 100644
index 0000000..ccb71ac
--- /dev/null
+++ b/0010-switch-stdvga-to-pci-vgabios.patch
@@ -0,0 +1,31 @@
+From 6ac04dff1ee3932d2ef94c1e42f4e8208fbf92bf Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 6 May 2010 11:13:11 +0200
+Subject: [PATCH 10/39] switch stdvga to pci vgabios
+
+---
+ hw/vga-pci.c |    7 +++----
+ 1 files changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/hw/vga-pci.c b/hw/vga-pci.c
+index 3907871..8e1ed35 100644
+--- a/hw/vga-pci.c
++++ b/hw/vga-pci.c
+@@ -105,11 +105,10 @@ static int pci_vga_initfn(PCIDevice *dev)
+             bios_total_size <<= 1;
+         pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
+                          PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
++     } else {
++         if (dev->romfile == NULL)
++             dev->romfile = qemu_strdup("vgabios-stdvga.bin");
+      }
+-
+-    vga_init_vbe(s);
+-     /* ROM BIOS */
+-     rom_add_vga(VGABIOS_FILENAME);
+      return 0;
+ }
+
+-- 
+1.7.2.3
+
diff --git a/0011-switch-vmware_vga-to-pci-vgabios.patch b/0011-switch-vmware_vga-to-pci-vgabios.patch
new file mode 100644
index 0000000..30bfa9c
--- /dev/null
+++ b/0011-switch-vmware_vga-to-pci-vgabios.patch
@@ -0,0 +1,50 @@
+From 07cdc867f1e12a4e8b4096e7f1f3ffda2f4e7d02 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 6 May 2010 11:14:11 +0200
+Subject: [PATCH 11/39] switch vmware_vga to pci vgabios
+
+---
+ hw/vmware_vga.c |    7 +------
+ 1 files changed, 1 insertions(+), 6 deletions(-)
+
+diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
+index 12bff48..682f287 100644
+--- a/hw/vmware_vga.c
++++ b/hw/vmware_vga.c
+@@ -114,14 +114,12 @@ struct pci_vmsvga_state_s {
+ # define SVGA_IO_BASE		SVGA_LEGACY_BASE_PORT
+ # define SVGA_IO_MUL		1
+ # define SVGA_FIFO_SIZE		0x10000
+-# define SVGA_MEM_BASE		0xe0000000
+ # define SVGA_PCI_DEVICE_ID	PCI_DEVICE_ID_VMWARE_SVGA2
+ #else
+ # define SVGA_ID		SVGA_ID_1
+ # define SVGA_IO_BASE		SVGA_LEGACY_BASE_PORT
+ # define SVGA_IO_MUL		4
+ # define SVGA_FIFO_SIZE		0x10000
+-# define SVGA_MEM_BASE		0xe0000000
+ # define SVGA_PCI_DEVICE_ID	PCI_DEVICE_ID_VMWARE_SVGA
+ #endif
+
+@@ -1171,10 +1169,6 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
+     vga_init(&s->vga);
+     vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
+
+-    vga_init_vbe(&s->vga);
+-
+-    rom_add_vga(VGABIOS_FILENAME);
+-
+     vmsvga_reset(s);
+ }
+
+@@ -1272,6 +1266,7 @@ static PCIDeviceInfo vmsvga_info = {
+     .qdev.size    = sizeof(struct pci_vmsvga_state_s),
+     .qdev.vmsd    = &vmstate_vmware_vga,
+     .init         = pci_vmsvga_initfn,
++    .romfile      = "vgabios-vmware.bin",
+ };
+
+ static void vmsvga_register(void)
+-- 
+1.7.2.3
+
diff --git a/0012-all-vga-refuse-hotplugging.patch b/0012-all-vga-refuse-hotplugging.patch
new file mode 100644
index 0000000..393b1b2
--- /dev/null
+++ b/0012-all-vga-refuse-hotplugging.patch
@@ -0,0 +1,61 @@
+From a659f6b472d95503657ac68a52242ce769006f17 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Tue, 11 May 2010 22:28:44 +0200
+Subject: [PATCH 12/39] all vga: refuse hotplugging.
+
+Try to pci hotplug a vga card, watch qemu die with hw_error().
+This patch fixes it.
+---
+ hw/cirrus_vga.c |    4 ++++
+ hw/vga-pci.c    |    4 ++++
+ hw/vmware_vga.c |    4 ++++
+ 3 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
+index efa7a42..dadaa80 100644
+--- a/hw/cirrus_vga.c
++++ b/hw/cirrus_vga.c
+@@ -3206,6 +3206,10 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
+      uint8_t *pci_conf = d->dev.config;
+      int device_id = CIRRUS_ID_CLGD5446;
+
++     if (dev->qdev.hotplugged) {
++         return -1;
++     }
++
+      /* setup VGA */
+      vga_common_init(&s->vga, VGA_RAM_SIZE);
+      cirrus_init_common(s, device_id, 1);
+diff --git a/hw/vga-pci.c b/hw/vga-pci.c
+index 8e1ed35..4e673a5 100644
+--- a/hw/vga-pci.c
++++ b/hw/vga-pci.c
+@@ -81,6 +81,10 @@ static int pci_vga_initfn(PCIDevice *dev)
+      VGACommonState *s = &d->vga;
+      uint8_t *pci_conf = d->dev.config;
+
++     if (dev->qdev.hotplugged) {
++         return -1;
++     }
++
+      // vga + console init
+      vga_common_init(s, VGA_RAM_SIZE);
+      vga_init(s);
+diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
+index 682f287..7ff89aa 100644
+--- a/hw/vmware_vga.c
++++ b/hw/vmware_vga.c
+@@ -1232,6 +1232,10 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
+     struct pci_vmsvga_state_s *s =
+         DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
+
++    if (dev->qdev.hotplugged) {
++        return -1;
++    }
++
+     pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
+     pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
+     pci_config_set_class(s->card.config, PCI_CLASS_DISPLAY_VGA);
+-- 
+1.7.2.3
+
diff --git a/0013-spice-tls-support.patch b/0013-spice-tls-support.patch
new file mode 100644
index 0000000..da247af
--- /dev/null
+++ b/0013-spice-tls-support.patch
@@ -0,0 +1,168 @@
+From e0d06d42a83e7796b2c39ad6cab3630c0a8c2845 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 11 Mar 2010 11:13:32 -0300
+Subject: [PATCH 13/39] spice: tls support
+
+Add options to the -spice command line switch to setup tls:
+
+tls-port
+	listening port
+
+x509-dir
+	x509 file directory.  Expects same filenames as
+	-vnc $display,x509=$dir
+
+x509-key-file
+x509-key-password
+x509-cert-file
+x509-cacert-file
+x509-dh-key-file
+	x509 files can also be set individually.
+
+tls-ciphers
+	which ciphers to use.
+---
+ qemu-config.c |   24 ++++++++++++++++++++
+ spice.c       |   66 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 86 insertions(+), 4 deletions(-)
+
+diff --git a/qemu-config.c b/qemu-config.c
+index 8a894cf..74bfc62 100644
+--- a/qemu-config.c
++++ b/qemu-config.c
+@@ -355,11 +355,35 @@ QemuOptsList qemu_spice_opts = {
+             .name = "port",
+             .type = QEMU_OPT_NUMBER,
+         },{
++            .name = "tls-port",
++            .type = QEMU_OPT_NUMBER,
++        },{
+             .name = "password",
+             .type = QEMU_OPT_STRING,
+         },{
+             .name = "disable-ticketing",
+             .type = QEMU_OPT_BOOL,
++        },{
++            .name = "x509-dir",
++            .type = QEMU_OPT_STRING,
++        },{
++            .name = "x509-key-file",
++            .type = QEMU_OPT_STRING,
++        },{
++            .name = "x509-key-password",
++            .type = QEMU_OPT_STRING,
++        },{
++            .name = "x509-cert-file",
++            .type = QEMU_OPT_STRING,
++        },{
++            .name = "x509-cacert-file",
++            .type = QEMU_OPT_STRING,
++        },{
++            .name = "x509-dh-key-file",
++            .type = QEMU_OPT_STRING,
++        },{
++            .name = "tls-ciphers",
++            .type = QEMU_OPT_STRING,
+         },
+         { /* end if list */ }
+     },
+diff --git a/spice.c b/spice.c
+index c763d52..3fe76cd 100644
+--- a/spice.c
++++ b/spice.c
+@@ -9,6 +9,7 @@
+ #include "qemu-spice.h"
+ #include "qemu-timer.h"
+ #include "qemu-queue.h"
++#include "qemu-x509.h"
+ #include "monitor.h"
+
+ /* core bits */
+@@ -126,18 +127,71 @@ static SpiceCoreInterface core_interface = {
+ void qemu_spice_init(void)
+ {
+     QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+-    const char *password;
+-    int port;
++    const char *password, *str, *x509_dir,
++        *x509_key_password = NULL,
++        *x509_dh_file = NULL,
++        *tls_ciphers = NULL;
++    char *x509_key_file = NULL,
++        *x509_cert_file = NULL,
++        *x509_cacert_file = NULL;
++    int port, tls_port, len;
+
+     if (!opts)
+         return;
+     port = qemu_opt_get_number(opts, "port", 0);
+-    if (!port)
++    tls_port = qemu_opt_get_number(opts, "tls-port", 0);
++    if (!port && !tls_port)
+         return;
+     password = qemu_opt_get(opts, "password");
+
++    if (tls_port) {
++        x509_dir = qemu_opt_get(opts, "x509-dir");
++        if (NULL == x509_dir)
++            x509_dir = ".";
++        len = strlen(x509_dir) + 32;
++
++        str = qemu_opt_get(opts, "x509-key-file");
++        if (str) {
++            x509_key_file = qemu_strdup(str);
++        } else {
++            x509_key_file = qemu_malloc(len);
++            snprintf(x509_key_file, len, "%s/%s", x509_dir, X509_SERVER_KEY_FILE);
++        }
++
++        str = qemu_opt_get(opts, "x509-cert-file");
++        if (str) {
++            x509_cert_file = qemu_strdup(str);
++        } else {
++            x509_cert_file = qemu_malloc(len);
++            snprintf(x509_cert_file, len, "%s/%s", x509_dir, X509_SERVER_CERT_FILE);
++        }
++
++        str = qemu_opt_get(opts, "x509-cacert-file");
++        if (str) {
++            x509_cacert_file = qemu_strdup(str);
++        } else {
++            x509_cacert_file = qemu_malloc(len);
++            snprintf(x509_cacert_file, len, "%s/%s", x509_dir, X509_CA_CERT_FILE);
++        }
++
++        x509_key_password = qemu_opt_get(opts, "x509-key-password");
++        x509_dh_file = qemu_opt_get(opts, "x509-dh-file");
++        tls_ciphers = qemu_opt_get(opts, "tls-ciphers");
++    }
++
+     spice_server = spice_server_new();
+-    spice_server_set_port(spice_server, port);
++    if (port) {
++        spice_server_set_port(spice_server, port);
++    }
++    if (tls_port) {
++        spice_server_set_tls(spice_server, tls_port,
++                             x509_cacert_file,
++                             x509_cert_file,
++                             x509_key_file,
++                             x509_key_password,
++                             x509_dh_file,
++                             tls_ciphers);
++    }
+     if (password)
+         spice_server_set_ticket(spice_server, password, 0, 0, 0);
+     if (qemu_opt_get_bool(opts, "disable-ticketing", 0))
+@@ -150,4 +204,8 @@ void qemu_spice_init(void)
+     using_spice = 1;
+
+     qemu_spice_input_init();
++
++    qemu_free(x509_key_file);
++    qemu_free(x509_cert_file);
++    qemu_free(x509_cacert_file);
+ }
+-- 
+1.7.2.3
+
diff --git a/0014-spice-add-qxl-device.patch b/0014-spice-add-qxl-device.patch
new file mode 100644
index 0000000..4ea90ba
--- /dev/null
+++ b/0014-spice-add-qxl-device.patch
@@ -0,0 +1,2085 @@
+From 4cd79eae3a476fda86b67a8075735a03c1254a08 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+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 <stdio.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <string.h>
++
++#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 <stdio.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <string.h>
++
++#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 <stdio.h>
++#include <stdlib.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <string.h>
++#include <pthread.h>
++
++#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
new file mode 100644
index 0000000..6725ffe
--- /dev/null
+++ b/0015-spice-add-audio.patch
@@ -0,0 +1,405 @@
+From f3e02bc08c4521dc53d858174612341462d588ce Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Tue, 13 Apr 2010 10:34:46 +0200
+Subject: [PATCH 15/39] spice: add audio
+
+Add support for the spice audio interface.
+
+The driver is first in the driver list, but can_be_default is set only
+in case spice is active.  So if you are using spice the spice audio
+driver is the default one, otherwise whatever comes first after spice in
+the list.  Overriding the default using QEMU_AUDIO_DRV works in any
+case.
+---
+ Makefile.objs      |    1 +
+ audio/audio.c      |    3 +
+ audio/audio_int.h  |    1 +
+ audio/spiceaudio.c |  312 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ qemu-spice.h       |    1 +
+ spice.c            |    1 +
+ 6 files changed, 319 insertions(+), 0 deletions(-)
+ create mode 100644 audio/spiceaudio.c
+
+diff --git a/Makefile.objs b/Makefile.objs
+index d05643f..9a6b0f3 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -94,6 +94,7 @@ common-obj-$(CONFIG_SPICE) += spice.o spice-input.o spice-display.o
+ audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
+ audio-obj-$(CONFIG_SDL) += sdlaudio.o
+ audio-obj-$(CONFIG_OSS) += ossaudio.o
++audio-obj-$(CONFIG_SPICE) += spiceaudio.o
+ audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
+ audio-obj-$(CONFIG_ALSA) += alsaaudio.o
+ audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
+diff --git a/audio/audio.c b/audio/audio.c
+index ad51077..ade342e 100644
+--- a/audio/audio.c
++++ b/audio/audio.c
+@@ -44,6 +44,9 @@
+     that we generate the list.
+ */
+ static struct audio_driver *drvtab[] = {
++#ifdef CONFIG_SPICE
++    &spice_audio_driver,
++#endif
+     CONFIG_AUDIO_DRIVERS
+     &no_audio_driver,
+     &wav_audio_driver
+diff --git a/audio/audio_int.h b/audio/audio_int.h
+index 06e313f..d1f6c2d 100644
+--- a/audio/audio_int.h
++++ b/audio/audio_int.h
+@@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver;
+ extern struct audio_driver dsound_audio_driver;
+ extern struct audio_driver esd_audio_driver;
+ extern struct audio_driver pa_audio_driver;
++extern struct audio_driver spice_audio_driver;
+ extern struct audio_driver winwave_audio_driver;
+ extern struct mixeng_volume nominal_volume;
+
+diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
+new file mode 100644
+index 0000000..8ae7499
+--- /dev/null
++++ b/audio/spiceaudio.c
+@@ -0,0 +1,312 @@
++#include "hw/hw.h"
++#include "qemu-timer.h"
++#include "qemu-spice.h"
++
++#define AUDIO_CAP "spice"
++#include "audio.h"
++#include "audio_int.h"
++
++#define LINE_IN_SAMPLES 1024
++#define LINE_OUT_SAMPLES 1024
++
++typedef struct SpiceVoiceOut {
++    HWVoiceOut            hw;
++    SpicePlaybackInstance sin;
++    int64_t               prev_ticks;
++    int                   active;
++    uint32_t              *frame;
++    uint32_t              *fpos;
++    uint32_t              fsize;
++} SpiceVoiceOut;
++
++typedef struct SpiceVoiceIn {
++    HWVoiceIn             hw;
++    SpiceRecordInstance   sin;
++    int64_t               prev_ticks;
++    int                   active;
++    uint32_t              samples[LINE_IN_SAMPLES];
++} SpiceVoiceIn;
++
++static const SpicePlaybackInterface playback_sif = {
++    .base.type          = SPICE_INTERFACE_PLAYBACK,
++    .base.description   = "playback",
++    .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
++};
++
++static const SpiceRecordInterface record_sif = {
++    .base.type          = SPICE_INTERFACE_RECORD,
++    .base.description   = "record",
++    .base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
++};
++
++static void *spice_audio_init(void)
++{
++    if (!using_spice) {
++        return NULL;
++    }
++    return &spice_audio_init;
++}
++
++static void spice_audio_fini(void *opaque)
++{
++    /* nothing */
++}
++
++static int calculate_samples(struct audio_pcm_info *info, int64_t *old_ticks)
++{
++    int64_t now;
++    int64_t ticks;
++    int64_t bytes;
++    int samples;
++
++    now = qemu_get_clock (vm_clock);
++    ticks = now - *old_ticks;
++    *old_ticks = now;
++    bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
++    bytes = audio_MIN (bytes, INT_MAX);
++    samples = bytes >> info->shift;
++    return samples;
++}
++
++/* playback */
++
++static int line_out_init(HWVoiceOut *hw, struct audsettings *as)
++{
++    SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
++    struct audsettings settings;
++
++    settings.freq       = SPICE_INTERFACE_PLAYBACK_FREQ;
++    settings.nchannels  = SPICE_INTERFACE_PLAYBACK_CHAN;
++    settings.fmt        = AUD_FMT_S16;
++    settings.endianness = AUDIO_HOST_ENDIANNESS;
++
++    audio_pcm_init_info(&hw->info, &settings);
++    hw->samples = LINE_OUT_SAMPLES;
++    out->active = 0;
++
++    out->sin.base.sif = &playback_sif.base;
++    spice_server_add_interface(spice_server, &out->sin.base);
++    return 0;
++}
++
++static void line_out_fini(HWVoiceOut *hw)
++{
++    SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
++
++    spice_server_remove_interface(&out->sin.base);
++}
++
++static int line_out_run(HWVoiceOut *hw, int live)
++{
++    SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
++    int rpos, decr;
++    int samples;
++
++    if (!live) {
++        return 0;
++    }
++
++    decr = calculate_samples(&hw->info, &out->prev_ticks);
++    decr = audio_MIN(live, decr);
++
++    samples = decr;
++    rpos = hw->rpos;
++    while (samples) {
++        int left_till_end_samples = hw->samples - rpos;
++        int len = audio_MIN(samples, left_till_end_samples);
++
++        if (!out->frame) {
++            spice_server_playback_get_buffer(&out->sin, &out->frame, &out->fsize);
++            out->fpos = out->frame;
++        }
++        if (out->frame) {
++            len = audio_MIN(len, out->fsize);
++            hw->clip(out->fpos, hw->mix_buf + rpos, len);
++            out->fsize -= len;
++            out->fpos  += len;
++            if (out->fsize == 0) {
++                spice_server_playback_put_samples(&out->sin, out->frame);
++                out->frame = out->fpos = NULL;
++            }
++        }
++        rpos = (rpos + len) % hw->samples;
++        samples -= len;
++    }
++    hw->rpos = rpos;
++    return decr;
++}
++
++static int line_out_write(SWVoiceOut *sw, void *buf, int len)
++{
++    return audio_pcm_sw_write(sw, buf, len);
++}
++
++static int line_out_ctl(HWVoiceOut *hw, int cmd, ...)
++{
++    SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
++
++    switch (cmd) {
++    case VOICE_ENABLE:
++        if (out->active) {
++            break;
++        }
++        out->active = 1;
++        out->prev_ticks = qemu_get_clock (vm_clock);
++        spice_server_playback_start(&out->sin);
++        break;
++    case VOICE_DISABLE:
++        if (!out->active) {
++            break;
++        }
++        out->active = 0;
++        if (out->frame) {
++            memset(out->fpos, 0, out->fsize << 2);
++            spice_server_playback_put_samples(&out->sin, out->frame);
++            out->frame = out->fpos = NULL;
++        }
++        spice_server_playback_stop(&out->sin);
++        break;
++    }
++    return 0;
++}
++
++/* record */
++
++static int line_in_init(HWVoiceIn *hw, struct audsettings *as)
++{
++    SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
++    struct audsettings settings;
++
++    settings.freq       = SPICE_INTERFACE_RECORD_FREQ;
++    settings.nchannels  = SPICE_INTERFACE_RECORD_CHAN;
++    settings.fmt        = AUD_FMT_S16;
++    settings.endianness = AUDIO_HOST_ENDIANNESS;
++
++    audio_pcm_init_info(&hw->info, &settings);
++    hw->samples = LINE_IN_SAMPLES;
++    in->active = 0;
++
++    in->sin.base.sif = &record_sif.base;
++    spice_server_add_interface(spice_server, &in->sin.base);
++    return 0;
++}
++
++static void line_in_fini(HWVoiceIn *hw)
++{
++    SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
++
++    spice_server_remove_interface(&in->sin.base);
++}
++
++static int line_in_run(HWVoiceIn *hw)
++{
++    SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
++    int num_samples;
++    int ready;
++    int len[2];
++    uint64_t delta_samp;
++    uint32_t *samples;
++
++    if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in(hw))) {
++        return 0;
++    }
++
++    delta_samp = calculate_samples(&hw->info, &in->prev_ticks);
++    num_samples = audio_MIN(num_samples, delta_samp);
++
++    ready = spice_server_record_get_samples(&in->sin, in->samples, num_samples);
++    samples = in->samples;
++    if (ready == 0) {
++        static uint32_t silence[LINE_IN_SAMPLES];
++        samples = silence;
++        ready = LINE_IN_SAMPLES;
++    }
++
++    num_samples = audio_MIN(ready, num_samples);
++
++    if (hw->wpos + num_samples > hw->samples) {
++        len[0] = hw->samples - hw->wpos;
++        len[1] = num_samples - len[0];
++    } else {
++        len[0] = num_samples;
++        len[1] = 0;
++    }
++
++    hw->conv(hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume);
++
++    if (len[1]) {
++        hw->conv(hw->conv_buf, samples + len[0], len[1],
++                 &nominal_volume);
++    }
++
++    hw->wpos = (hw->wpos + num_samples) % hw->samples;
++
++    return num_samples;
++}
++
++static int line_in_read(SWVoiceIn *sw, void *buf, int size)
++{
++    return audio_pcm_sw_read(sw, buf, size);
++}
++
++static int line_in_ctl(HWVoiceIn *hw, int cmd, ...)
++{
++    SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
++
++    switch (cmd) {
++    case VOICE_ENABLE:
++        if (in->active) {
++            break;
++        }
++        in->active = 1;
++        in->prev_ticks = qemu_get_clock (vm_clock);
++        spice_server_record_start(&in->sin);
++        break;
++    case VOICE_DISABLE:
++        if (!in->active) {
++            break;
++        }
++        in->active = 0;
++        spice_server_record_stop(&in->sin);
++        break;
++    }
++    return 0;
++}
++
++static struct audio_option audio_options[] = {
++    { /* end of list */ },
++};
++
++static struct audio_pcm_ops audio_callbacks = {
++    .init_out = line_out_init,
++    .fini_out = line_out_fini,
++    .run_out  = line_out_run,
++    .write    = line_out_write,
++    .ctl_out  = line_out_ctl,
++
++    .init_in  = line_in_init,
++    .fini_in  = line_in_fini,
++    .run_in   = line_in_run,
++    .read     = line_in_read,
++    .ctl_in   = line_in_ctl,
++};
++
++struct audio_driver spice_audio_driver = {
++    .name           = "spice",
++    .descr          = "spice audio driver",
++    .options        = audio_options,
++    .init           = spice_audio_init,
++    .fini           = spice_audio_fini,
++    .pcm_ops        = &audio_callbacks,
++    .max_voices_out = 1,
++    .max_voices_in  = 1,
++    .voice_size_out = sizeof(SpiceVoiceOut),
++    .voice_size_in  = sizeof(SpiceVoiceIn),
++};
++
++void qemu_spice_audio_init(void)
++{
++    spice_audio_driver.can_be_default = 1;
++}
+diff --git a/qemu-spice.h b/qemu-spice.h
+index f061004..6f19ba7 100644
+--- a/qemu-spice.h
++++ b/qemu-spice.h
+@@ -13,6 +13,7 @@ extern int using_spice;
+
+ void qemu_spice_init(void);
+ void qemu_spice_input_init(void);
++void qemu_spice_audio_init(void);
+ void qemu_spice_display_init(DisplayState *ds);
+
+ #else  /* CONFIG_SPICE */
+diff --git a/spice.c b/spice.c
+index 3fe76cd..fc76ef7 100644
+--- a/spice.c
++++ b/spice.c
+@@ -204,6 +204,7 @@ void qemu_spice_init(void)
+     using_spice = 1;
+
+     qemu_spice_input_init();
++    qemu_spice_audio_init();
+
+     qemu_free(x509_key_file);
+     qemu_free(x509_cert_file);
+-- 
+1.7.2.3
+
diff --git a/0016-spice-add-virtio-serial-based-vdi-port-backend.patch b/0016-spice-add-virtio-serial-based-vdi-port-backend.patch
new file mode 100644
index 0000000..91528c9
--- /dev/null
+++ b/0016-spice-add-virtio-serial-based-vdi-port-backend.patch
@@ -0,0 +1,238 @@
+From ebf4cebd082442ed2bc11475fde301c18648298d Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Tue, 20 Apr 2010 13:33:54 +0200
+Subject: [PATCH 16/39] spice: add virtio-serial based vdi port backend.
+
+Adds the spicevmc device.  This is a communication channel between the
+spice client and the guest.  It is used to send display information and
+mouse events from the spice clients to the guest.
+---
+ Makefile.target |    1 +
+ hw/spice-vmc.c  |  203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 204 insertions(+), 0 deletions(-)
+ create mode 100644 hw/spice-vmc.c
+
+diff --git a/Makefile.target b/Makefile.target
+index 4da33b5..90544c5 100644
+--- a/Makefile.target
++++ b/Makefile.target
+@@ -217,6 +217,7 @@ obj-i386-y += pc_piix.o
+ obj-i386-y += testdev.o
+ obj-i386-y += acpi.o acpi_piix4.o
+ obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
++obj-i386-$(CONFIG_SPICE) += spice-vmc.o
+
+ obj-i386-y += pcspk.o i8254.o
+ obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+new file mode 100644
+index 0000000..3f6a2bb
+--- /dev/null
++++ b/hw/spice-vmc.c
+@@ -0,0 +1,203 @@
++/*
++
++ Spice Virtual Machine Channel (VMC).
++
++ A virtio-serial port used for spice to guest communication, over
++ which spice client and a daemon in the guest operating system
++ communicate.
++
++ Replaces the old vdi_port PCI device.
++
++*/
++
++#include <stdio.h>
++#include <stdbool.h>
++#include <spice.h>
++#include <spice-experimental.h>
++
++#include "virtio-serial.h"
++#include "qemu-spice.h"
++
++#define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
++#define VMC_DEVICE_NAME       "spicevmc"
++
++#define dprintf(_svc, _level, _fmt, ...)                                \
++    do {                                                                \
++        if (_svc->debug >= _level) {                                    \
++            fprintf(stderr, "svc: " _fmt, ## __VA_ARGS__);              \
++        }                                                               \
++    } while (0)
++
++typedef struct SpiceVirtualChannel {
++    VirtIOSerialPort      port;
++    VMChangeStateEntry    *vmstate;
++    SpiceVDIPortInstance  sin;
++    bool                  active;
++    uint8_t               *buffer;
++    uint8_t               *datapos;
++    ssize_t               bufsize, datalen;
++    uint32_t              debug;
++} SpiceVirtualChannel;
++
++static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
++{
++    SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
++    ssize_t out;
++
++    out = virtio_serial_write(&svc->port, buf, len);
++    dprintf(svc, 2, "%s: %lu/%d\n", __func__, out, len);
++    return out;
++}
++
++static int vmc_read(SpiceVDIPortInstance *sin, uint8_t *buf, int len)
++{
++    SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
++    int bytes = MIN(len, svc->datalen);
++
++    dprintf(svc, 2, "%s: %d/%zd\n", __func__, bytes, svc->datalen);
++    if (bytes) {
++        memcpy(buf, svc->datapos, bytes);
++        svc->datapos += bytes;
++        svc->datalen -= bytes;
++        if (0 == svc->datalen) {
++            virtio_serial_throttle_port(&svc->port, false);
++        }
++    }
++    return bytes;
++}
++
++static SpiceVDIPortInterface vmc_interface = {
++    .base.type          = SPICE_INTERFACE_VDI_PORT,
++    .base.description   = "spice virtual channel vdi port",
++    .base.major_version = SPICE_INTERFACE_VDI_PORT_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_VDI_PORT_MINOR,
++    .write              = vmc_write,
++    .read               = vmc_read,
++};
++
++static void vmc_register_interface(SpiceVirtualChannel *svc)
++{
++    if (svc->active) {
++        return;
++    }
++    dprintf(svc, 1, "%s\n", __func__);
++    svc->sin.base.sif = &vmc_interface.base;
++    spice_server_add_interface(spice_server, &svc->sin.base);
++    svc->active = true;
++}
++
++static void vmc_unregister_interface(SpiceVirtualChannel *svc)
++{
++    if (!svc->active) {
++        return;
++    }
++    dprintf(svc, 1, "%s\n", __func__);
++    spice_server_remove_interface(&svc->sin.base);
++    svc->active = false;
++}
++
++
++static void vmc_change_state_handler(void *opaque, int running, int reason)
++{
++    SpiceVirtualChannel *svc = opaque;
++
++    if (running && svc->active) {
++        spice_server_vdi_port_wakeup(&svc->sin);
++    }
++}
++
++/*
++ * virtio-serial callbacks
++ */
++
++static void vmc_guest_open(VirtIOSerialPort *port)
++{
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 1, "%s\n", __func__);
++    vmc_register_interface(svc);
++}
++
++static void vmc_guest_close(VirtIOSerialPort *port)
++{
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 1, "%s\n", __func__);
++    vmc_unregister_interface(svc);
++}
++
++static void vmc_guest_ready(VirtIOSerialPort *port)
++{
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 1, "%s\n", __func__);
++    if (svc->active)
++        spice_server_vdi_port_wakeup(&svc->sin);
++}
++
++static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
++{
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 2, "%s: %zd\n", __func__, len);
++    assert(svc->datapos == 0);
++    if (svc->bufsize < len) {
++        svc->bufsize = len;
++        svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
++    }
++    memcpy(svc->buffer, buf, len);
++    svc->datapos = svc->buffer;
++    svc->datalen = len;
++    virtio_serial_throttle_port(&svc->port, true);
++    spice_server_vdi_port_wakeup(&svc->sin);
++}
++
++static int vmc_initfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    if (!using_spice)
++        return -1;
++
++    dprintf(svc, 1, "%s\n", __func__);
++    port->name = qemu_strdup(VMC_GUEST_DEVICE_NAME);
++    svc->vmstate = qemu_add_vm_change_state_handler(
++        vmc_change_state_handler, svc);
++    virtio_serial_open(port);
++    return 0;
++}
++
++static int vmc_exitfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 1, "%s\n", __func__);
++    vmc_unregister_interface(svc);
++    qemu_del_vm_change_state_handler(svc->vmstate);
++    virtio_serial_close(port);
++    return 0;
++}
++
++static VirtIOSerialPortInfo vmc_info = {
++    .qdev.name     = VMC_DEVICE_NAME,
++    .qdev.size     = sizeof(SpiceVirtualChannel),
++    .init          = vmc_initfn,
++    .exit          = vmc_exitfn,
++    .guest_open    = vmc_guest_open,
++    .guest_close   = vmc_guest_close,
++    .guest_ready   = vmc_guest_ready,
++    .have_data     = vmc_have_data,
++    .qdev.props = (Property[]) {
++        DEFINE_PROP_UINT32("nr", SpiceVirtualChannel, port.id, VIRTIO_CONSOLE_BAD_ID),
++        DEFINE_PROP_UINT32("debug", SpiceVirtualChannel, debug, 1),
++        DEFINE_PROP_END_OF_LIST(),
++    }
++};
++
++static void vmc_register(void)
++{
++    virtio_serial_port_qdev_register(&vmc_info);
++}
++device_init(vmc_register)
+-- 
+1.7.2.3
+
diff --git a/0017-spice-add-pci-vdi-port-backend-obsolete.patch b/0017-spice-add-pci-vdi-port-backend-obsolete.patch
new file mode 100644
index 0000000..6505bb7
--- /dev/null
+++ b/0017-spice-add-pci-vdi-port-backend-obsolete.patch
@@ -0,0 +1,592 @@
+From ee782dec6adaced9c5bb99d02253505fb635fa12 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Fri, 12 Mar 2010 16:26:18 +0100
+Subject: [PATCH 17/39] spice: add pci vdi port backend (obsolete).
+
+This is *not* intended to be merged upstream.  It is just here
+because the virtio-serial windows guest drivers are not ready,
+so you can't go with the new spice-vmc yet.
+---
+ Makefile.target |    2 +-
+ hw/spice-vdi.c  |  556 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 557 insertions(+), 1 deletions(-)
+ create mode 100644 hw/spice-vdi.c
+
+diff --git a/Makefile.target b/Makefile.target
+index 90544c5..025bdb8 100644
+--- a/Makefile.target
++++ b/Makefile.target
+@@ -217,7 +217,7 @@ obj-i386-y += pc_piix.o
+ obj-i386-y += testdev.o
+ obj-i386-y += acpi.o acpi_piix4.o
+ obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
+-obj-i386-$(CONFIG_SPICE) += spice-vmc.o
++obj-i386-$(CONFIG_SPICE) += spice-vmc.o spice-vdi.o
+
+ obj-i386-y += pcspk.o i8254.o
+ obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
+diff --git a/hw/spice-vdi.c b/hw/spice-vdi.c
+new file mode 100644
+index 0000000..23cbbe1
+--- /dev/null
++++ b/hw/spice-vdi.c
+@@ -0,0 +1,556 @@
++#include <pthread.h>
++#include <signal.h>
++
++#include "qemu-common.h"
++#include "qemu-spice.h"
++#include "hw/hw.h"
++#include "hw/pc.h"
++#include "hw/pci.h"
++#include "console.h"
++#include "hw/vga_int.h"
++#include "qemu-timer.h"
++#include "sysemu.h"
++#include "console.h"
++#include "pci.h"
++#include "hw.h"
++#include "cpu-common.h"
++
++#include <spice.h>
++#include <spice-experimental.h>
++#include <spice/ipc_ring.h>
++#include <spice/barrier.h>
++
++#undef SPICE_RING_PROD_ITEM
++#define SPICE_RING_PROD_ITEM(r, ret) {                                  \
++        typeof(r) start = r;                                            \
++        typeof(r) end = r + 1;                                          \
++        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
++        typeof(&(r)->items[prod]) m_item = &(r)->items[prod];           \
++        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
++            abort();                                                    \
++        }                                                               \
++        ret = &m_item->el;                                              \
++    }
++
++#undef SPICE_RING_CONS_ITEM
++#define SPICE_RING_CONS_ITEM(r, ret) {                                  \
++        typeof(r) start = r;                                            \
++        typeof(r) end = r + 1;                                          \
++        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
++        typeof(&(r)->items[cons]) m_item = &(r)->items[cons];           \
++        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
++            abort();                                                    \
++        }                                                               \
++        ret = &m_item->el;                                              \
++    }
++
++
++#undef ALIGN
++#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
++
++#define REDHAT_PCI_VENDOR_ID 0x1b36
++#define VDI_PORT_DEVICE_ID 0x0105
++#define VDI_PORT_REVISION 0x01
++
++#define VDI_PORT_INTERRUPT (1 << 0)
++
++#define VDI_PORT_MAGIC (*(uint32_t*)"VDIP")
++
++#define VDI_PORT_DEV_NAME "vdi_port"
++#define VDI_PORT_SAVE_VERSION 20
++
++#include <spice/start-packed.h>
++
++typedef struct SPICE_ATTR_PACKED VDIPortPacket {
++    uint32_t gen;
++    uint32_t size;
++    uint8_t data[512 - 2 * sizeof(uint32_t)];
++} VDIPortPacket;
++
++SPICE_RING_DECLARE(VDIPortRing, VDIPortPacket, 32);
++
++enum {
++    VDI_PORT_IO_RANGE_INDEX,
++    VDI_PORT_RAM_RANGE_INDEX,
++};
++
++enum {
++    VDI_PORT_IO_CONNECTION,
++    VDI_PORT_IO_NOTIFY = 4,
++    VDI_PORT_IO_UPDATE_IRQ = 8,
++
++    VDI_PORT_IO_RANGE_SIZE = 12
++};
++
++typedef struct SPICE_ATTR_PACKED VDIPortRam {
++    uint32_t magic;
++    uint32_t generation;
++    uint32_t int_pending;
++    uint32_t int_mask;
++    VDIPortRing input;
++    VDIPortRing output;
++    uint32_t reserv[32];
++} VDIPortRam;
++
++#include <spice/end-packed.h>
++
++typedef struct PCIVDIPortDevice {
++    PCIDevice pci_dev;
++    uint32_t io_base;
++    uint64_t ram_offset;
++    uint32_t ram_size;
++    VDIPortRam *ram;
++    uint32_t connected;
++    int running;
++    int new_gen_on_resume;
++    int active_interface;
++    SpiceVDIPortInstance sin;
++    int plug_read_pos;
++} PCIVDIPortDevice;
++
++static int debug = 1;
++
++static inline uint32_t msb_mask(uint32_t val)
++{
++    uint32_t mask;
++
++    do {
++        mask = ~(val - 1) & val;
++        val &= ~mask;
++    } while (mask < val);
++
++    return mask;
++}
++
++static inline void atomic_or(uint32_t *var, uint32_t add)
++{
++   __asm__ __volatile__ ("lock; orl %1, %0" : "+m" (*var) : "r" (add) : "memory");
++}
++
++static inline uint32_t atomic_exchange(uint32_t val, uint32_t *ptr)
++{
++   __asm__ __volatile__("xchgl %0, %1" : "+q"(val), "+m" (*ptr) : : "memory");
++   return val;
++}
++
++static void set_dirty(void *base, ram_addr_t offset, void *start, uint32_t length)
++{
++    assert(start >= base);
++
++    ram_addr_t addr =  (ram_addr_t)((uint8_t*)start - (uint8_t*)base) + offset;
++    ram_addr_t end =  ALIGN(addr + length, TARGET_PAGE_SIZE);
++
++    do {
++        cpu_physical_memory_set_dirty(addr);
++        addr += TARGET_PAGE_SIZE;
++    } while ( addr < end );
++}
++
++static inline void vdi_port_set_dirty(PCIVDIPortDevice *d, void *start, uint32_t length)
++{
++    set_dirty(d->ram, d->ram_offset, start, length);
++}
++
++static void vdi_port_new_gen(PCIVDIPortDevice *d)
++{
++    d->ram->generation = (d->ram->generation + 1 == 0) ? 1 : d->ram->generation + 1;
++    vdi_port_set_dirty(d, &d->ram->generation, sizeof(d->ram->generation));
++}
++
++static int vdi_port_irq_level(PCIVDIPortDevice *d)
++{
++    return !!(d->ram->int_pending & d->ram->int_mask);
++}
++
++static void vdi_port_notify_guest(PCIVDIPortDevice *d)
++{
++    uint32_t events = VDI_PORT_INTERRUPT;
++    uint32_t old_pending;
++
++    if (!d->connected) {
++        return;
++    }
++    old_pending = __sync_fetch_and_or(&d->ram->int_pending, events);
++    if ((old_pending & events) == events) {
++        return;
++    }
++    qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
++    vdi_port_set_dirty(d, &d->ram->int_pending, sizeof(d->ram->int_pending));
++}
++
++static int vdi_port_interface_write(SpiceVDIPortInstance *sin,
++                                    const uint8_t *buf, int len)
++{
++    PCIVDIPortDevice *d = container_of(sin, PCIVDIPortDevice, sin);
++    VDIPortRing *ring = &d->ram->output;
++    int do_notify = false;
++    int actual_write = 0;
++    int l = len;
++
++    if (!d->running) {
++        return 0;
++    }
++
++    while (len) {
++        VDIPortPacket *packet;
++        int notify;
++        int wait;
++
++        SPICE_RING_PROD_WAIT(ring, wait);
++        if (wait) {
++            break;
++        }
++
++        SPICE_RING_PROD_ITEM(ring, packet);
++        packet->gen = d->ram->generation;
++        packet->size = MIN(len, sizeof(packet->data));
++        memcpy(packet->data, buf, packet->size);
++        vdi_port_set_dirty(d, packet, sizeof(*packet) - (sizeof(packet->data) - packet->size));
++
++        SPICE_RING_PUSH(ring, notify);
++        do_notify = do_notify || notify;
++        len -= packet->size;
++        buf += packet->size;
++        actual_write += packet->size;
++    }
++    vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
++
++    if (do_notify) {
++        vdi_port_notify_guest(d);
++    }
++    if (debug > 1) {
++        fprintf(stderr, "%s: %d/%d\n", __FUNCTION__, actual_write, l);
++    }
++    return actual_write;
++}
++
++static int vdi_port_interface_read(SpiceVDIPortInstance *sin,
++                                   uint8_t *buf, int len)
++{
++    PCIVDIPortDevice *d = container_of(sin, PCIVDIPortDevice, sin);
++    VDIPortRing *ring = &d->ram->input;
++    uint32_t gen = d->ram->generation;
++    VDIPortPacket *packet;
++    int do_notify = false;
++    int actual_read = 0;
++    int l = len;
++
++    if (!d->running) {
++        return 0;
++    }
++
++    while (!SPICE_RING_IS_EMPTY(ring)) {
++        int notify;
++
++        SPICE_RING_CONS_ITEM(ring, packet);
++        if (packet->gen == gen) {
++            break;
++        }
++        SPICE_RING_POP(ring, notify);
++        do_notify = do_notify || notify;
++    }
++    while (len) {
++        VDIPortPacket *packet;
++        int wait;
++        int now;
++
++        SPICE_RING_CONS_WAIT(ring, wait);
++
++        if (wait) {
++            break;
++        }
++
++        SPICE_RING_CONS_ITEM(ring, packet);
++        if (packet->size > sizeof(packet->data)) {
++            vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
++            printf("%s: bad packet size\n", __FUNCTION__);
++            return 0;
++        }
++        now = MIN(len, packet->size - d->plug_read_pos);
++        memcpy(buf, packet->data + d->plug_read_pos, now);
++        len -= now;
++        buf += now;
++        actual_read +=  now;
++        if ((d->plug_read_pos += now) == packet->size) {
++            int notify;
++
++            d->plug_read_pos = 0;
++            SPICE_RING_POP(ring, notify);
++            do_notify = do_notify || notify;
++        }
++    }
++    vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
++
++    if (do_notify) {
++        vdi_port_notify_guest(d);
++    }
++    if (debug > 1) {
++        fprintf(stderr, "%s: %d/%d\n", __FUNCTION__, actual_read, l);
++    }
++    return actual_read;
++}
++
++static SpiceVDIPortInterface vdi_port_interface = {
++    .base.type          = SPICE_INTERFACE_VDI_PORT,
++    .base.description   = "vdi port",
++    .base.major_version = SPICE_INTERFACE_VDI_PORT_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_VDI_PORT_MINOR,
++
++    .write              = vdi_port_interface_write,
++    .read               = vdi_port_interface_read,
++};
++
++static void vdi_port_register_interface(PCIVDIPortDevice *d)
++{
++    if (d->active_interface ) {
++        return;
++    }
++
++    if (debug) {
++        fprintf(stderr, "%s\n", __FUNCTION__);
++    }
++    d->sin.base.sif = &vdi_port_interface.base;
++    spice_server_add_interface(spice_server, &d->sin.base);
++    d->active_interface = true;
++}
++
++static void vdi_port_unregister_interface(PCIVDIPortDevice *d)
++{
++    if (!d->active_interface ) {
++        return;
++    }
++    if (debug) {
++        fprintf(stderr, "%s\n", __FUNCTION__);
++    }
++    spice_server_remove_interface(&d->sin.base);
++    d->active_interface = false;
++}
++
++static uint32_t vdi_port_dev_connect(PCIVDIPortDevice *d)
++{
++    if (d->connected) {
++        if (debug) {
++            fprintf(stderr, "%s: already connected\n", __FUNCTION__);
++        }
++        return 0;
++    }
++    vdi_port_new_gen(d);
++    d->connected = true;
++    vdi_port_register_interface(d);
++    return d->ram->generation;
++}
++
++static void vdi_port_dev_disconnect(PCIVDIPortDevice *d)
++{
++    if (!d->connected) {
++        if (debug) {
++            fprintf(stderr, "%s: not connected\n", __FUNCTION__);
++        }
++        return;
++    }
++    d->connected = false;
++    vdi_port_unregister_interface(d);
++}
++
++static void vdi_port_dev_notify(PCIVDIPortDevice *d)
++{
++    spice_server_vdi_port_wakeup(&d->sin);
++}
++
++static void vdi_port_write_dword(void *opaque, uint32_t addr, uint32_t val)
++{
++    PCIVDIPortDevice *d = opaque;
++    uint32_t io_port = addr - d->io_base;
++
++    if (debug > 1) {
++        fprintf(stderr, "%s: addr 0x%x val 0x%x\n", __FUNCTION__, addr, val);
++    }
++    switch (io_port) {
++    case VDI_PORT_IO_NOTIFY:
++        if (!d->connected) {
++            fprintf(stderr, "%s: not connected\n", __FUNCTION__);
++            return;
++        }
++        vdi_port_dev_notify(d);
++        break;
++    case VDI_PORT_IO_UPDATE_IRQ:
++        qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
++        break;
++    case VDI_PORT_IO_CONNECTION:
++        vdi_port_dev_disconnect(d);
++        break;
++    default:
++        if (debug) {
++            fprintf(stderr, "%s: unexpected addr 0x%x val 0x%x\n",
++                    __FUNCTION__, addr, val);
++        }
++    };
++}
++
++static uint32_t vdi_port_read_dword(void *opaque, uint32_t addr)
++{
++    PCIVDIPortDevice *d = opaque;
++    uint32_t io_port = addr - d->io_base;
++
++    if (debug > 1) {
++        fprintf(stderr, "%s: addr 0x%x\n", __FUNCTION__, addr);
++    }
++    if (io_port == VDI_PORT_IO_CONNECTION) {
++        return vdi_port_dev_connect(d);
++    } else {
++        fprintf(stderr, "%s: unexpected addr 0x%x\n", __FUNCTION__, addr);
++    }
++    return 0xffffffff;
++}
++
++static void vdi_port_io_map(PCIDevice *pci_dev, int region_num,
++                            pcibus_t addr, pcibus_t size, int type)
++{
++    PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev, pci_dev);
++
++    if (debug) {
++        fprintf(stderr, "%s: base 0x%lx size 0x%lx\n", __FUNCTION__, addr, size);
++    }
++    d->io_base = addr;
++    register_ioport_write(addr, size, 4, vdi_port_write_dword, pci_dev);
++    register_ioport_read(addr, size, 4, vdi_port_read_dword, pci_dev);
++}
++
++static void vdi_port_ram_map(PCIDevice *pci_dev, int region_num,
++                             pcibus_t addr, pcibus_t size, int type)
++{
++    PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev, pci_dev);
++
++    if (debug) {
++        fprintf(stderr, "%s: addr 0x%lx size 0x%lx\n", __FUNCTION__, addr, size);
++    }
++
++    assert((addr & (size - 1)) == 0);
++    assert(size ==  d->ram_size);
++
++    cpu_register_physical_memory(addr, size, d->ram_offset | IO_MEM_RAM);
++}
++
++static void vdi_port_reset(PCIVDIPortDevice *d)
++{
++    memset(d->ram, 0, sizeof(*d->ram));
++    SPICE_RING_INIT(&d->ram->input);
++    SPICE_RING_INIT(&d->ram->output);
++    d->ram->magic = VDI_PORT_MAGIC;
++    d->ram->generation = 0;
++    d->ram->int_pending = 0;
++    d->ram->int_mask = 0;
++    d->connected = false;
++    d->plug_read_pos = 0;
++    vdi_port_set_dirty(d, d->ram, sizeof(*d->ram));
++}
++
++static void vdi_port_reset_handler(DeviceState *dev)
++{
++    PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev.qdev, dev);
++
++    if (d->connected) {
++        vdi_port_dev_disconnect(d);
++    }
++
++    vdi_port_reset(d);
++    qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
++}
++
++static int vdi_port_pre_load(void* opaque)
++{
++    PCIVDIPortDevice* d = opaque;
++
++    vdi_port_unregister_interface(d);
++    return 0;
++}
++
++static int vdi_port_post_load(void* opaque,int version_id)
++{
++    PCIVDIPortDevice* d = opaque;
++
++    if (d->connected) {
++        vdi_port_register_interface(d);
++    }
++    return 0;
++}
++
++static void vdi_port_vm_change_state_handler(void *opaque, int running, int reason)
++{
++    PCIVDIPortDevice* d = opaque;
++
++    if (running) {
++        d->running = true;
++        if (d->new_gen_on_resume) {
++            d->new_gen_on_resume = false;
++            vdi_port_new_gen(d);
++            vdi_port_notify_guest(d);
++        }
++        qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
++        vdi_port_dev_notify(d);
++    } else {
++        d->running = false;
++    }
++}
++
++static int vdi_port_init(PCIDevice *dev)
++{
++    PCIVDIPortDevice *vdi = (PCIVDIPortDevice *)dev;
++    uint8_t* config = vdi->pci_dev.config;
++    uint32_t ram_size = msb_mask(sizeof(VDIPortRam) * 2 - 1);
++
++    vdi->ram_offset = qemu_ram_alloc(&vdi->pci_dev.qdev, "bar1", ram_size);
++    vdi->ram = qemu_get_ram_ptr(vdi->ram_offset);
++    vdi_port_reset(vdi);
++    vdi->ram_size = ram_size;
++    vdi->new_gen_on_resume = false;
++    vdi->running = false;
++
++    pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID);
++    pci_config_set_device_id(config, VDI_PORT_DEVICE_ID);
++    pci_config_set_class(config, PCI_CLASS_COMMUNICATION_OTHER);
++    pci_set_byte(&config[PCI_REVISION_ID], VDI_PORT_REVISION);
++    pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
++
++    pci_register_bar(dev, VDI_PORT_IO_RANGE_INDEX,
++                     msb_mask(VDI_PORT_IO_RANGE_SIZE * 2 - 1),
++                     PCI_BASE_ADDRESS_SPACE_IO, vdi_port_io_map);
++
++    pci_register_bar(dev, VDI_PORT_RAM_RANGE_INDEX,
++                     vdi->ram_size , PCI_BASE_ADDRESS_SPACE_MEMORY,
++                     vdi_port_ram_map);
++
++    qemu_add_vm_change_state_handler(vdi_port_vm_change_state_handler, vdi);
++
++    return 0;
++}
++
++static VMStateDescription vdi_port_vmstate = {
++    .name = VDI_PORT_DEV_NAME,
++    .version_id = VDI_PORT_SAVE_VERSION,
++    .minimum_version_id = VDI_PORT_SAVE_VERSION,
++    .pre_load = vdi_port_pre_load,
++    .post_load = vdi_port_post_load,
++    .fields = (VMStateField []) {
++        VMSTATE_PCI_DEVICE(pci_dev, PCIVDIPortDevice),
++        VMSTATE_UINT32(connected, PCIVDIPortDevice),
++        VMSTATE_END_OF_LIST()
++    }
++};
++
++static PCIDeviceInfo vdi_port_info = {
++    .qdev.name = VDI_PORT_DEV_NAME,
++    .qdev.desc = "spice virtual desktop port (obsolete)",
++    .qdev.size = sizeof(PCIVDIPortDevice),
++    .qdev.vmsd = &vdi_port_vmstate,
++    .qdev.reset = vdi_port_reset_handler,
++
++    .init = vdi_port_init,
++};
++
++static void vdi_port_register(void)
++{
++    pci_qdev_register(&vdi_port_info);
++}
++
++device_init(vdi_port_register);
+-- 
+1.7.2.3
+
diff --git a/0018-use-memalign-instead-of-posix_memalign.patch b/0018-use-memalign-instead-of-posix_memalign.patch
new file mode 100644
index 0000000..d7264c4
--- /dev/null
+++ b/0018-use-memalign-instead-of-posix_memalign.patch
@@ -0,0 +1,29 @@
+From 898303cfd535d76ce971f3ac1310696937fbd286 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Mon, 14 Jun 2010 09:53:48 +0200
+Subject: [PATCH 18/39] use memalign instead of posix_memalign
+
+---
+ osdep.c |    5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/osdep.c b/osdep.c
+index 2375a69..ed2fd40 100644
+--- a/osdep.c
++++ b/osdep.c
+@@ -100,7 +100,12 @@ void *qemu_memalign(size_t alignment, size_t size)
+ #if defined(_POSIX_C_SOURCE) && !defined(__sun__)
+     int ret;
+     void *ptr;
++#if 0
+     ret = posix_memalign(&ptr, alignment, size);
++#else
++    ptr = memalign(alignment, size);
++    ret = (ptr == NULL) ? -1 : 0;
++#endif
+     if (ret != 0) {
+         fprintf(stderr, "Failed to allocate %zu B: %s\n",
+                 size, strerror(ret));
+-- 
+1.7.2.3
+
diff --git a/0019-spice-live-migration-wip.patch b/0019-spice-live-migration-wip.patch
new file mode 100644
index 0000000..4e6ef6b
--- /dev/null
+++ b/0019-spice-live-migration-wip.patch
@@ -0,0 +1,179 @@
+From 80b1dac2be1487d31e6766abe2359fcff1bf0481 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Fri, 23 Apr 2010 13:28:21 +0200
+Subject: [PATCH 19/39] spice: live migration (wip).
+
+Handle spice client migration, i.e. inform a spice client connected
+about the new host and connection parameters, so it can move over the
+connection automatically.
+---
+ monitor.c       |    1 +
+ qemu-monitor.hx |   11 +++++++
+ qemu-spice.h    |    2 +
+ spice.c         |   87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 101 insertions(+), 0 deletions(-)
+
+diff --git a/monitor.c b/monitor.c
+index e51df62..6674a8c 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -57,6 +57,7 @@
+ #include "osdep.h"
+ #include "exec-all.h"
+ #include "qemu-kvm.h"
++#include "qemu-spice.h"
+
+ //#define DEBUG
+ //#define DEBUG_COMPLETION
+diff --git a/qemu-monitor.hx b/qemu-monitor.hx
+index da7b796..c2570d9 100644
+--- a/qemu-monitor.hx
++++ b/qemu-monitor.hx
+@@ -2510,6 +2510,17 @@ ETEXI
+
+ HXCOMM DO NOT add new commands after 'info', move your addition before it!
+
++#if defined(CONFIG_SPICE)
++    {
++        .name       = "spice_migrate_info",
++        .args_type  = "hostname:s,port:i?,tls-port:i?,cert-subject:s?",
++        .params     = "hostname port tls-port cert-subject",
++        .help       = "send migration info to spice client",
++	.user_print = monitor_user_noop,
++        .mhandler.cmd_new = mon_spice_migrate,
++    },
++#endif
++
+ STEXI
+ @end table
+ ETEXI
+diff --git a/qemu-spice.h b/qemu-spice.h
+index 6f19ba7..3c8e959 100644
+--- a/qemu-spice.h
++++ b/qemu-spice.h
+@@ -16,6 +16,8 @@ void qemu_spice_input_init(void);
+ void qemu_spice_audio_init(void);
+ void qemu_spice_display_init(DisplayState *ds);
+
++int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
++
+ #else  /* CONFIG_SPICE */
+
+ #define using_spice 0
+diff --git a/spice.c b/spice.c
+index fc76ef7..1109b4f 100644
+--- a/spice.c
++++ b/spice.c
+@@ -11,6 +11,7 @@
+ #include "qemu-queue.h"
+ #include "qemu-x509.h"
+ #include "monitor.h"
++#include "hw/hw.h"
+
+ /* core bits */
+
+@@ -122,8 +123,90 @@ static SpiceCoreInterface core_interface = {
+     .watch_remove       = watch_remove,
+ };
+
++/* handle client migration */
++
++static int spice_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
++{
++    static int last_stage;
++    static int migrate_client, client_connected;
++    int ret = 1;
++
++    if (last_stage != stage) {
++        last_stage = stage;
++        fprintf(stderr, "%s: stage %d\n", __FUNCTION__, stage);
++    } else {
++        fprintf(stderr, ".");
++    }
++
++    switch (stage) {
++    case 1:
++        migrate_client = 1;
++        client_connected = 0;
++        fprintf(stderr, "%s: start client migration\n", __FUNCTION__);
++        if (spice_server_migrate_start(spice_server) != 0) {
++            fprintf(stderr, "%s: fail -> no client migration\n", __FUNCTION__);
++            migrate_client = 0;
++        }
++        break;
++    case 2:
++        if (!migrate_client)
++            break;
++        switch (spice_server_migrate_client_state(spice_server)) {
++        case SPICE_MIGRATE_CLIENT_NONE:
++            fprintf(stderr, "%s: no client connected\n", __FUNCTION__);
++            migrate_client = 0;
++            break;
++        case SPICE_MIGRATE_CLIENT_WAITING:
++            ret = 0;
++            break;
++        case SPICE_MIGRATE_CLIENT_READY:
++            if (!client_connected) {
++                fprintf(stderr, "%s: client connected to target\n", __FUNCTION__);
++                client_connected = 1;
++            }
++            break;
++        }
++        break;
++    case 3:
++        if (migrate_client && client_connected) {
++            fprintf(stderr, "%s: finish client migration\n", __FUNCTION__);
++            spice_server_migrate_end(spice_server, 1);
++        }
++        break;
++    }
++    return ret;
++}
++
++static void spice_save(QEMUFile *f, void *opaque)
++{
++    fprintf(stderr, "%s:\n", __FUNCTION__);
++}
++
++static int spice_load(QEMUFile *f, void *opaque, int version_id)
++{
++    fprintf(stderr, "%s:\n", __FUNCTION__);
++    return 0;
++}
++
+ /* functions for the rest of qemu */
+
++int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
++{
++    const char *hostname = qdict_get_str(qdict, "hostname");
++    const char *subject  = qdict_get_try_str(qdict, "cert-subject");
++    int port             = qdict_get_try_int(qdict, "port", -1);
++    int tls_port         = qdict_get_try_int(qdict, "tls-port", -1);
++
++    if (!spice_server) {
++        qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
++        return -1;
++    }
++
++    /* TODO: Convert to QError */
++    return spice_server_migrate_info(spice_server, hostname,
++                                     port, tls_port, subject);
++}
++
+ void qemu_spice_init(void)
+ {
+     QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+@@ -206,6 +289,10 @@ void qemu_spice_init(void)
+     qemu_spice_input_init();
+     qemu_spice_audio_init();
+
++    register_savevm_live(NULL, "spice", -1, 1, NULL,
++                         spice_live, spice_save, spice_load,
++                         spice_server);
++
+     qemu_free(x509_key_file);
+     qemu_free(x509_cert_file);
+     qemu_free(x509_cacert_file);
+-- 
+1.7.2.3
+
diff --git a/0020-spice-display-draw.h-is-internal-now.patch b/0020-spice-display-draw.h-is-internal-now.patch
new file mode 100644
index 0000000..e734447
--- /dev/null
+++ b/0020-spice-display-draw.h-is-internal-now.patch
@@ -0,0 +1,23 @@
+From 7241cc479a0f4a148ae60336add6d7be80da9ff0 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 8 Jul 2010 14:11:18 +0200
+Subject: [PATCH 20/39] spice-display: draw.h is internal now
+
+---
+ spice-display.h |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/spice-display.h b/spice-display.h
+index 70a7be4..b55e7ea 100644
+--- a/spice-display.h
++++ b/spice-display.h
+@@ -1,5 +1,5 @@
+ #include <spice/ipc_ring.h>
+-#include <spice/draw.h>
++#include <spice/enums.h>
+ #include <spice/qxl_dev.h>
+
+ #include "pflib.h"
+-- 
+1.7.2.3
+
diff --git a/0021-spice-display-disable-debug.patch b/0021-spice-display-disable-debug.patch
new file mode 100644
index 0000000..bdaee85
--- /dev/null
+++ b/0021-spice-display-disable-debug.patch
@@ -0,0 +1,25 @@
+From c269c8b87769b25c9d69d40944de0e883458af86 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 8 Jul 2010 14:31:10 +0200
+Subject: [PATCH 21/39] spice-display: disable debug
+
+---
+ spice-display.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/spice-display.c b/spice-display.c
+index a749e64..2291cc7 100644
+--- a/spice-display.c
++++ b/spice-display.c
+@@ -15,7 +15,7 @@
+
+ #include "spice-display.h"
+
+-static int debug = 1;
++static int debug = 0;
+
+ int qemu_spice_rect_is_empty(const QXLRect* r)
+ {
+-- 
+1.7.2.3
+
diff --git a/0022-spice-display-pci-rev-fixups.patch b/0022-spice-display-pci-rev-fixups.patch
new file mode 100644
index 0000000..87534af
--- /dev/null
+++ b/0022-spice-display-pci-rev-fixups.patch
@@ -0,0 +1,27 @@
+From 2912f038b4bfddd4c3dacb3b0102e45553859632 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 8 Jul 2010 16:29:15 +0200
+Subject: [PATCH 22/39] spice-display: pci rev fixups
+
+---
+ spice-display.c |    4 ----
+ 1 files changed, 0 insertions(+), 4 deletions(-)
+
+diff --git a/spice-display.c b/spice-display.c
+index 2291cc7..87a71cd 100644
+--- a/spice-display.c
++++ b/spice-display.c
+@@ -334,10 +334,6 @@ static const QXLInterface dpy_interface = {
+     .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
+     .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
+
+-    .pci_vendor              = REDHAT_PCI_VENDOR_ID,
+-    .pci_id                  = QXL_DEVICE_ID,
+-    .pci_revision            = QXL_REVISION,
+-
+     .attache_worker          = interface_attach_worker,
+     .set_compression_level   = interface_set_compression_level,
+     .set_mm_time             = interface_set_mm_time,
+-- 
+1.7.2.3
+
diff --git a/0023-qxl-pci-rev-fixups.patch b/0023-qxl-pci-rev-fixups.patch
new file mode 100644
index 0000000..5a9fc24
--- /dev/null
+++ b/0023-qxl-pci-rev-fixups.patch
@@ -0,0 +1,52 @@
+From 727553e1a33dccab2b27ee5e184e003440765289 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 8 Jul 2010 16:29:27 +0200
+Subject: [PATCH 23/39] qxl: pci rev fixups
+
+---
+ hw/qxl.c |   20 ++++++++------------
+ 1 files changed, 8 insertions(+), 12 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 475360c..2a0ea4e 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -511,10 +511,6 @@ static const QXLInterface qxl_interface = {
+     .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
+     .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
+
+-    .pci_vendor              = REDHAT_PCI_VENDOR_ID,
+-    .pci_id                  = QXL_DEVICE_ID,
+-    .pci_revision            = QXL_REVISION,
+-
+     .attache_worker          = interface_attach_worker,
+     .set_compression_level   = interface_set_compression_level,
+     .set_mm_time             = interface_set_mm_time,
+@@ -1136,16 +1132,16 @@ static int qxl_init(PCIDevice *dev)
+     qxl->generation = 1;
+
+     switch (qxl->revision) {
+-    case 1: /* qxl-1 */
+-        pci_device_id  = 0x0100;
+-        pci_device_rev = 1;
++    case 1: /* spice 0.4 -- qxl-1 */
++        pci_device_id  = QXL_DEVICE_ID_STABLE;
++        pci_device_rev = QXL_REVISION_STABLE_V04;
+         break;
+-    case 2: /* qxl-2 */
+-        pci_device_id  = 0x0100;
+-        pci_device_rev = 2;
++    case 2: /* spice 0.6 -- qxl-2 */
++        pci_device_id  = QXL_DEVICE_ID_STABLE;
++        pci_device_rev = QXL_REVISION_STABLE_V06;
+         break;
+-    default: /* unstable */
+-        pci_device_id  = 0x01ff;
++    default: /* experimental */
++        pci_device_id  = QXL_DEVICE_ID_DEVEL;
+         pci_device_rev = 1;
+         break;
+     }
+-- 
+1.7.2.3
+
diff --git a/0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch b/0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch
new file mode 100644
index 0000000..07882f3
--- /dev/null
+++ b/0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch
@@ -0,0 +1,26 @@
+From c9f9044475d392e55de4dd6e343477ce1a57eabc Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 8 Jul 2010 17:51:09 +0200
+Subject: [PATCH 24/39] qxl: support QXL_IO_DESTROY_ALL_SURFACES
+
+---
+ hw/qxl.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 2a0ea4e..7bd4467 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -930,6 +930,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+     case QXL_IO_DESTROY_SURFACE_WAIT:
+         d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
+         break;
++    case QXL_IO_DESTROY_ALL_SURFACES:
++        d->ssd.worker->destroy_surfaces(d->ssd.worker);
++        break;
+     default:
+         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
+         abort();
+-- 
+1.7.2.3
+
diff --git a/0025-spice-vmc-two-bugfixes-in-vmc_read.patch b/0025-spice-vmc-two-bugfixes-in-vmc_read.patch
new file mode 100644
index 0000000..3b4178b
--- /dev/null
+++ b/0025-spice-vmc-two-bugfixes-in-vmc_read.patch
@@ -0,0 +1,57 @@
+From c8fa37e075cf59e8b21af9211f6a6348c92ed098 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Mon, 12 Jul 2010 22:48:59 +0300
+Subject: [PATCH 25/39] spice-vmc: two bugfixes in vmc_read
+
+ * throttling with no discard means possible recursion, make
+  vmc_read handle that.
+ * zero datapos when data is done (from rhel6 version)
+---
+ hw/spice-vmc.c |   13 ++++++++-----
+ 1 files changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+index 3f6a2bb..06e30e6 100644
+--- a/hw/spice-vmc.c
++++ b/hw/spice-vmc.c
+@@ -45,7 +45,7 @@ static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
+     ssize_t out;
+
+     out = virtio_serial_write(&svc->port, buf, len);
+-    dprintf(svc, 2, "%s: %lu/%d\n", __func__, out, len);
++    dprintf(svc, 3, "%s: %lu/%d\n", __func__, out, len);
+     return out;
+ }
+
+@@ -54,13 +54,16 @@ static int vmc_read(SpiceVDIPortInstance *sin, uint8_t *buf, int len)
+     SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
+     int bytes = MIN(len, svc->datalen);
+
+-    dprintf(svc, 2, "%s: %d/%zd\n", __func__, bytes, svc->datalen);
+-    if (bytes) {
++    dprintf(svc, 2, "%s: %p %d/%d/%zd\n", __func__, svc->datapos, len, bytes, svc->datalen);
++    if (bytes > 0) {
+         memcpy(buf, svc->datapos, bytes);
+         svc->datapos += bytes;
+         svc->datalen -= bytes;
+-        if (0 == svc->datalen) {
++        assert(svc->datalen >= 0);
++        if (svc->datalen == 0) {
++            svc->datapos = 0;
+             virtio_serial_throttle_port(&svc->port, false);
++            // ^^^ !!! may call vmc_have_data, so don't touch svc after it!
+         }
+     }
+     return bytes;
+@@ -140,7 +143,7 @@ static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len
+     SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
+
+     dprintf(svc, 2, "%s: %zd\n", __func__, len);
+-    assert(svc->datapos == 0);
++    assert(svc->datalen == 0);
+     if (svc->bufsize < len) {
+         svc->bufsize = len;
+         svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
+-- 
+1.7.2.3
+
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
new file mode 100644
index 0000000..0af9bae
--- /dev/null
+++ b/0026-spice-enabling-disabling-jpeg-and-zlib-over-glz-via-.patch
@@ -0,0 +1,84 @@
+From 0045574847883167f5c2b569811e049616ee611d Mon Sep 17 00:00:00 2001
+From: Yonit Halperin <yhalperi at redhat.com>
+Date: Wed, 14 Jul 2010 13:26:34 +0300
+Subject: [PATCH 26/39] spice: enabling/disabling jpeg and zlib-over-glz via spice command line args
+
+---
+ qemu-config.c |    6 ++++++
+ spice.c       |   29 +++++++++++++++++++++++++++++
+ 2 files changed, 35 insertions(+), 0 deletions(-)
+
+diff --git a/qemu-config.c b/qemu-config.c
+index 74bfc62..3e4fcf9 100644
+--- a/qemu-config.c
++++ b/qemu-config.c
+@@ -384,6 +384,12 @@ QemuOptsList qemu_spice_opts = {
+         },{
+             .name = "tls-ciphers",
+             .type = QEMU_OPT_STRING,
++        },{
++            .name = "jpeg",
++            .type = QEMU_OPT_STRING,
++        },{
++            .name = "zlib-glz",
++            .type = QEMU_OPT_STRING,
+         },
+         { /* end if list */ }
+     },
+diff --git a/spice.c b/spice.c
+index 1109b4f..201e53c 100644
+--- a/spice.c
++++ b/spice.c
+@@ -207,6 +207,23 @@ int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+                                      port, tls_port, subject);
+ }
+
++static inline spice_wan_compression_t get_wan_compression_value(const char *str)
++{
++    if (!strcmp(str, "wan")) {
++        return SPICE_WAN_COMPRESSION_AUTO;
++    }
++
++    if (!strcmp(str, "never")) {
++        return SPICE_WAN_COMPRESSION_NEVER;
++    }
++
++    if (!strcmp(str, "always")) {
++        return SPICE_WAN_COMPRESSION_ALWAYS;
++    }
++
++    return SPICE_WAN_COMPRESSION_INVALID;
++}
++
+ void qemu_spice_init(void)
+ {
+     QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+@@ -218,6 +235,7 @@ void qemu_spice_init(void)
+         *x509_cert_file = NULL,
+         *x509_cacert_file = NULL;
+     int port, tls_port, len;
++    const char *jpeg, *zlib_glz;
+
+     if (!opts)
+         return;
+@@ -283,6 +301,17 @@ void qemu_spice_init(void)
+     /* TODO: make configurable via cmdline */
+     spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
+
++    jpeg = qemu_opt_get(opts, "jpeg");
++    zlib_glz = qemu_opt_get(opts, "zlib-glz");
++
++    if (jpeg) {
++        spice_server_set_jpeg_compression(spice_server, get_wan_compression_value(jpeg));
++    }
++
++    if (zlib_glz) {
++        spice_server_set_zlib_glz_compression(spice_server, get_wan_compression_value(zlib_glz));
++    }
++
+     spice_server_init(spice_server, &core_interface);
+     using_spice = 1;
+
+-- 
+1.7.2.3
+
diff --git a/0027-ifdef-new-config-options.patch b/0027-ifdef-new-config-options.patch
new file mode 100644
index 0000000..9b185eb
--- /dev/null
+++ b/0027-ifdef-new-config-options.patch
@@ -0,0 +1,57 @@
+From 9200133d24ee5b5dab71ce922882c3534d9e8a5a Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 15 Jul 2010 09:01:28 +0200
+Subject: [PATCH 27/39] ifdef new config options.
+
+---
+ spice.c |    6 +++++-
+ 1 files changed, 5 insertions(+), 1 deletions(-)
+
+diff --git a/spice.c b/spice.c
+index 201e53c..76e6ac1 100644
+--- a/spice.c
++++ b/spice.c
+@@ -207,6 +207,7 @@ int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+                                      port, tls_port, subject);
+ }
+
++#if defined(SPICE_SERVER_VERSION) && SPICE_SERVER_VERSION >= 0x000503
+ static inline spice_wan_compression_t get_wan_compression_value(const char *str)
+ {
+     if (!strcmp(str, "wan")) {
+@@ -223,6 +224,7 @@ static inline spice_wan_compression_t get_wan_compression_value(const char *str)
+
+     return SPICE_WAN_COMPRESSION_INVALID;
+ }
++#endif
+
+ void qemu_spice_init(void)
+ {
+@@ -235,7 +237,6 @@ void qemu_spice_init(void)
+         *x509_cert_file = NULL,
+         *x509_cacert_file = NULL;
+     int port, tls_port, len;
+-    const char *jpeg, *zlib_glz;
+
+     if (!opts)
+         return;
+@@ -301,6 +302,8 @@ void qemu_spice_init(void)
+     /* TODO: make configurable via cmdline */
+     spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
+
++#if defined(SPICE_SERVER_VERSION) && SPICE_SERVER_VERSION >= 0x000503
++    const char *jpeg, *zlib_glz;
+     jpeg = qemu_opt_get(opts, "jpeg");
+     zlib_glz = qemu_opt_get(opts, "zlib-glz");
+
+@@ -311,6 +314,7 @@ void qemu_spice_init(void)
+     if (zlib_glz) {
+         spice_server_set_zlib_glz_compression(spice_server, get_wan_compression_value(zlib_glz));
+     }
++#endif
+
+     spice_server_init(spice_server, &core_interface);
+     using_spice = 1;
+-- 
+1.7.2.3
+
diff --git a/0028-spice-vmc-add-counter-to-debug-statements.patch b/0028-spice-vmc-add-counter-to-debug-statements.patch
new file mode 100644
index 0000000..2a3b23c
--- /dev/null
+++ b/0028-spice-vmc-add-counter-to-debug-statements.patch
@@ -0,0 +1,27 @@
+From 2165916a311108d39c7aa45e5189af26712234b8 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Wed, 14 Jul 2010 16:30:35 +0300
+Subject: [PATCH 28/39] spice-vmc: add counter to debug statements
+
+---
+ hw/spice-vmc.c |    3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+index 06e30e6..041f243 100644
+--- a/hw/spice-vmc.c
++++ b/hw/spice-vmc.c
+@@ -23,8 +23,9 @@
+
+ #define dprintf(_svc, _level, _fmt, ...)                                \
+     do {                                                                \
++        static unsigned __dprintf_counter = 0;                          \
+         if (_svc->debug >= _level) {                                    \
+-            fprintf(stderr, "svc: " _fmt, ## __VA_ARGS__);              \
++            fprintf(stderr, "svc: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
+         }                                                               \
+     } while (0)
+
+-- 
+1.7.2.3
+
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
new file mode 100644
index 0000000..0378f1c
--- /dev/null
+++ b/0029-spice-vmc-split-vmc_write-to-max-sized-virtio_serial.patch
@@ -0,0 +1,53 @@
+From f86c044ae075d142e658e866572eb0a37ecad2e1 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Thu, 22 Jul 2010 00:21:18 +0300
+Subject: [PATCH 29/39] spice-vmc: split vmc_write to max sized virtio_serial_write calls
+
+workaround for current windows driver limitation (RHBZ 617000)
+---
+ hw/spice-vmc.c |   21 ++++++++++++++++++---
+ 1 files changed, 18 insertions(+), 3 deletions(-)
+
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+index 041f243..b9d64a2 100644
+--- a/hw/spice-vmc.c
++++ b/hw/spice-vmc.c
+@@ -21,6 +21,8 @@
+ #define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
+ #define VMC_DEVICE_NAME       "spicevmc"
+
++#define VMC_MAX_HOST_WRITE    2048
++
+ #define dprintf(_svc, _level, _fmt, ...)                                \
+     do {                                                                \
+         static unsigned __dprintf_counter = 0;                          \
+@@ -43,10 +45,23 @@ typedef struct SpiceVirtualChannel {
+ static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
+ {
+     SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
+-    ssize_t out;
++    ssize_t out = 0;
++    ssize_t last_out;
++    uint8_t* p = (uint8_t*)buf;
++
++    while (len > 0) {
++        last_out = virtio_serial_write(&svc->port, p,
++                            MIN(len, VMC_MAX_HOST_WRITE));
++        if (last_out > 0) {
++            out += last_out;
++            len -= last_out;
++            p += last_out;
++        } else {
++            break;
++        }
++    }
+
+-    out = virtio_serial_write(&svc->port, buf, len);
+-    dprintf(svc, 3, "%s: %lu/%d\n", __func__, out, len);
++    dprintf(svc, 3, "%s: %lu/%zd\n", __func__, out, len + out);
+     return out;
+ }
+
+-- 
+1.7.2.3
+
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
new file mode 100644
index 0000000..4eb6f8c
--- /dev/null
+++ b/0030-qxl-add-800x480-resolution-to-qxl_modes-n900-native.patch
@@ -0,0 +1,24 @@
+From be78cc4a136f8ec63dc6d7efd8356625c639a877 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Tue, 3 Aug 2010 11:37:51 +0300
+Subject: [PATCH 30/39] qxl: add 800x480 resolution to qxl_modes (n900 native)
+
+---
+ hw/qxl.c |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 7bd4467..86c0e03 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -64,6 +64,7 @@
+
+ static QXLMode qxl_modes[] = {
+     QXL_MODE_EX(640, 480),
++    QXL_MODE_EX(800, 480),
+     QXL_MODE_EX(800, 600),
+     QXL_MODE_EX(832, 624),
+     QXL_MODE_EX(1024, 768),
+-- 
+1.7.2.3
+
diff --git a/0031-qxl-savevm-fixes.patch b/0031-qxl-savevm-fixes.patch
new file mode 100644
index 0000000..93054e8
--- /dev/null
+++ b/0031-qxl-savevm-fixes.patch
@@ -0,0 +1,259 @@
+From e55e5fd43113a5b266efa6d17e44f0e9231a98ed Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 25 Aug 2010 16:08:37 +0000
+Subject: [PATCH 31/39] qxl: savevm fixes
+
+---
+ hw/qxl.c |  125 +++++++++++++++++++++++++++++++++++++++++++++----------------
+ hw/qxl.h |    6 +++
+ 2 files changed, 98 insertions(+), 33 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 86c0e03..4a15200 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -1087,6 +1087,14 @@ static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
+ {
+     PCIQXLDevice *qxl = opaque;
+     qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
++
++    if (!running && qxl->mode == QXL_MODE_NATIVE) {
++        /* dirty all vram (which holds surfaces) to make sure it is saved */
++        /* FIXME #1: should go out during "live" stage */
++        /* FIXME #2: we only need to save the areas which are actually used */
++        ram_addr_t addr = qxl->vram_offset;
++        qxl_set_dirty(addr, addr + qxl->vram_size);
++    }
+ }
+
+ /* display change listener */
+@@ -1134,6 +1142,8 @@ static int qxl_init(PCIDevice *dev)
+     qxl->id = device_id;
+     qxl->mode = QXL_MODE_UNDEFINED;
+     qxl->generation = 1;
++    qxl->num_memslots = NUM_MEMSLOTS;
++    qxl->num_surfaces = NUM_SURFACES;
+
+     switch (qxl->revision) {
+     case 1: /* spice 0.4 -- qxl-1 */
+@@ -1183,7 +1193,8 @@ static int qxl_init(PCIDevice *dev)
+         if (ram_size < 16 * 1024 * 1024)
+             ram_size = 16 * 1024 * 1024;
+         qxl->vga.vram_size = ram_size;
+-        qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar0", qxl->vga.vram_size);
++        qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram",
++                                              qxl->vga.vram_size);
+         qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
+
+         pci_config_set_class(config, PCI_CLASS_DISPLAY_OTHER);
+@@ -1195,14 +1206,14 @@ static int qxl_init(PCIDevice *dev)
+     pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
+
+     qxl->rom_size = qxl_rom_size();
+-    qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar2", qxl->rom_size);
++    qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size);
+     init_qxl_rom(qxl);
+     init_qxl_ram(qxl);
+
+     if (qxl->vram_size < 16 * 1024 * 1024)
+         qxl->vram_size = 16 * 1024 * 1024;
+     qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
+-    qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar1", qxl->vram_size);
++    qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);
+
+     pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
+                      msb_mask(QXL_IO_RANGE_SIZE * 2 - 1),
+@@ -1237,14 +1248,12 @@ static void qxl_pre_save(void *opaque)
+     uint8_t *ram_start = d->vga.vram_ptr;
+
+     dprintf(d, 1, "%s:\n", __FUNCTION__);
+-#if 1 /* wanna zap this */
+     if (d->last_release == NULL) {
+         d->last_release_offset = 0;
+     } else {
+         d->last_release_offset = (uint8_t *)d->last_release - ram_start;
+     }
+     assert(d->last_release_offset < d->vga.vram_size);
+-#endif
+ }
+
+ static int qxl_pre_load(void *opaque)
+@@ -1306,29 +1315,55 @@ static int qxl_post_load(void *opaque, int version)
+     }
+     dprintf(d, 1, "%s: done\n", __FUNCTION__);
+
+-#if 1 /* wanna zap this */
+-    if (d->last_release_offset >= d->vga.vram_size) {
+-        dprintf(d, 1, "%s: invalid last_release_offset %u, ram_size %u\n",
+-                __FUNCTION__, d->last_release_offset, d->vga.vram_size);
+-        exit(-1);
+-    }
+-
++    assert(d->last_release_offset < d->vga.vram_size);
+     if (d->last_release_offset == 0) {
+         d->last_release = NULL;
+     } else {
+         d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
+     }
+-#endif
++
++    /* spice 0.4 compatibility -- accept but ignore */
++    free(d->worker_data);
++    d->worker_data = NULL;
++    d->worker_data_size = 0;
+
+     return 0;
+ }
+
+-#define QXL_VER 1
++#define QXL_SAVE_VERSION 20
++
++static bool qxl_test_worker_data(void *opaque, int version_id)
++{
++    PCIQXLDevice* d = opaque;
++
++    if (d->revision != 1) {
++        return false;
++    }
++    if (!d->worker_data_size) {
++        return false;
++    }
++    if (!d->worker_data) {
++        d->worker_data = qemu_malloc(d->worker_data_size);
++    }
++    return true;
++}
++
++static bool qxl_test_spice04(void *opaque, int version_id)
++{
++    PCIQXLDevice* d = opaque;
++    return d->revision == 1;
++}
++
++static bool qxl_test_spice06(void *opaque)
++{
++    PCIQXLDevice* d = opaque;
++    return d->revision > 1;
++}
+
+ static VMStateDescription qxl_memslot = {
+     .name               = "qxl-memslot",
+-    .version_id         = QXL_VER,
+-    .minimum_version_id = QXL_VER,
++    .version_id         = QXL_SAVE_VERSION,
++    .minimum_version_id = QXL_SAVE_VERSION,
+     .fields = (VMStateField[]) {
+         VMSTATE_UINT64(slot.mem_start, struct guest_slots),
+         VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
+@@ -1339,8 +1374,8 @@ static VMStateDescription qxl_memslot = {
+
+ static VMStateDescription qxl_surface = {
+     .name               = "qxl-surface",
+-    .version_id         = QXL_VER,
+-    .minimum_version_id = QXL_VER,
++    .version_id         = QXL_SAVE_VERSION,
++    .minimum_version_id = QXL_SAVE_VERSION,
+     .fields = (VMStateField[]) {
+         VMSTATE_UINT32(width,      QXLSurfaceCreate),
+         VMSTATE_UINT32(height,     QXLSurfaceCreate),
+@@ -1355,34 +1390,58 @@ static VMStateDescription qxl_surface = {
+     }
+ };
+
++static VMStateDescription qxl_vmstate_spice06 = {
++    .name               = "qxl/spice06",
++    .version_id         = QXL_SAVE_VERSION,
++    .minimum_version_id = QXL_SAVE_VERSION,
++    .fields = (VMStateField []) {
++        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
++        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
++                             qxl_memslot, struct guest_slots),
++        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
++                       qxl_surface, QXLSurfaceCreate),
++        VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice),
++        VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0,
++                      vmstate_info_uint64, uint64_t),
++        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
++        VMSTATE_END_OF_LIST()
++    },
++};
++
+ static VMStateDescription qxl_vmstate = {
+     .name               = "qxl",
+-    .version_id         = QXL_VER,
+-    .minimum_version_id = QXL_VER,
++    .version_id         = QXL_SAVE_VERSION,
++    .minimum_version_id = QXL_SAVE_VERSION,
+     .pre_save           = qxl_pre_save,
+     .pre_load           = qxl_pre_load,
+     .post_load          = qxl_post_load,
+     .fields = (VMStateField []) {
+         VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
+-        VMSTATE_STRUCT(vga, PCIQXLDevice, QXL_VER, vmstate_vga_common, VGACommonState),
++        VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
+         VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
+-#if 1 /* wanna zap this */
+         VMSTATE_UINT32(num_free_res, PCIQXLDevice),
+         VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
+-#endif
+         VMSTATE_UINT32(mode, PCIQXLDevice),
+         VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
+-#if 1 /* new stuff */
+-        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, QXL_VER,
+-                             qxl_memslot, struct guest_slots),
+-        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, QXL_VER,
+-                       qxl_surface, QXLSurfaceCreate),
+-        VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, QXL_VER,
+-                      vmstate_info_uint64, uint64_t),
+-        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
+-#endif
++
++        /* spice 0.4 sends/expects them */
++        VMSTATE_VBUFFER_UINT32(vga.vram_ptr, PCIQXLDevice, 0, qxl_test_spice04, 0,
++                               vga.vram_size),
++        VMSTATE_UINT32_TEST(worker_data_size, PCIQXLDevice, qxl_test_spice04),
++        VMSTATE_VBUFFER_UINT32(worker_data, PCIQXLDevice, 0, qxl_test_worker_data, 0,
++                               worker_data_size),
++
+         VMSTATE_END_OF_LIST()
+-    }
++    },
++    .subsections = (VMStateSubsection[]) {
++        {
++            /* additional spice 0.6 state */
++            .vmsd   = &qxl_vmstate_spice06,
++            .needed = qxl_test_spice06,
++        },{
++            /* end of list */
++        },
++    },
+ };
+
+ static PCIDeviceInfo qxl_info = {
+diff --git a/hw/qxl.h b/hw/qxl.h
+index 1216405..caf3684 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -24,6 +24,9 @@ typedef struct PCIQXLDevice {
+     int                generation;
+     uint32_t           revision;
+
++    int32_t            num_memslots;
++    int32_t            num_surfaces;
++
+     struct guest_slots {
+         QXLMemSlot     slot;
+         void           *ptr;
+@@ -74,6 +77,9 @@ typedef struct PCIQXLDevice {
+     /* io bar */
+     uint32_t           io_base;
+
++    /* spice 0.4 loadvm compatibility */
++    void               *worker_data;
++    uint32_t           worker_data_size;
+ } PCIQXLDevice;
+
+ #define PANIC_ON(x) if ((x)) {                         \
+-- 
+1.7.2.3
+
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
new file mode 100644
index 0000000..54b7715
--- /dev/null
+++ b/0032-Revert-spice-vmc-split-vmc_write-to-max-sized-virtio.patch
@@ -0,0 +1,53 @@
+From f48f184b9d22bbd2e34fb4f3a7a760f0e98fae64 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 8 Sep 2010 11:45:30 +0200
+Subject: [PATCH 32/39] Revert "spice-vmc: split vmc_write to max sized virtio_serial_write calls"
+
+This reverts commit 380b75548db5116e538dc646e84bceb1c4b0e61b.
+---
+ hw/spice-vmc.c |   21 +++------------------
+ 1 files changed, 3 insertions(+), 18 deletions(-)
+
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+index b9d64a2..041f243 100644
+--- a/hw/spice-vmc.c
++++ b/hw/spice-vmc.c
+@@ -21,8 +21,6 @@
+ #define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
+ #define VMC_DEVICE_NAME       "spicevmc"
+
+-#define VMC_MAX_HOST_WRITE    2048
+-
+ #define dprintf(_svc, _level, _fmt, ...)                                \
+     do {                                                                \
+         static unsigned __dprintf_counter = 0;                          \
+@@ -45,23 +43,10 @@ typedef struct SpiceVirtualChannel {
+ static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
+ {
+     SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
+-    ssize_t out = 0;
+-    ssize_t last_out;
+-    uint8_t* p = (uint8_t*)buf;
+-
+-    while (len > 0) {
+-        last_out = virtio_serial_write(&svc->port, p,
+-                            MIN(len, VMC_MAX_HOST_WRITE));
+-        if (last_out > 0) {
+-            out += last_out;
+-            len -= last_out;
+-            p += last_out;
+-        } else {
+-            break;
+-        }
+-    }
++    ssize_t out;
+
+-    dprintf(svc, 3, "%s: %lu/%zd\n", __func__, out, len + out);
++    out = virtio_serial_write(&svc->port, buf, len);
++    dprintf(svc, 3, "%s: %lu/%d\n", __func__, out, len);
+     return out;
+ }
+
+-- 
+1.7.2.3
+
diff --git a/0033-Revert-spice-vmc-add-counter-to-debug-statements.patch b/0033-Revert-spice-vmc-add-counter-to-debug-statements.patch
new file mode 100644
index 0000000..6ff14e4
--- /dev/null
+++ b/0033-Revert-spice-vmc-add-counter-to-debug-statements.patch
@@ -0,0 +1,28 @@
+From a5d6e7e76bf5f5fb0e2c8232ddca2b850bfc1afa Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 8 Sep 2010 11:45:49 +0200
+Subject: [PATCH 33/39] Revert "spice-vmc: add counter to debug statements"
+
+This reverts commit f3ab5192a20ee9dc7776b13ec0ba75030bb52a20.
+---
+ hw/spice-vmc.c |    3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+index 041f243..06e30e6 100644
+--- a/hw/spice-vmc.c
++++ b/hw/spice-vmc.c
+@@ -23,9 +23,8 @@
+
+ #define dprintf(_svc, _level, _fmt, ...)                                \
+     do {                                                                \
+-        static unsigned __dprintf_counter = 0;                          \
+         if (_svc->debug >= _level) {                                    \
+-            fprintf(stderr, "svc: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
++            fprintf(stderr, "svc: " _fmt, ## __VA_ARGS__);              \
+         }                                                               \
+     } while (0)
+
+-- 
+1.7.2.3
+
diff --git a/0034-Revert-spice-vmc-two-bugfixes-in-vmc_read.patch b/0034-Revert-spice-vmc-two-bugfixes-in-vmc_read.patch
new file mode 100644
index 0000000..ce11f48
--- /dev/null
+++ b/0034-Revert-spice-vmc-two-bugfixes-in-vmc_read.patch
@@ -0,0 +1,55 @@
+From 84115ef1adf343c34eebfb1045cbc5c72892e3b2 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 8 Sep 2010 11:46:18 +0200
+Subject: [PATCH 34/39] Revert "spice-vmc: two bugfixes in vmc_read"
+
+This reverts commit 71983a37e30c68beab5e9056a4600d2958f77a04.
+---
+ hw/spice-vmc.c |   13 +++++--------
+ 1 files changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+index 06e30e6..3f6a2bb 100644
+--- a/hw/spice-vmc.c
++++ b/hw/spice-vmc.c
+@@ -45,7 +45,7 @@ static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
+     ssize_t out;
+
+     out = virtio_serial_write(&svc->port, buf, len);
+-    dprintf(svc, 3, "%s: %lu/%d\n", __func__, out, len);
++    dprintf(svc, 2, "%s: %lu/%d\n", __func__, out, len);
+     return out;
+ }
+
+@@ -54,16 +54,13 @@ static int vmc_read(SpiceVDIPortInstance *sin, uint8_t *buf, int len)
+     SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
+     int bytes = MIN(len, svc->datalen);
+
+-    dprintf(svc, 2, "%s: %p %d/%d/%zd\n", __func__, svc->datapos, len, bytes, svc->datalen);
+-    if (bytes > 0) {
++    dprintf(svc, 2, "%s: %d/%zd\n", __func__, bytes, svc->datalen);
++    if (bytes) {
+         memcpy(buf, svc->datapos, bytes);
+         svc->datapos += bytes;
+         svc->datalen -= bytes;
+-        assert(svc->datalen >= 0);
+-        if (svc->datalen == 0) {
+-            svc->datapos = 0;
++        if (0 == svc->datalen) {
+             virtio_serial_throttle_port(&svc->port, false);
+-            // ^^^ !!! may call vmc_have_data, so don't touch svc after it!
+         }
+     }
+     return bytes;
+@@ -143,7 +140,7 @@ static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len
+     SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
+
+     dprintf(svc, 2, "%s: %zd\n", __func__, len);
+-    assert(svc->datalen == 0);
++    assert(svc->datapos == 0);
+     if (svc->bufsize < len) {
+         svc->bufsize = len;
+         svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
+-- 
+1.7.2.3
+
diff --git a/0035-Revert-spice-live-migration-wip.patch b/0035-Revert-spice-live-migration-wip.patch
new file mode 100644
index 0000000..ace3f27
--- /dev/null
+++ b/0035-Revert-spice-live-migration-wip.patch
@@ -0,0 +1,181 @@
+From 3e0d1b6ed5f8e8b871803337008e104398e4db0a Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 8 Sep 2010 11:48:57 +0200
+Subject: [PATCH 35/39] Revert "spice: live migration (wip)."
+
+This reverts commit 85b9db9ba993af737c9c402cf2f67db7b1b3cbce.
+
+Conflicts:
+
+	spice.c
+---
+ monitor.c       |    1 -
+ qemu-monitor.hx |   11 -------
+ qemu-spice.h    |    2 -
+ spice.c         |   87 -------------------------------------------------------
+ 4 files changed, 0 insertions(+), 101 deletions(-)
+
+diff --git a/monitor.c b/monitor.c
+index 6674a8c..e51df62 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -57,7 +57,6 @@
+ #include "osdep.h"
+ #include "exec-all.h"
+ #include "qemu-kvm.h"
+-#include "qemu-spice.h"
+
+ //#define DEBUG
+ //#define DEBUG_COMPLETION
+diff --git a/qemu-monitor.hx b/qemu-monitor.hx
+index c2570d9..da7b796 100644
+--- a/qemu-monitor.hx
++++ b/qemu-monitor.hx
+@@ -2510,17 +2510,6 @@ ETEXI
+
+ HXCOMM DO NOT add new commands after 'info', move your addition before it!
+
+-#if defined(CONFIG_SPICE)
+-    {
+-        .name       = "spice_migrate_info",
+-        .args_type  = "hostname:s,port:i?,tls-port:i?,cert-subject:s?",
+-        .params     = "hostname port tls-port cert-subject",
+-        .help       = "send migration info to spice client",
+-	.user_print = monitor_user_noop,
+-        .mhandler.cmd_new = mon_spice_migrate,
+-    },
+-#endif
+-
+ STEXI
+ @end table
+ ETEXI
+diff --git a/qemu-spice.h b/qemu-spice.h
+index 3c8e959..6f19ba7 100644
+--- a/qemu-spice.h
++++ b/qemu-spice.h
+@@ -16,8 +16,6 @@ void qemu_spice_input_init(void);
+ void qemu_spice_audio_init(void);
+ void qemu_spice_display_init(DisplayState *ds);
+
+-int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
+-
+ #else  /* CONFIG_SPICE */
+
+ #define using_spice 0
+diff --git a/spice.c b/spice.c
+index 76e6ac1..e6f047d 100644
+--- a/spice.c
++++ b/spice.c
+@@ -11,7 +11,6 @@
+ #include "qemu-queue.h"
+ #include "qemu-x509.h"
+ #include "monitor.h"
+-#include "hw/hw.h"
+
+ /* core bits */
+
+@@ -123,90 +122,8 @@ static SpiceCoreInterface core_interface = {
+     .watch_remove       = watch_remove,
+ };
+
+-/* handle client migration */
+-
+-static int spice_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
+-{
+-    static int last_stage;
+-    static int migrate_client, client_connected;
+-    int ret = 1;
+-
+-    if (last_stage != stage) {
+-        last_stage = stage;
+-        fprintf(stderr, "%s: stage %d\n", __FUNCTION__, stage);
+-    } else {
+-        fprintf(stderr, ".");
+-    }
+-
+-    switch (stage) {
+-    case 1:
+-        migrate_client = 1;
+-        client_connected = 0;
+-        fprintf(stderr, "%s: start client migration\n", __FUNCTION__);
+-        if (spice_server_migrate_start(spice_server) != 0) {
+-            fprintf(stderr, "%s: fail -> no client migration\n", __FUNCTION__);
+-            migrate_client = 0;
+-        }
+-        break;
+-    case 2:
+-        if (!migrate_client)
+-            break;
+-        switch (spice_server_migrate_client_state(spice_server)) {
+-        case SPICE_MIGRATE_CLIENT_NONE:
+-            fprintf(stderr, "%s: no client connected\n", __FUNCTION__);
+-            migrate_client = 0;
+-            break;
+-        case SPICE_MIGRATE_CLIENT_WAITING:
+-            ret = 0;
+-            break;
+-        case SPICE_MIGRATE_CLIENT_READY:
+-            if (!client_connected) {
+-                fprintf(stderr, "%s: client connected to target\n", __FUNCTION__);
+-                client_connected = 1;
+-            }
+-            break;
+-        }
+-        break;
+-    case 3:
+-        if (migrate_client && client_connected) {
+-            fprintf(stderr, "%s: finish client migration\n", __FUNCTION__);
+-            spice_server_migrate_end(spice_server, 1);
+-        }
+-        break;
+-    }
+-    return ret;
+-}
+-
+-static void spice_save(QEMUFile *f, void *opaque)
+-{
+-    fprintf(stderr, "%s:\n", __FUNCTION__);
+-}
+-
+-static int spice_load(QEMUFile *f, void *opaque, int version_id)
+-{
+-    fprintf(stderr, "%s:\n", __FUNCTION__);
+-    return 0;
+-}
+-
+ /* functions for the rest of qemu */
+
+-int mon_spice_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+-{
+-    const char *hostname = qdict_get_str(qdict, "hostname");
+-    const char *subject  = qdict_get_try_str(qdict, "cert-subject");
+-    int port             = qdict_get_try_int(qdict, "port", -1);
+-    int tls_port         = qdict_get_try_int(qdict, "tls-port", -1);
+-
+-    if (!spice_server) {
+-        qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+-        return -1;
+-    }
+-
+-    /* TODO: Convert to QError */
+-    return spice_server_migrate_info(spice_server, hostname,
+-                                     port, tls_port, subject);
+-}
+-
+ #if defined(SPICE_SERVER_VERSION) && SPICE_SERVER_VERSION >= 0x000503
+ static inline spice_wan_compression_t get_wan_compression_value(const char *str)
+ {
+@@ -322,10 +239,6 @@ void qemu_spice_init(void)
+     qemu_spice_input_init();
+     qemu_spice_audio_init();
+
+-    register_savevm_live(NULL, "spice", -1, 1, NULL,
+-                         spice_live, spice_save, spice_load,
+-                         spice_server);
+-
+     qemu_free(x509_key_file);
+     qemu_free(x509_cert_file);
+     qemu_free(x509_cacert_file);
+-- 
+1.7.2.3
+
diff --git a/0036-Revert-spice-add-pci-vdi-port-backend-obsolete.patch b/0036-Revert-spice-add-pci-vdi-port-backend-obsolete.patch
new file mode 100644
index 0000000..fcf7d08
--- /dev/null
+++ b/0036-Revert-spice-add-pci-vdi-port-backend-obsolete.patch
@@ -0,0 +1,590 @@
+From 7bad8970dd7db3e3e0e0b11626656c68f4238884 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 8 Sep 2010 11:49:22 +0200
+Subject: [PATCH 36/39] Revert "spice: add pci vdi port backend (obsolete)."
+
+This reverts commit b56a2ed131bdb4ce42db8f33f87603c416e7a60a.
+---
+ Makefile.target |    2 +-
+ hw/spice-vdi.c  |  556 -------------------------------------------------------
+ 2 files changed, 1 insertions(+), 557 deletions(-)
+ delete mode 100644 hw/spice-vdi.c
+
+diff --git a/Makefile.target b/Makefile.target
+index 025bdb8..90544c5 100644
+--- a/Makefile.target
++++ b/Makefile.target
+@@ -217,7 +217,7 @@ obj-i386-y += pc_piix.o
+ obj-i386-y += testdev.o
+ obj-i386-y += acpi.o acpi_piix4.o
+ obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
+-obj-i386-$(CONFIG_SPICE) += spice-vmc.o spice-vdi.o
++obj-i386-$(CONFIG_SPICE) += spice-vmc.o
+
+ obj-i386-y += pcspk.o i8254.o
+ obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
+diff --git a/hw/spice-vdi.c b/hw/spice-vdi.c
+deleted file mode 100644
+index 23cbbe1..0000000
+--- a/hw/spice-vdi.c
++++ /dev/null
+@@ -1,556 +0,0 @@
+-#include <pthread.h>
+-#include <signal.h>
+-
+-#include "qemu-common.h"
+-#include "qemu-spice.h"
+-#include "hw/hw.h"
+-#include "hw/pc.h"
+-#include "hw/pci.h"
+-#include "console.h"
+-#include "hw/vga_int.h"
+-#include "qemu-timer.h"
+-#include "sysemu.h"
+-#include "console.h"
+-#include "pci.h"
+-#include "hw.h"
+-#include "cpu-common.h"
+-
+-#include <spice.h>
+-#include <spice-experimental.h>
+-#include <spice/ipc_ring.h>
+-#include <spice/barrier.h>
+-
+-#undef SPICE_RING_PROD_ITEM
+-#define SPICE_RING_PROD_ITEM(r, ret) {                                  \
+-        typeof(r) start = r;                                            \
+-        typeof(r) end = r + 1;                                          \
+-        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
+-        typeof(&(r)->items[prod]) m_item = &(r)->items[prod];           \
+-        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
+-            abort();                                                    \
+-        }                                                               \
+-        ret = &m_item->el;                                              \
+-    }
+-
+-#undef SPICE_RING_CONS_ITEM
+-#define SPICE_RING_CONS_ITEM(r, ret) {                                  \
+-        typeof(r) start = r;                                            \
+-        typeof(r) end = r + 1;                                          \
+-        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
+-        typeof(&(r)->items[cons]) m_item = &(r)->items[cons];           \
+-        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
+-            abort();                                                    \
+-        }                                                               \
+-        ret = &m_item->el;                                              \
+-    }
+-
+-
+-#undef ALIGN
+-#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+-
+-#define REDHAT_PCI_VENDOR_ID 0x1b36
+-#define VDI_PORT_DEVICE_ID 0x0105
+-#define VDI_PORT_REVISION 0x01
+-
+-#define VDI_PORT_INTERRUPT (1 << 0)
+-
+-#define VDI_PORT_MAGIC (*(uint32_t*)"VDIP")
+-
+-#define VDI_PORT_DEV_NAME "vdi_port"
+-#define VDI_PORT_SAVE_VERSION 20
+-
+-#include <spice/start-packed.h>
+-
+-typedef struct SPICE_ATTR_PACKED VDIPortPacket {
+-    uint32_t gen;
+-    uint32_t size;
+-    uint8_t data[512 - 2 * sizeof(uint32_t)];
+-} VDIPortPacket;
+-
+-SPICE_RING_DECLARE(VDIPortRing, VDIPortPacket, 32);
+-
+-enum {
+-    VDI_PORT_IO_RANGE_INDEX,
+-    VDI_PORT_RAM_RANGE_INDEX,
+-};
+-
+-enum {
+-    VDI_PORT_IO_CONNECTION,
+-    VDI_PORT_IO_NOTIFY = 4,
+-    VDI_PORT_IO_UPDATE_IRQ = 8,
+-
+-    VDI_PORT_IO_RANGE_SIZE = 12
+-};
+-
+-typedef struct SPICE_ATTR_PACKED VDIPortRam {
+-    uint32_t magic;
+-    uint32_t generation;
+-    uint32_t int_pending;
+-    uint32_t int_mask;
+-    VDIPortRing input;
+-    VDIPortRing output;
+-    uint32_t reserv[32];
+-} VDIPortRam;
+-
+-#include <spice/end-packed.h>
+-
+-typedef struct PCIVDIPortDevice {
+-    PCIDevice pci_dev;
+-    uint32_t io_base;
+-    uint64_t ram_offset;
+-    uint32_t ram_size;
+-    VDIPortRam *ram;
+-    uint32_t connected;
+-    int running;
+-    int new_gen_on_resume;
+-    int active_interface;
+-    SpiceVDIPortInstance sin;
+-    int plug_read_pos;
+-} PCIVDIPortDevice;
+-
+-static int debug = 1;
+-
+-static inline uint32_t msb_mask(uint32_t val)
+-{
+-    uint32_t mask;
+-
+-    do {
+-        mask = ~(val - 1) & val;
+-        val &= ~mask;
+-    } while (mask < val);
+-
+-    return mask;
+-}
+-
+-static inline void atomic_or(uint32_t *var, uint32_t add)
+-{
+-   __asm__ __volatile__ ("lock; orl %1, %0" : "+m" (*var) : "r" (add) : "memory");
+-}
+-
+-static inline uint32_t atomic_exchange(uint32_t val, uint32_t *ptr)
+-{
+-   __asm__ __volatile__("xchgl %0, %1" : "+q"(val), "+m" (*ptr) : : "memory");
+-   return val;
+-}
+-
+-static void set_dirty(void *base, ram_addr_t offset, void *start, uint32_t length)
+-{
+-    assert(start >= base);
+-
+-    ram_addr_t addr =  (ram_addr_t)((uint8_t*)start - (uint8_t*)base) + offset;
+-    ram_addr_t end =  ALIGN(addr + length, TARGET_PAGE_SIZE);
+-
+-    do {
+-        cpu_physical_memory_set_dirty(addr);
+-        addr += TARGET_PAGE_SIZE;
+-    } while ( addr < end );
+-}
+-
+-static inline void vdi_port_set_dirty(PCIVDIPortDevice *d, void *start, uint32_t length)
+-{
+-    set_dirty(d->ram, d->ram_offset, start, length);
+-}
+-
+-static void vdi_port_new_gen(PCIVDIPortDevice *d)
+-{
+-    d->ram->generation = (d->ram->generation + 1 == 0) ? 1 : d->ram->generation + 1;
+-    vdi_port_set_dirty(d, &d->ram->generation, sizeof(d->ram->generation));
+-}
+-
+-static int vdi_port_irq_level(PCIVDIPortDevice *d)
+-{
+-    return !!(d->ram->int_pending & d->ram->int_mask);
+-}
+-
+-static void vdi_port_notify_guest(PCIVDIPortDevice *d)
+-{
+-    uint32_t events = VDI_PORT_INTERRUPT;
+-    uint32_t old_pending;
+-
+-    if (!d->connected) {
+-        return;
+-    }
+-    old_pending = __sync_fetch_and_or(&d->ram->int_pending, events);
+-    if ((old_pending & events) == events) {
+-        return;
+-    }
+-    qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
+-    vdi_port_set_dirty(d, &d->ram->int_pending, sizeof(d->ram->int_pending));
+-}
+-
+-static int vdi_port_interface_write(SpiceVDIPortInstance *sin,
+-                                    const uint8_t *buf, int len)
+-{
+-    PCIVDIPortDevice *d = container_of(sin, PCIVDIPortDevice, sin);
+-    VDIPortRing *ring = &d->ram->output;
+-    int do_notify = false;
+-    int actual_write = 0;
+-    int l = len;
+-
+-    if (!d->running) {
+-        return 0;
+-    }
+-
+-    while (len) {
+-        VDIPortPacket *packet;
+-        int notify;
+-        int wait;
+-
+-        SPICE_RING_PROD_WAIT(ring, wait);
+-        if (wait) {
+-            break;
+-        }
+-
+-        SPICE_RING_PROD_ITEM(ring, packet);
+-        packet->gen = d->ram->generation;
+-        packet->size = MIN(len, sizeof(packet->data));
+-        memcpy(packet->data, buf, packet->size);
+-        vdi_port_set_dirty(d, packet, sizeof(*packet) - (sizeof(packet->data) - packet->size));
+-
+-        SPICE_RING_PUSH(ring, notify);
+-        do_notify = do_notify || notify;
+-        len -= packet->size;
+-        buf += packet->size;
+-        actual_write += packet->size;
+-    }
+-    vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
+-
+-    if (do_notify) {
+-        vdi_port_notify_guest(d);
+-    }
+-    if (debug > 1) {
+-        fprintf(stderr, "%s: %d/%d\n", __FUNCTION__, actual_write, l);
+-    }
+-    return actual_write;
+-}
+-
+-static int vdi_port_interface_read(SpiceVDIPortInstance *sin,
+-                                   uint8_t *buf, int len)
+-{
+-    PCIVDIPortDevice *d = container_of(sin, PCIVDIPortDevice, sin);
+-    VDIPortRing *ring = &d->ram->input;
+-    uint32_t gen = d->ram->generation;
+-    VDIPortPacket *packet;
+-    int do_notify = false;
+-    int actual_read = 0;
+-    int l = len;
+-
+-    if (!d->running) {
+-        return 0;
+-    }
+-
+-    while (!SPICE_RING_IS_EMPTY(ring)) {
+-        int notify;
+-
+-        SPICE_RING_CONS_ITEM(ring, packet);
+-        if (packet->gen == gen) {
+-            break;
+-        }
+-        SPICE_RING_POP(ring, notify);
+-        do_notify = do_notify || notify;
+-    }
+-    while (len) {
+-        VDIPortPacket *packet;
+-        int wait;
+-        int now;
+-
+-        SPICE_RING_CONS_WAIT(ring, wait);
+-
+-        if (wait) {
+-            break;
+-        }
+-
+-        SPICE_RING_CONS_ITEM(ring, packet);
+-        if (packet->size > sizeof(packet->data)) {
+-            vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
+-            printf("%s: bad packet size\n", __FUNCTION__);
+-            return 0;
+-        }
+-        now = MIN(len, packet->size - d->plug_read_pos);
+-        memcpy(buf, packet->data + d->plug_read_pos, now);
+-        len -= now;
+-        buf += now;
+-        actual_read +=  now;
+-        if ((d->plug_read_pos += now) == packet->size) {
+-            int notify;
+-
+-            d->plug_read_pos = 0;
+-            SPICE_RING_POP(ring, notify);
+-            do_notify = do_notify || notify;
+-        }
+-    }
+-    vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items));
+-
+-    if (do_notify) {
+-        vdi_port_notify_guest(d);
+-    }
+-    if (debug > 1) {
+-        fprintf(stderr, "%s: %d/%d\n", __FUNCTION__, actual_read, l);
+-    }
+-    return actual_read;
+-}
+-
+-static SpiceVDIPortInterface vdi_port_interface = {
+-    .base.type          = SPICE_INTERFACE_VDI_PORT,
+-    .base.description   = "vdi port",
+-    .base.major_version = SPICE_INTERFACE_VDI_PORT_MAJOR,
+-    .base.minor_version = SPICE_INTERFACE_VDI_PORT_MINOR,
+-
+-    .write              = vdi_port_interface_write,
+-    .read               = vdi_port_interface_read,
+-};
+-
+-static void vdi_port_register_interface(PCIVDIPortDevice *d)
+-{
+-    if (d->active_interface ) {
+-        return;
+-    }
+-
+-    if (debug) {
+-        fprintf(stderr, "%s\n", __FUNCTION__);
+-    }
+-    d->sin.base.sif = &vdi_port_interface.base;
+-    spice_server_add_interface(spice_server, &d->sin.base);
+-    d->active_interface = true;
+-}
+-
+-static void vdi_port_unregister_interface(PCIVDIPortDevice *d)
+-{
+-    if (!d->active_interface ) {
+-        return;
+-    }
+-    if (debug) {
+-        fprintf(stderr, "%s\n", __FUNCTION__);
+-    }
+-    spice_server_remove_interface(&d->sin.base);
+-    d->active_interface = false;
+-}
+-
+-static uint32_t vdi_port_dev_connect(PCIVDIPortDevice *d)
+-{
+-    if (d->connected) {
+-        if (debug) {
+-            fprintf(stderr, "%s: already connected\n", __FUNCTION__);
+-        }
+-        return 0;
+-    }
+-    vdi_port_new_gen(d);
+-    d->connected = true;
+-    vdi_port_register_interface(d);
+-    return d->ram->generation;
+-}
+-
+-static void vdi_port_dev_disconnect(PCIVDIPortDevice *d)
+-{
+-    if (!d->connected) {
+-        if (debug) {
+-            fprintf(stderr, "%s: not connected\n", __FUNCTION__);
+-        }
+-        return;
+-    }
+-    d->connected = false;
+-    vdi_port_unregister_interface(d);
+-}
+-
+-static void vdi_port_dev_notify(PCIVDIPortDevice *d)
+-{
+-    spice_server_vdi_port_wakeup(&d->sin);
+-}
+-
+-static void vdi_port_write_dword(void *opaque, uint32_t addr, uint32_t val)
+-{
+-    PCIVDIPortDevice *d = opaque;
+-    uint32_t io_port = addr - d->io_base;
+-
+-    if (debug > 1) {
+-        fprintf(stderr, "%s: addr 0x%x val 0x%x\n", __FUNCTION__, addr, val);
+-    }
+-    switch (io_port) {
+-    case VDI_PORT_IO_NOTIFY:
+-        if (!d->connected) {
+-            fprintf(stderr, "%s: not connected\n", __FUNCTION__);
+-            return;
+-        }
+-        vdi_port_dev_notify(d);
+-        break;
+-    case VDI_PORT_IO_UPDATE_IRQ:
+-        qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
+-        break;
+-    case VDI_PORT_IO_CONNECTION:
+-        vdi_port_dev_disconnect(d);
+-        break;
+-    default:
+-        if (debug) {
+-            fprintf(stderr, "%s: unexpected addr 0x%x val 0x%x\n",
+-                    __FUNCTION__, addr, val);
+-        }
+-    };
+-}
+-
+-static uint32_t vdi_port_read_dword(void *opaque, uint32_t addr)
+-{
+-    PCIVDIPortDevice *d = opaque;
+-    uint32_t io_port = addr - d->io_base;
+-
+-    if (debug > 1) {
+-        fprintf(stderr, "%s: addr 0x%x\n", __FUNCTION__, addr);
+-    }
+-    if (io_port == VDI_PORT_IO_CONNECTION) {
+-        return vdi_port_dev_connect(d);
+-    } else {
+-        fprintf(stderr, "%s: unexpected addr 0x%x\n", __FUNCTION__, addr);
+-    }
+-    return 0xffffffff;
+-}
+-
+-static void vdi_port_io_map(PCIDevice *pci_dev, int region_num,
+-                            pcibus_t addr, pcibus_t size, int type)
+-{
+-    PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev, pci_dev);
+-
+-    if (debug) {
+-        fprintf(stderr, "%s: base 0x%lx size 0x%lx\n", __FUNCTION__, addr, size);
+-    }
+-    d->io_base = addr;
+-    register_ioport_write(addr, size, 4, vdi_port_write_dword, pci_dev);
+-    register_ioport_read(addr, size, 4, vdi_port_read_dword, pci_dev);
+-}
+-
+-static void vdi_port_ram_map(PCIDevice *pci_dev, int region_num,
+-                             pcibus_t addr, pcibus_t size, int type)
+-{
+-    PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev, pci_dev);
+-
+-    if (debug) {
+-        fprintf(stderr, "%s: addr 0x%lx size 0x%lx\n", __FUNCTION__, addr, size);
+-    }
+-
+-    assert((addr & (size - 1)) == 0);
+-    assert(size ==  d->ram_size);
+-
+-    cpu_register_physical_memory(addr, size, d->ram_offset | IO_MEM_RAM);
+-}
+-
+-static void vdi_port_reset(PCIVDIPortDevice *d)
+-{
+-    memset(d->ram, 0, sizeof(*d->ram));
+-    SPICE_RING_INIT(&d->ram->input);
+-    SPICE_RING_INIT(&d->ram->output);
+-    d->ram->magic = VDI_PORT_MAGIC;
+-    d->ram->generation = 0;
+-    d->ram->int_pending = 0;
+-    d->ram->int_mask = 0;
+-    d->connected = false;
+-    d->plug_read_pos = 0;
+-    vdi_port_set_dirty(d, d->ram, sizeof(*d->ram));
+-}
+-
+-static void vdi_port_reset_handler(DeviceState *dev)
+-{
+-    PCIVDIPortDevice *d = DO_UPCAST(PCIVDIPortDevice, pci_dev.qdev, dev);
+-
+-    if (d->connected) {
+-        vdi_port_dev_disconnect(d);
+-    }
+-
+-    vdi_port_reset(d);
+-    qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
+-}
+-
+-static int vdi_port_pre_load(void* opaque)
+-{
+-    PCIVDIPortDevice* d = opaque;
+-
+-    vdi_port_unregister_interface(d);
+-    return 0;
+-}
+-
+-static int vdi_port_post_load(void* opaque,int version_id)
+-{
+-    PCIVDIPortDevice* d = opaque;
+-
+-    if (d->connected) {
+-        vdi_port_register_interface(d);
+-    }
+-    return 0;
+-}
+-
+-static void vdi_port_vm_change_state_handler(void *opaque, int running, int reason)
+-{
+-    PCIVDIPortDevice* d = opaque;
+-
+-    if (running) {
+-        d->running = true;
+-        if (d->new_gen_on_resume) {
+-            d->new_gen_on_resume = false;
+-            vdi_port_new_gen(d);
+-            vdi_port_notify_guest(d);
+-        }
+-        qemu_set_irq(d->pci_dev.irq[0], vdi_port_irq_level(d));
+-        vdi_port_dev_notify(d);
+-    } else {
+-        d->running = false;
+-    }
+-}
+-
+-static int vdi_port_init(PCIDevice *dev)
+-{
+-    PCIVDIPortDevice *vdi = (PCIVDIPortDevice *)dev;
+-    uint8_t* config = vdi->pci_dev.config;
+-    uint32_t ram_size = msb_mask(sizeof(VDIPortRam) * 2 - 1);
+-
+-    vdi->ram_offset = qemu_ram_alloc(&vdi->pci_dev.qdev, "bar1", ram_size);
+-    vdi->ram = qemu_get_ram_ptr(vdi->ram_offset);
+-    vdi_port_reset(vdi);
+-    vdi->ram_size = ram_size;
+-    vdi->new_gen_on_resume = false;
+-    vdi->running = false;
+-
+-    pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID);
+-    pci_config_set_device_id(config, VDI_PORT_DEVICE_ID);
+-    pci_config_set_class(config, PCI_CLASS_COMMUNICATION_OTHER);
+-    pci_set_byte(&config[PCI_REVISION_ID], VDI_PORT_REVISION);
+-    pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
+-
+-    pci_register_bar(dev, VDI_PORT_IO_RANGE_INDEX,
+-                     msb_mask(VDI_PORT_IO_RANGE_SIZE * 2 - 1),
+-                     PCI_BASE_ADDRESS_SPACE_IO, vdi_port_io_map);
+-
+-    pci_register_bar(dev, VDI_PORT_RAM_RANGE_INDEX,
+-                     vdi->ram_size , PCI_BASE_ADDRESS_SPACE_MEMORY,
+-                     vdi_port_ram_map);
+-
+-    qemu_add_vm_change_state_handler(vdi_port_vm_change_state_handler, vdi);
+-
+-    return 0;
+-}
+-
+-static VMStateDescription vdi_port_vmstate = {
+-    .name = VDI_PORT_DEV_NAME,
+-    .version_id = VDI_PORT_SAVE_VERSION,
+-    .minimum_version_id = VDI_PORT_SAVE_VERSION,
+-    .pre_load = vdi_port_pre_load,
+-    .post_load = vdi_port_post_load,
+-    .fields = (VMStateField []) {
+-        VMSTATE_PCI_DEVICE(pci_dev, PCIVDIPortDevice),
+-        VMSTATE_UINT32(connected, PCIVDIPortDevice),
+-        VMSTATE_END_OF_LIST()
+-    }
+-};
+-
+-static PCIDeviceInfo vdi_port_info = {
+-    .qdev.name = VDI_PORT_DEV_NAME,
+-    .qdev.desc = "spice virtual desktop port (obsolete)",
+-    .qdev.size = sizeof(PCIVDIPortDevice),
+-    .qdev.vmsd = &vdi_port_vmstate,
+-    .qdev.reset = vdi_port_reset_handler,
+-
+-    .init = vdi_port_init,
+-};
+-
+-static void vdi_port_register(void)
+-{
+-    pci_qdev_register(&vdi_port_info);
+-}
+-
+-device_init(vdi_port_register);
+-- 
+1.7.2.3
+
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
new file mode 100644
index 0000000..654ddc5
--- /dev/null
+++ b/0037-Revert-spice-add-virtio-serial-based-vdi-port-backen.patch
@@ -0,0 +1,236 @@
+From bebcc44cfe5da8a4881292fa564869a481eea4ae Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 8 Sep 2010 11:49:40 +0200
+Subject: [PATCH 37/39] Revert "spice: add virtio-serial based vdi port backend."
+
+This reverts commit ef9e975b1d34c1426867cef832ba6238a401b740.
+---
+ Makefile.target |    1 -
+ hw/spice-vmc.c  |  203 -------------------------------------------------------
+ 2 files changed, 0 insertions(+), 204 deletions(-)
+ delete mode 100644 hw/spice-vmc.c
+
+diff --git a/Makefile.target b/Makefile.target
+index 90544c5..4da33b5 100644
+--- a/Makefile.target
++++ b/Makefile.target
+@@ -217,7 +217,6 @@ obj-i386-y += pc_piix.o
+ obj-i386-y += testdev.o
+ obj-i386-y += acpi.o acpi_piix4.o
+ obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
+-obj-i386-$(CONFIG_SPICE) += spice-vmc.o
+
+ obj-i386-y += pcspk.o i8254.o
+ obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+deleted file mode 100644
+index 3f6a2bb..0000000
+--- a/hw/spice-vmc.c
++++ /dev/null
+@@ -1,203 +0,0 @@
+-/*
+-
+- Spice Virtual Machine Channel (VMC).
+-
+- A virtio-serial port used for spice to guest communication, over
+- which spice client and a daemon in the guest operating system
+- communicate.
+-
+- Replaces the old vdi_port PCI device.
+-
+-*/
+-
+-#include <stdio.h>
+-#include <stdbool.h>
+-#include <spice.h>
+-#include <spice-experimental.h>
+-
+-#include "virtio-serial.h"
+-#include "qemu-spice.h"
+-
+-#define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
+-#define VMC_DEVICE_NAME       "spicevmc"
+-
+-#define dprintf(_svc, _level, _fmt, ...)                                \
+-    do {                                                                \
+-        if (_svc->debug >= _level) {                                    \
+-            fprintf(stderr, "svc: " _fmt, ## __VA_ARGS__);              \
+-        }                                                               \
+-    } while (0)
+-
+-typedef struct SpiceVirtualChannel {
+-    VirtIOSerialPort      port;
+-    VMChangeStateEntry    *vmstate;
+-    SpiceVDIPortInstance  sin;
+-    bool                  active;
+-    uint8_t               *buffer;
+-    uint8_t               *datapos;
+-    ssize_t               bufsize, datalen;
+-    uint32_t              debug;
+-} SpiceVirtualChannel;
+-
+-static int vmc_write(SpiceVDIPortInstance *sin, const uint8_t *buf, int len)
+-{
+-    SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
+-    ssize_t out;
+-
+-    out = virtio_serial_write(&svc->port, buf, len);
+-    dprintf(svc, 2, "%s: %lu/%d\n", __func__, out, len);
+-    return out;
+-}
+-
+-static int vmc_read(SpiceVDIPortInstance *sin, uint8_t *buf, int len)
+-{
+-    SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
+-    int bytes = MIN(len, svc->datalen);
+-
+-    dprintf(svc, 2, "%s: %d/%zd\n", __func__, bytes, svc->datalen);
+-    if (bytes) {
+-        memcpy(buf, svc->datapos, bytes);
+-        svc->datapos += bytes;
+-        svc->datalen -= bytes;
+-        if (0 == svc->datalen) {
+-            virtio_serial_throttle_port(&svc->port, false);
+-        }
+-    }
+-    return bytes;
+-}
+-
+-static SpiceVDIPortInterface vmc_interface = {
+-    .base.type          = SPICE_INTERFACE_VDI_PORT,
+-    .base.description   = "spice virtual channel vdi port",
+-    .base.major_version = SPICE_INTERFACE_VDI_PORT_MAJOR,
+-    .base.minor_version = SPICE_INTERFACE_VDI_PORT_MINOR,
+-    .write              = vmc_write,
+-    .read               = vmc_read,
+-};
+-
+-static void vmc_register_interface(SpiceVirtualChannel *svc)
+-{
+-    if (svc->active) {
+-        return;
+-    }
+-    dprintf(svc, 1, "%s\n", __func__);
+-    svc->sin.base.sif = &vmc_interface.base;
+-    spice_server_add_interface(spice_server, &svc->sin.base);
+-    svc->active = true;
+-}
+-
+-static void vmc_unregister_interface(SpiceVirtualChannel *svc)
+-{
+-    if (!svc->active) {
+-        return;
+-    }
+-    dprintf(svc, 1, "%s\n", __func__);
+-    spice_server_remove_interface(&svc->sin.base);
+-    svc->active = false;
+-}
+-
+-
+-static void vmc_change_state_handler(void *opaque, int running, int reason)
+-{
+-    SpiceVirtualChannel *svc = opaque;
+-
+-    if (running && svc->active) {
+-        spice_server_vdi_port_wakeup(&svc->sin);
+-    }
+-}
+-
+-/*
+- * virtio-serial callbacks
+- */
+-
+-static void vmc_guest_open(VirtIOSerialPort *port)
+-{
+-    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
+-
+-    dprintf(svc, 1, "%s\n", __func__);
+-    vmc_register_interface(svc);
+-}
+-
+-static void vmc_guest_close(VirtIOSerialPort *port)
+-{
+-    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
+-
+-    dprintf(svc, 1, "%s\n", __func__);
+-    vmc_unregister_interface(svc);
+-}
+-
+-static void vmc_guest_ready(VirtIOSerialPort *port)
+-{
+-    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
+-
+-    dprintf(svc, 1, "%s\n", __func__);
+-    if (svc->active)
+-        spice_server_vdi_port_wakeup(&svc->sin);
+-}
+-
+-static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
+-{
+-    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
+-
+-    dprintf(svc, 2, "%s: %zd\n", __func__, len);
+-    assert(svc->datapos == 0);
+-    if (svc->bufsize < len) {
+-        svc->bufsize = len;
+-        svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
+-    }
+-    memcpy(svc->buffer, buf, len);
+-    svc->datapos = svc->buffer;
+-    svc->datalen = len;
+-    virtio_serial_throttle_port(&svc->port, true);
+-    spice_server_vdi_port_wakeup(&svc->sin);
+-}
+-
+-static int vmc_initfn(VirtIOSerialDevice *dev)
+-{
+-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+-    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
+-
+-    if (!using_spice)
+-        return -1;
+-
+-    dprintf(svc, 1, "%s\n", __func__);
+-    port->name = qemu_strdup(VMC_GUEST_DEVICE_NAME);
+-    svc->vmstate = qemu_add_vm_change_state_handler(
+-        vmc_change_state_handler, svc);
+-    virtio_serial_open(port);
+-    return 0;
+-}
+-
+-static int vmc_exitfn(VirtIOSerialDevice *dev)
+-{
+-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+-    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
+-
+-    dprintf(svc, 1, "%s\n", __func__);
+-    vmc_unregister_interface(svc);
+-    qemu_del_vm_change_state_handler(svc->vmstate);
+-    virtio_serial_close(port);
+-    return 0;
+-}
+-
+-static VirtIOSerialPortInfo vmc_info = {
+-    .qdev.name     = VMC_DEVICE_NAME,
+-    .qdev.size     = sizeof(SpiceVirtualChannel),
+-    .init          = vmc_initfn,
+-    .exit          = vmc_exitfn,
+-    .guest_open    = vmc_guest_open,
+-    .guest_close   = vmc_guest_close,
+-    .guest_ready   = vmc_guest_ready,
+-    .have_data     = vmc_have_data,
+-    .qdev.props = (Property[]) {
+-        DEFINE_PROP_UINT32("nr", SpiceVirtualChannel, port.id, VIRTIO_CONSOLE_BAD_ID),
+-        DEFINE_PROP_UINT32("debug", SpiceVirtualChannel, debug, 1),
+-        DEFINE_PROP_END_OF_LIST(),
+-    }
+-};
+-
+-static void vmc_register(void)
+-{
+-    virtio_serial_port_qdev_register(&vmc_info);
+-}
+-device_init(vmc_register)
+-- 
+1.7.2.3
+
diff --git a/0038-spice-add-virtio-serial-based-spice-vmchannel-backen.patch b/0038-spice-add-virtio-serial-based-spice-vmchannel-backen.patch
new file mode 100644
index 0000000..2423deb
--- /dev/null
+++ b/0038-spice-add-virtio-serial-based-spice-vmchannel-backen.patch
@@ -0,0 +1,297 @@
+From 5bdc01e675a51a123a813d62a8ae837db9360b7f Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Tue, 20 Apr 2010 13:33:54 +0200
+Subject: [PATCH 38/39] spice: add virtio-serial based spice vmchannel backend.
+
+Adds the spicevmc device.  This is a communication channel between the
+spice client and the guest.  It is used to send display information and
+mouse events from the spice clients to the guest.
+---
+ Makefile.target |    1 +
+ hw/spice-vmc.c  |  262 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 263 insertions(+), 0 deletions(-)
+ create mode 100644 hw/spice-vmc.c
+
+diff --git a/Makefile.target b/Makefile.target
+index 4da33b5..90544c5 100644
+--- a/Makefile.target
++++ b/Makefile.target
+@@ -217,6 +217,7 @@ obj-i386-y += pc_piix.o
+ obj-i386-y += testdev.o
+ obj-i386-y += acpi.o acpi_piix4.o
+ obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
++obj-i386-$(CONFIG_SPICE) += spice-vmc.o
+
+ obj-i386-y += pcspk.o i8254.o
+ obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
+diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
+new file mode 100644
+index 0000000..b77fc60
+--- /dev/null
++++ b/hw/spice-vmc.c
+@@ -0,0 +1,262 @@
++/*
++
++ Spice Virtual Machine Channel (VMC).
++
++ A virtio-serial port used for spice to guest communication, over
++ which spice client and a daemon in the guest operating system
++ communicate.
++
++ Replaces the old vdi_port PCI device.
++
++*/
++
++#include <stdio.h>
++#include <stdbool.h>
++#include <spice.h>
++#include <spice-experimental.h>
++
++#include "virtio-serial.h"
++#include "qemu-spice.h"
++
++#define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
++#define VMC_DEVICE_NAME       "spicevmc"
++
++/* windows guest driver bug workaround */
++#define VMC_MAX_HOST_WRITE    2048
++
++#define dprintf(_svc, _level, _fmt, ...)                                \
++    do {                                                                \
++        static unsigned __dprintf_counter = 0;                          \
++        if (_svc->debug >= _level) {                                    \
++            fprintf(stderr, "svc: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
++        }                                                               \
++    } while (0)
++
++typedef struct SpiceVirtualChannel {
++    VirtIOSerialPort         port;
++    VMChangeStateEntry       *vmstate;
++    SpiceCharDeviceInstance  sin;
++    char                     *subtype;
++    bool                     active;
++    uint8_t                  *buffer;
++    uint8_t                  *datapos;
++    ssize_t                  bufsize, datalen;
++    uint32_t                 debug;
++} SpiceVirtualChannel;
++
++static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
++{
++    SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
++    ssize_t out = 0;
++    ssize_t last_out;
++    uint8_t* p = (uint8_t*)buf;
++
++    while (len > 0) {
++        last_out = virtio_serial_write(&svc->port, p,
++                            MIN(len, VMC_MAX_HOST_WRITE));
++        if (last_out > 0) {
++            out += last_out;
++            len -= last_out;
++            p += last_out;
++        } else {
++            break;
++        }
++    }
++
++    dprintf(svc, 3, "%s: %lu/%zd\n", __func__, out, len + out);
++    return out;
++}
++
++static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
++{
++    SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
++    int bytes = MIN(len, svc->datalen);
++
++    dprintf(svc, 2, "%s: %p %d/%d/%zd\n", __func__, svc->datapos, len, bytes, svc->datalen);
++    if (bytes > 0) {
++        memcpy(buf, svc->datapos, bytes);
++        svc->datapos += bytes;
++        svc->datalen -= bytes;
++        assert(svc->datalen >= 0);
++        if (svc->datalen == 0) {
++            svc->datapos = 0;
++            virtio_serial_throttle_port(&svc->port, false);
++            // ^^^ !!! may call vmc_have_data, so don't touch svc after it!
++        }
++    }
++    return bytes;
++}
++
++static SpiceCharDeviceInterface vmc_interface = {
++    .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
++    .base.description   = "spice virtual channel char device",
++    .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
++    .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
++    .write              = vmc_write,
++    .read               = vmc_read,
++};
++
++static void vmc_register_interface(SpiceVirtualChannel *svc)
++{
++    if (svc->active) {
++        return;
++    }
++    dprintf(svc, 1, "%s\n", __func__);
++    svc->sin.base.sif = &vmc_interface.base;
++    spice_server_add_interface(spice_server, &svc->sin.base);
++    svc->active = true;
++}
++
++static void vmc_unregister_interface(SpiceVirtualChannel *svc)
++{
++    if (!svc->active) {
++        return;
++    }
++    dprintf(svc, 1, "%s\n", __func__);
++    spice_server_remove_interface(&svc->sin.base);
++    svc->active = false;
++}
++
++
++static void vmc_change_state_handler(void *opaque, int running, int reason)
++{
++    SpiceVirtualChannel *svc = opaque;
++
++    if (running && svc->active) {
++        spice_server_char_device_wakeup(&svc->sin);
++    }
++}
++
++/*
++ * virtio-serial callbacks
++ */
++
++static void vmc_guest_open(VirtIOSerialPort *port)
++{
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 1, "%s\n", __func__);
++    vmc_register_interface(svc);
++}
++
++static void vmc_guest_close(VirtIOSerialPort *port)
++{
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 1, "%s\n", __func__);
++    vmc_unregister_interface(svc);
++}
++
++static void vmc_guest_ready(VirtIOSerialPort *port)
++{
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 1, "%s\n", __func__);
++    if (svc->active) {
++        spice_server_char_device_wakeup(&svc->sin);
++    }
++}
++
++static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
++{
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 2, "%s: %zd\n", __func__, len);
++    assert(svc->datalen == 0);
++    if (svc->bufsize < len) {
++        svc->bufsize = len;
++        svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
++    }
++    memcpy(svc->buffer, buf, len);
++    svc->datapos = svc->buffer;
++    svc->datalen = len;
++    virtio_serial_throttle_port(&svc->port, true);
++    spice_server_char_device_wakeup(&svc->sin);
++}
++
++static void vmc_print_optional_subtypes(void)
++{
++    const char** psubtype = spice_server_char_device_recognized_subtypes();
++    int i;
++
++    fprintf(stderr, "supported subtypes: ");
++    for(i=0; *psubtype != NULL; ++psubtype, ++i) {
++        if (i == 0) {
++            fprintf(stderr, *psubtype);
++        } else {
++            fprintf(stderr, ", %s", *psubtype);
++        }
++    }
++    fprintf(stderr, "\n");
++}
++
++static int vmc_initfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++    const char** psubtype = spice_server_char_device_recognized_subtypes();
++    const char *subtype = NULL;
++
++    if (!using_spice) {
++        return -1;
++    }
++
++    dprintf(svc, 1, "%s\n", __func__);
++
++    if (svc->subtype == NULL) {
++        svc->subtype = strdup("vdagent");
++    }
++
++    for(;*psubtype != NULL; ++psubtype) {
++        if (strcmp(svc->subtype, *psubtype) == 0) {
++            subtype = *psubtype;
++            break;
++        }
++    }
++    if (subtype == NULL) {
++        fprintf(stderr, "spice-vmc: unsupported subtype\n");
++        vmc_print_optional_subtypes();
++        return -1;
++    }
++    port->name = qemu_strdup(VMC_GUEST_DEVICE_NAME);
++    svc->vmstate = qemu_add_vm_change_state_handler
++        (vmc_change_state_handler, svc);
++    svc->sin.subtype = svc->subtype;
++    virtio_serial_open(port);
++    return 0;
++}
++
++static int vmc_exitfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
++
++    dprintf(svc, 1, "%s\n", __func__);
++    vmc_unregister_interface(svc);
++    qemu_del_vm_change_state_handler(svc->vmstate);
++    virtio_serial_close(port);
++    return 0;
++}
++
++static VirtIOSerialPortInfo vmc_info = {
++    .qdev.name     = VMC_DEVICE_NAME,
++    .qdev.size     = sizeof(SpiceVirtualChannel),
++    .init          = vmc_initfn,
++    .exit          = vmc_exitfn,
++    .guest_open    = vmc_guest_open,
++    .guest_close   = vmc_guest_close,
++    .guest_ready   = vmc_guest_ready,
++    .have_data     = vmc_have_data,
++    .qdev.props = (Property[]) {
++        DEFINE_PROP_UINT32("nr", SpiceVirtualChannel, port.id, VIRTIO_CONSOLE_BAD_ID),
++        DEFINE_PROP_UINT32("debug", SpiceVirtualChannel, debug, 1),
++        DEFINE_PROP_STRING("subtype", SpiceVirtualChannel, subtype),
++        DEFINE_PROP_END_OF_LIST(),
++    }
++};
++
++static void vmc_register(void)
++{
++    virtio_serial_port_qdev_register(&vmc_info);
++}
++device_init(vmc_register)
+-- 
+1.7.2.3
+
diff --git a/0039-qxl-fix-release-ring-overrun.patch b/0039-qxl-fix-release-ring-overrun.patch
new file mode 100644
index 0000000..a8d041a
--- /dev/null
+++ b/0039-qxl-fix-release-ring-overrun.patch
@@ -0,0 +1,30 @@
+From 9394cbaab7701fe421d5c0168854d39d6a8ecfc2 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Tue, 7 Sep 2010 16:45:27 +0200
+Subject: [PATCH 39/39] qxl: fix release ring overrun
+
+---
+ hw/qxl.c |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 4a15200..8448893 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -377,10 +377,10 @@ static inline void qxl_push_free_res(PCIQXLDevice *d)
+     QXLReleaseRing *ring = &d->ram->release_ring;
+     uint64_t *item;
+
+-#define QXL_FREE_BUNCH_SIZE 10
++#define QXL_FREE_BUNCH_SIZE 32
+
+-    if (SPICE_RING_IS_EMPTY(ring) || (d->num_free_res == QXL_FREE_BUNCH_SIZE &&
+-                                      ring->prod - ring->cons + 1 != ring->num_items)) {
++    if (SPICE_RING_IS_EMPTY(ring) || (d->num_free_res >= QXL_FREE_BUNCH_SIZE &&
++                                      ring->prod - ring->cons + 2 != ring->num_items)) {
+         int notify;
+
+         SPICE_RING_PUSH(ring, notify);
+-- 
+1.7.2.3
+
diff --git a/pc-add-a-Fedora-13-machine-type-for-backward-compat.patch b/pc-add-a-Fedora-13-machine-type-for-backward-compat.patch
new file mode 100644
index 0000000..25938aa
--- /dev/null
+++ b/pc-add-a-Fedora-13-machine-type-for-backward-compat.patch
@@ -0,0 +1,37 @@
+From: Justin M. Forbes <jforbes at redhat.com>
+Date: Thu, Aug 19 09:13:45 2010 -0500
+Subject: pc: Add a Fedora-13 machine type for backwards compatibility.
+
+In Fedora 13 a fedora-13 machine type was added as default to allow
+interaction with upstream stable qemu which did not support the same
+feature set.  As a result we need to support this machine type through
+the Fedora 15 release.
+
+
+diff --git a/hw/pc_piix.c b/hw/pc_piix.c
+index 9e4bac8..eb1ed05 100644
+--- a/hw/pc_piix.c
++++ b/hw/pc_piix.c
+@@ -237,6 +237,14 @@ static QEMUMachine pc_machine = {
+     .is_default = 1,
+ };
+
++static QEMUMachine pc_machine_f13 = {
++    .name = "fedora-13",
++    .desc = "Standard PC",
++    .init = pc_init_pci,
++    .max_cpus = 255,
++    .is_default = 0,
++};
++
+ static QEMUMachine pc_machine_v0_12 = {
+     .name = "pc-0.12",
+     .desc = "Standard PC",
+@@ -348,6 +356,7 @@ static QEMUMachine isapc_machine = {
+ static void pc_machine_init(void)
+ {
+     qemu_register_machine(&pc_machine);
++    qemu_register_machine(&pc_machine_f13);
+     qemu_register_machine(&pc_machine_v0_12);
+     qemu_register_machine(&pc_machine_v0_11);
+     qemu_register_machine(&pc_machine_v0_10);
diff --git a/qemu.spec b/qemu.spec
index 5d3037d..b76a714 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1,9 +1,7 @@
-%define githead 25fdf4a
-
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 0.13.0
-Release: 0.5.20100809git%{githead}%{?dist}
+Release: 0.6.rc1%{?dist}
 # Epoch because we pushed a qemu-1.0 package
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
@@ -19,11 +17,7 @@ URL: http://www.qemu.org/
 %define _smp_mflags %{nil}
 %endif
 
-# Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}.tar.gz
-# The source for this package was pulled from upstream's git.  Use the
-# following commands to generate the tarball:
-# git archive --format=tar --prefix=qemu-kvm-0.13/ b81fe95 | gzip > qemu-kvm-0.13-b81fe95.tar.gz
-Source0: qemu-kvm-%{version}-%{githead}.tar.gz
+Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}-rc1.tar.gz
 Source1: qemu.init
 
 # Loads kvm kernel modules at boot
@@ -39,6 +33,51 @@ Source6: ksmtuned.init
 Source7: ksmtuned
 Source8: ksmtuned.conf
 
+# This patch must be carried through F-15 to support guests created
+# with F-13/
+Patch00: pc-add-a-Fedora-13-machine-type-for-backward-compat.patch
+
+# Patches from Fedora qemu git (http://git.fedorahosted.org/git/qemu-kvm-fedora.git)
+Patch01: 0001-add-pflib-PixelFormat-conversion-library.patch
+Patch02: 0002-configure-add-logging.patch
+Patch03: 0003-add-spice-into-the-configure-file.patch
+Patch04: 0004-spice-core-bits.patch
+Patch05: 0005-spice-add-keyboard.patch
+Patch06: 0006-spice-add-mouse.patch
+Patch07: 0007-spice-simple-display.patch
+Patch08: 0008-spice-add-tablet-support.patch
+Patch09: 0009-vgabios-update-to-0.6c-pcibios-patches.patch
+Patch10: 0010-switch-stdvga-to-pci-vgabios.patch
+Patch11: 0011-switch-vmware_vga-to-pci-vgabios.patch
+Patch12: 0012-all-vga-refuse-hotplugging.patch
+Patch13: 0013-spice-tls-support.patch
+Patch14: 0014-spice-add-qxl-device.patch
+Patch15: 0015-spice-add-audio.patch
+Patch16: 0016-spice-add-virtio-serial-based-vdi-port-backend.patch
+Patch17: 0017-spice-add-pci-vdi-port-backend-obsolete.patch
+Patch18: 0018-use-memalign-instead-of-posix_memalign.patch
+Patch19: 0019-spice-live-migration-wip.patch
+Patch20: 0020-spice-display-draw.h-is-internal-now.patch
+Patch21: 0021-spice-display-disable-debug.patch
+Patch22: 0022-spice-display-pci-rev-fixups.patch
+Patch23: 0023-qxl-pci-rev-fixups.patch
+Patch24: 0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch
+Patch25: 0025-spice-vmc-two-bugfixes-in-vmc_read.patch
+Patch26: 0026-spice-enabling-disabling-jpeg-and-zlib-over-glz-via-.patch
+Patch27: 0027-ifdef-new-config-options.patch
+Patch28: 0028-spice-vmc-add-counter-to-debug-statements.patch
+Patch29: 0029-spice-vmc-split-vmc_write-to-max-sized-virtio_serial.patch
+Patch30: 0030-qxl-add-800x480-resolution-to-qxl_modes-n900-native.patch
+Patch31: 0031-qxl-savevm-fixes.patch
+Patch32: 0032-Revert-spice-vmc-split-vmc_write-to-max-sized-virtio.patch
+Patch33: 0033-Revert-spice-vmc-add-counter-to-debug-statements.patch
+Patch34: 0034-Revert-spice-vmc-two-bugfixes-in-vmc_read.patch
+Patch35: 0035-Revert-spice-live-migration-wip.patch
+Patch36: 0036-Revert-spice-add-pci-vdi-port-backend-obsolete.patch
+Patch37: 0037-Revert-spice-add-virtio-serial-based-vdi-port-backen.patch
+Patch38: 0038-spice-add-virtio-serial-based-spice-vmchannel-backen.patch
+Patch39: 0039-qxl-fix-release-ring-overrun.patch
+
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel
 BuildRequires: libaio-devel
@@ -48,7 +87,8 @@ BuildRequires: pulseaudio-libs-devel
 BuildRequires: ncurses-devel
 BuildRequires: texinfo
 %ifarch x86_64
-BuildRequires: spice-protocol spice-server-devel
+BuildRequires: spice-protocol >= 0.6.0
+BuildRequires: spice-server-devel >= 0.6.0
 %endif
 Requires: %{name}-user = %{epoch}:%{version}-%{release}
 Requires: %{name}-system-x86 = %{epoch}:%{version}-%{release}
@@ -231,7 +271,48 @@ such as kvm_stat.
 %endif
 
 %prep
-%setup -q -n qemu-kvm-%{version}
+%setup -q -n qemu-kvm-%{version}-rc1
+
+%patch00 -p1
+%patch01 -p1
+%patch02 -p1
+%patch03 -p1
+%patch04 -p1
+%patch05 -p1
+%patch06 -p1
+%patch07 -p1
+%patch08 -p1
+%patch09 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch17 -p1
+%patch18 -p1
+%patch19 -p1
+%patch20 -p1
+%patch21 -p1
+%patch22 -p1
+%patch23 -p1
+%patch24 -p1
+%patch25 -p1
+%patch26 -p1
+%patch27 -p1
+%patch28 -p1
+%patch29 -p1
+%patch30 -p1
+%patch31 -p1
+%patch32 -p1
+%patch33 -p1
+%patch34 -p1
+%patch35 -p1
+%patch36 -p1
+%patch37 -p1
+%patch38 -p1
+%patch39 -p1
 
 %build
 # By default we build everything, but allow x86 to build a minimal version
@@ -546,6 +627,10 @@ fi
 %{_mandir}/man1/qemu-img.1*
 
 %changelog
+* Tue Aug 10 2010 Justin M. Forbes <jforbes at redhat.com> - 2:0.13.0-0.6.rc1
+- Move away from git snapshots as 0.13 is close to release
+- Updates for spice 0.6
+
 * Tue Aug 10 2010 Justin M. Forbes <jforbes at redhat.com> - 2:0.13.0-0.5.20100809git25fdf4a
 - Fix typo in e1000 gpxe rom requires.
 - Add links to newer vgabios
diff --git a/sources b/sources
index 7b285f1..d6e74dd 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-7f083a69c98b6b57bb2a4d52a7b50a72  qemu-kvm-0.13.0-25fdf4a.tar.gz
+b00b0206a49bd962024931b57781dea2  qemu-kvm-0.13.0-rc1.tar.gz


More information about the scm-commits mailing list