[Spice-commits] 188 commits - MAINTAINERS Makefile Makefile.objs Makefile.target aio.c audio/audio.c audio/audio_int.h audio/audio_template.h audio/paaudio.c audio/spiceaudio.c block.c block/cow.c block/curl.c block/iscsi.c block/nbd.c block/qcow2-cluster.c block/qcow2-refcount.c block/qcow2-snapshot.c block/qcow2.c block/qcow2.h block/rbd.c block/sheepdog.c block_int.h cmd.c configure docs/specs error.c exec-all.h fpu/softfloat.c gdbstub.c hmp-commands.hx hw/ac97.c hw/arm_mptimer.c hw/e1000.c hw/ide hw/m48t59.c hw/pc.c hw/pc_piix.c hw/pflash_cfi01.c hw/ptimer.c hw/qdev-monitor.c hw/qdev.c hw/qxl-render.c hw/qxl.c hw/qxl.h hw/realview.c hw/scsi-bus.c hw/scsi-defs.h hw/scsi-disk.c hw/usb hw/usb.h hw/versatile_i2c.c hw/versatilepb.c hw/virtio-scsi.c hw/virtio.c hw/virtio.h hw/xen.h hw/xen_common.h include/qemu linux-aio.c nbd.c nbd.h pc-bios/bios.bin posix-aio-compat.c qapi-schema.json qapi/qmp-input-visitor.c qemu-aio.h qemu-char.c qemu-coroutine-sleep.c qemu-ga.c qemu-img.c qemu-io. c qemu-nbd.c qemu-tool.c qga/commands-posix.c qmp-commands.hx qom/container.c qtest.c qtest.h roms/seabios scripts/create_config scripts/tracetool scripts/tracetool.py spice-qemu-char.c target-arm/cpu-qom.h target-arm/cpu.c target-arm/cpu.h target-arm/helper.c target-cris/cpu-qom.h target-cris/cpu.c target-cris/cpu.h target-cris/translate.c target-microblaze/cpu-qom.h target-microblaze/cpu.c target-microblaze/cpu.h target-microblaze/translate.c target-sparc/cpu.c target-xtensa/translate.c tci.c tests/.gitignore tests/Makefile tests/libqtest.c tests/m48t59-test.c tests/qemu-iotests tests/rtc-test.c tests/tcg trace-events xen-all.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Thu Apr 26 01:21:06 PDT 2012


 MAINTAINERS                           |    2 
 Makefile                              |   16 
 Makefile.objs                         |    6 
 Makefile.target                       |   20 -
 aio.c                                 |  172 +++-----
 audio/audio.c                         |   21 -
 audio/audio_int.h                     |    6 
 audio/audio_template.h                |    2 
 audio/paaudio.c                       |  475 ++++++++++++++++++++++--
 audio/spiceaudio.c                    |   41 ++
 block.c                               |   17 
 block/cow.c                           |    2 
 block/curl.c                          |   10 
 block/iscsi.c                         |    4 
 block/nbd.c                           |   61 ++-
 block/qcow2-cluster.c                 |  226 ++++++++---
 block/qcow2-refcount.c                |  164 ++++----
 block/qcow2-snapshot.c                |   16 
 block/qcow2.c                         |  252 +++++++++++-
 block/qcow2.h                         |   59 ++-
 block/rbd.c                           |    5 
 block/sheepdog.c                      |   11 
 block_int.h                           |    1 
 cmd.c                                 |   10 
 configure                             |   81 +++-
 docs/specs/qcow2.txt                  |  122 +++++-
 error.c                               |    2 
 exec-all.h                            |    2 
 fpu/softfloat.c                       |    4 
 gdbstub.c                             |    3 
 hmp-commands.hx                       |    4 
 hw/ac97.c                             |  139 ++-----
 hw/arm_mptimer.c                      |    3 
 hw/e1000.c                            |    2 
 hw/ide/core.c                         |  137 ++++--
 hw/ide/internal.h                     |    3 
 hw/m48t59.c                           |    6 
 hw/pc.c                               |    2 
 hw/pc_piix.c                          |    4 
 hw/pflash_cfi01.c                     |    1 
 hw/ptimer.c                           |   13 
 hw/qdev-monitor.c                     |    4 
 hw/qdev.c                             |    7 
 hw/qxl-render.c                       |    1 
 hw/qxl.c                              |    6 
 hw/qxl.h                              |    2 
 hw/realview.c                         |   83 ----
 hw/scsi-bus.c                         |    8 
 hw/scsi-defs.h                        |    1 
 hw/scsi-disk.c                        |  170 +++++++-
 hw/usb.h                              |    5 
 hw/usb/bus.c                          |   17 
 hw/usb/core.c                         |   17 
 hw/usb/desc.c                         |  126 +++---
 hw/usb/desc.h                         |   63 +++
 hw/usb/dev-hub.c                      |   43 ++
 hw/usb/hcd-ehci.c                     |   16 
 hw/usb/hcd-uhci.c                     |   16 
 hw/usb/host-linux.c                   |  237 ++++++------
 hw/usb/redirect.c                     |   11 
 hw/versatile_i2c.c                    |  105 +++++
 hw/versatilepb.c                      |   22 +
 hw/virtio-scsi.c                      |   26 -
 hw/virtio.c                           |    7 
 hw/virtio.h                           |    1 
 hw/xen.h                              |   10 
 hw/xen_common.h                       |   15 
 include/qemu/object.h                 |    3 
 linux-aio.c                           |    2 
 nbd.c                                 |  267 +++++++------
 nbd.h                                 |    6 
 pc-bios/bios.bin                      |binary
 posix-aio-compat.c                    |   45 --
 qapi-schema.json                      |   15 
 qapi/qmp-input-visitor.c              |   25 -
 qemu-aio.h                            |   19 
 qemu-char.c                           |    4 
 qemu-coroutine-sleep.c                |    3 
 qemu-ga.c                             |    7 
 qemu-img.c                            |    4 
 qemu-io.c                             |   17 
 qemu-nbd.c                            |   45 +-
 qemu-tool.c                           |    3 
 qga/commands-posix.c                  |   36 +
 qmp-commands.hx                       |    6 
 qom/container.c                       |    4 
 qtest.c                               |    8 
 qtest.h                               |   18 
 roms/seabios                          |    2 
 scripts/create_config                 |    8 
 scripts/tracetool                     |  666 ----------------------------------
 scripts/tracetool.py                  |  138 +++++++
 scripts/tracetool/__init__.py         |  271 +++++++++++++
 scripts/tracetool/backend/__init__.py |  111 +++++
 scripts/tracetool/backend/dtrace.py   |   97 ++++
 scripts/tracetool/backend/simple.py   |   55 ++
 scripts/tracetool/backend/stderr.py   |   56 ++
 scripts/tracetool/backend/ust.py      |   90 ++++
 scripts/tracetool/format/__init__.py  |   99 +++++
 scripts/tracetool/format/c.py         |   20 +
 scripts/tracetool/format/d.py         |   20 +
 scripts/tracetool/format/h.py         |   45 ++
 scripts/tracetool/format/stap.py      |   20 +
 spice-qemu-char.c                     |    2 
 target-arm/cpu-qom.h                  |   37 +
 target-arm/cpu.c                      |  625 +++++++++++++++++++++++++++++++
 target-arm/cpu.h                      |   10 
 target-arm/helper.c                   |  446 ++--------------------
 target-cris/cpu-qom.h                 |   70 +++
 target-cris/cpu.c                     |   90 ++++
 target-cris/cpu.h                     |    2 
 target-cris/translate.c               |   28 -
 target-microblaze/cpu-qom.h           |   70 +++
 target-microblaze/cpu.c               |  119 ++++++
 target-microblaze/cpu.h               |    2 
 target-microblaze/translate.c         |   57 --
 target-sparc/cpu.c                    |    4 
 target-xtensa/translate.c             |    2 
 tci.c                                 |    4 
 tests/.gitignore                      |   13 
 tests/Makefile                        |    3 
 tests/libqtest.c                      |    4 
 tests/m48t59-test.c                   |  259 +++++++++++++
 tests/qemu-iotests/005                |    2 
 tests/qemu-iotests/005.out            |    2 
 tests/qemu-iotests/013.out            |    2 
 tests/qemu-iotests/014.out            |    2 
 tests/qemu-iotests/015.out            |    2 
 tests/qemu-iotests/019.out            |    4 
 tests/qemu-iotests/022.out            |    2 
 tests/qemu-iotests/023.out            |   16 
 tests/qemu-iotests/024.out            |    6 
 tests/qemu-iotests/026.out            |  208 +++++-----
 tests/qemu-iotests/029.out            |    4 
 tests/qemu-iotests/030                |   12 
 tests/qemu-iotests/031                |   44 +-
 tests/qemu-iotests/031.out            |  132 ++++++
 tests/qemu-iotests/032                |   69 +++
 tests/qemu-iotests/032.out            |   78 +++
 tests/qemu-iotests/033                |   73 +++
 tests/qemu-iotests/033.out            |   29 +
 tests/qemu-iotests/034                |  113 +++++
 tests/qemu-iotests/034.out            |   81 ++++
 tests/qemu-iotests/check              |    6 
 tests/qemu-iotests/common             |   17 
 tests/qemu-iotests/common.config      |    2 
 tests/qemu-iotests/common.rc          |   38 +
 tests/qemu-iotests/group              |    3 
 tests/qemu-iotests/qcow2.py           |   24 -
 tests/rtc-test.c                      |   17 
 tests/tcg/xtensa/test_loop.S          |   36 +
 trace-events                          |   27 +
 xen-all.c                             |    2 
 153 files changed, 5831 insertions(+), 2450 deletions(-)

New commits:
commit d6c05bbf29a40c531830e3968491f876328bb08f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Apr 25 18:19:41 2012 +0200

    fix paaudio.c warnings
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/paaudio.c b/audio/paaudio.c
index e6708d0..aa15f16 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -505,8 +505,7 @@ fail:
         pa_stream_unref (stream);
     }
 
-    qpa_logerr (pa_context_errno (g->context),
-                "stream_new() failed\n");
+    *rerror = pa_context_errno (g->context);
 
     return NULL;
 }
commit cf36b31db209a261ee3bc2737e788e1ced0a1bec
Author: Peter Chubb <peter.chubb at nicta.com.au>
Date:   Fri Apr 20 15:32:30 2012 +1000

    Limit ptimer rate to something achievable
    
    If a guest sets very short timeouts, and asks for a timer to be reloaded on
    timeout, QEMU can go to 100%CPU utilisation and become unresponsive,
    as it is spending all its time generating timeout interrupts.  On real
    hardware this doesn't matter, as the interrupts are just coalesced,
    and the effect is to have the interrupt asserted all the time.
    
    This patch is a band-aid, that prevents timeouts less than 10
    microseconds from being set.  10 microseconds is a limit that was
    determined empirically on a variety of machines as the shortest that
    allowed QEMU to pick up a control-a c sequence to get at the monitor.
    
    Reported-by: Anna Lyons <anna.lyons at nicta.com.au>
    Signed-off-by: Peter Chubb <peter.chubb at nicta.com.au>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ptimer.c b/hw/ptimer.c
index de7d664..bc0b3f8 100644
--- a/hw/ptimer.c
+++ b/hw/ptimer.c
@@ -180,6 +180,19 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq)
    count = limit.  */
 void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
 {
+    /*
+     * Artificially limit timeout rate to something
+     * achievable under QEMU.  Otherwise, QEMU spends all
+     * its time generating timer interrupts, and there
+     * is no forward progress.
+     * About ten microseconds is the fastest that really works
+     * on the current generation of host machines.
+     */
+
+    if (limit * s->period < 10000 && s->period) {
+        limit = 10000 / s->period;
+    }
+
     s->limit = limit;
     if (reload)
         s->delta = limit;
commit dfe47e7029e117f65a14c0948021654f7f7d5d05
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Apr 5 13:21:46 2012 +0200

    qom: Refine container_get() to allow using a custom root
    
    Specify the root to search from as argument. This avoids hardcoding
    "/machine" in some places and makes it more flexible.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Paolo Bonzini <pbonzini at redhat.com>
    Cc: Anthony Liguori <anthony at codemonkey.ws>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 81d6548..dc4e4e1 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -181,7 +181,7 @@ static Object *qdev_get_peripheral(void)
     static Object *dev;
 
     if (dev == NULL) {
-        dev = container_get("/machine/peripheral");
+        dev = container_get(qdev_get_machine(), "/peripheral");
     }
 
     return dev;
@@ -192,7 +192,7 @@ static Object *qdev_get_peripheral_anon(void)
     static Object *dev;
 
     if (dev == NULL) {
-        dev = container_get("/machine/peripheral-anon");
+        dev = container_get(qdev_get_machine(), "/peripheral-anon");
     }
 
     return dev;
diff --git a/hw/qdev.c b/hw/qdev.c
index afbc975..0bcde20 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -158,8 +158,9 @@ int qdev_init(DeviceState *dev)
         static int unattached_count = 0;
         gchar *name = g_strdup_printf("device[%d]", unattached_count++);
 
-        object_property_add_child(container_get("/machine/unattached"), name,
-                                  OBJECT(dev), NULL);
+        object_property_add_child(container_get(qdev_get_machine(),
+                                                "/unattached"),
+                                  name, OBJECT(dev), NULL);
         g_free(name);
     }
 
@@ -677,7 +678,7 @@ Object *qdev_get_machine(void)
     static Object *dev;
 
     if (dev == NULL) {
-        dev = container_get("/machine");
+        dev = container_get(object_get_root(), "/machine");
     }
 
     return dev;
diff --git a/include/qemu/object.h b/include/qemu/object.h
index a675937..ca1649c 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -905,6 +905,7 @@ void object_property_add_str(Object *obj, const char *name,
 
 /**
  * container_get:
+ * @root: root of the #path, e.g., object_get_root()
  * @path: path to the container
  *
  * Return a container object whose path is @path.  Create more containers
@@ -912,7 +913,7 @@ void object_property_add_str(Object *obj, const char *name,
  *
  * Returns: the container object.
  */
-Object *container_get(const char *path);
+Object *container_get(Object *root, const char *path);
 
 
 #endif
diff --git a/qom/container.c b/qom/container.c
index 67e9e8a..c9940ab 100644
--- a/qom/container.c
+++ b/qom/container.c
@@ -25,7 +25,7 @@ static void container_register_types(void)
     type_register_static(&container_info);
 }
 
-Object *container_get(const char *path)
+Object *container_get(Object *root, const char *path)
 {
     Object *obj, *child;
     gchar **parts;
@@ -33,7 +33,7 @@ Object *container_get(const char *path)
 
     parts = g_strsplit(path, "/", 0);
     assert(parts != NULL && parts[0] != NULL && !parts[0][0]);
-    obj = object_get_root();
+    obj = root;
 
     for (i = 1; parts[i] != NULL; i++, obj = child) {
         child = object_resolve_path_component(obj, parts[i]);
commit 7f3bf92fad79dff1edcb796a875b5c0d57666162
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Apr 19 07:09:33 2012 -0500

    qtest: Fix tv_usec != long
    
    Sparc Debian 5.0.8 does not define __suseconds_t as long,
    but FMT_timeval expects %ld.
    
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Cc: Anthony Liguori <aliguori at us.ibm.com>
    Cc: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qtest.c b/qtest.c
index 18afcd9..fbfab4e 100644
--- a/qtest.c
+++ b/qtest.c
@@ -153,7 +153,7 @@ static void qtest_send_prefix(CharDriverState *chr)
 
     qtest_get_time(&tv);
     fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
-            tv.tv_sec, tv.tv_usec);
+            tv.tv_sec, (long) tv.tv_usec);
 }
 
 static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
@@ -201,7 +201,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
 
         qtest_get_time(&tv);
         fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
-                tv.tv_sec, tv.tv_usec);
+                tv.tv_sec, (long) tv.tv_usec);
         for (i = 0; words[i]; i++) {
             fprintf(qtest_log_fp, " %s", words[i]);
         }
@@ -399,7 +399,7 @@ static void qtest_event(void *opaque, int event)
         qtest_opened = true;
         if (qtest_log_fp) {
             fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
-                    start_time.tv_sec, start_time.tv_usec);
+                    start_time.tv_sec, (long) start_time.tv_usec);
         }
         break;
     case CHR_EVENT_CLOSED:
@@ -408,7 +408,7 @@ static void qtest_event(void *opaque, int event)
             qemu_timeval tv;
             qtest_get_time(&tv);
             fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
-                    tv.tv_sec, tv.tv_usec);
+                    tv.tv_sec, (long) tv.tv_usec);
         }
         break;
     default:
commit e3c56761b465a4253871c32b06ebbc2d8b3fc3e1
Author: Peter Portante <peter.portante at redhat.com>
Date:   Fri Apr 20 10:36:12 2012 -0400

    Remove extra pthread switch
    
      remove the extra pthread switch which might be there
      from the package config check for gthreads.
    
    Signed-off-by: Peter Portante <peter.portante at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index b8baf4f..dd09f1a 100755
--- a/configure
+++ b/configure
@@ -2083,7 +2083,16 @@ else
   for pthread_lib in $PTHREADLIBS_LIST; do
     if compile_prog "" "$pthread_lib" ; then
       pthread=yes
-      LIBS="$pthread_lib $LIBS"
+      found=no
+      for lib_entry in $LIBS; do
+        if test "$lib_entry" = "$pthread_lib"; then
+          found=yes
+          break
+        fi
+      done
+      if test "$found" = "no"; then
+        LIBS="$pthread_lib $LIBS"
+      fi
       break
     fi
   done
commit d10f9056bacf7991fd6a5f63ac2e0190e84ea3a7
Author: Kusanagi Kouichi <slash at ac.auone-net.jp>
Date:   Sun Apr 22 19:16:05 2012 +0900

    configure: Virtfs doesn't require libcap.
    
    Only proxy helper does.
    
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kusanagi Kouichi <slash at ac.auone-net.jp>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 2dffab8..b8baf4f 100755
--- a/configure
+++ b/configure
@@ -2889,9 +2889,11 @@ tools=
 if test "$softmmu" = yes ; then
   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
   if test "$virtfs" != no ; then
-      if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
+      if test "$linux" = yes && test "$attr" = yes ; then
 	  virtfs=yes
-	  tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
+	  if test "$cap" = yes ; then
+	      tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
+	  fi
       else
 	  if test "$virtfs" = yes; then
 	      feature_not_found "virtfs"
commit ac3107340fbb9422ea63ee5d6729775965e121fd
Author: Stefan Weil <sw at weilnetz.de>
Date:   Thu Apr 19 22:27:14 2012 +0200

    qemu-char: Fix crash when switching consoles
    
    qemu-system-arm (and other system emulations) crashes with SDL when
    the user switches consoles (Alt-Ctrl-F4).
    
    We already check for NULL pointers in qemu_chr_fe_ioctl,
    qemu_chr_be_can_write and other functions, so do this also
    for s->chr_read in qemu_chr_be_write. This fixes the crash.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qemu-char.c b/qemu-char.c
index 74c60e1..a9fc504 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -160,7 +160,9 @@ int qemu_chr_be_can_write(CharDriverState *s)
 
 void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
 {
-    s->chr_read(s->handler_opaque, buf, len);
+    if (s->chr_read) {
+        s->chr_read(s->handler_opaque, buf, len);
+    }
 }
 
 int qemu_chr_fe_get_msgfd(CharDriverState *s)
commit 023d3d67c7dc6e7f492de5b2336194c500d1779d
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:50 2012 -0300

    configure: add --with-confsuffix option
    
    This will allow the user to make Qemu use a different subdirectory name
    inside $datadir and $sysconfdir, instead of "/qemu".
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index df439c9..2dffab8 100755
--- a/configure
+++ b/configure
@@ -591,6 +591,8 @@ for opt do
   ;;
   --datadir=*) datadir="$optarg"
   ;;
+  --with-confsuffix=*) confsuffix="$optarg"
+  ;;
   --docdir=*) qemu_docdir="$optarg"
   ;;
   --sysconfdir=*) sysconfdir="$optarg"
@@ -1007,10 +1009,11 @@ echo "  --python=PYTHON          use specified python [$python]"
 echo "  --smbd=SMBD              use specified smbd [$smbd]"
 echo "  --static                 enable static build [$static]"
 echo "  --mandir=PATH            install man pages in PATH"
-echo "  --datadir=PATH           install firmware in PATH/qemu"
-echo "  --docdir=PATH            install documentation in PATH"
+echo "  --datadir=PATH           install firmware in PATH$confsuffix"
+echo "  --docdir=PATH            install documentation in PATH$confsuffix"
 echo "  --bindir=PATH            install binaries in PATH"
-echo "  --sysconfdir=PATH        install config in PATH/qemu"
+echo "  --sysconfdir=PATH        install config in PATH$confsuffix"
+echo "  --with-confsuffix=SUFFIX      suffix for Qemu data inside datadir and sysconfdir [$confsuffix]"
 echo "  --enable-debug-tcg       enable TCG debugging"
 echo "  --disable-debug-tcg      disable TCG debugging (default)"
 echo "  --enable-debug           enable common debug build options"
commit 528ae5b85079ce5744c7d682b11045eee7e0fb70
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:49 2012 -0300

    configure: change meaning of --datadir to Autoconf convention
    
    Autoconf uses --datadir for the /usr/share directory, not the
    program-specific subdirectory inside /usr/share. This changes configure
    to match autoconf behavior.
    
    Note that this will break compatibility with existing build scripts.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index bc0f7e2..df439c9 100755
--- a/configure
+++ b/configure
@@ -155,7 +155,7 @@ mingw32="no"
 EXESUF=""
 prefix="/usr/local"
 mandir="\${prefix}/share/man"
-qemu_datadir="\${prefix}/share/qemu"
+datadir="\${prefix}/share"
 qemu_docdir="\${prefix}/share/doc/qemu"
 bindir="\${prefix}/bin"
 libdir="\${prefix}/lib"
@@ -521,7 +521,7 @@ EOF
   fi
   prefix="c:/Program Files/QEMU"
   mandir="\${prefix}"
-  qemu_datadir="\${prefix}"
+  datadir="\${prefix}"
   qemu_docdir="\${prefix}"
   bindir="\${prefix}"
   sysconfdir="\${prefix}"
@@ -589,7 +589,7 @@ for opt do
   ;;
   --includedir=*) includedir="$optarg"
   ;;
-  --datadir=*) qemu_datadir="$optarg"
+  --datadir=*) datadir="$optarg"
   ;;
   --docdir=*) qemu_docdir="$optarg"
   ;;
@@ -1007,7 +1007,7 @@ echo "  --python=PYTHON          use specified python [$python]"
 echo "  --smbd=SMBD              use specified smbd [$smbd]"
 echo "  --static                 enable static build [$static]"
 echo "  --mandir=PATH            install man pages in PATH"
-echo "  --datadir=PATH           install firmware in PATH"
+echo "  --datadir=PATH           install firmware in PATH/qemu"
 echo "  --docdir=PATH            install documentation in PATH"
 echo "  --bindir=PATH            install binaries in PATH"
 echo "  --sysconfdir=PATH        install config in PATH/qemu"
@@ -2880,6 +2880,7 @@ if test "$mingw32" = "yes" ; then
 fi
 
 qemu_confdir=$sysconfdir$confsuffix
+qemu_datadir=$datadir$confsuffix
 
 tools=
 if test "$softmmu" = yes ; then
commit 0b3b717470c02013d692e8055efae7d64334a448
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:48 2012 -0300

    create_config: simplify prefix=* block, remove CONFIG_QEMU_PREFIX
    
    As now that block handles only the prefix variable, the code can be much
    simpler. This also removes the CONFIG_QEMU_PREFIX define as it is not
    used by any C code.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/scripts/create_config b/scripts/create_config
index 1d06eb1..c471e8c 100755
--- a/scripts/create_config
+++ b/scripts/create_config
@@ -23,13 +23,8 @@ case $line in
     eval "$name=\$define_value"
     ;;
  prefix=*)
-    name=${line%=*}
-    value=${line#*=}
-    define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
-    eval "define_value=\"$value\""
-    echo "#define CONFIG_QEMU_$define_name \"$define_value\""
     # save for the next definitions
-    eval "$name=\$define_value"
+    prefix=${line#*=}
     ;;
  CONFIG_AUDIO_DRIVERS=*)
     drivers=${line#*=}
commit c41cc50f66ea0e319cebd858af95423c880f8149
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:47 2012 -0300

    create_config: remove *dir block
    
    Now only the qemu_*dir variables will become #defines. The other
    directory names aren't used by the C code.
    
    That means the following #defines won't be available in C code anymore:
    
     - CONFIG_QEMU_BINDIR
     - CONFIG_QEMU_LIBDIR
     - CONFIG_QEMU_INCLUDEDIR
     - CONFIG_QEMU_MANDIR
     - CONFIG_QEMU_SYSCONFDIR
     - CONFIG_QEMU_LIBEXECDIR
    
    The following #defines are going to be kept because they are handled by
    the qemu_* block on create_config:
    
     - CONFIG_QEMU_CONFDIR
     - CONFIG_QEMU_DATADIR
     - CONFIG_QEMU_DOCDIR
    
    This one will be kept because it is set directly by ./configure:
    
     - CONFIG_QEMU_HELPERDIR
    
    This patch keeps the 'prefix=*' (CONFIG_QEMU_PREFIX) pattern because
    other variables may use $prefix on their config-host.mak definitions.
    The remaining code will be simplified on a further patch.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/scripts/create_config b/scripts/create_config
index f9ba2f5..1d06eb1 100755
--- a/scripts/create_config
+++ b/scripts/create_config
@@ -22,7 +22,7 @@ case $line in
     # save for the next definitions
     eval "$name=\$define_value"
     ;;
- prefix=* | [a-z]*dir=*) # directory configuration
+ prefix=*)
     name=${line%=*}
     value=${line#*=}
     define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
commit 9afa52ceb2a2e19ccfb69e13eab558613a93fb6c
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:46 2012 -0300

    config-host.mak: reorder variables a bit
    
    Cosmetic change.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 1f42031..bc0f7e2 100755
--- a/configure
+++ b/configure
@@ -3022,10 +3022,10 @@ echo "bindir=$bindir" >> $config_host_mak
 echo "libdir=$libdir" >> $config_host_mak
 echo "includedir=$includedir" >> $config_host_mak
 echo "mandir=$mandir" >> $config_host_mak
-echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
-echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
 echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
+echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
+echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
 echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
 echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
 
commit 5100cb446dbd3556897e08a81f6ef22b63373872
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:45 2012 -0300

    config-host.mak: remove CONFIG_QEMU_SHAREDIR
    
    There is no code using that variable according to 'git grep', so kill
    it.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index c0fac32..1f42031 100755
--- a/configure
+++ b/configure
@@ -3027,7 +3027,6 @@ echo "sysconfdir=$sysconfdir" >> $config_host_mak
 echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
 echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
 echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
-echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
 echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
 
 echo "ARCH=$ARCH" >> $config_host_mak
commit d7dd65bae3fcc13190da312b1be90364e86cd6aa
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:44 2012 -0300

    config-host.mak: rename docdir to qemu_docdir
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile b/Makefile
index a9bc796..4f43793 100644
--- a/Makefile
+++ b/Makefile
@@ -268,8 +268,8 @@ BLOBS=
 endif
 
 install-doc: $(DOCS)
-	$(INSTALL_DIR) "$(DESTDIR)$(docdir)"
-	$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(docdir)"
+	$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
+	$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
 ifdef CONFIG_POSIX
 	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 	$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
diff --git a/configure b/configure
index b64c99b..c0fac32 100755
--- a/configure
+++ b/configure
@@ -3024,7 +3024,7 @@ echo "includedir=$includedir" >> $config_host_mak
 echo "mandir=$mandir" >> $config_host_mak
 echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
-echo "docdir=$qemu_docdir" >> $config_host_mak
+echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
 echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
 echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
 echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
commit 80465e809af70cc311c1f47a84418f052209a3fe
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:43 2012 -0300

    Makefile: use $(qemu_confdir) instead of $(sysconfdir)/qemu
    
    Instead of hardcoding the directory suffix, use the qemu-specific
    directory variable.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile b/Makefile
index c8e4b53..a9bc796 100644
--- a/Makefile
+++ b/Makefile
@@ -281,8 +281,8 @@ ifdef CONFIG_VIRTFS
 	$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
 endif
 install-sysconfig:
-	$(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)/qemu"
-	$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(sysconfdir)/qemu"
+	$(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
+	$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
 
 install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
 	$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
commit 22d07038539429932b2de0489833e5987fbce496
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:42 2012 -0300

    config-host.mak: rename confdir to qemu_confdir
    
    $confdir is a confusing name, as it's not clear if it's "the system
    config dir" or "the Qemus-specific directory inside the config dir".
    $qemu_confdir makes it more clear.
    
    The current C code that uses CONFIG_QEMU_CONFDIR should be safe, as now
    create_config generates the same #define name (CONFIG_QEMU_CONFDIR) for
    both "confdir" and "qemu_confdir" variables.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 8788354..b64c99b 100755
--- a/configure
+++ b/configure
@@ -3025,7 +3025,7 @@ echo "mandir=$mandir" >> $config_host_mak
 echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
 echo "docdir=$qemu_docdir" >> $config_host_mak
-echo "confdir=$qemu_confdir" >> $config_host_mak
+echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
 echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
 echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
 echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
commit 6aae2a2e0e3c43e479f889389074cda8bef3a580
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:41 2012 -0300

    config-host.mak: rename datadir to qemu_datadir
    
    Autoconf concept of "datadir" is supposed to be "$prefix/share", not
    "$prefix/share/PACKAGE", so using datadir for the Qemu-specific
    directory is confusing.
    
    The current C code that uses CONFIG_QEMU_DATADIR should be safe, as now
    create_config generates the same #define name (CONFIG_QEMU_DATADIR) for
    both "datadir" and "qemu_datadir" variables.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile b/Makefile
index e0fe680..c8e4b53 100644
--- a/Makefile
+++ b/Makefile
@@ -294,14 +294,14 @@ ifneq ($(HELPERS-y),)
 	$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
 endif
 ifneq ($(BLOBS),)
-	$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
+	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
 	set -e; for x in $(BLOBS); do \
-		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
+		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
 	done
 endif
-	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
+	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
 	set -e; for x in $(KEYMAPS); do \
-		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
+		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
 	done
 	for d in $(TARGET_DIRS); do \
 	$(MAKE) -C $$d $@ || exit 1 ; \
diff --git a/Makefile.target b/Makefile.target
index 172289a..4fbbabf 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -485,8 +485,8 @@ ifneq ($(STRIP),)
 endif
 endif
 ifdef CONFIG_TRACE_SYSTEMTAP
-	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
-	$(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
+	$(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
 endif
 
 # Include automatically generated dependency files
diff --git a/configure b/configure
index cba5976..8788354 100755
--- a/configure
+++ b/configure
@@ -3022,7 +3022,7 @@ echo "bindir=$bindir" >> $config_host_mak
 echo "libdir=$libdir" >> $config_host_mak
 echo "includedir=$includedir" >> $config_host_mak
 echo "mandir=$mandir" >> $config_host_mak
-echo "datadir=$qemu_datadir" >> $config_host_mak
+echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
 echo "docdir=$qemu_docdir" >> $config_host_mak
 echo "confdir=$qemu_confdir" >> $config_host_mak
commit eb72952b81f254e39c21f892b6109f09a762c313
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:40 2012 -0300

    create_config: separate section for qemu_*dir variables (v2)
    
    The generic *dir section will eventually go away and be replaced with
    qemu_* section. By now, both sections will be kept, while the variables
    get renamed on config-host.mak.
    
    With this patch, a XXXdir variable will become a CONFIG_QEMU_XXXDIR
    define, and a qemu_XXXdir variable will become CONFIG_QEMU_XXXDIR as
    well (instead of becoming a CONFIG_QEMU_QEMU_XXXDIR define).
    
    Changes v1 -> v2:
     - Rebase on top of newer qemu.git changes, that changed
       "tr '[:lower:]' '[:upper:]'" to "LC_ALL=C tr '[a-z]' '[A-Z]'".
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/scripts/create_config b/scripts/create_config
index 470e05e..f9ba2f5 100755
--- a/scripts/create_config
+++ b/scripts/create_config
@@ -13,6 +13,15 @@ case $line in
     pkgversion=${line#*=}
     echo "#define QEMU_PKGVERSION \"$pkgversion\""
     ;;
+ qemu_*dir=*) # qemu-specific directory configuration
+    name=${line%=*}
+    value=${line#*=}
+    define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
+    eval "define_value=\"$value\""
+    echo "#define CONFIG_$define_name \"$define_value\""
+    # save for the next definitions
+    eval "$name=\$define_value"
+    ;;
  prefix=* | [a-z]*dir=*) # directory configuration
     name=${line%=*}
     value=${line#*=}
commit 10ea68b34378efd81a644f67cea7863c135a6fa8
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:39 2012 -0300

    configure: rename $confdir to $qemu_confdir
    
    There's no "confdir" variable on Autoconf, but it's good to make it
    clear that it's a variable for the Qemu-specific subdirectory inside
    $sysconfdir.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 93b6db1..cba5976 100755
--- a/configure
+++ b/configure
@@ -2879,7 +2879,7 @@ if test "$mingw32" = "yes" ; then
     done
 fi
 
-confdir=$sysconfdir$confsuffix
+qemu_confdir=$sysconfdir$confsuffix
 
 tools=
 if test "$softmmu" = yes ; then
@@ -3025,7 +3025,7 @@ echo "mandir=$mandir" >> $config_host_mak
 echo "datadir=$qemu_datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
 echo "docdir=$qemu_docdir" >> $config_host_mak
-echo "confdir=$confdir" >> $config_host_mak
+echo "confdir=$qemu_confdir" >> $config_host_mak
 echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
 echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
 echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
commit 850da188a2f11eee72a806d638c1c2d0935d989e
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:38 2012 -0300

    configure: rename $docdir to $qemu_docdir
    
    The autoconf "docdir" variable is used for the program-specific
    subdirectory, but anyway it's better to make it clear that the variable
    is used for the qemu-specific subdirectory path.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 76be4f2..93b6db1 100755
--- a/configure
+++ b/configure
@@ -156,7 +156,7 @@ EXESUF=""
 prefix="/usr/local"
 mandir="\${prefix}/share/man"
 qemu_datadir="\${prefix}/share/qemu"
-docdir="\${prefix}/share/doc/qemu"
+qemu_docdir="\${prefix}/share/doc/qemu"
 bindir="\${prefix}/bin"
 libdir="\${prefix}/lib"
 includedir="\${prefix}/include"
@@ -522,7 +522,7 @@ EOF
   prefix="c:/Program Files/QEMU"
   mandir="\${prefix}"
   qemu_datadir="\${prefix}"
-  docdir="\${prefix}"
+  qemu_docdir="\${prefix}"
   bindir="\${prefix}"
   sysconfdir="\${prefix}"
   confsuffix=""
@@ -591,7 +591,7 @@ for opt do
   ;;
   --datadir=*) qemu_datadir="$optarg"
   ;;
-  --docdir=*) docdir="$optarg"
+  --docdir=*) qemu_docdir="$optarg"
   ;;
   --sysconfdir=*) sysconfdir="$optarg"
   ;;
@@ -3024,7 +3024,7 @@ echo "includedir=$includedir" >> $config_host_mak
 echo "mandir=$mandir" >> $config_host_mak
 echo "datadir=$qemu_datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
-echo "docdir=$docdir" >> $config_host_mak
+echo "docdir=$qemu_docdir" >> $config_host_mak
 echo "confdir=$confdir" >> $config_host_mak
 echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
 echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
commit c00b2808053064a08b93f5ed901b21693a431b6d
Author: Eduardo Habkost <ehabkost at redhat.com>
Date:   Wed Apr 18 16:55:37 2012 -0300

    configure: rename $datadir to $qemu_datadir
    
    The variable is used for the qemu-specific directory and has a different
    meaning of the autoconf "datadir" variable (that's used for the
    $prefix/share directory, not for $prefix/share/PACKAGE).
    
    This doesn't change behavior or interfaces, it's just an internal
    variable rename.
    
    Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 8ed5a03..76be4f2 100755
--- a/configure
+++ b/configure
@@ -155,7 +155,7 @@ mingw32="no"
 EXESUF=""
 prefix="/usr/local"
 mandir="\${prefix}/share/man"
-datadir="\${prefix}/share/qemu"
+qemu_datadir="\${prefix}/share/qemu"
 docdir="\${prefix}/share/doc/qemu"
 bindir="\${prefix}/bin"
 libdir="\${prefix}/lib"
@@ -521,7 +521,7 @@ EOF
   fi
   prefix="c:/Program Files/QEMU"
   mandir="\${prefix}"
-  datadir="\${prefix}"
+  qemu_datadir="\${prefix}"
   docdir="\${prefix}"
   bindir="\${prefix}"
   sysconfdir="\${prefix}"
@@ -589,7 +589,7 @@ for opt do
   ;;
   --includedir=*) includedir="$optarg"
   ;;
-  --datadir=*) datadir="$optarg"
+  --datadir=*) qemu_datadir="$optarg"
   ;;
   --docdir=*) docdir="$optarg"
   ;;
@@ -2914,7 +2914,7 @@ if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then
 fi
 
 echo "Install prefix    $prefix"
-echo "BIOS directory    `eval echo $datadir`"
+echo "BIOS directory    `eval echo $qemu_datadir`"
 echo "binary directory  `eval echo $bindir`"
 echo "library directory `eval echo $libdir`"
 echo "include directory `eval echo $includedir`"
@@ -3022,7 +3022,7 @@ echo "bindir=$bindir" >> $config_host_mak
 echo "libdir=$libdir" >> $config_host_mak
 echo "includedir=$includedir" >> $config_host_mak
 echo "mandir=$mandir" >> $config_host_mak
-echo "datadir=$datadir" >> $config_host_mak
+echo "datadir=$qemu_datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
 echo "docdir=$docdir" >> $config_host_mak
 echo "confdir=$confdir" >> $config_host_mak
commit d0e71ef56fa22b7434d4e9f277a2091b2981ef98
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Apr 12 02:34:40 2012 +0200

    target-microblaze: QOM'ify CPU init
    
    Move code from cpu_mb_init() to a QOM initfn.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Tested-by: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
    [AF: Leave cpu_reset() call in cpu_mb_init()]

diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index 6f00b0d..9c3b74e 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -83,6 +83,16 @@ static void mb_cpu_reset(CPUState *s)
 #endif
 }
 
+static void mb_cpu_initfn(Object *obj)
+{
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj);
+    CPUMBState *env = &cpu->env;
+
+    cpu_exec_init(env);
+
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+}
+
 static void mb_cpu_class_init(ObjectClass *oc, void *data)
 {
     CPUClass *cc = CPU_CLASS(oc);
@@ -96,6 +106,7 @@ static const TypeInfo mb_cpu_type_info = {
     .name = TYPE_MICROBLAZE_CPU,
     .parent = TYPE_CPU,
     .instance_size = sizeof(MicroBlazeCPU),
+    .instance_init = mb_cpu_initfn,
     .class_size = sizeof(MicroBlazeCPUClass),
     .class_init = mb_cpu_class_init,
 };
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index e730c32..742b395 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1899,10 +1899,8 @@ CPUMBState *cpu_mb_init (const char *cpu_model)
     cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
     env = &cpu->env;
 
-    cpu_exec_init(env);
     cpu_reset(CPU(cpu));
     qemu_init_vcpu(env);
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
 
     if (tcg_initialized)
         return env;
commit 61b6208f8e2bfee096fbeefa20744dcc87c2530e
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Apr 12 02:26:28 2012 +0200

    target-microblaze: QOM'ify CPU reset
    
    Move code from cpu_state_reset() to QOM mb_cpu_reset().
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Tested-by: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>

diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index 21b62c6..6f00b0d 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -1,6 +1,8 @@
 /*
  * QEMU MicroBlaze CPU
  *
+ * Copyright (c) 2009 Edgar E. Iglesias
+ * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
  * Copyright (c) 2012 SUSE LINUX Products GmbH
  *
  * This library is free software; you can redistribute it and/or
@@ -29,9 +31,56 @@ static void mb_cpu_reset(CPUState *s)
     MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(cpu);
     CPUMBState *env = &cpu->env;
 
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
     mcc->parent_reset(s);
 
-    cpu_state_reset(env);
+    memset(env, 0, offsetof(CPUMBState, breakpoints));
+    tlb_flush(env, 1);
+
+    /* Disable stack protector.  */
+    env->shr = ~0;
+
+    env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
+                       | PVR0_USE_BARREL_MASK \
+                       | PVR0_USE_DIV_MASK \
+                       | PVR0_USE_HW_MUL_MASK \
+                       | PVR0_USE_EXC_MASK \
+                       | PVR0_USE_ICACHE_MASK \
+                       | PVR0_USE_DCACHE_MASK \
+                       | PVR0_USE_MMU \
+                       | (0xb << 8);
+    env->pvr.regs[2] = PVR2_D_OPB_MASK \
+                        | PVR2_D_LMB_MASK \
+                        | PVR2_I_OPB_MASK \
+                        | PVR2_I_LMB_MASK \
+                        | PVR2_USE_MSR_INSTR \
+                        | PVR2_USE_PCMP_INSTR \
+                        | PVR2_USE_BARREL_MASK \
+                        | PVR2_USE_DIV_MASK \
+                        | PVR2_USE_HW_MUL_MASK \
+                        | PVR2_USE_MUL64_MASK \
+                        | PVR2_USE_FPU_MASK \
+                        | PVR2_USE_FPU2_MASK \
+                        | PVR2_FPU_EXC_MASK \
+                        | 0;
+    env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family.  */
+    env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
+
+#if defined(CONFIG_USER_ONLY)
+    /* start in user mode with interrupts enabled.  */
+    env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
+    env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp.  */
+#else
+    env->sregs[SR_MSR] = 0;
+    mmu_init(&env->mmu);
+    env->mmu.c_mmu = 3;
+    env->mmu.c_mmu_tlb_access = 3;
+    env->mmu.c_mmu_zones = 16;
+#endif
 }
 
 static void mb_cpu_class_init(ObjectClass *oc, void *data)
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index f4d32c8..e730c32 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1900,7 +1900,7 @@ CPUMBState *cpu_mb_init (const char *cpu_model)
     env = &cpu->env;
 
     cpu_exec_init(env);
-    cpu_state_reset(env);
+    cpu_reset(CPU(cpu));
     qemu_init_vcpu(env);
     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
 
@@ -1944,54 +1944,7 @@ CPUMBState *cpu_mb_init (const char *cpu_model)
 
 void cpu_state_reset(CPUMBState *env)
 {
-    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
-        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
-        log_cpu_state(env, 0);
-    }
-
-    memset(env, 0, offsetof(CPUMBState, breakpoints));
-    tlb_flush(env, 1);
-
-    /* Disable stack protector.  */
-    env->shr = ~0;
-
-    env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
-                       | PVR0_USE_BARREL_MASK \
-                       | PVR0_USE_DIV_MASK \
-                       | PVR0_USE_HW_MUL_MASK \
-                       | PVR0_USE_EXC_MASK \
-                       | PVR0_USE_ICACHE_MASK \
-                       | PVR0_USE_DCACHE_MASK \
-                       | PVR0_USE_MMU \
-                       | (0xb << 8);
-    env->pvr.regs[2] = PVR2_D_OPB_MASK \
-                        | PVR2_D_LMB_MASK \
-                        | PVR2_I_OPB_MASK \
-                        | PVR2_I_LMB_MASK \
-                        | PVR2_USE_MSR_INSTR \
-                        | PVR2_USE_PCMP_INSTR \
-                        | PVR2_USE_BARREL_MASK \
-                        | PVR2_USE_DIV_MASK \
-                        | PVR2_USE_HW_MUL_MASK \
-                        | PVR2_USE_MUL64_MASK \
-                        | PVR2_USE_FPU_MASK \
-                        | PVR2_USE_FPU2_MASK \
-                        | PVR2_FPU_EXC_MASK \
-                        | 0;
-    env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family.  */
-    env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
-
-#if defined(CONFIG_USER_ONLY)
-    /* start in user mode with interrupts enabled.  */
-    env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
-    env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp.  */
-#else
-    env->sregs[SR_MSR] = 0;
-    mmu_init(&env->mmu);
-    env->mmu.c_mmu = 3;
-    env->mmu.c_mmu_tlb_access = 3;
-    env->mmu.c_mmu_zones = 16;
-#endif
+    cpu_reset(ENV_GET_CPU(env));
 }
 
 void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, int pc_pos)
commit b77f98cadad07a0863a6bfe1492c64f3a16ccbc5
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Apr 12 02:17:53 2012 +0200

    target-microblaze: QOM'ify CPU
    
    Embed CPUMBState as first member of QOM MicroBlazeCPU.
    
    Let CPUClass::reset() call cpu_state_reset() for now.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Tested-by: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
    [AF: Updated cpu.c to include cpu-qom.h indirectly via cpu.h]

diff --git a/Makefile.target b/Makefile.target
index 1b5d62b..172289a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -96,6 +96,7 @@ libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 libobj-$(TARGET_ARM) += cpu.o
 libobj-$(TARGET_CRIS) += cpu.o
 libobj-$(TARGET_LM32) += cpu.o
+libobj-$(TARGET_MICROBLAZE) += cpu.o
 libobj-$(TARGET_S390X) += cpu.o
 ifeq ($(TARGET_BASE_ARCH), sparc)
 libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h
new file mode 100644
index 0000000..4b23303
--- /dev/null
+++ b/target-microblaze/cpu-qom.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU MicroBlaze CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_MICROBLAZE_CPU_QOM_H
+#define QEMU_MICROBLAZE_CPU_QOM_H
+
+#include "qemu/cpu.h"
+
+#define TYPE_MICROBLAZE_CPU "microblaze-cpu"
+
+#define MICROBLAZE_CPU_CLASS(klass) \
+    OBJECT_CLASS_CHECK(MicroBlazeCPUClass, (klass), TYPE_MICROBLAZE_CPU)
+#define MICROBLAZE_CPU(obj) \
+    OBJECT_CHECK(MicroBlazeCPU, (obj), TYPE_MICROBLAZE_CPU)
+#define MICROBLAZE_CPU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(MicroBlazeCPUClass, (obj), TYPE_MICROBLAZE_CPU)
+
+/**
+ * MicroBlazeCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A MicroBlaze CPU model.
+ */
+typedef struct MicroBlazeCPUClass {
+    /*< private >*/
+    CPUClass parent_class;
+    /*< public >*/
+
+    void (*parent_reset)(CPUState *cpu);
+} MicroBlazeCPUClass;
+
+/**
+ * MicroBlazeCPU:
+ * @env: #CPUMBState
+ *
+ * A MicroBlaze CPU.
+ */
+typedef struct MicroBlazeCPU {
+    /*< private >*/
+    CPUState parent_obj;
+    /*< public >*/
+
+    CPUMBState env;
+} MicroBlazeCPU;
+
+static inline MicroBlazeCPU *mb_env_get_cpu(CPUMBState *env)
+{
+    return MICROBLAZE_CPU(container_of(env, MicroBlazeCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(mb_env_get_cpu(e))
+
+
+#endif
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
new file mode 100644
index 0000000..21b62c6
--- /dev/null
+++ b/target-microblaze/cpu.c
@@ -0,0 +1,59 @@
+/*
+ * QEMU MicroBlaze CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu.h"
+#include "qemu-common.h"
+
+
+/* CPUClass::reset() */
+static void mb_cpu_reset(CPUState *s)
+{
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(s);
+    MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(cpu);
+    CPUMBState *env = &cpu->env;
+
+    mcc->parent_reset(s);
+
+    cpu_state_reset(env);
+}
+
+static void mb_cpu_class_init(ObjectClass *oc, void *data)
+{
+    CPUClass *cc = CPU_CLASS(oc);
+    MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_CLASS(oc);
+
+    mcc->parent_reset = cc->reset;
+    cc->reset = mb_cpu_reset;
+}
+
+static const TypeInfo mb_cpu_type_info = {
+    .name = TYPE_MICROBLAZE_CPU,
+    .parent = TYPE_CPU,
+    .instance_size = sizeof(MicroBlazeCPU),
+    .class_size = sizeof(MicroBlazeCPUClass),
+    .class_init = mb_cpu_class_init,
+};
+
+static void mb_cpu_register_types(void)
+{
+    type_register_static(&mb_cpu_type_info);
+}
+
+type_init(mb_cpu_register_types)
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 33b23c2..718d5bb 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -266,6 +266,8 @@ struct CPUMBState {
     CPU_COMMON
 };
 
+#include "cpu-qom.h"
+
 CPUMBState *cpu_mb_init(const char *cpu_model);
 int cpu_mb_exec(CPUMBState *s);
 void cpu_mb_close(CPUMBState *s);
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index b602820..f4d32c8 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1891,11 +1891,13 @@ void cpu_dump_state (CPUMBState *env, FILE *f, fprintf_function cpu_fprintf,
 
 CPUMBState *cpu_mb_init (const char *cpu_model)
 {
+    MicroBlazeCPU *cpu;
     CPUMBState *env;
     static int tcg_initialized = 0;
     int i;
 
-    env = g_malloc0(sizeof(CPUMBState));
+    cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
+    env = &cpu->env;
 
     cpu_exec_init(env);
     cpu_state_reset(env);
commit aa0d1267b3aa69c87fbd37a896bdd3f44d45c3f3
Author: Andreas Färber <afaerber at suse.de>
Date:   Wed Apr 11 23:41:06 2012 +0200

    target-cris: Start QOM'ifying CPU init
    
    Move VR-independent code from cpu_cris_init() into an initfn.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 93c7e00..c596609 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -55,6 +55,14 @@ static void cris_cpu_reset(CPUState *s)
 #endif
 }
 
+static void cris_cpu_initfn(Object *obj)
+{
+    CRISCPU *cpu = CRIS_CPU(obj);
+    CPUCRISState *env = &cpu->env;
+
+    cpu_exec_init(env);
+}
+
 static void cris_cpu_class_init(ObjectClass *oc, void *data)
 {
     CPUClass *cc = CPU_CLASS(oc);
@@ -68,6 +76,7 @@ static const TypeInfo cris_cpu_type_info = {
     .name = TYPE_CRIS_CPU,
     .parent = TYPE_CPU,
     .instance_size = sizeof(CRISCPU),
+    .instance_init = cris_cpu_initfn,
     .abstract = false,
     .class_size = sizeof(CRISCPUClass),
     .class_init = cris_cpu_class_init,
diff --git a/target-cris/translate.c b/target-cris/translate.c
index d3dbac2..e353ea3 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3514,7 +3514,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
     env = &cpu->env;
 
 	env->pregs[PR_VR] = vr_by_name(cpu_model);
-	cpu_exec_init(env);
+
     cpu_reset(CPU(cpu));
 	qemu_init_vcpu(env);
 
commit 1c3b52fb1a44b407b52f4852c1931c571e77d308
Author: Andreas Färber <afaerber at suse.de>
Date:   Wed Apr 11 23:35:40 2012 +0200

    target-cris: QOM'ify CPU reset
    
    Move code from cpu_state_reset() into QOM cris_cpu_reset().
    Let CPU init call cpu_reset().
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 784846b..93c7e00 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -1,6 +1,9 @@
 /*
  * QEMU CRIS CPU
  *
+ * Copyright (c) 2008 AXIS Communications AB
+ * Written by Edgar E. Iglesias.
+ *
  * Copyright (c) 2012 SUSE LINUX Products GmbH
  *
  * This library is free software; you can redistribute it and/or
@@ -20,6 +23,7 @@
 
 #include "cpu.h"
 #include "qemu-common.h"
+#include "mmu.h"
 
 
 /* CPUClass::reset() */
@@ -28,10 +32,27 @@ static void cris_cpu_reset(CPUState *s)
     CRISCPU *cpu = CRIS_CPU(s);
     CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(cpu);
     CPUCRISState *env = &cpu->env;
+    uint32_t vr;
+
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
 
     ccc->parent_reset(s);
 
-    cpu_state_reset(env);
+    vr = env->pregs[PR_VR];
+    memset(env, 0, offsetof(CPUCRISState, breakpoints));
+    env->pregs[PR_VR] = vr;
+    tlb_flush(env, 1);
+
+#if defined(CONFIG_USER_ONLY)
+    /* start in user mode with interrupts enabled.  */
+    env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
+#else
+    cris_mmu_init(env);
+    env->pregs[PR_CCS] = 0;
+#endif
 }
 
 static void cris_cpu_class_init(ObjectClass *oc, void *data)
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 26c3f0b..d3dbac2 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3515,7 +3515,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
 
 	env->pregs[PR_VR] = vr_by_name(cpu_model);
 	cpu_exec_init(env);
-    cpu_state_reset(env);
+    cpu_reset(CPU(cpu));
 	qemu_init_vcpu(env);
 
 	if (tcg_initialized)
@@ -3577,25 +3577,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
 
 void cpu_state_reset(CPUCRISState *env)
 {
-	uint32_t vr;
-
-	if (qemu_loglevel_mask(CPU_LOG_RESET)) {
-		qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
-		log_cpu_state(env, 0);
-	}
-
-	vr = env->pregs[PR_VR];
-	memset(env, 0, offsetof(CPUCRISState, breakpoints));
-	env->pregs[PR_VR] = vr;
-	tlb_flush(env, 1);
-
-#if defined(CONFIG_USER_ONLY)
-	/* start in user mode with interrupts enabled.  */
-	env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
-#else
-	cris_mmu_init(env);
-	env->pregs[PR_CCS] = 0;
-#endif
+    cpu_reset(ENV_GET_CPU(env));
 }
 
 void restore_state_to_opc(CPUCRISState *env, TranslationBlock *tb, int pc_pos)
commit e739a48e58c41fc0d3caa24103abef9988c77cdf
Author: Andreas Färber <afaerber at suse.de>
Date:   Wed Apr 11 23:12:05 2012 +0200

    target-cris: QOM'ify CPU
    
    Embed CPUCRISState as first member of QOM CRISCPU.
    
    Let CPUClass::reset() call cpu_state_reset() for now.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>

diff --git a/Makefile.target b/Makefile.target
index 7eda443..1b5d62b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -94,6 +94,7 @@ libobj-$(TARGET_SPARC64) += vis_helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
 libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 libobj-$(TARGET_ARM) += cpu.o
+libobj-$(TARGET_CRIS) += cpu.o
 libobj-$(TARGET_LM32) += cpu.o
 libobj-$(TARGET_S390X) += cpu.o
 ifeq ($(TARGET_BASE_ARCH), sparc)
diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h
new file mode 100644
index 0000000..d0e5f04
--- /dev/null
+++ b/target-cris/cpu-qom.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU CRIS CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_CRIS_CPU_QOM_H
+#define QEMU_CRIS_CPU_QOM_H
+
+#include "qemu/cpu.h"
+
+#define TYPE_CRIS_CPU "cris-cpu"
+
+#define CRIS_CPU_CLASS(klass) \
+    OBJECT_CLASS_CHECK(CRISCPUClass, (klass), TYPE_CRIS_CPU)
+#define CRIS_CPU(obj) \
+    OBJECT_CHECK(CRISCPU, (obj), TYPE_CRIS_CPU)
+#define CRIS_CPU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(CRISCPUClass, (obj), TYPE_CRIS_CPU)
+
+/**
+ * CRISCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A CRIS CPU model.
+ */
+typedef struct CRISCPUClass {
+    /*< private >*/
+    CPUClass parent_class;
+    /*< public >*/
+
+    void (*parent_reset)(CPUState *cpu);
+} CRISCPUClass;
+
+/**
+ * CRISCPU:
+ * @env: #CPUCRISState
+ *
+ * A CRIS CPU.
+ */
+typedef struct CRISCPU {
+    /*< private >*/
+    CPUState parent_obj;
+    /*< public >*/
+
+    CPUCRISState env;
+} CRISCPU;
+
+static inline CRISCPU *cris_env_get_cpu(CPUCRISState *env)
+{
+    return CRIS_CPU(container_of(env, CRISCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(cris_env_get_cpu(e))
+
+
+#endif
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
new file mode 100644
index 0000000..784846b
--- /dev/null
+++ b/target-cris/cpu.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU CRIS CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu.h"
+#include "qemu-common.h"
+
+
+/* CPUClass::reset() */
+static void cris_cpu_reset(CPUState *s)
+{
+    CRISCPU *cpu = CRIS_CPU(s);
+    CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(cpu);
+    CPUCRISState *env = &cpu->env;
+
+    ccc->parent_reset(s);
+
+    cpu_state_reset(env);
+}
+
+static void cris_cpu_class_init(ObjectClass *oc, void *data)
+{
+    CPUClass *cc = CPU_CLASS(oc);
+    CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
+
+    ccc->parent_reset = cc->reset;
+    cc->reset = cris_cpu_reset;
+}
+
+static const TypeInfo cris_cpu_type_info = {
+    .name = TYPE_CRIS_CPU,
+    .parent = TYPE_CPU,
+    .instance_size = sizeof(CRISCPU),
+    .abstract = false,
+    .class_size = sizeof(CRISCPUClass),
+    .class_init = cris_cpu_class_init,
+};
+
+static void cris_cpu_register_types(void)
+{
+    type_register_static(&cris_cpu_type_info);
+}
+
+type_init(cris_cpu_register_types)
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 31899c2..5449cc4 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -169,6 +169,8 @@ typedef struct CPUCRISState {
 	void *load_info;
 } CPUCRISState;
 
+#include "cpu-qom.h"
+
 CPUCRISState *cpu_cris_init(const char *cpu_model);
 int cpu_cris_exec(CPUCRISState *s);
 void cpu_cris_close(CPUCRISState *s);
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 7224f46..26c3f0b 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3505,11 +3505,13 @@ static uint32_t vr_by_name(const char *name)
 
 CPUCRISState *cpu_cris_init (const char *cpu_model)
 {
+    CRISCPU *cpu;
 	CPUCRISState *env;
 	static int tcg_initialized = 0;
 	int i;
 
-	env = g_malloc0(sizeof(CPUCRISState));
+    cpu = CRIS_CPU(object_new(TYPE_CRIS_CPU));
+    env = &cpu->env;
 
 	env->pregs[PR_VR] = vr_by_name(cpu_model);
 	cpu_exec_init(env);
commit 092dfc7714ad7983aeb0cada5d5983e9fde8d84c
Merge: 6454678... ce6bf17...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 15:02:53 2012 -0500

    Merge remote-tracking branch 'origin/master' into staging
    
    * origin/master:
      qtest: fix memread and memwrite on 32 bit hosts

commit 645467842339207d895c41f4e4526507b95a636a
Merge: 1f8bcac... 57a33d8...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 14:29:11 2012 -0500

    Merge remote-tracking branch 'qmp/queue/qmp' into staging
    
    * qmp/queue/qmp:
      qapi: g_hash_table_find() instead of GHashTableIter.
      qmp: make block job command naming consistent

commit ce6bf17a97aa53496a385db5642a323ce3b877a1
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Apr 23 18:53:38 2012 +0000

    qtest: fix memread and memwrite on 32 bit hosts
    
    Use PRIx64 to print 64 bit values to avoid truncation
    on 32 bit hosts.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tests/libqtest.c b/tests/libqtest.c
index d47969e..1ce6fa1 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -356,7 +356,7 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
     gchar **args;
     size_t i;
 
-    qtest_sendf(s, "read 0x%x 0x%x\n", addr, size);
+    qtest_sendf(s, "read 0x%" PRIx64 " 0x%x\n", addr, size);
     args = qtest_rsp(s, 2);
 
     for (i = 0; i < size; i++) {
@@ -378,7 +378,7 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
     const uint8_t *ptr = data;
     size_t i;
 
-    qtest_sendf(s, "write 0x%x 0x%x 0x", addr, size);
+    qtest_sendf(s, "write 0x%" PRIx64 " 0x%x 0x", addr, size);
     for (i = 0; i < size; i++) {
         qtest_sendf(s, "%02x", ptr[i]);
     }
commit 1f8bcac09af61e58c5121aa0a932190700ad554d
Merge: cb4c254... 1042ec9...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 14:27:04 2012 -0500

    Merge remote-tracking branch 'kwolf/for-anthony' into staging
    
    * kwolf/for-anthony: (38 commits)
      qemu-iotests: Fix test 031 for qcow2 v3 support
      qemu-iotests: Add -o and make v3 the default for qcow2
      qcow2: Zero write support
      qemu-iotests: Test backing file COW with zero clusters
      qemu-iotests: add a simple test for write_zeroes
      qcow2: Support for feature table header extension
      qcow2: Support reading zero clusters
      qcow2: Version 3 images
      qcow2: Ignore reserved bits in check_refcounts
      qcow2: Ignore reserved bits in refcount table entries
      qcow2: Simplify count_cow_clusters
      qcow2: Refactor qcow2_free_any_clusters
      qcow2: Ignore reserved bits in L1/L2 entries
      qcow2: Fail write_compressed when overwriting data
      qcow2: Ignore reserved bits in count_contiguous_clusters()
      qcow2: Ignore reserved bits in get_cluster_offset
      qcow2: Save disk size in snapshot header
      Specification for qcow2 version 3
      qcow2: Fix refcount block allocation during qcow2_alloc_cluster_at()
      iotests: Resolve test failures caused by hostname
      ...

diff --cc block/nbd.c
index e0af5b4,524c9cf..56dbf6e
--- a/block/nbd.c
+++ b/block/nbd.c
@@@ -203,12 -191,13 +203,12 @@@ static int nbd_co_send_request(BDRVNBDS
      qemu_co_mutex_lock(&s->send_mutex);
      s->send_coroutine = qemu_coroutine_self();
      qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
-                             nbd_have_request, NULL, s);
+                             nbd_have_request, s);
      rc = nbd_send_request(s->sock, request);
 -    if (rc != -1 && iov) {
 +    if (rc >= 0 && iov) {
          ret = qemu_co_sendv(s->sock, iov, request->len, offset);
          if (ret != request->len) {
 -            errno = -EIO;
 -            rc = -1;
 +            return -EIO;
          }
      }
      qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
commit cb4c2548ea7cceef7260465773c6b8e634c186d4
Merge: 5469963... 02f5da1...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 14:15:09 2012 -0500

    Merge remote-tracking branch 'origin/master' into staging
    
    * origin/master:
      fix BCD mask for date (Solaris 2.5 guest hang fix)

commit 02f5da11d694df75af454205d8d81ac73dea50f0
Author: Artyom Tarasenko <atar4qemu at gmail.com>
Date:   Mon Apr 23 16:48:31 2012 +0200

    fix BCD mask for date (Solaris 2.5 guest hang fix)
    
    Fix BCD mask for date. The most visible effect of this patch is
    Solaris 2.5.1 doesn't hang at boot if the day of month is >21.
    
    Signed-off-by: Artyom Tarasenko <atar4qemu at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/m48t59.c b/hw/m48t59.c
index 60bbb00..0c50f45 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -239,7 +239,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
         break;
     case 0x1FF5:
         /* alarm date */
-        tmp = from_bcd(val & 0x1F);
+        tmp = from_bcd(val & 0x3F);
         if (tmp != 0) {
             NVRAM->alarm.tm_mday = tmp;
             NVRAM->buffer[0x1FF5] = val;
@@ -310,8 +310,8 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
         break;
     case 0x1FFD:
     case 0x07FD:
-        /* date */
-	tmp = from_bcd(val & 0x1F);
+        /* date (BCD) */
+       tmp = from_bcd(val & 0x3F);
 	if (tmp != 0) {
 	    get_time(NVRAM, &tm);
 	    tm.tm_mday = tmp;
commit 5469963394eba2df7c0a093a3792dc82e060cd65
Merge: 53878a1... 3c30dd5...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 11:49:59 2012 -0500

    Merge remote-tracking branch 'origin/master' into staging
    
    * origin/master: (27 commits)
      target-arm: Move reset handling to arm_cpu_reset
      target-arm: Drop cpu_reset_model_id()
      target-arm: Move cache ID register setup to cpu specific init fns
      target-arm: Move OMAP cp15_i_{max,min} reset to cpu_state_reset
      target-arm: Move feature register setup to per-CPU init fns
      target-arm: Move iWMMXT wCID reset to cpu_state_reset
      target-arm: Drop JTAG_ID documentation
      target-arm: Move SCTLR reset value setup to per cpu init fns
      target-arm: Move CTR setup to per cpu init fns
      target-arm: Move MVFR* setup to per cpu init fns
      target-arm: Move FPSID config to cpu init fns
      target-arm: Move feature bit settings to CPU init fns
      target-arm: Add QOM subclasses for each ARM cpu implementation
      target-arm: remind to keep arm features in sync with linux-user/elfload.c
      tci: GETPC() macro must return an uintptr_t
      gdbstub: Synchronize CPU state unconditionally in gdb_set_cpu_pc
      softfloat: make USE_SOFTFLOAT_STRUCT_TYPES compile
      target-xtensa: add tests for LOOPNEZ and LOOPGTZ
      target-xtensa: fix LOOPNEZ/LOOPGTZ translation
      qtest: add m48t59 tests for Sparc
      ...

commit 57a33d89672d7c6b1864185652b7cae0747f8323
Author: NODA, Kai <nodakai at gmail.com>
Date:   Sat Apr 21 22:41:27 2012 +0900

    qapi: g_hash_table_find() instead of GHashTableIter.
    
    GHashTableIter was first introduced in glib 2.16.
    This patch removes it in favor of older g_hash_table_find()
    for better compatibility with RHEL5.
    
    Signed-off-by: NODA, Kai <nodakai at gmail.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index 74386b9..4cdc47d 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -87,20 +87,29 @@ static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
     qiv->nb_stack++;
 }
 
+/** Only for qmp_input_pop. */
+static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
+{
+    *(const char **)user_pkey = (const char *)key;
+    return TRUE;
+}
+
 static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
 {
-    GHashTableIter iter;
-    gpointer key;
+    assert(qiv->nb_stack > 0);
 
-    if (qiv->strict && qiv->stack[qiv->nb_stack - 1].h) {
-        g_hash_table_iter_init(&iter, qiv->stack[qiv->nb_stack - 1].h);
-        if (g_hash_table_iter_next(&iter, &key, NULL)) {
-            error_set(errp, QERR_QMP_EXTRA_MEMBER, (char *) key);
+    if (qiv->strict) {
+        GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
+        if (top_ht) {
+            if (g_hash_table_size(top_ht)) {
+                const char *key;
+                g_hash_table_find(top_ht, always_true, &key);
+                error_set(errp, QERR_QMP_EXTRA_MEMBER, key);
+            }
+            g_hash_table_unref(top_ht);
         }
-        g_hash_table_unref(qiv->stack[qiv->nb_stack - 1].h);
     }
 
-    assert(qiv->nb_stack > 0);
     qiv->nb_stack--;
 }
 
commit db58f9c0605fa151b8c4d691aa9ff4c6cf0de62e
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Apr 11 16:27:10 2012 +0100

    qmp: make block job command naming consistent
    
    The block streaming and job commands used '_' instead of '-' for reasons
    of compatibility with libvirt, which already included support for the
    '_' naming.  However, the semantics of block_job_cancel have changed and
    libvirt now needs to handle the new semantics.
    
    Since the old semantics were never in a QEMU release we can still rename
    the commands to use '-' instead of '_'.  Libvirt is also happy because
    the new name can be used to distinguish QEMU binaries that support the
    latest block-job-cancel semantics from those that include a downstream
    block_job_cancel command.
    
    Therefore, let's apply the QAPI/QMP naming rules to the block streaming
    and job commands.  QEMU 1.1 will be the first release with these
    commands so no upstream users can break.
    
    Note that HMP commands are left with '_' because that is the convention
    there.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Reviewed-by: Eric Blake <eblake at redhat.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index ace55f3..6499895 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1548,7 +1548,8 @@
   'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
             'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
 
-# @block_stream:
+##
+# @block-stream:
 #
 # Copy data from a backing file into a block device.
 #
@@ -1556,7 +1557,7 @@
 # backing file has been copied.  This command returns immediately once streaming
 # has started.  The status of ongoing block streaming operations can be checked
 # with query-block-jobs.  The operation can be stopped before it has completed
-# using the block_job_cancel command.
+# using the block-job-cancel command.
 #
 # If a base file is specified then sectors are not copied from that base file and
 # its backing chain.  When streaming completes the image file will have the base
@@ -1578,10 +1579,10 @@
 #
 # Since: 1.1
 ##
-{ 'command': 'block_stream', 'data': { 'device': 'str', '*base': 'str' } }
+{ 'command': 'block-stream', 'data': { 'device': 'str', '*base': 'str' } }
 
 ##
-# @block_job_set_speed:
+# @block-job-set-speed:
 #
 # Set maximum speed for a background block operation.
 #
@@ -1599,11 +1600,11 @@
 #
 # Since: 1.1
 ##
-{ 'command': 'block_job_set_speed',
+{ 'command': 'block-job-set-speed',
   'data': { 'device': 'str', 'value': 'int' } }
 
 ##
-# @block_job_cancel:
+# @block-job-cancel:
 #
 # Stop an active block streaming operation.
 #
@@ -1629,7 +1630,7 @@
 #
 # Since: 1.1
 ##
-{ 'command': 'block_job_cancel', 'data': { 'device': 'str' } }
+{ 'command': 'block-job-cancel', 'data': { 'device': 'str' } }
 
 ##
 # @ObjectTypeInfo:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index c09ee85..f972332 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -687,19 +687,19 @@ Example:
 EQMP
 
     {
-        .name       = "block_stream",
+        .name       = "block-stream",
         .args_type  = "device:B,base:s?",
         .mhandler.cmd_new = qmp_marshal_input_block_stream,
     },
 
     {
-        .name       = "block_job_set_speed",
+        .name       = "block-job-set-speed",
         .args_type  = "device:B,value:o",
         .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
     },
 
     {
-        .name       = "block_job_cancel",
+        .name       = "block-job-cancel",
         .args_type  = "device:B",
         .mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
     },
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 1faf984..978fd82 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -49,7 +49,7 @@ class TestSingleDrive(ImageStreamingTestCase):
     def test_stream(self):
         self.assert_no_active_streams()
 
-        result = self.vm.qmp('block_stream', device='drive0')
+        result = self.vm.qmp('block-stream', device='drive0')
         self.assert_qmp(result, 'return', {})
 
         completed = False
@@ -68,7 +68,7 @@ class TestSingleDrive(ImageStreamingTestCase):
                          'image file not fully populated after streaming')
 
     def test_device_not_found(self):
-        result = self.vm.qmp('block_stream', device='nonexistent')
+        result = self.vm.qmp('block-stream', device='nonexistent')
         self.assert_qmp(result, 'error/class', 'DeviceNotFound')
 
 class TestStreamStop(ImageStreamingTestCase):
@@ -90,14 +90,14 @@ class TestStreamStop(ImageStreamingTestCase):
 
         self.assert_no_active_streams()
 
-        result = self.vm.qmp('block_stream', device='drive0')
+        result = self.vm.qmp('block-stream', device='drive0')
         self.assert_qmp(result, 'return', {})
 
         time.sleep(1)
         events = self.vm.get_qmp_events(wait=False)
         self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
 
-        self.vm.qmp('block_job_cancel', device='drive0')
+        self.vm.qmp('block-job-cancel', device='drive0')
         self.assert_qmp(result, 'return', {})
 
         cancelled = False
@@ -129,10 +129,10 @@ class TestSetSpeed(ImageStreamingTestCase):
     def perf_test_set_speed(self):
         self.assert_no_active_streams()
 
-        result = self.vm.qmp('block_stream', device='drive0')
+        result = self.vm.qmp('block-stream', device='drive0')
         self.assert_qmp(result, 'return', {})
 
-        result = self.vm.qmp('block_job_set_speed', device='drive0', value=8 * 1024 * 1024)
+        result = self.vm.qmp('block-job-set-speed', device='drive0', value=8 * 1024 * 1024)
         self.assert_qmp(result, 'return', {})
 
         completed = False
commit 53878a132aaadbedbe8fe0e44afa032a4ed73aea
Merge: 6b03296... 4c9f8d1...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 09:58:54 2012 -0500

    Merge remote-tracking branch 'sstabellini/build_fix' into staging
    
    * sstabellini/build_fix:
      xen: add a dummy xc_hvm_inject_msi for Xen < 4.2
      xen,configure: detect Xen 4.2

commit 6b03296606c665beb570eaa53a71f7688a43b9e7
Merge: 25896d8... fecccc4...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 09:58:33 2012 -0500

    Merge remote-tracking branch 'stefanha/trivial-patches' into staging
    
    * stefanha/trivial-patches:
      Add .gitignore for tests/
      e1000: Fix spelling (segmentaion -> segmentation) in debug output
      spice-qemu-char.c: Show what name is unsupported
      pflash_cfi01: remove redundant line
      qxl: Add missing GCC_FMT_ATTR and fix format specifier
      fix block_job_set_speed name in documentation
      error.c: don't return value for void function

commit 25896d8063f0ea02d4cc9159f6da622aeb115945
Merge: bec8eb8... 4bdd041...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 09:58:19 2012 -0500

    Merge remote-tracking branch 'mdroth/qga-pull-4-19-12' into staging
    
    * mdroth/qga-pull-4-19-12:
      qemu-ga: fix help output
      qemu-ga: generate missing stubs for fsfreeze

commit bec8eb8136309104d18a4757d20470883f0d5ac1
Merge: 4a1873f... e25ceb7...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 09:58:01 2012 -0500

    Merge remote-tracking branch 'bonzini/nbd-next' into staging
    
    * bonzini/nbd-next:
      nbd: obey FUA on reads
      nbd: do not include block_int.h
      nbd: do not block in nbd_wr_sync if no data at all is available
      nbd: consistently return negative errno values
      nbd: consistently check for <0 or >=0
      nbd: consistently use ssize_t
      nbd: avoid out of bounds access to recv_coroutine array

commit 4a1873fc8c3f692fcae25ed1ebf10003d5d5feb0
Merge: e5e3895... 3e46d87...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 09:57:47 2012 -0500

    Merge remote-tracking branch 'bonzini/scsi-next' into staging
    
    * bonzini/scsi-next:
      scsi: add SANITIZE command
      SCSI emulation: should tell the guest that we actually support thin provisioning
      SCSI emulation: Support unmap via WRITE_SAME_10.
      scsi: advertise DPOFUA
      scsi: small refactoring of MMC mode-sense
      scsi: support FUA on reads
      scsi: add a started field to SCSIDiskReq
      scsi: force unit access on VERIFY
      scsi: add support for FUA on writes
      scsi: move scsi_flush_complete around
      scsi: make code more homogeneous in AIO callback functions
      scsi: add missing test for cancelled request
      virtio-scsi: add multiqueue capability
      virtio: add virtio_queue_get_id
      virtio-scsi: prepare migration format for multiqueue
      scsi: fix memory leak

commit e5e3895702514253120965cfda75c58f28c39a00
Merge: 51006bb... 256a721...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Apr 23 09:57:04 2012 -0500

    Merge remote-tracking branch 'stefanha/tracing' into staging
    
    * stefanha/tracing:
      tracetool: handle DTrace keywords 'in', 'next', 'self'
      tracetool: Add MAINTAINERS info
      tracetool: Add support for the 'dtrace' backend
      tracetool: Add support for the 'ust' backend
      tracetool: Add support for the 'simple' backend
      tracetool: Add support for the 'stderr' backend
      tracetool: Add module for the 'h' format
      tracetool: Add module for the 'c' format
      tracetool: Rewrite infrastructure as python modules

commit 3c30dd5a68e9fee6af67cfd0d14ed7520820f36a
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:36 2012 +0000

    target-arm: Move reset handling to arm_cpu_reset
    
    Now that cpu_reset_model_id() has gone we can move the
    reset code over to the class reset function and have cpu_state_reset
    simply do a reset on the CPU QOM object.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 8259a0d..cc67d4d 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -20,18 +20,106 @@
 
 #include "cpu-qom.h"
 #include "qemu-common.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/loader.h"
+#endif
 
 /* CPUClass::reset() */
 static void arm_cpu_reset(CPUState *s)
 {
     ARMCPU *cpu = ARM_CPU(s);
     ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
+    CPUARMState *env = &cpu->env;
+    uint32_t tmp = 0;
+
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
 
     acc->parent_reset(s);
 
-    /* TODO Inline the current contents of cpu_state_reset(),
-            once cpu_reset_model_id() is eliminated. */
-    cpu_state_reset(&cpu->env);
+    tmp = env->cp15.c15_config_base_address;
+    memset(env, 0, offsetof(CPUARMState, breakpoints));
+    env->cp15.c15_config_base_address = tmp;
+    env->cp15.c0_cpuid = cpu->midr;
+    env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
+    env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
+    env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
+    env->cp15.c0_cachetype = cpu->ctr;
+    env->cp15.c1_sys = cpu->reset_sctlr;
+    env->cp15.c0_c1[0] = cpu->id_pfr0;
+    env->cp15.c0_c1[1] = cpu->id_pfr1;
+    env->cp15.c0_c1[2] = cpu->id_dfr0;
+    env->cp15.c0_c1[3] = cpu->id_afr0;
+    env->cp15.c0_c1[4] = cpu->id_mmfr0;
+    env->cp15.c0_c1[5] = cpu->id_mmfr1;
+    env->cp15.c0_c1[6] = cpu->id_mmfr2;
+    env->cp15.c0_c1[7] = cpu->id_mmfr3;
+    env->cp15.c0_c2[0] = cpu->id_isar0;
+    env->cp15.c0_c2[1] = cpu->id_isar1;
+    env->cp15.c0_c2[2] = cpu->id_isar2;
+    env->cp15.c0_c2[3] = cpu->id_isar3;
+    env->cp15.c0_c2[4] = cpu->id_isar4;
+    env->cp15.c0_c2[5] = cpu->id_isar5;
+    env->cp15.c15_i_min = 0xff0;
+    env->cp15.c0_clid = cpu->clidr;
+    memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr));
+
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
+    }
+
+#if defined(CONFIG_USER_ONLY)
+    env->uncached_cpsr = ARM_CPU_MODE_USR;
+    /* For user mode we must enable access to coprocessors */
+    env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        env->cp15.c15_cpar = 3;
+    } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+        env->cp15.c15_cpar = 1;
+    }
+#else
+    /* SVC mode with interrupts disabled.  */
+    env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+    /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
+       clear at reset.  Initial SP and PC are loaded from ROM.  */
+    if (IS_M(env)) {
+        uint32_t pc;
+        uint8_t *rom;
+        env->uncached_cpsr &= ~CPSR_I;
+        rom = rom_ptr(0);
+        if (rom) {
+            /* We should really use ldl_phys here, in case the guest
+               modified flash and reset itself.  However images
+               loaded via -kernel have not been copied yet, so load the
+               values directly from there.  */
+            env->regs[13] = ldl_p(rom);
+            pc = ldl_p(rom + 4);
+            env->thumb = pc & 1;
+            env->regs[15] = pc & ~1;
+        }
+    }
+    env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+    env->cp15.c2_base_mask = 0xffffc000u;
+    /* v7 performance monitor control register: same implementor
+     * field as main ID register, and we implement no event counters.
+     */
+    env->cp15.c9_pmcr = (cpu->midr & 0xff000000);
+#endif
+    set_flush_to_zero(1, &env->vfp.standard_fp_status);
+    set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
+    set_default_nan_mode(1, &env->vfp.standard_fp_status);
+    set_float_detect_tininess(float_tininess_before_rounding,
+                              &env->vfp.fp_status);
+    set_float_detect_tininess(float_tininess_before_rounding,
+                              &env->vfp.standard_fp_status);
+    tlb_flush(env, 1);
+    /* Reset is a state change for some CPUARMState fields which we
+     * bake assumptions about into translated code, so we need to
+     * tb_flush().
+     */
+    tb_flush(env);
 }
 
 static inline void set_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 653885a..101031d 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2,106 +2,11 @@
 #include "gdbstub.h"
 #include "helper.h"
 #include "host-utils.h"
-#if !defined(CONFIG_USER_ONLY)
-#include "hw/loader.h"
-#endif
 #include "sysemu.h"
 
-/* TODO Move contents into arm_cpu_reset() in cpu.c,
- *      once cpu_reset_model_id() is eliminated,
- *      and then forward to cpu_reset() here.
- */
 void cpu_state_reset(CPUARMState *env)
 {
-    uint32_t tmp = 0;
-    ARMCPU *cpu = arm_env_get_cpu(env);
-
-    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
-        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
-        log_cpu_state(env, 0);
-    }
-
-    tmp = env->cp15.c15_config_base_address;
-    memset(env, 0, offsetof(CPUARMState, breakpoints));
-    env->cp15.c15_config_base_address = tmp;
-    env->cp15.c0_cpuid = cpu->midr;
-    env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
-    env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
-    env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
-    env->cp15.c0_cachetype = cpu->ctr;
-    env->cp15.c1_sys = cpu->reset_sctlr;
-    env->cp15.c0_c1[0] = cpu->id_pfr0;
-    env->cp15.c0_c1[1] = cpu->id_pfr1;
-    env->cp15.c0_c1[2] = cpu->id_dfr0;
-    env->cp15.c0_c1[3] = cpu->id_afr0;
-    env->cp15.c0_c1[4] = cpu->id_mmfr0;
-    env->cp15.c0_c1[5] = cpu->id_mmfr1;
-    env->cp15.c0_c1[6] = cpu->id_mmfr2;
-    env->cp15.c0_c1[7] = cpu->id_mmfr3;
-    env->cp15.c0_c2[0] = cpu->id_isar0;
-    env->cp15.c0_c2[1] = cpu->id_isar1;
-    env->cp15.c0_c2[2] = cpu->id_isar2;
-    env->cp15.c0_c2[3] = cpu->id_isar3;
-    env->cp15.c0_c2[4] = cpu->id_isar4;
-    env->cp15.c0_c2[5] = cpu->id_isar5;
-    env->cp15.c15_i_min = 0xff0;
-    env->cp15.c0_clid = cpu->clidr;
-    memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr));
-
-    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
-        env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
-    }
-
-#if defined (CONFIG_USER_ONLY)
-    env->uncached_cpsr = ARM_CPU_MODE_USR;
-    /* For user mode we must enable access to coprocessors */
-    env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
-    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
-        env->cp15.c15_cpar = 3;
-    } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
-        env->cp15.c15_cpar = 1;
-    }
-#else
-    /* SVC mode with interrupts disabled.  */
-    env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
-    /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
-       clear at reset.  Initial SP and PC are loaded from ROM.  */
-    if (IS_M(env)) {
-        uint32_t pc;
-        uint8_t *rom;
-        env->uncached_cpsr &= ~CPSR_I;
-        rom = rom_ptr(0);
-        if (rom) {
-            /* We should really use ldl_phys here, in case the guest
-               modified flash and reset itself.  However images
-               loaded via -kernel have not been copied yet, so load the
-               values directly from there.  */
-            env->regs[13] = ldl_p(rom);
-            pc = ldl_p(rom + 4);
-            env->thumb = pc & 1;
-            env->regs[15] = pc & ~1;
-        }
-    }
-    env->vfp.xregs[ARM_VFP_FPEXC] = 0;
-    env->cp15.c2_base_mask = 0xffffc000u;
-    /* v7 performance monitor control register: same implementor
-     * field as main ID register, and we implement no event counters.
-     */
-    env->cp15.c9_pmcr = (cpu->midr & 0xff000000);
-#endif
-    set_flush_to_zero(1, &env->vfp.standard_fp_status);
-    set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
-    set_default_nan_mode(1, &env->vfp.standard_fp_status);
-    set_float_detect_tininess(float_tininess_before_rounding,
-                              &env->vfp.fp_status);
-    set_float_detect_tininess(float_tininess_before_rounding,
-                              &env->vfp.standard_fp_status);
-    tlb_flush(env, 1);
-    /* Reset is a state change for some CPUARMState fields which we
-     * bake assumptions about into translated code, so we need to
-     * tb_flush().
-     */
-    tb_flush(env);
+    cpu_reset(ENV_GET_CPU(env));
 }
 
 static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
commit caa1d0779e956afe694922ca4bf7e2903356fcff
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:35 2012 +0000

    target-arm: Drop cpu_reset_model_id()
    
    cpu_reset_model_id() is now empty and we can remove it.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5cbc7e0..653885a 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -7,66 +7,12 @@
 #endif
 #include "sysemu.h"
 
-static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
-{
-    switch (id) {
-    case ARM_CPUID_ARM926:
-        break;
-    case ARM_CPUID_ARM946:
-        break;
-    case ARM_CPUID_ARM1026:
-        break;
-    case ARM_CPUID_ARM1136:
-        /* This is the 1136 r1, which is a v6K core */
-    case ARM_CPUID_ARM1136_R2:
-        break;
-    case ARM_CPUID_ARM1176:
-        break;
-    case ARM_CPUID_ARM11MPCORE:
-        break;
-    case ARM_CPUID_CORTEXA8:
-        break;
-    case ARM_CPUID_CORTEXA9:
-        break;
-    case ARM_CPUID_CORTEXA15:
-        break;
-    case ARM_CPUID_CORTEXM3:
-        break;
-    case ARM_CPUID_ANY: /* For userspace emulation.  */
-        break;
-    case ARM_CPUID_TI915T:
-    case ARM_CPUID_TI925T:
-        break;
-    case ARM_CPUID_PXA250:
-    case ARM_CPUID_PXA255:
-    case ARM_CPUID_PXA260:
-    case ARM_CPUID_PXA261:
-    case ARM_CPUID_PXA262:
-        break;
-    case ARM_CPUID_PXA270_A0:
-    case ARM_CPUID_PXA270_A1:
-    case ARM_CPUID_PXA270_B0:
-    case ARM_CPUID_PXA270_B1:
-    case ARM_CPUID_PXA270_C0:
-    case ARM_CPUID_PXA270_C5:
-        break;
-    case ARM_CPUID_SA1100:
-    case ARM_CPUID_SA1110:
-        break;
-    default:
-        cpu_abort(env, "Bad CPU ID: %x\n", id);
-        break;
-    }
-
-}
-
 /* TODO Move contents into arm_cpu_reset() in cpu.c,
  *      once cpu_reset_model_id() is eliminated,
  *      and then forward to cpu_reset() here.
  */
 void cpu_state_reset(CPUARMState *env)
 {
-    uint32_t id;
     uint32_t tmp = 0;
     ARMCPU *cpu = arm_env_get_cpu(env);
 
@@ -75,11 +21,8 @@ void cpu_state_reset(CPUARMState *env)
         log_cpu_state(env, 0);
     }
 
-    id = cpu->midr;
     tmp = env->cp15.c15_config_base_address;
     memset(env, 0, offsetof(CPUARMState, breakpoints));
-    if (id)
-        cpu_reset_model_id(env, id);
     env->cp15.c15_config_base_address = tmp;
     env->cp15.c0_cpuid = cpu->midr;
     env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
@@ -144,7 +87,7 @@ void cpu_state_reset(CPUARMState *env)
     /* v7 performance monitor control register: same implementor
      * field as main ID register, and we implement no event counters.
      */
-    env->cp15.c9_pmcr = (id & 0xff000000);
+    env->cp15.c9_pmcr = (cpu->midr & 0xff000000);
 #endif
     set_flush_to_zero(1, &env->vfp.standard_fp_status);
     set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
commit 85df3786b21191d49d17dcb77f45ae75f6addad0
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:35 2012 +0000

    target-arm: Move cache ID register setup to cpu specific init fns
    
    Move cache ID register reset out of cpu_reset_model_id() by
    creating a field for the reset value in ARMCPU and setting it
    up in the cpu specific init functions.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 7603eff..b6c044a 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -89,6 +89,11 @@ typedef struct ARMCPU {
     uint32_t id_isar3;
     uint32_t id_isar4;
     uint32_t id_isar5;
+    uint32_t clidr;
+    /* The elements of this array are the CCSIDR values for each cache,
+     * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
+     */
+    uint32_t ccsidr[16];
 } ARMCPU;
 
 static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 333f7fc..8259a0d 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -270,6 +270,10 @@ static void cortex_a8_initfn(Object *obj)
     cpu->id_isar2 = 0x21232031;
     cpu->id_isar3 = 0x11112131;
     cpu->id_isar4 = 0x00111142;
+    cpu->clidr = (1 << 27) | (2 << 24) | 3;
+    cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */
+    cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */
+    cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */
 }
 
 static void cortex_a9_initfn(Object *obj)
@@ -304,6 +308,9 @@ static void cortex_a9_initfn(Object *obj)
     cpu->id_isar2 = 0x21232041;
     cpu->id_isar3 = 0x11112131;
     cpu->id_isar4 = 0x00111142;
+    cpu->clidr = (1 << 27) | (1 << 24) | 3;
+    cpu->ccsidr[0] = 0xe00fe015; /* 16k L1 dcache. */
+    cpu->ccsidr[1] = 0x200fe015; /* 16k L1 icache. */
 }
 
 static void cortex_a15_initfn(Object *obj)
@@ -336,6 +343,10 @@ static void cortex_a15_initfn(Object *obj)
     cpu->id_isar2 = 0x21232041;
     cpu->id_isar3 = 0x11112131;
     cpu->id_isar4 = 0x10011142;
+    cpu->clidr = 0x0a200023;
+    cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
+    cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
+    cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
 }
 
 static void ti925t_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index fb618a7..5cbc7e0 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -25,21 +25,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_ARM11MPCORE:
         break;
     case ARM_CPUID_CORTEXA8:
-        env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
-        env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
-        env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
-        env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
         break;
     case ARM_CPUID_CORTEXA9:
-        env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
-        env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
-        env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
         break;
     case ARM_CPUID_CORTEXA15:
-        env->cp15.c0_clid = 0x0a200023;
-        env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
-        env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
-        env->cp15.c0_ccsid[2] = 0x711fe07a; /* 4096K L2 unified cache */
         break;
     case ARM_CPUID_CORTEXM3:
         break;
@@ -113,6 +102,8 @@ void cpu_state_reset(CPUARMState *env)
     env->cp15.c0_c2[4] = cpu->id_isar4;
     env->cp15.c0_c2[5] = cpu->id_isar5;
     env->cp15.c15_i_min = 0xff0;
+    env->cp15.c0_clid = cpu->clidr;
+    memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr));
 
     if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
commit 8092d2f031e70eb2664d5fa1d9ed00ef1113ee71
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:35 2012 +0000

    target-arm: Move OMAP cp15_i_{max,min} reset to cpu_state_reset
    
    Move the OMAP-specific cp15_i_{max,min} reset to cpu_state_reset;
    since these registers are only accessible on CPUs with the
    OMAPCP feature set there's no need to guard this reset with
    either a CPUID or feature bit check.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 84830ff..fb618a7 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -47,8 +47,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
-        env->cp15.c15_i_max = 0x000;
-        env->cp15.c15_i_min = 0xff0;
         break;
     case ARM_CPUID_PXA250:
     case ARM_CPUID_PXA255:
@@ -114,6 +112,7 @@ void cpu_state_reset(CPUARMState *env)
     env->cp15.c0_c2[3] = cpu->id_isar3;
     env->cp15.c0_c2[4] = cpu->id_isar4;
     env->cp15.c0_c2[5] = cpu->id_isar5;
+    env->cp15.c15_i_min = 0xff0;
 
     if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
commit 2e4d7e3e3e97c4e0e68aca6221e3e7cb10b6041c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:34 2012 +0000

    target-arm: Move feature register setup to per-CPU init fns
    
    Move feature register value setup to per-CPU init functions.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 97f7e90..7603eff 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -75,6 +75,20 @@ typedef struct ARMCPU {
     uint32_t mvfr1;
     uint32_t ctr;
     uint32_t reset_sctlr;
+    uint32_t id_pfr0;
+    uint32_t id_pfr1;
+    uint32_t id_dfr0;
+    uint32_t id_afr0;
+    uint32_t id_mmfr0;
+    uint32_t id_mmfr1;
+    uint32_t id_mmfr2;
+    uint32_t id_mmfr3;
+    uint32_t id_isar0;
+    uint32_t id_isar1;
+    uint32_t id_isar2;
+    uint32_t id_isar3;
+    uint32_t id_isar4;
+    uint32_t id_isar5;
 } ARMCPU;
 
 static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 74a7d20..333f7fc 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -130,6 +130,13 @@ static void arm1026_initfn(Object *obj)
 static void arm1136_r2_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
+     * older core than plain "arm1136". In particular this does not
+     * have the v6K features.
+     * These ID register values are correct for 1136 but may be wrong
+     * for 1136_r2 (in particular r0p2 does not actually implement most
+     * of the ID registers).
+     */
     set_feature(&cpu->env, ARM_FEATURE_V6);
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM1136_R2;
@@ -138,6 +145,18 @@ static void arm1136_r2_initfn(Object *obj)
     cpu->mvfr1 = 0x00000000;
     cpu->ctr = 0x1dd20d2;
     cpu->reset_sctlr = 0x00050078;
+    cpu->id_pfr0 = 0x111;
+    cpu->id_pfr1 = 0x1;
+    cpu->id_dfr0 = 0x2;
+    cpu->id_afr0 = 0x3;
+    cpu->id_mmfr0 = 0x01130003;
+    cpu->id_mmfr1 = 0x10030302;
+    cpu->id_mmfr2 = 0x01222110;
+    cpu->id_isar0 = 0x00140011;
+    cpu->id_isar1 = 0x12002111;
+    cpu->id_isar2 = 0x11231111;
+    cpu->id_isar3 = 0x01102131;
+    cpu->id_isar4 = 0x141;
 }
 
 static void arm1136_initfn(Object *obj)
@@ -152,6 +171,18 @@ static void arm1136_initfn(Object *obj)
     cpu->mvfr1 = 0x00000000;
     cpu->ctr = 0x1dd20d2;
     cpu->reset_sctlr = 0x00050078;
+    cpu->id_pfr0 = 0x111;
+    cpu->id_pfr1 = 0x1;
+    cpu->id_dfr0 = 0x2;
+    cpu->id_afr0 = 0x3;
+    cpu->id_mmfr0 = 0x01130003;
+    cpu->id_mmfr1 = 0x10030302;
+    cpu->id_mmfr2 = 0x01222110;
+    cpu->id_isar0 = 0x00140011;
+    cpu->id_isar1 = 0x12002111;
+    cpu->id_isar2 = 0x11231111;
+    cpu->id_isar3 = 0x01102131;
+    cpu->id_isar4 = 0x141;
 }
 
 static void arm1176_initfn(Object *obj)
@@ -166,6 +197,18 @@ static void arm1176_initfn(Object *obj)
     cpu->mvfr1 = 0x00000000;
     cpu->ctr = 0x1dd20d2;
     cpu->reset_sctlr = 0x00050078;
+    cpu->id_pfr0 = 0x111;
+    cpu->id_pfr1 = 0x11;
+    cpu->id_dfr0 = 0x33;
+    cpu->id_afr0 = 0;
+    cpu->id_mmfr0 = 0x01130003;
+    cpu->id_mmfr1 = 0x10030302;
+    cpu->id_mmfr2 = 0x01222100;
+    cpu->id_isar0 = 0x0140011;
+    cpu->id_isar1 = 0x12002111;
+    cpu->id_isar2 = 0x11231121;
+    cpu->id_isar3 = 0x01102131;
+    cpu->id_isar4 = 0x01141;
 }
 
 static void arm11mpcore_initfn(Object *obj)
@@ -179,6 +222,18 @@ static void arm11mpcore_initfn(Object *obj)
     cpu->mvfr0 = 0x11111111;
     cpu->mvfr1 = 0x00000000;
     cpu->ctr = 0x1dd20d2;
+    cpu->id_pfr0 = 0x111;
+    cpu->id_pfr1 = 0x1;
+    cpu->id_dfr0 = 0;
+    cpu->id_afr0 = 0x2;
+    cpu->id_mmfr0 = 0x01100103;
+    cpu->id_mmfr1 = 0x10020302;
+    cpu->id_mmfr2 = 0x01222000;
+    cpu->id_isar0 = 0x00100011;
+    cpu->id_isar1 = 0x12002111;
+    cpu->id_isar2 = 0x11221011;
+    cpu->id_isar3 = 0x01102131;
+    cpu->id_isar4 = 0x141;
 }
 
 static void cortex_m3_initfn(Object *obj)
@@ -202,6 +257,19 @@ static void cortex_a8_initfn(Object *obj)
     cpu->mvfr1 = 0x00011100;
     cpu->ctr = 0x82048004;
     cpu->reset_sctlr = 0x00c50078;
+    cpu->id_pfr0 = 0x1031;
+    cpu->id_pfr1 = 0x11;
+    cpu->id_dfr0 = 0x400;
+    cpu->id_afr0 = 0;
+    cpu->id_mmfr0 = 0x31100003;
+    cpu->id_mmfr1 = 0x20000000;
+    cpu->id_mmfr2 = 0x01202000;
+    cpu->id_mmfr3 = 0x11;
+    cpu->id_isar0 = 0x00101111;
+    cpu->id_isar1 = 0x12112111;
+    cpu->id_isar2 = 0x21232031;
+    cpu->id_isar3 = 0x11112131;
+    cpu->id_isar4 = 0x00111142;
 }
 
 static void cortex_a9_initfn(Object *obj)
@@ -223,6 +291,19 @@ static void cortex_a9_initfn(Object *obj)
     cpu->mvfr1 = 0x01111111;
     cpu->ctr = 0x80038003;
     cpu->reset_sctlr = 0x00c50078;
+    cpu->id_pfr0 = 0x1031;
+    cpu->id_pfr1 = 0x11;
+    cpu->id_dfr0 = 0x000;
+    cpu->id_afr0 = 0;
+    cpu->id_mmfr0 = 0x00100103;
+    cpu->id_mmfr1 = 0x20000000;
+    cpu->id_mmfr2 = 0x01230000;
+    cpu->id_mmfr3 = 0x00002111;
+    cpu->id_isar0 = 0x00101111;
+    cpu->id_isar1 = 0x13112111;
+    cpu->id_isar2 = 0x21232041;
+    cpu->id_isar3 = 0x11112131;
+    cpu->id_isar4 = 0x00111142;
 }
 
 static void cortex_a15_initfn(Object *obj)
@@ -242,6 +323,19 @@ static void cortex_a15_initfn(Object *obj)
     cpu->mvfr1 = 0x11111111;
     cpu->ctr = 0x8444c004;
     cpu->reset_sctlr = 0x00c50078;
+    cpu->id_pfr0 = 0x00001131;
+    cpu->id_pfr1 = 0x00011011;
+    cpu->id_dfr0 = 0x02010555;
+    cpu->id_afr0 = 0x00000000;
+    cpu->id_mmfr0 = 0x10201105;
+    cpu->id_mmfr1 = 0x20000000;
+    cpu->id_mmfr2 = 0x01240000;
+    cpu->id_mmfr3 = 0x02102211;
+    cpu->id_isar0 = 0x02101110;
+    cpu->id_isar1 = 0x13112111;
+    cpu->id_isar2 = 0x21232041;
+    cpu->id_isar3 = 0x11112131;
+    cpu->id_isar4 = 0x10011142;
 }
 
 static void ti925t_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 319614a..84830ff 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -7,45 +7,6 @@
 #endif
 #include "sysemu.h"
 
-static uint32_t cortexa15_cp15_c0_c1[8] = {
-    0x00001131, 0x00011011, 0x02010555, 0x00000000,
-    0x10201105, 0x20000000, 0x01240000, 0x02102211
-};
-
-static uint32_t cortexa15_cp15_c0_c2[8] = {
-    0x02101110, 0x13112111, 0x21232041, 0x11112131, 0x10011142, 0, 0, 0
-};
-
-static uint32_t cortexa9_cp15_c0_c1[8] =
-{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
-
-static uint32_t cortexa9_cp15_c0_c2[8] =
-{ 0x00101111, 0x13112111, 0x21232041, 0x11112131, 0x00111142, 0, 0, 0 };
-
-static uint32_t cortexa8_cp15_c0_c1[8] =
-{ 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 };
-
-static uint32_t cortexa8_cp15_c0_c2[8] =
-{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 };
-
-static uint32_t mpcore_cp15_c0_c1[8] =
-{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 };
-
-static uint32_t mpcore_cp15_c0_c2[8] =
-{ 0x00100011, 0x12002111, 0x11221011, 0x01102131, 0x141, 0, 0, 0 };
-
-static uint32_t arm1136_cp15_c0_c1[8] =
-{ 0x111, 0x1, 0x2, 0x3, 0x01130003, 0x10030302, 0x01222110, 0 };
-
-static uint32_t arm1136_cp15_c0_c2[8] =
-{ 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 };
-
-static uint32_t arm1176_cp15_c0_c1[8] =
-{ 0x111, 0x11, 0x33, 0, 0x01130003, 0x10030302, 0x01222100, 0 };
-
-static uint32_t arm1176_cp15_c0_c2[8] =
-{ 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
-
 static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     switch (id) {
@@ -58,43 +19,23 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_ARM1136:
         /* This is the 1136 r1, which is a v6K core */
     case ARM_CPUID_ARM1136_R2:
-        /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
-         * older core than plain "arm1136". In particular this does not
-         * have the v6K features.
-         */
-        /* These ID register values are correct for 1136 but may be wrong
-         * for 1136_r2 (in particular r0p2 does not actually implement most
-         * of the ID registers).
-         */
-        memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
         break;
     case ARM_CPUID_ARM1176:
-        memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
         break;
     case ARM_CPUID_ARM11MPCORE:
-        memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
         break;
     case ARM_CPUID_CORTEXA8:
-        memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
         env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
         env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
         env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
         break;
     case ARM_CPUID_CORTEXA9:
-        memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
         env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
         env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
         break;
     case ARM_CPUID_CORTEXA15:
-        memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_clid = 0x0a200023;
         env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
         env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
@@ -159,6 +100,20 @@ void cpu_state_reset(CPUARMState *env)
     env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
     env->cp15.c0_cachetype = cpu->ctr;
     env->cp15.c1_sys = cpu->reset_sctlr;
+    env->cp15.c0_c1[0] = cpu->id_pfr0;
+    env->cp15.c0_c1[1] = cpu->id_pfr1;
+    env->cp15.c0_c1[2] = cpu->id_dfr0;
+    env->cp15.c0_c1[3] = cpu->id_afr0;
+    env->cp15.c0_c1[4] = cpu->id_mmfr0;
+    env->cp15.c0_c1[5] = cpu->id_mmfr1;
+    env->cp15.c0_c1[6] = cpu->id_mmfr2;
+    env->cp15.c0_c1[7] = cpu->id_mmfr3;
+    env->cp15.c0_c2[0] = cpu->id_isar0;
+    env->cp15.c0_c2[1] = cpu->id_isar1;
+    env->cp15.c0_c2[2] = cpu->id_isar2;
+    env->cp15.c0_c2[3] = cpu->id_isar3;
+    env->cp15.c0_c2[4] = cpu->id_isar4;
+    env->cp15.c0_c2[5] = cpu->id_isar5;
 
     if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
commit 0cc892fd97b2d232ae45a30aec342a2e0fb148aa
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:34 2012 +0000

    target-arm: Move iWMMXT wCID reset to cpu_state_reset
    
    Move the iWMMXT wCID reset to cpu_state_reset(). Since
    we use the same value for all CPUs with this feature
    (with the major/minor revision fields set to the QEMU
    specific 'Q' value) there's no need to create an ARMCPU
    field just for this.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3e31f94..319614a 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -121,7 +121,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_B1:
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
-        env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
         break;
     case ARM_CPUID_SA1100:
     case ARM_CPUID_SA1110:
@@ -161,6 +160,10 @@ void cpu_state_reset(CPUARMState *env)
     env->cp15.c0_cachetype = cpu->ctr;
     env->cp15.c1_sys = cpu->reset_sctlr;
 
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
+    }
+
 #if defined (CONFIG_USER_ONLY)
     env->uncached_cpsr = ARM_CPU_MODE_USR;
     /* For user mode we must enable access to coprocessors */
commit 4e851c380eda2bf27ff2ded85e4c80a342e6a72f
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:33 2012 +0000

    target-arm: Drop JTAG_ID documentation
    
    None of the machines in QEMU offer a JTAG debug interface, so this info
    was unused. Further, the PXA250 ID contradicts the February 2002
    Developer's Manual, which has it as 0xn9264013 with n the MIDR Revision.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index eab25ca..3e31f94 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -114,7 +114,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA260:
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
-        /* JTAG_ID is ((id << 28) | 0x09265013) */
         break;
     case ARM_CPUID_PXA270_A0:
     case ARM_CPUID_PXA270_A1:
@@ -122,7 +121,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_B1:
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
-        /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
         break;
     case ARM_CPUID_SA1100:
commit 0ca7e01cbc5f2850560e6a170ae1e4541aecce17
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:33 2012 +0000

    target-arm: Move SCTLR reset value setup to per cpu init fns
    
    Move the reset value of SCTLR to ARMCPU, initialised in
    the per-cpu init functions. It can then be reset by a
    simple copy, and we can drop the code from cpu_reset_model_id().
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index cb9198a..97f7e90 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -74,6 +74,7 @@ typedef struct ARMCPU {
     uint32_t mvfr0;
     uint32_t mvfr1;
     uint32_t ctr;
+    uint32_t reset_sctlr;
 } ARMCPU;
 
 static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 4f19d5c..74a7d20 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -102,6 +102,7 @@ static void arm926_initfn(Object *obj)
     cpu->midr = ARM_CPUID_ARM926;
     cpu->reset_fpsid = 0x41011090;
     cpu->ctr = 0x1dd20d2;
+    cpu->reset_sctlr = 0x00090078;
 }
 
 static void arm946_initfn(Object *obj)
@@ -111,6 +112,7 @@ static void arm946_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_MPU);
     cpu->midr = ARM_CPUID_ARM946;
     cpu->ctr = 0x0f004006;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void arm1026_initfn(Object *obj)
@@ -122,6 +124,7 @@ static void arm1026_initfn(Object *obj)
     cpu->midr = ARM_CPUID_ARM1026;
     cpu->reset_fpsid = 0x410110a0;
     cpu->ctr = 0x1dd20d2;
+    cpu->reset_sctlr = 0x00090078;
 }
 
 static void arm1136_r2_initfn(Object *obj)
@@ -134,6 +137,7 @@ static void arm1136_r2_initfn(Object *obj)
     cpu->mvfr0 = 0x11111111;
     cpu->mvfr1 = 0x00000000;
     cpu->ctr = 0x1dd20d2;
+    cpu->reset_sctlr = 0x00050078;
 }
 
 static void arm1136_initfn(Object *obj)
@@ -147,6 +151,7 @@ static void arm1136_initfn(Object *obj)
     cpu->mvfr0 = 0x11111111;
     cpu->mvfr1 = 0x00000000;
     cpu->ctr = 0x1dd20d2;
+    cpu->reset_sctlr = 0x00050078;
 }
 
 static void arm1176_initfn(Object *obj)
@@ -160,6 +165,7 @@ static void arm1176_initfn(Object *obj)
     cpu->mvfr0 = 0x11111111;
     cpu->mvfr1 = 0x00000000;
     cpu->ctr = 0x1dd20d2;
+    cpu->reset_sctlr = 0x00050078;
 }
 
 static void arm11mpcore_initfn(Object *obj)
@@ -195,6 +201,7 @@ static void cortex_a8_initfn(Object *obj)
     cpu->mvfr0 = 0x11110222;
     cpu->mvfr1 = 0x00011100;
     cpu->ctr = 0x82048004;
+    cpu->reset_sctlr = 0x00c50078;
 }
 
 static void cortex_a9_initfn(Object *obj)
@@ -215,6 +222,7 @@ static void cortex_a9_initfn(Object *obj)
     cpu->mvfr0 = 0x11110222;
     cpu->mvfr1 = 0x01111111;
     cpu->ctr = 0x80038003;
+    cpu->reset_sctlr = 0x00c50078;
 }
 
 static void cortex_a15_initfn(Object *obj)
@@ -233,6 +241,7 @@ static void cortex_a15_initfn(Object *obj)
     cpu->mvfr0 = 0x10110222;
     cpu->mvfr1 = 0x11111111;
     cpu->ctr = 0x8444c004;
+    cpu->reset_sctlr = 0x00c50078;
 }
 
 static void ti925t_initfn(Object *obj)
@@ -242,6 +251,7 @@ static void ti925t_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_OMAPCP);
     cpu->midr = ARM_CPUID_TI925T;
     cpu->ctr = 0x5109149;
+    cpu->reset_sctlr = 0x00000070;
 }
 
 static void sa1100_initfn(Object *obj)
@@ -249,6 +259,7 @@ static void sa1100_initfn(Object *obj)
     ARMCPU *cpu = ARM_CPU(obj);
     set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
     cpu->midr = ARM_CPUID_SA1100;
+    cpu->reset_sctlr = 0x00000070;
 }
 
 static void sa1110_initfn(Object *obj)
@@ -256,6 +267,7 @@ static void sa1110_initfn(Object *obj)
     ARMCPU *cpu = ARM_CPU(obj);
     set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
     cpu->midr = ARM_CPUID_SA1110;
+    cpu->reset_sctlr = 0x00000070;
 }
 
 static void pxa250_initfn(Object *obj)
@@ -265,6 +277,7 @@ static void pxa250_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA250;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa255_initfn(Object *obj)
@@ -274,6 +287,7 @@ static void pxa255_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA255;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa260_initfn(Object *obj)
@@ -283,6 +297,7 @@ static void pxa260_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA260;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa261_initfn(Object *obj)
@@ -292,6 +307,7 @@ static void pxa261_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA261;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa262_initfn(Object *obj)
@@ -301,6 +317,7 @@ static void pxa262_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA262;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa270a0_initfn(Object *obj)
@@ -311,6 +328,7 @@ static void pxa270a0_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_A0;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa270a1_initfn(Object *obj)
@@ -321,6 +339,7 @@ static void pxa270a1_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_A1;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa270b0_initfn(Object *obj)
@@ -331,6 +350,7 @@ static void pxa270b0_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_B0;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa270b1_initfn(Object *obj)
@@ -341,6 +361,7 @@ static void pxa270b1_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_B1;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa270c0_initfn(Object *obj)
@@ -351,6 +372,7 @@ static void pxa270c0_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_C0;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void pxa270c5_initfn(Object *obj)
@@ -361,6 +383,7 @@ static void pxa270c5_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_C5;
     cpu->ctr = 0xd172172;
+    cpu->reset_sctlr = 0x00000078;
 }
 
 static void arm_any_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index a23df14..eab25ca 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -50,13 +50,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     switch (id) {
     case ARM_CPUID_ARM926:
-        env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
-        env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
-        env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM1136:
         /* This is the 1136 r1, which is a v6K core */
@@ -71,12 +68,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
          */
         memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM1176:
         memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM11MPCORE:
         memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -89,7 +84,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
         env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
         env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
-        env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA9:
         memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -97,7 +91,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
         env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
         env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
-        env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA15:
         memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -106,7 +99,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
         env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
         env->cp15.c0_ccsid[2] = 0x711fe07a; /* 4096K L2 unified cache */
-        env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXM3:
         break;
@@ -114,7 +106,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
-        env->cp15.c1_sys = 0x00000070;
         env->cp15.c15_i_max = 0x000;
         env->cp15.c15_i_min = 0xff0;
         break;
@@ -124,7 +115,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
         /* JTAG_ID is ((id << 28) | 0x09265013) */
-        env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_PXA270_A0:
     case ARM_CPUID_PXA270_A1:
@@ -134,11 +124,9 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_C5:
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
-        env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_SA1100:
     case ARM_CPUID_SA1110:
-        env->cp15.c1_sys = 0x00000070;
         break;
     default:
         cpu_abort(env, "Bad CPU ID: %x\n", id);
@@ -173,6 +161,7 @@ void cpu_state_reset(CPUARMState *env)
     env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
     env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
     env->cp15.c0_cachetype = cpu->ctr;
+    env->cp15.c1_sys = cpu->reset_sctlr;
 
 #if defined (CONFIG_USER_ONLY)
     env->uncached_cpsr = ARM_CPU_MODE_USR;
commit 64e1671fd46669f097763f71b9a8cbcc0bf61cce
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:33 2012 +0000

    target-arm: Move CTR setup to per cpu init fns
    
    Move CTR (cache type register) value to an ARMCPU field
    set up by per-cpu init fns.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index c51eb84..cb9198a 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -73,6 +73,7 @@ typedef struct ARMCPU {
     uint32_t reset_fpsid;
     uint32_t mvfr0;
     uint32_t mvfr1;
+    uint32_t ctr;
 } ARMCPU;
 
 static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 80ca7aa..4f19d5c 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -101,6 +101,7 @@ static void arm926_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM926;
     cpu->reset_fpsid = 0x41011090;
+    cpu->ctr = 0x1dd20d2;
 }
 
 static void arm946_initfn(Object *obj)
@@ -109,6 +110,7 @@ static void arm946_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V5);
     set_feature(&cpu->env, ARM_FEATURE_MPU);
     cpu->midr = ARM_CPUID_ARM946;
+    cpu->ctr = 0x0f004006;
 }
 
 static void arm1026_initfn(Object *obj)
@@ -119,6 +121,7 @@ static void arm1026_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_AUXCR);
     cpu->midr = ARM_CPUID_ARM1026;
     cpu->reset_fpsid = 0x410110a0;
+    cpu->ctr = 0x1dd20d2;
 }
 
 static void arm1136_r2_initfn(Object *obj)
@@ -130,6 +133,7 @@ static void arm1136_r2_initfn(Object *obj)
     cpu->reset_fpsid = 0x410120b4;
     cpu->mvfr0 = 0x11111111;
     cpu->mvfr1 = 0x00000000;
+    cpu->ctr = 0x1dd20d2;
 }
 
 static void arm1136_initfn(Object *obj)
@@ -142,6 +146,7 @@ static void arm1136_initfn(Object *obj)
     cpu->reset_fpsid = 0x410120b4;
     cpu->mvfr0 = 0x11111111;
     cpu->mvfr1 = 0x00000000;
+    cpu->ctr = 0x1dd20d2;
 }
 
 static void arm1176_initfn(Object *obj)
@@ -154,6 +159,7 @@ static void arm1176_initfn(Object *obj)
     cpu->reset_fpsid = 0x410120b5;
     cpu->mvfr0 = 0x11111111;
     cpu->mvfr1 = 0x00000000;
+    cpu->ctr = 0x1dd20d2;
 }
 
 static void arm11mpcore_initfn(Object *obj)
@@ -166,6 +172,7 @@ static void arm11mpcore_initfn(Object *obj)
     cpu->reset_fpsid = 0x410120b4;
     cpu->mvfr0 = 0x11111111;
     cpu->mvfr1 = 0x00000000;
+    cpu->ctr = 0x1dd20d2;
 }
 
 static void cortex_m3_initfn(Object *obj)
@@ -187,6 +194,7 @@ static void cortex_a8_initfn(Object *obj)
     cpu->reset_fpsid = 0x410330c0;
     cpu->mvfr0 = 0x11110222;
     cpu->mvfr1 = 0x00011100;
+    cpu->ctr = 0x82048004;
 }
 
 static void cortex_a9_initfn(Object *obj)
@@ -206,6 +214,7 @@ static void cortex_a9_initfn(Object *obj)
     cpu->reset_fpsid = 0x41033090;
     cpu->mvfr0 = 0x11110222;
     cpu->mvfr1 = 0x01111111;
+    cpu->ctr = 0x80038003;
 }
 
 static void cortex_a15_initfn(Object *obj)
@@ -223,6 +232,7 @@ static void cortex_a15_initfn(Object *obj)
     cpu->reset_fpsid = 0x410430f0;
     cpu->mvfr0 = 0x10110222;
     cpu->mvfr1 = 0x11111111;
+    cpu->ctr = 0x8444c004;
 }
 
 static void ti925t_initfn(Object *obj)
@@ -231,6 +241,7 @@ static void ti925t_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V4T);
     set_feature(&cpu->env, ARM_FEATURE_OMAPCP);
     cpu->midr = ARM_CPUID_TI925T;
+    cpu->ctr = 0x5109149;
 }
 
 static void sa1100_initfn(Object *obj)
@@ -253,6 +264,7 @@ static void pxa250_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V5);
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA250;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa255_initfn(Object *obj)
@@ -261,6 +273,7 @@ static void pxa255_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V5);
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA255;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa260_initfn(Object *obj)
@@ -269,6 +282,7 @@ static void pxa260_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V5);
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA260;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa261_initfn(Object *obj)
@@ -277,6 +291,7 @@ static void pxa261_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V5);
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA261;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa262_initfn(Object *obj)
@@ -285,6 +300,7 @@ static void pxa262_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V5);
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA262;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa270a0_initfn(Object *obj)
@@ -294,6 +310,7 @@ static void pxa270a0_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_A0;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa270a1_initfn(Object *obj)
@@ -303,6 +320,7 @@ static void pxa270a1_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_A1;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa270b0_initfn(Object *obj)
@@ -312,6 +330,7 @@ static void pxa270b0_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_B0;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa270b1_initfn(Object *obj)
@@ -321,6 +340,7 @@ static void pxa270b1_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_B1;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa270c0_initfn(Object *obj)
@@ -330,6 +350,7 @@ static void pxa270c0_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_C0;
+    cpu->ctr = 0xd172172;
 }
 
 static void pxa270c5_initfn(Object *obj)
@@ -339,6 +360,7 @@ static void pxa270c5_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_C5;
+    cpu->ctr = 0xd172172;
 }
 
 static void arm_any_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 777bb03..a23df14 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -50,15 +50,12 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     switch (id) {
     case ARM_CPUID_ARM926:
-        env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
-        env->cp15.c0_cachetype = 0x0f004006;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
-        env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM1136:
@@ -74,24 +71,20 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
          */
         memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM1176:
         memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM11MPCORE:
         memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
         memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c0_cachetype = 0x82048004;
         env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
         env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
         env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
@@ -101,7 +94,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_CORTEXA9:
         memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c0_cachetype = 0x80038003;
         env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
         env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
         env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
@@ -110,7 +102,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_CORTEXA15:
         memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c0_cachetype = 0x8444c004;
         env->cp15.c0_clid = 0x0a200023;
         env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
         env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
@@ -123,7 +114,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
-        env->cp15.c0_cachetype = 0x5109149;
         env->cp15.c1_sys = 0x00000070;
         env->cp15.c15_i_max = 0x000;
         env->cp15.c15_i_min = 0xff0;
@@ -134,7 +124,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
         /* JTAG_ID is ((id << 28) | 0x09265013) */
-        env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_PXA270_A0:
@@ -145,7 +134,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_C5:
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
-        env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_SA1100:
@@ -184,6 +172,7 @@ void cpu_state_reset(CPUARMState *env)
     env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
     env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
     env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
+    env->cp15.c0_cachetype = cpu->ctr;
 
 #if defined (CONFIG_USER_ONLY)
     env->uncached_cpsr = ARM_CPU_MODE_USR;
commit bd35c3553bfe6acb47034b1bfb2cf093684f406d
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:32 2012 +0000

    target-arm: Move MVFR* setup to per cpu init fns
    
    Move the MVFR* VFP feature register values to ARMCPU,
    so they are set up by the implementation-specific instance
    init functions rather than in cpu_reset_model_id().
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 7cc4cd5..c51eb84 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -71,6 +71,8 @@ typedef struct ARMCPU {
      */
     uint32_t midr;
     uint32_t reset_fpsid;
+    uint32_t mvfr0;
+    uint32_t mvfr1;
 } ARMCPU;
 
 static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 5fb7803..80ca7aa 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -128,6 +128,8 @@ static void arm1136_r2_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM1136_R2;
     cpu->reset_fpsid = 0x410120b4;
+    cpu->mvfr0 = 0x11111111;
+    cpu->mvfr1 = 0x00000000;
 }
 
 static void arm1136_initfn(Object *obj)
@@ -138,6 +140,8 @@ static void arm1136_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM1136;
     cpu->reset_fpsid = 0x410120b4;
+    cpu->mvfr0 = 0x11111111;
+    cpu->mvfr1 = 0x00000000;
 }
 
 static void arm1176_initfn(Object *obj)
@@ -148,6 +152,8 @@ static void arm1176_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_VAPA);
     cpu->midr = ARM_CPUID_ARM1176;
     cpu->reset_fpsid = 0x410120b5;
+    cpu->mvfr0 = 0x11111111;
+    cpu->mvfr1 = 0x00000000;
 }
 
 static void arm11mpcore_initfn(Object *obj)
@@ -158,6 +164,8 @@ static void arm11mpcore_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_VAPA);
     cpu->midr = ARM_CPUID_ARM11MPCORE;
     cpu->reset_fpsid = 0x410120b4;
+    cpu->mvfr0 = 0x11111111;
+    cpu->mvfr1 = 0x00000000;
 }
 
 static void cortex_m3_initfn(Object *obj)
@@ -177,6 +185,8 @@ static void cortex_a8_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
     cpu->midr = ARM_CPUID_CORTEXA8;
     cpu->reset_fpsid = 0x410330c0;
+    cpu->mvfr0 = 0x11110222;
+    cpu->mvfr1 = 0x00011100;
 }
 
 static void cortex_a9_initfn(Object *obj)
@@ -194,6 +204,8 @@ static void cortex_a9_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V7MP);
     cpu->midr = ARM_CPUID_CORTEXA9;
     cpu->reset_fpsid = 0x41033090;
+    cpu->mvfr0 = 0x11110222;
+    cpu->mvfr1 = 0x01111111;
 }
 
 static void cortex_a15_initfn(Object *obj)
@@ -209,6 +221,8 @@ static void cortex_a15_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
     cpu->midr = ARM_CPUID_CORTEXA15;
     cpu->reset_fpsid = 0x410430f0;
+    cpu->mvfr0 = 0x10110222;
+    cpu->mvfr1 = 0x11111111;
 }
 
 static void ti925t_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3247dd3..777bb03 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -72,31 +72,23 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
          * for 1136_r2 (in particular r0p2 does not actually implement most
          * of the ID registers).
          */
-        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
-        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
         memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM1176:
-        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
-        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
         memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM11MPCORE:
-        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
-        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
         memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
-        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
-        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
         memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_cachetype = 0x82048004;
@@ -107,8 +99,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA9:
-        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
-        env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
         memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_cachetype = 0x80038003;
@@ -118,8 +108,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA15:
-        env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
-        env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
         memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_cachetype = 0x8444c004;
@@ -194,6 +182,8 @@ void cpu_state_reset(CPUARMState *env)
     env->cp15.c15_config_base_address = tmp;
     env->cp15.c0_cpuid = cpu->midr;
     env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
+    env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
+    env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
 
 #if defined (CONFIG_USER_ONLY)
     env->uncached_cpsr = ARM_CPU_MODE_USR;
commit 325b3ceff69c987e90acf9c8ef6f55e646b39767
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:32 2012 +0000

    target-arm: Move FPSID config to cpu init fns
    
    Move the reset FPSID to the ARMCPU struct, and set it in the
    per-implementation instance init function. At reset we then
    just copy the reset value into the CPUARMState field.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 7e2d4c9..7cc4cd5 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -70,6 +70,7 @@ typedef struct ARMCPU {
      * prefix means a constant register.
      */
     uint32_t midr;
+    uint32_t reset_fpsid;
 } ARMCPU;
 
 static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 46fbc2d..5fb7803 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -100,6 +100,7 @@ static void arm926_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V5);
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM926;
+    cpu->reset_fpsid = 0x41011090;
 }
 
 static void arm946_initfn(Object *obj)
@@ -117,6 +118,7 @@ static void arm1026_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     set_feature(&cpu->env, ARM_FEATURE_AUXCR);
     cpu->midr = ARM_CPUID_ARM1026;
+    cpu->reset_fpsid = 0x410110a0;
 }
 
 static void arm1136_r2_initfn(Object *obj)
@@ -125,6 +127,7 @@ static void arm1136_r2_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V6);
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM1136_R2;
+    cpu->reset_fpsid = 0x410120b4;
 }
 
 static void arm1136_initfn(Object *obj)
@@ -134,6 +137,7 @@ static void arm1136_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V6);
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM1136;
+    cpu->reset_fpsid = 0x410120b4;
 }
 
 static void arm1176_initfn(Object *obj)
@@ -143,6 +147,7 @@ static void arm1176_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     set_feature(&cpu->env, ARM_FEATURE_VAPA);
     cpu->midr = ARM_CPUID_ARM1176;
+    cpu->reset_fpsid = 0x410120b5;
 }
 
 static void arm11mpcore_initfn(Object *obj)
@@ -152,6 +157,7 @@ static void arm11mpcore_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_VFP);
     set_feature(&cpu->env, ARM_FEATURE_VAPA);
     cpu->midr = ARM_CPUID_ARM11MPCORE;
+    cpu->reset_fpsid = 0x410120b4;
 }
 
 static void cortex_m3_initfn(Object *obj)
@@ -170,6 +176,7 @@ static void cortex_a8_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_NEON);
     set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
     cpu->midr = ARM_CPUID_CORTEXA8;
+    cpu->reset_fpsid = 0x410330c0;
 }
 
 static void cortex_a9_initfn(Object *obj)
@@ -186,6 +193,7 @@ static void cortex_a9_initfn(Object *obj)
      */
     set_feature(&cpu->env, ARM_FEATURE_V7MP);
     cpu->midr = ARM_CPUID_CORTEXA9;
+    cpu->reset_fpsid = 0x41033090;
 }
 
 static void cortex_a15_initfn(Object *obj)
@@ -200,6 +208,7 @@ static void cortex_a15_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V7MP);
     set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
     cpu->midr = ARM_CPUID_CORTEXA15;
+    cpu->reset_fpsid = 0x410430f0;
 }
 
 static void ti925t_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index e495de6..3247dd3 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -50,7 +50,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     switch (id) {
     case ARM_CPUID_ARM926:
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
@@ -59,7 +58,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
@@ -74,7 +72,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
          * for 1136_r2 (in particular r0p2 does not actually implement most
          * of the ID registers).
          */
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
         memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -83,7 +80,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM1176:
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
         memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -92,7 +88,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM11MPCORE:
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
         memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -100,7 +95,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
         memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -113,7 +107,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA9:
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x41033090;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
         memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -125,7 +118,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA15:
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
         memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -201,6 +193,8 @@ void cpu_state_reset(CPUARMState *env)
         cpu_reset_model_id(env, id);
     env->cp15.c15_config_base_address = tmp;
     env->cp15.c0_cpuid = cpu->midr;
+    env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
+
 #if defined (CONFIG_USER_ONLY)
     env->uncached_cpsr = ARM_CPU_MODE_USR;
     /* For user mode we must enable access to coprocessors */
commit 581be09434f155ebe0ee7b532c20974843188958
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:31 2012 +0000

    target-arm: Move feature bit settings to CPU init fns
    
    Move the setting of the feature bits from cpu_reset_model_id()
    to each CPU's instance init function. This requires us to move
    the features field in CPUARMState so that it is not cleared
    on reset.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index a4bcb31..7e2d4c9 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -79,5 +79,6 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
 
 #define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e))
 
+void arm_cpu_realize(ARMCPU *cpu);
 
 #endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 6d4f8fe..46fbc2d 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -34,6 +34,11 @@ static void arm_cpu_reset(CPUState *s)
     cpu_state_reset(&cpu->env);
 }
 
+static inline void set_feature(CPUARMState *env, int feature)
+{
+    env->features |= 1u << feature;
+}
+
 static void arm_cpu_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
@@ -41,161 +46,288 @@ static void arm_cpu_initfn(Object *obj)
     cpu_exec_init(&cpu->env);
 }
 
+void arm_cpu_realize(ARMCPU *cpu)
+{
+    /* This function is called by cpu_arm_init() because it
+     * needs to do common actions based on feature bits, etc
+     * that have been set by the subclass init functions.
+     * When we have QOM realize support it should become
+     * a true realize function instead.
+     */
+    CPUARMState *env = &cpu->env;
+    /* Some features automatically imply others: */
+    if (arm_feature(env, ARM_FEATURE_V7)) {
+        set_feature(env, ARM_FEATURE_VAPA);
+        set_feature(env, ARM_FEATURE_THUMB2);
+        if (!arm_feature(env, ARM_FEATURE_M)) {
+            set_feature(env, ARM_FEATURE_V6K);
+        } else {
+            set_feature(env, ARM_FEATURE_V6);
+        }
+    }
+    if (arm_feature(env, ARM_FEATURE_V6K)) {
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_MVFR);
+    }
+    if (arm_feature(env, ARM_FEATURE_V6)) {
+        set_feature(env, ARM_FEATURE_V5);
+        if (!arm_feature(env, ARM_FEATURE_M)) {
+            set_feature(env, ARM_FEATURE_AUXCR);
+        }
+    }
+    if (arm_feature(env, ARM_FEATURE_V5)) {
+        set_feature(env, ARM_FEATURE_V4T);
+    }
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        set_feature(env, ARM_FEATURE_THUMB_DIV);
+    }
+    if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
+        set_feature(env, ARM_FEATURE_THUMB_DIV);
+    }
+    if (arm_feature(env, ARM_FEATURE_VFP4)) {
+        set_feature(env, ARM_FEATURE_VFP3);
+    }
+    if (arm_feature(env, ARM_FEATURE_VFP3)) {
+        set_feature(env, ARM_FEATURE_VFP);
+    }
+}
+
 /* CPU models */
 
 static void arm926_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM926;
 }
 
 static void arm946_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_MPU);
     cpu->midr = ARM_CPUID_ARM946;
 }
 
 static void arm1026_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_VFP);
+    set_feature(&cpu->env, ARM_FEATURE_AUXCR);
     cpu->midr = ARM_CPUID_ARM1026;
 }
 
 static void arm1136_r2_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V6);
+    set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM1136_R2;
 }
 
 static void arm1136_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V6K);
+    set_feature(&cpu->env, ARM_FEATURE_V6);
+    set_feature(&cpu->env, ARM_FEATURE_VFP);
     cpu->midr = ARM_CPUID_ARM1136;
 }
 
 static void arm1176_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V6K);
+    set_feature(&cpu->env, ARM_FEATURE_VFP);
+    set_feature(&cpu->env, ARM_FEATURE_VAPA);
     cpu->midr = ARM_CPUID_ARM1176;
 }
 
 static void arm11mpcore_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V6K);
+    set_feature(&cpu->env, ARM_FEATURE_VFP);
+    set_feature(&cpu->env, ARM_FEATURE_VAPA);
     cpu->midr = ARM_CPUID_ARM11MPCORE;
 }
 
 static void cortex_m3_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V7);
+    set_feature(&cpu->env, ARM_FEATURE_M);
     cpu->midr = ARM_CPUID_CORTEXM3;
 }
 
 static void cortex_a8_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V7);
+    set_feature(&cpu->env, ARM_FEATURE_VFP3);
+    set_feature(&cpu->env, ARM_FEATURE_NEON);
+    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
     cpu->midr = ARM_CPUID_CORTEXA8;
 }
 
 static void cortex_a9_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V7);
+    set_feature(&cpu->env, ARM_FEATURE_VFP3);
+    set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+    set_feature(&cpu->env, ARM_FEATURE_NEON);
+    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+    /* Note that A9 supports the MP extensions even for
+     * A9UP and single-core A9MP (which are both different
+     * and valid configurations; we don't model A9UP).
+     */
+    set_feature(&cpu->env, ARM_FEATURE_V7MP);
     cpu->midr = ARM_CPUID_CORTEXA9;
 }
 
 static void cortex_a15_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V7);
+    set_feature(&cpu->env, ARM_FEATURE_VFP4);
+    set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+    set_feature(&cpu->env, ARM_FEATURE_NEON);
+    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+    set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
+    set_feature(&cpu->env, ARM_FEATURE_V7MP);
+    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
     cpu->midr = ARM_CPUID_CORTEXA15;
 }
 
 static void ti925t_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V4T);
+    set_feature(&cpu->env, ARM_FEATURE_OMAPCP);
     cpu->midr = ARM_CPUID_TI925T;
 }
 
 static void sa1100_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
     cpu->midr = ARM_CPUID_SA1100;
 }
 
 static void sa1110_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
     cpu->midr = ARM_CPUID_SA1110;
 }
 
 static void pxa250_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA250;
 }
 
 static void pxa255_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA255;
 }
 
 static void pxa260_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA260;
 }
 
 static void pxa261_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA261;
 }
 
 static void pxa262_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
     cpu->midr = ARM_CPUID_PXA262;
 }
 
 static void pxa270a0_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_A0;
 }
 
 static void pxa270a1_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_A1;
 }
 
 static void pxa270b0_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_B0;
 }
 
 static void pxa270b1_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_B1;
 }
 
 static void pxa270c0_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_C0;
 }
 
 static void pxa270c5_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V5);
+    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
     cpu->midr = ARM_CPUID_PXA270_C5;
 }
 
 static void arm_any_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    set_feature(&cpu->env, ARM_FEATURE_V7);
+    set_feature(&cpu->env, ARM_FEATURE_VFP4);
+    set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+    set_feature(&cpu->env, ARM_FEATURE_NEON);
+    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+    set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
+    set_feature(&cpu->env, ARM_FEATURE_V7MP);
     cpu->midr = ARM_CPUID_ANY;
 }
 
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index d2f5c76..01e0e36 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -170,9 +170,6 @@ typedef struct CPUARMState {
     uint32_t teecr;
     uint32_t teehbr;
 
-    /* Internal CPU feature flags.  */
-    uint32_t features;
-
     /* VFP coprocessor state.  */
     struct {
         float64 regs[32];
@@ -228,6 +225,9 @@ typedef struct CPUARMState {
 
     /* These fields after the common ones so they are preserved on reset.  */
 
+    /* Internal CPU feature flags.  */
+    uint32_t features;
+
     /* Coprocessor IO used by peripherals */
     struct {
         ARMReadCPFunc *cp_read;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index afcd68c..e495de6 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -46,46 +46,30 @@ static uint32_t arm1176_cp15_c0_c1[8] =
 static uint32_t arm1176_cp15_c0_c2[8] =
 { 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
 
-static inline void set_feature(CPUARMState *env, int feature)
-{
-    env->features |= 1u << feature;
-}
-
 static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     switch (id) {
     case ARM_CPUID_ARM926:
-        set_feature(env, ARM_FEATURE_V5);
-        set_feature(env, ARM_FEATURE_VFP);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
-        set_feature(env, ARM_FEATURE_V5);
-        set_feature(env, ARM_FEATURE_MPU);
         env->cp15.c0_cachetype = 0x0f004006;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
-        set_feature(env, ARM_FEATURE_V5);
-        set_feature(env, ARM_FEATURE_VFP);
-        set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM1136:
         /* This is the 1136 r1, which is a v6K core */
-        set_feature(env, ARM_FEATURE_V6K);
-        /* Fall through */
     case ARM_CPUID_ARM1136_R2:
         /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
          * older core than plain "arm1136". In particular this does not
          * have the v6K features.
          */
-        set_feature(env, ARM_FEATURE_V6);
-        set_feature(env, ARM_FEATURE_VFP);
         /* These ID register values are correct for 1136 but may be wrong
          * for 1136_r2 (in particular r0p2 does not actually implement most
          * of the ID registers).
@@ -99,9 +83,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM1176:
-        set_feature(env, ARM_FEATURE_V6K);
-        set_feature(env, ARM_FEATURE_VFP);
-        set_feature(env, ARM_FEATURE_VAPA);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -111,9 +92,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM11MPCORE:
-        set_feature(env, ARM_FEATURE_V6K);
-        set_feature(env, ARM_FEATURE_VFP);
-        set_feature(env, ARM_FEATURE_VAPA);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -122,10 +100,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_VFP3);
-        set_feature(env, ARM_FEATURE_NEON);
-        set_feature(env, ARM_FEATURE_THUMB2EE);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
@@ -139,16 +113,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA9:
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_VFP3);
-        set_feature(env, ARM_FEATURE_VFP_FP16);
-        set_feature(env, ARM_FEATURE_NEON);
-        set_feature(env, ARM_FEATURE_THUMB2EE);
-        /* Note that A9 supports the MP extensions even for
-         * A9UP and single-core A9MP (which are both different
-         * and valid configurations; we don't model A9UP).
-         */
-        set_feature(env, ARM_FEATURE_V7MP);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41033090;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
@@ -161,14 +125,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA15:
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_VFP4);
-        set_feature(env, ARM_FEATURE_VFP_FP16);
-        set_feature(env, ARM_FEATURE_NEON);
-        set_feature(env, ARM_FEATURE_THUMB2EE);
-        set_feature(env, ARM_FEATURE_ARM_DIV);
-        set_feature(env, ARM_FEATURE_V7MP);
-        set_feature(env, ARM_FEATURE_GENERIC_TIMER);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
@@ -182,22 +138,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXM3:
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_M);
         break;
     case ARM_CPUID_ANY: /* For userspace emulation.  */
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_VFP4);
-        set_feature(env, ARM_FEATURE_VFP_FP16);
-        set_feature(env, ARM_FEATURE_NEON);
-        set_feature(env, ARM_FEATURE_THUMB2EE);
-        set_feature(env, ARM_FEATURE_ARM_DIV);
-        set_feature(env, ARM_FEATURE_V7MP);
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
-        set_feature(env, ARM_FEATURE_V4T);
-        set_feature(env, ARM_FEATURE_OMAPCP);
         env->cp15.c0_cachetype = 0x5109149;
         env->cp15.c1_sys = 0x00000070;
         env->cp15.c15_i_max = 0x000;
@@ -208,8 +153,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA260:
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
-        set_feature(env, ARM_FEATURE_V5);
-        set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
@@ -220,17 +163,13 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_B1:
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
-        set_feature(env, ARM_FEATURE_V5);
-        set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
-        set_feature(env, ARM_FEATURE_IWMMXT);
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
         env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_SA1100:
     case ARM_CPUID_SA1110:
-        set_feature(env, ARM_FEATURE_STRONGARM);
         env->cp15.c1_sys = 0x00000070;
         break;
     default:
@@ -238,41 +177,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     }
 
-    /* Some features automatically imply others: */
-    if (arm_feature(env, ARM_FEATURE_V7)) {
-        set_feature(env, ARM_FEATURE_VAPA);
-        set_feature(env, ARM_FEATURE_THUMB2);
-        if (!arm_feature(env, ARM_FEATURE_M)) {
-            set_feature(env, ARM_FEATURE_V6K);
-        } else {
-            set_feature(env, ARM_FEATURE_V6);
-        }
-    }
-    if (arm_feature(env, ARM_FEATURE_V6K)) {
-        set_feature(env, ARM_FEATURE_V6);
-        set_feature(env, ARM_FEATURE_MVFR);
-    }
-    if (arm_feature(env, ARM_FEATURE_V6)) {
-        set_feature(env, ARM_FEATURE_V5);
-        if (!arm_feature(env, ARM_FEATURE_M)) {
-            set_feature(env, ARM_FEATURE_AUXCR);
-        }
-    }
-    if (arm_feature(env, ARM_FEATURE_V5)) {
-        set_feature(env, ARM_FEATURE_V4T);
-    }
-    if (arm_feature(env, ARM_FEATURE_M)) {
-        set_feature(env, ARM_FEATURE_THUMB_DIV);
-    }
-    if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
-        set_feature(env, ARM_FEATURE_THUMB_DIV);
-    }
-    if (arm_feature(env, ARM_FEATURE_VFP4)) {
-        set_feature(env, ARM_FEATURE_VFP3);
-    }
-    if (arm_feature(env, ARM_FEATURE_VFP3)) {
-        set_feature(env, ARM_FEATURE_VFP);
-    }
 }
 
 /* TODO Move contents into arm_cpu_reset() in cpu.c,
@@ -413,6 +317,7 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
     cpu = ARM_CPU(object_new(cpu_model));
     env = &cpu->env;
     env->cpu_model_str = cpu_model;
+    arm_cpu_realize(cpu);
 
     if (tcg_enabled() && !inited) {
         inited = 1;
commit 777dc78411865f2721f8728c71edb0b215da57fc
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 17:58:31 2012 +0000

    target-arm: Add QOM subclasses for each ARM cpu implementation
    
    Register subclasses for each ARM CPU implementation.
    
    Let arm_cpu_list() enumerate CPU subclasses in alphabetical order,
    except for special value "any".
    
    Replace cpu_arm_find_by_name()'s string -> CPUID lookup by storing the
    CPUID (aka MIDR, Main ID Register) value in the class.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 42d2a6b..a4bcb31 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -58,6 +58,18 @@ typedef struct ARMCPU {
     /*< public >*/
 
     CPUARMState env;
+
+    /* The instance init functions for implementation-specific subclasses
+     * set these fields to specify the implementation-dependent values of
+     * various constant registers and reset values of non-constant
+     * registers.
+     * Some of these might become QOM properties eventually.
+     * Field names match the official register names as defined in the
+     * ARMv7AR ARM Architecture Reference Manual. A reset_ prefix
+     * is used for reset values of non-constant registers; no reset_
+     * prefix means a constant register.
+     */
+    uint32_t midr;
 } ARMCPU;
 
 static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index c3ed45b..6d4f8fe 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -34,6 +34,211 @@ static void arm_cpu_reset(CPUState *s)
     cpu_state_reset(&cpu->env);
 }
 
+static void arm_cpu_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+
+    cpu_exec_init(&cpu->env);
+}
+
+/* CPU models */
+
+static void arm926_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_ARM926;
+}
+
+static void arm946_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_ARM946;
+}
+
+static void arm1026_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_ARM1026;
+}
+
+static void arm1136_r2_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_ARM1136_R2;
+}
+
+static void arm1136_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_ARM1136;
+}
+
+static void arm1176_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_ARM1176;
+}
+
+static void arm11mpcore_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_ARM11MPCORE;
+}
+
+static void cortex_m3_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_CORTEXM3;
+}
+
+static void cortex_a8_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_CORTEXA8;
+}
+
+static void cortex_a9_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_CORTEXA9;
+}
+
+static void cortex_a15_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_CORTEXA15;
+}
+
+static void ti925t_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_TI925T;
+}
+
+static void sa1100_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_SA1100;
+}
+
+static void sa1110_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_SA1110;
+}
+
+static void pxa250_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA250;
+}
+
+static void pxa255_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA255;
+}
+
+static void pxa260_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA260;
+}
+
+static void pxa261_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA261;
+}
+
+static void pxa262_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA262;
+}
+
+static void pxa270a0_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA270_A0;
+}
+
+static void pxa270a1_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA270_A1;
+}
+
+static void pxa270b0_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA270_B0;
+}
+
+static void pxa270b1_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA270_B1;
+}
+
+static void pxa270c0_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA270_C0;
+}
+
+static void pxa270c5_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_PXA270_C5;
+}
+
+static void arm_any_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    cpu->midr = ARM_CPUID_ANY;
+}
+
+typedef struct ARMCPUInfo {
+    const char *name;
+    void (*initfn)(Object *obj);
+} ARMCPUInfo;
+
+static const ARMCPUInfo arm_cpus[] = {
+    { .name = "arm926",      .initfn = arm926_initfn },
+    { .name = "arm946",      .initfn = arm946_initfn },
+    { .name = "arm1026",     .initfn = arm1026_initfn },
+    /* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an
+     * older core than plain "arm1136". In particular this does not
+     * have the v6K features.
+     */
+    { .name = "arm1136-r2",  .initfn = arm1136_r2_initfn },
+    { .name = "arm1136",     .initfn = arm1136_initfn },
+    { .name = "arm1176",     .initfn = arm1176_initfn },
+    { .name = "arm11mpcore", .initfn = arm11mpcore_initfn },
+    { .name = "cortex-m3",   .initfn = cortex_m3_initfn },
+    { .name = "cortex-a8",   .initfn = cortex_a8_initfn },
+    { .name = "cortex-a9",   .initfn = cortex_a9_initfn },
+    { .name = "cortex-a15",  .initfn = cortex_a15_initfn },
+    { .name = "ti925t",      .initfn = ti925t_initfn },
+    { .name = "sa1100",      .initfn = sa1100_initfn },
+    { .name = "sa1110",      .initfn = sa1110_initfn },
+    { .name = "pxa250",      .initfn = pxa250_initfn },
+    { .name = "pxa255",      .initfn = pxa255_initfn },
+    { .name = "pxa260",      .initfn = pxa260_initfn },
+    { .name = "pxa261",      .initfn = pxa261_initfn },
+    { .name = "pxa262",      .initfn = pxa262_initfn },
+    /* "pxa270" is an alias for "pxa270-a0" */
+    { .name = "pxa270",      .initfn = pxa270a0_initfn },
+    { .name = "pxa270-a0",   .initfn = pxa270a0_initfn },
+    { .name = "pxa270-a1",   .initfn = pxa270a1_initfn },
+    { .name = "pxa270-b0",   .initfn = pxa270b0_initfn },
+    { .name = "pxa270-b1",   .initfn = pxa270b1_initfn },
+    { .name = "pxa270-c0",   .initfn = pxa270c0_initfn },
+    { .name = "pxa270-c5",   .initfn = pxa270c5_initfn },
+    { .name = "any",         .initfn = arm_any_initfn },
+};
+
 static void arm_cpu_class_init(ObjectClass *oc, void *data)
 {
     ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -43,18 +248,37 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
     cc->reset = arm_cpu_reset;
 }
 
+static void cpu_register(const ARMCPUInfo *info)
+{
+    TypeInfo type_info = {
+        .name = info->name,
+        .parent = TYPE_ARM_CPU,
+        .instance_size = sizeof(ARMCPU),
+        .instance_init = info->initfn,
+        .class_size = sizeof(ARMCPUClass),
+    };
+
+    type_register_static(&type_info);
+}
+
 static const TypeInfo arm_cpu_type_info = {
     .name = TYPE_ARM_CPU,
     .parent = TYPE_CPU,
     .instance_size = sizeof(ARMCPU),
-    .abstract = false,
+    .instance_init = arm_cpu_initfn,
+    .abstract = true,
     .class_size = sizeof(ARMCPUClass),
     .class_init = arm_cpu_class_init,
 };
 
 static void arm_cpu_register_types(void)
 {
+    int i;
+
     type_register_static(&arm_cpu_type_info);
+    for (i = 0; i < ARRAY_SIZE(arm_cpus); i++) {
+        cpu_register(&arm_cpus[i]);
+    }
 }
 
 type_init(arm_cpu_register_types)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 28f127b..afcd68c 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -46,8 +46,6 @@ static uint32_t arm1176_cp15_c0_c1[8] =
 static uint32_t arm1176_cp15_c0_c2[8] =
 { 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
 
-static uint32_t cpu_arm_find_by_name(const char *name);
-
 static inline void set_feature(CPUARMState *env, int feature)
 {
     env->features |= 1u << feature;
@@ -55,7 +53,6 @@ static inline void set_feature(CPUARMState *env, int feature)
 
 static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
-    env->cp15.c0_cpuid = id;
     switch (id) {
     case ARM_CPUID_ARM926:
         set_feature(env, ARM_FEATURE_V5);
@@ -201,7 +198,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_TI925T:
         set_feature(env, ARM_FEATURE_V4T);
         set_feature(env, ARM_FEATURE_OMAPCP);
-        env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring.  */
         env->cp15.c0_cachetype = 0x5109149;
         env->cp15.c1_sys = 0x00000070;
         env->cp15.c15_i_max = 0x000;
@@ -287,18 +283,20 @@ void cpu_state_reset(CPUARMState *env)
 {
     uint32_t id;
     uint32_t tmp = 0;
+    ARMCPU *cpu = arm_env_get_cpu(env);
 
     if (qemu_loglevel_mask(CPU_LOG_RESET)) {
         qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
         log_cpu_state(env, 0);
     }
 
-    id = env->cp15.c0_cpuid;
+    id = cpu->midr;
     tmp = env->cp15.c15_config_base_address;
     memset(env, 0, offsetof(CPUARMState, breakpoints));
     if (id)
         cpu_reset_model_id(env, id);
     env->cp15.c15_config_base_address = tmp;
+    env->cp15.c0_cpuid = cpu->midr;
 #if defined (CONFIG_USER_ONLY)
     env->uncached_cpsr = ARM_CPU_MODE_USR;
     /* For user mode we must enable access to coprocessors */
@@ -407,22 +405,20 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
 {
     ARMCPU *cpu;
     CPUARMState *env;
-    uint32_t id;
     static int inited = 0;
 
-    id = cpu_arm_find_by_name(cpu_model);
-    if (id == 0)
+    if (!object_class_by_name(cpu_model)) {
         return NULL;
-    cpu = ARM_CPU(object_new(TYPE_ARM_CPU));
+    }
+    cpu = ARM_CPU(object_new(cpu_model));
     env = &cpu->env;
-    cpu_exec_init(env);
+    env->cpu_model_str = cpu_model;
+
     if (tcg_enabled() && !inited) {
         inited = 1;
         arm_translate_init();
     }
 
-    env->cpu_model_str = cpu_model;
-    env->cp15.c0_cpuid = id;
     cpu_state_reset(env);
     if (arm_feature(env, ARM_FEATURE_NEON)) {
         gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
@@ -438,66 +434,51 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
     return env;
 }
 
-struct arm_cpu_t {
-    uint32_t id;
-    const char *name;
-};
-
-static const struct arm_cpu_t arm_cpu_names[] = {
-    { ARM_CPUID_ARM926, "arm926"},
-    { ARM_CPUID_ARM946, "arm946"},
-    { ARM_CPUID_ARM1026, "arm1026"},
-    { ARM_CPUID_ARM1136, "arm1136"},
-    { ARM_CPUID_ARM1136_R2, "arm1136-r2"},
-    { ARM_CPUID_ARM1176, "arm1176"},
-    { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
-    { ARM_CPUID_CORTEXM3, "cortex-m3"},
-    { ARM_CPUID_CORTEXA8, "cortex-a8"},
-    { ARM_CPUID_CORTEXA9, "cortex-a9"},
-    { ARM_CPUID_CORTEXA15, "cortex-a15" },
-    { ARM_CPUID_TI925T, "ti925t" },
-    { ARM_CPUID_PXA250, "pxa250" },
-    { ARM_CPUID_SA1100,    "sa1100" },
-    { ARM_CPUID_SA1110,    "sa1110" },
-    { ARM_CPUID_PXA255, "pxa255" },
-    { ARM_CPUID_PXA260, "pxa260" },
-    { ARM_CPUID_PXA261, "pxa261" },
-    { ARM_CPUID_PXA262, "pxa262" },
-    { ARM_CPUID_PXA270, "pxa270" },
-    { ARM_CPUID_PXA270_A0, "pxa270-a0" },
-    { ARM_CPUID_PXA270_A1, "pxa270-a1" },
-    { ARM_CPUID_PXA270_B0, "pxa270-b0" },
-    { ARM_CPUID_PXA270_B1, "pxa270-b1" },
-    { ARM_CPUID_PXA270_C0, "pxa270-c0" },
-    { ARM_CPUID_PXA270_C5, "pxa270-c5" },
-    { ARM_CPUID_ANY, "any"},
-    { 0, NULL}
-};
+typedef struct ARMCPUListState {
+    fprintf_function cpu_fprintf;
+    FILE *file;
+} ARMCPUListState;
 
-void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+/* Sort alphabetically by type name, except for "any". */
+static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b)
 {
-    int i;
+    ObjectClass *class_a = (ObjectClass *)a;
+    ObjectClass *class_b = (ObjectClass *)b;
+    const char *name_a, *name_b;
 
-    (*cpu_fprintf)(f, "Available CPUs:\n");
-    for (i = 0; arm_cpu_names[i].name; i++) {
-        (*cpu_fprintf)(f, "  %s\n", arm_cpu_names[i].name);
+    name_a = object_class_get_name(class_a);
+    name_b = object_class_get_name(class_b);
+    if (strcmp(name_a, "any") == 0) {
+        return 1;
+    } else if (strcmp(name_b, "any") == 0) {
+        return -1;
+    } else {
+        return strcmp(name_a, name_b);
     }
 }
 
-/* return 0 if not found */
-static uint32_t cpu_arm_find_by_name(const char *name)
+static void arm_cpu_list_entry(gpointer data, gpointer user_data)
 {
-    int i;
-    uint32_t id;
+    ObjectClass *oc = data;
+    ARMCPUListState *s = user_data;
 
-    id = 0;
-    for (i = 0; arm_cpu_names[i].name; i++) {
-        if (strcmp(name, arm_cpu_names[i].name) == 0) {
-            id = arm_cpu_names[i].id;
-            break;
-        }
-    }
-    return id;
+    (*s->cpu_fprintf)(s->file, "  %s\n",
+                      object_class_get_name(oc));
+}
+
+void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    ARMCPUListState s = {
+        .file = f,
+        .cpu_fprintf = cpu_fprintf,
+    };
+    GSList *list;
+
+    list = object_class_get_list(TYPE_ARM_CPU, false);
+    list = g_slist_sort(list, arm_cpu_list_compare);
+    (*cpu_fprintf)(f, "Available CPUs:\n");
+    g_slist_foreach(list, arm_cpu_list_entry, &s);
+    g_slist_free(list);
 }
 
 static int bad_mode_switch(CPUARMState *env, int mode)
commit ce854d7cc3ba71e8d2a97e1fb33e13ac3283cbd4
Author: Benoit Canet <benoit.canet at gmail.com>
Date:   Wed Nov 9 07:32:59 2011 +0000

    target-arm: remind to keep arm features in sync with linux-user/elfload.c
    
    Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c208c80..d2f5c76 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -360,6 +360,10 @@ enum arm_cpu_mode {
 #define ARM_IWMMXT_wCGR2	10
 #define ARM_IWMMXT_wCGR3	11
 
+/* If adding a feature bit which corresponds to a Linux ELF
+ * HWCAP bit, remember to update the feature-bit-to-hwcap
+ * mapping in linux-user/elfload.c:get_elf_hwcap().
+ */
 enum arm_features {
     ARM_FEATURE_VFP,
     ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
commit 75f05e4fd770d64e5ace1bf8e9bda536903da709
Merge: c3ca046... 964c695...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Apr 21 13:33:55 2012 +0000

    Merge branch 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
    
    * 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm:
      versatiblepb: add NOR flash support
      hw/arm_mptimer: Reset the qemu_timer at reset
      versatilepb: add ds1338 rtc device
      realview: break out versatile i2c controller code

commit c3ca04679e93a72635d6ef347886dbeba799b2d6
Author: Stefan Weil <sw at weilnetz.de>
Date:   Tue Apr 17 19:22:39 2012 +0200

    tci: GETPC() macro must return an uintptr_t
    
    Change the data type of tci_tb_ptr, so GETPC() returns an
    uintptr_t now (like for all other TCG targets).
    
    This completes commit 2050396801ca0c8359364d61eaadece951006057
    and fixes builds with TCI.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Reviewed-by: Eric Blake <eblake at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/exec-all.h b/exec-all.h
index 6bcc075..937d3ce 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -283,7 +283,7 @@ extern int tb_invalidated_flag;
 /* Alpha and SH4 user mode emulations and Softmmu call GETPC().
    For all others, GETPC remains undefined (which makes TCI a little faster. */
 # if defined(CONFIG_SOFTMMU) || defined(TARGET_ALPHA) || defined(TARGET_SH4)
-extern void *tci_tb_ptr;
+extern uintptr_t tci_tb_ptr;
 #  define GETPC() tci_tb_ptr
 # endif
 #elif defined(__s390__) && !defined(__s390x__)
diff --git a/tci.c b/tci.c
index c43fe7d..71de66d 100644
--- a/tci.c
+++ b/tci.c
@@ -58,7 +58,7 @@ CPUArchState *env;
 /* Targets which don't use GETPC also don't need tci_tb_ptr
    which makes them a little faster. */
 #if defined(GETPC)
-void *tci_tb_ptr;
+uintptr_t tci_tb_ptr;
 #endif
 
 static tcg_target_ulong tci_reg[TCG_TARGET_NB_REGS];
@@ -450,7 +450,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
 
     for (;;) {
 #if defined(GETPC)
-        tci_tb_ptr = tb_ptr;
+        tci_tb_ptr = (uintptr_t)tb_ptr;
 #endif
         TCGOpcode opc = tb_ptr[0];
 #if !defined(NDEBUG)
commit a896d03bb5f70ed76b3e9e1acba864115cfb5e01
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Mon Mar 12 06:24:45 2012 +0000

    gdbstub: Synchronize CPU state unconditionally in gdb_set_cpu_pc
    
    Synchronize the CPU state via cpu_sychronize_state() unconditionally
    in gdb_set_cpu_pc() rather than only in some of the target ifdef
    ladder cases.
    
    We can divide the CPUs into three categories:
     * non-KVM targets: no change of behaviour since we will use the
       kvm-stub.c no-op function.
     * i386 and s390: no change of behaviour since they were already
       calling this function
     * PPC (in KVM mode): this fixes an error: failing to synchronise
       was accidental and probably a bug.
    
    This also paves the way for other targets (specifically ARM) which
    can add KVM support in future without having to add another target
    specific change to this bit of code.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/gdbstub.c b/gdbstub.c
index 6a7e2c4..6a77a66 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1903,8 +1903,8 @@ static void gdb_breakpoint_remove_all(void)
 
 static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 {
-#if defined(TARGET_I386)
     cpu_synchronize_state(s->c_cpu);
+#if defined(TARGET_I386)
     s->c_cpu->eip = pc;
 #elif defined (TARGET_PPC)
     s->c_cpu->nip = pc;
@@ -1929,7 +1929,6 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 #elif defined (TARGET_ALPHA)
     s->c_cpu->pc = pc;
 #elif defined (TARGET_S390X)
-    cpu_synchronize_state(s->c_cpu);
     s->c_cpu->psw.addr = pc;
 #elif defined (TARGET_LM32)
     s->c_cpu->pc = pc;
commit 0eb4fc817fa14347a381d018eb29f1eef2fb43e4
Author: Juan Quintela <quintela at redhat.com>
Date:   Tue Mar 20 05:24:25 2012 +0000

    softfloat: make USE_SOFTFLOAT_STRUCT_TYPES compile
    
    This change makes it compile and return the same value than the #undef one.
    
    Signed-off-by: Juan Quintela <quintela at redhat.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index d37090a..9e1b5f9 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -2219,7 +2219,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
             }
         }
         /* Zero plus something non-zero : just return the something */
-        return c ^ (signflip << 31);
+        return make_float32(float32_val(c) ^ (signflip << 31));
     }
 
     if (aExp == 0) {
@@ -3772,7 +3772,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
             }
         }
         /* Zero plus something non-zero : just return the something */
-        return c ^ ((uint64_t)signflip << 63);
+        return make_float64(float64_val(c) ^ ((uint64_t)signflip << 63));
     }
 
     if (aExp == 0) {
commit 536a98d4d66444437e01ff2920df1a554df15efb
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Mon Apr 16 01:47:07 2012 +0400

    target-xtensa: add tests for LOOPNEZ and LOOPGTZ
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tests/tcg/xtensa/test_loop.S b/tests/tcg/xtensa/test_loop.S
index 5cead47..1c240e8 100644
--- a/tests/tcg/xtensa/test_loop.S
+++ b/tests/tcg/xtensa/test_loop.S
@@ -124,4 +124,40 @@ test lend_invalidation
     assert  eqi, a2, 7
 test_end
 
+test loopnez
+    movi    a2, 0
+    movi    a3, 5
+    loopnez a3, 1f
+    addi    a2, a2, 1
+1:
+    assert  eqi, a2, 5
+
+    movi    a2, 0
+    movi    a3, 0
+    loopnez a3, 1f
+    test_fail
+1:
+test_end
+
+test loopgtz
+    movi    a2, 0
+    movi    a3, 5
+    loopgtz a3, 1f
+    addi    a2, a2, 1
+1:
+    assert  eqi, a2, 5
+
+    movi    a2, 0
+    movi    a3, 0
+    loopgtz a3, 1f
+    test_fail
+1:
+
+    movi    a2, 0
+    movi    a3, 0x80000000
+    loopgtz a3, 1f
+    test_fail
+1:
+test_end
+
 test_suite_end
commit b18b37f7c5bc96dabdb08bcfb699b339a76104bf
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Mon Apr 16 01:47:06 2012 +0400

    target-xtensa: fix LOOPNEZ/LOOPGTZ translation
    
    Translation of LOOP instructions used to call LEND SR write handler to
    update LEND and invalidate relevant TBs. Now that LEND SR write handler
    ends TB, LOOPNEZ and LOOPGTZ generate wrong code (same as for simple
    LOOP). Fix it by calling wsr_lend helper directly.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 6900123..521c0e6 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -2278,7 +2278,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                         tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1);
                         tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc);
-                        gen_wsr_lend(dc, LEND, tmp);
+                        gen_helper_wsr_lend(tmp);
                         tcg_temp_free(tmp);
 
                         if (BRI8_R > 8) {
commit f91837a7f173e0334539024e4d8ba10c19a78bb7
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Apr 15 11:45:18 2012 +0000

    qtest: add m48t59 tests for Sparc
    
    Add simple m48t59 qtests, enable test only for Sparc32
    and Sparc64. On PPC, the device is behind PCI bus.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tests/Makefile b/tests/Makefile
index baf1d70..9988681 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -20,6 +20,8 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 # really in libqtest, not in the testcases themselves.
 check-qtest-i386-y = tests/rtc-test
 check-qtest-x86_64-y = $(check-qtest-i386-y)
+check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
+check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)
 
 GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
 
@@ -64,6 +66,7 @@ tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-
 tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
 
 tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
+tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y)
 
 # QTest rules
 
diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c
new file mode 100644
index 0000000..5179681
--- /dev/null
+++ b/tests/m48t59-test.c
@@ -0,0 +1,259 @@
+/*
+ * QTest testcase for the M48T59 and M48T08 real-time clocks
+ *
+ * Based on MC146818 RTC test:
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "libqtest.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define RTC_SECONDS             0x9
+#define RTC_MINUTES             0xa
+#define RTC_HOURS               0xb
+
+#define RTC_DAY_OF_WEEK         0xc
+#define RTC_DAY_OF_MONTH        0xd
+#define RTC_MONTH               0xe
+#define RTC_YEAR                0xf
+
+static uint32_t base;
+static uint16_t reg_base = 0x1ff0; /* 0x7f0 for m48t02 */
+static int base_year;
+static bool use_mmio;
+
+static uint8_t cmos_read_mmio(uint8_t reg)
+{
+    uint8_t data;
+
+    memread(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1);
+    return data;
+}
+
+static void cmos_write_mmio(uint8_t reg, uint8_t val)
+{
+    uint8_t data = val;
+
+    memwrite(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1);
+}
+
+static uint8_t cmos_read_ioio(uint8_t reg)
+{
+    outw(base + 0, reg_base + (uint16_t)reg);
+    return inb(base + 3);
+}
+
+static void cmos_write_ioio(uint8_t reg, uint8_t val)
+{
+    outw(base + 0, reg_base + (uint16_t)reg);
+    outb(base + 3, val);
+}
+
+static uint8_t cmos_read(uint8_t reg)
+{
+    if (use_mmio) {
+        return cmos_read_mmio(reg);
+    } else {
+        return cmos_read_ioio(reg);
+    }
+}
+
+static void cmos_write(uint8_t reg, uint8_t val)
+{
+    if (use_mmio) {
+        cmos_write_mmio(reg, val);
+    } else {
+        cmos_write_ioio(reg, val);
+    }
+}
+
+static int bcd2dec(int value)
+{
+    return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
+}
+
+static int tm_cmp(struct tm *lhs, struct tm *rhs)
+{
+    time_t a, b;
+    struct tm d1, d2;
+
+    memcpy(&d1, lhs, sizeof(d1));
+    memcpy(&d2, rhs, sizeof(d2));
+
+    a = mktime(&d1);
+    b = mktime(&d2);
+
+    if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    }
+
+    return 0;
+}
+
+#if 0
+static void print_tm(struct tm *tm)
+{
+    printf("%04d-%02d-%02d %02d:%02d:%02d %+02ld\n",
+           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
+}
+#endif
+
+static void cmos_get_date_time(struct tm *date)
+{
+    int sec, min, hour, mday, mon, year;
+    time_t ts;
+    struct tm dummy;
+
+    sec = cmos_read(RTC_SECONDS);
+    min = cmos_read(RTC_MINUTES);
+    hour = cmos_read(RTC_HOURS);
+    mday = cmos_read(RTC_DAY_OF_MONTH);
+    mon = cmos_read(RTC_MONTH);
+    year = cmos_read(RTC_YEAR);
+
+    sec = bcd2dec(sec);
+    min = bcd2dec(min);
+    hour = bcd2dec(hour);
+    mday = bcd2dec(mday);
+    mon = bcd2dec(mon);
+    year = bcd2dec(year);
+
+    ts = time(NULL);
+    localtime_r(&ts, &dummy);
+
+    date->tm_isdst = dummy.tm_isdst;
+    date->tm_sec = sec;
+    date->tm_min = min;
+    date->tm_hour = hour;
+    date->tm_mday = mday;
+    date->tm_mon = mon - 1;
+    date->tm_year = base_year + year - 1900;
+    date->tm_gmtoff = 0;
+
+    ts = mktime(date);
+}
+
+static void check_time(int wiggle)
+{
+    struct tm start, date[4], end;
+    struct tm *datep;
+    time_t ts;
+
+    /*
+     * This check assumes a few things.  First, we cannot guarantee that we get
+     * a consistent reading from the wall clock because we may hit an edge of
+     * the clock while reading.  To work around this, we read four clock readings
+     * such that at least two of them should match.  We need to assume that one
+     * reading is corrupt so we need four readings to ensure that we have at
+     * least two consecutive identical readings
+     *
+     * It's also possible that we'll cross an edge reading the host clock so
+     * simply check to make sure that the clock reading is within the period of
+     * when we expect it to be.
+     */
+
+    ts = time(NULL);
+    gmtime_r(&ts, &start);
+
+    cmos_get_date_time(&date[0]);
+    cmos_get_date_time(&date[1]);
+    cmos_get_date_time(&date[2]);
+    cmos_get_date_time(&date[3]);
+
+    ts = time(NULL);
+    gmtime_r(&ts, &end);
+
+    if (tm_cmp(&date[0], &date[1]) == 0) {
+        datep = &date[0];
+    } else if (tm_cmp(&date[1], &date[2]) == 0) {
+        datep = &date[1];
+    } else if (tm_cmp(&date[2], &date[3]) == 0) {
+        datep = &date[2];
+    } else {
+        g_assert_not_reached();
+    }
+
+    if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
+        long t, s;
+
+        start.tm_isdst = datep->tm_isdst;
+
+        t = (long)mktime(datep);
+        s = (long)mktime(&start);
+        if (t < s) {
+            g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
+        } else {
+            g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
+        }
+
+        g_assert_cmpint(ABS(t - s), <=, wiggle);
+    }
+}
+
+static int wiggle = 2;
+
+static void bcd_check_time(void)
+{
+    if (strcmp(qtest_get_arch(), "sparc64") == 0) {
+        base = 0x74;
+        base_year = 1900;
+        use_mmio = false;
+    } else if (strcmp(qtest_get_arch(), "sparc") == 0) {
+        base = 0x71200000;
+        base_year = 1968;
+        use_mmio = true;
+    } else { /* PPC: need to map macio in PCI */
+        g_assert_not_reached();
+    }
+    check_time(wiggle);
+}
+
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+    unsigned int i;
+
+    for (i = 0; i < 1000; i++) {
+        uint8_t reg, val;
+
+        reg = (uint8_t)g_test_rand_int_range(0, 16);
+        val = (uint8_t)g_test_rand_int_range(0, 256);
+
+        cmos_write(reg, val);
+        cmos_read(reg);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    QTestState *s = NULL;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    s = qtest_start("-display none -rtc clock=vm");
+
+    qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
+    qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
+    ret = g_test_run();
+
+    if (s) {
+        qtest_quit(s);
+    }
+
+    return ret;
+}
commit 964c695a54ceda3ac8c965542829d4e482e28de7
Author: Eric Benard <eric at eukrea.com>
Date:   Mon Apr 16 05:02:47 2012 +0000

    versatiblepb: add NOR flash support
    
    - add support for the 64MB NOR CFI01 flash available at
    0x34000000 on the versatilepb board
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/BBAJIHEC.html
    
    - tested with barebox bootloader
    
    Signed-off-by: Eric Bénard <eric at eukrea.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index d011554..7c79c54 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -17,6 +17,11 @@
 #include "boards.h"
 #include "blockdev.h"
 #include "exec-memory.h"
+#include "flash.h"
+
+#define VERSATILE_FLASH_ADDR 0x34000000
+#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
+#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
 
 /* Primary interrupt controller.  */
 
@@ -182,6 +187,7 @@ static void versatile_init(ram_addr_t ram_size,
     i2c_bus *i2c;
     int n;
     int done_smc = 0;
+    DriveInfo *dinfo;
 
     if (!cpu_model)
         cpu_model = "arm926";
@@ -316,6 +322,16 @@ static void versatile_init(ram_addr_t ram_size,
     /*  0x101f2000 UART1.  */
     /*  0x101f3000 UART2.  */
     /* 0x101f4000 SSPI.  */
+    /* 0x34000000 NOR Flash */
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
+                          VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
+                          VERSATILE_FLASH_SECT_SIZE,
+                          VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
+                          4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
+        fprintf(stderr, "qemu: Error registering flash memory.\n");
+    }
 
     versatile_binfo.ram_size = ram_size;
     versatile_binfo.kernel_filename = kernel_filename;
commit bdac1c1e958c3b0bb1d02e8fb8cc141306eea103
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Apr 20 15:38:52 2012 +0000

    hw/arm_mptimer: Reset the qemu_timer at reset
    
    On reset of the mpcore timer/watchdog block we need to
    delete the qemu_timer in case it was running.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index df7fb4c..fe43cbb 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -228,6 +228,9 @@ static void timerblock_reset(timerblock *tb)
     tb->control = 0;
     tb->status = 0;
     tb->tick = 0;
+    if (tb->timer) {
+        qemu_del_timer(tb->timer);
+    }
 }
 
 static void arm_mptimer_reset(DeviceState *dev)
commit b1f05696ccc7ee2a04a541e373d098ad17568d13
Author: Oskar Andero <oskar.andero at gmail.com>
Date:   Fri Apr 20 15:38:52 2012 +0000

    versatilepb: add ds1338 rtc device
    
    Add ds1338 rtc attached on i2c.
    
    Signed-off-by: Oskar Andero <oskar.andero at gmail.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 25afb1e..d011554 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -13,6 +13,7 @@
 #include "net.h"
 #include "sysemu.h"
 #include "pci.h"
+#include "i2c.h"
 #include "boards.h"
 #include "blockdev.h"
 #include "exec-memory.h"
@@ -178,6 +179,7 @@ static void versatile_init(ram_addr_t ram_size,
     DeviceState *pl041;
     PCIBus *pci_bus;
     NICInfo *nd;
+    i2c_bus *i2c;
     int n;
     int done_smc = 0;
 
@@ -268,6 +270,10 @@ static void versatile_init(ram_addr_t ram_size,
     /* Add PL031 Real Time Clock. */
     sysbus_create_simple("pl031", 0x101e8000, pic[10]);
 
+    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
+    i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+    i2c_create_slave(i2c, "ds1338", 0x68);
+
     /* Add PL041 AACI Interface to the LM4549 codec */
     pl041 = qdev_create(NULL, "pl041");
     qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
commit d1157ca418b9426be5e1857eca8142966397a32b
Author: Oskar Andero <oskar.andero at gmail.com>
Date:   Fri Apr 20 15:38:52 2012 +0000

    realview: break out versatile i2c controller code
    
    The versatile i2c controller implementation was separated to
    its own file called versatile_i2c.c. This is done as a preparation
    for adding i2c support to the versatilepb board.
    
    Signed-off-by: Oskar Andero <oskar.andero at gmail.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index 84951a0..b6a9330 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -364,6 +364,7 @@ endif
 obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
 obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
+obj-arm-y += versatile_i2c.o
 obj-arm-y += cadence_uart.o
 obj-arm-y += cadence_ttc.o
 obj-arm-y += cadence_gem.o
diff --git a/hw/realview.c b/hw/realview.c
index cf55204..ecf4701 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -15,91 +15,13 @@
 #include "net.h"
 #include "sysemu.h"
 #include "boards.h"
-#include "bitbang_i2c.h"
+#include "i2c.h"
 #include "blockdev.h"
 #include "exec-memory.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
 #define SMP_BOOTREG_ADDR 0x10000030
 
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    bitbang_i2c_interface *bitbang;
-    int out;
-    int in;
-} RealViewI2CState;
-
-static uint64_t realview_i2c_read(void *opaque, target_phys_addr_t offset,
-                                  unsigned size)
-{
-    RealViewI2CState *s = (RealViewI2CState *)opaque;
-
-    if (offset == 0) {
-        return (s->out & 1) | (s->in << 1);
-    } else {
-        hw_error("realview_i2c_read: Bad offset 0x%x\n", (int)offset);
-        return -1;
-    }
-}
-
-static void realview_i2c_write(void *opaque, target_phys_addr_t offset,
-                               uint64_t value, unsigned size)
-{
-    RealViewI2CState *s = (RealViewI2CState *)opaque;
-
-    switch (offset) {
-    case 0:
-        s->out |= value & 3;
-        break;
-    case 4:
-        s->out &= ~value;
-        break;
-    default:
-        hw_error("realview_i2c_write: Bad offset 0x%x\n", (int)offset);
-    }
-    bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
-    s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
-}
-
-static const MemoryRegionOps realview_i2c_ops = {
-    .read = realview_i2c_read,
-    .write = realview_i2c_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int realview_i2c_init(SysBusDevice *dev)
-{
-    RealViewI2CState *s = FROM_SYSBUS(RealViewI2CState, dev);
-    i2c_bus *bus;
-
-    bus = i2c_init_bus(&dev->qdev, "i2c");
-    s->bitbang = bitbang_i2c_init(bus);
-    memory_region_init_io(&s->iomem, &realview_i2c_ops, s,
-                          "realview-i2c", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static void realview_i2c_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = realview_i2c_init;
-}
-
-static TypeInfo realview_i2c_info = {
-    .name          = "realview_i2c",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(RealViewI2CState),
-    .class_init    = realview_i2c_class_init,
-};
-
-static void realview_register_types(void)
-{
-    type_register_static(&realview_i2c_info);
-}
-
 /* Board init.  */
 
 static struct arm_boot_info realview_binfo = {
@@ -328,7 +250,7 @@ static void realview_init(ram_addr_t ram_size,
         }
     }
 
-    dev = sysbus_create_simple("realview_i2c", 0x10002000, NULL);
+    dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
     i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
     i2c_create_slave(i2c, "ds1338", 0x68);
 
@@ -492,4 +414,3 @@ static void realview_machine_init(void)
 }
 
 machine_init(realview_machine_init);
-type_init(realview_register_types)
diff --git a/hw/versatile_i2c.c b/hw/versatile_i2c.c
new file mode 100644
index 0000000..88f530a
--- /dev/null
+++ b/hw/versatile_i2c.c
@@ -0,0 +1,105 @@
+/*
+ * ARM Versatile I2C controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Copyright (c) 2012 Oskar Andero <oskar.andero at gmail.com>
+ *
+ * This file is derived from hw/realview.c by Paul Brook
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "sysbus.h"
+#include "bitbang_i2c.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    bitbang_i2c_interface *bitbang;
+    int out;
+    int in;
+} VersatileI2CState;
+
+static uint64_t versatile_i2c_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
+{
+    VersatileI2CState *s = (VersatileI2CState *)opaque;
+
+    if (offset == 0) {
+        return (s->out & 1) | (s->in << 1);
+    } else {
+        hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
+        return -1;
+    }
+}
+
+static void versatile_i2c_write(void *opaque, target_phys_addr_t offset,
+                                uint64_t value, unsigned size)
+{
+    VersatileI2CState *s = (VersatileI2CState *)opaque;
+
+    switch (offset) {
+    case 0:
+        s->out |= value & 3;
+        break;
+    case 4:
+        s->out &= ~value;
+        break;
+    default:
+        hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
+    }
+    bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
+    s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
+}
+
+static const MemoryRegionOps versatile_i2c_ops = {
+    .read = versatile_i2c_read,
+    .write = versatile_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int versatile_i2c_init(SysBusDevice *dev)
+{
+    VersatileI2CState *s = FROM_SYSBUS(VersatileI2CState, dev);
+    i2c_bus *bus;
+
+    bus = i2c_init_bus(&dev->qdev, "i2c");
+    s->bitbang = bitbang_i2c_init(bus);
+    memory_region_init_io(&s->iomem, &versatile_i2c_ops, s,
+                          "versatile_i2c", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static void versatile_i2c_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = versatile_i2c_init;
+}
+
+static const TypeInfo versatile_i2c_info = {
+    .name          = "versatile_i2c",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(VersatileI2CState),
+    .class_init    = versatile_i2c_class_init,
+};
+
+static void versatile_i2c_register_types(void)
+{
+    type_register_static(&versatile_i2c_info);
+}
+
+type_init(versatile_i2c_register_types)
commit 1042ec94b19e0bfaae74c912ebbdfdbff8dd7db2
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Apr 12 17:21:44 2012 +0200

    qemu-iotests: Fix test 031 for qcow2 v3 support
    
    qcow2.py must be updated to work with version 3 images at all, the
    output has changed since the feature table extension has been added, and
    version 2 and version 3 images can't possibly have the same test output.
    
    Change the test case to completely ignore IMGOPTS and run the test for
    both compat=1.1 and compat=0.10 regardless of the ./check command line.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
index 6365f28..2d5e3b1 100755
--- a/tests/qemu-iotests/031
+++ b/tests/qemu-iotests/031
@@ -45,26 +45,34 @@ _supported_proto generic
 _supported_os Linux
 
 CLUSTER_SIZE=65536
-echo
-echo === Create image with unknown header extension ===
-echo
-_make_test_img 64M
-./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
-./qcow2.py $TEST_IMG dump-header
-_check_test_img
 
-echo
-echo === Rewrite header with no backing file ===
-echo
-$QEMU_IMG rebase -u -b "" $TEST_IMG
-./qcow2.py $TEST_IMG dump-header
-_check_test_img
+# qcow2.py output depends on the exact options used, so override the command
+# line here as an exception
+for IMGOPTS in "compat=0.10" "compat=1.1"; do
 
-echo
-echo === Add a backing file and format ===
-echo
-$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
-./qcow2.py $TEST_IMG dump-header
+    echo
+    echo ===== Testing with -o $IMGOPTS =====
+    echo
+    echo === Create image with unknown header extension ===
+    echo
+    _make_test_img 64M
+    ./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
+    ./qcow2.py $TEST_IMG dump-header
+    _check_test_img
+
+    echo
+    echo === Rewrite header with no backing file ===
+    echo
+    $QEMU_IMG rebase -u -b "" $TEST_IMG
+    ./qcow2.py $TEST_IMG dump-header
+    _check_test_img
+
+    echo
+    echo === Add a backing file and format ===
+    echo
+    $QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
+    ./qcow2.py $TEST_IMG dump-header
+done
 
 # success, all done
 echo "*** done"
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
index e1a536e..d3cab30 100644
--- a/tests/qemu-iotests/031.out
+++ b/tests/qemu-iotests/031.out
@@ -1,5 +1,7 @@
 QA output created by 031
 
+===== Testing with -o compat=0.10 =====
+
 === Create image with unknown header extension ===
 
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
@@ -16,6 +18,11 @@ refcount_table_offset     0x10000
 refcount_table_clusters   1
 nb_snapshots              0
 snapshot_offset           0x0
+incompatible_features     0x0
+compatible_features       0x0
+autoclear_features        0x0
+refcount_order            4
+header_length             72
 
 Header extension:
 magic                     0x12345678
@@ -39,6 +46,16 @@ refcount_table_offset     0x10000
 refcount_table_clusters   1
 nb_snapshots              0
 snapshot_offset           0x0
+incompatible_features     0x0
+compatible_features       0x0
+autoclear_features        0x0
+refcount_order            4
+header_length             72
+
+Header extension:
+magic                     0x6803f857
+length                    0
+data                      ''
 
 Header extension:
 magic                     0x12345678
@@ -51,7 +68,108 @@ No errors were found on the image.
 
 magic                     0x514649fb
 version                   2
-backing_file_offset       0x90
+backing_file_offset       0x98
+backing_file_size         0x17
+cluster_bits              16
+size                      67108864
+crypt_method              0
+l1_size                   1
+l1_table_offset           0x30000
+refcount_table_offset     0x10000
+refcount_table_clusters   1
+nb_snapshots              0
+snapshot_offset           0x0
+incompatible_features     0x0
+compatible_features       0x0
+autoclear_features        0x0
+refcount_order            4
+header_length             72
+
+Header extension:
+magic                     0xe2792aca
+length                    11
+data                      'host_device'
+
+Header extension:
+magic                     0x6803f857
+length                    0
+data                      ''
+
+Header extension:
+magic                     0x12345678
+length                    31
+data                      'This is a test header extension'
+
+
+===== Testing with -o compat=1.1 =====
+
+=== Create image with unknown header extension ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+magic                     0x514649fb
+version                   3
+backing_file_offset       0x0
+backing_file_size         0x0
+cluster_bits              16
+size                      67108864
+crypt_method              0
+l1_size                   1
+l1_table_offset           0x30000
+refcount_table_offset     0x10000
+refcount_table_clusters   1
+nb_snapshots              0
+snapshot_offset           0x0
+incompatible_features     0x0
+compatible_features       0x0
+autoclear_features        0x0
+refcount_order            4
+header_length             104
+
+Header extension:
+magic                     0x12345678
+length                    31
+data                      'This is a test header extension'
+
+No errors were found on the image.
+
+=== Rewrite header with no backing file ===
+
+magic                     0x514649fb
+version                   3
+backing_file_offset       0x0
+backing_file_size         0x0
+cluster_bits              16
+size                      67108864
+crypt_method              0
+l1_size                   1
+l1_table_offset           0x30000
+refcount_table_offset     0x10000
+refcount_table_clusters   1
+nb_snapshots              0
+snapshot_offset           0x0
+incompatible_features     0x0
+compatible_features       0x0
+autoclear_features        0x0
+refcount_order            4
+header_length             104
+
+Header extension:
+magic                     0x6803f857
+length                    0
+data                      ''
+
+Header extension:
+magic                     0x12345678
+length                    31
+data                      'This is a test header extension'
+
+No errors were found on the image.
+
+=== Add a backing file and format ===
+
+magic                     0x514649fb
+version                   3
+backing_file_offset       0xb8
 backing_file_size         0x17
 cluster_bits              16
 size                      67108864
@@ -62,6 +180,11 @@ refcount_table_offset     0x10000
 refcount_table_clusters   1
 nb_snapshots              0
 snapshot_offset           0x0
+incompatible_features     0x0
+compatible_features       0x0
+autoclear_features        0x0
+refcount_order            4
+header_length             104
 
 Header extension:
 magic                     0xe2792aca
@@ -69,6 +192,11 @@ length                    11
 data                      'host_device'
 
 Header extension:
+magic                     0x6803f857
+length                    0
+data                      ''
+
+Header extension:
 magic                     0x12345678
 length                    31
 data                      'This is a test header extension'
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
index bfb47e8..e27196a 100755
--- a/tests/qemu-iotests/qcow2.py
+++ b/tests/qemu-iotests/qcow2.py
@@ -35,6 +35,13 @@ class QcowHeader:
         [ uint32_t, '%d',   'refcount_table_clusters' ],
         [ uint32_t, '%d',   'nb_snapshots' ],
         [ uint64_t, '%#x',  'snapshot_offset' ],
+
+        # Version 3 header fields
+        [ uint64_t, '%#x',  'incompatible_features' ],
+        [ uint64_t, '%#x',  'compatible_features' ],
+        [ uint64_t, '%#x',  'autoclear_features' ],
+        [ uint32_t, '%d',   'refcount_order' ],
+        [ uint32_t, '%d',   'header_length' ],
     ];
 
     fmt = '>' + ''.join(field[0] for field in fields)
@@ -50,9 +57,10 @@ class QcowHeader:
         self.__dict__ = dict((field[2], header[i])
             for i, field in enumerate(QcowHeader.fields))
 
+        self.set_defaults()
         self.cluster_size = 1 << self.cluster_bits
 
-        fd.seek(self.get_header_length())
+        fd.seek(self.header_length)
         self.load_extensions(fd)
 
         if self.backing_file_offset:
@@ -61,11 +69,13 @@ class QcowHeader:
         else:
             self.backing_file = None
 
-    def get_header_length(self):
+    def set_defaults(self):
         if self.version == 2:
-            return 72
-        else:
-            raise Exception("version != 2 not supported")
+            self.incompatible_features = 0
+            self.compatible_features = 0
+            self.autoclear_features = 0
+            self.refcount_order = 4
+            self.header_length = 72
 
     def load_extensions(self, fd):
         self.extensions = []
@@ -86,7 +96,7 @@ class QcowHeader:
 
     def update_extensions(self, fd):
 
-        fd.seek(self.get_header_length())
+        fd.seek(self.header_length)
         extensions = self.extensions
         extensions.append(QcowHeaderExtension(0, 0, ""))
         for ex in extensions:
@@ -103,7 +113,7 @@ class QcowHeader:
 
 
     def update(self, fd):
-        header_bytes = self.get_header_length()
+        header_bytes = self.header_length
 
         self.update_extensions(fd)
 
commit 8900436891cd8955b0795945aa020c04eaa0e5d2
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Mar 27 13:45:14 2012 +0200

    qemu-iotests: Add -o and make v3 the default for qcow2
    
    This adds an -o option to qemu-iotests, which is an option string that
    is passed through to qemu-img create -o... This allows testing different
    subformat with a command like './check -qcow2 -o compat=0.10'.
    
    For qcow2, if no compat option is specified, compat=1.1 is the new
    default.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index aae1378..432732c 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -41,9 +41,6 @@ then
     exit 1
 fi
 
-# we need common
-. ./common
-
 # we need common.rc
 if ! . ./common.rc
 then
@@ -51,6 +48,9 @@ then
     exit 1
 fi
 
+# we need common
+. ./common
+
 #if [ `id -u` -ne 0 ]
 #then
 #    echo "check: QA must be run as root"
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index c187f6c..eeb70cb 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -35,6 +35,7 @@ diff="diff -u"
 verbose=false
 group=false
 xgroup=false
+imgopts=false
 showme=false
 sortme=false
 expunge=true
@@ -44,6 +45,7 @@ rm -f $tmp.list $tmp.tmp $tmp.sed
 
 export IMGFMT=raw
 export IMGPROTO=file
+export IMGOPTS=""
 export QEMU_IO_OPTIONS=""
 
 for r
@@ -103,6 +105,13 @@ s/ .*//p
 	mv $tmp.tmp $tmp.list
 	xgroup=false
 	continue
+
+    elif $imgopts
+    then
+        IMGOPTS="$r"
+        imgopts=false
+        continue
+
     fi
 
     xpand=true
@@ -130,6 +139,7 @@ check options
     -nocache		use O_DIRECT on backing file
     -misalign		misalign memory allocations
     -n			show me, do not run tests
+    -o options          -o options to pass to qemu-img create/convert
     -T			output timestamps
     -r 			randomize test order
     
@@ -223,6 +233,10 @@ testlist options
 	    showme=true
 	    xpand=false
 	    ;;
+        -o)
+            imgopts=true
+            xpand=false
+            ;;
         -r)	# randomize test order
 	    randomize=true
 	    xpand=false
@@ -299,6 +313,9 @@ BEGIN	{ for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
 
 done
 
+# Set default options for qemu-img create -o if they were not specified
+_set_default_imgopts
+
 if [ -s $tmp.list ]
 then
     # found some valid test numbers ... this is good
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 00ee754..4bc7420 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -53,19 +53,44 @@ else
     TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
 fi
 
+_optstr_add()
+{
+    if [ -n "$1" ]; then
+        echo "$1,$2"
+    else
+        echo "$2"
+    fi
+}
+
+_set_default_imgopts()
+{
+    if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
+        IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
+    fi
+}
+
 _make_test_img()
 {
     # extra qemu-img options can be added by tests
     # at least one argument (the image size) needs to be added
     local extra_img_options=""
     local image_size=$*
+    local optstr=""
+
+    if [ -n "$IMGOPTS" ]; then
+        optstr=$(_optstr_add "$optstr" "$IMGOPTS")
+    fi
 
     if [ "$1" = "-b" ]; then
         extra_img_options="$1 $2"
         image_size=$3
     fi
     if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
-        extra_img_options="-o cluster_size=$CLUSTER_SIZE $extra_img_options"
+        optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
+    fi
+
+    if [ -n "$optstr" ]; then
+        extra_img_options="-o $optstr $extra_img_options"
     fi
 
     # XXX(hch): have global image options?
@@ -76,6 +101,7 @@ _make_test_img()
 	sed -e "s# encryption=off##g" | \
 	sed -e "s# cluster_size=[0-9]\\+##g" | \
 	sed -e "s# table_size=0##g" | \
+	sed -e "s# compat='[^']*'##g" | \
 	sed -e "s# compat6=off##g" | \
 	sed -e "s# static=off##g"
 }
@@ -268,7 +294,11 @@ _require_command()
 
 _full_imgfmt_details()
 {
-    echo "$IMGFMT"
+    if [ -n "$IMGOPTS" ]; then
+        echo "$IMGFMT ($IMGOPTS)"
+    else
+        echo "$IMGFMT"
+    fi
 }
 
 _full_imgproto_details()
commit 621f058940ea9f1ef3d8774ef3203544f1228df1
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Mar 20 15:12:58 2012 +0100

    qcow2: Zero write support
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 421cd1b..fe74ddd 100644
--- a/block.c
+++ b/block.c
@@ -80,6 +80,8 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
                                                void *opaque,
                                                bool is_write);
 static void coroutine_fn bdrv_co_do_rw(void *opaque);
+static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors);
 
 static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
         bool is_write, double elapsed_time, uint64_t *wait);
@@ -1708,8 +1710,8 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
 
     if (drv->bdrv_co_write_zeroes &&
         buffer_is_zero(bounce_buffer, iov.iov_len)) {
-        ret = drv->bdrv_co_write_zeroes(bs, cluster_sector_num,
-                                        cluster_nb_sectors);
+        ret = bdrv_co_do_write_zeroes(bs, cluster_sector_num,
+                                      cluster_nb_sectors);
     } else {
         ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
                                   &bounce_qiov);
@@ -1819,9 +1821,15 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
     struct iovec iov;
     int ret;
 
+    /* TODO Emulate only part of misaligned requests instead of letting block
+     * drivers return -ENOTSUP and emulate everything */
+
     /* First try the efficient write zeroes operation */
     if (drv->bdrv_co_write_zeroes) {
-        return drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+        ret = drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+        if (ret != -ENOTSUP) {
+            return ret;
+        }
     }
 
     /* Fall back to bounce buffer if write zeroes is unsupported */
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 5e5f5cf..a747a88 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1102,3 +1102,75 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
 
     return 0;
 }
+
+/*
+ * This zeroes as many clusters of nb_clusters as possible at once (i.e.
+ * all clusters in the same L2 table) and returns the number of zeroed
+ * clusters.
+ */
+static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
+    unsigned int nb_clusters)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l2_table;
+    int l2_index;
+    int ret;
+    int i;
+
+    ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* Limit nb_clusters to one L2 table */
+    nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+
+    for (i = 0; i < nb_clusters; i++) {
+        uint64_t old_offset;
+
+        old_offset = be64_to_cpu(l2_table[l2_index + i]);
+
+        /* Update L2 entries */
+        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+        if (old_offset & QCOW_OFLAG_COMPRESSED) {
+            l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
+            qcow2_free_any_clusters(bs, old_offset, 1);
+        } else {
+            l2_table[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
+        }
+    }
+
+    ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return nb_clusters;
+}
+
+int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    unsigned int nb_clusters;
+    int ret;
+
+    /* The zero flag is only supported by version 3 and newer */
+    if (s->qcow_version < 3) {
+        return -ENOTSUP;
+    }
+
+    /* Each L2 table is handled by its own loop iteration */
+    nb_clusters = size_to_clusters(s, nb_sectors << BDRV_SECTOR_BITS);
+
+    while (nb_clusters > 0) {
+        ret = zero_single_l2(bs, offset, nb_clusters);
+        if (ret < 0) {
+            return ret;
+        }
+
+        nb_clusters -= ret;
+        offset += (ret * s->cluster_size);
+    }
+
+    return 0;
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index 41b195d..ad46c03 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1281,6 +1281,26 @@ static int qcow2_make_empty(BlockDriverState *bs)
     return 0;
 }
 
+static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
+{
+    int ret;
+    BDRVQcowState *s = bs->opaque;
+
+    /* Emulate misaligned zero writes */
+    if (sector_num % s->cluster_sectors || nb_sectors % s->cluster_sectors) {
+        return -ENOTSUP;
+    }
+
+    /* Whatever is left can use real zero clusters */
+    qemu_co_mutex_lock(&s->lock);
+    ret = qcow2_zero_clusters(bs, sector_num << BDRV_SECTOR_BITS,
+        nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+
+    return ret;
+}
+
 static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors)
 {
@@ -1558,6 +1578,7 @@ static BlockDriver bdrv_qcow2 = {
     .bdrv_co_writev         = qcow2_co_writev,
     .bdrv_co_flush_to_os    = qcow2_co_flush_to_os,
 
+    .bdrv_co_write_zeroes   = qcow2_co_write_zeroes,
     .bdrv_co_discard        = qcow2_co_discard,
     .bdrv_truncate          = qcow2_truncate,
     .bdrv_write_compressed  = qcow2_write_compressed,
diff --git a/block/qcow2.h b/block/qcow2.h
index 2a98244..93567f6 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -283,6 +283,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
 int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
     int nb_sectors);
+int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
 
 /* qcow2-snapshot.c functions */
 int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
commit ab3a32ad5ea841c313e5f9c5f0d4ec02a8e9ddfc
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Apr 12 15:28:12 2012 +0200

    qemu-iotests: Test backing file COW with zero clusters
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034
new file mode 100755
index 0000000..8254df8
--- /dev/null
+++ b/tests/qemu-iotests/034
@@ -0,0 +1,113 @@
+#!/bin/bash
+#
+# Test bdrv_write_zeroes with backing files
+#
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow qcow2 vmdk qed
+_supported_proto generic
+_supported_os Linux
+
+CLUSTER_SIZE=4k
+size=128M
+
+echo
+echo "== creating backing file for COW tests =="
+
+_make_test_img $size
+$QEMU_IO -c "write -P 0x55 0 1M" $TEST_IMG | _filter_qemu_io
+mv $TEST_IMG $TEST_IMG.base
+
+_make_test_img -b $TEST_IMG.base 6G
+
+echo
+echo "== zero write with backing file =="
+$QEMU_IO -c "write -z 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 513k 13k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (3) =="
+$QEMU_IO -c "read -P 0x55 0 64k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 256k 257k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 513k 13k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 526k 498k" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== overwriting zero cluster =="
+$QEMU_IO -c "write -P 0xa 60k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xb 64k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xc 76k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xd 252k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xe 248k 8k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (4) =="
+$QEMU_IO -c "read -P 0x55 0 60k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 60k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xb 64k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 72k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xc 76k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 80k 168k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xe 248k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xd 256k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 260k 64k" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== re-zeroing overwritten area =="
+$QEMU_IO -c "write -z 64k 192k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (5) =="
+$QEMU_IO -c "read -P 0x55 0 60k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 60k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xd 256k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 260k 253k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 513k 13k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 526k 498k" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/034.out b/tests/qemu-iotests/034.out
new file mode 100644
index 0000000..e82dae5
--- /dev/null
+++ b/tests/qemu-iotests/034.out
@@ -0,0 +1,81 @@
+QA output created by 034
+
+== creating backing file for COW tests ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base' 
+
+== zero write with backing file ==
+wrote 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (3) ==
+read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 263168/263168 bytes at offset 262144
+257 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 509952/509952 bytes at offset 538624
+498 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== overwriting zero cluster ==
+wrote 8192/8192 bytes at offset 61440
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 65536
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 4096/4096 bytes at offset 77824
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 258048
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 253952
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (4) ==
+read 61440/61440 bytes at offset 0
+60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 61440
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 8192/8192 bytes at offset 65536
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 73728
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 77824
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 172032/172032 bytes at offset 81920
+168 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 8192/8192 bytes at offset 253952
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 262144
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 266240
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== re-zeroing overwritten area ==
+wrote 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (5) ==
+read 61440/61440 bytes at offset 0
+60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 61440
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 262144
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 259072/259072 bytes at offset 266240
+253 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 509952/509952 bytes at offset 538624
+498 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index af34482..5934829 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -40,3 +40,4 @@
 031 rw auto quick
 032 rw auto
 033 rw auto
+034 rw auto backing
commit ee3a315edfb12d3c18195410050eed0e2d49cc27
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Mar 8 18:15:01 2012 +0100

    qemu-iotests: add a simple test for write_zeroes
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
new file mode 100755
index 0000000..9aee078
--- /dev/null
+++ b/tests/qemu-iotests/033
@@ -0,0 +1,73 @@
+#!/bin/bash
+#
+# Test aligned and misaligned write zeroes operations.
+#
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=pbonzini at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt generic
+_supported_proto generic
+_supported_os Linux
+
+
+size=128M
+_make_test_img $size
+
+echo
+echo "== preparing image =="
+$QEMU_IO -c "write -P 0xa 0x200 0x400" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xa 0x20000 0x600" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== verifying patterns (1) =="
+$QEMU_IO -c "read -P 0xa 0x200 0x200" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 0x20400 0x200" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== rewriting zeroes =="
+$QEMU_IO -c "write -P 0xb 0x10000 0x10000" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 0x10000 0x10000" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== verifying patterns (2) =="
+$QEMU_IO -c "read -P 0x0 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/033.out b/tests/qemu-iotests/033.out
new file mode 100644
index 0000000..8934883
--- /dev/null
+++ b/tests/qemu-iotests/033.out
@@ -0,0 +1,29 @@
+QA output created by 033
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
+
+== preparing image ==
+wrote 1024/1024 bytes at offset 512
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1536/1536 bytes at offset 131072
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verifying patterns (1) ==
+read 512/512 bytes at offset 512
+512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 132096
+512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== rewriting zeroes ==
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verifying patterns (2) ==
+read 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 92508a7..af34482 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -39,3 +39,4 @@
 030 rw auto
 031 rw auto quick
 032 rw auto
+033 rw auto
commit cfcc4c62ffe37170cf4b0c9e7acbd2dbaa792598
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Apr 12 15:20:27 2012 +0200

    qcow2: Support for feature table header extension
    
    Instead of printing an ugly bitmask, qemu can now print a more helpful
    string even for yet unknown features.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index 9a8b354..41b195d 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -54,6 +54,7 @@ typedef struct {
 } QCowExtension;
 #define  QCOW2_EXT_MAGIC_END 0
 #define  QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
+#define  QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
 
 static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
@@ -76,7 +77,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
  * return 0 upon success, non-0 otherwise
  */
 static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
-                                 uint64_t end_offset)
+                                 uint64_t end_offset, void **p_feature_table)
 {
     BDRVQcowState *s = bs->opaque;
     QCowExtension ext;
@@ -134,6 +135,18 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
 #endif
             break;
 
+        case QCOW2_EXT_MAGIC_FEATURE_TABLE:
+            if (p_feature_table != NULL) {
+                void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
+                ret = bdrv_pread(bs->file, offset , feature_table, ext.len);
+                if (ret < 0) {
+                    return ret;
+                }
+
+                *p_feature_table = feature_table;
+            }
+            break;
+
         default:
             /* unknown magic - save it in case we need to rewrite the header */
             {
@@ -182,6 +195,24 @@ static void report_unsupported(BlockDriverState *bs, const char *fmt, ...)
         bs->device_name, "qcow2", msg);
 }
 
+static void report_unsupported_feature(BlockDriverState *bs,
+    Qcow2Feature *table, uint64_t mask)
+{
+    while (table && table->name[0] != '\0') {
+        if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
+            if (mask & (1 << table->bit)) {
+                report_unsupported(bs, "%.46s",table->name);
+                mask &= ~(1 << table->bit);
+            }
+        }
+        table++;
+    }
+
+    if (mask) {
+        report_unsupported(bs, "Unknown incompatible feature: %" PRIx64, mask);
+    }
+}
+
 static int qcow2_open(BlockDriverState *bs, int flags)
 {
     BDRVQcowState *s = bs->opaque;
@@ -245,14 +276,23 @@ static int qcow2_open(BlockDriverState *bs, int flags)
         }
     }
 
+    if (header.backing_file_offset) {
+        ext_end = header.backing_file_offset;
+    } else {
+        ext_end = 1 << header.cluster_bits;
+    }
+
     /* Handle feature bits */
     s->incompatible_features    = header.incompatible_features;
     s->compatible_features      = header.compatible_features;
     s->autoclear_features       = header.autoclear_features;
 
     if (s->incompatible_features != 0) {
-        report_unsupported(bs, "incompatible features mask %" PRIx64,
-                           header.incompatible_features);
+        void *feature_table = NULL;
+        qcow2_read_extensions(bs, header.header_length, ext_end,
+                              &feature_table);
+        report_unsupported_feature(bs, feature_table,
+                                   s->incompatible_features);
         ret = -ENOTSUP;
         goto fail;
     }
@@ -343,12 +383,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     QLIST_INIT(&s->cluster_allocs);
 
     /* read qcow2 extensions */
-    if (header.backing_file_offset) {
-        ext_end = header.backing_file_offset;
-    } else {
-        ext_end = s->cluster_size;
-    }
-    if (qcow2_read_extensions(bs, header.header_length, ext_end)) {
+    if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL)) {
         ret = -EINVAL;
         goto fail;
     }
@@ -912,6 +947,19 @@ int qcow2_update_header(BlockDriverState *bs)
         buflen -= ret;
     }
 
+    /* Feature table */
+    Qcow2Feature features[] = {
+        /* no feature defined yet */
+    };
+
+    ret = header_ext_add(buf, QCOW2_EXT_MAGIC_FEATURE_TABLE,
+                         features, sizeof(features), buflen);
+    if (ret < 0) {
+        goto fail;
+    }
+    buf += ret;
+    buflen -= ret;
+
     /* Keep unknown header extensions */
     QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
         ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
diff --git a/block/qcow2.h b/block/qcow2.h
index df2bdfd..2a98244 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -104,6 +104,18 @@ typedef struct Qcow2UnknownHeaderExtension {
     uint8_t data[];
 } Qcow2UnknownHeaderExtension;
 
+enum {
+    QCOW2_FEAT_TYPE_INCOMPATIBLE    = 0,
+    QCOW2_FEAT_TYPE_COMPATIBLE      = 1,
+    QCOW2_FEAT_TYPE_AUTOCLEAR       = 2,
+};
+
+typedef struct Qcow2Feature {
+    uint8_t type;
+    uint8_t bit;
+    char    name[46];
+} QEMU_PACKED Qcow2Feature;
+
 typedef struct BDRVQcowState {
     int cluster_bits;
     int cluster_size;
commit 6377af48b0445e7ee50db6e0bd73a3a70098f5f4
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Mar 16 15:02:38 2012 +0100

    qcow2: Support reading zero clusters
    
    This adds support for reading zero clusters in version 3 images.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index b8836ba..5e5f5cf 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -453,6 +453,12 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
         c = 1;
         *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
         break;
+    case QCOW2_CLUSTER_ZERO:
+        c = count_contiguous_clusters(nb_clusters, s->cluster_size,
+                &l2_table[l2_index], 0,
+                QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
+        *cluster_offset = 0;
+        break;
     case QCOW2_CLUSTER_UNALLOCATED:
         /* how many empty clusters ? */
         c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
@@ -461,7 +467,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
     case QCOW2_CLUSTER_NORMAL:
         /* how many allocated clusters ? */
         c = count_contiguous_clusters(nb_clusters, s->cluster_size,
-                &l2_table[l2_index], 0, QCOW_OFLAG_COMPRESSED);
+                &l2_table[l2_index], 0,
+                QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
         *cluster_offset &= L2E_OFFSET_MASK;
         break;
     }
@@ -720,6 +727,7 @@ static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
             break;
         case QCOW2_CLUSTER_UNALLOCATED:
         case QCOW2_CLUSTER_COMPRESSED:
+        case QCOW2_CLUSTER_ZERO:
             break;
         default:
             abort();
@@ -868,9 +876,10 @@ again:
         && (cluster_offset & QCOW_OFLAG_COPIED))
     {
         /* We keep all QCOW_OFLAG_COPIED clusters */
-        keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
-                                                  &l2_table[l2_index], 0,
-                                                  QCOW_OFLAG_COPIED);
+        keep_clusters =
+            count_contiguous_clusters(nb_clusters, s->cluster_size,
+                                      &l2_table[l2_index], 0,
+                                      QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
         assert(keep_clusters <= nb_clusters);
         nb_clusters -= keep_clusters;
     } else {
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 0112cc3..812c93c 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -703,6 +703,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs,
                             nb_clusters << s->cluster_bits);
         break;
     case QCOW2_CLUSTER_UNALLOCATED:
+    case QCOW2_CLUSTER_ZERO:
         break;
     default:
         abort();
@@ -973,6 +974,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
                 l2_entry & ~511, nb_csectors * 512);
             break;
 
+        case QCOW2_CLUSTER_ZERO:
+            if ((l2_entry & L2E_OFFSET_MASK) == 0) {
+                break;
+            }
+            /* fall through */
+
         case QCOW2_CLUSTER_NORMAL:
         {
             /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
diff --git a/block/qcow2.c b/block/qcow2.c
index 3e1482f..9a8b354 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -536,6 +536,14 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
             }
             break;
 
+        case QCOW2_CLUSTER_ZERO:
+            if (s->qcow_version < 3) {
+                ret = -EIO;
+                goto fail;
+            }
+            qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
+            break;
+
         case QCOW2_CLUSTER_COMPRESSED:
             /* add AIO support for compressed blocks ? */
             ret = qcow2_decompress_cluster(bs, cluster_offset);
diff --git a/block/qcow2.h b/block/qcow2.h
index 2dc8ca2..df2bdfd 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -43,6 +43,8 @@
 #define QCOW_OFLAG_COPIED     (1LL << 63)
 /* indicate that the cluster is compressed (they never have the copied flag) */
 #define QCOW_OFLAG_COMPRESSED (1LL << 62)
+/* The cluster reads as all zeros */
+#define QCOW_OFLAG_ZERO (1LL << 0)
 
 #define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
 
@@ -184,6 +186,7 @@ enum {
     QCOW2_CLUSTER_UNALLOCATED,
     QCOW2_CLUSTER_NORMAL,
     QCOW2_CLUSTER_COMPRESSED,
+    QCOW2_CLUSTER_ZERO
 };
 
 #define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
@@ -213,6 +216,8 @@ static inline int qcow2_get_cluster_type(uint64_t l2_entry)
 {
     if (l2_entry & QCOW_OFLAG_COMPRESSED) {
         return QCOW2_CLUSTER_COMPRESSED;
+    } else if (l2_entry & QCOW_OFLAG_ZERO) {
+        return QCOW2_CLUSTER_ZERO;
     } else if (!(l2_entry & L2E_OFFSET_MASK)) {
         return QCOW2_CLUSTER_UNALLOCATED;
     } else {
commit 6744cbab8cd63b7ce72b3eee4f0055007acf0798
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Dec 15 12:20:58 2011 +0100

    qcow2: Version 3 images
    
    This adds the basic infrastructure to qcow2 to handle version 3 images.
    It includes code to create v3 images, allow header updates for v3 images
    and checks feature bits.
    
    It still misses support for zero clusters, so this is not a fully
    compliant implementation of v3 yet.
    
    The default for creating new images stays at v2 for now.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index 4c82adc..3e1482f 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -61,7 +61,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
 
     if (buf_size >= sizeof(QCowHeader) &&
         be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
-        be32_to_cpu(cow_header->version) >= QCOW_VERSION)
+        be32_to_cpu(cow_header->version) >= 2)
         return 100;
     else
         return 0;
@@ -169,6 +169,19 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs)
     }
 }
 
+static void report_unsupported(BlockDriverState *bs, const char *fmt, ...)
+{
+    char msg[64];
+    va_list ap;
+
+    va_start(ap, fmt);
+    vsnprintf(msg, sizeof(msg), fmt, ap);
+    va_end(ap);
+
+    qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+        bs->device_name, "qcow2", msg);
+}
+
 static int qcow2_open(BlockDriverState *bs, int flags)
 {
     BDRVQcowState *s = bs->opaque;
@@ -199,14 +212,64 @@ static int qcow2_open(BlockDriverState *bs, int flags)
         ret = -EINVAL;
         goto fail;
     }
-    if (header.version != QCOW_VERSION) {
-        char version[64];
-        snprintf(version, sizeof(version), "QCOW version %d", header.version);
-        qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
-            bs->device_name, "qcow2", version);
+    if (header.version < 2 || header.version > 3) {
+        report_unsupported(bs, "QCOW version %d", header.version);
+        ret = -ENOTSUP;
+        goto fail;
+    }
+
+    s->qcow_version = header.version;
+
+    /* Initialise version 3 header fields */
+    if (header.version == 2) {
+        header.incompatible_features    = 0;
+        header.compatible_features      = 0;
+        header.autoclear_features       = 0;
+        header.refcount_order           = 4;
+        header.header_length            = 72;
+    } else {
+        be64_to_cpus(&header.incompatible_features);
+        be64_to_cpus(&header.compatible_features);
+        be64_to_cpus(&header.autoclear_features);
+        be32_to_cpus(&header.refcount_order);
+        be32_to_cpus(&header.header_length);
+    }
+
+    if (header.header_length > sizeof(header)) {
+        s->unknown_header_fields_size = header.header_length - sizeof(header);
+        s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
+        ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields,
+                         s->unknown_header_fields_size);
+        if (ret < 0) {
+            goto fail;
+        }
+    }
+
+    /* Handle feature bits */
+    s->incompatible_features    = header.incompatible_features;
+    s->compatible_features      = header.compatible_features;
+    s->autoclear_features       = header.autoclear_features;
+
+    if (s->incompatible_features != 0) {
+        report_unsupported(bs, "incompatible features mask %" PRIx64,
+                           header.incompatible_features);
+        ret = -ENOTSUP;
+        goto fail;
+    }
+
+    if (!bs->read_only && s->autoclear_features != 0) {
+        s->autoclear_features = 0;
+        qcow2_update_header(bs);
+    }
+
+    /* Check support for various header values */
+    if (header.refcount_order != 4) {
+        report_unsupported(bs, "%d bit reference counts",
+                           1 << header.refcount_order);
         ret = -ENOTSUP;
         goto fail;
     }
+
     if (header.cluster_bits < MIN_CLUSTER_BITS ||
         header.cluster_bits > MAX_CLUSTER_BITS) {
         ret = -EINVAL;
@@ -285,7 +348,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     } else {
         ext_end = s->cluster_size;
     }
-    if (qcow2_read_extensions(bs, sizeof(header), ext_end)) {
+    if (qcow2_read_extensions(bs, header.header_length, ext_end)) {
         ret = -EINVAL;
         goto fail;
     }
@@ -321,6 +384,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     return ret;
 
  fail:
+    g_free(s->unknown_header_fields);
     cleanup_unknown_header_ext(bs);
     qcow2_free_snapshots(bs);
     qcow2_refcount_close(bs);
@@ -682,7 +746,9 @@ static void qcow2_close(BlockDriverState *bs)
     qcow2_cache_destroy(bs, s->l2_table_cache);
     qcow2_cache_destroy(bs, s->refcount_block_cache);
 
+    g_free(s->unknown_header_fields);
     cleanup_unknown_header_ext(bs);
+
     g_free(s->cluster_cache);
     qemu_vfree(s->cluster_data);
     qcow2_refcount_close(bs);
@@ -756,10 +822,10 @@ int qcow2_update_header(BlockDriverState *bs)
     int ret;
     uint64_t total_size;
     uint32_t refcount_table_clusters;
+    size_t header_length;
     Qcow2UnknownHeaderExtension *uext;
 
     buf = qemu_blockalign(bs, buflen);
-    memset(buf, 0, s->cluster_size);
 
     /* Header structure */
     header = (QCowHeader*) buf;
@@ -769,12 +835,14 @@ int qcow2_update_header(BlockDriverState *bs)
         goto fail;
     }
 
+    header_length = sizeof(*header) + s->unknown_header_fields_size;
     total_size = bs->total_sectors * BDRV_SECTOR_SIZE;
     refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
 
     *header = (QCowHeader) {
+        /* Version 2 fields */
         .magic                  = cpu_to_be32(QCOW_MAGIC),
-        .version                = cpu_to_be32(QCOW_VERSION),
+        .version                = cpu_to_be32(s->qcow_version),
         .backing_file_offset    = 0,
         .backing_file_size      = 0,
         .cluster_bits           = cpu_to_be32(s->cluster_bits),
@@ -786,10 +854,42 @@ int qcow2_update_header(BlockDriverState *bs)
         .refcount_table_clusters = cpu_to_be32(refcount_table_clusters),
         .nb_snapshots           = cpu_to_be32(s->nb_snapshots),
         .snapshots_offset       = cpu_to_be64(s->snapshots_offset),
+
+        /* Version 3 fields */
+        .incompatible_features  = cpu_to_be64(s->incompatible_features),
+        .compatible_features    = cpu_to_be64(s->compatible_features),
+        .autoclear_features     = cpu_to_be64(s->autoclear_features),
+        .refcount_order         = cpu_to_be32(3 + REFCOUNT_SHIFT),
+        .header_length          = cpu_to_be32(header_length),
     };
 
-    buf += sizeof(*header);
-    buflen -= sizeof(*header);
+    /* For older versions, write a shorter header */
+    switch (s->qcow_version) {
+    case 2:
+        ret = offsetof(QCowHeader, incompatible_features);
+        break;
+    case 3:
+        ret = sizeof(*header);
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    buf += ret;
+    buflen -= ret;
+    memset(buf, 0, buflen);
+
+    /* Preserve any unknown field in the header */
+    if (s->unknown_header_fields_size) {
+        if (buflen < s->unknown_header_fields_size) {
+            ret = -ENOSPC;
+            goto fail;
+        }
+
+        memcpy(buf, s->unknown_header_fields, s->unknown_header_fields_size);
+        buf += s->unknown_header_fields_size;
+        buflen -= s->unknown_header_fields_size;
+    }
 
     /* Backing file format header extension */
     if (*bs->backing_format) {
@@ -921,7 +1021,7 @@ static int preallocate(BlockDriverState *bs)
 static int qcow2_create2(const char *filename, int64_t total_size,
                          const char *backing_file, const char *backing_format,
                          int flags, size_t cluster_size, int prealloc,
-                         QEMUOptionParameter *options)
+                         QEMUOptionParameter *options, int version)
 {
     /* Calculate cluster_bits */
     int cluster_bits;
@@ -965,13 +1065,15 @@ static int qcow2_create2(const char *filename, int64_t total_size,
     /* Write the header */
     memset(&header, 0, sizeof(header));
     header.magic = cpu_to_be32(QCOW_MAGIC);
-    header.version = cpu_to_be32(QCOW_VERSION);
+    header.version = cpu_to_be32(version);
     header.cluster_bits = cpu_to_be32(cluster_bits);
     header.size = cpu_to_be64(0);
     header.l1_table_offset = cpu_to_be64(0);
     header.l1_size = cpu_to_be32(0);
     header.refcount_table_offset = cpu_to_be64(cluster_size);
     header.refcount_table_clusters = cpu_to_be32(1);
+    header.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT);
+    header.header_length = cpu_to_be32(sizeof(header));
 
     if (flags & BLOCK_FLAG_ENCRYPT) {
         header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
@@ -1053,6 +1155,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
     int flags = 0;
     size_t cluster_size = DEFAULT_CLUSTER_SIZE;
     int prealloc = 0;
+    int version = 2;
 
     /* Read out options */
     while (options && options->name) {
@@ -1078,6 +1181,16 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
                     options->value.s);
                 return -EINVAL;
             }
+        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) {
+            if (!options->value.s || !strcmp(options->value.s, "0.10")) {
+                version = 2;
+            } else if (!strcmp(options->value.s, "1.1")) {
+                version = 3;
+            } else {
+                fprintf(stderr, "Invalid compatibility level: '%s'\n",
+                    options->value.s);
+                return -EINVAL;
+            }
         }
         options++;
     }
@@ -1089,7 +1202,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
     }
 
     return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
-                         cluster_size, prealloc, options);
+                         cluster_size, prealloc, options, version);
 }
 
 static int qcow2_make_empty(BlockDriverState *bs)
@@ -1341,6 +1454,11 @@ static QEMUOptionParameter qcow2_create_options[] = {
         .help = "Virtual disk size"
     },
     {
+        .name = BLOCK_OPT_COMPAT_LEVEL,
+        .type = OPT_STRING,
+        .help = "Compatibility level (0.10 or 1.1)"
+    },
+    {
         .name = BLOCK_OPT_BACKING_FILE,
         .type = OPT_STRING,
         .help = "File name of a base image"
diff --git a/block/qcow2.h b/block/qcow2.h
index 291309a..2dc8ca2 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -33,7 +33,6 @@
 //#define DEBUG_EXT
 
 #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
-#define QCOW_VERSION 2
 
 #define QCOW_CRYPT_NONE 0
 #define QCOW_CRYPT_AES  1
@@ -71,6 +70,14 @@ typedef struct QCowHeader {
     uint32_t refcount_table_clusters;
     uint32_t nb_snapshots;
     uint64_t snapshots_offset;
+
+    /* The following fields are only valid for version >= 3 */
+    uint64_t incompatible_features;
+    uint64_t compatible_features;
+    uint64_t autoclear_features;
+
+    uint32_t refcount_order;
+    uint32_t header_length;
 } QCowHeader;
 
 typedef struct QCowSnapshot {
@@ -135,6 +142,14 @@ typedef struct BDRVQcowState {
     QCowSnapshot *snapshots;
 
     int flags;
+    int qcow_version;
+
+    uint64_t incompatible_features;
+    uint64_t compatible_features;
+    uint64_t autoclear_features;
+
+    size_t unknown_header_fields_size;
+    void* unknown_header_fields;
     QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
 } BDRVQcowState;
 
diff --git a/block_int.h b/block_int.h
index 0e5a032..0acb49f 100644
--- a/block_int.h
+++ b/block_int.h
@@ -50,6 +50,7 @@
 #define BLOCK_OPT_TABLE_SIZE    "table_size"
 #define BLOCK_OPT_PREALLOC      "preallocation"
 #define BLOCK_OPT_SUBFMT        "subformat"
+#define BLOCK_OPT_COMPAT_LEVEL  "compat"
 
 typedef struct BdrvTrackedRequest BdrvTrackedRequest;
 
commit afdf0abe779f4b11712eb306ab2d4299820457b8
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Mar 27 13:44:56 2012 +0200

    qcow2: Ignore reserved bits in check_refcounts
    
    Also don't infer the cluster type directly from the L2 entries, but use
    qcow2_get_cluster_type() to keep everything in a single place.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index e0854dc..0112cc3 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -940,7 +940,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
     int check_copied)
 {
     BDRVQcowState *s = bs->opaque;
-    uint64_t *l2_table, offset;
+    uint64_t *l2_table, l2_entry;
     int i, l2_size, nb_csectors, refcount;
 
     /* Read L2 table from disk */
@@ -952,54 +952,64 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
 
     /* Do the actual checks */
     for(i = 0; i < s->l2_size; i++) {
-        offset = be64_to_cpu(l2_table[i]);
-        if (offset != 0) {
-            if (offset & QCOW_OFLAG_COMPRESSED) {
-                /* Compressed clusters don't have QCOW_OFLAG_COPIED */
-                if (offset & QCOW_OFLAG_COPIED) {
-                    fprintf(stderr, "ERROR: cluster %" PRId64 ": "
-                        "copied flag must never be set for compressed "
-                        "clusters\n", offset >> s->cluster_bits);
-                    offset &= ~QCOW_OFLAG_COPIED;
-                    res->corruptions++;
-                }
+        l2_entry = be64_to_cpu(l2_table[i]);
+
+        switch (qcow2_get_cluster_type(l2_entry)) {
+        case QCOW2_CLUSTER_COMPRESSED:
+            /* Compressed clusters don't have QCOW_OFLAG_COPIED */
+            if (l2_entry & QCOW_OFLAG_COPIED) {
+                fprintf(stderr, "ERROR: cluster %" PRId64 ": "
+                    "copied flag must never be set for compressed "
+                    "clusters\n", l2_entry >> s->cluster_bits);
+                l2_entry &= ~QCOW_OFLAG_COPIED;
+                res->corruptions++;
+            }
 
-                /* Mark cluster as used */
-                nb_csectors = ((offset >> s->csize_shift) &
-                               s->csize_mask) + 1;
-                offset &= s->cluster_offset_mask;
-                inc_refcounts(bs, res, refcount_table, refcount_table_size,
-                    offset & ~511, nb_csectors * 512);
-            } else {
-                /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
-                if (check_copied) {
-                    uint64_t entry = offset;
-                    offset &= ~QCOW_OFLAG_COPIED;
-                    refcount = get_refcount(bs, offset >> s->cluster_bits);
-                    if (refcount < 0) {
-                        fprintf(stderr, "Can't get refcount for offset %"
-                            PRIx64 ": %s\n", entry, strerror(-refcount));
-                        goto fail;
-                    }
-                    if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
-                        fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
-                            PRIx64 " refcount=%d\n", entry, refcount);
-                        res->corruptions++;
-                    }
-                }
+            /* Mark cluster as used */
+            nb_csectors = ((l2_entry >> s->csize_shift) &
+                           s->csize_mask) + 1;
+            l2_entry &= s->cluster_offset_mask;
+            inc_refcounts(bs, res, refcount_table, refcount_table_size,
+                l2_entry & ~511, nb_csectors * 512);
+            break;
 
-                /* Mark cluster as used */
-                offset &= ~QCOW_OFLAG_COPIED;
-                inc_refcounts(bs, res, refcount_table,refcount_table_size,
-                    offset, s->cluster_size);
+        case QCOW2_CLUSTER_NORMAL:
+        {
+            /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
+            uint64_t offset = l2_entry & L2E_OFFSET_MASK;
 
-                /* Correct offsets are cluster aligned */
-                if (offset & (s->cluster_size - 1)) {
-                    fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
-                        "properly aligned; L2 entry corrupted.\n", offset);
+            if (check_copied) {
+                refcount = get_refcount(bs, offset >> s->cluster_bits);
+                if (refcount < 0) {
+                    fprintf(stderr, "Can't get refcount for offset %"
+                        PRIx64 ": %s\n", l2_entry, strerror(-refcount));
+                    goto fail;
+                }
+                if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
+                    fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
+                        PRIx64 " refcount=%d\n", l2_entry, refcount);
                     res->corruptions++;
                 }
             }
+
+            /* Mark cluster as used */
+            inc_refcounts(bs, res, refcount_table,refcount_table_size,
+                offset, s->cluster_size);
+
+            /* Correct offsets are cluster aligned */
+            if (offset & (s->cluster_size - 1)) {
+                fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
+                    "properly aligned; L2 entry corrupted.\n", offset);
+                res->corruptions++;
+            }
+            break;
+        }
+
+        case QCOW2_CLUSTER_UNALLOCATED:
+            break;
+
+        default:
+            abort();
         }
     }
 
@@ -1070,7 +1080,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
             }
 
             /* Mark L2 table as used */
-            l2_offset &= ~QCOW_OFLAG_COPIED;
+            l2_offset &= L1E_OFFSET_MASK;
             inc_refcounts(bs, res, refcount_table, refcount_table_size,
                 l2_offset, s->cluster_size);
 
commit 76dc9e0c8f369f1695e5413de2e28d69108476bb
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Mar 16 14:09:08 2012 +0100

    qcow2: Ignore reserved bits in refcount table entries
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 909d615..e0854dc 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -167,7 +167,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
     if (refcount_table_index < s->refcount_table_size) {
 
         uint64_t refcount_block_offset =
-            s->refcount_table[refcount_table_index];
+            s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK;
 
         /* If it's already there, we're done */
         if (refcount_block_offset) {
diff --git a/block/qcow2.h b/block/qcow2.h
index a22d7fa..291309a 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -175,6 +175,8 @@ enum {
 #define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
 #define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
 
+#define REFT_OFFSET_MASK 0xffffffffffffff00ULL
+
 static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
 {
     return (size + (s->cluster_size - 1)) >> s->cluster_bits;
commit 143550a83ef4eef86a847d00023d148e1f59f743
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Mar 27 13:17:22 2012 +0200

    qcow2: Simplify count_cow_clusters
    
    count_cow_clusters() tries to reuse existing functions, and all it
    achieves is to make things much more complicated than they really are:
    Everything needs COW, unless it's a normal cluster with refcount 1.
    
    This patch implements the obvious way of doing this, and by using
    qcow2_get_cluster_type() it gets rid of all flag magic.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index d1602d4..b8836ba 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -706,30 +706,27 @@ err:
 static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
     uint64_t *l2_table, int l2_index)
 {
-    int i = 0;
-    uint64_t cluster_offset;
+    int i;
 
-    while (i < nb_clusters) {
-        i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
-                &l2_table[l2_index], i,
-                QCOW_OFLAG_COPIED | QCOW_OFLAG_COMPRESSED);
-        if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
-            break;
-        }
+    for (i = 0; i < nb_clusters; i++) {
+        uint64_t l2_entry = be64_to_cpu(l2_table[l2_index + i]);
+        int cluster_type = qcow2_get_cluster_type(l2_entry);
 
-        i += count_contiguous_free_clusters(nb_clusters - i,
-                &l2_table[l2_index + i]);
-        if (i >= nb_clusters) {
+        switch(cluster_type) {
+        case QCOW2_CLUSTER_NORMAL:
+            if (l2_entry & QCOW_OFLAG_COPIED) {
+                goto out;
+            }
             break;
-        }
-
-        cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
-
-        if ((cluster_offset & QCOW_OFLAG_COPIED) ||
-                (cluster_offset & QCOW_OFLAG_COMPRESSED))
+        case QCOW2_CLUSTER_UNALLOCATED:
+        case QCOW2_CLUSTER_COMPRESSED:
             break;
+        default:
+            abort();
+        }
     }
 
+out:
     assert(i <= nb_clusters);
     return i;
 }
commit c7a4c37a0f768f7ad50f64414d578436019e1e96
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Mar 27 13:09:22 2012 +0200

    qcow2: Refactor qcow2_free_any_clusters
    
    Zero clusters will add another cluster type. Refactor the open-coded
    cluster type detection into a switch of QCOW2_CLUSTER_* options so that
    the detection is in a single place. This makes it easier to add new
    cluster types.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 84fa343..909d615 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -679,31 +679,34 @@ void qcow2_free_clusters(BlockDriverState *bs,
 }
 
 /*
- * free_any_clusters
- *
- * free clusters according to its type: compressed or not
- *
+ * Free a cluster using its L2 entry (handles clusters of all types, e.g.
+ * normal cluster, compressed cluster, etc.)
  */
-
 void qcow2_free_any_clusters(BlockDriverState *bs,
-    uint64_t cluster_offset, int nb_clusters)
+    uint64_t l2_entry, int nb_clusters)
 {
     BDRVQcowState *s = bs->opaque;
 
-    /* free the cluster */
-
-    if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
-        int nb_csectors;
-        nb_csectors = ((cluster_offset >> s->csize_shift) &
-                       s->csize_mask) + 1;
-        qcow2_free_clusters(bs,
-            (cluster_offset & s->cluster_offset_mask) & ~511,
-            nb_csectors * 512);
-        return;
+    switch (qcow2_get_cluster_type(l2_entry)) {
+    case QCOW2_CLUSTER_COMPRESSED:
+        {
+            int nb_csectors;
+            nb_csectors = ((l2_entry >> s->csize_shift) &
+                           s->csize_mask) + 1;
+            qcow2_free_clusters(bs,
+                (l2_entry & s->cluster_offset_mask) & ~511,
+                nb_csectors * 512);
+        }
+        break;
+    case QCOW2_CLUSTER_NORMAL:
+        qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
+                            nb_clusters << s->cluster_bits);
+        break;
+    case QCOW2_CLUSTER_UNALLOCATED:
+        break;
+    default:
+        abort();
     }
-
-    qcow2_free_clusters(bs, cluster_offset & L2E_OFFSET_MASK,
-                        nb_clusters << s->cluster_bits);
 }
 
 
commit 8e37f681d58bbe166c20559e77fd55b1cb8e6e4b
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Feb 23 15:40:55 2012 +0100

    qcow2: Ignore reserved bits in L1/L2 entries
    
    This changes the still existing places that assume that the only flags
    are QCOW_OFLAG_COPIED and QCOW_OFLAG_COMPRESSED to properly mask out
    reserved bits.
    
    It does not convert bdrv_check yet.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index dff782f..d1602d4 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -195,7 +195,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
 
     l2_table = *table;
 
-    if (old_l2_offset == 0) {
+    if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
         /* if there was no old l2 table, clear the new table */
         memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
     } else {
@@ -203,7 +203,8 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
 
         /* if there was an old l2 table, read it from the disk */
         BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
-        ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_offset,
+        ret = qcow2_cache_get(bs, s->l2_table_cache,
+            old_l2_offset & L1E_OFFSET_MASK,
             (void**) &old_table);
         if (ret < 0) {
             goto fail;
@@ -508,13 +509,13 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
             return ret;
         }
     }
-    l2_offset = s->l1_table[l1_index];
+
+    l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
 
     /* seek the l2 table of the given l2 offset */
 
-    if (l2_offset & QCOW_OFLAG_COPIED) {
+    if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
         /* load the l2 table in memory */
-        l2_offset &= ~QCOW_OFLAG_COPIED;
         ret = l2_load(bs, l2_offset, &l2_table);
         if (ret < 0) {
             return ret;
@@ -530,7 +531,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
         if (l2_offset) {
             qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
         }
-        l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
+        l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
     }
 
     /* find the cluster offset for the given disk offset */
@@ -687,8 +688,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
      */
     if (j != 0) {
         for (i = 0; i < j; i++) {
-            qcow2_free_any_clusters(bs,
-                be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
+            qcow2_free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1);
         }
     }
 
@@ -867,7 +867,9 @@ again:
      * Check how many clusters are already allocated and don't need COW, and how
      * many need a new allocation.
      */
-    if (cluster_offset & QCOW_OFLAG_COPIED) {
+    if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
+        && (cluster_offset & QCOW_OFLAG_COPIED))
+    {
         /* We keep all QCOW_OFLAG_COPIED clusters */
         keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
                                                   &l2_table[l2_index], 0,
@@ -886,7 +888,7 @@ again:
         cluster_offset = 0;
     }
 
-    cluster_offset &= ~QCOW_OFLAG_COPIED;
+    cluster_offset &= L2E_OFFSET_MASK;
 
     /* If there is something left to allocate, do that now */
     *m = (QCowL2Meta) {
@@ -1041,9 +1043,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
         uint64_t old_offset;
 
         old_offset = be64_to_cpu(l2_table[l2_index + i]);
-        old_offset &= ~QCOW_OFLAG_COPIED;
-
-        if (old_offset == 0) {
+        if ((old_offset & L2E_OFFSET_MASK) == 0) {
             continue;
         }
 
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 6c38337..84fa343 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -702,9 +702,8 @@ void qcow2_free_any_clusters(BlockDriverState *bs,
         return;
     }
 
-    qcow2_free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits);
-
-    return;
+    qcow2_free_clusters(bs, cluster_offset & L2E_OFFSET_MASK,
+                        nb_clusters << s->cluster_bits);
 }
 
 
@@ -764,7 +763,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
         l2_offset = l1_table[i];
         if (l2_offset) {
             old_l2_offset = l2_offset;
-            l2_offset &= ~QCOW_OFLAG_COPIED;
+            l2_offset &= L1E_OFFSET_MASK;
 
             ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
                 (void**) &l2_table);
@@ -796,10 +795,11 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                         /* compressed clusters are never modified */
                         refcount = 2;
                     } else {
+                        uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
                         if (addend != 0) {
-                            refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
+                            refcount = update_cluster_refcount(bs, cluster_index, addend);
                         } else {
-                            refcount = get_refcount(bs, offset >> s->cluster_bits);
+                            refcount = get_refcount(bs, cluster_index);
                         }
 
                         if (refcount < 0) {
commit b0b6862e5e1a1394e0ab3d5da94ba8b0da8664e2
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Mar 15 17:20:11 2012 +0100

    qcow2: Fail write_compressed when overwriting data
    
    qcow2_alloc_compressed_cluster_offset() already fails if the copied flag
    is set, because qcow2_write_compressed() doesn't perform COW as it would
    have to do to allow this.
    
    However, what we really want to check here is whether the cluster is
    allocated or not. With internal snapshots the copied flag may not be set
    on allocated clusters. Check the cluster offset instead.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 7b05990..dff782f 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -571,15 +571,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
         return 0;
     }
 
+    /* Compression can't overwrite anything. Fail if the cluster was already
+     * allocated. */
     cluster_offset = be64_to_cpu(l2_table[l2_index]);
-    if (cluster_offset & QCOW_OFLAG_COPIED) {
+    if (cluster_offset & L2E_OFFSET_MASK) {
         qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
         return 0;
     }
 
-    if (cluster_offset)
-        qcow2_free_any_clusters(bs, cluster_offset, 1);
-
     cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
     if (cluster_offset < 0) {
         qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
commit 2bfcc4a0a0b5120b6518e1c823c18cf0e8b963cb
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Mar 15 16:37:40 2012 +0100

    qcow2: Ignore reserved bits in count_contiguous_clusters()
    
    Until now, count_contiguous_clusters() has an argument that allowed to
    specify flags that should be ignored in the comparison, i.e. that are
    allowed to change between contiguous clusters.
    
    This patch changes the function so that it ignores all flags by default
    now and you need to pass the flags on which it should stop.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index c8c85d2..7b05990 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -246,28 +246,44 @@ fail:
     return ret;
 }
 
+/*
+ * Checks how many clusters in a given L2 table are contiguous in the image
+ * file. As soon as one of the flags in the bitmask stop_flags changes compared
+ * to the first cluster, the search is stopped and the cluster is not counted
+ * as contiguous. (This allows it, for example, to stop at the first compressed
+ * cluster which may require a different handling)
+ */
 static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
-        uint64_t *l2_table, uint64_t start, uint64_t mask)
+        uint64_t *l2_table, uint64_t start, uint64_t stop_flags)
 {
     int i;
-    uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
+    uint64_t mask = stop_flags | L2E_OFFSET_MASK;
+    uint64_t offset = be64_to_cpu(l2_table[0]) & mask;
 
     if (!offset)
         return 0;
 
-    for (i = start; i < start + nb_clusters; i++)
-        if (offset + (uint64_t) i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
+    for (i = start; i < start + nb_clusters; i++) {
+        uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
+        if (offset + (uint64_t) i * cluster_size != l2_entry) {
             break;
+        }
+    }
 
 	return (i - start);
 }
 
 static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
 {
-    int i = 0;
+    int i;
 
-    while(nb_clusters-- && l2_table[i] == 0)
-        i++;
+    for (i = 0; i < nb_clusters; i++) {
+        int type = qcow2_get_cluster_type(be64_to_cpu(l2_table[i]));
+
+        if (type != QCOW2_CLUSTER_UNALLOCATED) {
+            break;
+        }
+    }
 
     return i;
 }
@@ -444,7 +460,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
     case QCOW2_CLUSTER_NORMAL:
         /* how many allocated clusters ? */
         c = count_contiguous_clusters(nb_clusters, s->cluster_size,
-                &l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
+                &l2_table[l2_index], 0, QCOW_OFLAG_COMPRESSED);
         *cluster_offset &= L2E_OFFSET_MASK;
         break;
     }
@@ -696,7 +712,8 @@ static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
 
     while (i < nb_clusters) {
         i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
-                &l2_table[l2_index], i, 0);
+                &l2_table[l2_index], i,
+                QCOW_OFLAG_COPIED | QCOW_OFLAG_COMPRESSED);
         if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
             break;
         }
@@ -854,7 +871,8 @@ again:
     if (cluster_offset & QCOW_OFLAG_COPIED) {
         /* We keep all QCOW_OFLAG_COPIED clusters */
         keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
-                                                  &l2_table[l2_index], 0, 0);
+                                                  &l2_table[l2_index], 0,
+                                                  QCOW_OFLAG_COPIED);
         assert(keep_clusters <= nb_clusters);
         nb_clusters -= keep_clusters;
     } else {
commit 68d000a39074fe3888680491444a7fde2354cd84
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Mar 14 19:15:03 2012 +0100

    qcow2: Ignore reserved bits in get_cluster_offset
    
    With this change, reading from a qcow2 image ignores all reserved bits
    that are set in an L1 or L2 table entry.
    
    Now get_cluster_offset() assigns *cluster_offset only the offset without
    any other flags. The cluster type is not longer encoded in the offset,
    but a positive return value in case of success.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index dcf70a2..c8c85d2 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -367,11 +367,9 @@ out:
  *
  * on exit, *num is the number of contiguous sectors we can read.
  *
- * Return 0, if the offset is found
- * Return -errno, otherwise.
- *
+ * Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
+ * cases.
  */
-
 int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
     int *num, uint64_t *cluster_offset)
 {
@@ -407,19 +405,19 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
     /* seek the the l2 offset in the l1 table */
 
     l1_index = offset >> l1_bits;
-    if (l1_index >= s->l1_size)
+    if (l1_index >= s->l1_size) {
+        ret = QCOW2_CLUSTER_UNALLOCATED;
         goto out;
+    }
 
-    l2_offset = s->l1_table[l1_index];
-
-    /* seek the l2 table of the given l2 offset */
-
-    if (!l2_offset)
+    l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
+    if (!l2_offset) {
+        ret = QCOW2_CLUSTER_UNALLOCATED;
         goto out;
+    }
 
     /* load the l2 table in memory */
 
-    l2_offset &= ~QCOW_OFLAG_COPIED;
     ret = l2_load(bs, l2_offset, &l2_table);
     if (ret < 0) {
         return ret;
@@ -431,26 +429,37 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
     *cluster_offset = be64_to_cpu(l2_table[l2_index]);
     nb_clusters = size_to_clusters(s, nb_needed << 9);
 
-    if (!*cluster_offset) {
+    ret = qcow2_get_cluster_type(*cluster_offset);
+    switch (ret) {
+    case QCOW2_CLUSTER_COMPRESSED:
+        /* Compressed clusters can only be processed one by one */
+        c = 1;
+        *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
+        break;
+    case QCOW2_CLUSTER_UNALLOCATED:
         /* how many empty clusters ? */
         c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
-    } else {
+        *cluster_offset = 0;
+        break;
+    case QCOW2_CLUSTER_NORMAL:
         /* how many allocated clusters ? */
         c = count_contiguous_clusters(nb_clusters, s->cluster_size,
                 &l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
+        *cluster_offset &= L2E_OFFSET_MASK;
+        break;
     }
 
     qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
 
-   nb_available = (c * s->cluster_sectors);
+    nb_available = (c * s->cluster_sectors);
+
 out:
     if (nb_available > nb_needed)
         nb_available = nb_needed;
 
     *num = nb_available - index_in_cluster;
 
-    *cluster_offset &=~QCOW_OFLAG_COPIED;
-    return 0;
+    return ret;
 }
 
 /*
diff --git a/block/qcow2.c b/block/qcow2.c
index 70d3141..4c82adc 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -449,7 +449,8 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
         qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
             cur_nr_sectors * 512);
 
-        if (!cluster_offset) {
+        switch (ret) {
+        case QCOW2_CLUSTER_UNALLOCATED:
 
             if (bs->backing_hd) {
                 /* read from the base image */
@@ -469,7 +470,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
                 /* Note: in this case, no need to wait */
                 qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
             }
-        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+            break;
+
+        case QCOW2_CLUSTER_COMPRESSED:
             /* add AIO support for compressed blocks ? */
             ret = qcow2_decompress_cluster(bs, cluster_offset);
             if (ret < 0) {
@@ -479,7 +482,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
             qemu_iovec_from_buffer(&hd_qiov,
                 s->cluster_cache + index_in_cluster * 512,
                 512 * cur_nr_sectors);
-        } else {
+            break;
+
+        case QCOW2_CLUSTER_NORMAL:
             if ((cluster_offset & 511) != 0) {
                 ret = -EIO;
                 goto fail;
@@ -520,6 +525,12 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
                 qemu_iovec_from_buffer(&hd_qiov, cluster_data,
                     512 * cur_nr_sectors);
             }
+            break;
+
+        default:
+            g_assert_not_reached();
+            ret = -EIO;
+            goto fail;
         }
 
         remaining_sectors -= cur_nr_sectors;
diff --git a/block/qcow2.h b/block/qcow2.h
index ddb976a..a22d7fa 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -165,6 +165,16 @@ typedef struct QCowL2Meta
     QLIST_ENTRY(QCowL2Meta) next_in_flight;
 } QCowL2Meta;
 
+enum {
+    QCOW2_CLUSTER_UNALLOCATED,
+    QCOW2_CLUSTER_NORMAL,
+    QCOW2_CLUSTER_COMPRESSED,
+};
+
+#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
+#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
+#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
+
 static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
 {
     return (size + (s->cluster_size - 1)) >> s->cluster_bits;
@@ -182,6 +192,17 @@ static inline int64_t align_offset(int64_t offset, int n)
     return offset;
 }
 
+static inline int qcow2_get_cluster_type(uint64_t l2_entry)
+{
+    if (l2_entry & QCOW_OFLAG_COMPRESSED) {
+        return QCOW2_CLUSTER_COMPRESSED;
+    } else if (!(l2_entry & L2E_OFFSET_MASK)) {
+        return QCOW2_CLUSTER_UNALLOCATED;
+    } else {
+        return QCOW2_CLUSTER_NORMAL;
+    }
+}
+
 
 // FIXME Need qcow2_ prefix to global functions
 
commit 90b277593df873d3a2480f002e2eb5fe1f8e5277
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Apr 11 16:33:50 2012 +0200

    qcow2: Save disk size in snapshot header
    
    This allows that different snapshots of an image can have different
    sizes, which is a requirement for enabling image resizing even with
    images that have internal snapshots.
    
    We don't do the actual support for it now, but make sure that the
    additional field is present and not completely ignored in all version 3
    images. When trying to load a snapshot of different size, it returns
    an error.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 7d3fde5..42f971b 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -48,6 +48,7 @@ typedef struct QEMU_PACKED QCowSnapshotHeader {
 
 typedef struct QEMU_PACKED QCowSnapshotExtraData {
     uint64_t vm_state_size_large;
+    uint64_t disk_size;
 } QCowSnapshotExtraData;
 
 void qcow2_free_snapshots(BlockDriverState *bs)
@@ -117,6 +118,12 @@ int qcow2_read_snapshots(BlockDriverState *bs)
             sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
         }
 
+        if (extra_data_size >= 16) {
+            sn->disk_size = be64_to_cpu(extra.disk_size);
+        } else {
+            sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
+        }
+
         /* Read snapshot ID */
         sn->id_str = g_malloc(id_str_size + 1);
         ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
@@ -197,6 +204,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
 
         memset(&extra, 0, sizeof(extra));
         extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
+        extra.disk_size = cpu_to_be64(sn->disk_size);
 
         id_str_size = strlen(sn->id_str);
         name_size = strlen(sn->name);
@@ -330,6 +338,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     sn->id_str = g_strdup(sn_info->id_str);
     sn->name = g_strdup(sn_info->name);
 
+    sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
     sn->vm_state_size = sn_info->vm_state_size;
     sn->date_sec = sn_info->date_sec;
     sn->date_nsec = sn_info->date_nsec;
@@ -426,6 +435,13 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     }
     sn = &s->snapshots[snapshot_index];
 
+    if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
+        error_report("qcow2: Loading snapshots with different disk "
+            "size is not implemented");
+        ret = -ENOTSUP;
+        goto fail;
+    }
+
     /*
      * Make sure that the current L1 table is big enough to contain the whole
      * L1 table of the snapshot. If the snapshot L1 table is smaller, the
diff --git a/block/qcow2.h b/block/qcow2.h
index e4ac366..ddb976a 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -78,6 +78,7 @@ typedef struct QCowSnapshot {
     uint32_t l1_size;
     char *id_str;
     char *name;
+    uint64_t disk_size;
     uint64_t vm_state_size;
     uint32_t date_sec;
     uint32_t date_nsec;
commit 4fabffc11234d0587a213418574095e036110cd2
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Apr 12 13:20:41 2012 +0200

    Specification for qcow2 version 3
    
    This updates the qcow2 specification to cover version 3. It contains the
    following changes:
    
    - Added compatible/incompatible/auto-clear feature bits plus an optional
      feature name table to allow useful error messages even if an older
      version doesn't know some feature at all.
    
    - Configurable refcount width. If you don't want to use internal
      snapshots, make refcounts one bit and save cache space and I/O.
    
    - Zero cluster flags. This allows discard even with a backing file that
      doesn't contain zeros. It is also useful for copy-on-read/image
      streaming, as you'll want to keep sparseness without accessing the
      remote image for an unallocated cluster all the time.
    
    - Fixed internal snapshot metadata to use 64 bit VM state size. You
      can't save a snapshot of a VM with >= 4 GB RAM today.
    
    - Extended internal snapshot metadata to contain the disk size, so that
      resizing images that have snapshots can be allowed in the future.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
index b6adcad..65e6325 100644
--- a/docs/specs/qcow2.txt
+++ b/docs/specs/qcow2.txt
@@ -18,7 +18,7 @@ The first cluster of a qcow2 image contains the file header:
                     QCOW magic string ("QFI\xfb")
 
           4 -  7:   version
-                    Version number (only valid value is 2)
+                    Version number (valid values are 2 and 3)
 
           8 - 15:   backing_file_offset
                     Offset into the image file at which the backing file name
@@ -67,12 +67,45 @@ The first cluster of a qcow2 image contains the file header:
                     Offset into the image file at which the snapshot table
                     starts. Must be aligned to a cluster boundary.
 
+If the version is 3 or higher, the header has the following additional fields.
+For version 2, the values are assumed to be zero, unless specified otherwise
+in the description of a field.
+
+         72 -  79:  incompatible_features
+                    Bitmask of incompatible features. An implementation must
+                    fail to open an image if an unknown bit is set.
+
+                    Bits 0-63:  Reserved (set to 0)
+
+         80 -  87:  compatible_features
+                    Bitmask of compatible features. An implementation can
+                    safely ignore any unknown bits that are set.
+
+                    Bits 0-63:  Reserved (set to 0)
+
+         88 -  95:  autoclear_features
+                    Bitmask of auto-clear features. An implementation may only
+                    write to an image with unknown auto-clear features if it
+                    clears the respective bits from this field first.
+
+                    Bits 0-63:  Reserved (set to 0)
+
+         96 -  99:  refcount_order
+                    Describes the width of a reference count block entry (width
+                    in bits = 1 << refcount_order). For version 2 images, the
+                    order is always assumed to be 4 (i.e. the width is 16 bits).
+
+        100 - 103:  header_length
+                    Length of the header structure in bytes. For version 2
+                    images, the length is always assumed to be 72 bytes.
+
 Directly after the image header, optional sections called header extensions can
 be stored. Each extension has a structure like the following:
 
     Byte  0 -  3:   Header extension type:
                         0x00000000 - End of the header extension area
                         0xE2792ACA - Backing file format name
+                        0x6803f857 - Feature name table
                         other      - Unknown header extension, can be safely
                                      ignored
 
@@ -83,9 +116,37 @@ be stored. Each extension has a structure like the following:
           n -  m:   Padding to round up the header extension size to the next
                     multiple of 8.
 
+Unless stated otherwise, each header extension type shall appear at most once
+in the same image.
+
 The remaining space between the end of the header extension area and the end of
-the first cluster can be used for other data. Usually, the backing file name is
-stored there.
+the first cluster can be used for the backing file name. It is not allowed to
+store other data here, so that an implementation can safely modify the header
+and add extensions without harming data of compatible features that it
+doesn't support. Compatible features that need space for additional data can
+use a header extension.
+
+
+== Feature name table ==
+
+The feature name table is an optional header extension that contains the name
+for features used by the image. It can be used by applications that don't know
+the respective feature (e.g. because the feature was introduced only later) to
+display a useful error message.
+
+The number of entries in the feature name table is determined by the length of
+the header extension data. Each entry look like this:
+
+    Byte       0:   Type of feature (select feature bitmap)
+                        0: Incompatible feature
+                        1: Compatible feature
+                        2: Autoclear feature
+
+               1:   Bit number within the selected feature bitmap (valid
+                    values: 0-63)
+
+          2 - 47:   Feature name (padded with zeros, but not necessarily null
+                    terminated if it has full length)
 
 
 == Host cluster management ==
@@ -126,9 +187,11 @@ Refcount table entry:
                     been allocated. All refcounts managed by this refcount block
                     are 0.
 
-Refcount block entry:
+Refcount block entry (x = refcount_bits - 1):
 
-    Bit  0 - 15:    Reference count of the cluster
+    Bit  0 -  x:    Reference count of the cluster. If refcount_bits implies a
+                    sub-byte width, note that bit 0 means the least significant
+                    bit in this context.
 
 
 == Cluster mapping ==
@@ -168,9 +231,29 @@ L1 table entry:
                     refcount is exactly one. This information is only accurate
                     in the active L1 table.
 
-L2 table entry (for normal clusters):
+L2 table entry:
 
-    Bit  0 -  8:    Reserved (set to 0)
+    Bit  0 -  61:   Cluster descriptor
+
+              62:   0 for standard clusters
+                    1 for compressed clusters
+
+              63:   0 for a cluster that is unused or requires COW, 1 if its
+                    refcount is exactly one. This information is only accurate
+                    in L2 tables that are reachable from the the active L1
+                    table.
+
+Standard Cluster Descriptor:
+
+    Bit       0:    If set to 1, the cluster reads as all zeros. The host
+                    cluster offset can be used to describe a preallocation,
+                    but it won't be used for reading data from this cluster,
+                    nor is data read from the backing file if the cluster is
+                    unallocated.
+
+                    With version 2, this is always 0.
+
+         1 -  8:    Reserved (set to 0)
 
          9 - 55:    Bits 9-55 of host cluster offset. Must be aligned to a
                     cluster boundary. If the offset is 0, the cluster is
@@ -178,30 +261,18 @@ L2 table entry (for normal clusters):
 
         56 - 61:    Reserved (set to 0)
 
-             62:    0 (this cluster is not compressed)
 
-             63:    0 for a cluster that is unused or requires COW, 1 if its
-                    refcount is exactly one. This information is only accurate
-                    in L2 tables that are reachable from the the active L1
-                    table.
-
-L2 table entry (for compressed clusters; x = 62 - (cluster_size - 8)):
+Compressed Clusters Descriptor (x = 62 - (cluster_size - 8)):
 
     Bit  0 -  x:    Host cluster offset. This is usually _not_ aligned to a
                     cluster boundary!
 
        x+1 - 61:    Compressed size of the images in sectors of 512 bytes
 
-             62:    1 (this cluster is compressed using zlib)
-
-             63:    0 for a cluster that is unused or requires COW, 1 if its
-                    refcount is exactly one. This information is only accurate
-                    in L2 tables that are reachable from the the active L1
-                    table.
-
 If a cluster is unallocated, read requests shall read the data from the backing
-file. If there is no backing file or the backing file is smaller than the image,
-they shall read zeros for all parts that are not covered by the backing file.
+file (except if bit 0 in the Standard Cluster Descriptor is set). If there is
+no backing file or the backing file is smaller than the image, they shall read
+zeros for all parts that are not covered by the backing file.
 
 
 == Snapshots ==
@@ -261,6 +332,11 @@ Snapshot table entry:
                                     state is saved. If this field is present,
                                     the 32-bit value in bytes 32-35 is ignored.
 
+                    Byte 48 - 55:   Virtual disk size of the snapshot in bytes
+
+                    Version 3 images must include extra data at least up to
+                    byte 55.
+
         variable:   Unique ID string for the snapshot (not null terminated)
 
         variable:   Name of the snapshot (not null terminated)
commit f24423bd902bce29bc546cf8d030bfa369726ab1
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Apr 20 15:50:39 2012 +0200

    qcow2: Fix refcount block allocation during qcow2_alloc_cluster_at()
    
    Refcount block allocation and refcount table growth rely on
    s->free_cluster_index pointing to somewhere after the current
    allocation. Change qcow2_alloc_cluster_at() to fulfill this
    assumption.
    
    Without this change it could happen that a newly allocated refcount
    block and the allocated data block point to the same area in the image
    file, causing data corruption in the long run.
    
    This fixes a bug that became first visible after commit 250196f1.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 565bd54..6c38337 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -587,6 +587,7 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
 {
     BDRVQcowState *s = bs->opaque;
     uint64_t cluster_index;
+    uint64_t old_free_cluster_index;
     int i, refcount, ret;
 
     /* Check how many clusters there are free */
@@ -602,11 +603,16 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
     }
 
     /* And then allocate them */
+    old_free_cluster_index = s->free_cluster_index;
+    s->free_cluster_index = cluster_index + i;
+
     ret = update_refcount(bs, offset, i << s->cluster_bits, 1);
     if (ret < 0) {
         return ret;
     }
 
+    s->free_cluster_index = old_free_cluster_index;
+
     return i;
 }
 
commit fecccc4477451f82028c042eb700a20185d8cf65
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Fri Apr 20 11:40:24 2012 +1000

    Add .gitignore for tests/
    
    The new autotests in tests/ generate a number of files, both
    executable and source, which are not caught by the existing .gitignore
    files.  This patch adds a new .gitignore in tests/ which covers these.
    
    [Changed 'rtc-test' to '*-test' so future tests do not need to be added
    to .gitignore on a case-by-case basis.  Stefan]
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..f9041f3
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,13 @@
+check-qdict
+check-qfloat
+check-qint
+check-qjson
+check-qlist
+check-qstring
+test-qapi-types.[ch]
+test-qapi-visit.[ch]
+test-qmp-commands.h
+test-qmp-commands
+test-qmp-input-strict
+test-qmp-marshal.c
+*-test
commit 362f5fb5643a9cfcf4b5127f67af8dcb0fcb9130
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Apr 18 07:28:34 2012 +0200

    e1000: Fix spelling (segmentaion -> segmentation) in debug output
    
    This was reported by https://bugs.launchpad.net/qemu/+bug/984476.
    
    I also changed the case for 'error'.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/e1000.c b/hw/e1000.c
index 7babc0b..9c76462 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -481,7 +481,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
         } while (split_size -= bytes);
     } else if (!tp->tse && tp->cptse) {
         // context descriptor TSE is not set, while data descriptor TSE is set
-        DBGOUT(TXERR, "TCP segmentaion Error\n");
+        DBGOUT(TXERR, "TCP segmentation error\n");
     } else {
         split_size = MIN(sizeof(tp->data) - tp->size, split_size);
         pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
commit 4f5c0177381e066604a5fe1ffe9a69a0759fa4bb
Author: Eduardo Elias Ferreira <edusf at linux.vnet.ibm.com>
Date:   Mon Apr 16 09:51:42 2012 -0300

    spice-qemu-char.c: Show what name is unsupported
    
    Signed-off-by: Eduardo Elias Ferreira <edusf at linux.vnet.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 1e735ff..09aa22d 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -209,7 +209,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
         }
     }
     if (subtype == NULL) {
-        fprintf(stderr, "spice-qemu-char: unsupported name\n");
+        fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name);
         print_allowed_subtypes();
         return NULL;
     }
commit 4d6145488c84df52a2a0a20e3f36493d7417042a
Author: Eric Bénard <eric at eukrea.com>
Date:   Thu Apr 12 09:51:46 2012 +0200

    pflash_cfi01: remove redundant line
    
    Signed-off-by: Eric Bénard <eric at eukrea.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index b03f623..d1c7423 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -144,7 +144,6 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
             } else {
                 ret = p[offset];
                 ret |= p[offset + 1] << 8;
-                ret |= p[offset + 1] << 8;
                 ret |= p[offset + 2] << 16;
                 ret |= p[offset + 3] << 24;
             }
commit 5f8daf2e04709800531bc1ecbb7b49b637182777
Author: Stefan Weil <sw at weilnetz.de>
Date:   Sun Apr 1 22:07:30 2012 +0200

    qxl: Add missing GCC_FMT_ATTR and fix format specifier
    
    val is an uint64_t, therefore %d was not correct.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Acked-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index db2318e..c3540c3 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1370,7 +1370,7 @@ async_common:
     case QXL_IO_DESTROY_SURFACE_WAIT:
         if (val >= NUM_SURFACES) {
             qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
-                             "%d >= NUM_SURFACES", async, val);
+                             "%" PRIu64 " >= NUM_SURFACES", async, val);
             goto cancel_async;
         }
         qxl_spice_destroy_surface_wait(d, val, async);
diff --git a/hw/qxl.h b/hw/qxl.h
index 11a0db3..cbb1e2d 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -127,7 +127,7 @@ typedef struct PCIQXLDevice {
 
 /* qxl.c */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) GCC_FMT_ATTR(2, 3);
 
 void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
                            struct QXLRect *area, struct QXLRect *dirty_rects,
commit 4451b799626207ba66df78257fdf08c740cda6ae
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Apr 13 12:03:46 2012 +0200

    fix block_job_set_speed name in documentation
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index a6f5a84..461fa59 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -92,8 +92,8 @@ ETEXI
     },
 
 STEXI
- at item block_job_set_stream
- at findex block_job_set_stream
+ at item block_job_set_speed
+ at findex block_job_set_speed
 Set maximum speed for a background block operation.
 ETEXI
 
commit 0ed6dc1a982fd029557a17fda7606d679a6ebb28
Author: Amos Kong <akong at redhat.com>
Date:   Mon Apr 16 15:32:49 2012 +0800

    error.c: don't return value for void function
    
    It is invalid to return a value from a function
    returning void.
    
    [C99 6.8.6.4 says "A return statement with an expression shall not
    appear in a function whose return type is void" but gcc 4.6.3 with QEMU
    compile flags does not complain.  It's still worth fixing this.  Stefan]
    
    Signed-off-by: Amos Kong <akong at redhat.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/error.c b/error.c
index d3455ab..a52b771 100644
--- a/error.c
+++ b/error.c
@@ -93,7 +93,7 @@ QDict *error_get_data(Error *err)
 void error_set_field(Error *err, const char *field, const char *value)
 {
     QDict *dict = qdict_get_qdict(err->obj, "data");
-    return qdict_put(dict, field, qstring_from_str(value));
+    qdict_put(dict, field, qstring_from_str(value));
 }
 
 void error_free(Error *err)
commit 29926112a2fd619abedd8e21002f5d50c476b402
Author: Andreas Färber <afaerber at suse.de>
Date:   Fri Apr 20 12:50:24 2012 +0200

    iotests: Resolve test failures caused by hostname
    
    `hostname -s` may output an errror:
    hostname: Name or service not known
    This causes all tests to fail for `make check-block`.
    
    Suppress such error messages, letting the tests succeed.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
index a220684..df082e7 100644
--- a/tests/qemu-iotests/common.config
+++ b/tests/qemu-iotests/common.config
@@ -36,7 +36,7 @@ export LANG=C
 
 PATH=".:$PATH"
 
-HOST=`hostname -s`
+HOST=`hostname -s 2> /dev/null`
 HOSTOS=`uname -s`
 
 EMAIL=root at localhost    # where auto-qa will send its status messages
commit 80ccf93b884a2edab5ec62634758e942bba81b7c
Author: Liu Yuan <tailai.ly at taobao.com>
Date:   Fri Apr 20 17:10:56 2012 +0800

    qemu-img: let 'qemu-img convert' flush data
    
    The 'qemu-img convert -h' advertise that the default cache mode is
    'writeback', while in fact it is 'unsafe'.
    
    This patch 1) fix the help manual and 2) let bdrv_close() call bdrv_flush()
    
    2) is needed because some backend storage doesn't have a self-flush
    mechanism(for e.g., sheepdog), so we need to call bdrv_flush() to make
    sure the image is really writen to the storage instead of hanging around
    writeback cache forever.
    
    Signed-off-by: Liu Yuan <tailai.ly at taobao.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 4b96654..421cd1b 100644
--- a/block.c
+++ b/block.c
@@ -812,6 +812,7 @@ unlink_and_fail:
 
 void bdrv_close(BlockDriverState *bs)
 {
+    bdrv_flush(bs);
     if (bs->drv) {
         if (bs->job) {
             block_job_cancel_sync(bs->job);
diff --git a/qemu-img.c b/qemu-img.c
index 6a61ca8..0ae543c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -66,8 +66,8 @@ static void help(void)
            "  'filename' is a disk image filename\n"
            "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
            "  'cache' is the cache mode used to write the output disk image, the valid\n"
-           "    options are: 'none', 'writeback' (default), 'writethrough', 'directsync'\n"
-           "    and 'unsafe'\n"
+           "    options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
+           "    'directsync' and 'unsafe' (default for convert)\n"
            "  'size' is the disk image size in bytes. Optional suffixes\n"
            "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
            "    and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
commit 90449c388711c3defdc76da490926d1eca177b06
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Thu Apr 19 18:33:05 2012 +0000

    sparc: fix qtest
    
    Initialize TCG only when enabled.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 24f90f1..7ac6bdb 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -119,7 +119,9 @@ CPUSPARCState *cpu_sparc_init(const char *cpu_model)
     cpu = SPARC_CPU(object_new(TYPE_SPARC_CPU));
     env = &cpu->env;
 
-    gen_intermediate_code_init(env);
+    if (tcg_enabled()) {
+        gen_intermediate_code_init(env);
+    }
 
     if (cpu_sparc_register(env, cpu_model) < 0) {
         object_delete(OBJECT(cpu));
commit e776bffb53973619e93e805fa441bd5f3d999e27
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Thu Apr 19 18:52:35 2012 +0000

    qtest: add dummy functions for user emulators
    
    Allow qtest to be used also in files used for user emulators by
    introducing dummy functions.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/qtest.h b/qtest.h
index 1478343..723a4f9 100644
--- a/qtest.h
+++ b/qtest.h
@@ -16,6 +16,7 @@
 
 #include "qemu-common.h"
 
+#if !defined(CONFIG_USER_ONLY)
 extern int qtest_allowed;
 extern const char *qtest_chrdev;
 extern const char *qtest_log;
@@ -31,5 +32,22 @@ static inline int qtest_available(void)
 }
 
 int qtest_init(void);
+#else
+static inline bool qtest_enabled(void)
+{
+    return false;
+}
+
+static inline int qtest_available(void)
+{
+    return 0;
+}
+
+static inline int qtest_init(void)
+{
+    return 0;
+}
+
+#endif
 
 #endif
commit 85215d419b17aeedbfe93ff8d739b27937f72739
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Apr 15 07:36:49 2012 +0000

    qtest: add register fuzzing to RTC test
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index 983a980..f23ac3a 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -240,6 +240,22 @@ static void alarm_time(void)
     g_assert(cmos_read(RTC_REG_C) == 0);
 }
 
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+    unsigned int i;
+
+    for (i = 0; i < 1000; i++) {
+        uint8_t reg, val;
+
+        reg = (uint8_t)g_test_rand_int_range(0, 16);
+        val = (uint8_t)g_test_rand_int_range(0, 256);
+
+        cmos_write(reg, val);
+        cmos_read(reg);
+    }
+}
+
 int main(int argc, char **argv)
 {
     QTestState *s = NULL;
@@ -253,6 +269,7 @@ int main(int argc, char **argv)
     qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
     qtest_add_func("/rtc/dec/check-time", dec_check_time);
     qtest_add_func("/rtc/alarm-time", alarm_time);
+    qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
     ret = g_test_run();
 
     if (s) {
commit 4bdd04165a50899d8700d8009a3e044f88ade45f
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Tue Apr 17 11:28:27 2012 -0500

    qemu-ga: fix help output
    
    Reviewed-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qemu-ga.c b/qemu-ga.c
index d6f786e..74a1b02 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -117,12 +117,13 @@ static gboolean register_signal_handlers(void)
 static void usage(const char *cmd)
 {
     printf(
-"Usage: %s -c <channel_opts>\n"
+"Usage: %s [-m <method> -p <path>] [<options>]\n"
 "QEMU Guest Agent %s\n"
 "\n"
 "  -m, --method      transport method: one of unix-listen, virtio-serial, or\n"
 "                    isa-serial (virtio-serial is the default)\n"
-"  -p, --path        device/socket path (%s is the default for virtio-serial)\n"
+"  -p, --path        device/socket path (the default for virtio-serial is:\n"
+"                    %s)\n"
 "  -l, --logfile     set logfile path, logs to stderr by default\n"
 "  -f, --pidfile     specify pidfile (default is %s)\n"
 "  -v, --verbose     log extra debugging information\n"
@@ -131,7 +132,7 @@ static void usage(const char *cmd)
 #ifdef _WIN32
 "  -s, --service     service commands: install, uninstall\n"
 #endif
-"  -b, --blacklist   comma-separated list of RPCs to disable (no spaces, \"?\""
+"  -b, --blacklist   comma-separated list of RPCs to disable (no spaces, \"?\"\n"
 "                    to list available RPCs)\n"
 "  -h, --help        display this help and exit\n"
 "\n"
commit d35d4cb5175f75e503ee9da0b67ffbe22e8d63ab
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Fri Apr 13 21:07:36 2012 -0500

    qemu-ga: generate missing stubs for fsfreeze
    
    When linux-specific commands (including guest-fsfreeze-*) were consolidated
    under defined(__linux__), we forgot to account for the case where
    defined(__linux__) && !defined(FIFREEZE). As a result stubs are no longer
    being generated on linux hosts that don't have FIFREEZE support. Fix
    this.
    
    Tested-by: Andreas Färber <afaerber at suse.de>
    Reviewed-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index faf970d..087c3af 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -881,46 +881,50 @@ error:
 
 #else /* defined(__linux__) */
 
-GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+void qmp_guest_suspend_disk(Error **err)
 {
     error_set(err, QERR_UNSUPPORTED);
-
-    return 0;
 }
 
-int64_t qmp_guest_fsfreeze_freeze(Error **err)
+void qmp_guest_suspend_ram(Error **err)
 {
     error_set(err, QERR_UNSUPPORTED);
-
-    return 0;
 }
 
-int64_t qmp_guest_fsfreeze_thaw(Error **err)
+void qmp_guest_suspend_hybrid(Error **err)
 {
     error_set(err, QERR_UNSUPPORTED);
-
-    return 0;
 }
 
-void qmp_guest_suspend_disk(Error **err)
+GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
 {
-    error_set(err, QERR_UNSUPPORTED);
+    error_set(errp, QERR_UNSUPPORTED);
+    return NULL;
 }
 
-void qmp_guest_suspend_ram(Error **err)
+#endif
+
+#if !defined(CONFIG_FSFREEZE)
+
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
 {
     error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
 }
 
-void qmp_guest_suspend_hybrid(Error **err)
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
 {
     error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
 }
 
-GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
 {
-    error_set(errp, QERR_UNSUPPORTED);
-    return NULL;
+    error_set(err, QERR_UNSUPPORTED);
+
+    return 0;
 }
 
 #endif
commit e25ceb76e5b90ec4197cbe1cb859200bf6ee1284
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 11:59:11 2012 +0200

    nbd: obey FUA on reads
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/nbd.c b/nbd.c
index d4dafc6..153709f 100644
--- a/nbd.c
+++ b/nbd.c
@@ -842,6 +842,15 @@ static void nbd_trip(void *opaque)
     case NBD_CMD_READ:
         TRACE("Request type is READ");
 
+        if (request.type & NBD_CMD_FLAG_FUA) {
+            ret = bdrv_co_flush(exp->bs);
+            if (ret < 0) {
+                LOG("flush failed");
+                reply.error = -ret;
+                goto error_reply;
+            }
+        }
+
         ret = bdrv_read(exp->bs, (request.from + exp->dev_offset) / 512,
                         req->data, request.len / 512);
         if (ret < 0) {
commit 38ceff0412621a35fa618fb46cd7f0f6ff037c13
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Mar 12 16:17:27 2012 +0100

    nbd: do not include block_int.h
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/nbd.c b/nbd.c
index 4c6d7f1..d4dafc6 100644
--- a/nbd.c
+++ b/nbd.c
@@ -18,7 +18,6 @@
 
 #include "nbd.h"
 #include "block.h"
-#include "block_int.h"
 
 #include "qemu-coroutine.h"
 
@@ -703,7 +702,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset,
     exp->bs = bs;
     exp->dev_offset = dev_offset;
     exp->nbdflags = nbdflags;
-    exp->size = size == -1 ? exp->bs->total_sectors * 512 : size;
+    exp->size = size == -1 ? bdrv_getlength(bs) : size;
     return exp;
 }
 
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 6c3f9b5..5a0300e 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -17,7 +17,7 @@
  */
 
 #include "qemu-common.h"
-#include "block_int.h"
+#include "block.h"
 #include "nbd.h"
 
 #include <stdarg.h>
@@ -487,7 +487,7 @@ int main(int argc, char **argv)
         err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
     }
 
-    fd_size = bs->total_sectors * 512;
+    fd_size = bdrv_getlength(bs);
 
     if (partition != -1) {
         ret = find_partition(bs, partition, &dev_offset, &fd_size);
commit 9eb0bfca960b8cf24fb42e017c3a6479e5676f75
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 12 14:00:56 2012 +0200

    aio: simplify qemu_aio_wait
    
    The do...while loop can never loop, because select will just not return
    0 when invoked with infinite timeout.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/aio.c b/aio.c
index 5fcc0c6..0a9eb10 100644
--- a/aio.c
+++ b/aio.c
@@ -104,7 +104,11 @@ void qemu_aio_flush(void)
 
 bool qemu_aio_wait(void)
 {
+    AioHandler *node;
+    fd_set rdfds, wrfds;
+    int max_fd = -1;
     int ret;
+    bool busy;
 
     /*
      * If there are callbacks left that have been queued, we need to call then.
@@ -115,85 +119,76 @@ bool qemu_aio_wait(void)
         return true;
     }
 
-    do {
-        AioHandler *node;
-        fd_set rdfds, wrfds;
-        bool busy;
-        int max_fd = -1;
+    walking_handlers = 1;
 
-        walking_handlers = 1;
+    FD_ZERO(&rdfds);
+    FD_ZERO(&wrfds);
 
-        FD_ZERO(&rdfds);
-        FD_ZERO(&wrfds);
-
-        /* fill fd sets */
-        busy = false;
-        QLIST_FOREACH(node, &aio_handlers, node) {
-            /* If there aren't pending AIO operations, don't invoke callbacks.
-             * Otherwise, if there are no AIO requests, qemu_aio_wait() would
-             * wait indefinitely.
-             */
-            if (node->io_flush) {
-                if (node->io_flush(node->opaque) == 0) {
-                    continue;
-                }
-                busy = true;
-            }
-            if (!node->deleted && node->io_read) {
-                FD_SET(node->fd, &rdfds);
-                max_fd = MAX(max_fd, node->fd + 1);
-            }
-            if (!node->deleted && node->io_write) {
-                FD_SET(node->fd, &wrfds);
-                max_fd = MAX(max_fd, node->fd + 1);
+    /* fill fd sets */
+    busy = false;
+    QLIST_FOREACH(node, &aio_handlers, node) {
+        /* If there aren't pending AIO operations, don't invoke callbacks.
+         * Otherwise, if there are no AIO requests, qemu_aio_wait() would
+         * wait indefinitely.
+         */
+        if (node->io_flush) {
+            if (node->io_flush(node->opaque) == 0) {
+                continue;
             }
+            busy = true;
+        }
+        if (!node->deleted && node->io_read) {
+            FD_SET(node->fd, &rdfds);
+            max_fd = MAX(max_fd, node->fd + 1);
         }
+        if (!node->deleted && node->io_write) {
+            FD_SET(node->fd, &wrfds);
+            max_fd = MAX(max_fd, node->fd + 1);
+        }
+    }
 
-        walking_handlers = 0;
+    walking_handlers = 0;
 
-        /* No AIO operations?  Get us out of here */
-        if (!busy) {
-            return false;
-        }
+    /* No AIO operations?  Get us out of here */
+    if (!busy) {
+        return false;
+    }
 
-        /* wait until next event */
-        ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
-        if (ret == -1 && errno == EINTR)
-            continue;
-
-        /* if we have any readable fds, dispatch event */
-        if (ret > 0) {
-            walking_handlers = 1;
-
-            /* we have to walk very carefully in case
-             * qemu_aio_set_fd_handler is called while we're walking */
-            node = QLIST_FIRST(&aio_handlers);
-            while (node) {
-                AioHandler *tmp;
-
-                if (!node->deleted &&
-                    FD_ISSET(node->fd, &rdfds) &&
-                    node->io_read) {
-                    node->io_read(node->opaque);
-                }
-                if (!node->deleted &&
-                    FD_ISSET(node->fd, &wrfds) &&
-                    node->io_write) {
-                    node->io_write(node->opaque);
-                }
-
-                tmp = node;
-                node = QLIST_NEXT(node, node);
-
-                if (tmp->deleted) {
-                    QLIST_REMOVE(tmp, node);
-                    g_free(tmp);
-                }
+    /* wait until next event */
+    ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
+
+    /* if we have any readable fds, dispatch event */
+    if (ret > 0) {
+        walking_handlers = 1;
+
+        /* we have to walk very carefully in case
+         * qemu_aio_set_fd_handler is called while we're walking */
+        node = QLIST_FIRST(&aio_handlers);
+        while (node) {
+            AioHandler *tmp;
+
+            if (!node->deleted &&
+                FD_ISSET(node->fd, &rdfds) &&
+                node->io_read) {
+                node->io_read(node->opaque);
+            }
+            if (!node->deleted &&
+                FD_ISSET(node->fd, &wrfds) &&
+                node->io_write) {
+                node->io_write(node->opaque);
             }
 
-            walking_handlers = 0;
+            tmp = node;
+            node = QLIST_NEXT(node, node);
+
+            if (tmp->deleted) {
+                QLIST_REMOVE(tmp, node);
+                g_free(tmp);
+            }
         }
-    } while (ret == 0);
+
+        walking_handlers = 0;
+    }
 
     return true;
 }
commit bcdc18578d5b41180db2e17baa7563c5f05b39ee
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 12 14:00:55 2012 +0200

    aio: return "AIO in progress" state from qemu_aio_wait
    
    The definition of when qemu_aio_flush should loop is much simpler
    than it looks.  It just has to call qemu_aio_wait until it makes
    no progress and all flush callbacks return false.  qemu_aio_wait
    is the logical place to tell the caller about this.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/aio.c b/aio.c
index f19b3c6..5fcc0c6 100644
--- a/aio.c
+++ b/aio.c
@@ -99,41 +99,26 @@ int qemu_aio_set_fd_handler(int fd,
 
 void qemu_aio_flush(void)
 {
-    AioHandler *node;
-    int ret;
-
-    do {
-        ret = 0;
-
-	/*
-	 * If there are pending emulated aio start them now so flush
-	 * will be able to return 1.
-	 */
-        qemu_aio_wait();
-
-        QLIST_FOREACH(node, &aio_handlers, node) {
-            if (node->io_flush) {
-                ret |= node->io_flush(node->opaque);
-            }
-        }
-    } while (qemu_bh_poll() || ret > 0);
+    while (qemu_aio_wait());
 }
 
-void qemu_aio_wait(void)
+bool qemu_aio_wait(void)
 {
     int ret;
 
     /*
      * If there are callbacks left that have been queued, we need to call then.
-     * Return afterwards to avoid waiting needlessly in select().
+     * Do not call select in this case, because it is possible that the caller
+     * does not need a complete flush (as is the case for qemu_aio_wait loops).
      */
     if (qemu_bh_poll()) {
-        return;
+        return true;
     }
 
     do {
         AioHandler *node;
         fd_set rdfds, wrfds;
+        bool busy;
         int max_fd = -1;
 
         walking_handlers = 1;
@@ -142,14 +127,18 @@ void qemu_aio_wait(void)
         FD_ZERO(&wrfds);
 
         /* fill fd sets */
+        busy = false;
         QLIST_FOREACH(node, &aio_handlers, node) {
             /* If there aren't pending AIO operations, don't invoke callbacks.
              * Otherwise, if there are no AIO requests, qemu_aio_wait() would
              * wait indefinitely.
              */
-            if (node->io_flush && node->io_flush(node->opaque) == 0)
-                continue;
-
+            if (node->io_flush) {
+                if (node->io_flush(node->opaque) == 0) {
+                    continue;
+                }
+                busy = true;
+            }
             if (!node->deleted && node->io_read) {
                 FD_SET(node->fd, &rdfds);
                 max_fd = MAX(max_fd, node->fd + 1);
@@ -163,8 +152,9 @@ void qemu_aio_wait(void)
         walking_handlers = 0;
 
         /* No AIO operations?  Get us out of here */
-        if (max_fd == -1)
-            break;
+        if (!busy) {
+            return false;
+        }
 
         /* wait until next event */
         ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
@@ -204,4 +194,6 @@ void qemu_aio_wait(void)
             walking_handlers = 0;
         }
     } while (ret == 0);
+
+    return true;
 }
diff --git a/qemu-aio.h b/qemu-aio.h
index 0fc8409..bfdd35f 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -48,8 +48,10 @@ void qemu_aio_flush(void);
 /* Wait for a single AIO completion to occur.  This function will wait
  * until a single AIO event has completed and it will ensure something
  * has moved before returning. This can issue new pending aio as
- * result of executing I/O completion or bh callbacks. */
-void qemu_aio_wait(void);
+ * result of executing I/O completion or bh callbacks.
+ *
+ * Return whether there is still any pending AIO operation.  */
+bool qemu_aio_wait(void);
 
 /* Register a file descriptor and associated callbacks.  Behaves very similarly
  * to qemu_set_fd_handler2.  Unlike qemu_set_fd_handler2, these callbacks will
commit bafbd6a1c69fef73500309dc31c86984c6d22b43
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 12 14:00:54 2012 +0200

    aio: remove process_queue callback and qemu_aio_process_queue
    
    Both unused after the previous patch.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/aio.c b/aio.c
index eb3bf42..f19b3c6 100644
--- a/aio.c
+++ b/aio.c
@@ -35,7 +35,6 @@ struct AioHandler
     IOHandler *io_read;
     IOHandler *io_write;
     AioFlushHandler *io_flush;
-    AioProcessQueue *io_process_queue;
     int deleted;
     void *opaque;
     QLIST_ENTRY(AioHandler) node;
@@ -58,7 +57,6 @@ int qemu_aio_set_fd_handler(int fd,
                             IOHandler *io_read,
                             IOHandler *io_write,
                             AioFlushHandler *io_flush,
-                            AioProcessQueue *io_process_queue,
                             void *opaque)
 {
     AioHandler *node;
@@ -91,7 +89,6 @@ int qemu_aio_set_fd_handler(int fd,
         node->io_read = io_read;
         node->io_write = io_write;
         node->io_flush = io_flush;
-        node->io_process_queue = io_process_queue;
         node->opaque = opaque;
     }
 
@@ -122,39 +119,17 @@ void qemu_aio_flush(void)
     } while (qemu_bh_poll() || ret > 0);
 }
 
-int qemu_aio_process_queue(void)
-{
-    AioHandler *node;
-    int ret = 0;
-
-    walking_handlers = 1;
-
-    QLIST_FOREACH(node, &aio_handlers, node) {
-        if (node->io_process_queue) {
-            if (node->io_process_queue(node->opaque)) {
-                ret = 1;
-            }
-        }
-    }
-
-    walking_handlers = 0;
-
-    return ret;
-}
-
 void qemu_aio_wait(void)
 {
     int ret;
 
-    if (qemu_bh_poll())
-        return;
-
     /*
      * If there are callbacks left that have been queued, we need to call then.
      * Return afterwards to avoid waiting needlessly in select().
      */
-    if (qemu_aio_process_queue())
+    if (qemu_bh_poll()) {
         return;
+    }
 
     do {
         AioHandler *node;
diff --git a/block/curl.c b/block/curl.c
index a909eca..bf3680b 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -89,19 +89,17 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
     DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
     switch (action) {
         case CURL_POLL_IN:
-            qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush,
-                                    NULL, s);
+            qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush, s);
             break;
         case CURL_POLL_OUT:
-            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush,
-                                    NULL, s);
+            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush, s);
             break;
         case CURL_POLL_INOUT:
             qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
-                                    curl_aio_flush, NULL, s);
+                                    curl_aio_flush, s);
             break;
         case CURL_POLL_REMOVE:
-            qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
+            qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL);
             break;
     }
 
diff --git a/block/iscsi.c b/block/iscsi.c
index bd3ca11..5222726 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -108,7 +108,7 @@ iscsi_set_events(IscsiLun *iscsilun)
     qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
                            (iscsi_which_events(iscsi) & POLLOUT)
                            ? iscsi_process_write : NULL,
-                           iscsi_process_flush, NULL, iscsilun);
+                           iscsi_process_flush, iscsilun);
 }
 
 static void
@@ -682,7 +682,7 @@ static void iscsi_close(BlockDriverState *bs)
     IscsiLun *iscsilun = bs->opaque;
     struct iscsi_context *iscsi = iscsilun->iscsi;
 
-    qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL, NULL);
+    qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
     iscsi_destroy_context(iscsi);
     memset(iscsilun, 0, sizeof(IscsiLun));
 }
diff --git a/block/nbd.c b/block/nbd.c
index 161b299..524c9cf 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -191,7 +191,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
     qemu_co_mutex_lock(&s->send_mutex);
     s->send_coroutine = qemu_coroutine_self();
     qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
-                            nbd_have_request, NULL, s);
+                            nbd_have_request, s);
     rc = nbd_send_request(s->sock, request);
     if (rc != -1 && iov) {
         ret = qemu_co_sendv(s->sock, iov, request->len, offset);
@@ -201,7 +201,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
         }
     }
     qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
-                            nbd_have_request, NULL, s);
+                            nbd_have_request, s);
     s->send_coroutine = NULL;
     qemu_co_mutex_unlock(&s->send_mutex);
     return rc;
@@ -274,7 +274,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
      * kick the reply mechanism.  */
     socket_set_nonblock(sock);
     qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
-                            nbd_have_request, NULL, s);
+                            nbd_have_request, s);
 
     s->sock = sock;
     s->size = size;
@@ -294,7 +294,7 @@ static void nbd_teardown_connection(BlockDriverState *bs)
     request.len = 0;
     nbd_send_request(s->sock, &request);
 
-    qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL, NULL);
+    qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL);
     closesocket(s->sock);
 }
 
diff --git a/block/rbd.c b/block/rbd.c
index 46a8579..6cd8448 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -504,7 +504,7 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
     fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
     fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
     qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
-                            NULL, qemu_rbd_aio_flush_cb, NULL, s);
+                            NULL, qemu_rbd_aio_flush_cb, s);
 
 
     return 0;
@@ -525,8 +525,7 @@ static void qemu_rbd_close(BlockDriverState *bs)
 
     close(s->fds[0]);
     close(s->fds[1]);
-    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
-        NULL);
+    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL, NULL);
 
     rbd_close(s->image);
     rados_ioctx_destroy(s->io_ctx);
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 3eaf625..0ed6b19 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -799,8 +799,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
         return -1;
     }
 
-    qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request,
-                            NULL, s);
+    qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s);
     return fd;
 }
 
@@ -973,7 +972,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
     qemu_co_mutex_lock(&s->lock);
     s->co_send = qemu_coroutine_self();
     qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request,
-                            aio_flush_request, NULL, s);
+                            aio_flush_request, s);
     socket_set_cork(s->fd, 1);
 
     /* send a header */
@@ -995,7 +994,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
 
     socket_set_cork(s->fd, 0);
     qemu_aio_set_fd_handler(s->fd, co_read_response, NULL,
-                            aio_flush_request, NULL, s);
+                            aio_flush_request, s);
     qemu_co_mutex_unlock(&s->lock);
 
     return 0;
@@ -1135,7 +1134,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
     g_free(buf);
     return 0;
 out:
-    qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
+    qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
     if (s->fd >= 0) {
         closesocket(s->fd);
     }
@@ -1349,7 +1348,7 @@ static void sd_close(BlockDriverState *bs)
         error_report("%s, %s", sd_strerror(rsp->result), s->name);
     }
 
-    qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
+    qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
     closesocket(s->fd);
     if (s->cache_enabled) {
         closesocket(s->flush_fd);
diff --git a/linux-aio.c b/linux-aio.c
index 15261ec..fa0fbf3 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -214,7 +214,7 @@ void *laio_init(void)
         goto out_close_efd;
 
     qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
-        qemu_laio_flush_cb, NULL, s);
+        qemu_laio_flush_cb, s);
 
     return s;
 
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index 1066c60..68361f5 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -663,8 +663,7 @@ int paio_init(void)
     fcntl(s->rfd, F_SETFL, O_NONBLOCK);
     fcntl(s->wfd, F_SETFL, O_NONBLOCK);
 
-    qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush,
-        NULL, s);
+    qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
 
     ret = pthread_attr_init(&attr);
     if (ret)
diff --git a/qemu-aio.h b/qemu-aio.h
index 230c2f7..0fc8409 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -41,11 +41,6 @@ void qemu_aio_release(void *p);
 /* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
 typedef int (AioFlushHandler)(void *opaque);
 
-/* Runs all currently allowed AIO callbacks of completed requests in the
- * respective AIO backend. Returns 0 if no requests was handled, non-zero
- * if at least one queued request was handled. */
-typedef int (AioProcessQueue)(void *opaque);
-
 /* Flush any pending AIO operation. This function will block until all
  * outstanding AIO operations have been completed or cancelled. */
 void qemu_aio_flush(void);
@@ -56,13 +51,6 @@ void qemu_aio_flush(void);
  * result of executing I/O completion or bh callbacks. */
 void qemu_aio_wait(void);
 
-/*
- * Runs all currently allowed AIO callbacks of completed requests. Returns 0
- * if no requests were handled, non-zero if at least one request was
- * processed.
- */
-int qemu_aio_process_queue(void);
-
 /* Register a file descriptor and associated callbacks.  Behaves very similarly
  * to qemu_set_fd_handler2.  Unlike qemu_set_fd_handler2, these callbacks will
  * be invoked when using either qemu_aio_wait() or qemu_aio_flush().
@@ -74,7 +62,6 @@ int qemu_aio_set_fd_handler(int fd,
                             IOHandler *io_read,
                             IOHandler *io_write,
                             AioFlushHandler *io_flush,
-                            AioProcessQueue *io_process_queue,
                             void *opaque);
 
 #endif
commit 7fe7b68b32ba609faeeee03556aac0eb1b187c91
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Mar 5 09:10:35 2012 +0100

    nbd: do not block in nbd_wr_sync if no data at all is available
    
    Right now, nbd_wr_sync will hang if no data at all is available on the
    socket and the other side is not going to provide any.  Relax this by
    making it loop only for writes or partial reads.  This fixes a race
    where one thread is executing qemu_aio_wait() and another is executing
    main_loop_wait().  Then, the select() call in main_loop_wait() can return
    stale data and call the "readable" callback with no data in the socket.
    
    Reported-by: Laurent Vivier <laurent at vivier.eu>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/block/nbd.c b/block/nbd.c
index 1b0e384..e0af5b4 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -151,10 +151,18 @@ static void nbd_reply_ready(void *opaque)
 {
     BDRVNBDState *s = opaque;
     uint64_t i;
+    int ret;
 
     if (s->reply.handle == 0) {
-        /* No reply already in flight.  Fetch a header.  */
-        if (nbd_receive_reply(s->sock, &s->reply) < 0) {
+        /* No reply already in flight.  Fetch a header.  It is possible
+         * that another thread has done the same thing in parallel, so
+         * the socket is not readable anymore.
+         */
+        ret = nbd_receive_reply(s->sock, &s->reply);
+        if (ret == -EAGAIN) {
+            return;
+        }
+        if (ret < 0) {
             s->reply.handle = 0;
             goto fail;
         }
diff --git a/nbd.c b/nbd.c
index b31b3b2..4c6d7f1 100644
--- a/nbd.c
+++ b/nbd.c
@@ -78,9 +78,6 @@
 
 /* That's all folks */
 
-#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
-#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
-
 ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
 {
     size_t offset = 0;
@@ -107,7 +104,7 @@ ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
             err = socket_error();
 
             /* recoverable error */
-            if (err == EINTR || err == EAGAIN) {
+            if (err == EINTR || (offset > 0 && err == EAGAIN)) {
                 continue;
             }
 
@@ -126,6 +123,26 @@ ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
     return offset;
 }
 
+static ssize_t read_sync(int fd, void *buffer, size_t size)
+{
+    /* Sockets are kept in blocking mode in the negotiation phase.  After
+     * that, a non-readable socket simply means that another thread stole
+     * our request/reply.  Synchronization is done with recv_coroutine, so
+     * that this is coroutine-safe.
+     */
+    return nbd_wr_sync(fd, buffer, size, true);
+}
+
+static ssize_t write_sync(int fd, void *buffer, size_t size)
+{
+    int ret;
+    do {
+        /* For writes, we do expect the socket to be writable.  */
+        ret = nbd_wr_sync(fd, buffer, size, false);
+    } while (ret == -EAGAIN);
+    return ret;
+}
+
 static void combine_addr(char *buf, size_t len, const char* address,
                          uint16_t port)
 {
@@ -203,6 +220,7 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
         [28 .. 151]   reserved (0)
      */
 
+    socket_set_block(csock);
     rc = -EINVAL;
 
     TRACE("Beginning negotiation.");
@@ -222,6 +240,7 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
     TRACE("Negotiation succeeded.");
     rc = 0;
 fail:
+    socket_set_nonblock(csock);
     return rc;
 }
 
@@ -235,6 +254,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
 
     TRACE("Receiving negotiation.");
 
+    socket_set_block(csock);
     rc = -EINVAL;
 
     if (read_sync(csock, buf, 8) != 8) {
@@ -349,6 +369,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
     rc = 0;
 
 fail:
+    socket_set_nonblock(csock);
     return rc;
 }
 
@@ -742,8 +763,11 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *reque
     ssize_t rc;
 
     client->recv_coroutine = qemu_coroutine_self();
-    if (nbd_receive_request(csock, request) < 0) {
-        rc = -EIO;
+    rc = nbd_receive_request(csock, request);
+    if (rc < 0) {
+        if (rc != -EAGAIN) {
+            rc = -EIO;
+        }
         goto out;
     }
 
@@ -791,6 +815,9 @@ static void nbd_trip(void *opaque)
     TRACE("Reading request.");
 
     ret = nbd_co_receive_request(req, &request);
+    if (ret == -EAGAIN) {
+        goto done;
+    }
     if (ret == -EIO) {
         goto out;
     }
@@ -901,6 +928,7 @@ static void nbd_trip(void *opaque)
 
     TRACE("Request/Reply complete");
 
+done:
     nbd_request_put(req);
     return;
 
commit 185b43386ad999c80bdc58e41b87f05e5b3e8463
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Mar 5 08:56:10 2012 +0100

    nbd: consistently return negative errno values
    
    In the next patch we need to look at the return code of nbd_wr_sync.
    To avoid percolating the socket_error() ugliness all around, let's
    handle errors by returning negative errno values.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/block/nbd.c b/block/nbd.c
index 25e5268..1b0e384 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -200,8 +200,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
     if (rc >= 0 && iov) {
         ret = qemu_co_sendv(s->sock, iov, request->len, offset);
         if (ret != request->len) {
-            errno = -EIO;
-            rc = -1;
+            return -EIO;
         }
     }
     qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
@@ -271,7 +270,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
     if (ret < 0) {
         logout("Failed to negotiate with the NBD server\n");
         closesocket(sock);
-        return -errno;
+        return ret;
     }
 
     /* Now that we're connected, set the socket to be non-blocking and
@@ -340,7 +339,7 @@ static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
     nbd_coroutine_start(s, &request);
     ret = nbd_co_send_request(s, &request, NULL, 0);
     if (ret < 0) {
-        reply.error = errno;
+        reply.error = -ret;
     } else {
         nbd_co_receive_reply(s, &request, &reply, qiov->iov, offset);
     }
@@ -369,7 +368,7 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
     nbd_coroutine_start(s, &request);
     ret = nbd_co_send_request(s, &request, qiov->iov, offset);
     if (ret < 0) {
-        reply.error = errno;
+        reply.error = -ret;
     } else {
         nbd_co_receive_reply(s, &request, &reply, NULL, 0);
     }
@@ -437,7 +436,7 @@ static int nbd_co_flush(BlockDriverState *bs)
     nbd_coroutine_start(s, &request);
     ret = nbd_co_send_request(s, &request, NULL, 0);
     if (ret < 0) {
-        reply.error = errno;
+        reply.error = -ret;
     } else {
         nbd_co_receive_reply(s, &request, &reply, NULL, 0);
     }
@@ -463,7 +462,7 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
     nbd_coroutine_start(s, &request);
     ret = nbd_co_send_request(s, &request, NULL, 0);
     if (ret < 0) {
-        reply.error = errno;
+        reply.error = -ret;
     } else {
         nbd_co_receive_reply(s, &request, &reply, NULL, 0);
     }
diff --git a/nbd.c b/nbd.c
index 9832aa0..b31b3b2 100644
--- a/nbd.c
+++ b/nbd.c
@@ -81,9 +81,10 @@
 #define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
 #define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
 
-size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
+ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
 {
     size_t offset = 0;
+    int err;
 
     if (qemu_in_coroutine()) {
         if (do_read) {
@@ -103,15 +104,15 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
         }
 
         if (len < 0) {
-            errno = socket_error();
+            err = socket_error();
 
             /* recoverable error */
-            if (errno == EINTR || errno == EAGAIN) {
+            if (err == EINTR || err == EAGAIN) {
                 continue;
             }
 
             /* unrecoverable error */
-            return 0;
+            return -err;
         }
 
         /* eof */
@@ -192,6 +193,7 @@ int unix_socket_outgoing(const char *path)
 static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
 {
     char buf[8 + 8 + 8 + 128];
+    int rc;
 
     /* Negotiate
         [ 0 ..   7]   passwd   ("NBDMAGIC")
@@ -201,6 +203,8 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
         [28 .. 151]   reserved (0)
      */
 
+    rc = -EINVAL;
+
     TRACE("Beginning negotiation.");
     memcpy(buf, "NBDMAGIC", 8);
     cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
@@ -212,13 +216,13 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
 
     if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
         LOG("write failed");
-        errno = EINVAL;
-        return -1;
+        goto fail;
     }
 
     TRACE("Negotiation succeeded.");
-
-    return 0;
+    rc = 0;
+fail:
+    return rc;
 }
 
 int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
@@ -227,20 +231,21 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
     char buf[256];
     uint64_t magic, s;
     uint16_t tmp;
+    int rc;
 
     TRACE("Receiving negotiation.");
 
+    rc = -EINVAL;
+
     if (read_sync(csock, buf, 8) != 8) {
         LOG("read failed");
-        errno = EINVAL;
-        return -1;
+        goto fail;
     }
 
     buf[8] = '\0';
     if (strlen(buf) == 0) {
         LOG("server connection closed");
-        errno = EINVAL;
-        return -1;
+        goto fail;
     }
 
     TRACE("Magic is %c%c%c%c%c%c%c%c",
@@ -255,14 +260,12 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
 
     if (memcmp(buf, "NBDMAGIC", 8) != 0) {
         LOG("Invalid magic received");
-        errno = EINVAL;
-        return -1;
+        goto fail;
     }
 
     if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
         LOG("read failed");
-        errno = EINVAL;
-        return -1;
+        goto fail;
     }
     magic = be64_to_cpu(magic);
     TRACE("Magic is 0x%" PRIx64, magic);
@@ -275,61 +278,52 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
         TRACE("Checking magic (opts_magic)");
         if (magic != 0x49484156454F5054LL) {
             LOG("Bad magic received");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
         if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
             LOG("flags read failed");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
         *flags = be16_to_cpu(tmp) << 16;
         /* reserved for future use */
         if (write_sync(csock, &reserved, sizeof(reserved)) !=
             sizeof(reserved)) {
             LOG("write failed (reserved)");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
         /* write the export name */
         magic = cpu_to_be64(magic);
         if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
             LOG("write failed (magic)");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
         opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
         if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
             LOG("write failed (opt)");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
         namesize = cpu_to_be32(strlen(name));
         if (write_sync(csock, &namesize, sizeof(namesize)) !=
             sizeof(namesize)) {
             LOG("write failed (namesize)");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
         if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
             LOG("write failed (name)");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
     } else {
         TRACE("Checking magic (cli_magic)");
 
         if (magic != 0x00420281861253LL) {
             LOG("Bad magic received");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
     }
 
     if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
         LOG("read failed");
-        errno = EINVAL;
-        return -1;
+        goto fail;
     }
     *size = be64_to_cpu(s);
     *blocksize = 1024;
@@ -338,24 +332,24 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
     if (!name) {
         if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
             LOG("read failed (flags)");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
         *flags = be32_to_cpup(flags);
     } else {
         if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
             LOG("read failed (tmp)");
-            errno = EINVAL;
-            return -1;
+            goto fail;
         }
         *flags |= be32_to_cpu(tmp);
     }
     if (read_sync(csock, &buf, 124) != 124) {
         LOG("read failed (buf)");
-        errno = EINVAL;
-        return -1;
+        goto fail;
     }
-        return 0;
+    rc = 0;
+
+fail:
+    return rc;
 }
 
 #ifdef __linux__
@@ -366,8 +360,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
     if (ioctl(fd, NBD_SET_SOCK, csock) < 0) {
         int serrno = errno;
         LOG("Failed to set NBD socket");
-        errno = serrno;
-        return -1;
+        return -serrno;
     }
 
     TRACE("Setting block size to %lu", (unsigned long)blocksize);
@@ -375,8 +368,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
     if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) < 0) {
         int serrno = errno;
         LOG("Failed setting NBD block size");
-        errno = serrno;
-        return -1;
+        return -serrno;
     }
 
         TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
@@ -384,8 +376,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
     if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) < 0) {
         int serrno = errno;
         LOG("Failed setting size (in blocks)");
-        errno = serrno;
-        return -1;
+        return -serrno;
     }
 
     if (flags & NBD_FLAG_READ_ONLY) {
@@ -395,8 +386,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
         if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
             int serrno = errno;
             LOG("Failed setting read-only attribute");
-            errno = serrno;
-            return -1;
+            return -serrno;
         }
     }
 
@@ -404,8 +394,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
         && errno != ENOTTY) {
         int serrno = errno;
         LOG("Failed setting flags");
-        errno = serrno;
-        return -1;
+        return -serrno;
     }
 
     TRACE("Negotiation ended");
@@ -452,26 +441,24 @@ int nbd_client(int fd)
 #else
 int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 {
-    errno = ENOTSUP;
-    return -1;
+    return -ENOTSUP;
 }
 
 int nbd_disconnect(int fd)
 {
-    errno = ENOTSUP;
-    return -1;
+    return -ENOTSUP;
 }
 
 int nbd_client(int fd)
 {
-    errno = ENOTSUP;
-    return -1;
+    return -ENOTSUP;
 }
 #endif
 
 ssize_t nbd_send_request(int csock, struct nbd_request *request)
 {
     uint8_t buf[4 + 4 + 8 + 8 + 4];
+    ssize_t ret;
 
     cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
     cpu_to_be32w((uint32_t*)(buf + 4), request->type);
@@ -483,10 +470,14 @@ ssize_t nbd_send_request(int csock, struct nbd_request *request)
           "{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
           request->from, request->len, request->handle, request->type);
 
-    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+    ret = write_sync(csock, buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (ret != sizeof(buf)) {
         LOG("writing to socket failed");
-        errno = EINVAL;
-        return -1;
+        return -EINVAL;
     }
     return 0;
 }
@@ -495,11 +486,16 @@ static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
 {
     uint8_t buf[4 + 4 + 8 + 8 + 4];
     uint32_t magic;
+    ssize_t ret;
 
-    if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+    ret = read_sync(csock, buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (ret != sizeof(buf)) {
         LOG("read failed");
-        errno = EINVAL;
-        return -1;
+        return -EINVAL;
     }
 
     /* Request
@@ -522,8 +518,7 @@ static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
 
     if (magic != NBD_REQUEST_MAGIC) {
         LOG("invalid magic (got 0x%x)", magic);
-        errno = EINVAL;
-        return -1;
+        return -EINVAL;
     }
     return 0;
 }
@@ -532,11 +527,16 @@ ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
 {
     uint8_t buf[NBD_REPLY_SIZE];
     uint32_t magic;
+    ssize_t ret;
+
+    ret = read_sync(csock, buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
 
-    if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+    if (ret != sizeof(buf)) {
         LOG("read failed");
-        errno = EINVAL;
-        return -1;
+        return -EINVAL;
     }
 
     /* Reply
@@ -555,8 +555,7 @@ ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
 
     if (magic != NBD_REPLY_MAGIC) {
         LOG("invalid magic (got 0x%x)", magic);
-        errno = EINVAL;
-        return -1;
+        return -EINVAL;
     }
     return 0;
 }
@@ -564,6 +563,7 @@ ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
 static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
 {
     uint8_t buf[4 + 4 + 8];
+    ssize_t ret;
 
     /* Reply
        [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
@@ -576,10 +576,14 @@ static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
 
     TRACE("Sending response to client");
 
-    if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+    ret = write_sync(csock, buf, sizeof(buf));
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (ret != sizeof(buf)) {
         LOG("writing to socket failed");
-        errno = EINVAL;
-        return -1;
+        return -EINVAL;
     }
     return 0;
 }
@@ -713,22 +717,15 @@ static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
 
     if (!len) {
         rc = nbd_send_reply(csock, reply);
-        if (rc < 0) {
-            rc = -errno;
-        }
     } else {
         socket_set_cork(csock, 1);
         rc = nbd_send_reply(csock, reply);
         if (rc >= 0) {
             ret = qemu_co_send(csock, req->data, len);
             if (ret != len) {
-                errno = EIO;
-                rc = -1;
+                rc = -EIO;
             }
         }
-        if (rc < 0) {
-            rc = -errno;
-        }
         socket_set_cork(csock, 0);
     }
 
diff --git a/nbd.h b/nbd.h
index 217a82d..40d58d3 100644
--- a/nbd.h
+++ b/nbd.h
@@ -59,7 +59,7 @@ enum {
 
 #define NBD_BUFFER_SIZE (1024*1024)
 
-size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
+ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
 int tcp_socket_outgoing(const char *address, uint16_t port);
 int tcp_socket_incoming(const char *address, uint16_t port);
 int tcp_socket_outgoing_spec(const char *address_and_port);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 19cfb04..6c3f9b5 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -126,8 +126,7 @@ static int find_partition(BlockDriverState *bs, int partition,
     }
 
     if (data[510] != 0x55 || data[511] != 0xaa) {
-        errno = -EINVAL;
-        return -1;
+        return -EINVAL;
     }
 
     for (i = 0; i < 4; i++) {
@@ -165,8 +164,7 @@ static int find_partition(BlockDriverState *bs, int partition,
         }
     }
 
-    errno = -ENOENT;
-    return -1;
+    return -ENOENT;
 }
 
 static void termsig_handler(int signum)
@@ -491,9 +489,12 @@ int main(int argc, char **argv)
 
     fd_size = bs->total_sectors * 512;
 
-    if (partition != -1 &&
-        find_partition(bs, partition, &dev_offset, &fd_size)) {
-        err(EXIT_FAILURE, "Could not find partition %d", partition);
+    if (partition != -1) {
+        ret = find_partition(bs, partition, &dev_offset, &fd_size);
+        if (ret < 0) {
+            errno = -ret;
+            err(EXIT_FAILURE, "Could not find partition %d", partition);
+        }
     }
 
     exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags);
commit fc19f8a02e45c4d8ad24dd7eb374330b03dfc28e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Mar 7 11:05:34 2012 +0100

    nbd: consistently check for <0 or >=0
    
    This prepares for the following patch, which changes -1 return values
    to negative errno.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/block/nbd.c b/block/nbd.c
index 9972cdb..25e5268 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -197,7 +197,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
     qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
                             nbd_have_request, NULL, s);
     rc = nbd_send_request(s->sock, request);
-    if (rc != -1 && iov) {
+    if (rc >= 0 && iov) {
         ret = qemu_co_sendv(s->sock, iov, request->len, offset);
         if (ret != request->len) {
             errno = -EIO;
@@ -260,7 +260,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
     }
 
     /* Failed to establish connection */
-    if (sock == -1) {
+    if (sock < 0) {
         logout("Failed to establish connection to NBD server\n");
         return -errno;
     }
@@ -268,7 +268,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
     /* NBD handshake */
     ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size,
                                 &blocksize);
-    if (ret == -1) {
+    if (ret < 0) {
         logout("Failed to negotiate with the NBD server\n");
         closesocket(sock);
         return -errno;
@@ -331,13 +331,15 @@ static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
     BDRVNBDState *s = bs->opaque;
     struct nbd_request request;
     struct nbd_reply reply;
+    ssize_t ret;
 
     request.type = NBD_CMD_READ;
     request.from = sector_num * 512;
     request.len = nb_sectors * 512;
 
     nbd_coroutine_start(s, &request);
-    if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
+    ret = nbd_co_send_request(s, &request, NULL, 0);
+    if (ret < 0) {
         reply.error = errno;
     } else {
         nbd_co_receive_reply(s, &request, &reply, qiov->iov, offset);
@@ -354,6 +356,7 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
     BDRVNBDState *s = bs->opaque;
     struct nbd_request request;
     struct nbd_reply reply;
+    ssize_t ret;
 
     request.type = NBD_CMD_WRITE;
     if (!bdrv_enable_write_cache(bs) && (s->nbdflags & NBD_FLAG_SEND_FUA)) {
@@ -364,7 +367,8 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
     request.len = nb_sectors * 512;
 
     nbd_coroutine_start(s, &request);
-    if (nbd_co_send_request(s, &request, qiov->iov, offset) == -1) {
+    ret = nbd_co_send_request(s, &request, qiov->iov, offset);
+    if (ret < 0) {
         reply.error = errno;
     } else {
         nbd_co_receive_reply(s, &request, &reply, NULL, 0);
@@ -416,6 +420,7 @@ static int nbd_co_flush(BlockDriverState *bs)
     BDRVNBDState *s = bs->opaque;
     struct nbd_request request;
     struct nbd_reply reply;
+    ssize_t ret;
 
     if (!(s->nbdflags & NBD_FLAG_SEND_FLUSH)) {
         return 0;
@@ -430,7 +435,8 @@ static int nbd_co_flush(BlockDriverState *bs)
     request.len = 0;
 
     nbd_coroutine_start(s, &request);
-    if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
+    ret = nbd_co_send_request(s, &request, NULL, 0);
+    if (ret < 0) {
         reply.error = errno;
     } else {
         nbd_co_receive_reply(s, &request, &reply, NULL, 0);
@@ -445,6 +451,7 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
     BDRVNBDState *s = bs->opaque;
     struct nbd_request request;
     struct nbd_reply reply;
+    ssize_t ret;
 
     if (!(s->nbdflags & NBD_FLAG_SEND_TRIM)) {
         return 0;
@@ -454,7 +461,8 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
     request.len = nb_sectors * 512;
 
     nbd_coroutine_start(s, &request);
-    if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
+    ret = nbd_co_send_request(s, &request, NULL, 0);
+    if (ret < 0) {
         reply.error = errno;
     } else {
         nbd_co_receive_reply(s, &request, &reply, NULL, 0);
diff --git a/nbd.c b/nbd.c
index 4a5849c..9832aa0 100644
--- a/nbd.c
+++ b/nbd.c
@@ -102,12 +102,16 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
             len = send(fd, buffer + offset, size - offset, 0);
         }
 
-        if (len == -1)
+        if (len < 0) {
             errno = socket_error();
 
-        /* recoverable error */
-        if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
-            continue;
+            /* recoverable error */
+            if (errno == EINTR || errno == EAGAIN) {
+                continue;
+            }
+
+            /* unrecoverable error */
+            return 0;
         }
 
         /* eof */
@@ -115,11 +119,6 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
             break;
         }
 
-        /* unrecoverable error */
-        if (len == -1) {
-            return 0;
-        }
-
         offset += len;
     }
 
@@ -364,7 +363,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 {
     TRACE("Setting NBD socket");
 
-    if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
+    if (ioctl(fd, NBD_SET_SOCK, csock) < 0) {
         int serrno = errno;
         LOG("Failed to set NBD socket");
         errno = serrno;
@@ -373,7 +372,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 
     TRACE("Setting block size to %lu", (unsigned long)blocksize);
 
-    if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
+    if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) < 0) {
         int serrno = errno;
         LOG("Failed setting NBD block size");
         errno = serrno;
@@ -382,7 +381,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 
         TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
 
-    if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
+    if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) < 0) {
         int serrno = errno;
         LOG("Failed setting size (in blocks)");
         errno = serrno;
@@ -430,7 +429,7 @@ int nbd_client(int fd)
     TRACE("Doing NBD loop");
 
     ret = ioctl(fd, NBD_DO_IT);
-    if (ret == -1 && errno == EPIPE) {
+    if (ret < 0 && errno == EPIPE) {
         /* NBD_DO_IT normally returns EPIPE when someone has disconnected
          * the socket via NBD_DISCONNECT.  We do not want to return 1 in
          * that case.
@@ -714,20 +713,20 @@ static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
 
     if (!len) {
         rc = nbd_send_reply(csock, reply);
-        if (rc == -1) {
+        if (rc < 0) {
             rc = -errno;
         }
     } else {
         socket_set_cork(csock, 1);
         rc = nbd_send_reply(csock, reply);
-        if (rc != -1) {
+        if (rc >= 0) {
             ret = qemu_co_send(csock, req->data, len);
             if (ret != len) {
                 errno = EIO;
                 rc = -1;
             }
         }
-        if (rc == -1) {
+        if (rc < 0) {
             rc = -errno;
         }
         socket_set_cork(csock, 0);
@@ -746,7 +745,7 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *reque
     ssize_t rc;
 
     client->recv_coroutine = qemu_coroutine_self();
-    if (nbd_receive_request(csock, request) == -1) {
+    if (nbd_receive_request(csock, request) < 0) {
         rc = -EIO;
         goto out;
     }
@@ -860,8 +859,9 @@ static void nbd_trip(void *opaque)
             }
         }
 
-        if (nbd_co_send_reply(req, &reply, 0) < 0)
+        if (nbd_co_send_reply(req, &reply, 0) < 0) {
             goto out;
+        }
         break;
     case NBD_CMD_DISC:
         TRACE("Request type is DISCONNECT");
@@ -875,9 +875,9 @@ static void nbd_trip(void *opaque)
             LOG("flush failed");
             reply.error = -ret;
         }
-
-        if (nbd_co_send_reply(req, &reply, 0) < 0)
+        if (nbd_co_send_reply(req, &reply, 0) < 0) {
             goto out;
+        }
         break;
     case NBD_CMD_TRIM:
         TRACE("Request type is TRIM");
@@ -887,16 +887,18 @@ static void nbd_trip(void *opaque)
             LOG("discard failed");
             reply.error = -ret;
         }
-        if (nbd_co_send_reply(req, &reply, 0) < 0)
+        if (nbd_co_send_reply(req, &reply, 0) < 0) {
             goto out;
+        }
         break;
     default:
         LOG("invalid request type (%u) received", request.type);
     invalid_request:
         reply.error = -EINVAL;
     error_reply:
-        if (nbd_co_send_reply(req, &reply, 0) == -1)
+        if (nbd_co_send_reply(req, &reply, 0) < 0) {
             goto out;
+        }
         break;
     }
 
@@ -939,7 +941,7 @@ NBDClient *nbd_client_new(NBDExport *exp, int csock,
                           void (*close)(NBDClient *))
 {
     NBDClient *client;
-    if (nbd_send_negotiate(csock, exp->size, exp->nbdflags) == -1) {
+    if (nbd_send_negotiate(csock, exp->size, exp->nbdflags) < 0) {
         return NULL;
     }
     client = g_malloc0(sizeof(NBDClient));
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d4e7041..19cfb04 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -186,7 +186,7 @@ static void *show_parts(void *arg)
      *     modprobe nbd max_part=63
      */
     nbd = open(device, O_RDWR);
-    if (nbd != -1) {
+    if (nbd >= 0) {
         close(nbd);
     }
     return NULL;
@@ -203,25 +203,25 @@ static void *nbd_client_thread(void *arg)
     pthread_t show_parts_thread;
 
     sock = unix_socket_outgoing(sockpath);
-    if (sock == -1) {
+    if (sock < 0) {
         goto out;
     }
 
     ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
                                 &size, &blocksize);
-    if (ret == -1) {
+    if (ret < 0) {
         goto out;
     }
 
     fd = open(device, O_RDWR);
-    if (fd == -1) {
+    if (fd < 0) {
         /* Linux-only, we can use %m in printf.  */
         fprintf(stderr, "Failed to open %s: %m", device);
         goto out;
     }
 
     ret = nbd_init(fd, sock, nbdflags, size, blocksize);
-    if (ret == -1) {
+    if (ret < 0) {
         goto out;
     }
 
@@ -268,7 +268,7 @@ static void nbd_accept(void *opaque)
 
     int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
     nbd_started = true;
-    if (fd != -1 && nbd_client_new(exp, fd, nbd_client_closed)) {
+    if (fd >= 0 && nbd_client_new(exp, fd, nbd_client_closed)) {
         nb_fds++;
     }
 }
@@ -410,9 +410,9 @@ int main(int argc, char **argv)
 
     if (disconnect) {
         fd = open(argv[optind], O_RDWR);
-        if (fd == -1)
+        if (fd < 0) {
             err(EXIT_FAILURE, "Cannot open %s", argv[optind]);
-
+        }
         nbd_disconnect(fd);
 
         close(fd);
@@ -427,7 +427,7 @@ int main(int argc, char **argv)
         pid_t pid;
         int ret;
 
-        if (qemu_pipe(stderr_fd) == -1) {
+        if (qemu_pipe(stderr_fd) < 0) {
             err(EXIT_FAILURE, "Error setting up communication pipe");
         }
 
@@ -441,7 +441,7 @@ int main(int argc, char **argv)
 
             /* Temporarily redirect stderr to the parent's pipe...  */
             dup2(stderr_fd[1], STDERR_FILENO);
-            if (ret == -1) {
+            if (ret < 0) {
                 err(EXIT_FAILURE, "Failed to daemonize");
             }
 
@@ -459,11 +459,11 @@ int main(int argc, char **argv)
             while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
                 errors = true;
                 ret = qemu_write_full(STDERR_FILENO, buf, ret);
-                if (ret == -1) {
+                if (ret < 0) {
                     exit(EXIT_FAILURE);
                 }
             }
-            if (ret == -1) {
+            if (ret < 0) {
                 err(EXIT_FAILURE, "Cannot read from daemon");
             }
 
@@ -504,7 +504,7 @@ int main(int argc, char **argv)
         fd = tcp_socket_incoming(bindto, port);
     }
 
-    if (fd == -1) {
+    if (fd < 0) {
         return 1;
     }
 
commit 94e7340b5db8bce7866e44e700ffa8fd26585c7e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Mar 7 11:25:01 2012 +0100

    nbd: consistently use ssize_t
    
    GCC (pedantically, but correctly) considers that a negative ssize_t may
    become positive when casted to int.  This may cause uninitialized variable
    warnings when a function returns such a negative ssize_t and is inlined.
    Propagate ssize_t return types to avoid this.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/nbd.c b/nbd.c
index 406e555..4a5849c 100644
--- a/nbd.c
+++ b/nbd.c
@@ -470,7 +470,7 @@ int nbd_client(int fd)
 }
 #endif
 
-int nbd_send_request(int csock, struct nbd_request *request)
+ssize_t nbd_send_request(int csock, struct nbd_request *request)
 {
     uint8_t buf[4 + 4 + 8 + 8 + 4];
 
@@ -492,7 +492,7 @@ int nbd_send_request(int csock, struct nbd_request *request)
     return 0;
 }
 
-static int nbd_receive_request(int csock, struct nbd_request *request)
+static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
 {
     uint8_t buf[4 + 4 + 8 + 8 + 4];
     uint32_t magic;
@@ -529,13 +529,11 @@ static int nbd_receive_request(int csock, struct nbd_request *request)
     return 0;
 }
 
-int nbd_receive_reply(int csock, struct nbd_reply *reply)
+ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
 {
     uint8_t buf[NBD_REPLY_SIZE];
     uint32_t magic;
 
-    memset(buf, 0xAA, sizeof(buf));
-
     if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
         LOG("read failed");
         errno = EINVAL;
@@ -564,7 +562,7 @@ int nbd_receive_reply(int csock, struct nbd_reply *reply)
     return 0;
 }
 
-static int nbd_send_reply(int csock, struct nbd_reply *reply)
+static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
 {
     uint8_t buf[4 + 4 + 8];
 
@@ -702,12 +700,12 @@ static int nbd_can_read(void *opaque);
 static void nbd_read(void *opaque);
 static void nbd_restart_write(void *opaque);
 
-static int nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
-                             int len)
+static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
+                                 int len)
 {
     NBDClient *client = req->client;
     int csock = client->sock;
-    int rc, ret;
+    ssize_t rc, ret;
 
     qemu_co_mutex_lock(&client->send_lock);
     qemu_set_fd_handler2(csock, nbd_can_read, nbd_read,
@@ -741,11 +739,11 @@ static int nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
     return rc;
 }
 
-static int nbd_co_receive_request(NBDRequest *req, struct nbd_request *request)
+static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *request)
 {
     NBDClient *client = req->client;
     int csock = client->sock;
-    int rc;
+    ssize_t rc;
 
     client->recv_coroutine = qemu_coroutine_self();
     if (nbd_receive_request(csock, request) == -1) {
@@ -792,7 +790,7 @@ static void nbd_trip(void *opaque)
     NBDExport *exp = client->exp;
     struct nbd_request request;
     struct nbd_reply reply;
-    int ret;
+    ssize_t ret;
 
     TRACE("Reading request.");
 
diff --git a/nbd.h b/nbd.h
index a8382f0..217a82d 100644
--- a/nbd.h
+++ b/nbd.h
@@ -70,8 +70,8 @@ int unix_socket_incoming(const char *path);
 int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
                           off_t *size, size_t *blocksize);
 int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
-int nbd_send_request(int csock, struct nbd_request *request);
-int nbd_receive_reply(int csock, struct nbd_reply *reply);
+ssize_t nbd_send_request(int csock, struct nbd_request *request);
+ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply);
 int nbd_client(int fd);
 int nbd_disconnect(int fd);
 
commit dd3e8ac413a74a58d6a3ba16a26952f84370fcff
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Mar 12 15:23:13 2012 +0100

    nbd: avoid out of bounds access to recv_coroutine array
    
    This can happen with a buggy or malicious server.
    
    Reported-by: Michael Tokarev <mjt at tls.msk.ru>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/block/nbd.c b/block/nbd.c
index 161b299..9972cdb 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -150,7 +150,7 @@ static int nbd_have_request(void *opaque)
 static void nbd_reply_ready(void *opaque)
 {
     BDRVNBDState *s = opaque;
-    int i;
+    uint64_t i;
 
     if (s->reply.handle == 0) {
         /* No reply already in flight.  Fetch a header.  */
@@ -164,6 +164,10 @@ static void nbd_reply_ready(void *opaque)
      * handler acts as a synchronization point and ensures that only
      * one coroutine is called until the reply finishes.  */
     i = HANDLE_TO_INDEX(s, s->reply.handle);
+    if (i >= MAX_NBD_REQUESTS) {
+        goto fail;
+    }
+
     if (s->recv_coroutine[i]) {
         qemu_coroutine_enter(s->recv_coroutine[i], NULL);
         return;
commit adfe92f6d18c0e0a3694e19abb58eb55fd0c5993
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 12 14:00:53 2012 +0200

    posix-aio: merge posix_aio_process_queue and posix_aio_read
    
    posix_aio_read already calls qemu_aio_process_queue, and dually
    qemu_aio_process_queue is always followed by a select loop that calls
    posix_aio_read.
    
    No races are possible, so there is no need for a separate process_queue
    callback.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index d311d13..1066c60 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -468,26 +468,37 @@ static int qemu_paio_error(struct qemu_paiocb *aiocb)
     return ret;
 }
 
-static int posix_aio_process_queue(void *opaque)
+static void posix_aio_read(void *opaque)
 {
     PosixAioState *s = opaque;
     struct qemu_paiocb *acb, **pacb;
     int ret;
-    int result = 0;
+    ssize_t len;
+
+    /* read all bytes from signal pipe */
+    for (;;) {
+        char bytes[16];
+
+        len = read(s->rfd, bytes, sizeof(bytes));
+        if (len == -1 && errno == EINTR)
+            continue; /* try again */
+        if (len == sizeof(bytes))
+            continue; /* more to read */
+        break;
+    }
 
     for(;;) {
         pacb = &s->first_aio;
         for(;;) {
             acb = *pacb;
             if (!acb)
-                return result;
+                return;
 
             ret = qemu_paio_error(acb);
             if (ret == ECANCELED) {
                 /* remove the request */
                 *pacb = acb->next;
                 qemu_aio_release(acb);
-                result = 1;
             } else if (ret != EINPROGRESS) {
                 /* end of aio */
                 if (ret == 0) {
@@ -507,35 +518,12 @@ static int posix_aio_process_queue(void *opaque)
                 /* call the callback */
                 acb->common.cb(acb->common.opaque, ret);
                 qemu_aio_release(acb);
-                result = 1;
                 break;
             } else {
                 pacb = &acb->next;
             }
         }
     }
-
-    return result;
-}
-
-static void posix_aio_read(void *opaque)
-{
-    PosixAioState *s = opaque;
-    ssize_t len;
-
-    /* read all bytes from signal pipe */
-    for (;;) {
-        char bytes[16];
-
-        len = read(s->rfd, bytes, sizeof(bytes));
-        if (len == -1 && errno == EINTR)
-            continue; /* try again */
-        if (len == sizeof(bytes))
-            continue; /* more to read */
-        break;
-    }
-
-    posix_aio_process_queue(s);
 }
 
 static int posix_aio_flush(void *opaque)
@@ -676,7 +664,7 @@ int paio_init(void)
     fcntl(s->wfd, F_SETFL, O_NONBLOCK);
 
     qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush,
-        posix_aio_process_queue, s);
+        NULL, s);
 
     ret = pthread_attr_init(&attr);
     if (ret)
commit 8a83205d34fbd7b12061f4e85148eb4b587acdcc
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 12 14:00:52 2012 +0200

    qemu-tool: map vm_clock to rt_clock
    
    QED uses vm_clock timers so that images are not touched during and after
    migration.  This however does not apply to qemu-io and qemu-img.
    Treat vm_clock as a synonym for rt_clock there, and enable it.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-tool.c b/qemu-tool.c
index edb84f5..6579b00 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -61,7 +61,7 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
 
 int64_t cpu_get_clock(void)
 {
-    return 0;
+    return qemu_get_clock_ns(rt_clock);
 }
 
 int64_t cpu_get_icount(void)
@@ -87,7 +87,6 @@ int qemu_init_main_loop(void)
 {
     init_clocks();
     init_timer_alarm();
-    qemu_clock_enable(vm_clock, false);
     return main_loop_init();
 }
 
commit a5a5238ee49cd6a0f598f6f63a4a43dbe18d12b7
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 12 14:00:51 2012 +0200

    qemu-io: use main_loop_wait
    
    This will let timers run during aio_read and aio_write commands,
    though not during synchronous commands.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/cmd.c b/cmd.c
index 0806e18..7ffbb71 100644
--- a/cmd.c
+++ b/cmd.c
@@ -25,6 +25,7 @@
 
 #include "cmd.h"
 #include "qemu-aio.h"
+#include "main-loop.h"
 
 #define _(x)	x	/* not gettext support yet */
 
@@ -146,7 +147,7 @@ static void prep_fetchline(void *opaque)
 {
     int *fetchable = opaque;
 
-    qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+    qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
     *fetchable= 1;
 }
 
@@ -193,12 +194,11 @@ void command_loop(void)
         if (!prompted) {
             printf("%s", get_prompt());
             fflush(stdout);
-            qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
-                                    NULL, &fetchable);
+            qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
             prompted = 1;
         }
 
-        qemu_aio_wait();
+        main_loop_wait(false);
 
         if (!fetchable) {
             continue;
@@ -221,7 +221,7 @@ void command_loop(void)
         prompted = 0;
         fetchable = 0;
     }
-    qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+    qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
 }
 
 /* from libxcmd/input.c */
diff --git a/qemu-io.c b/qemu-io.c
index 3095a22..b48364f 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -15,6 +15,7 @@
 #include <libgen.h>
 
 #include "qemu-common.h"
+#include "main-loop.h"
 #include "block_int.h"
 #include "cmd.h"
 #include "trace/control.h"
@@ -295,7 +296,7 @@ static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
     bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
                    aio_rw_done, &async_ret);
     while (async_ret == NOT_DONE) {
-        qemu_aio_wait();
+        main_loop_wait(false);
     }
 
     *total = qiov->size;
@@ -309,7 +310,7 @@ static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
     bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
                     aio_rw_done, &async_ret);
     while (async_ret == NOT_DONE) {
-        qemu_aio_wait();
+        main_loop_wait(false);
     }
 
     *total = qiov->size;
@@ -352,7 +353,7 @@ static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
     }
 
     while (async_ret.num_done < num_reqs) {
-        qemu_aio_wait();
+        main_loop_wait(false);
     }
 
     return async_ret.error < 0 ? async_ret.error : 1;
commit 3e46d87d665bd9114f18e8d4a1b6de3641147775
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 15:43:41 2012 +0200

    scsi: add SANITIZE command
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index d847396..dbdb99c 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1200,6 +1200,7 @@ static const char *scsi_command_name(uint8_t cmd)
         [ UNMAP                    ] = "UNMAP",
         [ READ_TOC                 ] = "READ_TOC",
         [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
+        [ SANITIZE                 ] = "SANITIZE",
         [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
         [ LOG_SELECT               ] = "LOG_SELECT",
         [ LOG_SENSE                ] = "LOG_SENSE",
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 354ed7b..ca24192 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -78,6 +78,7 @@
 #define READ_TOC              0x43
 #define REPORT_DENSITY_SUPPORT 0x44
 #define GET_CONFIGURATION     0x46
+#define SANITIZE              0x48
 #define GET_EVENT_STATUS_NOTIFICATION 0x4a
 #define LOG_SELECT            0x4c
 #define LOG_SENSE             0x4d
commit f644a2904d5287332e4007f30c105a8622fb3db8
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Thu Apr 19 20:41:17 2012 +1000

    SCSI emulation: should tell the guest that we actually support thin provisioning
    
    Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
    [Actually, we should report it only if discard_granularity is nonzero.
     Older SBC drafts assigned 0 to thin provisioning and 1 to thick
     (resource-provisioned, they call it).  Newer drafts assign respectively
     1 and 2 - Paolo]
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 85a75c4..a029ab6 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -628,7 +628,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             outbuf[3] = buflen = 8;
             outbuf[4] = 0;
             outbuf[5] = 0x60; /* write_same 10/16 supported */
-            outbuf[6] = 0;
+            outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
             outbuf[7] = 0;
             break;
         }
commit c9e4d8284e1f3205aa3c05dc18932f9ca2c05f53
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Thu Apr 19 20:41:16 2012 +1000

    SCSI emulation: Support unmap via WRITE_SAME_10.
    
    This was added in SBC r26 in place of the reserved bits that were
    present up to that version.
    
    It is the same as WRITE_SAME_16 as far as QEMU is concerned.
    
    Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index fca31fa..85a75c4 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -627,7 +627,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         {
             outbuf[3] = buflen = 8;
             outbuf[4] = 0;
-            outbuf[5] = 0x40; /* write same with unmap supported */
+            outbuf[5] = 0x60; /* write_same 10/16 supported */
             outbuf[6] = 0;
             outbuf[7] = 0;
             break;
@@ -1558,10 +1558,11 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
             goto illegal_lba;
         }
         break;
+    case WRITE_SAME_10:
     case WRITE_SAME_16:
         len = r->req.cmd.xfer / s->qdev.blocksize;
 
-        DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
+        DPRINTF("WRITE SAME() (sector %" PRId64 ", count %d)\n",
                 r->req.cmd.lba, len);
 
         if (r->req.cmd.lba > s->qdev.max_lba) {
commit 6a2de0f2038349716049c9b9a972d6777c85424b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 10:28:15 2012 +0200

    scsi: advertise DPOFUA
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 2d9ac2d..fca31fa 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1093,14 +1093,15 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
     memset(outbuf, 0, r->req.cmd.xfer);
     p = outbuf;
 
-    dev_specific_param = 0x00;
     if (s->qdev.type == TYPE_DISK) {
+        dev_specific_param = 0x10; /* DPOFUA */
         if (bdrv_is_read_only(s->qdev.conf.bs)) {
             dev_specific_param |= 0x80; /* Readonly.  */
         }
     } else {
         /* MMC prescribes that CD/DVD drives have no block descriptors,
          * and defines no device-specific parameter.  */
+        dev_specific_param = 0x00;
         dbd = true;
     }
 
commit e590ecbed5da8716b83b348d26edb9e60b4e91c4
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 10:24:18 2012 +0200

    scsi: small refactoring of MMC mode-sense
    
    Make DBD a boolean value, and force device-specific parameter to zero.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 30ed3af..2d9ac2d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1080,11 +1080,12 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint64_t nb_sectors;
-    int page, dbd, buflen, ret, page_control;
+    bool dbd;
+    int page, buflen, ret, page_control;
     uint8_t *p;
     uint8_t dev_specific_param;
 
-    dbd = r->req.cmd.buf[1]  & 0x8;
+    dbd = (r->req.cmd.buf[1] & 0x8) != 0;
     page = r->req.cmd.buf[2] & 0x3f;
     page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
     DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
@@ -1092,10 +1093,15 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
     memset(outbuf, 0, r->req.cmd.xfer);
     p = outbuf;
 
-    if (bdrv_is_read_only(s->qdev.conf.bs)) {
-        dev_specific_param = 0x80; /* Readonly.  */
+    dev_specific_param = 0x00;
+    if (s->qdev.type == TYPE_DISK) {
+        if (bdrv_is_read_only(s->qdev.conf.bs)) {
+            dev_specific_param |= 0x80; /* Readonly.  */
+        }
     } else {
-        dev_specific_param = 0x00;
+        /* MMC prescribes that CD/DVD drives have no block descriptors,
+         * and defines no device-specific parameter.  */
+        dbd = true;
     }
 
     if (r->req.cmd.buf[0] == MODE_SENSE) {
@@ -1110,9 +1116,8 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
         p += 8;
     }
 
-    /* MMC prescribes that CD/DVD drives have no block descriptors.  */
     bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-    if (!dbd && s->qdev.type == TYPE_DISK && nb_sectors) {
+    if (!dbd && nb_sectors) {
         if (r->req.cmd.buf[0] == MODE_SENSE) {
             outbuf[3] = 8; /* Block descriptor length  */
         } else { /* MODE_SENSE_10 */
commit ac6684264642f1aea7cba5c0c3907409b1f7f904
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 11:55:28 2012 +0200

    scsi: support FUA on reads
    
    To force unit access on reads, flush the cache *before* doing the read.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 428d831..30ed3af 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -278,12 +278,48 @@ done:
     }
 }
 
+/* Actually issue a read to the block device.  */
+static void scsi_do_read(void *opaque, int ret)
+{
+    SCSIDiskReq *r = opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint32_t n;
+
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    if (r->req.sg) {
+        dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
+        r->req.resid -= r->req.sg->size;
+        r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
+                                     scsi_dma_complete, r);
+    } else {
+        n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+        r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
+                                      scsi_read_complete, r);
+    }
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
 /* Read more data from scsi device into buffer.  */
 static void scsi_read_data(SCSIRequest *req)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    uint32_t n;
+    bool first;
 
     if (r->sector_count == (uint32_t)-1) {
         DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
@@ -315,17 +351,13 @@ static void scsi_read_data(SCSIRequest *req)
         return;
     }
 
+    first = !r->started;
     r->started = true;
-    if (r->req.sg) {
-        dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
-        r->req.resid -= r->req.sg->size;
-        r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
-                                     scsi_dma_complete, r);
+    if (first && scsi_is_cmd_fua(&r->req.cmd)) {
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_do_read, r);
     } else {
-        n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
-        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
-        r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
-                                      scsi_read_complete, r);
+        scsi_do_read(r, 0);
     }
 }
 
commit a0e66a699e41f27cd70833045a71ddc52801dbb3
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 11:51:42 2012 +0200

    scsi: add a started field to SCSIDiskReq
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 09c2715..428d831 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -55,6 +55,7 @@ typedef struct SCSIDiskReq {
     uint64_t sector;
     uint32_t sector_count;
     uint32_t buflen;
+    bool started;
     struct iovec iov;
     QEMUIOVector qiov;
     BlockAcctCookie acct;
@@ -287,6 +288,7 @@ static void scsi_read_data(SCSIRequest *req)
     if (r->sector_count == (uint32_t)-1) {
         DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
         r->sector_count = 0;
+        r->started = true;
         scsi_req_data(&r->req, r->iov.iov_len);
         return;
     }
@@ -313,6 +315,7 @@ static void scsi_read_data(SCSIRequest *req)
         return;
     }
 
+    r->started = true;
     if (r->req.sg) {
         dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
         r->req.resid -= r->req.sg->size;
@@ -425,6 +428,7 @@ static void scsi_write_data(SCSIRequest *req)
 
     if (!r->req.sg && !r->qiov.size) {
         /* Called for the first time.  Ask the driver to send us more data.  */
+        r->started = true;
         scsi_write_complete(r, 0);
         return;
     }
commit 7f64f8e2c3c5a02636c2a6b8d6e6c5f7a62b89f7
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 11:46:13 2012 +0200

    scsi: force unit access on VERIFY
    
    Also DMA data from the host, to avoid that the host reports an
    underrun.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 7e6e17d..09c2715 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -185,6 +185,9 @@ static bool scsi_is_cmd_fua(SCSICommand *cmd)
     case WRITE_16:
         return (cmd->buf[1] & 8) != 0;
 
+    case VERIFY_10:
+    case VERIFY_12:
+    case VERIFY_16:
     case WRITE_VERIFY_10:
     case WRITE_VERIFY_12:
     case WRITE_VERIFY_16:
@@ -218,7 +221,10 @@ static void scsi_dma_complete(void *opaque, int ret)
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
 
-    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    }
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -427,6 +433,16 @@ static void scsi_write_data(SCSIRequest *req)
         return;
     }
 
+    if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
+        r->req.cmd.buf[0] == VERIFY_16) {
+        if (r->req.sg) {
+            scsi_dma_complete(r, 0);
+        } else {
+            scsi_write_complete(r, 0);
+        }
+        return;
+    }
+
     if (r->req.sg) {
         dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE);
         r->req.resid -= r->req.sg->size;
@@ -1350,8 +1366,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         }
         DPRINTF("Unsupported Service Action In\n");
         goto illegal_request;
-    case VERIFY_10:
-        break;
     default:
         scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
         return -1;
@@ -1435,7 +1449,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case MECHANISM_STATUS:
     case SERVICE_ACTION_IN_16:
     case REQUEST_SENSE:
-    case VERIFY_10:
         rc = scsi_disk_emulate_command(r);
         if (rc < 0) {
             return 0;
@@ -1461,6 +1474,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
         r->sector_count = len * (s->qdev.blocksize / 512);
         break;
+    case VERIFY_10:
+    case VERIFY_12:
+    case VERIFY_16:
     case WRITE_6:
     case WRITE_10:
     case WRITE_12:
@@ -1811,6 +1827,9 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
     case READ_10:
     case READ_12:
     case READ_16:
+    case VERIFY_10:
+    case VERIFY_12:
+    case VERIFY_16:
     case WRITE_6:
     case WRITE_10:
     case WRITE_12:
commit 3ed9902528d0ffd244310014f7dcdcb3df3e2a04
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Apr 18 15:12:01 2012 +0200

    block: allow interrupting a co_sleep_ns
    
    In the next patch we want to reenter the coroutine from
    block_job_cancel_sync and cancel the timer.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-coroutine-sleep.c b/qemu-coroutine-sleep.c
index fd65274..d7083ee 100644
--- a/qemu-coroutine-sleep.c
+++ b/qemu-coroutine-sleep.c
@@ -23,7 +23,6 @@ static void co_sleep_cb(void *opaque)
 {
     CoSleepCB *sleep_cb = opaque;
 
-    qemu_free_timer(sleep_cb->ts);
     qemu_coroutine_enter(sleep_cb->co, NULL);
 }
 
@@ -35,4 +34,6 @@ void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns)
     sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb);
     qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns);
     qemu_coroutine_yield();
+    qemu_del_timer(sleep_cb.ts);
+    qemu_free_timer(sleep_cb.ts);
 }
commit 2795ecf681107d55e4113592b3045ece5f6e7b3b
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Apr 18 16:27:06 2012 +0200

    qcow2: Fix return value of alloc_refcount_block
    
    Someone forgot something in commit 29c1a730... Documenting the right
    return value is not enough, you also need to actually return it in the
    code.
    
    This bug sometimes causes error return values even when everything has
    succeeded: The new offset of the refcount block is truncated to 32 bits
    and interpreted as signed. At least with small cluster sizes it's easy
    to get a negative return value this way.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index f39928a..565bd54 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -400,7 +400,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
         return ret;
     }
 
-    return new_block;
+    return 0;
 
 fail_table:
     g_free(new_table);
commit 8dc0a5e7a06c059683f9c379c0a4b0bbc20d5c74
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Apr 18 16:18:14 2012 +0200

    qcow2: Fix error handling in qcow2_alloc_cluster_offset
    
    If do_alloc_cluster_offset() fails, the error handling code tried to
    remove the request from the in-flight queue, to which it wasn't added
    yet, resulting in a NULL pointer dereference.
    
    m->nb_clusters really only becomes != 0 when the request is in the list.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index cbd224d..dcf70a2 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -931,7 +931,7 @@ again:
 fail:
     qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
 fail_put:
-    if (nb_clusters > 0) {
+    if (m->nb_clusters > 0) {
         QLIST_REMOVE(m, next_in_flight);
     }
     return ret;
commit e82dabd82e7a8ce0294bce829b3d2dd25eb3a514
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Mar 29 10:31:31 2012 +0100

    ide: convert ide_sector_write() to asynchronous I/O
    
    The IDE PIO write sector code path uses bdrv_write() and hence can make
    the guest unresponsive while the I/O request is in progress.  This patch
    converts ide_sector_write() to use bdrv_aio_writev() by using the
    BUSY_STAT bit to tell the guest that the request is in progress.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Reviewed-by: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
    Tested-by: Richard Davies <richard at arachsys.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9894b3b..a5216a6 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -688,40 +688,39 @@ static void ide_sector_write_timer_cb(void *opaque)
     ide_set_irq(s->bus);
 }
 
-void ide_sector_write(IDEState *s)
+static void ide_sector_write_cb(void *opaque, int ret)
 {
-    int64_t sector_num;
-    int ret, n, n1;
-
-    s->status = READY_STAT | SEEK_STAT;
-    sector_num = ide_get_sector(s);
-#if defined(DEBUG_IDE)
-    printf("write sector=%" PRId64 "\n", sector_num);
-#endif
-    n = s->nsector;
-    if (n > s->req_nb_sectors)
-        n = s->req_nb_sectors;
+    IDEState *s = opaque;
+    int n;
 
-    bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
-    ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
     bdrv_acct_done(s->bs, &s->acct);
 
+    s->pio_aiocb = NULL;
+    s->status &= ~BUSY_STAT;
+
     if (ret != 0) {
-        if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
+        if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY)) {
             return;
+        }
     }
 
+    n = s->nsector;
+    if (n > s->req_nb_sectors) {
+        n = s->req_nb_sectors;
+    }
     s->nsector -= n;
     if (s->nsector == 0) {
         /* no more sectors to write */
         ide_transfer_stop(s);
     } else {
-        n1 = s->nsector;
-        if (n1 > s->req_nb_sectors)
+        int n1 = s->nsector;
+        if (n1 > s->req_nb_sectors) {
             n1 = s->req_nb_sectors;
-        ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
+        }
+        ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
+                           ide_sector_write);
     }
-    ide_set_sector(s, sector_num + n);
+    ide_set_sector(s, ide_get_sector(s) + n);
 
     if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
         /* It seems there is a bug in the Windows 2000 installer HDD
@@ -737,6 +736,30 @@ void ide_sector_write(IDEState *s)
     }
 }
 
+void ide_sector_write(IDEState *s)
+{
+    int64_t sector_num;
+    int n;
+
+    s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
+    sector_num = ide_get_sector(s);
+#if defined(DEBUG_IDE)
+    printf("sector=%" PRId64 "\n", sector_num);
+#endif
+    n = s->nsector;
+    if (n > s->req_nb_sectors) {
+        n = s->req_nb_sectors;
+    }
+
+    s->iov.iov_base = s->io_buffer;
+    s->iov.iov_len  = n * BDRV_SECTOR_SIZE;
+    qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+    bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+    s->pio_aiocb = bdrv_aio_writev(s->bs, sector_num, &s->qiov, n,
+                                   ide_sector_write_cb, s);
+}
+
 static void ide_flush_cb(void *opaque, int ret)
 {
     IDEState *s = opaque;
commit bef0fd5958120542f126f2dedbfce65d8839a94d
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Mar 29 10:31:30 2012 +0100

    ide: convert ide_sector_read() to asynchronous I/O
    
    The IDE PIO interface currently uses bdrv_read() to perform reads
    synchronously.  Synchronous I/O in the vcpu thread is bad because it
    prevents the guest from executing code - it makes the guest
    unresponsive.
    
    This patch converts IDE PIO to use bdrv_aio_readv().  We simply need to
    use the BUSY_STAT status so the guest knows to wait while we are busy.
    
    The only external user of ide_sector_read() is restart behavior on I/O
    errors and it is not affected by this change.  We still need to restart
    I/O in the same way.
    
    Migration is also unaffected if I understand the code correctly.  We
    continue to use the same transfer function and the BUSY_STAT status
    should never be migrated since we flush I/O before migrating device
    state.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Reviewed-by: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
    Tested-by: Richard Davies <richard at arachsys.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 35723fd..9894b3b 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -471,40 +471,68 @@ static void ide_rw_error(IDEState *s) {
     ide_set_irq(s->bus);
 }
 
+static void ide_sector_read_cb(void *opaque, int ret)
+{
+    IDEState *s = opaque;
+    int n;
+
+    s->pio_aiocb = NULL;
+    s->status &= ~BUSY_STAT;
+
+    bdrv_acct_done(s->bs, &s->acct);
+    if (ret != 0) {
+        if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY |
+                                BM_STATUS_RETRY_READ)) {
+            return;
+        }
+    }
+
+    n = s->nsector;
+    if (n > s->req_nb_sectors) {
+        n = s->req_nb_sectors;
+    }
+
+    /* Allow the guest to read the io_buffer */
+    ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
+
+    ide_set_irq(s->bus);
+
+    ide_set_sector(s, ide_get_sector(s) + n);
+    s->nsector -= n;
+}
+
 void ide_sector_read(IDEState *s)
 {
     int64_t sector_num;
-    int ret, n;
+    int n;
 
     s->status = READY_STAT | SEEK_STAT;
     s->error = 0; /* not needed by IDE spec, but needed by Windows */
     sector_num = ide_get_sector(s);
     n = s->nsector;
+
     if (n == 0) {
-        /* no more sector to read from disk */
         ide_transfer_stop(s);
-    } else {
+        return;
+    }
+
+    s->status |= BUSY_STAT;
+
+    if (n > s->req_nb_sectors) {
+        n = s->req_nb_sectors;
+    }
+
 #if defined(DEBUG_IDE)
-        printf("read sector=%" PRId64 "\n", sector_num);
+    printf("sector=%" PRId64 "\n", sector_num);
 #endif
-        if (n > s->req_nb_sectors)
-            n = s->req_nb_sectors;
 
-        bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
-        ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
-        bdrv_acct_done(s->bs, &s->acct);
-        if (ret != 0) {
-            if (ide_handle_rw_error(s, -ret,
-                BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
-            {
-                return;
-            }
-        }
-        ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
-        ide_set_irq(s->bus);
-        ide_set_sector(s, sector_num + n);
-        s->nsector -= n;
-    }
+    s->iov.iov_base = s->io_buffer;
+    s->iov.iov_len  = n * BDRV_SECTOR_SIZE;
+    qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+    bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+    s->pio_aiocb = bdrv_aio_readv(s->bs, sector_num, &s->qiov, n,
+                                  ide_sector_read_cb, s);
 }
 
 static void dma_buf_commit(IDEState *s)
@@ -1765,6 +1793,12 @@ static void ide_reset(IDEState *s)
 #ifdef DEBUG_IDE
     printf("ide: reset\n");
 #endif
+
+    if (s->pio_aiocb) {
+        bdrv_aio_cancel(s->pio_aiocb);
+        s->pio_aiocb = NULL;
+    }
+
     if (s->drive_kind == IDE_CFATA)
         s->mult_sectors = 0;
     else
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 100efd3..f8a027d 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -385,6 +385,9 @@ struct IDEState {
     int cd_sector_size;
     int atapi_dma; /* true if dma is requested for the packet cmd */
     BlockAcctCookie acct;
+    BlockDriverAIOCB *pio_aiocb;
+    struct iovec iov;
+    QEMUIOVector qiov;
     /* ATA DMA state */
     int io_buffer_size;
     QEMUSGList sg;
commit 592fa07043095ba3141fb9d413693d3c202cba9a
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Apr 18 12:07:39 2012 +0200

    qemu-io: Add command line switch for cache mode
    
    To be used as in 'qemu-io -t writeback test.img'
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qemu-io.c b/qemu-io.c
index e6fcd77..3095a22 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1784,6 +1784,7 @@ static void usage(const char *name)
 "  -g, --growable       allow file to grow (only applies to protocols)\n"
 "  -m, --misalign       misalign allocations for O_DIRECT\n"
 "  -k, --native-aio     use kernel AIO implementation (on Linux only)\n"
+"  -t, --cache=MODE     use the given cache mode for the image\n"
 "  -T, --trace FILE     enable trace events listed in the given file\n"
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
@@ -1796,7 +1797,7 @@ int main(int argc, char **argv)
 {
     int readonly = 0;
     int growable = 0;
-    const char *sopt = "hVc:rsnmgkT:";
+    const char *sopt = "hVc:rsnmgkt:T:";
     const struct option lopt[] = {
         { "help", 0, NULL, 'h' },
         { "version", 0, NULL, 'V' },
@@ -1808,6 +1809,7 @@ int main(int argc, char **argv)
         { "misalign", 0, NULL, 'm' },
         { "growable", 0, NULL, 'g' },
         { "native-aio", 0, NULL, 'k' },
+        { "cache", 1, NULL, 't' },
         { "trace", 1, NULL, 'T' },
         { NULL, 0, NULL, 0 }
     };
@@ -1840,6 +1842,12 @@ int main(int argc, char **argv)
         case 'k':
             flags |= BDRV_O_NATIVE_AIO;
             break;
+        case 't':
+            if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
+                error_report("Invalid cache option: %s", optarg);
+                exit(1);
+            }
+            break;
         case 'T':
             if (!trace_backend_init(optarg, NULL)) {
                 exit(1); /* error message will have been printed */
commit 4e35b92a51571002a68d3be74b774546d9aefd19
Author: Stefan Weil <sw at weilnetz.de>
Date:   Tue Apr 17 19:41:08 2012 +0200

    block: Fix spelling in comment (ineffcient -> inefficient)
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/cow.c b/block/cow.c
index 8d3c9f8..a5a00eb 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -103,7 +103,7 @@ static int cow_open(BlockDriverState *bs, int flags)
 }
 
 /*
- * XXX(hch): right now these functions are extremely ineffcient.
+ * XXX(hch): right now these functions are extremely inefficient.
  * We should just read the whole bitmap we'll need in one go instead.
  */
 static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
commit 8ff9ae00da148ca98248eb2284ba432970e232ec
Author: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Date:   Tue Apr 17 16:23:44 2012 +0800

    iotests: fix error in 005
    
    According comment, we should not read again, we will write.
    
    Signed-off-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
index 74537db..b7970e3 100755
--- a/tests/qemu-iotests/005
+++ b/tests/qemu-iotests/005
@@ -65,7 +65,7 @@ $QEMU_IO -c "read 1024 4096" $TEST_IMG | _filter_qemu_io
 
 echo
 echo "small write"
-$QEMU_IO -c "read 8192 4096" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write 8192 4096" $TEST_IMG | _filter_qemu_io
 
 # success, all done
 echo "*** done"
diff --git a/tests/qemu-iotests/005.out b/tests/qemu-iotests/005.out
index 718a185..2d3e7df 100644
--- a/tests/qemu-iotests/005.out
+++ b/tests/qemu-iotests/005.out
@@ -8,6 +8,6 @@ read 4096/4096 bytes at offset 1024
 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
 small write
-read 4096/4096 bytes at offset 8192
+wrote 4096/4096 bytes at offset 8192
 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 *** done
commit 7094f12f868fc1b75b105bcc676e15964dab77af
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Apr 11 11:06:37 2012 +0200

    block: Drain requests in bdrv_close
    
    If an AIO request is in flight that refers to a BlockDriverState that
    has been closed and possibly even freed, more or less anything could
    happen. I have seen segfaults, -EBADF return values and qcow2 sometimes
    actually catches the situation in bdrv_close() and abort()s.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/block.c b/block.c
index c0c90f0..4b96654 100644
--- a/block.c
+++ b/block.c
@@ -816,6 +816,8 @@ void bdrv_close(BlockDriverState *bs)
         if (bs->job) {
             block_job_cancel_sync(bs->job);
         }
+        bdrv_drain_all();
+
         if (bs == bs_snapshots) {
             bs_snapshots = NULL;
         }
commit aafcdcc9ebd72b24bf8686f624ff98bb919de5fd
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Apr 11 10:45:51 2012 +0200

    qemu-iotests: Test bdrv_close while AIO is in flight
    
    If the BlockDriverState is closed/freed without draining the AIO
    requests first, the request coroutines may work on invalid data and file
    descriptors or have some dangling pointers that cause segfaults.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032
new file mode 100755
index 0000000..7155568
--- /dev/null
+++ b/tests/qemu-iotests/032
@@ -0,0 +1,69 @@
+#!/bin/bash
+#
+# Test that AIO requests are drained before an image is closed. This used
+# to segfault because the request coroutine kept running even after the
+# BlockDriverState was freed.
+#
+# Copyright (C) 2011 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+# This works for any image format (though unlikely to segfault for raw)
+_supported_fmt generic
+_supported_proto generic
+_supported_os Linux
+
+echo
+echo === Prepare image ===
+echo
+
+CLUSTER_SIZE=65536
+_make_test_img 64M
+
+# Allocate every other cluster so that afterwards a big write request will
+# actually loop a while and issue many I/O requests for the lower layer
+for i in $(seq 0 128 4096); do echo "write ${i}k 64k"; done | $QEMU_IO $TEST_IMG | _filter_qemu_io
+
+echo
+echo === AIO request during close ===
+echo
+$QEMU_IO -c "aio_write 0 4M" -c "close" $TEST_IMG | _filter_qemu_io
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/032.out b/tests/qemu-iotests/032.out
new file mode 100644
index 0000000..7272ac2
--- /dev/null
+++ b/tests/qemu-iotests/032.out
@@ -0,0 +1,78 @@
+QA output created by 032
+
+=== Prepare image ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io> wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 131072
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 262144
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 393216
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 524288
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 655360
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 786432
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 917504
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1048576
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1179648
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1310720
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1441792
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1572864
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1703936
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1835008
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1966080
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2097152
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2228224
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2359296
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2490368
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2621440
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2752512
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2883584
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3014656
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3145728
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3276800
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3407872
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3538944
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3670016
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3801088
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3932160
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 4063232
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 4194304
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> 
+=== AIO request during close ===
+
+wrote 4194304/4194304 bytes at offset 0
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 1742ede..92508a7 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -38,3 +38,4 @@
 029 rw auto quick
 030 rw auto
 031 rw auto quick
+032 rw auto
commit 7299550b252c2c88ae078030428435cf83315dd4
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Apr 11 11:21:25 2012 +0200

    qemu-iotests: Always filter cluster_size out in _make_test_img
    
    Some image formats do have a cluster size, others don't, but there are
    tests that work with both sets of images and currently we get failures
    because the qemu-img create output doesn't mention the cluster size for
    some formats.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/tests/qemu-iotests/013.out b/tests/qemu-iotests/013.out
index 3073e3f..0d57187 100644
--- a/tests/qemu-iotests/013.out
+++ b/tests/qemu-iotests/013.out
@@ -1,5 +1,5 @@
 QA output created by 013
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 
 Testing empty image
 
 At offset 0:
diff --git a/tests/qemu-iotests/014.out b/tests/qemu-iotests/014.out
index 8045613..0258d75 100644
--- a/tests/qemu-iotests/014.out
+++ b/tests/qemu-iotests/014.out
@@ -1,5 +1,5 @@
 QA output created by 014
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 
 Testing empty image:
 test2: With offset 0
 === Clusters to be compressed [1]
diff --git a/tests/qemu-iotests/015.out b/tests/qemu-iotests/015.out
index 3ba723d..d4b961c 100644
--- a/tests/qemu-iotests/015.out
+++ b/tests/qemu-iotests/015.out
@@ -1,7 +1,7 @@
 QA output created by 015
 
 creating image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=37748736 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=37748736 
 creating first snapshot
 wrote 37748736/37748736 bytes at offset 0
 36 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/019.out b/tests/qemu-iotests/019.out
index 241d30c..b51224b 100644
--- a/tests/qemu-iotests/019.out
+++ b/tests/qemu-iotests/019.out
@@ -1,5 +1,5 @@
 QA output created by 019
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 
 Filling base image
 
 === IO: pattern 42
@@ -269,7 +269,7 @@ qemu-io> wrote 65536/65536 bytes at offset 4296015872
 qemu-io> No errors were found on the image.
 Creating test image with backing file
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base' cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base' 
 Filling test image
 
 === IO: pattern 43
diff --git a/tests/qemu-iotests/022.out b/tests/qemu-iotests/022.out
index b900c71..aed86d5 100644
--- a/tests/qemu-iotests/022.out
+++ b/tests/qemu-iotests/022.out
@@ -1,5 +1,5 @@
 QA output created by 022
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 
 Testing empty image
 
 At offset 10485760:
diff --git a/tests/qemu-iotests/023.out b/tests/qemu-iotests/023.out
index 138434e..8a7c5b2 100644
--- a/tests/qemu-iotests/023.out
+++ b/tests/qemu-iotests/023.out
@@ -1,7 +1,7 @@
 QA output created by 023
 Creating new image; cluster size: 1024
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 
 Testing empty image
 
 At offset 0:
@@ -5664,7 +5664,7 @@ qemu-io> read 3072/3072 bytes at offset 4295491072
 qemu-io> No errors were found on the image.
 Creating another new image
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 
 More complex patterns
 
 test2: With offset 0
@@ -5887,7 +5887,7 @@ qemu-io> read 2048/2048 bytes at offset 4295001088
 qemu-io> No errors were found on the image.
 Creating new image; cluster size: 4096
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=4096 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 
 Testing empty image
 
 At offset 0:
@@ -12270,7 +12270,7 @@ qemu-io> read 12288/12288 bytes at offset 4301256704
 qemu-io> No errors were found on the image.
 Creating another new image
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=4096 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 
 More complex patterns
 
 test2: With offset 0
@@ -12493,7 +12493,7 @@ qemu-io> read 8192/8192 bytes at offset 4295102464
 qemu-io> No errors were found on the image.
 Creating new image; cluster size: 16384
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=16384 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 
 Testing empty image
 
 At offset 0:
@@ -18876,7 +18876,7 @@ qemu-io> read 49152/49152 bytes at offset 4395622400
 qemu-io> No errors were found on the image.
 Creating another new image
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=16384 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 
 More complex patterns
 
 test2: With offset 0
@@ -19099,7 +19099,7 @@ qemu-io> read 32768/32768 bytes at offset 4295507968
 qemu-io> No errors were found on the image.
 Creating new image; cluster size: 65536
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 
 Testing empty image
 
 At offset 0:
@@ -25482,7 +25482,7 @@ qemu-io> read 196608/196608 bytes at offset 5905547264
 qemu-io> No errors were found on the image.
 Creating another new image
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 
 More complex patterns
 
 test2: With offset 0
diff --git a/tests/qemu-iotests/024.out b/tests/qemu-iotests/024.out
index 4cee216..072207c 100644
--- a/tests/qemu-iotests/024.out
+++ b/tests/qemu-iotests/024.out
@@ -1,7 +1,7 @@
 QA output created by 024
 Creating backing file
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 === IO: pattern 0x11
 qemu-io> wrote 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -21,7 +21,7 @@ qemu-io> wrote 65536/65536 bytes at offset 917504
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 qemu-io> Creating new backing file
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 === IO: pattern 0x22
 qemu-io> wrote 131072/131072 bytes at offset 0
 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -33,7 +33,7 @@ qemu-io> wrote 131072/131072 bytes at offset 786432
 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 qemu-io> Creating COW image
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old' cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old' 
 === IO: pattern 0x33
 qemu-io> wrote 262144/262144 bytes at offset 0
 256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
index b503cf2..fb4f20e 100644
--- a/tests/qemu-iotests/026.out
+++ b/tests/qemu-iotests/026.out
@@ -1,63 +1,63 @@
 QA output created by 026
 Errors while writing 128 kB
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_update; errno: 5; imm: off; once: on; write 
 write failed: Input/output error
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_update; errno: 5; imm: off; once: on; write -b
 write failed: Input/output error
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_update; errno: 5; imm: off; once: off; write 
 write failed: Input/output error
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_update; errno: 5; imm: off; once: off; write -b
 write failed: Input/output error
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_update; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_update; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_update; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_update; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_load; errno: 5; imm: off; once: on; write 
 wrote 131072/131072 bytes at offset 0
@@ -65,7 +65,7 @@ wrote 131072/131072 bytes at offset 0
 write failed: Input/output error
 read failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_load; errno: 5; imm: off; once: on; write -b
 wrote 131072/131072 bytes at offset 0
@@ -73,7 +73,7 @@ wrote 131072/131072 bytes at offset 0
 write failed: Input/output error
 read failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_load; errno: 5; imm: off; once: off; write 
 wrote 131072/131072 bytes at offset 0
@@ -81,7 +81,7 @@ wrote 131072/131072 bytes at offset 0
 write failed: Input/output error
 read failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_load; errno: 5; imm: off; once: off; write -b
 wrote 131072/131072 bytes at offset 0
@@ -89,7 +89,7 @@ wrote 131072/131072 bytes at offset 0
 write failed: Input/output error
 read failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_load; errno: 28; imm: off; once: on; write 
 wrote 131072/131072 bytes at offset 0
@@ -97,7 +97,7 @@ wrote 131072/131072 bytes at offset 0
 write failed: No space left on device
 read failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_load; errno: 28; imm: off; once: on; write -b
 wrote 131072/131072 bytes at offset 0
@@ -105,7 +105,7 @@ wrote 131072/131072 bytes at offset 0
 write failed: No space left on device
 read failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_load; errno: 28; imm: off; once: off; write 
 wrote 131072/131072 bytes at offset 0
@@ -113,7 +113,7 @@ wrote 131072/131072 bytes at offset 0
 write failed: No space left on device
 read failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_load; errno: 28; imm: off; once: off; write -b
 wrote 131072/131072 bytes at offset 0
@@ -121,306 +121,306 @@ wrote 131072/131072 bytes at offset 0
 write failed: No space left on device
 read failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_update; errno: 5; imm: off; once: on; write 
 write failed: Input/output error
 
 128 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_update; errno: 5; imm: off; once: on; write -b
 write failed: Input/output error
 
 128 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_update; errno: 5; imm: off; once: off; write 
 write failed: Input/output error
 
 128 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_update; errno: 5; imm: off; once: off; write -b
 write failed: Input/output error
 
 128 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_update; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 
 128 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_update; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 
 128 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_update; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 
 128 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_update; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 
 128 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_alloc.write; errno: 5; imm: off; once: on; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b
 write failed: Input/output error
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_alloc.write; errno: 5; imm: off; once: off; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b
 write failed: Input/output error
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_alloc.write; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_alloc.write; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 
 1 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: write_aio; errno: 5; imm: off; once: on; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: write_aio; errno: 5; imm: off; once: on; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: write_aio; errno: 5; imm: off; once: off; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: write_aio; errno: 5; imm: off; once: off; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: write_aio; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: write_aio; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: write_aio; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: write_aio; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_load; errno: 5; imm: off; once: on; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_load; errno: 5; imm: off; once: on; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_load; errno: 5; imm: off; once: off; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_load; errno: 5; imm: off; once: off; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_load; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_load; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_load; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_load; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_update_part; errno: 5; imm: off; once: on; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_update_part; errno: 5; imm: off; once: on; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_update_part; errno: 5; imm: off; once: off; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_update_part; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_update_part; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_update_part; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc; errno: 5; imm: off; once: on; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc; errno: 5; imm: off; once: on; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc; errno: 5; imm: off; once: off; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: cluster_alloc; errno: 5; imm: off; once: on; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: cluster_alloc; errno: 5; imm: off; once: on; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: cluster_alloc; errno: 5; imm: off; once: off; write 
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: cluster_alloc; errno: 5; imm: off; once: off; write -b
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: cluster_alloc; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: cluster_alloc; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: cluster_alloc; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
@@ -428,116 +428,116 @@ No errors were found on the image.
 
 === Refcout table growth tests ===
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 
 55 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 
 251 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 
 10 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 
 23 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 
 10 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
 
 23 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write 
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write 
 write failed: No space left on device
 
 10 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b
 write failed: No space left on device
@@ -547,54 +547,54 @@ This means waste of disk space, but no harm to data.
 
 === L1 growth tests ===
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.alloc_table; errno: 5; imm: off; once: on
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.alloc_table; errno: 5; imm: off; once: off
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.alloc_table; errno: 28; imm: off; once: on
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.alloc_table; errno: 28; imm: off; once: off
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.write_table; errno: 5; imm: off; once: on
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.write_table; errno: 5; imm: off; once: off
 qcow2_free_clusters failed: Input/output error
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.write_table; errno: 28; imm: off; once: on
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.write_table; errno: 28; imm: off; once: off
 qcow2_free_clusters failed: No space left on device
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.activate_table; errno: 5; imm: off; once: on
 write failed: Input/output error
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.activate_table; errno: 5; imm: off; once: off
 qcow2_free_clusters failed: Input/output error
@@ -602,12 +602,12 @@ write failed: Input/output error
 
 96 leaked clusters were found on the image.
 This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.activate_table; errno: 28; imm: off; once: on
 write failed: No space left on device
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
 
 Event: l1_grow.activate_table; errno: 28; imm: off; once: off
 qcow2_free_clusters failed: No space left on device
diff --git a/tests/qemu-iotests/029.out b/tests/qemu-iotests/029.out
index c2ad30c..0eedb3a 100644
--- a/tests/qemu-iotests/029.out
+++ b/tests/qemu-iotests/029.out
@@ -1,9 +1,9 @@
 QA output created by 029
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
 wrote 4096/4096 bytes at offset 0
 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 cluster_size=1024 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 
 wrote 4194304/4194304 bytes at offset 0
 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
index 0f1bf68..e1a536e 100644
--- a/tests/qemu-iotests/031.out
+++ b/tests/qemu-iotests/031.out
@@ -2,7 +2,7 @@ QA output created by 031
 
 === Create image with unknown header extension ===
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
 magic                     0x514649fb
 version                   2
 backing_file_offset       0x0
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 4cb8dae..00ee754 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -58,7 +58,6 @@ _make_test_img()
     # extra qemu-img options can be added by tests
     # at least one argument (the image size) needs to be added
     local extra_img_options=""
-    local cluster_size_filter="s# cluster_size=[0-9]\\+##g"
     local image_size=$*
 
     if [ "$1" = "-b" ]; then
@@ -67,7 +66,6 @@ _make_test_img()
     fi
     if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
         extra_img_options="-o cluster_size=$CLUSTER_SIZE $extra_img_options"
-        cluster_size_filter=""
     fi
 
     # XXX(hch): have global image options?
@@ -76,7 +74,7 @@ _make_test_img()
     	sed -e "s#$TEST_DIR#TEST_DIR#g" | \
     	sed -e "s#$IMGFMT#IMGFMT#g" | \
 	sed -e "s# encryption=off##g" | \
-	sed -e "$cluster_size_filter" | \
+	sed -e "s# cluster_size=[0-9]\\+##g" | \
 	sed -e "s# table_size=0##g" | \
 	sed -e "s# compat6=off##g" | \
 	sed -e "s# static=off##g"
commit 7e8c49c56154ab5c45d4f07edf0c22728735da35
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 10:10:54 2012 +0200

    scsi: add support for FUA on writes
    
    To force unit access, add a flush operation after the actual write.
    WRITE AND VERIFY commands always flush according to SBC, so do it
    even though we do not perform the reread.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 158ed5b..7e6e17d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -174,6 +174,45 @@ done:
     }
 }
 
+static bool scsi_is_cmd_fua(SCSICommand *cmd)
+{
+    switch (cmd->buf[0]) {
+    case READ_10:
+    case READ_12:
+    case READ_16:
+    case WRITE_10:
+    case WRITE_12:
+    case WRITE_16:
+        return (cmd->buf[1] & 8) != 0;
+
+    case WRITE_VERIFY_10:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        return true;
+
+    case READ_6:
+    case WRITE_6:
+    default:
+        return false;
+    }
+}
+
+static void scsi_write_do_fua(SCSIDiskReq *r)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    if (scsi_is_cmd_fua(&r->req.cmd)) {
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
+        return;
+    }
+
+    scsi_req_complete(&r->req, GOOD);
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
 static void scsi_dma_complete(void *opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -189,7 +228,12 @@ static void scsi_dma_complete(void *opaque, int ret)
 
     r->sector += r->sector_count;
     r->sector_count = 0;
-    scsi_req_complete(&r->req, GOOD);
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        scsi_write_do_fua(r);
+        return;
+    } else {
+        scsi_req_complete(&r->req, GOOD);
+    }
 
 done:
     if (!r->req.io_canceled) {
@@ -342,7 +386,8 @@ static void scsi_write_complete(void * opaque, int ret)
     r->sector += n;
     r->sector_count -= n;
     if (r->sector_count == 0) {
-        scsi_req_complete(&r->req, GOOD);
+        scsi_write_do_fua(r);
+        return;
     } else {
         scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
         DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
commit b77912a77a613451e9aac9a12f721eb5e9f09185
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 10:05:04 2012 +0200

    scsi: move scsi_flush_complete around
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 1664793..158ed5b 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -153,7 +153,7 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
 }
 
-static void scsi_dma_complete(void *opaque, int ret)
+static void scsi_flush_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
@@ -166,8 +166,6 @@ static void scsi_dma_complete(void *opaque, int ret)
         }
     }
 
-    r->sector += r->sector_count;
-    r->sector_count = 0;
     scsi_req_complete(&r->req, GOOD);
 
 done:
@@ -176,16 +174,12 @@ done:
     }
 }
 
-static void scsi_read_complete(void * opaque, int ret)
+static void scsi_dma_complete(void *opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    int n;
 
-    if (r->req.aiocb != NULL) {
-        r->req.aiocb = NULL;
-        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    }
+    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -193,12 +187,9 @@ static void scsi_read_complete(void * opaque, int ret)
         }
     }
 
-    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
-
-    n = r->qiov.size / 512;
-    r->sector += n;
-    r->sector_count -= n;
-    scsi_req_data(&r->req, r->qiov.size);
+    r->sector += r->sector_count;
+    r->sector_count = 0;
+    scsi_req_complete(&r->req, GOOD);
 
 done:
     if (!r->req.io_canceled) {
@@ -206,12 +197,16 @@ done:
     }
 }
 
-static void scsi_flush_complete(void * opaque, int ret)
+static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    int n;
 
-    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    }
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -219,7 +214,12 @@ static void scsi_flush_complete(void * opaque, int ret)
         }
     }
 
-    scsi_req_complete(&r->req, GOOD);
+    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
+
+    n = r->qiov.size / 512;
+    r->sector += n;
+    r->sector_count -= n;
+    scsi_req_data(&r->req, r->qiov.size);
 
 done:
     if (!r->req.io_canceled) {
commit 80624c938d2d9d2b2cca56326876f213c31e1202
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 14:00:24 2012 +0200

    scsi: make code more homogeneous in AIO callback functions
    
    First scsi_flush_complete, like scsi_dma_complete, is always called with
    an active AIOCB.
    
    Second, always test for "ret < 0" to check for errors.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 792e9d0..1664793 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -160,7 +160,7 @@ static void scsi_dma_complete(void *opaque, int ret)
 
     bdrv_acct_done(s->qdev.conf.bs, &r->acct);
 
-    if (ret) {
+    if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
             goto done;
         }
@@ -187,7 +187,7 @@ static void scsi_read_complete(void * opaque, int ret)
         bdrv_acct_done(s->qdev.conf.bs, &r->acct);
     }
 
-    if (ret) {
+    if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
             goto done;
         }
@@ -211,10 +211,7 @@ static void scsi_flush_complete(void * opaque, int ret)
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
 
-    if (r->req.aiocb != NULL) {
-        r->req.aiocb = NULL;
-        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    }
+    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -335,7 +332,7 @@ static void scsi_write_complete(void * opaque, int ret)
         bdrv_acct_done(s->qdev.conf.bs, &r->acct);
     }
 
-    if (ret) {
+    if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
             goto done;
         }
commit b8aba8d7e3031ee3411a8e5eb07ac61f5b18f045
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Apr 19 10:09:49 2012 +0200

    scsi: add missing test for cancelled request
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9949786..792e9d0 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -171,7 +171,9 @@ static void scsi_dma_complete(void *opaque, int ret)
     scsi_req_complete(&r->req, GOOD);
 
 done:
-    scsi_req_unref(&r->req);
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
 }
 
 static void scsi_read_complete(void * opaque, int ret)
commit d2ad7dd46e72118a577e16b3c6dffdc43c961476
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Apr 6 10:39:46 2012 +0200

    virtio-scsi: add multiqueue capability
    
    Adding multiqueue is as simple as creating more than one virtqueues,
    and saving the queue number for each request.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 0d90d9c..e8328f4 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -129,12 +129,12 @@ typedef struct {
     VirtIOSCSIConf *conf;
 
     SCSIBus bus;
-    VirtQueue *ctrl_vq;
-    VirtQueue *event_vq;
-    VirtQueue *cmd_vq;
     uint32_t sense_size;
     uint32_t cdb_size;
     int resetting;
+    VirtQueue *ctrl_vq;
+    VirtQueue *event_vq;
+    VirtQueue *cmd_vqs[0];
 } VirtIOSCSI;
 
 typedef struct VirtIOSCSIReq {
@@ -240,8 +240,9 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
 static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
 {
     VirtIOSCSIReq *req = sreq->hba_private;
-    uint32_t n = 0;
+    uint32_t n = virtio_queue_get_id(req->vq) - 2;
 
+    assert(n < req->dev->conf->num_queues);
     qemu_put_be32s(f, &n);
     qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
 }
@@ -255,9 +256,9 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
 
     req = g_malloc(sizeof(*req));
     qemu_get_be32s(f, &n);
-    assert(n == 0);
+    assert(n < s->conf->num_queues);
     qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
-    virtio_scsi_parse_req(s, s->cmd_vq, req);
+    virtio_scsi_parse_req(s, s->cmd_vqs[n], req);
 
     scsi_req_ref(sreq);
     req->sreq = sreq;
@@ -584,10 +585,12 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
 {
     VirtIOSCSI *s;
     static int virtio_scsi_id;
+    size_t sz;
+    int i;
 
+    sz = sizeof(VirtIOSCSI) + proxyconf->num_queues * sizeof(VirtQueue *);
     s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
-                                         sizeof(VirtIOSCSIConfig),
-                                         sizeof(VirtIOSCSI));
+                                         sizeof(VirtIOSCSIConfig), sz);
 
     s->qdev = dev;
     s->conf = proxyconf;
@@ -602,8 +605,10 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
                                    virtio_scsi_handle_ctrl);
     s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
                                    NULL);
-    s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
-                                   virtio_scsi_handle_cmd);
+    for (i = 0; i < s->conf->num_queues; i++) {
+        s->cmd_vqs[i] = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+                                         virtio_scsi_handle_cmd);
+    }
 
     scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info);
     if (!dev->hotplugged) {
commit c80decdbd9ea679a17f6b0202ea1df0f840e4828
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Apr 6 10:38:37 2012 +0200

    virtio: add virtio_queue_get_id
    
    Serializing virtio-scsi requests needs a simple way to get from a
    VirtQueue to the number of the queue.  The virtio_queue_get_id
    provides this.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/virtio.c b/hw/virtio.c
index 064aecf..314abf8 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -624,6 +624,13 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n)
     return vdev->vq[n].vring.num;
 }
 
+int virtio_queue_get_id(VirtQueue *vq)
+{
+    VirtIODevice *vdev = vq->vdev;
+    assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_PCI_QUEUE_MAX]);
+    return vq - &vdev->vq[0];
+}
+
 void virtio_queue_notify_vq(VirtQueue *vq)
 {
     if (vq->vring.desc) {
diff --git a/hw/virtio.h b/hw/virtio.h
index 400c092..0aef7d1 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -229,6 +229,7 @@ target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n);
 uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
 void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
 VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
+int virtio_queue_get_id(VirtQueue *vq);
 EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
 EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
 void virtio_queue_notify_vq(VirtQueue *vq);
commit fcf104a74cb8d6d39dc935ab692afface3beab30
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Apr 6 10:20:43 2012 +0200

    virtio-scsi: prepare migration format for multiqueue
    
    In order to restore requests correctly from a multitude of virtqueues,
    we need to store the id of the request queue that each request came
    from.
    
    Do this even for single-queue, by storing a hard-coded zero, to
    simplify future implementation of multiqueue.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 45d54fa..0d90d9c 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -240,7 +240,9 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
 static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
 {
     VirtIOSCSIReq *req = sreq->hba_private;
+    uint32_t n = 0;
 
+    qemu_put_be32s(f, &n);
     qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
 }
 
@@ -249,8 +251,11 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
     SCSIBus *bus = sreq->bus;
     VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
     VirtIOSCSIReq *req;
+    uint32_t n;
 
     req = g_malloc(sizeof(*req));
+    qemu_get_be32s(f, &n);
+    assert(n == 0);
     qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
     virtio_scsi_parse_req(s, s->cmd_vq, req);
 
commit b7c8c35f0afb62efcacd18a64067fe164e3206b6
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Apr 6 14:12:42 2012 +0200

    scsi: fix memory leak
    
    scsibus_get_dev_path is leaking id if it is not NULL.  Fix it.
    
    Reported-by: Laszlo Ersek <lersek at redhat.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 8e76c5d..d847396 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1430,15 +1430,18 @@ static char *scsibus_get_dev_path(DeviceState *dev)
     SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
     DeviceState *hba = dev->parent_bus->parent;
     char *id = NULL;
+    char *path;
 
     if (hba && hba->parent_bus && hba->parent_bus->info->get_dev_path) {
         id = hba->parent_bus->info->get_dev_path(hba);
     }
     if (id) {
-        return g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
+        path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
     } else {
-        return g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
+        path = g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
     }
+    g_free(id);
+    return path;
 }
 
 static char *scsibus_get_fw_dev_path(DeviceState *dev)
commit 51006bbc45bc74977ae538190a53df2af534acb9
Merge: 25b9e14... 6e7a7f3...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Apr 18 10:05:58 2012 -0500

    Merge remote-tracking branch 'origin/master' into staging
    
    * origin/master:
      Allow controlling volume with PulseAudio backend
      configure: pa_simple is not needed anymore
      Do not use pa_simple PulseAudio API
      audio/spice: add support for volume control
      hw/ac97: add support for volume control
      hw/ac97: the volume mask is not only 0x1f
      hw/ac97: remove USE_MIXER code
      audio: don't apply volume effect if backend has VOICE_VOLUME_CAP
      audio: add VOICE_VOLUME ctl

commit 256a721d46a112d8807a488ec0176985c09bbbf1
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Apr 16 12:47:58 2012 +0100

    tracetool: handle DTrace keywords 'in', 'next', 'self'
    
    Language keywords cannot be used as argument names.  The DTrace backend
    appends an underscore to the argument name in order to make the argument
    name legal.
    
    This patch adds 'in', 'next', and 'self' keywords to dtrace.py.
    
    Also drop the unnecessary argument name lstrip() call.  The
    Arguments.build() method already ensures there is no space around
    argument names.  Furthermore it is misleading to do the lstrip() *after*
    checking against keywords because the keyword check would not match if
    spaces were in the name.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Reviewed-by: Alon Levy <alevy at redhat.com>
    Reviewed-by: Lluís Vilanova <vilanova at ac.upc.edu>

diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py
index cebbd57..9cab75c 100644
--- a/scripts/tracetool/backend/dtrace.py
+++ b/scripts/tracetool/backend/dtrace.py
@@ -86,10 +86,10 @@ def stap(events):
         i = 1
         if len(e.args) > 0:
             for name in e.args.names():
-                # 'limit' is a reserved keyword
-                if name == 'limit':
-                    name = '_limit'
-                out('  %s = $arg%d;' % (name.lstrip(), i))
+                # Append underscore to reserved keywords
+                if name in ('limit', 'in', 'next', 'self'):
+                    name += '_'
+                out('  %s = $arg%d;' % (name, i))
                 i += 1
 
         out('}')
commit f70fd8fdf646714c3f75d3b27a33f42caf856fc6
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Apr 3 20:48:17 2012 +0200

    tracetool: Add MAINTAINERS info
    
    Update the MAINTAINERS file to reflect the new Python tracetool code.
    
    [Commit description written by Stefan Hajnoczi]
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 922945c..cce37e7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -553,6 +553,8 @@ Tracing
 M: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
 S: Maintained
 F: trace/
+F: scripts/tracetool.py
+F: scripts/tracetool/
 F: docs/tracing.txt
 T: git://github.com/stefanha/qemu.git tracing
 
commit 52ef093aceddbe43dcc2cb4190e2178036dac60b
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Apr 3 20:48:12 2012 +0200

    tracetool: Add support for the 'dtrace' backend
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/scripts/tracetool.py b/scripts/tracetool.py
index fe2ea34..cacfd99 100755
--- a/scripts/tracetool.py
+++ b/scripts/tracetool.py
@@ -44,6 +44,11 @@ Options:
     --help                   This help message.
     --list-backends          Print list of available backends.
     --check-backend          Check if the given backend is valid.
+    --binary <path>          Full path to QEMU binary.
+    --target-type <type>     QEMU emulator target type ('system' or 'user').
+    --target-arch <arch>     QEMU emulator target arch.
+    --probe-prefix <prefix>  Prefix for dtrace probe names
+                             (default: qemu-<target-type>-<target-arch>).\
 """ % {
             "script" : _SCRIPT,
             "backends" : backend_descr,
@@ -71,6 +76,10 @@ def main(args):
     check_backend = False
     arg_backend = ""
     arg_format = ""
+    binary = None
+    target_type = None
+    target_arch = None
+    probe_prefix = None
     for opt, arg in opts:
         if opt == "--help":
             error_opt()
@@ -87,6 +96,15 @@ def main(args):
         elif opt == "--check-backend":
             check_backend = True
 
+        elif opt == "--binary":
+            binary = arg
+        elif opt == '--target-type':
+            target_type = arg
+        elif opt == '--target-arch':
+            target_arch = arg
+        elif opt == '--probe-prefix':
+            probe_prefix = arg
+
         else:
             error_opt("unhandled option: %s" % opt)
 
@@ -99,8 +117,20 @@ def main(args):
         else:
             sys.exit(1)
 
+    if arg_format == "stap":
+        if binary is None:
+            error_opt("--binary is required for SystemTAP tapset generator")
+        if probe_prefix is None and target_type is None:
+            error_opt("--target-type is required for SystemTAP tapset generator")
+        if probe_prefix is None and target_arch is None:
+            error_opt("--target-arch is required for SystemTAP tapset generator")
+
+        if probe_prefix is None:
+            probe_prefix = ".".join([ "qemu", target_type, target_arch ])
+
     try:
-        tracetool.generate(sys.stdin, arg_format, arg_backend)
+        tracetool.generate(sys.stdin, arg_format, arg_backend,
+                           binary = binary, probe_prefix = probe_prefix)
     except tracetool.TracetoolError as e:
         error_opt(str(e))
 
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
index 1719bb4..74fe21b 100644
--- a/scripts/tracetool/__init__.py
+++ b/scripts/tracetool/__init__.py
@@ -212,7 +212,8 @@ def try_import(mod_name, attr_name = None, attr_default = None):
         return False, None
 
 
-def generate(fevents, format, backend):
+def generate(fevents, format, backend,
+             binary = None, probe_prefix = None):
     """Generate the output for the given (format, backend) pair.
 
     Parameters
@@ -223,6 +224,10 @@ def generate(fevents, format, backend):
         Output format name.
     backend : str
         Output backend name.
+    binary : str or None
+        See tracetool.backend.dtrace.BINARY.
+    probe_prefix : str or None
+        See tracetool.backend.dtrace.PROBEPREFIX.
     """
     # fix strange python error (UnboundLocalError tracetool)
     import tracetool
@@ -245,6 +250,10 @@ def generate(fevents, format, backend):
         raise TracetoolError("backend '%s' not compatible with format '%s'" %
                              (backend, format))
 
+    import tracetool.backend.dtrace
+    tracetool.backend.dtrace.BINARY = binary
+    tracetool.backend.dtrace.PROBEPREFIX = probe_prefix
+
     events = _read_events(fevents)
 
     if backend == "nop":
diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py
new file mode 100644
index 0000000..cebbd57
--- /dev/null
+++ b/scripts/tracetool/backend/dtrace.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+DTrace/SystemTAP backend.
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+PROBEPREFIX = None
+
+def _probeprefix():
+    if PROBEPREFIX is None:
+        raise ValueError("you must set PROBEPREFIX")
+    return PROBEPREFIX
+
+
+BINARY = None
+
+def _binary():
+    if BINARY is None:
+        raise ValueError("you must set BINARY")
+    return BINARY
+
+
+def c(events):
+    pass
+
+
+def h(events):
+    out('#include "trace-dtrace.h"',
+        '')
+
+    for e in events:
+        out('static inline void trace_%(name)s(%(args)s) {',
+            '    QEMU_%(uppername)s(%(argnames)s);',
+            '}',
+            name = e.name,
+            args = e.args,
+            uppername = e.name.upper(),
+            argnames = ", ".join(e.args.names()),
+            )
+
+
+def d(events):
+    out('provider qemu {')
+
+    for e in events:
+        args = str(e.args)
+
+        # DTrace provider syntax expects foo() for empty
+        # params, not foo(void)
+        if args == 'void':
+            args = ''
+
+        # Define prototype for probe arguments
+        out('',
+            'probe %(name)s(%(args)s);',
+            name = e.name,
+            args = args,
+            )
+
+    out('',
+        '};')
+
+
+def stap(events):
+    for e in events:
+        # Define prototype for probe arguments
+        out('probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")',
+            '{',
+            probeprefix = _probeprefix(),
+            name = e.name,
+            binary = _binary(),
+            )
+
+        i = 1
+        if len(e.args) > 0:
+            for name in e.args.names():
+                # 'limit' is a reserved keyword
+                if name == 'limit':
+                    name = '_limit'
+                out('  %s = $arg%d;' % (name.lstrip(), i))
+                i += 1
+
+        out('}')
+
+    out()
diff --git a/scripts/tracetool/format/d.py b/scripts/tracetool/format/d.py
new file mode 100644
index 0000000..a2d5947
--- /dev/null
+++ b/scripts/tracetool/format/d.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .d file (DTrace only).
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+    out('/* This file is autogenerated by tracetool, do not edit. */')
diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py
new file mode 100644
index 0000000..50a4c69
--- /dev/null
+++ b/scripts/tracetool/format/stap.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .stp file (DTrace with SystemTAP only).
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+    out('/* This file is autogenerated by tracetool, do not edit. */')
commit fbc54b9412a905c460d0f5e9e0508d64f9e9759b
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Apr 3 20:48:06 2012 +0200

    tracetool: Add support for the 'ust' backend
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py
new file mode 100644
index 0000000..31a2ff0
--- /dev/null
+++ b/scripts/tracetool/backend/ust.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+LTTng User Space Tracing backend.
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+    out('#include <ust/marker.h>',
+        '#undef mutex_lock',
+        '#undef mutex_unlock',
+        '#undef inline',
+        '#undef wmb',
+        '#include "trace.h"')
+
+    for e in events:
+        argnames = ", ".join(e.args.names())
+        if len(e.args) > 0:
+            argnames = ', ' + argnames
+
+            out('DEFINE_TRACE(ust_%(name)s);',
+                '',
+                'static void ust_%(name)s_probe(%(args)s)',
+                '{',
+                '    trace_mark(ust, %(name)s, %(fmt)s%(argnames)s);',
+                '}',
+                name = e.name,
+                args = e.args,
+                fmt = e.fmt,
+                argnames = argnames,
+                )
+
+        else:
+            out('DEFINE_TRACE(ust_%(name)s);',
+                '',
+                'static void ust_%(name)s_probe(%(args)s)',
+                '{',
+                '    trace_mark(ust, %(name)s, UST_MARKER_NOARGS);',
+                '}',
+                name = e.name,
+                args = e.args,
+                )
+
+    # register probes
+    out('',
+        'static void __attribute__((constructor)) trace_init(void)',
+        '{')
+
+    for e in events:
+        out('    register_trace_ust_%(name)s(ust_%(name)s_probe);',
+            name = e.name,
+            )
+
+    out('}')
+
+
+def h(events):
+    out('#include <ust/tracepoint.h>',
+        '#undef mutex_lock',
+        '#undef mutex_unlock',
+        '#undef inline',
+        '#undef wmb')
+
+    for e in events:
+        if len(e.args) > 0:
+            out('DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s));',
+                '#define trace_%(name)s trace_ust_%(name)s',
+                name = e.name,
+                args = e.args,
+                argnames = ", ".join(e.args.names()),
+                )
+
+        else:
+            out('_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);',
+                '#define trace_%(name)s trace_ust_%(name)s',
+                name = e.name,
+                )
+
+    out()
commit dd03a39e8a5952fbb0d7a3960d45c33b726019a7
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Apr 3 20:48:01 2012 +0200

    tracetool: Add support for the 'simple' backend
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py
new file mode 100644
index 0000000..fbb5717
--- /dev/null
+++ b/scripts/tracetool/backend/simple.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Simple built-in backend.
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+    out('#include "trace.h"',
+        '',
+        'TraceEvent trace_list[] = {')
+
+    for e in events:
+        out('{.tp_name = "%(name)s", .state=0},',
+            name = e.name,
+            )
+
+    out('};')
+
+def h(events):
+    out('#include "trace/simple.h"',
+        '')
+
+    for num, e in enumerate(events):
+        if len(e.args):
+            argstr = e.args.names()
+            arg_prefix = ', (uint64_t)(uintptr_t)'
+            cast_args = arg_prefix + arg_prefix.join(argstr)
+            simple_args = (str(num) + cast_args)
+        else:
+            simple_args = str(num)
+
+        out('static inline void trace_%(name)s(%(args)s)',
+            '{',
+            '    trace%(argc)d(%(trace_args)s);',
+            '}',
+            name = e.name,
+            args = e.args,
+            argc = len(e.args),
+            trace_args = simple_args,
+            )
+
+    out('#define NR_TRACE_EVENTS %d' % len(events))
+    out('extern TraceEvent trace_list[NR_TRACE_EVENTS];')
commit 9008d85a96bb42ed40da6b4d70a0f14b9353f442
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Apr 3 20:47:55 2012 +0200

    tracetool: Add support for the 'stderr' backend
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/scripts/tracetool/backend/stderr.py b/scripts/tracetool/backend/stderr.py
new file mode 100644
index 0000000..917fde7
--- /dev/null
+++ b/scripts/tracetool/backend/stderr.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Stderr built-in backend.
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+    out('#include "trace.h"',
+        '',
+        'TraceEvent trace_list[] = {')
+
+    for e in events:
+        out('{.tp_name = "%(name)s", .state=0},',
+            name = e.name,
+            )
+
+    out('};')
+
+def h(events):
+    out('#include <stdio.h>',
+        '#include "trace/stderr.h"',
+        '',
+        'extern TraceEvent trace_list[];')
+
+    for num, e in enumerate(events):
+        argnames = ", ".join(e.args.names())
+        if len(e.args) > 0:
+            argnames = ", " + argnames
+
+        out('static inline void trace_%(name)s(%(args)s)',
+            '{',
+            '    if (trace_list[%(event_num)s].state != 0) {',
+            '        fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);',
+            '    }',
+            '}',
+            name = e.name,
+            args = e.args,
+            event_num = num,
+            fmt = e.fmt,
+            argnames = argnames,
+            )
+
+    out('',
+        '#define NR_TRACE_EVENTS %d' % len(events))
commit c419e62a037d44520b3d3a3849b919f8cdaf2249
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Apr 3 20:47:50 2012 +0200

    tracetool: Add module for the 'h' format
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py
new file mode 100644
index 0000000..6ffb3c2
--- /dev/null
+++ b/scripts/tracetool/format/h.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .h file.
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+    out('/* This file is autogenerated by tracetool, do not edit. */',
+        '',
+        '#ifndef TRACE_H',
+        '#define TRACE_H',
+        '',
+        '#include "qemu-common.h"')
+
+def end(events):
+    for e in events:
+        if "disable" in e.properties:
+            enabled = 0
+        else:
+            enabled = 1
+        out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled))
+    out('',
+        '#endif /* TRACE_H */')
+
+def nop(events):
+    for e in events:
+        out('',
+            'static inline void trace_%(name)s(%(args)s)',
+            '{',
+            '}',
+            name = e.name,
+            args = e.args,
+            )
commit 5de7f9c8eefcb42e5657817574b6f8b3b3720af2
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Apr 3 20:47:44 2012 +0200

    tracetool: Add module for the 'c' format
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py
new file mode 100644
index 0000000..35555ae
--- /dev/null
+++ b/scripts/tracetool/format/c.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .c file.
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+    out('/* This file is autogenerated by tracetool, do not edit. */')
commit 650ab98d1d9551f0ca2180c0d88427acfcb081cf
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Apr 3 20:47:39 2012 +0200

    tracetool: Rewrite infrastructure as python modules
    
    The tracetool script is written in shell and has hit several portability
    problems due to shell quirks or external tools across host platforms.
    Additionally the amount of string processing and lack of real data
    structures makes it tough to implement code generator backends for
    tracers that are more complex.
    
    This patch replaces the shell version of tracetool with a Python
    version.  The new tracetool design is:
    
      scripts/tracetool.py - top-level script
      scripts/tracetool/backend/ - tracer backends live here (simple, ust)
      scripts/tracetool/format/  - output formats live here (.c, .h)
    
    There is common code for trace-events definition parsing so that
    backends can focus on generating code rather than parsing input.
    
    Support for all existing backends (nop, stderr, simple, ust,
    and dtrace) is added back in follow-up patches.
    
    [Commit description written by Stefan Hajnoczi]
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/Makefile.objs b/Makefile.objs
index 5c3bcda..6d6f24d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -378,12 +378,12 @@ else
 trace.h: trace.h-timestamp
 endif
 trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=h --backend=$(TRACE_BACKEND) < $< > $@,"  GEN   trace.h")
 	@cmp -s $@ trace.h || cp $@ trace.h
 
 trace.c: trace.c-timestamp
 trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@,"  GEN   trace.c")
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=c --backend=$(TRACE_BACKEND) < $< > $@,"  GEN   trace.c")
 	@cmp -s $@ trace.c || cp $@ trace.c
 
 trace.o: trace.c $(GENERATED_HEADERS)
@@ -396,7 +396,7 @@ trace-dtrace.h: trace-dtrace.dtrace
 # rule file. So we use '.dtrace' instead
 trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
 trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=d --backend=$(TRACE_BACKEND) < $< > $@,"  GEN   trace-dtrace.dtrace")
 	@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
 
 trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
diff --git a/Makefile.target b/Makefile.target
index 84951a0..a0540cd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -59,12 +59,13 @@ TARGET_TYPE=system
 endif
 
 $(QEMU_PROG).stp: $(SRC_PATH)/trace-events
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \
-		--$(TRACE_BACKEND) \
-		--binary $(bindir)/$(QEMU_PROG) \
-		--target-arch $(TARGET_ARCH) \
-		--target-type $(TARGET_TYPE) \
-		--stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp,"  GEN   $(QEMU_PROG).stp")
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \
+		--format=stap \
+		--backend=$(TRACE_BACKEND) \
+		--binary=$(bindir)/$(QEMU_PROG) \
+		--target-arch=$(TARGET_ARCH) \
+		--target-type=$(TARGET_TYPE) \
+		< $(SRC_PATH)/trace-events > $(QEMU_PROG).stp,"  GEN   $(QEMU_PROG).stp")
 else
 stap:
 endif
diff --git a/configure b/configure
index 2d62d12..03b49f6 100755
--- a/configure
+++ b/configure
@@ -1097,7 +1097,7 @@ 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 "  --enable-trace-backend=B Set trace backend"
-echo "                           Available backends:" $("$source_path"/scripts/tracetool --list-backends)
+echo "                           Available backends:" $($python "$source_path"/scripts/tracetool.py --list-backends)
 echo "  --with-trace-file=NAME   Full PATH,NAME of file to store traces"
 echo "                           Default:trace-<pid>"
 echo "  --disable-spice          disable spice"
@@ -2670,7 +2670,7 @@ fi
 ##########################################
 # check if trace backend exists
 
-sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
+$python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend  > /dev/null 2> /dev/null
 if test "$?" -ne 0 ; then
   echo
   echo "Error: invalid trace backend"
diff --git a/scripts/tracetool b/scripts/tracetool
deleted file mode 100755
index 7b1c142..0000000
--- a/scripts/tracetool
+++ /dev/null
@@ -1,666 +0,0 @@
-#!/bin/sh
-#
-# Code generator for trace events
-#
-# Copyright IBM, Corp. 2010
-#
-# This work is licensed under the terms of the GNU GPL, version 2.  See
-# the COPYING file in the top-level directory.
-
-# Disable pathname expansion, makes processing text with '*' characters simpler
-set -f
-
-usage()
-{
-    cat >&2 <<EOF
-usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
-Generate tracing code for a file on stdin.
-
-Backends:
-  --nop     Tracing disabled
-  --simple  Simple built-in backend
-  --stderr  Stderr built-in backend
-  --ust     LTTng User Space Tracing backend
-  --dtrace  DTrace/SystemTAP backend
-
-Output formats:
-  -h     Generate .h file
-  -c     Generate .c file
-  -d     Generate .d file (DTrace only)
-  --stap Generate .stp file (DTrace with SystemTAP only)
-
-Options:
-  --binary       [path]    Full path to QEMU binary
-  --target-arch  [arch]    QEMU emulator target arch
-  --target-type  [type]    QEMU emulator target type ('system' or 'user')
-  --probe-prefix [prefix]  Prefix for dtrace probe names
-                           (default: qemu-\$targettype-\$targetarch)
-
-EOF
-    exit 1
-}
-
-# Print a line without interpreting backslash escapes
-#
-# The built-in echo command may interpret backslash escapes without an option
-# to disable this behavior.
-puts()
-{
-    printf "%s\n" "$1"
-}
-
-# Get the name of a trace event
-get_name()
-{
-    local name
-    name=${1%%\(*}
-    echo "${name##* }"
-}
-
-# Get the given property of a trace event
-# 1: trace-events line
-# 2: property name
-# -> return 0 if property is present, or 1 otherwise
-has_property()
-{
-    local props prop
-    props=${1%%\(*}
-    props=${props% *}
-    for prop in $props; do
-        if [ "$prop" = "$2" ]; then
-            return 0
-        fi
-    done
-    return 1
-}
-
-# Get the argument list of a trace event, including types and names
-get_args()
-{
-    local args
-    args=${1#*\(}
-    args=${args%%\)*}
-    echo "$args"
-
-    if (echo "$args" | grep "[ *]next\($\|[, ]\)" > /dev/null 2>&1); then
-        echo -e "\n#error 'next' is a bad argument name (clash with systemtap keyword)\n "
-    fi
-}
-
-# Get the argument name list of a trace event
-get_argnames()
-{
-    local nfields field name sep
-    nfields=0
-    sep="$2"
-    for field in $(get_args "$1"); do
-        nfields=$((nfields + 1))
-
-        # Drop pointer star
-        field=${field#\*}
-
-        # Only argument names have commas at the end
-        name=${field%,}
-        test "$field" = "$name" && continue
-
-        printf "%s%s " $name $sep
-    done
-
-    # Last argument name
-    if [ "$nfields" -gt 1 ]
-    then
-        printf "%s" "$name"
-    fi
-}
-
-# Get the number of arguments to a trace event
-get_argc()
-{
-    local name argc
-    argc=0
-    for name in $(get_argnames "$1", ","); do
-        argc=$((argc + 1))
-    done
-    echo $argc
-}
-
-# Get the format string including double quotes for a trace event
-get_fmt()
-{
-    puts "${1#*)}"
-}
-
-linetoh_begin_nop()
-{
-    return
-}
-
-linetoh_nop()
-{
-    local name args
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-
-    # Define an empty function for the trace event
-    cat <<EOF
-static inline void trace_$name($args)
-{
-}
-EOF
-}
-
-linetoh_end_nop()
-{
-    return
-}
-
-linetoc_begin_nop()
-{
-    return
-}
-
-linetoc_nop()
-{
-    # No need for function definitions in nop backend
-    return
-}
-
-linetod_nop()
-{
-    # Used when "disabled" events are processed
-    return
-}
-
-linetostap_nop()
-{
-    # Used when "disabled" events are processed
-    return
-}
-
-linetoc_end_nop()
-{
-    return
-}
-
-linetoh_begin_simple()
-{
-    cat <<EOF
-#include "trace/simple.h"
-EOF
-
-    simple_event_num=0
-}
-
-cast_args_to_uint64_t()
-{
-    local arg
-    for arg in $(get_argnames "$1", ","); do
-        printf "%s" "(uint64_t)(uintptr_t)$arg"
-    done
-}
-
-linetoh_simple()
-{
-    local name args argc trace_args
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argc=$(get_argc "$1")
-
-    trace_args="$simple_event_num"
-    if [ "$argc" -gt 0 ]
-    then
-        trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
-    fi
-
-    cat <<EOF
-static inline void trace_$name($args)
-{
-    trace$argc($trace_args);
-}
-EOF
-
-    simple_event_num=$((simple_event_num + 1))
-}
-
-linetoh_end_simple()
-{
-    cat <<EOF
-#define NR_TRACE_EVENTS $simple_event_num
-extern TraceEvent trace_list[NR_TRACE_EVENTS];
-EOF
-}
-
-linetoc_begin_simple()
-{
-    cat <<EOF
-#include "trace.h"
-
-TraceEvent trace_list[] = {
-EOF
-    simple_event_num=0
-
-}
-
-linetoc_simple()
-{
-    local name
-    name=$(get_name "$1")
-    cat <<EOF
-{.tp_name = "$name", .state=0},
-EOF
-    simple_event_num=$((simple_event_num + 1))
-}
-
-linetoc_end_simple()
-{
-    cat <<EOF
-};
-EOF
-}
-
-#STDERR
-linetoh_begin_stderr()
-{
-    cat <<EOF
-#include <stdio.h>
-#include "trace/stderr.h"
-
-extern TraceEvent trace_list[];
-EOF
-
-    stderr_event_num=0
-}
-
-linetoh_stderr()
-{
-    local name args argnames argc fmt
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argnames=$(get_argnames "$1" ",")
-    argc=$(get_argc "$1")
-    fmt=$(get_fmt "$1")
-
-    if [ "$argc" -gt 0 ]; then
-        argnames=", $argnames"
-    fi
-
-    cat <<EOF
-static inline void trace_$name($args)
-{
-    if (trace_list[$stderr_event_num].state != 0) {
-        fprintf(stderr, "$name " $fmt "\n" $argnames);
-    }
-}
-EOF
-    stderr_event_num=$((stderr_event_num + 1))
-
-}
-
-linetoh_end_stderr()
-{
-    cat <<EOF
-#define NR_TRACE_EVENTS $stderr_event_num
-EOF
-}
-
-linetoc_begin_stderr()
-{
-    cat <<EOF
-#include "trace.h"
-
-TraceEvent trace_list[] = {
-EOF
-    stderr_event_num=0
-}
-
-linetoc_stderr()
-{
-    local name
-    name=$(get_name "$1")
-    cat <<EOF
-{.tp_name = "$name", .state=0},
-EOF
-    stderr_event_num=$(($stderr_event_num + 1))
-}
-
-linetoc_end_stderr()
-{
-    cat <<EOF
-};
-EOF
-}
-#END OF STDERR
-
-# Clean up after UST headers which pollute the namespace
-ust_clean_namespace() {
-    cat <<EOF
-#undef mutex_lock
-#undef mutex_unlock
-#undef inline
-#undef wmb
-EOF
-}
-
-linetoh_begin_ust()
-{
-    echo "#include <ust/tracepoint.h>"
-    ust_clean_namespace
-}
-
-linetoh_ust()
-{
-    local name args argnames
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argnames=$(get_argnames "$1", ",")
-
-    cat <<EOF
-DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
-#define trace_$name trace_ust_$name
-EOF
-}
-
-linetoh_end_ust()
-{
-    return
-}
-
-linetoc_begin_ust()
-{
-    cat <<EOF
-#include <ust/marker.h>
-$(ust_clean_namespace)
-#include "trace.h"
-EOF
-}
-
-linetoc_ust()
-{
-    local name args argnames fmt
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argnames=$(get_argnames "$1", ",")
-    [ -z "$argnames" ] || argnames=", $argnames"
-    fmt=$(get_fmt "$1")
-
-    cat <<EOF
-DEFINE_TRACE(ust_$name);
-
-static void ust_${name}_probe($args)
-{
-    trace_mark(ust, $name, $fmt$argnames);
-}
-EOF
-
-    # Collect names for later
-    names="$names $name"
-}
-
-linetoc_end_ust()
-{
-    cat <<EOF
-static void __attribute__((constructor)) trace_init(void)
-{
-EOF
-
-    for name in $names; do
-        cat <<EOF
-    register_trace_ust_$name(ust_${name}_probe);
-EOF
-    done
-
-    echo "}"
-}
-
-linetoh_begin_dtrace()
-{
-    cat <<EOF
-#include "trace-dtrace.h"
-EOF
-}
-
-linetoh_dtrace()
-{
-    local name args argnames nameupper
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argnames=$(get_argnames "$1", ",")
-
-    nameupper=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
-
-    # Define an empty function for the trace event
-    cat <<EOF
-static inline void trace_$name($args) {
-    QEMU_${nameupper}($argnames);
-}
-EOF
-}
-
-linetoh_end_dtrace()
-{
-    return
-}
-
-linetoc_begin_dtrace()
-{
-    return
-}
-
-linetoc_dtrace()
-{
-    # No need for function definitions in dtrace backend
-    return
-}
-
-linetoc_end_dtrace()
-{
-    return
-}
-
-linetod_begin_dtrace()
-{
-    cat <<EOF
-provider qemu {
-EOF
-}
-
-linetod_dtrace()
-{
-    local name args
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-
-    # DTrace provider syntax expects foo() for empty
-    # params, not foo(void)
-    if [ "$args" = "void" ]; then
-       args=""
-    fi
-
-    # Define prototype for probe arguments
-    cat <<EOF
-        probe $name($args);
-EOF
-}
-
-linetod_end_dtrace()
-{
-    cat <<EOF
-};
-EOF
-}
-
-linetostap_begin_dtrace()
-{
-    return
-}
-
-linetostap_dtrace()
-{
-    local i arg name args arglist
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    arglist=$(get_argnames "$1", "")
-
-    # Define prototype for probe arguments
-    cat <<EOF
-probe $probeprefix.$name = process("$binary").mark("$name")
-{
-EOF
-
-    i=1
-    for arg in $arglist
-    do
-        # postfix reserved words with '_'
-        case "$arg" in
-            limit|in|next|self)
-                arg="${arg}_"
-                ;;
-        esac
-        cat <<EOF
-  $arg = \$arg$i;
-EOF
-        i="$((i+1))"
-    done
-
-    cat <<EOF
-}
-EOF
-}
-
-linetostap_end_dtrace()
-{
-    return
-}
-
-# Process stdin by calling begin, line, and end functions for the backend
-convert()
-{
-    local begin process_line end str name NAME enabled
-    begin="lineto$1_begin_$backend"
-    process_line="lineto$1_$backend"
-    end="lineto$1_end_$backend"
-
-    "$begin"
-
-    while read -r str; do
-        # Skip comments and empty lines
-        test -z "${str%%#*}" && continue
-
-        echo
-        # Process the line.  The nop backend handles disabled lines.
-        if has_property "$str" "disable"; then
-            "lineto$1_nop" "$str"
-            enabled=0
-        else
-            "$process_line" "$str"
-            enabled=1
-        fi
-        if [ "$1" = "h" ]; then
-            name=$(get_name "$str")
-            NAME=$(echo $name | LC_ALL=C tr '[a-z]' '[A-Z]')
-            echo "#define TRACE_${NAME}_ENABLED ${enabled}"
-        fi
-    done
-
-    echo
-    "$end"
-}
-
-tracetoh()
-{
-    cat <<EOF
-#ifndef TRACE_H
-#define TRACE_H
-
-/* This file is autogenerated by tracetool, do not edit. */
-
-#include "qemu-common.h"
-EOF
-    convert h
-    echo "#endif /* TRACE_H */"
-}
-
-tracetoc()
-{
-    echo "/* This file is autogenerated by tracetool, do not edit. */"
-    convert c
-}
-
-tracetod()
-{
-    if [ $backend != "dtrace" ]; then
-       echo "DTrace probe generator not applicable to $backend backend"
-       exit 1
-    fi
-    echo "/* This file is autogenerated by tracetool, do not edit. */"
-    convert d
-}
-
-tracetostap()
-{
-    if [ $backend != "dtrace" ]; then
-       echo "SystemTAP tapset generator not applicable to $backend backend"
-       exit 1
-    fi
-    if [ -z "$binary" ]; then
-       echo "--binary is required for SystemTAP tapset generator"
-       exit 1
-    fi
-    if [ -z "$probeprefix" -a -z "$targettype" ]; then
-       echo "--target-type is required for SystemTAP tapset generator"
-       exit 1
-    fi
-    if [ -z "$probeprefix" -a -z "$targetarch" ]; then
-       echo "--target-arch is required for SystemTAP tapset generator"
-       exit 1
-    fi
-    if [ -z "$probeprefix" ]; then
-        probeprefix="qemu.$targettype.$targetarch";
-    fi
-    echo "/* This file is autogenerated by tracetool, do not edit. */"
-    convert stap
-}
-
-
-backend=
-output=
-binary=
-targettype=
-targetarch=
-probeprefix=
-
-
-until [ -z "$1" ]
-do
-  case "$1" in
-    "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
-
-    "--binary") shift ; binary="$1" ;;
-    "--target-arch") shift ; targetarch="$1" ;;
-    "--target-type") shift ; targettype="$1" ;;
-    "--probe-prefix") shift ; probeprefix="$1" ;;
-
-    "-h" | "-c" | "-d") output="${1#-}" ;;
-    "--stap") output="${1#--}" ;;
-
-    "--check-backend") exit 0 ;; # used by ./configure to test for backend
-
-    "--list-backends") # used by ./configure to list available backends
-          echo "nop simple stderr ust dtrace"
-          exit 0
-          ;;
-
-    *)
-      usage;;
-  esac
-  shift
-done
-
-if [ "$backend" = "" -o "$output" = "" ]; then
-  usage
-fi
-
-gen="traceto$output"
-"$gen"
-
-exit 0
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
new file mode 100755
index 0000000..fe2ea34
--- /dev/null
+++ b/scripts/tracetool.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Command-line wrapper for the tracetool machinery.
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+import sys
+import getopt
+
+from tracetool import error_write, out
+import tracetool.backend
+import tracetool.format
+
+
+_SCRIPT = ""
+
+def error_opt(msg = None):
+    if msg is not None:
+        error_write("Error: " + msg + "\n")
+
+    backend_descr = "\n".join([ "    %-15s %s" % (n, d)
+                                for n,d in tracetool.backend.get_list() ])
+    format_descr = "\n".join([ "    %-15s %s" % (n, d)
+                               for n,d in tracetool.format.get_list() ])
+    error_write("""\
+Usage: %(script)s --format=<format> --backend=<backend> [<options>]
+
+Backends:
+%(backends)s
+
+Formats:
+%(formats)s
+
+Options:
+    --help                   This help message.
+    --list-backends          Print list of available backends.
+    --check-backend          Check if the given backend is valid.
+""" % {
+            "script" : _SCRIPT,
+            "backends" : backend_descr,
+            "formats" : format_descr,
+            })
+
+    if msg is None:
+        sys.exit(0)
+    else:
+        sys.exit(1)
+
+
+def main(args):
+    global _SCRIPT
+    _SCRIPT = args[0]
+
+    long_opts  = [ "backend=", "format=", "help", "list-backends", "check-backend" ]
+    long_opts += [ "binary=", "target-type=", "target-arch=", "probe-prefix=" ]
+
+    try:
+        opts, args = getopt.getopt(args[1:], "", long_opts)
+    except getopt.GetoptError as err:
+        error_opt(str(err))
+
+    check_backend = False
+    arg_backend = ""
+    arg_format = ""
+    for opt, arg in opts:
+        if opt == "--help":
+            error_opt()
+
+        elif opt == "--backend":
+            arg_backend = arg
+        elif opt == "--format":
+            arg_format = arg
+
+        elif opt == "--list-backends":
+            backends = tracetool.backend.get_list()
+            out(", ".join([ b for b,_ in backends ]))
+            sys.exit(0)
+        elif opt == "--check-backend":
+            check_backend = True
+
+        else:
+            error_opt("unhandled option: %s" % opt)
+
+    if arg_backend is None:
+        error_opt("backend not set")
+
+    if check_backend:
+        if tracetool.backend.exists(arg_backend):
+            sys.exit(0)
+        else:
+            sys.exit(1)
+
+    try:
+        tracetool.generate(sys.stdin, arg_format, arg_backend)
+    except tracetool.TracetoolError as e:
+        error_opt(str(e))
+
+if __name__ == "__main__":
+    main(sys.argv)
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
new file mode 100644
index 0000000..1719bb4
--- /dev/null
+++ b/scripts/tracetool/__init__.py
@@ -0,0 +1,262 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Machinery for generating tracing-related intermediate files.
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+import re
+import sys
+
+import tracetool.format
+import tracetool.backend
+
+
+def error_write(*lines):
+    """Write a set of error lines."""
+    sys.stderr.writelines("\n".join(lines) + "\n")
+
+def error(*lines):
+    """Write a set of error lines and exit."""
+    error_write(*lines)
+    sys.exit(1)
+
+
+def out(*lines, **kwargs):
+    """Write a set of output lines.
+
+    You can use kwargs as a shorthand for mapping variables when formating all
+    the strings in lines.
+    """
+    lines = [ l % kwargs for l in lines ]
+    sys.stdout.writelines("\n".join(lines) + "\n")
+
+
+class Arguments:
+    """Event arguments description."""
+
+    def __init__(self, args):
+        """
+        Parameters
+        ----------
+        args :
+            List of (type, name) tuples.
+        """
+        self._args = args
+
+    @staticmethod
+    def build(arg_str):
+        """Build and Arguments instance from an argument string.
+
+        Parameters
+        ----------
+        arg_str : str
+            String describing the event arguments.
+        """
+        res = []
+        for arg in arg_str.split(","):
+            arg = arg.strip()
+            parts = arg.split()
+            head, sep, tail = parts[-1].rpartition("*")
+            parts = parts[:-1]
+            if tail == "void":
+                assert len(parts) == 0 and sep == ""
+                continue
+            arg_type = " ".join(parts + [ " ".join([head, sep]).strip() ]).strip()
+            res.append((arg_type, tail))
+        return Arguments(res)
+
+    def __iter__(self):
+        """Iterate over the (type, name) pairs."""
+        return iter(self._args)
+
+    def __len__(self):
+        """Number of arguments."""
+        return len(self._args)
+
+    def __str__(self):
+        """String suitable for declaring function arguments."""
+        if len(self._args) == 0:
+            return "void"
+        else:
+            return ", ".join([ " ".join([t, n]) for t,n in self._args ])
+
+    def __repr__(self):
+        """Evaluable string representation for this object."""
+        return "Arguments(\"%s\")" % str(self)
+
+    def names(self):
+        """List of argument names."""
+        return [ name for _, name in self._args ]
+
+    def types(self):
+        """List of argument types."""
+        return [ type_ for type_, _ in self._args ]
+
+
+class Event(object):
+    """Event description.
+
+    Attributes
+    ----------
+    name : str
+        The event name.
+    fmt : str
+        The event format string.
+    properties : set(str)
+        Properties of the event.
+    args : Arguments
+        The event arguments.
+    """
+
+    _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
+
+    _VALID_PROPS = set(["disable"])
+
+    def __init__(self, name, props, fmt, args):
+        """
+        Parameters
+        ----------
+        name : string
+            Event name.
+        props : list of str
+            Property names.
+        fmt : str
+            Event printing format.
+        args : Arguments
+            Event arguments.
+        """
+        self.name = name
+        self.properties = props
+        self.fmt = fmt
+        self.args = args
+
+        unknown_props = set(self.properties) - self._VALID_PROPS
+        if len(unknown_props) > 0:
+            raise ValueError("Unknown properties: %s" % ", ".join(unknown_props))
+
+    @staticmethod
+    def build(line_str):
+        """Build an Event instance from a string.
+
+        Parameters
+        ----------
+        line_str : str
+            Line describing the event.
+        """
+        m = Event._CRE.match(line_str)
+        assert m is not None
+        groups = m.groupdict('')
+
+        name = groups["name"]
+        props = groups["props"].split()
+        fmt = groups["fmt"]
+        args = Arguments.build(groups["args"])
+
+        return Event(name, props, fmt, args)
+
+    def __repr__(self):
+        """Evaluable string representation for this object."""
+        return "Event('%s %s(%s) %s')" % (" ".join(self.properties),
+                                          self.name,
+                                          self.args,
+                                          self.fmt)
+
+def _read_events(fobj):
+    res = []
+    for line in fobj:
+        if not line.strip():
+            continue
+        if line.lstrip().startswith('#'):
+            continue
+        res.append(Event.build(line))
+    return res
+
+
+class TracetoolError (Exception):
+    """Exception for calls to generate."""
+    pass
+
+
+def try_import(mod_name, attr_name = None, attr_default = None):
+    """Try to import a module and get an attribute from it.
+
+    Parameters
+    ----------
+    mod_name : str
+        Module name.
+    attr_name : str, optional
+        Name of an attribute in the module.
+    attr_default : optional
+        Default value if the attribute does not exist in the module.
+
+    Returns
+    -------
+    A pair indicating whether the module could be imported and the module or
+    object or attribute value.
+    """
+    try:
+        module = __import__(mod_name, fromlist=["__package__"])
+        if attr_name is None:
+            return True, module
+        return True, getattr(module, str(attr_name), attr_default)
+    except ImportError:
+        return False, None
+
+
+def generate(fevents, format, backend):
+    """Generate the output for the given (format, backend) pair.
+
+    Parameters
+    ----------
+    fevents : file
+        Event description file.
+    format : str
+        Output format name.
+    backend : str
+        Output backend name.
+    """
+    # fix strange python error (UnboundLocalError tracetool)
+    import tracetool
+
+    format = str(format)
+    if len(format) is 0:
+        raise TracetoolError("format not set")
+    mformat = format.replace("-", "_")
+    if not tracetool.format.exists(mformat):
+        raise TracetoolError("unknown format: %s" % format)
+
+    backend = str(backend)
+    if len(backend) is 0:
+        raise TracetoolError("backend not set")
+    mbackend = backend.replace("-", "_")
+    if not tracetool.backend.exists(mbackend):
+        raise TracetoolError("unknown backend: %s" % backend)
+
+    if not tracetool.backend.compatible(mbackend, mformat):
+        raise TracetoolError("backend '%s' not compatible with format '%s'" %
+                             (backend, format))
+
+    events = _read_events(fevents)
+
+    if backend == "nop":
+        ( e.properies.add("disable") for e in events )
+
+    tracetool.format.generate_begin(mformat, events)
+    tracetool.backend.generate("nop", format,
+                               [ e
+                                 for e in events
+                                 if "disable" in e.properties ])
+    tracetool.backend.generate(backend, format,
+                               [ e
+                                 for e in events
+                                 if "disable" not in e.properties ])
+    tracetool.format.generate_end(mformat, events)
diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py
new file mode 100644
index 0000000..34b7ed8
--- /dev/null
+++ b/scripts/tracetool/backend/__init__.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Backend management.
+
+
+Creating new backends
+---------------------
+
+A new backend named 'foo-bar' corresponds to Python module
+'tracetool/backend/foo_bar.py'.
+
+A backend module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All backends must generate their contents through the 'tracetool.out' routine.
+
+
+Backend functions
+-----------------
+
+======== =======================================================================
+Function Description
+======== =======================================================================
+<format> Called to generate the format- and backend-specific code for each of
+         the specified events. If the function does not exist, the backend is
+         considered not compatible with the given format.
+======== =======================================================================
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+import pkgutil
+
+import tracetool
+
+
+def get_list():
+    """Get a list of (name, description) pairs."""
+    res = [("nop", "Tracing disabled.")]
+    for _, modname, _ in pkgutil.iter_modules(tracetool.backend.__path__):
+        module = tracetool.try_import("tracetool.backend." + modname)
+
+        # just in case; should never fail unless non-module files are put there
+        if not module[0]:
+            continue
+        module = module[1]
+
+        doc = module.__doc__
+        if doc is None:
+            doc = ""
+        doc = doc.strip().split("\n")[0]
+
+        name = modname.replace("_", "-")
+        res.append((name, doc))
+    return res
+
+
+def exists(name):
+    """Return whether the given backend exists."""
+    if len(name) == 0:
+        return False
+    if name == "nop":
+        return True
+    name = name.replace("-", "_")
+    return tracetool.try_import("tracetool.backend." + name)[1]
+
+
+def compatible(backend, format):
+    """Whether a backend is compatible with the given format."""
+    if not exists(backend):
+        raise ValueError("unknown backend: %s" % backend)
+
+    backend = backend.replace("-", "_")
+    format = format.replace("-", "_")
+
+    if backend == "nop":
+        return True
+    else:
+        func = tracetool.try_import("tracetool.backend." + backend,
+                                    format, None)[1]
+        return func is not None
+
+
+def _empty(events):
+    pass
+
+def generate(backend, format, events):
+    """Generate the per-event output for the given (backend, format) pair."""
+    if not compatible(backend, format):
+        raise ValueError("backend '%s' not compatible with format '%s'" %
+                         (backend, format))
+
+    backend = backend.replace("-", "_")
+    format = format.replace("-", "_")
+
+    if backend == "nop":
+        func = tracetool.try_import("tracetool.format." + format,
+                                    "nop", _empty)[1]
+    else:
+        func = tracetool.try_import("tracetool.backend." + backend,
+                                    format, None)[1]
+
+    func(events)
diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__init__.py
new file mode 100644
index 0000000..0e4baf0
--- /dev/null
+++ b/scripts/tracetool/format/__init__.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Format management.
+
+
+Creating new formats
+--------------------
+
+A new format named 'foo-bar' corresponds to Python module
+'tracetool/format/foo_bar.py'.
+
+A format module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All formats must generate their contents through the 'tracetool.out' routine.
+
+
+Format functions
+----------------
+
+All the following functions are optional, and no output will be generated if
+they do not exist.
+
+======== =======================================================================
+Function Description
+======== =======================================================================
+begin    Called to generate the format-specific file header.
+end      Called to generate the format-specific file footer.
+nop      Called to generate the per-event contents when the event is disabled or
+         the selected backend is 'nop'.
+======== =======================================================================
+"""
+
+__author__     = "Lluís Vilanova <vilanova at ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova at ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha at linux.vnet.ibm.com"
+
+
+import pkgutil
+
+import tracetool
+
+
+def get_list():
+    """Get a list of (name, description) pairs."""
+    res = []
+    for _, modname, _ in pkgutil.iter_modules(tracetool.format.__path__):
+        module = tracetool.try_import("tracetool.format." + modname)
+
+        # just in case; should never fail unless non-module files are put there
+        if not module[0]:
+            continue
+        module = module[1]
+
+        doc = module.__doc__
+        if doc is None:
+            doc = ""
+        doc = doc.strip().split("\n")[0]
+
+        name = modname.replace("_", "-")
+        res.append((name, doc))
+    return res
+
+
+def exists(name):
+    """Return whether the given format exists."""
+    if len(name) == 0:
+        return False
+    name = name.replace("-", "_")
+    return tracetool.try_import("tracetool.format." + name)[1]
+
+
+def _empty(events):
+    pass
+
+def generate_begin(name, events):
+    """Generate the header of the format-specific file."""
+    if not exists(name):
+        raise ValueError("unknown format: %s" % name)
+
+    name = name.replace("-", "_")
+    func = tracetool.try_import("tracetool.format." + name,
+                                "begin", _empty)[1]
+    func(events)
+
+def generate_end(name, events):
+    """Generate the footer of the format-specific file."""
+    if not exists(name):
+        raise ValueError("unknown format: %s" % name)
+
+    name = name.replace("-", "_")
+    func = tracetool.try_import("tracetool.format." + name,
+                                "end", _empty)[1]
+    func(events)
commit 25b9e14e78bf9790cdee12d57c45898e86866a24
Merge: b26d712... 06ddea4...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Apr 18 07:56:18 2012 -0500

    Merge remote-tracking branch 'spice/spice.v52' into staging
    
    * spice/spice.v52:
      qxl-render: fix broken vnc+spice since commit f934493
      qxl: set default values of vram*_size_mb to -1
      trace-events: remove unused qxl_vga_ioport_while_not_in_vga_mode

commit b26d712ecc9558fcd2a77a0b677a18d4919228bd
Merge: 6b034aa... c7020c9...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Apr 18 07:55:56 2012 -0500

    Merge remote-tracking branch 'kraxel/usb.46' into staging
    
    * kraxel/usb.46: (21 commits)
      usb-ehci: drop assert()
      usb-redir: Notify our peer when we reject a device due to a speed mismatch
      usb-ehci: Drop unused sofv value
      usb-host: rewrite usb_linux_update_endp_table
      usb: use USBDescriptor for endpoint descriptors.
      usb: use USBDescriptor for interface descriptors.
      usb: use USBDescriptor for config descriptors.
      usb: use USBDescriptor for device qualifier descriptors.
      usb: add USBDescriptor, use for device descriptors.
      usb-ehci: frindex always is a 14 bits counter
      usb-ehci: fix ehci_child_detach
      usb-hub: add tracepoints
      usb_packet_set_state: handle p->ep == NULL
      usb-host: add property to turn off pipelining
      usb-host: add usb packet to request tracepoints
      usb-host: trace canceled requests
      usb-host: trace emulated requests
      Add bootindex support to usb-host and usb-redir
      usb-uhci: queuing fix
      usb-uhci: stop queue filling when we find a in-flight td
      ...

commit 06ddea49f8127bd055dbc7e83df896d9311c88cc
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Apr 18 12:27:00 2012 +0300

    qxl-render: fix broken vnc+spice since commit f934493
    
    Notify any listeners such as vnc that the displaysurface has been
    changed, otherwise they will segfault when first accessing the freed old
    displaysurface data.
    
    Signed-off-by: Alon Levy <alevy at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 28ab182..f7f1bfd 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -127,6 +127,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
                     qxl->guest_primary.surface.width,
                     qxl->guest_primary.surface.height);
         }
+        dpy_resize(vga->ds);
     }
     for (i = 0; i < qxl->num_dirty_rects; i++) {
         if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
commit 79ce3567017e32ac96f7de7a8b04ed75ee710f89
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Mar 29 22:24:38 2012 +0200

    qxl: set default values of vram*_size_mb to -1
    
    The addition of those values caused a regression where not specifying
    any value for the vram bar size would result in a 4096 _byte_ surface
    area. This is ok for the windows driver but causes the X driver to be
    unusable. Also, it's a regression. This patch returns the default
    behavior of having a 64 megabyte vram BAR.
    
    Signed-off-by: Alon Levy <alevy at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 47a162e..db2318e 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1959,8 +1959,8 @@ static Property qxl_properties[] = {
         DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
         DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
         DEFINE_PROP_UINT32("ram_size_mb",  PCIQXLDevice, ram_size_mb, -1),
-        DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0),
-        DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0),
+        DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
+        DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
         DEFINE_PROP_END_OF_LIST(),
 };
 
commit a9257af0b9735dbf7e8a52b4bf8d6c80dd4fc446
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Mar 28 11:30:08 2012 +0200

    trace-events: remove unused qxl_vga_ioport_while_not_in_vga_mode
    
    The resulting stp file fails to load because of an unresolvable probe.
    
    Signed-off-by: Alon Levy <alevy at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/trace-events b/trace-events
index a5f276d..0e25d20 100644
--- a/trace-events
+++ b/trace-events
@@ -781,7 +781,6 @@ qxl_spice_reset_memslots(int qid) "%d"
 qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]"
 qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d"
 qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d"
-qxl_vga_ioport_while_not_in_vga_mode(int qid) "%d (int qid, reset to VGA mode because of VGA io)"
 
 # hw/qxl-render.c
 qxl_render_blit_guest_primary_initialized(void) ""
commit 4c9f8d1b4eb0e1a7e69df6373e9c2d40a929494d
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date:   Tue Apr 17 16:56:51 2012 +0000

    xen: add a dummy xc_hvm_inject_msi for Xen < 4.2
    
    xc_hvm_inject_msi is only available on Xen >= 4.2: add a dummy
    compatibility function for Xen < 4.2.
    
    Also enable msi support only on Xen >= 4.2.
    
    Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
    Acked-by: Anthony PERARD <anthony.perard at citrix.com>

diff --git a/hw/pc.c b/hw/pc.c
index 1f5aacb..4d34a33 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -916,7 +916,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
         msi_supported = true;
     }
 
-    if (xen_enabled()) {
+    if (xen_msi_support()) {
         msi_supported = true;
     }
 
diff --git a/hw/xen.h b/hw/xen.h
index e5926b7..3ae4cd0 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -57,4 +57,14 @@ void xen_register_framebuffer(struct MemoryRegion *mr);
 #  define HVM_MAX_VCPUS 32
 #endif
 
+static inline int xen_msi_support(void)
+{
+#if defined(CONFIG_XEN_CTRL_INTERFACE_VERSION) \
+    && CONFIG_XEN_CTRL_INTERFACE_VERSION >= 420
+    return xen_enabled();
+#else
+    return 0;
+#endif
+}
+
 #endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 0409ac7..7043c14 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -133,6 +133,21 @@ static inline int xc_fd(xc_interface *xen_xc)
 }
 #endif
 
+/* Xen before 4.2 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 420
+static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
+        uint64_t addr, uint32_t data)
+{
+    return -ENOSYS;
+}
+#else
+static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
+        uint64_t addr, uint32_t data)
+{
+    return xc_hvm_inject_msi(xen_xc, dom, addr, data);
+}
+#endif
+
 void destroy_hvm_domain(void);
 
 #endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/xen-all.c b/xen-all.c
index a08eec0..bdf9c0f 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -129,7 +129,7 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
 
 void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
 {
-    xc_hvm_inject_msi(xen_xc, xen_domid, addr, data);
+    xen_xc_hvm_inject_msi(xen_xc, xen_domid, addr, data);
 }
 
 static void xen_suspend_notifier(Notifier *notifier, void *data)
commit 8688e0652dc4fde816316fbd10869e3e33411968
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date:   Tue Apr 17 17:04:18 2012 +0000

    xen,configure: detect Xen 4.2
    
    Xen 4.2 is the first to support xc_hvm_inject_msi: use it to determine
    if we are running on it.
    
    Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
    Acked-by: Anthony PERARD <anthony.perard at citrix.com>

diff --git a/configure b/configure
index 1d94acd..38f45f3 100755
--- a/configure
+++ b/configure
@@ -1398,6 +1398,31 @@ int main(void) {
   xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
   xc_gnttab_open(NULL, 0);
   xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
+  xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000);
+  return 0;
+}
+EOF
+      compile_prog "" "$xen_libs"
+    ) ; then
+    xen_ctrl_version=420
+    xen=yes
+
+  elif (
+      cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+#include <stdint.h>
+#include <xen/hvm/hvm_info_table.h>
+#if !defined(HVM_MAX_VCPUS)
+# error HVM_MAX_VCPUS not defined
+#endif
+int main(void) {
+  xc_interface *xc;
+  xs_daemon_open();
+  xc = xc_interface_open(0, 0, 0);
+  xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+  xc_gnttab_open(NULL, 0);
+  xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
   return 0;
 }
 EOF
commit 6e7a7f3d9bc2031b4c93c05400b18775ba1b1f55
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:43 2012 +0200

    Allow controlling volume with PulseAudio backend
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 6f50c1c..e6708d0 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -677,15 +677,103 @@ static void qpa_fini_in (HWVoiceIn *hw)
 
 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
 {
-    (void) hw;
-    (void) cmd;
+    PAVoiceOut *pa = (PAVoiceOut *) hw;
+    pa_operation *op;
+    pa_cvolume v;
+    paaudio *g = &glob_paaudio;
+
+    pa_cvolume_init (&v);
+
+    switch (cmd) {
+    case VOICE_VOLUME:
+        {
+            SWVoiceOut *sw;
+            va_list ap;
+
+            va_start (ap, cmd);
+            sw = va_arg (ap, SWVoiceOut *);
+            va_end (ap);
+
+            v.channels = 2;
+            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
+            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
+
+            pa_threaded_mainloop_lock (g->mainloop);
+
+            op = pa_context_set_sink_input_volume (g->context,
+                pa_stream_get_index (pa->stream),
+                &v, NULL, NULL);
+            if (!op)
+                qpa_logerr (pa_context_errno (g->context),
+                            "set_sink_input_volume() failed\n");
+            else
+                pa_operation_unref (op);
+
+            op = pa_context_set_sink_input_mute (g->context,
+                pa_stream_get_index (pa->stream),
+               sw->vol.mute, NULL, NULL);
+            if (!op) {
+                qpa_logerr (pa_context_errno (g->context),
+                            "set_sink_input_mute() failed\n");
+            } else {
+                pa_operation_unref (op);
+            }
+
+            pa_threaded_mainloop_unlock (g->mainloop);
+        }
+    }
     return 0;
 }
 
 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 {
-    (void) hw;
-    (void) cmd;
+    PAVoiceIn *pa = (PAVoiceIn *) hw;
+    pa_operation *op;
+    pa_cvolume v;
+    paaudio *g = &glob_paaudio;
+
+    pa_cvolume_init (&v);
+
+    switch (cmd) {
+    case VOICE_VOLUME:
+        {
+            SWVoiceIn *sw;
+            va_list ap;
+
+            va_start (ap, cmd);
+            sw = va_arg (ap, SWVoiceIn *);
+            va_end (ap);
+
+            v.channels = 2;
+            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
+            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
+
+            pa_threaded_mainloop_lock (g->mainloop);
+
+            /* FIXME: use the upcoming "set_source_output_{volume,mute}" */
+            op = pa_context_set_source_volume_by_index (g->context,
+                pa_stream_get_device_index (pa->stream),
+                &v, NULL, NULL);
+            if (!op) {
+                qpa_logerr (pa_context_errno (g->context),
+                            "set_source_volume() failed\n");
+            } else {
+                pa_operation_unref(op);
+            }
+
+            op = pa_context_set_source_mute_by_index (g->context,
+                pa_stream_get_index (pa->stream),
+                sw->vol.mute, NULL, NULL);
+            if (!op) {
+                qpa_logerr (pa_context_errno (g->context),
+                            "set_source_mute() failed\n");
+            } else {
+                pa_operation_unref (op);
+            }
+
+            pa_threaded_mainloop_unlock (g->mainloop);
+        }
+    }
     return 0;
 }
 
@@ -822,5 +910,6 @@ struct audio_driver pa_audio_driver = {
     .max_voices_out = INT_MAX,
     .max_voices_in  = INT_MAX,
     .voice_size_out = sizeof (PAVoiceOut),
-    .voice_size_in  = sizeof (PAVoiceIn)
+    .voice_size_in  = sizeof (PAVoiceIn),
+    .ctl_caps       = VOICE_VOLUME_CAP
 };
commit a394aed235d6b3f048eeae83289f4d21eca7023c
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:42 2012 +0200

    configure: pa_simple is not needed anymore
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/configure b/configure
index 1d94acd..2d62d12 100755
--- a/configure
+++ b/configure
@@ -1855,9 +1855,9 @@ for drv in $audio_drv_list; do
     ;;
 
     pa)
-    audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \
-        "pa_simple *s = 0; pa_simple_free(s); return 0;"
-    libs_softmmu="-lpulse -lpulse-simple $libs_softmmu"
+    audio_drv_probe $drv pulse/mainloop.h "-lpulse" \
+        "pa_mainloop *m = 0; pa_mainloop_free (m); return 0;"
+    libs_softmmu="-lpulse $libs_softmmu"
     audio_pt_int="yes"
     ;;
 
commit ea9ebc2ce69198f7aca4b43652824c5d621ac978
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:41 2012 +0200

    Do not use pa_simple PulseAudio API
    
    Unfortunately, pa_simple is a limited API which doesn't let us
    retrieve the associated pa_stream. It is needed to control the volume
    of the stream.
    
    In v4:
    - add missing braces
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/paaudio.c b/audio/paaudio.c
index d1f3912..6f50c1c 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -2,8 +2,7 @@
 #include "qemu-common.h"
 #include "audio.h"
 
-#include <pulse/simple.h>
-#include <pulse/error.h>
+#include <pulse/pulseaudio.h>
 
 #define AUDIO_CAP "pulseaudio"
 #include "audio_int.h"
@@ -15,7 +14,7 @@ typedef struct {
     int live;
     int decr;
     int rpos;
-    pa_simple *s;
+    pa_stream *stream;
     void *pcm_buf;
     struct audio_pt pt;
 } PAVoiceOut;
@@ -26,17 +25,23 @@ typedef struct {
     int dead;
     int incr;
     int wpos;
-    pa_simple *s;
+    pa_stream *stream;
     void *pcm_buf;
     struct audio_pt pt;
+    const void *read_data;
+    size_t read_index, read_length;
 } PAVoiceIn;
 
-static struct {
+typedef struct {
     int samples;
     char *server;
     char *sink;
     char *source;
-} conf = {
+    pa_threaded_mainloop *mainloop;
+    pa_context *context;
+} paaudio;
+
+static paaudio glob_paaudio = {
     .samples = 4096,
 };
 
@@ -51,6 +56,126 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
     AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
 }
 
+#define CHECK_SUCCESS_GOTO(c, rerror, expression, label)        \
+    do {                                                        \
+        if (!(expression)) {                                    \
+            if (rerror) {                                       \
+                *(rerror) = pa_context_errno ((c)->context);    \
+            }                                                   \
+            goto label;                                         \
+        }                                                       \
+    } while (0);
+
+#define CHECK_DEAD_GOTO(c, stream, rerror, label)                       \
+    do {                                                                \
+        if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
+            !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
+            if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
+                ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
+                if (rerror) {                                           \
+                    *(rerror) = pa_context_errno ((c)->context);        \
+                }                                                       \
+            } else {                                                    \
+                if (rerror) {                                           \
+                    *(rerror) = PA_ERR_BADSTATE;                        \
+                }                                                       \
+            }                                                           \
+            goto label;                                                 \
+        }                                                               \
+    } while (0);
+
+static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
+{
+    paaudio *g = &glob_paaudio;
+
+    pa_threaded_mainloop_lock (g->mainloop);
+
+    CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+
+    while (length > 0) {
+        size_t l;
+
+        while (!p->read_data) {
+            int r;
+
+            r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
+            CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
+
+            if (!p->read_data) {
+                pa_threaded_mainloop_wait (g->mainloop);
+                CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+            } else {
+                p->read_index = 0;
+            }
+        }
+
+        l = p->read_length < length ? p->read_length : length;
+        memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
+
+        data = (uint8_t *) data + l;
+        length -= l;
+
+        p->read_index += l;
+        p->read_length -= l;
+
+        if (!p->read_length) {
+            int r;
+
+            r = pa_stream_drop (p->stream);
+            p->read_data = NULL;
+            p->read_length = 0;
+            p->read_index = 0;
+
+            CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
+        }
+    }
+
+    pa_threaded_mainloop_unlock (g->mainloop);
+    return 0;
+
+unlock_and_fail:
+    pa_threaded_mainloop_unlock (g->mainloop);
+    return -1;
+}
+
+static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
+{
+    paaudio *g = &glob_paaudio;
+
+    pa_threaded_mainloop_lock (g->mainloop);
+
+    CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+
+    while (length > 0) {
+        size_t l;
+        int r;
+
+        while (!(l = pa_stream_writable_size (p->stream))) {
+            pa_threaded_mainloop_wait (g->mainloop);
+            CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+        }
+
+        CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
+
+        if (l > length) {
+            l = length;
+        }
+
+        r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
+        CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
+
+        data = (const uint8_t *) data + l;
+        length -= l;
+    }
+
+    pa_threaded_mainloop_unlock (g->mainloop);
+    return 0;
+
+unlock_and_fail:
+    pa_threaded_mainloop_unlock (g->mainloop);
+    return -1;
+}
+
 static void *qpa_thread_out (void *arg)
 {
     PAVoiceOut *pa = arg;
@@ -77,7 +202,7 @@ static void *qpa_thread_out (void *arg)
             }
         }
 
-        decr = to_mix = audio_MIN (pa->live, conf.samples >> 2);
+        decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2);
         rpos = pa->rpos;
 
         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
@@ -91,8 +216,8 @@ static void *qpa_thread_out (void *arg)
 
             hw->clip (pa->pcm_buf, src, chunk);
 
-            if (pa_simple_write (pa->s, pa->pcm_buf,
-                                 chunk << hw->info.shift, &error) < 0) {
+            if (qpa_simple_write (pa, pa->pcm_buf,
+                                  chunk << hw->info.shift, &error) < 0) {
                 qpa_logerr (error, "pa_simple_write failed\n");
                 return NULL;
             }
@@ -169,7 +294,7 @@ static void *qpa_thread_in (void *arg)
             }
         }
 
-        incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2);
+        incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2);
         wpos = pa->wpos;
 
         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
@@ -181,8 +306,8 @@ static void *qpa_thread_in (void *arg)
             int chunk = audio_MIN (to_grab, hw->samples - wpos);
             void *buf = advance (pa->pcm_buf, wpos);
 
-            if (pa_simple_read (pa->s, buf,
-                                chunk << hw->info.shift, &error) < 0) {
+            if (qpa_simple_read (pa, buf,
+                                 chunk << hw->info.shift, &error) < 0) {
                 qpa_logerr (error, "pa_simple_read failed\n");
                 return NULL;
             }
@@ -283,6 +408,109 @@ static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
     }
 }
 
+static void context_state_cb (pa_context *c, void *userdata)
+{
+    paaudio *g = &glob_paaudio;
+
+    switch (pa_context_get_state(c)) {
+    case PA_CONTEXT_READY:
+    case PA_CONTEXT_TERMINATED:
+    case PA_CONTEXT_FAILED:
+        pa_threaded_mainloop_signal (g->mainloop, 0);
+        break;
+
+    case PA_CONTEXT_UNCONNECTED:
+    case PA_CONTEXT_CONNECTING:
+    case PA_CONTEXT_AUTHORIZING:
+    case PA_CONTEXT_SETTING_NAME:
+        break;
+    }
+}
+
+static void stream_state_cb (pa_stream *s, void * userdata)
+{
+    paaudio *g = &glob_paaudio;
+
+    switch (pa_stream_get_state (s)) {
+
+    case PA_STREAM_READY:
+    case PA_STREAM_FAILED:
+    case PA_STREAM_TERMINATED:
+        pa_threaded_mainloop_signal (g->mainloop, 0);
+        break;
+
+    case PA_STREAM_UNCONNECTED:
+    case PA_STREAM_CREATING:
+        break;
+    }
+}
+
+static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
+{
+    paaudio *g = &glob_paaudio;
+
+    pa_threaded_mainloop_signal (g->mainloop, 0);
+}
+
+static pa_stream *qpa_simple_new (
+        const char *server,
+        const char *name,
+        pa_stream_direction_t dir,
+        const char *dev,
+        const char *stream_name,
+        const pa_sample_spec *ss,
+        const pa_channel_map *map,
+        const pa_buffer_attr *attr,
+        int *rerror)
+{
+    paaudio *g = &glob_paaudio;
+    int r;
+    pa_stream *stream;
+
+    pa_threaded_mainloop_lock (g->mainloop);
+
+    stream = pa_stream_new (g->context, name, ss, map);
+    if (!stream) {
+        goto fail;
+    }
+
+    pa_stream_set_state_callback (stream, stream_state_cb, g);
+    pa_stream_set_read_callback (stream, stream_request_cb, g);
+    pa_stream_set_write_callback (stream, stream_request_cb, g);
+
+    if (dir == PA_STREAM_PLAYBACK) {
+        r = pa_stream_connect_playback (stream, dev, attr,
+                                        PA_STREAM_INTERPOLATE_TIMING
+                                        |PA_STREAM_ADJUST_LATENCY
+                                        |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
+    } else {
+        r = pa_stream_connect_record (stream, dev, attr,
+                                      PA_STREAM_INTERPOLATE_TIMING
+                                      |PA_STREAM_ADJUST_LATENCY
+                                      |PA_STREAM_AUTO_TIMING_UPDATE);
+    }
+
+    if (r < 0) {
+      goto fail;
+    }
+
+    pa_threaded_mainloop_unlock (g->mainloop);
+
+    return stream;
+
+fail:
+    pa_threaded_mainloop_unlock (g->mainloop);
+
+    if (stream) {
+        pa_stream_unref (stream);
+    }
+
+    qpa_logerr (pa_context_errno (g->context),
+                "stream_new() failed\n");
+
+    return NULL;
+}
+
 static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     int error;
@@ -306,24 +534,24 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 
     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 
-    pa->s = pa_simple_new (
-        conf.server,
+    pa->stream = qpa_simple_new (
+        glob_paaudio.server,
         "qemu",
         PA_STREAM_PLAYBACK,
-        conf.sink,
+        glob_paaudio.sink,
         "pcm.playback",
         &ss,
         NULL,                   /* channel map */
         &ba,                    /* buffering attributes */
         &error
         );
-    if (!pa->s) {
+    if (!pa->stream) {
         qpa_logerr (error, "pa_simple_new for playback failed\n");
         goto fail1;
     }
 
     audio_pcm_init_info (&hw->info, &obt_as);
-    hw->samples = conf.samples;
+    hw->samples = glob_paaudio.samples;
     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
     pa->rpos = hw->rpos;
     if (!pa->pcm_buf) {
@@ -342,8 +570,10 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
     g_free (pa->pcm_buf);
     pa->pcm_buf = NULL;
  fail2:
-    pa_simple_free (pa->s);
-    pa->s = NULL;
+    if (pa->stream) {
+        pa_stream_unref (pa->stream);
+        pa->stream = NULL;
+    }
  fail1:
     return -1;
 }
@@ -361,24 +591,24 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
 
     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 
-    pa->s = pa_simple_new (
-        conf.server,
+    pa->stream = qpa_simple_new (
+        glob_paaudio.server,
         "qemu",
         PA_STREAM_RECORD,
-        conf.source,
+        glob_paaudio.source,
         "pcm.capture",
         &ss,
         NULL,                   /* channel map */
         NULL,                   /* buffering attributes */
         &error
         );
-    if (!pa->s) {
+    if (!pa->stream) {
         qpa_logerr (error, "pa_simple_new for capture failed\n");
         goto fail1;
     }
 
     audio_pcm_init_info (&hw->info, &obt_as);
-    hw->samples = conf.samples;
+    hw->samples = glob_paaudio.samples;
     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
     pa->wpos = hw->wpos;
     if (!pa->pcm_buf) {
@@ -397,8 +627,10 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
     g_free (pa->pcm_buf);
     pa->pcm_buf = NULL;
  fail2:
-    pa_simple_free (pa->s);
-    pa->s = NULL;
+    if (pa->stream) {
+        pa_stream_unref (pa->stream);
+        pa->stream = NULL;
+    }
  fail1:
     return -1;
 }
@@ -413,9 +645,9 @@ static void qpa_fini_out (HWVoiceOut *hw)
     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 
-    if (pa->s) {
-        pa_simple_free (pa->s);
-        pa->s = NULL;
+    if (pa->stream) {
+        pa_stream_unref (pa->stream);
+        pa->stream = NULL;
     }
 
     audio_pt_fini (&pa->pt, AUDIO_FUNC);
@@ -433,9 +665,9 @@ static void qpa_fini_in (HWVoiceIn *hw)
     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 
-    if (pa->s) {
-        pa_simple_free (pa->s);
-        pa->s = NULL;
+    if (pa->stream) {
+        pa_stream_unref (pa->stream);
+        pa->stream = NULL;
     }
 
     audio_pt_fini (&pa->pt, AUDIO_FUNC);
@@ -460,37 +692,106 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 /* common */
 static void *qpa_audio_init (void)
 {
-    return &conf;
+    paaudio *g = &glob_paaudio;
+
+    g->mainloop = pa_threaded_mainloop_new ();
+    if (!g->mainloop) {
+        goto fail;
+    }
+
+    g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server);
+    if (!g->context) {
+        goto fail;
+    }
+
+    pa_context_set_state_callback (g->context, context_state_cb, g);
+
+    if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) {
+        qpa_logerr (pa_context_errno (g->context),
+                    "pa_context_connect() failed\n");
+        goto fail;
+    }
+
+    pa_threaded_mainloop_lock (g->mainloop);
+
+    if (pa_threaded_mainloop_start (g->mainloop) < 0) {
+        goto unlock_and_fail;
+    }
+
+    for (;;) {
+        pa_context_state_t state;
+
+        state = pa_context_get_state (g->context);
+
+        if (state == PA_CONTEXT_READY) {
+            break;
+        }
+
+        if (!PA_CONTEXT_IS_GOOD (state)) {
+            qpa_logerr (pa_context_errno (g->context),
+                        "Wrong context state\n");
+            goto unlock_and_fail;
+        }
+
+        /* Wait until the context is ready */
+        pa_threaded_mainloop_wait (g->mainloop);
+    }
+
+    pa_threaded_mainloop_unlock (g->mainloop);
+
+    return &glob_paaudio;
+
+unlock_and_fail:
+    pa_threaded_mainloop_unlock (g->mainloop);
+fail:
+    AUD_log (AUDIO_CAP, "Failed to initialize PA context");
+    return NULL;
 }
 
 static void qpa_audio_fini (void *opaque)
 {
-    (void) opaque;
+    paaudio *g = opaque;
+
+    if (g->mainloop) {
+        pa_threaded_mainloop_stop (g->mainloop);
+    }
+
+    if (g->context) {
+        pa_context_disconnect (g->context);
+        pa_context_unref (g->context);
+        g->context = NULL;
+    }
+
+    if (g->mainloop) {
+        pa_threaded_mainloop_free (g->mainloop);
+    }
+
+    g->mainloop = NULL;
 }
 
 struct audio_option qpa_options[] = {
     {
         .name  = "SAMPLES",
         .tag   = AUD_OPT_INT,
-        .valp  = &conf.samples,
+        .valp  = &glob_paaudio.samples,
         .descr = "buffer size in samples"
     },
     {
         .name  = "SERVER",
         .tag   = AUD_OPT_STR,
-        .valp  = &conf.server,
+        .valp  = &glob_paaudio.server,
         .descr = "server address"
     },
     {
         .name  = "SINK",
         .tag   = AUD_OPT_STR,
-        .valp  = &conf.sink,
+        .valp  = &glob_paaudio.sink,
         .descr = "sink device name"
     },
     {
         .name  = "SOURCE",
         .tag   = AUD_OPT_STR,
-        .valp  = &conf.source,
+        .valp  = &glob_paaudio.source,
         .descr = "source device name"
     },
     { /* End of list */ }
commit a70c99c6140bd4b0d0bc3ddc7c5fc09a773921c6
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:40 2012 +0200

    audio/spice: add support for volume control
    
    Use Spice server volume control API when available.
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index f972110..6f15591 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -202,7 +202,26 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
         }
         spice_server_playback_stop (&out->sin);
         break;
+    case VOICE_VOLUME:
+        {
+#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
+            SWVoiceOut *sw;
+            va_list ap;
+            uint16_t vol[2];
+
+            va_start (ap, cmd);
+            sw = va_arg (ap, SWVoiceOut *);
+            va_end (ap);
+
+            vol[0] = sw->vol.l / ((1ULL << 16) + 1);
+            vol[1] = sw->vol.r / ((1ULL << 16) + 1);
+            spice_server_playback_set_volume (&out->sin, 2, vol);
+            spice_server_playback_set_mute (&out->sin, sw->vol.mute);
+#endif
+            break;
+        }
     }
+
     return 0;
 }
 
@@ -304,7 +323,26 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
         in->active = 0;
         spice_server_record_stop (&in->sin);
         break;
+    case VOICE_VOLUME:
+        {
+#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
+            SWVoiceIn *sw;
+            va_list ap;
+            uint16_t vol[2];
+
+            va_start (ap, cmd);
+            sw = va_arg (ap, SWVoiceIn *);
+            va_end (ap);
+
+            vol[0] = sw->vol.l / ((1ULL << 16) + 1);
+            vol[1] = sw->vol.r / ((1ULL << 16) + 1);
+            spice_server_record_set_volume (&in->sin, 2, vol);
+            spice_server_record_set_mute (&in->sin, sw->vol.mute);
+#endif
+            break;
+        }
     }
+
     return 0;
 }
 
@@ -337,6 +375,9 @@ struct audio_driver spice_audio_driver = {
     .max_voices_in  = 1,
     .voice_size_out = sizeof (SpiceVoiceOut),
     .voice_size_in  = sizeof (SpiceVoiceIn),
+#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
+    .ctl_caps       = VOICE_VOLUME_CAP
+#endif
 };
 
 void qemu_spice_audio_init (void)
commit 19677a380a70348134ed7650b294522617eb03fc
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:39 2012 +0200

    hw/ac97: add support for volume control
    
    Combine output volume with Master and PCM registers values.
    Use default values in mixer_reset ().
    Set volume on post-load to update backend values.
    
    v4,v5:
    - fix some code style
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/hw/ac97.c b/hw/ac97.c
index f7866ed..177f729 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -436,6 +436,65 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
     AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
 }
 
+static void get_volume (uint16_t vol, uint16_t mask, int inverse,
+                        int *mute, uint8_t *lvol, uint8_t *rvol)
+{
+    *mute = (vol >> MUTE_SHIFT) & 1;
+    *rvol = (255 * (vol & mask)) / mask;
+    *lvol = (255 * ((vol >> 8) & mask)) / mask;
+
+    if (inverse) {
+        *rvol = 255 - *rvol;
+        *lvol = 255 - *lvol;
+    }
+}
+
+static void update_combined_volume_out (AC97LinkState *s)
+{
+    uint8_t lvol, rvol, plvol, prvol;
+    int mute, pmute;
+
+    get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1,
+                &mute, &lvol, &rvol);
+    /* FIXME: should be 1f according to spec */
+    get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1,
+                &pmute, &plvol, &prvol);
+
+    mute = mute | pmute;
+    lvol = (lvol * plvol) / 255;
+    rvol = (rvol * prvol) / 255;
+
+    AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
+}
+
+static void update_volume_in (AC97LinkState *s)
+{
+    uint8_t lvol, rvol;
+    int mute;
+
+    get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0,
+                &mute, &lvol, &rvol);
+
+    AUD_set_volume_in (s->voice_pi, mute, lvol, rvol);
+}
+
+static void set_volume (AC97LinkState *s, int index, uint32_t val)
+{
+    mixer_store (s, index, val);
+    if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) {
+        update_combined_volume_out (s);
+    } else if (index == AC97_Record_Gain_Mute) {
+        update_volume_in (s);
+    }
+}
+
+static void record_select (AC97LinkState *s, uint32_t val)
+{
+    uint8_t rs = val & REC_MASK;
+    uint8_t ls = (val >> 8) & REC_MASK;
+    mixer_store (s, AC97_Record_Select, rs | (ls << 8));
+}
+
 static void mixer_reset (AC97LinkState *s)
 {
     uint8_t active[LAST_INDEX];
@@ -470,6 +529,11 @@ static void mixer_reset (AC97LinkState *s)
     mixer_store (s, AC97_PCM_LR_ADC_Rate         , 0xbb80);
     mixer_store (s, AC97_MIC_ADC_Rate            , 0xbb80);
 
+    record_select (s, 0);
+    set_volume (s, AC97_Master_Volume_Mute, 0x8000);
+    set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808);
+    set_volume (s, AC97_Line_In_Volume_Mute, 0x8808);
+
     reset_voices (s, active);
 }
 
@@ -528,6 +592,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
         val |= mixer_load (s, index) & 0xf;
         mixer_store (s, index, val);
         break;
+    case AC97_PCM_Out_Volume_Mute:
+    case AC97_Master_Volume_Mute:
+    case AC97_Record_Gain_Mute:
+    case AC97_Line_In_Volume_Mute:
+        set_volume (s, index, val);
+        break;
+    case AC97_Record_Select:
+        record_select (s, val);
+        break;
     case AC97_Vendor_ID1:
     case AC97_Vendor_ID2:
         dolog ("Attempt to write vendor ID to %#x\n", val);
@@ -1080,6 +1153,14 @@ static int ac97_post_load (void *opaque, int version_id)
     uint8_t active[LAST_INDEX];
     AC97LinkState *s = opaque;
 
+    record_select (s, mixer_load (s, AC97_Record_Select));
+    set_volume (s, AC97_Master_Volume_Mute,
+                mixer_load (s, AC97_Master_Volume_Mute));
+    set_volume (s, AC97_PCM_Out_Volume_Mute,
+                mixer_load (s, AC97_PCM_Out_Volume_Mute));
+    set_volume (s, AC97_Line_In_Volume_Mute,
+                mixer_load (s, AC97_Line_In_Volume_Mute));
+
     active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
     active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
     active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM);
commit 5b72392603b6fcb6ac533cb5b74d1cfb4917a0e1
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:38 2012 +0200

    hw/ac97: the volume mask is not only 0x1f
    
    It's a case by case (see Table 66. AC ?97 Baseline Audio Register Map)
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/hw/ac97.c b/hw/ac97.c
index f2804e6..f7866ed 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -118,7 +118,6 @@ enum {
 #define EACS_VRA 1
 #define EACS_VRM 8
 
-#define VOL_MASK 0x1f
 #define MUTE_SHIFT 15
 
 #define REC_MASK 7
commit ed2997cdcbe483d453316ce1b2ff4eae6ce06b7d
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:37 2012 +0200

    hw/ac97: remove USE_MIXER code
    
    That code doesn't compile. The interesting bits for volume control are
    going to be rewritten in the following patch.
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/hw/ac97.c b/hw/ac97.c
index c0fd019..f2804e6 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -437,99 +437,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
     AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
 }
 
-#ifdef USE_MIXER
-static void set_volume (AC97LinkState *s, int index,
-                        audmixerctl_t mt, uint32_t val)
-{
-    int mute = (val >> MUTE_SHIFT) & 1;
-    uint8_t rvol = VOL_MASK - (val & VOL_MASK);
-    uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK);
-    rvol = 255 * rvol / VOL_MASK;
-    lvol = 255 * lvol / VOL_MASK;
-
-#ifdef SOFT_VOLUME
-    if (index == AC97_Master_Volume_Mute) {
-        AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
-    }
-    else {
-        AUD_set_volume (mt, &mute, &lvol, &rvol);
-    }
-#else
-    AUD_set_volume (mt, &mute, &lvol, &rvol);
-#endif
-
-    rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
-    lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
-    mixer_store (s, index, val);
-}
-
-static audrecsource_t ac97_to_aud_record_source (uint8_t i)
-{
-    switch (i) {
-    case REC_MIC:
-        return AUD_REC_MIC;
-
-    case REC_CD:
-        return AUD_REC_CD;
-
-    case REC_VIDEO:
-        return AUD_REC_VIDEO;
-
-    case REC_AUX:
-        return AUD_REC_AUX;
-
-    case REC_LINE_IN:
-        return AUD_REC_LINE_IN;
-
-    case REC_PHONE:
-        return AUD_REC_PHONE;
-
-    default:
-        dolog ("Unknown record source %d, using MIC\n", i);
-        return AUD_REC_MIC;
-    }
-}
-
-static uint8_t aud_to_ac97_record_source (audrecsource_t rs)
-{
-    switch (rs) {
-    case AUD_REC_MIC:
-        return REC_MIC;
-
-    case AUD_REC_CD:
-        return REC_CD;
-
-    case AUD_REC_VIDEO:
-        return REC_VIDEO;
-
-    case AUD_REC_AUX:
-        return REC_AUX;
-
-    case AUD_REC_LINE_IN:
-        return REC_LINE_IN;
-
-    case AUD_REC_PHONE:
-        return REC_PHONE;
-
-    default:
-        dolog ("Unknown audio recording source %d using MIC\n", rs);
-        return REC_MIC;
-    }
-}
-
-static void record_select (AC97LinkState *s, uint32_t val)
-{
-    uint8_t rs = val & REC_MASK;
-    uint8_t ls = (val >> 8) & REC_MASK;
-    audrecsource_t ars = ac97_to_aud_record_source (rs);
-    audrecsource_t als = ac97_to_aud_record_source (ls);
-    AUD_set_record_source (&als, &ars);
-    rs = aud_to_ac97_record_source (ars);
-    ls = aud_to_ac97_record_source (als);
-    mixer_store (s, AC97_Record_Select, rs | (ls << 8));
-}
-#endif
-
 static void mixer_reset (AC97LinkState *s)
 {
     uint8_t active[LAST_INDEX];
@@ -564,12 +471,6 @@ static void mixer_reset (AC97LinkState *s)
     mixer_store (s, AC97_PCM_LR_ADC_Rate         , 0xbb80);
     mixer_store (s, AC97_MIC_ADC_Rate            , 0xbb80);
 
-#ifdef USE_MIXER
-    record_select (s, 0);
-    set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME  , 0x8000);
-    set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM    , 0x8808);
-    set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808);
-#endif
     reset_voices (s, active);
 }
 
@@ -628,20 +529,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
         val |= mixer_load (s, index) & 0xf;
         mixer_store (s, index, val);
         break;
-#ifdef USE_MIXER
-    case AC97_Master_Volume_Mute:
-        set_volume (s, index, AUD_MIXER_VOLUME, val);
-        break;
-    case AC97_PCM_Out_Volume_Mute:
-        set_volume (s, index, AUD_MIXER_PCM, val);
-        break;
-    case AC97_Line_In_Volume_Mute:
-        set_volume (s, index, AUD_MIXER_LINE_IN, val);
-        break;
-    case AC97_Record_Select:
-        record_select (s, val);
-        break;
-#endif
     case AC97_Vendor_ID1:
     case AC97_Vendor_ID2:
         dolog ("Attempt to write vendor ID to %#x\n", val);
@@ -1194,14 +1081,6 @@ static int ac97_post_load (void *opaque, int version_id)
     uint8_t active[LAST_INDEX];
     AC97LinkState *s = opaque;
 
-#ifdef USE_MIXER
-    record_select (s, mixer_load (s, AC97_Record_Select));
-#define V_(a, b) set_volume (s, a, b, mixer_load (s, a))
-    V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME);
-    V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM);
-    V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN);
-#undef V_
-#endif
     active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
     active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
     active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM);
commit c01b2456238f73964876471452e27d4aad7900fb
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:36 2012 +0200

    audio: don't apply volume effect if backend has VOICE_VOLUME_CAP
    
    If the audio backend is capable of volume control, don't apply
    software volume (mixeng_volume ()), but instead, rely on backend
    volume control. This will allow guest to have full range volume
    control.
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/audio.c b/audio/audio.c
index d76c342..bd9237e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -957,7 +957,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
         total += isamp;
     }
 
-    mixeng_volume (sw->buf, ret, &sw->vol);
+    if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) {
+        mixeng_volume (sw->buf, ret, &sw->vol);
+    }
 
     sw->clip (buf, sw->buf, ret);
     sw->total_hw_samples_acquired += total;
@@ -1041,7 +1043,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
     swlim = audio_MIN (swlim, samples);
     if (swlim) {
         sw->conv (sw->buf, buf, swlim);
-        mixeng_volume (sw->buf, swlim, &sw->vol);
+
+        if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) {
+            mixeng_volume (sw->buf, swlim, &sw->vol);
+        }
     }
 
     while (swlim) {
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 117f95e..b9b0676 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -82,6 +82,7 @@ typedef struct HWVoiceOut {
     int samples;
     QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
     QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
+    int ctl_caps;
     struct audio_pcm_ops *pcm_ops;
     QLIST_ENTRY (HWVoiceOut) entries;
 } HWVoiceOut;
@@ -101,6 +102,7 @@ typedef struct HWVoiceIn {
 
     int samples;
     QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
+    int ctl_caps;
     struct audio_pcm_ops *pcm_ops;
     QLIST_ENTRY (HWVoiceIn) entries;
 } HWVoiceIn;
@@ -150,6 +152,7 @@ struct audio_driver {
     int max_voices_in;
     int voice_size_out;
     int voice_size_in;
+    int ctl_caps;
 };
 
 struct audio_pcm_ops {
@@ -233,6 +236,8 @@ void audio_run (const char *msg);
 #define VOICE_DISABLE 2
 #define VOICE_VOLUME 3
 
+#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
+
 static inline int audio_ring_dist (int dst, int src, int len)
 {
     return (dst >= src) ? (dst - src) : (len - src + dst);
diff --git a/audio/audio_template.h b/audio/audio_template.h
index e62a713..519432a 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
     }
 
     hw->pcm_ops = drv->pcm_ops;
+    hw->ctl_caps = drv->ctl_caps;
+
     QLIST_INIT (&hw->sw_head);
 #ifdef DAC
     QLIST_INIT (&hw->cap_head);
commit 6c95ab94f9f7e8d3156e4e16ecc7c499e141bb1a
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Apr 17 14:32:35 2012 +0200

    audio: add VOICE_VOLUME ctl
    
    Add a new PCM control operation to update the stream volume on the
    audio backend.  The argument given is a SWVoiceOut/SWVoiceIn.
    
    v4:
    - verified other backends didn't fail/assert on this new control
      they randomly return 0 or -1, but we ignore return value.
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/audio.c b/audio/audio.c
index 398763f..d76c342 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2053,17 +2053,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
 void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
 {
     if (sw) {
+        HWVoiceOut *hw = sw->hw;
+
         sw->vol.mute = mute;
         sw->vol.l = nominal_volume.l * lvol / 255;
         sw->vol.r = nominal_volume.r * rvol / 255;
+
+        if (hw->pcm_ops->ctl_out) {
+            hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw);
+        }
     }
 }
 
 void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
 {
     if (sw) {
+        HWVoiceIn *hw = sw->hw;
+
         sw->vol.mute = mute;
         sw->vol.l = nominal_volume.l * lvol / 255;
         sw->vol.r = nominal_volume.r * rvol / 255;
+
+        if (hw->pcm_ops->ctl_in) {
+            hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw);
+        }
     }
 }
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 2003f8b..117f95e 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -231,6 +231,7 @@ void audio_run (const char *msg);
 
 #define VOICE_ENABLE 1
 #define VOICE_DISABLE 2
+#define VOICE_VOLUME 3
 
 static inline int audio_ring_dist (int dst, int src, int len)
 {
commit 6b034aa138716a515c88f7894940d5d0aff2f3ed
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Apr 17 10:51:41 2012 +0200

    seabios: update to 1.7.0
    
    Update roms/seabios and pc-bios/bios.bin to the 1.7.0 release.
    Most noticable new feature is virtio-scsi support.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index e1f3923..5734ae5 100644
Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ
diff --git a/roms/seabios b/roms/seabios
index 2e8bd61..a026308 160000
--- a/roms/seabios
+++ b/roms/seabios
@@ -1 +1 @@
-Subproject commit 2e8bd611ce4e1e36b5a80c9ca6e256e23802f095
+Subproject commit a0263083cb4cda172832fbc916dc1417ee930574
commit c7020c974073ba9c0110d45361720a29ff6b2f59
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Mar 30 13:20:21 2012 +0200

    usb-ehci: drop assert()
    
    Not sure what the purpose of the assert() was, in any case it is bogous.
    We can arrive there if transfer descriptors passed to us from the guest
    failed to pass sanity checks, i.e. it is guest-triggerable.  We deal
    with that case by resetting the host controller.  Everything is ok, no
    need to throw a core dump here.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index e12f098..23631a4 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2009,7 +2009,6 @@ static void ehci_advance_state(EHCIState *ehci,
             fprintf(stderr, "processing error - resetting ehci HC\n");
             ehci_reset(ehci);
             again = 0;
-            assert(0);
         }
     }
     while (again);
commit 714f9db06c209fd42d67e6dffd4f7fd932b51b65
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Fri Mar 30 09:53:54 2012 +0200

    usb-redir: Notify our peer when we reject a device due to a speed mismatch
    
    Also cleanup (reset) our device state when we reject a device due to a
    speed mismatch.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 4288324..94ab463 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -836,7 +836,13 @@ static void usbredir_do_attach(void *opaque)
 {
     USBRedirDevice *dev = opaque;
 
-    usb_device_attach(&dev->dev);
+    if (usb_device_attach(&dev->dev) != 0) {
+        usbredir_device_disconnect(dev);
+        if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
+            usbredirparser_send_filter_reject(dev->parser);
+            usbredirparser_do_write(dev->parser);
+        }
+    }
 }
 
 /*
commit 8e24283b2687e1d58d5f6a4872198c29e8a45d00
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Fri Mar 30 09:53:53 2012 +0200

    usb-ehci: Drop unused sofv value
    
    The sofv value only ever gets a value assigned and is never used (read)
    anywhere, so we can just drop it.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index be02308..e12f098 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -403,7 +403,6 @@ struct EHCIState {
     /*
      *  Internal states, shadow registers, etc
      */
-    uint32_t sofv;
     QEMUTimer *frame_timer;
     int attach_poll_counter;
     int astate;                        // Current state in asynchronous schedule
@@ -1102,10 +1101,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
         val &= USBINTR_MASK;
         break;
 
-    case FRINDEX:
-        s->sofv = val >> 3;
-        break;
-
     case CONFIGFLAG:
         val &= 0x1;
         if (val) {
@@ -2157,9 +2152,6 @@ static void ehci_frame_timer(void *opaque)
                 ehci_set_interrupt(ehci, USBSTS_FLR);
                 ehci->frindex = 0;
             }
-
-            ehci->sofv = (ehci->frindex - 1) >> 3;
-            ehci->sofv &= 0x000003ff;
         }
 
         if (frames - i > ehci->maxframes) {
commit 96dd9aac37d30f3425088f81523942e67b2d03ac
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 29 16:06:28 2012 +0200

    usb-host: rewrite usb_linux_update_endp_table
    
    This patch carries a complete rewrite of the usb descriptor parser.
    Changes / improvements:
    
     * We are using the USBDescriptor struct instead of hard-coded offsets
       now to access descriptor data.
     * (debug) printfs are all gone, tracepoints have been added instead.
     * We don't try (and fail) to skip over unneeded descriptors.  We parse
       them all one by one.  We keep track of which configuration, interface
       and altsetting we are looking at and use this information to figure
       which desciptors are in use and which we can ignore.
     * On parse errors we clear all endpoint information, which will
       disallow any communication with the device, except control endpoint
       messages.  This makes sure we don't end up with a silly device state
       where half of the endpoints got enabled and the other half was left
       disabled.
     * Some sanity checks have been added.
    
    The new parser is more robust and also leaves complete device
    information in the trace log if you enable the ush_host_parse_*
    tracepoints.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index a382f0a..061a1b7 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -42,6 +42,7 @@
 #include <linux/usbdevice_fs.h>
 #include <linux/version.h>
 #include "hw/usb.h"
+#include "hw/usb/desc.h"
 
 /* We redefine it to avoid version problems */
 struct usb_ctrltransfer {
@@ -1108,121 +1109,128 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
     return USB_RET_ASYNC;
 }
 
-static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
-    uint8_t configuration, uint8_t interface)
-{
-    char device_name[64], line[1024];
-    int alt_setting;
-
-    sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
-            (int)configuration, (int)interface);
-
-    if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
-                            device_name)) {
-        /* Assume alt 0 on error */
-        return 0;
-    }
-    if (sscanf(line, "%d", &alt_setting) != 1) {
-        /* Assume alt 0 on error */
-        return 0;
-    }
-    return alt_setting;
-}
-
 /* returns 1 on problem encountered or 0 for success */
 static int usb_linux_update_endp_table(USBHostDevice *s)
 {
-    uint8_t *descriptors;
-    uint8_t devep, type, alt_interface;
-    uint16_t raw;
-    int interface, length, i, ep, pid;
+    static const char *tname[] = {
+        [USB_ENDPOINT_XFER_CONTROL] = "control",
+        [USB_ENDPOINT_XFER_ISOC]    = "isoc",
+        [USB_ENDPOINT_XFER_BULK]    = "bulk",
+        [USB_ENDPOINT_XFER_INT]     = "int",
+    };
+    uint8_t devep, type;
+    uint16_t mps, v, p;
+    int ep, pid;
+    unsigned int i, configuration = -1, interface = -1, altsetting = -1;
     struct endp_data *epd;
+    USBDescriptor *d;
+    bool active = false;
 
     usb_ep_init(&s->dev);
 
-    if (s->dev.configuration == 0) {
-        /* not configured yet -- leave all endpoints disabled */
-        return 0;
-    }
-
-    /* get the desired configuration, interface, and endpoint descriptors
-     * from device description */
-    descriptors = &s->descr[18];
-    length = s->descr_len - 18;
-    i = 0;
-
-    while (i < length) {
-        if (descriptors[i + 1] != USB_DT_CONFIG) {
-            fprintf(stderr, "invalid descriptor data\n");
-            return 1;
-        } else if (descriptors[i + 5] != s->dev.configuration) {
-            DPRINTF("not requested configuration %d\n", s->dev.configuration);
-            i += (descriptors[i + 3] << 8) + descriptors[i + 2];
-            continue;
-        }
-        i += descriptors[i];
-
-        if (descriptors[i + 1] != USB_DT_INTERFACE ||
-            (descriptors[i + 1] == USB_DT_INTERFACE &&
-             descriptors[i + 4] == 0)) {
-            i += descriptors[i];
-            continue;
+    for (i = 0;; i += d->bLength) {
+        if (i+2 >= s->descr_len) {
+            break;
         }
-
-        interface = descriptors[i + 2];
-        alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
-                                                  interface);
-
-        /* the current interface descriptor is the active interface
-         * and has endpoints */
-        if (descriptors[i + 3] != alt_interface) {
-            i += descriptors[i];
-            continue;
+        d = (void *)(s->descr + i);
+        if (d->bLength < 2) {
+            trace_usb_host_parse_error(s->bus_num, s->addr,
+                                       "descriptor too short");
+            goto error;
         }
-
-        /* advance to the endpoints */
-        while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
-            i += descriptors[i];
+        if (i + d->bLength > s->descr_len) {
+            trace_usb_host_parse_error(s->bus_num, s->addr,
+                                       "descriptor too long");
+            goto error;
         }
-
-        if (i >= length)
+        switch (d->bDescriptorType) {
+        case 0:
+            trace_usb_host_parse_error(s->bus_num, s->addr,
+                                       "invalid descriptor type");
+            goto error;
+        case USB_DT_DEVICE:
+            if (d->bLength < 0x12) {
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "device descriptor too short");
+                goto error;
+            }
+            v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo;
+            p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo;
+            trace_usb_host_parse_device(s->bus_num, s->addr, v, p);
             break;
-
-        while (i < length) {
-            if (descriptors[i + 1] != USB_DT_ENDPOINT) {
-                break;
+        case USB_DT_CONFIG:
+            if (d->bLength < 0x09) {
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "config descriptor too short");
+                goto error;
             }
-
-            devep = descriptors[i + 2];
+            configuration = d->u.config.bConfigurationValue;
+            active = (configuration == s->dev.configuration);
+            trace_usb_host_parse_config(s->bus_num, s->addr,
+                                        configuration, active);
+            break;
+        case USB_DT_INTERFACE:
+            if (d->bLength < 0x09) {
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "interface descriptor too short");
+                goto error;
+            }
+            interface = d->u.interface.bInterfaceNumber;
+            altsetting = d->u.interface.bAlternateSetting;
+            active = (configuration == s->dev.configuration) &&
+                (altsetting == s->dev.altsetting[interface]);
+            trace_usb_host_parse_interface(s->bus_num, s->addr,
+                                           interface, altsetting, active);
+            break;
+        case USB_DT_ENDPOINT:
+            if (d->bLength < 0x07) {
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "endpoint descriptor too short");
+                goto error;
+            }
+            devep = d->u.endpoint.bEndpointAddress;
             pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
             ep = devep & 0xf;
             if (ep == 0) {
-                fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
-                return 1;
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "invalid endpoint address");
+                goto error;
             }
 
-            type = descriptors[i + 3] & 0x3;
-            raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
-            usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
-            assert(usb_ep_get_type(&s->dev, pid, ep) ==
-                   USB_ENDPOINT_XFER_INVALID);
-            usb_ep_set_type(&s->dev, pid, ep, type);
-            usb_ep_set_ifnum(&s->dev, pid, ep, interface);
-            if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
-                (type == USB_ENDPOINT_XFER_BULK)) {
-                usb_ep_set_pipeline(&s->dev, pid, ep, true);
-            }
+            type = d->u.endpoint.bmAttributes & 0x3;
+            mps = d->u.endpoint.wMaxPacketSize_lo |
+                (d->u.endpoint.wMaxPacketSize_hi << 8);
+            trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep,
+                                          (devep & USB_DIR_IN) ? "in" : "out",
+                                          tname[type], active);
+
+            if (active) {
+                usb_ep_set_max_packet_size(&s->dev, pid, ep, mps);
+                assert(usb_ep_get_type(&s->dev, pid, ep) ==
+                       USB_ENDPOINT_XFER_INVALID);
+                usb_ep_set_type(&s->dev, pid, ep, type);
+                usb_ep_set_ifnum(&s->dev, pid, ep, interface);
+                if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
+                    (type == USB_ENDPOINT_XFER_BULK)) {
+                    usb_ep_set_pipeline(&s->dev, pid, ep, true);
+                }
 
-            epd = get_endp(s, pid, ep);
-            epd->halted = 0;
+                epd = get_endp(s, pid, ep);
+                epd->halted = 0;
+            }
 
-            i += descriptors[i];
+            break;
+        default:
+            trace_usb_host_parse_unknown(s->bus_num, s->addr,
+                                         d->bLength, d->bDescriptorType);
+            break;
         }
     }
-#ifdef DEBUG
-    usb_ep_dump(&s->dev);
-#endif
     return 0;
+
+error:
+    usb_ep_init(&s->dev);
+    return 1;
 }
 
 /*
diff --git a/trace-events b/trace-events
index e7ce5b2..d2e7879 100644
--- a/trace-events
+++ b/trace-events
@@ -337,6 +337,12 @@ usb_host_reset(int bus, int addr) "dev %d:%d"
 usb_host_auto_scan_enabled(void)
 usb_host_auto_scan_disabled(void)
 usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
+usb_host_parse_device(int bus, int addr, int vendor, int product) "dev %d:%d, id %04x:%04x"
+usb_host_parse_config(int bus, int addr, int value, int active) "dev %d:%d, value %d, active %d"
+usb_host_parse_interface(int bus, int addr, int num, int alt, int active) "dev %d:%d, num %d, alt %d, active %d"
+usb_host_parse_endpoint(int bus, int addr, int ep, const char *dir, const char *type, int active) "dev %d:%d, ep %d, %s, %s, active %d"
+usb_host_parse_unknown(int bus, int addr, int len, int type) "dev %d:%d, len %d, type %d"
+usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s"
 
 # hw/scsi-bus.c
 scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
commit e36a20d329b4cf52ce3b269345527e7ebcc00885
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 29 16:01:21 2012 +0200

    usb: use USBDescriptor for endpoint descriptors.
    
    Add endpoint descriptor substruct to USBDescriptor,
    use it in the descriptor generator code.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 2b8febb..3c77368 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -200,21 +200,23 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
 {
     uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
     uint8_t extralen = ep->extra ? ep->extra[0] : 0;
+    USBDescriptor *d = (void *)dest;
 
     if (len < bLength + extralen) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_ENDPOINT;
-    dest[0x02] = ep->bEndpointAddress;
-    dest[0x03] = ep->bmAttributes;
-    dest[0x04] = usb_lo(ep->wMaxPacketSize);
-    dest[0x05] = usb_hi(ep->wMaxPacketSize);
-    dest[0x06] = ep->bInterval;
+    d->bLength                      = bLength;
+    d->bDescriptorType              = USB_DT_ENDPOINT;
+
+    d->u.endpoint.bEndpointAddress  = ep->bEndpointAddress;
+    d->u.endpoint.bmAttributes      = ep->bmAttributes;
+    d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep->wMaxPacketSize);
+    d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep->wMaxPacketSize);
+    d->u.endpoint.bInterval         = ep->bInterval;
     if (ep->is_audio) {
-        dest[0x07] = ep->bRefresh;
-        dest[0x08] = ep->bSynchAddress;
+        d->u.endpoint.bRefresh      = ep->bRefresh;
+        d->u.endpoint.bSynchAddress = ep->bSynchAddress;
     }
     if (ep->extra) {
         memcpy(dest + bLength, ep->extra, extralen);
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 6f42eae..d164e8f 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -54,6 +54,15 @@ typedef struct USBDescriptor {
             uint8_t           bInterfaceProtocol;
             uint8_t           iInterface;
         } interface;
+        struct {
+            uint8_t           bEndpointAddress;
+            uint8_t           bmAttributes;
+            uint8_t           wMaxPacketSize_lo;
+            uint8_t           wMaxPacketSize_hi;
+            uint8_t           bInterval;
+            uint8_t           bRefresh;        /* only audio ep */
+            uint8_t           bSynchAddress;   /* only audio ep */
+        } endpoint;
     } u;
 } QEMU_PACKED USBDescriptor;
 
commit feafd797ee5b12d6831aaafccd41c192ad9cc8bd
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 29 12:30:33 2012 +0200

    usb: use USBDescriptor for interface descriptors.
    
    Add interface descriptor substruct to USBDescriptor,
    use it in the descriptor generator code.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 3466968..2b8febb 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -159,20 +159,22 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
 {
     uint8_t bLength = 0x09;
     int i, rc, pos = 0;
+    USBDescriptor *d = (void *)dest;
 
     if (len < bLength) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_INTERFACE;
-    dest[0x02] = iface->bInterfaceNumber;
-    dest[0x03] = iface->bAlternateSetting;
-    dest[0x04] = iface->bNumEndpoints;
-    dest[0x05] = iface->bInterfaceClass;
-    dest[0x06] = iface->bInterfaceSubClass;
-    dest[0x07] = iface->bInterfaceProtocol;
-    dest[0x08] = iface->iInterface;
+    d->bLength                        = bLength;
+    d->bDescriptorType                = USB_DT_INTERFACE;
+
+    d->u.interface.bInterfaceNumber   = iface->bInterfaceNumber;
+    d->u.interface.bAlternateSetting  = iface->bAlternateSetting;
+    d->u.interface.bNumEndpoints      = iface->bNumEndpoints;
+    d->u.interface.bInterfaceClass    = iface->bInterfaceClass;
+    d->u.interface.bInterfaceSubClass = iface->bInterfaceSubClass;
+    d->u.interface.bInterfaceProtocol = iface->bInterfaceProtocol;
+    d->u.interface.iInterface         = iface->iInterface;
     pos += bLength;
 
     for (i = 0; i < iface->ndesc; i++) {
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 298e050..6f42eae 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -45,6 +45,15 @@ typedef struct USBDescriptor {
             uint8_t           bmAttributes;
             uint8_t           bMaxPower;
         } config;
+        struct {
+            uint8_t           bInterfaceNumber;
+            uint8_t           bAlternateSetting;
+            uint8_t           bNumEndpoints;
+            uint8_t           bInterfaceClass;
+            uint8_t           bInterfaceSubClass;
+            uint8_t           bInterfaceProtocol;
+            uint8_t           iInterface;
+        } interface;
     } u;
 } QEMU_PACKED USBDescriptor;
 
commit 0a263db17a59a04b8f22540b284919956751e4f8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 29 12:24:08 2012 +0200

    usb: use USBDescriptor for config descriptors.
    
    Add config descriptor substruct to USBDescriptor,
    use it in the descriptor generator code.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 5cecb25..3466968 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -78,22 +78,24 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
 {
     uint8_t  bLength = 0x09;
     uint16_t wTotalLength = 0;
+    USBDescriptor *d = (void *)dest;
     int i, rc;
 
     if (len < bLength) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_CONFIG;
-    dest[0x04] = conf->bNumInterfaces;
-    dest[0x05] = conf->bConfigurationValue;
-    dest[0x06] = conf->iConfiguration;
-    dest[0x07] = conf->bmAttributes;
-    dest[0x08] = conf->bMaxPower;
+    d->bLength                      = bLength;
+    d->bDescriptorType              = USB_DT_CONFIG;
+
+    d->u.config.bNumInterfaces      = conf->bNumInterfaces;
+    d->u.config.bConfigurationValue = conf->bConfigurationValue;
+    d->u.config.iConfiguration      = conf->iConfiguration;
+    d->u.config.bmAttributes        = conf->bmAttributes;
+    d->u.config.bMaxPower           = conf->bMaxPower;
     wTotalLength += bLength;
 
-    /* handle grouped interfaces if any*/
+    /* handle grouped interfaces if any */
     for (i = 0; i < conf->nif_groups; i++) {
         rc = usb_desc_iface_group(&(conf->if_groups[i]),
                                   dest + wTotalLength,
@@ -113,8 +115,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
         wTotalLength += rc;
     }
 
-    dest[0x02] = usb_lo(wTotalLength);
-    dest[0x03] = usb_hi(wTotalLength);
+    d->u.config.wTotalLength_lo = usb_lo(wTotalLength);
+    d->u.config.wTotalLength_hi = usb_hi(wTotalLength);
     return wTotalLength;
 }
 
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 15d0780..298e050 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -36,6 +36,15 @@ typedef struct USBDescriptor {
             uint8_t           bNumConfigurations;
             uint8_t           bReserved;
         } device_qualifier;
+        struct {
+            uint8_t           wTotalLength_lo;
+            uint8_t           wTotalLength_hi;
+            uint8_t           bNumInterfaces;
+            uint8_t           bConfigurationValue;
+            uint8_t           iConfiguration;
+            uint8_t           bmAttributes;
+            uint8_t           bMaxPower;
+        } config;
     } u;
 } QEMU_PACKED USBDescriptor;
 
commit 3cfeee6177bb7c86db8e1fa01cd6f5d438e4c463
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 29 12:15:01 2012 +0200

    usb: use USBDescriptor for device qualifier descriptors.
    
    Add device qualifier substruct to USBDescriptor,
    use it in the descriptor generator code.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index de7e204..5cecb25 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -53,22 +53,23 @@ int usb_desc_device_qualifier(const USBDescDevice *dev,
                               uint8_t *dest, size_t len)
 {
     uint8_t bLength = 0x0a;
+    USBDescriptor *d = (void *)dest;
 
     if (len < bLength) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_DEVICE_QUALIFIER;
-
-    dest[0x02] = usb_lo(dev->bcdUSB);
-    dest[0x03] = usb_hi(dev->bcdUSB);
-    dest[0x04] = dev->bDeviceClass;
-    dest[0x05] = dev->bDeviceSubClass;
-    dest[0x06] = dev->bDeviceProtocol;
-    dest[0x07] = dev->bMaxPacketSize0;
-    dest[0x08] = dev->bNumConfigurations;
-    dest[0x09] = 0; /* reserved */
+    d->bLength                               = bLength;
+    d->bDescriptorType                       = USB_DT_DEVICE_QUALIFIER;
+
+    d->u.device_qualifier.bcdUSB_lo          = usb_lo(dev->bcdUSB);
+    d->u.device_qualifier.bcdUSB_hi          = usb_hi(dev->bcdUSB);
+    d->u.device_qualifier.bDeviceClass       = dev->bDeviceClass;
+    d->u.device_qualifier.bDeviceSubClass    = dev->bDeviceSubClass;
+    d->u.device_qualifier.bDeviceProtocol    = dev->bDeviceProtocol;
+    d->u.device_qualifier.bMaxPacketSize0    = dev->bMaxPacketSize0;
+    d->u.device_qualifier.bNumConfigurations = dev->bNumConfigurations;
+    d->u.device_qualifier.bReserved          = 0;
 
     return bLength;
 }
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index c5a242e..15d0780 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -26,6 +26,16 @@ typedef struct USBDescriptor {
             uint8_t           iSerialNumber;
             uint8_t           bNumConfigurations;
         } device;
+        struct {
+            uint8_t           bcdUSB_lo;
+            uint8_t           bcdUSB_hi;
+            uint8_t           bDeviceClass;
+            uint8_t           bDeviceSubClass;
+            uint8_t           bDeviceProtocol;
+            uint8_t           bMaxPacketSize0;
+            uint8_t           bNumConfigurations;
+            uint8_t           bReserved;
+        } device_qualifier;
     } u;
 } QEMU_PACKED USBDescriptor;
 
commit d3f904ea7b3027f58037e359cc199c2490dc5c3d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 29 12:04:54 2012 +0200

    usb: add USBDescriptor, use for device descriptors.
    
    This patch adds a new type for the binary representation of usb
    descriptors.  It is put into use for the descriptor generator code
    where the struct replaces the hard-coded offsets.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 9847a75..de7e204 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -18,32 +18,33 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
                     uint8_t *dest, size_t len)
 {
     uint8_t bLength = 0x12;
+    USBDescriptor *d = (void *)dest;
 
     if (len < bLength) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_DEVICE;
+    d->bLength                     = bLength;
+    d->bDescriptorType             = USB_DT_DEVICE;
 
-    dest[0x02] = usb_lo(dev->bcdUSB);
-    dest[0x03] = usb_hi(dev->bcdUSB);
-    dest[0x04] = dev->bDeviceClass;
-    dest[0x05] = dev->bDeviceSubClass;
-    dest[0x06] = dev->bDeviceProtocol;
-    dest[0x07] = dev->bMaxPacketSize0;
+    d->u.device.bcdUSB_lo          = usb_lo(dev->bcdUSB);
+    d->u.device.bcdUSB_hi          = usb_hi(dev->bcdUSB);
+    d->u.device.bDeviceClass       = dev->bDeviceClass;
+    d->u.device.bDeviceSubClass    = dev->bDeviceSubClass;
+    d->u.device.bDeviceProtocol    = dev->bDeviceProtocol;
+    d->u.device.bMaxPacketSize0    = dev->bMaxPacketSize0;
+
+    d->u.device.idVendor_lo        = usb_lo(id->idVendor);
+    d->u.device.idVendor_hi        = usb_hi(id->idVendor);
+    d->u.device.idProduct_lo       = usb_lo(id->idProduct);
+    d->u.device.idProduct_hi       = usb_hi(id->idProduct);
+    d->u.device.bcdDevice_lo       = usb_lo(id->bcdDevice);
+    d->u.device.bcdDevice_hi       = usb_hi(id->bcdDevice);
+    d->u.device.iManufacturer      = id->iManufacturer;
+    d->u.device.iProduct           = id->iProduct;
+    d->u.device.iSerialNumber      = id->iSerialNumber;
 
-    dest[0x08] = usb_lo(id->idVendor);
-    dest[0x09] = usb_hi(id->idVendor);
-    dest[0x0a] = usb_lo(id->idProduct);
-    dest[0x0b] = usb_hi(id->idProduct);
-    dest[0x0c] = usb_lo(id->bcdDevice);
-    dest[0x0d] = usb_hi(id->bcdDevice);
-    dest[0x0e] = id->iManufacturer;
-    dest[0x0f] = id->iProduct;
-    dest[0x10] = id->iSerialNumber;
-
-    dest[0x11] = dev->bNumConfigurations;
+    d->u.device.bNumConfigurations = dev->bNumConfigurations;
 
     return bLength;
 }
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index d6e07ea..c5a242e 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -3,6 +3,32 @@
 
 #include <inttypes.h>
 
+/* binary representation */
+typedef struct USBDescriptor {
+    uint8_t                   bLength;
+    uint8_t                   bDescriptorType;
+    union {
+        struct {
+            uint8_t           bcdUSB_lo;
+            uint8_t           bcdUSB_hi;
+            uint8_t           bDeviceClass;
+            uint8_t           bDeviceSubClass;
+            uint8_t           bDeviceProtocol;
+            uint8_t           bMaxPacketSize0;
+            uint8_t           idVendor_lo;
+            uint8_t           idVendor_hi;
+            uint8_t           idProduct_lo;
+            uint8_t           idProduct_hi;
+            uint8_t           bcdDevice_lo;
+            uint8_t           bcdDevice_hi;
+            uint8_t           iManufacturer;
+            uint8_t           iProduct;
+            uint8_t           iSerialNumber;
+            uint8_t           bNumConfigurations;
+        } device;
+    } u;
+} QEMU_PACKED USBDescriptor;
+
 struct USBDescID {
     uint16_t                  idVendor;
     uint16_t                  idProduct;
commit 58ea88d87a834923b31271750b8eab6403a797be
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Wed Mar 28 20:47:51 2012 +0200

    usb-ehci: frindex always is a 14 bits counter
    
    frindex always is a 14 bits counter, and not a 13 bits one as we were
    emulating. There are some subtle hints to this in the spec, first of all
    "Table 2-12. FRINDEX - Frame Index Register" says:
    "Bit 13:0 Frame Index. The value in this register increments at the end of
    each time frame (e.g. micro-frame). Bits [N:3] are used for the Frame List
    current index. This means that each location of the frame list is accessed
    8 times (frames or micro-frames) before moving to the next index. The
    following illustrates values of N based on the value of the Frame List
    Size field in the USBCMD register.
    
    USBCMD[Frame List Size]	Number Elements		 N
    00b				1024		12
    01b				 512		11
    10b				 256		10
    11b			    Reserved"
    
    Notice how the text talks about "Bits [N:3]" are used ..., it does
    NOT say that when N == 12 (our case) the counter will wrap from 8191 to 0,
    or in otherwords that it is a 13 bits counter (bits 0 - 12).
    
    The other hint is in "Table 2-10. USBSTS USB Status Register Bit Definitions":
    
    "Bit 3 Frame List Rollover - R/WC. The Host Controller sets this bit to a one
    when the Frame List Index (see Section 2.3.4) rolls over from its maximum value
    to zero. The exact value at which the rollover occurs depends on the frame
    list size. For example, if the frame list size (as programmed in the Frame
    List Size field of the USBCMD register) is 1024, the Frame Index Register
    rolls over every time FRINDEX[13] toggles. Similarly, if the size is 512,
    the Host Controller sets this bit to a one every time FRINDEX[12] toggles."
    
    Notice how this text talks about setting bit 3 when bit 13 of frindex toggles
    (when there are 1024 entries, so our case), so this indicates that frindex
    has a bit 13 making it a 14 bit counter.
    
    Besides these clear hints the real proof is in the pudding. Before this
    patch I could not stream data from a USB2 webcam under Windows XP, after
    this cam using a USB2 webcam under Windows XP works fine, and no regressions
    with other operating systems were seen.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 34f7538..be02308 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2149,11 +2149,15 @@ static void ehci_frame_timer(void *opaque)
         if ( !(ehci->usbsts & USBSTS_HALT)) {
             ehci->frindex += 8;
 
-            if (ehci->frindex > 0x00001fff) {
-                ehci->frindex = 0;
+            if (ehci->frindex == 0x00002000) {
                 ehci_set_interrupt(ehci, USBSTS_FLR);
             }
 
+            if (ehci->frindex == 0x00004000) {
+                ehci_set_interrupt(ehci, USBSTS_FLR);
+                ehci->frindex = 0;
+            }
+
             ehci->sofv = (ehci->frindex - 1) >> 3;
             ehci->sofv &= 0x000003ff;
         }
commit 088351a7e50b7f14cda9520bcb8a7896e226aa36
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Mar 23 15:43:45 2012 +0100

    usb-ehci: fix ehci_child_detach
    
    Looks like a cut+paste bug from ehci_detach.  When the device itself is
    detached from a ehci port (ehci_detach op) we have to clear the
    device pointer for the companion port too.  When a device gets removed
    from a downstream port of a usb hub (ehci_child_detach op) the ehci port
    where the usb hub is plugged in is not affected.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 60f9f5b..34f7538 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -797,7 +797,6 @@ static void ehci_child_detach(USBPort *port, USBDevice *child)
     if (portsc & PORTSC_POWNER) {
         USBPort *companion = s->companion_ports[port->index];
         companion->ops->child_detach(companion, child);
-        companion->dev = NULL;
         return;
     }
 
commit 529f8f9fa939b8db13bf5cd1cd549d993cf25cb8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Mar 23 15:42:58 2012 +0100

    usb-hub: add tracepoints
    
    Add tracepoints to the usb hub emulation.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index eb4e711..9c91665 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -22,11 +22,10 @@
  * THE SOFTWARE.
  */
 #include "qemu-common.h"
+#include "trace.h"
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
 
-//#define DEBUG
-
 #define NUM_PORTS 8
 
 typedef struct USBHubPort {
@@ -157,6 +156,7 @@ static void usb_hub_attach(USBPort *port1)
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
 
+    trace_usb_hub_attach(s->dev.addr, port1->index + 1);
     port->wPortStatus |= PORT_STAT_CONNECTION;
     port->wPortChange |= PORT_STAT_C_CONNECTION;
     if (port->port.dev->speed == USB_SPEED_LOW) {
@@ -172,6 +172,7 @@ static void usb_hub_detach(USBPort *port1)
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
 
+    trace_usb_hub_detach(s->dev.addr, port1->index + 1);
     usb_wakeup(s->intr);
 
     /* Let upstream know the device on this port is gone */
@@ -247,6 +248,7 @@ static void usb_hub_handle_reset(USBDevice *dev)
     USBHubPort *port;
     int i;
 
+    trace_usb_hub_reset(s->dev.addr);
     for (i = 0; i < NUM_PORTS; i++) {
         port = s->ports + i;
         port->wPortStatus = PORT_STAT_POWER;
@@ -261,12 +263,39 @@ static void usb_hub_handle_reset(USBDevice *dev)
     }
 }
 
+static const char *feature_name(int feature)
+{
+    static const char *name[] = {
+        [PORT_CONNECTION]    = "connection",
+        [PORT_ENABLE]        = "enable",
+        [PORT_SUSPEND]       = "suspend",
+        [PORT_OVERCURRENT]   = "overcurrent",
+        [PORT_RESET]         = "reset",
+        [PORT_POWER]         = "power",
+        [PORT_LOWSPEED]      = "lowspeed",
+        [PORT_HIGHSPEED]     = "highspeed",
+        [PORT_C_CONNECTION]  = "change connection",
+        [PORT_C_ENABLE]      = "change enable",
+        [PORT_C_SUSPEND]     = "change suspend",
+        [PORT_C_OVERCURRENT] = "change overcurrent",
+        [PORT_C_RESET]       = "change reset",
+        [PORT_TEST]          = "test",
+        [PORT_INDICATOR]     = "indicator",
+    };
+    if (feature < 0 || feature >= ARRAY_SIZE(name)) {
+        return "?";
+    }
+    return name[feature] ?: "?";
+}
+
 static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                int request, int value, int index, int length, uint8_t *data)
 {
     USBHubState *s = (USBHubState *)dev;
     int ret;
 
+    trace_usb_hub_control(s->dev.addr, request, value, index, length);
+
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
     if (ret >= 0) {
         return ret;
@@ -295,6 +324,9 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                 goto fail;
             }
             port = &s->ports[n];
+            trace_usb_hub_get_port_status(s->dev.addr, index,
+                                          port->wPortStatus,
+                                          port->wPortChange);
             data[0] = port->wPortStatus;
             data[1] = port->wPortStatus >> 8;
             data[2] = port->wPortChange;
@@ -315,6 +347,10 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             unsigned int n = index - 1;
             USBHubPort *port;
             USBDevice *dev;
+
+            trace_usb_hub_set_port_feature(s->dev.addr, index,
+                                           feature_name(value));
+
             if (n >= NUM_PORTS) {
                 goto fail;
             }
@@ -345,6 +381,9 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             unsigned int n = index - 1;
             USBHubPort *port;
 
+            trace_usb_hub_clear_port_feature(s->dev.addr, index,
+                                             feature_name(value));
+
             if (n >= NUM_PORTS) {
                 goto fail;
             }
diff --git a/trace-events b/trace-events
index e3b1787..e7ce5b2 100644
--- a/trace-events
+++ b/trace-events
@@ -289,7 +289,7 @@ usb_uhci_td_nextqh(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
 usb_uhci_td_async(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
 usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
 
-# hw/usb-desc.c
+# hw/usb/desc.c
 usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
 usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
 usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
@@ -301,6 +301,15 @@ usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d,
 usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
 usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
 
+# hw/usb/dev-hub.c
+usb_hub_reset(int addr) "dev %d"
+usb_hub_control(int addr, int request, int value, int index, int length) "dev %d, req 0x%x, value %d, index %d, langth %d"
+usb_hub_get_port_status(int addr, int nr, int status, int changed) "dev %d, port %d, status 0x%x, changed 0x%x"
+usb_hub_set_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s"
+usb_hub_clear_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s"
+usb_hub_attach(int addr, int nr) "dev %d, port %d"
+usb_hub_detach(int addr, int nr) "dev %d, port %d"
+
 # hw/usb/host-linux.c
 usb_host_open_started(int bus, int addr) "dev %d:%d"
 usb_host_open_success(int bus, int addr) "dev %d:%d"
commit f5bf14bf39ec1ca2ad70ca1ec0e38a3e1e3f252d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Mar 23 13:34:50 2012 +0100

    usb_packet_set_state: handle p->ep == NULL
    
    usb_packet_set_state can be called with p->ep = NULL.  The tracepoint
    there tries to log endpoint information, which leads to a segfault.
    This patch makes usb_packet_set_state handle the NULL pointer properly.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/core.c b/hw/usb/core.c
index a4048fe..9a14a53 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -484,12 +484,17 @@ void usb_packet_check_state(USBPacket *p, USBPacketState expected)
 
 void usb_packet_set_state(USBPacket *p, USBPacketState state)
 {
-    USBDevice *dev = p->ep->dev;
-    USBBus *bus = usb_bus_from_device(dev);
-
-    trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
-                                  usb_packet_state_name(p->state),
-                                  usb_packet_state_name(state));
+    if (p->ep) {
+        USBDevice *dev = p->ep->dev;
+        USBBus *bus = usb_bus_from_device(dev);
+        trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
+                                      usb_packet_state_name(p->state),
+                                      usb_packet_state_name(state));
+    } else {
+        trace_usb_packet_state_change(-1, "", -1, p,
+                                      usb_packet_state_name(p->state),
+                                      usb_packet_state_name(state));
+    }
     p->state = state;
 }
 
commit 39c20577009731d5e059db10ef269807b57e498d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 22 15:28:45 2012 +0100

    usb-host: add property to turn off pipelining
    
    Add a property to usb-host to disable the bulk endpoint pipelining.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 8084fd9..a382f0a 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -94,6 +94,10 @@ struct USBAutoFilter {
     uint32_t product_id;
 };
 
+enum USBHostDeviceOptions {
+    USB_HOST_OPT_PIPELINE,
+};
+
 typedef struct USBHostDevice {
     USBDevice dev;
     int       fd;
@@ -104,6 +108,7 @@ typedef struct USBHostDevice {
     int       descr_len;
     int       closing;
     uint32_t  iso_urb_count;
+    uint32_t  options;
     Notifier  exit;
 
     struct endp_data ep_in[USB_MAX_ENDPOINTS];
@@ -1203,7 +1208,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
                    USB_ENDPOINT_XFER_INVALID);
             usb_ep_set_type(&s->dev, pid, ep, type);
             usb_ep_set_ifnum(&s->dev, pid, ep, interface);
-            if (type == USB_ENDPOINT_XFER_BULK) {
+            if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
+                (type == USB_ENDPOINT_XFER_BULK)) {
                 usb_ep_set_pipeline(&s->dev, pid, ep, true);
             }
 
@@ -1431,6 +1437,8 @@ static Property usb_host_dev_properties[] = {
     DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
     DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
     DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex,        -1),
+    DEFINE_PROP_BIT("pipeline",    USBHostDevice, options,
+                    USB_HOST_OPT_PIPELINE, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
commit 19b89252a32e53aa8bd90a8d4c3e3dcc5f8fe46d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Mar 23 12:35:55 2012 +0100

    usb-host: add usb packet to request tracepoints
    
    Add pointer to USBPacket to all tracepoints tracking requests to make it
    easier to identify them when multiple requests are in flight.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 6ea59a7..8084fd9 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -375,10 +375,10 @@ static void async_complete(void *opaque)
             }
 
             if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
-                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
+                trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
                 usb_generic_async_ctrl_complete(&s->dev, p);
             } else if (!aurb->more) {
-                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
+                trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
                 usb_packet_complete(&s->dev, p);
             }
         }
@@ -392,7 +392,7 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
     USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
     AsyncURB *aurb;
 
-    trace_usb_host_req_canceled(s->bus_num, s->addr);
+    trace_usb_host_req_canceled(s->bus_num, s->addr, p);
 
     QLIST_FOREACH(aurb, &s->aurbs, next) {
         if (p != aurb->packet) {
@@ -847,12 +847,12 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     uint8_t *pbuf;
     uint8_t ep;
 
-    trace_usb_host_req_data(s->bus_num, s->addr,
+    trace_usb_host_req_data(s->bus_num, s->addr, p,
                             p->pid == USB_TOKEN_IN,
                             p->ep->nr, p->iov.size);
 
     if (!is_valid(s, p->pid, p->ep->nr)) {
-        trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
+        trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
         return USB_RET_NAK;
     }
 
@@ -867,7 +867,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
         ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
         if (ret < 0) {
             perror("USBDEVFS_CLEAR_HALT");
-            trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
+            trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
             return USB_RET_NAK;
         }
         clear_halt(s, p->pid, p->ep->nr);
@@ -922,11 +922,13 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
 
             switch(errno) {
             case ETIMEDOUT:
-                trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
+                trace_usb_host_req_complete(s->bus_num, s->addr, p,
+                                            USB_RET_NAK);
                 return USB_RET_NAK;
             case EPIPE:
             default:
-                trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
+                trace_usb_host_req_complete(s->bus_num, s->addr, p,
+                                            USB_RET_STALL);
                 return USB_RET_STALL;
             }
         }
@@ -1033,22 +1035,22 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
      */
 
     /* Note request is (bRequestType << 8) | bRequest */
-    trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
+    trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
 
     switch (request) {
     case DeviceOutRequest | USB_REQ_SET_ADDRESS:
         ret = usb_host_set_address(s, value);
-        trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+        trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
         return ret;
 
     case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
         ret = usb_host_set_config(s, value & 0xff);
-        trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+        trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
         return ret;
 
     case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
         ret = usb_host_set_interface(s, index, value);
-        trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+        trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
         return ret;
     }
 
diff --git a/trace-events b/trace-events
index 3e8da19..e3b1787 100644
--- a/trace-events
+++ b/trace-events
@@ -312,11 +312,11 @@ usb_host_set_config(int bus, int addr, int config) "dev %d:%d, config %d"
 usb_host_set_interface(int bus, int addr, int interface, int alt) "dev %d:%d, interface %d, alt %d"
 usb_host_claim_interfaces(int bus, int addr, int config, int nif) "dev %d:%d, config %d, nif %d"
 usb_host_release_interfaces(int bus, int addr) "dev %d:%d"
-usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%d, req 0x%x, value %d, index %d"
-usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
-usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
-usb_host_req_emulated(int bus, int addr, int status) "dev %d:%d, status %d"
-usb_host_req_canceled(int bus, int addr) "dev %d:%d"
+usb_host_req_control(int bus, int addr, void *p, int req, int value, int index) "dev %d:%d, packet %p, req 0x%x, value %d, index %d"
+usb_host_req_data(int bus, int addr, void *p, int in, int ep, int size) "dev %d:%d, packet %p, in %d, ep %d, size %d"
+usb_host_req_complete(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d"
+usb_host_req_emulated(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d"
+usb_host_req_canceled(int bus, int addr, void *p) "dev %d:%d, packet %p"
 usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
 usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
 usb_host_urb_canceled(int bus, int addr, void *aurb) "dev %d:%d, aurb %p"
commit 6aebe407968a0c7e0be2647391753471ed674c65
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Mar 23 12:26:59 2012 +0100

    usb-host: trace canceled requests
    
    Add tracepoints to track canceled requests.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 912ce23..6ea59a7 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -392,12 +392,14 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
     USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
     AsyncURB *aurb;
 
+    trace_usb_host_req_canceled(s->bus_num, s->addr);
+
     QLIST_FOREACH(aurb, &s->aurbs, next) {
         if (p != aurb->packet) {
             continue;
         }
 
-        DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
+        trace_usb_host_urb_canceled(s->bus_num, s->addr, aurb);
 
         /* Mark it as dead (see async_complete above) */
         aurb->packet = NULL;
diff --git a/trace-events b/trace-events
index 8ac1b62..3e8da19 100644
--- a/trace-events
+++ b/trace-events
@@ -316,8 +316,10 @@ usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%
 usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
 usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
 usb_host_req_emulated(int bus, int addr, int status) "dev %d:%d, status %d"
+usb_host_req_canceled(int bus, int addr) "dev %d:%d"
 usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
 usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
+usb_host_urb_canceled(int bus, int addr, void *aurb) "dev %d:%d, aurb %p"
 usb_host_ep_set_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
 usb_host_ep_clear_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
 usb_host_ep_start_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
commit e382e751ef7848b237be2d569815dcc4f8097306
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 22 15:10:55 2012 +0100

    usb-host: trace emulated requests
    
    Add tracepoint to track completion of emulated control requests.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 5eb6916..912ce23 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -1035,13 +1035,19 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
 
     switch (request) {
     case DeviceOutRequest | USB_REQ_SET_ADDRESS:
-        return usb_host_set_address(s, value);
+        ret = usb_host_set_address(s, value);
+        trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+        return ret;
 
     case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        return usb_host_set_config(s, value & 0xff);
+        ret = usb_host_set_config(s, value & 0xff);
+        trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+        return ret;
 
     case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
-        return usb_host_set_interface(s, index, value);
+        ret = usb_host_set_interface(s, index, value);
+        trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+        return ret;
     }
 
     /* The rest are asynchronous */
diff --git a/trace-events b/trace-events
index a5f276d..8ac1b62 100644
--- a/trace-events
+++ b/trace-events
@@ -315,6 +315,7 @@ usb_host_release_interfaces(int bus, int addr) "dev %d:%d"
 usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%d, req 0x%x, value %d, index %d"
 usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
 usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
+usb_host_req_emulated(int bus, int addr, int status) "dev %d:%d, status %d"
 usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
 usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
 usb_host_ep_set_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
commit 65bb3a5c11b00671c1067ee27ea364b6d7e6e2ac
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 22 10:48:03 2012 +0100

    Add bootindex support to usb-host and usb-redir
    
    When passing through a usb pendrive seabios will present it in the F12
    boot menu and will happily boot from it.
    
    This patch adds bootorder support so you can even make it the default
    boot device.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 90919c2..5eb6916 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -115,6 +115,7 @@ typedef struct USBHostDevice {
     int addr;
     char port[MAX_PORTLEN];
     struct USBAutoFilter match;
+    int32_t bootindex;
     int seen, errcount;
 
     QTAILQ_ENTRY(USBHostDevice) next;
@@ -1403,6 +1404,7 @@ static int usb_host_initfn(USBDevice *dev)
     if (s->match.bus_num != 0 && s->match.port != NULL) {
         usb_host_claim_port(s);
     }
+    add_boot_device_path(s->bootindex, &dev->qdev, NULL);
     return 0;
 }
 
@@ -1418,6 +1420,7 @@ static Property usb_host_dev_properties[] = {
     DEFINE_PROP_HEX32("vendorid",  USBHostDevice, match.vendor_id,  0),
     DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
     DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
+    DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex,        -1),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 8e9f175..4288324 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -74,6 +74,7 @@ struct USBRedirDevice {
     CharDriverState *cs;
     uint8_t debug;
     char *filter_str;
+    int32_t bootindex;
     /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
     const uint8_t *read_buf;
     int read_buf_size;
@@ -923,6 +924,7 @@ static int usbredir_initfn(USBDevice *udev)
     qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
                           usbredir_chardev_read, usbredir_chardev_event, dev);
 
+    add_boot_device_path(dev->bootindex, &udev->qdev, NULL);
     return 0;
 }
 
@@ -1452,6 +1454,7 @@ static Property usbredir_properties[] = {
     DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
     DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
     DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
+    DEFINE_PROP_INT32("bootindex", USBRedirDevice, bootindex, -1),
     DEFINE_PROP_END_OF_LIST(),
 };
 
commit ee008ba62673943d5cd40c5761955efdbca444cd
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Mar 29 16:02:20 2012 +0200

    usb-uhci: queuing fix
    
    When we queue up usb packets we may happen to find a already queued
    packet, which also might be finished at that point already.  We don't
    want continue processing the packet at this point though, so lets
    just signal back we've found a in-flight packet when in queuing mode.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 2be564b..266d550 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -795,7 +795,8 @@ out:
     return TD_RESULT_NEXT_QH;
 }
 
-static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask)
+static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
+                          uint32_t *int_mask, bool queuing)
 {
     UHCIAsync *async;
     int len = 0, max_len;
@@ -814,6 +815,12 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
 
         if (!async->done)
             return TD_RESULT_ASYNC_CONT;
+        if (queuing) {
+            /* we are busy filling the queue, we are not prepared
+               to consume completed packages then, just leave them
+               in async state */
+            return TD_RESULT_ASYNC_CONT;
+        }
 
         uhci_async_unlink(async);
         goto done;
@@ -964,7 +971,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
             break;
         }
         trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
-        ret = uhci_handle_td(s, plink, &ptd, &int_mask);
+        ret = uhci_handle_td(s, plink, &ptd, &int_mask, true);
         if (ret == TD_RESULT_ASYNC_CONT) {
             break;
         }
@@ -1048,7 +1055,7 @@ static void uhci_process_frame(UHCIState *s)
         trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
 
         old_td_ctrl = td.ctrl;
-        ret = uhci_handle_td(s, link, &td, &int_mask);
+        ret = uhci_handle_td(s, link, &td, &int_mask, false);
         if (old_td_ctrl != td.ctrl) {
             /* update the status bits of the TD */
             val = cpu_to_le32(td.ctrl);
commit 52b0fecdba217e02d7e7eef975d942b153950b2f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Mar 21 18:25:25 2012 +0100

    usb-uhci: stop queue filling when we find a in-flight td
    
    Not only QHs can form rings, but TDs too.  With the new
    queuing/pipelining support we are following TD chains and
    can actually walk in circles.  An assert() prevents us from
    entering an endless loop then.
    
    Fix is easy:  Just stop queuing when we figure the TD we are
    about to queue up is in flight already.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index e55dad9..2be564b 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -965,6 +965,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
         }
         trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
         ret = uhci_handle_td(s, plink, &ptd, &int_mask);
+        if (ret == TD_RESULT_ASYNC_CONT) {
+            break;
+        }
         assert(ret == TD_RESULT_ASYNC_START);
         assert(int_mask == 0);
         plink = ptd.link;
commit eeb0cf9abf5992f35eca18c4cc63300df30521a4
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Aug 22 09:09:51 2011 +0200

    usb/vmstate: add parent dev path
    
    ... to make vmstate id string truely unique with multiple host
    controllers, i.e. move from "1/usb-ptr" to "0000:00:01.3/1/usb-ptr"
    (usb tabled connected to piix3 uhci).
    
    This obviously breaks migration.  To handle this the usb bus
    property "full-path" is added.  When setting this to false old
    behavior is maintained.  This way current qemu will be compatible
    with old versions when started using '-M pc-$oldversion'.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 907d723..6a75718 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -377,6 +377,10 @@ static QEMUMachine pc_machine_v1_1 = {
             .driver   = "apic",\
             .property = "vapic",\
             .value    = "off",\
+        },{\
+            .driver   = "USB",\
+            .property = "full-path",\
+            .value    = "no",\
         }
 
 static QEMUMachine pc_machine_v1_0 = {
diff --git a/hw/usb.h b/hw/usb.h
index e95085f..ae7ccda 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -182,12 +182,17 @@ struct USBEndpoint {
     QTAILQ_HEAD(, USBPacket) queue;
 };
 
+enum USBDeviceFlags {
+    USB_DEV_FLAG_FULL_PATH,
+};
+
 /* definition of a USB device */
 struct USBDevice {
     DeviceState qdev;
     USBPort *port;
     char *port_path;
     void *opaque;
+    uint32_t flags;
 
     /* Actual connected speed */
     int speed;
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index d3f8358..2068640 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -19,6 +19,8 @@ static struct BusInfo usb_bus_info = {
     .get_fw_dev_path = usb_get_fw_dev_path,
     .props      = (Property[]) {
         DEFINE_PROP_STRING("port", USBDevice, port_path),
+        DEFINE_PROP_BIT("full-path", USBDevice, flags,
+                        USB_DEV_FLAG_FULL_PATH, true),
         DEFINE_PROP_END_OF_LIST()
     },
 };
@@ -460,7 +462,20 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
 static char *usb_get_dev_path(DeviceState *qdev)
 {
     USBDevice *dev = USB_DEVICE(qdev);
-    return g_strdup(dev->port->path);
+    DeviceState *hcd = qdev->parent_bus->parent;
+    char *id = NULL;
+
+    if ((dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) &&
+        hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) {
+        id = hcd->parent_bus->info->get_dev_path(hcd);
+    }
+    if (id) {
+        char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
+        g_free(id);
+        return ret;
+    } else {
+        return g_strdup(dev->port->path);
+    }
 }
 
 static char *usb_get_fw_dev_path(DeviceState *qdev)


More information about the Spice-commits mailing list