[Spice-commits] 197 commits - .gitignore MAINTAINERS Makefile Makefile.objs Makefile.target balloon.c balloon.h block.c block.h block/blkdebug.c block/blkverify.c block/bochs.c block/cloop.c block/cow.c block/dmg.c block/iscsi.c block/nbd.c block/parallels.c block/qcow.c block/qcow2-cluster.c block/qcow2.c block/qed.c block/raw-posix.c block/raw-win32.c block/raw.c block/rbd.c block/sheepdog.c block/vdi.c block/vmdk.c block/vpc.c block/vvfat.c block_int.h configure console.h cpus.c device_tree.c docs/specs error.c exec-all.h exec.c fpu/softfloat-specialize.h fpu/softfloat.c fpu/softfloat.h fsdev/file-op-9p.h fsdev/qemu-fsdev.c fsdev/qemu-fsdev.h gdbstub.c hmp-commands.hx hmp.c hmp.h hw/9pfs hw/acpi_piix4.c hw/audiodev.h hw/esp.c hw/fdc.c hw/fdc.h hw/hda-audio.c hw/i2c.c hw/ide hw/intel-hda.c hw/intel-hda.h hw/lm4549.c hw/lm4549.h hw/lsi53c895a.c hw/pc.c hw/pc.h hw/pc_piix.c hw/pci-stub.c hw/pci.c hw/pci.h hw/pl041.c hw/pl041.h hw/pl041.hx hw/qdev.c hw/qdev.h hw/qxl.c hw/qxl.h hw/rea lview.c hw/s390-virtio-bus.c hw/scsi-bus.c hw/scsi-defs.h hw/scsi-disk.c hw/scsi-generic.c hw/scsi.h hw/spapr_vio.c hw/spapr_vscsi.c hw/ssi.c hw/usb-msd.c hw/versatilepb.c hw/vexpress.c hw/virtio-balloon.c hw/xen_disk.c input.c kvm-all.c libcacard/cac.c libcacard/card_7816.c libcacard/vscclient.c linux-user/elfload.c linux-user/main.c linux-user/qemu-types.h linux-user/signal.c linux-user/sparc linux-user/strace.c linux-user/syscall.c linux-user/syscall_defs.h linux-user/vm86.c main-loop.c migration.c migration.h monitor.c monitor.h oslib-posix.c oslib-win32.c qapi-schema.json qemu-config.c qemu-doc.texi qemu-img.c qemu-io.c qemu-option.c qemu-option.h qemu-options.hx qemu-queue.h qemu-thread.h qemu_socket.h qerror.c qmp-commands.hx qmp.c scripts/analyse-9p-simpletrace.py scripts/kvm scripts/qapi-commands.py target-arm/cpu.h target-arm/helper.c target-arm/helper.h target-arm/machine.c target-arm/translate.c target-i386/cpu.h target-i386/helper.c target-i386/kvm.c target-i386 /machine.c target-i386/op_helper.c target-sparc/cpu.h target-sparc/cpu_init.c target-sparc/fop_helper.c target-sparc/helper.c target-sparc/helper.h target-sparc/int32_helper.c target-sparc/int64_helper.c target-sparc/ldst_helper.c target-sparc/machine.c target-sparc/mmu_helper.c target-sparc/op_helper.c target-sparc/translate.c target-sparc/vis_helper.c target-sparc/win_helper.c tcg/tcg-op.h trace-events ui/qemu-spice.h ui/spice-core.c ui/vnc.c vl.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Tue Nov 1 05:35:34 PDT 2011


 .gitignore                        |    1 
 MAINTAINERS                       |   11 
 Makefile                          |   32 
 Makefile.objs                     |   10 
 Makefile.target                   |    6 
 balloon.c                         |   72 -
 balloon.h                         |    6 
 block.c                           |  510 +++----
 block.h                           |   10 
 block/blkdebug.c                  |    6 
 block/blkverify.c                 |    9 
 block/bochs.c                     |   15 
 block/cloop.c                     |   15 
 block/cow.c                       |   34 
 block/dmg.c                       |   15 
 block/iscsi.c                     |  591 ++++++++
 block/nbd.c                       |   28 
 block/parallels.c                 |   15 
 block/qcow.c                      |   47 
 block/qcow2-cluster.c             |    6 
 block/qcow2.c                     |   74 -
 block/qed.c                       |   13 
 block/raw-posix.c                 |   23 
 block/raw-win32.c                 |    4 
 block/raw.c                       |   23 
 block/rbd.c                       |    4 
 block/sheepdog.c                  |   14 
 block/vdi.c                       |   29 
 block/vmdk.c                      |  113 +
 block/vpc.c                       |   34 
 block/vvfat.c                     |   28 
 block_int.h                       |   13 
 configure                         |   33 
 console.h                         |    9 
 cpus.c                            |   45 
 device_tree.c                     |    1 
 docs/specs/qcow2.txt              |    6 
 error.c                           |    3 
 exec-all.h                        |    3 
 exec.c                            |    1 
 fpu/softfloat-specialize.h        |  178 ++
 fpu/softfloat.c                   |  427 ++++++
 fpu/softfloat.h                   |   14 
 fsdev/file-op-9p.h                |   36 
 fsdev/qemu-fsdev.c                |    8 
 fsdev/qemu-fsdev.h                |    1 
 gdbstub.c                         |   35 
 hmp-commands.hx                   |    6 
 hmp.c                             |  407 +++++
 hmp.h                             |   10 
 hw/9pfs/codir.c                   |   16 
 hw/9pfs/cofile.c                  |   37 
 hw/9pfs/virtio-9p-coth.h          |    6 
 hw/9pfs/virtio-9p-handle.c        |   96 -
 hw/9pfs/virtio-9p-local.c         |  113 -
 hw/9pfs/virtio-9p-synth.c         |  571 ++++++++
 hw/9pfs/virtio-9p-synth.h         |   50 
 hw/9pfs/virtio-9p.c               |  122 +
 hw/9pfs/virtio-9p.h               |   27 
 hw/acpi_piix4.c                   |    4 
 hw/audiodev.h                     |    2 
 hw/esp.c                          |   16 
 hw/fdc.c                          |   14 
 hw/fdc.h                          |    9 
 hw/hda-audio.c                    |   26 
 hw/i2c.c                          |    2 
 hw/ide/ahci.c                     |   16 
 hw/ide/atapi.c                    |  119 -
 hw/ide/core.c                     |    6 
 hw/ide/internal.h                 |   71 -
 hw/ide/macio.c                    |    2 
 hw/intel-hda.c                    |   24 
 hw/intel-hda.h                    |    2 
 hw/lm4549.c                       |  336 ++++
 hw/lm4549.h                       |   43 
 hw/lsi53c895a.c                   |   30 
 hw/pc.c                           |   25 
 hw/pc.h                           |    3 
 hw/pc_piix.c                      |    5 
 hw/pci-stub.c                     |   15 
 hw/pci.c                          |  322 +---
 hw/pci.h                          |    4 
 hw/pl041.c                        |  636 +++++++++
 hw/pl041.h                        |  135 +
 hw/pl041.hx                       |   81 +
 hw/qdev.c                         |   24 
 hw/qdev.h                         |    4 
 hw/qxl.c                          |   66 
 hw/qxl.h                          |    3 
 hw/realview.c                     |    8 
 hw/s390-virtio-bus.c              |    4 
 hw/scsi-bus.c                     |  279 +++-
 hw/scsi-defs.h                    |   90 +
 hw/scsi-disk.c                    |  824 ++++++++----
 hw/scsi-generic.c                 |  201 +-
 hw/scsi.h                         |   39 
 hw/spapr_vio.c                    |    6 
 hw/spapr_vscsi.c                  |   54 
 hw/ssi.c                          |    6 
 hw/usb-msd.c                      |    8 
 hw/versatilepb.c                  |    8 
 hw/vexpress.c                     |    7 
 hw/virtio-balloon.c               |   78 -
 hw/xen_disk.c                     |    5 
 input.c                           |   64 
 kvm-all.c                         |   10 
 libcacard/cac.c                   |    3 
 libcacard/card_7816.c             |    2 
 libcacard/vscclient.c             |    9 
 linux-user/elfload.c              |    8 
 linux-user/main.c                 |   26 
 linux-user/qemu-types.h           |   12 
 linux-user/signal.c               |   50 
 linux-user/sparc/syscall_nr.h     |    3 
 linux-user/strace.c               |    4 
 linux-user/syscall.c              |  272 +---
 linux-user/syscall_defs.h         |   17 
 linux-user/vm86.c                 |    4 
 main-loop.c                       |   30 
 migration.c                       |   93 -
 migration.h                       |    2 
 monitor.c                         |  415 +-----
 monitor.h                         |    2 
 oslib-posix.c                     |    7 
 oslib-win32.c                     |    6 
 qapi-schema.json                  |  616 +++++++++
 qemu-config.c                     |    7 
 qemu-doc.texi                     |    2 
 qemu-img.c                        |   11 
 qemu-io.c                         |    6 
 qemu-option.c                     |   39 
 qemu-option.h                     |    3 
 qemu-options.hx                   |  113 +
 qemu-queue.h                      |   13 
 qemu-thread.h                     |    3 
 qemu_socket.h                     |    1 
 qerror.c                          |    4 
 qmp-commands.hx                   |   63 
 qmp.c                             |   27 
 scripts/analyse-9p-simpletrace.py |  164 +-
 scripts/kvm/kvm_stat              |  480 +++++++
 scripts/kvm/vmxcap                |  224 +++
 scripts/qapi-commands.py          |    4 
 target-arm/cpu.h                  |    4 
 target-arm/helper.c               |   26 
 target-arm/helper.h               |    3 
 target-arm/machine.c              |    2 
 target-arm/translate.c            |  118 +
 target-i386/cpu.h                 |    7 
 target-i386/helper.c              |    1 
 target-i386/kvm.c                 |   15 
 target-i386/machine.c             |   43 
 target-i386/op_helper.c           |    6 
 target-sparc/cpu.h                |   41 
 target-sparc/cpu_init.c           |   14 
 target-sparc/fop_helper.c         |  294 ++--
 target-sparc/helper.c             |  917 +------------
 target-sparc/helper.h             |  168 +-
 target-sparc/int32_helper.c       |   40 
 target-sparc/int64_helper.c       |   37 
 target-sparc/ldst_helper.c        | 2371 ++++++++++++++++++++++++++++++++++
 target-sparc/machine.c            |   20 
 target-sparc/mmu_helper.c         |  853 ++++++++++++
 target-sparc/op_helper.c          | 2584 --------------------------------------
 target-sparc/translate.c          | 1512 ++++++++++++----------
 target-sparc/vis_helper.c         |  251 ++-
 target-sparc/win_helper.c         |  253 ---
 tcg/tcg-op.h                      |   65 
 trace-events                      |   35 
 ui/qemu-spice.h                   |   14 
 ui/spice-core.c                   |  217 +--
 ui/vnc.c                          |  135 +
 vl.c                              |   22 
 173 files changed, 13378 insertions(+), 7243 deletions(-)

New commits:
commit ff74c5a9a91c6dbf1017195462aa4176f7381240
Merge: 8494a39... 9e0e2f9...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 31 15:05:40 2011 -0500

    Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging

commit 8494a397b68124f9898e7912173d460ee99ba3e2
Merge: d439b79... 336a691...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 31 11:09:00 2011 -0500

    Merge remote-tracking branch 'kwolf/for-anthony' into staging
    
    Conflicts:
    	block/vmdk.c

commit d439b79d730bf219e47c14ab94f1546bcc5045ab
Merge: 96b3d73... 2583e44...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 31 11:06:02 2011 -0500

    Merge remote-tracking branch 'aneesh/for-upstream-7' into staging

commit 96b3d73f5ad5838690d42666c566a48be9d173dc
Merge: 549f808... f795e74...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 31 11:02:29 2011 -0500

    Merge remote-tracking branch 'qmp/queue/qmp' into staging
    
    Conflicts:
    	ui/spice-core.c

diff --cc ui/spice-core.c
index 6d3dab6,f556849..5639c6f
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@@ -383,73 -336,59 +368,59 @@@ static const char *wan_compression_name
  
  /* functions for the rest of qemu */
  
- static void info_spice_iter(QObject *obj, void *opaque)
+ static SpiceChannelList *qmp_query_spice_channels(void)
  {
-     QDict *client;
-     Monitor *mon = opaque;
- 
-     client = qobject_to_qdict(obj);
-     monitor_printf(mon, "Channel:\n");
-     monitor_printf(mon, "     address: %s:%s%s\n",
-                    qdict_get_str(client, "host"),
-                    qdict_get_str(client, "port"),
-                    qdict_get_bool(client, "tls") ? " [tls]" : "");
-     monitor_printf(mon, "     session: %" PRId64 "\n",
-                    qdict_get_int(client, "connection-id"));
-     monitor_printf(mon, "     channel: %d:%d\n",
-                    (int)qdict_get_int(client, "channel-type"),
-                    (int)qdict_get_int(client, "channel-id"));
- }
+     SpiceChannelList *cur_item = NULL, *head = NULL;
+     ChannelList *item;
  
- void do_info_spice_print(Monitor *mon, const QObject *data)
- {
-     QDict *server;
-     QList *channels;
-     const char *host;
-     int port;
- 
-     server = qobject_to_qdict(data);
-     if (qdict_get_bool(server, "enabled") == 0) {
-         monitor_printf(mon, "Server: disabled\n");
-         return;
+     QTAILQ_FOREACH(item, &channel_list, link) {
+         SpiceChannelList *chan;
+         char host[NI_MAXHOST], port[NI_MAXSERV];
+ 
+         chan = g_malloc0(sizeof(*chan));
+         chan->value = g_malloc0(sizeof(*chan->value));
+ 
+         getnameinfo(&item->info->paddr, item->info->plen,
+                     host, sizeof(host), port, sizeof(port),
+                     NI_NUMERICHOST | NI_NUMERICSERV);
+         chan->value->host = g_strdup(host);
+         chan->value->port = g_strdup(port);
+         chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family));
+ 
+         chan->value->connection_id = item->info->connection_id;
+         chan->value->channel_type = item->info->type;
+         chan->value->channel_id = item->info->id;
+         chan->value->tls = item->info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
+ 
+        /* XXX: waiting for the qapi to support GSList */
+         if (!cur_item) {
+             head = cur_item = chan;
+         } else {
+             cur_item->next = chan;
+             cur_item = chan;
+         }
      }
  
-     monitor_printf(mon, "Server:\n");
-     host = qdict_get_str(server, "host");
-     port = qdict_get_try_int(server, "port", -1);
-     if (port != -1) {
-         monitor_printf(mon, "     address: %s:%d\n", host, port);
-     }
-     port = qdict_get_try_int(server, "tls-port", -1);
-     if (port != -1) {
-         monitor_printf(mon, "     address: %s:%d [tls]\n", host, port);
-     }
-     monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
-     monitor_printf(mon, "    compiled: %s\n",
-                    qdict_get_str(server, "compiled-version"));
- 
-     channels = qdict_get_qlist(server, "channels");
-     if (qlist_empty(channels)) {
-         monitor_printf(mon, "Channels: none\n");
-     } else {
-         qlist_iter(channels, info_spice_iter, mon);
-     }
+     return head;
  }
  
- void do_info_spice(Monitor *mon, QObject **ret_data)
+ SpiceInfo *qmp_query_spice(Error **errp)
  {
      QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
-     QDict *server;
-     QList *clist;
-     const char *addr;
      int port, tls_port;
+     const char *addr;
+     SpiceInfo *info;
      char version_string[20]; /* 12 = |255.255.255\0| is the max */
  
+     info = g_malloc0(sizeof(*info));
+ 
 -    if (!spice_server) {
 +    if (!spice_server || !opts) {
-         *ret_data = qobject_from_jsonf("{ 'enabled': false }");
-         return;
+         info->enabled = false;
+         return info;
      }
  
+     info->enabled = true;
+ 
      addr = qemu_opt_get(opts, "addr");
      port = qemu_opt_get_number(opts, "port", 0);
      tls_port = qemu_opt_get_number(opts, "tls-port", 0);
commit 549f808b577c7709aeaa0244972d3ae28fad97d2
Merge: 3a069ff... 21e87c4...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 31 11:00:27 2011 -0500

    Merge remote-tracking branch 'qemu-kvm-tmp/uq/master' into staging

commit 3a069ff11b9178a84f560435b2fd22294d839018
Merge: acba391... 3899edf...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 31 10:23:15 2011 -0500

    Merge remote-tracking branch 'stefanha/trivial-patches' into staging

commit acba391493badb972db654fa1299052fce0379a3
Merge: eca968d... d9676f8...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 31 10:14:06 2011 -0500

    Merge remote-tracking branch 'alon/pull-libcacard-assert' into staging

commit eca968d0d4250fe95abbc7ea99f887142f44b4e0
Merge: 03a0e94... 08cc67f...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 31 10:12:14 2011 -0500

    Merge remote-tracking branch 'spice/spice.v45' into staging

commit 2583e443676e6b9259425f7d5ccaccbfa9bf7886
Author: Harsh Prateek Bora <harsh at linux.vnet.ibm.com>
Date:   Fri Oct 14 02:05:02 2011 +0530

    hw/9pfs: Replace rwlocks with RCU variants of interfaces.
    
    Use QLIST_INSERT_HEAD_RCU and rcu_read_lock/unlock instead of rwlocks.
    Use v9fs_synth_mutex as a write-only mutex to handle concurrent writers.
    
    Signed-off-by: Harsh Prateek Bora <harsh at linux.vnet.ibm.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c
index 72a916c..f573616 100644
--- a/hw/9pfs/virtio-9p-synth.c
+++ b/hw/9pfs/virtio-9p-synth.c
@@ -30,8 +30,7 @@ V9fsSynthNode v9fs_synth_root = {
     .attr = &v9fs_synth_root.actual_attr,
 };
 
-/*FIXME!! should be converted to qemu_rwlock_t */
-static pthread_rwlock_t v9fs_synth_mutex;
+static QemuMutex  v9fs_synth_mutex;
 static int v9fs_synth_node_count;
 /* set to 1 when the synth fs is ready */
 static int v9fs_synth_fs;
@@ -60,7 +59,7 @@ static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
     }
     node->private = node;
     strncpy(node->name, name, sizeof(node->name));
-    QLIST_INSERT_HEAD(&parent->child, node, sibling);
+    QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
     return node;
 }
 
@@ -79,7 +78,7 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
     if (!parent) {
         parent = &v9fs_synth_root;
     }
-    pthread_rwlock_wrlock(&v9fs_synth_mutex);
+    qemu_mutex_lock(&v9fs_synth_mutex);
     QLIST_FOREACH(tmp, &parent->child, sibling) {
         if (!strcmp(tmp->name, name)) {
             ret = EEXIST;
@@ -95,7 +94,7 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
     *result = node;
     ret = 0;
 err_out:
-    pthread_rwlock_unlock(&v9fs_synth_mutex);
+    qemu_mutex_unlock(&v9fs_synth_mutex);
     return ret;
 }
 
@@ -116,7 +115,7 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
         parent = &v9fs_synth_root;
     }
 
-    pthread_rwlock_wrlock(&v9fs_synth_mutex);
+    qemu_mutex_lock(&v9fs_synth_mutex);
     QLIST_FOREACH(tmp, &parent->child, sibling) {
         if (!strcmp(tmp->name, name)) {
             ret = EEXIST;
@@ -134,10 +133,10 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
     node->attr->mode   = mode;
     node->private      = arg;
     strncpy(node->name, name, sizeof(node->name));
-    QLIST_INSERT_HEAD(&parent->child, node, sibling);
+    QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
     ret = 0;
 err_out:
-    pthread_rwlock_unlock(&v9fs_synth_mutex);
+    qemu_mutex_unlock(&v9fs_synth_mutex);
     return ret;
 }
 
@@ -230,7 +229,7 @@ static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry,
     int i = 0;
     V9fsSynthNode *node;
 
-    pthread_rwlock_rdlock(&v9fs_synth_mutex);
+    rcu_read_lock();
     QLIST_FOREACH(node, &dir->child, sibling) {
         /* This is the off child of the directory */
         if (i == off) {
@@ -238,7 +237,7 @@ static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry,
         }
         i++;
     }
-    pthread_rwlock_unlock(&v9fs_synth_mutex);
+    rcu_read_unlock();
     if (!node) {
         /* end of directory */
         *result = NULL;
@@ -483,13 +482,14 @@ static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
         goto out;
     }
     /* search for the name in the childern */
-    pthread_rwlock_rdlock(&v9fs_synth_mutex);
+    rcu_read_lock();
     QLIST_FOREACH(node, &dir_node->child, sibling) {
         if (!strcmp(node->name, name)) {
             break;
         }
     }
-    pthread_rwlock_unlock(&v9fs_synth_mutex);
+    rcu_read_unlock();
+
     if (!node) {
         errno = ENOENT;
         return -1;
@@ -519,11 +519,8 @@ static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir,
 
 static int v9fs_synth_init(FsContext *ctx)
 {
-    pthread_rwlockattr_t rwlockattr;
-
     QLIST_INIT(&v9fs_synth_root.child);
-    pthread_rwlockattr_init(&rwlockattr);
-    pthread_rwlock_init(&v9fs_synth_mutex, &rwlockattr);
+    qemu_mutex_init(&v9fs_synth_mutex);
 
     /* Add "." and ".." entries for root */
     v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
commit 5f7d05ecfda56b0b66ade19bc4d81eab46954149
Author: Harsh Prateek Bora <harsh at linux.vnet.ibm.com>
Date:   Tue Oct 25 12:10:40 2011 +0530

    qemu-queue: Introduce QLIST_INSERT_HEAD_RCU and dummy RCU wrappers.
    
    SynthFS needs a QLIST_INSERT_HEAD_RCU to make sure list instructions are not
    re-ordered and therefore avoiding a crash. There may be parallel readers which
    should be allowed for lock-free access and this variant allows us to get rid
    of rwlocks used by readers.
    
    SynthFS is a special case where we dont really need full RCU capabilities as
    it doesnt allow list entry deletion but concurrent readers/writers and
    instruction re-ordering should not result in a crash.
    
    Also, once the real rcu is available, dummy rcu macro definitions will go away
    and the code will still work as expected.
    
    This patchwork is based on inputs from Paolo Bonzini.
    
    Signed-off-by: Harsh Prateek Bora <harsh at linux.vnet.ibm.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/qemu-queue.h b/qemu-queue.h
index 1d07745..2214230 100644
--- a/qemu-queue.h
+++ b/qemu-queue.h
@@ -76,6 +76,8 @@
  * For details on the use of these macros, see the queue(3) manual page.
  */
 
+#include "qemu-barrier.h" /* for smp_wmb() */
+
 /*
  * List definitions.
  */
@@ -122,6 +124,17 @@ struct {                                                                \
         (elm)->field.le_prev = &(head)->lh_first;                       \
 } while (/*CONSTCOND*/0)
 
+#define QLIST_INSERT_HEAD_RCU(head, elm, field) do {                    \
+        (elm)->field.le_prev = &(head)->lh_first;                       \
+        (elm)->field.le_next = (head)->lh_first;                        \
+        smp_wmb(); /* fill elm before linking it */                     \
+        if ((head)->lh_first != NULL)  {                                \
+            (head)->lh_first->field.le_prev = &(elm)->field.le_next;    \
+        }                                                               \
+        (head)->lh_first = (elm);                                       \
+        smp_wmb();                                                      \
+} while (/* CONSTCOND*/0)
+
 #define QLIST_REMOVE(elm, field) do {                                   \
         if ((elm)->field.le_next != NULL)                               \
                 (elm)->field.le_next->field.le_prev =                   \
diff --git a/qemu-thread.h b/qemu-thread.h
index 0a73d50..e008b60 100644
--- a/qemu-thread.h
+++ b/qemu-thread.h
@@ -19,6 +19,9 @@ void qemu_mutex_lock(QemuMutex *mutex);
 int qemu_mutex_trylock(QemuMutex *mutex);
 void qemu_mutex_unlock(QemuMutex *mutex);
 
+#define rcu_read_lock() do { } while (0)
+#define rcu_read_unlock() do { } while (0)
+
 void qemu_cond_init(QemuCond *cond);
 void qemu_cond_destroy(QemuCond *cond);
 
commit 9db221ae73a18e0bd2b1ee6c7dc1904ed06fb464
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Oct 25 12:10:40 2011 +0530

    hw/9pfs: Add synthetic file system support using 9p
    
    This patch create a synthetic file system with mount tag
    v_synth when -virtfs_synth command line option is specified
    in qemu. The synthetic file system can be mounted in guest
    using 9p using the below command line
    
    mount -t 9p -oversion=9p2000.L,trans=virtio v_synth  <mountpint>
    
    Synthetic file system enabled different qemu subsystem to register
    callbacks for read and write events from guest. The subsystem
    can create directories and files in the synthetic file system as show
    in ex below
    
        qemu_v9fs_synth_mkdir(NULL, 0777, "test2", &node);
        qemu_v9fs_synth_add_file(node, 0777, "testfile",
                                 my_test_read, NULL, NULL);
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/Makefile.objs b/Makefile.objs
index 01587c8..3dead4e 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -310,6 +310,7 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
 9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-handle.o
+9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-synth.o
 
 hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
 $(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 27d10cb..7fd2aa7 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -24,6 +24,7 @@ static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries =
 static FsDriverTable FsDrivers[] = {
     { .name = "local", .ops = &local_ops},
     { .name = "handle", .ops = &handle_ops},
+    { .name = "synth", .ops = &synth_ops},
 };
 
 int qemu_fsdev_add(QemuOpts *opts)
diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index 5099085..8ef8473 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -53,4 +53,5 @@ int qemu_fsdev_add(QemuOpts *opts);
 FsDriverEntry *get_fsdev_fsentry(char *id);
 extern FileOperations local_ops;
 extern FileOperations handle_ops;
+extern FileOperations synth_ops;
 #endif
diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c
new file mode 100644
index 0000000..72a916c
--- /dev/null
+++ b/hw/9pfs/virtio-9p-synth.c
@@ -0,0 +1,574 @@
+/*
+ * Virtio 9p synthetic file system support
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Malahal Naineni <malahal at us.ibm.com>
+ *  Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-synth.h"
+
+#include <sys/stat.h>
+
+/* Root node for synth file system */
+V9fsSynthNode v9fs_synth_root = {
+    .name = "/",
+    .actual_attr = {
+        .mode = 0555 | S_IFDIR,
+        .nlink = 1,
+    },
+    .attr = &v9fs_synth_root.actual_attr,
+};
+
+/*FIXME!! should be converted to qemu_rwlock_t */
+static pthread_rwlock_t v9fs_synth_mutex;
+static int v9fs_synth_node_count;
+/* set to 1 when the synth fs is ready */
+static int v9fs_synth_fs;
+
+static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
+                                        const char *name,
+                                        V9fsSynthNodeAttr *attr, int inode)
+{
+    V9fsSynthNode *node;
+
+    /* Add directory type and remove write bits */
+    mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH);
+    node = g_malloc0(sizeof(V9fsSynthNode));
+    if (attr) {
+        /* We are adding .. or . entries */
+        node->attr = attr;
+        node->attr->nlink++;
+    } else {
+        node->attr = &node->actual_attr;
+        node->attr->inode = inode;
+        node->attr->nlink = 1;
+        /* We don't allow write to directories */
+        node->attr->mode   = mode;
+        node->attr->write = NULL;
+        node->attr->read  = NULL;
+    }
+    node->private = node;
+    strncpy(node->name, name, sizeof(node->name));
+    QLIST_INSERT_HEAD(&parent->child, node, sibling);
+    return node;
+}
+
+int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
+                          const char *name, V9fsSynthNode **result)
+{
+    int ret;
+    V9fsSynthNode *node, *tmp;
+
+    if (!v9fs_synth_fs) {
+        return EAGAIN;
+    }
+    if (!name || (strlen(name) >= NAME_MAX)) {
+        return EINVAL;
+    }
+    if (!parent) {
+        parent = &v9fs_synth_root;
+    }
+    pthread_rwlock_wrlock(&v9fs_synth_mutex);
+    QLIST_FOREACH(tmp, &parent->child, sibling) {
+        if (!strcmp(tmp->name, name)) {
+            ret = EEXIST;
+            goto err_out;
+        }
+    }
+    /* Add the name */
+    node = v9fs_add_dir_node(parent, mode, name, NULL, v9fs_synth_node_count++);
+    v9fs_add_dir_node(node, parent->attr->mode, "..",
+                      parent->attr, parent->attr->inode);
+    v9fs_add_dir_node(node, node->attr->mode, ".",
+                      node->attr, node->attr->inode);
+    *result = node;
+    ret = 0;
+err_out:
+    pthread_rwlock_unlock(&v9fs_synth_mutex);
+    return ret;
+}
+
+int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
+                             const char *name, v9fs_synth_read read,
+                             v9fs_synth_write write, void *arg)
+{
+    int ret;
+    V9fsSynthNode *node, *tmp;
+
+    if (!v9fs_synth_fs) {
+        return EAGAIN;
+    }
+    if (!name || (strlen(name) >= NAME_MAX)) {
+        return EINVAL;
+    }
+    if (!parent) {
+        parent = &v9fs_synth_root;
+    }
+
+    pthread_rwlock_wrlock(&v9fs_synth_mutex);
+    QLIST_FOREACH(tmp, &parent->child, sibling) {
+        if (!strcmp(tmp->name, name)) {
+            ret = EEXIST;
+            goto err_out;
+        }
+    }
+    /* Add file type and remove write bits */
+    mode = ((mode & 0777) | S_IFREG);
+    node = g_malloc0(sizeof(V9fsSynthNode));
+    node->attr         = &node->actual_attr;
+    node->attr->inode  = v9fs_synth_node_count++;
+    node->attr->nlink  = 1;
+    node->attr->read   = read;
+    node->attr->write  = write;
+    node->attr->mode   = mode;
+    node->private      = arg;
+    strncpy(node->name, name, sizeof(node->name));
+    QLIST_INSERT_HEAD(&parent->child, node, sibling);
+    ret = 0;
+err_out:
+    pthread_rwlock_unlock(&v9fs_synth_mutex);
+    return ret;
+}
+
+static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
+{
+    stbuf->st_dev = 0;
+    stbuf->st_ino = node->attr->inode;
+    stbuf->st_mode = node->attr->mode;
+    stbuf->st_nlink = node->attr->nlink;
+    stbuf->st_uid = 0;
+    stbuf->st_gid = 0;
+    stbuf->st_rdev = 0;
+    stbuf->st_size = 0;
+    stbuf->st_blksize = 0;
+    stbuf->st_blocks = 0;
+    stbuf->st_atime = 0;
+    stbuf->st_mtime = 0;
+    stbuf->st_ctime = 0;
+}
+
+static int v9fs_synth_lstat(FsContext *fs_ctx,
+                            V9fsPath *fs_path, struct stat *stbuf)
+{
+    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+    v9fs_synth_fill_statbuf(node, stbuf);
+    return 0;
+}
+
+static int v9fs_synth_fstat(FsContext *fs_ctx,
+                            V9fsFidOpenState *fs, struct stat *stbuf)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    v9fs_synth_fill_statbuf(synth_open->node, stbuf);
+    return 0;
+}
+
+static int v9fs_synth_opendir(FsContext *ctx,
+                             V9fsPath *fs_path, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open;
+    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+    synth_open = g_malloc(sizeof(*synth_open));
+    synth_open->node = node;
+    node->open_count++;
+    fs->private = synth_open;
+    return 0;
+}
+
+static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+
+    node->open_count--;
+    g_free(synth_open);
+    fs->private = NULL;
+    return 0;
+}
+
+static off_t v9fs_synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    return synth_open->offset;
+}
+
+static void v9fs_synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    synth_open->offset = off;
+}
+
+static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    v9fs_synth_seekdir(ctx, fs, 0);
+}
+
+static void v9fs_synth_direntry(V9fsSynthNode *node,
+                                struct dirent *entry, off_t off)
+{
+    strcpy(entry->d_name, node->name);
+    entry->d_ino = node->attr->inode;
+    entry->d_off = off + 1;
+}
+
+static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry,
+                                 struct dirent **result, off_t off)
+{
+    int i = 0;
+    V9fsSynthNode *node;
+
+    pthread_rwlock_rdlock(&v9fs_synth_mutex);
+    QLIST_FOREACH(node, &dir->child, sibling) {
+        /* This is the off child of the directory */
+        if (i == off) {
+            break;
+        }
+        i++;
+    }
+    pthread_rwlock_unlock(&v9fs_synth_mutex);
+    if (!node) {
+        /* end of directory */
+        *result = NULL;
+        return 0;
+    }
+    v9fs_synth_direntry(node, entry, off);
+    *result = entry;
+    return 0;
+}
+
+static int v9fs_synth_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+                                struct dirent *entry, struct dirent **result)
+{
+    int ret;
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+    ret = v9fs_synth_get_dentry(node, entry, result, synth_open->offset);
+    if (!ret && *result != NULL) {
+        synth_open->offset++;
+    }
+    return ret;
+}
+
+static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path,
+                           int flags, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open;
+    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+    synth_open = g_malloc(sizeof(*synth_open));
+    synth_open->node = node;
+    node->open_count++;
+    fs->private = synth_open;
+    return 0;
+}
+
+static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
+                            const char *name, int flags,
+                            FsCred *credp, V9fsFidOpenState *fs)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs)
+{
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+
+    node->open_count--;
+    g_free(synth_open);
+    fs->private = NULL;
+    return 0;
+}
+
+static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+                                  const struct iovec *iov,
+                                  int iovcnt, off_t offset)
+{
+    int i, count = 0, wcount;
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+    if (!node->attr->write) {
+        errno = EPERM;
+        return -1;
+    }
+    for (i = 0; i < iovcnt; i++) {
+        wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len,
+                                   offset, node->private);
+        offset += wcount;
+        count  += wcount;
+        /* If we wrote less than requested. we are done */
+        if (wcount < iov[i].iov_len) {
+            break;
+        }
+    }
+    return count;
+}
+
+static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+                                 const struct iovec *iov,
+                                 int iovcnt, off_t offset)
+{
+    int i, count = 0, rcount;
+    V9fsSynthOpenState *synth_open = fs->private;
+    V9fsSynthNode *node = synth_open->node;
+    if (!node->attr->read) {
+        errno = EPERM;
+        return -1;
+    }
+    for (i = 0; i < iovcnt; i++) {
+        rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len,
+                                  offset, node->private);
+        offset += rcount;
+        count  += rcount;
+        /* If we read less than requested. we are done */
+        if (rcount < iov[i].iov_len) {
+            break;
+        }
+    }
+    return count;
+}
+
+static int v9fs_synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+static int v9fs_synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_mknod(FsContext *fs_ctx, V9fsPath *path,
+                       const char *buf, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
+                       const char *buf, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static ssize_t v9fs_synth_readlink(FsContext *fs_ctx, V9fsPath *path,
+                                   char *buf, size_t bufsz)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+static int v9fs_synth_symlink(FsContext *fs_ctx, const char *oldpath,
+                              V9fsPath *newpath, const char *buf, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
+                           V9fsPath *newpath, const char *buf)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_rename(FsContext *ctx, const char *oldpath,
+                             const char *newpath)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
+                                const struct timespec *buf)
+{
+    errno = EPERM;
+    return 0;
+}
+
+static int v9fs_synth_remove(FsContext *ctx, const char *path)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
+{
+    errno = ENOSYS;
+    return 0;
+}
+
+static int v9fs_synth_statfs(FsContext *s, V9fsPath *fs_path,
+                             struct statfs *stbuf)
+{
+    stbuf->f_type = 0xABCD;
+    stbuf->f_bsize = 512;
+    stbuf->f_blocks = 0;
+    stbuf->f_files = v9fs_synth_node_count;
+    stbuf->f_namelen = NAME_MAX;
+    return 0;
+}
+
+static ssize_t v9fs_synth_lgetxattr(FsContext *ctx, V9fsPath *path,
+                                    const char *name, void *value, size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static ssize_t v9fs_synth_llistxattr(FsContext *ctx, V9fsPath *path,
+                                     void *value, size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path,
+                                const char *name, void *value,
+                                size_t size, int flags)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static int v9fs_synth_lremovexattr(FsContext *ctx,
+                                   V9fsPath *path, const char *name)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+                                   const char *name, V9fsPath *target)
+{
+    V9fsSynthNode *node;
+    V9fsSynthNode *dir_node;
+
+    /* "." and ".." are not allowed */
+    if (!strcmp(name, ".") || !strcmp(name, "..")) {
+        errno = EINVAL;
+        return -1;
+
+    }
+    if (!dir_path) {
+        dir_node = &v9fs_synth_root;
+    } else {
+        dir_node = *(V9fsSynthNode **)dir_path->data;
+    }
+    if (!strcmp(name, "/")) {
+        node = dir_node;
+        goto out;
+    }
+    /* search for the name in the childern */
+    pthread_rwlock_rdlock(&v9fs_synth_mutex);
+    QLIST_FOREACH(node, &dir_node->child, sibling) {
+        if (!strcmp(node->name, name)) {
+            break;
+        }
+    }
+    pthread_rwlock_unlock(&v9fs_synth_mutex);
+    if (!node) {
+        errno = ENOENT;
+        return -1;
+    }
+out:
+    /* Copy the node pointer to fid */
+    target->data = g_malloc(sizeof(void *));
+    memcpy(target->data, &node, sizeof(void *));
+    target->size = sizeof(void *);
+    return 0;
+}
+
+static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir,
+                               const char *old_name, V9fsPath *newdir,
+                               const char *new_name)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir,
+                               const char *name, int flags)
+{
+    errno = EPERM;
+    return -1;
+}
+
+static int v9fs_synth_init(FsContext *ctx)
+{
+    pthread_rwlockattr_t rwlockattr;
+
+    QLIST_INIT(&v9fs_synth_root.child);
+    pthread_rwlockattr_init(&rwlockattr);
+    pthread_rwlock_init(&v9fs_synth_mutex, &rwlockattr);
+
+    /* Add "." and ".." entries for root */
+    v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
+                      "..", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
+    v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
+                      ".", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
+
+    /* Mark the subsystem is ready for use */
+    v9fs_synth_fs = 1;
+    return 0;
+}
+
+FileOperations synth_ops = {
+    .init         = v9fs_synth_init,
+    .lstat        = v9fs_synth_lstat,
+    .readlink     = v9fs_synth_readlink,
+    .close        = v9fs_synth_close,
+    .closedir     = v9fs_synth_closedir,
+    .open         = v9fs_synth_open,
+    .opendir      = v9fs_synth_opendir,
+    .rewinddir    = v9fs_synth_rewinddir,
+    .telldir      = v9fs_synth_telldir,
+    .readdir_r    = v9fs_synth_readdir_r,
+    .seekdir      = v9fs_synth_seekdir,
+    .preadv       = v9fs_synth_preadv,
+    .pwritev      = v9fs_synth_pwritev,
+    .chmod        = v9fs_synth_chmod,
+    .mknod        = v9fs_synth_mknod,
+    .mkdir        = v9fs_synth_mkdir,
+    .fstat        = v9fs_synth_fstat,
+    .open2        = v9fs_synth_open2,
+    .symlink      = v9fs_synth_symlink,
+    .link         = v9fs_synth_link,
+    .truncate     = v9fs_synth_truncate,
+    .rename       = v9fs_synth_rename,
+    .chown        = v9fs_synth_chown,
+    .utimensat    = v9fs_synth_utimensat,
+    .remove       = v9fs_synth_remove,
+    .fsync        = v9fs_synth_fsync,
+    .statfs       = v9fs_synth_statfs,
+    .lgetxattr    = v9fs_synth_lgetxattr,
+    .llistxattr   = v9fs_synth_llistxattr,
+    .lsetxattr    = v9fs_synth_lsetxattr,
+    .lremovexattr = v9fs_synth_lremovexattr,
+    .name_to_path = v9fs_synth_name_to_path,
+    .renameat     = v9fs_synth_renameat,
+    .unlinkat     = v9fs_synth_unlinkat,
+};
diff --git a/hw/9pfs/virtio-9p-synth.h b/hw/9pfs/virtio-9p-synth.h
new file mode 100644
index 0000000..e03f434
--- /dev/null
+++ b/hw/9pfs/virtio-9p-synth.h
@@ -0,0 +1,50 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+
+typedef struct V9fsSynthNode V9fsSynthNode;
+typedef ssize_t (*v9fs_synth_read)(void *buf, int len, off_t offset,
+                                   void *arg);
+typedef ssize_t (*v9fs_synth_write)(void *buf, int len, off_t offset,
+                                    void *arg);
+typedef struct V9fsSynthNodeAttr {
+    int mode;
+    int inode;
+    int nlink;
+    v9fs_synth_read read;
+    v9fs_synth_write write;
+} V9fsSynthNodeAttr;
+
+struct V9fsSynthNode {
+    QLIST_HEAD(, V9fsSynthNode) child;
+    QLIST_ENTRY(V9fsSynthNode) sibling;
+    char name[NAME_MAX];
+    V9fsSynthNodeAttr *attr;
+    V9fsSynthNodeAttr actual_attr;
+    void *private;
+    int open_count;
+};
+
+typedef struct V9fsSynthOpenState {
+    off_t offset;
+    V9fsSynthNode *node;
+} V9fsSynthOpenState;
+
+extern int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
+                                 const char *name, V9fsSynthNode **result);
+extern int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
+                                    const char *name, v9fs_synth_read read,
+                                    v9fs_synth_write write, void *arg);
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 6273b85..7f88356 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -212,6 +212,12 @@ union V9fsFidOpenState {
     int fd;
     DIR *dir;
     V9fsXattr xattr;
+    /*
+     * private pointer for fs drivers, that
+     * have its own internal representation of
+     * open files.
+     */
+    void *private;
 };
 
 struct V9fsFidState
diff --git a/qemu-options.hx b/qemu-options.hx
index 1baa381..8df6165 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -628,6 +628,15 @@ read-write access is given.
 @end table
 ETEXI
 
+DEF("virtfs_synth", 0, QEMU_OPTION_virtfs_synth,
+    "-virtfs_synth Create synthetic file system image\n",
+    QEMU_ARCH_ALL)
+STEXI
+ at item -virtfs_synth
+ at findex -virtfs_synth
+Create synthetic file system image
+ETEXI
+
 DEFHEADING()
 
 DEF("name", HAS_ARG, QEMU_OPTION_name,
diff --git a/vl.c b/vl.c
index c51a740..37a79e5 100644
--- a/vl.c
+++ b/vl.c
@@ -2717,6 +2717,24 @@ int main(int argc, char **argv, char **envp)
                              qemu_opt_get(opts, "mount_tag"));
                 break;
             }
+            case QEMU_OPTION_virtfs_synth: {
+                QemuOpts *fsdev;
+                QemuOpts *device;
+
+                fsdev = qemu_opts_create(qemu_find_opts("fsdev"), "v_synth", 1);
+                if (!fsdev) {
+                    fprintf(stderr, "duplicate option: %s\n", "virtfs_synth");
+                    exit(1);
+                }
+                qemu_opt_set(fsdev, "fsdriver", "synth");
+                qemu_opt_set(fsdev, "path", "/"); /* ignored */
+
+                device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+                qemu_opt_set(device, "driver", "virtio-9p-pci");
+                qemu_opt_set(device, "fsdev", "v_synth");
+                qemu_opt_set(device, "mount_tag", "v_synth");
+                break;
+            }
             case QEMU_OPTION_serial:
                 add_device_config(DEV_SERIAL, optarg);
                 default_serial = 0;
commit cc720ddb5435ceaa4cda397ca3e74b099752b763
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Oct 25 12:10:40 2011 +0530

    hw/9pfs: Abstract open state of fid to V9fsFidOpenState
    
    To implement synthetic file system in Qemu we may not really
    require file descriptor and Dir *. Make generic code use
    V9fsFidOpenState instead.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 5788ff9..1928da2 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -78,6 +78,8 @@ typedef struct V9fsPath {
     char *data;
 } V9fsPath;
 
+typedef union V9fsFidOpenState V9fsFidOpenState;
+
 void cred_init(FsCred *);
 
 typedef struct FileOperations
@@ -94,22 +96,26 @@ typedef struct FileOperations
                    const char *, FsCred *);
     int (*link)(FsContext *, V9fsPath *, V9fsPath *, const char *);
     int (*setuid)(FsContext *, uid_t);
-    int (*close)(FsContext *, int);
-    int (*closedir)(FsContext *, DIR *);
-    DIR *(*opendir)(FsContext *, V9fsPath *);
-    int (*open)(FsContext *, V9fsPath *, int);
-    int (*open2)(FsContext *, V9fsPath *, const char *, int, FsCred *);
-    void (*rewinddir)(FsContext *, DIR *);
-    off_t (*telldir)(FsContext *, DIR *);
-    int (*readdir_r)(FsContext *, DIR *, struct dirent *, struct dirent **);
-    void (*seekdir)(FsContext *, DIR *, off_t);
-    ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
-    ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
+    int (*close)(FsContext *, V9fsFidOpenState *);
+    int (*closedir)(FsContext *, V9fsFidOpenState *);
+    int (*opendir)(FsContext *, V9fsPath *, V9fsFidOpenState *);
+    int (*open)(FsContext *, V9fsPath *, int, V9fsFidOpenState *);
+    int (*open2)(FsContext *, V9fsPath *, const char *,
+                 int, FsCred *, V9fsFidOpenState *);
+    void (*rewinddir)(FsContext *, V9fsFidOpenState *);
+    off_t (*telldir)(FsContext *, V9fsFidOpenState *);
+    int (*readdir_r)(FsContext *, V9fsFidOpenState *,
+                     struct dirent *, struct dirent **);
+    void (*seekdir)(FsContext *, V9fsFidOpenState *, off_t);
+    ssize_t (*preadv)(FsContext *, V9fsFidOpenState *,
+                      const struct iovec *, int, off_t);
+    ssize_t (*pwritev)(FsContext *, V9fsFidOpenState *,
+                       const struct iovec *, int, off_t);
     int (*mkdir)(FsContext *, V9fsPath *, const char *, FsCred *);
-    int (*fstat)(FsContext *, int, struct stat *);
+    int (*fstat)(FsContext *, V9fsFidOpenState *, struct stat *);
     int (*rename)(FsContext *, const char *, const char *);
     int (*truncate)(FsContext *, V9fsPath *, off_t);
-    int (*fsync)(FsContext *, int, int);
+    int (*fsync)(FsContext *, V9fsFidOpenState *, int);
     int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
     ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
                          const char *, void *, size_t);
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 72732e7..9b6d47d 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -29,7 +29,7 @@ int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent,
     v9fs_co_run_in_worker(
         {
             errno = 0;
-            err = s->ops->readdir_r(&s->ctx, fidp->fs.dir, dent, result);
+            err = s->ops->readdir_r(&s->ctx, &fidp->fs, dent, result);
             if (!*result && errno) {
                 err = -errno;
             } else {
@@ -49,7 +49,7 @@ off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
     }
     v9fs_co_run_in_worker(
         {
-            err = s->ops->telldir(&s->ctx, fidp->fs.dir);
+            err = s->ops->telldir(&s->ctx, &fidp->fs);
             if (err < 0) {
                 err = -errno;
             }
@@ -65,7 +65,7 @@ void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset)
     }
     v9fs_co_run_in_worker(
         {
-            s->ops->seekdir(&s->ctx, fidp->fs.dir, offset);
+            s->ops->seekdir(&s->ctx, &fidp->fs, offset);
         });
 }
 
@@ -77,7 +77,7 @@ void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
     }
     v9fs_co_run_in_worker(
         {
-            s->ops->rewinddir(&s->ctx, fidp->fs.dir);
+            s->ops->rewinddir(&s->ctx, &fidp->fs);
         });
 }
 
@@ -129,8 +129,8 @@ int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path);
-            if (!fidp->fs.dir) {
+            err = s->ops->opendir(&s->ctx, &fidp->path, &fidp->fs);
+            if (err < 0) {
                 err = -errno;
             } else {
                 err = 0;
@@ -146,7 +146,7 @@ int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
     return err;
 }
 
-int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
+int v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
 {
     int err;
     V9fsState *s = pdu->s;
@@ -156,7 +156,7 @@ int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
     }
     v9fs_co_run_in_worker(
         {
-            err = s->ops->closedir(&s->ctx, dir);
+            err = s->ops->closedir(&s->ctx, fs);
             if (err < 0) {
                 err = -errno;
             }
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 692811e..586b038 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -61,7 +61,7 @@ int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
     return err;
 }
 
-int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
+int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
 {
     int err;
     V9fsState *s = pdu->s;
@@ -71,7 +71,7 @@ int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
     }
     v9fs_co_run_in_worker(
         {
-            err = s->ops->fstat(&s->ctx, fd, stbuf);
+            err = s->ops->fstat(&s->ctx, &fidp->fs, stbuf);
             if (err < 0) {
                 err = -errno;
             }
@@ -90,8 +90,8 @@ int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
-            if (fidp->fs.fd == -1) {
+            err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
+            if (err == -1) {
                 err = -errno;
             } else {
                 err = 0;
@@ -130,9 +130,9 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
-                                        name->data, flags, &cred);
-            if (fidp->fs.fd == -1) {
+            err = s->ops->open2(&s->ctx, &fidp->path,
+                                name->data, flags, &cred, &fidp->fs);
+            if (err < 0) {
                 err = -errno;
             } else {
                 v9fs_path_init(&path);
@@ -141,12 +141,12 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
                     err = s->ops->lstat(&s->ctx, &path, stbuf);
                     if (err < 0) {
                         err = -errno;
-                        s->ops->close(&s->ctx, fidp->fs.fd);
+                        s->ops->close(&s->ctx, &fidp->fs);
                     } else {
                         v9fs_path_copy(&fidp->path, &path);
                     }
                 } else {
-                    s->ops->close(&s->ctx, fidp->fs.fd);
+                    s->ops->close(&s->ctx, &fidp->fs);
                 }
                 v9fs_path_free(&path);
             }
@@ -161,7 +161,7 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
     return err;
 }
 
-int v9fs_co_close(V9fsPDU *pdu, int fd)
+int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
 {
     int err;
     V9fsState *s = pdu->s;
@@ -171,7 +171,7 @@ int v9fs_co_close(V9fsPDU *pdu, int fd)
     }
     v9fs_co_run_in_worker(
         {
-            err = s->ops->close(&s->ctx, fd);
+            err = s->ops->close(&s->ctx, fs);
             if (err < 0) {
                 err = -errno;
             }
@@ -184,16 +184,15 @@ int v9fs_co_close(V9fsPDU *pdu, int fd)
 
 int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
 {
-    int fd, err;
+    int err;
     V9fsState *s = pdu->s;
 
     if (v9fs_request_cancelled(pdu)) {
         return -EINTR;
     }
-    fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
-            err = s->ops->fsync(&s->ctx, fd, datasync);
+            err = s->ops->fsync(&s->ctx, &fidp->fs, datasync);
             if (err < 0) {
                 err = -errno;
             }
@@ -226,16 +225,15 @@ int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
 int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
                     struct iovec *iov, int iovcnt, int64_t offset)
 {
-    int fd, err;
+    int err;
     V9fsState *s = pdu->s;
 
     if (v9fs_request_cancelled(pdu)) {
         return -EINTR;
     }
-    fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
-            err = s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
+            err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
             if (err < 0) {
                 err = -errno;
             }
@@ -246,16 +244,15 @@ int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
 int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
                    struct iovec *iov, int iovcnt, int64_t offset)
 {
-    int fd, err;
+    int err;
     V9fsState *s = pdu->s;
 
     if (v9fs_request_cancelled(pdu)) {
         return -EINTR;
     }
-    fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
-            err = s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
+            err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
             if (err < 0) {
                 err = -errno;
             }
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index ca96b9c..c4b74b0 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -80,7 +80,7 @@ extern int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *);
 extern int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags);
 extern int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *,
                             V9fsPath *, V9fsString *);
-extern int v9fs_co_fstat(V9fsPDU *, int, struct stat *);
+extern int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *);
 extern int v9fs_co_opendir(V9fsPDU *, V9fsFidState *);
 extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int);
 extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
@@ -88,8 +88,8 @@ extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
 extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *,
                              void *, size_t, int);
 extern int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *);
-extern int v9fs_co_closedir(V9fsPDU *, DIR *);
-extern int v9fs_co_close(V9fsPDU *, int);
+extern int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *);
+extern int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *);
 extern int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int);
 extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *,
                            const char *, gid_t, struct stat *);
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index 98809f1..c38e0e7 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -133,81 +133,91 @@ static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
     return ret;
 }
 
-static int handle_close(FsContext *ctx, int fd)
+static int handle_close(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return close(fd);
+    return close(fs->fd);
 }
 
-static int handle_closedir(FsContext *ctx, DIR *dir)
+static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return closedir(dir);
+    return closedir(fs->dir);
 }
 
-static int handle_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+static int handle_open(FsContext *ctx, V9fsPath *fs_path,
+                       int flags, V9fsFidOpenState *fs)
 {
     struct handle_data *data = (struct handle_data *)ctx->private;
 
-    return open_by_handle(data->mountfd, fs_path->data, flags);
+    fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
+    return fs->fd;
 }
 
-static DIR *handle_opendir(FsContext *ctx, V9fsPath *fs_path)
+static int handle_opendir(FsContext *ctx,
+                          V9fsPath *fs_path, V9fsFidOpenState *fs)
 {
-    int fd;
-    fd = handle_open(ctx, fs_path, O_DIRECTORY);
-    if (fd < 0) {
-        return NULL;
+    int ret;
+    ret = handle_open(ctx, fs_path, O_DIRECTORY, fs);
+    if (ret < 0) {
+        return -1;
     }
-    return fdopendir(fd);
+    fs->dir = fdopendir(ret);
+    if (!fs->dir) {
+        return -1;
+    }
+    return 0;
 }
 
-static void handle_rewinddir(FsContext *ctx, DIR *dir)
+static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return rewinddir(dir);
+    return rewinddir(fs->dir);
 }
 
-static off_t handle_telldir(FsContext *ctx, DIR *dir)
+static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return telldir(dir);
+    return telldir(fs->dir);
 }
 
-static int handle_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+                            struct dirent *entry,
                             struct dirent **result)
 {
-    return readdir_r(dir, entry, result);
+    return readdir_r(fs->dir, entry, result);
 }
 
-static void handle_seekdir(FsContext *ctx, DIR *dir, off_t off)
+static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
 {
-    return seekdir(dir, off);
+    return seekdir(fs->dir, off);
 }
 
-static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+                             const struct iovec *iov,
                              int iovcnt, off_t offset)
 {
 #ifdef CONFIG_PREADV
-    return preadv(fd, iov, iovcnt, offset);
+    return preadv(fs->fd, iov, iovcnt, offset);
 #else
-    int err = lseek(fd, offset, SEEK_SET);
+    int err = lseek(fs->fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        return readv(fd, iov, iovcnt);
+        return readv(fs->fd, iov, iovcnt);
     }
 #endif
 }
 
-static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+                              const struct iovec *iov,
                               int iovcnt, off_t offset)
 {
     ssize_t ret;
 #ifdef CONFIG_PREADV
-    ret = pwritev(fd, iov, iovcnt, offset);
+    ret = pwritev(fs->fd, iov, iovcnt, offset);
 #else
-    int err = lseek(fd, offset, SEEK_SET);
+    int err = lseek(fs->fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        ret = writev(fd, iov, iovcnt);
+        ret = writev(fs->fd, iov, iovcnt);
     }
 #endif
 #ifdef CONFIG_SYNC_FILE_RANGE
@@ -217,7 +227,7 @@ static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
          * We want to ensure that we don't leave dirty pages in the cache
          * after write when writeout=immediate is sepcified.
          */
-        sync_file_range(fd, offset, ret,
+        sync_file_range(fs->fd, offset, ret,
                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
     }
 #endif
@@ -274,13 +284,14 @@ static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
     return ret;
 }
 
-static int handle_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+static int handle_fstat(FsContext *fs_ctx, V9fsFidOpenState *fs,
+                        struct stat *stbuf)
 {
-    return fstat(fd, stbuf);
+    return fstat(fs->fd, stbuf);
 }
 
 static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
-                       int flags, FsCred *credp)
+                        int flags, FsCred *credp, V9fsFidOpenState *fs)
 {
     int ret;
     int dirfd, fd;
@@ -296,6 +307,8 @@ static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
         if (ret < 0) {
             close(fd);
             fd = ret;
+        } else {
+            fs->fd = fd;
         }
     }
     close(dirfd);
@@ -411,12 +424,12 @@ static int handle_remove(FsContext *ctx, const char *path)
     return -1;
 }
 
-static int handle_fsync(FsContext *ctx, int fd, int datasync)
+static int handle_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
 {
     if (datasync) {
-        return qemu_fdatasync(fd);
+        return qemu_fdatasync(fs->fd);
     } else {
-        return fsync(fd);
+        return fsync(fs->fd);
     }
 }
 
@@ -575,7 +588,8 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
 static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
                                  mode_t st_mode, uint64_t *st_gen)
 {
-    int err, fd;
+    int err;
+    V9fsFidOpenState fid_open;
 
     /*
      * Do not try to open special files like device nodes, fifos etc
@@ -584,12 +598,12 @@ static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
             return 0;
     }
-    fd = handle_open(ctx, path, O_RDONLY);
-    if (fd < 0) {
-        return fd;
+    err = handle_open(ctx, path, O_RDONLY, &fid_open);
+    if (err < 0) {
+        return err;
     }
-    err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
-    handle_close(ctx, fd);
+    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
+    handle_close(ctx, &fid_open);
     return err;
 }
 
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index b611681..782dc0a 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -156,81 +156,91 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
     return tsize;
 }
 
-static int local_close(FsContext *ctx, int fd)
+static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return close(fd);
+    return close(fs->fd);
 }
 
-static int local_closedir(FsContext *ctx, DIR *dir)
+static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return closedir(dir);
+    return closedir(fs->dir);
 }
 
-static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+static int local_open(FsContext *ctx, V9fsPath *fs_path,
+                      int flags, V9fsFidOpenState *fs)
 {
     char buffer[PATH_MAX];
     char *path = fs_path->data;
 
-    return open(rpath(ctx, path, buffer), flags);
+    fs->fd = open(rpath(ctx, path, buffer), flags);
+    return fs->fd;
 }
 
-static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path)
+static int local_opendir(FsContext *ctx,
+                         V9fsPath *fs_path, V9fsFidOpenState *fs)
 {
     char buffer[PATH_MAX];
     char *path = fs_path->data;
 
-    return opendir(rpath(ctx, path, buffer));
+    fs->dir = opendir(rpath(ctx, path, buffer));
+    if (!fs->dir) {
+        return -1;
+    }
+    return 0;
 }
 
-static void local_rewinddir(FsContext *ctx, DIR *dir)
+static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return rewinddir(dir);
+    return rewinddir(fs->dir);
 }
 
-static off_t local_telldir(FsContext *ctx, DIR *dir)
+static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
 {
-    return telldir(dir);
+    return telldir(fs->dir);
 }
 
-static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+                           struct dirent *entry,
                            struct dirent **result)
 {
-    return readdir_r(dir, entry, result);
+    return readdir_r(fs->dir, entry, result);
 }
 
-static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
+static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
 {
-    return seekdir(dir, off);
+    return seekdir(fs->dir, off);
 }
 
-static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+                            const struct iovec *iov,
                             int iovcnt, off_t offset)
 {
 #ifdef CONFIG_PREADV
-    return preadv(fd, iov, iovcnt, offset);
+    return preadv(fs->fd, iov, iovcnt, offset);
 #else
-    int err = lseek(fd, offset, SEEK_SET);
+    int err = lseek(fs->fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        return readv(fd, iov, iovcnt);
+        return readv(fs->fd, iov, iovcnt);
     }
 #endif
 }
 
-static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+                             const struct iovec *iov,
                              int iovcnt, off_t offset)
 {
     ssize_t ret
 ;
 #ifdef CONFIG_PREADV
-    ret = pwritev(fd, iov, iovcnt, offset);
+    ret = pwritev(fs->fd, iov, iovcnt, offset);
 #else
-    int err = lseek(fd, offset, SEEK_SET);
+    int err = lseek(fs->fd, offset, SEEK_SET);
     if (err == -1) {
         return err;
     } else {
-        ret = writev(fd, iov, iovcnt);
+        ret = writev(fs->fd, iov, iovcnt);
     }
 #endif
 #ifdef CONFIG_SYNC_FILE_RANGE
@@ -240,7 +250,7 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
          * We want to ensure that we don't leave dirty pages in the cache
          * after write when writeout=immediate is sepcified.
          */
-        sync_file_range(fd, offset, ret,
+        sync_file_range(fs->fd, offset, ret,
                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
     }
 #endif
@@ -356,10 +366,11 @@ out:
     return err;
 }
 
-static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+static int local_fstat(FsContext *fs_ctx,
+                       V9fsFidOpenState *fs, struct stat *stbuf)
 {
     int err;
-    err = fstat(fd, stbuf);
+    err = fstat(fs->fd, stbuf);
     if (err) {
         return err;
     }
@@ -370,16 +381,20 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
         mode_t tmp_mode;
         dev_t tmp_dev;
 
-        if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
+        if (fgetxattr(fs->fd, "user.virtfs.uid",
+                      &tmp_uid, sizeof(uid_t)) > 0) {
             stbuf->st_uid = tmp_uid;
         }
-        if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
+        if (fgetxattr(fs->fd, "user.virtfs.gid",
+                      &tmp_gid, sizeof(gid_t)) > 0) {
             stbuf->st_gid = tmp_gid;
         }
-        if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
+        if (fgetxattr(fs->fd, "user.virtfs.mode",
+                      &tmp_mode, sizeof(mode_t)) > 0) {
             stbuf->st_mode = tmp_mode;
         }
-        if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
+        if (fgetxattr(fs->fd, "user.virtfs.rdev",
+                      &tmp_dev, sizeof(dev_t)) > 0) {
                 stbuf->st_rdev = tmp_dev;
         }
     }
@@ -387,7 +402,7 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
 }
 
 static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
-                       int flags, FsCred *credp)
+                       int flags, FsCred *credp, V9fsFidOpenState *fs)
 {
     char *path;
     int fd = -1;
@@ -428,6 +443,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
         }
     }
     err = fd;
+    fs->fd = fd;
     goto out;
 
 err_end:
@@ -577,12 +593,12 @@ static int local_remove(FsContext *ctx, const char *path)
     return remove(rpath(ctx, path, buffer));
 }
 
-static int local_fsync(FsContext *ctx, int fd, int datasync)
+static int local_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
 {
     if (datasync) {
-        return qemu_fdatasync(fd);
+        return qemu_fdatasync(fs->fd);
     } else {
-        return fsync(fd);
+        return fsync(fs->fd);
     }
 }
 
@@ -677,7 +693,9 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
 static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
                                 mode_t st_mode, uint64_t *st_gen)
 {
-    int err, fd;
+    int err;
+    V9fsFidOpenState fid_open;
+
     /*
      * Do not try to open special files like device nodes, fifos etc
      * We can get fd for regular files and directories only
@@ -685,12 +703,12 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
             return 0;
     }
-    fd = local_open(ctx, path, O_RDONLY);
-    if (fd < 0) {
-        return fd;
+    err = local_open(ctx, path, O_RDONLY, &fid_open);
+    if (err < 0) {
+        return err;
     }
-    err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
-    local_close(ctx, fd);
+    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
+    local_close(ctx, &fid_open);
     return err;
 }
 
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index e7618d7..0777ece 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -455,11 +455,11 @@ static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
     if (fidp->fid_type == P9_FID_FILE) {
         /* If we reclaimed the fd no need to close */
         if (fidp->fs.fd != -1) {
-            retval = v9fs_co_close(pdu, fidp->fs.fd);
+            retval = v9fs_co_close(pdu, &fidp->fs);
         }
     } else if (fidp->fid_type == P9_FID_DIR) {
         if (fidp->fs.dir != NULL) {
-            retval = v9fs_co_closedir(pdu, fidp->fs.dir);
+            retval = v9fs_co_closedir(pdu, &fidp->fs);
         }
     } else if (fidp->fid_type == P9_FID_XATTR) {
         retval = v9fs_xattr_fid_clunk(pdu, fidp);
@@ -567,9 +567,9 @@ void v9fs_reclaim_fd(V9fsPDU *pdu)
         f = reclaim_list;
         reclaim_list = f->rclm_lst;
         if (f->fid_type == P9_FID_FILE) {
-            v9fs_co_close(pdu, f->fs_reclaim.fd);
+            v9fs_co_close(pdu, &f->fs_reclaim);
         } else if (f->fid_type == P9_FID_DIR) {
-            v9fs_co_closedir(pdu, f->fs_reclaim.dir);
+            v9fs_co_closedir(pdu, &f->fs_reclaim);
         }
         f->rclm_lst = NULL;
         /*
@@ -3009,7 +3009,7 @@ static void v9fs_lock(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
+    err = v9fs_co_fstat(pdu, fidp, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -3052,7 +3052,7 @@ static void v9fs_getlock(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
+    err = v9fs_co_fstat(pdu, fidp, &stbuf);
     if (err < 0) {
         goto out;
     }
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 802f580..6273b85 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -204,20 +204,23 @@ typedef struct V9fsXattr
     int flags;
 } V9fsXattr;
 
+/*
+ * Filled by fs driver on open and other
+ * calls.
+ */
+union V9fsFidOpenState {
+    int fd;
+    DIR *dir;
+    V9fsXattr xattr;
+};
+
 struct V9fsFidState
 {
     int fid_type;
     int32_t fid;
     V9fsPath path;
-    union {
-        int fd;
-        DIR *dir;
-        V9fsXattr xattr;
-    } fs;
-    union {
-        int fd;
-        DIR *dir;
-    } fs_reclaim;
+    V9fsFidOpenState fs;
+    V9fsFidOpenState fs_reclaim;
     int flags;
     int open_flags;
     uid_t uid;
commit 2c74c2cb4bedddbfa67628fbd5f9273b4e0e9903
Author: M. Mohan Kumar <mohan at in.ibm.com>
Date:   Tue Oct 25 12:10:39 2011 +0530

    hw/9pfs: Read-only support for 9p export
    
    A new fsdev parameter "readonly" is introduced to control accessing 9p export.
    "readonly" can be used to specify the access type. By default "rw" access
    is given to 9p export.
    
    Signed-off-by: M. Mohan Kumar <mohan at in.ibm.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 908e2a5..5788ff9 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -56,10 +56,12 @@ typedef struct extended_ops {
  * On failure ignore the error.
  */
 #define V9FS_SM_NONE                0x00000010
-
+#define V9FS_RDONLY                 0x00000020
 
 #define V9FS_SEC_MASK               0x0000001C
 
+
+
 typedef struct FsContext
 {
     uid_t uid;
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 5977bcc..27d10cb 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -35,7 +35,7 @@ int qemu_fsdev_add(QemuOpts *opts)
     const char *path = qemu_opt_get(opts, "path");
     const char *sec_model = qemu_opt_get(opts, "security_model");
     const char *writeout = qemu_opt_get(opts, "writeout");
-
+    bool ro = qemu_opt_get_bool(opts, "readonly", 0);
 
     if (!fsdev_id) {
         fprintf(stderr, "fsdev: No id specified\n");
@@ -86,6 +86,11 @@ int qemu_fsdev_add(QemuOpts *opts)
             fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT;
         }
     }
+    if (ro) {
+        fsle->fse.export_flags |= V9FS_RDONLY;
+    } else {
+        fsle->fse.export_flags &= ~V9FS_RDONLY;
+    }
 
     if (strcmp(fsdriver, "local")) {
         goto done;
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 8b6813f..e7618d7 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -1271,6 +1271,11 @@ static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
     dst->size++;
 }
 
+static inline bool is_ro_export(FsContext *ctx)
+{
+    return ctx->export_flags & V9FS_RDONLY;
+}
+
 static void v9fs_version(void *opaque)
 {
     V9fsPDU *pdu = opaque;
@@ -1690,6 +1695,14 @@ static void v9fs_open(void *opaque)
         } else {
             flags = omode_to_uflags(mode);
         }
+        if (is_ro_export(&s->ctx)) {
+            if (mode & O_WRONLY || mode & O_RDWR ||
+                mode & O_APPEND || mode & O_TRUNC) {
+                err = -EROFS;
+                goto out;
+            }
+            flags |= O_NOATIME;
+        }
         err = v9fs_co_open(pdu, fidp, flags);
         if (err < 0) {
             goto out;
@@ -3309,6 +3322,39 @@ static void v9fs_op_not_supp(void *opaque)
     complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
 }
 
+static void v9fs_fs_ro(void *opaque)
+{
+    V9fsPDU *pdu = opaque;
+    complete_pdu(pdu->s, pdu, -EROFS);
+}
+
+static inline bool is_read_only_op(V9fsPDU *pdu)
+{
+    switch (pdu->id) {
+    case P9_TREADDIR:
+    case P9_TSTATFS:
+    case P9_TGETATTR:
+    case P9_TXATTRWALK:
+    case P9_TLOCK:
+    case P9_TGETLOCK:
+    case P9_TREADLINK:
+    case P9_TVERSION:
+    case P9_TLOPEN:
+    case P9_TATTACH:
+    case P9_TSTAT:
+    case P9_TWALK:
+    case P9_TCLUNK:
+    case P9_TFSYNC:
+    case P9_TOPEN:
+    case P9_TREAD:
+    case P9_TAUTH:
+    case P9_TFLUSH:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
 {
     Coroutine *co;
@@ -3320,6 +3366,10 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
     } else {
         handler = pdu_co_handlers[pdu->id];
     }
+
+    if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
+        handler = v9fs_fs_ro;
+    }
     co = qemu_coroutine_create(handler);
     qemu_coroutine_enter(co, pdu);
 }
diff --git a/qemu-config.c b/qemu-config.c
index 90b6b3e..597d7e1 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -180,7 +180,11 @@ QemuOptsList qemu_fsdev_opts = {
         }, {
             .name = "writeout",
             .type = QEMU_OPT_STRING,
+        }, {
+            .name = "readonly",
+            .type = QEMU_OPT_BOOL,
         },
+
         { /*End of list */ }
     },
 };
@@ -205,6 +209,9 @@ QemuOptsList qemu_virtfs_opts = {
         }, {
             .name = "writeout",
             .type = QEMU_OPT_STRING,
+        }, {
+            .name = "readonly",
+            .type = QEMU_OPT_BOOL,
         },
 
         { /*End of list */ }
diff --git a/qemu-options.hx b/qemu-options.hx
index 5d2a776..1baa381 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -528,12 +528,12 @@ DEFHEADING(File system options:)
 
 DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
     "-fsdev fsdriver,id=id,path=path,[security_model={mapped|passthrough|none}]\n"
-    "       [,writeout=immediate]\n",
+    "       [,writeout=immediate][,readonly]\n",
     QEMU_ARCH_ALL)
 
 STEXI
 
- at item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}]
+ at item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly]
 @findex -fsdev
 Define a new file system device. Valid options are:
 @table @option
@@ -563,6 +563,9 @@ This is an optional argument. The only supported value is "immediate".
 This means that host page cache will be used to read and write data but
 write notification will be sent to the guest only when the data has been
 reported as written by the storage subsystem.
+ at item readonly
+Enables exporting 9p share as a readonly mount for guests. By default
+read-write access is given.
 @end table
 
 -fsdev option is used along with -device driver "virtio-9p-pci".
@@ -583,12 +586,12 @@ DEFHEADING(Virtual File system pass-through options:)
 
 DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
     "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
-    "        [,writeout=immediate]\n",
+    "        [,writeout=immediate][,readonly]\n",
     QEMU_ARCH_ALL)
 
 STEXI
 
- at item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}]
+ at item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}][,readonly]
 @findex -virtfs
 
 The general form of a Virtual File system pass-through options are:
@@ -619,6 +622,9 @@ This is an optional argument. The only supported value is "immediate".
 This means that host page cache will be used to read and write data but
 write notification will be sent to the guest only when the data has been
 reported as written by the storage subsystem.
+ at item readonly
+Enables exporting 9p share as a readonly mount for guests. By default
+read-write access is given.
 @end table
 ETEXI
 
diff --git a/vl.c b/vl.c
index 1ddb17b..c51a740 100644
--- a/vl.c
+++ b/vl.c
@@ -2707,6 +2707,8 @@ int main(int argc, char **argv, char **envp)
                 qemu_opt_set(fsdev, "security_model",
                              qemu_opt_get(opts, "security_model"));
 
+                qemu_opt_set_bool(fsdev, "readonly",
+                                qemu_opt_get_bool(opts, "readonly", 0));
                 device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
                 qemu_opt_set(device, "driver", "virtio-9p-pci");
                 qemu_opt_set(device, "fsdev",
commit f02b77c9bfc5c3ac93a89026f8c1d320f61f02c9
Author: M. Mohan Kumar <mohan at in.ibm.com>
Date:   Tue Oct 25 12:10:39 2011 +0530

    qemu: Add opt_set_bool functionality
    
    Signed-off-by: M. Mohan Kumar <mohan at in.ibm.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/qemu-option.c b/qemu-option.c
index 105d760..f97a758 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -168,7 +168,7 @@ QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
     return NULL;
 }
 
-static int parse_option_bool(const char *name, const char *value, int *ret)
+static int parse_option_bool(const char *name, const char *value, bool *ret)
 {
     if (value != NULL) {
         if (!strcmp(value, "on")) {
@@ -258,7 +258,7 @@ static int parse_option_size(const char *name, const char *value, uint64_t *ret)
 int set_option_parameter(QEMUOptionParameter *list, const char *name,
     const char *value)
 {
-    int flag;
+    bool flag;
 
     // Find a matching parameter
     list = get_option_parameter(list, name);
@@ -508,7 +508,7 @@ struct QemuOpt {
 
     const QemuOptDesc *desc;
     union {
-        int      boolean;
+        bool boolean;
         uint64_t uint;
     } value;
 
@@ -542,7 +542,7 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name)
     return opt ? opt->str : NULL;
 }
 
-int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval)
+bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
 {
     QemuOpt *opt = qemu_opt_find(opts, name);
 
@@ -636,6 +636,37 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
     return 0;
 }
 
+int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
+{
+    QemuOpt *opt;
+    const QemuOptDesc *desc = opts->list->desc;
+    int i;
+
+    for (i = 0; desc[i].name != NULL; i++) {
+        if (strcmp(desc[i].name, name) == 0) {
+            break;
+        }
+    }
+    if (desc[i].name == NULL) {
+        if (i == 0) {
+            /* empty list -> allow any */;
+        } else {
+            qerror_report(QERR_INVALID_PARAMETER, name);
+            return -1;
+        }
+    }
+
+    opt = g_malloc0(sizeof(*opt));
+    opt->name = g_strdup(name);
+    opt->opts = opts;
+    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+    if (desc[i].name != NULL) {
+        opt->desc = desc+i;
+    }
+    opt->value.boolean = !!val;
+    return 0;
+}
+
 int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
                      int abort_on_failure)
 {
diff --git a/qemu-option.h b/qemu-option.h
index b515813..07958e4 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -105,10 +105,11 @@ struct QemuOptsList {
 };
 
 const char *qemu_opt_get(QemuOpts *opts, const char *name);
-int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval);
+bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval);
 uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval);
 uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval);
 int qemu_opt_set(QemuOpts *opts, const char *name, const char *value);
+int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val);
 typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaque);
 int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
                      int abort_on_failure);
commit 15329e8338d5bb2b69e177d5ab4e01b8c1e488ff
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Oct 25 12:10:39 2011 +0530

    configure: Update configure so that open_by_handle_at check returns correct value
    
    According to David Gibson for some compiler/libc combinations, open_by_handle_at
    test in configure isn't quite right: because the file_handle pointer is never
    dereferenced, gcc doesn't complain even if it is undefined. Change the test
    as suggested by him.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/configure b/configure
index 4f87e0a..19e8394 100755
--- a/configure
+++ b/configure
@@ -2562,7 +2562,7 @@ fi
 open_by_hande_at=no
 cat > $TMPC << EOF
 #include <fcntl.h>
-int main(void) { struct file_handle *fh; open_by_handle_at(0, fh, 0); }
+int main(void) { struct file_handle fh; open_by_handle_at(0, &fh, 0); }
 EOF
 if compile_prog "" "" ; then
     open_by_handle_at=yes
commit 17b1971f631af18e87249ee6a509fcb47dec220d
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Oct 25 12:10:39 2011 +0530

    hw/9pfs: Fix error handling in local_mknod
    
    Update local_chown to remove unnecessary if loop
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index d561de8..b611681 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -281,7 +281,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
         if (err == -1) {
             goto out;
         }
-        local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+        err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
         if (err == -1) {
             serrno = errno;
             goto err_end;
@@ -551,15 +551,12 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
     char *path = fs_path->data;
 
     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
-            (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH)) {
-        return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
-                credp->fc_gid);
+        (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+        (fs_ctx->export_flags & V9FS_SM_NONE)) {
+        return lchown(rpath(fs_ctx, path, buffer),
+                      credp->fc_uid, credp->fc_gid);
     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
-    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
-               (fs_ctx->export_flags & V9FS_SM_NONE)) {
-        return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
-                credp->fc_gid);
     }
     return -1;
 }
commit 03a0e9444c2beff94ff26fbfc30ea067ea4bf6ed
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Oct 28 10:55:38 2011 +0100

    hw/vexpress.c, hw/realview.c: Add PL041 to VExpress, Realview boards
    
    Instantiate the PL041 audio on the Versatile Express and
    Realview board models.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/realview.c b/hw/realview.c
index 14281b0..9a8e63c 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -125,7 +125,7 @@ static void realview_init(ram_addr_t ram_size,
     MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
     MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
-    DeviceState *dev, *sysctl, *gpio2;
+    DeviceState *dev, *sysctl, *gpio2, *pl041;
     SysBusDevice *busdev;
     qemu_irq *irqp;
     qemu_irq pic[64];
@@ -232,6 +232,12 @@ static void realview_init(ram_addr_t ram_size,
         pic[n] = qdev_get_gpio_in(dev, n);
     }
 
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000);
+    sysbus_connect_irq(sysbus_from_qdev(pl041), 0, pic[19]);
+
     sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
     sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]);
 
diff --git a/hw/vexpress.c b/hw/vexpress.c
index c9766dd..0940a26 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -41,7 +41,7 @@ static void vexpress_a9_init(ram_addr_t ram_size,
 {
     CPUState *env = NULL;
     ram_addr_t ram_offset, vram_offset, sram_offset;
-    DeviceState *dev, *sysctl;
+    DeviceState *dev, *sysctl, *pl041;
     SysBusDevice *busdev;
     qemu_irq *irqp;
     qemu_irq pic[64];
@@ -118,6 +118,11 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     /* 0x10001000 SP810 system control */
     /* 0x10002000 serial bus PCI */
     /* 0x10004000 PL041 audio */
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000);
+    sysbus_connect_irq(sysbus_from_qdev(pl041), 0, pic[11]);
 
     dev = sysbus_create_varargs("pl181", 0x10005000, pic[9], pic[10], NULL);
     /* Wire up MMC card detect and read-only signals */
commit d028d02d0cb5faecb8270eca43066f13add72a29
Author: Mathieu Sonet <contact at elasticsheep.com>
Date:   Fri Oct 28 10:55:37 2011 +0100

    Add AACI audio playback support to the ARM Versatile/PB platform
    
    This driver emulates the ARM AACI interface (PL041) connected to a LM4549 codec.
    It enables audio playback for the Versatile/PB platform.
    
    Limitations:
    - Supports only a playback on one channel (Versatile/Vexpress)
    - Supports only one TX FIFO in compact-mode or non-compact mode.
    - Supports playback of 12, 16, 18 and 20 bits samples.
    - Record is not supported.
    - The PL041 is hardwired to a LM4549 codec.
    
    Versatile/PB test build:
    linux-2.6.38.5
    buildroot-2010.11
    alsa-lib-1.0.22
    alsa-utils-1.0.22
    mpg123-0.66
    
    Qemu host: Ubuntu 10.04 in Vmware/OS X
    
    Playback tested successfully with speaker-test/aplay/mpg123.
    
    Signed-off-by: Mathieu Sonet <contact at elasticsheep.com>
    [Peter Maydell: fixed typo in code clearing SL1RXBUSY/SL2RXBUSY
     bits, as spotted by Andrzej Zaborowski]
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/Makefile.target b/Makefile.target
index fe5f6f7..530c1d1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -362,6 +362,7 @@ obj-arm-y += syborg_virtio.o
 obj-arm-y += vexpress.o
 obj-arm-y += strongarm.o
 obj-arm-y += collie.o
+obj-arm-y += pl041.o lm4549.o
 
 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/lm4549.c b/hw/lm4549.c
new file mode 100644
index 0000000..4d5b831
--- /dev/null
+++ b/hw/lm4549.c
@@ -0,0 +1,336 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ *
+ * This driver emulates the LM4549 codec.
+ *
+ * It supports only one playback voice and no record voice.
+ */
+
+#include "hw.h"
+#include "audio/audio.h"
+#include "lm4549.h"
+
+#if 0
+#define LM4549_DEBUG  1
+#endif
+
+#if 0
+#define LM4549_DUMP_DAC_INPUT 1
+#endif
+
+#ifdef LM4549_DEBUG
+#define DPRINTF(fmt, ...) \
+do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+#include <stdio.h>
+static FILE *fp_dac_input;
+#endif
+
+/* LM4549 register list */
+enum {
+    LM4549_Reset                    = 0x00,
+    LM4549_Master_Volume            = 0x02,
+    LM4549_Line_Out_Volume          = 0x04,
+    LM4549_Master_Volume_Mono       = 0x06,
+    LM4549_PC_Beep_Volume           = 0x0A,
+    LM4549_Phone_Volume             = 0x0C,
+    LM4549_Mic_Volume               = 0x0E,
+    LM4549_Line_In_Volume           = 0x10,
+    LM4549_CD_Volume                = 0x12,
+    LM4549_Video_Volume             = 0x14,
+    LM4549_Aux_Volume               = 0x16,
+    LM4549_PCM_Out_Volume           = 0x18,
+    LM4549_Record_Select            = 0x1A,
+    LM4549_Record_Gain              = 0x1C,
+    LM4549_General_Purpose          = 0x20,
+    LM4549_3D_Control               = 0x22,
+    LM4549_Powerdown_Ctrl_Stat      = 0x26,
+    LM4549_Ext_Audio_ID             = 0x28,
+    LM4549_Ext_Audio_Stat_Ctrl      = 0x2A,
+    LM4549_PCM_Front_DAC_Rate       = 0x2C,
+    LM4549_PCM_ADC_Rate             = 0x32,
+    LM4549_Vendor_ID1               = 0x7C,
+    LM4549_Vendor_ID2               = 0x7E
+};
+
+static void lm4549_reset(lm4549_state *s)
+{
+    uint16_t *regfile = s->regfile;
+
+    regfile[LM4549_Reset]               = 0x0d50;
+    regfile[LM4549_Master_Volume]       = 0x8008;
+    regfile[LM4549_Line_Out_Volume]     = 0x8000;
+    regfile[LM4549_Master_Volume_Mono]  = 0x8000;
+    regfile[LM4549_PC_Beep_Volume]      = 0x0000;
+    regfile[LM4549_Phone_Volume]        = 0x8008;
+    regfile[LM4549_Mic_Volume]          = 0x8008;
+    regfile[LM4549_Line_In_Volume]      = 0x8808;
+    regfile[LM4549_CD_Volume]           = 0x8808;
+    regfile[LM4549_Video_Volume]        = 0x8808;
+    regfile[LM4549_Aux_Volume]          = 0x8808;
+    regfile[LM4549_PCM_Out_Volume]      = 0x8808;
+    regfile[LM4549_Record_Select]       = 0x0000;
+    regfile[LM4549_Record_Gain]         = 0x8000;
+    regfile[LM4549_General_Purpose]     = 0x0000;
+    regfile[LM4549_3D_Control]          = 0x0101;
+    regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
+    regfile[LM4549_Ext_Audio_ID]        = 0x0001;
+    regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x0000;
+    regfile[LM4549_PCM_Front_DAC_Rate]  = 0xbb80;
+    regfile[LM4549_PCM_ADC_Rate]        = 0xbb80;
+    regfile[LM4549_Vendor_ID1]          = 0x4e53;
+    regfile[LM4549_Vendor_ID2]          = 0x4331;
+}
+
+static void lm4549_audio_transfer(lm4549_state *s)
+{
+    uint32_t written_bytes, written_samples;
+    uint32_t i;
+
+    /* Activate the voice */
+    AUD_set_active_out(s->voice, 1);
+    s->voice_is_active = 1;
+
+    /* Try to write the buffer content */
+    written_bytes = AUD_write(s->voice, s->buffer,
+                              s->buffer_level * sizeof(uint16_t));
+    written_samples = written_bytes >> 1;
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+    fwrite(s->buffer, sizeof(uint8_t), written_bytes, fp_dac_input);
+#endif
+
+    s->buffer_level -= written_samples;
+
+    if (s->buffer_level > 0) {
+        /* Move the data back to the start of the buffer */
+        for (i = 0; i < s->buffer_level; i++) {
+            s->buffer[i] = s->buffer[i + written_samples];
+        }
+    }
+}
+
+static void lm4549_audio_out_callback(void *opaque, int free)
+{
+    lm4549_state *s = (lm4549_state *)opaque;
+    static uint32_t prev_buffer_level;
+
+#ifdef LM4549_DEBUG
+    int size = AUD_get_buffer_size_out(s->voice);
+    DPRINTF("audio_out_callback size = %i free = %i\n", size, free);
+#endif
+
+    /* Detect that no data are consumed
+       => disable the voice */
+    if (s->buffer_level == prev_buffer_level) {
+        AUD_set_active_out(s->voice, 0);
+        s->voice_is_active = 0;
+    }
+    prev_buffer_level = s->buffer_level;
+
+    /* Check if a buffer transfer is pending */
+    if (s->buffer_level == LM4549_BUFFER_SIZE) {
+        lm4549_audio_transfer(s);
+
+        /* Request more data */
+        if (s->data_req_cb != NULL) {
+            (s->data_req_cb)(s->opaque);
+        }
+    }
+}
+
+uint32_t lm4549_read(lm4549_state *s, target_phys_addr_t offset)
+{
+    uint16_t *regfile = s->regfile;
+    uint32_t value = 0;
+
+    /* Read the stored value */
+    assert(offset < 128);
+    value = regfile[offset];
+
+    DPRINTF("read [0x%02x] = 0x%04x\n", offset, value);
+
+    return value;
+}
+
+void lm4549_write(lm4549_state *s,
+                  target_phys_addr_t offset, uint32_t value)
+{
+    uint16_t *regfile = s->regfile;
+
+    assert(offset < 128);
+    DPRINTF("write [0x%02x] = 0x%04x\n", offset, value);
+
+    switch (offset) {
+    case LM4549_Reset:
+        lm4549_reset(s);
+        break;
+
+    case LM4549_PCM_Front_DAC_Rate:
+        regfile[LM4549_PCM_Front_DAC_Rate] = value;
+        DPRINTF("DAC rate change = %i\n", value);
+
+        /* Re-open a voice with the new sample rate */
+        struct audsettings as;
+        as.freq = value;
+        as.nchannels = 2;
+        as.fmt = AUD_FMT_S16;
+        as.endianness = 0;
+
+        s->voice = AUD_open_out(
+            &s->card,
+            s->voice,
+            "lm4549.out",
+            s,
+            lm4549_audio_out_callback,
+            &as
+        );
+        break;
+
+    case LM4549_Powerdown_Ctrl_Stat:
+        value &= ~0xf;
+        value |= regfile[LM4549_Powerdown_Ctrl_Stat] & 0xf;
+        regfile[LM4549_Powerdown_Ctrl_Stat] = value;
+        break;
+
+    case LM4549_Ext_Audio_ID:
+    case LM4549_Vendor_ID1:
+    case LM4549_Vendor_ID2:
+        DPRINTF("Write to read-only register 0x%x\n", (int)offset);
+        break;
+
+    default:
+        /* Store the new value */
+        regfile[offset] = value;
+        break;
+    }
+}
+
+uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right)
+{
+    /* The left and right samples are in 20-bit resolution.
+       The LM4549 has 18-bit resolution and only uses the bits [19:2].
+       This model supports 16-bit playback.
+    */
+
+    if (s->buffer_level >= LM4549_BUFFER_SIZE) {
+        DPRINTF("write_sample Buffer full\n");
+        return 0;
+    }
+
+    /* Store 16-bit samples in the buffer */
+    s->buffer[s->buffer_level++] = (left >> 4);
+    s->buffer[s->buffer_level++] = (right >> 4);
+
+    if (s->buffer_level == LM4549_BUFFER_SIZE) {
+        /* Trigger the transfer of the buffer to the audio host */
+        lm4549_audio_transfer(s);
+    }
+
+    return 1;
+}
+
+static int lm4549_post_load(void *opaque, int version_id)
+{
+    lm4549_state *s = (lm4549_state *)opaque;
+    uint16_t *regfile = s->regfile;
+
+    /* Re-open a voice with the current sample rate */
+    uint32_t freq = regfile[LM4549_PCM_Front_DAC_Rate];
+
+    DPRINTF("post_load freq = %i\n", freq);
+    DPRINTF("post_load voice_is_active = %i\n", s->voice_is_active);
+
+    struct audsettings as;
+    as.freq = freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    s->voice = AUD_open_out(
+        &s->card,
+        s->voice,
+        "lm4549.out",
+        s,
+        lm4549_audio_out_callback,
+        &as
+    );
+
+    /* Request data */
+    if (s->voice_is_active == 1) {
+        lm4549_audio_out_callback(s, AUD_get_buffer_size_out(s->voice));
+    }
+
+    return 0;
+}
+
+void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque)
+{
+    struct audsettings as;
+
+    /* Store the callback and opaque pointer */
+    s->data_req_cb = data_req_cb;
+    s->opaque = opaque;
+
+    /* Init the registers */
+    lm4549_reset(s);
+
+    /* Register an audio card */
+    AUD_register_card("lm4549", &s->card);
+
+    /* Open a default voice */
+    as.freq = 48000;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    s->voice = AUD_open_out(
+        &s->card,
+        s->voice,
+        "lm4549.out",
+        s,
+        lm4549_audio_out_callback,
+        &as
+    );
+
+    AUD_set_volume_out(s->voice, 0, 255, 255);
+
+    s->voice_is_active = 0;
+
+    /* Reset the input buffer */
+    memset(s->buffer, 0x00, sizeof(s->buffer));
+    s->buffer_level = 0;
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+    fp_dac_input = fopen("lm4549_dac_input.pcm", "wb");
+    if (!fp_dac_input) {
+        hw_error("Unable to open lm4549_dac_input.pcm for writing\n");
+    }
+#endif
+}
+
+const VMStateDescription vmstate_lm4549_state = {
+    .name = "lm4549_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = &lm4549_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(voice_is_active, lm4549_state),
+        VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
+        VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE),
+        VMSTATE_UINT32(buffer_level, lm4549_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
diff --git a/hw/lm4549.h b/hw/lm4549.h
new file mode 100644
index 0000000..70d0ac1
--- /dev/null
+++ b/hw/lm4549.h
@@ -0,0 +1,43 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ */
+
+#ifndef HW_LM4549_H
+#define HW_LM4549_H
+
+#include "audio/audio.h"
+
+typedef void (*lm4549_callback)(void *opaque);
+
+#define LM4549_BUFFER_SIZE (512 * 2) /* 512 16-bit stereo samples */
+
+
+typedef struct {
+    QEMUSoundCard card;
+    SWVoiceOut *voice;
+    uint32_t voice_is_active;
+
+    uint16_t regfile[128];
+    lm4549_callback data_req_cb;
+    void *opaque;
+
+    uint16_t buffer[LM4549_BUFFER_SIZE];
+    uint32_t buffer_level;
+} lm4549_state;
+
+extern const VMStateDescription vmstate_lm4549_state;
+
+
+void lm4549_init(lm4549_state *s, lm4549_callback data_req, void *opaque);
+uint32_t lm4549_read(lm4549_state *s, target_phys_addr_t offset);
+void lm4549_write(lm4549_state *s, target_phys_addr_t offset, uint32_t value);
+uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right);
+
+#endif /* #ifndef HW_LM4549_H */
diff --git a/hw/pl041.c b/hw/pl041.c
new file mode 100644
index 0000000..efd52ac
--- /dev/null
+++ b/hw/pl041.c
@@ -0,0 +1,636 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ *
+ * This driver emulates the ARM AACI interface
+ * connected to a LM4549 codec.
+ *
+ * Limitations:
+ * - Supports only a playback on one channel (Versatile/Vexpress)
+ * - Supports only one TX FIFO in compact-mode or non-compact mode.
+ * - Supports playback of 12, 16, 18 and 20 bits samples.
+ * - Record is not supported.
+ * - The PL041 is hardwired to a LM4549 codec.
+ *
+ */
+
+#include "sysbus.h"
+
+#include "pl041.h"
+#include "lm4549.h"
+
+#if 0
+#define PL041_DEBUG_LEVEL 1
+#endif
+
+#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 1)
+#define DBG_L1(fmt, ...) \
+do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DBG_L1(fmt, ...) \
+do { } while (0)
+#endif
+
+#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 2)
+#define DBG_L2(fmt, ...) \
+do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DBG_L2(fmt, ...) \
+do { } while (0)
+#endif
+
+
+#define MAX_FIFO_DEPTH      (1024)
+#define DEFAULT_FIFO_DEPTH  (8)
+
+#define SLOT1_RW    (1 << 19)
+
+/* This FIFO only stores 20-bit samples on 32-bit words.
+   So its level is independent of the selected mode */
+typedef struct {
+    uint32_t level;
+    uint32_t data[MAX_FIFO_DEPTH];
+} pl041_fifo;
+
+typedef struct {
+    pl041_fifo tx_fifo;
+    uint8_t tx_enabled;
+    uint8_t tx_compact_mode;
+    uint8_t tx_sample_size;
+
+    pl041_fifo rx_fifo;
+    uint8_t rx_enabled;
+    uint8_t rx_compact_mode;
+    uint8_t rx_sample_size;
+} pl041_channel;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    uint32_t fifo_depth; /* FIFO depth in non-compact mode */
+
+    pl041_regfile regs;
+    pl041_channel fifo1;
+    lm4549_state codec;
+} pl041_state;
+
+
+static const unsigned char pl041_default_id[8] = {
+    0x41, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
+};
+
+#if defined(PL041_DEBUG_LEVEL)
+#define REGISTER(name, offset) #name,
+static const char *pl041_regs_name[] = {
+    #include "pl041.hx"
+};
+#undef REGISTER
+#endif
+
+
+#if defined(PL041_DEBUG_LEVEL)
+static const char *get_reg_name(target_phys_addr_t offset)
+{
+    if (offset <= PL041_dr1_7) {
+        return pl041_regs_name[offset >> 2];
+    }
+
+    return "unknown";
+}
+#endif
+
+static uint8_t pl041_compute_periphid3(pl041_state *s)
+{
+    uint8_t id3 = 1; /* One channel */
+
+    /* Add the fifo depth information */
+    switch (s->fifo_depth) {
+    case 8:
+        id3 |= 0 << 3;
+        break;
+    case 32:
+        id3 |= 1 << 3;
+        break;
+    case 64:
+        id3 |= 2 << 3;
+        break;
+    case 128:
+        id3 |= 3 << 3;
+        break;
+    case 256:
+        id3 |= 4 << 3;
+        break;
+    case 512:
+        id3 |= 5 << 3;
+        break;
+    case 1024:
+        id3 |= 6 << 3;
+        break;
+    case 2048:
+        id3 |= 7 << 3;
+        break;
+    }
+
+    return id3;
+}
+
+static void pl041_reset(pl041_state *s)
+{
+    DBG_L1("pl041_reset\n");
+
+    memset(&s->regs, 0x00, sizeof(pl041_regfile));
+
+    s->regs.slfr = SL1TXEMPTY | SL2TXEMPTY | SL12TXEMPTY;
+    s->regs.sr1 = TXFE | RXFE | TXHE;
+    s->regs.isr1 = 0;
+
+    memset(&s->fifo1, 0x00, sizeof(s->fifo1));
+}
+
+
+static void pl041_fifo1_write(pl041_state *s, uint32_t value)
+{
+    pl041_channel *channel = &s->fifo1;
+    pl041_fifo *fifo = &s->fifo1.tx_fifo;
+
+    /* Push the value in the FIFO */
+    if (channel->tx_compact_mode == 0) {
+        /* Non-compact mode */
+
+        if (fifo->level < s->fifo_depth) {
+            /* Pad the value with 0 to obtain a 20-bit sample */
+            switch (channel->tx_sample_size) {
+            case 12:
+                value = (value << 8) & 0xFFFFF;
+                break;
+            case 16:
+                value = (value << 4) & 0xFFFFF;
+                break;
+            case 18:
+                value = (value << 2) & 0xFFFFF;
+                break;
+            case 20:
+            default:
+                break;
+            }
+
+            /* Store the sample in the FIFO */
+            fifo->data[fifo->level++] = value;
+        }
+#if defined(PL041_DEBUG_LEVEL)
+        else {
+            DBG_L1("fifo1 write: overrun\n");
+        }
+#endif
+    } else {
+        /* Compact mode */
+
+        if ((fifo->level + 2) < s->fifo_depth) {
+            uint32_t i = 0;
+            uint32_t sample = 0;
+
+            for (i = 0; i < 2; i++) {
+                sample = value & 0xFFFF;
+                value = value >> 16;
+
+                /* Pad each sample with 0 to obtain a 20-bit sample */
+                switch (channel->tx_sample_size) {
+                case 12:
+                    sample = sample << 8;
+                    break;
+                case 16:
+                default:
+                    sample = sample << 4;
+                    break;
+                }
+
+                /* Store the sample in the FIFO */
+                fifo->data[fifo->level++] = sample;
+            }
+        }
+#if defined(PL041_DEBUG_LEVEL)
+        else {
+            DBG_L1("fifo1 write: overrun\n");
+        }
+#endif
+    }
+
+    /* Update the status register */
+    if (fifo->level > 0) {
+        s->regs.sr1 &= ~(TXUNDERRUN | TXFE);
+    }
+
+    if (fifo->level >= (s->fifo_depth / 2)) {
+        s->regs.sr1 &= ~TXHE;
+    }
+
+    if (fifo->level >= s->fifo_depth) {
+        s->regs.sr1 |= TXFF;
+    }
+
+    DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1);
+}
+
+static void pl041_fifo1_transmit(pl041_state *s)
+{
+    pl041_channel *channel = &s->fifo1;
+    pl041_fifo *fifo = &s->fifo1.tx_fifo;
+    uint32_t slots = s->regs.txcr1 & TXSLOT_MASK;
+    uint32_t written_samples;
+
+    /* Check if FIFO1 transmit is enabled */
+    if ((channel->tx_enabled) && (slots & (TXSLOT3 | TXSLOT4))) {
+        if (fifo->level >= (s->fifo_depth / 2)) {
+            int i;
+
+            DBG_L1("Transfer FIFO level = %i\n", fifo->level);
+
+            /* Try to transfer the whole FIFO */
+            for (i = 0; i < (fifo->level / 2); i++) {
+                uint32_t left = fifo->data[i * 2];
+                uint32_t right = fifo->data[i * 2 + 1];
+
+                 /* Transmit two 20-bit samples to the codec */
+                if (lm4549_write_samples(&s->codec, left, right) == 0) {
+                    DBG_L1("Codec buffer full\n");
+                    break;
+                }
+            }
+
+            written_samples = i * 2;
+            if (written_samples > 0) {
+                /* Update the FIFO level */
+                fifo->level -= written_samples;
+
+                /* Move back the pending samples to the start of the FIFO */
+                for (i = 0; i < fifo->level; i++) {
+                    fifo->data[i] = fifo->data[written_samples + i];
+                }
+
+                /* Update the status register */
+                s->regs.sr1 &= ~TXFF;
+
+                if (fifo->level <= (s->fifo_depth / 2)) {
+                    s->regs.sr1 |= TXHE;
+                }
+
+                if (fifo->level == 0) {
+                    s->regs.sr1 |= TXFE | TXUNDERRUN;
+                    DBG_L1("Empty FIFO\n");
+                }
+            }
+        }
+    }
+}
+
+static void pl041_isr1_update(pl041_state *s)
+{
+    /* Update ISR1 */
+    if (s->regs.sr1 & TXUNDERRUN) {
+        s->regs.isr1 |= URINTR;
+    } else {
+        s->regs.isr1 &= ~URINTR;
+    }
+
+    if (s->regs.sr1 & TXHE) {
+        s->regs.isr1 |= TXINTR;
+    } else {
+        s->regs.isr1 &= ~TXINTR;
+    }
+
+    if (!(s->regs.sr1 & TXBUSY) && (s->regs.sr1 & TXFE)) {
+        s->regs.isr1 |= TXCINTR;
+    } else {
+        s->regs.isr1 &= ~TXCINTR;
+    }
+
+    /* Update the irq state */
+    qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0);
+    DBG_L2("Set interrupt sr1 = 0x%08x isr1 = 0x%08x masked = 0x%08x\n",
+           s->regs.sr1, s->regs.isr1, s->regs.isr1 & s->regs.ie1);
+}
+
+static void pl041_request_data(void *opaque)
+{
+    pl041_state *s = (pl041_state *)opaque;
+
+    /* Trigger pending transfers */
+    pl041_fifo1_transmit(s);
+    pl041_isr1_update(s);
+}
+
+static uint64_t pl041_read(void *opaque, target_phys_addr_t offset,
+                                unsigned size)
+{
+    pl041_state *s = (pl041_state *)opaque;
+    int value;
+
+    if ((offset >= PL041_periphid0) && (offset <= PL041_pcellid3)) {
+        if (offset == PL041_periphid3) {
+            value = pl041_compute_periphid3(s);
+        } else {
+            value = pl041_default_id[(offset - PL041_periphid0) >> 2];
+        }
+
+        DBG_L1("pl041_read [0x%08x] => 0x%08x\n", offset, value);
+        return value;
+    } else if (offset <= PL041_dr4_7) {
+        value = *((uint32_t *)&s->regs + (offset >> 2));
+    } else {
+        DBG_L1("pl041_read: Reserved offset %x\n", (int)offset);
+        return 0;
+    }
+
+    switch (offset) {
+    case PL041_allints:
+        value = s->regs.isr1 & 0x7F;
+        break;
+    }
+
+    DBG_L1("pl041_read [0x%08x] %s => 0x%08x\n", offset,
+           get_reg_name(offset), value);
+
+    return value;
+}
+
+static void pl041_write(void *opaque, target_phys_addr_t offset,
+                             uint64_t value, unsigned size)
+{
+    pl041_state *s = (pl041_state *)opaque;
+    uint16_t control, data;
+    uint32_t result;
+
+    DBG_L1("pl041_write [0x%08x] %s <= 0x%08x\n", offset,
+           get_reg_name(offset), (unsigned int)value);
+
+    /* Write the register */
+    if (offset <= PL041_dr4_7) {
+        *((uint32_t *)&s->regs + (offset >> 2)) = value;
+    } else {
+        DBG_L1("pl041_write: Reserved offset %x\n", (int)offset);
+        return;
+    }
+
+    /* Execute the actions */
+    switch (offset) {
+    case PL041_txcr1:
+    {
+        pl041_channel *channel = &s->fifo1;
+
+        uint32_t txen = s->regs.txcr1 & TXEN;
+        uint32_t tsize = (s->regs.txcr1 & TSIZE_MASK) >> TSIZE_MASK_BIT;
+        uint32_t compact_mode = (s->regs.txcr1 & TXCOMPACT) ? 1 : 0;
+#if defined(PL041_DEBUG_LEVEL)
+        uint32_t slots = (s->regs.txcr1 & TXSLOT_MASK) >> TXSLOT_MASK_BIT;
+        uint32_t txfen = (s->regs.txcr1 & TXFEN) > 0 ? 1 : 0;
+#endif
+
+        DBG_L1("=> txen = %i slots = 0x%01x tsize = %i compact = %i "
+               "txfen = %i\n", txen, slots,  tsize, compact_mode, txfen);
+
+        channel->tx_enabled = txen;
+        channel->tx_compact_mode = compact_mode;
+
+        switch (tsize) {
+        case 0:
+            channel->tx_sample_size = 16;
+            break;
+        case 1:
+            channel->tx_sample_size = 18;
+            break;
+        case 2:
+            channel->tx_sample_size = 20;
+            break;
+        case 3:
+            channel->tx_sample_size = 12;
+            break;
+        }
+
+        DBG_L1("TX enabled = %i\n", channel->tx_enabled);
+        DBG_L1("TX compact mode = %i\n", channel->tx_compact_mode);
+        DBG_L1("TX sample width = %i\n", channel->tx_sample_size);
+
+        /* Check if compact mode is allowed with selected tsize */
+        if (channel->tx_compact_mode == 1) {
+            if ((channel->tx_sample_size == 18) ||
+                (channel->tx_sample_size == 20)) {
+                channel->tx_compact_mode = 0;
+                DBG_L1("Compact mode not allowed with 18/20-bit sample size\n");
+            }
+        }
+
+        break;
+    }
+    case PL041_sl1tx:
+        s->regs.slfr &= ~SL1TXEMPTY;
+
+        control = (s->regs.sl1tx >> 12) & 0x7F;
+        data = (s->regs.sl2tx >> 4) & 0xFFFF;
+
+        if ((s->regs.sl1tx & SLOT1_RW) == 0) {
+            /* Write operation */
+            lm4549_write(&s->codec, control, data);
+        } else {
+            /* Read operation */
+            result = lm4549_read(&s->codec, control);
+
+            /* Store the returned value */
+            s->regs.sl1rx = s->regs.sl1tx & ~SLOT1_RW;
+            s->regs.sl2rx = result << 4;
+
+            s->regs.slfr &= ~(SL1RXBUSY | SL2RXBUSY);
+            s->regs.slfr |= SL1RXVALID | SL2RXVALID;
+        }
+        break;
+
+    case PL041_sl2tx:
+        s->regs.sl2tx = value;
+        s->regs.slfr &= ~SL2TXEMPTY;
+        break;
+
+    case PL041_intclr:
+        DBG_L1("=> Clear interrupt intclr = 0x%08x isr1 = 0x%08x\n",
+               s->regs.intclr, s->regs.isr1);
+
+        if (s->regs.intclr & TXUEC1) {
+            s->regs.sr1 &= ~TXUNDERRUN;
+        }
+        break;
+
+    case PL041_maincr:
+    {
+#if defined(PL041_DEBUG_LEVEL)
+        char debug[] = " AACIFE  SL1RXEN  SL1TXEN";
+        if (!(value & AACIFE)) {
+            debug[0] = '!';
+        }
+        if (!(value & SL1RXEN)) {
+            debug[8] = '!';
+        }
+        if (!(value & SL1TXEN)) {
+            debug[17] = '!';
+        }
+        DBG_L1("%s\n", debug);
+#endif
+
+        if ((s->regs.maincr & AACIFE) == 0) {
+            pl041_reset(s);
+        }
+        break;
+    }
+
+    case PL041_dr1_0:
+    case PL041_dr1_1:
+    case PL041_dr1_2:
+    case PL041_dr1_3:
+        pl041_fifo1_write(s, value);
+        break;
+    }
+
+    /* Transmit the FIFO content */
+    pl041_fifo1_transmit(s);
+
+    /* Update the ISR1 register */
+    pl041_isr1_update(s);
+}
+
+static void pl041_device_reset(DeviceState *d)
+{
+    pl041_state *s = DO_UPCAST(pl041_state, busdev.qdev, d);
+
+    pl041_reset(s);
+}
+
+static const MemoryRegionOps pl041_ops = {
+    .read = pl041_read,
+    .write = pl041_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pl041_init(SysBusDevice *dev)
+{
+    pl041_state *s = FROM_SYSBUS(pl041_state, dev);
+
+    DBG_L1("pl041_init 0x%08x\n", (uint32_t)s);
+
+    /* Check the device properties */
+    switch (s->fifo_depth) {
+    case 8:
+    case 32:
+    case 64:
+    case 128:
+    case 256:
+    case 512:
+    case 1024:
+    case 2048:
+        break;
+    case 16:
+    default:
+        /* NC FIFO depth of 16 is not allowed because its id bits in
+           AACIPERIPHID3 overlap with the id for the default NC FIFO depth */
+        fprintf(stderr, "pl041: unsupported non-compact fifo depth [%i]\n",
+                s->fifo_depth);
+        return -1;
+    }
+
+    /* Connect the device to the sysbus */
+    memory_region_init_io(&s->iomem, &pl041_ops, s, "pl041", 0x1000);
+    sysbus_init_mmio_region(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    /* Init the codec */
+    lm4549_init(&s->codec, &pl041_request_data, (void *)s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pl041_regfile = {
+    .name = "pl041_regfile",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile),
+        #include "pl041.hx"
+#undef REGISTER
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041_fifo = {
+    .name = "pl041_fifo",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(level, pl041_fifo),
+        VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041_channel = {
+    .name = "pl041_channel",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT(tx_fifo, pl041_channel, 0,
+                       vmstate_pl041_fifo, pl041_fifo),
+        VMSTATE_UINT8(tx_enabled, pl041_channel),
+        VMSTATE_UINT8(tx_compact_mode, pl041_channel),
+        VMSTATE_UINT8(tx_sample_size, pl041_channel),
+        VMSTATE_STRUCT(rx_fifo, pl041_channel, 0,
+                       vmstate_pl041_fifo, pl041_fifo),
+        VMSTATE_UINT8(rx_enabled, pl041_channel),
+        VMSTATE_UINT8(rx_compact_mode, pl041_channel),
+        VMSTATE_UINT8(rx_sample_size, pl041_channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041 = {
+    .name = "pl041",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(fifo_depth, pl041_state),
+        VMSTATE_STRUCT(regs, pl041_state, 0,
+                       vmstate_pl041_regfile, pl041_regfile),
+        VMSTATE_STRUCT(fifo1, pl041_state, 0,
+                       vmstate_pl041_channel, pl041_channel),
+        VMSTATE_STRUCT(codec, pl041_state, 0,
+                       vmstate_lm4549_state, lm4549_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo pl041_device_info = {
+    .init = pl041_init,
+    .qdev.name = "pl041",
+    .qdev.size = sizeof(pl041_state),
+    .qdev.vmsd = &vmstate_pl041,
+    .qdev.reset = pl041_device_reset,
+    .qdev.no_user = 1,
+    .qdev.props = (Property[]) {
+        /* Non-compact FIFO depth property */
+        DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state,
+                           fifo_depth, DEFAULT_FIFO_DEPTH),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pl041_register_device(void)
+{
+    sysbus_register_withprop(&pl041_device_info);
+}
+
+device_init(pl041_register_device)
diff --git a/hw/pl041.h b/hw/pl041.h
new file mode 100644
index 0000000..1f22432
--- /dev/null
+++ b/hw/pl041.h
@@ -0,0 +1,135 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ */
+
+#ifndef HW_PL041_H
+#define HW_PL041_H
+
+/* Register file */
+#define REGISTER(name, offset) uint32_t name;
+typedef struct {
+    #include "pl041.hx"
+} pl041_regfile;
+#undef REGISTER
+
+/* Register addresses */
+#define REGISTER(name, offset) PL041_##name = offset,
+enum {
+    #include "pl041.hx"
+
+    PL041_periphid0 = 0xFE0,
+    PL041_periphid1 = 0xFE4,
+    PL041_periphid2 = 0xFE8,
+    PL041_periphid3 = 0xFEC,
+    PL041_pcellid0  = 0xFF0,
+    PL041_pcellid1  = 0xFF4,
+    PL041_pcellid2  = 0xFF8,
+    PL041_pcellid3  = 0xFFC,
+};
+#undef REGISTER
+
+/* Register bits */
+
+/* IEx */
+#define TXCIE           (1 << 0)
+#define RXTIE           (1 << 1)
+#define TXIE            (1 << 2)
+#define RXIE            (1 << 3)
+#define RXOIE           (1 << 4)
+#define TXUIE           (1 << 5)
+#define RXTOIE          (1 << 6)
+
+/* TXCRx */
+#define TXEN            (1 << 0)
+#define TXSLOT1         (1 << 1)
+#define TXSLOT2         (1 << 2)
+#define TXSLOT3         (1 << 3)
+#define TXSLOT4         (1 << 4)
+#define TXCOMPACT       (1 << 15)
+#define TXFEN           (1 << 16)
+
+#define TXSLOT_MASK_BIT (1)
+#define TXSLOT_MASK     (0xFFF << TXSLOT_MASK_BIT)
+
+#define TSIZE_MASK_BIT  (13)
+#define TSIZE_MASK      (0x3 << TSIZE_MASK_BIT)
+
+#define TSIZE_16BITS    (0x0 << TSIZE_MASK_BIT)
+#define TSIZE_18BITS    (0x1 << TSIZE_MASK_BIT)
+#define TSIZE_20BITS    (0x2 << TSIZE_MASK_BIT)
+#define TSIZE_12BITS    (0x3 << TSIZE_MASK_BIT)
+
+/* SRx */
+#define RXFE         (1 << 0)
+#define TXFE         (1 << 1)
+#define RXHF         (1 << 2)
+#define TXHE         (1 << 3)
+#define RXFF         (1 << 4)
+#define TXFF         (1 << 5)
+#define RXBUSY       (1 << 6)
+#define TXBUSY       (1 << 7)
+#define RXOVERRUN    (1 << 8)
+#define TXUNDERRUN   (1 << 9)
+#define RXTIMEOUT    (1 << 10)
+#define RXTOFE       (1 << 11)
+
+/* ISRx */
+#define TXCINTR      (1 << 0)
+#define RXTOINTR     (1 << 1)
+#define TXINTR       (1 << 2)
+#define RXINTR       (1 << 3)
+#define ORINTR       (1 << 4)
+#define URINTR       (1 << 5)
+#define RXTOFEINTR   (1 << 6)
+
+/* SLFR */
+#define SL1RXBUSY    (1 << 0)
+#define SL1TXBUSY    (1 << 1)
+#define SL2RXBUSY    (1 << 2)
+#define SL2TXBUSY    (1 << 3)
+#define SL12RXBUSY   (1 << 4)
+#define SL12TXBUSY   (1 << 5)
+#define SL1RXVALID   (1 << 6)
+#define SL1TXEMPTY   (1 << 7)
+#define SL2RXVALID   (1 << 8)
+#define SL2TXEMPTY   (1 << 9)
+#define SL12RXVALID  (1 << 10)
+#define SL12TXEMPTY  (1 << 11)
+#define RAWGPIOINT   (1 << 12)
+#define RWIS         (1 << 13)
+
+/* MAINCR */
+#define AACIFE       (1 << 0)
+#define LOOPBACK     (1 << 1)
+#define LOWPOWER     (1 << 2)
+#define SL1RXEN      (1 << 3)
+#define SL1TXEN      (1 << 4)
+#define SL2RXEN      (1 << 5)
+#define SL2TXEN      (1 << 6)
+#define SL12RXEN     (1 << 7)
+#define SL12TXEN     (1 << 8)
+#define DMAENABLE    (1 << 9)
+
+/* INTCLR */
+#define WISC         (1 << 0)
+#define RXOEC1       (1 << 1)
+#define RXOEC2       (1 << 2)
+#define RXOEC3       (1 << 3)
+#define RXOEC4       (1 << 4)
+#define TXUEC1       (1 << 5)
+#define TXUEC2       (1 << 6)
+#define TXUEC3       (1 << 7)
+#define TXUEC4       (1 << 8)
+#define RXTOFEC1     (1 << 9)
+#define RXTOFEC2     (1 << 10)
+#define RXTOFEC3     (1 << 11)
+#define RXTOFEC4     (1 << 12)
+
+#endif /* #ifndef HW_PL041_H */
diff --git a/hw/pl041.hx b/hw/pl041.hx
new file mode 100644
index 0000000..e972996
--- /dev/null
+++ b/hw/pl041.hx
@@ -0,0 +1,81 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *****************************************************************
+ */
+
+/* PL041 register file description */
+
+REGISTER( rxcr1,   0x00 )
+REGISTER( txcr1,   0x04 )
+REGISTER( sr1,     0x08 )
+REGISTER( isr1,    0x0C )
+REGISTER( ie1,     0x10 )
+REGISTER( rxcr2,   0x14 )
+REGISTER( txcr2,   0x18 )
+REGISTER( sr2,     0x1C )
+REGISTER( isr2,    0x20 )
+REGISTER( ie2,     0x24 )
+REGISTER( rxcr3,   0x28 )
+REGISTER( txcr3,   0x2C )
+REGISTER( sr3,     0x30 )
+REGISTER( isr3,    0x34 )
+REGISTER( ie3,     0x38 )
+REGISTER( rxcr4,   0x3C )
+REGISTER( txcr4,   0x40 )
+REGISTER( sr4,     0x44 )
+REGISTER( isr4,    0x48 )
+REGISTER( ie4,     0x4C )
+REGISTER( sl1rx,   0x50 )
+REGISTER( sl1tx,   0x54 )
+REGISTER( sl2rx,   0x58 )
+REGISTER( sl2tx,   0x5C )
+REGISTER( sl12rx,  0x60 )
+REGISTER( sl12tx,  0x64 )
+REGISTER( slfr,    0x68 )
+REGISTER( slistat, 0x6C )
+REGISTER( slien,   0x70 )
+REGISTER( intclr,  0x74 )
+REGISTER( maincr,  0x78 )
+REGISTER( reset,   0x7C )
+REGISTER( sync,    0x80 )
+REGISTER( allints, 0x84 )
+REGISTER( mainfr,  0x88 )
+REGISTER( unused,  0x8C )
+REGISTER( dr1_0,   0x90 )
+REGISTER( dr1_1,   0x94 )
+REGISTER( dr1_2,   0x98 )
+REGISTER( dr1_3,   0x9C )
+REGISTER( dr1_4,   0xA0 )
+REGISTER( dr1_5,   0xA4 )
+REGISTER( dr1_6,   0xA8 )
+REGISTER( dr1_7,   0xAC )
+REGISTER( dr2_0,   0xB0 )
+REGISTER( dr2_1,   0xB4 )
+REGISTER( dr2_2,   0xB8 )
+REGISTER( dr2_3,   0xBC )
+REGISTER( dr2_4,   0xC0 )
+REGISTER( dr2_5,   0xC4 )
+REGISTER( dr2_6,   0xC8 )
+REGISTER( dr2_7,   0xCC )
+REGISTER( dr3_0,   0xD0 )
+REGISTER( dr3_1,   0xD4 )
+REGISTER( dr3_2,   0xD8 )
+REGISTER( dr3_3,   0xDC )
+REGISTER( dr3_4,   0xE0 )
+REGISTER( dr3_5,   0xE4 )
+REGISTER( dr3_6,   0xE8 )
+REGISTER( dr3_7,   0xEC )
+REGISTER( dr4_0,   0xF0 )
+REGISTER( dr4_1,   0xF4 )
+REGISTER( dr4_2,   0xF8 )
+REGISTER( dr4_3,   0xFC )
+REGISTER( dr4_4,   0x100 )
+REGISTER( dr4_5,   0x104 )
+REGISTER( dr4_6,   0x108 )
+REGISTER( dr4_7,   0x10C )
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 68402cc..6370600 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -182,6 +182,7 @@ static void versatile_init(ram_addr_t ram_size,
     qemu_irq sic[32];
     DeviceState *dev, *sysctl;
     SysBusDevice *busdev;
+    DeviceState *pl041;
     PCIBus *pci_bus;
     NICInfo *nd;
     int n;
@@ -273,6 +274,13 @@ static void versatile_init(ram_addr_t ram_size,
     /* Add PL031 Real Time Clock. */
     sysbus_create_simple("pl031", 0x101e8000, pic[10]);
 
+    /* Add PL041 AACI Interface to the LM4549 codec */
+    pl041 = qdev_create(NULL, "pl041");
+    qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
+    qdev_init_nofail(pl041);
+    sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000);
+    sysbus_connect_irq(sysbus_from_qdev(pl041), 0, sic[24]);
+
     /* Memory map for Versatile/PB:  */
     /* 0x10000000 System registers.  */
     /* 0x10001000 PCI controller config registers.  */
commit 375847a6c0330e3de0fd1589eeb5a364692b791e
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Fri Oct 28 02:11:05 2011 +0400

    MAINTAINERS: update wiki URL and machine names for target-xtensa
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 2b4c5d7..4535eeb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -118,7 +118,7 @@ F: target-i386/
 
 Xtensa
 M: Max Filippov <jcmvbkbc at gmail.com>
-W: http://kkv.spb.su/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
+W: http://wiki.osll.spb.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
 S: Maintained
 F: target-xtensa/
 
@@ -348,10 +348,15 @@ F: hw/pc.[ch] hw/pc_piix.c
 
 Xtensa Machines
 ---------------
-DC232B
+sim
 M: Max Filippov <jcmvbkbc at gmail.com>
 S: Maintained
-F: hw/xtensa_dc232b.c
+F: hw/xtensa_sim.c
+
+Avnet LX60
+M: Max Filippov <jcmvbkbc at gmail.com>
+S: Maintained
+F: hw/xtensa_lx60.c
 
 Devices
 -------
commit df072774cb0175c1ae93af18c6e1f54624831b7e
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Oct 27 14:15:00 2011 -0700

    tcg: Optimize some forms of deposit.
    
    If the deposit replaces the entire word, optimize to a move.
    
    If we're inserting to the top of the word, avoid the mask of arg2
    as we'll be shifting out all of the garbage and shifting in zeros.
    
    If the host is 32-bit, reduce a 64-bit deposit to a 32-bit deposit
    when possible.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index fea5983..24ec7fc 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -2045,38 +2045,75 @@ static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1,
 				       TCGv_i32 arg2, unsigned int ofs,
 				       unsigned int len)
 {
+    uint32_t mask;
+    TCGv_i32 t1;
+
+    if (ofs == 0 && len == 32) {
+        tcg_gen_mov_i32(ret, arg2);
+        return;
+    }
     if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) {
         tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
-    } else {
-        uint32_t mask = (1u << len) - 1;
-        TCGv_i32 t1 = tcg_temp_new_i32 ();
+        return;
+    }
+
+    mask = (1u << len) - 1;
+    t1 = tcg_temp_new_i32();
 
+    if (ofs + len < 32) {
         tcg_gen_andi_i32(t1, arg2, mask);
         tcg_gen_shli_i32(t1, t1, ofs);
-        tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
-        tcg_gen_or_i32(ret, ret, t1);
-
-        tcg_temp_free_i32(t1);
+    } else {
+        tcg_gen_shli_i32(t1, arg2, ofs);
     }
+    tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
+    tcg_gen_or_i32(ret, ret, t1);
+
+    tcg_temp_free_i32(t1);
 }
 
 static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
 				       TCGv_i64 arg2, unsigned int ofs,
 				       unsigned int len)
 {
+    uint64_t mask;
+    TCGv_i64 t1;
+
+    if (ofs == 0 && len == 64) {
+        tcg_gen_mov_i64(ret, arg2);
+        return;
+    }
     if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) {
         tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
-    } else {
-        uint64_t mask = (1ull << len) - 1;
-        TCGv_i64 t1 = tcg_temp_new_i64 ();
+        return;
+    }
 
+#if TCG_TARGET_REG_BITS == 32
+    if (ofs >= 32) {
+        tcg_gen_deposit_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1),
+                            TCGV_LOW(arg2), ofs - 32, len);
+        return;
+    }
+    if (ofs + len <= 32) {
+        tcg_gen_deposit_i32(TCGV_LOW(ret), TCGV_LOW(arg1),
+                            TCGV_LOW(arg2), ofs, len);
+        return;
+    }
+#endif
+
+    mask = (1ull << len) - 1;
+    t1 = tcg_temp_new_i64();
+
+    if (ofs + len < 64) {
         tcg_gen_andi_i64(t1, arg2, mask);
         tcg_gen_shli_i64(t1, t1, ofs);
-        tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
-        tcg_gen_or_i64(ret, ret, t1);
-
-        tcg_temp_free_i64(t1);
+    } else {
+        tcg_gen_shli_i64(t1, arg2, ofs);
     }
+    tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
+    tcg_gen_or_i64(ret, ret, t1);
+
+    tcg_temp_free_i64(t1);
 }
 
 /***************************************/
commit 7999f7e1273b63ec3a60d8cf2cb79cb88575744a
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Mon Oct 24 15:09:49 2011 +0530

    hw/9pfs: Make VirtFS tracing work correctly
    
    this patch fix multiple issues with VirtFS tracing.
    a) Add tracepoint to the correct code path. We handle error in complete_pdu
    b) Fix indentation in python script
    c) Fix variable naming issue in python script
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index aab3beb..8b6813f 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -969,7 +969,7 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
         if (s->proto_version == V9FS_PROTO_2000L) {
             id = P9_RLERROR;
         }
-        trace_complete_pdu(pdu->tag, pdu->id, err); /* Trace ERROR */
+        trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
     }
 
     /* fill out the header */
@@ -1332,11 +1332,11 @@ static void v9fs_attach(void *opaque)
     }
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
+    trace_v9fs_attach_return(pdu->tag, pdu->id,
+                             qid.type, qid.version, qid.path);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_attach_return(pdu->tag, pdu->id,
-                             qid.type, qid.version, qid.path);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&uname);
     v9fs_string_free(&aname);
@@ -1371,13 +1371,12 @@ static void v9fs_stat(void *opaque)
     }
     offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
     err = offset;
+    trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
+                           v9stat.atime, v9stat.mtime, v9stat.length);
     v9fs_stat_free(&v9stat);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
-                           v9stat.atime, v9stat.mtime, v9stat.length);
-
     complete_pdu(s, pdu, err);
 }
 
@@ -1421,13 +1420,12 @@ static void v9fs_getattr(void *opaque)
     }
     retval = offset;
     retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
-out:
-    put_fid(pdu, fidp);
-out_nofid:
     trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
                               v9stat_dotl.st_mode, v9stat_dotl.st_uid,
                               v9stat_dotl.st_gid);
-
+out:
+    put_fid(pdu, fidp);
+out_nofid:
     complete_pdu(s, pdu, retval);
 }
 
@@ -1605,6 +1603,7 @@ static void v9fs_walk(void *opaque)
         v9fs_path_copy(&newfidp->path, &path);
     }
     err = v9fs_walk_marshal(pdu, nwnames, qids);
+    trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
 out:
     put_fid(pdu, fidp);
     if (newfidp) {
@@ -1613,7 +1612,6 @@ out:
     v9fs_path_free(&dpath);
     v9fs_path_free(&path);
 out_nofid:
-    trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
     complete_pdu(s, pdu, err);
     if (nwnames && nwnames <= P9_MAXWELEM) {
         for (name_idx = 0; name_idx < nwnames; name_idx++) {
@@ -1648,10 +1646,10 @@ static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
 static void v9fs_open(void *opaque)
 {
     int flags;
-    int iounit;
     int32_t fid;
     int32_t mode;
     V9fsQID qid;
+    int iounit = 0;
     ssize_t err = 0;
     size_t offset = 7;
     struct stat stbuf;
@@ -1709,11 +1707,11 @@ static void v9fs_open(void *opaque)
         offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
         err = offset;
     }
+    trace_v9fs_open_return(pdu->tag, pdu->id,
+                           qid.type, qid.version, qid.path, iounit);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_open_return(pdu->tag, pdu->id,
-                           qid.type, qid.version, qid.path, iounit);
     complete_pdu(s, pdu, err);
 }
 
@@ -1759,11 +1757,11 @@ static void v9fs_lcreate(void *opaque)
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
+    trace_v9fs_lcreate_return(pdu->tag, pdu->id,
+                              qid.type, qid.version, qid.path, iounit);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_lcreate_return(pdu->tag, pdu->id,
-                              qid.type, qid.version, qid.path, iounit);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -1978,10 +1976,10 @@ static void v9fs_read(void *opaque)
     } else {
         err = -EINVAL;
     }
+    trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
     complete_pdu(s, pdu, err);
 }
 
@@ -2090,10 +2088,10 @@ static void v9fs_readdir(void *opaque)
     retval = offset;
     retval += pdu_marshal(pdu, offset, "d", count);
     retval += count;
+    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
     complete_pdu(s, pdu, retval);
 }
 
@@ -2202,10 +2200,10 @@ static void v9fs_write(void *opaque)
     } while (total < count && len > 0);
     offset += pdu_marshal(pdu, offset, "d", total);
     err = offset;
+    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
     complete_pdu(s, pdu, err);
 }
 
@@ -2362,11 +2360,11 @@ static void v9fs_create(void *opaque)
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
+    trace_v9fs_create_return(pdu->tag, pdu->id,
+                             qid.type, qid.version, qid.path, iounit);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-   trace_v9fs_create_return(pdu->tag, pdu->id,
-                            qid.type, qid.version, qid.path, iounit);
    complete_pdu(pdu->s, pdu, err);
    v9fs_string_free(&name);
    v9fs_string_free(&extension);
@@ -2401,11 +2399,11 @@ static void v9fs_symlink(void *opaque)
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
+    trace_v9fs_symlink_return(pdu->tag, pdu->id,
+                              qid.type, qid.version, qid.path);
 out:
     put_fid(pdu, dfidp);
 out_nofid:
-    trace_v9fs_symlink_return(pdu->tag, pdu->id,
-                              qid.type, qid.version, qid.path);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
     v9fs_string_free(&symname);
@@ -2950,10 +2948,11 @@ static void v9fs_mknod(void *opaque)
     stat_to_qid(&stbuf, &qid);
     err = offset;
     err += pdu_marshal(pdu, offset, "Q", &qid);
+    trace_v9fs_mknod_return(pdu->tag, pdu->id,
+                            qid.type, qid.version, qid.path);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_mknod_return(pdu->tag, pdu->id, qid.type, qid.version, qid.path);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -3049,12 +3048,11 @@ static void v9fs_getlock(void *opaque)
                           glock->start, glock->length, glock->proc_id,
                           &glock->client_id);
     err = offset;
+    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
+                              glock->length, glock->proc_id);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
-                              glock->length, glock->proc_id);
-
     complete_pdu(s, pdu, err);
     v9fs_string_free(&glock->client_id);
     g_free(glock);
@@ -3089,11 +3087,11 @@ static void v9fs_mkdir(void *opaque)
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
+    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
+                            qid.type, qid.version, qid.path, err);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
-                            qid.type, qid.version, qid.path, err);
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -3183,13 +3181,13 @@ static void v9fs_xattrwalk(void *opaque)
         offset += pdu_marshal(pdu, offset, "q", size);
         err = offset;
     }
+    trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
 out:
     put_fid(pdu, file_fidp);
     if (xattr_fidp) {
         put_fid(pdu, xattr_fidp);
     }
 out_nofid:
-    trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -3260,11 +3258,11 @@ static void v9fs_readlink(void *opaque)
     }
     offset += pdu_marshal(pdu, offset, "s", &target);
     err = offset;
+    trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
     v9fs_string_free(&target);
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
     complete_pdu(pdu->s, pdu, err);
 }
 
diff --git a/scripts/analyse-9p-simpletrace.py b/scripts/analyse-9p-simpletrace.py
index 4358d6b..b6d58fd 100755
--- a/scripts/analyse-9p-simpletrace.py
+++ b/scripts/analyse-9p-simpletrace.py
@@ -7,11 +7,11 @@
 import simpletrace
 
 class VirtFSRequestTracker(simpletrace.Analyzer):
-	def begin(self):
-		print "Pretty printing 9p simpletrace log ..."
+        def begin(self):
+                print "Pretty printing 9p simpletrace log ..."
 
-        def complete_pdu(self, tag, id, err):
-                print "ERROR (tag =", tag, ", id =", id, ",err =", err, ")"
+        def v9fs_rerror(self, tag, id, err):
+                print "RERROR (tag =", tag, ", id =", id, ",err =", err, ")"
 
         def v9fs_version(self, tag, id, msize, version):
                 print "TVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")"
@@ -22,121 +22,121 @@ class VirtFSRequestTracker(simpletrace.Analyzer):
         def v9fs_attach(self, tag, id, fid, afid, uname, aname):
                 print "TATTACH (tag =", tag, ", fid =", fid, ", afid =", afid, ", uname =", uname, ", aname =", aname, ")"
 
-	def v9fs_attach_return(self, tag, id, type, verison, path):
-		print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})"
+        def v9fs_attach_return(self, tag, id, type, version, path):
+                print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})"
 
-	def v9fs_stat(self, tag, id, fid):
-		print "TSTAT (tag =", tag, ", fid =", fid, ")"
+        def v9fs_stat(self, tag, id, fid):
+                print "TSTAT (tag =", tag, ", fid =", fid, ")"
 
-	def v9fs_stat_return(self, tag, id, mode, atime, mtime, length):
-		print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")"
+        def v9fs_stat_return(self, tag, id, mode, atime, mtime, length):
+                print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")"
 
-	def v9fs_getattr(self, tag, id, fid, request_mask):
-		print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")"
+        def v9fs_getattr(self, tag, id, fid, request_mask):
+                print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")"
 
-	def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid):
-		print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")"
+        def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid):
+                print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")"
 
-	def v9fs_walk(self, tag, id, fid, newfid, nwnames):
-		print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")"
+        def v9fs_walk(self, tag, id, fid, newfid, nwnames):
+                print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")"
 
-	def v9fs_walk_return(self, tag, id, nwnames, qids):
-		print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")"
+        def v9fs_walk_return(self, tag, id, nwnames, qids):
+                print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")"
 
-	def v9fs_open(self, tag, id, fid, mode):
-		print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")"
+        def v9fs_open(self, tag, id, fid, mode):
+                print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")"
 
-	def v9fs_open_return(self, tag, id, type, version, path, iounit):
-		print "ROPEN (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+        def v9fs_open_return(self, tag, id, type, version, path, iounit):
+                print "ROPEN (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
 
-	def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid):
-		print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")"
+        def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid):
+                print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")"
 
-	def v9fs_lcreate_return(self, id, type, version, path, iounit):
-		print "RLCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+        def v9fs_lcreate_return(self, tag, id, type, version, path, iounit):
+                print "RLCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
 
-	def v9fs_fsync(self, tag, id, fid, datasync):
-		print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")"
+        def v9fs_fsync(self, tag, id, fid, datasync):
+                print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")"
 
-	def v9fs_clunk(self, tag, id, fid):
-		print "TCLUNK (tag =", tag, ", fid =", fid, ")"
+        def v9fs_clunk(self, tag, id, fid):
+                print "TCLUNK (tag =", tag, ", fid =", fid, ")"
 
-	def v9fs_read(self, tag, id, fid, off, max_count):
-		print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")"
+        def v9fs_read(self, tag, id, fid, off, max_count):
+                print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")"
 
-	def v9fs_read_return(self, tag, id, count, err):
-		print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")"
+        def v9fs_read_return(self, tag, id, count, err):
+                print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")"
 
-	def v9fs_readdir(self, tag, id, fid, offset, max_count):
-		print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")"
+        def v9fs_readdir(self, tag, id, fid, offset, max_count):
+                print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")"
 
-	def v9fs_readdir_return(self, tag, id, count, retval):
-		print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")"
+        def v9fs_readdir_return(self, tag, id, count, retval):
+                print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")"
 
-	def v9fs_write(self, tag, id, fid, off, count, cnt):
-		print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")"
+        def v9fs_write(self, tag, id, fid, off, count, cnt):
+                print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")"
 
-	def v9fs_write_return(self, tag, id, total, err):
-		print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")"
+        def v9fs_write_return(self, tag, id, total, err):
+                print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")"
 
-	def v9fs_create(self, tag, id, fid, perm, name, mode):
-		print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")"
+        def v9fs_create(self, tag, id, fid, name, perm, mode):
+                print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")"
 
-	def v9fs_create_return(self, tag, id, type, verison, path, iounit):
-		print "RCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
+        def v9fs_create_return(self, tag, id, type, version, path, iounit):
+                print "RCREATE (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")"
 
-	def v9fs_symlink(self, tag, id, fid, name, symname, gid):
-		print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")"
+        def v9fs_symlink(self, tag, id, fid, name, symname, gid):
+                print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")"
 
-	def v9fs_symlink_return(self, tag, id, type, version, path):
-		print "RSYMLINK (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "})"
+        def v9fs_symlink_return(self, tag, id, type, version, path):
+                print "RSYMLINK (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "})"
 
-	def v9fs_flush(self, tag, id, flush_tag):
-		print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")"
+        def v9fs_flush(self, tag, id, flush_tag):
+                print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")"
 
-	def v9fs_link(self, tag, id, dfid, oldfid, name):
-		print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")"
+        def v9fs_link(self, tag, id, dfid, oldfid, name):
+                print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")"
 
-	def v9fs_remove(self, tag, id, fid):
-		print "TREMOVE (tag =", tag, ", fid =", fid, ")"
+        def v9fs_remove(self, tag, id, fid):
+                print "TREMOVE (tag =", tag, ", fid =", fid, ")"
 
-	def v9fs_wstat(self, tag, id, fid, mode, atime, mtime):
-		print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")"
+        def v9fs_wstat(self, tag, id, fid, mode, atime, mtime):
+                print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")"
 
-	def v9fs_mknod(self, tag, id, fid, mode, major, minor):
-		print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")"
+        def v9fs_mknod(self, tag, id, fid, mode, major, minor):
+                print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")"
 
-	def v9fs_lock(self, tag, id, fid, type, start, length):
-		print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
+        def v9fs_lock(self, tag, id, fid, type, start, length):
+                print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
 
-	def v9fs_lock_return(self, tag, id, status):
-		print "RLOCK (tag =", tag, ", status =", status, ")"
+        def v9fs_lock_return(self, tag, id, status):
+                print "RLOCK (tag =", tag, ", status =", status, ")"
 
-	def v9fs_getlock(self, tag, id, fid, type, start, length):
-		print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
+        def v9fs_getlock(self, tag, id, fid, type, start, length):
+                print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")"
 
-	def v9fs_getlock_return(self, tag, id, type, start, length, proc_id):
-		print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id,  ")"
+        def v9fs_getlock_return(self, tag, id, type, start, length, proc_id):
+                print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id,  ")"
 
-	def v9fs_mkdir(self, tag, id, fid, name, mode, gid):
-		print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")"
+        def v9fs_mkdir(self, tag, id, fid, name, mode, gid):
+                print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")"
 
-	def v9fs_mkdir_return(self, tag, id, type, version, path, err):
-		print "RMKDIR (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")"
+        def v9fs_mkdir_return(self, tag, id, type, version, path, err):
+                print "RMKDIR (tag =", tag,  ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")"
 
-	def v9fs_xattrwalk(self, tag, id, fid, newfid, name):
-		print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")"
+        def v9fs_xattrwalk(self, tag, id, fid, newfid, name):
+                print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")"
 
-	def v9fs_xattrwalk_return(self, tag, id, size):
-		print "RXATTRWALK (tag =", tag, ", xattrsize  =", size, ")"
+        def v9fs_xattrwalk_return(self, tag, id, size):
+                print "RXATTRWALK (tag =", tag, ", xattrsize  =", size, ")"
 
-	def v9fs_xattrcreate(self, tag, id, fid, name, size, flags):
-		print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")"
+        def v9fs_xattrcreate(self, tag, id, fid, name, size, flags):
+                print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")"
 
-	def v9fs_readlink(self, tag, id, fid):
-		print "TREADLINK (tag =", tag, ", fid =", fid, ")"
+        def v9fs_readlink(self, tag, id, fid):
+                print "TREADLINK (tag =", tag, ", fid =", fid, ")"
 
-	def v9fs_readlink_return(self, tag, id, target):
-		print "RREADLINK (tag =", tag, ", target =", target, ")"
+        def v9fs_readlink_return(self, tag, id, target):
+                print "RREADLINK (tag =", tag, ", target =", target, ")"
 
 simpletrace.run(VirtFSRequestTracker())
diff --git a/trace-events b/trace-events
index 820b1d6..7d05c82 100644
--- a/trace-events
+++ b/trace-events
@@ -555,7 +555,7 @@ open_eth_desc_read(uint32_t addr, uint32_t v) "DESC[%04x] -> %08x"
 open_eth_desc_write(uint32_t addr, uint32_t v) "DESC[%04x] <- %08x"
 
 # hw/9pfs/virtio-9p.c
-complete_pdu(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d"
+v9fs_rerror(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d"
 v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
 v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
 v9fs_attach(uint16_t tag, uint8_t id, int32_t fid, int32_t afid, char* uname, char* aname) "tag %u id %u fid %d afid %d uname %s aname %s"
commit c2f36c6ce777c461faffa904aabaeb56e6458b9e
Author: Stefan Weil <sw at weilnetz.de>
Date:   Sun Oct 23 08:19:10 2011 +0200

    exec-all: Fix void pointer arithmetic
    
    Adding an offset to a void pointer works with gcc but is not allowed
    by the current C standards. With -pedantic, gcc complains:
    
    exec-all.h:344: error: pointer of type ‘void *’ used in arithmetic
    
    Fix this, and also replace (unsigned long) by (uintptr_t) in the same
    statement.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/exec-all.h b/exec-all.h
index 72ef246..85a37bf 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -340,8 +340,7 @@ static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add
         cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
 #endif
     }
-    p = (void *)(unsigned long)addr
-        + env1->tlb_table[mmu_idx][page_index].addend;
+    p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);
     return qemu_ram_addr_from_host_nofail(p);
 }
 #endif
commit d787fcf45f193d3f439ee431f82b7a075c9f5784
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Thu Oct 20 11:41:01 2011 +1100

    Add linux-headers/asm to .gitignore
    
    linux-headers/asm is a symlink generated during configure.  It should not,
    therefore be committed to git, nor show up in git diffs and the like.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Reviewed-by: Juan Quintela <quintela at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/.gitignore b/.gitignore
index 59c343c..6d2acab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@ libdis*
 libhw32
 libhw64
 libuser
+linux-headers/asm
 qapi-generated
 qemu-doc.html
 qemu-tech.html
commit 336a6915bc7089fb20fea4ba99972ad9a97c5f52
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Oct 25 12:53:37 2011 +0200

    scsi-disk: add scsi-block for device passthrough
    
    scsi-block is a new device that supports device passthrough of Linux
    block devices (i.e. /dev/sda, not /dev/sg0).  It uses SG_IO for commands
    other than I/O commands, and regular AIO read/writes for I/O commands.
    Besides being simpler to configure (no mapping required to scsi-generic
    device names), this removes the need for a large bounce buffer and,
    in the future, will get scatter/gather support for free from scsi-disk.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 352d41f..1c04872 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -39,6 +39,10 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "blockdev.h"
 #include "block_int.h"
 
+#ifdef __linux
+#include <scsi/sg.h>
+#endif
+
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
 
@@ -1588,6 +1592,105 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
     return req;
 }
 
+#ifdef __linux__
+static int get_device_type(SCSIDiskState *s)
+{
+    BlockDriverState *bdrv = s->qdev.conf.bs;
+    uint8_t cmd[16];
+    uint8_t buf[36];
+    uint8_t sensebuf[8];
+    sg_io_hdr_t io_header;
+    int ret;
+
+    memset(cmd, 0, sizeof(cmd));
+    memset(buf, 0, sizeof(buf));
+    cmd[0] = INQUIRY;
+    cmd[4] = sizeof(buf);
+
+    memset(&io_header, 0, sizeof(io_header));
+    io_header.interface_id = 'S';
+    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+    io_header.dxfer_len = sizeof(buf);
+    io_header.dxferp = buf;
+    io_header.cmdp = cmd;
+    io_header.cmd_len = sizeof(cmd);
+    io_header.mx_sb_len = sizeof(sensebuf);
+    io_header.sbp = sensebuf;
+    io_header.timeout = 6000; /* XXX */
+
+    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
+    if (ret < 0 || io_header.driver_status || io_header.host_status) {
+        return -1;
+    }
+    s->qdev.type = buf[0];
+    s->removable = (buf[1] & 0x80) != 0;
+    return 0;
+}
+
+static int scsi_block_initfn(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    int sg_version;
+    int rc;
+
+    if (!s->qdev.conf.bs) {
+        error_report("scsi-block: drive property not set");
+        return -1;
+    }
+
+    /* check we are using a driver managing SG_IO (version 3 and after) */
+    if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+        sg_version < 30000) {
+        error_report("scsi-block: scsi generic interface too old");
+        return -1;
+    }
+
+    /* get device type from INQUIRY data */
+    rc = get_device_type(s);
+    if (rc < 0) {
+        error_report("scsi-block: INQUIRY failed");
+        return -1;
+    }
+
+    /* Make a guess for the block size, we'll fix it when the guest sends.
+     * READ CAPACITY.  If they don't, they likely would assume these sizes
+     * anyway. (TODO: check in /sys).
+     */
+    if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) {
+        s->qdev.blocksize = 2048;
+    } else {
+        s->qdev.blocksize = 512;
+    }
+    return scsi_initfn(&s->qdev);
+}
+
+static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
+                                           uint32_t lun, uint8_t *buf,
+                                           void *hba_private)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+
+    switch (buf[0]) {
+    case READ_6:
+    case READ_10:
+    case READ_12:
+    case READ_16:
+    case WRITE_6:
+    case WRITE_10:
+    case WRITE_12:
+    case WRITE_16:
+    case WRITE_VERIFY_10:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
+                              hba_private);
+    }
+
+    return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
+                          hba_private);
+}
+#endif
+
 #define DEFINE_SCSI_DISK_PROPERTIES()                           \
     DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),          \
     DEFINE_PROP_STRING("ver",  SCSIDiskState, version),         \
@@ -1623,6 +1726,21 @@ static SCSIDeviceInfo scsi_disk_info[] = {
             DEFINE_SCSI_DISK_PROPERTIES(),
             DEFINE_PROP_END_OF_LIST(),
         },
+#ifdef __linux__
+    },{
+        .qdev.name    = "scsi-block",
+        .qdev.fw_name = "disk",
+        .qdev.desc    = "SCSI block device passthrough",
+        .qdev.size    = sizeof(SCSIDiskState),
+        .qdev.reset   = scsi_disk_reset,
+        .init         = scsi_block_initfn,
+        .destroy      = scsi_destroy,
+        .alloc_req    = scsi_block_new_request,
+        .qdev.props   = (Property[]) {
+            DEFINE_SCSI_DISK_PROPERTIES(),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+#endif
     },{
         .qdev.name    = "scsi-disk", /* legacy -device scsi-disk */
         .qdev.fw_name = "disk",
commit 71544d30a6f8b91574552a61cd5bd122a77e82d1
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Oct 25 12:53:36 2011 +0200

    scsi: push request restart to SCSIDevice
    
    The request restart mechanism is generic and could be reused for
    scsi-generic.  In the meanwhile, pushing it to SCSIDevice avoids
    that scsi_dma_restart_bh looks at SCSIGenericReqs when working on
    a scsi-block device.
    
    The code is the same that is already in hw/scsi-disk.c, with
    the type flags replaced by req->cmd.mode and a more generic way to
    requeue SCSI_XFER_NONE commands.
    
    I also added a missing call to qemu_del_vm_change_state_handler.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index dfce5fb..e6ebbd5 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -8,6 +8,7 @@
 
 static char *scsibus_get_fw_dev_path(DeviceState *dev);
 static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
+static void scsi_req_dequeue(SCSIRequest *req);
 static int scsi_build_sense(uint8_t *in_buf, int in_len,
                             uint8_t *buf, int len, bool fixed);
 
@@ -33,6 +34,53 @@ void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
     bus->qbus.allow_hotplug = 1;
 }
 
+static void scsi_dma_restart_bh(void *opaque)
+{
+    SCSIDevice *s = opaque;
+    SCSIRequest *req, *next;
+
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+
+    QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
+        scsi_req_ref(req);
+        if (req->retry) {
+            req->retry = false;
+            switch (req->cmd.mode) {
+            case SCSI_XFER_FROM_DEV:
+            case SCSI_XFER_TO_DEV:
+                scsi_req_continue(req);
+                break;
+            case SCSI_XFER_NONE:
+                scsi_req_dequeue(req);
+                scsi_req_enqueue(req);
+                break;
+            }
+        }
+        scsi_req_unref(req);
+    }
+}
+
+void scsi_req_retry(SCSIRequest *req)
+{
+    /* No need to save a reference, because scsi_dma_restart_bh just
+     * looks at the request list.  */
+    req->retry = true;
+}
+
+static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
+{
+    SCSIDevice *s = opaque;
+
+    if (!running) {
+        return;
+    }
+    if (!s->bh) {
+        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
+        qemu_bh_schedule(s->bh);
+    }
+}
+
 static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
@@ -83,6 +131,10 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
     dev->info = info;
     QTAILQ_INIT(&dev->requests);
     rc = dev->info->init(dev);
+    if (rc == 0) {
+        dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
+                                                         dev);
+    }
 
 err:
     return rc;
@@ -92,6 +144,9 @@ static int scsi_qdev_exit(DeviceState *qdev)
 {
     SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
 
+    if (dev->vmsentry) {
+        qemu_del_vm_change_state_handler(dev->vmsentry);
+    }
     if (dev->info->destroy) {
         dev->info->destroy(dev);
     }
@@ -586,6 +641,7 @@ int32_t scsi_req_enqueue(SCSIRequest *req)
 static void scsi_req_dequeue(SCSIRequest *req)
 {
     trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
+    req->retry = false;
     if (req->enqueued) {
         QTAILQ_REMOVE(&req->dev->requests, req, next);
         req->enqueued = false;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index bb07737..352d41f 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -42,12 +42,6 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
 
-#define SCSI_REQ_STATUS_RETRY           0x01
-#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
-#define SCSI_REQ_STATUS_RETRY_READ      0x00
-#define SCSI_REQ_STATUS_RETRY_WRITE     0x02
-#define SCSI_REQ_STATUS_RETRY_FLUSH     0x04
-
 typedef struct SCSIDiskState SCSIDiskState;
 
 typedef struct SCSIDiskReq {
@@ -58,7 +52,6 @@ typedef struct SCSIDiskReq {
     uint32_t buflen;
     struct iovec iov;
     QEMUIOVector qiov;
-    uint32_t status;
     BlockAcctCookie acct;
 } SCSIDiskReq;
 
@@ -75,8 +68,7 @@ struct SCSIDiskState
     bool tray_locked;
 };
 
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
-static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf);
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error);
 
 static void scsi_free_request(SCSIRequest *req)
 {
@@ -102,7 +94,6 @@ static void scsi_cancel_io(SCSIRequest *req)
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
 
     DPRINTF("Cancel tag=0x%x\n", req->tag);
-    r->status &= ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
     if (r->req.aiocb) {
         bdrv_aio_cancel(r->req.aiocb);
 
@@ -139,7 +130,7 @@ static void scsi_read_complete(void * opaque, int ret)
     }
 
     if (ret) {
-        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
+        if (scsi_handle_rw_error(r, -ret)) {
             goto done;
         }
     }
@@ -168,7 +159,7 @@ static void scsi_flush_complete(void * opaque, int ret)
     }
 
     if (ret < 0) {
-        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
+        if (scsi_handle_rw_error(r, -ret)) {
             goto done;
         }
     }
@@ -233,9 +224,9 @@ static void scsi_read_data(SCSIRequest *req)
  * scsi_handle_rw_error always manages its reference counts, independent
  * of the return value.
  */
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
 {
-    int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
+    int is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     BlockErrorAction action = bdrv_get_on_error(s->qdev.conf.bs, is_read);
 
@@ -247,17 +238,10 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
     if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
             || action == BLOCK_ERR_STOP_ANY) {
 
-        type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
-        r->status |= SCSI_REQ_STATUS_RETRY | type;
-
         bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
         vm_stop(RUN_STATE_IO_ERROR);
         bdrv_iostatus_set_err(s->qdev.conf.bs, error);
-
-        /* No need to save a reference, because scsi_dma_restart_bh just
-         * looks at the request list.  If a request is canceled, the
-         * retry request is just dropped.
-         */
+        scsi_req_retry(&r->req);
     } else {
         switch (error) {
         case ENOMEDIUM:
@@ -290,7 +274,7 @@ static void scsi_write_complete(void * opaque, int ret)
     }
 
     if (ret) {
-        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
+        if (scsi_handle_rw_error(r, -ret)) {
             goto done;
         }
     }
@@ -347,51 +331,6 @@ static void scsi_write_data(SCSIRequest *req)
     }
 }
 
-static void scsi_dma_restart_bh(void *opaque)
-{
-    SCSIDiskState *s = opaque;
-    SCSIRequest *req;
-    SCSIDiskReq *r;
-
-    qemu_bh_delete(s->bh);
-    s->bh = NULL;
-
-    QTAILQ_FOREACH(req, &s->qdev.requests, next) {
-        r = DO_UPCAST(SCSIDiskReq, req, req);
-        if (r->status & SCSI_REQ_STATUS_RETRY) {
-            int status = r->status;
-
-            r->status &=
-                ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
-
-            switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
-            case SCSI_REQ_STATUS_RETRY_READ:
-                scsi_read_data(&r->req);
-                break;
-            case SCSI_REQ_STATUS_RETRY_WRITE:
-                scsi_write_data(&r->req);
-                break;
-            case SCSI_REQ_STATUS_RETRY_FLUSH:
-                scsi_send_command(&r->req, r->req.cmd.buf);
-                break;
-            }
-        }
-    }
-}
-
-static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
-{
-    SCSIDiskState *s = opaque;
-
-    if (!running) {
-        return;
-    }
-    if (!s->bh) {
-        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
-        qemu_bh_schedule(s->bh);
-    }
-}
-
 /* Return a pointer to the data buffer.  */
 static uint8_t *scsi_get_buf(SCSIRequest *req)
 {
@@ -1591,7 +1530,6 @@ static int scsi_initfn(SCSIDevice *dev)
     }
     bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
 
-    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
     bdrv_iostatus_enable(s->qdev.conf.bs);
     add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
     return 0;
diff --git a/hw/scsi.h b/hw/scsi.h
index fcc3455..ff8fdd0 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,6 +3,7 @@
 
 #include "qdev.h"
 #include "block.h"
+#include "sysemu.h"
 
 #define MAX_SCSI_DEVS	255
 
@@ -52,6 +53,7 @@ struct SCSIRequest {
     uint32_t sense_len;
     bool enqueued;
     bool io_canceled;
+    bool retry;
     void *hba_private;
     QTAILQ_ENTRY(SCSIRequest) next;
 };
@@ -59,6 +61,8 @@ struct SCSIRequest {
 struct SCSIDevice
 {
     DeviceState qdev;
+    VMChangeStateEntry *vmsentry;
+    QEMUBH *bh;
     uint32_t id;
     BlockConf conf;
     SCSIDeviceInfo *info;
@@ -194,6 +198,7 @@ uint8_t *scsi_req_get_buf(SCSIRequest *req);
 int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
 void scsi_req_abort(SCSIRequest *req, int status);
 void scsi_req_cancel(SCSIRequest *req);
+void scsi_req_retry(SCSIRequest *req);
 void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
 int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
 SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
commit c9501c951c3dbe007dfba9328156be2d931f6d94
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Oct 25 12:53:35 2011 +0200

    scsi-generic: bump SCSIRequest reference count until aio completion runs
    
    Same as before, but for scsi-generic.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 2f95f2d..9594cc1 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -113,6 +113,9 @@ static void scsi_command_complete(void *opaque, int ret)
             r, r->req.tag, status);
 
     scsi_req_complete(&r->req, status);
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
 }
 
 /* Cancel a pending data transfer.  */
@@ -123,6 +126,11 @@ static void scsi_cancel_io(SCSIRequest *req)
     DPRINTF("Cancel tag=0x%x\n", req->tag);
     if (r->req.aiocb) {
         bdrv_aio_cancel(r->req.aiocb);
+
+        /* This reference was left in by scsi_*_data.  We take ownership of
+         * it independent of whether bdrv_aio_cancel completes the request
+         * or not.  */
+        scsi_req_unref(&r->req);
     }
     r->req.aiocb = NULL;
 }
@@ -183,6 +191,9 @@ static void scsi_read_complete(void * opaque, int ret)
         bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
 
         scsi_req_data(&r->req, len);
+        if (!r->req.io_canceled) {
+            scsi_req_unref(&r->req);
+        }
     }
 }
 
@@ -194,6 +205,9 @@ static void scsi_read_data(SCSIRequest *req)
     int ret;
 
     DPRINTF("scsi_read_data 0x%x\n", req->tag);
+
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
     if (r->len == -1) {
         scsi_command_complete(r, 0);
         return;
@@ -242,6 +256,8 @@ static void scsi_write_data(SCSIRequest *req)
         return;
     }
 
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
     ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
     if (ret < 0) {
         scsi_command_complete(r, ret);
@@ -285,6 +301,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
             g_free(r->buf);
         r->buflen = 0;
         r->buf = NULL;
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
         ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
         if (ret < 0) {
             scsi_command_complete(r, ret);
commit c7bae6a75b5b43d560f5b18386447842f9bfec37
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Oct 25 12:53:34 2011 +0200

    scsi-disk: bump SCSIRequest reference count until aio completion runs
    
    In some cases a request may be canceled before the completion callback
    runs.  Keep a reference to the request between starting an AIO operation
    and the corresponding scsi_req_cancel or scsi_*_complete.
    
    When a request has to be retried, the request can be dropped because
    scsi_dma_restart_bh only looks at requests that are enqueued.  As such,
    they always have at least a reference.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 415f81d..bb07737 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -102,8 +102,14 @@ static void scsi_cancel_io(SCSIRequest *req)
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
 
     DPRINTF("Cancel tag=0x%x\n", req->tag);
+    r->status &= ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
     if (r->req.aiocb) {
         bdrv_aio_cancel(r->req.aiocb);
+
+        /* This reference was left in by scsi_*_data.  We take ownership of
+         * it the moment scsi_req_cancel is called, independent of whether
+         * bdrv_aio_cancel completes the request or not.  */
+        scsi_req_unref(&r->req);
     }
     r->req.aiocb = NULL;
 }
@@ -134,7 +140,7 @@ static void scsi_read_complete(void * opaque, int ret)
 
     if (ret) {
         if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
-            return;
+            goto done;
         }
     }
 
@@ -144,6 +150,11 @@ static void scsi_read_complete(void * opaque, int ret)
     r->sector += n;
     r->sector_count -= n;
     scsi_req_data(&r->req, r->qiov.size);
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
 }
 
 static void scsi_flush_complete(void * opaque, int ret)
@@ -158,11 +169,16 @@ static void scsi_flush_complete(void * opaque, int ret)
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
-            return;
+            goto done;
         }
     }
 
     scsi_req_complete(&r->req, GOOD);
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
 }
 
 /* Read more data from scsi device into buffer.  */
@@ -188,6 +204,8 @@ static void scsi_read_data(SCSIRequest *req)
     /* No data transfer may already be in progress */
     assert(r->req.aiocb == NULL);
 
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
         DPRINTF("Data transfer direction invalid\n");
         scsi_read_complete(r, -EINVAL);
@@ -196,7 +214,9 @@ static void scsi_read_data(SCSIRequest *req)
 
     if (s->tray_open) {
         scsi_read_complete(r, -ENOMEDIUM);
+        return;
     }
+
     n = scsi_init_iovec(r);
     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,
@@ -206,6 +226,13 @@ static void scsi_read_data(SCSIRequest *req)
     }
 }
 
+/*
+ * scsi_handle_rw_error has two return values.  0 means that the error
+ * must be ignored, 1 means that the error has been processed and the
+ * caller should not do anything else for this request.  Note that
+ * scsi_handle_rw_error always manages its reference counts, independent
+ * of the return value.
+ */
 static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
 {
     int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
@@ -226,6 +253,11 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
         bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
         vm_stop(RUN_STATE_IO_ERROR);
         bdrv_iostatus_set_err(s->qdev.conf.bs, error);
+
+        /* No need to save a reference, because scsi_dma_restart_bh just
+         * looks at the request list.  If a request is canceled, the
+         * retry request is just dropped.
+         */
     } else {
         switch (error) {
         case ENOMEDIUM:
@@ -259,7 +291,7 @@ static void scsi_write_complete(void * opaque, int ret)
 
     if (ret) {
         if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
-            return;
+            goto done;
         }
     }
 
@@ -273,6 +305,11 @@ static void scsi_write_complete(void * opaque, int ret)
         DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
         scsi_req_data(&r->req, r->qiov.size);
     }
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
 }
 
 static void scsi_write_data(SCSIRequest *req)
@@ -284,6 +321,8 @@ static void scsi_write_data(SCSIRequest *req)
     /* No data transfer may already be in progress */
     assert(r->req.aiocb == NULL);
 
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
     if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
         DPRINTF("Data transfer direction invalid\n");
         scsi_write_complete(r, -EINVAL);
@@ -294,6 +333,7 @@ static void scsi_write_data(SCSIRequest *req)
     if (n) {
         if (s->tray_open) {
             scsi_write_complete(r, -ENOMEDIUM);
+            return;
         }
         bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
         r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
@@ -1332,6 +1372,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         r->iov.iov_len = rc;
         break;
     case SYNCHRONIZE_CACHE:
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
         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);
         if (r->req.aiocb == NULL) {
commit e88c591d63ed1bc8520f4f276bebd77c22e4ec72
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Oct 25 12:53:33 2011 +0200

    scsi: do not call transfer_data after canceling a request
    
    Otherwise, if cancellation is "faked" by the AIO layer and goes
    through qemu_aio_flush, the whole request is completed synchronously
    during scsi_req_cancel.
    
    Using the enqueued flag would work here, but not in the next patches,
    so I'm introducing a new io_canceled flag.  That's because scsi_req_data
    is a synchronous callback and the enqueued flag might be reset by the
    time it returns.  scsi-disk cannot unref the request until after calling
    scsi_req_data.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 3cf571e..dfce5fb 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1107,8 +1107,12 @@ void scsi_req_continue(SCSIRequest *req)
    Once it completes, calling scsi_req_continue will restart I/O.  */
 void scsi_req_data(SCSIRequest *req, int len)
 {
-    trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
-    req->bus->info->transfer_data(req, len);
+    if (req->io_canceled) {
+        trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
+    } else {
+        trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
+        req->bus->info->transfer_data(req, len);
+    }
 }
 
 void scsi_req_print(SCSIRequest *req)
@@ -1173,11 +1177,15 @@ void scsi_req_complete(SCSIRequest *req, int status)
 
 void scsi_req_cancel(SCSIRequest *req)
 {
-    if (req->ops->cancel_io) {
-        req->ops->cancel_io(req);
+    if (!req->enqueued) {
+        return;
     }
     scsi_req_ref(req);
     scsi_req_dequeue(req);
+    req->io_canceled = true;
+    if (req->ops->cancel_io) {
+        req->ops->cancel_io(req);
+    }
     if (req->bus->info->cancel) {
         req->bus->info->cancel(req);
     }
@@ -1186,10 +1194,17 @@ void scsi_req_cancel(SCSIRequest *req)
 
 void scsi_req_abort(SCSIRequest *req, int status)
 {
+    if (!req->enqueued) {
+        return;
+    }
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    req->io_canceled = true;
     if (req->ops->cancel_io) {
         req->ops->cancel_io(req);
     }
     scsi_req_complete(req, status);
+    scsi_req_unref(req);
 }
 
 void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
diff --git a/hw/scsi.h b/hw/scsi.h
index 8ea744a..fcc3455 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -51,6 +51,7 @@ struct SCSIRequest {
     uint8_t sense[SCSI_SENSE_BUF_SIZE];
     uint32_t sense_len;
     bool enqueued;
+    bool io_canceled;
     void *hba_private;
     QTAILQ_ENTRY(SCSIRequest) next;
 };
diff --git a/trace-events b/trace-events
index a888055..56443af 100644
--- a/trace-events
+++ b/trace-events
@@ -278,6 +278,7 @@ usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
 # hw/scsi-bus.c
 scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
 scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
+scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
 scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
 scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
 scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
commit 63db0f0eee3c0b2cc3a06b36daf50c4e7801ea1b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 12:58:31 2011 +0200

    scsi: pass cdb to alloc_req
    
    This will let scsi-block choose between passthrough and emulation.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 1f38ac8..3cf571e 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -451,7 +451,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
             req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
                                  hba_private);
         } else {
-            req = d->info->alloc_req(d, tag, lun, hba_private);
+            req = d->info->alloc_req(d, tag, lun, buf, hba_private);
         }
     }
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 77673f2..415f81d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1598,8 +1598,8 @@ static const SCSIReqOps scsi_disk_reqops = {
     .get_buf      = scsi_get_buf,
 };
 
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
-                                     uint32_t lun, void *hba_private)
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                                     uint8_t *buf, void *hba_private)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
     SCSIRequest *req;
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 32f50cd..2f95f2d 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -431,7 +431,7 @@ const SCSIReqOps scsi_generic_req_ops = {
 };
 
 static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
-                                     void *hba_private)
+                                     uint8_t *buf, void *hba_private)
 {
     SCSIRequest *req;
 
diff --git a/hw/scsi.h b/hw/scsi.h
index 01c6655..8ea744a 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -94,7 +94,7 @@ struct SCSIDeviceInfo {
     scsi_qdev_initfn init;
     void (*destroy)(SCSIDevice *s);
     SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
-                              void *hba_private);
+                              uint8_t *buf, void *hba_private);
     void (*unit_attention_reported)(SCSIDevice *s);
 };
 
commit 765d1525a6c727674c5f6f459da4fdaeeda91162
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 12:54:31 2011 +0200

    scsi: export scsi_generic_reqops
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index a5e77cb..32f50cd 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -420,7 +420,7 @@ static int scsi_generic_initfn(SCSIDevice *s)
     return 0;
 }
 
-static const SCSIReqOps scsi_generic_req_ops = {
+const SCSIReqOps scsi_generic_req_ops = {
     .size         = sizeof(SCSIGenericReq),
     .free_req     = scsi_free_request,
     .send_command = scsi_send_command,
diff --git a/hw/scsi.h b/hw/scsi.h
index af558c3..01c6655 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -197,4 +197,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
 int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
 SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
 
+/* scsi-generic.c. */
+extern const SCSIReqOps scsi_generic_req_ops;
+
 #endif
commit adcf2754b99dcab33c5c0c523eb3b970c1a24f6c
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 12:57:59 2011 +0200

    scsi: make reqops const
    
    Also delete a stale occurrence of SCSIReqOps inside SCSIDeviceInfo.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index bdd6e94..1f38ac8 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -160,7 +160,7 @@ static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
     return 0;
 }
 
-struct SCSIReqOps reqops_invalid_opcode = {
+static const struct SCSIReqOps reqops_invalid_opcode = {
     .size         = sizeof(SCSIRequest),
     .send_command = scsi_invalid_command
 };
@@ -178,7 +178,7 @@ static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
     return 0;
 }
 
-struct SCSIReqOps reqops_unit_attention = {
+static const struct SCSIReqOps reqops_unit_attention = {
     .size         = sizeof(SCSIRequest),
     .send_command = scsi_unit_attention
 };
@@ -386,7 +386,7 @@ static uint8_t *scsi_target_get_buf(SCSIRequest *req)
     return r->buf;
 }
 
-struct SCSIReqOps reqops_target_command = {
+static const struct SCSIReqOps reqops_target_command = {
     .size         = sizeof(SCSITargetReq),
     .send_command = scsi_target_send_command,
     .read_data    = scsi_target_read_data,
@@ -394,8 +394,8 @@ struct SCSIReqOps reqops_target_command = {
 };
 
 
-SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
-                            uint32_t lun, void *hba_private)
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+                            uint32_t tag, uint32_t lun, void *hba_private)
 {
     SCSIRequest *req;
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 74990a8..77673f2 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1588,7 +1588,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
     }
 }
 
-static SCSIReqOps scsi_disk_reqops = {
+static const SCSIReqOps scsi_disk_reqops = {
     .size         = sizeof(SCSIDiskReq),
     .free_req     = scsi_free_request,
     .send_command = scsi_send_command,
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index fcf23cd..a5e77cb 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -420,7 +420,7 @@ static int scsi_generic_initfn(SCSIDevice *s)
     return 0;
 }
 
-static SCSIReqOps scsi_generic_req_ops = {
+static const SCSIReqOps scsi_generic_req_ops = {
     .size         = sizeof(SCSIGenericReq),
     .free_req     = scsi_free_request,
     .send_command = scsi_send_command,
diff --git a/hw/scsi.h b/hw/scsi.h
index d56e875..af558c3 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -41,7 +41,7 @@ struct SCSICommand {
 struct SCSIRequest {
     SCSIBus           *bus;
     SCSIDevice        *dev;
-    SCSIReqOps        *ops;
+    const SCSIReqOps  *ops;
     uint32_t          refcount;
     uint32_t          tag;
     uint32_t          lun;
@@ -96,7 +96,6 @@ struct SCSIDeviceInfo {
     SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
                               void *hba_private);
     void (*unit_attention_reported)(SCSIDevice *s);
-    SCSIReqOps reqops;
 };
 
 struct SCSIBusInfo {
@@ -176,8 +175,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
 
 int scsi_sense_valid(SCSISense sense);
 
-SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
-                            uint32_t lun, void *hba_private);
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+                            uint32_t tag, uint32_t lun, void *hba_private);
 SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
                           uint8_t *buf, void *hba_private);
 int32_t scsi_req_enqueue(SCSIRequest *req);
commit 7877903aa0ef318017441c32605bc64650e6a326
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 13 10:39:50 2011 +0200

    scsi: move max_lba to SCSIDevice
    
    The field is only in scsi-disk for now.  Moving it up to SCSIDevice makes
    it easier to reuse the scsi-generic reqops elsewhere.
    
    At the same time, make scsi-generic get max_lba from snooped READ CAPACITY
    commands as well.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index af1001d..74990a8 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -66,7 +66,6 @@ struct SCSIDiskState
 {
     SCSIDevice qdev;
     uint32_t removable;
-    uint64_t max_lba;
     bool media_changed;
     bool media_event;
     QEMUBH *bh;
@@ -1175,7 +1174,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         /* Returned value is the address of the last sector.  */
         nb_sectors--;
         /* Remember the new size for read/write sanity checking. */
-        s->max_lba = nb_sectors;
+        s->qdev.max_lba = nb_sectors;
         /* Clip to 2TB, instead of returning capacity modulo 2TB. */
         if (nb_sectors > UINT32_MAX) {
             nb_sectors = UINT32_MAX;
@@ -1230,7 +1229,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
             /* Returned value is the address of the last sector.  */
             nb_sectors--;
             /* Remember the new size for read/write sanity checking. */
-            s->max_lba = nb_sectors;
+            s->qdev.max_lba = nb_sectors;
             outbuf[0] = (nb_sectors >> 56) & 0xff;
             outbuf[1] = (nb_sectors >> 48) & 0xff;
             outbuf[2] = (nb_sectors >> 40) & 0xff;
@@ -1345,7 +1344,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case READ_16:
         len = r->req.cmd.xfer / s->qdev.blocksize;
         DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
-        if (r->req.cmd.lba > s->max_lba) {
+        if (r->req.cmd.lba > s->qdev.max_lba) {
             goto illegal_lba;
         }
         r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
@@ -1362,7 +1361,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
                 (command & 0xe) == 0xe ? "And Verify " : "",
                 r->req.cmd.lba, len);
-        if (r->req.cmd.lba > s->max_lba) {
+        if (r->req.cmd.lba > s->qdev.max_lba) {
             goto illegal_lba;
         }
         r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
@@ -1388,7 +1387,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case SEEK_10:
         DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
                 r->req.cmd.lba);
-        if (r->req.cmd.lba > s->max_lba) {
+        if (r->req.cmd.lba > s->qdev.max_lba) {
             goto illegal_lba;
         }
         break;
@@ -1398,7 +1397,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
                 r->req.cmd.lba, len);
 
-        if (r->req.cmd.lba > s->max_lba) {
+        if (r->req.cmd.lba > s->qdev.max_lba) {
             goto illegal_lba;
         }
 
@@ -1457,7 +1456,7 @@ static void scsi_disk_reset(DeviceState *dev)
     if (nb_sectors) {
         nb_sectors--;
     }
-    s->max_lba = nb_sectors;
+    s->qdev.max_lba = nb_sectors;
 }
 
 static void scsi_destroy(SCSIDevice *dev)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 4d7ad82..fcf23cd 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -174,9 +174,11 @@ static void scsi_read_complete(void * opaque, int ret)
         /* Snoop READ CAPACITY output to set the blocksize.  */
         if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
             s->blocksize = ldl_be_p(&r->buf[4]);
+            s->max_lba = ldl_be_p(&r->buf[0]);
         } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
                    (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
             s->blocksize = ldl_be_p(&r->buf[8]);
+            s->max_lba = ldq_be_p(&r->buf[0]);
         }
         bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
 
diff --git a/hw/scsi.h b/hw/scsi.h
index c8649cf..d56e875 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -70,6 +70,7 @@ struct SCSIDevice
     uint32_t lun;
     int blocksize;
     int type;
+    uint64_t max_lba;
 };
 
 /* cdrom.c */
commit e39be4823215e511d0e85aa33b2a5ade71064c72
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 14:27:40 2011 +0200

    scsi-disk: small clean up to INQUIRY
    
    Set s->removable, s->qdev.blocksize and s->qdev.type in the callers
    of scsi_initfn.
    
    With this in place, s->qdev.type is allowed, and we can just reuse it
    as the first byte in VPD data (just like we do in standard INQUIRY data).
    Also set s->removable is set consistently and we can use it.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index f89e6c5..af1001d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -381,11 +381,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             return -1;
         }
 
-        if (s->qdev.type == TYPE_ROM) {
-            outbuf[buflen++] = 5;
-        } else {
-            outbuf[buflen++] = 0;
-        }
+        outbuf[buflen++] = s->qdev.type & 0x1f;
         outbuf[buflen++] = page_code ; // this page
         outbuf[buflen++] = 0x00;
 
@@ -529,11 +525,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     memset(outbuf, 0, buflen);
 
     outbuf[0] = s->qdev.type & 0x1f;
+    outbuf[1] = s->removable ? 0x80 : 0;
     if (s->qdev.type == TYPE_ROM) {
-        outbuf[1] = 0x80;
         memcpy(&outbuf[16], "QEMU CD-ROM     ", 16);
     } else {
-        outbuf[1] = s->removable ? 0x80 : 0;
         memcpy(&outbuf[16], "QEMU HARDDISK   ", 16);
     }
     memcpy(&outbuf[8], "QEMU    ", 8);
@@ -1518,7 +1513,7 @@ static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
     }
 }
 
-static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
+static int scsi_initfn(SCSIDevice *dev)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
     DriveInfo *dinfo;
@@ -1528,7 +1523,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
         return -1;
     }
 
-    if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->qdev.conf.bs)) {
+    if (!s->removable && !bdrv_is_inserted(s->qdev.conf.bs)) {
         error_report("Device needs media, but drive is empty");
         return -1;
     }
@@ -1550,18 +1545,11 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
         return -1;
     }
 
-    if (scsi_type == TYPE_ROM) {
+    if (s->removable) {
         bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s);
-        s->qdev.blocksize = 2048;
-    } else if (scsi_type == TYPE_DISK) {
-        s->qdev.blocksize = s->qdev.conf.logical_block_size;
-    } else {
-        error_report("scsi-disk: Unhandled SCSI type %02x", scsi_type);
-        return -1;
     }
     bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
 
-    s->qdev.type = scsi_type;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
     bdrv_iostatus_enable(s->qdev.conf.bs);
     add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
@@ -1570,27 +1558,35 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
 
 static int scsi_hd_initfn(SCSIDevice *dev)
 {
-    return scsi_initfn(dev, TYPE_DISK);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    s->qdev.blocksize = s->qdev.conf.logical_block_size;
+    s->qdev.type = TYPE_DISK;
+    return scsi_initfn(&s->qdev);
 }
 
 static int scsi_cd_initfn(SCSIDevice *dev)
 {
-    return scsi_initfn(dev, TYPE_ROM);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    s->qdev.blocksize = 2048;
+    s->qdev.type = TYPE_ROM;
+    s->removable = true;
+    return scsi_initfn(&s->qdev);
 }
 
 static int scsi_disk_initfn(SCSIDevice *dev)
 {
     DriveInfo *dinfo;
-    uint8_t scsi_type;
 
     if (!dev->conf.bs) {
-        scsi_type = TYPE_DISK;  /* will die in scsi_initfn() */
-    } else {
-        dinfo = drive_get_by_blockdev(dev->conf.bs);
-        scsi_type = dinfo->media_cd ? TYPE_ROM : TYPE_DISK;
+        return scsi_initfn(dev);  /* ... and die there */
     }
 
-    return scsi_initfn(dev, scsi_type);
+    dinfo = drive_get_by_blockdev(dev->conf.bs);
+    if (dinfo->media_cd) {
+        return scsi_cd_initfn(dev);
+    } else {
+        return scsi_hd_initfn(dev);
+    }
 }
 
 static SCSIReqOps scsi_disk_reqops = {
commit 69377307b25f12235560d21050808a8de5793199
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 13 10:35:46 2011 +0200

    scsi-disk: remove cluster_size
    
    This field is redundant, and having it makes it more complicated
    to share reqops between the upcoming scsi-block and scsi-generic.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 8a05031..f89e6c5 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -65,9 +65,6 @@ typedef struct SCSIDiskReq {
 struct SCSIDiskState
 {
     SCSIDevice qdev;
-    /* The qemu block layer uses a fixed 512 byte sector size.
-       This is the number of 512 byte blocks in a single scsi sector.  */
-    int cluster_size;
     uint32_t removable;
     uint64_t max_lba;
     bool media_changed;
@@ -854,7 +851,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
         p[4] = heads & 0xff;
         p[5] = secs & 0xff;
-        p[6] = s->cluster_size * 2;
+        p[6] = s->qdev.blocksize >> 8;
         p[8] = (cylinders >> 8) & 0xff;
         p[9] = cylinders & 0xff;
         /* Write precomp start cylinder, disabled */
@@ -983,7 +980,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
         } else { /* MODE_SENSE_10 */
             outbuf[7] = 8; /* Block descriptor length  */
         }
-        nb_sectors /= s->cluster_size;
+        nb_sectors /= (s->qdev.blocksize / 512);
         if (nb_sectors > 0xffffff) {
             nb_sectors = 0;
         }
@@ -993,7 +990,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
         p[3] = nb_sectors & 0xff;
         p[4] = 0; /* reserved */
         p[5] = 0; /* bytes 5-7 are the sector size in bytes */
-        p[6] = s->cluster_size * 2;
+        p[6] = s->qdev.blocksize >> 8;
         p[7] = 0;
         p += 8;
     }
@@ -1044,7 +1041,7 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     start_track = req->cmd.buf[6];
     bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
     DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
-    nb_sectors /= s->cluster_size;
+    nb_sectors /= s->qdev.blocksize / 512;
     switch (format) {
     case 0:
         toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
@@ -1179,7 +1176,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
             goto illegal_request;
         }
-        nb_sectors /= s->cluster_size;
+        nb_sectors /= s->qdev.blocksize / 512;
         /* Returned value is the address of the last sector.  */
         nb_sectors--;
         /* Remember the new size for read/write sanity checking. */
@@ -1194,7 +1191,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         outbuf[3] = nb_sectors & 0xff;
         outbuf[4] = 0;
         outbuf[5] = 0;
-        outbuf[6] = s->cluster_size * 2;
+        outbuf[6] = s->qdev.blocksize >> 8;
         outbuf[7] = 0;
         buflen = 8;
         break;
@@ -1234,7 +1231,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
             if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
                 goto illegal_request;
             }
-            nb_sectors /= s->cluster_size;
+            nb_sectors /= s->qdev.blocksize / 512;
             /* Returned value is the address of the last sector.  */
             nb_sectors--;
             /* Remember the new size for read/write sanity checking. */
@@ -1249,7 +1246,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
             outbuf[7] = nb_sectors & 0xff;
             outbuf[8] = 0;
             outbuf[9] = 0;
-            outbuf[10] = s->cluster_size * 2;
+            outbuf[10] = s->qdev.blocksize >> 8;
             outbuf[11] = 0;
             outbuf[12] = 0;
             outbuf[13] = get_physical_block_exp(&s->qdev.conf);
@@ -1356,8 +1353,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         if (r->req.cmd.lba > s->max_lba) {
             goto illegal_lba;
         }
-        r->sector = r->req.cmd.lba * s->cluster_size;
-        r->sector_count = len * s->cluster_size;
+        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+        r->sector_count = len * (s->qdev.blocksize / 512);
         break;
     case WRITE_6:
     case WRITE_10:
@@ -1373,8 +1370,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         if (r->req.cmd.lba > s->max_lba) {
             goto illegal_lba;
         }
-        r->sector = r->req.cmd.lba * s->cluster_size;
-        r->sector_count = len * s->cluster_size;
+        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+        r->sector_count = len * (s->qdev.blocksize / 512);
         break;
     case MODE_SELECT:
         DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
@@ -1417,8 +1414,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
             goto fail;
         }
 
-        rc = bdrv_discard(s->qdev.conf.bs, r->req.cmd.lba * s->cluster_size,
-                          len * s->cluster_size);
+        rc = bdrv_discard(s->qdev.conf.bs,
+                          r->req.cmd.lba * (s->qdev.blocksize / 512),
+                          len * (s->qdev.blocksize / 512));
         if (rc < 0) {
             /* XXX: better error code ?*/
             goto fail;
@@ -1460,7 +1458,7 @@ static void scsi_disk_reset(DeviceState *dev)
     scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
 
     bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-    nb_sectors /= s->cluster_size;
+    nb_sectors /= s->qdev.blocksize / 512;
     if (nb_sectors) {
         nb_sectors--;
     }
@@ -1561,7 +1559,6 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
         error_report("scsi-disk: Unhandled SCSI type %02x", scsi_type);
         return -1;
     }
-    s->cluster_size = s->qdev.blocksize / 512;
     bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
 
     s->qdev.type = scsi_type;
commit 44740c38168bd46e2a99094a42cbdbb781299604
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 12:54:16 2011 +0200

    scsi-disk: do not duplicate BlockDriverState member
    
    Same as for scsi-generic, avoid duplication even if it causes longer
    lines.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index e800ab3..8a05031 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -65,7 +65,6 @@ typedef struct SCSIDiskReq {
 struct SCSIDiskState
 {
     SCSIDevice qdev;
-    BlockDriverState *bs;
     /* The qemu block layer uses a fixed 512 byte sector size.
        This is the number of 512 byte blocks in a single scsi sector.  */
     int cluster_size;
@@ -119,7 +118,7 @@ static uint32_t scsi_init_iovec(SCSIDiskReq *r)
 
     if (!r->iov.iov_base) {
         r->buflen = SCSI_DMA_BUF_SIZE;
-        r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
+        r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
     }
     r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
@@ -134,7 +133,7 @@ static void scsi_read_complete(void * opaque, int ret)
 
     if (r->req.aiocb != NULL) {
         r->req.aiocb = NULL;
-        bdrv_acct_done(s->bs, &r->acct);
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
     }
 
     if (ret) {
@@ -158,7 +157,7 @@ static void scsi_flush_complete(void * opaque, int ret)
 
     if (r->req.aiocb != NULL) {
         r->req.aiocb = NULL;
-        bdrv_acct_done(s->bs, &r->acct);
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
     }
 
     if (ret < 0) {
@@ -203,8 +202,8 @@ static void scsi_read_data(SCSIRequest *req)
         scsi_read_complete(r, -ENOMEDIUM);
     }
     n = scsi_init_iovec(r);
-    bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
-    r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
+    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);
     if (r->req.aiocb == NULL) {
         scsi_read_complete(r, -EIO);
@@ -215,10 +214,10 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
 {
     int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
+    BlockErrorAction action = bdrv_get_on_error(s->qdev.conf.bs, is_read);
 
     if (action == BLOCK_ERR_IGNORE) {
-        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
+        bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_IGNORE, is_read);
         return 0;
     }
 
@@ -228,9 +227,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
         type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
         r->status |= SCSI_REQ_STATUS_RETRY | type;
 
-        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
+        bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
         vm_stop(RUN_STATE_IO_ERROR);
-        bdrv_iostatus_set_err(s->bs, error);
+        bdrv_iostatus_set_err(s->qdev.conf.bs, error);
     } else {
         switch (error) {
         case ENOMEDIUM:
@@ -246,7 +245,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
             scsi_check_condition(r, SENSE_CODE(IO_ERROR));
             break;
         }
-        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
+        bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_REPORT, is_read);
     }
     return 1;
 }
@@ -259,7 +258,7 @@ static void scsi_write_complete(void * opaque, int ret)
 
     if (r->req.aiocb != NULL) {
         r->req.aiocb = NULL;
-        bdrv_acct_done(s->bs, &r->acct);
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
     }
 
     if (ret) {
@@ -300,8 +299,8 @@ static void scsi_write_data(SCSIRequest *req)
         if (s->tray_open) {
             scsi_write_complete(r, -ENOMEDIUM);
         }
-        bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
-        r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
+        r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
                                        scsi_write_complete, r);
         if (r->req.aiocb == NULL) {
             scsi_write_complete(r, -ENOMEM);
@@ -440,7 +439,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         case 0x83: /* Device identification page, mandatory */
         {
             int max_len = 255 - 8;
-            int id_len = strlen(bdrv_get_device_name(s->bs));
+            int id_len = strlen(bdrv_get_device_name(s->qdev.conf.bs));
 
             if (id_len > max_len) {
                 id_len = max_len;
@@ -454,7 +453,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             outbuf[buflen++] = 0;   // reserved
             outbuf[buflen++] = id_len; // length of data following
 
-            memcpy(outbuf+buflen, bdrv_get_device_name(s->bs), id_len);
+            memcpy(outbuf+buflen, bdrv_get_device_name(s->qdev.conf.bs), id_len);
             buflen += id_len;
             break;
         }
@@ -571,10 +570,10 @@ static inline bool media_is_dvd(SCSIDiskState *s)
     if (s->qdev.type != TYPE_ROM) {
         return false;
     }
-    if (!bdrv_is_inserted(s->bs)) {
+    if (!bdrv_is_inserted(s->qdev.conf.bs)) {
         return false;
     }
-    bdrv_get_geometry(s->bs, &nb_sectors);
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
     return nb_sectors > CD_MAX_SECTORS;
 }
 
@@ -584,10 +583,10 @@ static inline bool media_is_cd(SCSIDiskState *s)
     if (s->qdev.type != TYPE_ROM) {
         return false;
     }
-    if (!bdrv_is_inserted(s->bs)) {
+    if (!bdrv_is_inserted(s->qdev.conf.bs)) {
         return false;
     }
-    bdrv_get_geometry(s->bs, &nb_sectors);
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
     return nb_sectors <= CD_MAX_SECTORS;
 }
 
@@ -615,7 +614,7 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
     }
 
     if (format != 0xff) {
-        if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
             scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
             return -1;
         }
@@ -637,7 +636,7 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
         if (layer != 0) {
             goto fail;
         }
-        bdrv_get_geometry(s->bs, &nb_sectors);
+        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
 
         outbuf[4] = 1;   /* DVD-ROM, part version 1 */
         outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
@@ -692,7 +691,7 @@ static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
     media_status = 0;
     if (s->tray_open) {
         media_status = MS_TRAY_OPEN;
-    } else if (bdrv_is_inserted(s->bs)) {
+    } else if (bdrv_is_inserted(s->qdev.conf.bs)) {
         media_status = MS_MEDIA_PRESENT;
     }
 
@@ -795,7 +794,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         [MODE_PAGE_CAPABILITIES]           = (1 << TYPE_ROM),
     };
 
-    BlockDriverState *bdrv = s->bs;
+    BlockDriverState *bdrv = s->qdev.conf.bs;
     int cylinders, heads, secs;
     uint8_t *p = *p_outbuf;
 
@@ -887,7 +886,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         if (page_control == 1) { /* Changeable Values */
             break;
         }
-        if (bdrv_enable_write_cache(s->bs)) {
+        if (bdrv_enable_write_cache(s->qdev.conf.bs)) {
             p[2] = 4; /* WCE */
         }
         break;
@@ -959,7 +958,7 @@ 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->bs)) {
+    if (bdrv_is_read_only(s->qdev.conf.bs)) {
         dev_specific_param = 0x80; /* Readonly.  */
     } else {
         dev_specific_param = 0x00;
@@ -977,7 +976,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
         p += 8;
     }
 
-    bdrv_get_geometry(s->bs, &nb_sectors);
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
     if (!dbd && nb_sectors) {
         if (r->req.cmd.buf[0] == MODE_SENSE) {
             outbuf[3] = 8; /* Block descriptor length  */
@@ -1043,7 +1042,7 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     msf = req->cmd.buf[1] & 2;
     format = req->cmd.buf[2] & 0xf;
     start_track = req->cmd.buf[6];
-    bdrv_get_geometry(s->bs, &nb_sectors);
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
     DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
     nb_sectors /= s->cluster_size;
     switch (format) {
@@ -1080,12 +1079,12 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
     if (s->qdev.type == TYPE_ROM && loej) {
         if (!start && !s->tray_open && s->tray_locked) {
             scsi_check_condition(r,
-                                 bdrv_is_inserted(s->bs)
+                                 bdrv_is_inserted(s->qdev.conf.bs)
                                  ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
                                  : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
             return -1;
         }
-        bdrv_eject(s->bs, !start);
+        bdrv_eject(s->qdev.conf.bs, !start);
         s->tray_open = !start;
     }
     return 0;
@@ -1112,13 +1111,13 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
             goto illegal_request;
         }
         r->buflen = MAX(4096, req->cmd.xfer);
-        r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
+        r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
     }
 
     outbuf = r->iov.iov_base;
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
-        if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
             goto not_ready;
         }
         break;
@@ -1168,12 +1167,12 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         break;
     case ALLOW_MEDIUM_REMOVAL:
         s->tray_locked = req->cmd.buf[4] & 1;
-        bdrv_lock_medium(s->bs, req->cmd.buf[4] & 1);
+        bdrv_lock_medium(s->qdev.conf.bs, req->cmd.buf[4] & 1);
         break;
     case READ_CAPACITY_10:
         /* The normal LEN field for this command is zero.  */
         memset(outbuf, 0, 8);
-        bdrv_get_geometry(s->bs, &nb_sectors);
+        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
         if (!nb_sectors) {
             goto not_ready;
         }
@@ -1228,7 +1227,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
             DPRINTF("SAI READ CAPACITY(16)\n");
             memset(outbuf, 0, req->cmd.xfer);
-            bdrv_get_geometry(s->bs, &nb_sectors);
+            bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
             if (!nb_sectors) {
                 goto not_ready;
             }
@@ -1275,7 +1274,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
     return buflen;
 
 not_ready:
-    if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+    if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
         scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
     } else {
         scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
@@ -1342,8 +1341,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         r->iov.iov_len = rc;
         break;
     case SYNCHRONIZE_CACHE:
-        bdrv_acct_start(s->bs, &r->acct, 0, BDRV_ACCT_FLUSH);
-        r->req.aiocb = bdrv_aio_flush(s->bs, scsi_flush_complete, r);
+        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);
         if (r->req.aiocb == NULL) {
             scsi_flush_complete(r, -EIO);
         }
@@ -1418,7 +1417,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
             goto fail;
         }
 
-        rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
+        rc = bdrv_discard(s->qdev.conf.bs, r->req.cmd.lba * s->cluster_size,
                           len * s->cluster_size);
         if (rc < 0) {
             /* XXX: better error code ?*/
@@ -1460,7 +1459,7 @@ static void scsi_disk_reset(DeviceState *dev)
 
     scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
 
-    bdrv_get_geometry(s->bs, &nb_sectors);
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
     nb_sectors /= s->cluster_size;
     if (nb_sectors) {
         nb_sectors--;
@@ -1530,16 +1529,15 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
         error_report("scsi-disk: drive property not set");
         return -1;
     }
-    s->bs = s->qdev.conf.bs;
 
-    if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->bs)) {
+    if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->qdev.conf.bs)) {
         error_report("Device needs media, but drive is empty");
         return -1;
     }
 
     if (!s->serial) {
         /* try to fall back to value set with legacy -drive serial=... */
-        dinfo = drive_get_by_blockdev(s->bs);
+        dinfo = drive_get_by_blockdev(s->qdev.conf.bs);
         if (*dinfo->serial) {
             s->serial = g_strdup(dinfo->serial);
         }
@@ -1549,13 +1547,13 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
         s->version = g_strdup(QEMU_VERSION);
     }
 
-    if (bdrv_is_sg(s->bs)) {
+    if (bdrv_is_sg(s->qdev.conf.bs)) {
         error_report("scsi-disk: unwanted /dev/sg*");
         return -1;
     }
 
     if (scsi_type == TYPE_ROM) {
-        bdrv_set_dev_ops(s->bs, &scsi_cd_block_ops, s);
+        bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s);
         s->qdev.blocksize = 2048;
     } else if (scsi_type == TYPE_DISK) {
         s->qdev.blocksize = s->qdev.conf.logical_block_size;
@@ -1564,11 +1562,11 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
         return -1;
     }
     s->cluster_size = s->qdev.blocksize / 512;
-    bdrv_set_buffer_alignment(s->bs, s->qdev.blocksize);
+    bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
 
     s->qdev.type = scsi_type;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
-    bdrv_iostatus_enable(s->bs);
+    bdrv_iostatus_enable(s->qdev.conf.bs);
     add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
     return 0;
 }
commit 9b6eef8a319f11f977add658b622b60900877410
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 13 10:36:27 2011 +0200

    scsi-generic: snoop READ CAPACITY commands to get block size
    
    Instead of "guessing" the block size when there is no medium in the
    drive, wait for the guest to send a READ CAPACITY command and snoop
    it from there.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 5ad3d57..4d7ad82 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -155,6 +155,7 @@ static int execute_command(BlockDriverState *bdrv,
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    SCSIDevice *s = r->req.dev;
     int len;
 
     r->req.aiocb = NULL;
@@ -170,6 +171,15 @@ static void scsi_read_complete(void * opaque, int ret)
     if (len == 0) {
         scsi_command_complete(r, 0);
     } else {
+        /* Snoop READ CAPACITY output to set the blocksize.  */
+        if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
+            s->blocksize = ldl_be_p(&r->buf[4]);
+        } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
+                   (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
+            s->blocksize = ldl_be_p(&r->buf[8]);
+        }
+        bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
+
         scsi_req_data(&r->req, len);
     }
 }
@@ -298,36 +308,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
     }
 }
 
-static int get_blocksize(BlockDriverState *bdrv)
-{
-    uint8_t cmd[10];
-    uint8_t buf[8];
-    uint8_t sensebuf[8];
-    sg_io_hdr_t io_header;
-    int ret;
-
-    memset(cmd, 0, sizeof(cmd));
-    memset(buf, 0, sizeof(buf));
-    cmd[0] = READ_CAPACITY_10;
-
-    memset(&io_header, 0, sizeof(io_header));
-    io_header.interface_id = 'S';
-    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
-    io_header.dxfer_len = sizeof(buf);
-    io_header.dxferp = buf;
-    io_header.cmdp = cmd;
-    io_header.cmd_len = sizeof(cmd);
-    io_header.mx_sb_len = sizeof(sensebuf);
-    io_header.sbp = sensebuf;
-    io_header.timeout = 6000; /* XXX */
-
-    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
-    if (ret < 0 || io_header.driver_status || io_header.host_status) {
-        return -1;
-    }
-    return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
-}
-
 static int get_stream_blocksize(BlockDriverState *bdrv)
 {
     uint8_t cmd[6];
@@ -413,21 +393,25 @@ static int scsi_generic_initfn(SCSIDevice *s)
     /* define device state */
     s->type = scsiid.scsi_type;
     DPRINTF("device type %d\n", s->type);
-    if (s->type == TYPE_TAPE) {
+    switch (s->type) {
+    case TYPE_TAPE:
         s->blocksize = get_stream_blocksize(s->conf.bs);
         if (s->blocksize == -1) {
             s->blocksize = 0;
         }
-    } else {
-        s->blocksize = get_blocksize(s->conf.bs);
-        /* removable media returns 0 if not present */
-        if (s->blocksize <= 0) {
-            if (s->type == TYPE_ROM || s->type  == TYPE_WORM) {
-                s->blocksize = 2048;
-            } else {
-                s->blocksize = 512;
-            }
-        }
+        break;
+
+        /* Make a guess for block devices, we'll fix it when the guest sends.
+         * READ CAPACITY.  If they don't, they likely would assume these sizes
+         * anyway. (TODO: they could also send MODE SENSE).
+         */
+    case TYPE_ROM:
+    case TYPE_WORM:
+        s->blocksize = 2048;
+        break;
+    default:
+        s->blocksize = 512;
+        break;
     }
 
     DPRINTF("block size %d\n", s->blocksize);
commit a3b16e71ab733f76104231b873dff48d43fb3890
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 14:53:43 2011 +0200

    scsi-generic: look at host status
    
    Pass down the host status so that failing transport can be detected
    by the guest.  Similar treatment of host status could be done in
    virtio-blk, too.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index c313749..5ad3d57 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -39,8 +39,13 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
 
 #define SCSI_SENSE_BUF_SIZE 96
 
-#define SG_ERR_DRIVER_TIMEOUT 0x06
-#define SG_ERR_DRIVER_SENSE 0x08
+#define SG_ERR_DRIVER_TIMEOUT  0x06
+#define SG_ERR_DRIVER_SENSE    0x08
+
+#define SG_ERR_DID_OK          0x00
+#define SG_ERR_DID_NO_CONNECT  0x01
+#define SG_ERR_DID_BUS_BUSY    0x02
+#define SG_ERR_DID_TIME_OUT    0x03
 
 #ifndef MAX_UINT
 #define MAX_UINT ((unsigned int)-1)
@@ -68,8 +73,9 @@ static void scsi_command_complete(void *opaque, int ret)
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
 
     r->req.aiocb = NULL;
-    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
+    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
         r->req.sense_len = r->io_header.sb_len_wr;
+    }
 
     if (ret != 0) {
         switch (ret) {
@@ -86,9 +92,15 @@ static void scsi_command_complete(void *opaque, int ret)
             break;
         }
     } else {
-        if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
+        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
+            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
+            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
+            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
             status = BUSY;
             BADF("Driver Timeout\n");
+        } else if (r->io_header.host_status) {
+            status = CHECK_CONDITION;
+            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
         } else if (r->io_header.status) {
             status = r->io_header.status;
         } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
commit fe0ed71279eb442b920f0080c763438dbaa09f74
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 14:49:48 2011 +0200

    scsi-generic: check ioctl statuses when SG_IO succeeds
    
    A succeeding ioctl does not imply that the SCSI command succeeded.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 5ef4825..c313749 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -310,9 +310,9 @@ static int get_blocksize(BlockDriverState *bdrv)
     io_header.timeout = 6000; /* XXX */
 
     ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
-    if (ret < 0)
+    if (ret < 0 || io_header.driver_status || io_header.host_status) {
         return -1;
-
+    }
     return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
 }
 
@@ -341,9 +341,9 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
     io_header.timeout = 6000; /* XXX */
 
     ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
-    if (ret < 0)
+    if (ret < 0 || io_header.driver_status || io_header.host_status) {
         return -1;
-
+    }
     return (buf[9] << 16) | (buf[10] << 8) | buf[11];
 }
 
commit 6a58a3a6ebb738e4173f93ecc089b45dd57c7574
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 11:54:59 2011 +0200

    scsi-generic: remove scsi_req_fixup
    
    This is not needed anymore, since asynchronous ioctls were introduced
    by commit 221f715 (new scsi-generic abstraction, use SG_IO, 2009-03-28).
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 4af0f24..5ef4825 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -232,19 +232,6 @@ static uint8_t *scsi_get_buf(SCSIRequest *req)
     return r->buf;
 }
 
-static void scsi_req_fixup(SCSIRequest *req)
-{
-    switch(req->cmd.buf[0]) {
-    case REWIND:
-    case START_STOP:
-        if (req->dev->type == TYPE_TAPE) {
-            /* force IMMED, otherwise qemu waits end of command */
-            req->cmd.buf[1] = 0x01;
-        }
-        break;
-    }
-}
-
 /* Execute a scsi command.  Returns the length of the data expected by the
    command.  This will be Positive for data transfers from the device
    (eg. disk reads), negative for transfers to the device (eg. disk writes),
@@ -256,8 +243,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
     SCSIDevice *s = r->req.dev;
     int ret;
 
-    scsi_req_fixup(&r->req);
-
     DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
             r->req.cmd.xfer, cmd[0]);
 
commit 8869e103979e499babe73488abe1f9c935746a60
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 12 12:49:35 2011 +0200

    scsi-generic: drop SCSIGenericState
    
    It is not needed, because s->bs is already stored in SCSIDevice, and
    can be reached from the conf.bs member.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 8f6b70d..4af0f24 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -46,8 +46,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
 #define MAX_UINT ((unsigned int)-1)
 #endif
 
-typedef struct SCSIGenericState SCSIGenericState;
-
 typedef struct SCSIGenericReq {
     SCSIRequest req;
     uint8_t *buf;
@@ -56,12 +54,6 @@ typedef struct SCSIGenericReq {
     sg_io_hdr_t io_header;
 } SCSIGenericReq;
 
-struct SCSIGenericState
-{
-    SCSIDevice qdev;
-    BlockDriverState *bs;
-};
-
 static void scsi_free_request(SCSIRequest *req)
 {
     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
@@ -174,7 +166,7 @@ static void scsi_read_complete(void * opaque, int ret)
 static void scsi_read_data(SCSIRequest *req)
 {
     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+    SCSIDevice *s = r->req.dev;
     int ret;
 
     DPRINTF("scsi_read_data 0x%x\n", req->tag);
@@ -183,17 +175,16 @@ static void scsi_read_data(SCSIRequest *req)
         return;
     }
 
-    ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+    ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
     if (ret < 0) {
         scsi_command_complete(r, ret);
-        return;
     }
 }
 
 static void scsi_write_complete(void * opaque, int ret)
 {
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+    SCSIDevice *s = r->req.dev;
 
     DPRINTF("scsi_write_complete() ret = %d\n", ret);
     r->req.aiocb = NULL;
@@ -204,9 +195,9 @@ static void scsi_write_complete(void * opaque, int ret)
     }
 
     if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
-        s->qdev.type == TYPE_TAPE) {
-        s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
-        DPRINTF("block size %d\n", s->qdev.blocksize);
+        s->type == TYPE_TAPE) {
+        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
+        DPRINTF("block size %d\n", s->blocksize);
     }
 
     scsi_command_complete(r, ret);
@@ -216,8 +207,8 @@ static void scsi_write_complete(void * opaque, int ret)
    The transfer may complete asynchronously.  */
 static void scsi_write_data(SCSIRequest *req)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIDevice *s = r->req.dev;
     int ret;
 
     DPRINTF("scsi_write_data 0x%x\n", req->tag);
@@ -227,7 +218,7 @@ static void scsi_write_data(SCSIRequest *req)
         return;
     }
 
-    ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
+    ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
     if (ret < 0) {
         scsi_command_complete(r, ret);
     }
@@ -261,8 +252,8 @@ static void scsi_req_fixup(SCSIRequest *req)
 
 static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIDevice *s = r->req.dev;
     int ret;
 
     scsi_req_fixup(&r->req);
@@ -285,7 +276,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
             g_free(r->buf);
         r->buflen = 0;
         r->buf = NULL;
-        ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
+        ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
         if (ret < 0) {
             scsi_command_complete(r, ret);
             return 0;
@@ -373,77 +364,76 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
 
 static void scsi_generic_reset(DeviceState *dev)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
+    SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
 
-    scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
+    scsi_device_purge_requests(s, SENSE_CODE(RESET));
 }
 
-static void scsi_destroy(SCSIDevice *d)
+static void scsi_destroy(SCSIDevice *s)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-
-    scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
-    blockdev_mark_auto_del(s->qdev.conf.bs);
+    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
+    blockdev_mark_auto_del(s->conf.bs);
 }
 
-static int scsi_generic_initfn(SCSIDevice *dev)
+static int scsi_generic_initfn(SCSIDevice *s)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
     int sg_version;
     struct sg_scsi_id scsiid;
 
-    if (!s->qdev.conf.bs) {
+    if (!s->conf.bs) {
         error_report("scsi-generic: drive property not set");
         return -1;
     }
-    s->bs = s->qdev.conf.bs;
 
     /* check we are really using a /dev/sg* file */
-    if (!bdrv_is_sg(s->bs)) {
+    if (!bdrv_is_sg(s->conf.bs)) {
         error_report("scsi-generic: not /dev/sg*");
         return -1;
     }
 
-    if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
+    if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
         error_report("Device doesn't support drive option werror");
         return -1;
     }
-    if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
+    if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
         error_report("Device doesn't support drive option rerror");
         return -1;
     }
 
     /* check we are using a driver managing SG_IO (version 3 and after */
-    if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
         sg_version < 30000) {
         error_report("scsi-generic: scsi generic interface too old");
         return -1;
     }
 
     /* get LUN of the /dev/sg? */
-    if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
+    if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
         error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
         return -1;
     }
 
     /* define device state */
-    s->qdev.type = scsiid.scsi_type;
-    DPRINTF("device type %d\n", s->qdev.type);
-    if (s->qdev.type == TYPE_TAPE) {
-        s->qdev.blocksize = get_stream_blocksize(s->bs);
-        if (s->qdev.blocksize == -1)
-            s->qdev.blocksize = 0;
+    s->type = scsiid.scsi_type;
+    DPRINTF("device type %d\n", s->type);
+    if (s->type == TYPE_TAPE) {
+        s->blocksize = get_stream_blocksize(s->conf.bs);
+        if (s->blocksize == -1) {
+            s->blocksize = 0;
+        }
     } else {
-        s->qdev.blocksize = get_blocksize(s->bs);
+        s->blocksize = get_blocksize(s->conf.bs);
         /* removable media returns 0 if not present */
-        if (s->qdev.blocksize <= 0) {
-            if (s->qdev.type == TYPE_ROM || s->qdev.type  == TYPE_WORM)
-                s->qdev.blocksize = 2048;
-            else
-                s->qdev.blocksize = 512;
+        if (s->blocksize <= 0) {
+            if (s->type == TYPE_ROM || s->type  == TYPE_WORM) {
+                s->blocksize = 2048;
+            } else {
+                s->blocksize = 512;
+            }
         }
     }
-    DPRINTF("block size %d\n", s->qdev.blocksize);
+
+    DPRINTF("block size %d\n", s->blocksize);
     return 0;
 }
 
@@ -469,13 +459,13 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
 static SCSIDeviceInfo scsi_generic_info = {
     .qdev.name    = "scsi-generic",
     .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
-    .qdev.size    = sizeof(SCSIGenericState),
+    .qdev.size    = sizeof(SCSIDevice),
     .qdev.reset   = scsi_generic_reset,
     .init         = scsi_generic_initfn,
     .destroy      = scsi_destroy,
     .alloc_req    = scsi_new_request,
     .qdev.props   = (Property[]) {
-        DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
+        DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
commit 628e95b61650f00607e8ddcf952b2e93f6ac3c89
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Oct 4 15:36:05 2011 +0200

    scsi-disk: fix retrying a flush
    
    Flush does not go anymore through scsi_disk_emulate_command.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 6b139ac..e800ab3 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -81,7 +81,7 @@ struct SCSIDiskState
 };
 
 static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
-static int scsi_disk_emulate_command(SCSIDiskReq *r);
+static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf);
 
 static void scsi_free_request(SCSIRequest *req)
 {
@@ -325,7 +325,6 @@ static void scsi_dma_restart_bh(void *opaque)
         r = DO_UPCAST(SCSIDiskReq, req, req);
         if (r->status & SCSI_REQ_STATUS_RETRY) {
             int status = r->status;
-            int ret;
 
             r->status &=
                 ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
@@ -338,10 +337,8 @@ static void scsi_dma_restart_bh(void *opaque)
                 scsi_write_data(&r->req);
                 break;
             case SCSI_REQ_STATUS_RETRY_FLUSH:
-                ret = scsi_disk_emulate_command(r);
-                if (ret == 0) {
-                    scsi_req_complete(&r->req, GOOD);
-                }
+                scsi_send_command(&r->req, r->req.cmd.buf);
+                break;
             }
         }
     }
commit 7cec78b6f0e9a3b33732afd14a811849d219ffbc
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Oct 3 13:57:06 2011 +0200

    scsi-disk: fail READ CAPACITY if LBA != 0 but PMI == 0
    
    Tested by the Windows Logo Kit SCSI Compliance test. From SBC-3, paragraph
    5.25: "The LOGICAL BLOCK ADDRESS field shall be set to zero if the PMI
    bit is set to zero. If the PMI bit is set to zero and the LOGICAL BLOCK
    ADDRESS field is not set to zero, then the device server shall terminate
    the command with CHECK CONDITION status with the sense key set to ILLEGAL
    REQUEST and the additional sense code set to INVALID FIELD IN CDB".
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 50fc3d6..6b139ac 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1180,6 +1180,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         if (!nb_sectors) {
             goto not_ready;
         }
+        if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
+            goto illegal_request;
+        }
         nb_sectors /= s->cluster_size;
         /* Returned value is the address of the last sector.  */
         nb_sectors--;
@@ -1232,6 +1235,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
             if (!nb_sectors) {
                 goto not_ready;
             }
+            if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
+                goto illegal_request;
+            }
             nb_sectors /= s->cluster_size;
             /* Returned value is the address of the last sector.  */
             nb_sectors--;
commit 0d3545e76c856be4cce26cf1c96981b26cafb6b1
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Jul 27 23:24:50 2011 +0200

    scsi: add channel to addressing
    
    This also requires little more than adding the new argument to
    scsi_device_find, and the qdev property.  All devices by default
    end up on channel 0.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/esp.c b/hw/esp.c
index 5742bb3..b698a43 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -217,7 +217,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
         s->async_len = 0;
     }
 
-    s->current_dev = scsi_device_find(&s->bus, target, 0);
+    s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
     if (!s->current_dev) {
         // No such drive
         s->rregs[ESP_RSTAT] = 0;
@@ -237,7 +237,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
 
     trace_esp_do_busid_cmd(busid);
     lun = busid & 7;
-    current_lun = scsi_device_find(&s->bus, s->current_dev->id, lun);
+    current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
     s->current_req = scsi_req_new(current_lun, 0, lun, buf, NULL);
     datalen = scsi_req_enqueue(s->current_req);
     s->ti_size = datalen;
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index d26e442..2984cea 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -767,7 +767,7 @@ static void lsi_do_command(LSIState *s)
     s->command_complete = 0;
 
     id = (s->select_tag >> 8) & 0xf;
-    dev = scsi_device_find(&s->bus, id, s->current_lun);
+    dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
     if (!dev) {
         lsi_bad_selection(s, id);
         return;
@@ -1198,7 +1198,7 @@ again:
                 }
                 s->sstat0 |= LSI_SSTAT0_WOA;
                 s->scntl1 &= ~LSI_SCNTL1_IARB;
-                if (!scsi_device_find(&s->bus, id, 0)) {
+                if (!scsi_device_find(&s->bus, 0, id, 0)) {
                     lsi_bad_selection(s, id);
                     break;
                 }
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index cec06db..bdd6e94 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -16,6 +16,7 @@ static struct BusInfo scsi_bus_info = {
     .size  = sizeof(SCSIBus),
     .get_fw_dev_path = scsibus_get_fw_dev_path,
     .props = (Property[]) {
+        DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
         DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
         DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
         DEFINE_PROP_END_OF_LIST(),
@@ -40,6 +41,10 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
     SCSIDevice *d;
     int rc = -1;
 
+    if (dev->channel > bus->info->max_channel) {
+        error_report("bad scsi channel id: %d", dev->channel);
+        goto err;
+    }
     if (dev->id != -1 && dev->id > bus->info->max_target) {
         error_report("bad scsi device id: %d", dev->id);
         goto err;
@@ -51,7 +56,7 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
             dev->lun = 0;
         }
         do {
-            d = scsi_device_find(bus, ++id, dev->lun);
+            d = scsi_device_find(bus, dev->channel, ++id, dev->lun);
         } while (d && d->lun == dev->lun && id <= bus->info->max_target);
         if (id > bus->info->max_target) {
             error_report("no free target");
@@ -61,7 +66,7 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
     } else if (dev->lun == -1) {
         int lun = -1;
         do {
-            d = scsi_device_find(bus, dev->id, ++lun);
+            d = scsi_device_find(bus, dev->channel, dev->id, ++lun);
         } while (d && d->lun == lun && lun < bus->info->max_lun);
         if (lun > bus->info->max_lun) {
             error_report("no free lun");
@@ -69,7 +74,7 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
         }
         dev->lun = lun;
     } else {
-        d = scsi_device_find(bus, dev->id, dev->lun);
+        d = scsi_device_find(bus, dev->channel, dev->id, dev->lun);
         if (dev->lun == d->lun && dev != d) {
             qdev_free(&d->qdev);
         }
@@ -203,7 +208,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
 {
     DeviceState *qdev;
     int i, len, n;
-    int id;
+    int channel, id;
     bool found_lun0;
 
     if (r->req.cmd.xfer < 16) {
@@ -212,13 +217,14 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
     if (r->req.cmd.buf[2] > 2) {
         return false;
     }
+    channel = r->req.dev->channel;
     id = r->req.dev->id;
     found_lun0 = false;
     n = 0;
     QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
         SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
 
-        if (dev->id == id) {
+        if (dev->channel == channel && dev->id == id) {
             if (dev->lun == 0) {
                 found_lun0 = true;
             }
@@ -240,7 +246,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
     QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
         SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
 
-        if (dev->id == id) {
+        if (dev->channel == channel && dev->id == id) {
             store_lun(&r->buf[i], dev->lun);
             i += 8;
         }
@@ -1203,12 +1209,12 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev)
     char path[100];
 
     snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev),
-             0, d->id, d->lun);
+             d->channel, d->id, d->lun);
 
     return strdup(path);
 }
 
-SCSIDevice *scsi_device_find(SCSIBus *bus, int id, int lun)
+SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
 {
     DeviceState *qdev;
     SCSIDevice *target_dev = NULL;
@@ -1216,7 +1222,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int id, int lun)
     QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
         SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
 
-        if (dev->id == id) {
+        if (dev->channel == channel && dev->id == id) {
             if (dev->lun == lun) {
                 return dev;
             }
diff --git a/hw/scsi.h b/hw/scsi.h
index 401d8d3..c8649cf 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -66,6 +66,7 @@ struct SCSIDevice
     uint8_t sense[SCSI_SENSE_BUF_SIZE];
     uint32_t sense_len;
     QTAILQ_HEAD(, SCSIRequest) requests;
+    uint32_t channel;
     uint32_t lun;
     int blocksize;
     int type;
@@ -99,7 +100,7 @@ struct SCSIDeviceInfo {
 
 struct SCSIBusInfo {
     int tcq;
-    int max_target, max_lun;
+    int max_channel, max_target, max_lun;
     void (*transfer_data)(SCSIRequest *req, uint32_t arg);
     void (*complete)(SCSIRequest *req, uint32_t arg);
     void (*cancel)(SCSIRequest *req);
@@ -194,6 +195,6 @@ void scsi_req_abort(SCSIRequest *req, int status);
 void scsi_req_cancel(SCSIRequest *req);
 void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
 int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
-SCSIDevice *scsi_device_find(SCSIBus *bus, int target, int lun);
+SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
 
 #endif
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index e6c3581..00e2d2d 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -160,11 +160,7 @@ retry:
         abort();
     }
 
-    if (channel) {
-        *lun = -1;
-        return NULL;
-    }
-    return scsi_device_find(bus, id, *lun);
+    return scsi_device_find(bus, channel, id, *lun);
 }
 
 static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
@@ -892,7 +888,8 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
 
 static const struct SCSIBusInfo vscsi_scsi_info = {
     .tcq = true,
-    .max_target = 63, /* logical unit addressing format */
+    .max_channel = 7, /* logical unit addressing format */
+    .max_target = 63,
     .max_lun = 31,
 
     .transfer_data = vscsi_transfer_data,
commit 7e0380b9bbf7c40361e06e6e0d8675a55bd0dea0
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Sat Aug 13 18:55:17 2011 +0200

    scsi: allow arbitrary LUNs
    
    This only requires changes in two places: in SCSIBus, we need to look
    for a free LUN if somebody creates a device with a pre-existing scsi-id
    but the default LUN (-1, meaning "search for a free spot"); in vSCSI,
    we need to actually parse the LUN according to the SCSI spec.
    
    For vSCSI, max_target/max_lun are set according to the logical unit
    addressing format in SAM.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/esp.c b/hw/esp.c
index aad290f..5742bb3 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -724,7 +724,8 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
 
 static const struct SCSIBusInfo esp_scsi_info = {
     .tcq = false,
-    .ndev = ESP_MAX_DEVS,
+    .max_target = ESP_MAX_DEVS,
+    .max_lun = 7,
 
     .transfer_data = esp_transfer_data,
     .complete = esp_command_complete,
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index c15f167..d26e442 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2085,7 +2085,8 @@ static int lsi_scsi_uninit(PCIDevice *d)
 
 static const struct SCSIBusInfo lsi_scsi_info = {
     .tcq = true,
-    .ndev = LSI_MAX_DEVS,
+    .max_target = LSI_MAX_DEVS,
+    .max_lun = 0,  /* LUN support is buggy */
 
     .transfer_data = lsi_transfer_data,
     .complete = lsi_command_complete,
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index a2d57a7..cec06db 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -17,7 +17,7 @@ static struct BusInfo scsi_bus_info = {
     .get_fw_dev_path = scsibus_get_fw_dev_path,
     .props = (Property[]) {
         DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
-        DEFINE_PROP_UINT32("lun", SCSIDevice, lun, 0),
+        DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
@@ -37,26 +37,42 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
     SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
     SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
     SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
-    SCSIDevice *olddev;
+    SCSIDevice *d;
     int rc = -1;
 
-    if (dev->id == -1) {
-        int id;
-        for (id = 0; id < bus->info->ndev; id++) {
-            if (!scsi_device_find(bus, id, 0)) {
-                dev->id = id;
-                break;
-            }
-        }
-    }
-    if (dev->id >= bus->info->ndev) {
+    if (dev->id != -1 && dev->id > bus->info->max_target) {
         error_report("bad scsi device id: %d", dev->id);
         goto err;
     }
 
-    olddev = scsi_device_find(bus, dev->id, dev->lun);
-    if (olddev && dev->lun == olddev->lun) {
-        qdev_free(&olddev->qdev);
+    if (dev->id == -1) {
+        int id = -1;
+        if (dev->lun == -1) {
+            dev->lun = 0;
+        }
+        do {
+            d = scsi_device_find(bus, ++id, dev->lun);
+        } while (d && d->lun == dev->lun && id <= bus->info->max_target);
+        if (id > bus->info->max_target) {
+            error_report("no free target");
+            goto err;
+        }
+        dev->id = id;
+    } else if (dev->lun == -1) {
+        int lun = -1;
+        do {
+            d = scsi_device_find(bus, dev->id, ++lun);
+        } while (d && d->lun == lun && lun < bus->info->max_lun);
+        if (lun > bus->info->max_lun) {
+            error_report("no free lun");
+            goto err;
+        }
+        dev->lun = lun;
+    } else {
+        d = scsi_device_find(bus, dev->id, dev->lun);
+        if (dev->lun == d->lun && dev != d) {
+            qdev_free(&d->qdev);
+        }
     }
 
     dev->info = info;
@@ -115,7 +131,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
     int res = 0, unit;
 
     loc_push_none(&loc);
-    for (unit = 0; unit < bus->info->ndev; unit++) {
+    for (unit = 0; unit < bus->info->max_target; unit++) {
         dinfo = drive_get(IF_SCSI, bus->busnr, unit);
         if (dinfo == NULL) {
             continue;
diff --git a/hw/scsi.h b/hw/scsi.h
index add3d2d..401d8d3 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -98,7 +98,8 @@ struct SCSIDeviceInfo {
 };
 
 struct SCSIBusInfo {
-    int tcq, ndev;
+    int tcq;
+    int max_target, max_lun;
     void (*transfer_data)(SCSIRequest *req, uint32_t arg);
     void (*complete)(SCSIRequest *req, uint32_t arg);
     void (*cancel)(SCSIRequest *req);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index ea3bb08..e6c3581 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -131,9 +131,39 @@ static void vscsi_put_req(vscsi_req *req)
 
 static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
 {
-    /* XXX Figure that one out properly ! This is crackpot */
-    int id = (srp_lun >> 56) & 0x7f;
-    *lun = (srp_lun >> 48) & 0xff;
+    int channel = 0, id = 0;
+
+retry:
+    switch (srp_lun >> 62) {
+    case 0:
+        if ((srp_lun >> 56) != 0) {
+            channel = (srp_lun >> 56) & 0x3f;
+            id = (srp_lun >> 48) & 0xff;
+            srp_lun <<= 16;
+            goto retry;
+        }
+        *lun = (srp_lun >> 48) & 0xff;
+        break;
+
+    case 1:
+        *lun = (srp_lun >> 48) & 0x3fff;
+        break;
+    case 2:
+        channel = (srp_lun >> 53) & 0x7;
+        id = (srp_lun >> 56) & 0x3f;
+        *lun = (srp_lun >> 48) & 0x1f;
+        break;
+    case 3:
+        *lun = -1;
+        return NULL;
+    default:
+        abort();
+    }
+
+    if (channel) {
+        *lun = -1;
+        return NULL;
+    }
     return scsi_device_find(bus, id, *lun);
 }
 
@@ -862,7 +892,8 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
 
 static const struct SCSIBusInfo vscsi_scsi_info = {
     .tcq = true,
-    .ndev = VSCSI_REQ_LIMIT,
+    .max_target = 63, /* logical unit addressing format */
+    .max_lun = 31,
 
     .transfer_data = vscsi_transfer_data,
     .complete = vscsi_command_complete,
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 2c047fa..1a0815a 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -497,7 +497,8 @@ static void usb_msd_password_cb(void *opaque, int err)
 
 static const struct SCSIBusInfo usb_msd_scsi_info = {
     .tcq = false,
-    .ndev = 1,
+    .max_target = 0,
+    .max_lun = 0,
 
     .transfer_data = usb_msd_transfer_data,
     .complete = usb_msd_command_complete,
commit ba74307c5a3c2ff87d4596a10828faf7560d4552
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Sep 14 20:39:36 2011 +0200

    scsi: implement REPORT LUNS for arbitrary LUNs
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 7104e98..a2d57a7 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -170,7 +170,7 @@ typedef struct SCSITargetReq SCSITargetReq;
 struct SCSITargetReq {
     SCSIRequest req;
     int len;
-    uint8_t buf[64];
+    uint8_t buf[2056];
 };
 
 static void store_lun(uint8_t *outbuf, int lun)
@@ -185,23 +185,52 @@ static void store_lun(uint8_t *outbuf, int lun)
 
 static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
 {
-    int len;
+    DeviceState *qdev;
+    int i, len, n;
+    int id;
+    bool found_lun0;
+
     if (r->req.cmd.xfer < 16) {
         return false;
     }
     if (r->req.cmd.buf[2] > 2) {
         return false;
     }
-    len = MIN(sizeof r->buf, r->req.cmd.xfer);
+    id = r->req.dev->id;
+    found_lun0 = false;
+    n = 0;
+    QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
+        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+
+        if (dev->id == id) {
+            if (dev->lun == 0) {
+                found_lun0 = true;
+            }
+            n += 8;
+        }
+    }
+    if (!found_lun0) {
+        n += 8;
+    }
+    len = MIN(n + 8, r->req.cmd.xfer & ~7);
+    if (len > sizeof(r->buf)) {
+        /* TODO: > 256 LUNs? */
+        return false;
+    }
+
     memset(r->buf, 0, len);
-    if (r->req.dev->lun != 0) {
-        r->buf[3] = 16;
-        r->len = 24;
-        store_lun(&r->buf[16], r->req.dev->lun);
-    } else {
-        r->buf[3] = 8;
-        r->len = 16;
+    stl_be_p(&r->buf, n);
+    i = found_lun0 ? 8 : 16;
+    QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
+        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+
+        if (dev->id == id) {
+            store_lun(&r->buf[i], dev->lun);
+            i += 8;
+        }
     }
+    assert(i == n + 8);
+    r->len = len;
     return true;
 }
 
commit f48a7a6e35bb6d50573cfb42f13878c593fb6c0c
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Jul 28 18:02:13 2011 +0200

    scsi: remove devs array from SCSIBus
    
    Change the devs array into a linked list, and add a scsi_device_find
    function to navigate the children list instead.  This lets the SCSI
    bus use more complex addressing, and HBAs can talk to the correct device
    when there are multiple LUNs per target.
    
    scsi_device_find may return another LUN on the same target if none is
    found that matches exactly.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/esp.c b/hw/esp.c
index d3fb1c6..aad290f 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -217,7 +217,8 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
         s->async_len = 0;
     }
 
-    if (target >= ESP_MAX_DEVS || !s->bus.devs[target]) {
+    s->current_dev = scsi_device_find(&s->bus, target, 0);
+    if (!s->current_dev) {
         // No such drive
         s->rregs[ESP_RSTAT] = 0;
         s->rregs[ESP_RINTR] = INTR_DC;
@@ -225,7 +226,6 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
         esp_raise_irq(s);
         return 0;
     }
-    s->current_dev = s->bus.devs[target];
     return dmalen;
 }
 
@@ -233,10 +233,12 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
 {
     int32_t datalen;
     int lun;
+    SCSIDevice *current_lun;
 
     trace_esp_do_busid_cmd(busid);
     lun = busid & 7;
-    s->current_req = scsi_req_new(s->current_dev, 0, lun, buf, NULL);
+    current_lun = scsi_device_find(&s->bus, s->current_dev->id, lun);
+    s->current_req = scsi_req_new(current_lun, 0, lun, buf, NULL);
     datalen = scsi_req_enqueue(s->current_req);
     s->ti_size = datalen;
     if (datalen != 0) {
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 4eeb496..c15f167 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -531,7 +531,7 @@ static void lsi_bad_selection(LSIState *s, uint32_t id)
 /* Initiate a SCSI layer data transfer.  */
 static void lsi_do_dma(LSIState *s, int out)
 {
-    uint32_t count, id;
+    uint32_t count;
     target_phys_addr_t addr;
     SCSIDevice *dev;
 
@@ -542,12 +542,8 @@ static void lsi_do_dma(LSIState *s, int out)
         return;
     }
 
-    id = (s->current->tag >> 8) & 0xf;
-    dev = s->bus.devs[id];
-    if (!dev) {
-        lsi_bad_selection(s, id);
-        return;
-    }
+    dev = s->current->req->dev;
+    assert(dev);
 
     count = s->dbc;
     if (count > s->current->dma_len)
@@ -771,7 +767,7 @@ static void lsi_do_command(LSIState *s)
     s->command_complete = 0;
 
     id = (s->select_tag >> 8) & 0xf;
-    dev = s->bus.devs[id];
+    dev = scsi_device_find(&s->bus, id, s->current_lun);
     if (!dev) {
         lsi_bad_selection(s, id);
         return;
@@ -1202,7 +1198,7 @@ again:
                 }
                 s->sstat0 |= LSI_SSTAT0_WOA;
                 s->scntl1 &= ~LSI_SCNTL1_IARB;
-                if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) {
+                if (!scsi_device_find(&s->bus, id, 0)) {
                     lsi_bad_selection(s, id);
                     break;
                 }
@@ -1684,13 +1680,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
         if (val & LSI_SCNTL1_RST) {
             if (!(s->sstat0 & LSI_SSTAT0_RST)) {
                 DeviceState *dev;
-                int id;
 
-                for (id = 0; id < LSI_MAX_DEVS; id++) {
-                    if (s->bus.devs[id]) {
-                        dev = &s->bus.devs[id]->qdev;
-                        dev->info->reset(dev);
-                    }
+                QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
+                    dev->info->reset(dev);
                 }
                 s->sstat0 |= LSI_SSTAT0_RST;
                 lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
diff --git a/hw/qdev.h b/hw/qdev.h
index a7cc48b..36a4198 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -73,7 +73,7 @@ struct BusState {
     const char *name;
     int allow_hotplug;
     int qdev_allocated;
-    QTAILQ_HEAD(, DeviceState) children;
+    QTAILQ_HEAD(ChildrenHead, DeviceState) children;
     QLIST_ENTRY(BusState) sibling;
 };
 
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index d9d4e18..7104e98 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -37,12 +37,16 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
     SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
     SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
     SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+    SCSIDevice *olddev;
     int rc = -1;
 
     if (dev->id == -1) {
-        for (dev->id = 0; dev->id < bus->info->ndev; dev->id++) {
-            if (bus->devs[dev->id] == NULL)
+        int id;
+        for (id = 0; id < bus->info->ndev; id++) {
+            if (!scsi_device_find(bus, id, 0)) {
+                dev->id = id;
                 break;
+            }
         }
     }
     if (dev->id >= bus->info->ndev) {
@@ -50,17 +54,14 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
         goto err;
     }
 
-    if (bus->devs[dev->id]) {
-        qdev_free(&bus->devs[dev->id]->qdev);
+    olddev = scsi_device_find(bus, dev->id, dev->lun);
+    if (olddev && dev->lun == olddev->lun) {
+        qdev_free(&olddev->qdev);
     }
-    bus->devs[dev->id] = dev;
 
     dev->info = info;
     QTAILQ_INIT(&dev->requests);
     rc = dev->info->init(dev);
-    if (rc != 0) {
-        bus->devs[dev->id] = NULL;
-    }
 
 err:
     return rc;
@@ -69,13 +70,10 @@ err:
 static int scsi_qdev_exit(DeviceState *qdev)
 {
     SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
-    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
 
-    assert(bus->devs[dev->id] != NULL);
-    if (bus->devs[dev->id]->info->destroy) {
-        bus->devs[dev->id]->info->destroy(bus->devs[dev->id]);
+    if (dev->info->destroy) {
+        dev->info->destroy(dev);
     }
-    bus->devs[dev->id] = NULL;
     return 0;
 }
 
@@ -1157,19 +1155,28 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
 static char *scsibus_get_fw_dev_path(DeviceState *dev)
 {
     SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
-    SCSIBus *bus = scsi_bus_from_device(d);
     char path[100];
-    int i;
 
-    for (i = 0; i < bus->info->ndev; i++) {
-        if (bus->devs[i] == d) {
-            break;
-        }
-    }
+    snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev),
+             0, d->id, d->lun);
 
-    assert(i != bus->info->ndev);
+    return strdup(path);
+}
+
+SCSIDevice *scsi_device_find(SCSIBus *bus, int id, int lun)
+{
+    DeviceState *qdev;
+    SCSIDevice *target_dev = NULL;
 
-    snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i);
+    QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
+        SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
 
-    return strdup(path);
+        if (dev->id == id) {
+            if (dev->lun == lun) {
+                return dev;
+            }
+            target_dev = dev;
+        }
+    }
+    return target_dev;
 }
diff --git a/hw/scsi.h b/hw/scsi.h
index b76c4ee..add3d2d 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -110,8 +110,6 @@ struct SCSIBus {
 
     SCSISense unit_attention;
     const SCSIBusInfo *info;
-
-    SCSIDevice *devs[MAX_SCSI_DEVS];
 };
 
 void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
@@ -195,5 +193,6 @@ void scsi_req_abort(SCSIRequest *req, int status);
 void scsi_req_cancel(SCSIRequest *req);
 void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
 int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
+SCSIDevice *scsi_device_find(SCSIBus *bus, int target, int lun);
 
 #endif
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 33ae9b4..ea3bb08 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -129,11 +129,12 @@ static void vscsi_put_req(vscsi_req *req)
     req->active = 0;
 }
 
-static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
+static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
 {
     /* XXX Figure that one out properly ! This is crackpot */
-    *id = (srp_lun >> 56) & 0x7f;
+    int id = (srp_lun >> 56) & 0x7f;
     *lun = (srp_lun >> 48) & 0xff;
+    return scsi_device_find(bus, id, *lun);
 }
 
 static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
@@ -582,14 +583,11 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
 {
     union srp_iu *srp = &req->iu.srp;
     SCSIDevice *sdev;
-    int n, id, lun;
+    int n, lun;
 
-    vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun);
-
-    /* Qemu vs. linux issue with LUNs to be sorted out ... */
-    sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL;
+    sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
     if (!sdev) {
-        dprintf("VSCSI: Command for id %d with no drive\n", id);
+        dprintf("VSCSI: Command for lun %08" PRIx64 " with no drive\n", be64_to_cpu(srp->cmd.lun));
         if (srp->cmd.cdb[0] == INQUIRY) {
             vscsi_inquiry_no_target(s, req);
         } else {
commit d8bb00d6d72eba317f78501434fc37db4968fa31
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Sep 14 09:28:06 2011 +0200

    qdev: switch children device list to QTAILQ
    
    SCSI buses will need to read the children list first-to-last.  This
    requires using a QTAILQ, because hell breaks loose if you just try
    inserting at the tail (thus reversing the order of all existing
    visits from last-to-first to first-to-tail).
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 29f0f76..d9075e6 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -276,7 +276,7 @@ static void piix4_update_hotplug(PIIX4PMState *s)
 
     s->pci0_hotplug_enable = ~0;
 
-    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+    QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
         PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
         PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
         int slot = PCI_SLOT(pdev->devfn);
@@ -486,7 +486,7 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
     PCIDeviceInfo *info;
     int slot = ffs(val) - 1;
 
-    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+    QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
         dev = DO_UPCAST(PCIDevice, qdev, qdev);
         info = container_of(qdev->info, PCIDeviceInfo, qdev);
         if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
diff --git a/hw/i2c.c b/hw/i2c.c
index 49b9ecb..9bcf3e1 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -84,7 +84,7 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
     DeviceState *qdev;
     i2c_slave *slave = NULL;
 
-    QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
         i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
         if (candidate->address == address) {
             slave = candidate;
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index f97775c..675b659 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -86,7 +86,7 @@ HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
     DeviceState *qdev;
     HDACodecDevice *cdev;
 
-    QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (cdev->cad == cad) {
             return cdev;
@@ -490,7 +490,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
     DeviceState *qdev;
     HDACodecDevice *cdev;
 
-    QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (cdev->info->stream) {
             cdev->info->stream(cdev, stream, running, output);
@@ -1114,7 +1114,7 @@ static void intel_hda_reset(DeviceState *dev)
     d->wall_base_ns = qemu_get_clock_ns(vm_clock);
 
     /* reset codecs */
-    QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (qdev->info->reset) {
             qdev->info->reset(qdev);
diff --git a/hw/qdev.c b/hw/qdev.c
index a223d41..50976dd 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -91,7 +91,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
     qdev_prop_set_defaults(dev, dev->info->props);
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
     qdev_prop_set_globals(dev);
-    QLIST_INSERT_HEAD(&bus->children, dev, sibling);
+    QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
     if (qdev_hotplug) {
         assert(bus->allow_hotplug);
         dev->hotplugged = 1;
@@ -408,7 +408,7 @@ void qdev_free(DeviceState *dev)
         if (dev->opts)
             qemu_opts_del(dev->opts);
     }
-    QLIST_REMOVE(dev, sibling);
+    QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
     for (prop = dev->info->props; prop && prop->name; prop++) {
         if (prop->info->free) {
             prop->info->free(dev, prop);
@@ -510,7 +510,7 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
         }
     }
 
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         err = qdev_walk_children(dev, devfn, busfn, opaque);
         if (err < 0) {
             return err;
@@ -560,7 +560,7 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
         return bus;
     }
 
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         QLIST_FOREACH(child, &dev->child_bus, sibling) {
             ret = qbus_find_recursive(child, name, info);
             if (ret) {
@@ -576,7 +576,7 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
     DeviceState *dev, *ret;
     BusState *child;
 
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->id && strcmp(dev->id, id) == 0)
             return dev;
         QLIST_FOREACH(child, &dev->child_bus, sibling) {
@@ -609,7 +609,7 @@ static void qbus_list_dev(BusState *bus)
     const char *sep = " ";
 
     error_printf("devices at \"%s\":", bus->name);
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         error_printf("%s\"%s\"", sep, dev->info->name);
         if (dev->id)
             error_printf("/\"%s\"", dev->id);
@@ -640,17 +640,17 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
      *   (2) driver name
      *   (3) driver alias, if present
      */
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->id  &&  strcmp(dev->id, elem) == 0) {
             return dev;
         }
     }
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (strcmp(dev->info->name, elem) == 0) {
             return dev;
         }
     }
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
             return dev;
         }
@@ -774,7 +774,7 @@ void qbus_create_inplace(BusState *bus, BusInfo *info,
         bus->name = buf;
     }
 
-    QLIST_INIT(&bus->children);
+    QTAILQ_INIT(&bus->children);
     if (parent) {
         QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
         parent->num_child_bus++;
@@ -809,7 +809,7 @@ void qbus_free(BusState *bus)
 {
     DeviceState *dev;
 
-    while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
+    while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
         qdev_free(dev);
     }
     if (bus->parent) {
@@ -878,7 +878,7 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent)
     qdev_printf("bus: %s\n", bus->name);
     indent += 2;
     qdev_printf("type %s\n", bus->info->name);
-    QLIST_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
         qdev_print(mon, dev, indent);
     }
 }
diff --git a/hw/qdev.h b/hw/qdev.h
index aa7ae36..a7cc48b 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -42,7 +42,7 @@ struct DeviceState {
     qemu_irq *gpio_in;
     QLIST_HEAD(, BusState) child_bus;
     int num_child_bus;
-    QLIST_ENTRY(DeviceState) sibling;
+    QTAILQ_ENTRY(DeviceState) sibling;
     int instance_id_alias;
     int alias_required_for_version;
 };
@@ -73,7 +73,7 @@ struct BusState {
     const char *name;
     int allow_hotplug;
     int qdev_allocated;
-    QLIST_HEAD(, DeviceState) children;
+    QTAILQ_HEAD(, DeviceState) children;
     QLIST_ENTRY(BusState) sibling;
 };
 
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index e2f3e32..0ce6406 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -274,7 +274,7 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
     DeviceState *dev;
     int i;
 
-    QLIST_FOREACH(dev, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
         _dev = (VirtIOS390Device *)dev;
         for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
             if (!virtio_queue_get_addr(_dev->vdev, i))
@@ -297,7 +297,7 @@ VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem)
     VirtIOS390Device *_dev;
     DeviceState *dev;
 
-    QLIST_FOREACH(dev, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
         _dev = (VirtIOS390Device *)dev;
         if (_dev->dev_offs == mem) {
             return _dev;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 35818e1..977603f 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -63,7 +63,7 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
     DeviceState *qdev;
     VIOsPAPRDevice *dev = NULL;
 
-    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
         dev = (VIOsPAPRDevice *)qdev;
         if (dev->reg == reg) {
             break;
@@ -588,7 +588,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
         return;
     }
 
-    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
         dev = (VIOsPAPRDevice *)qdev;
         spapr_vio_quiesce_one(dev);
     }
@@ -726,7 +726,7 @@ int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
     DeviceState *qdev;
     int ret = 0;
 
-    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
         VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
 
         ret = vio_make_devnode(dev, fdt);
diff --git a/hw/ssi.c b/hw/ssi.c
index 3f4c5f9..9842fe7 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -25,8 +25,8 @@ static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
     SSIBus *bus;
 
     bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
-    if (QLIST_FIRST(&bus->qbus.children) != dev
-        || QLIST_NEXT(dev, sibling) != NULL) {
+    if (QTAILQ_FIRST(&bus->qbus.children) != dev
+        || QTAILQ_NEXT(dev, sibling) != NULL) {
         hw_error("Too many devices on SSI bus");
     }
 
@@ -61,7 +61,7 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
 {
     DeviceState *dev;
     SSISlave *slave;
-    dev = QLIST_FIRST(&bus->qbus.children);
+    dev = QTAILQ_FIRST(&bus->qbus.children);
     if (!dev) {
         return 0;
     }
commit afd4030c16d290e460cc93f8f9e353516b5451a2
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Sat Aug 13 15:44:45 2011 +0200

    scsi: move tcq/ndev to SCSIBusOps (now SCSIBusInfo)
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/esp.c b/hw/esp.c
index 697c2c5..d3fb1c6 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -720,7 +720,10 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
     *dma_enable = qdev_get_gpio_in(dev, 1);
 }
 
-static const struct SCSIBusOps esp_scsi_ops = {
+static const struct SCSIBusInfo esp_scsi_info = {
+    .tcq = false,
+    .ndev = ESP_MAX_DEVS,
+
     .transfer_data = esp_transfer_data,
     .complete = esp_command_complete,
     .cancel = esp_request_cancelled
@@ -740,7 +743,7 @@ static int esp_init1(SysBusDevice *dev)
 
     qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
 
-    scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, &esp_scsi_ops);
+    scsi_bus_new(&s->bus, &dev->qdev, &esp_scsi_info);
     return scsi_bus_legacy_handle_cmdline(&s->bus);
 }
 
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index e077ec0..4eeb496 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -1686,7 +1686,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
                 DeviceState *dev;
                 int id;
 
-                for (id = 0; id < s->bus.ndev; id++) {
+                for (id = 0; id < LSI_MAX_DEVS; id++) {
                     if (s->bus.devs[id]) {
                         dev = &s->bus.devs[id]->qdev;
                         dev->info->reset(dev);
@@ -2091,7 +2091,10 @@ static int lsi_scsi_uninit(PCIDevice *d)
     return 0;
 }
 
-static const struct SCSIBusOps lsi_scsi_ops = {
+static const struct SCSIBusInfo lsi_scsi_info = {
+    .tcq = true,
+    .ndev = LSI_MAX_DEVS,
+
     .transfer_data = lsi_transfer_data,
     .complete = lsi_command_complete,
     .cancel = lsi_request_cancelled
@@ -2118,7 +2121,7 @@ static int lsi_scsi_init(PCIDevice *dev)
     pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
     QTAILQ_INIT(&s->queue);
 
-    scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, &lsi_scsi_ops);
+    scsi_bus_new(&s->bus, &dev->qdev, &lsi_scsi_info);
     if (!dev->qdev.hotplugged) {
         return scsi_bus_legacy_handle_cmdline(&s->bus);
     }
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 867b1a8..d9d4e18 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -24,14 +24,11 @@ static struct BusInfo scsi_bus_info = {
 static int next_scsi_bus;
 
 /* Create a scsi bus, and attach devices to it.  */
-void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
-                  const SCSIBusOps *ops)
+void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
 {
     qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
     bus->busnr = next_scsi_bus++;
-    bus->tcq = tcq;
-    bus->ndev = ndev;
-    bus->ops = ops;
+    bus->info = info;
     bus->qbus.allow_hotplug = 1;
 }
 
@@ -43,12 +40,12 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
     int rc = -1;
 
     if (dev->id == -1) {
-        for (dev->id = 0; dev->id < bus->ndev; dev->id++) {
+        for (dev->id = 0; dev->id < bus->info->ndev; dev->id++) {
             if (bus->devs[dev->id] == NULL)
                 break;
         }
     }
-    if (dev->id >= bus->ndev) {
+    if (dev->id >= bus->info->ndev) {
         error_report("bad scsi device id: %d", dev->id);
         goto err;
     }
@@ -120,7 +117,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
     int res = 0, unit;
 
     loc_push_none(&loc);
-    for (unit = 0; unit < bus->ndev; unit++) {
+    for (unit = 0; unit < bus->info->ndev; unit++) {
         dinfo = drive_get(IF_SCSI, bus->busnr, unit);
         if (dinfo == NULL) {
             continue;
@@ -265,7 +262,7 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
         r->buf[2] = 5; /* Version */
         r->buf[3] = 2 | 0x10; /* HiSup, response data format */
         r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
-        r->buf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); /* Sync, TCQ.  */
+        r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ.  */
         memcpy(&r->buf[8], "QEMU    ", 8);
         memcpy(&r->buf[16], "QEMU TARGET     ", 16);
         strncpy((char *) &r->buf[32], QEMU_VERSION, 4);
@@ -1062,7 +1059,7 @@ void scsi_req_continue(SCSIRequest *req)
 void scsi_req_data(SCSIRequest *req, int len)
 {
     trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
-    req->bus->ops->transfer_data(req, len);
+    req->bus->info->transfer_data(req, len);
 }
 
 void scsi_req_print(SCSIRequest *req)
@@ -1121,7 +1118,7 @@ void scsi_req_complete(SCSIRequest *req, int status)
 
     scsi_req_ref(req);
     scsi_req_dequeue(req);
-    req->bus->ops->complete(req, req->status);
+    req->bus->info->complete(req, req->status);
     scsi_req_unref(req);
 }
 
@@ -1132,8 +1129,8 @@ void scsi_req_cancel(SCSIRequest *req)
     }
     scsi_req_ref(req);
     scsi_req_dequeue(req);
-    if (req->bus->ops->cancel) {
-        req->bus->ops->cancel(req);
+    if (req->bus->info->cancel) {
+        req->bus->info->cancel(req);
     }
     scsi_req_unref(req);
 }
@@ -1164,13 +1161,13 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev)
     char path[100];
     int i;
 
-    for (i = 0; i < bus->ndev; i++) {
+    for (i = 0; i < bus->info->ndev; i++) {
         if (bus->devs[i] == d) {
             break;
         }
     }
 
-    assert(i != bus->ndev);
+    assert(i != bus->info->ndev);
 
     snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i);
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index dd2b605..50fc3d6 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -564,7 +564,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     }
 
     /* Sync data transfer and TCQ.  */
-    outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0);
+    outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);
     return buflen;
 }
 
diff --git a/hw/scsi.h b/hw/scsi.h
index 7004aaa..b76c4ee 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -9,7 +9,7 @@
 #define SCSI_CMD_BUF_SIZE     16
 
 typedef struct SCSIBus SCSIBus;
-typedef struct SCSIBusOps SCSIBusOps;
+typedef struct SCSIBusInfo SCSIBusInfo;
 typedef struct SCSICommand SCSICommand;
 typedef struct SCSIDevice SCSIDevice;
 typedef struct SCSIDeviceInfo SCSIDeviceInfo;
@@ -97,7 +97,8 @@ struct SCSIDeviceInfo {
     SCSIReqOps reqops;
 };
 
-struct SCSIBusOps {
+struct SCSIBusInfo {
+    int tcq, ndev;
     void (*transfer_data)(SCSIRequest *req, uint32_t arg);
     void (*complete)(SCSIRequest *req, uint32_t arg);
     void (*cancel)(SCSIRequest *req);
@@ -108,14 +109,12 @@ struct SCSIBus {
     int busnr;
 
     SCSISense unit_attention;
-    int tcq, ndev;
-    const SCSIBusOps *ops;
+    const SCSIBusInfo *info;
 
     SCSIDevice *devs[MAX_SCSI_DEVS];
 };
 
-void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
-                  const SCSIBusOps *ops);
+void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
 void scsi_qdev_register(SCSIDeviceInfo *info);
 
 static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index e8426d7..33ae9b4 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -862,7 +862,10 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
     return 0;
 }
 
-static const struct SCSIBusOps vscsi_scsi_ops = {
+static const struct SCSIBusInfo vscsi_scsi_info = {
+    .tcq = true,
+    .ndev = VSCSI_REQ_LIMIT,
+
     .transfer_data = vscsi_transfer_data,
     .complete = vscsi_command_complete,
     .cancel = vscsi_request_cancelled
@@ -883,8 +886,7 @@ static int spapr_vscsi_init(VIOsPAPRDevice *dev)
 
     dev->crq.SendFunc = vscsi_do_crq;
 
-    scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT,
-                 &vscsi_scsi_ops);
+    scsi_bus_new(&s->bus, &dev->qdev, &vscsi_scsi_info);
     if (!dev->qdev.hotplugged) {
         scsi_bus_legacy_handle_cmdline(&s->bus);
     }
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 08d2d2a..2c047fa 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -495,7 +495,10 @@ static void usb_msd_password_cb(void *opaque, int err)
         qdev_unplug(&s->dev.qdev);
 }
 
-static const struct SCSIBusOps usb_msd_scsi_ops = {
+static const struct SCSIBusInfo usb_msd_scsi_info = {
+    .tcq = false,
+    .ndev = 1,
+
     .transfer_data = usb_msd_transfer_data,
     .complete = usb_msd_command_complete,
     .cancel = usb_msd_request_cancelled
@@ -536,7 +539,7 @@ static int usb_msd_initfn(USBDevice *dev)
     }
 
     usb_desc_init(dev);
-    scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, &usb_msd_scsi_ops);
+    scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info);
     s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
     if (!s->scsi_dev) {
         return -1;
commit 3c2f7c12c2e19707cb4e28dd57180f7be3dd4950
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 16:26:51 2011 +0200

    scsi-disk: report media changed via GET EVENT STATUS NOTIFICATION
    
    This adds support for media change notification via the GET EVENT STATUS
    NOTIFICATION command, used by Linux versions 2.6.38 and newer.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 8f8a94d..dd2b605 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -72,6 +72,7 @@ struct SCSIDiskState
     uint32_t removable;
     uint64_t max_lba;
     bool media_changed;
+    bool media_event;
     QEMUBH *bh;
     char *version;
     char *serial;
@@ -687,11 +688,58 @@ fail:
     return -1;
 }
 
-static int scsi_get_event_status_notification(SCSIDiskState *s,
-                                              SCSIDiskReq *r, uint8_t *outbuf)
+static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
 {
-    scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
-    return -1;
+    uint8_t event_code, media_status;
+
+    media_status = 0;
+    if (s->tray_open) {
+        media_status = MS_TRAY_OPEN;
+    } else if (bdrv_is_inserted(s->bs)) {
+        media_status = MS_MEDIA_PRESENT;
+    }
+
+    /* Event notification descriptor */
+    event_code = MEC_NO_CHANGE;
+    if (media_status != MS_TRAY_OPEN && s->media_event) {
+        event_code = MEC_NEW_MEDIA;
+        s->media_event = false;
+    }
+
+    outbuf[0] = event_code;
+    outbuf[1] = media_status;
+
+    /* These fields are reserved, just clear them. */
+    outbuf[2] = 0;
+    outbuf[3] = 0;
+    return 4;
+}
+
+static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r,
+                                              uint8_t *outbuf)
+{
+    int size;
+    uint8_t *buf = r->req.cmd.buf;
+    uint8_t notification_class_request = buf[4];
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    if ((buf[1] & 1) == 0) {
+        /* asynchronous */
+        return -1;
+    }
+
+    size = 4;
+    outbuf[0] = outbuf[1] = 0;
+    outbuf[3] = 1 << GESN_MEDIA; /* supported events */
+    if (notification_class_request & (1 << GESN_MEDIA)) {
+        outbuf[2] = GESN_MEDIA;
+        size += scsi_event_status_media(s, &outbuf[size]);
+    } else {
+        outbuf[2] = 0x80;
+    }
+    stw_be_p(outbuf, size - 4);
+    return size;
 }
 
 static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
@@ -1442,6 +1490,7 @@ static void scsi_cd_change_media_cb(void *opaque, bool load)
     s->media_changed = load;
     s->tray_open = !load;
     s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM);
+    s->media_event = true;
 }
 
 static bool scsi_cd_is_tray_open(void *opaque)
commit ceb792ef299a1bb0144c56fab45631d17c35e7f5
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 15:57:15 2011 +0200

    scsi-disk: support READ DVD STRUCTURE
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 38b196b..8f8a94d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -580,10 +580,110 @@ static inline bool media_is_dvd(SCSIDiskState *s)
     return nb_sectors > CD_MAX_SECTORS;
 }
 
+static inline bool media_is_cd(SCSIDiskState *s)
+{
+    uint64_t nb_sectors;
+    if (s->qdev.type != TYPE_ROM) {
+        return false;
+    }
+    if (!bdrv_is_inserted(s->bs)) {
+        return false;
+    }
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    return nb_sectors <= CD_MAX_SECTORS;
+}
+
 static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
                                    uint8_t *outbuf)
 {
-    scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
+    static const int rds_caps_size[5] = {
+        [0] = 2048 + 4,
+        [1] = 4 + 4,
+        [3] = 188 + 4,
+        [4] = 2048 + 4,
+    };
+
+    uint8_t media = r->req.cmd.buf[1];
+    uint8_t layer = r->req.cmd.buf[6];
+    uint8_t format = r->req.cmd.buf[7];
+    int size = -1;
+
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    if (media != 0) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+        return -1;
+    }
+
+    if (format != 0xff) {
+        if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+            return -1;
+        }
+        if (media_is_cd(s)) {
+            scsi_check_condition(r, SENSE_CODE(INCOMPATIBLE_FORMAT));
+            return -1;
+        }
+        if (format >= ARRAY_SIZE(rds_caps_size)) {
+            return -1;
+        }
+        size = rds_caps_size[format];
+        memset(outbuf, 0, size);
+    }
+
+    switch (format) {
+    case 0x00: {
+        /* Physical format information */
+        uint64_t nb_sectors;
+        if (layer != 0) {
+            goto fail;
+        }
+        bdrv_get_geometry(s->bs, &nb_sectors);
+
+        outbuf[4] = 1;   /* DVD-ROM, part version 1 */
+        outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
+        outbuf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
+        outbuf[7] = 0;   /* default densities */
+
+        stl_be_p(&outbuf[12], (nb_sectors >> 2) - 1); /* end sector */
+        stl_be_p(&outbuf[16], (nb_sectors >> 2) - 1); /* l0 end sector */
+        break;
+    }
+
+    case 0x01: /* DVD copyright information, all zeros */
+        break;
+
+    case 0x03: /* BCA information - invalid field for no BCA info */
+        return -1;
+
+    case 0x04: /* DVD disc manufacturing information, all zeros */
+        break;
+
+    case 0xff: { /* List capabilities */
+        int i;
+        size = 4;
+        for (i = 0; i < ARRAY_SIZE(rds_caps_size); i++) {
+            if (!rds_caps_size[i]) {
+                continue;
+            }
+            outbuf[size] = i;
+            outbuf[size + 1] = 0x40; /* Not writable, readable */
+            stw_be_p(&outbuf[size + 2], rds_caps_size[i]);
+            size += 4;
+        }
+        break;
+     }
+
+    default:
+        return -1;
+    }
+
+    /* Size of buffer, not including 2 byte size field */
+    stw_be_p(outbuf, size - 2);
+    return size;
+
+fail:
     return -1;
 }
 
commit 430ee2f26f01f146f3757467b3f0b802ad309ff8
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 15:22:31 2011 +0200

    scsi-disk: support DVD profile in GET CONFIGURATION
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 116e562..38b196b 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -567,6 +567,19 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     return buflen;
 }
 
+static inline bool media_is_dvd(SCSIDiskState *s)
+{
+    uint64_t nb_sectors;
+    if (s->qdev.type != TYPE_ROM) {
+        return false;
+    }
+    if (!bdrv_is_inserted(s->bs)) {
+        return false;
+    }
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    return nb_sectors > CD_MAX_SECTORS;
+}
+
 static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
                                    uint8_t *outbuf)
 {
@@ -581,17 +594,38 @@ static int scsi_get_event_status_notification(SCSIDiskState *s,
     return -1;
 }
 
-static int scsi_get_configuration(SCSIDiskState *s, SCSIDiskReq *r,
-                                  uint8_t *outbuf)
+static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
 {
+    int current;
+
     if (s->qdev.type != TYPE_ROM) {
         return -1;
     }
-    memset(outbuf, 0, 8);
-    /* ??? This should probably return much more information.  For now
-       just return the basic header indicating the CD-ROM profile.  */
-    outbuf[7] = 8; /* CD-ROM */
-    return 8;
+    current = media_is_dvd(s) ? MMC_PROFILE_DVD_ROM : MMC_PROFILE_CD_ROM;
+    memset(outbuf, 0, 40);
+    stl_be_p(&outbuf[0], 36); /* Bytes after the data length field */
+    stw_be_p(&outbuf[6], current);
+    /* outbuf[8] - outbuf[19]: Feature 0 - Profile list */
+    outbuf[10] = 0x03; /* persistent, current */
+    outbuf[11] = 8; /* two profiles */
+    stw_be_p(&outbuf[12], MMC_PROFILE_DVD_ROM);
+    outbuf[14] = (current == MMC_PROFILE_DVD_ROM);
+    stw_be_p(&outbuf[16], MMC_PROFILE_CD_ROM);
+    outbuf[18] = (current == MMC_PROFILE_CD_ROM);
+    /* outbuf[20] - outbuf[31]: Feature 1 - Core feature */
+    stw_be_p(&outbuf[20], 1);
+    outbuf[22] = 0x08 | 0x03; /* version 2, persistent, current */
+    outbuf[23] = 8;
+    stl_be_p(&outbuf[24], 1); /* SCSI */
+    outbuf[28] = 1; /* DBE = 1, mandatory */
+    /* outbuf[32] - outbuf[39]: Feature 3 - Removable media feature */
+    stw_be_p(&outbuf[32], 3);
+    outbuf[34] = 0x08 | 0x03; /* version 2, persistent, current */
+    outbuf[35] = 4;
+    outbuf[36] = 0x39; /* tray, load=1, eject=1, unlocked at powerup, lock=1 */
+    /* TODO: Random readable, CD read, DVD read, drive serial number,
+       power management */
+    return 40;
 }
 
 static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf)
@@ -1024,7 +1058,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         }
         break;
     case GET_CONFIGURATION:
-        buflen = scsi_get_configuration(s, r, outbuf);
+        buflen = scsi_get_configuration(s, outbuf);
         if (buflen < 0) {
             goto illegal_request;
         }
commit a07c7dcd6f33b668747148ac28c0e147f958aa18
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 15:08:22 2011 +0200

    atapi/scsi-disk: make mode page values coherent between the two
    
    This patch adds to scsi-disk the missing mode page 0x01 for both disk
    and CD-ROM drives, and mode page 0x0e for CD drives only.
    
    A few offsets were wrong in atapi.c.  Also change the 2Ah mode page to
    expose DVD media read capabilities in the IDE cdrom.  This lets you run
    dvd+rw-mediainfo on the virtual DVD drives.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index e898da2..90b6729 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -751,7 +751,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
 
             buf[8] = MODE_PAGE_CAPABILITIES;
             buf[9] = 28 - 10;
-            buf[10] = 0x00;
+            buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
             buf[11] = 0x00;
 
             /* Claim PLAY_AUDIO capability (0x01) since some Linux
@@ -760,14 +760,14 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[13] = 3 << 5;
             buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
             if (s->tray_locked) {
-                buf[6] |= 1 << 1;
+                buf[14] |= 1 << 1;
             }
-            buf[15] = 0x00;
-            cpu_to_ube16(&buf[16], 706);
-            buf[18] = 0;
+            buf[15] = 0x00; /* No volume & mute control, no changer */
+            cpu_to_ube16(&buf[16], 704); /* 4x read speed */
+            buf[18] = 0; /* Two volume levels */
             buf[19] = 2;
-            cpu_to_ube16(&buf[20], 512);
-            cpu_to_ube16(&buf[22], 706);
+            cpu_to_ube16(&buf[20], 512); /* 512k buffer */
+            cpu_to_ube16(&buf[22], 704); /* 4x read speed current */
             buf[24] = 0;
             buf[25] = 0;
             buf[26] = 0;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 8f3ada6..116e562 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -611,6 +611,8 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         [MODE_PAGE_HD_GEOMETRY]            = (1 << TYPE_DISK),
         [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
         [MODE_PAGE_CACHING]                = (1 << TYPE_DISK) | (1 << TYPE_ROM),
+        [MODE_PAGE_R_W_ERROR]              = (1 << TYPE_DISK) | (1 << TYPE_ROM),
+        [MODE_PAGE_AUDIO_CTL]              = (1 << TYPE_ROM),
         [MODE_PAGE_CAPABILITIES]           = (1 << TYPE_ROM),
     };
 
@@ -711,13 +713,26 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         }
         break;
 
+    case MODE_PAGE_R_W_ERROR:
+        p[1] = 10;
+        p[2] = 0x80; /* Automatic Write Reallocation Enabled */
+        if (s->qdev.type == TYPE_ROM) {
+            p[3] = 0x20; /* Read Retry Count */
+        }
+        break;
+
+    case MODE_PAGE_AUDIO_CTL:
+        p[1] = 14;
+        break;
+
     case MODE_PAGE_CAPABILITIES:
         p[1] = 0x14;
         if (page_control == 1) { /* Changeable Values */
             break;
         }
-        p[2] = 3; // CD-R & CD-RW read
-        p[3] = 0; // Writing not supported
+
+        p[2] = 0x3b; /* CD-R & CD-RW read */
+        p[3] = 0; /* Writing not supported */
         p[4] = 0x7f; /* Audio, composite, digital out,
                         mode 2 form 1&2, multi session */
         p[5] = 0xff; /* CD DA, DA accurate, RW supported,
@@ -727,17 +742,17 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         /* Locking supported, jumper present, eject, tray */
         p[7] = 0; /* no volume & mute control, no
                      changer */
-        p[8] = (50 * 176) >> 8; // 50x read speed
+        p[8] = (50 * 176) >> 8; /* 50x read speed */
         p[9] = (50 * 176) & 0xff;
-        p[10] = 0 >> 8; // No volume
-        p[11] = 0 & 0xff;
-        p[12] = 2048 >> 8; // 2M buffer
+        p[10] = 2 >> 8; /* Two volume levels */
+        p[11] = 2 & 0xff;
+        p[12] = 2048 >> 8; /* 2M buffer */
         p[13] = 2048 & 0xff;
-        p[14] = (16 * 176) >> 8; // 16x read speed current
+        p[14] = (16 * 176) >> 8; /* 16x read speed current */
         p[15] = (16 * 176) & 0xff;
-        p[18] = (16 * 176) >> 8; // 16x write speed
+        p[18] = (16 * 176) >> 8; /* 16x write speed */
         p[19] = (16 * 176) & 0xff;
-        p[20] = (16 * 176) >> 8; // 16x write speed current
+        p[20] = (16 * 176) >> 8; /* 16x write speed current */
         p[21] = (16 * 176) & 0xff;
         break;
 
commit a8f4bbe2900f0ebdead032fb8da137777bddd925
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 14:50:15 2011 +0200

    scsi-disk: store valid mode pages in a table
    
    A small refactoring of the MODE SENSE implementation in scsi-disk.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index bdb98ef..8f3ada6 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -607,10 +607,23 @@ static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf)
 static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
                            int page_control)
 {
+    static const int mode_sense_valid[0x3f] = {
+        [MODE_PAGE_HD_GEOMETRY]            = (1 << TYPE_DISK),
+        [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
+        [MODE_PAGE_CACHING]                = (1 << TYPE_DISK) | (1 << TYPE_ROM),
+        [MODE_PAGE_CAPABILITIES]           = (1 << TYPE_ROM),
+    };
+
     BlockDriverState *bdrv = s->bs;
     int cylinders, heads, secs;
     uint8_t *p = *p_outbuf;
 
+    if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) {
+        return -1;
+    }
+
+    p[0] = page;
+
     /*
      * If Changeable Values are requested, a mask denoting those mode parameters
      * that are changeable shall be returned. As we currently don't support
@@ -619,10 +632,6 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
      */
     switch (page) {
     case MODE_PAGE_HD_GEOMETRY:
-        if (s->qdev.type == TYPE_ROM) {
-            return -1;
-        }
-        p[0] = 4;
         p[1] = 0x16;
         if (page_control == 1) { /* Changeable Values */
             break;
@@ -654,10 +663,6 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         break;
 
     case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
-        if (s->qdev.type == TYPE_ROM) {
-            return -1;
-        }
-        p[0] = 5;
         p[1] = 0x1e;
         if (page_control == 1) { /* Changeable Values */
             break;
@@ -707,10 +712,6 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         break;
 
     case MODE_PAGE_CAPABILITIES:
-        if (s->qdev.type != TYPE_ROM) {
-            return -1;
-        }
-        p[0] = 0x2a;
         p[1] = 0x14;
         if (page_control == 1) { /* Changeable Values */
             break;
commit b6c251ab1739cd67817db003e9878f92c3feff2b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 14:33:47 2011 +0200

    scsi-disk: add stubs for more MMC commands
    
    This patch adds a few stub implementations for MMC commands to
    scsi-disk, to be filled in later in the series.  It also adds to
    scsi-defs.h constants for commands implemented by ide/atapi.c,
    when missing.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 5e6c9b7..d0a467a 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -113,6 +113,7 @@
 #define READ_12               0xa8
 #define WRITE_12              0xaa
 #define SERVICE_ACTION_IN_12  0xab
+#define READ_DVD_STRUCTURE    0xad
 #define WRITE_VERIFY_12       0xae
 #define VERIFY_12             0xaf
 #define SEARCH_HIGH_12        0xb0
@@ -122,6 +123,8 @@
 #define SEND_VOLUME_TAG       0xb6
 #define READ_DEFECT_DATA_12   0xb7
 #define SET_CD_SPEED          0xbb
+#define MECHANISM_STATUS      0xbd
+#define READ_CD               0xbe
 
 /*
  * SERVICE ACTION IN subcodes
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 3a08848..bdb98ef 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -567,6 +567,43 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     return buflen;
 }
 
+static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
+                                   uint8_t *outbuf)
+{
+    scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
+    return -1;
+}
+
+static int scsi_get_event_status_notification(SCSIDiskState *s,
+                                              SCSIDiskReq *r, uint8_t *outbuf)
+{
+    scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
+    return -1;
+}
+
+static int scsi_get_configuration(SCSIDiskState *s, SCSIDiskReq *r,
+                                  uint8_t *outbuf)
+{
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    memset(outbuf, 0, 8);
+    /* ??? This should probably return much more information.  For now
+       just return the basic header indicating the CD-ROM profile.  */
+    outbuf[7] = 8; /* CD-ROM */
+    return 8;
+}
+
+static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf)
+{
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    memset(outbuf, 0, 8);
+    outbuf[5] = 1; /* CD-ROM */
+    return 8;
+}
+
 static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
                            int page_control)
 {
@@ -964,12 +1001,29 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         outbuf[7] = 0;
         buflen = 8;
         break;
+    case MECHANISM_STATUS:
+        buflen = scsi_emulate_mechanism_status(s, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
     case GET_CONFIGURATION:
-        memset(outbuf, 0, 8);
-        /* ??? This should probably return much more information.  For now
-           just return the basic header indicating the CD-ROM profile.  */
-        outbuf[7] = 8; // CD-ROM
-        buflen = 8;
+        buflen = scsi_get_configuration(s, r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case GET_EVENT_STATUS_NOTIFICATION:
+        buflen = scsi_get_event_status_notification(s, r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case READ_DVD_STRUCTURE:
+        buflen = scsi_read_dvd_structure(s, r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
         break;
     case SERVICE_ACTION_IN_16:
         /* Service Action In subcommands. */
@@ -1073,7 +1127,10 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case ALLOW_MEDIUM_REMOVAL:
     case READ_CAPACITY_10:
     case READ_TOC:
+    case READ_DVD_STRUCTURE:
     case GET_CONFIGURATION:
+    case GET_EVENT_STATUS_NOTIFICATION:
+    case MECHANISM_STATUS:
     case SERVICE_ACTION_IN_16:
     case VERIFY_10:
         rc = scsi_disk_emulate_command(r);
commit f01b59319c70cb71e6e1003948e49e1aa32e3dae
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Oct 17 16:39:27 2011 +0200

    scsi-disk: fix coding style issues (braces)
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 880cb22..3a08848 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -350,9 +350,9 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
 {
     SCSIDiskState *s = opaque;
 
-    if (!running)
+    if (!running) {
         return;
-
+    }
     if (!s->bh) {
         s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
         qemu_bh_schedule(s->bh);
@@ -403,8 +403,9 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
                     "buffer size %zd\n", req->cmd.xfer);
             pages = buflen++;
             outbuf[buflen++] = 0x00; // list of supported pages (this page)
-            if (s->serial)
+            if (s->serial) {
                 outbuf[buflen++] = 0x80; // unit serial number
+            }
             outbuf[buflen++] = 0x83; // device identification
             if (s->qdev.type == TYPE_DISK) {
                 outbuf[buflen++] = 0xb0; // block limits
@@ -423,10 +424,12 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             }
 
             l = strlen(s->serial);
-            if (l > req->cmd.xfer)
+            if (l > req->cmd.xfer) {
                 l = req->cmd.xfer;
-            if (l > 20)
+            }
+            if (l > 20) {
                 l = 20;
+            }
 
             DPRINTF("Inquiry EVPD[Serial number] "
                     "buffer size %zd\n", req->cmd.xfer);
@@ -441,8 +444,9 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             int max_len = 255 - 8;
             int id_len = strlen(bdrv_get_device_name(s->bs));
 
-            if (id_len > max_len)
+            if (id_len > max_len) {
                 id_len = max_len;
+            }
             DPRINTF("Inquiry EVPD[Device identification] "
                     "buffer size %zd\n", req->cmd.xfer);
 
@@ -525,9 +529,9 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     }
 
     buflen = req->cmd.xfer;
-    if (buflen > SCSI_MAX_INQUIRY_LEN)
+    if (buflen > SCSI_MAX_INQUIRY_LEN) {
         buflen = SCSI_MAX_INQUIRY_LEN;
-
+    }
     memset(outbuf, 0, buflen);
 
     outbuf[0] = s->qdev.type & 0x1f;
@@ -749,8 +753,9 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
             outbuf[7] = 8; /* Block descriptor length  */
         }
         nb_sectors /= s->cluster_size;
-        if (nb_sectors > 0xffffff)
+        if (nb_sectors > 0xffffff) {
             nb_sectors = 0;
+        }
         p[0] = 0; /* media density code */
         p[1] = (nb_sectors >> 16) & 0xff;
         p[2] = (nb_sectors >> 8) & 0xff;
@@ -791,8 +796,9 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
         outbuf[0] = ((buflen - 2) >> 8) & 0xff;
         outbuf[1] = (buflen - 2) & 0xff;
     }
-    if (buflen > r->req.cmd.xfer)
+    if (buflen > r->req.cmd.xfer) {
         buflen = r->req.cmd.xfer;
+    }
     return buflen;
 }
 
@@ -826,8 +832,9 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     default:
         return -1;
     }
-    if (toclen > req->cmd.xfer)
+    if (toclen > req->cmd.xfer) {
         toclen = req->cmd.xfer;
+    }
     return toclen;
 }
 
@@ -879,40 +886,48 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
     outbuf = r->iov.iov_base;
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
-        if (s->tray_open || !bdrv_is_inserted(s->bs))
+        if (s->tray_open || !bdrv_is_inserted(s->bs)) {
             goto not_ready;
+        }
         break;
     case INQUIRY:
         buflen = scsi_disk_emulate_inquiry(req, outbuf);
-        if (buflen < 0)
+        if (buflen < 0) {
             goto illegal_request;
+        }
         break;
     case MODE_SENSE:
     case MODE_SENSE_10:
         buflen = scsi_disk_emulate_mode_sense(r, outbuf);
-        if (buflen < 0)
+        if (buflen < 0) {
             goto illegal_request;
+        }
         break;
     case READ_TOC:
         buflen = scsi_disk_emulate_read_toc(req, outbuf);
-        if (buflen < 0)
+        if (buflen < 0) {
             goto illegal_request;
+        }
         break;
     case RESERVE:
-        if (req->cmd.buf[1] & 1)
+        if (req->cmd.buf[1] & 1) {
             goto illegal_request;
+        }
         break;
     case RESERVE_10:
-        if (req->cmd.buf[1] & 3)
+        if (req->cmd.buf[1] & 3) {
             goto illegal_request;
+        }
         break;
     case RELEASE:
-        if (req->cmd.buf[1] & 1)
+        if (req->cmd.buf[1] & 1) {
             goto illegal_request;
+        }
         break;
     case RELEASE_10:
-        if (req->cmd.buf[1] & 3)
+        if (req->cmd.buf[1] & 3) {
             goto illegal_request;
+        }
         break;
     case START_STOP:
         if (scsi_disk_emulate_start_stop(r) < 0) {
@@ -927,16 +942,18 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
         /* The normal LEN field for this command is zero.  */
         memset(outbuf, 0, 8);
         bdrv_get_geometry(s->bs, &nb_sectors);
-        if (!nb_sectors)
+        if (!nb_sectors) {
             goto not_ready;
+        }
         nb_sectors /= s->cluster_size;
         /* Returned value is the address of the last sector.  */
         nb_sectors--;
         /* Remember the new size for read/write sanity checking. */
         s->max_lba = nb_sectors;
         /* Clip to 2TB, instead of returning capacity modulo 2TB. */
-        if (nb_sectors > UINT32_MAX)
+        if (nb_sectors > UINT32_MAX) {
             nb_sectors = UINT32_MAX;
+        }
         outbuf[0] = (nb_sectors >> 24) & 0xff;
         outbuf[1] = (nb_sectors >> 16) & 0xff;
         outbuf[2] = (nb_sectors >> 8) & 0xff;
@@ -960,8 +977,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
             DPRINTF("SAI READ CAPACITY(16)\n");
             memset(outbuf, 0, req->cmd.xfer);
             bdrv_get_geometry(s->bs, &nb_sectors);
-            if (!nb_sectors)
+            if (!nb_sectors) {
                 goto not_ready;
+            }
             nb_sectors /= s->cluster_size;
             /* Returned value is the address of the last sector.  */
             nb_sectors--;
@@ -1078,8 +1096,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case READ_16:
         len = r->req.cmd.xfer / s->qdev.blocksize;
         DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
-        if (r->req.cmd.lba > s->max_lba)
+        if (r->req.cmd.lba > s->max_lba) {
             goto illegal_lba;
+        }
         r->sector = r->req.cmd.lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         break;
@@ -1094,8 +1113,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
         DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
                 (command & 0xe) == 0xe ? "And Verify " : "",
                 r->req.cmd.lba, len);
-        if (r->req.cmd.lba > s->max_lba)
+        if (r->req.cmd.lba > s->max_lba) {
             goto illegal_lba;
+        }
         r->sector = r->req.cmd.lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         break;
@@ -1168,8 +1188,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
         return -len;
     } else {
-        if (!r->sector_count)
+        if (!r->sector_count) {
             r->sector_count = -1;
+        }
         return len;
     }
 }
commit 8a9c16f69e3ecbcc6e6bc068012986b87412c876
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 16:26:06 2011 +0200

    scsi-disk: report media changed via unit attention sense codes
    
    Building on the previous patch, this one adds a media change callback
    to scsi-disk.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index c190509..867b1a8 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -847,6 +847,11 @@ const struct SCSISense sense_code_RESET = {
     .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
 };
 
+/* Unit attention, No medium */
+const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
+    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
+};
+
 /* Unit attention, Medium may have changed */
 const struct SCSISense sense_code_MEDIUM_CHANGED = {
     .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a6ef060..880cb22 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -71,6 +71,7 @@ struct SCSIDiskState
     int cluster_size;
     uint32_t removable;
     uint64_t max_lba;
+    bool media_changed;
     QEMUBH *bh;
     char *version;
     char *serial;
@@ -1198,7 +1199,21 @@ static void scsi_destroy(SCSIDevice *dev)
 
 static void scsi_cd_change_media_cb(void *opaque, bool load)
 {
-    ((SCSIDiskState *)opaque)->tray_open = !load;
+    SCSIDiskState *s = opaque;
+
+    /*
+     * When a CD gets changed, we have to report an ejected state and
+     * then a loaded state to guests so that they detect tray
+     * open/close and media change events.  Guests that do not use
+     * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
+     * states rely on this behavior.
+     *
+     * media_changed governs the state machine used for unit attention
+     * report.  media_event is used by GET EVENT STATUS NOTIFICATION.
+     */
+    s->media_changed = load;
+    s->tray_open = !load;
+    s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM);
 }
 
 static bool scsi_cd_is_tray_open(void *opaque)
@@ -1217,6 +1232,15 @@ static const BlockDevOps scsi_cd_block_ops = {
     .is_medium_locked = scsi_cd_is_medium_locked,
 };
 
+static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    if (s->media_changed) {
+        s->media_changed = false;
+        s->qdev.unit_attention = SENSE_CODE(MEDIUM_CHANGED);
+    }
+}
+
 static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
@@ -1329,6 +1353,7 @@ static SCSIDeviceInfo scsi_disk_info[] = {
         .init         = scsi_hd_initfn,
         .destroy      = scsi_destroy,
         .alloc_req    = scsi_new_request,
+        .unit_attention_reported = scsi_disk_unit_attention_reported,
         .qdev.props   = (Property[]) {
             DEFINE_SCSI_DISK_PROPERTIES(),
             DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
@@ -1343,6 +1368,7 @@ static SCSIDeviceInfo scsi_disk_info[] = {
         .init         = scsi_cd_initfn,
         .destroy      = scsi_destroy,
         .alloc_req    = scsi_new_request,
+        .unit_attention_reported = scsi_disk_unit_attention_reported,
         .qdev.props   = (Property[]) {
             DEFINE_SCSI_DISK_PROPERTIES(),
             DEFINE_PROP_END_OF_LIST(),
@@ -1356,6 +1382,7 @@ static SCSIDeviceInfo scsi_disk_info[] = {
         .init         = scsi_disk_initfn,
         .destroy      = scsi_destroy,
         .alloc_req    = scsi_new_request,
+        .unit_attention_reported = scsi_disk_unit_attention_reported,
         .qdev.props   = (Property[]) {
             DEFINE_SCSI_DISK_PROPERTIES(),
             DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
diff --git a/hw/scsi.h b/hw/scsi.h
index 6d40b8e..7004aaa 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -161,6 +161,8 @@ extern const struct SCSISense sense_code_IO_ERROR;
 extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
 /* Command aborted, Logical Unit failure */
 extern const struct SCSISense sense_code_LUN_FAILURE;
+/* LUN not ready, Medium not present */
+extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
 /* Unit attention, Power on, reset or bus device reset occurred */
 extern const struct SCSISense sense_code_RESET;
 /* Unit attention, Medium may have changed*/
commit 3653d8c40e04d78eb6b5b069522daf7cc72d4f06
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 16:19:53 2011 +0200

    scsi: notify the device when unit attention is reported
    
    Reporting media change events via unit attention sense codes requires
    a small state machine: first report "NO MEDIUM", then report "MEDIUM MAY
    HAVE CHANGED".  Unfortunately there is no good hooking point for the
    device to notice that its pending unit attention condition has been
    reported.  This patch reworks the generic machinery to add one.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index fc2f823..c190509 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -295,6 +295,13 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
         r->len = scsi_device_get_sense(r->req.dev, r->buf,
                                        MIN(req->cmd.xfer, sizeof r->buf),
                                        (req->cmd.buf[1] & 1) == 0);
+        if (r->req.dev->sense_is_ua) {
+            if (r->req.dev->info->unit_attention_reported) {
+                r->req.dev->info->unit_attention_reported(req->dev);
+            }
+            r->req.dev->sense_len = 0;
+            r->req.dev->sense_is_ua = false;
+        }
         break;
     default:
         scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
@@ -383,7 +390,13 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
             (buf[0] != INQUIRY &&
              buf[0] != REPORT_LUNS &&
              buf[0] != GET_CONFIGURATION &&
-             buf[0] != GET_EVENT_STATUS_NOTIFICATION)) {
+             buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
+
+             /*
+              * If we already have a pending unit attention condition,
+              * report this one before triggering another one.
+              */
+             !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
             req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun,
                                  hba_private);
         } else if (lun != d->lun ||
@@ -479,10 +492,15 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
      *
      * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
      * 10b for HBAs that do not support it (do not call scsi_req_get_sense).
-     * In the latter case, scsi_req_complete clears unit attention conditions
-     * after moving them to the device's sense buffer.
+     * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
      */
-    scsi_clear_unit_attention(req);
+    if (req->dev->sense_is_ua) {
+        if (req->dev->info->unit_attention_reported) {
+            req->dev->info->unit_attention_reported(req->dev);
+        }
+        req->dev->sense_len = 0;
+        req->dev->sense_is_ua = false;
+    }
     return ret;
 }
 
@@ -1082,8 +1100,12 @@ void scsi_req_complete(SCSIRequest *req, int status)
 
     if (req->sense_len) {
         memcpy(req->dev->sense, req->sense, req->sense_len);
+        req->dev->sense_len = req->sense_len;
+        req->dev->sense_is_ua = (req->ops == &reqops_unit_attention);
+    } else {
+        req->dev->sense_len = 0;
+        req->dev->sense_is_ua = false;
     }
-    req->dev->sense_len = req->sense_len;
 
     /*
      * Unit attention state is now stored in the device's sense buffer
diff --git a/hw/scsi.h b/hw/scsi.h
index e8dcabf..6d40b8e 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -62,6 +62,7 @@ struct SCSIDevice
     BlockConf conf;
     SCSIDeviceInfo *info;
     SCSISense unit_attention;
+    bool sense_is_ua;
     uint8_t sense[SCSI_SENSE_BUF_SIZE];
     uint32_t sense_len;
     QTAILQ_HEAD(, SCSIRequest) requests;
@@ -92,6 +93,7 @@ struct SCSIDeviceInfo {
     void (*destroy)(SCSIDevice *s);
     SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
                               void *hba_private);
+    void (*unit_attention_reported)(SCSIDevice *s);
     SCSIReqOps reqops;
 };
 
commit af0e1ea2d32eafd837c51326368ce2d8f36e6871
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Oct 17 16:34:59 2011 +0200

    atapi: cleanup/fix mode sense results
    
    The first two bytes (after the 8-byte ATAPI header) are the mode page
    number and the number of bytes after the length field itself.  Make
    this clear in the code.
    
    The AUDIO_CTL page was filled with wrong values.  It is not anymore in
    MMC, but at least keep the values sane.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 347c38d..e898da2 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -711,8 +711,8 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[6] = 0;
             buf[7] = 0;
 
-            buf[8] = 0x01;
-            buf[9] = 0x06;
+            buf[8] = MODE_PAGE_R_W_ERROR;
+            buf[9] = 16 - 10;
             buf[10] = 0x00;
             buf[11] = 0x05;
             buf[12] = 0x00;
@@ -730,6 +730,8 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[6] = 0;
             buf[7] = 0;
 
+            buf[8] = MODE_PAGE_AUDIO_CTL;
+            buf[9] = 24 - 10;
             /* Fill with CDROM audio volume */
             buf[17] = 0;
             buf[19] = 0;
@@ -747,8 +749,8 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[6] = 0;
             buf[7] = 0;
 
-            buf[8] = 0x2a;
-            buf[9] = 0x12;
+            buf[8] = MODE_PAGE_CAPABILITIES;
+            buf[9] = 28 - 10;
             buf[10] = 0x00;
             buf[11] = 0x00;
 
commit f0f992e6509354e0e9d3bd46681bacb1ff53f62b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 16:00:52 2011 +0200

    atapi: move GESN definitions to scsi-defs.h
    
    As a complement to the previous patch, move definitions for GET EVENT
    STATUS NOTIFICATION from the two functions to scsi-defs.h.
    
    The NCR_* constants are just bit values corresponding to the ENC_*
    values, with no offsets even, so keep just one copy.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index be3b728..347c38d 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -505,19 +505,6 @@ static int ide_dvd_read_structure(IDEState *s, int format,
 static unsigned int event_status_media(IDEState *s,
                                        uint8_t *buf)
 {
-    enum media_event_code {
-        MEC_NO_CHANGE = 0,       /* Status unchanged */
-        MEC_EJECT_REQUESTED,     /* received a request from user to eject */
-        MEC_NEW_MEDIA,           /* new media inserted and ready for access */
-        MEC_MEDIA_REMOVAL,       /* only for media changers */
-        MEC_MEDIA_CHANGED,       /* only for media changers */
-        MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */
-        MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */
-    };
-    enum media_status {
-        MS_TRAY_OPEN = 1,
-        MS_MEDIA_PRESENT = 2,
-    };
     uint8_t event_code, media_status;
 
     media_status = 0;
@@ -564,27 +551,6 @@ static void cmd_get_event_status_notification(IDEState *s,
         uint8_t notification_class;
         uint8_t supported_events;
     } QEMU_PACKED *gesn_event_header;
-
-    enum notification_class_request_type {
-        NCR_RESERVED1 = 1 << 0,
-        NCR_OPERATIONAL_CHANGE = 1 << 1,
-        NCR_POWER_MANAGEMENT = 1 << 2,
-        NCR_EXTERNAL_REQUEST = 1 << 3,
-        NCR_MEDIA = 1 << 4,
-        NCR_MULTI_HOST = 1 << 5,
-        NCR_DEVICE_BUSY = 1 << 6,
-        NCR_RESERVED2 = 1 << 7,
-    };
-    enum event_notification_class_field {
-        ENC_NO_EVENTS = 0,
-        ENC_OPERATIONAL_CHANGE,
-        ENC_POWER_MANAGEMENT,
-        ENC_EXTERNAL_REQUEST,
-        ENC_MEDIA,
-        ENC_MULTIPLE_HOSTS,
-        ENC_DEVICE_BUSY,
-        ENC_RESERVED,
-    };
     unsigned int max_len, used_len;
 
     gesn_cdb = (void *)packet;
@@ -606,8 +572,11 @@ static void cmd_get_event_status_notification(IDEState *s,
      * These are the supported events.
      *
      * We currently only support requests of the 'media' type.
+     * Notification class requests and supported event classes are bitmasks,
+     * but they are build from the same values as the "notification class"
+     * field.
      */
-    gesn_event_header->supported_events = NCR_MEDIA;
+    gesn_event_header->supported_events = 1 << GESN_MEDIA;
 
     /*
      * We use |= below to set the class field; other bits in this byte
@@ -621,8 +590,8 @@ static void cmd_get_event_status_notification(IDEState *s,
      * notification_class_request_type enum above specifies the
      * priority: upper elements are higher prio than lower ones.
      */
-    if (gesn_cdb->class & NCR_MEDIA) {
-        gesn_event_header->notification_class |= ENC_MEDIA;
+    if (gesn_cdb->class & (1 << GESN_MEDIA)) {
+        gesn_event_header->notification_class |= GESN_MEDIA;
         used_len = event_status_media(s, buf);
     } else {
         gesn_event_header->notification_class = 0x80; /* No event available */
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 6bb4df7..5e6c9b7 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -203,6 +203,27 @@
  * of MODE_PAGE_SENSE_POWER */
 #define MODE_PAGE_CDROM                       0x0d
 
+/* Event notification classes for GET EVENT STATUS NOTIFICATION */
+#define GESN_NO_EVENTS                0
+#define GESN_OPERATIONAL_CHANGE       1
+#define GESN_POWER_MANAGEMENT         2
+#define GESN_EXTERNAL_REQUEST         3
+#define GESN_MEDIA                    4
+#define GESN_MULTIPLE_HOSTS           5
+#define GESN_DEVICE_BUSY              6
+
+/* Event codes for MEDIA event status notification */
+#define MEC_NO_CHANGE                 0
+#define MEC_EJECT_REQUESTED           1
+#define MEC_NEW_MEDIA                 2
+#define MEC_MEDIA_REMOVAL             3 /* only for media changers */
+#define MEC_MEDIA_CHANGED             4 /* only for media changers */
+#define MEC_BG_FORMAT_COMPLETED       5 /* MRW or DVD+RW b/g format completed */
+#define MEC_BG_FORMAT_RESTARTED       6 /* MRW or DVD+RW b/g format restarted */
+
+#define MS_TRAY_OPEN                  1
+#define MS_MEDIA_PRESENT              2
+
 /*
  * Based on values from <linux/cdrom.h> but extending CD_MINS
  * to the maximum common size allowed by the Orange's Book ATIP
commit 67cc61e43077eeffc7c95a1bb25d05a12d051c67
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 14:41:56 2011 +0200

    atapi/scsi: unify definitions for MMC
    
    The definitions in ide/internal.h are duplicates, since ATAPI commands
    actually come from SCSI.  Use the ones in scsi-defs.h and move the
    missing ones there.  Two exceptions:
    
    - MODE_PAGE_WRITE_PARMS conflicts with the "flexible disk geometry"
    page in scsi-disk.c.  It is unused, so pick the latter.
    
    - GPCMD_* is left in ide/internal.h, at least for now.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 3f909c3..be3b728 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -154,10 +154,10 @@ void ide_atapi_io_error(IDEState *s, int ret)
 {
     /* XXX: handle more errors */
     if (ret == -ENOMEDIUM) {
-        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+        ide_atapi_cmd_error(s, NOT_READY,
                             ASC_MEDIUM_NOT_PRESENT);
     } else {
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                             ASC_LOGICAL_BLOCK_OOR);
     }
 }
@@ -282,7 +282,7 @@ static void ide_atapi_cmd_check_status(IDEState *s)
 #ifdef DEBUG_IDE_ATAPI
     printf("atapi_cmd_check_status\n");
 #endif
-    s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4);
+    s->error = MC_ERR | (UNIT_ATTENTION << 4);
     s->status = ERR_STAT;
     s->nsector = 0;
     ide_set_irq(s->bus);
@@ -354,7 +354,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
                                        ide_atapi_cmd_read_dma_cb, s);
     if (!s->bus->dma->aiocb) {
         /* Note: media not present is the most likely case */
-        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+        ide_atapi_cmd_error(s, NOT_READY,
                             ASC_MEDIUM_NOT_PRESENT);
         goto eot;
     }
@@ -595,7 +595,7 @@ static void cmd_get_event_status_notification(IDEState *s,
     /* It is fine by the MMC spec to not support async mode operations */
     if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */
         /* Only polling is supported, asynchronous mode is not. */
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                             ASC_INV_FIELD_IN_CMD_PACKET);
         return;
     }
@@ -643,8 +643,8 @@ static void cmd_request_sense(IDEState *s, uint8_t *buf)
     buf[7] = 10;
     buf[12] = s->asc;
 
-    if (s->sense_key == SENSE_UNIT_ATTENTION) {
-        s->sense_key = SENSE_NONE;
+    if (s->sense_key == UNIT_ATTENTION) {
+        s->sense_key = NO_SENSE;
     }
 
     ide_atapi_cmd_reply(s, 18, max_len);
@@ -676,7 +676,7 @@ static void cmd_get_configuration(IDEState *s, uint8_t *buf)
 
     /* only feature 0 is supported */
     if (buf[2] != 0 || buf[3] != 0) {
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                             ASC_INV_FIELD_IN_CMD_PACKET);
         return;
     }
@@ -733,7 +733,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
     switch(action) {
     case 0: /* current values */
         switch(code) {
-        case GPMODE_R_W_ERROR_PAGE: /* error recovery */
+        case MODE_PAGE_R_W_ERROR: /* error recovery */
             cpu_to_ube16(&buf[0], 16 + 6);
             buf[2] = 0x70;
             buf[3] = 0;
@@ -752,7 +752,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[15] = 0x00;
             ide_atapi_cmd_reply(s, 16, max_len);
             break;
-        case GPMODE_AUDIO_CTL_PAGE:
+        case MODE_PAGE_AUDIO_CTL:
             cpu_to_ube16(&buf[0], 24 + 6);
             buf[2] = 0x70;
             buf[3] = 0;
@@ -769,7 +769,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
 
             ide_atapi_cmd_reply(s, 24, max_len);
             break;
-        case GPMODE_CAPABILITIES_PAGE:
+        case MODE_PAGE_CAPABILITIES:
             cpu_to_ube16(&buf[0], 28 + 6);
             buf[2] = 0x70;
             buf[3] = 0;
@@ -813,14 +813,14 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
         goto error_cmd;
     default:
     case 3: /* saved values */
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                             ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
         break;
     }
     return;
 
 error_cmd:
-    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+    ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
 }
 
 static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
@@ -883,7 +883,7 @@ static void cmd_read_cd(IDEState *s, uint8_t* buf)
         ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
         break;
     default:
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                             ASC_INV_FIELD_IN_CMD_PACKET);
         break;
     }
@@ -896,7 +896,7 @@ static void cmd_seek(IDEState *s, uint8_t* buf)
 
     lba = ube32_to_cpu(buf + 2);
     if (lba >= total_sectors) {
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
         return;
     }
 
@@ -912,7 +912,7 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
     if (loej) {
         if (!start && !s->tray_open && s->tray_locked) {
             sense = bdrv_is_inserted(s->bs)
-                ? SENSE_NOT_READY : SENSE_ILLEGAL_REQUEST;
+                ? NOT_READY : ILLEGAL_REQUEST;
             ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
             return;
         }
@@ -971,7 +971,7 @@ static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf)
         break;
     default:
     error_cmd:
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                             ASC_INV_FIELD_IN_CMD_PACKET);
     }
 }
@@ -997,11 +997,11 @@ static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
 
     if (format < 0xff) {
         if (media_is_cd(s)) {
-            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+            ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                                 ASC_INCOMPATIBLE_FORMAT);
             return;
         } else if (!media_present(s)) {
-            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+            ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                                 ASC_INV_FIELD_IN_CMD_PACKET);
             return;
         }
@@ -1017,7 +1017,7 @@ static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
                 ret = ide_dvd_read_structure(s, format, buf, buf);
 
                 if (ret < 0) {
-                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
+                    ide_atapi_cmd_error(s, ILLEGAL_REQUEST, -ret);
                 } else {
                     ide_atapi_cmd_reply(s, ret, max_len);
                 }
@@ -1034,7 +1034,7 @@ static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
         case 0x90: /* TODO: List of recognized format layers */
         case 0xc0: /* TODO: Write protection status */
         default:
-            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+            ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
                                 ASC_INV_FIELD_IN_CMD_PACKET);
             break;
     }
@@ -1106,7 +1106,7 @@ void ide_atapi_cmd(IDEState *s)
      * condition response unless a higher priority status, defined by the drive
      * here, is pending.
      */
-    if (s->sense_key == SENSE_UNIT_ATTENTION &&
+    if (s->sense_key == UNIT_ATTENTION &&
         !(atapi_cmd_table[s->io_buffer[0]].flags & ALLOW_UA)) {
         ide_atapi_cmd_check_status(s);
         return;
@@ -1119,10 +1119,10 @@ void ide_atapi_cmd(IDEState *s)
      * states rely on this behavior.
      */
     if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
-        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+        ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
 
         s->cdrom_changed = 0;
-        s->sense_key = SENSE_UNIT_ATTENTION;
+        s->sense_key = UNIT_ATTENTION;
         s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
         return;
     }
@@ -1131,7 +1131,7 @@ void ide_atapi_cmd(IDEState *s)
     if ((atapi_cmd_table[s->io_buffer[0]].flags & CHECK_READY) &&
         (!media_present(s) || !bdrv_is_inserted(s->bs)))
     {
-        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+        ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
         return;
     }
 
@@ -1141,5 +1141,5 @@ void ide_atapi_cmd(IDEState *s)
         return;
     }
 
-    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE);
+    ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE);
 }
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 29305d3..9a2fd30 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -799,7 +799,7 @@ static void ide_cd_change_cb(void *opaque, bool load)
      * First indicate to the guest that a CD has been removed.  That's
      * done on the next command the guest sends us.
      *
-     * Then we set SENSE_UNIT_ATTENTION, by which the guest will
+     * Then we set UNIT_ATTENTION, by which the guest will
      * detect a new CD in the drive.  See ide_atapi_cmd() for details.
      */
     s->cdrom_changed = 1;
@@ -2027,7 +2027,7 @@ static int ide_drive_post_load(void *opaque, int version_id)
     IDEState *s = opaque;
 
     if (version_id < 3) {
-        if (s->sense_key == SENSE_UNIT_ATTENTION &&
+        if (s->sense_key == UNIT_ATTENTION &&
             s->asc == ASC_MEDIUM_MAY_HAVE_CHANGED) {
             s->cdrom_changed = 1;
         }
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index c39dc05..00b28df 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -11,6 +11,7 @@
 #include "iorange.h"
 #include "dma.h"
 #include "sysemu.h"
+#include "hw/scsi-defs.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -280,71 +281,6 @@ typedef struct IDEDMAOps IDEDMAOps;
 #define GPCMD_GET_MEDIA_STATUS		    0xda
 #define GPCMD_MODE_SENSE_6		    0x1a
 
-/* Mode page codes for mode sense/set */
-#define GPMODE_R_W_ERROR_PAGE		0x01
-#define GPMODE_WRITE_PARMS_PAGE		0x05
-#define GPMODE_AUDIO_CTL_PAGE		0x0e
-#define GPMODE_POWER_PAGE		0x1a
-#define GPMODE_FAULT_FAIL_PAGE		0x1c
-#define GPMODE_TO_PROTECT_PAGE		0x1d
-#define GPMODE_CAPABILITIES_PAGE	0x2a
-#define GPMODE_ALL_PAGES		0x3f
-/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
- * of MODE_SENSE_POWER_PAGE */
-#define GPMODE_CDROM_PAGE		0x0d
-
-/*
- * Based on values from <linux/cdrom.h> but extending CD_MINS
- * to the maximum common size allowed by the Orange's Book ATIP
- *
- * 90 and 99 min CDs are also available but using them as the
- * upper limit reduces the effectiveness of the heuristic to
- * detect DVDs burned to less than 25% of their maximum capacity
- */
-
-/* Some generally useful CD-ROM information */
-#define CD_MINS                       80 /* max. minutes per CD */
-#define CD_SECS                       60 /* seconds per minute */
-#define CD_FRAMES                     75 /* frames per second */
-#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
-#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
-#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
-
-/*
- * The MMC values are not IDE specific and might need to be moved
- * to a common header if they are also needed for the SCSI emulation
- */
-
-/* Profile list from MMC-6 revision 1 table 91 */
-#define MMC_PROFILE_NONE                0x0000
-#define MMC_PROFILE_CD_ROM              0x0008
-#define MMC_PROFILE_CD_R                0x0009
-#define MMC_PROFILE_CD_RW               0x000A
-#define MMC_PROFILE_DVD_ROM             0x0010
-#define MMC_PROFILE_DVD_R_SR            0x0011
-#define MMC_PROFILE_DVD_RAM             0x0012
-#define MMC_PROFILE_DVD_RW_RO           0x0013
-#define MMC_PROFILE_DVD_RW_SR           0x0014
-#define MMC_PROFILE_DVD_R_DL_SR         0x0015
-#define MMC_PROFILE_DVD_R_DL_JR         0x0016
-#define MMC_PROFILE_DVD_RW_DL           0x0017
-#define MMC_PROFILE_DVD_DDR             0x0018
-#define MMC_PROFILE_DVD_PLUS_RW         0x001A
-#define MMC_PROFILE_DVD_PLUS_R          0x001B
-#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
-#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
-#define MMC_PROFILE_BD_ROM              0x0040
-#define MMC_PROFILE_BD_R_SRM            0x0041
-#define MMC_PROFILE_BD_R_RRM            0x0042
-#define MMC_PROFILE_BD_RE               0x0043
-#define MMC_PROFILE_HDDVD_ROM           0x0050
-#define MMC_PROFILE_HDDVD_R             0x0051
-#define MMC_PROFILE_HDDVD_RAM           0x0052
-#define MMC_PROFILE_HDDVD_RW            0x0053
-#define MMC_PROFILE_HDDVD_R_DL          0x0058
-#define MMC_PROFILE_HDDVD_RW_DL         0x005A
-#define MMC_PROFILE_INVALID             0xFFFF
-
 #define ATAPI_INT_REASON_CD             0x01 /* 0 = data transfer */
 #define ATAPI_INT_REASON_IO             0x02 /* 1 = transfer to the host */
 #define ATAPI_INT_REASON_REL            0x04
@@ -366,11 +302,6 @@ typedef struct IDEDMAOps IDEDMAOps;
 #define CFA_INVALID_ADDRESS     0x21
 #define CFA_ADDRESS_OVERFLOW    0x2f
 
-#define SENSE_NONE            0
-#define SENSE_NOT_READY       2
-#define SENSE_ILLEGAL_REQUEST 5
-#define SENSE_UNIT_ATTENTION  6
-
 #define SMART_READ_DATA       0xd0
 #define SMART_READ_THRESH     0xd1
 #define SMART_ATTR_AUTOSAVE   0xd2
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 37b8239..70b3342 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -87,7 +87,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
     if (!m->aiocb) {
         qemu_sglist_destroy(&s->sg);
         /* Note: media not present is the most likely case */
-        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+        ide_atapi_cmd_error(s, NOT_READY,
                             ASC_MEDIUM_NOT_PRESENT);
         goto done;
     }
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index aca65a1..fc2f823 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -800,7 +800,7 @@ const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
 };
 
 /* Illegal request, Incompatible medium installed */
-const struct SCSISense sense_code_INCOMPATIBLE_MEDIUM = {
+const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
     .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
 };
 
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index bfe9392..6bb4df7 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -188,3 +188,69 @@
 #define TYPE_INACTIVE       0x20
 #define TYPE_NO_LUN         0x7f
 
+/* Mode page codes for mode sense/set */
+#define MODE_PAGE_R_W_ERROR                   0x01
+#define MODE_PAGE_HD_GEOMETRY                 0x04
+#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY      0x05
+#define MODE_PAGE_CACHING                     0x08
+#define MODE_PAGE_AUDIO_CTL                   0x0e
+#define MODE_PAGE_POWER                       0x1a
+#define MODE_PAGE_FAULT_FAIL                  0x1c
+#define MODE_PAGE_TO_PROTECT                  0x1d
+#define MODE_PAGE_CAPABILITIES                0x2a
+#define MODE_PAGE_ALLS                        0x3f
+/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
+ * of MODE_PAGE_SENSE_POWER */
+#define MODE_PAGE_CDROM                       0x0d
+
+/*
+ * Based on values from <linux/cdrom.h> but extending CD_MINS
+ * to the maximum common size allowed by the Orange's Book ATIP
+ *
+ * 90 and 99 min CDs are also available but using them as the
+ * upper limit reduces the effectiveness of the heuristic to
+ * detect DVDs burned to less than 25% of their maximum capacity
+ */
+
+/* Some generally useful CD-ROM information */
+#define CD_MINS                       80 /* max. minutes per CD */
+#define CD_SECS                       60 /* seconds per minute */
+#define CD_FRAMES                     75 /* frames per second */
+#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+
+/*
+ * The MMC values are not IDE specific and might need to be moved
+ * to a common header if they are also needed for the SCSI emulation
+ */
+
+/* Profile list from MMC-6 revision 1 table 91 */
+#define MMC_PROFILE_NONE                0x0000
+#define MMC_PROFILE_CD_ROM              0x0008
+#define MMC_PROFILE_CD_R                0x0009
+#define MMC_PROFILE_CD_RW               0x000A
+#define MMC_PROFILE_DVD_ROM             0x0010
+#define MMC_PROFILE_DVD_R_SR            0x0011
+#define MMC_PROFILE_DVD_RAM             0x0012
+#define MMC_PROFILE_DVD_RW_RO           0x0013
+#define MMC_PROFILE_DVD_RW_SR           0x0014
+#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+#define MMC_PROFILE_DVD_RW_DL           0x0017
+#define MMC_PROFILE_DVD_DDR             0x0018
+#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+#define MMC_PROFILE_DVD_PLUS_R          0x001B
+#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+#define MMC_PROFILE_BD_ROM              0x0040
+#define MMC_PROFILE_BD_R_SRM            0x0041
+#define MMC_PROFILE_BD_R_RRM            0x0042
+#define MMC_PROFILE_BD_RE               0x0043
+#define MMC_PROFILE_HDDVD_ROM           0x0050
+#define MMC_PROFILE_HDDVD_R             0x0051
+#define MMC_PROFILE_HDDVD_RAM           0x0052
+#define MMC_PROFILE_HDDVD_RW            0x0053
+#define MMC_PROFILE_HDDVD_R_DL          0x0058
+#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+#define MMC_PROFILE_INVALID             0xFFFF
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9c62569..a6ef060 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -576,7 +576,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
      * The buffer was already menset to zero by the caller of this function.
      */
     switch (page) {
-    case 4: /* Rigid disk device geometry page. */
+    case MODE_PAGE_HD_GEOMETRY:
         if (s->qdev.type == TYPE_ROM) {
             return -1;
         }
@@ -611,7 +611,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         p[21] = 5400 & 0xff;
         break;
 
-    case 5: /* Flexible disk device geometry page. */
+    case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
         if (s->qdev.type == TYPE_ROM) {
             return -1;
         }
@@ -653,7 +653,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         p[29] = 5400 & 0xff;
         break;
 
-    case 8: /* Caching page.  */
+    case MODE_PAGE_CACHING:
         p[0] = 8;
         p[1] = 0x12;
         if (page_control == 1) { /* Changeable Values */
@@ -664,7 +664,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         }
         break;
 
-    case 0x2a: /* CD Capabilities and Mechanical Status page. */
+    case MODE_PAGE_CAPABILITIES:
         if (s->qdev.type != TYPE_ROM) {
             return -1;
         }
commit 7e218df5181f1c26d52ef525b30a416c60a2160b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Sep 19 17:19:21 2011 +0200

    scsi: pass correct sense code for ENOMEDIUM
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 6909578..9c62569 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -231,6 +231,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
         bdrv_iostatus_set_err(s->bs, error);
     } else {
         switch (error) {
+        case ENOMEDIUM:
+            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+            break;
         case ENOMEM:
             scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE));
             break;
commit d99902287c0c57219b3b33c713f14d55124b0002
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Fri Oct 28 20:13:39 2011 +1100

    Documentation: Add syntax for using sheepdog devices
    
    Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-options.hx b/qemu-options.hx
index c55080c..8be6f4b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1778,6 +1778,33 @@ Example for Unix Domain Sockets
 qemu --drive file=nbd:unix:/tmp/nbd-socket
 @end example
 
+ at item Sheepdog
+Sheepdog is a distributed storage system for QEMU.
+QEMU supports using either local sheepdog devices or remote networked
+devices.
+
+Syntax for specifying a sheepdog device
+ at table @list
+``sheepdog:<vdiname>''
+
+``sheepdog:<vdiname>:<snapid>''
+
+``sheepdog:<vdiname>:<tag>''
+
+``sheepdog:<host>:<port>:<vdiname>''
+
+``sheepdog:<host>:<port>:<vdiname>:<snapid>''
+
+``sheepdog:<host>:<port>:<vdiname>:<tag>''
+ at end table
+
+Example
+ at example
+qemu --drive file=sheepdog:192.0.2.1:30000:MyVirtualMachine
+ at end example
+
+See also @url{http://http://www.osrg.net/sheepdog/}.
+
 @end table
 ETEXI
 
commit 03f541bd6eacdc6c2893f72b975257c89cab2b74
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Oct 27 10:54:28 2011 +0100

    block: reinitialize across bdrv_close()/bdrv_open()
    
    Several BlockDriverState fields are not being reinitialized across
    bdrv_close()/bdrv_open().  Make sure they are reset to their default
    values.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index cb37086..96f3c3f 100644
--- a/block.c
+++ b/block.c
@@ -472,10 +472,13 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
     bs->total_sectors = 0;
     bs->encrypted = 0;
     bs->valid_key = 0;
+    bs->sg = 0;
     bs->open_flags = flags;
+    bs->growable = 0;
     bs->buffer_alignment = 512;
 
     pstrcpy(bs->filename, sizeof(bs->filename), filename);
+    bs->backing_file[0] = '\0';
 
     if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
         return -ENOTSUP;
@@ -484,8 +487,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
     bs->drv = drv;
     bs->opaque = g_malloc0(drv->instance_size);
 
-    if (flags & BDRV_O_CACHE_WB)
-        bs->enable_write_cache = 1;
+    bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
 
     /*
      * Clear flags that are internal to the block layer before opening the
commit e7c637967e6aad195b5f30cfd995913c9e0b4666
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Oct 27 10:54:27 2011 +0100

    block: set bs->read_only before .bdrv_open()
    
    Several block drivers set bs->read_only in .bdrv_open() but
    block.c:bdrv_open_common() clobbers its value.  Additionally, QED uses
    bdrv_is_read_only() in .bdrv_open() to decide whether to perform
    consistency checks.
    
    The correct ordering is to initialize bs->read_only from the open flags
    before calling .bdrv_open().  This way block drivers can override it if
    necessary and can use bdrv_is_read_only() in .bdrv_open().
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index d5ec0be..cb37086 100644
--- a/block.c
+++ b/block.c
@@ -500,6 +500,8 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
         open_flags |= BDRV_O_RDWR;
     }
 
+    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
+
     /* Open the image, either directly or using a protocol */
     if (drv->bdrv_file_open) {
         ret = drv->bdrv_file_open(bs, filename, open_flags);
@@ -514,8 +516,6 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
         goto free_and_fail;
     }
 
-    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
-
     ret = refresh_total_sectors(bs, bs->total_sectors);
     if (ret < 0) {
         goto free_and_fail;
commit b46578555c4bce64e3daba4591334aba2d12c156
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Oct 27 10:54:26 2011 +0100

    qemu-io: delete bs instead of leaking it
    
    Using bdrv_close() is not enough to free a BlockDriverState.  Since we
    explicitly create it with bdrv_new(), use bdrv_delete() to close and
    delete it.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-io.c b/qemu-io.c
index c45a413..5af887e 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1582,7 +1582,7 @@ static const cmdinfo_t map_cmd = {
 
 static int close_f(int argc, char **argv)
 {
-    bdrv_close(bs);
+    bdrv_delete(bs);
     bs = NULL;
     return 0;
 }
@@ -1611,6 +1611,7 @@ static int openfile(char *name, int flags, int growable)
 
         if (bdrv_open(bs, name, flags, NULL) < 0) {
             fprintf(stderr, "%s: can't open device %s\n", progname, name);
+            bdrv_delete(bs);
             bs = NULL;
             return 1;
         }
@@ -1834,7 +1835,7 @@ int main(int argc, char **argv)
     qemu_aio_flush();
 
     if (bs) {
-        bdrv_close(bs);
+        bdrv_delete(bs);
     }
     return 0;
 }
commit c95de7e2c40da4235ceda6d134ae069dae80157e
Author: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Date:   Thu Oct 27 17:22:28 2011 +0800

    block: fix qcow2_co_flush deadlock
    
    If qcow2_cache_flush failed, s->lock will not be unlock.
    
    Signed-off-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index a181932..ef057d3 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1113,11 +1113,13 @@ static int qcow2_co_flush(BlockDriverState *bs)
     qemu_co_mutex_lock(&s->lock);
     ret = qcow2_cache_flush(bs, s->l2_table_cache);
     if (ret < 0) {
+        qemu_co_mutex_unlock(&s->lock);
         return ret;
     }
 
     ret = qcow2_cache_flush(bs, s->refcount_block_cache);
     if (ret < 0) {
+        qemu_co_mutex_unlock(&s->lock);
         return ret;
     }
     qemu_co_mutex_unlock(&s->lock);
commit 08ae330e1754bf03df1388065ea508dc089ab3fd
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Thu Oct 27 20:33:21 2011 +1100

    Documentation: Describe NBD URL syntax
    
    This patch adds a short description of how to specify a NBD device
    to QEMU.
    Syntax for both TCP and Unix Domain Sockets are provided as well
    as examples.
    
    Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-options.hx b/qemu-options.hx
index 424bae9..c55080c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1757,6 +1757,27 @@ qemu --drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
 iSCSI support is an optional feature of QEMU and only available when
 compiled and linked against libiscsi.
 
+ at item NBD
+QEMU supports NBD (Network Block Devices) both using TCP protocol as well
+as Unix Domain Sockets.
+
+Syntax for specifying a NBD device using TCP
+``nbd:<server-ip>:<port>[:exportname=<export>]''
+
+Syntax for specifying a NBD device using Unix Domain Sockets
+``nbd:unix:<domain-socket>[:exportname=<export>]''
+
+
+Example for TCP
+ at example
+qemu --drive file=nbd:192.0.2.1:30000
+ at end example
+
+Example for Unix Domain Sockets
+ at example
+qemu --drive file=nbd:unix:/tmp/nbd-socket
+ at end example
+
 @end table
 ETEXI
 
commit 93897b9fd43548e9c15cf8bece2d9e5174b01fc7
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Oct 26 12:25:52 2011 +0200

    vmdk: Fix possible segfaults
    
    Data we read from the disk isn't necessarily null terminated and may not
    contain the string we're looking for. The code needs to be a bit more careful
    here.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index fa0e8bd..8caaf0b 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -227,6 +227,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
         cid_str_size = sizeof("CID");
     }
 
+    desc[DESC_SIZE - 1] = '\0';
     p_name = strstr(desc, cid_str);
     if (p_name != NULL) {
         p_name += cid_str_size;
@@ -243,13 +244,17 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
     BDRVVmdkState *s = bs->opaque;
     int ret;
 
-    memset(desc, 0, sizeof(desc));
     ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
     if (ret < 0) {
         return ret;
     }
 
+    desc[DESC_SIZE - 1] = '\0';
     tmp_str = strstr(desc, "parentCID");
+    if (tmp_str == NULL) {
+        return -EINVAL;
+    }
+
     pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
     p_name = strstr(desc, "CID");
     if (p_name != NULL) {
commit 99f1835d9bc744f98370254600530e66f32e6d81
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Oct 26 12:25:25 2011 +0200

    vmdk: Improve error handling
    
    Return the right error values in some more places.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 6cdbfb7..fa0e8bd 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -212,8 +212,10 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
     const char *p_name, *cid_str;
     size_t cid_str_size;
     BDRVVmdkState *s = bs->opaque;
+    int ret;
 
-    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
+    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
         return 0;
     }
 
@@ -239,10 +241,12 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
     char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
     char *p_name, *tmp_str;
     BDRVVmdkState *s = bs->opaque;
+    int ret;
 
     memset(desc, 0, sizeof(desc));
-    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
-        return -EIO;
+    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
+        return ret;
     }
 
     tmp_str = strstr(desc, "parentCID");
@@ -254,9 +258,11 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
         pstrcat(desc, sizeof(desc), tmp_desc);
     }
 
-    if (bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE) < 0) {
-        return -EIO;
+    ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
+        return ret;
     }
+
     return 0;
 }
 
@@ -1109,7 +1115,10 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
         /* update CID on the first write every time the virtual disk is
          * opened */
         if (!s->cid_updated) {
-            vmdk_write_cid(bs, time(NULL));
+            ret = vmdk_write_cid(bs, time(NULL));
+            if (ret < 0) {
+                return ret;
+            }
             s->cid_updated = true;
         }
     }
commit bac8d7b45dd855759204117e5a05452ede01bbab
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Oct 26 12:22:40 2011 +0200

    vmdk: Fix use of uninitialised value
    
    In error cases, cid is never set.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 6be592f..6cdbfb7 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -208,7 +208,7 @@ static void vmdk_free_last_extent(BlockDriverState *bs)
 static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
 {
     char desc[DESC_SIZE];
-    uint32_t cid;
+    uint32_t cid = 0;
     const char *p_name, *cid_str;
     size_t cid_str_size;
     BDRVVmdkState *s = bs->opaque;
commit fb60105d4942a26f571b1be92a8b9e7528d0c4d8
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Oct 26 11:52:47 2011 +0200

    ide: Fix off-by-one error in array index check
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 280a117..29305d3 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2039,7 +2039,7 @@ static int ide_drive_pio_post_load(void *opaque, int version_id)
 {
     IDEState *s = opaque;
 
-    if (s->end_transfer_fn_idx > ARRAY_SIZE(transfer_end_table)) {
+    if (s->end_transfer_fn_idx >= ARRAY_SIZE(transfer_end_table)) {
         return -EINVAL;
     }
     s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
commit 64ebe71aa0e498d24e8c02b133192142fce3a0d0
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Oct 26 11:21:50 2011 +0200

    qcow: Fix bdrv_write_compressed error handling
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/block/qcow.c b/block/qcow.c
index ab36b29..35e21eb 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -736,8 +736,6 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
         return -EINVAL;
 
     out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
-    if (!out_buf)
-        return -1;
 
     /* best compression, small window, no zlib header */
     memset(&strm, 0, sizeof(strm));
@@ -745,8 +743,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
                        Z_DEFLATED, -12,
                        9, Z_DEFAULT_STRATEGY);
     if (ret != 0) {
-        g_free(out_buf);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
 
     strm.avail_in = s->cluster_size;
@@ -756,9 +754,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 
     ret = deflate(&strm, Z_FINISH);
     if (ret != Z_STREAM_END && ret != Z_OK) {
-        g_free(out_buf);
         deflateEnd(&strm);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
     out_len = strm.next_out - out_buf;
 
@@ -766,19 +764,29 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 
     if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
         /* could not compress: write normal cluster */
-        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        if (ret < 0) {
+            goto fail;
+        }
     } else {
         cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
                                             out_len, 0, 0);
+        if (cluster_offset == 0) {
+            ret = -EIO;
+            goto fail;
+        }
+
         cluster_offset &= s->cluster_offset_mask;
-        if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
-            g_free(out_buf);
-            return -1;
+        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
+        if (ret < 0) {
+            goto fail;
         }
     }
 
+    ret = 0;
+fail:
     g_free(out_buf);
-    return 0;
+    return ret;
 }
 
 static coroutine_fn int qcow_co_flush(BlockDriverState *bs)
commit 2b5728164fcf5211bbae8d3c2fc6df62dd6b2295
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Oct 26 11:03:01 2011 +0200

    block: Fix bdrv_open use after free
    
    tmp_filename was used outside the block it was defined in, i.e. after it went
    out of scope. Move its declaration to the top level.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index f86984f..d5ec0be 100644
--- a/block.c
+++ b/block.c
@@ -571,6 +571,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
               BlockDriver *drv)
 {
     int ret;
+    char tmp_filename[PATH_MAX];
 
     if (flags & BDRV_O_SNAPSHOT) {
         BlockDriverState *bs1;
@@ -578,7 +579,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         int is_protocol = 0;
         BlockDriver *bdrv_qcow2;
         QEMUOptionParameter *options;
-        char tmp_filename[PATH_MAX];
         char backing_filename[PATH_MAX];
 
         /* if snapshot, we create a temporary backing file and open it
commit 3574c608195c10f4ac48bb6a27d1c5e2c5f9ac3a
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Oct 26 11:02:11 2011 +0200

    block: Remove dead code
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 70aab63..f86984f 100644
--- a/block.c
+++ b/block.c
@@ -2028,11 +2028,7 @@ const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
 void bdrv_get_backing_filename(BlockDriverState *bs,
                                char *filename, int filename_size)
 {
-    if (!bs->backing_file) {
-        pstrcpy(filename, filename_size, "");
-    } else {
-        pstrcpy(filename, filename_size, bs->backing_file);
-    }
+    pstrcpy(filename, filename_size, bs->backing_file);
 }
 
 int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
commit 3789985f406ecb99f7d3e6521bb4310228f0577c
Author: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
Date:   Thu Oct 27 14:58:57 2011 +0800

    qcow2: fix some errors and typo in qcow2.txt
    
    Signed-off-by: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
index 8fc3cb2..e792953 100644
--- a/docs/specs/qcow2.txt
+++ b/docs/specs/qcow2.txt
@@ -108,8 +108,8 @@ as follows:
 
     refcount_block_entries = (cluster_size / sizeof(uint16_t))
 
-    refcount_block_index = (offset / cluster_size) % refcount_table_entries
-    refcount_table_index = (offset / cluster_size) / refcount_table_entries
+    refcount_block_index = (offset / cluster_size) % refcount_block_entries
+    refcount_table_index = (offset / cluster_size) / refcount_block_entries
 
     refcount_block = load_cluster(refcount_table[refcount_table_index]);
     return refcount_block[refcount_block_index];
@@ -211,7 +211,7 @@ switch the active L1 table, so that a different set of host clusters are
 exposed to the guest.
 
 When creating a snapshot, the L1 table should be copied and the refcount of all
-L2 tables and clusters reachable form this L1 table must be increased, so that
+L2 tables and clusters reachable from this L1 table must be increased, so that
 a write causes a COW and isn't visible in other snapshots.
 
 When loading a snapshot, bit 63 of all entries in the new active L1 table and
commit c794b4e0fd9ef8d72b068614dcdb2418c105d5cc
Author: Eric Sunshine <sunshine at sunshineco.com>
Date:   Wed Oct 26 15:51:18 2011 -0400

    Teach block/vdi about "discarded" (no longer allocated) blocks
    
    An entry in the VDI block map will hold an offset to the actual block if
    the block is allocated, or one of two specially-interpreted values if
    not allocated. Using VirtualBox terminology, value VDI_IMAGE_BLOCK_FREE
    (0xffffffff) represents a never-allocated block (semantically arbitrary
    content).  VDI_IMAGE_BLOCK_ZERO (0xfffffffe) represents a "discarded"
    block (semantically zero-filled).  block/vdi knows only about
    VDI_IMAGE_BLOCK_FREE.  Teach it about VDI_IMAGE_BLOCK_ZERO.
    
    Signed-off-by: Eric Sunshine <sunshine at sunshineco.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vdi.c b/block/vdi.c
index 883046d..523a640 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -114,8 +114,13 @@ void uuid_unparse(const uuid_t uu, char *out);
  */
 #define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
 
-/* Unallocated blocks use this index (no need to convert endianness). */
-#define VDI_UNALLOCATED UINT32_MAX
+/* A never-allocated block; semantically arbitrary content. */
+#define VDI_UNALLOCATED 0xffffffffU
+
+/* A discarded (no longer allocated) block; semantically zero-filled. */
+#define VDI_DISCARDED   0xfffffffeU
+
+#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
 
 #if !defined(CONFIG_UUID)
 void uuid_generate(uuid_t out)
@@ -307,10 +312,10 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
     /* Check block map and value of blocks_allocated. */
     for (block = 0; block < s->header.blocks_in_image; block++) {
         uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
-        if (bmap_entry != VDI_UNALLOCATED) {
+        if (VDI_IS_ALLOCATED(bmap_entry)) {
             if (bmap_entry < s->header.blocks_in_image) {
                 blocks_allocated++;
-                if (bmap[bmap_entry] == VDI_UNALLOCATED) {
+                if (!VDI_IS_ALLOCATED(bmap[bmap_entry])) {
                     bmap[bmap_entry] = bmap_entry;
                 } else {
                     fprintf(stderr, "ERROR: block index %" PRIu32
@@ -472,7 +477,7 @@ static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
         n_sectors = nb_sectors;
     }
     *pnum = n_sectors;
-    return bmap_entry != VDI_UNALLOCATED;
+    return VDI_IS_ALLOCATED(bmap_entry);
 }
 
 static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
@@ -603,7 +608,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
     /* prepare next AIO request */
     acb->n_sectors = n_sectors;
     bmap_entry = le32_to_cpu(s->bmap[block_index]);
-    if (bmap_entry == VDI_UNALLOCATED) {
+    if (!VDI_IS_ALLOCATED(bmap_entry)) {
         /* Block not allocated, return zeros, no need to wait. */
         memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
         ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
@@ -685,7 +690,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
         if (acb->header_modified) {
             VdiHeader *header = acb->block_buffer;
             logout("now writing modified header\n");
-            assert(acb->bmap_first != VDI_UNALLOCATED);
+            assert(VDI_IS_ALLOCATED(acb->bmap_first));
             *header = s->header;
             vdi_header_to_le(header);
             acb->header_modified = 0;
@@ -699,7 +704,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
                 goto done;
             }
             return;
-        } else if (acb->bmap_first != VDI_UNALLOCATED) {
+        } else if (VDI_IS_ALLOCATED(acb->bmap_first)) {
             /* One or more new blocks were allocated. */
             uint64_t offset;
             uint32_t bmap_first;
@@ -749,7 +754,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
     /* prepare next AIO request */
     acb->n_sectors = n_sectors;
     bmap_entry = le32_to_cpu(s->bmap[block_index]);
-    if (bmap_entry == VDI_UNALLOCATED) {
+    if (!VDI_IS_ALLOCATED(bmap_entry)) {
         /* Allocate new block and write to it. */
         uint64_t offset;
         uint8_t *block;
commit 0f5314a2c8eeb1b1e775b480e252053157069cf7
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Wed Oct 26 23:51:37 2011 +1100

    Documentation: Add iSCSI section
    
    Add new section for device URL syntax for special files and describe the iSCSI
    URL with examples
    
    Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-options.hx b/qemu-options.hx
index 5d2a776..424bae9 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -148,6 +148,9 @@ Define a new drive. Valid options are:
 This option defines which disk image (@pxref{disk_images}) to use with
 this drive. If the filename contains comma, you must double it
 (for instance, "file=my,,file" to use file "my,file").
+
+Special files such as iSCSI devices can be specified using protocol
+specific URLs. See the section for "Device URL Syntax" for more information.
 @item if=@var{interface}
 This option defines on which type on interface the drive is connected.
 Available types are: ide, scsi, sd, mtd, floppy, pflash, virtio.
@@ -1718,6 +1721,45 @@ ETEXI
 
 DEFHEADING()
 
+STEXI
+DEFHEADING(Device URL Syntax:)
+
+In addition to using normal file images for the emulated storage devices,
+QEMU can also use networked resources such as iSCSI devices. These are
+specified using a special URL syntax.
+
+ at table @option
+ at item iSCSI
+iSCSI support allows QEMU to access iSCSI resources directly and use as
+images for the guest storage. Both disk and cdrom images are supported.
+
+Syntax for specifying iSCSI LUNs is
+``iscsi://<target-ip>[:<port>]/<target-iqn>/<lun>''
+
+Example (without authentication):
+ at example
+qemu -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
+--drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+ at end example
+
+Example (CHAP username/password via URL):
+ at example
+qemu --drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
+ at end example
+
+Example (CHAP username/password via environment variables):
+ at example
+LIBISCSI_CHAP_USERNAME="user" \
+LIBISCSI_CHAP_PASSWORD="password" \
+qemu --drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+ at end example
+
+iSCSI support is an optional feature of QEMU and only available when
+compiled and linked against libiscsi.
+
+ at end table
+ETEXI
+
 DEFHEADING(Bluetooth(R) options:)
 
 DEF("bt", HAS_ARG, QEMU_OPTION_bt, \
commit c589b24972794a92fe3b5d6b9f4f09ef29e95460
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Tue Oct 25 19:24:24 2011 +1100

    iSCSI block driver
    
    This provides built-in support for iSCSI to QEMU.
    
    This has the advantage that the iSCSI devices need not be made visible to the host, which is useful if you have very many virtual machines and very many iscsi devices.
    It also has the benefit that non-root users of QEMU can access iSCSI devices across the network without requiring root privilege on the host.
    
    This driver interfaces with the multiplatform posix library for iscsi initiator/client access to iscsi devices hosted at
        git://github.com/sahlberg/libiscsi.git
    
    The patch adds the driver to interface with the iscsi library.
    It also updated the configure script to
    * by default, probe is libiscsi is available and if so, build
      qemu against libiscsi.
    * --enable-libiscsi
      Force a build against libiscsi. If libiscsi is not available
      the build will fail.
    * --disable-libiscsi
      Do not link against libiscsi, even if it is available.
    
    When linked with libiscsi, qemu gains support to access iscsi resources such as disks and cdrom directly, without having to make the devices visible to the host.
    
    You can specify devices using a iscsi url of the form :
    iscsi://[<username>[:<password>@]]<host>[:<port]/<target-iqn-name>/<lun>
    When using authentication, the password can optionally be set with
    LIBISCSI_CHAP_PASSWORD="password" to avoid it showing up in the process list
    
    Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 01587c8..d18417c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -36,6 +36,7 @@ block-nested-y += qed-check.o
 block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
+block-nested-$(CONFIG_LIBISCSI) += iscsi.o
 block-nested-$(CONFIG_CURL) += curl.o
 block-nested-$(CONFIG_RBD) += rbd.o
 
diff --git a/block/iscsi.c b/block/iscsi.c
new file mode 100644
index 0000000..938c568
--- /dev/null
+++ b/block/iscsi.c
@@ -0,0 +1,591 @@
+/*
+ * QEMU Block driver for iSCSI images
+ *
+ * Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg at gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config-host.h"
+
+#include <poll.h>
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "block_int.h"
+#include "trace.h"
+
+#include <iscsi/iscsi.h>
+#include <iscsi/scsi-lowlevel.h>
+
+
+typedef struct IscsiLun {
+    struct iscsi_context *iscsi;
+    int lun;
+    int block_size;
+    unsigned long num_blocks;
+} IscsiLun;
+
+typedef struct IscsiAIOCB {
+    BlockDriverAIOCB common;
+    QEMUIOVector *qiov;
+    QEMUBH *bh;
+    IscsiLun *iscsilun;
+    struct scsi_task *task;
+    uint8_t *buf;
+    int status;
+    int canceled;
+    size_t read_size;
+    size_t read_offset;
+} IscsiAIOCB;
+
+struct IscsiTask {
+    IscsiLun *iscsilun;
+    BlockDriverState *bs;
+    int status;
+    int complete;
+};
+
+static void
+iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
+                    void *private_data)
+{
+}
+
+static void
+iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
+    IscsiLun *iscsilun = acb->iscsilun;
+
+    acb->common.cb(acb->common.opaque, -ECANCELED);
+    acb->canceled = 1;
+
+    /* send a task mgmt call to the target to cancel the task on the target */
+    iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
+                                     iscsi_abort_task_cb, NULL);
+
+    /* then also cancel the task locally in libiscsi */
+    iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
+}
+
+static AIOPool iscsi_aio_pool = {
+    .aiocb_size         = sizeof(IscsiAIOCB),
+    .cancel             = iscsi_aio_cancel,
+};
+
+
+static void iscsi_process_read(void *arg);
+static void iscsi_process_write(void *arg);
+
+static int iscsi_process_flush(void *arg)
+{
+    IscsiLun *iscsilun = arg;
+
+    return iscsi_queue_length(iscsilun->iscsi) > 0;
+}
+
+static void
+iscsi_set_events(IscsiLun *iscsilun)
+{
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+
+    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);
+}
+
+static void
+iscsi_process_read(void *arg)
+{
+    IscsiLun *iscsilun = arg;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+
+    iscsi_service(iscsi, POLLIN);
+    iscsi_set_events(iscsilun);
+}
+
+static void
+iscsi_process_write(void *arg)
+{
+    IscsiLun *iscsilun = arg;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+
+    iscsi_service(iscsi, POLLOUT);
+    iscsi_set_events(iscsilun);
+}
+
+
+static int
+iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
+{
+    acb->bh = qemu_bh_new(cb, acb);
+    if (!acb->bh) {
+        error_report("oom: could not create iscsi bh");
+        return -EIO;
+    }
+
+    qemu_bh_schedule(acb->bh);
+    return 0;
+}
+
+static void
+iscsi_readv_writev_bh_cb(void *p)
+{
+    IscsiAIOCB *acb = p;
+
+    qemu_bh_delete(acb->bh);
+
+    if (acb->canceled == 0) {
+        acb->common.cb(acb->common.opaque, acb->status);
+    }
+
+    qemu_aio_release(acb);
+}
+
+
+static void
+iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
+                     void *command_data, void *opaque)
+{
+    IscsiAIOCB *acb = opaque;
+
+    trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
+
+    g_free(acb->buf);
+
+    if (acb->canceled != 0) {
+        qemu_aio_release(acb);
+        scsi_free_scsi_task(acb->task);
+        acb->task = NULL;
+        return;
+    }
+
+    acb->status = 0;
+    if (status < 0) {
+        error_report("Failed to write10 data to iSCSI lun. %s",
+                     iscsi_get_error(iscsi));
+        acb->status = -EIO;
+    }
+
+    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+    scsi_free_scsi_task(acb->task);
+    acb->task = NULL;
+}
+
+static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
+{
+    return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
+                 QEMUIOVector *qiov, int nb_sectors,
+                 BlockDriverCompletionFunc *cb,
+                 void *opaque)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+    IscsiAIOCB *acb;
+    size_t size;
+    int fua = 0;
+
+    /* set FUA on writes when cache mode is write through */
+    if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
+        fua = 1;
+    }
+
+    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+    trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
+
+    acb->iscsilun = iscsilun;
+    acb->qiov     = qiov;
+
+    acb->canceled   = 0;
+
+    /* XXX we should pass the iovec to write10 to avoid the extra copy */
+    /* this will allow us to get rid of 'buf' completely */
+    size = nb_sectors * BDRV_SECTOR_SIZE;
+    acb->buf = g_malloc(size);
+    qemu_iovec_to_buffer(acb->qiov, acb->buf);
+    acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
+                              sector_qemu2lun(sector_num, iscsilun),
+                              fua, 0, iscsilun->block_size,
+                              iscsi_aio_write10_cb, acb);
+    if (acb->task == NULL) {
+        error_report("iSCSI: Failed to send write10 command. %s",
+                     iscsi_get_error(iscsi));
+        g_free(acb->buf);
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    iscsi_set_events(iscsilun);
+
+    return &acb->common;
+}
+
+static void
+iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
+                    void *command_data, void *opaque)
+{
+    IscsiAIOCB *acb = opaque;
+
+    trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
+
+    if (acb->canceled != 0) {
+        qemu_aio_release(acb);
+        scsi_free_scsi_task(acb->task);
+        acb->task = NULL;
+        return;
+    }
+
+    acb->status = 0;
+    if (status != 0) {
+        error_report("Failed to read10 data from iSCSI lun. %s",
+                     iscsi_get_error(iscsi));
+        acb->status = -EIO;
+    }
+
+    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+    scsi_free_scsi_task(acb->task);
+    acb->task = NULL;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
+                QEMUIOVector *qiov, int nb_sectors,
+                BlockDriverCompletionFunc *cb,
+                void *opaque)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+    IscsiAIOCB *acb;
+    size_t qemu_read_size, lun_read_size;
+    int i;
+
+    qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
+
+    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+    trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
+
+    acb->iscsilun = iscsilun;
+    acb->qiov     = qiov;
+
+    acb->canceled    = 0;
+    acb->read_size   = qemu_read_size;
+    acb->buf         = NULL;
+
+    /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
+     * may be misaligned to the LUN, so we may need to read some extra
+     * data.
+     */
+    acb->read_offset = 0;
+    if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
+        uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
+
+        acb->read_offset  = bdrv_offset % iscsilun->block_size;
+    }
+
+    lun_read_size  = (qemu_read_size + iscsilun->block_size
+                     + acb->read_offset - 1)
+                     / iscsilun->block_size * iscsilun->block_size;
+    acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
+                             sector_qemu2lun(sector_num, iscsilun),
+                             lun_read_size, iscsilun->block_size,
+                             iscsi_aio_read10_cb, acb);
+    if (acb->task == NULL) {
+        error_report("iSCSI: Failed to send read10 command. %s",
+                     iscsi_get_error(iscsi));
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    for (i = 0; i < acb->qiov->niov; i++) {
+        scsi_task_add_data_in_buffer(acb->task,
+                acb->qiov->iov[i].iov_len,
+                acb->qiov->iov[i].iov_base);
+    }
+
+    iscsi_set_events(iscsilun);
+
+    return &acb->common;
+}
+
+
+static void
+iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
+                     void *command_data, void *opaque)
+{
+    IscsiAIOCB *acb = opaque;
+
+    if (acb->canceled != 0) {
+        qemu_aio_release(acb);
+        scsi_free_scsi_task(acb->task);
+        acb->task = NULL;
+        return;
+    }
+
+    acb->status = 0;
+    if (status < 0) {
+        error_report("Failed to sync10 data on iSCSI lun. %s",
+                     iscsi_get_error(iscsi));
+        acb->status = -EIO;
+    }
+
+    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+    scsi_free_scsi_task(acb->task);
+    acb->task = NULL;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_flush(BlockDriverState *bs,
+                BlockDriverCompletionFunc *cb, void *opaque)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = iscsilun->iscsi;
+    IscsiAIOCB *acb;
+
+    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+
+    acb->iscsilun = iscsilun;
+    acb->canceled   = 0;
+
+    acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
+                                         0, 0, 0, 0,
+                                         iscsi_synccache10_cb,
+                                         acb);
+    if (acb->task == NULL) {
+        error_report("iSCSI: Failed to send synchronizecache10 command. %s",
+                     iscsi_get_error(iscsi));
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
+    iscsi_set_events(iscsilun);
+
+    return &acb->common;
+}
+
+static int64_t
+iscsi_getlength(BlockDriverState *bs)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    int64_t len;
+
+    len  = iscsilun->num_blocks;
+    len *= iscsilun->block_size;
+
+    return len;
+}
+
+static void
+iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
+                        void *command_data, void *opaque)
+{
+    struct IscsiTask *itask = opaque;
+    struct scsi_readcapacity10 *rc10;
+    struct scsi_task *task = command_data;
+
+    if (status != 0) {
+        error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
+                     iscsi_get_error(iscsi));
+        itask->status   = 1;
+        itask->complete = 1;
+        scsi_free_scsi_task(task);
+        return;
+    }
+
+    rc10 = scsi_datain_unmarshall(task);
+    if (rc10 == NULL) {
+        error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
+        itask->status   = 1;
+        itask->complete = 1;
+        scsi_free_scsi_task(task);
+        return;
+    }
+
+    itask->iscsilun->block_size = rc10->block_size;
+    itask->iscsilun->num_blocks = rc10->lba;
+    itask->bs->total_sectors = (uint64_t)rc10->lba *
+                               rc10->block_size / BDRV_SECTOR_SIZE ;
+
+    itask->status   = 0;
+    itask->complete = 1;
+    scsi_free_scsi_task(task);
+}
+
+
+static void
+iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
+                 void *opaque)
+{
+    struct IscsiTask *itask = opaque;
+    struct scsi_task *task;
+
+    if (status != 0) {
+        itask->status   = 1;
+        itask->complete = 1;
+        return;
+    }
+
+    task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, 0, 0,
+                                   iscsi_readcapacity10_cb, opaque);
+    if (task == NULL) {
+        error_report("iSCSI: failed to send readcapacity command.");
+        itask->status   = 1;
+        itask->complete = 1;
+        return;
+    }
+}
+
+/*
+ * We support iscsi url's on the form
+ * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
+ */
+static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct iscsi_context *iscsi = NULL;
+    struct iscsi_url *iscsi_url = NULL;
+    struct IscsiTask task;
+    int ret;
+
+    if ((BDRV_SECTOR_SIZE % 512) != 0) {
+        error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
+                     "BDRV_SECTOR_SIZE(%lld) is not a multiple "
+                     "of 512", BDRV_SECTOR_SIZE);
+        return -EINVAL;
+    }
+
+    memset(iscsilun, 0, sizeof(IscsiLun));
+
+    /* Should really append the KVM name after the ':' here */
+    iscsi = iscsi_create_context("iqn.2008-11.org.linux-kvm:");
+    if (iscsi == NULL) {
+        error_report("iSCSI: Failed to create iSCSI context.");
+        ret = -ENOMEM;
+        goto failed;
+    }
+
+    iscsi_url = iscsi_parse_full_url(iscsi, filename);
+    if (iscsi_url == NULL) {
+        error_report("Failed to parse URL : %s %s", filename,
+                     iscsi_get_error(iscsi));
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
+        error_report("iSCSI: Failed to set target name.");
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    if (iscsi_url->user != NULL) {
+        ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
+                                              iscsi_url->passwd);
+        if (ret != 0) {
+            error_report("Failed to set initiator username and password");
+            ret = -EINVAL;
+            goto failed;
+        }
+    }
+    if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
+        error_report("iSCSI: Failed to set session type to normal.");
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
+
+    task.iscsilun = iscsilun;
+    task.status = 0;
+    task.complete = 0;
+    task.bs = bs;
+
+    iscsilun->iscsi = iscsi;
+    iscsilun->lun   = iscsi_url->lun;
+
+    if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
+                                 iscsi_connect_cb, &task)
+        != 0) {
+        error_report("iSCSI: Failed to start async connect.");
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    while (!task.complete) {
+        iscsi_set_events(iscsilun);
+        qemu_aio_wait();
+    }
+    if (task.status != 0) {
+        error_report("iSCSI: Failed to connect to LUN : %s",
+                     iscsi_get_error(iscsi));
+        ret = -EINVAL;
+        goto failed;
+    }
+
+    if (iscsi_url != NULL) {
+        iscsi_destroy_url(iscsi_url);
+    }
+    return 0;
+
+failed:
+    if (iscsi_url != NULL) {
+        iscsi_destroy_url(iscsi_url);
+    }
+    if (iscsi != NULL) {
+        iscsi_destroy_context(iscsi);
+    }
+    memset(iscsilun, 0, sizeof(IscsiLun));
+    return ret;
+}
+
+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);
+    iscsi_destroy_context(iscsi);
+    memset(iscsilun, 0, sizeof(IscsiLun));
+}
+
+static BlockDriver bdrv_iscsi = {
+    .format_name     = "iscsi",
+    .protocol_name   = "iscsi",
+
+    .instance_size   = sizeof(IscsiLun),
+    .bdrv_file_open  = iscsi_open,
+    .bdrv_close      = iscsi_close,
+
+    .bdrv_getlength  = iscsi_getlength,
+
+    .bdrv_aio_readv  = iscsi_aio_readv,
+    .bdrv_aio_writev = iscsi_aio_writev,
+    .bdrv_aio_flush  = iscsi_aio_flush,
+};
+
+static void iscsi_block_init(void)
+{
+    bdrv_register(&bdrv_iscsi);
+}
+
+block_init(iscsi_block_init);
diff --git a/configure b/configure
index 4f87e0a..3009bbc 100755
--- a/configure
+++ b/configure
@@ -182,6 +182,7 @@ usb_redir=""
 opengl=""
 zlib="yes"
 guest_agent="yes"
+libiscsi=""
 
 # parse CC options first
 for opt do
@@ -657,6 +658,10 @@ for opt do
   ;;
   --enable-spice) spice="yes"
   ;;
+  --disable-libiscsi) libiscsi="no"
+  ;;
+  --enable-libiscsi) libiscsi="yes"
+  ;;
   --enable-profiler) profiler="yes"
   ;;
   --enable-cocoa)
@@ -1046,6 +1051,8 @@ echo "                           Default:trace-<pid>"
 echo "  --disable-spice          disable spice"
 echo "  --enable-spice           enable spice"
 echo "  --enable-rbd             enable building the rados block device (rbd)"
+echo "  --disable-libiscsi       disable iscsi support"
+echo "  --enable-libiscsi        enable iscsi support"
 echo "  --disable-smartcard      disable smartcard support"
 echo "  --enable-smartcard       enable smartcard support"
 echo "  --disable-smartcard-nss  disable smartcard nss support"
@@ -2335,6 +2342,25 @@ if compile_prog "" "" ; then
 fi
 
 ##########################################
+# Do we have libiscsi
+if test "$libiscsi" != "no" ; then
+  cat > $TMPC << EOF
+#include <iscsi/iscsi.h>
+int main(void) { iscsi_create_context(""); return 0; }
+EOF
+  if compile_prog "-Werror" "-liscsi" ; then
+    libiscsi="yes"
+    LIBS="$LIBS -liscsi"
+  else
+    if test "$libiscsi" = "yes" ; then
+      feature_not_found "libiscsi"
+    fi
+    libiscsi="no"
+  fi
+fi
+
+
+##########################################
 # Do we need librt
 cat > $TMPC <<EOF
 #include <signal.h>
@@ -2744,6 +2770,7 @@ echo "xfsctl support    $xfs"
 echo "nss used          $smartcard_nss"
 echo "usb net redir     $usb_redir"
 echo "OpenGL support    $opengl"
+echo "libiscsi support  $libiscsi"
 echo "build guest agent $guest_agent"
 
 if test "$sdl_too_old" = "yes"; then
@@ -3042,6 +3069,10 @@ if test "$opengl" = "yes" ; then
   echo "CONFIG_OPENGL=y" >> $config_host_mak
 fi
 
+if test "$libiscsi" = "yes" ; then
+  echo "CONFIG_LIBISCSI=y" >> $config_host_mak
+fi
+
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
   echo "CONFIG_BSD=y" >> $config_host_mak
diff --git a/trace-events b/trace-events
index 820b1d6..a888055 100644
--- a/trace-events
+++ b/trace-events
@@ -505,6 +505,12 @@ escc_sunkbd_event_out(int ch) "Translated keycode %2.2x"
 escc_kbd_command(int val) "Command %d"
 escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x"
 
+# block/iscsi.c
+iscsi_aio_write10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
+iscsi_aio_writev(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
+iscsi_aio_read10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
+iscsi_aio_readv(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
+
 # hw/esp.c
 esp_raise_irq(void) "Raise IRQ"
 esp_lower_irq(void) "Lower IRQ"
commit b5a12aa204f842c8010ac9d2e4b115114dbf09f0
Merge: 9f60639... 50c796f...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Thu Oct 27 20:27:07 2011 +0000

    Merge branch 'rth/vis2' of git://repo.or.cz/qemu/rth
    
    * 'rth/vis2' of git://repo.or.cz/qemu/rth:
      target-sparc: Implement FALIGNDATA inline.
      target-sparc: Implement BMASK/BSHUFFLE.
      target-sparc: Implement ALIGNADDR* inline.
      target-sparc: Implement EDGE* instructions.
      target-sparc: Implement fpack{16,32,fix}.
      target-sparc: Implement PDIST.
      target-sparc: Do exceptions management fully inside the helpers.
      target-sparc: Change fpr representation to doubles.
      target-sparc: Undo cpu_fpr rename.
      target-sparc: Extract float128 move to a function.
      target-sparc: Extract common code for floating-point operations.
      target-sparc: Make FPU/VIS helpers const when possible.
      target-sparc: Pass float64 parameters instead of dt0/1 temporaries.
      target-sparc: Add accessors for double-precision fpr access.
      target-sparc: Mark fprs dirty in store accessor.
      target-sparc: Add accessors for single-precision fpr access.

commit f795e743bd026471bcf7952d272424f1fd32e83b
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Oct 21 16:05:43 2011 -0200

    Drop qemu-objects.h from modules that don't require it
    
    Previous commits dropped most qobjects usage from qemu modules
    (now they are a low level interface used by the QAPI). However,
    some modules still include the qemu-objects.h header file.
    
    This commit drops qemu-objects.h from some of those modules
    and includes qjson.h instead, which is what they actually need.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/block.c b/block.c
index 551aa80..b5c1544 100644
--- a/block.c
+++ b/block.c
@@ -27,7 +27,7 @@
 #include "monitor.h"
 #include "block_int.h"
 #include "module.h"
-#include "qemu-objects.h"
+#include "qjson.h"
 #include "qemu-coroutine.h"
 #include "qmp-commands.h"
 
diff --git a/error.c b/error.c
index 68c0039..990050f 100644
--- a/error.c
+++ b/error.c
@@ -12,8 +12,9 @@
 
 #include "qemu-common.h"
 #include "error.h"
+#include "qjson.h"
+#include "qdict.h"
 #include "error_int.h"
-#include "qemu-objects.h"
 #include "qerror.h"
 
 struct Error
diff --git a/vl.c b/vl.c
index 1ddb17b..fb28ffc 100644
--- a/vl.c
+++ b/vl.c
@@ -143,9 +143,9 @@ int main(int argc, char **argv)
 #include "audio/audio.h"
 #include "migration.h"
 #include "kvm.h"
+#include "qjson.h"
 #include "qemu-option.h"
 #include "qemu-config.h"
-#include "qemu-objects.h"
 #include "qemu-options.h"
 #include "qmp-commands.h"
 #include "main-loop.h"
commit b5c30586c91f15c1d80ad2d56ed1815077719b9b
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Oct 21 16:24:28 2011 -0200

    Monitor: do_info(): Drop QMP command handling code
    
    Previous commits converted all existing QMP commands to the QAPI,
    now each info command does its own QMP call.
    
    Let's then drop all QMP command handling code from do_info().
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index 1e09b91..e3c7d0d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -123,8 +123,6 @@ typedef struct mon_cmd_t {
     void (*user_print)(Monitor *mon, const QObject *data);
     union {
         void (*info)(Monitor *mon);
-        void (*info_new)(Monitor *mon, QObject **ret_data);
-        int  (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
         void (*cmd)(Monitor *mon, const QDict *qdict);
         int  (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
         int  (*cmd_async)(Monitor *mon, const QDict *params,
@@ -679,21 +677,6 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
     }
 }
 
-static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
-{
-    int ret;
-
-    MonitorCompletionData *cb_data = g_malloc(sizeof(*cb_data));
-    cb_data->mon = mon;
-    cb_data->user_print = cmd->user_print;
-    monitor_suspend(mon);
-    ret = cmd->mhandler.info_async(mon, user_monitor_complete, cb_data);
-    if (ret < 0) {
-        monitor_resume(mon);
-        g_free(cb_data);
-    }
-}
-
 static void do_info(Monitor *mon, const QDict *qdict)
 {
     const mon_cmd_t *cmd;
@@ -712,20 +695,7 @@ static void do_info(Monitor *mon, const QDict *qdict)
         goto help;
     }
 
-    if (handler_is_async(cmd)) {
-        user_async_info_handler(mon, cmd);
-    } else if (handler_is_qobject(cmd)) {
-        QObject *info_data = NULL;
-
-        cmd->mhandler.info_new(mon, &info_data);
-        if (info_data) {
-            cmd->user_print(mon, info_data);
-            qobject_decref(info_data);
-        }
-    } else {
-        cmd->mhandler.info(mon);
-    }
-
+    cmd->mhandler.info(mon);
     return;
 
 help:
commit 40e5a01d1add8cca5732dd079c92e9bf4f07d7ff
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Oct 21 16:15:31 2011 -0200

    QMP: Drop the query commands dispatch table
    
    Because QMP development originated in the monitor, it has
    inherited the monitor's distinction between query- and
    non-query commands.
    
    However, previous commits unified both commands and the
    distinction is gone. This commit drops the query commands
    dispatch table and does some simplifications along the way.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index edcacda..1e09b91 100644
--- a/monitor.c
+++ b/monitor.c
@@ -205,7 +205,6 @@ static const mon_cmd_t mon_cmds[];
 static const mon_cmd_t info_cmds[];
 
 static const mon_cmd_t qmp_cmds[];
-static const mon_cmd_t qmp_query_cmds[];
 
 Monitor *cur_mon;
 Monitor *default_mon;
@@ -663,11 +662,6 @@ static int qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
     return cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
 }
 
-static void qmp_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
-{
-    cmd->mhandler.info_async(mon, qmp_monitor_complete, mon);
-}
-
 static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
                                    const QDict *params)
 {
@@ -738,32 +732,16 @@ help:
     help_cmd(mon, "info");
 }
 
-static CommandInfoList *alloc_cmd_entry(const char *cmd_name)
-{
-    CommandInfoList *info;
-
-    info = g_malloc0(sizeof(*info));
-    info->value = g_malloc0(sizeof(*info->value));
-    info->value->name = g_strdup(cmd_name);
-
-    return info;
-}
-
 CommandInfoList *qmp_query_commands(Error **errp)
 {
     CommandInfoList *info, *cmd_list = NULL;
     const mon_cmd_t *cmd;
 
     for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
-        info = alloc_cmd_entry(cmd->name);
-        info->next = cmd_list;
-        cmd_list = info;
-    }
+        info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->name = g_strdup(cmd->name);
 
-    for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) {
-        char buf[128];
-        snprintf(buf, sizeof(buf), "query-%s", cmd->name);
-        info = alloc_cmd_entry(buf);
         info->next = cmd_list;
         cmd_list = info;
     }
@@ -2952,10 +2930,6 @@ static const mon_cmd_t qmp_cmds[] = {
     { /* NULL */ },
 };
 
-static const mon_cmd_t qmp_query_cmds[] = {
-    { /* NULL */ },
-};
-
 /*******************************************************************/
 
 static const char *pch;
@@ -3750,11 +3724,6 @@ static const mon_cmd_t *monitor_find_command(const char *cmdname)
     return search_dispatch_table(mon_cmds, cmdname);
 }
 
-static const mon_cmd_t *qmp_find_query_cmd(const char *info_item)
-{
-    return search_dispatch_table(qmp_query_cmds, info_item);
-}
-
 static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
 {
     return search_dispatch_table(qmp_cmds, cmdname);
@@ -4678,22 +4647,6 @@ static QDict *qmp_check_input_obj(QObject *input_obj)
     return input_dict;
 }
 
-static void qmp_call_query_cmd(Monitor *mon, const mon_cmd_t *cmd)
-{
-    QObject *ret_data = NULL;
-
-    if (handler_is_async(cmd)) {
-        qmp_async_info_handler(mon, cmd);
-        if (monitor_has_error(mon)) {
-            monitor_protocol_emitter(mon, NULL);
-        }
-    } else {
-        cmd->mhandler.info_new(mon, &ret_data);
-        monitor_protocol_emitter(mon, ret_data);
-        qobject_decref(ret_data);
-    }
-}
-
 static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
                          const QDict *params)
 {
@@ -4714,10 +4667,9 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
     QObject *obj;
     QDict *input, *args;
     const mon_cmd_t *cmd;
+    const char *cmd_name;
     Monitor *mon = cur_mon;
-    const char *cmd_name, *query_cmd;
 
-    query_cmd = NULL;
     args = input = NULL;
 
     obj = json_parser_parse(tokens, NULL);
@@ -4744,9 +4696,6 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
     }
 
     cmd = qmp_find_cmd(cmd_name);
-    if (!cmd && strstart(cmd_name, "query-", &query_cmd)) {
-        cmd = qmp_find_query_cmd(query_cmd);
-    }
     if (!cmd) {
         qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
         goto err_out;
@@ -4765,9 +4714,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
         goto err_out;
     }
 
-    if (query_cmd) {
-        qmp_call_query_cmd(mon, cmd);
-    } else if (handler_is_async(cmd)) {
+    if (handler_is_async(cmd)) {
         err = qmp_async_cmd_handler(mon, cmd, args);
         if (err) {
             /* emit the error response */
commit 79627472db3629de66fe81019560aa9cb6900268
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Oct 21 14:15:33 2011 -0200

    qapi: Convert query-pci
    
    This also fixes a bug with the old version: QMP would invert device id
    and vendor id. This would look ok on HMP because it was printing
    "device:vendor" instead of "vendor:device".
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index e0b40b1..443d3a7 100644
--- a/hmp.c
+++ b/hmp.c
@@ -388,6 +388,107 @@ void hmp_info_balloon(Monitor *mon)
     qapi_free_BalloonInfo(info);
 }
 
+static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
+{
+    PciMemoryRegionList *region;
+
+    monitor_printf(mon, "  Bus %2" PRId64 ", ", dev->bus);
+    monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
+                   dev->slot, dev->function);
+    monitor_printf(mon, "    ");
+
+    if (dev->class_info.has_desc) {
+        monitor_printf(mon, "%s", dev->class_info.desc);
+    } else {
+        monitor_printf(mon, "Class %04" PRId64, dev->class_info.class);
+    }
+
+    monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
+                   dev->id.vendor, dev->id.device);
+
+    if (dev->has_irq) {
+        monitor_printf(mon, "      IRQ %" PRId64 ".\n", dev->irq);
+    }
+
+    if (dev->has_pci_bridge) {
+        monitor_printf(mon, "      BUS %" PRId64 ".\n",
+                       dev->pci_bridge->bus.number);
+        monitor_printf(mon, "      secondary bus %" PRId64 ".\n",
+                       dev->pci_bridge->bus.secondary);
+        monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",
+                       dev->pci_bridge->bus.subordinate);
+
+        monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
+                       dev->pci_bridge->bus.io_range->base,
+                       dev->pci_bridge->bus.io_range->limit);
+
+        monitor_printf(mon,
+                       "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
+                       dev->pci_bridge->bus.memory_range->base,
+                       dev->pci_bridge->bus.memory_range->limit);
+
+        monitor_printf(mon, "      prefetchable memory range "
+                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
+                       dev->pci_bridge->bus.prefetchable_range->base,
+                       dev->pci_bridge->bus.prefetchable_range->limit);
+    }
+
+    for (region = dev->regions; region; region = region->next) {
+        uint64_t addr, size;
+
+        addr = region->value->address;
+        size = region->value->size;
+
+        monitor_printf(mon, "      BAR%" PRId64 ": ", region->value->bar);
+
+        if (!strcmp(region->value->type, "io")) {
+            monitor_printf(mon, "I/O at 0x%04" PRIx64
+                                " [0x%04" PRIx64 "].\n",
+                           addr, addr + size - 1);
+        } else {
+            monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
+                               " [0x%08" PRIx64 "].\n",
+                           region->value->mem_type_64 ? 64 : 32,
+                           region->value->prefetch ? " prefetchable" : "",
+                           addr, addr + size - 1);
+        }
+    }
+
+    monitor_printf(mon, "      id \"%s\"\n", dev->qdev_id);
+
+    if (dev->has_pci_bridge) {
+        if (dev->pci_bridge->has_devices) {
+            PciDeviceInfoList *cdev;
+            for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) {
+                hmp_info_pci_device(mon, cdev->value);
+            }
+        }
+    }
+}
+
+void hmp_info_pci(Monitor *mon)
+{
+    PciInfoList *info;
+    Error *err = NULL;
+
+    info = qmp_query_pci(&err);
+    if (err) {
+        monitor_printf(mon, "PCI devices not supported\n");
+        error_free(err);
+        return;
+    }
+
+    for (; info; info = info->next) {
+        PciDeviceInfoList *dev;
+
+        for (dev = info->value->devices; dev; dev = dev->next) {
+            hmp_info_pci_device(mon, dev->value);
+        }
+    }
+
+    qapi_free_PciInfoList(info);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index d2c2d88..4422578 100644
--- a/hmp.h
+++ b/hmp.h
@@ -31,6 +31,7 @@ void hmp_info_blockstats(Monitor *mon);
 void hmp_info_vnc(Monitor *mon);
 void hmp_info_spice(Monitor *mon);
 void hmp_info_balloon(Monitor *mon);
+void hmp_info_pci(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/hw/pci-stub.c b/hw/pci-stub.c
index 1fb105d..636171c 100644
--- a/hw/pci-stub.c
+++ b/hw/pci-stub.c
@@ -21,20 +21,17 @@
 #include "sysemu.h"
 #include "monitor.h"
 #include "pci.h"
+#include "qmp-commands.h"
 
-static void pci_error_message(Monitor *mon)
+PciInfoList *qmp_query_pci(Error **errp)
 {
-    monitor_printf(mon, "PCI devices not supported\n");
+    error_set(errp, QERR_UNSUPPORTED);
+    return NULL;
 }
 
-void do_pci_info(Monitor *mon, QObject **ret_data)
-{
-    pci_error_message(mon);
-}
-
-void do_pci_info_print(Monitor *mon, const QObject *data)
+static void pci_error_message(Monitor *mon)
 {
-    pci_error_message(mon);
+    monitor_printf(mon, "PCI devices not supported\n");
 }
 
 int do_pcie_aer_inejct_error(Monitor *mon,
diff --git a/hw/pci.c b/hw/pci.c
index e8cc1b0..399227f 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -29,8 +29,8 @@
 #include "net.h"
 #include "sysemu.h"
 #include "loader.h"
-#include "qemu-objects.h"
 #include "range.h"
+#include "qmp-commands.h"
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -1164,276 +1164,194 @@ void pci_for_each_device(PCIBus *bus, int bus_num,
     }
 }
 
-static void pci_device_print(Monitor *mon, QDict *device)
+static const pci_class_desc *get_class_desc(int class)
 {
-    QDict *qdict;
-    QListEntry *entry;
-    uint64_t addr, size;
-
-    monitor_printf(mon, "  Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));
-    monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
-                        qdict_get_int(device, "slot"),
-                        qdict_get_int(device, "function"));
-    monitor_printf(mon, "    ");
-
-    qdict = qdict_get_qdict(device, "class_info");
-    if (qdict_haskey(qdict, "desc")) {
-        monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));
-    } else {
-        monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
-    }
-
-    qdict = qdict_get_qdict(device, "id");
-    monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
-                        qdict_get_int(qdict, "device"),
-                        qdict_get_int(qdict, "vendor"));
+    const pci_class_desc *desc;
 
-    if (qdict_haskey(device, "irq")) {
-        monitor_printf(mon, "      IRQ %" PRId64 ".\n",
-                            qdict_get_int(device, "irq"));
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class) {
+        desc++;
     }
 
-    if (qdict_haskey(device, "pci_bridge")) {
-        QDict *info;
-
-        qdict = qdict_get_qdict(device, "pci_bridge");
-
-        info = qdict_get_qdict(qdict, "bus");
-        monitor_printf(mon, "      BUS %" PRId64 ".\n",
-                            qdict_get_int(info, "number"));
-        monitor_printf(mon, "      secondary bus %" PRId64 ".\n",
-                            qdict_get_int(info, "secondary"));
-        monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",
-                            qdict_get_int(info, "subordinate"));
+    return desc;
+}
 
-        info = qdict_get_qdict(qdict, "io_range");
-        monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
-                       qdict_get_int(info, "base"),
-                       qdict_get_int(info, "limit"));
+static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
 
-        info = qdict_get_qdict(qdict, "memory_range");
-        monitor_printf(mon,
-                       "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
-                       qdict_get_int(info, "base"),
-                       qdict_get_int(info, "limit"));
+static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
+{
+    PciMemoryRegionList *head = NULL, *cur_item = NULL;
+    int i;
 
-        info = qdict_get_qdict(qdict, "prefetchable_range");
-        monitor_printf(mon, "      prefetchable memory range "
-                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
-                       qdict_get_int(info, "base"),
-        qdict_get_int(info, "limit"));
-    }
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        const PCIIORegion *r = &dev->io_regions[i];
+        PciMemoryRegionList *region;
 
-    QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {
-        qdict = qobject_to_qdict(qlist_entry_obj(entry));
-        monitor_printf(mon, "      BAR%d: ", (int) qdict_get_int(qdict, "bar"));
+        if (!r->size) {
+            continue;
+        }
 
-        addr = qdict_get_int(qdict, "address");
-        size = qdict_get_int(qdict, "size");
+        region = g_malloc0(sizeof(*region));
+        region->value = g_malloc0(sizeof(*region->value));
 
-        if (!strcmp(qdict_get_str(qdict, "type"), "io")) {
-            monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
-                                " [0x%04"FMT_PCIBUS"].\n",
-                                addr, addr + size - 1);
+        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+            region->value->type = g_strdup("io");
         } else {
-            monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS
-                               " [0x%08"FMT_PCIBUS"].\n",
-                                qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
-                                qdict_get_bool(qdict, "prefetch") ?
-                                " prefetchable" : "", addr, addr + size - 1);
+            region->value->type = g_strdup("memory");
+            region->value->has_prefetch = true;
+            region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
+            region->value->has_mem_type_64 = true;
+            region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
         }
-    }
 
-    monitor_printf(mon, "      id \"%s\"\n", qdict_get_str(device, "qdev_id"));
+        region->value->bar = i;
+        region->value->address = r->addr;
+        region->value->size = r->size;
 
-    if (qdict_haskey(device, "pci_bridge")) {
-        qdict = qdict_get_qdict(device, "pci_bridge");
-        if (qdict_haskey(qdict, "devices")) {
-            QListEntry *dev;
-            QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
-                pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
-            }
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = region;
+        } else {
+            cur_item->next = region;
+            cur_item = region;
         }
     }
-}
-
-void do_pci_info_print(Monitor *mon, const QObject *data)
-{
-    QListEntry *bus, *dev;
 
-    QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {
-        QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));
-        QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
-            pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
-        }
-    }
+    return head;
 }
 
-static QObject *pci_get_dev_class(const PCIDevice *dev)
+static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
+                                           int bus_num)
 {
-    int class;
-    const pci_class_desc *desc;
+    PciBridgeInfo *info;
 
-    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
-    desc = pci_class_descriptions;
-    while (desc->desc && class != desc->class)
-        desc++;
+    info = g_malloc0(sizeof(*info));
 
-    if (desc->desc) {
-        return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
-                                  desc->desc, class);
-    } else {
-        return qobject_from_jsonf("{ 'class': %d }", class);
-    }
-}
+    info->bus.number = dev->config[PCI_PRIMARY_BUS];
+    info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
+    info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
 
-static QObject *pci_get_dev_id(const PCIDevice *dev)
-{
-    return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
-                              pci_get_word(dev->config + PCI_VENDOR_ID),
-                              pci_get_word(dev->config + PCI_DEVICE_ID));
-}
+    info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
+    info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
+    info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
 
-static QObject *pci_get_regions_list(const PCIDevice *dev)
-{
-    int i;
-    QList *regions_list;
-
-    regions_list = qlist_new();
-
-    for (i = 0; i < PCI_NUM_REGIONS; i++) {
-        QObject *obj;
-        const PCIIORegion *r = &dev->io_regions[i];
+    info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
+    info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
+    info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
 
-        if (!r->size) {
-            continue;
-        }
+    info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range));
+    info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+    info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
 
-        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
-                                     "'address': %" PRId64 ", "
-                                     "'size': %" PRId64 " }",
-                                     i, r->addr, r->size);
-        } else {
-            int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
-
-            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
-                                     "'mem_type_64': %i, 'prefetch': %i, "
-                                     "'address': %" PRId64 ", "
-                                     "'size': %" PRId64 " }",
-                                     i, mem_type_64,
-                                     r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
-                                     r->addr, r->size);
+    if (dev->config[PCI_SECONDARY_BUS] != 0) {
+        PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
+        if (child_bus) {
+            info->has_devices = true;
+            info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
         }
-
-        qlist_append_obj(regions_list, obj);
     }
 
-    return QOBJECT(regions_list);
+    return info;
 }
 
-static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);
-
-static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)
+static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
+                                           int bus_num)
 {
+    const pci_class_desc *desc;
+    PciDeviceInfo *info;
     uint8_t type;
-    QObject *obj;
+    int class;
+
+    info = g_malloc0(sizeof(*info));
+    info->bus = bus_num;
+    info->slot = PCI_SLOT(dev->devfn);
+    info->function = PCI_FUNC(dev->devfn);
 
-    obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d,"                                       "'class_info': %p, 'id': %p, 'regions': %p,"
-                              " 'qdev_id': %s }",
-                              bus_num,
-                              PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
-                              pci_get_dev_class(dev), pci_get_dev_id(dev),
-                              pci_get_regions_list(dev),
-                              dev->qdev.id ? dev->qdev.id : "");
+    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
+    info->class_info.class = class;
+    desc = get_class_desc(class);
+    if (desc->desc) {
+        info->class_info.has_desc = true;
+        info->class_info.desc = g_strdup(desc->desc);
+    }
+
+    info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
+    info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
+    info->regions = qmp_query_pci_regions(dev);
+    info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
 
     if (dev->config[PCI_INTERRUPT_PIN] != 0) {
-        QDict *qdict = qobject_to_qdict(obj);
-        qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
+        info->has_irq = true;
+        info->irq = dev->config[PCI_INTERRUPT_LINE];
     }
 
     type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
     if (type == PCI_HEADER_TYPE_BRIDGE) {
-        QDict *qdict;
-        QObject *pci_bridge;
-
-        pci_bridge = qobject_from_jsonf("{ 'bus': "
-        "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "
-        "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
-        "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
-        "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",
-        dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS],
-        dev->config[PCI_SUBORDINATE_BUS],
-        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),
-        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),
-        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
-        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
-        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
-                               PCI_BASE_ADDRESS_MEM_PREFETCH),
-        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
-                                PCI_BASE_ADDRESS_MEM_PREFETCH));
-
-        if (dev->config[PCI_SECONDARY_BUS] != 0) {
-            PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
-
-            if (child_bus) {
-                qdict = qobject_to_qdict(pci_bridge);
-                qdict_put_obj(qdict, "devices",
-                              pci_get_devices_list(child_bus,
-                                                   dev->config[PCI_SECONDARY_BUS]));
-            }
-        }
-        qdict = qobject_to_qdict(obj);
-        qdict_put_obj(qdict, "pci_bridge", pci_bridge);
+        info->has_pci_bridge = true;
+        info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
     }
 
-    return obj;
+    return info;
 }
 
-static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
+static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
 {
-    int devfn;
+    PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
     PCIDevice *dev;
-    QList *dev_list;
-
-    dev_list = qlist_new();
+    int devfn;
 
     for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
         dev = bus->devices[devfn];
         if (dev) {
-            qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus, bus_num));
+            info = g_malloc0(sizeof(*info));
+            info->value = qmp_query_pci_device(dev, bus, bus_num);
+
+            /* XXX: waiting for the qapi to support GSList */
+            if (!cur_item) {
+                head = cur_item = info;
+            } else {
+                cur_item->next = info;
+                cur_item = info;
+            }
         }
     }
 
-    return QOBJECT(dev_list);
+    return head;
 }
 
-static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
+static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
 {
+    PciInfo *info = NULL;
+
     bus = pci_find_bus(bus, bus_num);
     if (bus) {
-        return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
-                                  bus_num, pci_get_devices_list(bus, bus_num));
+        info = g_malloc0(sizeof(*info));
+        info->bus = bus_num;
+        info->devices = qmp_query_pci_devices(bus, bus_num);
     }
 
-    return NULL;
+    return info;
 }
 
-void do_pci_info(Monitor *mon, QObject **ret_data)
+PciInfoList *qmp_query_pci(Error **errp)
 {
-    QList *bus_list;
+    PciInfoList *info, *head = NULL, *cur_item = NULL;
     struct PCIHostBus *host;
 
-    bus_list = qlist_new();
-
     QLIST_FOREACH(host, &host_buses, next) {
-        QObject *obj = pci_get_bus_dict(host->bus, 0);
-        if (obj) {
-            qlist_append_obj(bus_list, obj);
+        info = g_malloc0(sizeof(*info));
+        info->value = qmp_query_pci_bus(host->bus, 0);
+
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
         }
     }
 
-    *ret_data = QOBJECT(bus_list);
+    return head;
 }
 
 static const char * const pci_nic_models[] = {
diff --git a/hw/pci.h b/hw/pci.h
index 86a81c8..98f30f7 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -2,7 +2,6 @@
 #define QEMU_PCI_H
 
 #include "qemu-common.h"
-#include "qobject.h"
 
 #include "qdev.h"
 #include "memory.h"
@@ -271,9 +270,6 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
 int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
                      unsigned *slotp);
 
-void do_pci_info_print(Monitor *mon, const QObject *data);
-void do_pci_info(Monitor *mon, QObject **ret_data);
-
 void pci_device_deassert_intx(PCIDevice *dev);
 
 static inline void
diff --git a/monitor.c b/monitor.c
index 379b7d4..edcacda 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2738,8 +2738,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show PCI info",
-        .user_print = do_pci_info_print,
-        .mhandler.info_new = do_pci_info,
+        .mhandler.info = hmp_info_pci,
     },
 #if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
     defined(TARGET_PPC)
@@ -2954,14 +2953,6 @@ static const mon_cmd_t qmp_cmds[] = {
 };
 
 static const mon_cmd_t qmp_query_cmds[] = {
-    {
-        .name       = "pci",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show PCI info",
-        .user_print = do_pci_info_print,
-        .mhandler.info_new = do_pci_info,
-    },
     { /* NULL */ },
 };
 
diff --git a/qapi-schema.json b/qapi-schema.json
index b2814cd..cb1ba77 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -703,6 +703,134 @@
 { 'command': 'query-balloon', 'returns': 'BalloonInfo' }
 
 ##
+# @PciMemoryRange:
+#
+# A PCI device memory region
+#
+# @base: the starting address (guest physical)
+#
+# @limit: the ending address (guest physical)
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
+
+##
+# @PciMemoryRegion
+#
+# Information about a PCI device I/O region.
+#
+# @bar: the index of the Base Address Register for this region
+#
+# @type: 'io' if the region is a PIO region
+#        'memory' if the region is a MMIO region
+#
+# @prefetch: #optional if @type is 'memory', true if the memory is prefetchable
+#
+# @mem_type_64: #optional if @type is 'memory', true if the BAR is 64-bit
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciMemoryRegion',
+  'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
+           '*prefetch': 'bool', '*mem_type_64': 'bool' } }
+
+##
+# @PciBridgeInfo:
+#
+# Information about a PCI Bridge device
+#
+# @bus.number: primary bus interface number.  This should be the number of the
+#              bus the device resides on.
+#
+# @bus.secondary: secondary bus interface number.  This is the number of the
+#                 main bus for the bridge
+#
+# @bus.subordinate: This is the highest number bus that resides below the
+#                   bridge.
+#
+# @bus.io_range: The PIO range for all devices on this bridge
+#
+# @bus.memory_range: The MMIO range for all devices on this bridge
+#
+# @bus.prefetchable_range: The range of prefetchable MMIO for all devices on
+#                          this bridge
+#
+# @devices: a list of @PciDeviceInfo for each device on this bridge
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciBridgeInfo',
+  'data': {'bus': { 'number': 'int', 'secondary': 'int', 'subordinate': 'int',
+                    'io_range': 'PciMemoryRange',
+                    'memory_range': 'PciMemoryRange',
+                    'prefetchable_range': 'PciMemoryRange' },
+           '*devices': ['PciDeviceInfo']} }
+
+##
+# @PciDeviceInfo:
+#
+# Information about a PCI device
+#
+# @bus: the bus number of the device
+#
+# @slot: the slot the device is located in
+#
+# @function: the function of the slot used by the device
+#
+# @class_info.desc: #optional a string description of the device's class
+#
+# @class_info.class: the class code of the device
+#
+# @id.device: the PCI device id
+#
+# @id.vendor: the PCI vendor id
+#
+# @irq: #optional if an IRQ is assigned to the device, the IRQ number
+#
+# @qdev_id: the device name of the PCI device
+#
+# @pci_bridge: if the device is a PCI bridge, the bridge information
+#
+# @regions: a list of the PCI I/O regions associated with the device
+#
+# Notes: the contents of @class_info.desc are not stable and should only be
+#        treated as informational.
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciDeviceInfo',
+  'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
+           'class_info': {'*desc': 'str', 'class': 'int'},
+           'id': {'device': 'int', 'vendor': 'int'},
+           '*irq': 'int', 'qdev_id': 'str', '*pci_bridge': 'PciBridgeInfo',
+           'regions': ['PciMemoryRegion']} }
+
+##
+# @PciInfo:
+#
+# Information about a PCI bus
+#
+# @bus: the bus index
+#
+# @devices: a list of devices on this bus
+#
+# Since: 0.14.0
+##
+{ 'type': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
+
+##
+# @query-pci:
+#
+# Return information about the PCI bus topology of the guest.
+#
+# Returns: a list of @PciInfo for each PCI bus
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-pci', 'returns': ['PciInfo'] }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 8ef6ca2..eb3072c 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1576,6 +1576,12 @@ Note: This example has been shortened as the real response is too long.
 
 EQMP
 
+    {
+        .name       = "query-pci",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_pci,
+    },
+
 SQMP
 query-kvm
 ---------
commit 96637bcdf9e00db77265229d3d30d952bdde74be
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Oct 21 11:41:37 2011 -0200

    qapi: Convert query-balloon
    
    Please, note that some of the code supporting memory statistics is
    still around (eg. virtio_balloon_receive_stats() and reset_stats()).
    
    Also, the qmp_query_balloon() function is synchronous and thus doesn't
    make any use of the (not fully working) monitor's asynchronous command
    support (the old non-qapi implementation did).
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/balloon.c b/balloon.c
index a2133db..e1cd5fa 100644
--- a/balloon.c
+++ b/balloon.c
@@ -25,12 +25,11 @@
  */
 
 #include "monitor.h"
-#include "qjson.h"
-#include "qint.h"
 #include "cpu-common.h"
 #include "kvm.h"
 #include "balloon.h"
 #include "trace.h"
+#include "qmp-commands.h"
 
 static QEMUBalloonEvent *balloon_event_fn;
 static QEMUBalloonStatus *balloon_stat_fn;
@@ -72,76 +71,33 @@ static int qemu_balloon(ram_addr_t target)
     return 1;
 }
 
-static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
+static int qemu_balloon_status(BalloonInfo *info)
 {
     if (!balloon_stat_fn) {
         return 0;
     }
-    balloon_stat_fn(balloon_opaque, cb, opaque);
+    balloon_stat_fn(balloon_opaque, info);
     return 1;
 }
 
-static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
+BalloonInfo *qmp_query_balloon(Error **errp)
 {
-    Monitor *mon = opaque;
-
-    if (strcmp(key, "actual")) {
-        monitor_printf(mon, ",%s=%" PRId64, key,
-                       qint_get_int(qobject_to_qint(obj)));
-    }
-}
-
-void monitor_print_balloon(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-    if (!qdict_haskey(qdict, "actual")) {
-        return;
-    }
-    monitor_printf(mon, "balloon: actual=%" PRId64,
-                   qdict_get_int(qdict, "actual") >> 20);
-    qdict_iter(qdict, print_balloon_stat, mon);
-    monitor_printf(mon, "\n");
-}
-
-/**
- * do_info_balloon(): Balloon information
- *
- * Make an asynchronous request for balloon info.  When the request completes
- * a QDict will be returned according to the following specification:
- *
- * - "actual": current balloon value in bytes
- * The following fields may or may not be present:
- * - "mem_swapped_in": Amount of memory swapped in (bytes)
- * - "mem_swapped_out": Amount of memory swapped out (bytes)
- * - "major_page_faults": Number of major faults
- * - "minor_page_faults": Number of minor faults
- * - "free_mem": Total amount of free and unused memory (bytes)
- * - "total_mem": Total amount of available memory (bytes)
- *
- * Example:
- *
- * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
- *   "major_page_faults": 142, "minor_page_faults": 239245,
- *   "free_mem": 1014185984, "total_mem": 1044668416 }
- */
-int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
-{
-    int ret;
+    BalloonInfo *info;
 
     if (kvm_enabled() && !kvm_has_sync_mmu()) {
-        qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
-        return -1;
+        error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
+        return NULL;
     }
 
-    ret = qemu_balloon_status(cb, opaque);
-    if (!ret) {
-        qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
-        return -1;
+    info = g_malloc0(sizeof(*info));
+
+    if (qemu_balloon_status(info) == 0) {
+        error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
+        qapi_free_BalloonInfo(info);
+        return NULL;
     }
 
-    return 0;
+    return info;
 }
 
 /**
diff --git a/balloon.h b/balloon.h
index f59e288..b36abea 100644
--- a/balloon.h
+++ b/balloon.h
@@ -15,17 +15,15 @@
 #define _QEMU_BALLOON_H
 
 #include "monitor.h"
+#include "qapi-types.h"
 
 typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
-typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
-                                 void *cb_data);
+typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
 
 int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
 			     QEMUBalloonStatus *stat_func, void *opaque);
 void qemu_remove_balloon_handler(void *opaque);
 
-void monitor_print_balloon(Monitor *mon, const QObject *data);
-int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
 int do_balloon(Monitor *mon, const QDict *params,
                MonitorCompletion cb, void *opaque);
 
diff --git a/hmp.c b/hmp.c
index aae13c0..e0b40b1 100644
--- a/hmp.c
+++ b/hmp.c
@@ -349,6 +349,45 @@ out:
     qapi_free_SpiceInfo(info);
 }
 
+void hmp_info_balloon(Monitor *mon)
+{
+    BalloonInfo *info;
+    Error *err = NULL;
+
+    info = qmp_query_balloon(&err);
+    if (err) {
+        monitor_printf(mon, "%s\n", error_get_pretty(err));
+        error_free(err);
+        return;
+    }
+
+    monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
+    if (info->has_mem_swapped_in) {
+        monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
+    }
+    if (info->has_mem_swapped_out) {
+        monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
+    }
+    if (info->has_major_page_faults) {
+        monitor_printf(mon, " major_page_faults=%" PRId64,
+                       info->major_page_faults);
+    }
+    if (info->has_minor_page_faults) {
+        monitor_printf(mon, " minor_page_faults=%" PRId64,
+                       info->minor_page_faults);
+    }
+    if (info->has_free_mem) {
+        monitor_printf(mon, " free_mem=%" PRId64, info->free_mem);
+    }
+    if (info->has_total_mem) {
+        monitor_printf(mon, " total_mem=%" PRId64, info->total_mem);
+    }
+
+    monitor_printf(mon, "\n");
+
+    qapi_free_BalloonInfo(info);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index 09f3a01..d2c2d88 100644
--- a/hmp.h
+++ b/hmp.h
@@ -30,6 +30,7 @@ void hmp_info_block(Monitor *mon);
 void hmp_info_blockstats(Monitor *mon);
 void hmp_info_vnc(Monitor *mon);
 void hmp_info_spice(Monitor *mon);
+void hmp_info_balloon(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 5f8f4bd..e24a2bf 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -18,22 +18,14 @@
 #include "virtio.h"
 #include "pc.h"
 #include "cpu.h"
-#include "monitor.h"
 #include "balloon.h"
 #include "virtio-balloon.h"
 #include "kvm.h"
-#include "qlist.h"
-#include "qint.h"
-#include "qstring.h"
 
 #if defined(__linux__)
 #include <sys/mman.h>
 #endif
 
-/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
-#define ENABLE_GUEST_STATS   0
-
-
 typedef struct VirtIOBalloon
 {
     VirtIODevice vdev;
@@ -43,8 +35,6 @@ typedef struct VirtIOBalloon
     uint64_t stats[VIRTIO_BALLOON_S_NR];
     VirtQueueElement stats_vq_elem;
     size_t stats_vq_offset;
-    MonitorCompletion *stats_callback;
-    void *stats_opaque_callback_data;
     DeviceState *qdev;
 } VirtIOBalloon;
 
@@ -76,31 +66,6 @@ static inline void reset_stats(VirtIOBalloon *dev)
     for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
 }
 
-static void stat_put(QDict *dict, const char *label, uint64_t val)
-{
-    if (val != -1)
-        qdict_put(dict, label, qint_from_int(val));
-}
-
-static QObject *get_stats_qobject(VirtIOBalloon *dev)
-{
-    QDict *dict = qdict_new();
-    uint64_t actual = ram_size - ((uint64_t) dev->actual <<
-                                  VIRTIO_BALLOON_PFN_SHIFT);
-
-    stat_put(dict, "actual", actual);
-#if ENABLE_GUEST_STATS
-    stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
-    stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
-    stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
-    stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
-    stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
-    stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
-#endif
-
-    return QOBJECT(dict);
-}
-
 static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtIOBalloon *s = to_virtio_balloon(vdev);
@@ -131,20 +96,6 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
     }
 }
 
-static void complete_stats_request(VirtIOBalloon *vb)
-{
-    QObject *stats;
-
-    if (!vb->stats_opaque_callback_data)
-        return;
-
-    stats = get_stats_qobject(vb);
-    vb->stats_callback(vb->stats_opaque_callback_data, stats);
-    qobject_decref(stats);
-    vb->stats_opaque_callback_data = NULL;
-    vb->stats_callback = NULL;
-}
-
 static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
@@ -172,8 +123,6 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
             s->stats[tag] = val;
     }
     s->stats_vq_offset = offset;
-
-    complete_stats_request(s);
 }
 
 static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
@@ -202,32 +151,33 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
     return f;
 }
 
-static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
-                                void *cb_data)
+static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
 {
     VirtIOBalloon *dev = opaque;
 
-    /* For now, only allow one request at a time.  This restriction can be
-     * removed later by queueing callback and data pairs.
+#if 0
+    /* Disable guest-provided stats for now. For more details please check:
+     * https://bugzilla.redhat.com/show_bug.cgi?id=623903
+     *
+     * If you do enable it (which is probably not going to happen as we
+     * need a new command for it), remember that you also need to fill the
+     * appropriate members of the BalloonInfo structure so that the stats
+     * are returned to the client.
      */
-    if (dev->stats_callback != NULL) {
-        return;
-    }
-    dev->stats_callback = cb;
-    dev->stats_opaque_callback_data = cb_data;
-
-    if (ENABLE_GUEST_STATS
-        && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
+    if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
         virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
         virtio_notify(&dev->vdev, dev->svq);
         return;
     }
+#endif
 
     /* Stats are not supported.  Clear out any stale values that might
      * have been set by a more featureful guest kernel.
      */
     reset_stats(dev);
-    complete_stats_request(dev);
+
+    info->actual = ram_size - ((uint64_t) dev->actual <<
+                               VIRTIO_BALLOON_PFN_SHIFT);
 }
 
 static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
diff --git a/monitor.c b/monitor.c
index fc3da38..379b7d4 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2904,9 +2904,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show balloon information",
-        .user_print = monitor_print_balloon,
-        .mhandler.info_async = do_info_balloon,
-        .flags      = MONITOR_CMD_ASYNC,
+        .mhandler.info = hmp_info_balloon,
     },
     {
         .name       = "qtree",
@@ -2964,15 +2962,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .user_print = do_pci_info_print,
         .mhandler.info_new = do_pci_info,
     },
-    {
-        .name       = "balloon",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show balloon information",
-        .user_print = monitor_print_balloon,
-        .mhandler.info_async = do_info_balloon,
-        .flags      = MONITOR_CMD_ASYNC,
-    },
     { /* NULL */ },
 };
 
diff --git a/qapi-schema.json b/qapi-schema.json
index 087a463..b2814cd 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -659,6 +659,50 @@
 { 'command': 'query-spice', 'returns': 'SpiceInfo' }
 
 ##
+# @BalloonInfo:
+#
+# Information about the guest balloon device.
+#
+# @actual: the number of bytes the balloon currently contains
+#
+# @mem_swapped_in: #optional number of pages swapped in within the guest
+#
+# @mem_swapped_out: #optional number of pages swapped out within the guest
+#
+# @major_page_faults: #optional number of major page faults within the guest
+#
+# @minor_page_faults: #optional number of minor page faults within the guest
+#
+# @free_mem: #optional amount of memory (in bytes) free in the guest
+#
+# @total_mem: #optional amount of memory (in bytes) visible to the guest
+#
+# Since: 0.14.0
+#
+# Notes: all current versions of QEMU do not fill out optional information in
+#        this structure.
+##
+{ 'type': 'BalloonInfo',
+  'data': {'actual': 'int', '*mem_swapped_in': 'int',
+           '*mem_swapped_out': 'int', '*major_page_faults': 'int',
+           '*minor_page_faults': 'int', '*free_mem': 'int',
+           '*total_mem': 'int'} }
+
+##
+# @query-balloon:
+#
+# Return information about the balloon device.
+#
+# Returns: @BalloonInfo on success
+#          If the balloon driver is enabled but not functional because the KVM
+#          kernel module cannot support it, KvmMissingCap
+#          If no balloon device is present, DeviceNotActive
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e99c240..8ef6ca2 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1989,3 +1989,8 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-balloon",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_balloon,
+    },
commit d1f29646f21321e60d1be4e72ac3b6caaa0239cc
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Oct 20 17:01:33 2011 -0200

    qapi: Convert query-spice
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index 6d86fe3..aae13c0 100644
--- a/hmp.c
+++ b/hmp.c
@@ -306,6 +306,49 @@ out:
     qapi_free_VncInfo(info);
 }
 
+void hmp_info_spice(Monitor *mon)
+{
+    SpiceChannelList *chan;
+    SpiceInfo *info;
+
+    info = qmp_query_spice(NULL);
+
+    if (!info->enabled) {
+        monitor_printf(mon, "Server: disabled\n");
+        goto out;
+    }
+
+    monitor_printf(mon, "Server:\n");
+    if (info->has_port) {
+        monitor_printf(mon, "     address: %s:%" PRId64 "\n",
+                       info->host, info->port);
+    }
+    if (info->has_tls_port) {
+        monitor_printf(mon, "     address: %s:%" PRId64 " [tls]\n",
+                       info->host, info->tls_port);
+    }
+    monitor_printf(mon, "        auth: %s\n", info->auth);
+    monitor_printf(mon, "    compiled: %s\n", info->compiled_version);
+
+    if (!info->has_channels || info->channels == NULL) {
+        monitor_printf(mon, "Channels: none\n");
+    } else {
+        for (chan = info->channels; chan; chan = chan->next) {
+            monitor_printf(mon, "Channel:\n");
+            monitor_printf(mon, "     address: %s:%s%s\n",
+                           chan->value->host, chan->value->port,
+                           chan->value->tls ? " [tls]" : "");
+            monitor_printf(mon, "     session: %" PRId64 "\n",
+                           chan->value->connection_id);
+            monitor_printf(mon, "     channel: %" PRId64 ":%" PRId64 "\n",
+                           chan->value->channel_type, chan->value->channel_id);
+        }
+    }
+
+out:
+    qapi_free_SpiceInfo(info);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index 7713348..09f3a01 100644
--- a/hmp.h
+++ b/hmp.h
@@ -29,6 +29,7 @@ void hmp_info_cpus(Monitor *mon);
 void hmp_info_block(Monitor *mon);
 void hmp_info_blockstats(Monitor *mon);
 void hmp_info_vnc(Monitor *mon);
+void hmp_info_spice(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/monitor.c b/monitor.c
index d7c72bb..fc3da38 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2857,8 +2857,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the spice server status",
-        .user_print = do_info_spice_print,
-        .mhandler.info_new = do_info_spice,
+        .mhandler.info = hmp_info_spice,
     },
 #endif
     {
@@ -2965,16 +2964,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .user_print = do_pci_info_print,
         .mhandler.info_new = do_pci_info,
     },
-#if defined(CONFIG_SPICE)
-    {
-        .name       = "spice",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the spice server status",
-        .user_print = do_info_spice_print,
-        .mhandler.info_new = do_info_spice,
-    },
-#endif
     {
         .name       = "balloon",
         .args_type  = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 23be143..087a463 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -585,6 +585,80 @@
 { 'command': 'query-vnc', 'returns': 'VncInfo' }
 
 ##
+# @SpiceChannel
+#
+# Information about a SPICE client channel.
+#
+# @host: The host name of the client.  QEMU tries to resolve this to a DNS name
+#        when possible.
+#
+# @family: 'ipv6' if the client is connected via IPv6 and TCP
+#          'ipv4' if the client is connected via IPv4 and TCP
+#          'unix' if the client is connected via a unix domain socket
+#          'unknown' otherwise
+#
+# @port: The client's port number.
+#
+# @connection-id: SPICE connection id number.  All channels with the same id
+#                 belong to the same SPICE session.
+#
+# @connection-type: SPICE channel type number.  "1" is the main control channel,
+#                   filter for this one if you want track spice sessions only
+#
+# @channel-id: SPICE channel ID number.  Usually "0", might be different needed
+#              when multiple channels of the same type exist, such as multiple
+#              display channels in a multihead setup
+#
+# @tls: true if the channel is encrypted, false otherwise.
+#
+# Since: 0.14.0
+##
+{ 'type': 'SpiceChannel',
+  'data': {'host': 'str', 'family': 'str', 'port': 'str',
+           'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
+           'tls': 'bool'} }
+
+##
+# @SpiceInfo
+#
+# Information about the SPICE session.
+# 
+# @enabled: true if the SPICE server is enabled, false otherwise
+#
+# @host: #optional The hostname the SPICE server is bound to.  This depends on
+#        the name resolution on the host and may be an IP address.
+#
+# @port: #optional The SPICE server's port number.
+#
+# @compiled-version: #optional SPICE server version.
+#
+# @tls-port: #optional The SPICE server's TLS port number.
+#
+# @auth: #optional the current authentication type used by the server
+#        'none' if no authentication is being used
+#        'spice' (TODO: describe)
+#
+# @channels: a list of @SpiceChannel for each active spice channel
+#
+# Since: 0.14.0
+##
+{ 'type': 'SpiceInfo',
+  'data': {'enabled': 'bool', '*host': 'str', '*port': 'int',
+           '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
+           '*channels': ['SpiceChannel']} }
+
+##
+# @query-spice
+#
+# Returns information about the current SPICE server
+#
+# Returns: @SpiceInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-spice', 'returns': 'SpiceInfo' }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 0953d3f..e99c240 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1817,6 +1817,14 @@ Example:
 
 EQMP
 
+#if defined(CONFIG_SPICE)
+    {
+        .name       = "query-spice",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_spice,
+    },
+#endif
+
 SQMP
 query-name
 ----------
diff --git a/qmp.c b/qmp.c
index 3a58cfe..511dd62 100644
--- a/qmp.c
+++ b/qmp.c
@@ -105,3 +105,15 @@ VncInfo *qmp_query_vnc(Error **errp)
     return NULL;
 };
 #endif
+
+#ifndef CONFIG_SPICE
+/* If SPICE support is enabled, the "true" query-spice command is
+   defined in the SPICE subsystem. Also note that we use a small
+   trick to maintain query-spice's original behavior, which is not
+   to be available in the namespace if SPICE is not compiled in */
+SpiceInfo *qmp_query_spice(Error **errp)
+{
+    error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice");
+    return NULL;
+};
+#endif
diff --git a/ui/spice-core.c b/ui/spice-core.c
index b33366e..f556849 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -27,6 +27,7 @@
 #include "qemu-queue.h"
 #include "qemu-x509.h"
 #include "qemu_socket.h"
+#include "qmp-commands.h"
 #include "qint.h"
 #include "qbool.h"
 #include "qstring.h"
@@ -194,22 +195,6 @@ static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
     qdict_put(dict, "tls", qbool_from_int(tls));
 }
 
-static QList *channel_list_get(void)
-{
-    ChannelList *item;
-    QList *list;
-    QDict *dict;
-
-    list = qlist_new();
-    QTAILQ_FOREACH(item, &channel_list, link) {
-        dict = qdict_new();
-        add_addr_info(dict, &item->info->paddr, item->info->plen);
-        add_channel_info(dict, item->info);
-        qlist_append(list, dict);
-    }
-    return list;
-}
-
 static void channel_event(int event, SpiceChannelEventInfo *info)
 {
     static const int qevent[] = {
@@ -351,98 +336,90 @@ static const char *wan_compression_names[] = {
 
 /* functions for the rest of qemu */
 
-static void info_spice_iter(QObject *obj, void *opaque)
+static SpiceChannelList *qmp_query_spice_channels(void)
 {
-    QDict *client;
-    Monitor *mon = opaque;
-
-    client = qobject_to_qdict(obj);
-    monitor_printf(mon, "Channel:\n");
-    monitor_printf(mon, "     address: %s:%s%s\n",
-                   qdict_get_str(client, "host"),
-                   qdict_get_str(client, "port"),
-                   qdict_get_bool(client, "tls") ? " [tls]" : "");
-    monitor_printf(mon, "     session: %" PRId64 "\n",
-                   qdict_get_int(client, "connection-id"));
-    monitor_printf(mon, "     channel: %d:%d\n",
-                   (int)qdict_get_int(client, "channel-type"),
-                   (int)qdict_get_int(client, "channel-id"));
-}
-
-void do_info_spice_print(Monitor *mon, const QObject *data)
-{
-    QDict *server;
-    QList *channels;
-    const char *host;
-    int port;
-
-    server = qobject_to_qdict(data);
-    if (qdict_get_bool(server, "enabled") == 0) {
-        monitor_printf(mon, "Server: disabled\n");
-        return;
-    }
+    SpiceChannelList *cur_item = NULL, *head = NULL;
+    ChannelList *item;
 
-    monitor_printf(mon, "Server:\n");
-    host = qdict_get_str(server, "host");
-    port = qdict_get_try_int(server, "port", -1);
-    if (port != -1) {
-        monitor_printf(mon, "     address: %s:%d\n", host, port);
-    }
-    port = qdict_get_try_int(server, "tls-port", -1);
-    if (port != -1) {
-        monitor_printf(mon, "     address: %s:%d [tls]\n", host, port);
+    QTAILQ_FOREACH(item, &channel_list, link) {
+        SpiceChannelList *chan;
+        char host[NI_MAXHOST], port[NI_MAXSERV];
+
+        chan = g_malloc0(sizeof(*chan));
+        chan->value = g_malloc0(sizeof(*chan->value));
+
+        getnameinfo(&item->info->paddr, item->info->plen,
+                    host, sizeof(host), port, sizeof(port),
+                    NI_NUMERICHOST | NI_NUMERICSERV);
+        chan->value->host = g_strdup(host);
+        chan->value->port = g_strdup(port);
+        chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family));
+
+        chan->value->connection_id = item->info->connection_id;
+        chan->value->channel_type = item->info->type;
+        chan->value->channel_id = item->info->id;
+        chan->value->tls = item->info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
+
+       /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = chan;
+        } else {
+            cur_item->next = chan;
+            cur_item = chan;
+        }
     }
-    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
-    monitor_printf(mon, "    compiled: %s\n",
-                   qdict_get_str(server, "compiled-version"));
 
-    channels = qdict_get_qlist(server, "channels");
-    if (qlist_empty(channels)) {
-        monitor_printf(mon, "Channels: none\n");
-    } else {
-        qlist_iter(channels, info_spice_iter, mon);
-    }
+    return head;
 }
 
-void do_info_spice(Monitor *mon, QObject **ret_data)
+SpiceInfo *qmp_query_spice(Error **errp)
 {
     QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
-    QDict *server;
-    QList *clist;
-    const char *addr;
     int port, tls_port;
+    const char *addr;
+    SpiceInfo *info;
     char version_string[20]; /* 12 = |255.255.255\0| is the max */
 
+    info = g_malloc0(sizeof(*info));
+
     if (!spice_server) {
-        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
-        return;
+        info->enabled = false;
+        return info;
     }
 
+    info->enabled = true;
+
     addr = qemu_opt_get(opts, "addr");
     port = qemu_opt_get_number(opts, "port", 0);
     tls_port = qemu_opt_get_number(opts, "tls-port", 0);
-    clist = channel_list_get();
 
-    server = qdict_new();
-    qdict_put(server, "enabled", qbool_from_int(true));
-    qdict_put(server, "auth", qstring_from_str(auth));
-    qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0"));
+    info->has_auth = true;
+    info->auth = g_strdup(auth);
+
+    info->has_host = true;
+    info->host = g_strdup(addr ? addr : "0.0.0.0");
+
+    info->has_compiled_version = true;
     snprintf(version_string, sizeof(version_string), "%d.%d.%d",
              (SPICE_SERVER_VERSION & 0xff0000) >> 16,
              (SPICE_SERVER_VERSION & 0xff00) >> 8,
              SPICE_SERVER_VERSION & 0xff);
-    qdict_put(server, "compiled-version", qstring_from_str(version_string));
+    info->compiled_version = g_strdup(version_string);
+
     if (port) {
-        qdict_put(server, "port", qint_from_int(port));
+        info->has_port = true;
+        info->port = port;
     }
     if (tls_port) {
-        qdict_put(server, "tls-port", qint_from_int(tls_port));
-    }
-    if (clist) {
-        qdict_put(server, "channels", clist);
+        info->has_tls_port = true;
+        info->tls_port = tls_port;
     }
 
-    *ret_data = QOBJECT(server);
+    /* for compatibility with the original command */
+    info->has_channels = true;
+    info->channels = qmp_query_spice_channels();
+
+    return info;
 }
 
 static void migration_state_notifier(Notifier *notifier, void *data)
commit 2b54aa879ea8490e25107dfc51a6ee268c84c273
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Oct 17 16:41:22 2011 -0200

    qapi: Convert query-vnc
    
    There are three important remarks in relation to the non-qapi command:
    
     1. This commit also fixes the behavior of the 'query-vnc' and 'info vnc'
        commands to return an error when qemu is built without VNC support
        (ie. --disable-vnc). The non-qapi command would return the OK
        response in QMP and no response in HMP
    
     2. The qapi version explicitly marks the fields 'host', 'family',
        'service' and 'auth' as optional. Their are not documented as optional
        in the non-qapi command doc, but they would not be returned if
        vnc support is disabled. The qapi version maintains the same
        semantics, but documents those fields correctly
    
     3. The 'clients' field, which is a list, is marked as optional but is
        always returned. If there are no clients connected an empty list
        is returned. This is not the Right Way to this in the qapi but it's
        how the non-qapi command used to work
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/console.h b/console.h
index 9c1487e..6ac4ed3 100644
--- a/console.h
+++ b/console.h
@@ -383,8 +383,6 @@ char *vnc_display_local_addr(DisplayState *ds);
 #ifdef CONFIG_VNC
 int vnc_display_password(DisplayState *ds, const char *password);
 int vnc_display_pw_expire(DisplayState *ds, time_t expires);
-void do_info_vnc_print(Monitor *mon, const QObject *data);
-void do_info_vnc(Monitor *mon, QObject **ret_data);
 #else
 static inline int vnc_display_password(DisplayState *ds, const char *password)
 {
@@ -396,13 +394,6 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
     qerror_report(QERR_FEATURE_DISABLED, "vnc");
     return -ENODEV;
 };
-static inline void do_info_vnc(Monitor *mon, QObject **ret_data)
-{
-};
-static inline void do_info_vnc_print(Monitor *mon, const QObject *data)
-{
-    monitor_printf(mon, "VNC support disabled\n");
-};
 #endif
 
 /* curses.c */
diff --git a/hmp.c b/hmp.c
index eab2ddf..6d86fe3 100644
--- a/hmp.c
+++ b/hmp.c
@@ -260,6 +260,52 @@ void hmp_info_blockstats(Monitor *mon)
     qapi_free_BlockStatsList(stats_list);
 }
 
+void hmp_info_vnc(Monitor *mon)
+{
+    VncInfo *info;
+    Error *err = NULL;
+    VncClientInfoList *client;
+
+    info = qmp_query_vnc(&err);
+    if (err) {
+        monitor_printf(mon, "%s\n", error_get_pretty(err));
+        error_free(err);
+        return;
+    }
+
+    if (!info->enabled) {
+        monitor_printf(mon, "Server: disabled\n");
+        goto out;
+    }
+
+    monitor_printf(mon, "Server:\n");
+    if (info->has_host && info->has_service) {
+        monitor_printf(mon, "     address: %s:%s\n", info->host, info->service);
+    }
+    if (info->has_auth) {
+        monitor_printf(mon, "        auth: %s\n", info->auth);
+    }
+
+    if (!info->has_clients || info->clients == NULL) {
+        monitor_printf(mon, "Client: none\n");
+    } else {
+        for (client = info->clients; client; client = client->next) {
+            monitor_printf(mon, "Client:\n");
+            monitor_printf(mon, "     address: %s:%s\n",
+                           client->value->host, client->value->service);
+            monitor_printf(mon, "  x509_dname: %s\n",
+                           client->value->x509_dname ?
+                           client->value->x509_dname : "none");
+            monitor_printf(mon, "    username: %s\n",
+                           client->value->has_sasl_username ?
+                           client->value->sasl_username : "none");
+        }
+    }
+
+out:
+    qapi_free_VncInfo(info);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index f8c50d4..7713348 100644
--- a/hmp.h
+++ b/hmp.h
@@ -28,6 +28,7 @@ void hmp_info_migrate(Monitor *mon);
 void hmp_info_cpus(Monitor *mon);
 void hmp_info_block(Monitor *mon);
 void hmp_info_blockstats(Monitor *mon);
+void hmp_info_vnc(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/monitor.c b/monitor.c
index 70e5460..d7c72bb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2849,8 +2849,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the vnc server status",
-        .user_print = do_info_vnc_print,
-        .mhandler.info_new = do_info_vnc,
+        .mhandler.info = hmp_info_vnc,
     },
 #if defined(CONFIG_SPICE)
     {
@@ -2966,14 +2965,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .user_print = do_pci_info_print,
         .mhandler.info_new = do_pci_info,
     },
-    {
-        .name       = "vnc",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the vnc server status",
-        .user_print = do_info_vnc_print,
-        .mhandler.info_new = do_info_vnc,
-    },
 #if defined(CONFIG_SPICE)
     {
         .name       = "spice",
diff --git a/qapi-schema.json b/qapi-schema.json
index 45494d8..23be143 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -504,6 +504,87 @@
 { 'command': 'query-blockstats', 'returns': ['BlockStats'] }
 
 ##
+# @VncClientInfo:
+#
+# Information about a connected VNC client.
+#
+# @host: The host name of the client.  QEMU tries to resolve this to a DNS name
+#        when possible.
+#
+# @family: 'ipv6' if the client is connected via IPv6 and TCP
+#          'ipv4' if the client is connected via IPv4 and TCP
+#          'unix' if the client is connected via a unix domain socket
+#          'unknown' otherwise
+#
+# @service: The service name of the client's port.  This may depends on the
+#           host system's service database so symbolic names should not be
+#           relied on.
+#
+# @x509_dname: #optional If x509 authentication is in use, the Distinguished
+#              Name of the client.
+#
+# @sasl_username: #optional If SASL authentication is in use, the SASL username
+#                 used for authentication.
+#
+# Since: 0.14.0
+##
+{ 'type': 'VncClientInfo',
+  'data': {'host': 'str', 'family': 'str', 'service': 'str',
+           '*x509_dname': 'str', '*sasl_username': 'str'} }
+
+##
+# @VncInfo:
+#
+# Information about the VNC session.
+#
+# @enabled: true if the VNC server is enabled, false otherwise
+#
+# @host: #optional The hostname the VNC server is bound to.  This depends on
+#        the name resolution on the host and may be an IP address.
+#
+# @family: #optional 'ipv6' if the host is listening for IPv6 connections
+#                    'ipv4' if the host is listening for IPv4 connections
+#                    'unix' if the host is listening on a unix domain socket
+#                    'unknown' otherwise
+#
+# @service: #optional The service name of the server's port.  This may depends
+#           on the host system's service database so symbolic names should not
+#           be relied on.
+#
+# @auth: #optional the current authentication type used by the server
+#        'none' if no authentication is being used
+#        'vnc' if VNC authentication is being used
+#        'vencrypt+plain' if VEncrypt is used with plain text authentication
+#        'vencrypt+tls+none' if VEncrypt is used with TLS and no authentication
+#        'vencrypt+tls+vnc' if VEncrypt is used with TLS and VNC authentication
+#        'vencrypt+tls+plain' if VEncrypt is used with TLS and plain text auth
+#        'vencrypt+x509+none' if VEncrypt is used with x509 and no auth
+#        'vencrypt+x509+vnc' if VEncrypt is used with x509 and VNC auth
+#        'vencrypt+x509+plain' if VEncrypt is used with x509 and plain text auth
+#        'vencrypt+tls+sasl' if VEncrypt is used with TLS and SASL auth
+#        'vencrypt+x509+sasl' if VEncrypt is used with x509 and SASL auth
+#
+# @clients: a list of @VncClientInfo of all currently connected clients
+#
+# Since: 0.14.0
+##
+{ 'type': 'VncInfo',
+  'data': {'enabled': 'bool', '*host': 'str', '*family': 'str',
+           '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
+
+##
+# @query-vnc:
+#
+# Returns information about the current VNC server
+#
+# Returns: @VncInfo
+#          If VNC support is not compiled in, FeatureDisabled
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-vnc', 'returns': 'VncInfo' }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a250a7a..0953d3f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1741,6 +1741,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-vnc",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_vnc,
+    },
+
 SQMP
 query-spice
 -----------
diff --git a/qmp.c b/qmp.c
index e84922b..3a58cfe 100644
--- a/qmp.c
+++ b/qmp.c
@@ -95,3 +95,13 @@ void qmp_cpu(int64_t index, Error **errp)
 {
     /* Just do nothing */
 }
+
+#ifndef CONFIG_VNC
+/* If VNC support is enabled, the "true" query-vnc command is
+   defined in the VNC subsystem */
+VncInfo *qmp_query_vnc(Error **errp)
+{
+    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+    return NULL;
+};
+#endif
diff --git a/ui/vnc.c b/ui/vnc.c
index fc3a612..32d4cb7 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -31,6 +31,7 @@
 #include "qemu-timer.h"
 #include "acl.h"
 #include "qemu-objects.h"
+#include "qmp-commands.h"
 
 #define VNC_REFRESH_INTERVAL_BASE 30
 #define VNC_REFRESH_INTERVAL_INC  50
@@ -274,80 +275,110 @@ static void vnc_qmp_event(VncState *vs, MonitorEvent event)
     qobject_decref(data);
 }
 
-static void info_vnc_iter(QObject *obj, void *opaque)
+static VncClientInfo *qmp_query_vnc_client(const VncState *client)
 {
-    QDict *client;
-    Monitor *mon = opaque;
+    struct sockaddr_storage sa;
+    socklen_t salen = sizeof(sa);
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    VncClientInfo *info;
+
+    if (getpeername(client->csock, (struct sockaddr *)&sa, &salen) < 0) {
+        return NULL;
+    }
+
+    if (getnameinfo((struct sockaddr *)&sa, salen,
+                    host, sizeof(host),
+                    serv, sizeof(serv),
+                    NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+        return NULL;
+    }
 
-    client = qobject_to_qdict(obj);
-    monitor_printf(mon, "Client:\n");
-    monitor_printf(mon, "     address: %s:%s\n",
-                   qdict_get_str(client, "host"),
-                   qdict_get_str(client, "service"));
+    info = g_malloc0(sizeof(*info));
+    info->host = g_strdup(host);
+    info->service = g_strdup(serv);
+    info->family = g_strdup(inet_strfamily(sa.ss_family));
 
 #ifdef CONFIG_VNC_TLS
-    monitor_printf(mon, "  x509_dname: %s\n",
-        qdict_haskey(client, "x509_dname") ?
-        qdict_get_str(client, "x509_dname") : "none");
+    if (client->tls.session && client->tls.dname) {
+        info->has_x509_dname = true;
+        info->x509_dname = g_strdup(client->tls.dname);
+    }
 #endif
 #ifdef CONFIG_VNC_SASL
-    monitor_printf(mon, "    username: %s\n",
-        qdict_haskey(client, "sasl_username") ?
-        qdict_get_str(client, "sasl_username") : "none");
-#endif
-}
-
-void do_info_vnc_print(Monitor *mon, const QObject *data)
-{
-    QDict *server;
-    QList *clients;
-
-    server = qobject_to_qdict(data);
-    if (qdict_get_bool(server, "enabled") == 0) {
-        monitor_printf(mon, "Server: disabled\n");
-        return;
+    if (client->sasl.conn && client->sasl.username) {
+        info->has_sasl_username = true;
+        info->sasl_username = g_strdup(client->sasl.username);
     }
+#endif
 
-    monitor_printf(mon, "Server:\n");
-    monitor_printf(mon, "     address: %s:%s\n",
-                   qdict_get_str(server, "host"),
-                   qdict_get_str(server, "service"));
-    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
-
-    clients = qdict_get_qlist(server, "clients");
-    if (qlist_empty(clients)) {
-        monitor_printf(mon, "Client: none\n");
-    } else {
-        qlist_iter(clients, info_vnc_iter, mon);
-    }
+    return info;
 }
 
-void do_info_vnc(Monitor *mon, QObject **ret_data)
+VncInfo *qmp_query_vnc(Error **errp)
 {
+    VncInfo *info = g_malloc0(sizeof(*info));
+
     if (vnc_display == NULL || vnc_display->display == NULL) {
-        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
+        info->enabled = false;
     } else {
-        QList *clist;
+        VncClientInfoList *cur_item = NULL;
+        struct sockaddr_storage sa;
+        socklen_t salen = sizeof(sa);
+        char host[NI_MAXHOST];
+        char serv[NI_MAXSERV];
         VncState *client;
 
-        clist = qlist_new();
+        info->enabled = true;
+
+        /* for compatibility with the original command */
+        info->has_clients = true;
+
         QTAILQ_FOREACH(client, &vnc_display->clients, next) {
-            if (client->info) {
-                /* incref so that it's not freed by upper layers */
-                qobject_incref(client->info);
-                qlist_append_obj(clist, client->info);
+            VncClientInfoList *cinfo = g_malloc0(sizeof(*info));
+            cinfo->value = qmp_query_vnc_client(client);
+
+            /* XXX: waiting for the qapi to support GSList */
+            if (!cur_item) {
+                info->clients = cur_item = cinfo;
+            } else {
+                cur_item->next = cinfo;
+                cur_item = cinfo;
             }
         }
 
-        *ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }",
-                                       QOBJECT(clist));
-        assert(*ret_data != NULL);
+        if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa,
+                        &salen) == -1) {
+            error_set(errp, QERR_UNDEFINED_ERROR);
+            goto out_error;
+        }
 
-        if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) {
-            qobject_decref(*ret_data);
-            *ret_data = NULL;
+        if (getnameinfo((struct sockaddr *)&sa, salen,
+                        host, sizeof(host),
+                        serv, sizeof(serv),
+                        NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+            error_set(errp, QERR_UNDEFINED_ERROR);
+            goto out_error;
         }
+
+        info->has_host = true;
+        info->host = g_strdup(host);
+
+        info->has_service = true;
+        info->service = g_strdup(serv);
+
+        info->has_family = true;
+        info->family = g_strdup(inet_strfamily(sa.ss_family));
+
+        info->has_auth = true;
+        info->auth = g_strdup(vnc_auth_name(vnc_display));
     }
+
+    return info;
+
+out_error:
+    qapi_free_VncInfo(info);
+    return NULL;
 }
 
 /* TODO
commit bf82632841cd5cd9b4275913591efe4a2035b969
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Oct 19 15:15:57 2011 -0200

    qerror: Add a user string for QERR_FEATURE_DISABLED
    
    Missing from commit 821601ea5b.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qerror.c b/qerror.c
index 68998d4..4b48b39 100644
--- a/qerror.c
+++ b/qerror.c
@@ -117,6 +117,10 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "No file descriptor supplied via SCM_RIGHTS",
     },
     {
+        .error_fmt = QERR_FEATURE_DISABLED,
+        .desc      = "The feature '%(name)' is not enabled",
+    },
+    {
         .error_fmt = QERR_INVALID_BLOCK_FORMAT,
         .desc      = "Invalid block format '%(name)'",
     },
commit f11f57e405a99732ed0f3294904c2dd258d77629
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Sep 22 15:56:36 2011 -0300

    qapi: Convert query-blockstats
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/block.c b/block.c
index e648513..551aa80 100644
--- a/block.c
+++ b/block.c
@@ -1874,93 +1874,56 @@ BlockInfoList *qmp_query_block(Error **errp)
     return head;
 }
 
-static void bdrv_stats_iter(QObject *data, void *opaque)
-{
-    QDict *qdict;
-    Monitor *mon = opaque;
-
-    qdict = qobject_to_qdict(data);
-    monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
-
-    qdict = qobject_to_qdict(qdict_get(qdict, "stats"));
-    monitor_printf(mon, " rd_bytes=%" PRId64
-                        " wr_bytes=%" PRId64
-                        " rd_operations=%" PRId64
-                        " wr_operations=%" PRId64
-                        " flush_operations=%" PRId64
-                        " wr_total_time_ns=%" PRId64
-                        " rd_total_time_ns=%" PRId64
-                        " flush_total_time_ns=%" PRId64
-                        "\n",
-                        qdict_get_int(qdict, "rd_bytes"),
-                        qdict_get_int(qdict, "wr_bytes"),
-                        qdict_get_int(qdict, "rd_operations"),
-                        qdict_get_int(qdict, "wr_operations"),
-                        qdict_get_int(qdict, "flush_operations"),
-                        qdict_get_int(qdict, "wr_total_time_ns"),
-                        qdict_get_int(qdict, "rd_total_time_ns"),
-                        qdict_get_int(qdict, "flush_total_time_ns"));
-}
-
-void bdrv_stats_print(Monitor *mon, const QObject *data)
-{
-    qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
-}
-
-static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
-{
-    QObject *res;
-    QDict *dict;
-
-    res = qobject_from_jsonf("{ 'stats': {"
-                             "'rd_bytes': %" PRId64 ","
-                             "'wr_bytes': %" PRId64 ","
-                             "'rd_operations': %" PRId64 ","
-                             "'wr_operations': %" PRId64 ","
-                             "'wr_highest_offset': %" PRId64 ","
-                             "'flush_operations': %" PRId64 ","
-                             "'wr_total_time_ns': %" PRId64 ","
-                             "'rd_total_time_ns': %" PRId64 ","
-                             "'flush_total_time_ns': %" PRId64
-                             "} }",
-                             bs->nr_bytes[BDRV_ACCT_READ],
-                             bs->nr_bytes[BDRV_ACCT_WRITE],
-                             bs->nr_ops[BDRV_ACCT_READ],
-                             bs->nr_ops[BDRV_ACCT_WRITE],
-                             bs->wr_highest_sector *
-                             (uint64_t)BDRV_SECTOR_SIZE,
-                             bs->nr_ops[BDRV_ACCT_FLUSH],
-                             bs->total_time_ns[BDRV_ACCT_WRITE],
-                             bs->total_time_ns[BDRV_ACCT_READ],
-                             bs->total_time_ns[BDRV_ACCT_FLUSH]);
-    dict  = qobject_to_qdict(res);
-
-    if (*bs->device_name) {
-        qdict_put(dict, "device", qstring_from_str(bs->device_name));
+/* Consider exposing this as a full fledged QMP command */
+static BlockStats *qmp_query_blockstat(const BlockDriverState *bs, Error **errp)
+{
+    BlockStats *s;
+
+    s = g_malloc0(sizeof(*s));
+
+    if (bs->device_name[0]) {
+        s->has_device = true;
+        s->device = g_strdup(bs->device_name);
     }
 
+    s->stats = g_malloc0(sizeof(*s->stats));
+    s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ];
+    s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE];
+    s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ];
+    s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE];
+    s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE;
+    s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH];
+    s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE];
+    s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ];
+    s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH];
+
     if (bs->file) {
-        QObject *parent = bdrv_info_stats_bs(bs->file);
-        qdict_put_obj(dict, "parent", parent);
+        s->has_parent = true;
+        s->parent = qmp_query_blockstat(bs->file, NULL);
     }
 
-    return res;
+    return s;
 }
 
-void bdrv_info_stats(Monitor *mon, QObject **ret_data)
+BlockStatsList *qmp_query_blockstats(Error **errp)
 {
-    QObject *obj;
-    QList *devices;
+    BlockStatsList *head = NULL, *cur_item = NULL;
     BlockDriverState *bs;
 
-    devices = qlist_new();
-
     QTAILQ_FOREACH(bs, &bdrv_states, list) {
-        obj = bdrv_info_stats_bs(bs);
-        qlist_append_obj(devices, obj);
+        BlockStatsList *info = g_malloc0(sizeof(*info));
+        info->value = qmp_query_blockstat(bs, NULL);
+
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
+        }
     }
 
-    *ret_data = QOBJECT(devices);
+    return head;
 }
 
 const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
diff --git a/hmp.c b/hmp.c
index 5912250..eab2ddf 100644
--- a/hmp.c
+++ b/hmp.c
@@ -226,6 +226,40 @@ void hmp_info_block(Monitor *mon)
     qapi_free_BlockInfoList(block_list);
 }
 
+void hmp_info_blockstats(Monitor *mon)
+{
+    BlockStatsList *stats_list, *stats;
+
+    stats_list = qmp_query_blockstats(NULL);
+
+    for (stats = stats_list; stats; stats = stats->next) {
+        if (!stats->value->has_device) {
+            continue;
+        }
+
+        monitor_printf(mon, "%s:", stats->value->device);
+        monitor_printf(mon, " rd_bytes=%" PRId64
+                       " wr_bytes=%" PRId64
+                       " rd_operations=%" PRId64
+                       " wr_operations=%" PRId64
+                       " flush_operations=%" PRId64
+                       " wr_total_time_ns=%" PRId64
+                       " rd_total_time_ns=%" PRId64
+                       " flush_total_time_ns=%" PRId64
+                       "\n",
+                       stats->value->stats->rd_bytes,
+                       stats->value->stats->wr_bytes,
+                       stats->value->stats->rd_operations,
+                       stats->value->stats->wr_operations,
+                       stats->value->stats->flush_operations,
+                       stats->value->stats->wr_total_time_ns,
+                       stats->value->stats->rd_total_time_ns,
+                       stats->value->stats->flush_total_time_ns);
+    }
+
+    qapi_free_BlockStatsList(stats_list);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index f5ec417..f8c50d4 100644
--- a/hmp.h
+++ b/hmp.h
@@ -27,6 +27,7 @@ void hmp_info_mice(Monitor *mon);
 void hmp_info_migrate(Monitor *mon);
 void hmp_info_cpus(Monitor *mon);
 void hmp_info_block(Monitor *mon);
+void hmp_info_blockstats(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/monitor.c b/monitor.c
index 3e76f4c..70e5460 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2681,8 +2681,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show block device statistics",
-        .user_print = bdrv_stats_print,
-        .mhandler.info_new = bdrv_info_stats,
+        .mhandler.info = hmp_info_blockstats,
     },
     {
         .name       = "registers",
@@ -2960,14 +2959,6 @@ static const mon_cmd_t qmp_cmds[] = {
 
 static const mon_cmd_t qmp_query_cmds[] = {
     {
-        .name       = "blockstats",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show block device statistics",
-        .user_print = bdrv_stats_print,
-        .mhandler.info_new = bdrv_info_stats,
-    },
-    {
         .name       = "pci",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 5e3570e..45494d8 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -437,6 +437,73 @@
 { 'command': 'query-block', 'returns': ['BlockInfo'] }
 
 ##
+# @BlockDeviceStats:
+#
+# Statistics of a virtual block device or a block backing device.
+#
+# @rd_bytes:      The number of bytes read by the device.
+#
+# @wr_bytes:      The number of bytes written by the device.
+#
+# @rd_operations: The number of read operations performed by the device.
+#
+# @wr_operations: The number of write operations performed by the device.
+#
+# @flush_operations: The number of cache flush operations performed by the
+#                    device (since 0.15.0)
+#
+# @flush_total_time_ns: Total time spend on cache flushes in nano-seconds
+#                       (since 0.15.0).
+#
+# @wr_total_time_ns: Total time spend on writes in nano-seconds (since 0.15.0).
+#
+# @rd_total_time_ns: Total_time_spend on reads in nano-seconds (since 0.15.0).
+#
+# @wr_highest_offset: The offset after the greatest byte written to the
+#                     device.  The intended use of this information is for
+#                     growable sparse files (like qcow2) that are used on top
+#                     of a physical device.
+#
+# Since: 0.14.0
+##
+{ 'type': 'BlockDeviceStats',
+  'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'rd_operations': 'int',
+           'wr_operations': 'int', 'flush_operations': 'int',
+           'flush_total_time_ns': 'int', 'wr_total_time_ns': 'int',
+           'rd_total_time_ns': 'int', 'wr_highest_offset': 'int' } }
+
+##
+# @BlockStats:
+#
+# Statistics of a virtual block device or a block backing device.
+#
+# @device: #optional If the stats are for a virtual block device, the name
+#          corresponding to the virtual block device.
+#
+# @stats:  A @BlockDeviceStats for the device.
+#
+# @parent: #optional This may point to the backing block device if this is a
+#          a virtual block device.  If it's a backing block, this will point
+#          to the backing file is one is present.
+#
+# Since: 0.14.0
+##
+{ 'type': 'BlockStats',
+  'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
+           '*parent': 'BlockStats'} }
+
+##
+# @query-blockstats:
+#
+# Query the @BlockStats for all virtual block devices.
+#
+# Returns: A list of @BlockStats for each virtual block devices.
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-blockstats', 'returns': ['BlockStats'] }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 0cf0be7..a250a7a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1311,6 +1311,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-blockstats",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_blockstats,
+    },
+
 SQMP
 query-cpus
 ----------
commit b202381800d81fbff9978abbdea95760dd363bb6
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Sep 21 17:16:47 2011 -0300

    qapi: Convert query-block
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/block.c b/block.c
index 1a4625f..e648513 100644
--- a/block.c
+++ b/block.c
@@ -29,6 +29,7 @@
 #include "module.h"
 #include "qemu-objects.h"
 #include "qemu-coroutine.h"
+#include "qmp-commands.h"
 
 #ifdef CONFIG_BSD
 #include <sys/types.h>
@@ -1824,106 +1825,53 @@ void bdrv_mon_event(const BlockDriverState *bdrv,
     qobject_decref(data);
 }
 
-static void bdrv_print_dict(QObject *obj, void *opaque)
+BlockInfoList *qmp_query_block(Error **errp)
 {
-    QDict *bs_dict;
-    Monitor *mon = opaque;
-
-    bs_dict = qobject_to_qdict(obj);
-
-    monitor_printf(mon, "%s: removable=%d",
-                        qdict_get_str(bs_dict, "device"),
-                        qdict_get_bool(bs_dict, "removable"));
-
-    if (qdict_get_bool(bs_dict, "removable")) {
-        monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
-        monitor_printf(mon, " tray-open=%d",
-                       qdict_get_bool(bs_dict, "tray-open"));
-    }
-
-    if (qdict_haskey(bs_dict, "io-status")) {
-        monitor_printf(mon, " io-status=%s", qdict_get_str(bs_dict, "io-status"));
-    }
-
-    if (qdict_haskey(bs_dict, "inserted")) {
-        QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
-
-        monitor_printf(mon, " file=");
-        monitor_print_filename(mon, qdict_get_str(qdict, "file"));
-        if (qdict_haskey(qdict, "backing_file")) {
-            monitor_printf(mon, " backing_file=");
-            monitor_print_filename(mon, qdict_get_str(qdict, "backing_file"));
-        }
-        monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
-                            qdict_get_bool(qdict, "ro"),
-                            qdict_get_str(qdict, "drv"),
-                            qdict_get_bool(qdict, "encrypted"));
-    } else {
-        monitor_printf(mon, " [not inserted]");
-    }
-
-    monitor_printf(mon, "\n");
-}
-
-void bdrv_info_print(Monitor *mon, const QObject *data)
-{
-    qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
-}
-
-static const char *const io_status_name[BLOCK_DEVICE_IO_STATUS_MAX] = {
-    [BLOCK_DEVICE_IO_STATUS_OK] = "ok",
-    [BLOCK_DEVICE_IO_STATUS_FAILED] = "failed",
-    [BLOCK_DEVICE_IO_STATUS_NOSPACE] = "nospace",
-};
-
-void bdrv_info(Monitor *mon, QObject **ret_data)
-{
-    QList *bs_list;
+    BlockInfoList *head = NULL, *cur_item = NULL;
     BlockDriverState *bs;
 
-    bs_list = qlist_new();
-
     QTAILQ_FOREACH(bs, &bdrv_states, list) {
-        QObject *bs_obj;
-        QDict *bs_dict;
+        BlockInfoList *info = g_malloc0(sizeof(*info));
 
-        bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
-                                    "'removable': %i, 'locked': %i }",
-                                    bs->device_name,
-                                    bdrv_dev_has_removable_media(bs),
-                                    bdrv_dev_is_medium_locked(bs));
-        bs_dict = qobject_to_qdict(bs_obj);
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->device = g_strdup(bs->device_name);
+        info->value->type = g_strdup("unknown");
+        info->value->locked = bdrv_dev_is_medium_locked(bs);
+        info->value->removable = bdrv_dev_has_removable_media(bs);
 
         if (bdrv_dev_has_removable_media(bs)) {
-            qdict_put(bs_dict, "tray-open",
-                      qbool_from_int(bdrv_dev_is_tray_open(bs)));
+            info->value->has_tray_open = true;
+            info->value->tray_open = bdrv_dev_is_tray_open(bs);
         }
 
         if (bdrv_iostatus_is_enabled(bs)) {
-            qdict_put(bs_dict, "io-status",
-                      qstring_from_str(io_status_name[bs->iostatus]));
+            info->value->has_io_status = true;
+            info->value->io_status = bs->iostatus;
         }
 
         if (bs->drv) {
-            QObject *obj;
-
-            obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
-                                     "'encrypted': %i }",
-                                     bs->filename, bs->read_only,
-                                     bs->drv->format_name,
-                                     bdrv_is_encrypted(bs));
-            if (bs->backing_file[0] != '\0') {
-                QDict *qdict = qobject_to_qdict(obj);
-                qdict_put(qdict, "backing_file",
-                          qstring_from_str(bs->backing_file));
+            info->value->has_inserted = true;
+            info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
+            info->value->inserted->file = g_strdup(bs->filename);
+            info->value->inserted->ro = bs->read_only;
+            info->value->inserted->drv = g_strdup(bs->drv->format_name);
+            info->value->inserted->encrypted = bs->encrypted;
+            if (bs->backing_file[0]) {
+                info->value->inserted->has_backing_file = true;
+                info->value->inserted->backing_file = g_strdup(bs->backing_file);
             }
+        }
 
-            qdict_put_obj(bs_dict, "inserted", obj);
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
         }
-        qlist_append_obj(bs_list, bs_obj);
     }
 
-    *ret_data = QOBJECT(bs_list);
+    return head;
 }
 
 static void bdrv_stats_iter(QObject *data, void *opaque)
diff --git a/block.h b/block.h
index c37b1bf..38cd748 100644
--- a/block.h
+++ b/block.h
@@ -77,11 +77,6 @@ typedef enum {
     BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
 } BlockMonEventAction;
 
-typedef enum {
-    BLOCK_DEVICE_IO_STATUS_OK, BLOCK_DEVICE_IO_STATUS_FAILED,
-    BLOCK_DEVICE_IO_STATUS_NOSPACE, BLOCK_DEVICE_IO_STATUS_MAX
-} BlockIOStatus;
-
 void bdrv_iostatus_enable(BlockDriverState *bs);
 void bdrv_iostatus_reset(BlockDriverState *bs);
 void bdrv_iostatus_disable(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index 3929ec9..f4547f6 100644
--- a/block_int.h
+++ b/block_int.h
@@ -29,6 +29,7 @@
 #include "qemu-queue.h"
 #include "qemu-coroutine.h"
 #include "qemu-timer.h"
+#include "qapi-types.h"
 
 #define BLOCK_FLAG_ENCRYPT	1
 #define BLOCK_FLAG_COMPAT6	4
@@ -203,7 +204,7 @@ struct BlockDriverState {
     int cyls, heads, secs, translation;
     BlockErrorAction on_read_error, on_write_error;
     bool iostatus_enabled;
-    BlockIOStatus iostatus;
+    BlockDeviceIoStatus iostatus;
     char device_name[32];
     unsigned long *dirty_bitmap;
     int64_t dirty_count;
diff --git a/hmp.c b/hmp.c
index 172fe9c..5912250 100644
--- a/hmp.c
+++ b/hmp.c
@@ -184,6 +184,48 @@ void hmp_info_cpus(Monitor *mon)
     qapi_free_CpuInfoList(cpu_list);
 }
 
+void hmp_info_block(Monitor *mon)
+{
+    BlockInfoList *block_list, *info;
+
+    block_list = qmp_query_block(NULL);
+
+    for (info = block_list; info; info = info->next) {
+        monitor_printf(mon, "%s: removable=%d",
+                       info->value->device, info->value->removable);
+
+        if (info->value->removable) {
+            monitor_printf(mon, " locked=%d", info->value->locked);
+            monitor_printf(mon, " tray-open=%d", info->value->tray_open);
+        }
+
+        if (info->value->has_io_status) {
+            monitor_printf(mon, " io-status=%s",
+                           BlockDeviceIoStatus_lookup[info->value->io_status]);
+        }
+
+        if (info->value->has_inserted) {
+            monitor_printf(mon, " file=");
+            monitor_print_filename(mon, info->value->inserted->file);
+
+            if (info->value->inserted->has_backing_file) {
+                monitor_printf(mon, " backing_file=");
+                monitor_print_filename(mon, info->value->inserted->backing_file);
+            }
+            monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
+                           info->value->inserted->ro,
+                           info->value->inserted->drv,
+                           info->value->inserted->encrypted);
+        } else {
+            monitor_printf(mon, " [not inserted]");
+        }
+
+        monitor_printf(mon, "\n");
+    }
+
+    qapi_free_BlockInfoList(block_list);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index d9a83eb..f5ec417 100644
--- a/hmp.h
+++ b/hmp.h
@@ -26,6 +26,7 @@ void hmp_info_chardev(Monitor *mon);
 void hmp_info_mice(Monitor *mon);
 void hmp_info_migrate(Monitor *mon);
 void hmp_info_cpus(Monitor *mon);
+void hmp_info_block(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/monitor.c b/monitor.c
index 2f49c74..3e76f4c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2674,8 +2674,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the block devices",
-        .user_print = bdrv_info_print,
-        .mhandler.info_new = bdrv_info,
+        .mhandler.info = hmp_info_block,
     },
     {
         .name       = "blockstats",
@@ -2961,14 +2960,6 @@ static const mon_cmd_t qmp_cmds[] = {
 
 static const mon_cmd_t qmp_query_cmds[] = {
     {
-        .name       = "block",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the block devices",
-        .user_print = bdrv_info_print,
-        .mhandler.info_new = bdrv_info,
-    },
-    {
         .name       = "blockstats",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index a1bf90d..5e3570e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -352,6 +352,91 @@
 { 'command': 'query-cpus', 'returns': ['CpuInfo'] }
 
 ##
+# @BlockDeviceInfo:
+#
+# Information about the backing device for a block device.
+#
+# @file: the filename of the backing device
+#
+# @ro: true if the backing device was open read-only
+#
+# @drv: the name of the block format used to open the backing device. As of
+#       0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg',
+#       'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
+#       'host_floppy', 'http', 'https', 'nbd', 'parallels', 'qcow',
+#       'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
+#
+# @backing_file: #optional the name of the backing file (for copy-on-write)
+#
+# @encrypted: true if the backing device is encrypted
+#
+# Since: 0.14.0
+#
+# Notes: This interface is only found in @BlockInfo.
+##
+{ 'type': 'BlockDeviceInfo',
+  'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
+            '*backing_file': 'str', 'encrypted': 'bool' } }
+
+##
+# @BlockDeviceIoStatus:
+#
+# An enumeration of block device I/O status.
+#
+# @ok: The last I/O operation has succeeded
+#
+# @failed: The last I/O operation has failed
+#
+# @nospace: The last I/O operation has failed due to a no-space condition
+#
+# Since: 1.0
+##
+{ 'enum': 'BlockDeviceIoStatus', 'data': [ 'ok', 'failed', 'nospace' ] }
+
+##
+# @BlockInfo:
+#
+# Block device information.  This structure describes a virtual device and
+# the backing device associated with it.
+#
+# @device: The device name associated with the virtual device.
+#
+# @type: This field is returned only for compatibility reasons, it should
+#        not be used (always returns 'unknown')
+#
+# @removable: True if the device supports removable media.
+#
+# @locked: True if the guest has locked this device from having its media
+#          removed
+#
+# @tray_open: #optional True if the device has a tray and it is open
+#             (only present if removable is true)
+#
+# @io-status: #optional @BlockDeviceIoStatus. Only present if the device
+#             supports it and the VM is configured to stop on errors
+#
+# @inserted: #optional @BlockDeviceInfo describing the device if media is
+#            present
+#
+# Since:  0.14.0
+##
+{ 'type': 'BlockInfo',
+  'data': {'device': 'str', 'type': 'str', 'removable': 'bool',
+           'locked': 'bool', '*inserted': 'BlockDeviceInfo',
+           '*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus'} }
+
+##
+# @query-block:
+#
+# Get a list of BlockInfo for all virtual block devices.
+#
+# Returns: a list of @BlockInfo describing each virtual block device
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-block', 'returns': ['BlockInfo'] }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 434ce6c..0cf0be7 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1198,6 +1198,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-block",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_block,
+    },
+
 SQMP
 query-blockstats
 ----------------
commit 58e21ef5ab262fb91256435c31cc7bfeead59754
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Oct 14 17:22:24 2011 -0300

    block: Rename the BlockIOStatus enum values
    
    The biggest change is to rename its prefix from BDRV_IOS to
    BLOCK_DEVICE_IO_STATUS.
    
    Next commit will convert the query-block command to the QAPI
    and that's how the enumeration is going to be generated.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/block.c b/block.c
index 4dc2b85..1a4625f 100644
--- a/block.c
+++ b/block.c
@@ -1870,10 +1870,10 @@ void bdrv_info_print(Monitor *mon, const QObject *data)
     qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
 }
 
-static const char *const io_status_name[BDRV_IOS_MAX] = {
-    [BDRV_IOS_OK] = "ok",
-    [BDRV_IOS_FAILED] = "failed",
-    [BDRV_IOS_ENOSPC] = "nospace",
+static const char *const io_status_name[BLOCK_DEVICE_IO_STATUS_MAX] = {
+    [BLOCK_DEVICE_IO_STATUS_OK] = "ok",
+    [BLOCK_DEVICE_IO_STATUS_FAILED] = "failed",
+    [BLOCK_DEVICE_IO_STATUS_NOSPACE] = "nospace",
 };
 
 void bdrv_info(Monitor *mon, QObject **ret_data)
@@ -3140,7 +3140,7 @@ int bdrv_in_use(BlockDriverState *bs)
 void bdrv_iostatus_enable(BlockDriverState *bs)
 {
     bs->iostatus_enabled = true;
-    bs->iostatus = BDRV_IOS_OK;
+    bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
 }
 
 /* The I/O status is only enabled if the drive explicitly
@@ -3161,7 +3161,7 @@ void bdrv_iostatus_disable(BlockDriverState *bs)
 void bdrv_iostatus_reset(BlockDriverState *bs)
 {
     if (bdrv_iostatus_is_enabled(bs)) {
-        bs->iostatus = BDRV_IOS_OK;
+        bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
     }
 }
 
@@ -3170,9 +3170,11 @@ void bdrv_iostatus_reset(BlockDriverState *bs)
    possible to implement this without device models being involved */
 void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
 {
-    if (bdrv_iostatus_is_enabled(bs) && bs->iostatus == BDRV_IOS_OK) {
+    if (bdrv_iostatus_is_enabled(bs) &&
+        bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
         assert(error >= 0);
-        bs->iostatus = error == ENOSPC ? BDRV_IOS_ENOSPC : BDRV_IOS_FAILED;
+        bs->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
+                                         BLOCK_DEVICE_IO_STATUS_FAILED;
     }
 }
 
diff --git a/block.h b/block.h
index 1823e93..c37b1bf 100644
--- a/block.h
+++ b/block.h
@@ -78,7 +78,8 @@ typedef enum {
 } BlockMonEventAction;
 
 typedef enum {
-    BDRV_IOS_OK, BDRV_IOS_FAILED, BDRV_IOS_ENOSPC, BDRV_IOS_MAX
+    BLOCK_DEVICE_IO_STATUS_OK, BLOCK_DEVICE_IO_STATUS_FAILED,
+    BLOCK_DEVICE_IO_STATUS_NOSPACE, BLOCK_DEVICE_IO_STATUS_MAX
 } BlockIOStatus;
 
 void bdrv_iostatus_enable(BlockDriverState *bs);
commit d6bf279e7a949ad49a48a215f9ec28cb6ceb28aa
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Oct 14 17:11:23 2011 -0300

    block: iostatus: Drop BDRV_IOS_INVAL
    
    A future commit will convert bdrv_info() to the QAPI and it won't
    provide IOS_INVAL.
    
    Luckily all we have to do is to add a new 'iostatus_enabled'
    member to BlockDriverState and use it instead.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/block.c b/block.c
index 70aab63..4dc2b85 100644
--- a/block.c
+++ b/block.c
@@ -3139,6 +3139,7 @@ int bdrv_in_use(BlockDriverState *bs)
 
 void bdrv_iostatus_enable(BlockDriverState *bs)
 {
+    bs->iostatus_enabled = true;
     bs->iostatus = BDRV_IOS_OK;
 }
 
@@ -3146,7 +3147,7 @@ void bdrv_iostatus_enable(BlockDriverState *bs)
  * enables it _and_ the VM is configured to stop on errors */
 bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
 {
-    return (bs->iostatus != BDRV_IOS_INVAL &&
+    return (bs->iostatus_enabled &&
            (bs->on_write_error == BLOCK_ERR_STOP_ENOSPC ||
             bs->on_write_error == BLOCK_ERR_STOP_ANY    ||
             bs->on_read_error == BLOCK_ERR_STOP_ANY));
@@ -3154,7 +3155,7 @@ bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
 
 void bdrv_iostatus_disable(BlockDriverState *bs)
 {
-    bs->iostatus = BDRV_IOS_INVAL;
+    bs->iostatus_enabled = false;
 }
 
 void bdrv_iostatus_reset(BlockDriverState *bs)
diff --git a/block.h b/block.h
index 5a042c9..1823e93 100644
--- a/block.h
+++ b/block.h
@@ -78,8 +78,7 @@ typedef enum {
 } BlockMonEventAction;
 
 typedef enum {
-    BDRV_IOS_INVAL, BDRV_IOS_OK, BDRV_IOS_FAILED, BDRV_IOS_ENOSPC,
-    BDRV_IOS_MAX
+    BDRV_IOS_OK, BDRV_IOS_FAILED, BDRV_IOS_ENOSPC, BDRV_IOS_MAX
 } BlockIOStatus;
 
 void bdrv_iostatus_enable(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index dac00f5..3929ec9 100644
--- a/block_int.h
+++ b/block_int.h
@@ -202,6 +202,7 @@ struct BlockDriverState {
        drivers. They are not used by the block driver */
     int cyls, heads, secs, translation;
     BlockErrorAction on_read_error, on_write_error;
+    bool iostatus_enabled;
     BlockIOStatus iostatus;
     char device_name[32];
     unsigned long *dirty_bitmap;
commit de0b36b67ea3e1ab3aa1b6625c4fd5cb29fa0ada
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Sep 21 16:38:35 2011 -0300

    qapi: Convert query-cpus
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/cpus.c b/cpus.c
index 79a7656..f768683 100644
--- a/cpus.c
+++ b/cpus.c
@@ -30,6 +30,7 @@
 #include "gdbstub.h"
 #include "dma.h"
 #include "kvm.h"
+#include "qmp-commands.h"
 
 #include "qemu-thread.h"
 #include "cpus.h"
@@ -1094,3 +1095,47 @@ void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
     cpu_list(f, cpu_fprintf); /* deprecated */
 #endif
 }
+
+CpuInfoList *qmp_query_cpus(Error **errp)
+{
+    CpuInfoList *head = NULL, *cur_item = NULL;
+    CPUState *env;
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        CpuInfoList *info;
+
+        cpu_synchronize_state(env);
+
+        info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->CPU = env->cpu_index;
+        info->value->current = (env == first_cpu);
+        info->value->halted = env->halted;
+        info->value->thread_id = env->thread_id;
+#if defined(TARGET_I386)
+        info->value->has_pc = true;
+        info->value->pc = env->eip + env->segs[R_CS].base;
+#elif defined(TARGET_PPC)
+        info->value->has_nip = true;
+        info->value->nip = env->nip;
+#elif defined(TARGET_SPARC)
+        info->value->has_pc = true;
+        info->value->pc = env->pc;
+        info->value->has_npc = true;
+        info->value->npc = env->npc;
+#elif defined(TARGET_MIPS)
+        info->value->has_PC = true;
+        info->value->PC = env->active_tc.PC;
+#endif
+
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = info;
+        } else {
+            cur_item->next = info;
+            cur_item = info;
+        }
+    }
+
+    return head;
+}
diff --git a/hmp.c b/hmp.c
index 35b0ca0..172fe9c 100644
--- a/hmp.c
+++ b/hmp.c
@@ -145,6 +145,45 @@ void hmp_info_migrate(Monitor *mon)
     qapi_free_MigrationInfo(info);
 }
 
+void hmp_info_cpus(Monitor *mon)
+{
+    CpuInfoList *cpu_list, *cpu;
+
+    cpu_list = qmp_query_cpus(NULL);
+
+    for (cpu = cpu_list; cpu; cpu = cpu->next) {
+        int active = ' ';
+
+        if (cpu->value->CPU == monitor_get_cpu_index()) {
+            active = '*';
+        }
+
+        monitor_printf(mon, "%c CPU #%" PRId64 ": ", active, cpu->value->CPU);
+
+        if (cpu->value->has_pc) {
+            monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc);
+        }
+        if (cpu->value->has_nip) {
+            monitor_printf(mon, "nip=0x%016" PRIx64, cpu->value->nip);
+        }
+        if (cpu->value->has_npc) {
+            monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc);
+            monitor_printf(mon, "npc=0x%016" PRIx64, cpu->value->npc);
+        }
+        if (cpu->value->has_PC) {
+            monitor_printf(mon, "PC=0x%016" PRIx64, cpu->value->PC);
+        }
+
+        if (cpu->value->halted) {
+            monitor_printf(mon, " (halted)");
+        }
+
+        monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
+    }
+
+    qapi_free_CpuInfoList(cpu_list);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index 9322b7f..d9a83eb 100644
--- a/hmp.h
+++ b/hmp.h
@@ -25,6 +25,7 @@ void hmp_info_uuid(Monitor *mon);
 void hmp_info_chardev(Monitor *mon);
 void hmp_info_mice(Monitor *mon);
 void hmp_info_migrate(Monitor *mon);
+void hmp_info_cpus(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/monitor.c b/monitor.c
index 1edb646..2f49c74 100644
--- a/monitor.c
+++ b/monitor.c
@@ -812,96 +812,6 @@ static void do_info_registers(Monitor *mon)
 #endif
 }
 
-static void print_cpu_iter(QObject *obj, void *opaque)
-{
-    QDict *cpu;
-    int active = ' ';
-    Monitor *mon = opaque;
-
-    assert(qobject_type(obj) == QTYPE_QDICT);
-    cpu = qobject_to_qdict(obj);
-
-    if (qdict_get_bool(cpu, "current")) {
-        active = '*';
-    }
-
-    monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU"));
-
-#if defined(TARGET_I386)
-    monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
-                   (target_ulong) qdict_get_int(cpu, "pc"));
-#elif defined(TARGET_PPC)
-    monitor_printf(mon, "nip=0x" TARGET_FMT_lx,
-                   (target_long) qdict_get_int(cpu, "nip"));
-#elif defined(TARGET_SPARC)
-    monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
-                   (target_long) qdict_get_int(cpu, "pc"));
-    monitor_printf(mon, "npc=0x" TARGET_FMT_lx,
-                   (target_long) qdict_get_int(cpu, "npc"));
-#elif defined(TARGET_MIPS)
-    monitor_printf(mon, "PC=0x" TARGET_FMT_lx,
-                   (target_long) qdict_get_int(cpu, "PC"));
-#endif
-
-    if (qdict_get_bool(cpu, "halted")) {
-        monitor_printf(mon, " (halted)");
-    }
-
-    monitor_printf(mon, " thread_id=%" PRId64 " ",
-                   qdict_get_int(cpu, "thread_id"));
-
-    monitor_printf(mon, "\n");
-}
-
-static void monitor_print_cpus(Monitor *mon, const QObject *data)
-{
-    QList *cpu_list;
-
-    assert(qobject_type(data) == QTYPE_QLIST);
-    cpu_list = qobject_to_qlist(data);
-    qlist_iter(cpu_list, print_cpu_iter, mon);
-}
-
-static void do_info_cpus(Monitor *mon, QObject **ret_data)
-{
-    CPUState *env;
-    QList *cpu_list;
-
-    cpu_list = qlist_new();
-
-    /* just to set the default cpu if not already done */
-    mon_get_cpu();
-
-    for(env = first_cpu; env != NULL; env = env->next_cpu) {
-        QDict *cpu;
-        QObject *obj;
-
-        cpu_synchronize_state(env);
-
-        obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }",
-                                 env->cpu_index, env == mon->mon_cpu,
-                                 env->halted);
-
-        cpu = qobject_to_qdict(obj);
-
-#if defined(TARGET_I386)
-        qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base));
-#elif defined(TARGET_PPC)
-        qdict_put(cpu, "nip", qint_from_int(env->nip));
-#elif defined(TARGET_SPARC)
-        qdict_put(cpu, "pc", qint_from_int(env->pc));
-        qdict_put(cpu, "npc", qint_from_int(env->npc));
-#elif defined(TARGET_MIPS)
-        qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
-#endif
-        qdict_put(cpu, "thread_id", qint_from_int(env->thread_id));
-
-        qlist_append(cpu_list, cpu);
-    }
-
-    *ret_data = QOBJECT(cpu_list);
-}
-
 static void do_info_jit(Monitor *mon)
 {
     dump_exec_info((FILE *)mon, monitor_fprintf);
@@ -2787,8 +2697,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show infos for each CPU",
-        .user_print = monitor_print_cpus,
-        .mhandler.info_new = do_info_cpus,
+        .mhandler.info = hmp_info_cpus,
     },
     {
         .name       = "history",
@@ -3068,14 +2977,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .mhandler.info_new = bdrv_info_stats,
     },
     {
-        .name       = "cpus",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show infos for each CPU",
-        .user_print = monitor_print_cpus,
-        .mhandler.info_new = do_info_cpus,
-    },
-    {
         .name       = "pci",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index e4cf6da..a1bf90d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -306,6 +306,52 @@
 { 'command': 'query-mice', 'returns': ['MouseInfo'] }
 
 ##
+# @CpuInfo:
+#
+# Information about a virtual CPU
+#
+# @CPU: the index of the virtual CPU
+#
+# @current: this only exists for backwards compatible and should be ignored
+# 
+# @halted: true if the virtual CPU is in the halt state.  Halt usually refers
+#          to a processor specific low power mode.
+#
+# @pc: #optional If the target is i386 or x86_64, this is the 64-bit instruction
+#                pointer.
+#                If the target is Sparc, this is the PC component of the
+#                instruction pointer.
+#
+# @nip: #optional If the target is PPC, the instruction pointer
+#
+# @npc: #optional If the target is Sparc, the NPC component of the instruction
+#                 pointer
+#
+# @PC: #optional If the target is MIPS, the instruction pointer
+#
+# @thread_id: ID of the underlying host thread
+#
+# Since: 0.14.0
+#
+# Notes: @halted is a transient state that changes frequently.  By the time the
+#        data is sent to the client, the guest may no longer be halted.
+##
+{ 'type': 'CpuInfo',
+  'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', '*pc': 'int',
+           '*nip': 'int', '*npc': 'int', '*PC': 'int', 'thread_id': 'int'} }
+
+##
+# @query-cpus:
+#
+# Returns a list of information about each virtual CPU.
+#
+# Returns: a list of @CpuInfo for each virtual CPU
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-cpus', 'returns': ['CpuInfo'] }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index dcca53c..434ce6c 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1347,6 +1347,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-cpus",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_cpus,
+    },
+
 SQMP
 query-pci
 ---------
commit 755f196898e75bf453957609d1dbe02f73e5b12a
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Oct 6 14:31:39 2011 -0300

    qapi: Convert the cpu command
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index ab08d58..969ccf5 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -587,8 +587,7 @@ ETEXI
         .args_type  = "index:i",
         .params     = "index",
         .help       = "set the default CPU",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_cpu_set,
+        .mhandler.cmd = hmp_cpu,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 619b8ba..35b0ca0 100644
--- a/hmp.c
+++ b/hmp.c
@@ -165,3 +165,15 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
 {
     qmp_system_powerdown(NULL);
 }
+
+void hmp_cpu(Monitor *mon, const QDict *qdict)
+{
+    int64_t cpu_index;
+
+    /* XXX: drop the monitor_set_cpu() usage when all HMP commands that
+            use it are converted to the QAPI */
+    cpu_index = qdict_get_int(qdict, "index");
+    if (monitor_set_cpu(cpu_index) < 0) {
+        monitor_printf(mon, "invalid CPU index\n");
+    }
+}
diff --git a/hmp.h b/hmp.h
index 49d9662..9322b7f 100644
--- a/hmp.h
+++ b/hmp.h
@@ -29,5 +29,6 @@ void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
 void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
+void hmp_cpu(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 3e1cd33..1edb646 100644
--- a/monitor.c
+++ b/monitor.c
@@ -902,17 +902,6 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data)
     *ret_data = QOBJECT(cpu_list);
 }
 
-static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    int index = qdict_get_int(qdict, "index");
-    if (monitor_set_cpu(index) < 0) {
-        qerror_report(QERR_INVALID_PARAMETER_VALUE, "index",
-                      "a CPU number");
-        return -1;
-    }
-    return 0;
-}
-
 static void do_info_jit(Monitor *mon)
 {
     dump_exec_info((FILE *)mon, monitor_fprintf);
diff --git a/qapi-schema.json b/qapi-schema.json
index eb155b4..e4cf6da 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -351,3 +351,14 @@
 #        prompting the user in some way.
 ##
 { 'command': 'system_powerdown' }
+
+##
+# @cpu:
+#
+# This command is a nop that is only provided for the purposes of compatibility.
+#
+# Since: 0.14.0
+#
+# Notes: Do not use this command.
+##
+{ 'command': 'cpu', 'data': {'index': 'int'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 8efdb25..dcca53c 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -331,10 +331,7 @@ EQMP
     {
         .name       = "cpu",
         .args_type  = "index:i",
-        .params     = "index",
-        .help       = "set the default CPU",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_cpu_set,
+        .mhandler.cmd_new = qmp_marshal_input_cpu,
     },
 
 SQMP
diff --git a/qmp.c b/qmp.c
index bf58b05..e84922b 100644
--- a/qmp.c
+++ b/qmp.c
@@ -90,3 +90,8 @@ void qmp_system_powerdown(Error **erp)
 {
     qemu_system_powerdown_request();
 }
+
+void qmp_cpu(int64_t index, Error **errp)
+{
+    /* Just do nothing */
+}
commit 99b7796f601cd275b16b3e7122874953ed1a0b1f
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Oct 24 10:53:44 2011 -0200

    Monitor: Introduce monitor_get_cpu_index()
    
    Returns 'cur_mons's CPU index. A future commit will use it.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index 3f99ea0..3e1cd33 100644
--- a/monitor.c
+++ b/monitor.c
@@ -794,6 +794,11 @@ static CPUState *mon_get_cpu(void)
     return cur_mon->mon_cpu;
 }
 
+int monitor_get_cpu_index(void)
+{
+    return mon_get_cpu()->cpu_index;
+}
+
 static void do_info_registers(Monitor *mon)
 {
     CPUState *env;
diff --git a/monitor.h b/monitor.h
index 9b723b2..e76795f 100644
--- a/monitor.h
+++ b/monitor.h
@@ -58,6 +58,7 @@ void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 void monitor_print_filename(Monitor *mon, const char *filename);
 void monitor_flush(Monitor *mon);
 int monitor_set_cpu(int cpu_index);
+int monitor_get_cpu_index(void);
 
 typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
 
commit b025c8b4ab108a5a4bb4ef1e2500fc63214e2193
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Oct 6 14:02:57 2011 -0300

    Monitor: Make mon_set_cpu() public
    
    Also rename it to monitor_set_cpu().
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index ea5ccd8..3f99ea0 100644
--- a/monitor.c
+++ b/monitor.c
@@ -514,7 +514,6 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params,
     return 0;
 }
 
-static int mon_set_cpu(int cpu_index);
 static void handle_user_command(Monitor *mon, const char *cmdline);
 
 static int do_hmp_passthrough(Monitor *mon, const QDict *params,
@@ -532,7 +531,7 @@ static int do_hmp_passthrough(Monitor *mon, const QDict *params,
     cur_mon = &hmp;
 
     if (qdict_haskey(params, "cpu-index")) {
-        ret = mon_set_cpu(qdict_get_int(params, "cpu-index"));
+        ret = monitor_set_cpu(qdict_get_int(params, "cpu-index"));
         if (ret < 0) {
             cur_mon = old_mon;
             qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
@@ -772,8 +771,8 @@ CommandInfoList *qmp_query_commands(Error **errp)
     return cmd_list;
 }
 
-/* get the current CPU defined by the user */
-static int mon_set_cpu(int cpu_index)
+/* set the current CPU defined by the user */
+int monitor_set_cpu(int cpu_index)
 {
     CPUState *env;
 
@@ -789,7 +788,7 @@ static int mon_set_cpu(int cpu_index)
 static CPUState *mon_get_cpu(void)
 {
     if (!cur_mon->mon_cpu) {
-        mon_set_cpu(0);
+        monitor_set_cpu(0);
     }
     cpu_synchronize_state(cur_mon->mon_cpu);
     return cur_mon->mon_cpu;
@@ -901,7 +900,7 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data)
 static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     int index = qdict_get_int(qdict, "index");
-    if (mon_set_cpu(index) < 0) {
+    if (monitor_set_cpu(index) < 0) {
         qerror_report(QERR_INVALID_PARAMETER_VALUE, "index",
                       "a CPU number");
         return -1;
diff --git a/monitor.h b/monitor.h
index 4f2d328..9b723b2 100644
--- a/monitor.h
+++ b/monitor.h
@@ -57,6 +57,7 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 void monitor_print_filename(Monitor *mon, const char *filename);
 void monitor_flush(Monitor *mon);
+int monitor_set_cpu(int cpu_index);
 
 typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
 
commit 791e7c820e969a69aa2568fb528dbe9f7e923f5a
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Tue Sep 13 17:37:16 2011 -0300

    qapi: Convert query-migrate
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index 9c6d896..619b8ba 100644
--- a/hmp.c
+++ b/hmp.c
@@ -114,6 +114,37 @@ void hmp_info_mice(Monitor *mon)
     qapi_free_MouseInfoList(mice_list);
 }
 
+void hmp_info_migrate(Monitor *mon)
+{
+    MigrationInfo *info;
+
+    info = qmp_query_migrate(NULL);
+
+    if (info->has_status) {
+        monitor_printf(mon, "Migration status: %s\n", info->status);
+    }
+
+    if (info->has_ram) {
+        monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n",
+                       info->ram->transferred >> 10);
+        monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n",
+                       info->ram->remaining >> 10);
+        monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n",
+                       info->ram->total >> 10);
+    }
+
+    if (info->has_disk) {
+        monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n",
+                       info->disk->transferred >> 10);
+        monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n",
+                       info->disk->remaining >> 10);
+        monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n",
+                       info->disk->total >> 10);
+    }
+
+    qapi_free_MigrationInfo(info);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index 4e6697d..49d9662 100644
--- a/hmp.h
+++ b/hmp.h
@@ -24,6 +24,7 @@ void hmp_info_status(Monitor *mon);
 void hmp_info_uuid(Monitor *mon);
 void hmp_info_chardev(Monitor *mon);
 void hmp_info_mice(Monitor *mon);
+void hmp_info_migrate(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/migration.c b/migration.c
index bdca72e..6c70f72 100644
--- a/migration.c
+++ b/migration.c
@@ -19,7 +19,7 @@
 #include "block.h"
 #include "qemu_socket.h"
 #include "block-migration.h"
-#include "qemu-objects.h"
+#include "qmp-commands.h"
 
 //#define DEBUG_MIGRATION
 
@@ -107,53 +107,9 @@ uint64_t migrate_max_downtime(void)
     return max_downtime;
 }
 
-static void migrate_print_status(Monitor *mon, const char *name,
-                                 const QDict *status_dict)
+MigrationInfo *qmp_query_migrate(Error **errp)
 {
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(qdict_get(status_dict, name));
-
-    monitor_printf(mon, "transferred %s: %" PRIu64 " kbytes\n", name,
-                        qdict_get_int(qdict, "transferred") >> 10);
-    monitor_printf(mon, "remaining %s: %" PRIu64 " kbytes\n", name,
-                        qdict_get_int(qdict, "remaining") >> 10);
-    monitor_printf(mon, "total %s: %" PRIu64 " kbytes\n", name,
-                        qdict_get_int(qdict, "total") >> 10);
-}
-
-void do_info_migrate_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-
-    monitor_printf(mon, "Migration status: %s\n",
-                   qdict_get_str(qdict, "status"));
-
-    if (qdict_haskey(qdict, "ram")) {
-        migrate_print_status(mon, "ram", qdict);
-    }
-
-    if (qdict_haskey(qdict, "disk")) {
-        migrate_print_status(mon, "disk", qdict);
-    }
-}
-
-static void migrate_put_status(QDict *qdict, const char *name,
-                               uint64_t trans, uint64_t rem, uint64_t total)
-{
-    QObject *obj;
-
-    obj = qobject_from_jsonf("{ 'transferred': %" PRId64 ", "
-                               "'remaining': %" PRId64 ", "
-                               "'total': %" PRId64 " }", trans, rem, total);
-    qdict_put_obj(qdict, name, obj);
-}
-
-void do_info_migrate(Monitor *mon, QObject **ret_data)
-{
-    QDict *qdict;
+    MigrationInfo *info = g_malloc0(sizeof(*info));
     MigrationState *s = migrate_get_current();
 
     switch (s->state) {
@@ -161,30 +117,38 @@ void do_info_migrate(Monitor *mon, QObject **ret_data)
         /* no migration has happened ever */
         break;
     case MIG_STATE_ACTIVE:
-        qdict = qdict_new();
-        qdict_put(qdict, "status", qstring_from_str("active"));
+        info->has_status = true;
+        info->status = g_strdup("active");
 
-        migrate_put_status(qdict, "ram", ram_bytes_transferred(),
-                           ram_bytes_remaining(), ram_bytes_total());
+        info->has_ram = true;
+        info->ram = g_malloc0(sizeof(*info->ram));
+        info->ram->transferred = ram_bytes_transferred();
+        info->ram->remaining = ram_bytes_remaining();
+        info->ram->total = ram_bytes_total();
 
         if (blk_mig_active()) {
-            migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
-                               blk_mig_bytes_remaining(),
-                               blk_mig_bytes_total());
+            info->has_disk = true;
+            info->disk = g_malloc0(sizeof(*info->disk));
+            info->disk->transferred = blk_mig_bytes_transferred();
+            info->disk->remaining = blk_mig_bytes_remaining();
+            info->disk->total = blk_mig_bytes_total();
         }
-
-        *ret_data = QOBJECT(qdict);
         break;
     case MIG_STATE_COMPLETED:
-        *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
+        info->has_status = true;
+        info->status = g_strdup("completed");
         break;
     case MIG_STATE_ERROR:
-        *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
+        info->has_status = true;
+        info->status = g_strdup("failed");
         break;
     case MIG_STATE_CANCELLED:
-        *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
+        info->has_status = true;
+        info->status = g_strdup("cancelled");
         break;
     }
+
+    return info;
 }
 
 /* shared migration helpers */
diff --git a/monitor.c b/monitor.c
index d95abce..ea5ccd8 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2999,8 +2999,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show migration status",
-        .user_print = do_info_migrate_print,
-        .mhandler.info_new = do_info_migrate,
+        .mhandler.info = hmp_info_migrate,
     },
     {
         .name       = "balloon",
@@ -3110,14 +3109,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
     },
 #endif
     {
-        .name       = "migrate",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show migration status",
-        .user_print = do_info_migrate_print,
-        .mhandler.info_new = do_info_migrate,
-    },
-    {
         .name       = "balloon",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 3175c82..eb155b4 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -226,6 +226,56 @@
 { 'command': 'query-commands', 'returns': ['CommandInfo'] }
 
 ##
+# @MigrationStats
+#
+# Detailed migration status.
+#
+# @transferred: amount of bytes already transferred to the target VM
+#
+# @remaining: amount of bytes remaining to be transferred to the target VM
+#
+# @total: total amount of bytes involved in the migration process
+#
+# Since: 0.14.0.
+##
+{ 'type': 'MigrationStats',
+  'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' } }
+
+##
+# @MigrationInfo
+#
+# Information about current migration process.
+#
+# @status: #optional string describing the current migration status.
+#          As of 0.14.0 this can be 'active', 'completed', 'failed' or
+#          'cancelled'. If this field is not returned, no migration process
+#          has been initiated
+#
+# @ram: #optional @MigrationStats containing detailed migration status,
+#       only returned if status is 'active'
+#
+# @disk: #optional @MigrationStats containing detailed disk migration
+#        status, only returned if status is 'active' and it is a block
+#        migration
+#
+# Since: 0.14.0
+##
+{ 'type': 'MigrationInfo',
+  'data': {'*status': 'str', '*ram': 'MigrationStats',
+           '*disk': 'MigrationStats'} }
+
+##
+# @query-migrate
+#
+# Returns information about current migration process.
+#
+# Returns: @MigrationInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-migrate', 'returns': 'MigrationInfo' }
+
+##
 # @MouseInfo:
 #
 # Information about a mouse device.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index c535560..8efdb25 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1919,6 +1919,12 @@ Examples:
 
 EQMP
 
+    {
+        .name       = "query-migrate",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_migrate,
+    },
+
 SQMP
 query-balloon
 -------------
commit e235cec3762d2aa20b548114ea7b172113690463
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Sep 21 15:29:55 2011 -0300

    qapi: Convert query-mice
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index 34416fc..9c6d896 100644
--- a/hmp.c
+++ b/hmp.c
@@ -94,6 +94,26 @@ void hmp_info_chardev(Monitor *mon)
     qapi_free_ChardevInfoList(char_info);
 }
 
+void hmp_info_mice(Monitor *mon)
+{
+    MouseInfoList *mice_list, *mouse;
+
+    mice_list = qmp_query_mice(NULL);
+    if (!mice_list) {
+        monitor_printf(mon, "No mouse devices connected\n");
+        return;
+    }
+
+    for (mouse = mice_list; mouse; mouse = mouse->next) {
+        monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
+                       mouse->value->current ? '*' : ' ',
+                       mouse->value->index, mouse->value->name,
+                       mouse->value->absolute ? " (absolute)" : "");
+    }
+
+    qapi_free_MouseInfoList(mice_list);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index 92433cf..4e6697d 100644
--- a/hmp.h
+++ b/hmp.h
@@ -23,6 +23,7 @@ void hmp_info_kvm(Monitor *mon);
 void hmp_info_status(Monitor *mon);
 void hmp_info_uuid(Monitor *mon);
 void hmp_info_chardev(Monitor *mon);
+void hmp_info_mice(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/input.c b/input.c
index e2f7c92..9ade63f 100644
--- a/input.c
+++ b/input.c
@@ -26,7 +26,8 @@
 #include "net.h"
 #include "monitor.h"
 #include "console.h"
-#include "qjson.h"
+#include "error.h"
+#include "qmp-commands.h"
 
 static QEMUPutKBDEvent *qemu_put_kbd_event;
 static void *qemu_put_kbd_event_opaque;
@@ -211,60 +212,27 @@ int kbd_mouse_has_absolute(void)
     return 0;
 }
 
-static void info_mice_iter(QObject *data, void *opaque)
-{
-    QDict *mouse;
-    Monitor *mon = opaque;
-
-    mouse = qobject_to_qdict(data);
-    monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
-                  (qdict_get_bool(mouse, "current") ? '*' : ' '),
-                   qdict_get_int(mouse, "index"), qdict_get_str(mouse, "name"),
-                   qdict_get_bool(mouse, "absolute") ? " (absolute)" : "");
-}
-
-void do_info_mice_print(Monitor *mon, const QObject *data)
-{
-    QList *mice_list;
-
-    mice_list = qobject_to_qlist(data);
-    if (qlist_empty(mice_list)) {
-        monitor_printf(mon, "No mouse devices connected\n");
-        return;
-    }
-
-    qlist_iter(mice_list, info_mice_iter, mon);
-}
-
-void do_info_mice(Monitor *mon, QObject **ret_data)
+MouseInfoList *qmp_query_mice(Error **errp)
 {
+    MouseInfoList *mice_list = NULL;
     QEMUPutMouseEntry *cursor;
-    QList *mice_list;
-    int current;
-
-    mice_list = qlist_new();
+    bool current = true;
 
-    if (QTAILQ_EMPTY(&mouse_handlers)) {
-        goto out;
-    }
+    QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
+        MouseInfoList *info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->name = g_strdup(cursor->qemu_put_mouse_event_name);
+        info->value->index = cursor->index;
+        info->value->absolute = !!cursor->qemu_put_mouse_event_absolute;
+        info->value->current = current;
 
-    current = QTAILQ_FIRST(&mouse_handlers)->index;
+        current = false;
 
-    QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
-        QObject *obj;
-        obj = qobject_from_jsonf("{ 'name': %s,"
-                                 "  'index': %d,"
-                                 "  'current': %i,"
-                                 "  'absolute': %i }",
-                                 cursor->qemu_put_mouse_event_name,
-                                 cursor->index,
-                                 cursor->index == current,
-                                 !!cursor->qemu_put_mouse_event_absolute);
-        qlist_append_obj(mice_list, obj);
+        info->next = mice_list;
+        mice_list = info;
     }
 
-out:
-    *ret_data = QOBJECT(mice_list);
+    return mice_list;
 }
 
 void do_mouse_set(Monitor *mon, const QDict *qdict)
diff --git a/monitor.c b/monitor.c
index ffda0fe..d95abce 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2942,8 +2942,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show which guest mouse is receiving events",
-        .user_print = do_info_mice_print,
-        .mhandler.info_new = do_info_mice,
+        .mhandler.info = hmp_info_mice,
     },
     {
         .name       = "vnc",
@@ -3093,14 +3092,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .mhandler.info_new = do_pci_info,
     },
     {
-        .name       = "mice",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show which guest mouse is receiving events",
-        .user_print = do_info_mice_print,
-        .mhandler.info_new = do_info_mice,
-    },
-    {
         .name       = "vnc",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 5922c4a..3175c82 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -226,6 +226,36 @@
 { 'command': 'query-commands', 'returns': ['CommandInfo'] }
 
 ##
+# @MouseInfo:
+#
+# Information about a mouse device.
+#
+# @name: the name of the mouse device
+#
+# @index: the index of the mouse device
+#
+# @current: true if this device is currently receiving mouse events
+#
+# @absolute: true if this device supports absolute coordinates as input
+#
+# Since: 0.14.0
+##
+{ 'type': 'MouseInfo',
+  'data': {'name': 'str', 'index': 'int', 'current': 'bool',
+           'absolute': 'bool'} }
+
+##
+# @query-mice:
+#
+# Returns information about each active mouse device
+#
+# Returns: a list of @MouseInfo for each device
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-mice', 'returns': ['MouseInfo'] }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4328e8b..c535560 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1663,6 +1663,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-mice",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_mice,
+    },
+
 SQMP
 query-vnc
 ---------
commit 694a099a542563f40116743c963066ce142a7755
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Oct 19 14:51:14 2011 -0200

    qapi-commands.py: Don't call the output marshal on error
    
    Today we generate something like this:
    
        int qmp_marshal_input_query_foo(...)
    
            ...
    
            retval = qmp_query_foo(errp);
            qmp_marshal_output_query_foo(retval, ret, errp);
    
            ...
    
    However, if qmp_query_foo() fails 'retval' will probably be NULL,
    which can cause a segfault as not all visitors check if 'retval'
    is valid.
    
    This commit fixes that by changing the code generator to only
    call the output marshal if qmp_query_foo() succeeds, like this:
    
        retval = qmp_query_foo(errp);
        if (!error_is_set(errp)) {
            qmp_marshal_output_query_foo(retval, ret, errp);
        }
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index c947ba4..f7def16 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -62,7 +62,9 @@ def gen_sync_call(name, args, ret_type, indent=0):
                 name=c_var(name), args=arglist, retval=retval).rstrip()
     if ret_type:
         ret += "\n" + mcgen(''''
-%(marshal_output_call)s
+if (!error_is_set(errp)) {
+    %(marshal_output_call)s
+}
 ''',
                             marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
     pop_indent(indent)
commit 9e0e2f967b17fc88cd288963e9cb1187d4b3841b
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Oct 26 09:59:18 2011 -0700

    ppc64-linux-user: Fix syscall return type.
    
    Use target_ulong instead of hard-coded uint32_t.
    Remove the disabled printf's that are redundant with -strace.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/main.c b/linux-user/main.c
index c36a8af..d1bbc57 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1341,7 +1341,7 @@ void cpu_loop(CPUPPCState *env)
 {
     target_siginfo_t info;
     int trapnr;
-    uint32_t ret;
+    target_ulong ret;
 
     for(;;) {
         cpu_exec_start(env);
@@ -1704,27 +1704,20 @@ void cpu_loop(CPUPPCState *env)
              * PPC ABI uses overflow flag in cr0 to signal an error
              * in syscalls.
              */
-#if 0
-            printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
-                   env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
-#endif
             env->crf[0] &= ~0x1;
             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
                              env->gpr[5], env->gpr[6], env->gpr[7],
                              env->gpr[8], 0, 0);
-            if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
+            if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
                 /* Returning from a successful sigreturn syscall.
                    Avoid corrupting register state.  */
                 break;
             }
-            if (ret > (uint32_t)(-515)) {
+            if (ret > (target_ulong)(-515)) {
                 env->crf[0] |= 0x1;
                 ret = -ret;
             }
             env->gpr[3] = ret;
-#if 0
-            printf("syscall returned 0x%08x (%d)\n", ret, ret);
-#endif
             break;
         case POWERPC_EXCP_STCX:
             if (do_store_exclusive(env)) {
commit 8e78064e9d95094b7db8e82e57fa6d57fd38b333
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Oct 26 09:59:17 2011 -0700

    ppc64-linux-user: Properly interpret the entry function descriptor.
    
    Don't confuse the load address with the load bias.  They're equal
    for ET_DYN objects (i.e. ld.so) but different for ET_EXEC objects
    (i.e. statically linked).
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 8677bba..a413976 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -618,8 +618,8 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
 {
     _regs->gpr[1] = infop->start_stack;
 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_addr;
-    infop->entry = ldq_raw(infop->entry) + infop->load_addr;
+    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
+    infop->entry = ldq_raw(infop->entry) + infop->load_bias;
 #endif
     _regs->nip = infop->entry;
 }
@@ -1884,11 +1884,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     info->start_stack = bprm->p;
 
     /* If we have an interpreter, set that as the program's entry point.
-       Copy the load_addr as well, to help PPC64 interpret the entry
+       Copy the load_bias as well, to help PPC64 interpret the entry
        point as a function descriptor.  Do this after creating elf tables
        so that we copy the original program entry point into the AUXV.  */
     if (elf_interpreter) {
-        info->load_addr = interp_info.load_addr;
+        info->load_bias = interp_info.load_bias;
         info->entry = interp_info.entry;
         free(elf_interpreter);
     }
commit 7cd393ac1db87a5268173ce2286a4283c9e7a4a9
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Oct 25 10:34:08 2011 -0700

    sparc-linux-user: Add some missing syscall numbers
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h
index be503f2..f201f9f 100644
--- a/linux-user/sparc/syscall_nr.h
+++ b/linux-user/sparc/syscall_nr.h
@@ -136,6 +136,7 @@
 #define TARGET_NR_utimes             138 /* SunOS Specific                              */
 #define TARGET_NR_stat64		139 /* Linux sparc32 Specific			   */
 #define TARGET_NR_getpeername        141 /* Common                                      */
+#define TARGET_NR_futex              142 /* gethostid under SunOS                       */
 #define TARGET_NR_gettid             143 /* ENOSYS under SunOS                          */
 #define TARGET_NR_getrlimit          144 /* Common                                      */
 #define TARGET_NR_setrlimit          145 /* Common                                      */
@@ -153,6 +154,7 @@
 #define TARGET_NR_getdomainname      162 /* SunOS Specific                              */
 #define TARGET_NR_setdomainname      163 /* Common                                      */
 #define TARGET_NR_quotactl           165 /* Common                                      */
+#define TARGET_NR_set_tid_address    166 /* Linux specific, exportfs under SunOS        */
 #define TARGET_NR_mount              167 /* Common                                      */
 #define TARGET_NR_ustat              168 /* Common                                      */
 #define TARGET_NR_getdents           174 /* Common                                      */
@@ -177,6 +179,7 @@
 #define TARGET_NR_readahead          205 /* Linux Specific                              */
 #define TARGET_NR_socketcall         206 /* Linux Specific                              */
 #define TARGET_NR_syslog             207 /* Linux Specific                              */
+#define TARGET_NR_tgkill             211 /* Linux Specific                              */
 #define TARGET_NR_waitpid            212 /* Linux Specific                              */
 #define TARGET_NR_swapoff            213 /* Linux Specific                              */
 #define TARGET_NR_sysinfo            214 /* Linux Specific                              */
commit 59f7182f945ca9a0a689ab60bfcd7e37c25fc4cb
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Oct 25 10:34:07 2011 -0700

    sparc-linux-user: Fixup sending SIGSEGV
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/main.c b/linux-user/main.c
index 2bc10ed..c36a8af 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1148,7 +1148,7 @@ void cpu_loop (CPUSPARCState *env)
         case TT_TFAULT:
         case TT_DFAULT:
             {
-                info.si_signo = SIGSEGV;
+                info.si_signo = TARGET_SIGSEGV;
                 info.si_errno = 0;
                 /* XXX: check env->error_code */
                 info.si_code = TARGET_SEGV_MAPERR;
@@ -1166,7 +1166,7 @@ void cpu_loop (CPUSPARCState *env)
         case TT_TFAULT:
         case TT_DFAULT:
             {
-                info.si_signo = SIGSEGV;
+                info.si_signo = TARGET_SIGSEGV;
                 info.si_errno = 0;
                 /* XXX: check env->error_code */
                 info.si_code = TARGET_SEGV_MAPERR;
commit 75f22e4e69aa4e6d58f52c1863910b3245acc719
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Oct 25 10:34:06 2011 -0700

    sparc-linux-user: Handle SIGILL.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/main.c b/linux-user/main.c
index e7dad54..2bc10ed 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1191,6 +1191,15 @@ void cpu_loop (CPUSPARCState *env)
         case EXCP_INTERRUPT:
             /* just indicate that signals should be handled asap */
             break;
+        case TT_ILL_INSN:
+            {
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                info.si_code = TARGET_ILL_ILLOPC;
+                info._sifields._sigfault._addr = env->pc;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
         case EXCP_DEBUG:
             {
                 int sig;
commit 0f6b4d21121bec70b383b4a3bc1c46d9c83f8692
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Sep 27 14:39:42 2011 +0200

    linux-user: implement reboot syscall
    
    For OBS, we're running a full cross-guest inside of a VM. When a build
    is done there, we reboot the guest as shutdown mechanism.
    
    Unfortunately, reboot is not implemented in linux-user. So this mechanism
    fails, spilling unpretty warnings. This patch implements sys_reboot()
    emulation.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6159571..9f5da36 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -248,6 +248,8 @@ _syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len,
 #define __NR_sys_sched_setaffinity __NR_sched_setaffinity
 _syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
           unsigned long *, user_mask_ptr);
+_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
+          void *, arg);
 
 static bitmask_transtbl fcntl_flags_tbl[] = {
   { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
@@ -5872,7 +5874,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 #endif
     case TARGET_NR_reboot:
-        goto unimplemented;
+        if (!(p = lock_user_string(arg4)))
+            goto efault;
+        ret = reboot(arg1, arg2, arg3, p);
+        unlock_user(p, arg4, 0);
+        break;
 #ifdef TARGET_NR_readdir
     case TARGET_NR_readdir:
         goto unimplemented;
commit f4c690101c74afcc58deead71f6302fe343718b7
Author: Alexander Graf <agraf at suse.de>
Date:   Sun Sep 25 06:25:35 2011 +0200

    linux-user: fix openat
    
    When running openat using qemu-arm, we stumbled over invalid permissions
    on the created files. The reason for this is that the mode parameter gets
    treates as an O_... flag, which it isn't - it's a permission bitmask.
    
    This patch removes the needless translation of the mode parameter,
    rendering permission passing of openat() to work with linux-user.
    
    Reported-by: Dirk Mueller <dmueller at suse.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9a63357..6159571 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -379,25 +379,13 @@ static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
 }
 #endif
 #ifdef TARGET_NR_openat
-static int sys_openat(int dirfd, const char *pathname, int flags, ...)
+static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
 {
   /*
    * open(2) has extra parameter 'mode' when called with
    * flag O_CREAT.
    */
   if ((flags & O_CREAT) != 0) {
-      va_list ap;
-      mode_t mode;
-
-      /*
-       * Get the 'mode' parameter and translate it to
-       * host bits.
-       */
-      va_start(ap, flags);
-      mode = va_arg(ap, mode_t);
-      mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
-      va_end(ap);
-
       return (openat(dirfd, pathname, flags, mode));
   }
   return (openat(dirfd, pathname, flags));
commit cbb21eed186647716b9e8404a9e90d3fc5c6c467
Author: Matthias Braun <matze at braunis.de>
Date:   Fri Aug 12 19:57:41 2011 +0200

    linux-user: fix abi_(u)long, target_ulong mismatch
    
    abi_(u)long might be different from target_ulong, so don't use tswapl
    but introduce a new tswapal
    
    Signed-off-by: Matthias Braun <matze at braunis.de>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/qemu-types.h b/linux-user/qemu-types.h
index 1adda9f..fe7f662 100644
--- a/linux-user/qemu-types.h
+++ b/linux-user/qemu-types.h
@@ -9,6 +9,12 @@ typedef int32_t abi_long;
 #define TARGET_ABI_FMT_ld "%d"
 #define TARGET_ABI_FMT_lu "%u"
 #define TARGET_ABI_BITS 32
+
+static inline abi_ulong tswapal(abi_ulong v)
+{
+    return tswap32(v);
+}
+
 #else
 typedef target_ulong abi_ulong;
 typedef target_long abi_long;
@@ -20,5 +26,11 @@ typedef target_long abi_long;
 #if TARGET_ABI_BITS == 32
 #define TARGET_ABI32 1
 #endif
+
+static inline abi_ulong tswapal(abi_ulong v)
+{
+    return tswapl(v);
+}
+
 #endif
 #endif
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 40c5eb1..e4addcd 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -152,7 +152,7 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
 
     host_to_target_sigset_internal(&d1, s);
     for(i = 0;i < TARGET_NSIG_WORDS; i++)
-        d->sig[i] = tswapl(d1.sig[i]);
+        d->sig[i] = tswapal(d1.sig[i]);
 }
 
 static void target_to_host_sigset_internal(sigset_t *d,
@@ -173,7 +173,7 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
     int i;
 
     for(i = 0;i < TARGET_NSIG_WORDS; i++)
-        s1.sig[i] = tswapl(s->sig[i]);
+        s1.sig[i] = tswapal(s->sig[i]);
     target_to_host_sigset_internal(d, &s1);
 }
 
@@ -234,14 +234,14 @@ static void tswap_siginfo(target_siginfo_t *tinfo,
     if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
         sig == SIGBUS || sig == SIGTRAP) {
         tinfo->_sifields._sigfault._addr =
-            tswapl(info->_sifields._sigfault._addr);
+            tswapal(info->_sifields._sigfault._addr);
     } else if (sig == SIGIO) {
 	tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
     } else if (sig >= TARGET_SIGRTMIN) {
         tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
         tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
         tinfo->_sifields._rt._sigval.sival_ptr =
-            tswapl(info->_sifields._rt._sigval.sival_ptr);
+            tswapal(info->_sifields._rt._sigval.sival_ptr);
     }
 }
 
@@ -262,7 +262,7 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
     info->si_pid = tswap32(tinfo->_sifields._rt._pid);
     info->si_uid = tswap32(tinfo->_sifields._rt._uid);
     info->si_value.sival_ptr =
-            (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
+            (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
 }
 
 static int fatal_signal (int sig)
@@ -586,19 +586,19 @@ int do_sigaction(int sig, const struct target_sigaction *act,
             sig, act, oact);
 #endif
     if (oact) {
-        oact->_sa_handler = tswapl(k->_sa_handler);
-        oact->sa_flags = tswapl(k->sa_flags);
+        oact->_sa_handler = tswapal(k->_sa_handler);
+        oact->sa_flags = tswapal(k->sa_flags);
 #if !defined(TARGET_MIPS)
-        oact->sa_restorer = tswapl(k->sa_restorer);
+        oact->sa_restorer = tswapal(k->sa_restorer);
 #endif
         oact->sa_mask = k->sa_mask;
     }
     if (act) {
         /* FIXME: This is not threadsafe.  */
-        k->_sa_handler = tswapl(act->_sa_handler);
-        k->sa_flags = tswapl(act->sa_flags);
+        k->_sa_handler = tswapal(act->_sa_handler);
+        k->sa_flags = tswapal(act->sa_flags);
 #if !defined(TARGET_MIPS)
-        k->sa_restorer = tswapl(act->sa_restorer);
+        k->sa_restorer = tswapal(act->sa_restorer);
 #endif
         k->sa_mask = act->sa_mask;
 
diff --git a/linux-user/strace.c b/linux-user/strace.c
index fe9326a..90027a1 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -169,7 +169,7 @@ print_fdset(int n, abi_ulong target_fds_addr)
             return;
 
         for (i=n; i>=0; i--) {
-            if ((tswapl(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1)
+            if ((tswapal(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1)
                 gemu_log("%d,", i );
             }
         unlock_user(target_fds, target_fds_addr, 0);
@@ -245,7 +245,7 @@ print_execve(const struct syscallname *name,
 	arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
         if (!arg_ptr)
             return;
-	arg_addr = tswapl(*arg_ptr);
+    arg_addr = tswapal(*arg_ptr);
 	unlock_user(arg_ptr, arg_ptr_addr, 0);
         if (!arg_addr)
             break;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7735008..9a63357 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -931,53 +931,55 @@ static inline abi_long host_to_target_rusage(abi_ulong target_addr,
 
     if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0))
         return -TARGET_EFAULT;
-    target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
-    target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
-    target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
-    target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
-    target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
-    target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
-    target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
-    target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
-    target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
-    target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
-    target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
-    target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
-    target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
-    target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
-    target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
-    target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
-    target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
-    target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
+    target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec);
+    target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec);
+    target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec);
+    target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec);
+    target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss);
+    target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss);
+    target_rusage->ru_idrss = tswapal(rusage->ru_idrss);
+    target_rusage->ru_isrss = tswapal(rusage->ru_isrss);
+    target_rusage->ru_minflt = tswapal(rusage->ru_minflt);
+    target_rusage->ru_majflt = tswapal(rusage->ru_majflt);
+    target_rusage->ru_nswap = tswapal(rusage->ru_nswap);
+    target_rusage->ru_inblock = tswapal(rusage->ru_inblock);
+    target_rusage->ru_oublock = tswapal(rusage->ru_oublock);
+    target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd);
+    target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv);
+    target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals);
+    target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw);
+    target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw);
     unlock_user_struct(target_rusage, target_addr, 1);
 
     return 0;
 }
 
-static inline rlim_t target_to_host_rlim(target_ulong target_rlim)
+static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
 {
-    target_ulong target_rlim_swap;
+    abi_ulong target_rlim_swap;
     rlim_t result;
     
-    target_rlim_swap = tswapl(target_rlim);
-    if (target_rlim_swap == TARGET_RLIM_INFINITY || target_rlim_swap != (rlim_t)target_rlim_swap)
-        result = RLIM_INFINITY;
-    else
-        result = target_rlim_swap;
+    target_rlim_swap = tswapal(target_rlim);
+    if (target_rlim_swap == TARGET_RLIM_INFINITY)
+        return RLIM_INFINITY;
+
+    result = target_rlim_swap;
+    if (target_rlim_swap != (rlim_t)result)
+        return RLIM_INFINITY;
     
     return result;
 }
 
-static inline target_ulong host_to_target_rlim(rlim_t rlim)
+static inline abi_ulong host_to_target_rlim(rlim_t rlim)
 {
-    target_ulong target_rlim_swap;
-    target_ulong result;
+    abi_ulong target_rlim_swap;
+    abi_ulong result;
     
-    if (rlim == RLIM_INFINITY || rlim != (target_long)rlim)
+    if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
         target_rlim_swap = TARGET_RLIM_INFINITY;
     else
         target_rlim_swap = rlim;
-    result = tswapl(target_rlim_swap);
+    result = tswapal(target_rlim_swap);
     
     return result;
 }
@@ -1196,7 +1198,7 @@ static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
     mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
     mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
     if (len == sizeof(struct target_ip_mreqn))
-        mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
+        mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
     unlock_user(target_smreqn, target_addr, 0);
 
     return 0;
@@ -1268,10 +1270,10 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
     struct target_cmsghdr *target_cmsg;
     socklen_t space = 0;
     
-    msg_controllen = tswapl(target_msgh->msg_controllen);
+    msg_controllen = tswapal(target_msgh->msg_controllen);
     if (msg_controllen < sizeof (struct target_cmsghdr)) 
         goto the_end;
-    target_cmsg_addr = tswapl(target_msgh->msg_control);
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
     target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
     if (!target_cmsg)
         return -TARGET_EFAULT;
@@ -1280,7 +1282,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
         void *data = CMSG_DATA(cmsg);
         void *target_data = TARGET_CMSG_DATA(target_cmsg);
 
-        int len = tswapl(target_cmsg->cmsg_len)
+        int len = tswapal(target_cmsg->cmsg_len)
                   - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
 
         space += CMSG_SPACE(len);
@@ -1325,10 +1327,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
     struct target_cmsghdr *target_cmsg;
     socklen_t space = 0;
 
-    msg_controllen = tswapl(target_msgh->msg_controllen);
+    msg_controllen = tswapal(target_msgh->msg_controllen);
     if (msg_controllen < sizeof (struct target_cmsghdr)) 
         goto the_end;
-    target_cmsg_addr = tswapl(target_msgh->msg_control);
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
     target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
     if (!target_cmsg)
         return -TARGET_EFAULT;
@@ -1348,7 +1350,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
 
         target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
         target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
-        target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
+        target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
 
         if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
             gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
@@ -1367,7 +1369,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
     }
     unlock_user(target_cmsg, target_cmsg_addr, space);
  the_end:
-    target_msgh->msg_controllen = tswapl(space);
+    target_msgh->msg_controllen = tswapal(space);
     return 0;
 }
 
@@ -1687,8 +1689,8 @@ static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
     if (!target_vec)
         return -TARGET_EFAULT;
     for(i = 0;i < count; i++) {
-        base = tswapl(target_vec[i].iov_base);
-        vec[i].iov_len = tswapl(target_vec[i].iov_len);
+        base = tswapal(target_vec[i].iov_base);
+        vec[i].iov_len = tswapal(target_vec[i].iov_len);
         if (vec[i].iov_len != 0) {
             vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
             /* Don't check lock_user return value. We must call writev even
@@ -1714,7 +1716,7 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
         return -TARGET_EFAULT;
     for(i = 0;i < count; i++) {
         if (target_vec[i].iov_base) {
-            base = tswapl(target_vec[i].iov_base);
+            base = tswapal(target_vec[i].iov_base);
             unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
         }
     }
@@ -1813,7 +1815,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
     if (msgp->msg_name) {
         msg.msg_namelen = tswap32(msgp->msg_namelen);
         msg.msg_name = alloca(msg.msg_namelen);
-        ret = target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
+        ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name),
                                 msg.msg_namelen);
         if (ret) {
             unlock_user_struct(msgp, target_msg, send ? 0 : 1);
@@ -1823,13 +1825,13 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
         msg.msg_name = NULL;
         msg.msg_namelen = 0;
     }
-    msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
+    msg.msg_controllen = 2 * tswapal(msgp->msg_controllen);
     msg.msg_control = alloca(msg.msg_controllen);
     msg.msg_flags = tswap32(msgp->msg_flags);
 
-    count = tswapl(msgp->msg_iovlen);
+    count = tswapal(msgp->msg_iovlen);
     vec = alloca(count * sizeof(struct iovec));
-    target_vec = tswapl(msgp->msg_iov);
+    target_vec = tswapal(msgp->msg_iov);
     lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send);
     msg.msg_iovlen = count;
     msg.msg_iov = vec;
@@ -2332,12 +2334,12 @@ static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
     if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
         return -TARGET_EFAULT;
     target_ip = &(target_sd->sem_perm);
-    host_ip->__key = tswapl(target_ip->__key);
-    host_ip->uid = tswapl(target_ip->uid);
-    host_ip->gid = tswapl(target_ip->gid);
-    host_ip->cuid = tswapl(target_ip->cuid);
-    host_ip->cgid = tswapl(target_ip->cgid);
-    host_ip->mode = tswapl(target_ip->mode);
+    host_ip->__key = tswapal(target_ip->__key);
+    host_ip->uid = tswapal(target_ip->uid);
+    host_ip->gid = tswapal(target_ip->gid);
+    host_ip->cuid = tswapal(target_ip->cuid);
+    host_ip->cgid = tswapal(target_ip->cgid);
+    host_ip->mode = tswap16(target_ip->mode);
     unlock_user_struct(target_sd, target_addr, 0);
     return 0;
 }
@@ -2351,12 +2353,12 @@ static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
     if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
         return -TARGET_EFAULT;
     target_ip = &(target_sd->sem_perm);
-    target_ip->__key = tswapl(host_ip->__key);
-    target_ip->uid = tswapl(host_ip->uid);
-    target_ip->gid = tswapl(host_ip->gid);
-    target_ip->cuid = tswapl(host_ip->cuid);
-    target_ip->cgid = tswapl(host_ip->cgid);
-    target_ip->mode = tswapl(host_ip->mode);
+    target_ip->__key = tswapal(host_ip->__key);
+    target_ip->uid = tswapal(host_ip->uid);
+    target_ip->gid = tswapal(host_ip->gid);
+    target_ip->cuid = tswapal(host_ip->cuid);
+    target_ip->cgid = tswapal(host_ip->cgid);
+    target_ip->mode = tswap16(host_ip->mode);
     unlock_user_struct(target_sd, target_addr, 1);
     return 0;
 }
@@ -2370,9 +2372,9 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
         return -TARGET_EFAULT;
     if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
         return -TARGET_EFAULT;
-    host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
-    host_sd->sem_otime = tswapl(target_sd->sem_otime);
-    host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
+    host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapal(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
     unlock_user_struct(target_sd, target_addr, 0);
     return 0;
 }
@@ -2386,9 +2388,9 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
         return -TARGET_EFAULT;
     if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
         return -TARGET_EFAULT;;
-    target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
-    target_sd->sem_otime = tswapl(host_sd->sem_otime);
-    target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
+    target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapal(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
     unlock_user_struct(target_sd, target_addr, 1);
     return 0;
 }
@@ -2516,9 +2518,9 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd,
     switch( cmd ) {
 	case GETVAL:
 	case SETVAL:
-            arg.val = tswapl(target_su.val);
+            arg.val = tswap32(target_su.val);
             ret = get_errno(semctl(semid, semnum, cmd, arg));
-            target_su.val = tswapl(arg.val);
+            target_su.val = tswap32(arg.val);
             break;
 	case GETALL:
 	case SETALL:
@@ -2634,14 +2636,14 @@ static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
         return -TARGET_EFAULT;
     if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
         return -TARGET_EFAULT;
-    host_md->msg_stime = tswapl(target_md->msg_stime);
-    host_md->msg_rtime = tswapl(target_md->msg_rtime);
-    host_md->msg_ctime = tswapl(target_md->msg_ctime);
-    host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
-    host_md->msg_qnum = tswapl(target_md->msg_qnum);
-    host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
-    host_md->msg_lspid = tswapl(target_md->msg_lspid);
-    host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
+    host_md->msg_stime = tswapal(target_md->msg_stime);
+    host_md->msg_rtime = tswapal(target_md->msg_rtime);
+    host_md->msg_ctime = tswapal(target_md->msg_ctime);
+    host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
+    host_md->msg_qnum = tswapal(target_md->msg_qnum);
+    host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
+    host_md->msg_lspid = tswapal(target_md->msg_lspid);
+    host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
     unlock_user_struct(target_md, target_addr, 0);
     return 0;
 }
@@ -2655,14 +2657,14 @@ static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
         return -TARGET_EFAULT;
     if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
         return -TARGET_EFAULT;
-    target_md->msg_stime = tswapl(host_md->msg_stime);
-    target_md->msg_rtime = tswapl(host_md->msg_rtime);
-    target_md->msg_ctime = tswapl(host_md->msg_ctime);
-    target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
-    target_md->msg_qnum = tswapl(host_md->msg_qnum);
-    target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
-    target_md->msg_lspid = tswapl(host_md->msg_lspid);
-    target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
+    target_md->msg_stime = tswapal(host_md->msg_stime);
+    target_md->msg_rtime = tswapal(host_md->msg_rtime);
+    target_md->msg_ctime = tswapal(host_md->msg_ctime);
+    target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
+    target_md->msg_qnum = tswapal(host_md->msg_qnum);
+    target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
+    target_md->msg_lspid = tswapal(host_md->msg_lspid);
+    target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
     unlock_user_struct(target_md, target_addr, 1);
     return 0;
 }
@@ -2743,7 +2745,7 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp,
     if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
         return -TARGET_EFAULT;
     host_mb = malloc(msgsz+sizeof(long));
-    host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
+    host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
     memcpy(host_mb->mtext, target_mb->mtext, msgsz);
     ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
     free(host_mb);
@@ -2765,7 +2767,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
         return -TARGET_EFAULT;
 
     host_mb = malloc(msgsz+sizeof(long));
-    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));
+    ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
 
     if (ret > 0) {
         abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
@@ -2778,7 +2780,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
         unlock_user(target_mtext, target_mtext_addr, ret);
     }
 
-    target_mb->mtype = tswapl(host_mb->mtype);
+    target_mb->mtype = tswapal(host_mb->mtype);
     free(host_mb);
 
 end:
@@ -3649,7 +3651,7 @@ static abi_long write_ldt(CPUX86State *env,
     if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1))
         return -TARGET_EFAULT;
     ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
-    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
+    ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
     ldt_info.limit = tswap32(target_ldt_info->limit);
     ldt_info.flags = tswap32(target_ldt_info->flags);
     unlock_user_struct(target_ldt_info, ptr, 0);
@@ -3764,7 +3766,7 @@ static abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
     if (!target_ldt_info)
         return -TARGET_EFAULT;
     ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
-    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
+    ldt_info.base_addr = tswapal(target_ldt_info->base_addr);
     ldt_info.limit = tswap32(target_ldt_info->limit);
     ldt_info.flags = tswap32(target_ldt_info->flags);
     if (ldt_info.entry_number == -1) {
@@ -3875,7 +3877,7 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
     base_addr = (entry_1 >> 16) | 
         (entry_2 & 0xff000000) | 
         ((entry_2 & 0xff) << 16);
-    target_ldt_info->base_addr = tswapl(base_addr);
+    target_ldt_info->base_addr = tswapal(base_addr);
     target_ldt_info->limit = tswap32(limit);
     target_ldt_info->flags = tswap32(flags);
     unlock_user_struct(target_ldt_info, ptr, 1);
@@ -4175,8 +4177,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
             return -TARGET_EFAULT;
         fl.l_type = tswap16(target_fl->l_type);
         fl.l_whence = tswap16(target_fl->l_whence);
-        fl.l_start = tswapl(target_fl->l_start);
-        fl.l_len = tswapl(target_fl->l_len);
+        fl.l_start = tswapal(target_fl->l_start);
+        fl.l_len = tswapal(target_fl->l_len);
         fl.l_pid = tswap32(target_fl->l_pid);
         unlock_user_struct(target_fl, arg, 0);
         ret = get_errno(fcntl(fd, host_cmd, &fl));
@@ -4185,8 +4187,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
                 return -TARGET_EFAULT;
             target_fl->l_type = tswap16(fl.l_type);
             target_fl->l_whence = tswap16(fl.l_whence);
-            target_fl->l_start = tswapl(fl.l_start);
-            target_fl->l_len = tswapl(fl.l_len);
+            target_fl->l_start = tswapal(fl.l_start);
+            target_fl->l_len = tswapal(fl.l_len);
             target_fl->l_pid = tswap32(fl.l_pid);
             unlock_user_struct(target_fl, arg, 1);
         }
@@ -4198,8 +4200,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
             return -TARGET_EFAULT;
         fl.l_type = tswap16(target_fl->l_type);
         fl.l_whence = tswap16(target_fl->l_whence);
-        fl.l_start = tswapl(target_fl->l_start);
-        fl.l_len = tswapl(target_fl->l_len);
+        fl.l_start = tswapal(target_fl->l_start);
+        fl.l_len = tswapal(target_fl->l_len);
         fl.l_pid = tswap32(target_fl->l_pid);
         unlock_user_struct(target_fl, arg, 0);
         ret = get_errno(fcntl(fd, host_cmd, &fl));
@@ -4210,8 +4212,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
             return -TARGET_EFAULT;
         fl64.l_type = tswap16(target_fl64->l_type) >> 1;
         fl64.l_whence = tswap16(target_fl64->l_whence);
-        fl64.l_start = tswapl(target_fl64->l_start);
-        fl64.l_len = tswapl(target_fl64->l_len);
+        fl64.l_start = tswap64(target_fl64->l_start);
+        fl64.l_len = tswap64(target_fl64->l_len);
         fl64.l_pid = tswap32(target_fl64->l_pid);
         unlock_user_struct(target_fl64, arg, 0);
         ret = get_errno(fcntl(fd, host_cmd, &fl64));
@@ -4220,8 +4222,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
                 return -TARGET_EFAULT;
             target_fl64->l_type = tswap16(fl64.l_type) >> 1;
             target_fl64->l_whence = tswap16(fl64.l_whence);
-            target_fl64->l_start = tswapl(fl64.l_start);
-            target_fl64->l_len = tswapl(fl64.l_len);
+            target_fl64->l_start = tswap64(fl64.l_start);
+            target_fl64->l_len = tswap64(fl64.l_len);
             target_fl64->l_pid = tswap32(fl64.l_pid);
             unlock_user_struct(target_fl64, arg, 1);
         }
@@ -4232,8 +4234,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
             return -TARGET_EFAULT;
         fl64.l_type = tswap16(target_fl64->l_type) >> 1;
         fl64.l_whence = tswap16(target_fl64->l_whence);
-        fl64.l_start = tswapl(target_fl64->l_start);
-        fl64.l_len = tswapl(target_fl64->l_len);
+        fl64.l_start = tswap64(target_fl64->l_start);
+        fl64.l_len = tswap64(target_fl64->l_len);
         fl64.l_pid = tswap32(target_fl64->l_pid);
         unlock_user_struct(target_fl64, arg, 0);
         ret = get_errno(fcntl(fd, host_cmd, &fl64));
@@ -4426,8 +4428,8 @@ static inline abi_long target_to_host_timespec(struct timespec *host_ts,
 
     if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
         return -TARGET_EFAULT;
-    host_ts->tv_sec = tswapl(target_ts->tv_sec);
-    host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
+    host_ts->tv_sec = tswapal(target_ts->tv_sec);
+    host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
     unlock_user_struct(target_ts, target_addr, 0);
     return 0;
 }
@@ -4439,8 +4441,8 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
 
     if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
         return -TARGET_EFAULT;
-    target_ts->tv_sec = tswapl(host_ts->tv_sec);
-    target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
+    target_ts->tv_sec = tswapal(host_ts->tv_sec);
+    target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
     unlock_user_struct(target_ts, target_addr, 1);
     return 0;
 }
@@ -5004,8 +5006,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             if (arg2) {
                 if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
                     goto efault;
-                tbuf.actime = tswapl(target_tbuf->actime);
-                tbuf.modtime = tswapl(target_tbuf->modtime);
+                tbuf.actime = tswapal(target_tbuf->actime);
+                tbuf.modtime = tswapal(target_tbuf->modtime);
                 unlock_user_struct(target_tbuf, arg2, 0);
                 host_tbuf = &tbuf;
             } else {
@@ -5162,10 +5164,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
                 if (!tmsp)
                     goto efault;
-                tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
-                tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
-                tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
-                tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
+                tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
+                tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
+                tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
+                tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
             }
             if (!is_error(ret))
                 ret = host_to_target_clock_t(ret);
@@ -5687,11 +5689,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
             if (!lock_user_struct(VERIFY_READ, sel, arg1, 1))
                 goto efault;
-            nsel = tswapl(sel->n);
-            inp = tswapl(sel->inp);
-            outp = tswapl(sel->outp);
-            exp = tswapl(sel->exp);
-            tvp = tswapl(sel->tvp);
+            nsel = tswapal(sel->n);
+            inp = tswapal(sel->inp);
+            outp = tswapal(sel->outp);
+            exp = tswapal(sel->exp);
+            tvp = tswapal(sel->tvp);
             unlock_user_struct(sel, arg1, 0);
             ret = do_select(nsel, inp, outp, exp, tvp);
         }
@@ -5759,8 +5761,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 if (!arg7) {
                     goto efault;
                 }
-                arg_sigset = tswapl(arg7[0]);
-                arg_sigsize = tswapl(arg7[1]);
+                arg_sigset = tswapal(arg7[0]);
+                arg_sigsize = tswapal(arg7[1]);
                 unlock_user(arg7, arg6, 0);
 
                 if (arg_sigset) {
@@ -5897,12 +5899,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             abi_ulong v1, v2, v3, v4, v5, v6;
             if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
                 goto efault;
-            v1 = tswapl(v[0]);
-            v2 = tswapl(v[1]);
-            v3 = tswapl(v[2]);
-            v4 = tswapl(v[3]);
-            v5 = tswapl(v[4]);
-            v6 = tswapl(v[5]);
+            v1 = tswapal(v[0]);
+            v2 = tswapal(v[1]);
+            v3 = tswapal(v[2]);
+            v4 = tswapal(v[3]);
+            v5 = tswapal(v[4]);
+            v6 = tswapal(v[5]);
             unlock_user(v, arg1, 0);
             ret = get_errno(target_mmap(v1, v2, v3,
                                         target_to_host_bitmask(v4, mmap_flags_tbl),
@@ -6525,8 +6527,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                     reclen = de->d_reclen;
 		    treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
                     tde->d_reclen = tswap16(treclen);
-                    tde->d_ino = tswapl(de->d_ino);
-                    tde->d_off = tswapl(de->d_off);
+                    tde->d_ino = tswapal(de->d_ino);
+                    tde->d_off = tswapal(de->d_off);
 		    tnamelen = treclen - (2 * sizeof(abi_long) + 2);
 		    if (tnamelen > 256)
                         tnamelen = 256;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 5fd4c9c..9dd1b8e 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -209,9 +209,9 @@ __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cms
   struct target_cmsghdr *__ptr;
 
   __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg
-                                    + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
-  if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapl(__mhdr->msg_control))
-      > tswapl(__mhdr->msg_controllen))
+                                    + TARGET_CMSG_ALIGN (tswapal(__cmsg->cmsg_len)));
+  if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapal(__mhdr->msg_control))
+      > tswapal(__mhdr->msg_controllen))
     /* No more entries.  */
     return (struct target_cmsghdr *)0;
   return __cmsg;
@@ -292,7 +292,7 @@ static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
 {
     int i;
     for(i = 0;i < TARGET_NSIG_WORDS; i++)
-        d->sig[i] = tswapl(s->sig[i]);
+        d->sig[i] = tswapal(s->sig[i]);
 }
 #else
 static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
diff --git a/linux-user/vm86.c b/linux-user/vm86.c
index 0b2439d..2c4ffeb 100644
--- a/linux-user/vm86.c
+++ b/linux-user/vm86.c
@@ -432,7 +432,7 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
     env->eflags = (env->eflags & ~SAFE_MASK) |
         (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
 
-    ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
+    ts->vm86plus.cpu_type = tswapal(target_v86->cpu_type);
     switch (ts->vm86plus.cpu_type) {
     case TARGET_CPU_286:
         ts->v86mask = 0;
@@ -468,7 +468,7 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
            &target_v86->int_revectored, 32);
     memcpy(&ts->vm86plus.int21_revectored,
            &target_v86->int21_revectored, 32);
-    ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
+    ts->vm86plus.vm86plus.flags = tswapal(target_v86->vm86plus.flags);
     memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
            target_v86->vm86plus.vm86dbg_intxxtab, 32);
     unlock_user_struct(target_v86, vm86_addr, 0);
commit 6cafd027be3a6cad710d99bde4a2b3b662869e5d
Author: Matthias Braun <matze at braunis.de>
Date:   Fri Sep 9 19:30:25 2011 +0200

    linux-user: fix rlimit syscalls on sparc(64)
    
    Signed-off-by: Matthias Braun <matze at braunis.de>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 1bc54c7..5fd4c9c 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -687,7 +687,7 @@ struct target_rlimit {
 
 #if defined(TARGET_ALPHA)
 #define TARGET_RLIM_INFINITY	0x7fffffffffffffffull
-#elif defined(TARGET_MIPS) || defined(TARGET_SPARC)
+#elif defined(TARGET_MIPS) || (defined(TARGET_SPARC) && TARGET_ABI_BITS == 32)
 #define TARGET_RLIM_INFINITY	0x7fffffffUL
 #else
 #define TARGET_RLIM_INFINITY	((abi_ulong)-1)
@@ -716,8 +716,13 @@ struct target_rlimit {
 #define TARGET_RLIMIT_STACK		3
 #define TARGET_RLIMIT_CORE		4
 #define TARGET_RLIMIT_RSS		5
+#if defined(TARGET_SPARC)
+#define TARGET_RLIMIT_NOFILE		6
+#define TARGET_RLIMIT_NPROC		7
+#else
 #define TARGET_RLIMIT_NPROC		6
 #define TARGET_RLIMIT_NOFILE		7
+#endif
 #define TARGET_RLIMIT_MEMLOCK		8
 #define TARGET_RLIMIT_AS		9
 #define TARGET_RLIMIT_LOCKS		10
commit 26b746db49ab0dcaaf5a700d0fc055e5188dcc70
Author: Matthias Braun <matze at braunis.de>
Date:   Fri Sep 9 19:31:17 2011 +0200

    linux-user: fix TARGET_RLIM_INFINITY declaration
    
    Signed-off-by: Matthias Braun <matze at braunis.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 15c44d4..1bc54c7 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -690,7 +690,7 @@ struct target_rlimit {
 #elif defined(TARGET_MIPS) || defined(TARGET_SPARC)
 #define TARGET_RLIM_INFINITY	0x7fffffffUL
 #else
-#define TARGET_RLIM_INFINITY	((target_ulong)~0UL)
+#define TARGET_RLIM_INFINITY	((abi_ulong)-1)
 #endif
 
 #if defined(TARGET_MIPS)
commit 9f60639b848944200c3d33a89233d808de0b5a43
Merge: fafd8bc... 12b1de3...
Author: Andrzej Zaborowski <andrew.zaborowski at intel.com>
Date:   Thu Oct 27 01:02:46 2011 +0200

    Merge branch 'target-arm.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm

commit 50c796f9d842bbefeb39ac64d7fe961056ee0267
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Oct 18 09:41:30 2011 -0700

    target-sparc: Implement FALIGNDATA inline.
    
    This is a relatively simple sequence of shifts.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 3ee12a9..faaf8dc 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -125,7 +125,6 @@ DEF_HELPER_1(fqtoi, s32, env)
 DEF_HELPER_2(fstox, s64, env, f32)
 DEF_HELPER_2(fdtox, s64, env, f64)
 DEF_HELPER_1(fqtox, s64, env)
-DEF_HELPER_3(faligndata, i64, env, i64, i64)
 
 DEF_HELPER_FLAGS_2(fpmerge, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fmul8x16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 50fc587..9318540 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2338,6 +2338,31 @@ static void gen_alignaddr(TCGv dst, TCGv s1, TCGv s2, bool left)
 
     tcg_temp_free(tmp);
 }
+
+static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2)
+{
+    TCGv t1, t2, shift;
+
+    t1 = tcg_temp_new();
+    t2 = tcg_temp_new();
+    shift = tcg_temp_new();
+
+    tcg_gen_andi_tl(shift, gsr, 7);
+    tcg_gen_shli_tl(shift, shift, 3);
+    tcg_gen_shl_tl(t1, s1, shift);
+
+    /* A shift of 64 does not produce 0 in TCG.  Divide this into a
+       shift of (up to 63) followed by a constant shift of 1.  */
+    tcg_gen_xori_tl(shift, shift, 63);
+    tcg_gen_shr_tl(t2, s2, shift);
+    tcg_gen_shri_tl(t2, t2, 1);
+
+    tcg_gen_or_tl(dst, t1, t2);
+
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    tcg_temp_free(shift);
+}
 #endif
 
 #define CHECK_IU_FEATURE(dc, FEATURE)                      \
@@ -4307,12 +4332,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x048: /* VIS I faligndata */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_faligndata(cpu_dst_64, cpu_env,
-                                          cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_faligndata);
                     break;
                 case 0x04b: /* VIS I fpmerge */
                     CHECK_FPU_FEATURE(dc, VIS1);
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index 7830120..a992c29 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -41,18 +41,6 @@ target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
         GET_FIELD_SP(pixel_addr, 11, 12);
 }
 
-uint64_t helper_faligndata(CPUState *env, uint64_t src1, uint64_t src2)
-{
-    uint64_t tmp;
-
-    tmp = src1 << ((env->gsr & 7) * 8);
-    /* on many architectures a shift of 64 does nothing */
-    if ((env->gsr & 7) != 0) {
-        tmp |= src2 >> (64 - (env->gsr & 7) * 8);
-    }
-    return tmp;
-}
-
 #ifdef HOST_WORDS_BIGENDIAN
 #define VIS_B64(n) b[7 - (n)]
 #define VIS_W64(n) w[3 - (n)]
commit 793a137a41ad4125011c7022cf16a1baa40a5ab6
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Oct 18 09:24:43 2011 -0700

    target-sparc: Implement BMASK/BSHUFFLE.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 73fb0ee..3ee12a9 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -140,6 +140,7 @@ DEF_HELPER_FLAGS_3(pdist, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fpack16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64, i64)
 DEF_HELPER_FLAGS_3(fpack32, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fpackfix, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64, i64)
+DEF_HELPER_FLAGS_3(bshuffle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
 #define VIS_HELPER(name)                                                 \
     DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_CONST | TCG_CALL_PURE,  \
                        i64, i64, i64)                                    \
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 685a907..50fc587 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -4192,8 +4192,13 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x019: /* VIS II bmask */
-                    // XXX
-                    goto illegal_insn;
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    cpu_src2 = get_src1(insn, cpu_src2);
+                    tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2);
+                    tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, cpu_dst, 32, 32);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x020: /* VIS I fcmple16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
@@ -4314,8 +4319,9 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpmerge);
                     break;
                 case 0x04c: /* VIS II bshuffle */
-                    // XXX
-                    goto illegal_insn;
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_helper_bshuffle);
+                    break;
                 case 0x04d: /* VIS I fexpand */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fexpand);
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index 40adb47..7830120 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -470,3 +470,32 @@ uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2)
 
     return ret;
 }
+
+uint64 helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
+{
+    union {
+        uint64_t ll[2];
+        uint8_t b[16];
+    } s;
+    VIS64 r;
+    uint32_t i, mask, host;
+
+    /* Set up S such that we can index across all of the bytes.  */
+#ifdef HOST_WORDS_BIGENDIAN
+    s.ll[0] = src1;
+    s.ll[1] = src2;
+    host = 0;
+#else
+    s.ll[1] = src1;
+    s.ll[0] = src2;
+    host = 15;
+#endif
+    mask = gsr >> 32;
+
+    for (i = 0; i < 8; ++i) {
+        unsigned e = (mask >> (28 - i*4)) & 0xf;
+        r.VIS_B64(i) = s.b[e ^ host];
+    }
+
+    return r.ll;
+}
commit add545ab11450c7049468fccdcd362b47740d9fe
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Oct 18 08:35:58 2011 -0700

    target-sparc: Implement ALIGNADDR* inline.
    
    While ALIGNADDR was implemented out-of-line, ALIGNADDRL was not
    implemeneted at all.  However, this is a very simple operation
    so we're better off doing this inline.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 07c39a9..73fb0ee 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -17,7 +17,6 @@ DEF_HELPER_2(wrccr, void, env, tl)
 DEF_HELPER_1(rdcwp, tl, env)
 DEF_HELPER_2(wrcwp, void, env, tl)
 DEF_HELPER_FLAGS_2(array8, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
-DEF_HELPER_3(alignaddr, tl, env, tl, tl)
 DEF_HELPER_1(popc, tl, tl)
 DEF_HELPER_3(ldda_asi, void, tl, int, int)
 DEF_HELPER_4(ldf_asi, void, tl, int, int, int)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index d02cf06..685a907 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2324,6 +2324,20 @@ static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2,
     tcg_temp_free(t1);
     tcg_temp_free(t2);
 }
+
+static void gen_alignaddr(TCGv dst, TCGv s1, TCGv s2, bool left)
+{
+    TCGv tmp = tcg_temp_new();
+
+    tcg_gen_add_tl(tmp, s1, s2);
+    tcg_gen_andi_tl(dst, tmp, -8);
+    if (left) {
+        tcg_gen_neg_tl(tmp, tmp);
+    }
+    tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3);
+
+    tcg_temp_free(tmp);
+}
 #endif
 
 #define CHECK_IU_FEATURE(dc, FEATURE)                      \
@@ -4167,11 +4181,17 @@ static void disas_sparc_insn(DisasContext * dc)
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_alignaddr(cpu_dst, cpu_env, cpu_src1, cpu_src2);
+                    gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 0);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
-                case 0x019: /* VIS II bmask */
                 case 0x01a: /* VIS I alignaddrl */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1 = get_src1(insn, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
+                case 0x019: /* VIS II bmask */
                     // XXX
                     goto illegal_insn;
                 case 0x020: /* VIS I fcmple16 */
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index 59ca8d7..40adb47 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -41,17 +41,6 @@ target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
         GET_FIELD_SP(pixel_addr, 11, 12);
 }
 
-target_ulong helper_alignaddr(CPUState *env, target_ulong addr,
-                              target_ulong offset)
-{
-    uint64_t tmp;
-
-    tmp = addr + offset;
-    env->gsr &= ~7ULL;
-    env->gsr |= tmp & 7ULL;
-    return tmp & ~7ULL;
-}
-
 uint64_t helper_faligndata(CPUState *env, uint64_t src1, uint64_t src2)
 {
     uint64_t tmp;
commit 6c07355325b7622c595b961b53755ad5450db0c4
Author: Richard Henderson <rth at twiddle.net>
Date:   Mon Oct 17 19:57:23 2011 -0700

    target-sparc: Implement EDGE* instructions.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 102c83a..d02cf06 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2221,6 +2221,109 @@ static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
 
     tcg_temp_free_i32(r_tl);
 }
+
+static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2,
+                     int width, bool cc, bool left)
+{
+    TCGv lo1, lo2, t1, t2;
+    uint64_t amask, tabl, tabr;
+    int shift, imask, omask;
+
+    if (cc) {
+        tcg_gen_mov_tl(cpu_cc_src, s1);
+        tcg_gen_mov_tl(cpu_cc_src2, s2);
+        tcg_gen_sub_tl(cpu_cc_dst, s1, s2);
+        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB);
+        dc->cc_op = CC_OP_SUB;
+    }
+
+    /* Theory of operation: there are two tables, left and right (not to
+       be confused with the left and right versions of the opcode).  These
+       are indexed by the low 3 bits of the inputs.  To make things "easy",
+       these tables are loaded into two constants, TABL and TABR below.
+       The operation index = (input & imask) << shift calculates the index
+       into the constant, while val = (table >> index) & omask calculates
+       the value we're looking for.  */
+    switch (width) {
+    case 8:
+        imask = 0x7;
+        shift = 3;
+        omask = 0xff;
+        if (left) {
+            tabl = 0x80c0e0f0f8fcfeffULL;
+            tabr = 0xff7f3f1f0f070301ULL;
+        } else {
+            tabl = 0x0103070f1f3f7fffULL;
+            tabr = 0xfffefcf8f0e0c080ULL;
+        }
+        break;
+    case 16:
+        imask = 0x6;
+        shift = 1;
+        omask = 0xf;
+        if (left) {
+            tabl = 0x8cef;
+            tabr = 0xf731;
+        } else {
+            tabl = 0x137f;
+            tabr = 0xfec8;
+        }
+        break;
+    case 32:
+        imask = 0x4;
+        shift = 0;
+        omask = 0x3;
+        if (left) {
+            tabl = (2 << 2) | 3;
+            tabr = (3 << 2) | 1;
+        } else {
+            tabl = (1 << 2) | 3;
+            tabr = (3 << 2) | 2;
+        }
+        break;
+    default:
+        abort();
+    }
+
+    lo1 = tcg_temp_new();
+    lo2 = tcg_temp_new();
+    tcg_gen_andi_tl(lo1, s1, imask);
+    tcg_gen_andi_tl(lo2, s2, imask);
+    tcg_gen_shli_tl(lo1, lo1, shift);
+    tcg_gen_shli_tl(lo2, lo2, shift);
+
+    t1 = tcg_const_tl(tabl);
+    t2 = tcg_const_tl(tabr);
+    tcg_gen_shr_tl(lo1, t1, lo1);
+    tcg_gen_shr_tl(lo2, t2, lo2);
+    tcg_gen_andi_tl(dst, lo1, omask);
+    tcg_gen_andi_tl(lo2, lo2, omask);
+
+    amask = -8;
+    if (AM_CHECK(dc)) {
+        amask &= 0xffffffffULL;
+    }
+    tcg_gen_andi_tl(s1, s1, amask);
+    tcg_gen_andi_tl(s2, s2, amask);
+
+    /* We want to compute
+        dst = (s1 == s2 ? lo1 : lo1 & lo2).
+       We've already done dst = lo1, so this reduces to
+        dst &= (s1 == s2 ? -1 : lo2)
+       Which we perform by
+        lo2 |= -(s1 == s2)
+        dst &= lo2
+    */
+    tcg_gen_setcond_tl(TCG_COND_EQ, t1, s1, s2);
+    tcg_gen_neg_tl(t1, t1);
+    tcg_gen_or_tl(lo2, lo2, t1);
+    tcg_gen_and_tl(dst, dst, lo2);
+
+    tcg_temp_free(lo1);
+    tcg_temp_free(lo2);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+}
 #endif
 
 #define CHECK_IU_FEATURE(dc, FEATURE)                      \
@@ -3954,19 +4057,89 @@ static void disas_sparc_insn(DisasContext * dc)
 
                 switch (opf) {
                 case 0x000: /* VIS I edge8cc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 1, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x001: /* VIS II edge8n */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 0, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x002: /* VIS I edge8lcc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 1, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x003: /* VIS II edge8ln */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 0, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x004: /* VIS I edge16cc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 1, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x005: /* VIS II edge16n */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 0, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x006: /* VIS I edge16lcc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 1, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x007: /* VIS II edge16ln */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 0, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x008: /* VIS I edge32cc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 1, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x009: /* VIS II edge32n */
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 0, 0);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x00a: /* VIS I edge32lcc */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 1, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x00b: /* VIS II edge32ln */
-                    // XXX
-                    goto illegal_insn;
+                    CHECK_FPU_FEATURE(dc, VIS2);
+                    gen_movl_reg_TN(rs1, cpu_src1);
+                    gen_movl_reg_TN(rs2, cpu_src2);
+                    gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 0, 1);
+                    gen_movl_TN_reg(rd, cpu_dst);
+                    break;
                 case 0x010: /* VIS I array8 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
commit 2dedf31497bf3f89167bed0aa91c5700579d0b79
Author: Richard Henderson <rth at twiddle.net>
Date:   Mon Oct 17 18:03:47 2011 -0700

    target-sparc: Implement fpack{16,32,fix}.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 22f9dce..07c39a9 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -138,6 +138,9 @@ DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
 DEF_HELPER_FLAGS_3(pdist, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fpack16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64, i64)
+DEF_HELPER_FLAGS_3(fpack32, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fpackfix, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64, i64)
 #define VIS_HELPER(name)                                                 \
     DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_CONST | TCG_CALL_PURE,  \
                        i64, i64, i64)                                    \
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 2646aaf..102c83a 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1739,6 +1739,20 @@ static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
     gen_store_fpr_D(dc, rd, dst);
 }
 
+static inline void gen_gsr_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+                           void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src1, src2;
+
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_gsr, src1, src2);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
 static inline void gen_ne_fop_DDDD(DisasContext *dc, int rd, int rs1, int rs2,
                            void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
 {
@@ -4072,9 +4086,23 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld8ulx16);
                     break;
                 case 0x03a: /* VIS I fpack32 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_gsr_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpack32);
+                    break;
                 case 0x03b: /* VIS I fpack16 */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fpack16(cpu_dst_32, cpu_gsr, cpu_src1_64);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    break;
                 case 0x03d: /* VIS I fpackfix */
-                    goto illegal_insn;
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fpackfix(cpu_dst_32, cpu_gsr, cpu_src1_64);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    break;
                 case 0x03e: /* VIS I pdist */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     gen_ne_fop_DDDD(dc, rd, rs1, rs2, gen_helper_pdist);
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index cd5d4a7..59ca8d7 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -417,3 +417,67 @@ uint64_t helper_pdist(uint64_t sum, uint64_t src1, uint64_t src2)
 
     return sum;
 }
+
+uint32_t helper_fpack16(uint64_t gsr, uint64_t rs2)
+{
+    int scale = (gsr >> 3) & 0xf;
+    uint32_t ret = 0;
+    int byte;
+
+    for (byte = 0; byte < 4; byte++) {
+        uint32_t val;
+        int16_t src = rs2 >> (byte * 16);
+        int32_t scaled = src << scale;
+        int32_t from_fixed = scaled >> 7;
+
+        val = (from_fixed < 0 ?  0 :
+               from_fixed > 255 ?  255 : from_fixed);
+
+        ret |= val << (8 * byte);
+    }
+
+    return ret;
+}
+
+uint64_t helper_fpack32(uint64_t gsr, uint64_t rs1, uint64_t rs2)
+{
+    int scale = (gsr >> 3) & 0x1f;
+    uint64_t ret = 0;
+    int word;
+
+    ret = (rs1 << 8) & ~(0x000000ff000000ffULL);
+    for (word = 0; word < 2; word++) {
+        uint64_t val;
+        int32_t src = rs2 >> (word * 32);
+        int64_t scaled = (int64_t)src << scale;
+        int64_t from_fixed = scaled >> 23;
+
+        val = (from_fixed < 0 ? 0 :
+               (from_fixed > 255) ? 255 : from_fixed);
+
+        ret |= val << (32 * word);
+    }
+
+    return ret;
+}
+
+uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2)
+{
+    int scale = (gsr >> 3) & 0x1f;
+    uint32_t ret = 0;
+    int word;
+
+    for (word = 0; word < 2; word++) {
+        uint32_t val;
+        int32_t src = rs2 >> (word * 32);
+        int64_t scaled = src << scale;
+        int64_t from_fixed = scaled >> 16;
+
+        val = (from_fixed < -32768 ? -32768 :
+               from_fixed > 32767 ?  32767 : from_fixed);
+
+        ret |= (val & 0xffff) << (word * 16);
+    }
+
+    return ret;
+}
commit f888300b818a46bb1b339d68d6748bc097396a7b
Author: Richard Henderson <rth at twiddle.net>
Date:   Mon Oct 17 17:32:26 2011 -0700

    target-sparc: Implement PDIST.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 22fb8ef..22f9dce 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -137,6 +137,7 @@ DEF_HELPER_FLAGS_2(fmul8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_3(pdist, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64)
 #define VIS_HELPER(name)                                                 \
     DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_CONST | TCG_CALL_PURE,  \
                        i64, i64, i64)                                    \
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 0b9ace3..2646aaf 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1738,6 +1738,21 @@ static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
 
     gen_store_fpr_D(dc, rd, dst);
 }
+
+static inline void gen_ne_fop_DDDD(DisasContext *dc, int rd, int rs1, int rs2,
+                           void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src0, src1, src2;
+
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+    src0 = gen_load_fpr_D(dc, rd);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, src0, src1, src2);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
 #endif
 
 static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
@@ -4059,9 +4074,11 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x03a: /* VIS I fpack32 */
                 case 0x03b: /* VIS I fpack16 */
                 case 0x03d: /* VIS I fpackfix */
-                case 0x03e: /* VIS I pdist */
-                    // XXX
                     goto illegal_insn;
+                case 0x03e: /* VIS I pdist */
+                    CHECK_FPU_FEATURE(dc, VIS1);
+                    gen_ne_fop_DDDD(dc, rd, rs1, rs2, gen_helper_pdist);
+                    break;
                 case 0x048: /* VIS I faligndata */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index 39c8d9a..cd5d4a7 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -396,3 +396,24 @@ VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
 VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
 VIS_CMPHELPER(helper_fcmple, FCMPLE)
 VIS_CMPHELPER(helper_fcmpne, FCMPNE)
+
+uint64_t helper_pdist(uint64_t sum, uint64_t src1, uint64_t src2)
+{
+    int i;
+    for (i = 0; i < 8; i++) {
+        int s1, s2;
+
+        s1 = (src1 >> (56 - (i * 8))) & 0xff;
+        s2 = (src2 >> (56 - (i * 8))) & 0xff;
+
+        /* Absolute value of difference. */
+        s1 -= s2;
+        if (s1 < 0) {
+            s1 = -s1;
+        }
+
+        sum += s1;
+    }
+
+    return sum;
+}
commit 445167723d12d6e14d4f11b4104c48c8b25329db
Author: Richard Henderson <rth at twiddle.net>
Date:   Mon Oct 17 11:25:56 2011 -0700

    target-sparc: Do exceptions management fully inside the helpers.
    
    This reduces the size of the individual translation blocks, since
    we only emit a single call for each FOP rather than three.  In
    addition, clear_float_exceptions expands inline to a single byte store.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
index e652021..c7a2512 100644
--- a/target-sparc/fop_helper.c
+++ b/target-sparc/fop_helper.c
@@ -23,22 +23,71 @@
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
 
+static void check_ieee_exceptions(CPUState *env)
+{
+    target_ulong status;
+
+    status = get_float_exception_flags(&env->fp_status);
+    if (status) {
+        /* Copy IEEE 754 flags into FSR */
+        if (status & float_flag_invalid) {
+            env->fsr |= FSR_NVC;
+        }
+        if (status & float_flag_overflow) {
+            env->fsr |= FSR_OFC;
+        }
+        if (status & float_flag_underflow) {
+            env->fsr |= FSR_UFC;
+        }
+        if (status & float_flag_divbyzero) {
+            env->fsr |= FSR_DZC;
+        }
+        if (status & float_flag_inexact) {
+            env->fsr |= FSR_NXC;
+        }
+
+        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
+            /* Unmasked exception, generate a trap */
+            env->fsr |= FSR_FTT_IEEE_EXCP;
+            helper_raise_exception(env, TT_FP_EXCP);
+        } else {
+            /* Accumulate exceptions */
+            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+        }
+    }
+}
+
+static inline void clear_float_exceptions(CPUState *env)
+{
+    set_float_exception_flags(0, &env->fp_status);
+}
+
 #define F_HELPER(name, p) void helper_f##name##p(CPUState *env)
 
 #define F_BINOP(name)                                           \
-    float32 helper_f ## name ## s (CPUState * env, float32 src1,\
+    float32 helper_f ## name ## s (CPUState *env, float32 src1, \
                                    float32 src2)                \
     {                                                           \
-        return float32_ ## name (src1, src2, &env->fp_status);  \
+        float32 ret;                                            \
+        clear_float_exceptions(env);                            \
+        ret = float32_ ## name (src1, src2, &env->fp_status);   \
+        check_ieee_exceptions(env);                             \
+        return ret;                                             \
     }                                                           \
     float64 helper_f ## name ## d (CPUState * env, float64 src1,\
                                    float64 src2)                \
     {                                                           \
-        return float64_ ## name (src1, src2, &env->fp_status);  \
+        float64 ret;                                            \
+        clear_float_exceptions(env);                            \
+        ret = float64_ ## name (src1, src2, &env->fp_status);   \
+        check_ieee_exceptions(env);                             \
+        return ret;                                             \
     }                                                           \
     F_HELPER(name, q)                                           \
     {                                                           \
+        clear_float_exceptions(env);                            \
         QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
+        check_ieee_exceptions(env);                             \
     }
 
 F_BINOP(add);
@@ -49,16 +98,22 @@ F_BINOP(div);
 
 float64 helper_fsmuld(CPUState *env, float32 src1, float32 src2)
 {
-    return float64_mul(float32_to_float64(src1, &env->fp_status),
-                       float32_to_float64(src2, &env->fp_status),
-                       &env->fp_status);
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = float64_mul(float32_to_float64(src1, &env->fp_status),
+                      float32_to_float64(src2, &env->fp_status),
+                      &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 void helper_fdmulq(CPUState *env, float64 src1, float64 src2)
 {
+    clear_float_exceptions(env);
     QT0 = float128_mul(float64_to_float128(src1, &env->fp_status),
                        float64_to_float128(src2, &env->fp_status),
                        &env->fp_status);
+    check_ieee_exceptions(env);
 }
 
 float32 helper_fnegs(float32 src)
@@ -81,32 +136,48 @@ F_HELPER(neg, q)
 /* Integer to float conversion.  */
 float32 helper_fitos(CPUState *env, int32_t src)
 {
-    return int32_to_float32(src, &env->fp_status);
+    /* Inexact error possible converting int to float.  */
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = int32_to_float32(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 float64 helper_fitod(CPUState *env, int32_t src)
 {
+    /* No possible exceptions converting int to double.  */
     return int32_to_float64(src, &env->fp_status);
 }
 
 void helper_fitoq(CPUState *env, int32_t src)
 {
+    /* No possible exceptions converting int to long double.  */
     QT0 = int32_to_float128(src, &env->fp_status);
 }
 
 #ifdef TARGET_SPARC64
 float32 helper_fxtos(CPUState *env, int64_t src)
 {
-    return int64_to_float32(src, &env->fp_status);
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = int64_to_float32(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 float64 helper_fxtod(CPUState *env, int64_t src)
 {
-    return int64_to_float64(src, &env->fp_status);
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = int64_to_float64(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 void helper_fxtoq(CPUState *env, int64_t src)
 {
+    /* No possible exceptions converting long long to long double.  */
     QT0 = int64_to_float128(src, &env->fp_status);
 }
 #endif
@@ -115,64 +186,108 @@ void helper_fxtoq(CPUState *env, int64_t src)
 /* floating point conversion */
 float32 helper_fdtos(CPUState *env, float64 src)
 {
-    return float64_to_float32(src, &env->fp_status);
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = float64_to_float32(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 float64 helper_fstod(CPUState *env, float32 src)
 {
-    return float32_to_float64(src, &env->fp_status);
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = float32_to_float64(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 float32 helper_fqtos(CPUState *env)
 {
-    return float128_to_float32(QT1, &env->fp_status);
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = float128_to_float32(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 void helper_fstoq(CPUState *env, float32 src)
 {
+    clear_float_exceptions(env);
     QT0 = float32_to_float128(src, &env->fp_status);
+    check_ieee_exceptions(env);
 }
 
 float64 helper_fqtod(CPUState *env)
 {
-    return float128_to_float64(QT1, &env->fp_status);
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = float128_to_float64(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 void helper_fdtoq(CPUState *env, float64 src)
 {
+    clear_float_exceptions(env);
     QT0 = float64_to_float128(src, &env->fp_status);
+    check_ieee_exceptions(env);
 }
 
 /* Float to integer conversion.  */
 int32_t helper_fstoi(CPUState *env, float32 src)
 {
-    return float32_to_int32_round_to_zero(src, &env->fp_status);
+    int32_t ret;
+    clear_float_exceptions(env);
+    ret = float32_to_int32_round_to_zero(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 int32_t helper_fdtoi(CPUState *env, float64 src)
 {
-    return float64_to_int32_round_to_zero(src, &env->fp_status);
+    int32_t ret;
+    clear_float_exceptions(env);
+    ret = float64_to_int32_round_to_zero(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 int32_t helper_fqtoi(CPUState *env)
 {
-    return float128_to_int32_round_to_zero(QT1, &env->fp_status);
+    int32_t ret;
+    clear_float_exceptions(env);
+    ret = float128_to_int32_round_to_zero(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 #ifdef TARGET_SPARC64
 int64_t helper_fstox(CPUState *env, float32 src)
 {
-    return float32_to_int64_round_to_zero(src, &env->fp_status);
+    int64_t ret;
+    clear_float_exceptions(env);
+    ret = float32_to_int64_round_to_zero(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 int64_t helper_fdtox(CPUState *env, float64 src)
 {
-    return float64_to_int64_round_to_zero(src, &env->fp_status);
+    int64_t ret;
+    clear_float_exceptions(env);
+    ret = float64_to_int64_round_to_zero(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 int64_t helper_fqtox(CPUState *env)
 {
-    return float128_to_int64_round_to_zero(QT1, &env->fp_status);
+    int64_t ret;
+    clear_float_exceptions(env);
+    ret = float128_to_int64_round_to_zero(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 #endif
 
@@ -195,17 +310,27 @@ void helper_fabsq(CPUState *env)
 
 float32 helper_fsqrts(CPUState *env, float32 src)
 {
-    return float32_sqrt(src, &env->fp_status);
+    float32 ret;
+    clear_float_exceptions(env);
+    ret = float32_sqrt(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 float64 helper_fsqrtd(CPUState *env, float64 src)
 {
-    return float64_sqrt(src, &env->fp_status);
+    float64 ret;
+    clear_float_exceptions(env);
+    ret = float64_sqrt(src, &env->fp_status);
+    check_ieee_exceptions(env);
+    return ret;
 }
 
 void helper_fsqrtq(CPUState *env)
 {
+    clear_float_exceptions(env);
     QT0 = float128_sqrt(QT1, &env->fp_status);
+    check_ieee_exceptions(env);
 }
 
 #define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
@@ -318,45 +443,6 @@ GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
 #undef GEN_FCMP_T
 #undef GEN_FCMP
 
-void helper_check_ieee_exceptions(CPUState *env)
-{
-    target_ulong status;
-
-    status = get_float_exception_flags(&env->fp_status);
-    if (status) {
-        /* Copy IEEE 754 flags into FSR */
-        if (status & float_flag_invalid) {
-            env->fsr |= FSR_NVC;
-        }
-        if (status & float_flag_overflow) {
-            env->fsr |= FSR_OFC;
-        }
-        if (status & float_flag_underflow) {
-            env->fsr |= FSR_UFC;
-        }
-        if (status & float_flag_divbyzero) {
-            env->fsr |= FSR_DZC;
-        }
-        if (status & float_flag_inexact) {
-            env->fsr |= FSR_NXC;
-        }
-
-        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
-            /* Unmasked exception, generate a trap */
-            env->fsr |= FSR_FTT_IEEE_EXCP;
-            helper_raise_exception(env, TT_FP_EXCP);
-        } else {
-            /* Accumulate exceptions */
-            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
-        }
-    }
-}
-
-void helper_clear_float_exceptions(CPUState *env)
-{
-    set_float_exception_flags(0, &env->fp_status);
-}
-
 static inline void set_fsr(CPUState *env)
 {
     int rnd_mode;
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index ba0ad81..22fb8ef 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -46,8 +46,6 @@ DEF_HELPER_4(ld_asi, i64, tl, int, int, int)
 DEF_HELPER_4(st_asi, void, tl, i64, int, int)
 #endif
 DEF_HELPER_2(ldfsr, void, env, i32)
-DEF_HELPER_1(check_ieee_exceptions, void, env)
-DEF_HELPER_1(clear_float_exceptions, void, env)
 DEF_HELPER_FLAGS_1(fabss, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32)
 DEF_HELPER_2(fsqrts, f32, env, f32)
 DEF_HELPER_2(fsqrtd, f64, env, f64)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 2c123b1..0b9ace3 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1626,23 +1626,16 @@ static inline void gen_op_clear_ieee_excp_and_FTT(void)
     tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK);
 }
 
-static inline void gen_clear_float_exceptions(void)
-{
-    gen_helper_clear_float_exceptions(cpu_env);
-}
-
 static inline void gen_fop_FF(DisasContext *dc, int rd, int rs,
                               void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32))
 {
     TCGv_i32 dst, src;
 
-    gen_clear_float_exceptions();
     src = gen_load_fpr_F(dc, rs);
     dst = gen_dest_fpr_F();
 
     gen(dst, cpu_env, src);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_F(dc, rd, dst);
 }
 
@@ -1664,14 +1657,12 @@ static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
 {
     TCGv_i32 dst, src1, src2;
 
-    gen_clear_float_exceptions();
     src1 = gen_load_fpr_F(dc, rs1);
     src2 = gen_load_fpr_F(dc, rs2);
     dst = gen_dest_fpr_F();
 
     gen(dst, cpu_env, src1, src2);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_F(dc, rd, dst);
 }
 
@@ -1696,13 +1687,11 @@ static inline void gen_fop_DD(DisasContext *dc, int rd, int rs,
 {
     TCGv_i64 dst, src;
 
-    gen_clear_float_exceptions();
     src = gen_load_fpr_D(dc, rs);
     dst = gen_dest_fpr_D();
 
     gen(dst, cpu_env, src);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_D(dc, rd, dst);
 }
 
@@ -1726,14 +1715,12 @@ static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
 {
     TCGv_i64 dst, src1, src2;
 
-    gen_clear_float_exceptions();
     src1 = gen_load_fpr_D(dc, rs1);
     src2 = gen_load_fpr_D(dc, rs2);
     dst = gen_dest_fpr_D();
 
     gen(dst, cpu_env, src1, src2);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_D(dc, rd, dst);
 }
 
@@ -1756,12 +1743,10 @@ static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
 static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
                               void (*gen)(TCGv_ptr))
 {
-    gen_clear_float_exceptions();
     gen_op_load_fpr_QT1(QFPREG(rs));
 
     gen(cpu_env);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_op_store_QT0_fpr(QFPREG(rd));
     gen_update_fprs_dirty(QFPREG(rd));
 }
@@ -1782,13 +1767,11 @@ static inline void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs,
 static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
                                void (*gen)(TCGv_ptr))
 {
-    gen_clear_float_exceptions();
     gen_op_load_fpr_QT0(QFPREG(rs1));
     gen_op_load_fpr_QT1(QFPREG(rs2));
 
     gen(cpu_env);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_op_store_QT0_fpr(QFPREG(rd));
     gen_update_fprs_dirty(QFPREG(rd));
 }
@@ -1799,14 +1782,12 @@ static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
     TCGv_i64 dst;
     TCGv_i32 src1, src2;
 
-    gen_clear_float_exceptions();
     src1 = gen_load_fpr_F(dc, rs1);
     src2 = gen_load_fpr_F(dc, rs2);
     dst = gen_dest_fpr_D();
 
     gen(dst, cpu_env, src1, src2);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_D(dc, rd, dst);
 }
 
@@ -1815,13 +1796,11 @@ static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
 {
     TCGv_i64 src1, src2;
 
-    gen_clear_float_exceptions();
     src1 = gen_load_fpr_D(dc, rs1);
     src2 = gen_load_fpr_D(dc, rs2);
 
     gen(cpu_env, src1, src2);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_op_store_QT0_fpr(QFPREG(rd));
     gen_update_fprs_dirty(QFPREG(rd));
 }
@@ -1833,13 +1812,11 @@ static inline void gen_fop_DF(DisasContext *dc, int rd, int rs,
     TCGv_i64 dst;
     TCGv_i32 src;
 
-    gen_clear_float_exceptions();
     src = gen_load_fpr_F(dc, rs);
     dst = gen_dest_fpr_D();
 
     gen(dst, cpu_env, src);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_D(dc, rd, dst);
 }
 #endif
@@ -1864,13 +1841,11 @@ static inline void gen_fop_FD(DisasContext *dc, int rd, int rs,
     TCGv_i32 dst;
     TCGv_i64 src;
 
-    gen_clear_float_exceptions();
     src = gen_load_fpr_D(dc, rs);
     dst = gen_dest_fpr_F();
 
     gen(dst, cpu_env, src);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_F(dc, rd, dst);
 }
 
@@ -1879,13 +1854,11 @@ static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs,
 {
     TCGv_i32 dst;
 
-    gen_clear_float_exceptions();
     gen_op_load_fpr_QT1(QFPREG(rs));
     dst = gen_dest_fpr_F();
 
     gen(dst, cpu_env);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_F(dc, rd, dst);
 }
 
@@ -1894,13 +1867,11 @@ static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs,
 {
     TCGv_i64 dst;
 
-    gen_clear_float_exceptions();
     gen_op_load_fpr_QT1(QFPREG(rs));
     dst = gen_dest_fpr_D();
 
     gen(dst, cpu_env);
 
-    gen_helper_check_ieee_exceptions(cpu_env);
     gen_store_fpr_D(dc, rd, dst);
 }
 
commit 30038fd81808f7c3bca92be2369e74c8ca7b3d69
Author: Richard Henderson <rth at twiddle.net>
Date:   Mon Oct 17 10:42:49 2011 -0700

    target-sparc: Change fpr representation to doubles.
    
    This allows a more efficient representation for 64-bit hosts.
    It should be about the same for 32-bit hosts, as we can still
    access the individual pieces of the double.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/gdbstub.c b/gdbstub.c
index 4009058..a25f404 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -814,7 +814,11 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 #if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
     if (n < 64) {
         /* fprs */
-        GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
+        if (n & 1) {
+            GET_REG32(env->fpr[(n - 32) / 2].l.lower);
+        } else {
+            GET_REG32(env->fpr[(n - 32) / 2].l.upper);
+        }
     }
     /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
     switch (n) {
@@ -831,15 +835,15 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 #else
     if (n < 64) {
         /* f0-f31 */
-        GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
+        if (n & 1) {
+            GET_REG32(env->fpr[(n - 32) / 2].l.lower);
+        } else {
+            GET_REG32(env->fpr[(n - 32) / 2].l.upper);
+        }
     }
     if (n < 80) {
         /* f32-f62 (double width, even numbers only) */
-        uint64_t val;
-
-        val = (uint64_t)*((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) << 32;
-        val |= *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]);
-        GET_REG64(val);
+        GET_REG64(env->fpr[(n - 32) / 2].ll);
     }
     switch (n) {
     case 80: GET_REGL(env->pc);
@@ -878,7 +882,12 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 #if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
     else if (n < 64) {
         /* fprs */
-        *((uint32_t *)&env->fpr[n - 32]) = tmp;
+        /* f0-f31 */
+        if (n & 1) {
+            env->fpr[(n - 32) / 2].l.lower = tmp;
+        } else {
+            env->fpr[(n - 32) / 2].l.upper = tmp;
+        }
     } else {
         /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
         switch (n) {
@@ -896,12 +905,16 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 #else
     else if (n < 64) {
         /* f0-f31 */
-        env->fpr[n] = ldfl_p(mem_buf);
+        tmp = ldl_p(mem_buf);
+        if (n & 1) {
+            env->fpr[(n - 32) / 2].l.lower = tmp;
+        } else {
+            env->fpr[(n - 32) / 2].l.upper = tmp;
+        }
         return 4;
     } else if (n < 80) {
         /* f32-f62 (double width, even numbers only) */
-        *((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) = tmp >> 32;
-        *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]) = tmp;
+        env->fpr[(n - 32) / 2].ll = tmp;
     } else {
         switch (n) {
         case 80: env->pc = tmp; break;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 40c5eb1..f3b767e 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -2296,12 +2296,14 @@ void sparc64_set_context(CPUSPARCState *env)
      */
     err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
     {
-        uint32_t *src, *dst;
-        src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
-        dst = env->fpr;
-        /* XXX: check that the CPU storage is the same as user context */
-        for (i = 0; i < 64; i++, dst++, src++)
-            err |= __get_user(*dst, src);
+        uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
+        for (i = 0; i < 64; i++, src++) {
+            if (i & 1) {
+                err |= __get_user(env->fpr[i/2].l.lower, src);
+            } else {
+                err |= __get_user(env->fpr[i/2].l.upper, src);
+            }
+        }
     }
     err |= __get_user(env->fsr,
                       &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
@@ -2390,12 +2392,14 @@ void sparc64_get_context(CPUSPARCState *env)
     err |= __put_user(i7, &(mcp->mc_i7));
 
     {
-        uint32_t *src, *dst;
-        src = env->fpr;
-        dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
-        /* XXX: check that the CPU storage is the same as user context */
-        for (i = 0; i < 64; i++, dst++, src++)
-            err |= __put_user(*src, dst);
+        uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
+        for (i = 0; i < 64; i++, dst++) {
+            if (i & 1) {
+                err |= __put_user(env->fpr[i/2].l.lower, dst);
+            } else {
+                err |= __put_user(env->fpr[i/2].l.upper, dst);
+            }
+        }
     }
     err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
     err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
diff --git a/monitor.c b/monitor.c
index ffda0fe..d13bd15 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3471,55 +3471,55 @@ static const MonitorDef monitor_defs[] = {
 #endif
     { "tbr", offsetof(CPUState, tbr) },
     { "fsr", offsetof(CPUState, fsr) },
-    { "f0", offsetof(CPUState, fpr[0]) },
-    { "f1", offsetof(CPUState, fpr[1]) },
-    { "f2", offsetof(CPUState, fpr[2]) },
-    { "f3", offsetof(CPUState, fpr[3]) },
-    { "f4", offsetof(CPUState, fpr[4]) },
-    { "f5", offsetof(CPUState, fpr[5]) },
-    { "f6", offsetof(CPUState, fpr[6]) },
-    { "f7", offsetof(CPUState, fpr[7]) },
-    { "f8", offsetof(CPUState, fpr[8]) },
-    { "f9", offsetof(CPUState, fpr[9]) },
-    { "f10", offsetof(CPUState, fpr[10]) },
-    { "f11", offsetof(CPUState, fpr[11]) },
-    { "f12", offsetof(CPUState, fpr[12]) },
-    { "f13", offsetof(CPUState, fpr[13]) },
-    { "f14", offsetof(CPUState, fpr[14]) },
-    { "f15", offsetof(CPUState, fpr[15]) },
-    { "f16", offsetof(CPUState, fpr[16]) },
-    { "f17", offsetof(CPUState, fpr[17]) },
-    { "f18", offsetof(CPUState, fpr[18]) },
-    { "f19", offsetof(CPUState, fpr[19]) },
-    { "f20", offsetof(CPUState, fpr[20]) },
-    { "f21", offsetof(CPUState, fpr[21]) },
-    { "f22", offsetof(CPUState, fpr[22]) },
-    { "f23", offsetof(CPUState, fpr[23]) },
-    { "f24", offsetof(CPUState, fpr[24]) },
-    { "f25", offsetof(CPUState, fpr[25]) },
-    { "f26", offsetof(CPUState, fpr[26]) },
-    { "f27", offsetof(CPUState, fpr[27]) },
-    { "f28", offsetof(CPUState, fpr[28]) },
-    { "f29", offsetof(CPUState, fpr[29]) },
-    { "f30", offsetof(CPUState, fpr[30]) },
-    { "f31", offsetof(CPUState, fpr[31]) },
+    { "f0", offsetof(CPUState, fpr[0].l.upper) },
+    { "f1", offsetof(CPUState, fpr[0].l.lower) },
+    { "f2", offsetof(CPUState, fpr[1].l.upper) },
+    { "f3", offsetof(CPUState, fpr[1].l.lower) },
+    { "f4", offsetof(CPUState, fpr[2].l.upper) },
+    { "f5", offsetof(CPUState, fpr[2].l.lower) },
+    { "f6", offsetof(CPUState, fpr[3].l.upper) },
+    { "f7", offsetof(CPUState, fpr[3].l.lower) },
+    { "f8", offsetof(CPUState, fpr[4].l.upper) },
+    { "f9", offsetof(CPUState, fpr[4].l.lower) },
+    { "f10", offsetof(CPUState, fpr[5].l.upper) },
+    { "f11", offsetof(CPUState, fpr[5].l.lower) },
+    { "f12", offsetof(CPUState, fpr[6].l.upper) },
+    { "f13", offsetof(CPUState, fpr[6].l.lower) },
+    { "f14", offsetof(CPUState, fpr[7].l.upper) },
+    { "f15", offsetof(CPUState, fpr[7].l.lower) },
+    { "f16", offsetof(CPUState, fpr[8].l.upper) },
+    { "f17", offsetof(CPUState, fpr[8].l.lower) },
+    { "f18", offsetof(CPUState, fpr[9].l.upper) },
+    { "f19", offsetof(CPUState, fpr[9].l.lower) },
+    { "f20", offsetof(CPUState, fpr[10].l.upper) },
+    { "f21", offsetof(CPUState, fpr[10].l.lower) },
+    { "f22", offsetof(CPUState, fpr[11].l.upper) },
+    { "f23", offsetof(CPUState, fpr[11].l.lower) },
+    { "f24", offsetof(CPUState, fpr[12].l.upper) },
+    { "f25", offsetof(CPUState, fpr[12].l.lower) },
+    { "f26", offsetof(CPUState, fpr[13].l.upper) },
+    { "f27", offsetof(CPUState, fpr[13].l.lower) },
+    { "f28", offsetof(CPUState, fpr[14].l.upper) },
+    { "f29", offsetof(CPUState, fpr[14].l.lower) },
+    { "f30", offsetof(CPUState, fpr[15].l.upper) },
+    { "f31", offsetof(CPUState, fpr[15].l.lower) },
 #ifdef TARGET_SPARC64
-    { "f32", offsetof(CPUState, fpr[32]) },
-    { "f34", offsetof(CPUState, fpr[34]) },
-    { "f36", offsetof(CPUState, fpr[36]) },
-    { "f38", offsetof(CPUState, fpr[38]) },
-    { "f40", offsetof(CPUState, fpr[40]) },
-    { "f42", offsetof(CPUState, fpr[42]) },
-    { "f44", offsetof(CPUState, fpr[44]) },
-    { "f46", offsetof(CPUState, fpr[46]) },
-    { "f48", offsetof(CPUState, fpr[48]) },
-    { "f50", offsetof(CPUState, fpr[50]) },
-    { "f52", offsetof(CPUState, fpr[52]) },
-    { "f54", offsetof(CPUState, fpr[54]) },
-    { "f56", offsetof(CPUState, fpr[56]) },
-    { "f58", offsetof(CPUState, fpr[58]) },
-    { "f60", offsetof(CPUState, fpr[60]) },
-    { "f62", offsetof(CPUState, fpr[62]) },
+    { "f32", offsetof(CPUState, fpr[16]) },
+    { "f34", offsetof(CPUState, fpr[17]) },
+    { "f36", offsetof(CPUState, fpr[18]) },
+    { "f38", offsetof(CPUState, fpr[19]) },
+    { "f40", offsetof(CPUState, fpr[20]) },
+    { "f42", offsetof(CPUState, fpr[21]) },
+    { "f44", offsetof(CPUState, fpr[22]) },
+    { "f46", offsetof(CPUState, fpr[23]) },
+    { "f48", offsetof(CPUState, fpr[24]) },
+    { "f50", offsetof(CPUState, fpr[25]) },
+    { "f52", offsetof(CPUState, fpr[26]) },
+    { "f54", offsetof(CPUState, fpr[27]) },
+    { "f56", offsetof(CPUState, fpr[28]) },
+    { "f58", offsetof(CPUState, fpr[29]) },
+    { "f60", offsetof(CPUState, fpr[30]) },
+    { "f62", offsetof(CPUState, fpr[31]) },
     { "asi", offsetof(CPUState, asi) },
     { "pstate", offsetof(CPUState, pstate) },
     { "cansave", offsetof(CPUState, cansave) },
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 4eace33..38a7074 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -3,16 +3,17 @@
 
 #include "config.h"
 #include "qemu-common.h"
+#include "bswap.h"
 
 #if !defined(TARGET_SPARC64)
 #define TARGET_LONG_BITS 32
-#define TARGET_FPREGS 32
+#define TARGET_DPREGS 16
 #define TARGET_PAGE_BITS 12 /* 4k */
 #define TARGET_PHYS_ADDR_SPACE_BITS 36
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
 #else
 #define TARGET_LONG_BITS 64
-#define TARGET_FPREGS 64
+#define TARGET_DPREGS 32
 #define TARGET_PAGE_BITS 13 /* 8k */
 #define TARGET_PHYS_ADDR_SPACE_BITS 41
 # ifdef TARGET_ABI32
@@ -395,7 +396,7 @@ typedef struct CPUSPARCState {
 
     uint32_t psr;      /* processor state register */
     target_ulong fsr;      /* FPU state register */
-    float32 fpr[TARGET_FPREGS];  /* floating point registers */
+    CPU_DoubleU fpr[TARGET_DPREGS];  /* floating point registers */
     uint32_t cwp;      /* index of current register window (extracted
                           from PSR) */
 #if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c
index 6954800..c7269b5 100644
--- a/target-sparc/cpu_init.c
+++ b/target-sparc/cpu_init.c
@@ -813,11 +813,11 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
         }
     }
     cpu_fprintf(f, "\nFloating Point Registers:\n");
-    for (i = 0; i < TARGET_FPREGS; i++) {
+    for (i = 0; i < TARGET_DPREGS; i++) {
         if ((i & 3) == 0) {
-            cpu_fprintf(f, "%%f%02d:", i);
+            cpu_fprintf(f, "%%f%02d:", i * 2);
         }
-        cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
+        cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll);
         if ((i & 3) == 3) {
             cpu_fprintf(f, "\n");
         }
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 80e5408..b59707e 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -2045,7 +2045,7 @@ void helper_ldda_asi(target_ulong addr, int asi, int rd)
 void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
 {
     unsigned int i;
-    CPU_DoubleU u;
+    target_ulong val;
 
     helper_check_align(addr, 3);
     addr = asi_address_mask(env, asi, addr);
@@ -2060,13 +2060,11 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
             return;
         }
         helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
-                                                         0);
-            addr += 4;
+        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
+            env->fpr[rd/2].ll = helper_ld_asi(addr, asi & 0x8f, 8, 0);
         }
-
         return;
+
     case 0x16: /* UA2007 Block load primary, user privilege */
     case 0x17: /* UA2007 Block load secondary, user privilege */
     case 0x1e: /* UA2007 Block load primary LE, user privilege */
@@ -2080,13 +2078,11 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
             return;
         }
         helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4,
-                                                         0);
-            addr += 4;
+        for (i = 0; i < 8; i++, rd += 2, addr += 4) {
+            env->fpr[rd/2].ll = helper_ld_asi(addr, asi & 0x19, 8, 0);
         }
-
         return;
+
     default:
         break;
     }
@@ -2094,20 +2090,19 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
     switch (size) {
     default:
     case 4:
-        *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
+        val = helper_ld_asi(addr, asi, size, 0);
+        if (rd & 1) {
+            env->fpr[rd/2].l.lower = val;
+        } else {
+            env->fpr[rd/2].l.upper = val;
+        }
         break;
     case 8:
-        u.ll = helper_ld_asi(addr, asi, size, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        env->fpr[rd/2].ll = helper_ld_asi(addr, asi, size, 0);
         break;
     case 16:
-        u.ll = helper_ld_asi(addr, asi, 8, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
-        u.ll = helper_ld_asi(addr + 8, asi, 8, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        env->fpr[rd/2].ll = helper_ld_asi(addr, asi, 8, 0);
+        env->fpr[rd/2 + 1].ll = helper_ld_asi(addr + 8, asi, 8, 0);
         break;
     }
 }
@@ -2115,8 +2110,7 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
 void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
 {
     unsigned int i;
-    target_ulong val = 0;
-    CPU_DoubleU u;
+    target_ulong val;
 
     helper_check_align(addr, 3);
     addr = asi_address_mask(env, asi, addr);
@@ -2133,10 +2127,8 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
             return;
         }
         helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            val = *(uint32_t *)&env->fpr[rd++];
-            helper_st_asi(addr, val, asi & 0x8f, 4);
-            addr += 4;
+        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
+            helper_st_asi(addr, env->fpr[rd/2].ll, asi & 0x8f, 8);
         }
 
         return;
@@ -2153,10 +2145,8 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
             return;
         }
         helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            val = *(uint32_t *)&env->fpr[rd++];
-            helper_st_asi(addr, val, asi & 0x19, 4);
-            addr += 4;
+        for (i = 0; i < 8; i++, rd += 2, addr += 8) {
+            helper_st_asi(addr, env->fpr[rd/2].ll, asi & 0x19, 8);
         }
 
         return;
@@ -2167,20 +2157,19 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
     switch (size) {
     default:
     case 4:
-        helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
+        if (rd & 1) {
+            val = env->fpr[rd/2].l.lower;
+        } else {
+            val = env->fpr[rd/2].l.upper;
+        }
+        helper_st_asi(addr, val, asi, size);
         break;
     case 8:
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr, u.ll, asi, size);
+        helper_st_asi(addr, env->fpr[rd/2].ll, asi, size);
         break;
     case 16:
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr, u.ll, asi, 8);
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr + 8, u.ll, asi, 8);
+        helper_st_asi(addr, env->fpr[rd/2].ll, asi, 8);
+        helper_st_asi(addr + 8, env->fpr[rd/2 + 1].ll, asi, 8);
         break;
     }
 }
diff --git a/target-sparc/machine.c b/target-sparc/machine.c
index 56ae041..235b088 100644
--- a/target-sparc/machine.c
+++ b/target-sparc/machine.c
@@ -21,13 +21,9 @@ void cpu_save(QEMUFile *f, void *opaque)
         qemu_put_betls(f, &env->regbase[i]);
 
     /* FPU */
-    for(i = 0; i < TARGET_FPREGS; i++) {
-        union {
-            float32 f;
-            uint32_t i;
-        } u;
-        u.f = env->fpr[i];
-        qemu_put_be32(f, u.i);
+    for (i = 0; i < TARGET_DPREGS; i++) {
+        qemu_put_be32(f, env->fpr[i].l.upper);
+        qemu_put_be32(f, env->fpr[i].l.lower);
     }
 
     qemu_put_betls(f, &env->pc);
@@ -128,13 +124,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         qemu_get_betls(f, &env->regbase[i]);
 
     /* FPU */
-    for(i = 0; i < TARGET_FPREGS; i++) {
-        union {
-            float32 f;
-            uint32_t i;
-        } u;
-        u.i = qemu_get_be32(f);
-        env->fpr[i] = u.f;
+    for (i = 0; i < TARGET_DPREGS; i++) {
+        env->fpr[i].l.upper = qemu_get_be32(f);
+        env->fpr[i].l.lower = qemu_get_be32(f);
     }
 
     qemu_get_betls(f, &env->pc);
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 0b95b64..2c123b1 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -63,7 +63,7 @@ static TCGv cpu_tmp0;
 static TCGv_i32 cpu_tmp32;
 static TCGv_i64 cpu_tmp64;
 /* Floating point registers */
-static TCGv_i32 cpu_fpr[TARGET_FPREGS];
+static TCGv_i64 cpu_fpr[TARGET_DPREGS];
 
 static target_ulong gen_opc_npc[OPC_BUF_SIZE];
 static target_ulong gen_opc_jump_pc[2];
@@ -82,8 +82,8 @@ typedef struct DisasContext {
     uint32_t cc_op;  /* current CC operation */
     struct TranslationBlock *tb;
     sparc_def_t *def;
-    TCGv_i64 t64[3];
-    int n_t64;
+    TCGv_i32 t32[3];
+    int n_t32;
 } DisasContext;
 
 // This function uses non-native bit order
@@ -126,12 +126,44 @@ static inline void gen_update_fprs_dirty(int rd)
 /* floating point registers moves */
 static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src)
 {
-    return cpu_fpr[src];
+#if TCG_TARGET_REG_BITS == 32
+    if (src & 1) {
+        return TCGV_LOW(cpu_fpr[src / 2]);
+    } else {
+        return TCGV_HIGH(cpu_fpr[src / 2]);
+    }
+#else
+    if (src & 1) {
+        return MAKE_TCGV_I32(GET_TCGV_I64(cpu_fpr[src / 2]));
+    } else {
+        TCGv_i32 ret = tcg_temp_local_new_i32();
+        TCGv_i64 t = tcg_temp_new_i64();
+
+        tcg_gen_shri_i64(t, cpu_fpr[src / 2], 32);
+        tcg_gen_trunc_i64_i32(ret, t);
+        tcg_temp_free_i64(t);
+
+        dc->t32[dc->n_t32++] = ret;
+        assert(dc->n_t32 <= ARRAY_SIZE(dc->t32));
+
+        return ret;
+    }
+#endif
 }
 
 static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
 {
-    tcg_gen_mov_i32(cpu_fpr[dst], v);
+#if TCG_TARGET_REG_BITS == 32
+    if (dst & 1) {
+        tcg_gen_mov_i32(TCGV_LOW(cpu_fpr[dst / 2]), v);
+    } else {
+        tcg_gen_mov_i32(TCGV_HIGH(cpu_fpr[dst / 2]), v);
+    }
+#else
+    TCGv_i64 t = MAKE_TCGV_I64(GET_TCGV_I32(v));
+    tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t,
+                        (dst & 1 ? 0 : 32), 32);
+#endif
     gen_update_fprs_dirty(dst);
 }
 
@@ -142,42 +174,14 @@ static TCGv_i32 gen_dest_fpr_F(void)
 
 static TCGv_i64 gen_load_fpr_D(DisasContext *dc, unsigned int src)
 {
-    TCGv_i64 ret = tcg_temp_new_i64();
     src = DFPREG(src);
-
-#if TCG_TARGET_REG_BITS == 32
-    tcg_gen_mov_i32(TCGV_HIGH(ret), cpu_fpr[src]);
-    tcg_gen_mov_i32(TCGV_LOW(ret), cpu_fpr[src + 1]);
-#else
-    {
-        TCGv_i64 t = tcg_temp_new_i64();
-        tcg_gen_extu_i32_i64(ret, cpu_fpr[src]);
-        tcg_gen_extu_i32_i64(t, cpu_fpr[src + 1]);
-        tcg_gen_shli_i64(ret, ret, 32);
-        tcg_gen_or_i64(ret, ret, t);
-        tcg_temp_free_i64(t);
-    }
-#endif
-
-    dc->t64[dc->n_t64++] = ret;
-    assert(dc->n_t64 <= ARRAY_SIZE(dc->t64));
-
-    return ret;
+    return cpu_fpr[src / 2];
 }
 
 static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v)
 {
     dst = DFPREG(dst);
-
-#if TCG_TARGET_REG_BITS == 32
-    tcg_gen_mov_i32(cpu__fpu[dst], TCGV_HIGH(v));
-    tcg_gen_mov_i32(cpu__fpu[dst + 1], TCGV_LOW(v));
-#else
-    tcg_gen_trunc_i64_i32(cpu_fpr[dst + 1], v);
-    tcg_gen_shri_i64(v, v, 32);
-    tcg_gen_trunc_i64_i32(cpu_fpr[dst], v);
-#endif
-
+    tcg_gen_mov_i64(cpu_fpr[dst / 2], v);
     gen_update_fprs_dirty(dst);
 }
 
@@ -188,50 +192,36 @@ static TCGv_i64 gen_dest_fpr_D(void)
 
 static void gen_op_load_fpr_QT0(unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.lower));
-    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.lowest));
+    tcg_gen_st_i64(cpu_fpr[src / 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, ll.upper));
+    tcg_gen_st_i64(cpu_fpr[src/2 + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, ll.lower));
 }
 
 static void gen_op_load_fpr_QT1(unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt1) +
-                   offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
-                   offsetof(CPU_QuadU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt1) +
-                   offsetof(CPU_QuadU, l.lower));
-    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt1) +
-                   offsetof(CPU_QuadU, l.lowest));
+    tcg_gen_st_i64(cpu_fpr[src / 2], cpu_env, offsetof(CPUSPARCState, qt1) +
+                   offsetof(CPU_QuadU, ll.upper));
+    tcg_gen_st_i64(cpu_fpr[src/2 + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
+                   offsetof(CPU_QuadU, ll.lower));
 }
 
 static void gen_op_store_QT0_fpr(unsigned int dst)
 {
-    tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.upper));
-    tcg_gen_ld_i32(cpu_fpr[dst + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.lower));
-    tcg_gen_ld_i32(cpu_fpr[dst + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
-                   offsetof(CPU_QuadU, l.lowest));
+    tcg_gen_ld_i64(cpu_fpr[dst / 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, ll.upper));
+    tcg_gen_ld_i64(cpu_fpr[dst/2 + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+                   offsetof(CPU_QuadU, ll.lower));
 }
 
 #ifdef TARGET_SPARC64
-static void gen_move_Q(int rd, int rs)
+static void gen_move_Q(unsigned int rd, unsigned int rs)
 {
     rd = QFPREG(rd);
     rs = QFPREG(rs);
 
-    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs]);
-    tcg_gen_mov_i32(cpu_fpr[rd + 1], cpu_fpr[rs + 1]);
-    tcg_gen_mov_i32(cpu_fpr[rd + 2], cpu_fpr[rs + 2]);
-    tcg_gen_mov_i32(cpu_fpr[rd + 3], cpu_fpr[rs + 3]);
+    tcg_gen_mov_i64(cpu_fpr[rd / 2], cpu_fpr[rs / 2]);
+    tcg_gen_mov_i64(cpu_fpr[rd / 2 + 1], cpu_fpr[rs / 2 + 1]);
     gen_update_fprs_dirty(rd);
 }
 #endif
@@ -5001,6 +4991,13 @@ static void disas_sparc_insn(DisasContext * dc)
  egress:
     tcg_temp_free(cpu_tmp1);
     tcg_temp_free(cpu_tmp2);
+    if (dc->n_t32 != 0) {
+        int i;
+        for (i = dc->n_t32 - 1; i >= 0; --i) {
+            tcg_temp_free_i32(dc->t32[i]);
+        }
+        dc->n_t32 = 0;
+    }
 }
 
 static inline void gen_intermediate_code_internal(TranslationBlock * tb,
@@ -5100,9 +5097,6 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
     tcg_temp_free_i64(cpu_tmp64);
     tcg_temp_free_i32(cpu_tmp32);
     tcg_temp_free(cpu_tmp0);
-    for (j = dc->n_t64 - 1; j >= 0; --j) {
-        tcg_temp_free_i64(dc->t64[j]);
-    }
 
     if (tb->cflags & CF_LAST_IO)
         gen_io_end();
@@ -5168,15 +5162,11 @@ void gen_intermediate_code_init(CPUSPARCState *env)
         "g6",
         "g7",
     };
-    static const char * const fregnames[64] = {
-        "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
-        "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
-        "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
-        "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
-        "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
-        "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
-        "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
-        "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
+    static const char * const fregnames[32] = {
+        "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14",
+        "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30",
+        "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",
+        "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
     };
 
     /* init various static tables */
@@ -5246,14 +5236,16 @@ void gen_intermediate_code_init(CPUSPARCState *env)
         cpu_tbr = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, tbr),
                                      "tbr");
 #endif
-        for (i = 1; i < 8; i++)
+        for (i = 1; i < 8; i++) {
             cpu_gregs[i] = tcg_global_mem_new(TCG_AREG0,
                                               offsetof(CPUState, gregs[i]),
                                               gregnames[i]);
-        for (i = 0; i < TARGET_FPREGS; i++)
-            cpu_fpr[i] = tcg_global_mem_new_i32(TCG_AREG0,
+        }
+        for (i = 0; i < TARGET_DPREGS; i++) {
+            cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                                 offsetof(CPUState, fpr[i]),
                                                 fregnames[i]);
+        }
 
         /* register helpers */
 
commit 45c7b743cda3e87e528516ac1dd039d5932433a3
Author: Richard Henderson <rth at twiddle.net>
Date:   Sat Oct 15 12:12:02 2011 -0700

    target-sparc: Undo cpu_fpr rename.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 106b406..0b95b64 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -63,7 +63,7 @@ static TCGv cpu_tmp0;
 static TCGv_i32 cpu_tmp32;
 static TCGv_i64 cpu_tmp64;
 /* Floating point registers */
-static TCGv_i32 cpu__fpr[TARGET_FPREGS];
+static TCGv_i32 cpu_fpr[TARGET_FPREGS];
 
 static target_ulong gen_opc_npc[OPC_BUF_SIZE];
 static target_ulong gen_opc_jump_pc[2];
@@ -126,12 +126,12 @@ static inline void gen_update_fprs_dirty(int rd)
 /* floating point registers moves */
 static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src)
 {
-    return cpu__fpr[src];
+    return cpu_fpr[src];
 }
 
 static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
 {
-    tcg_gen_mov_i32(cpu__fpr[dst], v);
+    tcg_gen_mov_i32(cpu_fpr[dst], v);
     gen_update_fprs_dirty(dst);
 }
 
@@ -146,13 +146,13 @@ static TCGv_i64 gen_load_fpr_D(DisasContext *dc, unsigned int src)
     src = DFPREG(src);
 
 #if TCG_TARGET_REG_BITS == 32
-    tcg_gen_mov_i32(TCGV_HIGH(ret), cpu__fpr[src]);
-    tcg_gen_mov_i32(TCGV_LOW(ret), cpu__fpr[src + 1]);
+    tcg_gen_mov_i32(TCGV_HIGH(ret), cpu_fpr[src]);
+    tcg_gen_mov_i32(TCGV_LOW(ret), cpu_fpr[src + 1]);
 #else
     {
         TCGv_i64 t = tcg_temp_new_i64();
-        tcg_gen_extu_i32_i64(ret, cpu__fpr[src]);
-        tcg_gen_extu_i32_i64(t, cpu__fpr[src + 1]);
+        tcg_gen_extu_i32_i64(ret, cpu_fpr[src]);
+        tcg_gen_extu_i32_i64(t, cpu_fpr[src + 1]);
         tcg_gen_shli_i64(ret, ret, 32);
         tcg_gen_or_i64(ret, ret, t);
         tcg_temp_free_i64(t);
@@ -173,9 +173,9 @@ static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v)
     tcg_gen_mov_i32(cpu__fpu[dst], TCGV_HIGH(v));
     tcg_gen_mov_i32(cpu__fpu[dst + 1], TCGV_LOW(v));
 #else
-    tcg_gen_trunc_i64_i32(cpu__fpr[dst + 1], v);
+    tcg_gen_trunc_i64_i32(cpu_fpr[dst + 1], v);
     tcg_gen_shri_i64(v, v, 32);
-    tcg_gen_trunc_i64_i32(cpu__fpr[dst], v);
+    tcg_gen_trunc_i64_i32(cpu_fpr[dst], v);
 #endif
 
     gen_update_fprs_dirty(dst);
@@ -188,37 +188,37 @@ static TCGv_i64 gen_dest_fpr_D(void)
 
 static void gen_op_load_fpr_QT0(unsigned int src)
 {
-    tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_st_i32(cpu__fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.upper));
-    tcg_gen_st_i32(cpu__fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.lower));
-    tcg_gen_st_i32(cpu__fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.lowest));
 }
 
 static void gen_op_load_fpr_QT1(unsigned int src)
 {
-    tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, qt1) +
+    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt1) +
                    offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_st_i32(cpu__fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
+    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
                    offsetof(CPU_QuadU, l.upper));
-    tcg_gen_st_i32(cpu__fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt1) +
+    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt1) +
                    offsetof(CPU_QuadU, l.lower));
-    tcg_gen_st_i32(cpu__fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt1) +
+    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt1) +
                    offsetof(CPU_QuadU, l.lowest));
 }
 
 static void gen_op_store_QT0_fpr(unsigned int dst)
 {
-    tcg_gen_ld_i32(cpu__fpr[dst], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_ld_i32(cpu__fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.upper));
-    tcg_gen_ld_i32(cpu__fpr[dst + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_ld_i32(cpu_fpr[dst + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.lower));
-    tcg_gen_ld_i32(cpu__fpr[dst + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_ld_i32(cpu_fpr[dst + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.lowest));
 }
 
@@ -228,10 +228,10 @@ static void gen_move_Q(int rd, int rs)
     rd = QFPREG(rd);
     rs = QFPREG(rs);
 
-    tcg_gen_mov_i32(cpu__fpr[rd], cpu__fpr[rs]);
-    tcg_gen_mov_i32(cpu__fpr[rd + 1], cpu__fpr[rs + 1]);
-    tcg_gen_mov_i32(cpu__fpr[rd + 2], cpu__fpr[rs + 2]);
-    tcg_gen_mov_i32(cpu__fpr[rd + 3], cpu__fpr[rs + 3]);
+    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs]);
+    tcg_gen_mov_i32(cpu_fpr[rd + 1], cpu_fpr[rs + 1]);
+    tcg_gen_mov_i32(cpu_fpr[rd + 2], cpu_fpr[rs + 2]);
+    tcg_gen_mov_i32(cpu_fpr[rd + 3], cpu_fpr[rs + 3]);
     gen_update_fprs_dirty(rd);
 }
 #endif
@@ -5251,9 +5251,9 @@ void gen_intermediate_code_init(CPUSPARCState *env)
                                               offsetof(CPUState, gregs[i]),
                                               gregnames[i]);
         for (i = 0; i < TARGET_FPREGS; i++)
-            cpu__fpr[i] = tcg_global_mem_new_i32(TCG_AREG0,
-                                                 offsetof(CPUState, fpr[i]),
-                                                 fregnames[i]);
+            cpu_fpr[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                                offsetof(CPUState, fpr[i]),
+                                                fregnames[i]);
 
         /* register helpers */
 
commit ac11f7767f06c25a2fd4d2d05f8d9487aabd8d01
Author: Richard Henderson <rth at twiddle.net>
Date:   Sat Oct 15 12:00:08 2011 -0700

    target-sparc: Extract float128 move to a function.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 6c13f1c..106b406 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -222,6 +222,20 @@ static void gen_op_store_QT0_fpr(unsigned int dst)
                    offsetof(CPU_QuadU, l.lowest));
 }
 
+#ifdef TARGET_SPARC64
+static void gen_move_Q(int rd, int rs)
+{
+    rd = QFPREG(rd);
+    rs = QFPREG(rs);
+
+    tcg_gen_mov_i32(cpu__fpr[rd], cpu__fpr[rs]);
+    tcg_gen_mov_i32(cpu__fpr[rd + 1], cpu__fpr[rs + 1]);
+    tcg_gen_mov_i32(cpu__fpr[rd + 2], cpu__fpr[rs + 2]);
+    tcg_gen_mov_i32(cpu__fpr[rd + 3], cpu__fpr[rs + 3]);
+    gen_update_fprs_dirty(rd);
+}
+#endif
+
 /* moves */
 #ifdef CONFIG_USER_ONLY
 #define supervisor(dc) 0
@@ -2831,15 +2845,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x3: /* V9 fmovq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd)],
-                                    cpu__fpr[QFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 1],
-                                    cpu__fpr[QFPREG(rs2) + 1]);
-                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 2],
-                                    cpu__fpr[QFPREG(rs2) + 2]);
-                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 3],
-                                    cpu__fpr[QFPREG(rs2) + 3]);
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_move_Q(rd, rs2);
                     break;
                 case 0x6: /* V9 fnegd */
                     gen_ne_fop_DD(dc, rd, rs2, gen_helper_fnegd);
@@ -2924,11 +2930,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1 = get_src1(insn, cpu_src1);
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
-                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd)], cpu__fpr[QFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 1], cpu__fpr[QFPREG(rs2) + 1]);
-                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 2], cpu__fpr[QFPREG(rs2) + 2]);
-                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 3], cpu__fpr[QFPREG(rs2) + 3]);
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_move_Q(rd, rs2);
                     gen_set_label(l1);
                     break;
                 }
@@ -2978,15 +2980,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_fcond(r_cond, fcc, cond);                   \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd)],           \
-                                        cpu__fpr[QFPREG(rs2)]);         \
-                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 1],       \
-                                        cpu__fpr[QFPREG(rs2) + 1]);     \
-                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 2],       \
-                                        cpu__fpr[QFPREG(rs2) + 2]);     \
-                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 3],       \
-                                        cpu__fpr[QFPREG(rs2) + 3]);     \
-                        gen_update_fprs_dirty(QFPREG(rd));              \
+                        gen_move_Q(rd, rs2);                            \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -3077,15 +3071,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_cond(r_cond, icc, cond, dc);                \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd)],           \
-                                        cpu__fpr[QFPREG(rs2)]);         \
-                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 1],       \
-                                        cpu__fpr[QFPREG(rs2) + 1]);     \
-                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 2],       \
-                                        cpu__fpr[QFPREG(rs2) + 2]);     \
-                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 3],       \
-                                        cpu__fpr[QFPREG(rs2) + 3]);     \
-                        gen_update_fprs_dirty(QFPREG(rd));              \
+                        gen_move_Q(rd, rs2);                            \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
commit 61f17f6ebacd4e9cc8ac8168119bbf6d9f72cc9f
Author: Richard Henderson <rth at twiddle.net>
Date:   Sat Oct 15 11:52:00 2011 -0700

    target-sparc: Extract common code for floating-point operations.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 80f0058..6c13f1c 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1627,6 +1627,305 @@ static inline void gen_clear_float_exceptions(void)
     gen_helper_clear_float_exceptions(cpu_env);
 }
 
+static inline void gen_fop_FF(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32))
+{
+    TCGv_i32 dst, src;
+
+    gen_clear_float_exceptions();
+    src = gen_load_fpr_F(dc, rs);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, cpu_env, src);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+static inline void gen_ne_fop_FF(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_i32, TCGv_i32))
+{
+    TCGv_i32 dst, src;
+
+    src = gen_load_fpr_F(dc, rs);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, src);
+
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
+                        void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32))
+{
+    TCGv_i32 dst, src1, src2;
+
+    gen_clear_float_exceptions();
+    src1 = gen_load_fpr_F(dc, rs1);
+    src2 = gen_load_fpr_F(dc, rs2);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, cpu_env, src1, src2);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_ne_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
+                                  void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
+{
+    TCGv_i32 dst, src1, src2;
+
+    src1 = gen_load_fpr_F(dc, rs1);
+    src2 = gen_load_fpr_F(dc, rs2);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, src1, src2);
+
+    gen_store_fpr_F(dc, rd, dst);
+}
+#endif
+
+static inline void gen_fop_DD(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64))
+{
+    TCGv_i64 dst, src;
+
+    gen_clear_float_exceptions();
+    src = gen_load_fpr_D(dc, rs);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_ne_fop_DD(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src;
+
+    src = gen_load_fpr_D(dc, rs);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, src);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+#endif
+
+static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+                        void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src1, src2;
+
+    gen_clear_float_exceptions();
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src1, src2);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+                                  void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 dst, src1, src2;
+
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, src1, src2);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+#endif
+
+static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_ptr))
+{
+    gen_clear_float_exceptions();
+    gen_op_load_fpr_QT1(QFPREG(rs));
+
+    gen(cpu_env);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_ptr))
+{
+    gen_op_load_fpr_QT1(QFPREG(rs));
+
+    gen(cpu_env);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+#endif
+
+static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
+                               void (*gen)(TCGv_ptr))
+{
+    gen_clear_float_exceptions();
+    gen_op_load_fpr_QT0(QFPREG(rs1));
+    gen_op_load_fpr_QT1(QFPREG(rs2));
+
+    gen(cpu_env);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
+static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
+                        void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32, TCGv_i32))
+{
+    TCGv_i64 dst;
+    TCGv_i32 src1, src2;
+
+    gen_clear_float_exceptions();
+    src1 = gen_load_fpr_F(dc, rs1);
+    src2 = gen_load_fpr_F(dc, rs2);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src1, src2);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
+                               void (*gen)(TCGv_ptr, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 src1, src2;
+
+    gen_clear_float_exceptions();
+    src1 = gen_load_fpr_D(dc, rs1);
+    src2 = gen_load_fpr_D(dc, rs2);
+
+    gen(cpu_env, src1, src2);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
+#ifdef TARGET_SPARC64
+static inline void gen_fop_DF(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32))
+{
+    TCGv_i64 dst;
+    TCGv_i32 src;
+
+    gen_clear_float_exceptions();
+    src = gen_load_fpr_F(dc, rs);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_D(dc, rd, dst);
+}
+#endif
+
+static inline void gen_ne_fop_DF(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32))
+{
+    TCGv_i64 dst;
+    TCGv_i32 src;
+
+    src = gen_load_fpr_F(dc, rs);
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env, src);
+
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+static inline void gen_fop_FD(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i64))
+{
+    TCGv_i32 dst;
+    TCGv_i64 src;
+
+    gen_clear_float_exceptions();
+    src = gen_load_fpr_D(dc, rs);
+    dst = gen_dest_fpr_F();
+
+    gen(dst, cpu_env, src);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i32, TCGv_ptr))
+{
+    TCGv_i32 dst;
+
+    gen_clear_float_exceptions();
+    gen_op_load_fpr_QT1(QFPREG(rs));
+    dst = gen_dest_fpr_F();
+
+    gen(dst, cpu_env);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_F(dc, rd, dst);
+}
+
+static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs,
+                              void (*gen)(TCGv_i64, TCGv_ptr))
+{
+    TCGv_i64 dst;
+
+    gen_clear_float_exceptions();
+    gen_op_load_fpr_QT1(QFPREG(rs));
+    dst = gen_dest_fpr_D();
+
+    gen(dst, cpu_env);
+
+    gen_helper_check_ieee_exceptions(cpu_env);
+    gen_store_fpr_D(dc, rd, dst);
+}
+
+static inline void gen_ne_fop_QF(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_ptr, TCGv_i32))
+{
+    TCGv_i32 src;
+
+    src = gen_load_fpr_F(dc, rs);
+
+    gen(cpu_env, src);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
+static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
+                                 void (*gen)(TCGv_ptr, TCGv_i64))
+{
+    TCGv_i64 src;
+
+    src = gen_load_fpr_D(dc, rs);
+
+    gen(cpu_env, src);
+
+    gen_op_store_QT0_fpr(QFPREG(rd));
+    gen_update_fprs_dirty(QFPREG(rd));
+}
+
 /* asi moves */
 #ifdef TARGET_SPARC64
 static inline TCGv_i32 gen_get_asi(int insn, TCGv r_addr)
@@ -2415,279 +2714,115 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_store_fpr_F(dc, rd, cpu_src1_32);
                     break;
                 case 0x5: /* fnegs */
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fnegs(cpu_dst_32, cpu_src1_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FF(dc, rd, rs2, gen_helper_fnegs);
                     break;
                 case 0x9: /* fabss */
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fabss(cpu_dst_32, cpu_src1_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FF(dc, rd, rs2, gen_helper_fabss);
                     break;
                 case 0x29: /* fsqrts */
                     CHECK_FPU_FEATURE(dc, FSQRT);
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fsqrts(cpu_dst_32, cpu_env, cpu_src1_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FF(dc, rd, rs2, gen_helper_fsqrts);
                     break;
                 case 0x2a: /* fsqrtd */
                     CHECK_FPU_FEATURE(dc, FSQRT);
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fsqrtd(cpu_dst_64, cpu_env, cpu_src1_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DD(dc, rd, rs2, gen_helper_fsqrtd);
                     break;
                 case 0x2b: /* fsqrtq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fsqrtq(cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_fop_QQ(dc, rd, rs2, gen_helper_fsqrtq);
                     break;
                 case 0x41: /* fadds */
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fadds(cpu_dst_32, cpu_env,
-                                     cpu_src1_32, cpu_src2_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fadds);
                     break;
                 case 0x42: /* faddd */
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_faddd(cpu_dst_64, cpu_env,
-                                     cpu_src1_64, cpu_src2_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_faddd);
                     break;
                 case 0x43: /* faddq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT0(QFPREG(rs1));
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_faddq(cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_faddq);
                     break;
                 case 0x45: /* fsubs */
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fsubs(cpu_dst_32, cpu_env,
-                                     cpu_src1_32, cpu_src2_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fsubs);
                     break;
                 case 0x46: /* fsubd */
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fsubd(cpu_dst_64, cpu_env,
-                                     cpu_src1_64, cpu_src2_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fsubd);
                     break;
                 case 0x47: /* fsubq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT0(QFPREG(rs1));
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fsubq(cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fsubq);
                     break;
                 case 0x49: /* fmuls */
                     CHECK_FPU_FEATURE(dc, FMUL);
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fmuls(cpu_dst_32, cpu_env,
-                                     cpu_src1_32, cpu_src2_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fmuls);
                     break;
                 case 0x4a: /* fmuld */
                     CHECK_FPU_FEATURE(dc, FMUL);
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmuld(cpu_dst_64, cpu_env,
-                                     cpu_src1_64, cpu_src2_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld);
                     break;
                 case 0x4b: /* fmulq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     CHECK_FPU_FEATURE(dc, FMUL);
-                    gen_op_load_fpr_QT0(QFPREG(rs1));
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fmulq(cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fmulq);
                     break;
                 case 0x4d: /* fdivs */
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fdivs(cpu_dst_32, cpu_env,
-                                     cpu_src1_32, cpu_src2_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FFF(dc, rd, rs1, rs2, gen_helper_fdivs);
                     break;
                 case 0x4e: /* fdivd */
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fdivd(cpu_dst_64, cpu_env,
-                                     cpu_src1_64, cpu_src2_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DDD(dc, rd, rs1, rs2, gen_helper_fdivd);
                     break;
                 case 0x4f: /* fdivq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT0(QFPREG(rs1));
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    gen_helper_fdivq(cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_fop_QQQ(dc, rd, rs1, rs2, gen_helper_fdivq);
                     break;
                 case 0x69: /* fsmuld */
                     CHECK_FPU_FEATURE(dc, FSMULD);
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fsmuld(cpu_dst_64, cpu_env,
-                                      cpu_src1_32, cpu_src2_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DFF(dc, rd, rs1, rs2, gen_helper_fsmuld);
                     break;
                 case 0x6e: /* fdmulq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fdmulq(cpu_env, cpu_src1_64, cpu_src2_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_fop_QDD(dc, rd, rs1, rs2, gen_helper_fdmulq);
                     break;
                 case 0xc4: /* fitos */
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fitos(cpu_dst_32, cpu_env, cpu_src1_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FF(dc, rd, rs2, gen_helper_fitos);
                     break;
                 case 0xc6: /* fdtos */
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fdtos(cpu_dst_32, cpu_env, cpu_src1_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FD(dc, rd, rs2, gen_helper_fdtos);
                     break;
                 case 0xc7: /* fqtos */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fqtos(cpu_dst_32, cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FQ(dc, rd, rs2, gen_helper_fqtos);
                     break;
                 case 0xc8: /* fitod */
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fitod(cpu_dst_64, cpu_env, cpu_src1_32);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DF(dc, rd, rs2, gen_helper_fitod);
                     break;
                 case 0xc9: /* fstod */
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fstod(cpu_dst_64, cpu_env, cpu_src1_32);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DF(dc, rd, rs2, gen_helper_fstod);
                     break;
                 case 0xcb: /* fqtod */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_clear_float_exceptions();
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fqtod(cpu_dst_64, cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DQ(dc, rd, rs2, gen_helper_fqtod);
                     break;
                 case 0xcc: /* fitoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    gen_helper_fitoq(cpu_env, cpu_src1_32);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_ne_fop_QF(dc, rd, rs2, gen_helper_fitoq);
                     break;
                 case 0xcd: /* fstoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    gen_helper_fstoq(cpu_env, cpu_src1_32);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_ne_fop_QF(dc, rd, rs2, gen_helper_fstoq);
                     break;
                 case 0xce: /* fdtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fdtoq(cpu_env, cpu_src1_64);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_ne_fop_QD(dc, rd, rs2, gen_helper_fdtoq);
                     break;
                 case 0xd1: /* fstoi */
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fstoi(cpu_dst_32, cpu_env, cpu_src1_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FF(dc, rd, rs2, gen_helper_fstoi);
                     break;
                 case 0xd2: /* fdtoi */
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fdtoi(cpu_dst_32, cpu_env, cpu_src1_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FD(dc, rd, rs2, gen_helper_fdtoi);
                     break;
                 case 0xd3: /* fqtoi */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fqtoi(cpu_dst_32, cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FQ(dc, rd, rs2, gen_helper_fqtoi);
                     break;
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 fmovd */
@@ -2707,80 +2842,38 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x6: /* V9 fnegd */
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fnegd(cpu_dst_64, cpu_src1_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DD(dc, rd, rs2, gen_helper_fnegd);
                     break;
                 case 0x7: /* V9 fnegq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_helper_fnegq(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_ne_fop_QQ(dc, rd, rs2, gen_helper_fnegq);
                     break;
                 case 0xa: /* V9 fabsd */
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fabsd(cpu_dst_64, cpu_src1_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DD(dc, rd, rs2, gen_helper_fabsd);
                     break;
                 case 0xb: /* V9 fabsq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_helper_fabsq(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_ne_fop_QQ(dc, rd, rs2, gen_helper_fabsq);
                     break;
                 case 0x81: /* V9 fstox */
-                    gen_clear_float_exceptions();
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fstox(cpu_dst_64, cpu_env, cpu_src1_32);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DF(dc, rd, rs2, gen_helper_fstox);
                     break;
                 case 0x82: /* V9 fdtox */
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fdtox(cpu_dst_64, cpu_env, cpu_src1_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DD(dc, rd, rs2, gen_helper_fdtox);
                     break;
                 case 0x83: /* V9 fqtox */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
-                    gen_clear_float_exceptions();
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fqtox(cpu_dst_64, cpu_env);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DQ(dc, rd, rs2, gen_helper_fqtox);
                     break;
                 case 0x84: /* V9 fxtos */
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fxtos(cpu_dst_32, cpu_env, cpu_src1_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_fop_FD(dc, rd, rs2, gen_helper_fxtos);
                     break;
                 case 0x88: /* V9 fxtod */
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fxtod(cpu_dst_64, cpu_env, cpu_src1_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_fop_DD(dc, rd, rs2, gen_helper_fxtod);
                     break;
                 case 0x8c: /* V9 fxtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_clear_float_exceptions();
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fxtoq(cpu_env, cpu_src1_64);
-                    gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_QT0_fpr(QFPREG(rd));
-                    gen_update_fprs_dirty(QFPREG(rd));
+                    gen_ne_fop_QD(dc, rd, rs2, gen_helper_fxtoq);
                     break;
 #endif
                 default:
@@ -3990,65 +4083,31 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x031: /* VIS I fmul8x16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8x16(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16);
                     break;
                 case 0x033: /* VIS I fmul8x16au */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8x16au(cpu_dst_64, cpu_src1_64,
-                                          cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16au);
                     break;
                 case 0x035: /* VIS I fmul8x16al */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8x16al(cpu_dst_64, cpu_src1_64,
-                                          cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8x16al);
                     break;
                 case 0x036: /* VIS I fmul8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8sux16(cpu_dst_64, cpu_src1_64,
-                                          cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8sux16);
                     break;
                 case 0x037: /* VIS I fmul8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8ulx16(cpu_dst_64, cpu_src1_64,
-                                          cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmul8ulx16);
                     break;
                 case 0x038: /* VIS I fmuld8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmuld8sux16(cpu_dst_64, cpu_src1_64,
-                                           cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld8sux16);
                     break;
                 case 0x039: /* VIS I fmuld8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmuld8ulx16(cpu_dst_64, cpu_src1_64,
-                                           cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld8ulx16);
                     break;
                 case 0x03a: /* VIS I fpack32 */
                 case 0x03b: /* VIS I fpack16 */
@@ -4067,86 +4126,46 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x04b: /* VIS I fpmerge */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpmerge(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpmerge);
                     break;
                 case 0x04c: /* VIS II bshuffle */
                     // XXX
                     goto illegal_insn;
                 case 0x04d: /* VIS I fexpand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fexpand(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fexpand);
                     break;
                 case 0x050: /* VIS I fpadd16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpadd16(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpadd16);
                     break;
                 case 0x051: /* VIS I fpadd16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fpadd16s(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, gen_helper_fpadd16s);
                     break;
                 case 0x052: /* VIS I fpadd32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpadd32(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpadd32);
                     break;
                 case 0x053: /* VIS I fpadd32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_add_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_add_i32);
                     break;
                 case 0x054: /* VIS I fpsub16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpsub16(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpsub16);
                     break;
                 case 0x055: /* VIS I fpsub16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fpsub16s(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, gen_helper_fpsub16s);
                     break;
                 case 0x056: /* VIS I fpsub32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpsub32(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fpsub32);
                     break;
                 case 0x057: /* VIS I fpsub32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_sub_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_sub_i32);
                     break;
                 case 0x060: /* VIS I fzero */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4162,143 +4181,75 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x062: /* VIS I fnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_nor_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_nor_i64);
                     break;
                 case 0x063: /* VIS I fnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_nor_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_nor_i32);
                     break;
                 case 0x064: /* VIS I fandnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_andc_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_andc_i64);
                     break;
                 case 0x065: /* VIS I fandnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_andc_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_andc_i32);
                     break;
                 case 0x066: /* VIS I fnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_not_i64(cpu_dst_64, cpu_src1_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DD(dc, rd, rs2, tcg_gen_not_i64);
                     break;
                 case 0x067: /* VIS I fnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_not_i32(cpu_dst_32, cpu_src1_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FF(dc, rd, rs2, tcg_gen_not_i32);
                     break;
                 case 0x068: /* VIS I fandnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_andc_i64(cpu_dst_64, cpu_src2_64, cpu_src1_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs2, rs1, tcg_gen_andc_i64);
                     break;
                 case 0x069: /* VIS I fandnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_andc_i32(cpu_dst_32, cpu_src2_32, cpu_src1_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs2, rs1, tcg_gen_andc_i32);
                     break;
                 case 0x06a: /* VIS I fnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_not_i64(cpu_dst_64, cpu_src1_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DD(dc, rd, rs1, tcg_gen_not_i64);
                     break;
                 case 0x06b: /* VIS I fnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_not_i32(cpu_dst_32, cpu_src1_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FF(dc, rd, rs1, tcg_gen_not_i32);
                     break;
                 case 0x06c: /* VIS I fxor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_xor_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_xor_i64);
                     break;
                 case 0x06d: /* VIS I fxors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_xor_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_xor_i32);
                     break;
                 case 0x06e: /* VIS I fnand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_nand_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_nand_i64);
                     break;
                 case 0x06f: /* VIS I fnands */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_nand_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_nand_i32);
                     break;
                 case 0x070: /* VIS I fand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_and_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_and_i64);
                     break;
                 case 0x071: /* VIS I fands */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_and_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_and_i32);
                     break;
                 case 0x072: /* VIS I fxnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_eqv_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_eqv_i64);
                     break;
                 case 0x073: /* VIS I fxnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_eqv_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_eqv_i32);
                     break;
                 case 0x074: /* VIS I fsrc1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4312,19 +4263,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x076: /* VIS I fornot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_orc_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_orc_i64);
                     break;
                 case 0x077: /* VIS I fornot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_orc_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_orc_i32);
                     break;
                 case 0x078: /* VIS I fsrc2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4338,35 +4281,19 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x07a: /* VIS I fornot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_orc_i64(cpu_dst_64, cpu_src2_64, cpu_src1_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs2, rs1, tcg_gen_orc_i64);
                     break;
                 case 0x07b: /* VIS I fornot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_orc_i32(cpu_dst_32, cpu_src2_32, cpu_src1_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs2, rs1, tcg_gen_orc_i32);
                     break;
                 case 0x07c: /* VIS I for */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
-                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    cpu_dst_64 = gen_dest_fpr_D();
-                    tcg_gen_or_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
-                    gen_store_fpr_D(dc, rd, cpu_dst_64);
+                    gen_ne_fop_DDD(dc, rd, rs1, rs2, tcg_gen_or_i64);
                     break;
                 case 0x07d: /* VIS I fors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
-                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    cpu_dst_32 = gen_dest_fpr_F();
-                    tcg_gen_or_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
-                    gen_store_fpr_F(dc, rd, cpu_dst_32);
+                    gen_ne_fop_FFF(dc, rd, rs1, rs2, tcg_gen_or_i32);
                     break;
                 case 0x07e: /* VIS I fone */
                     CHECK_FPU_FEATURE(dc, VIS1);
commit f027c3b1927fd1506a456532eac0e924d7a0879f
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Oct 19 14:56:43 2011 -0700

    target-sparc: Make FPU/VIS helpers const when possible.
    
    This also removes the unused ENV parameter from these helpers.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
index f6348c2..e652021 100644
--- a/target-sparc/fop_helper.c
+++ b/target-sparc/fop_helper.c
@@ -182,7 +182,7 @@ float32 helper_fabss(float32 src)
 }
 
 #ifdef TARGET_SPARC64
-float64 helper_fabsd(CPUState *env, float64 src)
+float64 helper_fabsd(float64 src)
 {
     return float64_abs(src);
 }
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 86fad6e..ba0ad81 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -16,7 +16,7 @@ DEF_HELPER_1(rdccr, tl, env)
 DEF_HELPER_2(wrccr, void, env, tl)
 DEF_HELPER_1(rdcwp, tl, env)
 DEF_HELPER_2(wrcwp, void, env, tl)
-DEF_HELPER_3(array8, tl, env, tl, tl)
+DEF_HELPER_FLAGS_2(array8, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
 DEF_HELPER_3(alignaddr, tl, env, tl, tl)
 DEF_HELPER_1(popc, tl, tl)
 DEF_HELPER_3(ldda_asi, void, tl, int, int)
@@ -48,7 +48,7 @@ DEF_HELPER_4(st_asi, void, tl, i64, int, int)
 DEF_HELPER_2(ldfsr, void, env, i32)
 DEF_HELPER_1(check_ieee_exceptions, void, env)
 DEF_HELPER_1(clear_float_exceptions, void, env)
-DEF_HELPER_1(fabss, f32, f32)
+DEF_HELPER_FLAGS_1(fabss, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32)
 DEF_HELPER_2(fsqrts, f32, env, f32)
 DEF_HELPER_2(fsqrtd, f64, env, f64)
 DEF_HELPER_3(fcmps, void, env, f32, f32)
@@ -60,7 +60,7 @@ DEF_HELPER_1(fcmpq, void, env)
 DEF_HELPER_1(fcmpeq, void, env)
 #ifdef TARGET_SPARC64
 DEF_HELPER_2(ldxfsr, void, env, i64)
-DEF_HELPER_2(fabsd, f64, env, f64)
+DEF_HELPER_FLAGS_1(fabsd, TCG_CALL_CONST | TCG_CALL_PURE, f64, f64)
 DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
 DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
 DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
@@ -102,14 +102,14 @@ DEF_HELPER_3(fdivs, f32, env, f32, f32)
 DEF_HELPER_3(fsmuld, f64, env, f32, f32)
 DEF_HELPER_3(fdmulq, void, env, f64, f64);
 
-DEF_HELPER_1(fnegs, f32, f32)
+DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32)
 DEF_HELPER_2(fitod, f64, env, s32)
 DEF_HELPER_2(fitoq, void, env, s32)
 
 DEF_HELPER_2(fitos, f32, env, s32)
 
 #ifdef TARGET_SPARC64
-DEF_HELPER_1(fnegd, f64, f64)
+DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_CONST | TCG_CALL_PURE, f64, f64)
 DEF_HELPER_1(fnegq, void, env)
 DEF_HELPER_2(fxtos, f32, env, s64)
 DEF_HELPER_2(fxtod, f64, env, s64)
@@ -130,26 +130,32 @@ DEF_HELPER_2(fdtox, s64, env, f64)
 DEF_HELPER_1(fqtox, s64, env)
 DEF_HELPER_3(faligndata, i64, env, i64, i64)
 
-DEF_HELPER_3(fpmerge, i64, env, i64, i64)
-DEF_HELPER_3(fmul8x16, i64, env, i64, i64)
-DEF_HELPER_3(fmul8x16al, i64, env, i64, i64)
-DEF_HELPER_3(fmul8x16au, i64, env, i64, i64)
-DEF_HELPER_3(fmul8sux16, i64, env, i64, i64)
-DEF_HELPER_3(fmul8ulx16, i64, env, i64, i64)
-DEF_HELPER_3(fmuld8sux16, i64, env, i64, i64)
-DEF_HELPER_3(fmuld8ulx16, i64, env, i64, i64)
-DEF_HELPER_3(fexpand, i64, env, i64, i64)
-#define VIS_HELPER(name)                                 \
-    DEF_HELPER_3(f ## name ## 16, i64, env, i64, i64)    \
-    DEF_HELPER_3(f ## name ## 16s, i32, env, i32, i32)   \
-    DEF_HELPER_3(f ## name ## 32, i64, env, i64, i64)    \
-    DEF_HELPER_3(f ## name ## 32s, i32, env, i32, i32)
+DEF_HELPER_FLAGS_2(fpmerge, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8x16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8x16al, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8x16au, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8sux16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmul8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+#define VIS_HELPER(name)                                                 \
+    DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_CONST | TCG_CALL_PURE,  \
+                       i64, i64, i64)                                    \
+    DEF_HELPER_FLAGS_2(f ## name ## 16s, TCG_CALL_CONST | TCG_CALL_PURE, \
+                       i32, i32, i32)                                    \
+    DEF_HELPER_FLAGS_2(f ## name ## 32, TCG_CALL_CONST | TCG_CALL_PURE,  \
+                       i64, i64, i64)                                    \
+    DEF_HELPER_FLAGS_2(f ## name ## 32s, TCG_CALL_CONST | TCG_CALL_PURE, \
+                       i32, i32, i32)
 
 VIS_HELPER(padd);
 VIS_HELPER(psub);
-#define VIS_CMPHELPER(name)                              \
-    DEF_HELPER_3(f##name##16, i64, env, i64, i64)        \
-    DEF_HELPER_3(f##name##32, i64, env, i64, i64)
+#define VIS_CMPHELPER(name)                                              \
+    DEF_HELPER_FLAGS_2(f##name##16, TCG_CALL_CONST | TCG_CALL_PURE,      \
+                       i64, i64, i64)                                    \
+    DEF_HELPER_FLAGS_2(f##name##32, TCG_CALL_CONST | TCG_CALL_PURE,      \
+                       i64, i64, i64)
 VIS_CMPHELPER(cmpgt);
 VIS_CMPHELPER(cmpeq);
 VIS_CMPHELPER(cmple);
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index f41ef98..80f0058 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2722,7 +2722,7 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0xa: /* V9 fabsd */
                     cpu_src1_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fabsd(cpu_dst_64, cpu_env, cpu_src1_64);
+                    gen_helper_fabsd(cpu_dst_64, cpu_src1_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0xb: /* V9 fabsq */
@@ -3902,14 +3902,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x012: /* VIS I array16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
                     tcg_gen_shli_i64(cpu_dst, cpu_dst, 1);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
@@ -3917,7 +3917,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1 = get_src1(insn, cpu_src1);
                     gen_movl_reg_TN(rs2, cpu_src2);
-                    gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
+                    gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
                     tcg_gen_shli_i64(cpu_dst, cpu_dst, 2);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
@@ -3936,64 +3936,56 @@ static void disas_sparc_insn(DisasContext * dc)
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fcmple16(cpu_dst, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fcmple16(cpu_dst, cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x022: /* VIS I fcmpne16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fcmpne16(cpu_dst, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fcmpne16(cpu_dst, cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x024: /* VIS I fcmple32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fcmple32(cpu_dst, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fcmple32(cpu_dst, cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x026: /* VIS I fcmpne32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fcmpne32(cpu_dst, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fcmpne32(cpu_dst, cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x028: /* VIS I fcmpgt16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fcmpgt16(cpu_dst, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fcmpgt16(cpu_dst, cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02a: /* VIS I fcmpeq16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fcmpeq16(cpu_dst, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fcmpeq16(cpu_dst, cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02c: /* VIS I fcmpgt32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fcmpgt32(cpu_dst, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fcmpgt32(cpu_dst, cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02e: /* VIS I fcmpeq32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
-                    gen_helper_fcmpeq32(cpu_dst, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fcmpeq32(cpu_dst, cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x031: /* VIS I fmul8x16 */
@@ -4001,8 +3993,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8x16(cpu_dst_64, cpu_env,
-                                        cpu_src1_64, cpu_src2_64);
+                    gen_helper_fmul8x16(cpu_dst_64, cpu_src1_64, cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x033: /* VIS I fmul8x16au */
@@ -4010,8 +4001,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8x16au(cpu_dst_64, cpu_env,
-                                          cpu_src1_64, cpu_src2_64);
+                    gen_helper_fmul8x16au(cpu_dst_64, cpu_src1_64,
+                                          cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x035: /* VIS I fmul8x16al */
@@ -4019,8 +4010,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8x16al(cpu_dst_64, cpu_env,
-                                          cpu_src1_64, cpu_src2_64);
+                    gen_helper_fmul8x16al(cpu_dst_64, cpu_src1_64,
+                                          cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x036: /* VIS I fmul8sux16 */
@@ -4028,8 +4019,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8sux16(cpu_dst_64, cpu_env,
-                                          cpu_src1_64, cpu_src2_64);
+                    gen_helper_fmul8sux16(cpu_dst_64, cpu_src1_64,
+                                          cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x037: /* VIS I fmul8ulx16 */
@@ -4037,8 +4028,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmul8ulx16(cpu_dst_64, cpu_env,
-                                          cpu_src1_64, cpu_src2_64);
+                    gen_helper_fmul8ulx16(cpu_dst_64, cpu_src1_64,
+                                          cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x038: /* VIS I fmuld8sux16 */
@@ -4046,8 +4037,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmuld8sux16(cpu_dst_64, cpu_env,
-                                           cpu_src1_64, cpu_src2_64);
+                    gen_helper_fmuld8sux16(cpu_dst_64, cpu_src1_64,
+                                           cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x039: /* VIS I fmuld8ulx16 */
@@ -4055,8 +4046,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fmuld8ulx16(cpu_dst_64, cpu_env,
-                                           cpu_src1_64, cpu_src2_64);
+                    gen_helper_fmuld8ulx16(cpu_dst_64, cpu_src1_64,
+                                           cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x03a: /* VIS I fpack32 */
@@ -4079,8 +4070,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpmerge(cpu_dst_64, cpu_env,
-                                       cpu_src1_64, cpu_src2_64);
+                    gen_helper_fpmerge(cpu_dst_64, cpu_src1_64, cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x04c: /* VIS II bshuffle */
@@ -4091,8 +4081,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fexpand(cpu_dst_64, cpu_env,
-                                       cpu_src1_64, cpu_src2_64);
+                    gen_helper_fexpand(cpu_dst_64, cpu_src1_64, cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x050: /* VIS I fpadd16 */
@@ -4100,8 +4089,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpadd16(cpu_dst_64, cpu_env,
-                                       cpu_src1_64, cpu_src2_64);
+                    gen_helper_fpadd16(cpu_dst_64, cpu_src1_64, cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x051: /* VIS I fpadd16s */
@@ -4109,8 +4097,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_32 = gen_load_fpr_F(dc, rs1);
                     cpu_src2_32 = gen_load_fpr_F(dc, rs2);
                     cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fpadd16s(cpu_dst_32, cpu_env,
-                                        cpu_src1_32, cpu_src2_32);
+                    gen_helper_fpadd16s(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x052: /* VIS I fpadd32 */
@@ -4118,8 +4105,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpadd32(cpu_dst_64, cpu_env,
-                                       cpu_src1_64, cpu_src2_64);
+                    gen_helper_fpadd32(cpu_dst_64, cpu_src1_64, cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x053: /* VIS I fpadd32s */
@@ -4135,8 +4121,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpsub16(cpu_dst_64, cpu_env,
-                                       cpu_src1_64, cpu_src2_64);
+                    gen_helper_fpsub16(cpu_dst_64, cpu_src1_64, cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x055: /* VIS I fpsub16s */
@@ -4144,8 +4129,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_32 = gen_load_fpr_F(dc, rs1);
                     cpu_src2_32 = gen_load_fpr_F(dc, rs2);
                     cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fpsub16s(cpu_dst_32, cpu_env,
-                                        cpu_src1_32, cpu_src2_32);
+                    gen_helper_fpsub16s(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x056: /* VIS I fpsub32 */
@@ -4153,8 +4137,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1_64 = gen_load_fpr_D(dc, rs1);
                     cpu_src2_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_64 = gen_dest_fpr_D();
-                    gen_helper_fpsub32(cpu_dst_64, cpu_env,
-                                       cpu_src1_64, cpu_src2_64);
+                    gen_helper_fpsub32(cpu_dst_64, cpu_src1_64, cpu_src2_64);
                     gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x057: /* VIS I fpsub32s */
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index a007b0f..39c8d9a 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -28,8 +28,7 @@
 #define GET_FIELD_SP(X, FROM, TO)               \
     GET_FIELD(X, 63 - (TO), 63 - (FROM))
 
-target_ulong helper_array8(CPUState *env, target_ulong pixel_addr,
-                           target_ulong cubesize)
+target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
 {
     return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
         (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
@@ -97,7 +96,7 @@ typedef union {
     float32 f;
 } VIS32;
 
-uint64_t helper_fpmerge(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fpmerge(uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
 
@@ -117,7 +116,7 @@ uint64_t helper_fpmerge(CPUState *env, uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fmul8x16(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fmul8x16(uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
@@ -141,7 +140,7 @@ uint64_t helper_fmul8x16(CPUState *env, uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fmul8x16al(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fmul8x16al(uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
@@ -165,7 +164,7 @@ uint64_t helper_fmul8x16al(CPUState *env, uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fmul8x16au(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fmul8x16au(uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
@@ -189,7 +188,7 @@ uint64_t helper_fmul8x16au(CPUState *env, uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fmul8sux16(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fmul8sux16(uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
@@ -213,7 +212,7 @@ uint64_t helper_fmul8sux16(CPUState *env, uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fmul8ulx16(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fmul8ulx16(uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
@@ -237,7 +236,7 @@ uint64_t helper_fmul8ulx16(CPUState *env, uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fmuld8sux16(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fmuld8sux16(uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
@@ -260,7 +259,7 @@ uint64_t helper_fmuld8sux16(CPUState *env, uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fmuld8ulx16(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fmuld8ulx16(uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
@@ -283,7 +282,7 @@ uint64_t helper_fmuld8ulx16(CPUState *env, uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fexpand(CPUState *env, uint64_t src1, uint64_t src2)
+uint64_t helper_fexpand(uint64_t src1, uint64_t src2)
 {
     VIS32 s;
     VIS64 d;
@@ -299,7 +298,7 @@ uint64_t helper_fexpand(CPUState *env, uint64_t src1, uint64_t src2)
 }
 
 #define VIS_HELPER(name, F)                             \
-    uint64_t name##16(CPUState *env, uint64_t src1, uint64_t src2) \
+    uint64_t name##16(uint64_t src1, uint64_t src2)     \
     {                                                   \
         VIS64 s, d;                                     \
                                                         \
@@ -314,8 +313,7 @@ uint64_t helper_fexpand(CPUState *env, uint64_t src1, uint64_t src2)
         return d.ll;                                    \
     }                                                   \
                                                         \
-    uint32_t name##16s(CPUState *env, uint32_t src1,    \
-                       uint32_t src2)                   \
+    uint32_t name##16s(uint32_t src1, uint32_t src2)    \
     {                                                   \
         VIS32 s, d;                                     \
                                                         \
@@ -328,7 +326,7 @@ uint64_t helper_fexpand(CPUState *env, uint64_t src1, uint64_t src2)
         return d.l;                                     \
     }                                                   \
                                                         \
-    uint64_t name##32(CPUState *env, uint64_t src1, uint64_t src2) \
+    uint64_t name##32(uint64_t src1, uint64_t src2)     \
     {                                                   \
         VIS64 s, d;                                     \
                                                         \
@@ -341,8 +339,7 @@ uint64_t helper_fexpand(CPUState *env, uint64_t src1, uint64_t src2)
         return d.ll;                                    \
     }                                                   \
                                                         \
-    uint32_t name##32s(CPUState *env, uint32_t src1,    \
-                       uint32_t src2)                   \
+    uint32_t name##32s(uint32_t src1, uint32_t src2)    \
     {                                                   \
         VIS32 s, d;                                     \
                                                         \
@@ -360,7 +357,7 @@ VIS_HELPER(helper_fpadd, FADD)
 VIS_HELPER(helper_fpsub, FSUB)
 
 #define VIS_CMPHELPER(name, F)                                    \
-    uint64_t name##16(CPUState *env, uint64_t src1, uint64_t src2) \
+    uint64_t name##16(uint64_t src1, uint64_t src2)               \
     {                                                             \
         VIS64 s, d;                                               \
                                                                   \
@@ -376,7 +373,7 @@ VIS_HELPER(helper_fpsub, FSUB)
         return d.ll;                                              \
     }                                                             \
                                                                   \
-    uint64_t name##32(CPUState *env, uint64_t src1, uint64_t src2) \
+    uint64_t name##32(uint64_t src1, uint64_t src2)               \
     {                                                             \
         VIS64 s, d;                                               \
                                                                   \
commit 03fb8cfc638ed18b4364949765778d7121d27f56
Author: Richard Henderson <rth at twiddle.net>
Date:   Sat Oct 15 10:20:20 2011 -0700

    target-sparc: Pass float64 parameters instead of dt0/1 temporaries.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 25b4f1a..4eace33 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -463,7 +463,6 @@ typedef struct CPUSPARCState {
     uint64_t prom_addr;
 #endif
     /* temporary float registers */
-    float64 dt0, dt1;
     float128 qt0, qt1;
     float_status fp_status;
 #if defined(TARGET_SPARC64)
diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
index 23502f3..f6348c2 100644
--- a/target-sparc/fop_helper.c
+++ b/target-sparc/fop_helper.c
@@ -20,8 +20,6 @@
 #include "cpu.h"
 #include "helper.h"
 
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
 
@@ -33,9 +31,10 @@
     {                                                           \
         return float32_ ## name (src1, src2, &env->fp_status);  \
     }                                                           \
-    F_HELPER(name, d)                                           \
+    float64 helper_f ## name ## d (CPUState * env, float64 src1,\
+                                   float64 src2)                \
     {                                                           \
-        DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
+        return float64_ ## name (src1, src2, &env->fp_status);  \
     }                                                           \
     F_HELPER(name, q)                                           \
     {                                                           \
@@ -48,17 +47,17 @@ F_BINOP(mul);
 F_BINOP(div);
 #undef F_BINOP
 
-void helper_fsmuld(CPUState *env, float32 src1, float32 src2)
+float64 helper_fsmuld(CPUState *env, float32 src1, float32 src2)
 {
-    DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
-                      float32_to_float64(src2, &env->fp_status),
-                      &env->fp_status);
+    return float64_mul(float32_to_float64(src1, &env->fp_status),
+                       float32_to_float64(src2, &env->fp_status),
+                       &env->fp_status);
 }
 
-void helper_fdmulq(CPUState *env)
+void helper_fdmulq(CPUState *env, float64 src1, float64 src2)
 {
-    QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
-                       float64_to_float128(DT1, &env->fp_status),
+    QT0 = float128_mul(float64_to_float128(src1, &env->fp_status),
+                       float64_to_float128(src2, &env->fp_status),
                        &env->fp_status);
 }
 
@@ -68,9 +67,9 @@ float32 helper_fnegs(float32 src)
 }
 
 #ifdef TARGET_SPARC64
-F_HELPER(neg, d)
+float64 helper_fnegd(float64 src)
 {
-    DT0 = float64_chs(DT1);
+    return float64_chs(src);
 }
 
 F_HELPER(neg, q)
@@ -85,9 +84,9 @@ float32 helper_fitos(CPUState *env, int32_t src)
     return int32_to_float32(src, &env->fp_status);
 }
 
-void helper_fitod(CPUState *env, int32_t src)
+float64 helper_fitod(CPUState *env, int32_t src)
 {
-    DT0 = int32_to_float64(src, &env->fp_status);
+    return int32_to_float64(src, &env->fp_status);
 }
 
 void helper_fitoq(CPUState *env, int32_t src)
@@ -96,32 +95,32 @@ void helper_fitoq(CPUState *env, int32_t src)
 }
 
 #ifdef TARGET_SPARC64
-float32 helper_fxtos(CPUState *env)
+float32 helper_fxtos(CPUState *env, int64_t src)
 {
-    return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+    return int64_to_float32(src, &env->fp_status);
 }
 
-F_HELPER(xto, d)
+float64 helper_fxtod(CPUState *env, int64_t src)
 {
-    DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+    return int64_to_float64(src, &env->fp_status);
 }
 
-F_HELPER(xto, q)
+void helper_fxtoq(CPUState *env, int64_t src)
 {
-    QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
+    QT0 = int64_to_float128(src, &env->fp_status);
 }
 #endif
 #undef F_HELPER
 
 /* floating point conversion */
-float32 helper_fdtos(CPUState *env)
+float32 helper_fdtos(CPUState *env, float64 src)
 {
-    return float64_to_float32(DT1, &env->fp_status);
+    return float64_to_float32(src, &env->fp_status);
 }
 
-void helper_fstod(CPUState *env, float32 src)
+float64 helper_fstod(CPUState *env, float32 src)
 {
-    DT0 = float32_to_float64(src, &env->fp_status);
+    return float32_to_float64(src, &env->fp_status);
 }
 
 float32 helper_fqtos(CPUState *env)
@@ -134,14 +133,14 @@ void helper_fstoq(CPUState *env, float32 src)
     QT0 = float32_to_float128(src, &env->fp_status);
 }
 
-void helper_fqtod(CPUState *env)
+float64 helper_fqtod(CPUState *env)
 {
-    DT0 = float128_to_float64(QT1, &env->fp_status);
+    return float128_to_float64(QT1, &env->fp_status);
 }
 
-void helper_fdtoq(CPUState *env)
+void helper_fdtoq(CPUState *env, float64 src)
 {
-    QT0 = float64_to_float128(DT1, &env->fp_status);
+    QT0 = float64_to_float128(src, &env->fp_status);
 }
 
 /* Float to integer conversion.  */
@@ -150,9 +149,9 @@ int32_t helper_fstoi(CPUState *env, float32 src)
     return float32_to_int32_round_to_zero(src, &env->fp_status);
 }
 
-int32_t helper_fdtoi(CPUState *env)
+int32_t helper_fdtoi(CPUState *env, float64 src)
 {
-    return float64_to_int32_round_to_zero(DT1, &env->fp_status);
+    return float64_to_int32_round_to_zero(src, &env->fp_status);
 }
 
 int32_t helper_fqtoi(CPUState *env)
@@ -161,19 +160,19 @@ int32_t helper_fqtoi(CPUState *env)
 }
 
 #ifdef TARGET_SPARC64
-void helper_fstox(CPUState *env, float32 src)
+int64_t helper_fstox(CPUState *env, float32 src)
 {
-    *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
+    return float32_to_int64_round_to_zero(src, &env->fp_status);
 }
 
-void helper_fdtox(CPUState *env)
+int64_t helper_fdtox(CPUState *env, float64 src)
 {
-    *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+    return float64_to_int64_round_to_zero(src, &env->fp_status);
 }
 
-void helper_fqtox(CPUState *env)
+int64_t helper_fqtox(CPUState *env)
 {
-    *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
+    return float128_to_int64_round_to_zero(QT1, &env->fp_status);
 }
 #endif
 
@@ -183,9 +182,9 @@ float32 helper_fabss(float32 src)
 }
 
 #ifdef TARGET_SPARC64
-void helper_fabsd(CPUState *env)
+float64 helper_fabsd(CPUState *env, float64 src)
 {
-    DT0 = float64_abs(DT1);
+    return float64_abs(src);
 }
 
 void helper_fabsq(CPUState *env)
@@ -199,9 +198,9 @@ float32 helper_fsqrts(CPUState *env, float32 src)
     return float32_sqrt(src, &env->fp_status);
 }
 
-void helper_fsqrtd(CPUState *env)
+float64 helper_fsqrtd(CPUState *env, float64 src)
 {
-    DT0 = float64_sqrt(DT1, &env->fp_status);
+    return float64_sqrt(src, &env->fp_status);
 }
 
 void helper_fsqrtq(CPUState *env)
@@ -245,8 +244,8 @@ void helper_fsqrtq(CPUState *env)
             break;                                                      \
         }                                                               \
     }
-#define GEN_FCMPS(name, size, FS, E)                                    \
-    void glue(helper_, name)(CPUState *env, float32 src1, float32 src2) \
+#define GEN_FCMP_T(name, size, FS, E)                                   \
+    void glue(helper_, name)(CPUState *env, size src1, size src2)       \
     {                                                                   \
         env->fsr &= FSR_FTT_NMASK;                                      \
         if (E && (glue(size, _is_any_nan)(src1) ||                      \
@@ -282,41 +281,42 @@ void helper_fsqrtq(CPUState *env)
         }                                                               \
     }
 
-GEN_FCMPS(fcmps, float32, 0, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+GEN_FCMP_T(fcmps, float32, 0, 0);
+GEN_FCMP_T(fcmpd, float64, 0, 0);
 
-GEN_FCMPS(fcmpes, float32, 0, 1);
-GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
+GEN_FCMP_T(fcmpes, float32, 0, 1);
+GEN_FCMP_T(fcmped, float64, 0, 1);
 
 GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
 GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
 
 #ifdef TARGET_SPARC64
-GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
+GEN_FCMP_T(fcmps_fcc1, float32, 22, 0);
+GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0);
 GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
 
-GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
+GEN_FCMP_T(fcmps_fcc2, float32, 24, 0);
+GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0);
 GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
 
-GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+GEN_FCMP_T(fcmps_fcc3, float32, 26, 0);
+GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0);
 GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
 
-GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
-GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1);
+GEN_FCMP_T(fcmped_fcc1, float64, 22, 1);
 GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
 
-GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
-GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1);
+GEN_FCMP_T(fcmped_fcc2, float64, 24, 1);
 GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
 
-GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
-GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
+GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1);
+GEN_FCMP_T(fcmped_fcc3, float64, 26, 1);
 GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
 #endif
-#undef GEN_FCMPS
+#undef GEN_FCMP_T
+#undef GEN_FCMP
 
 void helper_check_ieee_exceptions(CPUState *env)
 {
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 615ddef..86fad6e 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -39,8 +39,6 @@ DEF_HELPER_3(udiv, tl, env, tl, tl)
 DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
 DEF_HELPER_3(sdiv, tl, env, tl, tl)
 DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
-DEF_HELPER_2(stdf, void, tl, int)
-DEF_HELPER_2(lddf, void, tl, int)
 DEF_HELPER_2(ldqf, void, tl, int)
 DEF_HELPER_2(stqf, void, tl, int)
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
@@ -52,29 +50,29 @@ DEF_HELPER_1(check_ieee_exceptions, void, env)
 DEF_HELPER_1(clear_float_exceptions, void, env)
 DEF_HELPER_1(fabss, f32, f32)
 DEF_HELPER_2(fsqrts, f32, env, f32)
-DEF_HELPER_1(fsqrtd, void, env)
+DEF_HELPER_2(fsqrtd, f64, env, f64)
 DEF_HELPER_3(fcmps, void, env, f32, f32)
-DEF_HELPER_1(fcmpd, void, env)
+DEF_HELPER_3(fcmpd, void, env, f64, f64)
 DEF_HELPER_3(fcmpes, void, env, f32, f32)
-DEF_HELPER_1(fcmped, void, env)
+DEF_HELPER_3(fcmped, void, env, f64, f64)
 DEF_HELPER_1(fsqrtq, void, env)
 DEF_HELPER_1(fcmpq, void, env)
 DEF_HELPER_1(fcmpeq, void, env)
 #ifdef TARGET_SPARC64
 DEF_HELPER_2(ldxfsr, void, env, i64)
-DEF_HELPER_1(fabsd, void, env)
+DEF_HELPER_2(fabsd, f64, env, f64)
 DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
 DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
 DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
-DEF_HELPER_1(fcmpd_fcc1, void, env)
-DEF_HELPER_1(fcmpd_fcc2, void, env)
-DEF_HELPER_1(fcmpd_fcc3, void, env)
+DEF_HELPER_3(fcmpd_fcc1, void, env, f64, f64)
+DEF_HELPER_3(fcmpd_fcc2, void, env, f64, f64)
+DEF_HELPER_3(fcmpd_fcc3, void, env, f64, f64)
 DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32)
 DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32)
 DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
-DEF_HELPER_1(fcmped_fcc1, void, env)
-DEF_HELPER_1(fcmped_fcc2, void, env)
-DEF_HELPER_1(fcmped_fcc3, void, env)
+DEF_HELPER_3(fcmped_fcc1, void, env, f64, f64)
+DEF_HELPER_3(fcmped_fcc2, void, env, f64, f64)
+DEF_HELPER_3(fcmped_fcc3, void, env, f64, f64)
 DEF_HELPER_1(fabsq, void, env)
 DEF_HELPER_1(fcmpq_fcc1, void, env)
 DEF_HELPER_1(fcmpq_fcc2, void, env)
@@ -86,77 +84,78 @@ DEF_HELPER_1(fcmpeq_fcc3, void, env)
 DEF_HELPER_2(raise_exception, void, env, int)
 DEF_HELPER_0(shutdown, void)
 #define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
-#define F_HELPER_DQ_0_1(name)                   \
-    F_HELPER_0_1(name ## d);                    \
-    F_HELPER_0_1(name ## q)
 
-F_HELPER_DQ_0_1(add);
-F_HELPER_DQ_0_1(sub);
-F_HELPER_DQ_0_1(mul);
-F_HELPER_DQ_0_1(div);
+DEF_HELPER_3(faddd, f64, env, f64, f64)
+DEF_HELPER_3(fsubd, f64, env, f64, f64)
+DEF_HELPER_3(fmuld, f64, env, f64, f64)
+DEF_HELPER_3(fdivd, f64, env, f64, f64)
+F_HELPER_0_1(addq)
+F_HELPER_0_1(subq)
+F_HELPER_0_1(mulq)
+F_HELPER_0_1(divq)
 
 DEF_HELPER_3(fadds, f32, env, f32, f32)
 DEF_HELPER_3(fsubs, f32, env, f32, f32)
 DEF_HELPER_3(fmuls, f32, env, f32, f32)
 DEF_HELPER_3(fdivs, f32, env, f32, f32)
 
-DEF_HELPER_3(fsmuld, void, env, f32, f32)
-F_HELPER_0_1(dmulq);
+DEF_HELPER_3(fsmuld, f64, env, f32, f32)
+DEF_HELPER_3(fdmulq, void, env, f64, f64);
 
 DEF_HELPER_1(fnegs, f32, f32)
-DEF_HELPER_2(fitod, void, env, s32)
+DEF_HELPER_2(fitod, f64, env, s32)
 DEF_HELPER_2(fitoq, void, env, s32)
 
 DEF_HELPER_2(fitos, f32, env, s32)
 
 #ifdef TARGET_SPARC64
-DEF_HELPER_1(fnegd, void, env)
+DEF_HELPER_1(fnegd, f64, f64)
 DEF_HELPER_1(fnegq, void, env)
-DEF_HELPER_1(fxtos, i32, env)
-F_HELPER_DQ_0_1(xto);
+DEF_HELPER_2(fxtos, f32, env, s64)
+DEF_HELPER_2(fxtod, f64, env, s64)
+DEF_HELPER_2(fxtoq, void, env, s64)
 #endif
-DEF_HELPER_1(fdtos, f32, env)
-DEF_HELPER_2(fstod, void, env, f32)
+DEF_HELPER_2(fdtos, f32, env, f64)
+DEF_HELPER_2(fstod, f64, env, f32)
 DEF_HELPER_1(fqtos, f32, env)
 DEF_HELPER_2(fstoq, void, env, f32)
-F_HELPER_0_1(qtod);
-F_HELPER_0_1(dtoq);
+DEF_HELPER_1(fqtod, f64, env)
+DEF_HELPER_2(fdtoq, void, env, f64)
 DEF_HELPER_2(fstoi, s32, env, f32)
-DEF_HELPER_1(fdtoi, s32, env)
+DEF_HELPER_2(fdtoi, s32, env, f64)
 DEF_HELPER_1(fqtoi, s32, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_2(fstox, void, env, i32)
-F_HELPER_0_1(dtox);
-F_HELPER_0_1(qtox);
-F_HELPER_0_1(aligndata);
+DEF_HELPER_2(fstox, s64, env, f32)
+DEF_HELPER_2(fdtox, s64, env, f64)
+DEF_HELPER_1(fqtox, s64, env)
+DEF_HELPER_3(faligndata, i64, env, i64, i64)
 
-F_HELPER_0_1(pmerge);
-F_HELPER_0_1(mul8x16);
-F_HELPER_0_1(mul8x16al);
-F_HELPER_0_1(mul8x16au);
-F_HELPER_0_1(mul8sux16);
-F_HELPER_0_1(mul8ulx16);
-F_HELPER_0_1(muld8sux16);
-F_HELPER_0_1(muld8ulx16);
-F_HELPER_0_1(expand);
+DEF_HELPER_3(fpmerge, i64, env, i64, i64)
+DEF_HELPER_3(fmul8x16, i64, env, i64, i64)
+DEF_HELPER_3(fmul8x16al, i64, env, i64, i64)
+DEF_HELPER_3(fmul8x16au, i64, env, i64, i64)
+DEF_HELPER_3(fmul8sux16, i64, env, i64, i64)
+DEF_HELPER_3(fmul8ulx16, i64, env, i64, i64)
+DEF_HELPER_3(fmuld8sux16, i64, env, i64, i64)
+DEF_HELPER_3(fmuld8ulx16, i64, env, i64, i64)
+DEF_HELPER_3(fexpand, i64, env, i64, i64)
 #define VIS_HELPER(name)                                 \
-    F_HELPER_0_1(name##16);                              \
+    DEF_HELPER_3(f ## name ## 16, i64, env, i64, i64)    \
     DEF_HELPER_3(f ## name ## 16s, i32, env, i32, i32)   \
-    F_HELPER_0_1(name##32);                              \
+    DEF_HELPER_3(f ## name ## 32, i64, env, i64, i64)    \
     DEF_HELPER_3(f ## name ## 32s, i32, env, i32, i32)
 
 VIS_HELPER(padd);
 VIS_HELPER(psub);
 #define VIS_CMPHELPER(name)                              \
-    DEF_HELPER_1(f##name##16, i64, env);                 \
-    DEF_HELPER_1(f##name##32, i64, env)
+    DEF_HELPER_3(f##name##16, i64, env, i64, i64)        \
+    DEF_HELPER_3(f##name##32, i64, env, i64, i64)
 VIS_CMPHELPER(cmpgt);
 VIS_CMPHELPER(cmpeq);
 VIS_CMPHELPER(cmple);
 VIS_CMPHELPER(cmpne);
 #endif
 #undef F_HELPER_0_1
-#undef F_HELPER_DQ_0_1
 #undef VIS_HELPER
 #undef VIS_CMPHELPER
 DEF_HELPER_1(compute_psr, void, env);
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 1fb3996..80e5408 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -66,8 +66,6 @@
 #endif
 #endif
 
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
 
@@ -2214,56 +2212,6 @@ target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
 }
 #endif /* TARGET_SPARC64 */
 
-void helper_stdf(target_ulong addr, int mem_idx)
-{
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        stfq_user(addr, DT0);
-        break;
-    case MMU_KERNEL_IDX:
-        stfq_kernel(addr, DT0);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        stfq_hypv(addr, DT0);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    stfq_raw(address_mask(env, addr), DT0);
-#endif
-}
-
-void helper_lddf(target_ulong addr, int mem_idx)
-{
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        DT0 = ldfq_user(addr);
-        break;
-    case MMU_KERNEL_IDX:
-        DT0 = ldfq_kernel(addr);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        DT0 = ldfq_hypv(addr);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    DT0 = ldfq_raw(address_mask(env, addr));
-#endif
-}
-
 void helper_ldqf(target_ulong addr, int mem_idx)
 {
     /* XXX add 128 bit load */
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 937e711..f41ef98 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -186,30 +186,6 @@ static TCGv_i64 gen_dest_fpr_D(void)
     return cpu_tmp64;
 }
 
-static void gen_op_load_fpr_DT0(unsigned int src)
-{
-    tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, dt0) +
-                   offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_st_i32(cpu__fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
-                   offsetof(CPU_DoubleU, l.lower));
-}
-
-static void gen_op_load_fpr_DT1(unsigned int src)
-{
-    tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, dt1) +
-                   offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_st_i32(cpu__fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt1) +
-                   offsetof(CPU_DoubleU, l.lower));
-}
-
-static void gen_op_store_DT0_fpr(unsigned int dst)
-{
-    tcg_gen_ld_i32(cpu__fpr[dst], cpu_env, offsetof(CPUSPARCState, dt0) +
-                   offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_ld_i32(cpu__fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
-                   offsetof(CPU_DoubleU, l.lower));
-}
-
 static void gen_op_load_fpr_QT0(unsigned int src)
 {
     tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) +
@@ -1490,20 +1466,20 @@ static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
     }
 }
 
-static inline void gen_op_fcmpd(int fccno)
+static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpd(cpu_env);
+        gen_helper_fcmpd(cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmpd_fcc1(cpu_env);
+        gen_helper_fcmpd_fcc1(cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmpd_fcc2(cpu_env);
+        gen_helper_fcmpd_fcc2(cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmpd_fcc3(cpu_env);
+        gen_helper_fcmpd_fcc3(cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1544,20 +1520,20 @@ static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
     }
 }
 
-static inline void gen_op_fcmped(int fccno)
+static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmped(cpu_env);
+        gen_helper_fcmped(cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmped_fcc1(cpu_env);
+        gen_helper_fcmped_fcc1(cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmped_fcc2(cpu_env);
+        gen_helper_fcmped_fcc2(cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmped_fcc3(cpu_env);
+        gen_helper_fcmped_fcc3(cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1587,9 +1563,9 @@ static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
     gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
 }
 
-static inline void gen_op_fcmpd(int fccno)
+static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
-    gen_helper_fcmpd(cpu_env);
+    gen_helper_fcmpd(cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpq(int fccno)
@@ -1602,9 +1578,9 @@ static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
     gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
 }
 
-static inline void gen_op_fcmped(int fccno)
+static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
-    gen_helper_fcmped(cpu_env);
+    gen_helper_fcmped(cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpeq(int fccno)
@@ -2461,12 +2437,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x2a: /* fsqrtd */
                     CHECK_FPU_FEATURE(dc, FSQRT);
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fsqrtd(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fsqrtd(cpu_dst_64, cpu_env, cpu_src1_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x2b: /* fsqrtq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2488,13 +2464,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x42: /* faddd */
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_faddd(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_faddd(cpu_dst_64, cpu_env,
+                                     cpu_src1_64, cpu_src2_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x43: /* faddq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2517,13 +2494,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x46: /* fsubd */
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fsubd(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fsubd(cpu_dst_64, cpu_env,
+                                     cpu_src1_64, cpu_src2_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x47: /* fsubq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2548,13 +2526,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x4a: /* fmuld */
                     CHECK_FPU_FEATURE(dc, FMUL);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fmuld(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fmuld(cpu_dst_64, cpu_env,
+                                     cpu_src1_64, cpu_src2_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x4b: /* fmulq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2578,13 +2557,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x4e: /* fdivd */
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdivd(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fdivd(cpu_dst_64, cpu_env,
+                                     cpu_src1_64, cpu_src2_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x4f: /* fdivq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2601,17 +2581,18 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_clear_float_exceptions();
                     cpu_src1_32 = gen_load_fpr_F(dc, rs1);
                     cpu_src2_32 = gen_load_fpr_F(dc, rs2);
-                    gen_helper_fsmuld(cpu_env, cpu_src1_32, cpu_src2_32);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fsmuld(cpu_dst_64, cpu_env,
+                                      cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x6e: /* fdmulq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdmulq(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fdmulq(cpu_env, cpu_src1_64, cpu_src2_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
@@ -2625,10 +2606,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0xc6: /* fdtos */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fdtos(cpu_dst_32, cpu_env);
+                    gen_helper_fdtos(cpu_dst_32, cpu_env, cpu_src1_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
@@ -2643,24 +2624,24 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0xc8: /* fitod */
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    gen_helper_fitod(cpu_env, cpu_src1_32);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fitod(cpu_dst_64, cpu_env, cpu_src1_32);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0xc9: /* fstod */
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    gen_helper_fstod(cpu_env, cpu_src1_32);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fstod(cpu_dst_64, cpu_env, cpu_src1_32);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0xcb: /* fqtod */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fqtod(cpu_env);
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fqtod(cpu_dst_64, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0xcc: /* fitoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2678,8 +2659,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0xce: /* fdtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fdtoq(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fdtoq(cpu_env, cpu_src1_64);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
@@ -2692,10 +2673,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0xd2: /* fdtoi */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fdtoi(cpu_dst_32, cpu_env);
+                    gen_helper_fdtoi(cpu_dst_32, cpu_env, cpu_src1_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
@@ -2726,10 +2707,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x6: /* V9 fnegd */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fnegd(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fnegd(cpu_dst_64, cpu_src1_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x7: /* V9 fnegq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2739,10 +2720,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xa: /* V9 fabsd */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fabsd(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fabsd(cpu_dst_64, cpu_env, cpu_src1_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0xb: /* V9 fabsq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2754,49 +2735,49 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x81: /* V9 fstox */
                     gen_clear_float_exceptions();
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
-                    gen_helper_fstox(cpu_env, cpu_src1_32);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fstox(cpu_dst_64, cpu_env, cpu_src1_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x82: /* V9 fdtox */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdtox(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fdtox(cpu_dst_64, cpu_env, cpu_src1_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x83: /* V9 fqtox */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fqtox(cpu_env);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fqtox(cpu_dst_64, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x84: /* V9 fxtos */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
                     cpu_dst_32 = gen_dest_fpr_F();
-                    gen_helper_fxtos(cpu_dst_32, cpu_env);
+                    gen_helper_fxtos(cpu_dst_32, cpu_env, cpu_src1_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
                     break;
                 case 0x88: /* V9 fxtod */
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fxtod(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fxtod(cpu_dst_64, cpu_env, cpu_src1_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x8c: /* V9 fxtoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fxtoq(cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fxtoq(cpu_env, cpu_src1_64);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
@@ -3046,9 +3027,9 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fcmps(rd & 3, cpu_src1_32, cpu_src2_32);
                         break;
                     case 0x52: /* fcmpd, V9 %fcc */
-                        gen_op_load_fpr_DT0(DFPREG(rs1));
-                        gen_op_load_fpr_DT1(DFPREG(rs2));
-                        gen_op_fcmpd(rd & 3);
+                        cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                        cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                        gen_op_fcmpd(rd & 3, cpu_src1_64, cpu_src2_64);
                         break;
                     case 0x53: /* fcmpq, V9 %fcc */
                         CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -3062,9 +3043,9 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fcmpes(rd & 3, cpu_src1_32, cpu_src2_32);
                         break;
                     case 0x56: /* fcmped, V9 %fcc */
-                        gen_op_load_fpr_DT0(DFPREG(rs1));
-                        gen_op_load_fpr_DT1(DFPREG(rs2));
-                        gen_op_fcmped(rd & 3);
+                        cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                        cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                        gen_op_fcmped(rd & 3, cpu_src1_64, cpu_src2_64);
                         break;
                     case 0x57: /* fcmpeq, V9 %fcc */
                         CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -3953,115 +3934,130 @@ static void disas_sparc_insn(DisasContext * dc)
                     goto illegal_insn;
                 case 0x020: /* VIS I fcmple16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmple16(cpu_dst, cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmple16(cpu_dst, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x022: /* VIS I fcmpne16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpne16(cpu_dst, cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpne16(cpu_dst, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x024: /* VIS I fcmple32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmple32(cpu_dst, cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmple32(cpu_dst, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x026: /* VIS I fcmpne32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpne32(cpu_dst, cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpne32(cpu_dst, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x028: /* VIS I fcmpgt16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpgt16(cpu_dst, cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpgt16(cpu_dst, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02a: /* VIS I fcmpeq16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpeq16(cpu_dst, cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpeq16(cpu_dst, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02c: /* VIS I fcmpgt32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpgt32(cpu_dst, cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpgt32(cpu_dst, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x02e: /* VIS I fcmpeq32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fcmpeq32(cpu_dst, cpu_env);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    gen_helper_fcmpeq32(cpu_dst, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x031: /* VIS I fmul8x16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fmul8x16(cpu_dst_64, cpu_env,
+                                        cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x033: /* VIS I fmul8x16au */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16au(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fmul8x16au(cpu_dst_64, cpu_env,
+                                          cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x035: /* VIS I fmul8x16al */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8x16al(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fmul8x16al(cpu_dst_64, cpu_env,
+                                          cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x036: /* VIS I fmul8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8sux16(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fmul8sux16(cpu_dst_64, cpu_env,
+                                          cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x037: /* VIS I fmul8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmul8ulx16(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fmul8ulx16(cpu_dst_64, cpu_env,
+                                          cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x038: /* VIS I fmuld8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmuld8sux16(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fmuld8sux16(cpu_dst_64, cpu_env,
+                                           cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x039: /* VIS I fmuld8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fmuld8ulx16(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fmuld8ulx16(cpu_dst_64, cpu_env,
+                                           cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x03a: /* VIS I fpack32 */
                 case 0x03b: /* VIS I fpack16 */
@@ -4071,38 +4067,42 @@ static void disas_sparc_insn(DisasContext * dc)
                     goto illegal_insn;
                 case 0x048: /* VIS I faligndata */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_faligndata(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_faligndata(cpu_dst_64, cpu_env,
+                                          cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x04b: /* VIS I fpmerge */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpmerge(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fpmerge(cpu_dst_64, cpu_env,
+                                       cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x04c: /* VIS II bshuffle */
                     // XXX
                     goto illegal_insn;
                 case 0x04d: /* VIS I fexpand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fexpand(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fexpand(cpu_dst_64, cpu_env,
+                                       cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x050: /* VIS I fpadd16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpadd16(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fpadd16(cpu_dst_64, cpu_env,
+                                       cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x051: /* VIS I fpadd16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4115,11 +4115,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x052: /* VIS I fpadd32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpadd32(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fpadd32(cpu_dst_64, cpu_env,
+                                       cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x053: /* VIS I fpadd32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4131,11 +4132,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x054: /* VIS I fpsub16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpsub16(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fpsub16(cpu_dst_64, cpu_env,
+                                       cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x055: /* VIS I fpsub16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4148,11 +4150,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x056: /* VIS I fpsub32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs1));
-                    gen_op_load_fpr_DT1(DFPREG(rs2));
-                    gen_helper_fpsub32(cpu_env);
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    gen_helper_fpsub32(cpu_dst_64, cpu_env,
+                                       cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x057: /* VIS I fpsub32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4811,16 +4814,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     }
                     break;
                 case 0x23:      /* lddf, load double fpreg */
-                    {
-                        TCGv_i32 r_const;
-
-                        r_const = tcg_const_i32(dc->mem_idx);
-                        gen_address_mask(dc, cpu_addr);
-                        gen_helper_lddf(cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
-                        gen_op_store_DT0_fpr(DFPREG(rd));
-                        gen_update_fprs_dirty(DFPREG(rd));
-                    }
+                    gen_address_mask(dc, cpu_addr);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_qemu_ld64(cpu_dst_64, cpu_addr, dc->mem_idx);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 default:
                     goto illegal_insn;
@@ -4971,15 +4968,9 @@ static void disas_sparc_insn(DisasContext * dc)
 #endif
 #endif
                 case 0x27: /* stdf, store double fpreg */
-                    {
-                        TCGv_i32 r_const;
-
-                        gen_op_load_fpr_DT0(DFPREG(rd));
-                        r_const = tcg_const_i32(dc->mem_idx);
-                        gen_address_mask(dc, cpu_addr);
-                        gen_helper_stdf(cpu_addr, r_const);
-                        tcg_temp_free_i32(r_const);
-                    }
+                    gen_address_mask(dc, cpu_addr);
+                    cpu_src1_64 = gen_load_fpr_D(dc, rd);
+                    tcg_gen_qemu_st64(cpu_src1_64, cpu_addr, dc->mem_idx);
                     break;
                 default:
                     goto illegal_insn;
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index a22c10b..a007b0f 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -20,11 +20,6 @@
 #include "cpu.h"
 #include "helper.h"
 
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
-#define QT0 (env->qt0)
-#define QT1 (env->qt1)
-
 /* This function uses non-native bit order */
 #define GET_FIELD(X, FROM, TO)                                  \
     ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
@@ -58,16 +53,16 @@ target_ulong helper_alignaddr(CPUState *env, target_ulong addr,
     return tmp & ~7ULL;
 }
 
-void helper_faligndata(CPUState *env)
+uint64_t helper_faligndata(CPUState *env, uint64_t src1, uint64_t src2)
 {
     uint64_t tmp;
 
-    tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
+    tmp = src1 << ((env->gsr & 7) * 8);
     /* on many architectures a shift of 64 does nothing */
     if ((env->gsr & 7) != 0) {
-        tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
+        tmp |= src2 >> (64 - (env->gsr & 7) * 8);
     }
-    *((uint64_t *)&DT0) = tmp;
+    return tmp;
 }
 
 #ifdef HOST_WORDS_BIGENDIAN
@@ -102,12 +97,12 @@ typedef union {
     float32 f;
 } VIS32;
 
-void helper_fpmerge(CPUState *env)
+uint64_t helper_fpmerge(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
 
-    s.d = DT0;
-    d.d = DT1;
+    s.ll = src1;
+    d.ll = src2;
 
     /* Reverse calculation order to handle overlap */
     d.VIS_B64(7) = s.VIS_B64(3);
@@ -119,16 +114,16 @@ void helper_fpmerge(CPUState *env)
     d.VIS_B64(1) = s.VIS_B64(0);
     /* d.VIS_B64(0) = d.VIS_B64(0); */
 
-    DT0 = d.d;
+    return d.ll;
 }
 
-void helper_fmul8x16(CPUState *env)
+uint64_t helper_fmul8x16(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
 
-    s.d = DT0;
-    d.d = DT1;
+    s.ll = src1;
+    d.ll = src2;
 
 #define PMUL(r)                                                 \
     tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
@@ -143,16 +138,16 @@ void helper_fmul8x16(CPUState *env)
     PMUL(3);
 #undef PMUL
 
-    DT0 = d.d;
+    return d.ll;
 }
 
-void helper_fmul8x16al(CPUState *env)
+uint64_t helper_fmul8x16al(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
 
-    s.d = DT0;
-    d.d = DT1;
+    s.ll = src1;
+    d.ll = src2;
 
 #define PMUL(r)                                                 \
     tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
@@ -167,16 +162,16 @@ void helper_fmul8x16al(CPUState *env)
     PMUL(3);
 #undef PMUL
 
-    DT0 = d.d;
+    return d.ll;
 }
 
-void helper_fmul8x16au(CPUState *env)
+uint64_t helper_fmul8x16au(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
 
-    s.d = DT0;
-    d.d = DT1;
+    s.ll = src1;
+    d.ll = src2;
 
 #define PMUL(r)                                                 \
     tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
@@ -191,16 +186,16 @@ void helper_fmul8x16au(CPUState *env)
     PMUL(3);
 #undef PMUL
 
-    DT0 = d.d;
+    return d.ll;
 }
 
-void helper_fmul8sux16(CPUState *env)
+uint64_t helper_fmul8sux16(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
 
-    s.d = DT0;
-    d.d = DT1;
+    s.ll = src1;
+    d.ll = src2;
 
 #define PMUL(r)                                                         \
     tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
@@ -215,16 +210,16 @@ void helper_fmul8sux16(CPUState *env)
     PMUL(3);
 #undef PMUL
 
-    DT0 = d.d;
+    return d.ll;
 }
 
-void helper_fmul8ulx16(CPUState *env)
+uint64_t helper_fmul8ulx16(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
 
-    s.d = DT0;
-    d.d = DT1;
+    s.ll = src1;
+    d.ll = src2;
 
 #define PMUL(r)                                                         \
     tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
@@ -239,16 +234,16 @@ void helper_fmul8ulx16(CPUState *env)
     PMUL(3);
 #undef PMUL
 
-    DT0 = d.d;
+    return d.ll;
 }
 
-void helper_fmuld8sux16(CPUState *env)
+uint64_t helper_fmuld8sux16(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
 
-    s.d = DT0;
-    d.d = DT1;
+    s.ll = src1;
+    d.ll = src2;
 
 #define PMUL(r)                                                         \
     tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
@@ -262,16 +257,16 @@ void helper_fmuld8sux16(CPUState *env)
     PMUL(0);
 #undef PMUL
 
-    DT0 = d.d;
+    return d.ll;
 }
 
-void helper_fmuld8ulx16(CPUState *env)
+uint64_t helper_fmuld8ulx16(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS64 s, d;
     uint32_t tmp;
 
-    s.d = DT0;
-    d.d = DT1;
+    s.ll = src1;
+    d.ll = src2;
 
 #define PMUL(r)                                                         \
     tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
@@ -285,38 +280,38 @@ void helper_fmuld8ulx16(CPUState *env)
     PMUL(0);
 #undef PMUL
 
-    DT0 = d.d;
+    return d.ll;
 }
 
-void helper_fexpand(CPUState *env)
+uint64_t helper_fexpand(CPUState *env, uint64_t src1, uint64_t src2)
 {
     VIS32 s;
     VIS64 d;
 
-    s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
-    d.d = DT1;
+    s.l = (uint32_t)src1;
+    d.ll = src2;
     d.VIS_W64(0) = s.VIS_B32(0) << 4;
     d.VIS_W64(1) = s.VIS_B32(1) << 4;
     d.VIS_W64(2) = s.VIS_B32(2) << 4;
     d.VIS_W64(3) = s.VIS_B32(3) << 4;
 
-    DT0 = d.d;
+    return d.ll;
 }
 
 #define VIS_HELPER(name, F)                             \
-    void name##16(CPUState *env)                        \
+    uint64_t name##16(CPUState *env, uint64_t src1, uint64_t src2) \
     {                                                   \
         VIS64 s, d;                                     \
                                                         \
-        s.d = DT0;                                      \
-        d.d = DT1;                                      \
+        s.ll = src1;                                    \
+        d.ll = src2;                                    \
                                                         \
         d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
         d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
         d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
         d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
                                                         \
-        DT0 = d.d;                                      \
+        return d.ll;                                    \
     }                                                   \
                                                         \
     uint32_t name##16s(CPUState *env, uint32_t src1,    \
@@ -333,17 +328,17 @@ void helper_fexpand(CPUState *env)
         return d.l;                                     \
     }                                                   \
                                                         \
-    void name##32(CPUState *env)                        \
+    uint64_t name##32(CPUState *env, uint64_t src1, uint64_t src2) \
     {                                                   \
         VIS64 s, d;                                     \
                                                         \
-        s.d = DT0;                                      \
-        d.d = DT1;                                      \
+        s.ll = src1;                                    \
+        d.ll = src2;                                    \
                                                         \
         d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
         d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
                                                         \
-        DT0 = d.d;                                      \
+        return d.ll;                                    \
     }                                                   \
                                                         \
     uint32_t name##32s(CPUState *env, uint32_t src1,    \
@@ -365,12 +360,12 @@ VIS_HELPER(helper_fpadd, FADD)
 VIS_HELPER(helper_fpsub, FSUB)
 
 #define VIS_CMPHELPER(name, F)                                    \
-    uint64_t name##16(CPUState *env)                              \
+    uint64_t name##16(CPUState *env, uint64_t src1, uint64_t src2) \
     {                                                             \
         VIS64 s, d;                                               \
                                                                   \
-        s.d = DT0;                                                \
-        d.d = DT1;                                                \
+        s.ll = src1;                                              \
+        d.ll = src2;                                              \
                                                                   \
         d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0;     \
         d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0;    \
@@ -381,12 +376,12 @@ VIS_HELPER(helper_fpsub, FSUB)
         return d.ll;                                              \
     }                                                             \
                                                                   \
-    uint64_t name##32(CPUState *env)                              \
+    uint64_t name##32(CPUState *env, uint64_t src1, uint64_t src2) \
     {                                                             \
         VIS64 s, d;                                               \
                                                                   \
-        s.d = DT0;                                                \
-        d.d = DT1;                                                \
+        s.ll = src1;                                              \
+        d.ll = src2;                                              \
                                                                   \
         d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0;     \
         d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0;    \
commit 96eda024123402a14e39f6d336d7bee7e2bcbcf9
Author: Richard Henderson <rth at twiddle.net>
Date:   Fri Oct 14 15:47:35 2011 -0700

    target-sparc: Add accessors for double-precision fpr access.
    
    Begin using i64 quantities to manipulate double-precision values.
    On a 64-bit host this will, for the moment, generate less efficient
    code; on a 32-bit host code quality should be largely unchanged.
    Code quality for 64-bit will be adjusted with a subsequent patch.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 26f7e36..937e711 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -82,6 +82,8 @@ typedef struct DisasContext {
     uint32_t cc_op;  /* current CC operation */
     struct TranslationBlock *tb;
     sparc_def_t *def;
+    TCGv_i64 t64[3];
+    int n_t64;
 } DisasContext;
 
 // This function uses non-native bit order
@@ -129,7 +131,7 @@ static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src)
 
 static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
 {
-    tcg_gen_mov_i32 (cpu__fpr[dst], v);
+    tcg_gen_mov_i32(cpu__fpr[dst], v);
     gen_update_fprs_dirty(dst);
 }
 
@@ -138,6 +140,52 @@ static TCGv_i32 gen_dest_fpr_F(void)
     return cpu_tmp32;
 }
 
+static TCGv_i64 gen_load_fpr_D(DisasContext *dc, unsigned int src)
+{
+    TCGv_i64 ret = tcg_temp_new_i64();
+    src = DFPREG(src);
+
+#if TCG_TARGET_REG_BITS == 32
+    tcg_gen_mov_i32(TCGV_HIGH(ret), cpu__fpr[src]);
+    tcg_gen_mov_i32(TCGV_LOW(ret), cpu__fpr[src + 1]);
+#else
+    {
+        TCGv_i64 t = tcg_temp_new_i64();
+        tcg_gen_extu_i32_i64(ret, cpu__fpr[src]);
+        tcg_gen_extu_i32_i64(t, cpu__fpr[src + 1]);
+        tcg_gen_shli_i64(ret, ret, 32);
+        tcg_gen_or_i64(ret, ret, t);
+        tcg_temp_free_i64(t);
+    }
+#endif
+
+    dc->t64[dc->n_t64++] = ret;
+    assert(dc->n_t64 <= ARRAY_SIZE(dc->t64));
+
+    return ret;
+}
+
+static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v)
+{
+    dst = DFPREG(dst);
+
+#if TCG_TARGET_REG_BITS == 32
+    tcg_gen_mov_i32(cpu__fpu[dst], TCGV_HIGH(v));
+    tcg_gen_mov_i32(cpu__fpu[dst + 1], TCGV_LOW(v));
+#else
+    tcg_gen_trunc_i64_i32(cpu__fpr[dst + 1], v);
+    tcg_gen_shri_i64(v, v, 32);
+    tcg_gen_trunc_i64_i32(cpu__fpr[dst], v);
+#endif
+
+    gen_update_fprs_dirty(dst);
+}
+
+static TCGv_i64 gen_dest_fpr_D(void)
+{
+    return cpu_tmp64;
+}
+
 static void gen_op_load_fpr_DT0(unsigned int src)
 {
     tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, dt0) +
@@ -1909,6 +1957,7 @@ static void disas_sparc_insn(DisasContext * dc)
     unsigned int insn, opc, rs1, rs2, rd;
     TCGv cpu_src1, cpu_src2, cpu_tmp1, cpu_tmp2;
     TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32;
+    TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64;
     target_long simm;
 
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
@@ -2661,11 +2710,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 fmovd */
-                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    gen_store_fpr_D(dc, rd, cpu_src1_64);
                     break;
                 case 0x3: /* V9 fmovq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2791,9 +2837,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1 = get_src1(insn, cpu_src1);
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
-                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)], cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1], cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    gen_store_fpr_D(dc, rd, cpu_src1_64);
                     gen_set_label(l1);
                     break;
                 } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr
@@ -2843,11 +2888,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_fcond(r_cond, fcc, cond);                   \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)],           \
-                                        cpu__fpr[DFPREG(rs2)]);         \
-                        tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1],       \
-                                        cpu__fpr[DFPREG(rs2) + 1]);     \
-                        gen_update_fprs_dirty(DFPREG(rd));              \
+                        cpu_src1_64 = gen_load_fpr_D(dc, rs2);          \
+                        gen_store_fpr_D(dc, rd, cpu_src1_64);           \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2944,10 +2986,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_cond(r_cond, icc, cond, dc);                \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)],           \
-                                        cpu__fpr[DFPREG(rs2)]);         \
-                        tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1],       \
-                                        cpu__fpr[DFPREG(rs2) + 1]);     \
+                        cpu_src1_64 = gen_load_fpr_D(dc, rs2);          \
+                        gen_store_fpr_D(dc, rd, cpu_src1_64);           \
                         gen_update_fprs_dirty(DFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
@@ -4124,9 +4164,9 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x060: /* VIS I fzero */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu__fpr[DFPREG(rd)], 0);
-                    tcg_gen_movi_i32(cpu__fpr[DFPREG(rd) + 1], 0);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_movi_i64(cpu_dst_64, 0);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x061: /* VIS I fzeros */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4136,13 +4176,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x062: /* VIS I fnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nor_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs1)],
-                                    cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_nor_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs1) + 1],
-                                    cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_nor_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x063: /* VIS I fnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4154,13 +4192,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x064: /* VIS I fandnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu__fpr[DFPREG(rd)],
-                                     cpu__fpr[DFPREG(rs1)],
-                                     cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_andc_i32(cpu__fpr[DFPREG(rd) + 1],
-                                     cpu__fpr[DFPREG(rs1) + 1],
-                                     cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_andc_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x065: /* VIS I fandnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4172,11 +4208,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x066: /* VIS I fnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_not_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_not_i64(cpu_dst_64, cpu_src1_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x067: /* VIS I fnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4187,13 +4222,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x068: /* VIS I fandnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu__fpr[DFPREG(rd)],
-                                     cpu__fpr[DFPREG(rs2)],
-                                     cpu__fpr[DFPREG(rs1)]);
-                    tcg_gen_andc_i32(cpu__fpr[DFPREG(rd) + 1],
-                                     cpu__fpr[DFPREG(rs2) + 1],
-                                     cpu__fpr[DFPREG(rs1) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_andc_i64(cpu_dst_64, cpu_src2_64, cpu_src1_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x069: /* VIS I fandnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4205,11 +4238,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x06a: /* VIS I fnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs1)]);
-                    tcg_gen_not_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs1) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_not_i64(cpu_dst_64, cpu_src1_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x06b: /* VIS I fnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4220,13 +4252,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x06c: /* VIS I fxor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xor_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs1)],
-                                    cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_xor_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs1) + 1],
-                                    cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_xor_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x06d: /* VIS I fxors */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4238,13 +4268,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x06e: /* VIS I fnand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nand_i32(cpu__fpr[DFPREG(rd)],
-                                     cpu__fpr[DFPREG(rs1)],
-                                     cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_nand_i32(cpu__fpr[DFPREG(rd) + 1],
-                                     cpu__fpr[DFPREG(rs1) + 1],
-                                     cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_nand_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x06f: /* VIS I fnands */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4256,13 +4284,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x070: /* VIS I fand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_and_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs1)],
-                                    cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_and_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs1) + 1],
-                                    cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_and_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x071: /* VIS I fands */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4274,13 +4300,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x072: /* VIS I fxnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_eqv_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs1)],
-                                    cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_eqv_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs1) + 1],
-                                    cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_eqv_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x073: /* VIS I fxnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4292,11 +4316,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x074: /* VIS I fsrc1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs1)]);
-                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs1) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    gen_store_fpr_D(dc, rd, cpu_src1_64);
                     break;
                 case 0x075: /* VIS I fsrc1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4305,13 +4326,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x076: /* VIS I fornot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs1)],
-                                    cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_orc_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs1) + 1],
-                                    cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_orc_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x077: /* VIS I fornot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4323,9 +4342,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x078: /* VIS I fsrc2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_op_load_fpr_DT0(DFPREG(rs2));
-                    gen_op_store_DT0_fpr(DFPREG(rd));
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs2);
+                    gen_store_fpr_D(dc, rd, cpu_src1_64);
                     break;
                 case 0x079: /* VIS I fsrc2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4334,13 +4352,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x07a: /* VIS I fornot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu__fpr[DFPREG(rd)],
-                                    cpu__fpr[DFPREG(rs2)],
-                                    cpu__fpr[DFPREG(rs1)]);
-                    tcg_gen_orc_i32(cpu__fpr[DFPREG(rd) + 1],
-                                    cpu__fpr[DFPREG(rs2) + 1],
-                                    cpu__fpr[DFPREG(rs1) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_orc_i64(cpu_dst_64, cpu_src2_64, cpu_src1_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x07b: /* VIS I fornot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4352,13 +4368,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x07c: /* VIS I for */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_or_i32(cpu__fpr[DFPREG(rd)],
-                                   cpu__fpr[DFPREG(rs1)],
-                                   cpu__fpr[DFPREG(rs2)]);
-                    tcg_gen_or_i32(cpu__fpr[DFPREG(rd) + 1],
-                                   cpu__fpr[DFPREG(rs1) + 1],
-                                   cpu__fpr[DFPREG(rs2) + 1]);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_src1_64 = gen_load_fpr_D(dc, rs1);
+                    cpu_src2_64 = gen_load_fpr_D(dc, rs2);
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_or_i64(cpu_dst_64, cpu_src1_64, cpu_src2_64);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x07d: /* VIS I fors */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4370,9 +4384,9 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x07e: /* VIS I fone */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu__fpr[DFPREG(rd)], -1);
-                    tcg_gen_movi_i32(cpu__fpr[DFPREG(rd) + 1], -1);
-                    gen_update_fprs_dirty(DFPREG(rd));
+                    cpu_dst_64 = gen_dest_fpr_D();
+                    tcg_gen_movi_i64(cpu_dst_64, -1);
+                    gen_store_fpr_D(dc, rd, cpu_dst_64);
                     break;
                 case 0x07f: /* VIS I fones */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -5199,6 +5213,10 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
     tcg_temp_free_i64(cpu_tmp64);
     tcg_temp_free_i32(cpu_tmp32);
     tcg_temp_free(cpu_tmp0);
+    for (j = dc->n_t64 - 1; j >= 0; --j) {
+        tcg_temp_free_i64(dc->t64[j]);
+    }
+
     if (tb->cflags & CF_LAST_IO)
         gen_io_end();
     if (!dc->is_br) {
commit 141ae5c13f2a0ac51c7ae7dfe17dbfb91d931110
Author: Richard Henderson <rth at twiddle.net>
Date:   Fri Oct 14 15:03:25 2011 -0700

    target-sparc: Mark fprs dirty in store accessor.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index da52ce6..26f7e36 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -114,6 +114,13 @@ static int sign_extend(int x, int len)
 
 #define IS_IMM (insn & (1<<13))
 
+static inline void gen_update_fprs_dirty(int rd)
+{
+#if defined(TARGET_SPARC64)
+    tcg_gen_ori_i32(cpu_fprs, cpu_fprs, (rd < 32) ? 1 : 2);
+#endif
+}
+
 /* floating point registers moves */
 static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src)
 {
@@ -123,6 +130,7 @@ static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src)
 static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
 {
     tcg_gen_mov_i32 (cpu__fpr[dst], v);
+    gen_update_fprs_dirty(dst);
 }
 
 static TCGv_i32 gen_dest_fpr_F(void)
@@ -1585,13 +1593,6 @@ static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond)
     return 0;
 }
 
-static inline void gen_update_fprs_dirty(int rd)
-{
-#if defined(TARGET_SPARC64)
-    tcg_gen_ori_i32(cpu_fprs, cpu_fprs, (rd < 32) ? 1 : 2);
-#endif
-}
-
 static inline void gen_op_clear_ieee_excp_and_FTT(void)
 {
     tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK);
@@ -2387,21 +2388,18 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x1: /* fmovs */
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
                     gen_store_fpr_F(dc, rd, cpu_src1_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x5: /* fnegs */
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
                     cpu_dst_32 = gen_dest_fpr_F();
                     gen_helper_fnegs(cpu_dst_32, cpu_src1_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x9: /* fabss */
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
                     cpu_dst_32 = gen_dest_fpr_F();
                     gen_helper_fabss(cpu_dst_32, cpu_src1_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x29: /* fsqrts */
                     CHECK_FPU_FEATURE(dc, FSQRT);
@@ -2411,7 +2409,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fsqrts(cpu_dst_32, cpu_env, cpu_src1_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x2a: /* fsqrtd */
                     CHECK_FPU_FEATURE(dc, FSQRT);
@@ -2440,7 +2437,6 @@ static void disas_sparc_insn(DisasContext * dc)
                                      cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x42: /* faddd */
                     gen_op_load_fpr_DT0(DFPREG(rs1));
@@ -2470,7 +2466,6 @@ static void disas_sparc_insn(DisasContext * dc)
                                      cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x46: /* fsubd */
                     gen_op_load_fpr_DT0(DFPREG(rs1));
@@ -2501,7 +2496,6 @@ static void disas_sparc_insn(DisasContext * dc)
                                      cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x4a: /* fmuld */
                     CHECK_FPU_FEATURE(dc, FMUL);
@@ -2533,7 +2527,6 @@ static void disas_sparc_insn(DisasContext * dc)
                                      cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x4e: /* fdivd */
                     gen_op_load_fpr_DT0(DFPREG(rs1));
@@ -2581,7 +2574,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fitos(cpu_dst_32, cpu_env, cpu_src1_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xc6: /* fdtos */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
@@ -2590,7 +2582,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fdtos(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xc7: /* fqtos */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2600,7 +2591,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fqtos(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xc8: /* fitod */
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
@@ -2651,7 +2641,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fstoi(cpu_dst_32, cpu_env, cpu_src1_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xd2: /* fdtoi */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
@@ -2660,7 +2649,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fdtoi(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0xd3: /* fqtoi */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
@@ -2670,7 +2658,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fqtoi(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 fmovd */
@@ -2750,7 +2737,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fxtos(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x88: /* V9 fxtod */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
@@ -2795,7 +2781,6 @@ static void disas_sparc_insn(DisasContext * dc)
                                        0, l1);
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
                     gen_store_fpr_F(dc, rd, cpu_src1_32);
-                    gen_update_fprs_dirty(rd);
                     gen_set_label(l1);
                     break;
                 } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr
@@ -2844,7 +2829,6 @@ static void disas_sparc_insn(DisasContext * dc)
                                            0, l1);                      \
                         cpu_src1_32 = gen_load_fpr_F(dc, rs2);          \
                         gen_store_fpr_F(dc, rd, cpu_src1_32);           \
-                        gen_update_fprs_dirty(rd);                      \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -2946,7 +2930,6 @@ static void disas_sparc_insn(DisasContext * dc)
                                            0, l1);                      \
                         cpu_src1_32 = gen_load_fpr_F(dc, rs2);          \
                         gen_store_fpr_F(dc, rd, cpu_src1_32);           \
-                        gen_update_fprs_dirty(rd);                      \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
                     }
@@ -4089,7 +4072,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fpadd16s(cpu_dst_32, cpu_env,
                                         cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x052: /* VIS I fpadd32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4106,7 +4088,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_add_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x054: /* VIS I fpsub16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4124,7 +4105,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_helper_fpsub16s(cpu_dst_32, cpu_env,
                                         cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x056: /* VIS I fpsub32 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4141,7 +4121,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_sub_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x060: /* VIS I fzero */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4154,7 +4133,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_movi_i32(cpu_dst_32, 0);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x062: /* VIS I fnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4173,7 +4151,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_nor_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x064: /* VIS I fandnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4192,7 +4169,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_andc_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x066: /* VIS I fnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4208,7 +4184,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_not_i32(cpu_dst_32, cpu_src1_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x068: /* VIS I fandnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4227,7 +4202,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_andc_i32(cpu_dst_32, cpu_src2_32, cpu_src1_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x06a: /* VIS I fnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4243,7 +4217,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_not_i32(cpu_dst_32, cpu_src1_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x06c: /* VIS I fxor */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4262,7 +4235,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_xor_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x06e: /* VIS I fnand */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4281,7 +4253,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_nand_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x070: /* VIS I fand */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4300,7 +4271,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_and_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x072: /* VIS I fxnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4319,7 +4289,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_eqv_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x074: /* VIS I fsrc1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4333,7 +4302,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_32 = gen_load_fpr_F(dc, rs1);
                     gen_store_fpr_F(dc, rd, cpu_src1_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x076: /* VIS I fornot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4352,7 +4320,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_orc_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x078: /* VIS I fsrc2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4364,7 +4331,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     CHECK_FPU_FEATURE(dc, VIS1);
                     cpu_src1_32 = gen_load_fpr_F(dc, rs2);
                     gen_store_fpr_F(dc, rd, cpu_src1_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x07a: /* VIS I fornot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4383,7 +4349,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_orc_i32(cpu_dst_32, cpu_src2_32, cpu_src1_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x07c: /* VIS I for */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4402,7 +4367,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_or_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x07e: /* VIS I fone */
                     CHECK_FPU_FEATURE(dc, VIS1);
@@ -4415,7 +4379,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_movi_i32(cpu_dst_32, -1);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x080: /* VIS I shutdown */
                 case 0x081: /* VIS II siam */
@@ -4801,7 +4764,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_dst_32 = gen_dest_fpr_F();
                     tcg_gen_trunc_tl_i32(cpu_dst_32, cpu_tmp0);
                     gen_store_fpr_F(dc, rd, cpu_dst_32);
-                    gen_update_fprs_dirty(rd);
                     break;
                 case 0x21:      /* ldfsr, V9 ldxfsr */
 #ifdef TARGET_SPARC64
commit 208ae65722a27033bc88d07bf047f1f0c89c77de
Author: Richard Henderson <rth at twiddle.net>
Date:   Fri Oct 14 14:58:32 2011 -0700

    target-sparc: Add accessors for single-precision fpr access.
    
    Load, store, and "create destination".  This version attempts to
    change the behaviour of the translator as little as possible.  We
    previously used cpu_tmp32 as the temporary destination, and we
    continue to use that.  This will eventually allow a change in
    representation of the fprs.
    
    Change the name of the cpu_fpr array to make certain that all
    instances are converted.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 383fd9c..da52ce6 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -63,7 +63,7 @@ static TCGv cpu_tmp0;
 static TCGv_i32 cpu_tmp32;
 static TCGv_i64 cpu_tmp64;
 /* Floating point registers */
-static TCGv_i32 cpu_fpr[TARGET_FPREGS];
+static TCGv_i32 cpu__fpr[TARGET_FPREGS];
 
 static target_ulong gen_opc_npc[OPC_BUF_SIZE];
 static target_ulong gen_opc_jump_pc[2];
@@ -115,63 +115,78 @@ static int sign_extend(int x, int len)
 #define IS_IMM (insn & (1<<13))
 
 /* floating point registers moves */
+static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src)
+{
+    return cpu__fpr[src];
+}
+
+static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v)
+{
+    tcg_gen_mov_i32 (cpu__fpr[dst], v);
+}
+
+static TCGv_i32 gen_dest_fpr_F(void)
+{
+    return cpu_tmp32;
+}
+
 static void gen_op_load_fpr_DT0(unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, dt0) +
+    tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, dt0) +
                    offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
+    tcg_gen_st_i32(cpu__fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
                    offsetof(CPU_DoubleU, l.lower));
 }
 
 static void gen_op_load_fpr_DT1(unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, dt1) +
+    tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, dt1) +
                    offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt1) +
+    tcg_gen_st_i32(cpu__fpr[src + 1], cpu_env, offsetof(CPUSPARCState, dt1) +
                    offsetof(CPU_DoubleU, l.lower));
 }
 
 static void gen_op_store_DT0_fpr(unsigned int dst)
 {
-    tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, dt0) +
+    tcg_gen_ld_i32(cpu__fpr[dst], cpu_env, offsetof(CPUSPARCState, dt0) +
                    offsetof(CPU_DoubleU, l.upper));
-    tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
+    tcg_gen_ld_i32(cpu__fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, dt0) +
                    offsetof(CPU_DoubleU, l.lower));
 }
 
 static void gen_op_load_fpr_QT0(unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_st_i32(cpu__fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_st_i32(cpu__fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.lower));
-    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_st_i32(cpu__fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.lowest));
 }
 
 static void gen_op_load_fpr_QT1(unsigned int src)
 {
-    tcg_gen_st_i32(cpu_fpr[src], cpu_env, offsetof(CPUSPARCState, qt1) +
+    tcg_gen_st_i32(cpu__fpr[src], cpu_env, offsetof(CPUSPARCState, qt1) +
                    offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_st_i32(cpu_fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
+    tcg_gen_st_i32(cpu__fpr[src + 1], cpu_env, offsetof(CPUSPARCState, qt1) +
                    offsetof(CPU_QuadU, l.upper));
-    tcg_gen_st_i32(cpu_fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt1) +
+    tcg_gen_st_i32(cpu__fpr[src + 2], cpu_env, offsetof(CPUSPARCState, qt1) +
                    offsetof(CPU_QuadU, l.lower));
-    tcg_gen_st_i32(cpu_fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt1) +
+    tcg_gen_st_i32(cpu__fpr[src + 3], cpu_env, offsetof(CPUSPARCState, qt1) +
                    offsetof(CPU_QuadU, l.lowest));
 }
 
 static void gen_op_store_QT0_fpr(unsigned int dst)
 {
-    tcg_gen_ld_i32(cpu_fpr[dst], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_ld_i32(cpu__fpr[dst], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.upmost));
-    tcg_gen_ld_i32(cpu_fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_ld_i32(cpu__fpr[dst + 1], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.upper));
-    tcg_gen_ld_i32(cpu_fpr[dst + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_ld_i32(cpu__fpr[dst + 2], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.lower));
-    tcg_gen_ld_i32(cpu_fpr[dst + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
+    tcg_gen_ld_i32(cpu__fpr[dst + 3], cpu_env, offsetof(CPUSPARCState, qt0) +
                    offsetof(CPU_QuadU, l.lowest));
 }
 
@@ -1892,6 +1907,7 @@ static void disas_sparc_insn(DisasContext * dc)
 {
     unsigned int insn, opc, rs1, rs2, rd;
     TCGv cpu_src1, cpu_src2, cpu_tmp1, cpu_tmp2;
+    TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32;
     target_long simm;
 
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
@@ -2369,23 +2385,32 @@ static void disas_sparc_insn(DisasContext * dc)
                 save_state(dc, cpu_cond);
                 switch (xop) {
                 case 0x1: /* fmovs */
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_store_fpr_F(dc, rd, cpu_src1_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x5: /* fnegs */
-                    gen_helper_fnegs(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fnegs(cpu_dst_32, cpu_src1_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x9: /* fabss */
-                    gen_helper_fabss(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fabss(cpu_dst_32, cpu_src1_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x29: /* fsqrts */
                     CHECK_FPU_FEATURE(dc, FSQRT);
                     gen_clear_float_exceptions();
-                    gen_helper_fsqrts(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fsqrts(cpu_dst_32, cpu_env, cpu_src1_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x2a: /* fsqrtd */
@@ -2408,10 +2433,13 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x41: /* fadds */
                     gen_clear_float_exceptions();
-                    gen_helper_fadds(cpu_tmp32, cpu_env, cpu_fpr[rs1],
-                                     cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fadds(cpu_dst_32, cpu_env,
+                                     cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x42: /* faddd */
@@ -2435,10 +2463,13 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x45: /* fsubs */
                     gen_clear_float_exceptions();
-                    gen_helper_fsubs(cpu_tmp32, cpu_env, cpu_fpr[rs1],
-                                     cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fsubs(cpu_dst_32, cpu_env,
+                                     cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x46: /* fsubd */
@@ -2463,10 +2494,13 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x49: /* fmuls */
                     CHECK_FPU_FEATURE(dc, FMUL);
                     gen_clear_float_exceptions();
-                    gen_helper_fmuls(cpu_tmp32, cpu_env, cpu_fpr[rs1],
-                                     cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fmuls(cpu_dst_32, cpu_env,
+                                     cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x4a: /* fmuld */
@@ -2492,10 +2526,13 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x4d: /* fdivs */
                     gen_clear_float_exceptions();
-                    gen_helper_fdivs(cpu_tmp32, cpu_env, cpu_fpr[rs1],
-                                     cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fdivs(cpu_dst_32, cpu_env,
+                                     cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x4e: /* fdivd */
@@ -2520,7 +2557,9 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x69: /* fsmuld */
                     CHECK_FPU_FEATURE(dc, FSMULD);
                     gen_clear_float_exceptions();
-                    gen_helper_fsmuld(cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    gen_helper_fsmuld(cpu_env, cpu_src1_32, cpu_src2_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
@@ -2537,35 +2576,41 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0xc4: /* fitos */
                     gen_clear_float_exceptions();
-                    gen_helper_fitos(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fitos(cpu_dst_32, cpu_env, cpu_src1_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0xc6: /* fdtos */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdtos(cpu_tmp32, cpu_env);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fdtos(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0xc7: /* fqtos */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fqtos(cpu_tmp32, cpu_env);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fqtos(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0xc8: /* fitod */
-                    gen_helper_fitod(cpu_env, cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_helper_fitod(cpu_env, cpu_src1_32);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0xc9: /* fstod */
-                    gen_helper_fstod(cpu_env, cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_helper_fstod(cpu_env, cpu_src1_32);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
@@ -2580,13 +2625,15 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0xcc: /* fitoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_helper_fitoq(cpu_env, cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_helper_fitoq(cpu_env, cpu_src1_32);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0xcd: /* fstoq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    gen_helper_fstoq(cpu_env, cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_helper_fstoq(cpu_env, cpu_src1_32);
                     gen_op_store_QT0_fpr(QFPREG(rd));
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
@@ -2599,44 +2646,50 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0xd1: /* fstoi */
                     gen_clear_float_exceptions();
-                    gen_helper_fstoi(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fstoi(cpu_dst_32, cpu_env, cpu_src1_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0xd2: /* fdtoi */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fdtoi(cpu_tmp32, cpu_env);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fdtoi(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0xd3: /* fqtoi */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
                     gen_op_load_fpr_QT1(QFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fqtoi(cpu_tmp32, cpu_env);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fqtoi(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 fmovd */
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x3: /* V9 fmovq */
                     CHECK_FPU_FEATURE(dc, FLOAT128);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], cpu_fpr[QFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],
-                                    cpu_fpr[QFPREG(rs2) + 1]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],
-                                    cpu_fpr[QFPREG(rs2) + 2]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],
-                                    cpu_fpr[QFPREG(rs2) + 3]);
+                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd)],
+                                    cpu__fpr[QFPREG(rs2)]);
+                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 1],
+                                    cpu__fpr[QFPREG(rs2) + 1]);
+                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 2],
+                                    cpu__fpr[QFPREG(rs2) + 2]);
+                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 3],
+                                    cpu__fpr[QFPREG(rs2) + 3]);
                     gen_update_fprs_dirty(QFPREG(rd));
                     break;
                 case 0x6: /* V9 fnegd */
@@ -2667,7 +2720,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x81: /* V9 fstox */
                     gen_clear_float_exceptions();
-                    gen_helper_fstox(cpu_env, cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_helper_fstox(cpu_env, cpu_src1_32);
                     gen_helper_check_ieee_exceptions(cpu_env);
                     gen_op_store_DT0_fpr(DFPREG(rd));
                     gen_update_fprs_dirty(DFPREG(rd));
@@ -2692,9 +2746,10 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x84: /* V9 fxtos */
                     gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_clear_float_exceptions();
-                    gen_helper_fxtos(cpu_tmp32, cpu_env);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fxtos(cpu_dst_32, cpu_env);
                     gen_helper_check_ieee_exceptions(cpu_env);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x88: /* V9 fxtod */
@@ -2738,7 +2793,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1 = get_src1(insn, cpu_src1);
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_store_fpr_F(dc, rd, cpu_src1_32);
                     gen_update_fprs_dirty(rd);
                     gen_set_label(l1);
                     break;
@@ -2750,8 +2806,8 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1 = get_src1(insn, cpu_src1);
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1], cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)], cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1], cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     gen_set_label(l1);
                     break;
@@ -2764,10 +2820,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     cpu_src1 = get_src1(insn, cpu_src1);
                     tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1,
                                        0, l1);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], cpu_fpr[QFPREG(rs2)]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1], cpu_fpr[QFPREG(rs2) + 1]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2], cpu_fpr[QFPREG(rs2) + 2]);
-                    tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3], cpu_fpr[QFPREG(rs2) + 3]);
+                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd)], cpu__fpr[QFPREG(rs2)]);
+                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 1], cpu__fpr[QFPREG(rs2) + 1]);
+                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 2], cpu__fpr[QFPREG(rs2) + 2]);
+                    tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 3], cpu__fpr[QFPREG(rs2) + 3]);
                     gen_update_fprs_dirty(QFPREG(rd));
                     gen_set_label(l1);
                     break;
@@ -2786,7 +2842,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_fcond(r_cond, fcc, cond);                   \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);     \
+                        cpu_src1_32 = gen_load_fpr_F(dc, rs2);          \
+                        gen_store_fpr_F(dc, rd, cpu_src1_32);           \
                         gen_update_fprs_dirty(rd);                      \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
@@ -2802,10 +2859,10 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_fcond(r_cond, fcc, cond);                   \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)],            \
-                                        cpu_fpr[DFPREG(rs2)]);          \
-                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],        \
-                                        cpu_fpr[DFPREG(rs2) + 1]);      \
+                        tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)],           \
+                                        cpu__fpr[DFPREG(rs2)]);         \
+                        tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1],       \
+                                        cpu__fpr[DFPREG(rs2) + 1]);     \
                         gen_update_fprs_dirty(DFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
@@ -2821,14 +2878,14 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_fcond(r_cond, fcc, cond);                   \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)],            \
-                                        cpu_fpr[QFPREG(rs2)]);          \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],        \
-                                        cpu_fpr[QFPREG(rs2) + 1]);      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],        \
-                                        cpu_fpr[QFPREG(rs2) + 2]);      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],        \
-                                        cpu_fpr[QFPREG(rs2) + 3]);      \
+                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd)],           \
+                                        cpu__fpr[QFPREG(rs2)]);         \
+                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 1],       \
+                                        cpu__fpr[QFPREG(rs2) + 1]);     \
+                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 2],       \
+                                        cpu__fpr[QFPREG(rs2) + 2]);     \
+                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 3],       \
+                                        cpu__fpr[QFPREG(rs2) + 3]);     \
                         gen_update_fprs_dirty(QFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
@@ -2887,7 +2944,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_cond(r_cond, icc, cond, dc);                \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);     \
+                        cpu_src1_32 = gen_load_fpr_F(dc, rs2);          \
+                        gen_store_fpr_F(dc, rd, cpu_src1_32);           \
                         gen_update_fprs_dirty(rd);                      \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
@@ -2903,10 +2961,10 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_cond(r_cond, icc, cond, dc);                \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)],            \
-                                        cpu_fpr[DFPREG(rs2)]);          \
-                        tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],        \
-                                        cpu_fpr[DFPREG(rs2) + 1]);      \
+                        tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)],           \
+                                        cpu__fpr[DFPREG(rs2)]);         \
+                        tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1],       \
+                                        cpu__fpr[DFPREG(rs2) + 1]);     \
                         gen_update_fprs_dirty(DFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
@@ -2922,14 +2980,14 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_cond(r_cond, icc, cond, dc);                \
                         tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond,         \
                                            0, l1);                      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)],            \
-                                        cpu_fpr[QFPREG(rs2)]);          \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],        \
-                                        cpu_fpr[QFPREG(rs2) + 1]);      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],        \
-                                        cpu_fpr[QFPREG(rs2) + 2]);      \
-                        tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],        \
-                                        cpu_fpr[QFPREG(rs2) + 3]);      \
+                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd)],           \
+                                        cpu__fpr[QFPREG(rs2)]);         \
+                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 1],       \
+                                        cpu__fpr[QFPREG(rs2) + 1]);     \
+                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 2],       \
+                                        cpu__fpr[QFPREG(rs2) + 2]);     \
+                        tcg_gen_mov_i32(cpu__fpr[QFPREG(rd) + 3],       \
+                                        cpu__fpr[QFPREG(rs2) + 3]);     \
                         gen_update_fprs_dirty(QFPREG(rd));              \
                         gen_set_label(l1);                              \
                         tcg_temp_free(r_cond);                          \
@@ -2960,7 +3018,9 @@ static void disas_sparc_insn(DisasContext * dc)
 #undef FMOVQCC
 #endif
                     case 0x51: /* fcmps, V9 %fcc */
-                        gen_op_fcmps(rd & 3, cpu_fpr[rs1], cpu_fpr[rs2]);
+                        cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                        cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                        gen_op_fcmps(rd & 3, cpu_src1_32, cpu_src2_32);
                         break;
                     case 0x52: /* fcmpd, V9 %fcc */
                         gen_op_load_fpr_DT0(DFPREG(rs1));
@@ -2974,7 +3034,9 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fcmpq(rd & 3);
                         break;
                     case 0x55: /* fcmpes, V9 %fcc */
-                        gen_op_fcmpes(rd & 3, cpu_fpr[rs1], cpu_fpr[rs2]);
+                        cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                        cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                        gen_op_fcmpes(rd & 3, cpu_src1_32, cpu_src2_32);
                         break;
                     case 0x56: /* fcmped, V9 %fcc */
                         gen_op_load_fpr_DT0(DFPREG(rs1));
@@ -4021,8 +4083,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x051: /* VIS I fpadd16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpadd16s(cpu_fpr[rd], cpu_env,
-                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fpadd16s(cpu_dst_32, cpu_env,
+                                        cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x052: /* VIS I fpadd32 */
@@ -4035,8 +4101,11 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x053: /* VIS I fpadd32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpadd32s(cpu_fpr[rd], cpu_env,
-                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_add_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x054: /* VIS I fpsub16 */
@@ -4049,8 +4118,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x055: /* VIS I fpsub16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpsub16s(cpu_fpr[rd], cpu_env,
-                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    gen_helper_fpsub16s(cpu_dst_32, cpu_env,
+                                        cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x056: /* VIS I fpsub32 */
@@ -4063,169 +4136,222 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x057: /* VIS I fpsub32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpsub32s(cpu_fpr[rd], cpu_env,
-                                        cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_sub_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x060: /* VIS I fzero */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], 0);
-                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], 0);
+                    tcg_gen_movi_i32(cpu__fpr[DFPREG(rd)], 0);
+                    tcg_gen_movi_i32(cpu__fpr[DFPREG(rd) + 1], 0);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x061: /* VIS I fzeros */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu_fpr[rd], 0);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_movi_i32(cpu_dst_32, 0);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x062: /* VIS I fnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nor_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                    cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_nor_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_nor_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs1)],
+                                    cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_nor_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs1) + 1],
+                                    cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x063: /* VIS I fnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nor_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_nor_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x064: /* VIS I fandnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                     cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1],
-                                     cpu_fpr[DFPREG(rs1) + 1],
-                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_andc_i32(cpu__fpr[DFPREG(rd)],
+                                     cpu__fpr[DFPREG(rs1)],
+                                     cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_andc_i32(cpu__fpr[DFPREG(rd) + 1],
+                                     cpu__fpr[DFPREG(rs1) + 1],
+                                     cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x065: /* VIS I fandnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_andc_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x066: /* VIS I fnot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_not_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_not_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x067: /* VIS I fnot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_not_i32(cpu_dst_32, cpu_src1_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x068: /* VIS I fandnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)],
-                                     cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_andc_i32(cpu_fpr[DFPREG(rd) + 1],
-                                     cpu_fpr[DFPREG(rs2) + 1],
-                                     cpu_fpr[DFPREG(rs1) + 1]);
+                    tcg_gen_andc_i32(cpu__fpr[DFPREG(rd)],
+                                     cpu__fpr[DFPREG(rs2)],
+                                     cpu__fpr[DFPREG(rs1)]);
+                    tcg_gen_andc_i32(cpu__fpr[DFPREG(rd) + 1],
+                                     cpu__fpr[DFPREG(rs2) + 1],
+                                     cpu__fpr[DFPREG(rs1) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x069: /* VIS I fandnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_andc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_andc_i32(cpu_dst_32, cpu_src2_32, cpu_src1_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x06a: /* VIS I fnot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_not_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    tcg_gen_not_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs1)]);
+                    tcg_gen_not_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs1) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x06b: /* VIS I fnot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_not_i32(cpu_fpr[rd], cpu_fpr[rs1]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_not_i32(cpu_dst_32, cpu_src1_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x06c: /* VIS I fxor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                    cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_xor_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs1)],
+                                    cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_xor_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs1) + 1],
+                                    cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x06d: /* VIS I fxors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xor_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_xor_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x06e: /* VIS I fnand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nand_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                     cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_nand_i32(cpu_fpr[DFPREG(rd) + 1],
-                                     cpu_fpr[DFPREG(rs1) + 1],
-                                     cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_nand_i32(cpu__fpr[DFPREG(rd)],
+                                     cpu__fpr[DFPREG(rs1)],
+                                     cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_nand_i32(cpu__fpr[DFPREG(rd) + 1],
+                                     cpu__fpr[DFPREG(rs1) + 1],
+                                     cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x06f: /* VIS I fnands */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_nand_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_nand_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x070: /* VIS I fand */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_and_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                    cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_and_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_and_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs1)],
+                                    cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_and_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs1) + 1],
+                                    cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x071: /* VIS I fands */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_and_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_and_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x072: /* VIS I fxnor */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2)], -1);
-                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd)], cpu_tmp32,
-                                    cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[DFPREG(rs2) + 1], -1);
-                    tcg_gen_xor_i32(cpu_fpr[DFPREG(rd) + 1], cpu_tmp32,
-                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    tcg_gen_eqv_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs1)],
+                                    cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_eqv_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs1) + 1],
+                                    cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x073: /* VIS I fxnors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_xori_i32(cpu_tmp32, cpu_fpr[rs2], -1);
-                    tcg_gen_xor_i32(cpu_fpr[rd], cpu_tmp32, cpu_fpr[rs1]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_eqv_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x074: /* VIS I fsrc1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs1)]);
+                    tcg_gen_mov_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs1) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x075: /* VIS I fsrc1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs1]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    gen_store_fpr_F(dc, rd, cpu_src1_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x076: /* VIS I fornot2 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                    cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_orc_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs1)],
+                                    cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_orc_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs1) + 1],
+                                    cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x077: /* VIS I fornot2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_orc_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x078: /* VIS I fsrc2 */
@@ -4236,46 +4362,59 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x079: /* VIS I fsrc2s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs2);
+                    gen_store_fpr_F(dc, rd, cpu_src1_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x07a: /* VIS I fornot1 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)],
-                                    cpu_fpr[DFPREG(rs1)]);
-                    tcg_gen_orc_i32(cpu_fpr[DFPREG(rd) + 1],
-                                    cpu_fpr[DFPREG(rs2) + 1],
-                                    cpu_fpr[DFPREG(rs1) + 1]);
+                    tcg_gen_orc_i32(cpu__fpr[DFPREG(rd)],
+                                    cpu__fpr[DFPREG(rs2)],
+                                    cpu__fpr[DFPREG(rs1)]);
+                    tcg_gen_orc_i32(cpu__fpr[DFPREG(rd) + 1],
+                                    cpu__fpr[DFPREG(rs2) + 1],
+                                    cpu__fpr[DFPREG(rs1) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x07b: /* VIS I fornot1s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_orc_i32(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_orc_i32(cpu_dst_32, cpu_src2_32, cpu_src1_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x07c: /* VIS I for */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_or_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs1)],
-                                   cpu_fpr[DFPREG(rs2)]);
-                    tcg_gen_or_i32(cpu_fpr[DFPREG(rd) + 1],
-                                   cpu_fpr[DFPREG(rs1) + 1],
-                                   cpu_fpr[DFPREG(rs2) + 1]);
+                    tcg_gen_or_i32(cpu__fpr[DFPREG(rd)],
+                                   cpu__fpr[DFPREG(rs1)],
+                                   cpu__fpr[DFPREG(rs2)]);
+                    tcg_gen_or_i32(cpu__fpr[DFPREG(rd) + 1],
+                                   cpu__fpr[DFPREG(rs1) + 1],
+                                   cpu__fpr[DFPREG(rs2) + 1]);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x07d: /* VIS I fors */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_or_i32(cpu_fpr[rd], cpu_fpr[rs1], cpu_fpr[rs2]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rs1);
+                    cpu_src2_32 = gen_load_fpr_F(dc, rs2);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_or_i32(cpu_dst_32, cpu_src1_32, cpu_src2_32);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x07e: /* VIS I fone */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd)], -1);
-                    tcg_gen_movi_i32(cpu_fpr[DFPREG(rd) + 1], -1);
+                    tcg_gen_movi_i32(cpu__fpr[DFPREG(rd)], -1);
+                    tcg_gen_movi_i32(cpu__fpr[DFPREG(rd) + 1], -1);
                     gen_update_fprs_dirty(DFPREG(rd));
                     break;
                 case 0x07f: /* VIS I fones */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    tcg_gen_movi_i32(cpu_fpr[rd], -1);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_movi_i32(cpu_dst_32, -1);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x080: /* VIS I shutdown */
@@ -4659,7 +4798,9 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x20:      /* ldf, load fpreg */
                     gen_address_mask(dc, cpu_addr);
                     tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
-                    tcg_gen_trunc_tl_i32(cpu_fpr[rd], cpu_tmp0);
+                    cpu_dst_32 = gen_dest_fpr_F();
+                    tcg_gen_trunc_tl_i32(cpu_dst_32, cpu_tmp0);
+                    gen_store_fpr_F(dc, rd, cpu_dst_32);
                     gen_update_fprs_dirty(rd);
                     break;
                 case 0x21:      /* ldfsr, V9 ldxfsr */
@@ -4810,7 +4951,8 @@ static void disas_sparc_insn(DisasContext * dc)
                 switch (xop) {
                 case 0x24: /* stf, store fpreg */
                     gen_address_mask(dc, cpu_addr);
-                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_fpr[rd]);
+                    cpu_src1_32 = gen_load_fpr_F(dc, rd);
+                    tcg_gen_ext_i32_tl(cpu_tmp0, cpu_src1_32);
                     tcg_gen_qemu_st32(cpu_tmp0, cpu_addr, dc->mem_idx);
                     break;
                 case 0x25: /* stfsr, V9 stxfsr */
@@ -5242,9 +5384,9 @@ void gen_intermediate_code_init(CPUSPARCState *env)
                                               offsetof(CPUState, gregs[i]),
                                               gregnames[i]);
         for (i = 0; i < TARGET_FPREGS; i++)
-            cpu_fpr[i] = tcg_global_mem_new_i32(TCG_AREG0,
-                                                offsetof(CPUState, fpr[i]),
-                                                fregnames[i]);
+            cpu__fpr[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                                                 offsetof(CPUState, fpr[i]),
+                                                 fregnames[i]);
 
         /* register helpers */
 
commit fafd8bceb58afb2da179efd8266b6df38a8719a9
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Aug 1 10:15:51 2011 +0000

    Sparc: split load and store op helpers
    
    Move load and store op helpers top ldst_helper.c.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index 8e25a88..fe5f6f7 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -78,7 +78,8 @@ libobj-$(TARGET_SPARC64) += vis_helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
 libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 ifeq ($(TARGET_BASE_ARCH), sparc)
-libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o cpu_init.o
+libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
+libobj-y += cpu_init.o
 endif
 libobj-$(TARGET_SPARC) += int32_helper.o
 libobj-$(TARGET_SPARC64) += int64_helper.o
@@ -97,7 +98,7 @@ tcg/tcg.o: cpu.h
 
 # HELPER_CFLAGS is used for all the code compiled with static register
 # variables
-op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+op_helper.o ldst_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 
 # Note: this is a workaround. The real fix is to avoid compiling
 # cpu_signal_handler() in user-exec.c.
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
new file mode 100644
index 0000000..1fb3996
--- /dev/null
+++ b/target-sparc/ldst_helper.c
@@ -0,0 +1,2434 @@
+/*
+ * Helpers for loads and stores
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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 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/>.
+ */
+
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
+
+//#define DEBUG_MMU
+//#define DEBUG_MXCC
+//#define DEBUG_UNALIGNED
+//#define DEBUG_UNASSIGNED
+//#define DEBUG_ASI
+//#define DEBUG_CACHE_CONTROL
+
+#ifdef DEBUG_MMU
+#define DPRINTF_MMU(fmt, ...)                                   \
+    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MMU(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_MXCC
+#define DPRINTF_MXCC(fmt, ...)                                  \
+    do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MXCC(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_ASI
+#define DPRINTF_ASI(fmt, ...)                                   \
+    do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
+#endif
+
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...)                                 \
+    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
+#ifdef TARGET_SPARC64
+#ifndef TARGET_ABI32
+#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
+#else
+#define AM_CHECK(env1) (1)
+#endif
+#endif
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size);
+#else
+#ifdef TARGET_SPARC64
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+                                 int is_asi, int size);
+#endif
+#endif
+
+#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+/* Calculates TSB pointer value for fault page size 8k or 64k */
+static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
+                                       uint64_t tag_access_register,
+                                       int page_size)
+{
+    uint64_t tsb_base = tsb_register & ~0x1fffULL;
+    int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
+    int tsb_size  = tsb_register & 0xf;
+
+    /* discard lower 13 bits which hold tag access context */
+    uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
+
+    /* now reorder bits */
+    uint64_t tsb_base_mask = ~0x1fffULL;
+    uint64_t va = tag_access_va;
+
+    /* move va bits to correct position */
+    if (page_size == 8*1024) {
+        va >>= 9;
+    } else if (page_size == 64*1024) {
+        va >>= 12;
+    }
+
+    if (tsb_size) {
+        tsb_base_mask <<= tsb_size;
+    }
+
+    /* calculate tsb_base mask and adjust va if split is in use */
+    if (tsb_split) {
+        if (page_size == 8*1024) {
+            va &= ~(1ULL << (13 + tsb_size));
+        } else if (page_size == 64*1024) {
+            va |= (1ULL << (13 + tsb_size));
+        }
+        tsb_base_mask <<= 1;
+    }
+
+    return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
+}
+
+/* Calculates tag target register value by reordering bits
+   in tag access register */
+static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
+{
+    return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
+}
+
+static void replace_tlb_entry(SparcTLBEntry *tlb,
+                              uint64_t tlb_tag, uint64_t tlb_tte,
+                              CPUState *env1)
+{
+    target_ulong mask, size, va, offset;
+
+    /* flush page range if translation is valid */
+    if (TTE_IS_VALID(tlb->tte)) {
+
+        mask = 0xffffffffffffe000ULL;
+        mask <<= 3 * ((tlb->tte >> 61) & 3);
+        size = ~mask + 1;
+
+        va = tlb->tag & mask;
+
+        for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
+            tlb_flush_page(env1, va + offset);
+        }
+    }
+
+    tlb->tag = tlb_tag;
+    tlb->tte = tlb_tte;
+}
+
+static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
+                      const char *strmmu, CPUState *env1)
+{
+    unsigned int i;
+    target_ulong mask;
+    uint64_t context;
+
+    int is_demap_context = (demap_addr >> 6) & 1;
+
+    /* demap context */
+    switch ((demap_addr >> 4) & 3) {
+    case 0: /* primary */
+        context = env1->dmmu.mmu_primary_context;
+        break;
+    case 1: /* secondary */
+        context = env1->dmmu.mmu_secondary_context;
+        break;
+    case 2: /* nucleus */
+        context = 0;
+        break;
+    case 3: /* reserved */
+    default:
+        return;
+    }
+
+    for (i = 0; i < 64; i++) {
+        if (TTE_IS_VALID(tlb[i].tte)) {
+
+            if (is_demap_context) {
+                /* will remove non-global entries matching context value */
+                if (TTE_IS_GLOBAL(tlb[i].tte) ||
+                    !tlb_compare_context(&tlb[i], context)) {
+                    continue;
+                }
+            } else {
+                /* demap page
+                   will remove any entry matching VA */
+                mask = 0xffffffffffffe000ULL;
+                mask <<= 3 * ((tlb[i].tte >> 61) & 3);
+
+                if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
+                    continue;
+                }
+
+                /* entry should be global or matching context value */
+                if (!TTE_IS_GLOBAL(tlb[i].tte) &&
+                    !tlb_compare_context(&tlb[i], context)) {
+                    continue;
+                }
+            }
+
+            replace_tlb_entry(&tlb[i], 0, 0, env1);
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
+            dump_mmu(stdout, fprintf, env1);
+#endif
+        }
+    }
+}
+
+static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
+                                 uint64_t tlb_tag, uint64_t tlb_tte,
+                                 const char *strmmu, CPUState *env1)
+{
+    unsigned int i, replace_used;
+
+    /* Try replacing invalid entry */
+    for (i = 0; i < 64; i++) {
+        if (!TTE_IS_VALID(tlb[i].tte)) {
+            replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
+            dump_mmu(stdout, fprintf, env1);
+#endif
+            return;
+        }
+    }
+
+    /* All entries are valid, try replacing unlocked entry */
+
+    for (replace_used = 0; replace_used < 2; ++replace_used) {
+
+        /* Used entries are not replaced on first pass */
+
+        for (i = 0; i < 64; i++) {
+            if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
+
+                replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+                DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
+                            strmmu, (replace_used ? "used" : "unused"), i);
+                dump_mmu(stdout, fprintf, env1);
+#endif
+                return;
+            }
+        }
+
+        /* Now reset used bit and search for unused entries again */
+
+        for (i = 0; i < 64; i++) {
+            TTE_SET_UNUSED(tlb[i].tte);
+        }
+    }
+
+#ifdef DEBUG_MMU
+    DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
+#endif
+    /* error state? */
+}
+
+#endif
+
+static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
+{
+#ifdef TARGET_SPARC64
+    if (AM_CHECK(env1)) {
+        addr &= 0xffffffffULL;
+    }
+#endif
+    return addr;
+}
+
+/* returns true if access using this ASI is to have address translated by MMU
+   otherwise access is to raw physical address */
+static inline int is_translating_asi(int asi)
+{
+#ifdef TARGET_SPARC64
+    /* Ultrasparc IIi translating asi
+       - note this list is defined by cpu implementation
+    */
+    switch (asi) {
+    case 0x04 ... 0x11:
+    case 0x16 ... 0x19:
+    case 0x1E ... 0x1F:
+    case 0x24 ... 0x2C:
+    case 0x70 ... 0x73:
+    case 0x78 ... 0x79:
+    case 0x80 ... 0xFF:
+        return 1;
+
+    default:
+        return 0;
+    }
+#else
+    /* TODO: check sparc32 bits */
+    return 0;
+#endif
+}
+
+static inline target_ulong asi_address_mask(CPUState *env1,
+                                            int asi, target_ulong addr)
+{
+    if (is_translating_asi(asi)) {
+        return address_mask(env, addr);
+    } else {
+        return addr;
+    }
+}
+
+void helper_check_align(target_ulong addr, uint32_t align)
+{
+    if (addr & align) {
+#ifdef DEBUG_UNALIGNED
+        printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
+               "\n", addr, env->pc);
+#endif
+        helper_raise_exception(env, TT_UNALIGNED);
+    }
+}
+
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) &&   \
+    defined(DEBUG_MXCC)
+static void dump_mxcc(CPUState *env)
+{
+    printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n",
+           env->mxccdata[0], env->mxccdata[1],
+           env->mxccdata[2], env->mxccdata[3]);
+    printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n"
+           "          %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+           "\n",
+           env->mxccregs[0], env->mxccregs[1],
+           env->mxccregs[2], env->mxccregs[3],
+           env->mxccregs[4], env->mxccregs[5],
+           env->mxccregs[6], env->mxccregs[7]);
+}
+#endif
+
+#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY))     \
+    && defined(DEBUG_ASI)
+static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
+                     uint64_t r1)
+{
+    switch (size) {
+    case 1:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xff);
+        break;
+    case 2:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xffff);
+        break;
+    case 4:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
+                    addr, asi, r1 & 0xffffffff);
+        break;
+    case 8:
+        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
+                    addr, asi, r1);
+        break;
+    }
+}
+#endif
+
+#ifndef TARGET_SPARC64
+#ifndef CONFIG_USER_ONLY
+
+
+/* Leon3 cache control */
+
+static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+                          addr, val, size);
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+
+        /* These values must always be read as zeros */
+        val &= ~CACHE_CTRL_FD;
+        val &= ~CACHE_CTRL_FI;
+        val &= ~CACHE_CTRL_IB;
+        val &= ~CACHE_CTRL_IP;
+        val &= ~CACHE_CTRL_DP;
+
+        env->cache_control = val;
+        break;
+    case 0x04:              /* Instruction cache configuration */
+    case 0x08:              /* Data cache configuration */
+        /* Read Only */
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+        break;
+    };
+}
+
+static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+    uint64_t ret = 0;
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return 0;
+    }
+
+    switch (addr) {
+    case 0x00:              /* Cache control */
+        ret = env->cache_control;
+        break;
+
+        /* Configuration registers are read and only always keep those
+           predefined values */
+
+    case 0x04:              /* Instruction cache configuration */
+        ret = 0x10220000;
+        break;
+    case 0x08:              /* Data cache configuration */
+        ret = 0x18220000;
+        break;
+    default:
+        DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+        break;
+    };
+    DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
+                          addr, ret, size);
+    return ret;
+}
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
+    uint32_t last_addr = addr;
+#endif
+
+    helper_check_align(addr, size - 1);
+    switch (asi) {
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+        switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                ret = leon3_cache_control_ld(addr, size);
+            }
+            break;
+        case 0x01c00a00: /* MXCC control register */
+            if (size == 8) {
+                ret = env->mxccregs[3];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00a04: /* MXCC control register */
+            if (size == 4) {
+                ret = env->mxccregs[3];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00c00: /* Module reset register */
+            if (size == 8) {
+                ret = env->mxccregs[5];
+                /* should we do something here? */
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00f00: /* MBus port address register */
+            if (size == 8) {
+                ret = env->mxccregs[7];
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        default:
+            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+                         size);
+            break;
+        }
+        DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
+                     "addr = %08x -> ret = %" PRIx64 ","
+                     "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
+#ifdef DEBUG_MXCC
+        dump_mxcc(env);
+#endif
+        break;
+    case 3: /* MMU probe */
+        {
+            int mmulev;
+
+            mmulev = (addr >> 8) & 15;
+            if (mmulev > 4) {
+                ret = 0;
+            } else {
+                ret = mmu_probe(env, addr, mmulev);
+            }
+            DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
+                        addr, mmulev, ret);
+        }
+        break;
+    case 4: /* read MMU regs */
+        {
+            int reg = (addr >> 8) & 0x1f;
+
+            ret = env->mmuregs[reg];
+            if (reg == 3) { /* Fault status cleared on read */
+                env->mmuregs[3] = 0;
+            } else if (reg == 0x13) { /* Fault status read */
+                ret = env->mmuregs[3];
+            } else if (reg == 0x14) { /* Fault address read */
+                ret = env->mmuregs[4];
+            }
+            DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
+        }
+        break;
+    case 5: /* Turbosparc ITLB Diagnostic */
+    case 6: /* Turbosparc DTLB Diagnostic */
+    case 7: /* Turbosparc IOTLB Diagnostic */
+        break;
+    case 9: /* Supervisor code access */
+        switch (size) {
+        case 1:
+            ret = ldub_code(addr);
+            break;
+        case 2:
+            ret = lduw_code(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_code(addr);
+            break;
+        case 8:
+            ret = ldq_code(addr);
+            break;
+        }
+        break;
+    case 0xa: /* User data access */
+        switch (size) {
+        case 1:
+            ret = ldub_user(addr);
+            break;
+        case 2:
+            ret = lduw_user(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_user(addr);
+            break;
+        case 8:
+            ret = ldq_user(addr);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch (size) {
+        case 1:
+            ret = ldub_kernel(addr);
+            break;
+        case 2:
+            ret = lduw_kernel(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_kernel(addr);
+            break;
+        case 8:
+            ret = ldq_kernel(addr);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+        break;
+    case 0x20: /* MMU passthrough */
+        switch (size) {
+        case 1:
+            ret = ldub_phys(addr);
+            break;
+        case 2:
+            ret = lduw_phys(addr);
+            break;
+        default:
+        case 4:
+            ret = ldl_phys(addr);
+            break;
+        case 8:
+            ret = ldq_phys(addr);
+            break;
+        }
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+        switch (size) {
+        case 1:
+            ret = ldub_phys((target_phys_addr_t)addr
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 2:
+            ret = lduw_phys((target_phys_addr_t)addr
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        default:
+        case 4:
+            ret = ldl_phys((target_phys_addr_t)addr
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 8:
+            ret = ldq_phys((target_phys_addr_t)addr
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        }
+        break;
+    case 0x30: /* Turbosparc secondary cache diagnostic */
+    case 0x31: /* Turbosparc RAM snoop */
+    case 0x32: /* Turbosparc page table descriptor diagnostic */
+    case 0x39: /* data cache diagnostic register */
+        ret = 0;
+        break;
+    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
+        {
+            int reg = (addr >> 8) & 3;
+
+            switch (reg) {
+            case 0: /* Breakpoint Value (Addr) */
+                ret = env->mmubpregs[reg];
+                break;
+            case 1: /* Breakpoint Mask */
+                ret = env->mmubpregs[reg];
+                break;
+            case 2: /* Breakpoint Control */
+                ret = env->mmubpregs[reg];
+                break;
+            case 3: /* Breakpoint Status */
+                ret = env->mmubpregs[reg];
+                env->mmubpregs[reg] = 0ULL;
+                break;
+            }
+            DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
+                        ret);
+        }
+        break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        ret = env->mmubpctrv;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        ret = env->mmubpctrc;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        ret = env->mmubpctrs;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        ret = env->mmubpaction;
+        break;
+    case 8: /* User code access, XXX */
+    default:
+        do_unassigned_access(addr, 0, 0, asi, size);
+        ret = 0;
+        break;
+    }
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
+{
+    helper_check_align(addr, size - 1);
+    switch (asi) {
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+        switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+                leon3_cache_control_st(addr, val, size);
+            }
+            break;
+
+        case 0x01c00000: /* MXCC stream data register 0 */
+            if (size == 8) {
+                env->mxccdata[0] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00008: /* MXCC stream data register 1 */
+            if (size == 8) {
+                env->mxccdata[1] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00010: /* MXCC stream data register 2 */
+            if (size == 8) {
+                env->mxccdata[2] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00018: /* MXCC stream data register 3 */
+            if (size == 8) {
+                env->mxccdata[3] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00100: /* MXCC stream source */
+            if (size == 8) {
+                env->mxccregs[0] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        0);
+            env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        8);
+            env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        16);
+            env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+                                        24);
+            break;
+        case 0x01c00200: /* MXCC stream destination */
+            if (size == 8) {
+                env->mxccregs[1] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  0,
+                     env->mxccdata[0]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  8,
+                     env->mxccdata[1]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
+                     env->mxccdata[2]);
+            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
+                     env->mxccdata[3]);
+            break;
+        case 0x01c00a00: /* MXCC control register */
+            if (size == 8) {
+                env->mxccregs[3] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00a04: /* MXCC control register */
+            if (size == 4) {
+                env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
+                    | val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00e00: /* MXCC error register  */
+            /* writing a 1 bit clears the error */
+            if (size == 8) {
+                env->mxccregs[6] &= ~val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        case 0x01c00f00: /* MBus port address register */
+            if (size == 8) {
+                env->mxccregs[7] = val;
+            } else {
+                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+                             size);
+            }
+            break;
+        default:
+            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+                         size);
+            break;
+        }
+        DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
+                     asi, size, addr, val);
+#ifdef DEBUG_MXCC
+        dump_mxcc(env);
+#endif
+        break;
+    case 3: /* MMU flush */
+        {
+            int mmulev;
+
+            mmulev = (addr >> 8) & 15;
+            DPRINTF_MMU("mmu flush level %d\n", mmulev);
+            switch (mmulev) {
+            case 0: /* flush page */
+                tlb_flush_page(env, addr & 0xfffff000);
+                break;
+            case 1: /* flush segment (256k) */
+            case 2: /* flush region (16M) */
+            case 3: /* flush context (4G) */
+            case 4: /* flush entire */
+                tlb_flush(env, 1);
+                break;
+            default:
+                break;
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+        }
+        break;
+    case 4: /* write MMU regs */
+        {
+            int reg = (addr >> 8) & 0x1f;
+            uint32_t oldreg;
+
+            oldreg = env->mmuregs[reg];
+            switch (reg) {
+            case 0: /* Control Register */
+                env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
+                    (val & 0x00ffffff);
+                /* Mappings generated during no-fault mode or MMU
+                   disabled mode are invalid in normal mode */
+                if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
+                    (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) {
+                    tlb_flush(env, 1);
+                }
+                break;
+            case 1: /* Context Table Pointer Register */
+                env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
+                break;
+            case 2: /* Context Register */
+                env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
+                if (oldreg != env->mmuregs[reg]) {
+                    /* we flush when the MMU context changes because
+                       QEMU has no MMU context support */
+                    tlb_flush(env, 1);
+                }
+                break;
+            case 3: /* Synchronous Fault Status Register with Clear */
+            case 4: /* Synchronous Fault Address Register */
+                break;
+            case 0x10: /* TLB Replacement Control Register */
+                env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
+                break;
+            case 0x13: /* Synchronous Fault Status Register with Read
+                          and Clear */
+                env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
+                break;
+            case 0x14: /* Synchronous Fault Address Register */
+                env->mmuregs[4] = val;
+                break;
+            default:
+                env->mmuregs[reg] = val;
+                break;
+            }
+            if (oldreg != env->mmuregs[reg]) {
+                DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
+                            reg, oldreg, env->mmuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+        }
+        break;
+    case 5: /* Turbosparc ITLB Diagnostic */
+    case 6: /* Turbosparc DTLB Diagnostic */
+    case 7: /* Turbosparc IOTLB Diagnostic */
+        break;
+    case 0xa: /* User data access */
+        switch (size) {
+        case 1:
+            stb_user(addr, val);
+            break;
+        case 2:
+            stw_user(addr, val);
+            break;
+        default:
+        case 4:
+            stl_user(addr, val);
+            break;
+        case 8:
+            stq_user(addr, val);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch (size) {
+        case 1:
+            stb_kernel(addr, val);
+            break;
+        case 2:
+            stw_kernel(addr, val);
+            break;
+        default:
+        case 4:
+            stl_kernel(addr, val);
+            break;
+        case 8:
+            stq_kernel(addr, val);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+    case 0x10: /* I/D-cache flush page */
+    case 0x11: /* I/D-cache flush segment */
+    case 0x12: /* I/D-cache flush region */
+    case 0x13: /* I/D-cache flush context */
+    case 0x14: /* I/D-cache flush user */
+        break;
+    case 0x17: /* Block copy, sta access */
+        {
+            /* val = src
+               addr = dst
+               copy 32 bytes */
+            unsigned int i;
+            uint32_t src = val & ~3, dst = addr & ~3, temp;
+
+            for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
+                temp = ldl_kernel(src);
+                stl_kernel(dst, temp);
+            }
+        }
+        break;
+    case 0x1f: /* Block fill, stda access */
+        {
+            /* addr = dst
+               fill 32 bytes with val */
+            unsigned int i;
+            uint32_t dst = addr & 7;
+
+            for (i = 0; i < 32; i += 8, dst += 8) {
+                stq_kernel(dst, val);
+            }
+        }
+        break;
+    case 0x20: /* MMU passthrough */
+        {
+            switch (size) {
+            case 1:
+                stb_phys(addr, val);
+                break;
+            case 2:
+                stw_phys(addr, val);
+                break;
+            case 4:
+            default:
+                stl_phys(addr, val);
+                break;
+            case 8:
+                stq_phys(addr, val);
+                break;
+            }
+        }
+        break;
+    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+        {
+            switch (size) {
+            case 1:
+                stb_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 2:
+                stw_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 4:
+            default:
+                stl_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            case 8:
+                stq_phys((target_phys_addr_t)addr
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+                break;
+            }
+        }
+        break;
+    case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */
+    case 0x31: /* store buffer data, Ross RT620 I-cache flush or
+                  Turbosparc snoop RAM */
+    case 0x32: /* store buffer control or Turbosparc page table
+                  descriptor diagnostic */
+    case 0x36: /* I-cache flash clear */
+    case 0x37: /* D-cache flash clear */
+        break;
+    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
+        {
+            int reg = (addr >> 8) & 3;
+
+            switch (reg) {
+            case 0: /* Breakpoint Value (Addr) */
+                env->mmubpregs[reg] = (val & 0xfffffffffULL);
+                break;
+            case 1: /* Breakpoint Mask */
+                env->mmubpregs[reg] = (val & 0xfffffffffULL);
+                break;
+            case 2: /* Breakpoint Control */
+                env->mmubpregs[reg] = (val & 0x7fULL);
+                break;
+            case 3: /* Breakpoint Status */
+                env->mmubpregs[reg] = (val & 0xfULL);
+                break;
+            }
+            DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
+                        env->mmuregs[reg]);
+        }
+        break;
+    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+        env->mmubpctrv = val & 0xffffffff;
+        break;
+    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+        env->mmubpctrc = val & 0x3;
+        break;
+    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+        env->mmubpctrs = val & 0x3;
+        break;
+    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+        env->mmubpaction = val & 0x1fff;
+        break;
+    case 8: /* User code access, XXX */
+    case 9: /* Supervisor code access, XXX */
+    default:
+        do_unassigned_access(addr, 1, 0, asi, size);
+        break;
+    }
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+}
+
+#endif /* CONFIG_USER_ONLY */
+#else /* TARGET_SPARC64 */
+
+#ifdef CONFIG_USER_ONLY
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+    target_ulong last_addr = addr;
+#endif
+
+    if (asi < 0x80) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0x82: /* Primary no-fault */
+    case 0x8a: /* Primary no-fault LE */
+        if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            return 0;
+        }
+        /* Fall through */
+    case 0x80: /* Primary */
+    case 0x88: /* Primary LE */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_raw(addr);
+                break;
+            case 2:
+                ret = lduw_raw(addr);
+                break;
+            case 4:
+                ret = ldl_raw(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_raw(addr);
+                break;
+            }
+        }
+        break;
+    case 0x83: /* Secondary no-fault */
+    case 0x8b: /* Secondary no-fault LE */
+        if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            return 0;
+        }
+        /* Fall through */
+    case 0x81: /* Secondary */
+    case 0x89: /* Secondary LE */
+        /* XXX */
+        break;
+    default:
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0x8a: /* Primary no-fault LE */
+    case 0x8b: /* Secondary no-fault LE */
+        switch (size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+    if (asi < 0x80) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch (size) {
+        case 2:
+            val = bswap16(val);
+            break;
+        case 4:
+            val = bswap32(val);
+            break;
+        case 8:
+            val = bswap64(val);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch (asi) {
+    case 0x80: /* Primary */
+    case 0x88: /* Primary LE */
+        {
+            switch (size) {
+            case 1:
+                stb_raw(addr, val);
+                break;
+            case 2:
+                stw_raw(addr, val);
+                break;
+            case 4:
+                stl_raw(addr, val);
+                break;
+            case 8:
+            default:
+                stq_raw(addr, val);
+                break;
+            }
+        }
+        break;
+    case 0x81: /* Secondary */
+    case 0x89: /* Secondary LE */
+        /* XXX */
+        return;
+
+    case 0x82: /* Primary no-fault, RO */
+    case 0x83: /* Secondary no-fault, RO */
+    case 0x8a: /* Primary no-fault LE, RO */
+    case 0x8b: /* Secondary no-fault LE, RO */
+    default:
+        do_unassigned_access(addr, 1, 0, 1, size);
+        return;
+    }
+}
+
+#else /* CONFIG_USER_ONLY */
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+    target_ulong last_addr = addr;
+#endif
+
+    asi &= 0xff;
+
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* process nonfaulting loads first */
+    if ((asi & 0xf6) == 0x82) {
+        int mmu_idx;
+
+        /* secondary space access has lowest asi bit equal to 1 */
+        if (env->pstate & PS_PRIV) {
+            mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
+        } else {
+            mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
+        }
+
+        if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
+#ifdef DEBUG_ASI
+            dump_asi("read ", last_addr, asi, size, ret);
+#endif
+            /* env->exception_index is set in get_physical_address_data(). */
+            helper_raise_exception(env, env->exception_index);
+        }
+
+        /* convert nonfaulting load ASIs to normal load ASIs */
+        asi &= ~0x02;
+    }
+
+    switch (asi) {
+    case 0x10: /* As if user primary */
+    case 0x11: /* As if user secondary */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x80: /* Primary */
+    case 0x81: /* Secondary */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0xe2: /* UA2007 Primary block init */
+    case 0xe3: /* UA2007 Secondary block init */
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            if (cpu_hypervisor_mode(env)) {
+                switch (size) {
+                case 1:
+                    ret = ldub_hypv(addr);
+                    break;
+                case 2:
+                    ret = lduw_hypv(addr);
+                    break;
+                case 4:
+                    ret = ldl_hypv(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_hypv(addr);
+                    break;
+                }
+            } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch (size) {
+                    case 1:
+                        ret = ldub_kernel_secondary(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel_secondary(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel_secondary(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel_secondary(addr);
+                        break;
+                    }
+                } else {
+                    switch (size) {
+                    case 1:
+                        ret = ldub_kernel(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel(addr);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
+                switch (size) {
+                case 1:
+                    ret = ldub_user_secondary(addr);
+                    break;
+                case 2:
+                    ret = lduw_user_secondary(addr);
+                    break;
+                case 4:
+                    ret = ldl_user_secondary(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user_secondary(addr);
+                    break;
+                }
+            } else {
+                switch (size) {
+                case 1:
+                    ret = ldub_user(addr);
+                    break;
+                case 2:
+                    ret = lduw_user(addr);
+                    break;
+                case 4:
+                    ret = ldl_user(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user(addr);
+                    break;
+                }
+            }
+        }
+        break;
+    case 0x14: /* Bypass */
+    case 0x15: /* Bypass, non-cacheable */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_phys(addr);
+                break;
+            case 2:
+                ret = lduw_phys(addr);
+                break;
+            case 4:
+                ret = ldl_phys(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_phys(addr);
+                break;
+            }
+            break;
+        }
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+                  Only ldda allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return 0;
+    case 0x04: /* Nucleus */
+    case 0x0c: /* Nucleus Little Endian (LE) */
+        {
+            switch (size) {
+            case 1:
+                ret = ldub_nucleus(addr);
+                break;
+            case 2:
+                ret = lduw_nucleus(addr);
+                break;
+            case 4:
+                ret = ldl_nucleus(addr);
+                break;
+            default:
+            case 8:
+                ret = ldq_nucleus(addr);
+                break;
+            }
+            break;
+        }
+    case 0x4a: /* UPA config */
+        /* XXX */
+        break;
+    case 0x45: /* LSU */
+        ret = env->lsu;
+        break;
+    case 0x50: /* I-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+
+            if (reg == 0) {
+                /* I-TSB Tag Target register */
+                ret = ultrasparc_tag_target(env->immu.tag_access);
+            } else {
+                ret = env->immuregs[reg];
+            }
+
+            break;
+        }
+    case 0x51: /* I-MMU 8k TSB pointer */
+        {
+            /* env->immuregs[5] holds I-MMU TSB register value
+               env->immuregs[6] holds I-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+                                         8*1024);
+            break;
+        }
+    case 0x52: /* I-MMU 64k TSB pointer */
+        {
+            /* env->immuregs[5] holds I-MMU TSB register value
+               env->immuregs[6] holds I-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+                                         64*1024);
+            break;
+        }
+    case 0x55: /* I-MMU data access */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->itlb[reg].tte;
+            break;
+        }
+    case 0x56: /* I-MMU tag read */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->itlb[reg].tag;
+            break;
+        }
+    case 0x58: /* D-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+
+            if (reg == 0) {
+                /* D-TSB Tag Target register */
+                ret = ultrasparc_tag_target(env->dmmu.tag_access);
+            } else {
+                ret = env->dmmuregs[reg];
+            }
+            break;
+        }
+    case 0x59: /* D-MMU 8k TSB pointer */
+        {
+            /* env->dmmuregs[5] holds D-MMU TSB register value
+               env->dmmuregs[6] holds D-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+                                         8*1024);
+            break;
+        }
+    case 0x5a: /* D-MMU 64k TSB pointer */
+        {
+            /* env->dmmuregs[5] holds D-MMU TSB register value
+               env->dmmuregs[6] holds D-MMU Tag Access register value */
+            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+                                         64*1024);
+            break;
+        }
+    case 0x5d: /* D-MMU data access */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->dtlb[reg].tte;
+            break;
+        }
+    case 0x5e: /* D-MMU tag read */
+        {
+            int reg = (addr >> 3) & 0x3f;
+
+            ret = env->dtlb[reg].tag;
+            break;
+        }
+    case 0x46: /* D-cache data */
+    case 0x47: /* D-cache tag access */
+    case 0x4b: /* E-cache error enable */
+    case 0x4c: /* E-cache asynchronous fault status */
+    case 0x4d: /* E-cache asynchronous fault address */
+    case 0x4e: /* E-cache tag data */
+    case 0x66: /* I-cache instruction access */
+    case 0x67: /* I-cache tag access */
+    case 0x6e: /* I-cache predecode */
+    case 0x6f: /* I-cache LRU etc. */
+    case 0x76: /* E-cache tag */
+    case 0x7e: /* E-cache tag */
+        break;
+    case 0x5b: /* D-MMU data pointer */
+    case 0x48: /* Interrupt dispatch, RO */
+    case 0x49: /* Interrupt data receive */
+    case 0x7f: /* Incoming interrupt vector, RO */
+        /* XXX */
+        break;
+    case 0x54: /* I-MMU data in, WO */
+    case 0x57: /* I-MMU demap, WO */
+    case 0x5c: /* D-MMU data in, WO */
+    case 0x5f: /* D-MMU demap, WO */
+    case 0x77: /* Interrupt vector, WO */
+    default:
+        do_unassigned_access(addr, 0, 0, 1, size);
+        ret = 0;
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x0c: /* Nucleus Little Endian (LE) */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch (size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+#ifdef DEBUG_ASI
+    dump_asi("read ", last_addr, asi, size, ret);
+#endif
+    return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+    dump_asi("write", addr, asi, size, val);
+#endif
+
+    asi &= 0xff;
+
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    helper_check_align(addr, size - 1);
+    addr = asi_address_mask(env, asi, addr);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x0c: /* Nucleus Little Endian (LE) */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+        switch (size) {
+        case 2:
+            val = bswap16(val);
+            break;
+        case 4:
+            val = bswap32(val);
+            break;
+        case 8:
+            val = bswap64(val);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch (asi) {
+    case 0x10: /* As if user primary */
+    case 0x11: /* As if user secondary */
+    case 0x18: /* As if user primary LE */
+    case 0x19: /* As if user secondary LE */
+    case 0x80: /* Primary */
+    case 0x81: /* Secondary */
+    case 0x88: /* Primary LE */
+    case 0x89: /* Secondary LE */
+    case 0xe2: /* UA2007 Primary block init */
+    case 0xe3: /* UA2007 Secondary block init */
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            if (cpu_hypervisor_mode(env)) {
+                switch (size) {
+                case 1:
+                    stb_hypv(addr, val);
+                    break;
+                case 2:
+                    stw_hypv(addr, val);
+                    break;
+                case 4:
+                    stl_hypv(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_hypv(addr, val);
+                    break;
+                }
+            } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch (size) {
+                    case 1:
+                        stb_kernel_secondary(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel_secondary(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel_secondary(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel_secondary(addr, val);
+                        break;
+                    }
+                } else {
+                    switch (size) {
+                    case 1:
+                        stb_kernel(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel(addr, val);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
+                switch (size) {
+                case 1:
+                    stb_user_secondary(addr, val);
+                    break;
+                case 2:
+                    stw_user_secondary(addr, val);
+                    break;
+                case 4:
+                    stl_user_secondary(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user_secondary(addr, val);
+                    break;
+                }
+            } else {
+                switch (size) {
+                case 1:
+                    stb_user(addr, val);
+                    break;
+                case 2:
+                    stw_user(addr, val);
+                    break;
+                case 4:
+                    stl_user(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user(addr, val);
+                    break;
+                }
+            }
+        }
+        break;
+    case 0x14: /* Bypass */
+    case 0x15: /* Bypass, non-cacheable */
+    case 0x1c: /* Bypass LE */
+    case 0x1d: /* Bypass, non-cacheable LE */
+        {
+            switch (size) {
+            case 1:
+                stb_phys(addr, val);
+                break;
+            case 2:
+                stw_phys(addr, val);
+                break;
+            case 4:
+                stl_phys(addr, val);
+                break;
+            case 8:
+            default:
+                stq_phys(addr, val);
+                break;
+            }
+        }
+        return;
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+                  Only ldda allowed */
+        helper_raise_exception(env, TT_ILL_INSN);
+        return;
+    case 0x04: /* Nucleus */
+    case 0x0c: /* Nucleus Little Endian (LE) */
+        {
+            switch (size) {
+            case 1:
+                stb_nucleus(addr, val);
+                break;
+            case 2:
+                stw_nucleus(addr, val);
+                break;
+            case 4:
+                stl_nucleus(addr, val);
+                break;
+            default:
+            case 8:
+                stq_nucleus(addr, val);
+                break;
+            }
+            break;
+        }
+
+    case 0x4a: /* UPA config */
+        /* XXX */
+        return;
+    case 0x45: /* LSU */
+        {
+            uint64_t oldreg;
+
+            oldreg = env->lsu;
+            env->lsu = val & (DMMU_E | IMMU_E);
+            /* Mappings generated during D/I MMU disabled mode are
+               invalid in normal mode */
+            if (oldreg != env->lsu) {
+                DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
+                            oldreg, env->lsu);
+#ifdef DEBUG_MMU
+                dump_mmu(stdout, fprintf, env1);
+#endif
+                tlb_flush(env, 1);
+            }
+            return;
+        }
+    case 0x50: /* I-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->immuregs[reg];
+            switch (reg) {
+            case 0: /* RO */
+                return;
+            case 1: /* Not in I-MMU */
+            case 2:
+                return;
+            case 3: /* SFSR */
+                if ((val & 1) == 0) {
+                    val = 0; /* Clear SFSR */
+                }
+                env->immu.sfsr = val;
+                break;
+            case 4: /* RO */
+                return;
+            case 5: /* TSB access */
+                DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", env->immu.tsb, val);
+                env->immu.tsb = val;
+                break;
+            case 6: /* Tag access */
+                env->immu.tag_access = val;
+                break;
+            case 7:
+            case 8:
+                return;
+            default:
+                break;
+            }
+
+            if (oldreg != env->immuregs[reg]) {
+                DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x54: /* I-MMU data in */
+        replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
+        return;
+    case 0x55: /* I-MMU data access */
+        {
+            /* TODO: auto demap */
+
+            unsigned int i = (addr >> 3) & 0x3f;
+
+            replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x57: /* I-MMU demap */
+        demap_tlb(env->itlb, addr, "immu", env);
+        return;
+    case 0x58: /* D-MMU regs */
+        {
+            int reg = (addr >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->dmmuregs[reg];
+            switch (reg) {
+            case 0: /* RO */
+            case 4:
+                return;
+            case 3: /* SFSR */
+                if ((val & 1) == 0) {
+                    val = 0; /* Clear SFSR, Fault address */
+                    env->dmmu.sfar = 0;
+                }
+                env->dmmu.sfsr = val;
+                break;
+            case 1: /* Primary context */
+                env->dmmu.mmu_primary_context = val;
+                /* can be optimized to only flush MMU_USER_IDX
+                   and MMU_KERNEL_IDX entries */
+                tlb_flush(env, 1);
+                break;
+            case 2: /* Secondary context */
+                env->dmmu.mmu_secondary_context = val;
+                /* can be optimized to only flush MMU_USER_SECONDARY_IDX
+                   and MMU_KERNEL_SECONDARY_IDX entries */
+                tlb_flush(env, 1);
+                break;
+            case 5: /* TSB access */
+                DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", env->dmmu.tsb, val);
+                env->dmmu.tsb = val;
+                break;
+            case 6: /* Tag access */
+                env->dmmu.tag_access = val;
+                break;
+            case 7: /* Virtual Watchpoint */
+            case 8: /* Physical Watchpoint */
+            default:
+                env->dmmuregs[reg] = val;
+                break;
+            }
+
+            if (oldreg != env->dmmuregs[reg]) {
+                DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+                            PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
+            }
+#ifdef DEBUG_MMU
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x5c: /* D-MMU data in */
+        replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
+        return;
+    case 0x5d: /* D-MMU data access */
+        {
+            unsigned int i = (addr >> 3) & 0x3f;
+
+            replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+            DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
+            dump_mmu(stdout, fprintf, env);
+#endif
+            return;
+        }
+    case 0x5f: /* D-MMU demap */
+        demap_tlb(env->dtlb, addr, "dmmu", env);
+        return;
+    case 0x49: /* Interrupt data receive */
+        /* XXX */
+        return;
+    case 0x46: /* D-cache data */
+    case 0x47: /* D-cache tag access */
+    case 0x4b: /* E-cache error enable */
+    case 0x4c: /* E-cache asynchronous fault status */
+    case 0x4d: /* E-cache asynchronous fault address */
+    case 0x4e: /* E-cache tag data */
+    case 0x66: /* I-cache instruction access */
+    case 0x67: /* I-cache tag access */
+    case 0x6e: /* I-cache predecode */
+    case 0x6f: /* I-cache LRU etc. */
+    case 0x76: /* E-cache tag */
+    case 0x7e: /* E-cache tag */
+        return;
+    case 0x51: /* I-MMU 8k TSB pointer, RO */
+    case 0x52: /* I-MMU 64k TSB pointer, RO */
+    case 0x56: /* I-MMU tag read, RO */
+    case 0x59: /* D-MMU 8k TSB pointer, RO */
+    case 0x5a: /* D-MMU 64k TSB pointer, RO */
+    case 0x5b: /* D-MMU data pointer, RO */
+    case 0x5e: /* D-MMU tag read, RO */
+    case 0x48: /* Interrupt dispatch, RO */
+    case 0x7f: /* Incoming interrupt vector, RO */
+    case 0x82: /* Primary no-fault, RO */
+    case 0x83: /* Secondary no-fault, RO */
+    case 0x8a: /* Primary no-fault LE, RO */
+    case 0x8b: /* Secondary no-fault LE, RO */
+    default:
+        do_unassigned_access(addr, 1, 0, 1, size);
+        return;
+    }
+}
+#endif /* CONFIG_USER_ONLY */
+
+void helper_ldda_asi(target_ulong addr, int asi, int rd)
+{
+    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+        || (cpu_has_hypervisor(env)
+            && asi >= 0x30 && asi < 0x80
+            && !(env->hpstate & HS_PRIV))) {
+        helper_raise_exception(env, TT_PRIV_ACT);
+    }
+
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+#if !defined(CONFIG_USER_ONLY)
+    case 0x24: /* Nucleus quad LDD 128 bit atomic */
+    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */
+        helper_check_align(addr, 0xf);
+        if (rd == 0) {
+            env->gregs[1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->gregs[1]);
+            }
+        } else if (rd < 8) {
+            env->gregs[rd] = ldq_nucleus(addr);
+            env->gregs[rd + 1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->gregs[rd]);
+                bswap64s(&env->gregs[rd + 1]);
+            }
+        } else {
+            env->regwptr[rd] = ldq_nucleus(addr);
+            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
+            if (asi == 0x2c) {
+                bswap64s(&env->regwptr[rd]);
+                bswap64s(&env->regwptr[rd + 1]);
+            }
+        }
+        break;
+#endif
+    default:
+        helper_check_align(addr, 0x3);
+        if (rd == 0) {
+            env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        } else if (rd < 8) {
+            env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
+            env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        } else {
+            env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
+            env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+        }
+        break;
+    }
+}
+
+void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
+{
+    unsigned int i;
+    CPU_DoubleU u;
+
+    helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0xf0: /* UA2007/JPS1 Block load primary */
+    case 0xf1: /* UA2007/JPS1 Block load secondary */
+    case 0xf8: /* UA2007/JPS1 Block load primary LE */
+    case 0xf9: /* UA2007/JPS1 Block load secondary LE */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
+                                                         0);
+            addr += 4;
+        }
+
+        return;
+    case 0x16: /* UA2007 Block load primary, user privilege */
+    case 0x17: /* UA2007 Block load secondary, user privilege */
+    case 0x1e: /* UA2007 Block load primary LE, user privilege */
+    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+    case 0x70: /* JPS1 Block load primary, user privilege */
+    case 0x71: /* JPS1 Block load secondary, user privilege */
+    case 0x78: /* JPS1 Block load primary LE, user privilege */
+    case 0x79: /* JPS1 Block load secondary LE, user privilege */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4,
+                                                         0);
+            addr += 4;
+        }
+
+        return;
+    default:
+        break;
+    }
+
+    switch (size) {
+    default:
+    case 4:
+        *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
+        break;
+    case 8:
+        u.ll = helper_ld_asi(addr, asi, size, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        break;
+    case 16:
+        u.ll = helper_ld_asi(addr, asi, 8, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        u.ll = helper_ld_asi(addr + 8, asi, 8, 0);
+        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+        break;
+    }
+}
+
+void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
+{
+    unsigned int i;
+    target_ulong val = 0;
+    CPU_DoubleU u;
+
+    helper_check_align(addr, 3);
+    addr = asi_address_mask(env, asi, addr);
+
+    switch (asi) {
+    case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
+    case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
+    case 0xf0: /* UA2007/JPS1 Block store primary */
+    case 0xf1: /* UA2007/JPS1 Block store secondary */
+    case 0xf8: /* UA2007/JPS1 Block store primary LE */
+    case 0xf9: /* UA2007/JPS1 Block store secondary LE */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            val = *(uint32_t *)&env->fpr[rd++];
+            helper_st_asi(addr, val, asi & 0x8f, 4);
+            addr += 4;
+        }
+
+        return;
+    case 0x16: /* UA2007 Block load primary, user privilege */
+    case 0x17: /* UA2007 Block load secondary, user privilege */
+    case 0x1e: /* UA2007 Block load primary LE, user privilege */
+    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+    case 0x70: /* JPS1 Block store primary, user privilege */
+    case 0x71: /* JPS1 Block store secondary, user privilege */
+    case 0x78: /* JPS1 Block load primary LE, user privilege */
+    case 0x79: /* JPS1 Block load secondary LE, user privilege */
+        if (rd & 7) {
+            helper_raise_exception(env, TT_ILL_INSN);
+            return;
+        }
+        helper_check_align(addr, 0x3f);
+        for (i = 0; i < 16; i++) {
+            val = *(uint32_t *)&env->fpr[rd++];
+            helper_st_asi(addr, val, asi & 0x19, 4);
+            addr += 4;
+        }
+
+        return;
+    default:
+        break;
+    }
+
+    switch (size) {
+    default:
+    case 4:
+        helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
+        break;
+    case 8:
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr, u.ll, asi, size);
+        break;
+    case 16:
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr, u.ll, asi, 8);
+        u.l.upper = *(uint32_t *)&env->fpr[rd++];
+        u.l.lower = *(uint32_t *)&env->fpr[rd++];
+        helper_st_asi(addr + 8, u.ll, asi, 8);
+        break;
+    }
+}
+
+target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
+                            target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    val2 &= 0xffffffffUL;
+    ret = helper_ld_asi(addr, asi, 4, 0);
+    ret &= 0xffffffffUL;
+    if (val2 == ret) {
+        helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
+    }
+    return ret;
+}
+
+target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
+                             target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    ret = helper_ld_asi(addr, asi, 8, 0);
+    if (val2 == ret) {
+        helper_st_asi(addr, val1, asi, 8);
+    }
+    return ret;
+}
+#endif /* TARGET_SPARC64 */
+
+void helper_stdf(target_ulong addr, int mem_idx)
+{
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        stfq_user(addr, DT0);
+        break;
+    case MMU_KERNEL_IDX:
+        stfq_kernel(addr, DT0);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        stfq_hypv(addr, DT0);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    stfq_raw(address_mask(env, addr), DT0);
+#endif
+}
+
+void helper_lddf(target_ulong addr, int mem_idx)
+{
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        DT0 = ldfq_user(addr);
+        break;
+    case MMU_KERNEL_IDX:
+        DT0 = ldfq_kernel(addr);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        DT0 = ldfq_hypv(addr);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    DT0 = ldfq_raw(address_mask(env, addr));
+#endif
+}
+
+void helper_ldqf(target_ulong addr, int mem_idx)
+{
+    /* XXX add 128 bit load */
+    CPU_QuadU u;
+
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        u.ll.upper = ldq_user(addr);
+        u.ll.lower = ldq_user(addr + 8);
+        QT0 = u.q;
+        break;
+    case MMU_KERNEL_IDX:
+        u.ll.upper = ldq_kernel(addr);
+        u.ll.lower = ldq_kernel(addr + 8);
+        QT0 = u.q;
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        u.ll.upper = ldq_hypv(addr);
+        u.ll.lower = ldq_hypv(addr + 8);
+        QT0 = u.q;
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    u.ll.upper = ldq_raw(address_mask(env, addr));
+    u.ll.lower = ldq_raw(address_mask(env, addr + 8));
+    QT0 = u.q;
+#endif
+}
+
+void helper_stqf(target_ulong addr, int mem_idx)
+{
+    /* XXX add 128 bit store */
+    CPU_QuadU u;
+
+    helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+    switch (mem_idx) {
+    case MMU_USER_IDX:
+        u.q = QT0;
+        stq_user(addr, u.ll.upper);
+        stq_user(addr + 8, u.ll.lower);
+        break;
+    case MMU_KERNEL_IDX:
+        u.q = QT0;
+        stq_kernel(addr, u.ll.upper);
+        stq_kernel(addr + 8, u.ll.lower);
+        break;
+#ifdef TARGET_SPARC64
+    case MMU_HYPV_IDX:
+        u.q = QT0;
+        stq_hypv(addr, u.ll.upper);
+        stq_hypv(addr + 8, u.ll.lower);
+        break;
+#endif
+    default:
+        DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
+        break;
+    }
+#else
+    u.q = QT0;
+    stq_raw(address_mask(env, addr), u.ll.upper);
+    stq_raw(address_mask(env, addr + 8), u.ll.lower);
+#endif
+}
+
+#ifndef TARGET_SPARC64
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
+{
+    int fault_type;
+
+#ifdef DEBUG_UNASSIGNED
+    if (is_asi) {
+        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+               " asi 0x%02x from " TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", size,
+               size == 1 ? "" : "s", addr, is_asi, env->pc);
+    } else {
+        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+               " from " TARGET_FMT_lx "\n",
+               is_exec ? "exec" : is_write ? "write" : "read", size,
+               size == 1 ? "" : "s", addr, env->pc);
+    }
+#endif
+    /* Don't overwrite translation and access faults */
+    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
+    if ((fault_type > 4) || (fault_type == 0)) {
+        env->mmuregs[3] = 0; /* Fault status register */
+        if (is_asi) {
+            env->mmuregs[3] |= 1 << 16;
+        }
+        if (env->psrs) {
+            env->mmuregs[3] |= 1 << 5;
+        }
+        if (is_exec) {
+            env->mmuregs[3] |= 1 << 6;
+        }
+        if (is_write) {
+            env->mmuregs[3] |= 1 << 7;
+        }
+        env->mmuregs[3] |= (5 << 2) | 2;
+        /* SuperSPARC will never place instruction fault addresses in the FAR */
+        if (!is_exec) {
+            env->mmuregs[4] = addr; /* Fault address register */
+        }
+    }
+    /* overflow (same type fault was not read before another fault) */
+    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
+        env->mmuregs[3] |= 1;
+    }
+
+    if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
+        if (is_exec) {
+            helper_raise_exception(env, TT_CODE_ACCESS);
+        } else {
+            helper_raise_exception(env, TT_DATA_ACCESS);
+        }
+    }
+
+    /* flush neverland mappings created during no-fault mode,
+       so the sequential MMU faults report proper fault types */
+    if (env->mmuregs[0] & MMU_NF) {
+        tlb_flush(env, 1);
+    }
+}
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+                                 int is_asi, int size)
+#else
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+                                 int is_exec, int is_asi, int size)
+#endif
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
+           "\n", addr, env->pc);
+#endif
+
+    if (is_exec) {
+        helper_raise_exception(env, TT_CODE_ACCESS);
+    } else {
+        helper_raise_exception(env, TT_DATA_ACCESS);
+    }
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_unassigned_access(addr, is_write, is_exec, is_asi, size);
+    env = saved_env;
+}
+#endif
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 0f77ebf..02b660d 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -3,2322 +3,6 @@
 #include "helper.h"
 
 #if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif
-
-//#define DEBUG_MMU
-//#define DEBUG_MXCC
-//#define DEBUG_UNALIGNED
-//#define DEBUG_UNASSIGNED
-//#define DEBUG_ASI
-//#define DEBUG_CACHE_CONTROL
-
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...)                                   \
-    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_MXCC
-#define DPRINTF_MXCC(fmt, ...)                                  \
-    do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MXCC(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_ASI
-#define DPRINTF_ASI(fmt, ...)                                   \
-    do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
-#endif
-
-#ifdef DEBUG_CACHE_CONTROL
-#define DPRINTF_CACHE_CONTROL(fmt, ...)                                 \
-    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
-#endif
-
-#ifdef TARGET_SPARC64
-#ifndef TARGET_ABI32
-#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
-#else
-#define AM_CHECK(env1) (1)
-#endif
-#endif
-
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
-#define QT0 (env->qt0)
-#define QT1 (env->qt1)
-
-#if !defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size);
-#else
-#ifdef TARGET_SPARC64
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                                 int is_asi, int size);
-#endif
-#endif
-
-#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
-/* Calculates TSB pointer value for fault page size 8k or 64k */
-static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
-                                       uint64_t tag_access_register,
-                                       int page_size)
-{
-    uint64_t tsb_base = tsb_register & ~0x1fffULL;
-    int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
-    int tsb_size  = tsb_register & 0xf;
-
-    /* discard lower 13 bits which hold tag access context */
-    uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
-
-    /* now reorder bits */
-    uint64_t tsb_base_mask = ~0x1fffULL;
-    uint64_t va = tag_access_va;
-
-    /* move va bits to correct position */
-    if (page_size == 8*1024) {
-        va >>= 9;
-    } else if (page_size == 64*1024) {
-        va >>= 12;
-    }
-
-    if (tsb_size) {
-        tsb_base_mask <<= tsb_size;
-    }
-
-    /* calculate tsb_base mask and adjust va if split is in use */
-    if (tsb_split) {
-        if (page_size == 8*1024) {
-            va &= ~(1ULL << (13 + tsb_size));
-        } else if (page_size == 64*1024) {
-            va |= (1ULL << (13 + tsb_size));
-        }
-        tsb_base_mask <<= 1;
-    }
-
-    return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
-}
-
-/* Calculates tag target register value by reordering bits
-   in tag access register */
-static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
-{
-    return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
-}
-
-static void replace_tlb_entry(SparcTLBEntry *tlb,
-                              uint64_t tlb_tag, uint64_t tlb_tte,
-                              CPUState *env1)
-{
-    target_ulong mask, size, va, offset;
-
-    /* flush page range if translation is valid */
-    if (TTE_IS_VALID(tlb->tte)) {
-
-        mask = 0xffffffffffffe000ULL;
-        mask <<= 3 * ((tlb->tte >> 61) & 3);
-        size = ~mask + 1;
-
-        va = tlb->tag & mask;
-
-        for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
-            tlb_flush_page(env1, va + offset);
-        }
-    }
-
-    tlb->tag = tlb_tag;
-    tlb->tte = tlb_tte;
-}
-
-static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
-                      const char *strmmu, CPUState *env1)
-{
-    unsigned int i;
-    target_ulong mask;
-    uint64_t context;
-
-    int is_demap_context = (demap_addr >> 6) & 1;
-
-    /* demap context */
-    switch ((demap_addr >> 4) & 3) {
-    case 0: /* primary */
-        context = env1->dmmu.mmu_primary_context;
-        break;
-    case 1: /* secondary */
-        context = env1->dmmu.mmu_secondary_context;
-        break;
-    case 2: /* nucleus */
-        context = 0;
-        break;
-    case 3: /* reserved */
-    default:
-        return;
-    }
-
-    for (i = 0; i < 64; i++) {
-        if (TTE_IS_VALID(tlb[i].tte)) {
-
-            if (is_demap_context) {
-                /* will remove non-global entries matching context value */
-                if (TTE_IS_GLOBAL(tlb[i].tte) ||
-                    !tlb_compare_context(&tlb[i], context)) {
-                    continue;
-                }
-            } else {
-                /* demap page
-                   will remove any entry matching VA */
-                mask = 0xffffffffffffe000ULL;
-                mask <<= 3 * ((tlb[i].tte >> 61) & 3);
-
-                if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
-                    continue;
-                }
-
-                /* entry should be global or matching context value */
-                if (!TTE_IS_GLOBAL(tlb[i].tte) &&
-                    !tlb_compare_context(&tlb[i], context)) {
-                    continue;
-                }
-            }
-
-            replace_tlb_entry(&tlb[i], 0, 0, env1);
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
-            dump_mmu(stdout, fprintf, env1);
-#endif
-        }
-    }
-}
-
-static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
-                                 uint64_t tlb_tag, uint64_t tlb_tte,
-                                 const char *strmmu, CPUState *env1)
-{
-    unsigned int i, replace_used;
-
-    /* Try replacing invalid entry */
-    for (i = 0; i < 64; i++) {
-        if (!TTE_IS_VALID(tlb[i].tte)) {
-            replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
-            dump_mmu(stdout, fprintf, env1);
-#endif
-            return;
-        }
-    }
-
-    /* All entries are valid, try replacing unlocked entry */
-
-    for (replace_used = 0; replace_used < 2; ++replace_used) {
-
-        /* Used entries are not replaced on first pass */
-
-        for (i = 0; i < 64; i++) {
-            if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
-
-                replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
-#ifdef DEBUG_MMU
-                DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
-                            strmmu, (replace_used ? "used" : "unused"), i);
-                dump_mmu(stdout, fprintf, env1);
-#endif
-                return;
-            }
-        }
-
-        /* Now reset used bit and search for unused entries again */
-
-        for (i = 0; i < 64; i++) {
-            TTE_SET_UNUSED(tlb[i].tte);
-        }
-    }
-
-#ifdef DEBUG_MMU
-    DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
-#endif
-    /* error state? */
-}
-
-#endif
-
-static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
-{
-#ifdef TARGET_SPARC64
-    if (AM_CHECK(env1)) {
-        addr &= 0xffffffffULL;
-    }
-#endif
-    return addr;
-}
-
-/* returns true if access using this ASI is to have address translated by MMU
-   otherwise access is to raw physical address */
-static inline int is_translating_asi(int asi)
-{
-#ifdef TARGET_SPARC64
-    /* Ultrasparc IIi translating asi
-       - note this list is defined by cpu implementation
-    */
-    switch (asi) {
-    case 0x04 ... 0x11:
-    case 0x16 ... 0x19:
-    case 0x1E ... 0x1F:
-    case 0x24 ... 0x2C:
-    case 0x70 ... 0x73:
-    case 0x78 ... 0x79:
-    case 0x80 ... 0xFF:
-        return 1;
-
-    default:
-        return 0;
-    }
-#else
-    /* TODO: check sparc32 bits */
-    return 0;
-#endif
-}
-
-static inline target_ulong asi_address_mask(CPUState *env1,
-                                            int asi, target_ulong addr)
-{
-    if (is_translating_asi(asi)) {
-        return address_mask(env, addr);
-    } else {
-        return addr;
-    }
-}
-
-void helper_check_align(target_ulong addr, uint32_t align)
-{
-    if (addr & align) {
-#ifdef DEBUG_UNALIGNED
-        printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
-               "\n", addr, env->pc);
-#endif
-        helper_raise_exception(env, TT_UNALIGNED);
-    }
-}
-
-#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) &&   \
-    defined(DEBUG_MXCC)
-static void dump_mxcc(CPUState *env)
-{
-    printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n",
-           env->mxccdata[0], env->mxccdata[1],
-           env->mxccdata[2], env->mxccdata[3]);
-    printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n"
-           "          %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
-           "\n",
-           env->mxccregs[0], env->mxccregs[1],
-           env->mxccregs[2], env->mxccregs[3],
-           env->mxccregs[4], env->mxccregs[5],
-           env->mxccregs[6], env->mxccregs[7]);
-}
-#endif
-
-#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY))     \
-    && defined(DEBUG_ASI)
-static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
-                     uint64_t r1)
-{
-    switch (size) {
-    case 1:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xff);
-        break;
-    case 2:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xffff);
-        break;
-    case 4:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
-                    addr, asi, r1 & 0xffffffff);
-        break;
-    case 8:
-        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
-                    addr, asi, r1);
-        break;
-    }
-}
-#endif
-
-#ifndef TARGET_SPARC64
-#ifndef CONFIG_USER_ONLY
-
-
-/* Leon3 cache control */
-
-static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
-{
-    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
-                          addr, val, size);
-
-    if (size != 4) {
-        DPRINTF_CACHE_CONTROL("32bits only\n");
-        return;
-    }
-
-    switch (addr) {
-    case 0x00:              /* Cache control */
-
-        /* These values must always be read as zeros */
-        val &= ~CACHE_CTRL_FD;
-        val &= ~CACHE_CTRL_FI;
-        val &= ~CACHE_CTRL_IB;
-        val &= ~CACHE_CTRL_IP;
-        val &= ~CACHE_CTRL_DP;
-
-        env->cache_control = val;
-        break;
-    case 0x04:              /* Instruction cache configuration */
-    case 0x08:              /* Data cache configuration */
-        /* Read Only */
-        break;
-    default:
-        DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
-        break;
-    };
-}
-
-static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
-{
-    uint64_t ret = 0;
-
-    if (size != 4) {
-        DPRINTF_CACHE_CONTROL("32bits only\n");
-        return 0;
-    }
-
-    switch (addr) {
-    case 0x00:              /* Cache control */
-        ret = env->cache_control;
-        break;
-
-        /* Configuration registers are read and only always keep those
-           predefined values */
-
-    case 0x04:              /* Instruction cache configuration */
-        ret = 0x10220000;
-        break;
-    case 0x08:              /* Data cache configuration */
-        ret = 0x18220000;
-        break;
-    default:
-        DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
-        break;
-    };
-    DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
-                          addr, ret, size);
-    return ret;
-}
-
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
-    uint32_t last_addr = addr;
-#endif
-
-    helper_check_align(addr, size - 1);
-    switch (asi) {
-    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
-        switch (addr) {
-        case 0x00:          /* Leon3 Cache Control */
-        case 0x08:          /* Leon3 Instruction Cache config */
-        case 0x0C:          /* Leon3 Date Cache config */
-            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
-                ret = leon3_cache_control_ld(addr, size);
-            }
-            break;
-        case 0x01c00a00: /* MXCC control register */
-            if (size == 8) {
-                ret = env->mxccregs[3];
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00a04: /* MXCC control register */
-            if (size == 4) {
-                ret = env->mxccregs[3];
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00c00: /* Module reset register */
-            if (size == 8) {
-                ret = env->mxccregs[5];
-                /* should we do something here? */
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00f00: /* MBus port address register */
-            if (size == 8) {
-                ret = env->mxccregs[7];
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        default:
-            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
-                         size);
-            break;
-        }
-        DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
-                     "addr = %08x -> ret = %" PRIx64 ","
-                     "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
-#ifdef DEBUG_MXCC
-        dump_mxcc(env);
-#endif
-        break;
-    case 3: /* MMU probe */
-        {
-            int mmulev;
-
-            mmulev = (addr >> 8) & 15;
-            if (mmulev > 4) {
-                ret = 0;
-            } else {
-                ret = mmu_probe(env, addr, mmulev);
-            }
-            DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
-                        addr, mmulev, ret);
-        }
-        break;
-    case 4: /* read MMU regs */
-        {
-            int reg = (addr >> 8) & 0x1f;
-
-            ret = env->mmuregs[reg];
-            if (reg == 3) { /* Fault status cleared on read */
-                env->mmuregs[3] = 0;
-            } else if (reg == 0x13) { /* Fault status read */
-                ret = env->mmuregs[3];
-            } else if (reg == 0x14) { /* Fault address read */
-                ret = env->mmuregs[4];
-            }
-            DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
-        }
-        break;
-    case 5: /* Turbosparc ITLB Diagnostic */
-    case 6: /* Turbosparc DTLB Diagnostic */
-    case 7: /* Turbosparc IOTLB Diagnostic */
-        break;
-    case 9: /* Supervisor code access */
-        switch (size) {
-        case 1:
-            ret = ldub_code(addr);
-            break;
-        case 2:
-            ret = lduw_code(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_code(addr);
-            break;
-        case 8:
-            ret = ldq_code(addr);
-            break;
-        }
-        break;
-    case 0xa: /* User data access */
-        switch (size) {
-        case 1:
-            ret = ldub_user(addr);
-            break;
-        case 2:
-            ret = lduw_user(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_user(addr);
-            break;
-        case 8:
-            ret = ldq_user(addr);
-            break;
-        }
-        break;
-    case 0xb: /* Supervisor data access */
-        switch (size) {
-        case 1:
-            ret = ldub_kernel(addr);
-            break;
-        case 2:
-            ret = lduw_kernel(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_kernel(addr);
-            break;
-        case 8:
-            ret = ldq_kernel(addr);
-            break;
-        }
-        break;
-    case 0xc: /* I-cache tag */
-    case 0xd: /* I-cache data */
-    case 0xe: /* D-cache tag */
-    case 0xf: /* D-cache data */
-        break;
-    case 0x20: /* MMU passthrough */
-        switch (size) {
-        case 1:
-            ret = ldub_phys(addr);
-            break;
-        case 2:
-            ret = lduw_phys(addr);
-            break;
-        default:
-        case 4:
-            ret = ldl_phys(addr);
-            break;
-        case 8:
-            ret = ldq_phys(addr);
-            break;
-        }
-        break;
-    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
-        switch (size) {
-        case 1:
-            ret = ldub_phys((target_phys_addr_t)addr
-                            | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        case 2:
-            ret = lduw_phys((target_phys_addr_t)addr
-                            | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        default:
-        case 4:
-            ret = ldl_phys((target_phys_addr_t)addr
-                           | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        case 8:
-            ret = ldq_phys((target_phys_addr_t)addr
-                           | ((target_phys_addr_t)(asi & 0xf) << 32));
-            break;
-        }
-        break;
-    case 0x30: /* Turbosparc secondary cache diagnostic */
-    case 0x31: /* Turbosparc RAM snoop */
-    case 0x32: /* Turbosparc page table descriptor diagnostic */
-    case 0x39: /* data cache diagnostic register */
-        ret = 0;
-        break;
-    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
-        {
-            int reg = (addr >> 8) & 3;
-
-            switch (reg) {
-            case 0: /* Breakpoint Value (Addr) */
-                ret = env->mmubpregs[reg];
-                break;
-            case 1: /* Breakpoint Mask */
-                ret = env->mmubpregs[reg];
-                break;
-            case 2: /* Breakpoint Control */
-                ret = env->mmubpregs[reg];
-                break;
-            case 3: /* Breakpoint Status */
-                ret = env->mmubpregs[reg];
-                env->mmubpregs[reg] = 0ULL;
-                break;
-            }
-            DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
-                        ret);
-        }
-        break;
-    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
-        ret = env->mmubpctrv;
-        break;
-    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
-        ret = env->mmubpctrc;
-        break;
-    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
-        ret = env->mmubpctrs;
-        break;
-    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
-        ret = env->mmubpaction;
-        break;
-    case 8: /* User code access, XXX */
-    default:
-        do_unassigned_access(addr, 0, 0, asi, size);
-        ret = 0;
-        break;
-    }
-    if (sign) {
-        switch (size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
-{
-    helper_check_align(addr, size - 1);
-    switch (asi) {
-    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
-        switch (addr) {
-        case 0x00:          /* Leon3 Cache Control */
-        case 0x08:          /* Leon3 Instruction Cache config */
-        case 0x0C:          /* Leon3 Date Cache config */
-            if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
-                leon3_cache_control_st(addr, val, size);
-            }
-            break;
-
-        case 0x01c00000: /* MXCC stream data register 0 */
-            if (size == 8) {
-                env->mxccdata[0] = val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00008: /* MXCC stream data register 1 */
-            if (size == 8) {
-                env->mxccdata[1] = val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00010: /* MXCC stream data register 2 */
-            if (size == 8) {
-                env->mxccdata[2] = val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00018: /* MXCC stream data register 3 */
-            if (size == 8) {
-                env->mxccdata[3] = val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00100: /* MXCC stream source */
-            if (size == 8) {
-                env->mxccregs[0] = val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        0);
-            env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        8);
-            env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        16);
-            env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
-                                        24);
-            break;
-        case 0x01c00200: /* MXCC stream destination */
-            if (size == 8) {
-                env->mxccregs[1] = val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  0,
-                     env->mxccdata[0]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  8,
-                     env->mxccdata[1]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
-                     env->mxccdata[2]);
-            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
-                     env->mxccdata[3]);
-            break;
-        case 0x01c00a00: /* MXCC control register */
-            if (size == 8) {
-                env->mxccregs[3] = val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00a04: /* MXCC control register */
-            if (size == 4) {
-                env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
-                    | val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00e00: /* MXCC error register  */
-            /* writing a 1 bit clears the error */
-            if (size == 8) {
-                env->mxccregs[6] &= ~val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        case 0x01c00f00: /* MBus port address register */
-            if (size == 8) {
-                env->mxccregs[7] = val;
-            } else {
-                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
-                             size);
-            }
-            break;
-        default:
-            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
-                         size);
-            break;
-        }
-        DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
-                     asi, size, addr, val);
-#ifdef DEBUG_MXCC
-        dump_mxcc(env);
-#endif
-        break;
-    case 3: /* MMU flush */
-        {
-            int mmulev;
-
-            mmulev = (addr >> 8) & 15;
-            DPRINTF_MMU("mmu flush level %d\n", mmulev);
-            switch (mmulev) {
-            case 0: /* flush page */
-                tlb_flush_page(env, addr & 0xfffff000);
-                break;
-            case 1: /* flush segment (256k) */
-            case 2: /* flush region (16M) */
-            case 3: /* flush context (4G) */
-            case 4: /* flush entire */
-                tlb_flush(env, 1);
-                break;
-            default:
-                break;
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-        }
-        break;
-    case 4: /* write MMU regs */
-        {
-            int reg = (addr >> 8) & 0x1f;
-            uint32_t oldreg;
-
-            oldreg = env->mmuregs[reg];
-            switch (reg) {
-            case 0: /* Control Register */
-                env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
-                    (val & 0x00ffffff);
-                /* Mappings generated during no-fault mode or MMU
-                   disabled mode are invalid in normal mode */
-                if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
-                    (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) {
-                    tlb_flush(env, 1);
-                }
-                break;
-            case 1: /* Context Table Pointer Register */
-                env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
-                break;
-            case 2: /* Context Register */
-                env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
-                if (oldreg != env->mmuregs[reg]) {
-                    /* we flush when the MMU context changes because
-                       QEMU has no MMU context support */
-                    tlb_flush(env, 1);
-                }
-                break;
-            case 3: /* Synchronous Fault Status Register with Clear */
-            case 4: /* Synchronous Fault Address Register */
-                break;
-            case 0x10: /* TLB Replacement Control Register */
-                env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
-                break;
-            case 0x13: /* Synchronous Fault Status Register with Read
-                          and Clear */
-                env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
-                break;
-            case 0x14: /* Synchronous Fault Address Register */
-                env->mmuregs[4] = val;
-                break;
-            default:
-                env->mmuregs[reg] = val;
-                break;
-            }
-            if (oldreg != env->mmuregs[reg]) {
-                DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
-                            reg, oldreg, env->mmuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-        }
-        break;
-    case 5: /* Turbosparc ITLB Diagnostic */
-    case 6: /* Turbosparc DTLB Diagnostic */
-    case 7: /* Turbosparc IOTLB Diagnostic */
-        break;
-    case 0xa: /* User data access */
-        switch (size) {
-        case 1:
-            stb_user(addr, val);
-            break;
-        case 2:
-            stw_user(addr, val);
-            break;
-        default:
-        case 4:
-            stl_user(addr, val);
-            break;
-        case 8:
-            stq_user(addr, val);
-            break;
-        }
-        break;
-    case 0xb: /* Supervisor data access */
-        switch (size) {
-        case 1:
-            stb_kernel(addr, val);
-            break;
-        case 2:
-            stw_kernel(addr, val);
-            break;
-        default:
-        case 4:
-            stl_kernel(addr, val);
-            break;
-        case 8:
-            stq_kernel(addr, val);
-            break;
-        }
-        break;
-    case 0xc: /* I-cache tag */
-    case 0xd: /* I-cache data */
-    case 0xe: /* D-cache tag */
-    case 0xf: /* D-cache data */
-    case 0x10: /* I/D-cache flush page */
-    case 0x11: /* I/D-cache flush segment */
-    case 0x12: /* I/D-cache flush region */
-    case 0x13: /* I/D-cache flush context */
-    case 0x14: /* I/D-cache flush user */
-        break;
-    case 0x17: /* Block copy, sta access */
-        {
-            /* val = src
-               addr = dst
-               copy 32 bytes */
-            unsigned int i;
-            uint32_t src = val & ~3, dst = addr & ~3, temp;
-
-            for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
-                temp = ldl_kernel(src);
-                stl_kernel(dst, temp);
-            }
-        }
-        break;
-    case 0x1f: /* Block fill, stda access */
-        {
-            /* addr = dst
-               fill 32 bytes with val */
-            unsigned int i;
-            uint32_t dst = addr & 7;
-
-            for (i = 0; i < 32; i += 8, dst += 8) {
-                stq_kernel(dst, val);
-            }
-        }
-        break;
-    case 0x20: /* MMU passthrough */
-        {
-            switch (size) {
-            case 1:
-                stb_phys(addr, val);
-                break;
-            case 2:
-                stw_phys(addr, val);
-                break;
-            case 4:
-            default:
-                stl_phys(addr, val);
-                break;
-            case 8:
-                stq_phys(addr, val);
-                break;
-            }
-        }
-        break;
-    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
-        {
-            switch (size) {
-            case 1:
-                stb_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 2:
-                stw_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 4:
-            default:
-                stl_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            case 8:
-                stq_phys((target_phys_addr_t)addr
-                         | ((target_phys_addr_t)(asi & 0xf) << 32), val);
-                break;
-            }
-        }
-        break;
-    case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */
-    case 0x31: /* store buffer data, Ross RT620 I-cache flush or
-                  Turbosparc snoop RAM */
-    case 0x32: /* store buffer control or Turbosparc page table
-                  descriptor diagnostic */
-    case 0x36: /* I-cache flash clear */
-    case 0x37: /* D-cache flash clear */
-        break;
-    case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
-        {
-            int reg = (addr >> 8) & 3;
-
-            switch (reg) {
-            case 0: /* Breakpoint Value (Addr) */
-                env->mmubpregs[reg] = (val & 0xfffffffffULL);
-                break;
-            case 1: /* Breakpoint Mask */
-                env->mmubpregs[reg] = (val & 0xfffffffffULL);
-                break;
-            case 2: /* Breakpoint Control */
-                env->mmubpregs[reg] = (val & 0x7fULL);
-                break;
-            case 3: /* Breakpoint Status */
-                env->mmubpregs[reg] = (val & 0xfULL);
-                break;
-            }
-            DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
-                        env->mmuregs[reg]);
-        }
-        break;
-    case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
-        env->mmubpctrv = val & 0xffffffff;
-        break;
-    case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
-        env->mmubpctrc = val & 0x3;
-        break;
-    case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
-        env->mmubpctrs = val & 0x3;
-        break;
-    case 0x4c: /* SuperSPARC MMU Breakpoint Action */
-        env->mmubpaction = val & 0x1fff;
-        break;
-    case 8: /* User code access, XXX */
-    case 9: /* Supervisor code access, XXX */
-    default:
-        do_unassigned_access(addr, 1, 0, asi, size);
-        break;
-    }
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-}
-
-#endif /* CONFIG_USER_ONLY */
-#else /* TARGET_SPARC64 */
-
-#ifdef CONFIG_USER_ONLY
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_ASI)
-    target_ulong last_addr = addr;
-#endif
-
-    if (asi < 0x80) {
-        helper_raise_exception(env, TT_PRIV_ACT);
-    }
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0x82: /* Primary no-fault */
-    case 0x8a: /* Primary no-fault LE */
-        if (page_check_range(addr, size, PAGE_READ) == -1) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            return 0;
-        }
-        /* Fall through */
-    case 0x80: /* Primary */
-    case 0x88: /* Primary LE */
-        {
-            switch (size) {
-            case 1:
-                ret = ldub_raw(addr);
-                break;
-            case 2:
-                ret = lduw_raw(addr);
-                break;
-            case 4:
-                ret = ldl_raw(addr);
-                break;
-            default:
-            case 8:
-                ret = ldq_raw(addr);
-                break;
-            }
-        }
-        break;
-    case 0x83: /* Secondary no-fault */
-    case 0x8b: /* Secondary no-fault LE */
-        if (page_check_range(addr, size, PAGE_READ) == -1) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            return 0;
-        }
-        /* Fall through */
-    case 0x81: /* Secondary */
-    case 0x89: /* Secondary LE */
-        /* XXX */
-        break;
-    default:
-        break;
-    }
-
-    /* Convert from little endian */
-    switch (asi) {
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-    case 0x8a: /* Primary no-fault LE */
-    case 0x8b: /* Secondary no-fault LE */
-        switch (size) {
-        case 2:
-            ret = bswap16(ret);
-            break;
-        case 4:
-            ret = bswap32(ret);
-            break;
-        case 8:
-            ret = bswap64(ret);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    /* Convert to signed number */
-    if (sign) {
-        switch (size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
-{
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-    if (asi < 0x80) {
-        helper_raise_exception(env, TT_PRIV_ACT);
-    }
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    /* Convert to little endian */
-    switch (asi) {
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-        switch (size) {
-        case 2:
-            val = bswap16(val);
-            break;
-        case 4:
-            val = bswap32(val);
-            break;
-        case 8:
-            val = bswap64(val);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    switch (asi) {
-    case 0x80: /* Primary */
-    case 0x88: /* Primary LE */
-        {
-            switch (size) {
-            case 1:
-                stb_raw(addr, val);
-                break;
-            case 2:
-                stw_raw(addr, val);
-                break;
-            case 4:
-                stl_raw(addr, val);
-                break;
-            case 8:
-            default:
-                stq_raw(addr, val);
-                break;
-            }
-        }
-        break;
-    case 0x81: /* Secondary */
-    case 0x89: /* Secondary LE */
-        /* XXX */
-        return;
-
-    case 0x82: /* Primary no-fault, RO */
-    case 0x83: /* Secondary no-fault, RO */
-    case 0x8a: /* Primary no-fault LE, RO */
-    case 0x8b: /* Secondary no-fault LE, RO */
-    default:
-        do_unassigned_access(addr, 1, 0, 1, size);
-        return;
-    }
-}
-
-#else /* CONFIG_USER_ONLY */
-
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
-    uint64_t ret = 0;
-#if defined(DEBUG_ASI)
-    target_ulong last_addr = addr;
-#endif
-
-    asi &= 0xff;
-
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV))) {
-        helper_raise_exception(env, TT_PRIV_ACT);
-    }
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    /* process nonfaulting loads first */
-    if ((asi & 0xf6) == 0x82) {
-        int mmu_idx;
-
-        /* secondary space access has lowest asi bit equal to 1 */
-        if (env->pstate & PS_PRIV) {
-            mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
-        } else {
-            mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
-        }
-
-        if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            /* env->exception_index is set in get_physical_address_data(). */
-            helper_raise_exception(env, env->exception_index);
-        }
-
-        /* convert nonfaulting load ASIs to normal load ASIs */
-        asi &= ~0x02;
-    }
-
-    switch (asi) {
-    case 0x10: /* As if user primary */
-    case 0x11: /* As if user secondary */
-    case 0x18: /* As if user primary LE */
-    case 0x19: /* As if user secondary LE */
-    case 0x80: /* Primary */
-    case 0x81: /* Secondary */
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-    case 0xe2: /* UA2007 Primary block init */
-    case 0xe3: /* UA2007 Secondary block init */
-        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
-            if (cpu_hypervisor_mode(env)) {
-                switch (size) {
-                case 1:
-                    ret = ldub_hypv(addr);
-                    break;
-                case 2:
-                    ret = lduw_hypv(addr);
-                    break;
-                case 4:
-                    ret = ldl_hypv(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_hypv(addr);
-                    break;
-                }
-            } else {
-                /* secondary space access has lowest asi bit equal to 1 */
-                if (asi & 1) {
-                    switch (size) {
-                    case 1:
-                        ret = ldub_kernel_secondary(addr);
-                        break;
-                    case 2:
-                        ret = lduw_kernel_secondary(addr);
-                        break;
-                    case 4:
-                        ret = ldl_kernel_secondary(addr);
-                        break;
-                    default:
-                    case 8:
-                        ret = ldq_kernel_secondary(addr);
-                        break;
-                    }
-                } else {
-                    switch (size) {
-                    case 1:
-                        ret = ldub_kernel(addr);
-                        break;
-                    case 2:
-                        ret = lduw_kernel(addr);
-                        break;
-                    case 4:
-                        ret = ldl_kernel(addr);
-                        break;
-                    default:
-                    case 8:
-                        ret = ldq_kernel(addr);
-                        break;
-                    }
-                }
-            }
-        } else {
-            /* secondary space access has lowest asi bit equal to 1 */
-            if (asi & 1) {
-                switch (size) {
-                case 1:
-                    ret = ldub_user_secondary(addr);
-                    break;
-                case 2:
-                    ret = lduw_user_secondary(addr);
-                    break;
-                case 4:
-                    ret = ldl_user_secondary(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_user_secondary(addr);
-                    break;
-                }
-            } else {
-                switch (size) {
-                case 1:
-                    ret = ldub_user(addr);
-                    break;
-                case 2:
-                    ret = lduw_user(addr);
-                    break;
-                case 4:
-                    ret = ldl_user(addr);
-                    break;
-                default:
-                case 8:
-                    ret = ldq_user(addr);
-                    break;
-                }
-            }
-        }
-        break;
-    case 0x14: /* Bypass */
-    case 0x15: /* Bypass, non-cacheable */
-    case 0x1c: /* Bypass LE */
-    case 0x1d: /* Bypass, non-cacheable LE */
-        {
-            switch (size) {
-            case 1:
-                ret = ldub_phys(addr);
-                break;
-            case 2:
-                ret = lduw_phys(addr);
-                break;
-            case 4:
-                ret = ldl_phys(addr);
-                break;
-            default:
-            case 8:
-                ret = ldq_phys(addr);
-                break;
-            }
-            break;
-        }
-    case 0x24: /* Nucleus quad LDD 128 bit atomic */
-    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
-                  Only ldda allowed */
-        helper_raise_exception(env, TT_ILL_INSN);
-        return 0;
-    case 0x04: /* Nucleus */
-    case 0x0c: /* Nucleus Little Endian (LE) */
-        {
-            switch (size) {
-            case 1:
-                ret = ldub_nucleus(addr);
-                break;
-            case 2:
-                ret = lduw_nucleus(addr);
-                break;
-            case 4:
-                ret = ldl_nucleus(addr);
-                break;
-            default:
-            case 8:
-                ret = ldq_nucleus(addr);
-                break;
-            }
-            break;
-        }
-    case 0x4a: /* UPA config */
-        /* XXX */
-        break;
-    case 0x45: /* LSU */
-        ret = env->lsu;
-        break;
-    case 0x50: /* I-MMU regs */
-        {
-            int reg = (addr >> 3) & 0xf;
-
-            if (reg == 0) {
-                /* I-TSB Tag Target register */
-                ret = ultrasparc_tag_target(env->immu.tag_access);
-            } else {
-                ret = env->immuregs[reg];
-            }
-
-            break;
-        }
-    case 0x51: /* I-MMU 8k TSB pointer */
-        {
-            /* env->immuregs[5] holds I-MMU TSB register value
-               env->immuregs[6] holds I-MMU Tag Access register value */
-            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
-                                         8*1024);
-            break;
-        }
-    case 0x52: /* I-MMU 64k TSB pointer */
-        {
-            /* env->immuregs[5] holds I-MMU TSB register value
-               env->immuregs[6] holds I-MMU Tag Access register value */
-            ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
-                                         64*1024);
-            break;
-        }
-    case 0x55: /* I-MMU data access */
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->itlb[reg].tte;
-            break;
-        }
-    case 0x56: /* I-MMU tag read */
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->itlb[reg].tag;
-            break;
-        }
-    case 0x58: /* D-MMU regs */
-        {
-            int reg = (addr >> 3) & 0xf;
-
-            if (reg == 0) {
-                /* D-TSB Tag Target register */
-                ret = ultrasparc_tag_target(env->dmmu.tag_access);
-            } else {
-                ret = env->dmmuregs[reg];
-            }
-            break;
-        }
-    case 0x59: /* D-MMU 8k TSB pointer */
-        {
-            /* env->dmmuregs[5] holds D-MMU TSB register value
-               env->dmmuregs[6] holds D-MMU Tag Access register value */
-            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
-                                         8*1024);
-            break;
-        }
-    case 0x5a: /* D-MMU 64k TSB pointer */
-        {
-            /* env->dmmuregs[5] holds D-MMU TSB register value
-               env->dmmuregs[6] holds D-MMU Tag Access register value */
-            ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
-                                         64*1024);
-            break;
-        }
-    case 0x5d: /* D-MMU data access */
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->dtlb[reg].tte;
-            break;
-        }
-    case 0x5e: /* D-MMU tag read */
-        {
-            int reg = (addr >> 3) & 0x3f;
-
-            ret = env->dtlb[reg].tag;
-            break;
-        }
-    case 0x46: /* D-cache data */
-    case 0x47: /* D-cache tag access */
-    case 0x4b: /* E-cache error enable */
-    case 0x4c: /* E-cache asynchronous fault status */
-    case 0x4d: /* E-cache asynchronous fault address */
-    case 0x4e: /* E-cache tag data */
-    case 0x66: /* I-cache instruction access */
-    case 0x67: /* I-cache tag access */
-    case 0x6e: /* I-cache predecode */
-    case 0x6f: /* I-cache LRU etc. */
-    case 0x76: /* E-cache tag */
-    case 0x7e: /* E-cache tag */
-        break;
-    case 0x5b: /* D-MMU data pointer */
-    case 0x48: /* Interrupt dispatch, RO */
-    case 0x49: /* Interrupt data receive */
-    case 0x7f: /* Incoming interrupt vector, RO */
-        /* XXX */
-        break;
-    case 0x54: /* I-MMU data in, WO */
-    case 0x57: /* I-MMU demap, WO */
-    case 0x5c: /* D-MMU data in, WO */
-    case 0x5f: /* D-MMU demap, WO */
-    case 0x77: /* Interrupt vector, WO */
-    default:
-        do_unassigned_access(addr, 0, 0, 1, size);
-        ret = 0;
-        break;
-    }
-
-    /* Convert from little endian */
-    switch (asi) {
-    case 0x0c: /* Nucleus Little Endian (LE) */
-    case 0x18: /* As if user primary LE */
-    case 0x19: /* As if user secondary LE */
-    case 0x1c: /* Bypass LE */
-    case 0x1d: /* Bypass, non-cacheable LE */
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-        switch(size) {
-        case 2:
-            ret = bswap16(ret);
-            break;
-        case 4:
-            ret = bswap32(ret);
-            break;
-        case 8:
-            ret = bswap64(ret);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    /* Convert to signed number */
-    if (sign) {
-        switch (size) {
-        case 1:
-            ret = (int8_t) ret;
-            break;
-        case 2:
-            ret = (int16_t) ret;
-            break;
-        case 4:
-            ret = (int32_t) ret;
-            break;
-        default:
-            break;
-        }
-    }
-#ifdef DEBUG_ASI
-    dump_asi("read ", last_addr, asi, size, ret);
-#endif
-    return ret;
-}
-
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
-{
-#ifdef DEBUG_ASI
-    dump_asi("write", addr, asi, size, val);
-#endif
-
-    asi &= 0xff;
-
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV))) {
-        helper_raise_exception(env, TT_PRIV_ACT);
-    }
-
-    helper_check_align(addr, size - 1);
-    addr = asi_address_mask(env, asi, addr);
-
-    /* Convert to little endian */
-    switch (asi) {
-    case 0x0c: /* Nucleus Little Endian (LE) */
-    case 0x18: /* As if user primary LE */
-    case 0x19: /* As if user secondary LE */
-    case 0x1c: /* Bypass LE */
-    case 0x1d: /* Bypass, non-cacheable LE */
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-        switch (size) {
-        case 2:
-            val = bswap16(val);
-            break;
-        case 4:
-            val = bswap32(val);
-            break;
-        case 8:
-            val = bswap64(val);
-            break;
-        default:
-            break;
-        }
-    default:
-        break;
-    }
-
-    switch (asi) {
-    case 0x10: /* As if user primary */
-    case 0x11: /* As if user secondary */
-    case 0x18: /* As if user primary LE */
-    case 0x19: /* As if user secondary LE */
-    case 0x80: /* Primary */
-    case 0x81: /* Secondary */
-    case 0x88: /* Primary LE */
-    case 0x89: /* Secondary LE */
-    case 0xe2: /* UA2007 Primary block init */
-    case 0xe3: /* UA2007 Secondary block init */
-        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
-            if (cpu_hypervisor_mode(env)) {
-                switch (size) {
-                case 1:
-                    stb_hypv(addr, val);
-                    break;
-                case 2:
-                    stw_hypv(addr, val);
-                    break;
-                case 4:
-                    stl_hypv(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_hypv(addr, val);
-                    break;
-                }
-            } else {
-                /* secondary space access has lowest asi bit equal to 1 */
-                if (asi & 1) {
-                    switch (size) {
-                    case 1:
-                        stb_kernel_secondary(addr, val);
-                        break;
-                    case 2:
-                        stw_kernel_secondary(addr, val);
-                        break;
-                    case 4:
-                        stl_kernel_secondary(addr, val);
-                        break;
-                    case 8:
-                    default:
-                        stq_kernel_secondary(addr, val);
-                        break;
-                    }
-                } else {
-                    switch (size) {
-                    case 1:
-                        stb_kernel(addr, val);
-                        break;
-                    case 2:
-                        stw_kernel(addr, val);
-                        break;
-                    case 4:
-                        stl_kernel(addr, val);
-                        break;
-                    case 8:
-                    default:
-                        stq_kernel(addr, val);
-                        break;
-                    }
-                }
-            }
-        } else {
-            /* secondary space access has lowest asi bit equal to 1 */
-            if (asi & 1) {
-                switch (size) {
-                case 1:
-                    stb_user_secondary(addr, val);
-                    break;
-                case 2:
-                    stw_user_secondary(addr, val);
-                    break;
-                case 4:
-                    stl_user_secondary(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_user_secondary(addr, val);
-                    break;
-                }
-            } else {
-                switch (size) {
-                case 1:
-                    stb_user(addr, val);
-                    break;
-                case 2:
-                    stw_user(addr, val);
-                    break;
-                case 4:
-                    stl_user(addr, val);
-                    break;
-                case 8:
-                default:
-                    stq_user(addr, val);
-                    break;
-                }
-            }
-        }
-        break;
-    case 0x14: /* Bypass */
-    case 0x15: /* Bypass, non-cacheable */
-    case 0x1c: /* Bypass LE */
-    case 0x1d: /* Bypass, non-cacheable LE */
-        {
-            switch (size) {
-            case 1:
-                stb_phys(addr, val);
-                break;
-            case 2:
-                stw_phys(addr, val);
-                break;
-            case 4:
-                stl_phys(addr, val);
-                break;
-            case 8:
-            default:
-                stq_phys(addr, val);
-                break;
-            }
-        }
-        return;
-    case 0x24: /* Nucleus quad LDD 128 bit atomic */
-    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
-                  Only ldda allowed */
-        helper_raise_exception(env, TT_ILL_INSN);
-        return;
-    case 0x04: /* Nucleus */
-    case 0x0c: /* Nucleus Little Endian (LE) */
-        {
-            switch (size) {
-            case 1:
-                stb_nucleus(addr, val);
-                break;
-            case 2:
-                stw_nucleus(addr, val);
-                break;
-            case 4:
-                stl_nucleus(addr, val);
-                break;
-            default:
-            case 8:
-                stq_nucleus(addr, val);
-                break;
-            }
-            break;
-        }
-
-    case 0x4a: /* UPA config */
-        /* XXX */
-        return;
-    case 0x45: /* LSU */
-        {
-            uint64_t oldreg;
-
-            oldreg = env->lsu;
-            env->lsu = val & (DMMU_E | IMMU_E);
-            /* Mappings generated during D/I MMU disabled mode are
-               invalid in normal mode */
-            if (oldreg != env->lsu) {
-                DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
-                            oldreg, env->lsu);
-#ifdef DEBUG_MMU
-                dump_mmu(stdout, fprintf, env1);
-#endif
-                tlb_flush(env, 1);
-            }
-            return;
-        }
-    case 0x50: /* I-MMU regs */
-        {
-            int reg = (addr >> 3) & 0xf;
-            uint64_t oldreg;
-
-            oldreg = env->immuregs[reg];
-            switch (reg) {
-            case 0: /* RO */
-                return;
-            case 1: /* Not in I-MMU */
-            case 2:
-                return;
-            case 3: /* SFSR */
-                if ((val & 1) == 0) {
-                    val = 0; /* Clear SFSR */
-                }
-                env->immu.sfsr = val;
-                break;
-            case 4: /* RO */
-                return;
-            case 5: /* TSB access */
-                DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", env->immu.tsb, val);
-                env->immu.tsb = val;
-                break;
-            case 6: /* Tag access */
-                env->immu.tag_access = val;
-                break;
-            case 7:
-            case 8:
-                return;
-            default:
-                break;
-            }
-
-            if (oldreg != env->immuregs[reg]) {
-                DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x54: /* I-MMU data in */
-        replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
-        return;
-    case 0x55: /* I-MMU data access */
-        {
-            /* TODO: auto demap */
-
-            unsigned int i = (addr >> 3) & 0x3f;
-
-            replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
-
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x57: /* I-MMU demap */
-        demap_tlb(env->itlb, addr, "immu", env);
-        return;
-    case 0x58: /* D-MMU regs */
-        {
-            int reg = (addr >> 3) & 0xf;
-            uint64_t oldreg;
-
-            oldreg = env->dmmuregs[reg];
-            switch (reg) {
-            case 0: /* RO */
-            case 4:
-                return;
-            case 3: /* SFSR */
-                if ((val & 1) == 0) {
-                    val = 0; /* Clear SFSR, Fault address */
-                    env->dmmu.sfar = 0;
-                }
-                env->dmmu.sfsr = val;
-                break;
-            case 1: /* Primary context */
-                env->dmmu.mmu_primary_context = val;
-                /* can be optimized to only flush MMU_USER_IDX
-                   and MMU_KERNEL_IDX entries */
-                tlb_flush(env, 1);
-                break;
-            case 2: /* Secondary context */
-                env->dmmu.mmu_secondary_context = val;
-                /* can be optimized to only flush MMU_USER_SECONDARY_IDX
-                   and MMU_KERNEL_SECONDARY_IDX entries */
-                tlb_flush(env, 1);
-                break;
-            case 5: /* TSB access */
-                DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", env->dmmu.tsb, val);
-                env->dmmu.tsb = val;
-                break;
-            case 6: /* Tag access */
-                env->dmmu.tag_access = val;
-                break;
-            case 7: /* Virtual Watchpoint */
-            case 8: /* Physical Watchpoint */
-            default:
-                env->dmmuregs[reg] = val;
-                break;
-            }
-
-            if (oldreg != env->dmmuregs[reg]) {
-                DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
-                            PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
-            }
-#ifdef DEBUG_MMU
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x5c: /* D-MMU data in */
-        replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
-        return;
-    case 0x5d: /* D-MMU data access */
-        {
-            unsigned int i = (addr >> 3) & 0x3f;
-
-            replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
-
-#ifdef DEBUG_MMU
-            DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
-            dump_mmu(stdout, fprintf, env);
-#endif
-            return;
-        }
-    case 0x5f: /* D-MMU demap */
-        demap_tlb(env->dtlb, addr, "dmmu", env);
-        return;
-    case 0x49: /* Interrupt data receive */
-        /* XXX */
-        return;
-    case 0x46: /* D-cache data */
-    case 0x47: /* D-cache tag access */
-    case 0x4b: /* E-cache error enable */
-    case 0x4c: /* E-cache asynchronous fault status */
-    case 0x4d: /* E-cache asynchronous fault address */
-    case 0x4e: /* E-cache tag data */
-    case 0x66: /* I-cache instruction access */
-    case 0x67: /* I-cache tag access */
-    case 0x6e: /* I-cache predecode */
-    case 0x6f: /* I-cache LRU etc. */
-    case 0x76: /* E-cache tag */
-    case 0x7e: /* E-cache tag */
-        return;
-    case 0x51: /* I-MMU 8k TSB pointer, RO */
-    case 0x52: /* I-MMU 64k TSB pointer, RO */
-    case 0x56: /* I-MMU tag read, RO */
-    case 0x59: /* D-MMU 8k TSB pointer, RO */
-    case 0x5a: /* D-MMU 64k TSB pointer, RO */
-    case 0x5b: /* D-MMU data pointer, RO */
-    case 0x5e: /* D-MMU tag read, RO */
-    case 0x48: /* Interrupt dispatch, RO */
-    case 0x7f: /* Incoming interrupt vector, RO */
-    case 0x82: /* Primary no-fault, RO */
-    case 0x83: /* Secondary no-fault, RO */
-    case 0x8a: /* Primary no-fault LE, RO */
-    case 0x8b: /* Secondary no-fault LE, RO */
-    default:
-        do_unassigned_access(addr, 1, 0, 1, size);
-        return;
-    }
-}
-#endif /* CONFIG_USER_ONLY */
-
-void helper_ldda_asi(target_ulong addr, int asi, int rd)
-{
-    if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-        || (cpu_has_hypervisor(env)
-            && asi >= 0x30 && asi < 0x80
-            && !(env->hpstate & HS_PRIV))) {
-        helper_raise_exception(env, TT_PRIV_ACT);
-    }
-
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-#if !defined(CONFIG_USER_ONLY)
-    case 0x24: /* Nucleus quad LDD 128 bit atomic */
-    case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */
-        helper_check_align(addr, 0xf);
-        if (rd == 0) {
-            env->gregs[1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->gregs[1]);
-            }
-        } else if (rd < 8) {
-            env->gregs[rd] = ldq_nucleus(addr);
-            env->gregs[rd + 1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->gregs[rd]);
-                bswap64s(&env->gregs[rd + 1]);
-            }
-        } else {
-            env->regwptr[rd] = ldq_nucleus(addr);
-            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
-            if (asi == 0x2c) {
-                bswap64s(&env->regwptr[rd]);
-                bswap64s(&env->regwptr[rd + 1]);
-            }
-        }
-        break;
-#endif
-    default:
-        helper_check_align(addr, 0x3);
-        if (rd == 0) {
-            env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        } else if (rd < 8) {
-            env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
-            env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        } else {
-            env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
-            env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
-        }
-        break;
-    }
-}
-
-void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
-{
-    unsigned int i;
-    CPU_DoubleU u;
-
-    helper_check_align(addr, 3);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0xf0: /* UA2007/JPS1 Block load primary */
-    case 0xf1: /* UA2007/JPS1 Block load secondary */
-    case 0xf8: /* UA2007/JPS1 Block load primary LE */
-    case 0xf9: /* UA2007/JPS1 Block load secondary LE */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
-                                                         0);
-            addr += 4;
-        }
-
-        return;
-    case 0x16: /* UA2007 Block load primary, user privilege */
-    case 0x17: /* UA2007 Block load secondary, user privilege */
-    case 0x1e: /* UA2007 Block load primary LE, user privilege */
-    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
-    case 0x70: /* JPS1 Block load primary, user privilege */
-    case 0x71: /* JPS1 Block load secondary, user privilege */
-    case 0x78: /* JPS1 Block load primary LE, user privilege */
-    case 0x79: /* JPS1 Block load secondary LE, user privilege */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4,
-                                                         0);
-            addr += 4;
-        }
-
-        return;
-    default:
-        break;
-    }
-
-    switch (size) {
-    default:
-    case 4:
-        *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
-        break;
-    case 8:
-        u.ll = helper_ld_asi(addr, asi, size, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
-        break;
-    case 16:
-        u.ll = helper_ld_asi(addr, asi, 8, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
-        u.ll = helper_ld_asi(addr + 8, asi, 8, 0);
-        *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
-        *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
-        break;
-    }
-}
-
-void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
-{
-    unsigned int i;
-    target_ulong val = 0;
-    CPU_DoubleU u;
-
-    helper_check_align(addr, 3);
-    addr = asi_address_mask(env, asi, addr);
-
-    switch (asi) {
-    case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
-    case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
-    case 0xf0: /* UA2007/JPS1 Block store primary */
-    case 0xf1: /* UA2007/JPS1 Block store secondary */
-    case 0xf8: /* UA2007/JPS1 Block store primary LE */
-    case 0xf9: /* UA2007/JPS1 Block store secondary LE */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            val = *(uint32_t *)&env->fpr[rd++];
-            helper_st_asi(addr, val, asi & 0x8f, 4);
-            addr += 4;
-        }
-
-        return;
-    case 0x16: /* UA2007 Block load primary, user privilege */
-    case 0x17: /* UA2007 Block load secondary, user privilege */
-    case 0x1e: /* UA2007 Block load primary LE, user privilege */
-    case 0x1f: /* UA2007 Block load secondary LE, user privilege */
-    case 0x70: /* JPS1 Block store primary, user privilege */
-    case 0x71: /* JPS1 Block store secondary, user privilege */
-    case 0x78: /* JPS1 Block load primary LE, user privilege */
-    case 0x79: /* JPS1 Block load secondary LE, user privilege */
-        if (rd & 7) {
-            helper_raise_exception(env, TT_ILL_INSN);
-            return;
-        }
-        helper_check_align(addr, 0x3f);
-        for (i = 0; i < 16; i++) {
-            val = *(uint32_t *)&env->fpr[rd++];
-            helper_st_asi(addr, val, asi & 0x19, 4);
-            addr += 4;
-        }
-
-        return;
-    default:
-        break;
-    }
-
-    switch (size) {
-    default:
-    case 4:
-        helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
-        break;
-    case 8:
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr, u.ll, asi, size);
-        break;
-    case 16:
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr, u.ll, asi, 8);
-        u.l.upper = *(uint32_t *)&env->fpr[rd++];
-        u.l.lower = *(uint32_t *)&env->fpr[rd++];
-        helper_st_asi(addr + 8, u.ll, asi, 8);
-        break;
-    }
-}
-
-target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
-                            target_ulong val2, uint32_t asi)
-{
-    target_ulong ret;
-
-    val2 &= 0xffffffffUL;
-    ret = helper_ld_asi(addr, asi, 4, 0);
-    ret &= 0xffffffffUL;
-    if (val2 == ret) {
-        helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
-    }
-    return ret;
-}
-
-target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
-                             target_ulong val2, uint32_t asi)
-{
-    target_ulong ret;
-
-    ret = helper_ld_asi(addr, asi, 8, 0);
-    if (val2 == ret) {
-        helper_st_asi(addr, val1, asi, 8);
-    }
-    return ret;
-}
-#endif /* TARGET_SPARC64 */
-
-void helper_stdf(target_ulong addr, int mem_idx)
-{
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        stfq_user(addr, DT0);
-        break;
-    case MMU_KERNEL_IDX:
-        stfq_kernel(addr, DT0);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        stfq_hypv(addr, DT0);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    stfq_raw(address_mask(env, addr), DT0);
-#endif
-}
-
-void helper_lddf(target_ulong addr, int mem_idx)
-{
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        DT0 = ldfq_user(addr);
-        break;
-    case MMU_KERNEL_IDX:
-        DT0 = ldfq_kernel(addr);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        DT0 = ldfq_hypv(addr);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    DT0 = ldfq_raw(address_mask(env, addr));
-#endif
-}
-
-void helper_ldqf(target_ulong addr, int mem_idx)
-{
-    /* XXX add 128 bit load */
-    CPU_QuadU u;
-
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        u.ll.upper = ldq_user(addr);
-        u.ll.lower = ldq_user(addr + 8);
-        QT0 = u.q;
-        break;
-    case MMU_KERNEL_IDX:
-        u.ll.upper = ldq_kernel(addr);
-        u.ll.lower = ldq_kernel(addr + 8);
-        QT0 = u.q;
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        u.ll.upper = ldq_hypv(addr);
-        u.ll.lower = ldq_hypv(addr + 8);
-        QT0 = u.q;
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    u.ll.upper = ldq_raw(address_mask(env, addr));
-    u.ll.lower = ldq_raw(address_mask(env, addr + 8));
-    QT0 = u.q;
-#endif
-}
-
-void helper_stqf(target_ulong addr, int mem_idx)
-{
-    /* XXX add 128 bit store */
-    CPU_QuadU u;
-
-    helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
-    switch (mem_idx) {
-    case MMU_USER_IDX:
-        u.q = QT0;
-        stq_user(addr, u.ll.upper);
-        stq_user(addr + 8, u.ll.lower);
-        break;
-    case MMU_KERNEL_IDX:
-        u.q = QT0;
-        stq_kernel(addr, u.ll.upper);
-        stq_kernel(addr + 8, u.ll.lower);
-        break;
-#ifdef TARGET_SPARC64
-    case MMU_HYPV_IDX:
-        u.q = QT0;
-        stq_hypv(addr, u.ll.upper);
-        stq_hypv(addr + 8, u.ll.lower);
-        break;
-#endif
-    default:
-        DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
-        break;
-    }
-#else
-    u.q = QT0;
-    stq_raw(address_mask(env, addr), u.ll.upper);
-    stq_raw(address_mask(env, addr + 8), u.ll.lower);
-#endif
-}
-
-#if !defined(CONFIG_USER_ONLY)
-
 static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
                                 void *retaddr);
 
@@ -2388,103 +72,3 @@ void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
 }
 
 #endif /* !CONFIG_USER_ONLY */
-
-#ifndef TARGET_SPARC64
-#if !defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size)
-{
-    int fault_type;
-
-#ifdef DEBUG_UNASSIGNED
-    if (is_asi) {
-        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
-               " asi 0x%02x from " TARGET_FMT_lx "\n",
-               is_exec ? "exec" : is_write ? "write" : "read", size,
-               size == 1 ? "" : "s", addr, is_asi, env->pc);
-    } else {
-        printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
-               " from " TARGET_FMT_lx "\n",
-               is_exec ? "exec" : is_write ? "write" : "read", size,
-               size == 1 ? "" : "s", addr, env->pc);
-    }
-#endif
-    /* Don't overwrite translation and access faults */
-    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
-    if ((fault_type > 4) || (fault_type == 0)) {
-        env->mmuregs[3] = 0; /* Fault status register */
-        if (is_asi) {
-            env->mmuregs[3] |= 1 << 16;
-        }
-        if (env->psrs) {
-            env->mmuregs[3] |= 1 << 5;
-        }
-        if (is_exec) {
-            env->mmuregs[3] |= 1 << 6;
-        }
-        if (is_write) {
-            env->mmuregs[3] |= 1 << 7;
-        }
-        env->mmuregs[3] |= (5 << 2) | 2;
-        /* SuperSPARC will never place instruction fault addresses in the FAR */
-        if (!is_exec) {
-            env->mmuregs[4] = addr; /* Fault address register */
-        }
-    }
-    /* overflow (same type fault was not read before another fault) */
-    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
-        env->mmuregs[3] |= 1;
-    }
-
-    if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
-        if (is_exec) {
-            helper_raise_exception(env, TT_CODE_ACCESS);
-        } else {
-            helper_raise_exception(env, TT_DATA_ACCESS);
-        }
-    }
-
-    /* flush neverland mappings created during no-fault mode,
-       so the sequential MMU faults report proper fault types */
-    if (env->mmuregs[0] & MMU_NF) {
-        tlb_flush(env, 1);
-    }
-}
-#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                                 int is_asi, int size)
-#else
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size)
-#endif
-{
-#ifdef DEBUG_UNASSIGNED
-    printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
-           "\n", addr, env->pc);
-#endif
-
-    if (is_exec) {
-        helper_raise_exception(env, TT_CODE_ACCESS);
-    } else {
-        helper_raise_exception(env, TT_DATA_ACCESS);
-    }
-}
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
-                           int is_write, int is_exec, int is_asi, int size)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    /* Ignore unassigned accesses outside of CPU context */
-    if (env1) {
-        do_unassigned_access(addr, is_write, is_exec, is_asi, size);
-    }
-    env = saved_env;
-}
-#endif
commit 870be6ad57d38dd630c5d5ac7e01fc5d8b784485
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 11 15:53:35 2011 +0000

    Sparc: convert win_helper to trace framework
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/win_helper.c b/target-sparc/win_helper.c
index f42d996..a68c649 100644
--- a/target-sparc/win_helper.c
+++ b/target-sparc/win_helper.c
@@ -19,15 +19,7 @@
 
 #include "cpu.h"
 #include "helper.h"
-
-//#define DEBUG_PSTATE
-
-#ifdef DEBUG_PSTATE
-#define DPRINTF_PSTATE(fmt, ...)                                \
-    do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
-#endif
+#include "trace.h"
 
 static inline void memcpy32(target_ulong *dst, const target_ulong *src)
 {
@@ -293,11 +285,7 @@ static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate)
 {
     switch (pstate) {
     default:
-        DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
-                       pstate,
-                       (pstate & PS_IG) ? " IG" : "",
-                       (pstate & PS_MG) ? " MG" : "",
-                       (pstate & PS_AG) ? " AG" : "");
+        trace_win_helper_gregset_error(pstate);
         /* pass through to normal set of global registers */
     case 0:
         return env->bgregs;
@@ -324,16 +312,15 @@ void cpu_change_pstate(CPUState *env, uint32_t new_pstate)
     new_pstate_regs = new_pstate & 0xc01;
 
     if (new_pstate_regs != pstate_regs) {
-        DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
-                       pstate_regs, new_pstate_regs);
+        trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs);
+
         /* Switch global register bank */
         src = get_gregset(env, new_pstate_regs);
         dst = get_gregset(env, pstate_regs);
         memcpy32(dst, env->gregs);
         memcpy32(env->gregs, src);
     } else {
-        DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
-                       new_pstate_regs);
+        trace_win_helper_no_switch_pstate(new_pstate_regs);
     }
     env->pstate = new_pstate;
 }
@@ -352,8 +339,7 @@ void helper_wrpstate(CPUState *env, target_ulong new_state)
 void helper_wrpil(CPUState *env, target_ulong new_pil)
 {
 #if !defined(CONFIG_USER_ONLY)
-    DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
-                   env->psrpil, (uint32_t)new_pil);
+    trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
 
     env->psrpil = new_pil;
 
@@ -375,7 +361,7 @@ void helper_done(CPUState *env)
     cpu_put_cwp64(env, tsptr->tstate & 0xff);
     env->tl--;
 
-    DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
+    trace_win_helper_done(env->tl);
 
 #if !defined(CONFIG_USER_ONLY)
     if (cpu_interrupts_enabled(env)) {
@@ -396,7 +382,7 @@ void helper_retry(CPUState *env)
     cpu_put_cwp64(env, tsptr->tstate & 0xff);
     env->tl--;
 
-    DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
+    trace_win_helper_retry(env->tl);
 
 #if !defined(CONFIG_USER_ONLY)
     if (cpu_interrupts_enabled(env)) {
diff --git a/trace-events b/trace-events
index 0cc1f66..820b1d6 100644
--- a/trace-events
+++ b/trace-events
@@ -616,3 +616,11 @@ int_helper_clear_softint(uint32_t softint) "new %08x"
 int_helper_write_softint(uint32_t softint) "new %08x"
 int_helper_icache_freeze(void) "Instruction cache: freeze"
 int_helper_dcache_freeze(void) "Data cache: freeze"
+
+# target-sparc/win_helper.c
+win_helper_gregset_error(uint32_t pstate) "ERROR in get_gregset: active pstate bits=%x"
+win_helper_switch_pstate(uint32_t pstate_regs, uint32_t new_pstate_regs) "change_pstate: switching regs old=%x new=%x"
+win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=%x (unchanged)"
+win_helper_wrpil(uint32_t psrpil, uint32_t new_pil) "old=%x new=%x"
+win_helper_done(uint32_t tl) "tl=%d"
+win_helper_retry(uint32_t tl) "tl=%d"
commit 11e66bca8ab0985e988e7c2fd019b743d79b4732
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 11 15:05:41 2011 +0000

    Sparc: convert interrupt helpers to trace framework
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
index 1c6ba6d..3a749bf 100644
--- a/target-sparc/int32_helper.c
+++ b/target-sparc/int32_helper.c
@@ -18,16 +18,9 @@
  */
 
 #include "cpu.h"
+#include "trace.h"
 
 //#define DEBUG_PCALL
-//#define DEBUG_CACHE_CONTROL
-
-#ifdef DEBUG_CACHE_CONTROL
-#define DPRINTF_CACHE_CONTROL(fmt, ...)                                 \
-    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
-#endif
 
 #ifdef DEBUG_PCALL
 static const char * const excp_names[0x80] = {
@@ -142,7 +135,7 @@ static void leon3_cache_control_int(CPUState *env)
         state = env->cache_control & CACHE_STATE_MASK;
         if (state == CACHE_ENABLED) {
             state = CACHE_FROZEN;
-            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
+            trace_int_helper_icache_freeze();
         }
 
         env->cache_control &= ~CACHE_STATE_MASK;
@@ -154,7 +147,7 @@ static void leon3_cache_control_int(CPUState *env)
         state = (env->cache_control >> 2) & CACHE_STATE_MASK;
         if (state == CACHE_ENABLED) {
             state = CACHE_FROZEN;
-            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
+            trace_int_helper_dcache_freeze();
         }
 
         env->cache_control &= ~(CACHE_STATE_MASK << 2);
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
index c9c5e0e..1d471db 100644
--- a/target-sparc/int64_helper.c
+++ b/target-sparc/int64_helper.c
@@ -19,16 +19,9 @@
 
 #include "cpu.h"
 #include "helper.h"
+#include "trace.h"
 
 //#define DEBUG_PCALL
-//#define DEBUG_PSTATE
-
-#ifdef DEBUG_PSTATE
-#define DPRINTF_PSTATE(fmt, ...)                                \
-    do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
-#endif
 
 #ifdef DEBUG_PCALL
 static const char * const excp_names[0x80] = {
@@ -172,33 +165,37 @@ trap_state *cpu_tsptr(CPUState* env)
     return &env->ts[env->tl & MAXTL_MASK];
 }
 
-static void do_modify_softint(CPUState *env, const char *operation,
-                              uint32_t value)
+static bool do_modify_softint(CPUState *env, uint32_t value)
 {
     if (env->softint != value) {
         env->softint = value;
-        DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
 #if !defined(CONFIG_USER_ONLY)
         if (cpu_interrupts_enabled(env)) {
             cpu_check_irqs(env);
         }
 #endif
+        return true;
     }
+    return false;
 }
 
 void helper_set_softint(CPUState *env, uint64_t value)
 {
-    do_modify_softint(env, "helper_set_softint",
-                      env->softint | (uint32_t)value);
+    if (do_modify_softint(env, env->softint | (uint32_t)value)) {
+        trace_int_helper_set_softint(env->softint);
+    }
 }
 
 void helper_clear_softint(CPUState *env, uint64_t value)
 {
-    do_modify_softint(env, "helper_clear_softint",
-                      env->softint & (uint32_t)~value);
+    if (do_modify_softint(env, env->softint & (uint32_t)~value)) {
+        trace_int_helper_clear_softint(env->softint);
+    }
 }
 
 void helper_write_softint(CPUState *env, uint64_t value)
 {
-    do_modify_softint(env, "helper_write_softint", (uint32_t)value);
+    if (do_modify_softint(env, (uint32_t)value)) {
+        trace_int_helper_write_softint(env->softint);
+    }
 }
diff --git a/trace-events b/trace-events
index 7b5aa91..0cc1f66 100644
--- a/trace-events
+++ b/trace-events
@@ -609,3 +609,10 @@ mmu_helper_tmiss(uint64_t address, uint64_t context) "TMISS at %"PRIx64" context
 mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
 mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
 mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at %"PRIx64" -> %"PRIx64", mmu_idx=%d tl=%d primary context=%"PRIx64" secondary context=%"PRIx64""
+
+# target-sparc/int_helper.c
+int_helper_set_softint(uint32_t softint) "new %08x"
+int_helper_clear_softint(uint32_t softint) "new %08x"
+int_helper_write_softint(uint32_t softint) "new %08x"
+int_helper_icache_freeze(void) "Instruction cache: freeze"
+int_helper_dcache_freeze(void) "Data cache: freeze"
commit ec0ceb1759317a8c0e4b4fd63087aca8ecb6cf96
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 11 14:51:24 2011 +0000

    Sparc: convert mmu_helper to trace framework
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
index 5743081..8cdc224 100644
--- a/target-sparc/mmu_helper.c
+++ b/target-sparc/mmu_helper.c
@@ -18,15 +18,7 @@
  */
 
 #include "cpu.h"
-
-//#define DEBUG_MMU
-
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...)                                   \
-    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
-#endif
+#include "trace.h"
 
 /* Sparc MMU emulation */
 
@@ -538,10 +530,7 @@ static int get_physical_address_data(CPUState *env,
             if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
                 do_fault = 1;
                 sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
-
-                DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
-                            " mmu_idx=%d tl=%d\n",
-                            address, context, mmu_idx, env->tl);
+                trace_mmu_helper_dfault(address, context, mmu_idx, env->tl);
             }
             if (rw == 4) {
                 if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
@@ -562,9 +551,7 @@ static int get_physical_address_data(CPUState *env,
                 do_fault = 1;
                 env->exception_index = TT_DPROT;
 
-                DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
-                            " mmu_idx=%d tl=%d\n",
-                            address, context, mmu_idx, env->tl);
+                trace_mmu_helper_dprot(address, context, mmu_idx, env->tl);
             }
 
             if (!do_fault) {
@@ -598,8 +585,7 @@ static int get_physical_address_data(CPUState *env,
         }
     }
 
-    DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
-                address, context);
+    trace_mmu_helper_dmiss(address, context);
 
     /*
      * On MMU misses:
@@ -662,8 +648,7 @@ static int get_physical_address_code(CPUState *env,
 
                 env->immu.tag_access = (address & ~0x1fffULL) | context;
 
-                DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
-                            address, context);
+                trace_mmu_helper_tfault(address, context);
 
                 return 1;
             }
@@ -673,8 +658,7 @@ static int get_physical_address_code(CPUState *env,
         }
     }
 
-    DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
-                address, context);
+    trace_mmu_helper_tmiss(address, context);
 
     /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
     env->immu.tag_access = (address & ~0x1fffULL) | context;
@@ -691,21 +675,20 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
        everything when an entry is evicted.  */
     *page_size = TARGET_PAGE_SIZE;
 
-#if defined(DEBUG_MMU)
     /* safety net to catch wrong softmmu index use from dynamic code */
     if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
-        DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
-                    " primary context=%" PRIx64
-                    " secondary context=%" PRIx64
-                " address=%" PRIx64
-                "\n",
-                (rw == 2 ? "CODE" : "DATA"),
-                env->tl, mmu_idx,
-                env->dmmu.mmu_primary_context,
-                env->dmmu.mmu_secondary_context,
-                address);
+        if (rw == 2) {
+            trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx,
+                                                env->dmmu.mmu_primary_context,
+                                                env->dmmu.mmu_secondary_context,
+                                                address);
+        } else {
+            trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx,
+                                                env->dmmu.mmu_primary_context,
+                                                env->dmmu.mmu_secondary_context,
+                                                address);
+        }
     }
-#endif
 
     if (rw == 2) {
         return get_physical_address_code(env, physical, prot, address,
@@ -732,16 +715,9 @@ int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
         vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
                              (TARGET_PAGE_SIZE - 1));
 
-        DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
-                    " vaddr %" PRIx64
-                    " mmu_idx=%d"
-                    " tl=%d"
-                    " primary context=%" PRIx64
-                    " secondary context=%" PRIx64
-                    "\n",
-                    address, paddr, vaddr, mmu_idx, env->tl,
-                    env->dmmu.mmu_primary_context,
-                    env->dmmu.mmu_secondary_context);
+        trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
+                                   env->dmmu.mmu_primary_context,
+                                   env->dmmu.mmu_secondary_context);
 
         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
         return 0;
diff --git a/trace-events b/trace-events
index 49ac1c1..7b5aa91 100644
--- a/trace-events
+++ b/trace-events
@@ -599,3 +599,13 @@ v9fs_xattrwalk_return(uint16_t tag, uint8_t id, int64_t size) "tag %d id %d size
 v9fs_xattrcreate(uint16_t tag, uint8_t id, int32_t fid, char* name, int64_t size, int flags) "tag %d id %d fid %d name %s size %"PRId64" flags %d"
 v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
 v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s"
+
+# target-sparc/mmu_helper.c
+mmu_helper_dfault(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DFAULT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d"
+mmu_helper_dprot(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DPROT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d"
+mmu_helper_dmiss(uint64_t address, uint64_t context) "DMISS at %"PRIx64" context %"PRIx64""
+mmu_helper_tfault(uint64_t address, uint64_t context) "TFAULT at %"PRIx64" context %"PRIx64""
+mmu_helper_tmiss(uint64_t address, uint64_t context) "TMISS at %"PRIx64" context %"PRIx64""
+mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
+mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64""
+mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at %"PRIx64" -> %"PRIx64", mmu_idx=%d tl=%d primary context=%"PRIx64" secondary context=%"PRIx64""
commit 163fa5ca51e7167330e6135c09eca6120c022b7f
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 11 11:30:01 2011 +0000

    Sparc: split MMU helpers
    
    Move MMU helpers to mmu_helper.c.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index cc4dc1c..8e25a88 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -78,7 +78,7 @@ libobj-$(TARGET_SPARC64) += vis_helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
 libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 ifeq ($(TARGET_BASE_ARCH), sparc)
-libobj-y += fop_helper.o cc_helper.o win_helper.o cpu_init.o
+libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o cpu_init.o
 endif
 libobj-$(TARGET_SPARC) += int32_helper.o
 libobj-$(TARGET_SPARC64) += int64_helper.o
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index ce1e668..25b4f1a 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -510,7 +510,7 @@ typedef struct CPUSPARCState {
 CPUSPARCState *cpu_sparc_init(const char *cpu_model);
 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
 void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
-/* helper.c */
+/* mmu_helper.c */
 int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
                                int mmu_idx);
 #define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 1b21782..18609c4 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -1,5 +1,5 @@
 /*
- *  sparc helpers
+ *  Misc Sparc helpers
  *
  *  Copyright (c) 2003-2005 Fabrice Bellard
  *
@@ -22,864 +22,6 @@
 #include "helper.h"
 #include "sysemu.h"
 
-//#define DEBUG_MMU
-
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...)                                   \
-    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
-#endif
-
-/* Sparc MMU emulation */
-
-#if defined(CONFIG_USER_ONLY)
-
-int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
-                               int mmu_idx)
-{
-    if (rw & 2) {
-        env1->exception_index = TT_TFAULT;
-    } else {
-        env1->exception_index = TT_DFAULT;
-    }
-    return 1;
-}
-
-#else
-
-#ifndef TARGET_SPARC64
-/*
- * Sparc V8 Reference MMU (SRMMU)
- */
-static const int access_table[8][8] = {
-    { 0, 0, 0, 0, 8, 0, 12, 12 },
-    { 0, 0, 0, 0, 8, 0, 0, 0 },
-    { 8, 8, 0, 0, 0, 8, 12, 12 },
-    { 8, 8, 0, 0, 0, 8, 0, 0 },
-    { 8, 0, 8, 0, 8, 8, 12, 12 },
-    { 8, 0, 8, 0, 8, 0, 8, 0 },
-    { 8, 8, 8, 0, 8, 8, 12, 12 },
-    { 8, 8, 8, 0, 8, 8, 8, 0 }
-};
-
-static const int perm_table[2][8] = {
-    {
-        PAGE_READ,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
-        PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC
-    },
-    {
-        PAGE_READ,
-        PAGE_READ | PAGE_WRITE,
-        PAGE_READ | PAGE_EXEC,
-        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
-        PAGE_EXEC,
-        PAGE_READ,
-        0,
-        0,
-    }
-};
-
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
-                                int *prot, int *access_index,
-                                target_ulong address, int rw, int mmu_idx,
-                                target_ulong *page_size)
-{
-    int access_perms = 0;
-    target_phys_addr_t pde_ptr;
-    uint32_t pde;
-    int error_code = 0, is_dirty, is_user;
-    unsigned long page_offset;
-
-    is_user = mmu_idx == MMU_USER_IDX;
-
-    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
-        *page_size = TARGET_PAGE_SIZE;
-        /* Boot mode: instruction fetches are taken from PROM */
-        if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
-            *physical = env->prom_addr | (address & 0x7ffffULL);
-            *prot = PAGE_READ | PAGE_EXEC;
-            return 0;
-        }
-        *physical = address;
-        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        return 0;
-    }
-
-    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
-    *physical = 0xffffffffffff0000ULL;
-
-    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
-    /* Context base + context number */
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-
-    /* Ctx pde */
-    switch (pde & PTE_ENTRYTYPE_MASK) {
-    default:
-    case 0: /* Invalid */
-        return 1 << 2;
-    case 2: /* L0 PTE, maybe should not happen? */
-    case 3: /* Reserved */
-        return 4 << 2;
-    case 1: /* L0 PDE */
-        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
-        pde = ldl_phys(pde_ptr);
-
-        switch (pde & PTE_ENTRYTYPE_MASK) {
-        default:
-        case 0: /* Invalid */
-            return (1 << 8) | (1 << 2);
-        case 3: /* Reserved */
-            return (1 << 8) | (4 << 2);
-        case 1: /* L1 PDE */
-            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
-            pde = ldl_phys(pde_ptr);
-
-            switch (pde & PTE_ENTRYTYPE_MASK) {
-            default:
-            case 0: /* Invalid */
-                return (2 << 8) | (1 << 2);
-            case 3: /* Reserved */
-                return (2 << 8) | (4 << 2);
-            case 1: /* L2 PDE */
-                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
-                pde = ldl_phys(pde_ptr);
-
-                switch (pde & PTE_ENTRYTYPE_MASK) {
-                default:
-                case 0: /* Invalid */
-                    return (3 << 8) | (1 << 2);
-                case 1: /* PDE, should not happen */
-                case 3: /* Reserved */
-                    return (3 << 8) | (4 << 2);
-                case 2: /* L3 PTE */
-                    page_offset = (address & TARGET_PAGE_MASK) &
-                        (TARGET_PAGE_SIZE - 1);
-                }
-                *page_size = TARGET_PAGE_SIZE;
-                break;
-            case 2: /* L2 PTE */
-                page_offset = address & 0x3ffff;
-                *page_size = 0x40000;
-            }
-            break;
-        case 2: /* L1 PTE */
-            page_offset = address & 0xffffff;
-            *page_size = 0x1000000;
-        }
-    }
-
-    /* check access */
-    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
-    error_code = access_table[*access_index][access_perms];
-    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
-        return error_code;
-    }
-
-    /* update page modified and dirty bits */
-    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
-    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
-        pde |= PG_ACCESSED_MASK;
-        if (is_dirty) {
-            pde |= PG_MODIFIED_MASK;
-        }
-        stl_phys_notdirty(pde_ptr, pde);
-    }
-
-    /* the page can be put in the TLB */
-    *prot = perm_table[is_user][access_perms];
-    if (!(pde & PG_MODIFIED_MASK)) {
-        /* only set write access if already dirty... otherwise wait
-           for dirty access */
-        *prot &= ~PAGE_WRITE;
-    }
-
-    /* Even if large ptes, we map only one 4KB page in the cache to
-       avoid filling it too fast */
-    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
-    return error_code;
-}
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                               int mmu_idx)
-{
-    target_phys_addr_t paddr;
-    target_ulong vaddr;
-    target_ulong page_size;
-    int error_code = 0, prot, access_index;
-
-    error_code = get_physical_address(env, &paddr, &prot, &access_index,
-                                      address, rw, mmu_idx, &page_size);
-    if (error_code == 0) {
-        vaddr = address & TARGET_PAGE_MASK;
-        paddr &= TARGET_PAGE_MASK;
-#ifdef DEBUG_MMU
-        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
-               TARGET_FMT_lx "\n", address, paddr, vaddr);
-#endif
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
-        return 0;
-    }
-
-    if (env->mmuregs[3]) { /* Fault status register */
-        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
-    }
-    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
-    env->mmuregs[4] = address; /* Fault address register */
-
-    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
-        /* No fault mode: if a mapping is available, just override
-           permissions. If no mapping is available, redirect accesses to
-           neverland. Fake/overridden mappings will be flushed when
-           switching to normal mode. */
-        vaddr = address & TARGET_PAGE_MASK;
-        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
-        return 0;
-    } else {
-        if (rw & 2) {
-            env->exception_index = TT_TFAULT;
-        } else {
-            env->exception_index = TT_DFAULT;
-        }
-        return 1;
-    }
-}
-
-target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
-{
-    target_phys_addr_t pde_ptr;
-    uint32_t pde;
-
-    /* Context base + context number */
-    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
-        (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-
-    switch (pde & PTE_ENTRYTYPE_MASK) {
-    default:
-    case 0: /* Invalid */
-    case 2: /* PTE, maybe should not happen? */
-    case 3: /* Reserved */
-        return 0;
-    case 1: /* L1 PDE */
-        if (mmulev == 3) {
-            return pde;
-        }
-        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
-        pde = ldl_phys(pde_ptr);
-
-        switch (pde & PTE_ENTRYTYPE_MASK) {
-        default:
-        case 0: /* Invalid */
-        case 3: /* Reserved */
-            return 0;
-        case 2: /* L1 PTE */
-            return pde;
-        case 1: /* L2 PDE */
-            if (mmulev == 2) {
-                return pde;
-            }
-            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
-            pde = ldl_phys(pde_ptr);
-
-            switch (pde & PTE_ENTRYTYPE_MASK) {
-            default:
-            case 0: /* Invalid */
-            case 3: /* Reserved */
-                return 0;
-            case 2: /* L2 PTE */
-                return pde;
-            case 1: /* L3 PDE */
-                if (mmulev == 1) {
-                    return pde;
-                }
-                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
-                pde = ldl_phys(pde_ptr);
-
-                switch (pde & PTE_ENTRYTYPE_MASK) {
-                default:
-                case 0: /* Invalid */
-                case 1: /* PDE, should not happen */
-                case 3: /* Reserved */
-                    return 0;
-                case 2: /* L3 PTE */
-                    return pde;
-                }
-            }
-        }
-    }
-    return 0;
-}
-
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
-{
-    target_ulong va, va1, va2;
-    unsigned int n, m, o;
-    target_phys_addr_t pde_ptr, pa;
-    uint32_t pde;
-
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-    (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
-                   (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
-    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
-        pde = mmu_probe(env, va, 2);
-        if (pde) {
-            pa = cpu_get_phys_page_debug(env, va);
-            (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
-                           " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
-            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
-                pde = mmu_probe(env, va1, 1);
-                if (pde) {
-                    pa = cpu_get_phys_page_debug(env, va1);
-                    (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
-                                   TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
-                                   va1, pa, pde);
-                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
-                        pde = mmu_probe(env, va2, 0);
-                        if (pde) {
-                            pa = cpu_get_phys_page_debug(env, va2);
-                            (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
-                                           TARGET_FMT_plx " PTE: "
-                                           TARGET_FMT_lx "\n",
-                                           va2, pa, pde);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-/* Gdb expects all registers windows to be flushed in ram. This function handles
- * reads (and only reads) in stack frames as if windows were flushed. We assume
- * that the sparc ABI is followed.
- */
-int target_memory_rw_debug(CPUState *env, target_ulong addr,
-                           uint8_t *buf, int len, int is_write)
-{
-    int i;
-    int len1;
-    int cwp = env->cwp;
-
-    if (!is_write) {
-        for (i = 0; i < env->nwindows; i++) {
-            int off;
-            target_ulong fp = env->regbase[cwp * 16 + 22];
-
-            /* Assume fp == 0 means end of frame.  */
-            if (fp == 0) {
-                break;
-            }
-
-            cwp = cpu_cwp_inc(env, cwp + 1);
-
-            /* Invalid window ? */
-            if (env->wim & (1 << cwp)) {
-                break;
-            }
-
-            /* According to the ABI, the stack is growing downward.  */
-            if (addr + len < fp) {
-                break;
-            }
-
-            /* Not in this frame.  */
-            if (addr > fp + 64) {
-                continue;
-            }
-
-            /* Handle access before this window.  */
-            if (addr < fp) {
-                len1 = fp - addr;
-                if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
-                    return -1;
-                }
-                addr += len1;
-                len -= len1;
-                buf += len1;
-            }
-
-            /* Access byte per byte to registers. Not very efficient but speed
-             * is not critical.
-             */
-            off = addr - fp;
-            len1 = 64 - off;
-
-            if (len1 > len) {
-                len1 = len;
-            }
-
-            for (; len1; len1--) {
-                int reg = cwp * 16 + 8 + (off >> 2);
-                union {
-                    uint32_t v;
-                    uint8_t c[4];
-                } u;
-                u.v = cpu_to_be32(env->regbase[reg]);
-                *buf++ = u.c[off & 3];
-                addr++;
-                len--;
-                off++;
-            }
-
-            if (len == 0) {
-                return 0;
-            }
-        }
-    }
-    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
-}
-
-#else /* !TARGET_SPARC64 */
-
-/* 41 bit physical address space */
-static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
-{
-    return x & 0x1ffffffffffULL;
-}
-
-/*
- * UltraSparc IIi I/DMMUs
- */
-
-/* Returns true if TTE tag is valid and matches virtual address value
-   in context requires virtual address mask value calculated from TTE
-   entry size */
-static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
-                                       uint64_t address, uint64_t context,
-                                       target_phys_addr_t *physical)
-{
-    uint64_t mask;
-
-    switch (TTE_PGSIZE(tlb->tte)) {
-    default:
-    case 0x0: /* 8k */
-        mask = 0xffffffffffffe000ULL;
-        break;
-    case 0x1: /* 64k */
-        mask = 0xffffffffffff0000ULL;
-        break;
-    case 0x2: /* 512k */
-        mask = 0xfffffffffff80000ULL;
-        break;
-    case 0x3: /* 4M */
-        mask = 0xffffffffffc00000ULL;
-        break;
-    }
-
-    /* valid, context match, virtual address match? */
-    if (TTE_IS_VALID(tlb->tte) &&
-        (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
-        && compare_masked(address, tlb->tag, mask)) {
-        /* decode physical address */
-        *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
-        return 1;
-    }
-
-    return 0;
-}
-
-static int get_physical_address_data(CPUState *env,
-                                     target_phys_addr_t *physical, int *prot,
-                                     target_ulong address, int rw, int mmu_idx)
-{
-    unsigned int i;
-    uint64_t context;
-    uint64_t sfsr = 0;
-
-    int is_user = (mmu_idx == MMU_USER_IDX ||
-                   mmu_idx == MMU_USER_SECONDARY_IDX);
-
-    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
-        *physical = ultrasparc_truncate_physical(address);
-        *prot = PAGE_READ | PAGE_WRITE;
-        return 0;
-    }
-
-    switch (mmu_idx) {
-    case MMU_USER_IDX:
-    case MMU_KERNEL_IDX:
-        context = env->dmmu.mmu_primary_context & 0x1fff;
-        sfsr |= SFSR_CT_PRIMARY;
-        break;
-    case MMU_USER_SECONDARY_IDX:
-    case MMU_KERNEL_SECONDARY_IDX:
-        context = env->dmmu.mmu_secondary_context & 0x1fff;
-        sfsr |= SFSR_CT_SECONDARY;
-        break;
-    case MMU_NUCLEUS_IDX:
-        sfsr |= SFSR_CT_NUCLEUS;
-        /* FALLTHRU */
-    default:
-        context = 0;
-        break;
-    }
-
-    if (rw == 1) {
-        sfsr |= SFSR_WRITE_BIT;
-    } else if (rw == 4) {
-        sfsr |= SFSR_NF_BIT;
-    }
-
-    for (i = 0; i < 64; i++) {
-        /* ctx match, vaddr match, valid? */
-        if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
-            int do_fault = 0;
-
-            /* access ok? */
-            /* multiple bits in SFSR.FT may be set on TT_DFAULT */
-            if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
-                do_fault = 1;
-                sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
-
-                DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
-                            " mmu_idx=%d tl=%d\n",
-                            address, context, mmu_idx, env->tl);
-            }
-            if (rw == 4) {
-                if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
-                    do_fault = 1;
-                    sfsr |= SFSR_FT_NF_E_BIT;
-                }
-            } else {
-                if (TTE_IS_NFO(env->dtlb[i].tte)) {
-                    do_fault = 1;
-                    sfsr |= SFSR_FT_NFO_BIT;
-                }
-            }
-
-            if (do_fault) {
-                /* faults above are reported with TT_DFAULT. */
-                env->exception_index = TT_DFAULT;
-            } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
-                do_fault = 1;
-                env->exception_index = TT_DPROT;
-
-                DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
-                            " mmu_idx=%d tl=%d\n",
-                            address, context, mmu_idx, env->tl);
-            }
-
-            if (!do_fault) {
-                *prot = PAGE_READ;
-                if (TTE_IS_W_OK(env->dtlb[i].tte)) {
-                    *prot |= PAGE_WRITE;
-                }
-
-                TTE_SET_USED(env->dtlb[i].tte);
-
-                return 0;
-            }
-
-            if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
-                sfsr |= SFSR_OW_BIT; /* overflow (not read before
-                                        another fault) */
-            }
-
-            if (env->pstate & PS_PRIV) {
-                sfsr |= SFSR_PR_BIT;
-            }
-
-            /* FIXME: ASI field in SFSR must be set */
-            env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
-
-            env->dmmu.sfar = address; /* Fault address register */
-
-            env->dmmu.tag_access = (address & ~0x1fffULL) | context;
-
-            return 1;
-        }
-    }
-
-    DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
-                address, context);
-
-    /*
-     * On MMU misses:
-     * - UltraSPARC IIi: SFSR and SFAR unmodified
-     * - JPS1: SFAR updated and some fields of SFSR updated
-     */
-    env->dmmu.tag_access = (address & ~0x1fffULL) | context;
-    env->exception_index = TT_DMISS;
-    return 1;
-}
-
-static int get_physical_address_code(CPUState *env,
-                                     target_phys_addr_t *physical, int *prot,
-                                     target_ulong address, int mmu_idx)
-{
-    unsigned int i;
-    uint64_t context;
-
-    int is_user = (mmu_idx == MMU_USER_IDX ||
-                   mmu_idx == MMU_USER_SECONDARY_IDX);
-
-    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
-        /* IMMU disabled */
-        *physical = ultrasparc_truncate_physical(address);
-        *prot = PAGE_EXEC;
-        return 0;
-    }
-
-    if (env->tl == 0) {
-        /* PRIMARY context */
-        context = env->dmmu.mmu_primary_context & 0x1fff;
-    } else {
-        /* NUCLEUS context */
-        context = 0;
-    }
-
-    for (i = 0; i < 64; i++) {
-        /* ctx match, vaddr match, valid? */
-        if (ultrasparc_tag_match(&env->itlb[i],
-                                 address, context, physical)) {
-            /* access ok? */
-            if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
-                /* Fault status register */
-                if (env->immu.sfsr & SFSR_VALID_BIT) {
-                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
-                                                     another fault) */
-                } else {
-                    env->immu.sfsr = 0;
-                }
-                if (env->pstate & PS_PRIV) {
-                    env->immu.sfsr |= SFSR_PR_BIT;
-                }
-                if (env->tl > 0) {
-                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
-                }
-
-                /* FIXME: ASI field in SFSR must be set */
-                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
-                env->exception_index = TT_TFAULT;
-
-                env->immu.tag_access = (address & ~0x1fffULL) | context;
-
-                DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
-                            address, context);
-
-                return 1;
-            }
-            *prot = PAGE_EXEC;
-            TTE_SET_USED(env->itlb[i].tte);
-            return 0;
-        }
-    }
-
-    DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
-                address, context);
-
-    /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
-    env->immu.tag_access = (address & ~0x1fffULL) | context;
-    env->exception_index = TT_TMISS;
-    return 1;
-}
-
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
-                                int *prot, int *access_index,
-                                target_ulong address, int rw, int mmu_idx,
-                                target_ulong *page_size)
-{
-    /* ??? We treat everything as a small page, then explicitly flush
-       everything when an entry is evicted.  */
-    *page_size = TARGET_PAGE_SIZE;
-
-#if defined(DEBUG_MMU)
-    /* safety net to catch wrong softmmu index use from dynamic code */
-    if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
-        DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
-                    " primary context=%" PRIx64
-                    " secondary context=%" PRIx64
-                " address=%" PRIx64
-                "\n",
-                (rw == 2 ? "CODE" : "DATA"),
-                env->tl, mmu_idx,
-                env->dmmu.mmu_primary_context,
-                env->dmmu.mmu_secondary_context,
-                address);
-    }
-#endif
-
-    if (rw == 2) {
-        return get_physical_address_code(env, physical, prot, address,
-                                         mmu_idx);
-    } else {
-        return get_physical_address_data(env, physical, prot, address, rw,
-                                         mmu_idx);
-    }
-}
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                               int mmu_idx)
-{
-    target_ulong virt_addr, vaddr;
-    target_phys_addr_t paddr;
-    target_ulong page_size;
-    int error_code = 0, prot, access_index;
-
-    error_code = get_physical_address(env, &paddr, &prot, &access_index,
-                                      address, rw, mmu_idx, &page_size);
-    if (error_code == 0) {
-        virt_addr = address & TARGET_PAGE_MASK;
-        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
-                             (TARGET_PAGE_SIZE - 1));
-
-        DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
-                    " vaddr %" PRIx64
-                    " mmu_idx=%d"
-                    " tl=%d"
-                    " primary context=%" PRIx64
-                    " secondary context=%" PRIx64
-                    "\n",
-                    address, paddr, vaddr, mmu_idx, env->tl,
-                    env->dmmu.mmu_primary_context,
-                    env->dmmu.mmu_secondary_context);
-
-        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
-        return 0;
-    }
-    /* XXX */
-    return 1;
-}
-
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
-{
-    unsigned int i;
-    const char *mask;
-
-    (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
-                   PRId64 "\n",
-                   env->dmmu.mmu_primary_context,
-                   env->dmmu.mmu_secondary_context);
-    if ((env->lsu & DMMU_E) == 0) {
-        (*cpu_fprintf)(f, "DMMU disabled\n");
-    } else {
-        (*cpu_fprintf)(f, "DMMU dump\n");
-        for (i = 0; i < 64; i++) {
-            switch (TTE_PGSIZE(env->dtlb[i].tte)) {
-            default:
-            case 0x0:
-                mask = "  8k";
-                break;
-            case 0x1:
-                mask = " 64k";
-                break;
-            case 0x2:
-                mask = "512k";
-                break;
-            case 0x3:
-                mask = "  4M";
-                break;
-            }
-            if (TTE_IS_VALID(env->dtlb[i].tte)) {
-                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
-                               ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
-                               i,
-                               env->dtlb[i].tag & (uint64_t)~0x1fffULL,
-                               TTE_PA(env->dtlb[i].tte),
-                               mask,
-                               TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
-                               TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
-                               TTE_IS_LOCKED(env->dtlb[i].tte) ?
-                               "locked" : "unlocked",
-                               env->dtlb[i].tag & (uint64_t)0x1fffULL,
-                               TTE_IS_GLOBAL(env->dtlb[i].tte) ?
-                               "global" : "local");
-            }
-        }
-    }
-    if ((env->lsu & IMMU_E) == 0) {
-        (*cpu_fprintf)(f, "IMMU disabled\n");
-    } else {
-        (*cpu_fprintf)(f, "IMMU dump\n");
-        for (i = 0; i < 64; i++) {
-            switch (TTE_PGSIZE(env->itlb[i].tte)) {
-            default:
-            case 0x0:
-                mask = "  8k";
-                break;
-            case 0x1:
-                mask = " 64k";
-                break;
-            case 0x2:
-                mask = "512k";
-                break;
-            case 0x3:
-                mask = "  4M";
-                break;
-            }
-            if (TTE_IS_VALID(env->itlb[i].tte)) {
-                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
-                               ", %s, %s, %s, ctx %" PRId64 " %s\n",
-                               i,
-                               env->itlb[i].tag & (uint64_t)~0x1fffULL,
-                               TTE_PA(env->itlb[i].tte),
-                               mask,
-                               TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
-                               TTE_IS_LOCKED(env->itlb[i].tte) ?
-                               "locked" : "unlocked",
-                               env->itlb[i].tag & (uint64_t)0x1fffULL,
-                               TTE_IS_GLOBAL(env->itlb[i].tte) ?
-                               "global" : "local");
-            }
-        }
-    }
-}
-
-#endif /* TARGET_SPARC64 */
-
-static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
-                                   target_ulong addr, int rw, int mmu_idx)
-{
-    target_ulong page_size;
-    int prot, access_index;
-
-    return get_physical_address(env, phys, &prot, &access_index, addr, rw,
-                                mmu_idx, &page_size);
-}
-
-#if defined(TARGET_SPARC64)
-target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
-                                           int mmu_idx)
-{
-    target_phys_addr_t phys_addr;
-
-    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
-        return -1;
-    }
-    return phys_addr;
-}
-#endif
-
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
-    target_phys_addr_t phys_addr;
-    int mmu_idx = cpu_mmu_index(env);
-
-    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
-        if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
-            return -1;
-        }
-    }
-    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
-        return -1;
-    }
-    return phys_addr;
-}
-#endif
-
-/* misc op helpers */
 void helper_raise_exception(CPUState *env, int tt)
 {
     env->exception_index = tt;
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
new file mode 100644
index 0000000..5743081
--- /dev/null
+++ b/target-sparc/mmu_helper.c
@@ -0,0 +1,877 @@
+/*
+ *  Sparc MMU helpers
+ *
+ *  Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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 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/>.
+ */
+
+#include "cpu.h"
+
+//#define DEBUG_MMU
+
+#ifdef DEBUG_MMU
+#define DPRINTF_MMU(fmt, ...)                                   \
+    do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MMU(fmt, ...) do {} while (0)
+#endif
+
+/* Sparc MMU emulation */
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    if (rw & 2) {
+        env1->exception_index = TT_TFAULT;
+    } else {
+        env1->exception_index = TT_DFAULT;
+    }
+    return 1;
+}
+
+#else
+
+#ifndef TARGET_SPARC64
+/*
+ * Sparc V8 Reference MMU (SRMMU)
+ */
+static const int access_table[8][8] = {
+    { 0, 0, 0, 0, 8, 0, 12, 12 },
+    { 0, 0, 0, 0, 8, 0, 0, 0 },
+    { 8, 8, 0, 0, 0, 8, 12, 12 },
+    { 8, 8, 0, 0, 0, 8, 0, 0 },
+    { 8, 0, 8, 0, 8, 8, 12, 12 },
+    { 8, 0, 8, 0, 8, 0, 8, 0 },
+    { 8, 8, 8, 0, 8, 8, 12, 12 },
+    { 8, 8, 8, 0, 8, 8, 8, 0 }
+};
+
+static const int perm_table[2][8] = {
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC
+    },
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ,
+        0,
+        0,
+    }
+};
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+                                int *prot, int *access_index,
+                                target_ulong address, int rw, int mmu_idx,
+                                target_ulong *page_size)
+{
+    int access_perms = 0;
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+    int error_code = 0, is_dirty, is_user;
+    unsigned long page_offset;
+
+    is_user = mmu_idx == MMU_USER_IDX;
+
+    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
+        *page_size = TARGET_PAGE_SIZE;
+        /* Boot mode: instruction fetches are taken from PROM */
+        if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
+            *physical = env->prom_addr | (address & 0x7ffffULL);
+            *prot = PAGE_READ | PAGE_EXEC;
+            return 0;
+        }
+        *physical = address;
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return 0;
+    }
+
+    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
+    *physical = 0xffffffffffff0000ULL;
+
+    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
+    /* Context base + context number */
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    /* Ctx pde */
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+        return 1 << 2;
+    case 2: /* L0 PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        return 4 << 2;
+    case 1: /* L0 PDE */
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde = ldl_phys(pde_ptr);
+
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+            return (1 << 8) | (1 << 2);
+        case 3: /* Reserved */
+            return (1 << 8) | (4 << 2);
+        case 1: /* L1 PDE */
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+            pde = ldl_phys(pde_ptr);
+
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+                return (2 << 8) | (1 << 2);
+            case 3: /* Reserved */
+                return (2 << 8) | (4 << 2);
+            case 1: /* L2 PDE */
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+                pde = ldl_phys(pde_ptr);
+
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                    return (3 << 8) | (1 << 2);
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return (3 << 8) | (4 << 2);
+                case 2: /* L3 PTE */
+                    page_offset = (address & TARGET_PAGE_MASK) &
+                        (TARGET_PAGE_SIZE - 1);
+                }
+                *page_size = TARGET_PAGE_SIZE;
+                break;
+            case 2: /* L2 PTE */
+                page_offset = address & 0x3ffff;
+                *page_size = 0x40000;
+            }
+            break;
+        case 2: /* L1 PTE */
+            page_offset = address & 0xffffff;
+            *page_size = 0x1000000;
+        }
+    }
+
+    /* check access */
+    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
+    error_code = access_table[*access_index][access_perms];
+    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
+        return error_code;
+    }
+
+    /* update page modified and dirty bits */
+    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
+    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+        pde |= PG_ACCESSED_MASK;
+        if (is_dirty) {
+            pde |= PG_MODIFIED_MASK;
+        }
+        stl_phys_notdirty(pde_ptr, pde);
+    }
+
+    /* the page can be put in the TLB */
+    *prot = perm_table[is_user][access_perms];
+    if (!(pde & PG_MODIFIED_MASK)) {
+        /* only set write access if already dirty... otherwise wait
+           for dirty access */
+        *prot &= ~PAGE_WRITE;
+    }
+
+    /* Even if large ptes, we map only one 4KB page in the cache to
+       avoid filling it too fast */
+    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
+    return error_code;
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    target_phys_addr_t paddr;
+    target_ulong vaddr;
+    target_ulong page_size;
+    int error_code = 0, prot, access_index;
+
+    error_code = get_physical_address(env, &paddr, &prot, &access_index,
+                                      address, rw, mmu_idx, &page_size);
+    if (error_code == 0) {
+        vaddr = address & TARGET_PAGE_MASK;
+        paddr &= TARGET_PAGE_MASK;
+#ifdef DEBUG_MMU
+        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
+               TARGET_FMT_lx "\n", address, paddr, vaddr);
+#endif
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        return 0;
+    }
+
+    if (env->mmuregs[3]) { /* Fault status register */
+        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+    }
+    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
+    env->mmuregs[4] = address; /* Fault address register */
+
+    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
+        /* No fault mode: if a mapping is available, just override
+           permissions. If no mapping is available, redirect accesses to
+           neverland. Fake/overridden mappings will be flushed when
+           switching to normal mode. */
+        vaddr = address & TARGET_PAGE_MASK;
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
+        return 0;
+    } else {
+        if (rw & 2) {
+            env->exception_index = TT_TFAULT;
+        } else {
+            env->exception_index = TT_DFAULT;
+        }
+        return 1;
+    }
+}
+
+target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
+{
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+
+    /* Context base + context number */
+    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
+        (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+    case 2: /* PTE, maybe should not happen? */
+    case 3: /* Reserved */
+        return 0;
+    case 1: /* L1 PDE */
+        if (mmulev == 3) {
+            return pde;
+        }
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde = ldl_phys(pde_ptr);
+
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+        case 3: /* Reserved */
+            return 0;
+        case 2: /* L1 PTE */
+            return pde;
+        case 1: /* L2 PDE */
+            if (mmulev == 2) {
+                return pde;
+            }
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+            pde = ldl_phys(pde_ptr);
+
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+            case 3: /* Reserved */
+                return 0;
+            case 2: /* L2 PTE */
+                return pde;
+            case 1: /* L3 PDE */
+                if (mmulev == 1) {
+                    return pde;
+                }
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+                pde = ldl_phys(pde_ptr);
+
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return 0;
+                case 2: /* L3 PTE */
+                    return pde;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    target_ulong va, va1, va2;
+    unsigned int n, m, o;
+    target_phys_addr_t pde_ptr, pa;
+    uint32_t pde;
+
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+    (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
+                   (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
+    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
+        pde = mmu_probe(env, va, 2);
+        if (pde) {
+            pa = cpu_get_phys_page_debug(env, va);
+            (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
+                           " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
+            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
+                pde = mmu_probe(env, va1, 1);
+                if (pde) {
+                    pa = cpu_get_phys_page_debug(env, va1);
+                    (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
+                                   TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
+                                   va1, pa, pde);
+                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
+                        pde = mmu_probe(env, va2, 0);
+                        if (pde) {
+                            pa = cpu_get_phys_page_debug(env, va2);
+                            (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
+                                           TARGET_FMT_plx " PTE: "
+                                           TARGET_FMT_lx "\n",
+                                           va2, pa, pde);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+/* Gdb expects all registers windows to be flushed in ram. This function handles
+ * reads (and only reads) in stack frames as if windows were flushed. We assume
+ * that the sparc ABI is followed.
+ */
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                           uint8_t *buf, int len, int is_write)
+{
+    int i;
+    int len1;
+    int cwp = env->cwp;
+
+    if (!is_write) {
+        for (i = 0; i < env->nwindows; i++) {
+            int off;
+            target_ulong fp = env->regbase[cwp * 16 + 22];
+
+            /* Assume fp == 0 means end of frame.  */
+            if (fp == 0) {
+                break;
+            }
+
+            cwp = cpu_cwp_inc(env, cwp + 1);
+
+            /* Invalid window ? */
+            if (env->wim & (1 << cwp)) {
+                break;
+            }
+
+            /* According to the ABI, the stack is growing downward.  */
+            if (addr + len < fp) {
+                break;
+            }
+
+            /* Not in this frame.  */
+            if (addr > fp + 64) {
+                continue;
+            }
+
+            /* Handle access before this window.  */
+            if (addr < fp) {
+                len1 = fp - addr;
+                if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
+                    return -1;
+                }
+                addr += len1;
+                len -= len1;
+                buf += len1;
+            }
+
+            /* Access byte per byte to registers. Not very efficient but speed
+             * is not critical.
+             */
+            off = addr - fp;
+            len1 = 64 - off;
+
+            if (len1 > len) {
+                len1 = len;
+            }
+
+            for (; len1; len1--) {
+                int reg = cwp * 16 + 8 + (off >> 2);
+                union {
+                    uint32_t v;
+                    uint8_t c[4];
+                } u;
+                u.v = cpu_to_be32(env->regbase[reg]);
+                *buf++ = u.c[off & 3];
+                addr++;
+                len--;
+                off++;
+            }
+
+            if (len == 0) {
+                return 0;
+            }
+        }
+    }
+    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+
+#else /* !TARGET_SPARC64 */
+
+/* 41 bit physical address space */
+static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
+{
+    return x & 0x1ffffffffffULL;
+}
+
+/*
+ * UltraSparc IIi I/DMMUs
+ */
+
+/* Returns true if TTE tag is valid and matches virtual address value
+   in context requires virtual address mask value calculated from TTE
+   entry size */
+static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
+                                       uint64_t address, uint64_t context,
+                                       target_phys_addr_t *physical)
+{
+    uint64_t mask;
+
+    switch (TTE_PGSIZE(tlb->tte)) {
+    default:
+    case 0x0: /* 8k */
+        mask = 0xffffffffffffe000ULL;
+        break;
+    case 0x1: /* 64k */
+        mask = 0xffffffffffff0000ULL;
+        break;
+    case 0x2: /* 512k */
+        mask = 0xfffffffffff80000ULL;
+        break;
+    case 0x3: /* 4M */
+        mask = 0xffffffffffc00000ULL;
+        break;
+    }
+
+    /* valid, context match, virtual address match? */
+    if (TTE_IS_VALID(tlb->tte) &&
+        (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
+        && compare_masked(address, tlb->tag, mask)) {
+        /* decode physical address */
+        *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
+        return 1;
+    }
+
+    return 0;
+}
+
+static int get_physical_address_data(CPUState *env,
+                                     target_phys_addr_t *physical, int *prot,
+                                     target_ulong address, int rw, int mmu_idx)
+{
+    unsigned int i;
+    uint64_t context;
+    uint64_t sfsr = 0;
+
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
+    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
+        *physical = ultrasparc_truncate_physical(address);
+        *prot = PAGE_READ | PAGE_WRITE;
+        return 0;
+    }
+
+    switch (mmu_idx) {
+    case MMU_USER_IDX:
+    case MMU_KERNEL_IDX:
+        context = env->dmmu.mmu_primary_context & 0x1fff;
+        sfsr |= SFSR_CT_PRIMARY;
+        break;
+    case MMU_USER_SECONDARY_IDX:
+    case MMU_KERNEL_SECONDARY_IDX:
+        context = env->dmmu.mmu_secondary_context & 0x1fff;
+        sfsr |= SFSR_CT_SECONDARY;
+        break;
+    case MMU_NUCLEUS_IDX:
+        sfsr |= SFSR_CT_NUCLEUS;
+        /* FALLTHRU */
+    default:
+        context = 0;
+        break;
+    }
+
+    if (rw == 1) {
+        sfsr |= SFSR_WRITE_BIT;
+    } else if (rw == 4) {
+        sfsr |= SFSR_NF_BIT;
+    }
+
+    for (i = 0; i < 64; i++) {
+        /* ctx match, vaddr match, valid? */
+        if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
+            int do_fault = 0;
+
+            /* access ok? */
+            /* multiple bits in SFSR.FT may be set on TT_DFAULT */
+            if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
+                do_fault = 1;
+                sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
+
+                DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
+                            " mmu_idx=%d tl=%d\n",
+                            address, context, mmu_idx, env->tl);
+            }
+            if (rw == 4) {
+                if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NF_E_BIT;
+                }
+            } else {
+                if (TTE_IS_NFO(env->dtlb[i].tte)) {
+                    do_fault = 1;
+                    sfsr |= SFSR_FT_NFO_BIT;
+                }
+            }
+
+            if (do_fault) {
+                /* faults above are reported with TT_DFAULT. */
+                env->exception_index = TT_DFAULT;
+            } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
+                do_fault = 1;
+                env->exception_index = TT_DPROT;
+
+                DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
+                            " mmu_idx=%d tl=%d\n",
+                            address, context, mmu_idx, env->tl);
+            }
+
+            if (!do_fault) {
+                *prot = PAGE_READ;
+                if (TTE_IS_W_OK(env->dtlb[i].tte)) {
+                    *prot |= PAGE_WRITE;
+                }
+
+                TTE_SET_USED(env->dtlb[i].tte);
+
+                return 0;
+            }
+
+            if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
+                sfsr |= SFSR_OW_BIT; /* overflow (not read before
+                                        another fault) */
+            }
+
+            if (env->pstate & PS_PRIV) {
+                sfsr |= SFSR_PR_BIT;
+            }
+
+            /* FIXME: ASI field in SFSR must be set */
+            env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
+
+            env->dmmu.sfar = address; /* Fault address register */
+
+            env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+
+            return 1;
+        }
+    }
+
+    DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
+                address, context);
+
+    /*
+     * On MMU misses:
+     * - UltraSPARC IIi: SFSR and SFAR unmodified
+     * - JPS1: SFAR updated and some fields of SFSR updated
+     */
+    env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+    env->exception_index = TT_DMISS;
+    return 1;
+}
+
+static int get_physical_address_code(CPUState *env,
+                                     target_phys_addr_t *physical, int *prot,
+                                     target_ulong address, int mmu_idx)
+{
+    unsigned int i;
+    uint64_t context;
+
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
+    if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
+        /* IMMU disabled */
+        *physical = ultrasparc_truncate_physical(address);
+        *prot = PAGE_EXEC;
+        return 0;
+    }
+
+    if (env->tl == 0) {
+        /* PRIMARY context */
+        context = env->dmmu.mmu_primary_context & 0x1fff;
+    } else {
+        /* NUCLEUS context */
+        context = 0;
+    }
+
+    for (i = 0; i < 64; i++) {
+        /* ctx match, vaddr match, valid? */
+        if (ultrasparc_tag_match(&env->itlb[i],
+                                 address, context, physical)) {
+            /* access ok? */
+            if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
+                /* Fault status register */
+                if (env->immu.sfsr & SFSR_VALID_BIT) {
+                    env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
+                                                     another fault) */
+                } else {
+                    env->immu.sfsr = 0;
+                }
+                if (env->pstate & PS_PRIV) {
+                    env->immu.sfsr |= SFSR_PR_BIT;
+                }
+                if (env->tl > 0) {
+                    env->immu.sfsr |= SFSR_CT_NUCLEUS;
+                }
+
+                /* FIXME: ASI field in SFSR must be set */
+                env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
+                env->exception_index = TT_TFAULT;
+
+                env->immu.tag_access = (address & ~0x1fffULL) | context;
+
+                DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
+                            address, context);
+
+                return 1;
+            }
+            *prot = PAGE_EXEC;
+            TTE_SET_USED(env->itlb[i].tte);
+            return 0;
+        }
+    }
+
+    DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
+                address, context);
+
+    /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
+    env->immu.tag_access = (address & ~0x1fffULL) | context;
+    env->exception_index = TT_TMISS;
+    return 1;
+}
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+                                int *prot, int *access_index,
+                                target_ulong address, int rw, int mmu_idx,
+                                target_ulong *page_size)
+{
+    /* ??? We treat everything as a small page, then explicitly flush
+       everything when an entry is evicted.  */
+    *page_size = TARGET_PAGE_SIZE;
+
+#if defined(DEBUG_MMU)
+    /* safety net to catch wrong softmmu index use from dynamic code */
+    if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
+        DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
+                    " primary context=%" PRIx64
+                    " secondary context=%" PRIx64
+                " address=%" PRIx64
+                "\n",
+                (rw == 2 ? "CODE" : "DATA"),
+                env->tl, mmu_idx,
+                env->dmmu.mmu_primary_context,
+                env->dmmu.mmu_secondary_context,
+                address);
+    }
+#endif
+
+    if (rw == 2) {
+        return get_physical_address_code(env, physical, prot, address,
+                                         mmu_idx);
+    } else {
+        return get_physical_address_data(env, physical, prot, address, rw,
+                                         mmu_idx);
+    }
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx)
+{
+    target_ulong virt_addr, vaddr;
+    target_phys_addr_t paddr;
+    target_ulong page_size;
+    int error_code = 0, prot, access_index;
+
+    error_code = get_physical_address(env, &paddr, &prot, &access_index,
+                                      address, rw, mmu_idx, &page_size);
+    if (error_code == 0) {
+        virt_addr = address & TARGET_PAGE_MASK;
+        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
+                             (TARGET_PAGE_SIZE - 1));
+
+        DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
+                    " vaddr %" PRIx64
+                    " mmu_idx=%d"
+                    " tl=%d"
+                    " primary context=%" PRIx64
+                    " secondary context=%" PRIx64
+                    "\n",
+                    address, paddr, vaddr, mmu_idx, env->tl,
+                    env->dmmu.mmu_primary_context,
+                    env->dmmu.mmu_secondary_context);
+
+        tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+        return 0;
+    }
+    /* XXX */
+    return 1;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    unsigned int i;
+    const char *mask;
+
+    (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
+                   PRId64 "\n",
+                   env->dmmu.mmu_primary_context,
+                   env->dmmu.mmu_secondary_context);
+    if ((env->lsu & DMMU_E) == 0) {
+        (*cpu_fprintf)(f, "DMMU disabled\n");
+    } else {
+        (*cpu_fprintf)(f, "DMMU dump\n");
+        for (i = 0; i < 64; i++) {
+            switch (TTE_PGSIZE(env->dtlb[i].tte)) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if (TTE_IS_VALID(env->dtlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+                               ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->dtlb[i].tag & (uint64_t)~0x1fffULL,
+                               TTE_PA(env->dtlb[i].tte),
+                               mask,
+                               TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
+                               TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
+                               TTE_IS_LOCKED(env->dtlb[i].tte) ?
+                               "locked" : "unlocked",
+                               env->dtlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->dtlb[i].tte) ?
+                               "global" : "local");
+            }
+        }
+    }
+    if ((env->lsu & IMMU_E) == 0) {
+        (*cpu_fprintf)(f, "IMMU disabled\n");
+    } else {
+        (*cpu_fprintf)(f, "IMMU dump\n");
+        for (i = 0; i < 64; i++) {
+            switch (TTE_PGSIZE(env->itlb[i].tte)) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if (TTE_IS_VALID(env->itlb[i].tte)) {
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+                               ", %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->itlb[i].tag & (uint64_t)~0x1fffULL,
+                               TTE_PA(env->itlb[i].tte),
+                               mask,
+                               TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
+                               TTE_IS_LOCKED(env->itlb[i].tte) ?
+                               "locked" : "unlocked",
+                               env->itlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->itlb[i].tte) ?
+                               "global" : "local");
+            }
+        }
+    }
+}
+
+#endif /* TARGET_SPARC64 */
+
+static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
+                                   target_ulong addr, int rw, int mmu_idx)
+{
+    target_ulong page_size;
+    int prot, access_index;
+
+    return get_physical_address(env, phys, &prot, &access_index, addr, rw,
+                                mmu_idx, &page_size);
+}
+
+#if defined(TARGET_SPARC64)
+target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
+                                           int mmu_idx)
+{
+    target_phys_addr_t phys_addr;
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
+        return -1;
+    }
+    return phys_addr;
+}
+#endif
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    target_phys_addr_t phys_addr;
+    int mmu_idx = cpu_mmu_index(env);
+
+    if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
+        if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
+            return -1;
+        }
+    }
+    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
+        return -1;
+    }
+    return phys_addr;
+}
+#endif
commit b7da25f003f2641f3be7f79efb4d9707e6ac1907
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 11 12:03:08 2011 +0000

    Sparc: fix coding style in helper.c
    
    Before the next patch, fix coding style of the areas affected.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 5f8cf31..1b21782 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -25,7 +25,7 @@
 //#define DEBUG_MMU
 
 #ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...) \
+#define DPRINTF_MMU(fmt, ...)                                   \
     do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
 #else
 #define DPRINTF_MMU(fmt, ...) do {} while (0)
@@ -38,10 +38,11 @@
 int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
                                int mmu_idx)
 {
-    if (rw & 2)
+    if (rw & 2) {
         env1->exception_index = TT_TFAULT;
-    else
+    } else {
         env1->exception_index = TT_DFAULT;
+    }
     return 1;
 }
 
@@ -100,7 +101,7 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
 
     if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
         *page_size = TARGET_PAGE_SIZE;
-        // Boot mode: instruction fetches are taken from PROM
+        /* Boot mode: instruction fetches are taken from PROM */
         if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
             *physical = env->prom_addr | (address & 0x7ffffULL);
             *prot = PAGE_READ | PAGE_EXEC;
@@ -111,7 +112,7 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
         return 0;
     }
 
-    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
+    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
     *physical = 0xffffffffffff0000ULL;
 
     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
@@ -178,15 +179,17 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
     /* check access */
     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
     error_code = access_table[*access_index][access_perms];
-    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
+    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
         return error_code;
+    }
 
     /* update page modified and dirty bits */
     is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
     if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
         pde |= PG_ACCESSED_MASK;
-        if (is_dirty)
+        if (is_dirty) {
             pde |= PG_MODIFIED_MASK;
+        }
         stl_phys_notdirty(pde_ptr, pde);
     }
 
@@ -205,8 +208,8 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
 }
 
 /* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx)
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx)
 {
     target_phys_addr_t paddr;
     target_ulong vaddr;
@@ -226,25 +229,27 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
         return 0;
     }
 
-    if (env->mmuregs[3]) /* Fault status register */
+    if (env->mmuregs[3]) { /* Fault status register */
         env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+    }
     env->mmuregs[3] |= (access_index << 5) | error_code | 2;
     env->mmuregs[4] = address; /* Fault address register */
 
     if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
-        // No fault mode: if a mapping is available, just override
-        // permissions. If no mapping is available, redirect accesses to
-        // neverland. Fake/overridden mappings will be flushed when
-        // switching to normal mode.
+        /* No fault mode: if a mapping is available, just override
+           permissions. If no mapping is available, redirect accesses to
+           neverland. Fake/overridden mappings will be flushed when
+           switching to normal mode. */
         vaddr = address & TARGET_PAGE_MASK;
         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
         return 0;
     } else {
-        if (rw & 2)
+        if (rw & 2) {
             env->exception_index = TT_TFAULT;
-        else
+        } else {
             env->exception_index = TT_DFAULT;
+        }
         return 1;
     }
 }
@@ -266,8 +271,9 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
     case 3: /* Reserved */
         return 0;
     case 1: /* L1 PDE */
-        if (mmulev == 3)
+        if (mmulev == 3) {
             return pde;
+        }
         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
         pde = ldl_phys(pde_ptr);
 
@@ -279,8 +285,9 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
         case 2: /* L1 PTE */
             return pde;
         case 1: /* L2 PDE */
-            if (mmulev == 2)
+            if (mmulev == 2) {
                 return pde;
+            }
             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
             pde = ldl_phys(pde_ptr);
 
@@ -292,8 +299,9 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
             case 2: /* L2 PTE */
                 return pde;
             case 1: /* L3 PDE */
-                if (mmulev == 1)
+                if (mmulev == 1) {
                     return pde;
+                }
                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
                 pde = ldl_phys(pde_ptr);
 
@@ -434,7 +442,7 @@ int target_memory_rw_debug(CPUState *env, target_ulong addr,
 
 #else /* !TARGET_SPARC64 */
 
-// 41 bit physical address space
+/* 41 bit physical address space */
 static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
 {
     return x & 0x1ffffffffffULL;
@@ -444,8 +452,9 @@ static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
  * UltraSparc IIi I/DMMUs
  */
 
-// Returns true if TTE tag is valid and matches virtual address value in context
-// requires virtual address mask value calculated from TTE entry size
+/* Returns true if TTE tag is valid and matches virtual address value
+   in context requires virtual address mask value calculated from TTE
+   entry size */
 static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
                                        uint64_t address, uint64_t context,
                                        target_phys_addr_t *physical)
@@ -454,26 +463,25 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
 
     switch (TTE_PGSIZE(tlb->tte)) {
     default:
-    case 0x0: // 8k
+    case 0x0: /* 8k */
         mask = 0xffffffffffffe000ULL;
         break;
-    case 0x1: // 64k
+    case 0x1: /* 64k */
         mask = 0xffffffffffff0000ULL;
         break;
-    case 0x2: // 512k
+    case 0x2: /* 512k */
         mask = 0xfffffffffff80000ULL;
         break;
-    case 0x3: // 4M
+    case 0x3: /* 4M */
         mask = 0xffffffffffc00000ULL;
         break;
     }
 
-    // valid, context match, virtual address match?
+    /* valid, context match, virtual address match? */
     if (TTE_IS_VALID(tlb->tte) &&
         (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
-        && compare_masked(address, tlb->tag, mask))
-    {
-        // decode physical address
+        && compare_masked(address, tlb->tag, mask)) {
+        /* decode physical address */
         *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
         return 1;
     }
@@ -498,7 +506,7 @@ static int get_physical_address_data(CPUState *env,
         return 0;
     }
 
-    switch(mmu_idx) {
+    switch (mmu_idx) {
     case MMU_USER_IDX:
     case MMU_KERNEL_IDX:
         context = env->dmmu.mmu_primary_context & 0x1fff;
@@ -524,11 +532,11 @@ static int get_physical_address_data(CPUState *env,
     }
 
     for (i = 0; i < 64; i++) {
-        // ctx match, vaddr match, valid?
+        /* ctx match, vaddr match, valid? */
         if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
             int do_fault = 0;
 
-            // access ok?
+            /* access ok? */
             /* multiple bits in SFSR.FT may be set on TT_DFAULT */
             if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
                 do_fault = 1;
@@ -632,10 +640,10 @@ static int get_physical_address_code(CPUState *env,
     }
 
     for (i = 0; i < 64; i++) {
-        // ctx match, vaddr match, valid?
+        /* ctx match, vaddr match, valid? */
         if (ultrasparc_tag_match(&env->itlb[i],
                                  address, context, physical)) {
-            // access ok?
+            /* access ok? */
             if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
                 /* Fault status register */
                 if (env->immu.sfsr & SFSR_VALID_BIT) {
@@ -686,7 +694,7 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
        everything when an entry is evicted.  */
     *page_size = TARGET_PAGE_SIZE;
 
-#if defined (DEBUG_MMU)
+#if defined(DEBUG_MMU)
     /* safety net to catch wrong softmmu index use from dynamic code */
     if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
         DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
@@ -702,17 +710,18 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
     }
 #endif
 
-    if (rw == 2)
+    if (rw == 2) {
         return get_physical_address_code(env, physical, prot, address,
                                          mmu_idx);
-    else
+    } else {
         return get_physical_address_data(env, physical, prot, address, rw,
                                          mmu_idx);
+    }
 }
 
 /* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx)
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx)
 {
     target_ulong virt_addr, vaddr;
     target_phys_addr_t paddr;
@@ -740,7 +749,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
         return 0;
     }
-    // XXX
+    /* XXX */
     return 1;
 }
 
@@ -785,7 +794,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
                                TTE_IS_LOCKED(env->dtlb[i].tte) ?
                                "locked" : "unlocked",
                                env->dtlb[i].tag & (uint64_t)0x1fffULL,
-                               TTE_IS_GLOBAL(env->dtlb[i].tte)?
+                               TTE_IS_GLOBAL(env->dtlb[i].tte) ?
                                "global" : "local");
             }
         }
@@ -821,7 +830,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
                                TTE_IS_LOCKED(env->itlb[i].tte) ?
                                "locked" : "unlocked",
                                env->itlb[i].tag & (uint64_t)0x1fffULL,
-                               TTE_IS_GLOBAL(env->itlb[i].tte)?
+                               TTE_IS_GLOBAL(env->itlb[i].tte) ?
                                "global" : "local");
             }
         }
commit 7a5e4488cd1d0e80500be4781010ac4873a9585b
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Jul 4 18:15:42 2011 +0000

    Sparc: avoid AREG0 for division op helpers
    
    Make [su]div{,cc} helpers take a parameter for CPUState instead
    of relying on global env. Move the functions to helper.c.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 7a25605..5f8cf31 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -919,3 +919,79 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
 #endif
 }
 #endif
+
+static target_ulong helper_udiv_common(CPUState *env, target_ulong a,
+                                       target_ulong b, int cc)
+{
+    int overflow = 0;
+    uint64_t x0;
+    uint32_t x1;
+
+    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+    x1 = (b & 0xffffffff);
+
+    if (x1 == 0) {
+        helper_raise_exception(env, TT_DIV_ZERO);
+    }
+
+    x0 = x0 / x1;
+    if (x0 > 0xffffffff) {
+        x0 = 0xffffffff;
+        overflow = 1;
+    }
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
+    }
+    return x0;
+}
+
+target_ulong helper_udiv(CPUState *env, target_ulong a, target_ulong b)
+{
+    return helper_udiv_common(env, a, b, 0);
+}
+
+target_ulong helper_udiv_cc(CPUState *env, target_ulong a, target_ulong b)
+{
+    return helper_udiv_common(env, a, b, 1);
+}
+
+static target_ulong helper_sdiv_common(CPUState *env, target_ulong a,
+                                       target_ulong b, int cc)
+{
+    int overflow = 0;
+    int64_t x0;
+    int32_t x1;
+
+    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+    x1 = (b & 0xffffffff);
+
+    if (x1 == 0) {
+        helper_raise_exception(env, TT_DIV_ZERO);
+    }
+
+    x0 = x0 / x1;
+    if ((int32_t) x0 != x0) {
+        x0 = x0 < 0 ? 0x80000000 : 0x7fffffff;
+        overflow = 1;
+    }
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
+    }
+    return x0;
+}
+
+target_ulong helper_sdiv(CPUState *env, target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(env, a, b, 0);
+}
+
+target_ulong helper_sdiv_cc(CPUState *env, target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(env, a, b, 1);
+}
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 943b4ba..615ddef 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -35,10 +35,10 @@ DEF_HELPER_2(check_align, void, tl, i32)
 DEF_HELPER_1(debug, void, env)
 DEF_HELPER_1(save, void, env)
 DEF_HELPER_1(restore, void, env)
-DEF_HELPER_2(udiv, tl, tl, tl)
-DEF_HELPER_2(udiv_cc, tl, tl, tl)
-DEF_HELPER_2(sdiv, tl, tl, tl)
-DEF_HELPER_2(sdiv_cc, tl, tl, tl)
+DEF_HELPER_3(udiv, tl, env, tl, tl)
+DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
+DEF_HELPER_3(sdiv, tl, env, tl, tl)
+DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
 DEF_HELPER_2(stdf, void, tl, int)
 DEF_HELPER_2(lddf, void, tl, int)
 DEF_HELPER_2(ldqf, void, tl, int)
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index e0a13fd..0f77ebf 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -2195,80 +2195,6 @@ target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
 }
 #endif /* TARGET_SPARC64 */
 
-static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
-{
-    int overflow = 0;
-    uint64_t x0;
-    uint32_t x1;
-
-    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = (b & 0xffffffff);
-
-    if (x1 == 0) {
-        helper_raise_exception(env, TT_DIV_ZERO);
-    }
-
-    x0 = x0 / x1;
-    if (x0 > 0xffffffff) {
-        x0 = 0xffffffff;
-        overflow = 1;
-    }
-
-    if (cc) {
-        env->cc_dst = x0;
-        env->cc_src2 = overflow;
-        env->cc_op = CC_OP_DIV;
-    }
-    return x0;
-}
-
-target_ulong helper_udiv(target_ulong a, target_ulong b)
-{
-    return helper_udiv_common(a, b, 0);
-}
-
-target_ulong helper_udiv_cc(target_ulong a, target_ulong b)
-{
-    return helper_udiv_common(a, b, 1);
-}
-
-static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
-{
-    int overflow = 0;
-    int64_t x0;
-    int32_t x1;
-
-    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
-    x1 = (b & 0xffffffff);
-
-    if (x1 == 0) {
-        helper_raise_exception(env, TT_DIV_ZERO);
-    }
-
-    x0 = x0 / x1;
-    if ((int32_t) x0 != x0) {
-        x0 = x0 < 0 ? 0x80000000 : 0x7fffffff;
-        overflow = 1;
-    }
-
-    if (cc) {
-        env->cc_dst = x0;
-        env->cc_src2 = overflow;
-        env->cc_op = CC_OP_DIV;
-    }
-    return x0;
-}
-
-target_ulong helper_sdiv(target_ulong a, target_ulong b)
-{
-    return helper_sdiv_common(a, b, 0);
-}
-
-target_ulong helper_sdiv_cc(target_ulong a, target_ulong b)
-{
-    return helper_sdiv_common(a, b, 1);
-}
-
 void helper_stdf(target_ulong addr, int mem_idx)
 {
     helper_check_align(addr, 7);
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 714808b..383fd9c 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -3271,19 +3271,23 @@ static void disas_sparc_insn(DisasContext * dc)
                     case 0xe: /* udiv */
                         CHECK_IU_FEATURE(dc, DIV);
                         if (xop & 0x10) {
-                            gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_udiv_cc(cpu_dst, cpu_env, cpu_src1,
+                                               cpu_src2);
                             dc->cc_op = CC_OP_DIV;
                         } else {
-                            gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_udiv(cpu_dst, cpu_env, cpu_src1,
+                                            cpu_src2);
                         }
                         break;
                     case 0xf: /* sdiv */
                         CHECK_IU_FEATURE(dc, DIV);
                         if (xop & 0x10) {
-                            gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_sdiv_cc(cpu_dst, cpu_env, cpu_src1,
+                                               cpu_src2);
                             dc->cc_op = CC_OP_DIV;
                         } else {
-                            gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
+                            gen_helper_sdiv(cpu_dst, cpu_env, cpu_src1,
+                                            cpu_src2);
                         }
                         break;
                     default:
commit 7922703623a989b59ce7f7b57a3c8ebe5c0f6b53
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Aug 1 09:20:58 2011 +0000

    Sparc: avoid AREG0 for softint op helpers and Leon cache control
    
    Make softint op helpers and Leon cache irq manager take a parameter
    for CPUState instead of relying on global env. Move the functions
    to int{32,64}_helper.c.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 6bf9275..ce1e668 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -335,6 +335,27 @@ enum {
 #define SFSR_CT_NOTRANS     (3ULL <<  4)
 #define SFSR_CT_MASK        (3ULL <<  4)
 
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+   any effect on the emulated */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED   0x0
+#define CACHE_FROZEN     0x1
+#define CACHE_ENABLED    0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
+
 typedef struct SparcTLBEntry {
     uint64_t tag;
     uint64_t tte;
@@ -478,7 +499,7 @@ typedef struct CPUSPARCState {
     sparc_def_t *def;
 
     void *irq_manager;
-    void (*qemu_irq_ack) (void *irq_manager, int intno);
+    void (*qemu_irq_ack)(CPUState *env, void *irq_manager, int intno);
 
     /* Leon3 cache control */
     uint32_t cache_control;
@@ -523,8 +544,9 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
 int cpu_cwp_dec(CPUState *env1, int cwp);
 void cpu_set_cwp(CPUState *env1, int new_cwp);
 
-/* op_helper.c */
-void leon3_irq_manager(void *irq_manager, int intno);
+/* int_helper.c */
+void do_interrupt(CPUState *env);
+void leon3_irq_manager(CPUState *env, void *irq_manager, int intno);
 
 /* sun4m.c, sun4u.c */
 void cpu_check_irqs(CPUSPARCState *env);
@@ -721,9 +743,6 @@ static inline bool tb_am_enabled(int tb_flags)
 #endif
 }
 
-/* helper.c */
-void do_interrupt(CPUState *env);
-
 static inline bool cpu_has_work(CPUState *env1)
 {
     return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index b18cbc6..943b4ba 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -24,9 +24,9 @@ DEF_HELPER_4(ldf_asi, void, tl, int, int, int)
 DEF_HELPER_4(stf_asi, void, tl, int, int, int)
 DEF_HELPER_4(cas_asi, tl, tl, tl, tl, i32)
 DEF_HELPER_4(casx_asi, tl, tl, tl, tl, i32)
-DEF_HELPER_1(set_softint, void, i64)
-DEF_HELPER_1(clear_softint, void, i64)
-DEF_HELPER_1(write_softint, void, i64)
+DEF_HELPER_2(set_softint, void, env, i64)
+DEF_HELPER_2(clear_softint, void, env, i64)
+DEF_HELPER_2(write_softint, void, env, i64)
 DEF_HELPER_2(tick_set_count, void, ptr, i64)
 DEF_HELPER_1(tick_get_count, i64, ptr)
 DEF_HELPER_2(tick_set_limit, void, ptr, i64)
diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
index 219a6c6..1c6ba6d 100644
--- a/target-sparc/int32_helper.c
+++ b/target-sparc/int32_helper.c
@@ -20,6 +20,14 @@
 #include "cpu.h"
 
 //#define DEBUG_PCALL
+//#define DEBUG_CACHE_CONTROL
+
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...)                                 \
+    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
 
 #ifdef DEBUG_PCALL
 static const char * const excp_names[0x80] = {
@@ -119,7 +127,44 @@ void do_interrupt(CPUState *env)
 #if !defined(CONFIG_USER_ONLY)
     /* IRQ acknowledgment */
     if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
-        env->qemu_irq_ack(env->irq_manager, intno);
+        env->qemu_irq_ack(env, env->irq_manager, intno);
     }
 #endif
 }
+
+#if !defined(CONFIG_USER_ONLY)
+static void leon3_cache_control_int(CPUState *env)
+{
+    uint32_t state = 0;
+
+    if (env->cache_control & CACHE_CTRL_IF) {
+        /* Instruction cache state */
+        state = env->cache_control & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
+        }
+
+        env->cache_control &= ~CACHE_STATE_MASK;
+        env->cache_control |= state;
+    }
+
+    if (env->cache_control & CACHE_CTRL_DF) {
+        /* Data cache state */
+        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
+        }
+
+        env->cache_control &= ~(CACHE_STATE_MASK << 2);
+        env->cache_control |= (state << 2);
+    }
+}
+
+void leon3_irq_manager(CPUState *env, void *irq_manager, int intno)
+{
+    leon3_irq_ack(irq_manager, intno);
+    leon3_cache_control_int(env);
+}
+#endif
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
index 2bb1910..c9c5e0e 100644
--- a/target-sparc/int64_helper.c
+++ b/target-sparc/int64_helper.c
@@ -18,8 +18,17 @@
  */
 
 #include "cpu.h"
+#include "helper.h"
 
 //#define DEBUG_PCALL
+//#define DEBUG_PSTATE
+
+#ifdef DEBUG_PSTATE
+#define DPRINTF_PSTATE(fmt, ...)                                \
+    do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
+#endif
 
 #ifdef DEBUG_PCALL
 static const char * const excp_names[0x80] = {
@@ -162,3 +171,34 @@ trap_state *cpu_tsptr(CPUState* env)
 {
     return &env->ts[env->tl & MAXTL_MASK];
 }
+
+static void do_modify_softint(CPUState *env, const char *operation,
+                              uint32_t value)
+{
+    if (env->softint != value) {
+        env->softint = value;
+        DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
+#if !defined(CONFIG_USER_ONLY)
+        if (cpu_interrupts_enabled(env)) {
+            cpu_check_irqs(env);
+        }
+#endif
+    }
+}
+
+void helper_set_softint(CPUState *env, uint64_t value)
+{
+    do_modify_softint(env, "helper_set_softint",
+                      env->softint | (uint32_t)value);
+}
+
+void helper_clear_softint(CPUState *env, uint64_t value)
+{
+    do_modify_softint(env, "helper_clear_softint",
+                      env->softint & (uint32_t)~value);
+}
+
+void helper_write_softint(CPUState *env, uint64_t value)
+{
+    do_modify_softint(env, "helper_write_softint", (uint32_t)value);
+}
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index cb0bf2e..e0a13fd 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -11,7 +11,6 @@
 //#define DEBUG_UNALIGNED
 //#define DEBUG_UNASSIGNED
 //#define DEBUG_ASI
-//#define DEBUG_PSTATE
 //#define DEBUG_CACHE_CONTROL
 
 #ifdef DEBUG_MMU
@@ -33,13 +32,6 @@
     do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
 #endif
 
-#ifdef DEBUG_PSTATE
-#define DPRINTF_PSTATE(fmt, ...)                                \
-    do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
-#endif
-
 #ifdef DEBUG_CACHE_CONTROL
 #define DPRINTF_CACHE_CONTROL(fmt, ...)                                 \
     do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
@@ -60,27 +52,6 @@
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
 
-/* Leon3 cache control */
-
-/* Cache control: emulate the behavior of cache control registers but without
-   any effect on the emulated */
-
-#define CACHE_STATE_MASK 0x3
-#define CACHE_DISABLED   0x0
-#define CACHE_FROZEN     0x1
-#define CACHE_ENABLED    0x3
-
-/* Cache Control register fields */
-
-#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
-#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
-#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
-#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
-#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
-#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
-#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
-#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
-
 #if !defined(CONFIG_USER_ONLY)
 static void do_unassigned_access(target_phys_addr_t addr, int is_write,
                                  int is_exec, int is_asi, int size);
@@ -384,35 +355,6 @@ static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
 
 /* Leon3 cache control */
 
-static void leon3_cache_control_int(void)
-{
-    uint32_t state = 0;
-
-    if (env->cache_control & CACHE_CTRL_IF) {
-        /* Instruction cache state */
-        state = env->cache_control & CACHE_STATE_MASK;
-        if (state == CACHE_ENABLED) {
-            state = CACHE_FROZEN;
-            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
-        }
-
-        env->cache_control &= ~CACHE_STATE_MASK;
-        env->cache_control |= state;
-    }
-
-    if (env->cache_control & CACHE_CTRL_DF) {
-        /* Data cache state */
-        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
-        if (state == CACHE_ENABLED) {
-            state = CACHE_FROZEN;
-            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
-        }
-
-        env->cache_control &= ~(CACHE_STATE_MASK << 2);
-        env->cache_control |= (state << 2);
-    }
-}
-
 static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
 {
     DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
@@ -477,12 +419,6 @@ static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
     return ret;
 }
 
-void leon3_irq_manager(void *irq_manager, int intno)
-{
-    leon3_irq_ack(irq_manager, intno);
-    leon3_cache_control_int();
-}
-
 uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
 {
     uint64_t ret = 0;
@@ -2455,36 +2391,6 @@ void helper_stqf(target_ulong addr, int mem_idx)
 #endif
 }
 
-#ifdef TARGET_SPARC64
-static void do_modify_softint(const char *operation, uint32_t value)
-{
-    if (env->softint != value) {
-        env->softint = value;
-        DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
-#if !defined(CONFIG_USER_ONLY)
-        if (cpu_interrupts_enabled(env)) {
-            cpu_check_irqs(env);
-        }
-#endif
-    }
-}
-
-void helper_set_softint(uint64_t value)
-{
-    do_modify_softint("helper_set_softint", env->softint | (uint32_t)value);
-}
-
-void helper_clear_softint(uint64_t value)
-{
-    do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value);
-}
-
-void helper_write_softint(uint64_t value)
-{
-    do_modify_softint("helper_write_softint", (uint32_t)value);
-}
-#endif
-
 #if !defined(CONFIG_USER_ONLY)
 
 static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 01849a6..714808b 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -3412,19 +3412,19 @@ static void disas_sparc_insn(DisasContext * dc)
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_set_softint(cpu_tmp64);
+                                gen_helper_set_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x15: /* Softint clear */
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_clear_softint(cpu_tmp64);
+                                gen_helper_clear_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x16: /* Softint write */
                                 if (!supervisor(dc))
                                     goto illegal_insn;
                                 tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
-                                gen_helper_write_softint(cpu_tmp64);
+                                gen_helper_write_softint(cpu_env, cpu_tmp64);
                                 break;
                             case 0x17: /* Tick compare */
 #if !defined(CONFIG_USER_ONLY)
commit 063c367558dc4e811e0c10a64f49838acb108c38
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jul 3 21:01:59 2011 +0000

    Sparc: avoid AREG0 for CWP and PSTATE helpers
    
    Make CWP and PSTATE helpers take a parameter for CPUState instead
    of relying on global env. Remove wrapper functions.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index 1e90df7..cc4dc1c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -97,7 +97,7 @@ tcg/tcg.o: cpu.h
 
 # HELPER_CFLAGS is used for all the code compiled with static register
 # variables
-op_helper.o win_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 
 # Note: this is a workaround. The real fix is to avoid compiling
 # cpu_signal_handler() in user-exec.c.
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 57d0073..b18cbc6 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -1,21 +1,21 @@
 #include "def-helper.h"
 
 #ifndef TARGET_SPARC64
-DEF_HELPER_0(rett, void)
-DEF_HELPER_1(wrpsr, void, tl)
-DEF_HELPER_0(rdpsr, tl)
+DEF_HELPER_1(rett, void, env)
+DEF_HELPER_2(wrpsr, void, env, tl)
+DEF_HELPER_1(rdpsr, tl, env)
 #else
-DEF_HELPER_1(wrpil, void, tl)
-DEF_HELPER_1(wrpstate, void, tl)
-DEF_HELPER_0(done, void)
-DEF_HELPER_0(retry, void)
-DEF_HELPER_0(flushw, void)
-DEF_HELPER_0(saved, void)
-DEF_HELPER_0(restored, void)
-DEF_HELPER_0(rdccr, tl)
-DEF_HELPER_1(wrccr, void, tl)
-DEF_HELPER_0(rdcwp, tl)
-DEF_HELPER_1(wrcwp, void, tl)
+DEF_HELPER_2(wrpil, void, env, tl)
+DEF_HELPER_2(wrpstate, void, env, tl)
+DEF_HELPER_1(done, void, env)
+DEF_HELPER_1(retry, void, env)
+DEF_HELPER_1(flushw, void, env)
+DEF_HELPER_1(saved, void, env)
+DEF_HELPER_1(restored, void, env)
+DEF_HELPER_1(rdccr, tl, env)
+DEF_HELPER_2(wrccr, void, env, tl)
+DEF_HELPER_1(rdcwp, tl, env)
+DEF_HELPER_2(wrcwp, void, env, tl)
 DEF_HELPER_3(array8, tl, env, tl, tl)
 DEF_HELPER_3(alignaddr, tl, env, tl, tl)
 DEF_HELPER_1(popc, tl, tl)
@@ -33,8 +33,8 @@ DEF_HELPER_2(tick_set_limit, void, ptr, i64)
 #endif
 DEF_HELPER_2(check_align, void, tl, i32)
 DEF_HELPER_1(debug, void, env)
-DEF_HELPER_0(save, void)
-DEF_HELPER_0(restore, void)
+DEF_HELPER_1(save, void, env)
+DEF_HELPER_1(restore, void, env)
 DEF_HELPER_2(udiv, tl, tl, tl)
 DEF_HELPER_2(udiv_cc, tl, tl, tl)
 DEF_HELPER_2(sdiv, tl, tl, tl)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 528ca92..01849a6 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2107,7 +2107,7 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifdef TARGET_SPARC64
                 case 0x2: /* V9 rdccr */
                     gen_helper_compute_psr(cpu_env);
-                    gen_helper_rdccr(cpu_dst);
+                    gen_helper_rdccr(cpu_dst, cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x3: /* V9 rdasi */
@@ -2184,7 +2184,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     goto priv_insn;
                 gen_helper_compute_psr(cpu_env);
                 dc->cc_op = CC_OP_FLAGS;
-                gen_helper_rdpsr(cpu_dst);
+                gen_helper_rdpsr(cpu_dst, cpu_env);
 #else
                 CHECK_IU_FEATURE(dc, HYPV);
                 if (!hypervisor(dc))
@@ -2297,7 +2297,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
                     break;
                 case 9: // cwp
-                    gen_helper_rdcwp(cpu_tmp0);
+                    gen_helper_rdcwp(cpu_tmp0, cpu_env);
                     break;
                 case 10: // cansave
                     tcg_gen_ld_i32(cpu_tmp32, cpu_env,
@@ -2351,7 +2351,7 @@ static void disas_sparc_insn(DisasContext * dc)
             } else if (xop == 0x2b) { /* rdtbr / V9 flushw */
 #ifdef TARGET_SPARC64
                 save_state(dc, cpu_cond);
-                gen_helper_flushw();
+                gen_helper_flushw(cpu_env);
 #else
                 if (!supervisor(dc))
                     goto priv_insn;
@@ -3379,7 +3379,7 @@ static void disas_sparc_insn(DisasContext * dc)
 #else
                             case 0x2: /* V9 wrccr */
                                 tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
-                                gen_helper_wrccr(cpu_dst);
+                                gen_helper_wrccr(cpu_env, cpu_dst);
                                 tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
                                 dc->cc_op = CC_OP_FLAGS;
                                 break;
@@ -3499,10 +3499,10 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifdef TARGET_SPARC64
                             switch (rd) {
                             case 0:
-                                gen_helper_saved();
+                                gen_helper_saved(cpu_env);
                                 break;
                             case 1:
-                                gen_helper_restored();
+                                gen_helper_restored(cpu_env);
                                 break;
                             case 2: /* UA2005 allclean */
                             case 3: /* UA2005 otherw */
@@ -3514,7 +3514,7 @@ static void disas_sparc_insn(DisasContext * dc)
                             }
 #else
                             tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
-                            gen_helper_wrpsr(cpu_dst);
+                            gen_helper_wrpsr(cpu_env, cpu_dst);
                             tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
                             dc->cc_op = CC_OP_FLAGS;
                             save_state(dc, cpu_cond);
@@ -3598,7 +3598,7 @@ static void disas_sparc_insn(DisasContext * dc)
 
                                     tcg_gen_mov_tl(r_tmp, cpu_tmp0);
                                     save_state(dc, cpu_cond);
-                                    gen_helper_wrpstate(r_tmp);
+                                    gen_helper_wrpstate(cpu_env, r_tmp);
                                     tcg_temp_free(r_tmp);
                                     dc->npc = DYNAMIC_PC;
                                 }
@@ -3617,10 +3617,10 @@ static void disas_sparc_insn(DisasContext * dc)
                                 }
                                 break;
                             case 8: // pil
-                                gen_helper_wrpil(cpu_tmp0);
+                                gen_helper_wrpil(cpu_env, cpu_tmp0);
                                 break;
                             case 9: // cwp
-                                gen_helper_wrcwp(cpu_tmp0);
+                                gen_helper_wrcwp(cpu_env, cpu_tmp0);
                                 break;
                             case 10: // cansave
                                 tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
@@ -4307,7 +4307,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     } else
                         tcg_gen_mov_tl(cpu_dst, cpu_src1);
                 }
-                gen_helper_restore();
+                gen_helper_restore(cpu_env);
                 gen_mov_pc_npc(dc, cpu_cond);
                 r_const = tcg_const_i32(3);
                 gen_helper_check_align(cpu_dst, r_const);
@@ -4359,7 +4359,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_temp_free_i32(r_const);
                         tcg_gen_mov_tl(cpu_npc, cpu_dst);
                         dc->npc = DYNAMIC_PC;
-                        gen_helper_rett();
+                        gen_helper_rett(cpu_env);
                     }
                     goto jmp_insn;
 #endif
@@ -4370,12 +4370,12 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x3c:      /* save */
                     save_state(dc, cpu_cond);
-                    gen_helper_save();
+                    gen_helper_save(cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
                 case 0x3d:      /* restore */
                     save_state(dc, cpu_cond);
-                    gen_helper_restore();
+                    gen_helper_restore(cpu_env);
                     gen_movl_TN_reg(rd, cpu_dst);
                     break;
 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
@@ -4387,14 +4387,14 @@ static void disas_sparc_insn(DisasContext * dc)
                                 goto priv_insn;
                             dc->npc = DYNAMIC_PC;
                             dc->pc = DYNAMIC_PC;
-                            gen_helper_done();
+                            gen_helper_done(cpu_env);
                             goto jmp_insn;
                         case 1:
                             if (!supervisor(dc))
                                 goto priv_insn;
                             dc->npc = DYNAMIC_PC;
                             dc->pc = DYNAMIC_PC;
-                            gen_helper_retry();
+                            gen_helper_retry(cpu_env);
                             goto jmp_insn;
                         default:
                             goto illegal_insn;
diff --git a/target-sparc/win_helper.c b/target-sparc/win_helper.c
index 8bf2123..f42d996 100644
--- a/target-sparc/win_helper.c
+++ b/target-sparc/win_helper.c
@@ -18,7 +18,6 @@
  */
 
 #include "cpu.h"
-#include "dyngen-exec.h"
 #include "helper.h"
 
 //#define DEBUG_PSTATE
@@ -42,7 +41,7 @@ static inline void memcpy32(target_ulong *dst, const target_ulong *src)
     dst[7] = src[7];
 }
 
-static void set_cwp(int new_cwp)
+void cpu_set_cwp(CPUState *env, int new_cwp)
 {
     /* put the modified wrap registers at their proper location */
     if (env->cwp == env->nwindows - 1) {
@@ -57,17 +56,7 @@ static void set_cwp(int new_cwp)
     env->regwptr = env->regbase + (new_cwp * 16);
 }
 
-void cpu_set_cwp(CPUState *env1, int new_cwp)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    set_cwp(new_cwp);
-    env = saved_env;
-}
-
-static target_ulong get_psr(void)
+target_ulong cpu_get_psr(CPUState *env)
 {
     helper_compute_psr(env);
 
@@ -83,19 +72,7 @@ static target_ulong get_psr(void)
 #endif
 }
 
-target_ulong cpu_get_psr(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_psr();
-    env = saved_env;
-    return ret;
-}
-
-static void put_psr(target_ulong val)
+void cpu_put_psr(CPUState *env, target_ulong val)
 {
     env->psr = val & PSR_ICC;
 #if !defined(TARGET_SPARC64)
@@ -109,22 +86,12 @@ static void put_psr(target_ulong val)
     env->psrs = (val & PSR_S) ? 1 : 0;
     env->psrps = (val & PSR_PS) ? 1 : 0;
     env->psret = (val & PSR_ET) ? 1 : 0;
-    set_cwp(val & PSR_CWP);
+    cpu_set_cwp(env, val & PSR_CWP);
 #endif
     env->cc_op = CC_OP_FLAGS;
 }
 
-void cpu_put_psr(CPUState *env1, target_ulong val)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_psr(val);
-    env = saved_env;
-}
-
-static int cwp_inc(int cwp)
+int cpu_cwp_inc(CPUState *env, int cwp)
 {
     if (unlikely(cwp >= env->nwindows)) {
         cwp -= env->nwindows;
@@ -132,19 +99,7 @@ static int cwp_inc(int cwp)
     return cwp;
 }
 
-int cpu_cwp_inc(CPUState *env1, int cwp)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = cwp_inc(cwp);
-    env = saved_env;
-    return ret;
-}
-
-static int cwp_dec(int cwp)
+int cpu_cwp_dec(CPUState *env, int cwp)
 {
     if (unlikely(cwp < 0)) {
         cwp += env->nwindows;
@@ -152,20 +107,8 @@ static int cwp_dec(int cwp)
     return cwp;
 }
 
-int cpu_cwp_dec(CPUState *env1, int cwp)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = cwp_dec(cwp);
-    env = saved_env;
-    return ret;
-}
-
 #ifndef TARGET_SPARC64
-void helper_rett(void)
+void helper_rett(CPUState *env)
 {
     unsigned int cwp;
 
@@ -174,39 +117,39 @@ void helper_rett(void)
     }
 
     env->psret = 1;
-    cwp = cwp_inc(env->cwp + 1) ;
+    cwp = cpu_cwp_inc(env, env->cwp + 1) ;
     if (env->wim & (1 << cwp)) {
         helper_raise_exception(env, TT_WIN_UNF);
     }
-    set_cwp(cwp);
+    cpu_set_cwp(env, cwp);
     env->psrs = env->psrps;
 }
 
 /* XXX: use another pointer for %iN registers to avoid slow wrapping
    handling ? */
-void helper_save(void)
+void helper_save(CPUState *env)
 {
     uint32_t cwp;
 
-    cwp = cwp_dec(env->cwp - 1);
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
     if (env->wim & (1 << cwp)) {
         helper_raise_exception(env, TT_WIN_OVF);
     }
-    set_cwp(cwp);
+    cpu_set_cwp(env, cwp);
 }
 
-void helper_restore(void)
+void helper_restore(CPUState *env)
 {
     uint32_t cwp;
 
-    cwp = cwp_inc(env->cwp + 1);
+    cwp = cpu_cwp_inc(env, env->cwp + 1);
     if (env->wim & (1 << cwp)) {
         helper_raise_exception(env, TT_WIN_UNF);
     }
-    set_cwp(cwp);
+    cpu_set_cwp(env, cwp);
 }
 
-void helper_wrpsr(target_ulong new_psr)
+void helper_wrpsr(CPUState *env, target_ulong new_psr)
 {
     if ((new_psr & PSR_CWP) >= env->nwindows) {
         helper_raise_exception(env, TT_ILL_INSN);
@@ -215,19 +158,19 @@ void helper_wrpsr(target_ulong new_psr)
     }
 }
 
-target_ulong helper_rdpsr(void)
+target_ulong helper_rdpsr(CPUState *env)
 {
-    return get_psr();
+    return cpu_get_psr(env);
 }
 
 #else
 /* XXX: use another pointer for %iN registers to avoid slow wrapping
    handling ? */
-void helper_save(void)
+void helper_save(CPUState *env)
 {
     uint32_t cwp;
 
-    cwp = cwp_dec(env->cwp - 1);
+    cwp = cpu_cwp_dec(env, env->cwp - 1);
     if (env->cansave == 0) {
         helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
                                                 (TT_WOTHER |
@@ -240,16 +183,16 @@ void helper_save(void)
         } else {
             env->cansave--;
             env->canrestore++;
-            set_cwp(cwp);
+            cpu_set_cwp(env, cwp);
         }
     }
 }
 
-void helper_restore(void)
+void helper_restore(CPUState *env)
 {
     uint32_t cwp;
 
-    cwp = cwp_inc(env->cwp + 1);
+    cwp = cpu_cwp_inc(env, env->cwp + 1);
     if (env->canrestore == 0) {
         helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
                                                (TT_WOTHER |
@@ -258,11 +201,11 @@ void helper_restore(void)
     } else {
         env->cansave++;
         env->canrestore--;
-        set_cwp(cwp);
+        cpu_set_cwp(env, cwp);
     }
 }
 
-void helper_flushw(void)
+void helper_flushw(CPUState *env)
 {
     if (env->cansave != env->nwindows - 2) {
         helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
@@ -272,7 +215,7 @@ void helper_flushw(void)
     }
 }
 
-void helper_saved(void)
+void helper_saved(CPUState *env)
 {
     env->cansave++;
     if (env->otherwin == 0) {
@@ -282,7 +225,7 @@ void helper_saved(void)
     }
 }
 
-void helper_restored(void)
+void helper_restored(CPUState *env)
 {
     env->canrestore++;
     if (env->cleanwin < env->nwindows - 1) {
@@ -295,102 +238,58 @@ void helper_restored(void)
     }
 }
 
-static target_ulong get_ccr(void)
+target_ulong cpu_get_ccr(CPUState *env)
 {
     target_ulong psr;
 
-    psr = get_psr();
+    psr = cpu_get_psr(env);
 
     return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
 }
 
-target_ulong cpu_get_ccr(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_ccr();
-    env = saved_env;
-    return ret;
-}
-
-static void put_ccr(target_ulong val)
+void cpu_put_ccr(CPUState *env, target_ulong val)
 {
     env->xcc = (val >> 4) << 20;
     env->psr = (val & 0xf) << 20;
     CC_OP = CC_OP_FLAGS;
 }
 
-void cpu_put_ccr(CPUState *env1, target_ulong val)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_ccr(val);
-    env = saved_env;
-}
-
-static target_ulong get_cwp64(void)
+target_ulong cpu_get_cwp64(CPUState *env)
 {
     return env->nwindows - 1 - env->cwp;
 }
 
-target_ulong cpu_get_cwp64(CPUState *env1)
-{
-    CPUState *saved_env;
-    target_ulong ret;
-
-    saved_env = env;
-    env = env1;
-    ret = get_cwp64();
-    env = saved_env;
-    return ret;
-}
-
-static void put_cwp64(int cwp)
+void cpu_put_cwp64(CPUState *env, int cwp)
 {
     if (unlikely(cwp >= env->nwindows || cwp < 0)) {
         cwp %= env->nwindows;
     }
-    set_cwp(env->nwindows - 1 - cwp);
+    cpu_set_cwp(env, env->nwindows - 1 - cwp);
 }
 
-void cpu_put_cwp64(CPUState *env1, int cwp)
+target_ulong helper_rdccr(CPUState *env)
 {
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    put_cwp64(cwp);
-    env = saved_env;
-}
-
-target_ulong helper_rdccr(void)
-{
-    return get_ccr();
+    return cpu_get_ccr(env);
 }
 
-void helper_wrccr(target_ulong new_ccr)
+void helper_wrccr(CPUState *env, target_ulong new_ccr)
 {
-    put_ccr(new_ccr);
+    cpu_put_ccr(env, new_ccr);
 }
 
 /* CWP handling is reversed in V9, but we still use the V8 register
    order. */
-target_ulong helper_rdcwp(void)
+target_ulong helper_rdcwp(CPUState *env)
 {
-    return get_cwp64();
+    return cpu_get_cwp64(env);
 }
 
-void helper_wrcwp(target_ulong new_cwp)
+void helper_wrcwp(CPUState *env, target_ulong new_cwp)
 {
-    put_cwp64(new_cwp);
+    cpu_put_cwp64(env, new_cwp);
 }
 
-static inline uint64_t *get_gregset(uint32_t pstate)
+static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate)
 {
     switch (pstate) {
     default:
@@ -411,7 +310,7 @@ static inline uint64_t *get_gregset(uint32_t pstate)
     }
 }
 
-static inline void change_pstate(uint32_t new_pstate)
+void cpu_change_pstate(CPUState *env, uint32_t new_pstate)
 {
     uint32_t pstate_regs, new_pstate_regs;
     uint64_t *src, *dst;
@@ -428,8 +327,8 @@ static inline void change_pstate(uint32_t new_pstate)
         DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
                        pstate_regs, new_pstate_regs);
         /* Switch global register bank */
-        src = get_gregset(new_pstate_regs);
-        dst = get_gregset(pstate_regs);
+        src = get_gregset(env, new_pstate_regs);
+        dst = get_gregset(env, pstate_regs);
         memcpy32(dst, env->gregs);
         memcpy32(env->gregs, src);
     } else {
@@ -439,9 +338,9 @@ static inline void change_pstate(uint32_t new_pstate)
     env->pstate = new_pstate;
 }
 
-void helper_wrpstate(target_ulong new_state)
+void helper_wrpstate(CPUState *env, target_ulong new_state)
 {
-    change_pstate(new_state & 0xf3f);
+    cpu_change_pstate(env, new_state & 0xf3f);
 
 #if !defined(CONFIG_USER_ONLY)
     if (cpu_interrupts_enabled(env)) {
@@ -450,17 +349,7 @@ void helper_wrpstate(target_ulong new_state)
 #endif
 }
 
-void cpu_change_pstate(CPUState *env1, uint32_t new_pstate)
-{
-    CPUState *saved_env;
-
-    saved_env = env;
-    env = env1;
-    change_pstate(new_pstate);
-    env = saved_env;
-}
-
-void helper_wrpil(target_ulong new_pil)
+void helper_wrpil(CPUState *env, target_ulong new_pil)
 {
 #if !defined(CONFIG_USER_ONLY)
     DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
@@ -474,16 +363,16 @@ void helper_wrpil(target_ulong new_pil)
 #endif
 }
 
-void helper_done(void)
+void helper_done(CPUState *env)
 {
     trap_state *tsptr = cpu_tsptr(env);
 
     env->pc = tsptr->tnpc;
     env->npc = tsptr->tnpc + 4;
-    put_ccr(tsptr->tstate >> 32);
+    cpu_put_ccr(env, tsptr->tstate >> 32);
     env->asi = (tsptr->tstate >> 24) & 0xff;
-    change_pstate((tsptr->tstate >> 8) & 0xf3f);
-    put_cwp64(tsptr->tstate & 0xff);
+    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
+    cpu_put_cwp64(env, tsptr->tstate & 0xff);
     env->tl--;
 
     DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
@@ -495,16 +384,16 @@ void helper_done(void)
 #endif
 }
 
-void helper_retry(void)
+void helper_retry(CPUState *env)
 {
     trap_state *tsptr = cpu_tsptr(env);
 
     env->pc = tsptr->tpc;
     env->npc = tsptr->tnpc;
-    put_ccr(tsptr->tstate >> 32);
+    cpu_put_ccr(env, tsptr->tstate >> 32);
     env->asi = (tsptr->tstate >> 24) & 0xff;
-    change_pstate((tsptr->tstate >> 8) & 0xf3f);
-    put_cwp64(tsptr->tstate & 0xff);
+    cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
+    cpu_put_cwp64(env, tsptr->tstate & 0xff);
     env->tl--;
 
     DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
commit e86d9b12b52a2e1cf9e18d55f471fa085911b166
Merge: 0ec024f... 6db39ae...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Oct 26 10:29:24 2011 -0500

    Merge remote-tracking branch 'kwolf/for-anthony' into staging

commit 3899edf7e4a13439793aaad21a17863a3b9152c2
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Wed Oct 26 15:06:14 2011 +0400

    ahci: fix DPRINTF format strings
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 1c7e3a0..0af201d 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -327,7 +327,7 @@ static void ahci_mem_write(void *opaque, target_phys_addr_t addr,
     }
 
     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
-        DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
+        DPRINTF(-1, "(addr 0x%08X), val 0x%08"PRIX64"\n", (unsigned) addr, val);
 
         switch (addr) {
             case HOST_CAP: /* R/WO, RO */
@@ -777,7 +777,8 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
     ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
                                 ncq_fis->sector_count_low;
 
-    DPRINTF(port, "NCQ transfer LBA from %ld to %ld, drive max %ld\n",
+    DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", "
+            "drive max %"PRId64"\n",
             ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
             s->dev[port].port.ifs[0].nb_sectors - 1);
 
@@ -786,10 +787,12 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
 
     switch(ncq_fis->command) {
         case READ_FPDMA_QUEUED:
-            DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
+            DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", "
+                    "tag %d\n",
                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
 
-            DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
+            DPRINTF(port, "tag %d aio read %"PRId64"\n",
+                    ncq_tfs->tag, ncq_tfs->lba);
 
             bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
                             (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE,
@@ -799,10 +802,11 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
                                            ncq_cb, ncq_tfs);
             break;
         case WRITE_FPDMA_QUEUED:
-            DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
+            DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n",
                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
 
-            DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
+            DPRINTF(port, "tag %d aio write %"PRId64"\n",
+                    ncq_tfs->tag, ncq_tfs->lba);
 
             bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
                             (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE,
commit 1a1a0e20683139edab32eaaeaa64f60cb2d5ff46
Author: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
Date:   Tue Oct 25 10:22:18 2011 +0200

    Documentation: fix typo
    
    Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/qemu-doc.texi b/qemu-doc.texi
index ad19b73..149e9bd 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -227,7 +227,7 @@ QEMU uses YM3812 emulation by Tatsuyuki Satoh.
 QEMU uses GUS emulation (GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
 by Tibor "TS" Schütz.
 
-Not that, by default, GUS shares IRQ(7) with parallel ports and so
+Note that, by default, GUS shares IRQ(7) with parallel ports and so
 qemu must be told to not have parallel ports to have working GUS
 
 @example
commit 1ce9c1921059913245dab20bdf8f11d1afab2e08
Author: Hervé Poussineau <hpoussin at reactos.org>
Date:   Mon Oct 24 21:52:38 2011 +0200

    Fix typo: buf -> bus
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/audiodev.h b/hw/audiodev.h
index 8e930b2..d60c349 100644
--- a/hw/audiodev.h
+++ b/hw/audiodev.h
@@ -11,7 +11,7 @@ int Adlib_init(qemu_irq *pic);
 int GUS_init(qemu_irq *pic);
 
 /* ac97.c */
-int ac97_init(PCIBus *buf);
+int ac97_init(PCIBus *bus);
 
 /* cs4231a.c */
 int cs4231a_init(qemu_irq *pic);
commit 4ab328d6488e117c369198c932d03acd7b4a1b4d
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Oct 24 13:33:01 2011 +0200

    tools: reorganize Makefile variables
    
    - Add all dependencies of the block layer to block-obj-y, and all
      dependencies of QObject to qobject-obj-y
    
    - Remove the block layer from tools-obj-y, add it to qemu-img, qemu-nbd,
      qemu-io
    
    - Add qobject-obj-y and tools-obj-y wherever useful, remove duplicates
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/Makefile b/Makefile
index f63fc02..ba8d738 100644
--- a/Makefile
+++ b/Makefile
@@ -146,27 +146,25 @@ endif
 qemu-img.o: qemu-img-cmds.h
 qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS)
 
-tools-obj-y = qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) \
-        $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+tools-obj-y = qemu-tool.o $(oslib-obj-y) $(trace-obj-y) \
+	qemu-timer-common.o cutils.o
 
-qemu-img$(EXESUF): qemu-img.o $(tools-obj-y)
-qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y)
-qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y)
+qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
+qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
+qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
 
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $@")
 
 check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
 
-CHECK_PROG_DEPS = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o
-
-check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
-check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
-check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
-check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
-check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
-check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
-test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(CHECK_PROG_DEPS)
+check-qint: check-qint.o qint.o $(tools-obj-y)
+check-qstring: check-qstring.o qstring.o $(tools-obj-y)
+check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y)
+check-qlist: check-qlist.o qlist.o qint.o $(tools-obj-y)
+check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y)
+check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
+test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
 
 $(qapi-obj-y): $(GENERATED_HEADERS)
 qapi-dir := qapi-generated
@@ -204,16 +202,16 @@ qmp-marshal.c: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -m -o "." < $<, "  GEN   $@")
 
 test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+test-visitor: test-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
 
 test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
-test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
+test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
 
 QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c)
 $(QGALIB_GEN): $(GENERATED_HEADERS)
 $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
 
-qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(qapi-obj-y) $(trace-obj-y) $(qobject-obj-y) $(version-obj-y) $(addprefix $(qapi-dir)/, qga-qapi-visit.o qga-qapi-types.o qga-qmp-marshal.o)
+qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qobject-obj-y) $(version-obj-y) $(addprefix $(qapi-dir)/, qga-qapi-visit.o qga-qapi-types.o qga-qmp-marshal.o)
 
 QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
 
diff --git a/Makefile.objs b/Makefile.objs
index 01587c8..a19e7c5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -2,7 +2,7 @@
 # QObject
 qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
 qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
-qobject-obj-y += qerror.o error.o
+qobject-obj-y += qerror.o error.o qemu-error.o
 
 #######################################################################
 # oslib-obj-y is code depending on the OS (win32 vs posix)
@@ -25,7 +25,7 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
 
 block-obj-y = cutils.o cache-utils.o qemu-option.o module.o async.o
 block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
-block-obj-y += $(coroutine-obj-y)
+block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
@@ -76,7 +76,7 @@ common-obj-y = $(block-obj-y) blockdev.o
 common-obj-y += $(net-obj-y)
 common-obj-y += $(qobject-obj-y)
 common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
-common-obj-y += readline.o console.o cursor.o qemu-error.o
+common-obj-y += readline.o console.o cursor.o
 common-obj-y += $(oslib-obj-y)
 common-obj-$(CONFIG_WIN32) += os-win32.o
 common-obj-$(CONFIG_POSIX) += os-posix.o
@@ -415,7 +415,7 @@ common-obj-y += qmp.o hmp.o
 
 qga-nested-y = guest-agent-commands.o guest-agent-command-state.o
 qga-obj-y = $(addprefix qga/, $(qga-nested-y))
-qga-obj-y += qemu-ga.o qemu-tool.o qemu-error.o qemu-sockets.o module.o qemu-option.o cutils.o osdep.o
+qga-obj-y += qemu-ga.o qemu-sockets.o module.o qemu-option.o
 qga-obj-$(CONFIG_WIN32) += oslib-win32.o
 qga-obj-$(CONFIG_POSIX) += oslib-posix.o
 
commit 8f355d6775d2f424c306c5a53f61a0528de5737e
Author: 陳韋任 <chenwj at iis.sinica.edu.tw>
Date:   Fri Oct 21 17:57:09 2011 +0800

    exec.c: Remove useless comment
    
      As phys_ram_size had been removed since QEMU 0.12. Remove the useless
    comment.
    
    Signed-off-by: Chen Wen-Ren <chenwj at iis.sinica.edu.tw>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/exec.c b/exec.c
index 9dc4edb..2f3c6a0 100644
--- a/exec.c
+++ b/exec.c
@@ -469,7 +469,6 @@ static void code_gen_alloc(unsigned long tb_size)
     code_gen_buffer_size = tb_size;
     if (code_gen_buffer_size == 0) {
 #if defined(CONFIG_USER_ONLY)
-        /* in user mode, phys_ram_size is not meaningful */
         code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
 #else
         /* XXX: needs adjustments */
commit 512a2cf8e9c52ac72cace5572eed16f9003cd11c
Author: Pavel Borzenkov <pavel.borzenkov at gmail.com>
Date:   Tue Oct 18 21:17:56 2011 +0400

    qed: remove unneeded variable assignment
    
    'ret' is unconditionally overwitten by qed_read_l1_table_sync()
    
    Spotted by Clang Analyzer
    
    Signed-off-by: Pavel Borzenkov <pavel.borzenkov at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/block/qed.c b/block/qed.c
index 7fab155..e6720db 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -388,7 +388,6 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
     if (ret < 0) {
         return ret;
     }
-    ret = 0; /* ret should always be 0 or -errno */
     qed_header_le_to_cpu(&le_header, &s->header);
 
     if (s->header.magic != QED_MAGIC) {
commit feba23b14340965b9dad9251ec9a7a47313fbf69
Author: Pavel Borzenkov <pavel.borzenkov at gmail.com>
Date:   Tue Oct 18 21:17:35 2011 +0400

    qed: don't pass NULL to memcpy
    
    Spotted by Clang Analyzer
    
    [Note this memcpy call has always been safe because the length will be 0
    when the pointer is NULL]
    
    Signed-off-by: Pavel Borzenkov <pavel.borzenkov at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/block/qed.c b/block/qed.c
index e87dc4d..7fab155 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1425,8 +1425,10 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
     memcpy(buffer, &le_header, sizeof(le_header));
     buffer_len = sizeof(le_header);
 
-    memcpy(buffer + buffer_len, backing_file, backing_file_len);
-    buffer_len += backing_file_len;
+    if (backing_file) {
+        memcpy(buffer + buffer_len, backing_file, backing_file_len);
+        buffer_len += backing_file_len;
+    }
 
     /* Write new header */
     ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len);
commit 8379e46d1fd681b8aa4714382e2cdab05e5d0575
Author: Pavel Borzenkov <pavel.borzenkov at gmail.com>
Date:   Tue Oct 18 21:19:03 2011 +0400

    vmdk: vmdk_read_cid returns garbage if p_name is NULL
    
    Spotted by Clang Analyzer
    
    Signed-off-by: Pavel Borzenkov <pavel.borzenkov at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 3969131..a75dcc2 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -207,7 +207,7 @@ static void vmdk_free_last_extent(BlockDriverState *bs)
 static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
 {
     char desc[DESC_SIZE];
-    uint32_t cid;
+    uint32_t cid = 0xffffffff;
     const char *p_name, *cid_str;
     size_t cid_str_size;
     BDRVVmdkState *s = bs->opaque;
commit c18a1c88059bd546a198d95a10e9e17b11d062d1
Author: Pavel Borzenkov <pavel.borzenkov at gmail.com>
Date:   Tue Oct 18 21:18:22 2011 +0400

    vmdk: remove unneeded variable assignment
    
    Spotted by Clang Analyzer
    
    Signed-off-by: Pavel Borzenkov <pavel.borzenkov at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 5d16ec4..3969131 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1387,7 +1387,6 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
             bdrv_delete(bs);
             return -EINVAL;
         }
-        filesize = bdrv_getlength(bs);
         parent_cid = vmdk_read_cid(bs, 0);
         bdrv_delete(bs);
         relative_path(parent_filename, sizeof(parent_filename),
commit bff39b6360eefc65b9f8f438cf03dab21afba5bf
Author: Stefan Weil <sw at weilnetz.de>
Date:   Mon Oct 17 22:12:09 2011 +0200

    device_tree: Fix potential memory leak
    
    cppcheck error report:
    
    device_tree.c:156: error: Memory leak: dupname
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/device_tree.c b/device_tree.c
index dc69232..86a694c 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -153,6 +153,7 @@ int qemu_devtree_add_subnode(void *fdt, const char *name)
     int retval;
 
     if (!basename) {
+        g_free(dupname);
         return -1;
     }
 
commit 0ec024f63696edb42c9841e756811ba31fd18ab8
Author: Stefan Weil <sw at weilnetz.de>
Date:   Tue Oct 25 22:23:17 2011 +0200

    main-loop: Add missing include file
    
    stdint.h defines the POSIX data types and is needed
    for MinGW-w64 (and maybe other hosts).
    
    v2: Instead of adding stdint.h directly, qemu-common.h is now
    included and duplicate include statements were removed.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/main-loop.c b/main-loop.c
index bfecdb7..60e9748 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -21,36 +21,16 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "config-host.h"
-#include <unistd.h>
-#include <signal.h>
-#include <time.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <stdbool.h>
 
-#ifdef _WIN32
-#include <windows.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <arpa/inet.h>
-#include <sys/select.h>
-#include <sys/stat.h>
-#include "compatfd.h"
-#endif
-
-#include <glib.h>
-
-#include "main-loop.h"
+#include "qemu-common.h"
 #include "qemu-timer.h"
-#include "slirp/libslirp.h"
+#include "slirp/slirp.h"
+#include "main-loop.h"
 
 #ifndef _WIN32
 
+#include "compatfd.h"
+
 static int io_thread_fd = -1;
 
 void qemu_notify_event(void)
commit d300854b1ccd036e0d7c58d789f4ab8d372263e6
Author: Stefan Weil <sw at weilnetz.de>
Date:   Tue Oct 25 07:16:25 2011 +0200

    target-sparc: Fix use of g_new0 / g_free
    
    g_malloc0 needs g_free instead of free.
    While fixing this, I also replaced g_malloc0 by g_new0
    as was suggested by Stuart Brady.
    
    Cc: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c
index 08b72a9..6954800 100644
--- a/target-sparc/cpu_init.c
+++ b/target-sparc/cpu_init.c
@@ -74,7 +74,7 @@ static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
         return -1;
     }
 
-    env->def = g_malloc0(sizeof(*def));
+    env->def = g_new0(sparc_def_t, 1);
     memcpy(env->def, def, sizeof(*def));
 #if defined(CONFIG_USER_ONLY)
     if ((env->def->features & CPU_FEATURE_FLOAT)) {
@@ -100,15 +100,15 @@ static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
 
 static void cpu_sparc_close(CPUSPARCState *env)
 {
-    free(env->def);
-    free(env);
+    g_free(env->def);
+    g_free(env);
 }
 
 CPUSPARCState *cpu_sparc_init(const char *cpu_model)
 {
     CPUSPARCState *env;
 
-    env = g_malloc0(sizeof(CPUSPARCState));
+    env = g_new0(CPUSPARCState, 1);
     cpu_exec_init(env);
 
     gen_intermediate_code_init(env);
commit f37e2a6bb3ee440219a7724722e8c0363cd5dc2e
Author: Stefan Weil <sw at weilnetz.de>
Date:   Mon Oct 24 22:29:48 2011 +0200

    target-sparc: Fix order of function parameters
    
    The MinGW-w64 gcc complains about wrong parameters for
    gen_helper_fpadd16_s and three other functions.
    
    gen_helper_fpadd16_s is declared like this (hidden in lots of macros):
    
    static inline void
     gen_helper_fpadd16s(TCGv_i32 retval, TCGv_ptr arg1,
                         TCGv_i32 arg2, TCGv_i32 arg3);
    
    So it looks like cpu_env should be the 2nd parameter.
    
    Please review this patch as I have no environment to test it
    (maybe the 1st parameter should be cpu_dst?).
    
    Cc: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 214252a..528ca92 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -4017,7 +4017,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x051: /* VIS I fpadd16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpadd16s(cpu_env, cpu_fpr[rd],
+                    gen_helper_fpadd16s(cpu_fpr[rd], cpu_env,
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -4031,7 +4031,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x053: /* VIS I fpadd32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpadd32s(cpu_env, cpu_fpr[rd],
+                    gen_helper_fpadd32s(cpu_fpr[rd], cpu_env,
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -4045,7 +4045,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x055: /* VIS I fpsub16s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpsub16s(cpu_env, cpu_fpr[rd],
+                    gen_helper_fpsub16s(cpu_fpr[rd], cpu_env,
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_update_fprs_dirty(rd);
                     break;
@@ -4059,7 +4059,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x057: /* VIS I fpsub32s */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_helper_fpsub32s(cpu_env, cpu_fpr[rd],
+                    gen_helper_fpsub32s(cpu_fpr[rd], cpu_env,
                                         cpu_fpr[rs1], cpu_fpr[rs2]);
                     gen_update_fprs_dirty(rd);
                     break;
commit ba43d28916c4f51c19bd7366089155ce81bee058
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Oct 25 16:53:01 2011 +0200

    hda: do not mix output and input stream states, RHBZ #740493
    
    Windows 7 may use the same stream number for input and output.
    Current code will confuse streams.
    
    Changes since v1:
    - keep running_compat[] for migration version 1
    - add running_real[] for migration version 2
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index c699d6f..9b089e6 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -466,7 +466,8 @@ struct HDAAudioState {
     QEMUSoundCard card;
     const desc_codec *desc;
     HDAAudioStream st[4];
-    bool running[16];
+    bool running_compat[16];
+    bool running_real[2 * 16];
 
     /* properties */
     uint32_t debug;
@@ -663,7 +664,7 @@ static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
         st->channel = payload & 0x0f;
         dprint(a, 2, "%s: stream %d, channel %d\n",
                st->node->name, st->stream, st->channel);
-        hda_audio_set_running(st, a->running[st->stream]);
+        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
         hda_codec_response(hda, true, 0);
         break;
     case AC_VERB_GET_CONV:
@@ -746,16 +747,20 @@ fail:
     hda_codec_response(hda, true, 0);
 }
 
-static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running)
+static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
 {
     HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
     int s;
 
-    a->running[stnr] = running;
+    a->running_compat[stnr] = running;
+    a->running_real[output * 16 + stnr] = running;
     for (s = 0; s < ARRAY_SIZE(a->st); s++) {
         if (a->st[s].node == NULL) {
             continue;
         }
+        if (a->st[s].output != output) {
+            continue;
+        }
         if (a->st[s].stream != stnr) {
             continue;
         }
@@ -837,6 +842,12 @@ static int hda_audio_post_load(void *opaque, int version)
     int i;
 
     dprint(a, 1, "%s\n", __FUNCTION__);
+    if (version == 1) {
+        /* assume running_compat[] is for output streams */
+        for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
+            a->running_real[16 + i] = a->running_compat[i];
+    }
+
     for (i = 0; i < ARRAY_SIZE(a->st); i++) {
         st = a->st + i;
         if (st->node == NULL)
@@ -844,7 +855,7 @@ static int hda_audio_post_load(void *opaque, int version)
         hda_codec_parse_fmt(st->format, &st->as);
         hda_audio_setup(st);
         hda_audio_set_amp(st);
-        hda_audio_set_running(st, a->running[st->stream]);
+        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
     }
     return 0;
 }
@@ -868,13 +879,14 @@ static const VMStateDescription vmstate_hda_audio_stream = {
 
 static const VMStateDescription vmstate_hda_audio = {
     .name = "hda-audio",
-    .version_id = 1,
+    .version_id = 2,
     .post_load = hda_audio_post_load,
     .fields = (VMStateField []) {
         VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
                              vmstate_hda_audio_stream,
                              HDAAudioStream),
-        VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16),
+        VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
+        VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index c6a3fec..f97775c 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -485,7 +485,7 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
     st->bp    = 0;
 }
 
-static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
 {
     DeviceState *qdev;
     HDACodecDevice *cdev;
@@ -493,7 +493,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
     QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (cdev->info->stream) {
-            cdev->info->stream(cdev, stream, running);
+            cdev->info->stream(cdev, stream, running, output);
         }
     }
 }
@@ -567,6 +567,7 @@ static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t
 
 static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
 {
+    bool output = reg->stream >= 4;
     IntelHDAStream *st = d->st + reg->stream;
 
     if (st->ctl & 0x01) {
@@ -582,11 +583,11 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
             dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
                    reg->stream, stnr, st->cbl);
             intel_hda_parse_bdl(d, st);
-            intel_hda_notify_codecs(d, stnr, true);
+            intel_hda_notify_codecs(d, stnr, true, output);
         } else {
             /* stop */
             dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
-            intel_hda_notify_codecs(d, stnr, false);
+            intel_hda_notify_codecs(d, stnr, false, output);
         }
     }
     intel_hda_update_irq(d);
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index 4e44e38..65fd2a8 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -34,7 +34,7 @@ struct HDACodecDeviceInfo {
     int (*init)(HDACodecDevice *dev);
     int (*exit)(HDACodecDevice *dev);
     void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
-    void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
+    void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
 };
 
 void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
commit 36ac4ad3d054a7b4962a6393630a73591cfa9558
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Oct 25 16:53:00 2011 +0200

    hda: do not mix output and input streams, RHBZ #740493
    
    Windows 7 may use the same stream number for input and output.
    That will result in lot of garbage on playback.
    
    The hardcoded value of 4 needs to be in sync with GCAP streams
    description and IN/OUT registers.
    
    Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 4272204..c6a3fec 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -389,14 +389,15 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
 {
     HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
     IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
-    IntelHDAStream *st = NULL;
     target_phys_addr_t addr;
     uint32_t s, copy, left;
+    IntelHDAStream *st;
     bool irq = false;
 
-    for (s = 0; s < ARRAY_SIZE(d->st); s++) {
-        if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) {
-            st = d->st + s;
+    st = output ? d->st + 4 : d->st;
+    for (s = 0; s < 4; s++) {
+        if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
+            st = st + s;
             break;
         }
     }
commit d9676f82e54cc7503ad3eb28f996edfeff58a870
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Oct 19 21:03:22 2011 +0200

    libcacard: Fix wrong assertion (reported by cppcheck)
    
    assert("...") will never do anything. This assertion handles a case
    which should never occur, so it must be assert(!"...").
    
    Cc: Alon Levy <alevy at redhat.com>
    Signed-off-by: Stefan Weil <sw at weilnetz.de>

diff --git a/libcacard/card_7816.c b/libcacard/card_7816.c
index 9fd59d4..6fe27d5 100644
--- a/libcacard/card_7816.c
+++ b/libcacard/card_7816.c
@@ -754,7 +754,7 @@ vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
         return vcard7816_vm_process_apdu(card, apdu, response);
     case VCARD_DIRECT:
         /* if we are type direct, then the applet should handle everything */
-        assert("VCARD_DIRECT: applet failure");
+        assert(!"VCARD_DIRECT: applet failure");
         break;
     }
     *response =
commit e7c5e89318946b57bcc3f65264be595401c12663
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Sep 27 17:19:25 2011 +0300

    libcacard/vscclient: fix error paths for socket creation
    
    Signed-off-by: Alon Levy <alevy at redhat.com>

diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
index 2191f60..e317a25 100644
--- a/libcacard/vscclient.c
+++ b/libcacard/vscclient.c
@@ -357,6 +357,7 @@ connect_to_qemu(
     if (sock < 0) {
         /* Error */
         fprintf(stderr, "Error opening socket!\n");
+        return -1;
     }
 
     memset(&hints, 0, sizeof(struct addrinfo));
@@ -370,13 +371,13 @@ connect_to_qemu(
     if (ret != 0) {
         /* Error */
         fprintf(stderr, "getaddrinfo failed\n");
-        return 5;
+        return -1;
     }
 
     if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) {
         /* Error */
         fprintf(stderr, "Could not connect\n");
-        return 5;
+        return -1;
     }
     if (verbose) {
         printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
@@ -505,6 +506,10 @@ main(
     qemu_host = strdup(argv[argc - 2]);
     qemu_port = strdup(argv[argc - 1]);
     sock = connect_to_qemu(qemu_host, qemu_port);
+    if (sock == -1) {
+        fprintf(stderr, "error opening socket, exiting.\n");
+        exit(5);
+    }
 
     qemu_mutex_init(&write_lock);
     qemu_mutex_init(&pending_reader_lock);
commit 7fc7e5844cd3f5018c0853268f1bc173572e5fb7
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Sep 27 17:18:50 2011 +0300

    libcacard/cac: fix typo in cac_delete_pki_applet_private
    
    Signed-off-by: Alon Levy <alevy at redhat.com>

diff --git a/libcacard/cac.c b/libcacard/cac.c
index f4b0b1b..927a4ca 100644
--- a/libcacard/cac.c
+++ b/libcacard/cac.c
@@ -266,7 +266,8 @@ static void
 cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
 {
     CACPKIAppletData *pki_applet_data = NULL;
-    if (pki_applet_data == NULL) {
+
+    if (applet_private == NULL) {
         return;
     }
     pki_applet_data = &(applet_private->u.pki_data);
commit 08cc67f32ebe9b7dc3e1410f0678f198c092c0e7
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Oct 21 15:56:21 2011 +0200

    spice: fix file handle cleanup
    
    Setting both read and write handlers to NULL in qemu_set_fd_handler
    is not enougth to make qemu purge the file handle from the list.
    We must set opaque to NULL too.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/spice-core.c b/ui/spice-core.c
index be52356..6d3dab6 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -133,7 +133,7 @@ static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *
 
 static void watch_remove(SpiceWatch *watch)
 {
-    watch_update_mask(watch, 0);
+    qemu_set_fd_handler(watch->fd, NULL, NULL, NULL);
     QTAILQ_REMOVE(&watches, watch, next);
     g_free(watch);
 }
commit 9f0f352d8546f217780013dd35ab157d667195dd
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 23 17:03:52 2011 +0200

    qxl: reset update_surface
    
    update init_qxl_ram to reset update_surface to 0. This fixes one case
    of breakage when installing an old driver in a vm that had a new driver
    installed. The newer driver would know about surface creation and would
    change update_surface to !=0, then a reset would happen, all surfaces
    are destroyed, then the old driver is initialized and issues an
    UPDATE_AREA, and spice server aborts on invalid surface.
    
    RHBZ: 690427
    
    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 3a3b3a4..12f71aa 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -331,6 +331,7 @@ static void init_qxl_ram(PCIQXLDevice *d)
     d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
     d->ram->int_pending = cpu_to_le32(0);
     d->ram->int_mask    = cpu_to_le32(0);
+    d->ram->update_surface = 0;
     SPICE_RING_INIT(&d->ram->cmd_ring);
     SPICE_RING_INIT(&d->ram->cursor_ring);
     SPICE_RING_INIT(&d->ram->release_ring);
commit 30f6da6656c94964ba8677928588592d9667007e
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Oct 18 18:58:54 2011 +0200

    qxl: fix guest cursor tracking
    
    (1) If the guest cursor command is empty, don't reload it after migration.
    (2) Cleaning the guest cursor when it is released by
        the spice server. In addition, explicitly reset the
        cursor in spice upon destroying the primary surface
        (was done by spice-server implicitly). This will prevent
        access to pci memory that was released.
    
    RHBZ: 744518
    
    Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 2ca1b04..3a3b3a4 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -236,6 +236,9 @@ void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
 void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
 {
     qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
+    qemu_mutex_lock(&qxl->track_lock);
+    qxl->guest_cursor = 0;
+    qemu_mutex_unlock(&qxl->track_lock);
 }
 
 
@@ -400,7 +403,9 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
     {
         QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
         if (cmd->type == QXL_CURSOR_SET) {
+            qemu_mutex_lock(&qxl->track_lock);
             qxl->guest_cursor = ext->cmd.data;
+            qemu_mutex_unlock(&qxl->track_lock);
         }
         break;
     }
@@ -1065,6 +1070,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
 
     d->mode = QXL_MODE_UNDEFINED;
     qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
+    qxl_spice_reset_cursor(d);
     return 1;
 }
 
@@ -1704,10 +1710,12 @@ static int qxl_post_load(void *opaque, int version)
             cmds[out].group_id = MEMSLOT_GROUP_GUEST;
             out++;
         }
-        cmds[out].cmd.data = d->guest_cursor;
-        cmds[out].cmd.type = QXL_CMD_CURSOR;
-        cmds[out].group_id = MEMSLOT_GROUP_GUEST;
-        out++;
+        if (d->guest_cursor) {
+            cmds[out].cmd.data = d->guest_cursor;
+            cmds[out].cmd.type = QXL_CMD_CURSOR;
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+            out++;
+        }
         qxl_spice_loadvm_commands(d, cmds, out);
         g_free(cmds);
 
commit 78e60ba53d5bf3c8b59aada8c22c1bd3aed3d344
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Oct 17 14:11:16 2011 +0200

    qxl: factor out properties
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index fb2b22d..2ca1b04 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1781,6 +1781,19 @@ static VMStateDescription qxl_vmstate = {
     },
 };
 
+static Property qxl_properties[] = {
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
+                           QXL_DEFAULT_REVISION),
+        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
+        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_END_OF_LIST(),
+};
+
 static PCIDeviceInfo qxl_info_primary = {
     .qdev.name    = "qxl-vga",
     .qdev.desc    = "Spice QXL GPU (primary, vga compatible)",
@@ -1793,18 +1806,7 @@ static PCIDeviceInfo qxl_info_primary = {
     .vendor_id    = REDHAT_PCI_VENDOR_ID,
     .device_id    = QXL_DEVICE_ID_STABLE,
     .class_id     = PCI_CLASS_DISPLAY_VGA,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
-                           64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
-                           64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
-                           QXL_DEFAULT_REVISION),
-        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
-        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
-        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+    .qdev.props   = qxl_properties,
 };
 
 static PCIDeviceInfo qxl_info_secondary = {
@@ -1817,18 +1819,7 @@ static PCIDeviceInfo qxl_info_secondary = {
     .vendor_id    = REDHAT_PCI_VENDOR_ID,
     .device_id    = QXL_DEVICE_ID_STABLE,
     .class_id     = PCI_CLASS_DISPLAY_OTHER,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
-                           64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
-                           64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
-                           QXL_DEFAULT_REVISION),
-        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
-        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
-        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+    .qdev.props   = qxl_properties,
 };
 
 static void qxl_register(void)
commit 3bb781f3ed91bd3f085ded4d16f089e7b66f1076
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Oct 4 13:25:53 2011 +0200

    ui/spice-core: fix segfault in monitor
    
    Fix segfault if a qxl device is present but no spice command line
    argument is given.
    
    RHBZ 743251.
    
    Signed-off-by: Alon Levy <alevy at redhat.com>

diff --git a/ui/spice-core.c b/ui/spice-core.c
index 4c06c36..be52356 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -445,7 +445,7 @@ void do_info_spice(Monitor *mon, QObject **ret_data)
     int port, tls_port;
     char version_string[20]; /* 12 = |255.255.255\0| is the max */
 
-    if (!spice_server) {
+    if (!spice_server || !opts) {
         *ret_data = qobject_from_jsonf("{ 'enabled': false }");
         return;
     }
commit 4ec8d3077b799fcdd9fe0f38e432791c8fceb88e
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Sep 20 17:21:07 2011 +0200

    qxl: Drop phread_yield on OOM
    
    This was only a best-effort attempt, by far not guaranteed to have an
    effect. Drop it so that also no direct pthread usage remain in the
    device model.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index a0b0f36..fb2b22d 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -18,8 +18,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <pthread.h>
-
 #include "qemu-common.h"
 #include "qemu-timer.h"
 #include "qemu-queue.h"
@@ -1215,10 +1213,6 @@ async_common:
         if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
             break;
         }
-        pthread_yield();
-        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
-            break;
-        }
         d->oom_running = 1;
         qxl_spice_oom(d);
         d->oom_running = 0;
commit 691f5c7bde07218127e034cca4e2581f66a6ddcf
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Sep 20 17:14:40 2011 +0200

    qxl: Convert to QEMU thread API
    
    Use QEMU thread API instead of pthread directly. We still need to get
    rid of pthread_yield, though, to drop pthread.h inclusion.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 03848ed..a0b0f36 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1372,7 +1372,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
     if ((old_pending & le_events) == le_events) {
         return;
     }
-    if (pthread_self() == d->main) {
+    if (qemu_thread_is_self(&d->main)) {
         qxl_update_irq(d);
     } else {
         if (write(d->pipe[1], d, 1) != 1) {
@@ -1391,7 +1391,7 @@ static void init_pipe_signaling(PCIQXLDevice *d)
    fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
    fcntl(d->pipe[0], F_SETOWN, getpid());
 
-   d->main = pthread_self();
+   qemu_thread_get_self(&d->main);
    qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
 }
 
diff --git a/hw/qxl.h b/hw/qxl.h
index 868db81..37b2619 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -4,6 +4,7 @@
 #include "hw.h"
 #include "pci.h"
 #include "vga_int.h"
+#include "qemu-thread.h"
 
 #include "ui/qemu-spice.h"
 #include "ui/spice-display.h"
@@ -63,7 +64,7 @@ typedef struct PCIQXLDevice {
     QemuMutex          track_lock;
 
     /* thread signaling */
-    pthread_t          main;
+    QemuThread         main;
     int                pipe[2];
 
     /* ram pci bar */
commit f9ab6091b0a741c47546b38301836f2ab6ce978d
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Sep 20 17:14:33 2011 +0200

    spice: Convert core to QEMU thread API
    
    No need to use pthread directly, we have proper abstractions for
    identity checking.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/spice-core.c b/ui/spice-core.c
index 8a86e45..4c06c36 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -19,10 +19,10 @@
 #include <spice-experimental.h>
 
 #include <netdb.h>
-#include <pthread.h>
 
 #include "qemu-common.h"
 #include "qemu-spice.h"
+#include "qemu-thread.h"
 #include "qemu-timer.h"
 #include "qemu-queue.h"
 #include "qemu-x509.h"
@@ -45,7 +45,7 @@ static char *auth_passwd;
 static time_t auth_expires = TIME_MAX;
 int using_spice = 0;
 
-static pthread_t me;
+static QemuThread me;
 
 struct SpiceTimer {
     QEMUTimer *timer;
@@ -229,7 +229,7 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
      * thread and grab the iothread lock if so before calling qemu
      * functions.
      */
-    bool need_lock = !pthread_equal(me, pthread_self());
+    bool need_lock = !qemu_thread_is_self(&me);
     if (need_lock) {
         qemu_mutex_lock_iothread();
     }
@@ -556,7 +556,7 @@ void qemu_spice_init(void)
     spice_image_compression_t compression;
     spice_wan_compression_t wan_compr;
 
-    me = pthread_self();
+    qemu_thread_get_self(&me);
 
    if (!opts) {
         return;
commit 026f773f562d118962fbdf3c28c66571f75f96fe
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Oct 17 10:03:19 2011 +0200

    spice: support the new migration interface (spice 0.8.3)
    
    - call spice_server_migrate_(start|end|connect).
    - register spice_migrate_connect completion callback
    
    Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/spice-core.c b/ui/spice-core.c
index 62ffb9b..8a86e45 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -288,6 +288,38 @@ static SpiceCoreInterface core_interface = {
 #endif
 };
 
+#ifdef SPICE_INTERFACE_MIGRATION
+typedef struct SpiceMigration {
+    SpiceMigrateInstance sin;
+    struct {
+        MonitorCompletion *cb;
+        void *opaque;
+    } connect_complete;
+} SpiceMigration;
+
+static void migrate_connect_complete_cb(SpiceMigrateInstance *sin);
+
+static const SpiceMigrateInterface migrate_interface = {
+    .base.type = SPICE_INTERFACE_MIGRATION,
+    .base.description = "migration",
+    .base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR,
+    .migrate_connect_complete = migrate_connect_complete_cb,
+    .migrate_end_complete = NULL,
+};
+
+static SpiceMigration spice_migrate;
+
+static void migrate_connect_complete_cb(SpiceMigrateInstance *sin)
+{
+    SpiceMigration *sm = container_of(sin, SpiceMigration, sin);
+    if (sm->connect_complete.cb) {
+        sm->connect_complete.cb(sm->connect_complete.opaque, NULL);
+    }
+    sm->connect_complete.cb = NULL;
+}
+#endif
+
 /* config string parsing */
 
 static int name2enum(const char *string, const char *table[], int entries)
@@ -449,9 +481,19 @@ static void migration_state_notifier(Notifier *notifier, void *data)
 {
     MigrationState *s = data;
 
-    if (migration_has_finished(s)) {
+    if (migration_is_active(s)) {
+#ifdef SPICE_INTERFACE_MIGRATION
+        spice_server_migrate_start(spice_server);
+#endif
+    } else if (migration_has_finished(s)) {
 #if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */
+#ifndef SPICE_INTERFACE_MIGRATION
         spice_server_migrate_switch(spice_server);
+#else
+        spice_server_migrate_end(spice_server, true);
+    } else if (migration_has_failed(s)) {
+        spice_server_migrate_end(spice_server, false);
+#endif
 #endif
     }
 }
@@ -461,9 +503,16 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
                             MonitorCompletion *cb, void *opaque)
 {
     int ret;
+#ifdef SPICE_INTERFACE_MIGRATION
+    spice_migrate.connect_complete.cb = cb;
+    spice_migrate.connect_complete.opaque = opaque;
+    ret = spice_server_migrate_connect(spice_server, hostname,
+                                       port, tls_port, subject);
+#else
     ret = spice_server_migrate_info(spice_server, hostname,
                                     port, tls_port, subject);
     cb(opaque, NULL);
+#endif
     return ret;
 }
 
@@ -654,6 +703,11 @@ void qemu_spice_init(void)
 
     migration_state.notify = migration_state_notifier;
     add_migration_state_change_notifier(&migration_state);
+#ifdef SPICE_INTERFACE_MIGRATION
+    spice_migrate.sin.base.sif = &migrate_interface.base;
+    spice_migrate.connect_complete.cb = NULL;
+    qemu_spice_add_interface(&spice_migrate.sin.base);
+#endif
 
     qemu_spice_input_init();
     qemu_spice_audio_init();
commit edc5cb1a52b2847201acf78b0fba67ab3c2464d5
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Oct 17 10:03:18 2011 +0200

    spice: turn client_migrate_info to async
    
    RHBZ 737921
    Spice client is required to connect to the migration target before/as migration
    starts. Since after migration starts, the target qemu is blocked and cannot accept new spice client
    we trigger the connection to the target upon client_migrate_info command.
    client_migrate_info completion cb will be called after spice client has been
    connected to the target (or a timeout). See following patches and spice patches.
    
    Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index ab08d58..e181267 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -824,7 +824,8 @@ ETEXI
         .params     = "protocol hostname port tls-port cert-subject",
         .help       = "send migration info to spice/vnc client",
         .user_print = monitor_user_noop,
-        .mhandler.cmd_new = client_migrate_info,
+        .mhandler.cmd_async = client_migrate_info,
+        .flags      = MONITOR_CMD_ASYNC,
     },
 
 STEXI
diff --git a/monitor.c b/monitor.c
index ffda0fe..13b0fa5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1153,7 +1153,8 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d
     return -1;
 }
 
-static int client_migrate_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int client_migrate_info(Monitor *mon, const QDict *qdict,
+                               MonitorCompletion cb, void *opaque)
 {
     const char *protocol = qdict_get_str(qdict, "protocol");
     const char *hostname = qdict_get_str(qdict, "hostname");
@@ -1168,7 +1169,8 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, QObject **ret_d
             return -1;
         }
 
-        ret = qemu_spice_migrate_info(hostname, port, tls_port, subject);
+        ret = qemu_spice_migrate_info(hostname, port, tls_port, subject,
+                                      cb, opaque);
         if (ret != 0) {
             qerror_report(QERR_UNDEFINED_ERROR);
             return -1;
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4328e8b..cb60d0c 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -569,7 +569,8 @@ EQMP
         .params     = "protocol hostname port tls-port cert-subject",
         .help       = "send migration info to spice/vnc client",
         .user_print = monitor_user_noop,
-        .mhandler.cmd_new = client_migrate_info,
+        .mhandler.cmd_async = client_migrate_info,
+        .flags      = MONITOR_CMD_ASYNC,
     },
 
 SQMP
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index f34be69..c35b29c 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -25,6 +25,7 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "qemu-char.h"
+#include "monitor.h"
 
 extern int using_spice;
 
@@ -37,7 +38,8 @@ int qemu_spice_set_passwd(const char *passwd,
                           bool fail_if_connected, bool disconnect_if_connected);
 int qemu_spice_set_pw_expire(time_t expires);
 int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
-                            const char *subject);
+                            const char *subject,
+                            MonitorCompletion cb, void *opaque);
 
 void do_info_spice_print(Monitor *mon, const QObject *data);
 void do_info_spice(Monitor *mon, QObject **ret_data);
@@ -45,6 +47,7 @@ void do_info_spice(Monitor *mon, QObject **ret_data);
 int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr);
 
 #else  /* CONFIG_SPICE */
+#include "monitor.h"
 
 #define using_spice 0
 static inline int qemu_spice_set_passwd(const char *passwd,
@@ -57,8 +60,13 @@ static inline int qemu_spice_set_pw_expire(time_t expires)
 {
     return -1;
 }
-static inline int qemu_spice_migrate_info(const char *h, int p, int t, const char *s)
-{ return -1; }
+static inline int qemu_spice_migrate_info(const char *h, int p, int t,
+                                          const char *s,
+                                          MonitorCompletion cb, void *opaque)
+{
+    cb(opaque, NULL);
+    return -1;
+}
 
 #endif /* CONFIG_SPICE */
 
diff --git a/ui/spice-core.c b/ui/spice-core.c
index b33366e..62ffb9b 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -457,10 +457,14 @@ static void migration_state_notifier(Notifier *notifier, void *data)
 }
 
 int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
-                            const char *subject)
+                            const char *subject,
+                            MonitorCompletion *cb, void *opaque)
 {
-    return spice_server_migrate_info(spice_server, hostname,
-                                     port, tls_port, subject);
+    int ret;
+    ret = spice_server_migrate_info(spice_server, hostname,
+                                    port, tls_port, subject);
+    cb(opaque, NULL);
+    return ret;
 }
 
 static int add_channel(const char *name, const char *value, void *opaque)
commit afe2df69cf9305b195d96afc545d3fefc0fb5f5d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Oct 25 13:50:11 2011 +0200

    migration: add status query functions
    
    Add migration_is_active and migration_has_failed functions
    to query migration state.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/migration.c b/migration.c
index bdca72e..d693567 100644
--- a/migration.c
+++ b/migration.c
@@ -372,11 +372,22 @@ void remove_migration_state_change_notifier(Notifier *notify)
     notifier_list_remove(&migration_state_notifiers, notify);
 }
 
+bool migration_is_active(MigrationState *s)
+{
+    return s->state == MIG_STATE_ACTIVE;
+}
+
 bool migration_has_finished(MigrationState *s)
 {
     return s->state == MIG_STATE_COMPLETED;
 }
 
+bool migration_has_failed(MigrationState *s)
+{
+    return (s->state == MIG_STATE_CANCELLED ||
+            s->state == MIG_STATE_ERROR);
+}
+
 void migrate_fd_connect(MigrationState *s)
 {
     int ret;
diff --git a/migration.h b/migration.h
index a1f80d0..1b8ee58 100644
--- a/migration.h
+++ b/migration.h
@@ -76,7 +76,9 @@ void migrate_fd_connect(MigrationState *s);
 
 void add_migration_state_change_notifier(Notifier *notify);
 void remove_migration_state_change_notifier(Notifier *notify);
+bool migration_is_active(MigrationState *);
 bool migration_has_finished(MigrationState *);
+bool migration_has_failed(MigrationState *);
 
 uint64_t ram_bytes_remaining(void);
 uint64_t ram_bytes_transferred(void);
commit 21e87c4625f290824f4f05d098e576cda40421ce
Author: Avi Kivity <avi at redhat.com>
Date:   Tue Oct 4 16:26:35 2011 +0200

    i386: wire up MSR_IA32_MISC_ENABLE
    
    It's needed for its default value - bit 0 specifies that "rep movs" is
    good enough for memcpy, and Linux may use a slower memcpu if it is not set,
    depending on cpu family/model.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 29412dc..a08ce9d 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -300,6 +300,10 @@
 
 #define MSR_IA32_PERF_STATUS            0x198
 
+#define MSR_IA32_MISC_ENABLE		0x1a0
+/* Indicates good rep/movs microcode on some processors: */
+#define MSR_IA32_MISC_ENABLE_DEFAULT    1
+
 #define MSR_MTRRphysBase(reg)		(0x200 + 2 * (reg))
 #define MSR_MTRRphysMask(reg)		(0x200 + 2 * (reg) + 1)
 
@@ -691,6 +695,7 @@ typedef struct CPUX86State {
     uint64_t tsc_deadline;
 
     uint64_t mcg_status;
+    uint64_t msr_ia32_misc_enable;
 
     /* exception/interrupt handling */
     int error_code;
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 5df40d4..6c6a167 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -98,6 +98,7 @@ void cpu_reset(CPUX86State *env)
     env->mxcsr = 0x1f80;
 
     env->pat = 0x0007040600070406ULL;
+    env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
 
     memset(env->dr, 0, sizeof(env->dr));
     env->dr[6] = DR6_FIXED_1;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 90a6ffb..ddd115c 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -61,6 +61,7 @@ static bool has_msr_star;
 static bool has_msr_hsave_pa;
 static bool has_msr_tsc_deadline;
 static bool has_msr_async_pf_en;
+static bool has_msr_misc_enable;
 static int lm_capable_kernel;
 
 static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
@@ -573,6 +574,10 @@ static int kvm_get_supported_msrs(KVMState *s)
                     has_msr_tsc_deadline = true;
                     continue;
                 }
+                if (kvm_msr_list->indices[i] == MSR_IA32_MISC_ENABLE) {
+                    has_msr_misc_enable = true;
+                    continue;
+                }
             }
         }
 
@@ -889,6 +894,10 @@ static int kvm_put_msrs(CPUState *env, int level)
     if (has_msr_tsc_deadline) {
         kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSCDEADLINE, env->tsc_deadline);
     }
+    if (has_msr_misc_enable) {
+        kvm_msr_entry_set(&msrs[n++], MSR_IA32_MISC_ENABLE,
+                          env->msr_ia32_misc_enable);
+    }
 #ifdef TARGET_X86_64
     if (lm_capable_kernel) {
         kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
@@ -1138,6 +1147,9 @@ static int kvm_get_msrs(CPUState *env)
     if (has_msr_tsc_deadline) {
         msrs[n++].index = MSR_IA32_TSCDEADLINE;
     }
+    if (has_msr_misc_enable) {
+        msrs[n++].index = MSR_IA32_MISC_ENABLE;
+    }
 
     if (!env->tsc_valid) {
         msrs[n++].index = MSR_IA32_TSC;
@@ -1224,6 +1236,9 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_MCG_CTL:
             env->mcg_ctl = msrs[i].data;
             break;
+        case MSR_IA32_MISC_ENABLE:
+            env->msr_ia32_misc_enable = msrs[i].data;
+            break;
         default:
             if (msrs[i].index >= MSR_MC0_CTL &&
                 msrs[i].index < MSR_MC0_CTL + (env->mcg_cap & 0xff) * 4) {
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 176d372..d6e98ff 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -328,6 +328,24 @@ static const VMStateDescription vmstate_msr_tscdeadline = {
     }
 };
 
+static bool misc_enable_needed(void *opaque)
+{
+    CPUState *env = opaque;
+
+    return env->msr_ia32_misc_enable != MSR_IA32_MISC_ENABLE_DEFAULT;
+}
+
+static const VMStateDescription vmstate_msr_ia32_misc_enable = {
+    .name = "cpu/msr_ia32_misc_enable",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(msr_ia32_misc_enable, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_cpu = {
     .name = "cpu",
     .version_id = CPU_SAVE_VERSION,
@@ -441,6 +459,9 @@ static const VMStateDescription vmstate_cpu = {
         }, {
             .vmsd = &vmstate_msr_tscdeadline,
             .needed = tscdeadline_needed,
+        }, {
+            .vmsd = &vmstate_msr_ia32_misc_enable,
+            .needed = misc_enable_needed,
         } , {
             /* empty */
         }
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 3bb5a91..c89e4a4 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -3280,6 +3280,9 @@ void helper_wrmsr(void)
     case MSR_TSC_AUX:
         env->tsc_aux = val;
         break;
+    case MSR_IA32_MISC_ENABLE:
+        env->msr_ia32_misc_enable = val;
+        break;
     default:
         if ((uint32_t)ECX >= MSR_MC0_CTL
             && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
@@ -3413,6 +3416,9 @@ void helper_rdmsr(void)
     case MSR_MCG_STATUS:
         val = env->mcg_status;
         break;
+    case MSR_IA32_MISC_ENABLE:
+        val = env->msr_ia32_misc_enable;
+        break;
     default:
         if ((uint32_t)ECX >= MSR_MC0_CTL
             && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
commit aa82ba549a3a88f7215e65956f3cb4bfd34835cc
Author: Liu, Jinsong <jinsong.liu at intel.com>
Date:   Wed Oct 5 16:52:32 2011 -0300

    kvm: support TSC deadline MSR with subsection
    
    KVM add emulation of lapic tsc deadline timer for guest.
    This patch is co-operation work at qemu side.
    
    Use subsections to save/restore the field (mtosatti).
    
    Signed-off-by: Liu, Jinsong <jinsong.liu at intel.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index ae36489..29412dc 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -283,6 +283,7 @@
 #define MSR_IA32_APICBASE_BSP           (1<<8)
 #define MSR_IA32_APICBASE_ENABLE        (1<<11)
 #define MSR_IA32_APICBASE_BASE          (0xfffff<<12)
+#define MSR_IA32_TSCDEADLINE            0x6e0
 
 #define MSR_MTRRcap			0xfe
 #define MSR_MTRRcap_VCNT		8
@@ -687,6 +688,7 @@ typedef struct CPUX86State {
     uint64_t async_pf_en_msr;
 
     uint64_t tsc;
+    uint64_t tsc_deadline;
 
     uint64_t mcg_status;
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index b6eef04..90a6ffb 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -59,6 +59,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 
 static bool has_msr_star;
 static bool has_msr_hsave_pa;
+static bool has_msr_tsc_deadline;
 static bool has_msr_async_pf_en;
 static int lm_capable_kernel;
 
@@ -568,6 +569,10 @@ static int kvm_get_supported_msrs(KVMState *s)
                     has_msr_hsave_pa = true;
                     continue;
                 }
+                if (kvm_msr_list->indices[i] == MSR_IA32_TSCDEADLINE) {
+                    has_msr_tsc_deadline = true;
+                    continue;
+                }
             }
         }
 
@@ -881,6 +886,9 @@ static int kvm_put_msrs(CPUState *env, int level)
     if (has_msr_hsave_pa) {
         kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
     }
+    if (has_msr_tsc_deadline) {
+        kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSCDEADLINE, env->tsc_deadline);
+    }
 #ifdef TARGET_X86_64
     if (lm_capable_kernel) {
         kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
@@ -1127,6 +1135,9 @@ static int kvm_get_msrs(CPUState *env)
     if (has_msr_hsave_pa) {
         msrs[n++].index = MSR_VM_HSAVE_PA;
     }
+    if (has_msr_tsc_deadline) {
+        msrs[n++].index = MSR_IA32_TSCDEADLINE;
+    }
 
     if (!env->tsc_valid) {
         msrs[n++].index = MSR_IA32_TSC;
@@ -1195,6 +1206,9 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_IA32_TSC:
             env->tsc = msrs[i].data;
             break;
+        case MSR_IA32_TSCDEADLINE:
+            env->tsc_deadline = msrs[i].data;
+            break;
         case MSR_VM_HSAVE_PA:
             env->vm_hsave = msrs[i].data;
             break;
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 9aca8e0..176d372 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -310,6 +310,24 @@ static const VMStateDescription vmstate_fpop_ip_dp = {
     }
 };
 
+static bool tscdeadline_needed(void *opaque)
+{
+    CPUState *env = opaque;
+
+    return env->tsc_deadline != 0;
+}
+
+static const VMStateDescription vmstate_msr_tscdeadline = {
+    .name = "cpu/msr_tscdeadline",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(tsc_deadline, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_cpu = {
     .name = "cpu",
     .version_id = CPU_SAVE_VERSION,
@@ -420,6 +438,9 @@ static const VMStateDescription vmstate_cpu = {
         } , {
             .vmsd = &vmstate_fpop_ip_dp,
             .needed = fpop_ip_dp_needed,
+        }, {
+            .vmsd = &vmstate_msr_tscdeadline,
+            .needed = tscdeadline_needed,
         } , {
             /* empty */
         }
commit 38d2c27ea68468bd2fdaa19c74d9e6d290f94777
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date:   Mon Oct 24 21:27:16 2011 -0200

    Revert "kvm: support TSC deadline MSR"
    
    This reverts commit bfc2455ddbb41148494a084d15777e6bed7533c3.
    New patch with subsections will follow.
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index a973f2e..ae36489 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -283,7 +283,6 @@
 #define MSR_IA32_APICBASE_BSP           (1<<8)
 #define MSR_IA32_APICBASE_ENABLE        (1<<11)
 #define MSR_IA32_APICBASE_BASE          (0xfffff<<12)
-#define MSR_IA32_TSCDEADLINE            0x6e0
 
 #define MSR_MTRRcap			0xfe
 #define MSR_MTRRcap_VCNT		8
@@ -688,7 +687,6 @@ typedef struct CPUX86State {
     uint64_t async_pf_en_msr;
 
     uint64_t tsc;
-    uint64_t tsc_deadline;
 
     uint64_t mcg_status;
 
@@ -949,7 +947,7 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 #define cpu_list_id x86_cpu_list
 #define cpudef_setup	x86_cpudef_setup
 
-#define CPU_SAVE_VERSION 13
+#define CPU_SAVE_VERSION 12
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 90a6ffb..b6eef04 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -59,7 +59,6 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 
 static bool has_msr_star;
 static bool has_msr_hsave_pa;
-static bool has_msr_tsc_deadline;
 static bool has_msr_async_pf_en;
 static int lm_capable_kernel;
 
@@ -569,10 +568,6 @@ static int kvm_get_supported_msrs(KVMState *s)
                     has_msr_hsave_pa = true;
                     continue;
                 }
-                if (kvm_msr_list->indices[i] == MSR_IA32_TSCDEADLINE) {
-                    has_msr_tsc_deadline = true;
-                    continue;
-                }
             }
         }
 
@@ -886,9 +881,6 @@ static int kvm_put_msrs(CPUState *env, int level)
     if (has_msr_hsave_pa) {
         kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
     }
-    if (has_msr_tsc_deadline) {
-        kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSCDEADLINE, env->tsc_deadline);
-    }
 #ifdef TARGET_X86_64
     if (lm_capable_kernel) {
         kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
@@ -1135,9 +1127,6 @@ static int kvm_get_msrs(CPUState *env)
     if (has_msr_hsave_pa) {
         msrs[n++].index = MSR_VM_HSAVE_PA;
     }
-    if (has_msr_tsc_deadline) {
-        msrs[n++].index = MSR_IA32_TSCDEADLINE;
-    }
 
     if (!env->tsc_valid) {
         msrs[n++].index = MSR_IA32_TSC;
@@ -1206,9 +1195,6 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_IA32_TSC:
             env->tsc = msrs[i].data;
             break;
-        case MSR_IA32_TSCDEADLINE:
-            env->tsc_deadline = msrs[i].data;
-            break;
         case MSR_VM_HSAVE_PA:
             env->vm_hsave = msrs[i].data;
             break;
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 25fa97d..9aca8e0 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -410,7 +410,6 @@ static const VMStateDescription vmstate_cpu = {
         VMSTATE_UINT64_V(xcr0, CPUState, 12),
         VMSTATE_UINT64_V(xstate_bv, CPUState, 12),
         VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12),
-        VMSTATE_UINT64_V(tsc_deadline, CPUState, 13),
         VMSTATE_END_OF_LIST()
         /* The above list is not sorted /wrt version numbers, watch out! */
     },
commit 1cae88b9f4121c9af0bf677435c6129e643280fd
Author: Avi Kivity <avi at redhat.com>
Date:   Tue Oct 18 19:43:12 2011 +0200

    kvm: avoid reentring kvm_flush_coalesced_mmio_buffer()
    
    mmio callbacks invoked by kvm_flush_coalesced_mmio_buffer() may
    themselves indirectly call kvm_flush_coalesced_mmio_buffer().
    Prevent reentering the function by checking a flag that indicates
    we're processing coalesced mmio requests.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/kvm-all.c b/kvm-all.c
index e7faf5c..c09ddf7 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -64,6 +64,7 @@ struct KVMState
     int vmfd;
     int coalesced_mmio;
     struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
+    bool coalesced_flush_in_progress;
     int broken_set_mem_region;
     int migration_log;
     int vcpu_events;
@@ -876,6 +877,13 @@ static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
 void kvm_flush_coalesced_mmio_buffer(void)
 {
     KVMState *s = kvm_state;
+
+    if (s->coalesced_flush_in_progress) {
+        return;
+    }
+
+    s->coalesced_flush_in_progress = true;
+
     if (s->coalesced_mmio_ring) {
         struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring;
         while (ring->first != ring->last) {
@@ -888,6 +896,8 @@ void kvm_flush_coalesced_mmio_buffer(void)
             ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
         }
     }
+
+    s->coalesced_flush_in_progress = false;
 }
 
 static void do_kvm_cpu_synchronize_state(void *_env)
commit 626c427624ac1d6b5dd245cb37988f046cec5f03
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Oct 7 09:37:49 2011 +0200

    kvm: Add top-like kvm statistics script
    
    Taken from original qemu-kvm/kvm/kvm_stat.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat
new file mode 100755
index 0000000..56d2bd7
--- /dev/null
+++ b/scripts/kvm/kvm_stat
@@ -0,0 +1,480 @@
+#!/usr/bin/python
+#
+# top-like utility for displaying kvm statistics
+#
+# Copyright 2006-2008 Qumranet Technologies
+# Copyright 2008-2011 Red Hat, Inc.
+#
+# Authors:
+#  Avi Kivity <avi at redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+import curses
+import sys, os, time, optparse
+
+class DebugfsProvider(object):
+    def __init__(self):
+        self.base = '/sys/kernel/debug/kvm'
+        self._fields = os.listdir(self.base)
+    def fields(self):
+        return self._fields
+    def select(self, fields):
+        self._fields = fields
+    def read(self):
+        def val(key):
+            return int(file(self.base + '/' + key).read())
+        return dict([(key, val(key)) for key in self._fields])
+
+vmx_exit_reasons = {
+    0: 'EXCEPTION_NMI',
+    1: 'EXTERNAL_INTERRUPT',
+    2: 'TRIPLE_FAULT',
+    7: 'PENDING_INTERRUPT',
+    8: 'NMI_WINDOW',
+    9: 'TASK_SWITCH',
+    10: 'CPUID',
+    12: 'HLT',
+    14: 'INVLPG',
+    15: 'RDPMC',
+    16: 'RDTSC',
+    18: 'VMCALL',
+    19: 'VMCLEAR',
+    20: 'VMLAUNCH',
+    21: 'VMPTRLD',
+    22: 'VMPTRST',
+    23: 'VMREAD',
+    24: 'VMRESUME',
+    25: 'VMWRITE',
+    26: 'VMOFF',
+    27: 'VMON',
+    28: 'CR_ACCESS',
+    29: 'DR_ACCESS',
+    30: 'IO_INSTRUCTION',
+    31: 'MSR_READ',
+    32: 'MSR_WRITE',
+    33: 'INVALID_STATE',
+    36: 'MWAIT_INSTRUCTION',
+    39: 'MONITOR_INSTRUCTION',
+    40: 'PAUSE_INSTRUCTION',
+    41: 'MCE_DURING_VMENTRY',
+    43: 'TPR_BELOW_THRESHOLD',
+    44: 'APIC_ACCESS',
+    48: 'EPT_VIOLATION',
+    49: 'EPT_MISCONFIG',
+    54: 'WBINVD',
+    55: 'XSETBV',
+}
+
+svm_exit_reasons = {
+    0x000: 'READ_CR0',
+    0x003: 'READ_CR3',
+    0x004: 'READ_CR4',
+    0x008: 'READ_CR8',
+    0x010: 'WRITE_CR0',
+    0x013: 'WRITE_CR3',
+    0x014: 'WRITE_CR4',
+    0x018: 'WRITE_CR8',
+    0x020: 'READ_DR0',
+    0x021: 'READ_DR1',
+    0x022: 'READ_DR2',
+    0x023: 'READ_DR3',
+    0x024: 'READ_DR4',
+    0x025: 'READ_DR5',
+    0x026: 'READ_DR6',
+    0x027: 'READ_DR7',
+    0x030: 'WRITE_DR0',
+    0x031: 'WRITE_DR1',
+    0x032: 'WRITE_DR2',
+    0x033: 'WRITE_DR3',
+    0x034: 'WRITE_DR4',
+    0x035: 'WRITE_DR5',
+    0x036: 'WRITE_DR6',
+    0x037: 'WRITE_DR7',
+    0x040: 'EXCP_BASE',
+    0x060: 'INTR',
+    0x061: 'NMI',
+    0x062: 'SMI',
+    0x063: 'INIT',
+    0x064: 'VINTR',
+    0x065: 'CR0_SEL_WRITE',
+    0x066: 'IDTR_READ',
+    0x067: 'GDTR_READ',
+    0x068: 'LDTR_READ',
+    0x069: 'TR_READ',
+    0x06a: 'IDTR_WRITE',
+    0x06b: 'GDTR_WRITE',
+    0x06c: 'LDTR_WRITE',
+    0x06d: 'TR_WRITE',
+    0x06e: 'RDTSC',
+    0x06f: 'RDPMC',
+    0x070: 'PUSHF',
+    0x071: 'POPF',
+    0x072: 'CPUID',
+    0x073: 'RSM',
+    0x074: 'IRET',
+    0x075: 'SWINT',
+    0x076: 'INVD',
+    0x077: 'PAUSE',
+    0x078: 'HLT',
+    0x079: 'INVLPG',
+    0x07a: 'INVLPGA',
+    0x07b: 'IOIO',
+    0x07c: 'MSR',
+    0x07d: 'TASK_SWITCH',
+    0x07e: 'FERR_FREEZE',
+    0x07f: 'SHUTDOWN',
+    0x080: 'VMRUN',
+    0x081: 'VMMCALL',
+    0x082: 'VMLOAD',
+    0x083: 'VMSAVE',
+    0x084: 'STGI',
+    0x085: 'CLGI',
+    0x086: 'SKINIT',
+    0x087: 'RDTSCP',
+    0x088: 'ICEBP',
+    0x089: 'WBINVD',
+    0x08a: 'MONITOR',
+    0x08b: 'MWAIT',
+    0x08c: 'MWAIT_COND',
+    0x400: 'NPF',
+}
+
+vendor_exit_reasons = {
+    'vmx': vmx_exit_reasons,
+    'svm': svm_exit_reasons,
+}
+
+exit_reasons = None
+
+for line in file('/proc/cpuinfo').readlines():
+    if line.startswith('flags'):
+        for flag in line.split():
+            if flag in vendor_exit_reasons:
+                exit_reasons = vendor_exit_reasons[flag]
+
+filters = {
+    'kvm_exit': ('exit_reason', exit_reasons)
+}
+
+def invert(d):
+    return dict((x[1], x[0]) for x in d.iteritems())
+
+for f in filters:
+    filters[f] = (filters[f][0], invert(filters[f][1]))
+
+import ctypes, struct, array
+
+libc = ctypes.CDLL('libc.so.6')
+syscall = libc.syscall
+class perf_event_attr(ctypes.Structure):
+    _fields_ = [('type', ctypes.c_uint32),
+                ('size', ctypes.c_uint32),
+                ('config', ctypes.c_uint64),
+                ('sample_freq', ctypes.c_uint64),
+                ('sample_type', ctypes.c_uint64),
+                ('read_format', ctypes.c_uint64),
+                ('flags', ctypes.c_uint64),
+                ('wakeup_events', ctypes.c_uint32),
+                ('bp_type', ctypes.c_uint32),
+                ('bp_addr', ctypes.c_uint64),
+                ('bp_len', ctypes.c_uint64),
+                ]
+def _perf_event_open(attr, pid, cpu, group_fd, flags):
+    return syscall(298, ctypes.pointer(attr), ctypes.c_int(pid),
+                   ctypes.c_int(cpu), ctypes.c_int(group_fd),
+                   ctypes.c_long(flags))
+
+PERF_TYPE_HARDWARE              = 0
+PERF_TYPE_SOFTWARE              = 1
+PERF_TYPE_TRACEPOINT            = 2
+PERF_TYPE_HW_CACHE              = 3
+PERF_TYPE_RAW                   = 4
+PERF_TYPE_BREAKPOINT            = 5
+
+PERF_SAMPLE_IP                  = 1 << 0
+PERF_SAMPLE_TID                 = 1 << 1
+PERF_SAMPLE_TIME                = 1 << 2
+PERF_SAMPLE_ADDR                = 1 << 3
+PERF_SAMPLE_READ                = 1 << 4
+PERF_SAMPLE_CALLCHAIN           = 1 << 5
+PERF_SAMPLE_ID                  = 1 << 6
+PERF_SAMPLE_CPU                 = 1 << 7
+PERF_SAMPLE_PERIOD              = 1 << 8
+PERF_SAMPLE_STREAM_ID           = 1 << 9
+PERF_SAMPLE_RAW                 = 1 << 10
+
+PERF_FORMAT_TOTAL_TIME_ENABLED  = 1 << 0
+PERF_FORMAT_TOTAL_TIME_RUNNING  = 1 << 1
+PERF_FORMAT_ID                  = 1 << 2
+PERF_FORMAT_GROUP               = 1 << 3
+
+import re
+
+sys_tracing = '/sys/kernel/debug/tracing'
+
+class Group(object):
+    def __init__(self, cpu):
+        self.events = []
+        self.group_leader = None
+        self.cpu = cpu
+    def add_event(self, name, event_set, tracepoint, filter = None):
+        self.events.append(Event(group = self,
+                                 name = name, event_set = event_set,
+                                 tracepoint = tracepoint, filter = filter))
+        if len(self.events) == 1:
+            self.file = os.fdopen(self.events[0].fd)
+    def read(self):
+        bytes = 8 * (1 + len(self.events))
+        fmt = 'xxxxxxxx' + 'q' * len(self.events)
+        return dict(zip([event.name for event in self.events],
+                        struct.unpack(fmt, self.file.read(bytes))))
+
+class Event(object):
+    def __init__(self, group, name, event_set, tracepoint, filter = None):
+        self.name = name
+        attr = perf_event_attr()
+        attr.type = PERF_TYPE_TRACEPOINT
+        attr.size = ctypes.sizeof(attr)
+        id_path = os.path.join(sys_tracing, 'events', event_set,
+                               tracepoint, 'id')
+        id = int(file(id_path).read())
+        attr.config = id
+        attr.sample_type = (PERF_SAMPLE_RAW
+                            | PERF_SAMPLE_TIME
+                            | PERF_SAMPLE_CPU)
+        attr.sample_period = 1
+        attr.read_format = PERF_FORMAT_GROUP
+        group_leader = -1
+        if group.events:
+            group_leader = group.events[0].fd
+        fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0)
+        if fd == -1:
+            raise Exception('perf_event_open failed')
+        if filter:
+            import fcntl
+            fcntl.ioctl(fd, 0x40082406, filter)
+        self.fd = fd
+    def enable(self):
+        import fcntl
+        fcntl.ioctl(self.fd, 0x00002400, 0)
+    def disable(self):
+        import fcntl
+        fcntl.ioctl(self.fd, 0x00002401, 0)
+
+class TracepointProvider(object):
+    def __init__(self):
+        path = os.path.join(sys_tracing, 'events', 'kvm')
+        fields = [f
+                  for f in os.listdir(path)
+                  if os.path.isdir(os.path.join(path, f))]
+        extra = []
+        for f in fields:
+            if f in filters:
+                subfield, values = filters[f]
+                for name, number in values.iteritems():
+                    extra.append(f + '(' + name + ')')
+        fields += extra
+        self._setup(fields)
+        self.select(fields)
+    def fields(self):
+        return self._fields
+    def _setup(self, _fields):
+        self._fields = _fields
+        cpure = r'cpu([0-9]+)'
+        self.cpus = [int(re.match(cpure, x).group(1))
+                     for x in os.listdir('/sys/devices/system/cpu')
+                     if re.match(cpure, x)]
+        import resource
+        nfiles = len(self.cpus) * 1000
+        resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles))
+        events = []
+        self.group_leaders = []
+        for cpu in self.cpus:
+            group = Group(cpu)
+            for name in _fields:
+                tracepoint = name
+                filter = None
+                m = re.match(r'(.*)\((.*)\)', name)
+                if m:
+                    tracepoint, sub = m.groups()
+                    filter = '%s==%d\0' % (filters[tracepoint][0],
+                                           filters[tracepoint][1][sub])
+                event = group.add_event(name, event_set = 'kvm',
+                                        tracepoint = tracepoint,
+                                        filter = filter)
+            self.group_leaders.append(group)
+    def select(self, fields):
+        for group in self.group_leaders:
+            for event in group.events:
+                if event.name in fields:
+                    event.enable()
+                else:
+                    event.disable()
+    def read(self):
+        from collections import defaultdict
+        ret = defaultdict(int)
+        for group in self.group_leaders:
+            for name, val in group.read().iteritems():
+                ret[name] += val
+        return ret
+
+class Stats:
+    def __init__(self, provider, fields = None):
+        self.provider = provider
+        self.fields_filter = fields
+        self._update()
+    def _update(self):
+        def wanted(key):
+            import re
+            if not self.fields_filter:
+                return True
+            return re.match(self.fields_filter, key) is not None
+        self.values = dict([(key, None)
+                            for key in provider.fields()
+                            if wanted(key)])
+        self.provider.select(self.values.keys())
+    def set_fields_filter(self, fields_filter):
+        self.fields_filter = fields_filter
+        self._update()
+    def get(self):
+        new = self.provider.read()
+        for key in self.provider.fields():
+            oldval = self.values.get(key, (0, 0))
+            newval = new[key]
+            newdelta = None
+            if oldval is not None:
+                newdelta = newval - oldval[0]
+            self.values[key] = (newval, newdelta)
+        return self.values
+
+if not os.access('/sys/kernel/debug', os.F_OK):
+    print 'Please enable CONFIG_DEBUG_FS in your kernel'
+    sys.exit(1)
+if not os.access('/sys/kernel/debug/kvm', os.F_OK):
+    print "Please mount debugfs ('mount -t debugfs debugfs /sys/kernel/debug')"
+    print "and ensure the kvm modules are loaded"
+    sys.exit(1)
+
+label_width = 40
+number_width = 10
+
+def tui(screen, stats):
+    curses.use_default_colors()
+    curses.noecho()
+    drilldown = False
+    fields_filter = stats.fields_filter
+    def update_drilldown():
+        if not fields_filter:
+            if drilldown:
+                stats.set_fields_filter(None)
+            else:
+                stats.set_fields_filter(r'^[^\(]*$')
+    update_drilldown()
+    def refresh(sleeptime):
+        screen.erase()
+        screen.addstr(0, 0, 'kvm statistics')
+        row = 2
+        s = stats.get()
+        def sortkey(x):
+            if s[x][1]:
+                return (-s[x][1], -s[x][0])
+            else:
+                return (0, -s[x][0])
+        for key in sorted(s.keys(), key = sortkey):
+            if row >= screen.getmaxyx()[0]:
+                break
+            values = s[key]
+            if not values[0] and not values[1]:
+                break
+            col = 1
+            screen.addstr(row, col, key)
+            col += label_width
+            screen.addstr(row, col, '%10d' % (values[0],))
+            col += number_width
+            if values[1] is not None:
+                screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
+            row += 1
+        screen.refresh()
+
+    sleeptime = 0.25
+    while True:
+        refresh(sleeptime)
+        curses.halfdelay(int(sleeptime * 10))
+        sleeptime = 3
+        try:
+            c = screen.getkey()
+            if c == 'x':
+                drilldown = not drilldown
+                update_drilldown()
+            if c == 'q':
+                break
+        except KeyboardInterrupt:
+            break
+        except curses.error:
+            continue
+
+def batch(stats):
+    s = stats.get()
+    time.sleep(1)
+    s = stats.get()
+    for key in sorted(s.keys()):
+        values = s[key]
+        print '%-22s%10d%10d' % (key, values[0], values[1])
+
+def log(stats):
+    keys = sorted(stats.get().iterkeys())
+    def banner():
+        for k in keys:
+            print '%10s' % k[0:9],
+        print
+    def statline():
+        s = stats.get()
+        for k in keys:
+            print ' %9d' % s[k][1],
+        print
+    line = 0
+    banner_repeat = 20
+    while True:
+        time.sleep(1)
+        if line % banner_repeat == 0:
+            banner()
+        statline()
+        line += 1
+
+options = optparse.OptionParser()
+options.add_option('-1', '--once', '--batch',
+                   action = 'store_true',
+                   default = False,
+                   dest = 'once',
+                   help = 'run in batch mode for one second',
+                   )
+options.add_option('-l', '--log',
+                   action = 'store_true',
+                   default = False,
+                   dest = 'log',
+                   help = 'run in logging mode (like vmstat)',
+                   )
+options.add_option('-f', '--fields',
+                   action = 'store',
+                   default = None,
+                   dest = 'fields',
+                   help = 'fields to display (regex)',
+                   )
+(options, args) = options.parse_args(sys.argv)
+
+try:
+    provider = TracepointProvider()
+except:
+    provider = DebugfsProvider()
+
+stats = Stats(provider, fields = options.fields)
+
+if options.log:
+    log(stats)
+elif not options.once:
+    import curses.wrapper
+    curses.wrapper(tui, stats)
+else:
+    batch(stats)
commit 5f6caa4f2ba45c8a99c915c09c4d56bd1621a450
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Oct 7 09:37:57 2011 +0200

    kvm: Add tool for querying VMX capabilities
    
    Taken from original qemu-kvm/kvm/scripts/vmxcap.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap
new file mode 100755
index 0000000..a74ce71
--- /dev/null
+++ b/scripts/kvm/vmxcap
@@ -0,0 +1,224 @@
+#!/usr/bin/python
+#
+# tool for querying VMX capabilities
+#
+# Copyright 2009-2010 Red Hat, Inc.
+#
+# Authors:
+#  Avi Kivity <avi at redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+MSR_IA32_VMX_BASIC = 0x480
+MSR_IA32_VMX_PINBASED_CTLS = 0x481
+MSR_IA32_VMX_PROCBASED_CTLS = 0x482
+MSR_IA32_VMX_EXIT_CTLS = 0x483
+MSR_IA32_VMX_ENTRY_CTLS = 0x484
+MSR_IA32_VMX_MISC_CTLS = 0x485
+MSR_IA32_VMX_PROCBASED_CTLS2 = 0x48B
+MSR_IA32_VMX_EPT_VPID_CAP = 0x48C
+MSR_IA32_VMX_TRUE_PINBASED_CTLS = 0x48D
+MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E
+MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F
+MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490
+
+class msr(object):
+    def __init__(self):
+        try:
+            self.f = file('/dev/cpu/0/msr')
+        except:
+            self.f = file('/dev/msr0')
+    def read(self, index, default = None):
+        import struct
+        self.f.seek(index)
+        try:
+            return struct.unpack('Q', self.f.read(8))[0]
+        except:
+            return default
+
+class Control(object):
+    def __init__(self, name, bits, cap_msr, true_cap_msr = None):
+        self.name = name
+        self.bits = bits
+        self.cap_msr = cap_msr
+        self.true_cap_msr = true_cap_msr
+    def read2(self, nr):
+        m = msr()
+        val = m.read(nr, 0)
+        return (val & 0xffffffff, val >> 32)
+    def show(self):
+        print self.name
+        mbz, mb1 = self.read2(self.cap_msr)
+        tmbz, tmb1 = 0, 0
+        if self.true_cap_msr:
+            tmbz, tmb1 = self.read2(self.true_cap_msr)
+        for bit in sorted(self.bits.keys()):
+            zero = not (mbz & (1 << bit))
+            one = mb1 & (1 << bit)
+            true_zero = not (tmbz & (1 << bit))
+            true_one = tmb1 & (1 << bit)
+            s= '?'
+            if (self.true_cap_msr and true_zero and true_one
+                and one and not zero):
+                s = 'default'
+            elif zero and not one:
+                s = 'no'
+            elif one and not zero:
+                s = 'forced'
+            elif one and zero:
+                s = 'yes'
+            print '  %-40s %s' % (self.bits[bit], s)
+
+class Misc(object):
+    def __init__(self, name, bits, msr):
+        self.name = name
+        self.bits = bits
+        self.msr = msr
+    def show(self):
+        print self.name
+        value = msr().read(self.msr, 0)
+        def first_bit(key):
+            if type(key) is tuple:
+                return key[0]
+            else:
+                return key
+        for bits in sorted(self.bits.keys(), key = first_bit):
+            if type(bits) is tuple:
+                lo, hi = bits
+                fmt = int
+            else:
+                lo = hi = bits
+                def fmt(x):
+                    return { True: 'yes', False: 'no' }[x]
+            v = (value >> lo) & ((1 << (hi - lo + 1)) - 1)
+            print '  %-40s %s' % (self.bits[bits], fmt(v))
+
+controls = [
+    Control(
+        name = 'pin-based controls',
+        bits = {
+            0: 'External interrupt exiting',
+            3: 'NMI exiting',
+            5: 'Virtual NMIs',
+            6: 'Activate VMX-preemption timer',
+            },
+        cap_msr = MSR_IA32_VMX_PINBASED_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_PINBASED_CTLS,
+        ),
+
+    Control(
+        name = 'primary processor-based controls',
+        bits = {
+            2: 'Interrupt window exiting',
+            3: 'Use TSC offsetting',
+            7: 'HLT exiting',
+            9: 'INVLPG exiting',
+            10: 'MWAIT exiting',
+            11: 'RDPMC exiting',
+            12: 'RDTSC exiting',
+            15: 'CR3-load exiting',
+            16: 'CR3-store exiting',
+            19: 'CR8-load exiting',
+            20: 'CR8-store exiting',
+            21: 'Use TPR shadow',
+            22: 'NMI-window exiting',
+            23: 'MOV-DR exiting',
+            24: 'Unconditional I/O exiting',
+            25: 'Use I/O bitmaps',
+            27: 'Monitor trap flag',
+            28: 'Use MSR bitmaps',
+            29: 'MONITOR exiting',
+            30: 'PAUSE exiting',
+            31: 'Activate secondary control',
+            },
+        cap_msr = MSR_IA32_VMX_PROCBASED_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
+        ),
+
+    Control(
+        name = 'secondary processor-based controls',
+        bits = {
+            0: 'Virtualize APIC accesses',
+            1: 'Enable EPT',
+            2: 'Descriptor-table exiting',
+            4: 'Virtualize x2APIC mode',
+            5: 'Enable VPID',
+            6: 'WBINVD exiting',
+            7: 'Unrestricted guest',
+            10: 'PAUSE-loop exiting',
+            },
+        cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2,
+        ),
+
+    Control(
+        name = 'VM-Exit controls',
+        bits = {
+            2: 'Save debug controls',
+            9: 'Host address-space size',
+            12: 'Load IA32_PERF_GLOBAL_CTRL',
+            15: 'Acknowledge interrupt on exit',
+            18: 'Save IA32_PAT',
+            19: 'Load IA32_PAT',
+            20: 'Save IA32_EFER',
+            21: 'Load IA32_EFER',
+            22: 'Save VMX-preemption timer value',
+            },
+        cap_msr = MSR_IA32_VMX_EXIT_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_EXIT_CTLS,
+        ),
+
+    Control(
+        name = 'VM-Entry controls',
+        bits = {
+            2: 'Load debug controls',
+            9: 'IA-64 mode guest',
+            10: 'Entry to SMM',
+            11: 'Deactivate dual-monitor treatment',
+            13: 'Load IA32_PERF_GLOBAL_CTRL',
+            14: 'Load IA32_PAT',
+            15: 'Load IA32_EFER',
+            },
+        cap_msr = MSR_IA32_VMX_ENTRY_CTLS,
+        true_cap_msr = MSR_IA32_VMX_TRUE_ENTRY_CTLS,
+        ),
+
+    Misc(
+        name = 'Miscellaneous data',
+        bits = {
+            (0,4): 'VMX-preemption timer scale (log2)',
+            5: 'Store EFER.LMA into IA-32e mode guest control',
+            6: 'HLT activity state',
+            7: 'Shutdown activity state',
+            8: 'Wait-for-SIPI activity state',
+            (16,24): 'Number of CR3-target values',
+            (25,27): 'MSR-load/store count recommenation',
+            (32,62): 'MSEG revision identifier',
+            },
+        msr = MSR_IA32_VMX_MISC_CTLS,
+        ),
+
+    Misc(
+        name = 'VPID and EPT capabilities',
+        bits = {
+            0: 'Execute-only EPT translations',
+            6: 'Page-walk length 4',
+            8: 'Paging-structure memory type UC',
+            14: 'Paging-structure memory type WB',
+            16: '2MB EPT pages',
+            17: '1GB EPT pages',
+            20: 'INVEPT supported',
+            25: 'Single-context INVEPT',
+            26: 'All-context INVEPT',
+            32: 'INVVPID supported',
+            40: 'Individual-address INVVPID',
+            41: 'Single-context INVVPID',
+            42: 'All-context INVVPID',
+            43: 'Single-context-retaining-globals INVVPID',
+            },
+        msr = MSR_IA32_VMX_EPT_VPID_CAP,
+        ),
+    ]
+
+for c in controls:
+    c.show()
commit 6db39ae2e250f15da17462444ea18a9fcef41e05
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 20 13:16:25 2011 +0200

    block: change discard to co_discard
    
    Since coroutine operation is now mandatory, convert both bdrv_discard
    implementations to coroutines.  For qcow2, this means taking the lock
    around the operation.  raw-posix remains synchronous.
    
    The bdrv_discard callback is then unused and can be eliminated.
    
    Reviewed-by: Kevin Wolf <kwolf at redhat.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 81fb709..70aab63 100644
--- a/block.c
+++ b/block.c
@@ -2962,8 +2962,6 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
             qemu_coroutine_yield();
             return co.ret;
         }
-    } else if (bs->drv->bdrv_discard) {
-        return bs->drv->bdrv_discard(bs, sector_num, nb_sectors);
     } else {
         return 0;
     }
diff --git a/block/qcow2.c b/block/qcow2.c
index 6ef38bf..a181932 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -978,11 +978,17 @@ static int qcow2_make_empty(BlockDriverState *bs)
     return 0;
 }
 
-static int qcow2_discard(BlockDriverState *bs, int64_t sector_num,
-    int nb_sectors)
+static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
 {
-    return qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
+    int ret;
+    BDRVQcowState *s = bs->opaque;
+
+    qemu_co_mutex_lock(&s->lock);
+    ret = qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
         nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
 }
 
 static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
@@ -1239,7 +1245,7 @@ static BlockDriver bdrv_qcow2 = {
     .bdrv_co_writev     = qcow2_co_writev,
     .bdrv_co_flush      = qcow2_co_flush,
 
-    .bdrv_discard           = qcow2_discard,
+    .bdrv_co_discard        = qcow2_co_discard,
     .bdrv_truncate          = qcow2_truncate,
     .bdrv_write_compressed  = qcow2_write_compressed,
 
diff --git a/block/raw-posix.c b/block/raw-posix.c
index afcb4c1..a3de373 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -602,7 +602,8 @@ static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
 }
 #endif
 
-static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+static coroutine_fn int raw_co_discard(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
 {
 #ifdef CONFIG_XFS
     BDRVRawState *s = bs->opaque;
@@ -632,7 +633,7 @@ static BlockDriver bdrv_file = {
     .bdrv_file_open = raw_open,
     .bdrv_close = raw_close,
     .bdrv_create = raw_create,
-    .bdrv_discard = raw_discard,
+    .bdrv_co_discard = raw_co_discard,
 
     .bdrv_aio_readv = raw_aio_readv,
     .bdrv_aio_writev = raw_aio_writev,
diff --git a/block_int.h b/block_int.h
index bc3b07e..dac00f5 100644
--- a/block_int.h
+++ b/block_int.h
@@ -62,8 +62,6 @@ struct BlockDriver {
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
     int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
-    int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
-                        int nb_sectors);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
commit 8b94ff85737062876c03e7506abb500521c749b9
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 20 13:16:24 2011 +0200

    block: change flush to co_flush
    
    Since coroutine operation is now mandatory, convert all bdrv_flush
    implementations to coroutines.  For qcow2, this means taking the lock.
    Other implementations are simpler and just forward bdrv_flush to the
    underlying protocol, so they can avoid the lock.
    
    The bdrv_flush callback is then unused and can be eliminated.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 28508f2..81fb709 100644
--- a/block.c
+++ b/block.c
@@ -2892,8 +2892,6 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
             qemu_coroutine_yield();
             return co.ret;
         }
-    } else if (bs->drv->bdrv_flush) {
-        return bs->drv->bdrv_flush(bs);
     } else {
         /*
          * Some block drivers always operate in either writethrough or unsafe
diff --git a/block/cow.c b/block/cow.c
index 29fa844..707c0aa 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -306,9 +306,9 @@ exit:
     return ret;
 }
 
-static int cow_flush(BlockDriverState *bs)
+static coroutine_fn int cow_co_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
+    return bdrv_co_flush(bs->file);
 }
 
 static QEMUOptionParameter cow_create_options[] = {
@@ -334,7 +334,7 @@ static BlockDriver bdrv_cow = {
     .bdrv_write         = cow_co_write,
     .bdrv_close		= cow_close,
     .bdrv_create	= cow_create,
-    .bdrv_flush		= cow_flush,
+    .bdrv_co_flush      = cow_co_flush,
     .bdrv_is_allocated	= cow_is_allocated,
 
     .create_options = cow_create_options,
diff --git a/block/qcow.c b/block/qcow.c
index f93e3eb..ab36b29 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -781,10 +781,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
-static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static coroutine_fn int qcow_co_flush(BlockDriverState *bs)
 {
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
@@ -824,9 +823,9 @@ static BlockDriver bdrv_qcow = {
     .bdrv_is_allocated	= qcow_is_allocated,
     .bdrv_set_key	= qcow_set_key,
     .bdrv_make_empty	= qcow_make_empty,
-    .bdrv_co_readv  = qcow_co_readv,
-    .bdrv_co_writev = qcow_co_writev,
-    .bdrv_aio_flush	= qcow_aio_flush,
+    .bdrv_co_readv      = qcow_co_readv,
+    .bdrv_co_writev     = qcow_co_writev,
+    .bdrv_co_flush      = qcow_co_flush,
     .bdrv_write_compressed = qcow_write_compressed,
     .bdrv_get_info	= qcow_get_info,
 
diff --git a/block/qcow2.c b/block/qcow2.c
index 91f4f04..6ef38bf 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1099,24 +1099,24 @@ fail:
     return ret;
 }
 
-static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs,
-                                         BlockDriverCompletionFunc *cb,
-                                         void *opaque)
+static int qcow2_co_flush(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
     int ret;
 
+    qemu_co_mutex_lock(&s->lock);
     ret = qcow2_cache_flush(bs, s->l2_table_cache);
     if (ret < 0) {
-        return NULL;
+        return ret;
     }
 
     ret = qcow2_cache_flush(bs, s->refcount_block_cache);
     if (ret < 0) {
-        return NULL;
+        return ret;
     }
+    qemu_co_mutex_unlock(&s->lock);
 
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int64_t qcow2_vm_state_offset(BDRVQcowState *s)
@@ -1237,7 +1237,7 @@ static BlockDriver bdrv_qcow2 = {
 
     .bdrv_co_readv      = qcow2_co_readv,
     .bdrv_co_writev     = qcow2_co_writev,
-    .bdrv_aio_flush     = qcow2_aio_flush,
+    .bdrv_co_flush      = qcow2_co_flush,
 
     .bdrv_discard           = qcow2_discard,
     .bdrv_truncate          = qcow2_truncate,
diff --git a/block/raw-win32.c b/block/raw-win32.c
index b7dd357..f5f73bc 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -281,7 +281,7 @@ static BlockDriver bdrv_file = {
     .bdrv_file_open	= raw_open,
     .bdrv_close		= raw_close,
     .bdrv_create	= raw_create,
-    .bdrv_flush		= raw_flush,
+    .bdrv_co_flush      = raw_flush,
     .bdrv_read		= raw_read,
     .bdrv_write		= raw_write,
     .bdrv_truncate	= raw_truncate,
@@ -409,7 +409,7 @@ static BlockDriver bdrv_host_device = {
     .bdrv_probe_device	= hdev_probe_device,
     .bdrv_file_open	= hdev_open,
     .bdrv_close		= raw_close,
-    .bdrv_flush		= raw_flush,
+    .bdrv_co_flush      = raw_flush,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_read		= raw_read,
diff --git a/block/rbd.c b/block/rbd.c
index 3068c82..c684e0c 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -705,7 +705,7 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
     return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 }
 
-static int qemu_rbd_flush(BlockDriverState *bs)
+static int qemu_rbd_co_flush(BlockDriverState *bs)
 {
 #if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
     /* rbd_flush added in 0.1.1 */
@@ -851,7 +851,7 @@ static BlockDriver bdrv_rbd = {
     .bdrv_file_open     = qemu_rbd_open,
     .bdrv_close         = qemu_rbd_close,
     .bdrv_create        = qemu_rbd_create,
-    .bdrv_flush         = qemu_rbd_flush,
+    .bdrv_co_flush      = qemu_rbd_co_flush,
     .bdrv_get_info      = qemu_rbd_getinfo,
     .create_options     = qemu_rbd_create_options,
     .bdrv_getlength     = qemu_rbd_getlength,
diff --git a/block/vdi.c b/block/vdi.c
index 1d5ad2b..883046d 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -936,10 +936,10 @@ static void vdi_close(BlockDriverState *bs)
 {
 }
 
-static int vdi_flush(BlockDriverState *bs)
+static coroutine_fn int vdi_co_flush(BlockDriverState *bs)
 {
     logout("\n");
-    return bdrv_flush(bs->file);
+    return bdrv_co_flush(bs->file);
 }
 
 
@@ -975,7 +975,7 @@ static BlockDriver bdrv_vdi = {
     .bdrv_open = vdi_open,
     .bdrv_close = vdi_close,
     .bdrv_create = vdi_create,
-    .bdrv_flush = vdi_flush,
+    .bdrv_co_flush = vdi_co_flush,
     .bdrv_is_allocated = vdi_is_allocated,
     .bdrv_make_empty = vdi_make_empty,
 
diff --git a/block/vmdk.c b/block/vmdk.c
index 3b376ed..6be592f 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1494,14 +1494,14 @@ static void vmdk_close(BlockDriverState *bs)
     vmdk_free_extents(bs);
 }
 
-static int vmdk_flush(BlockDriverState *bs)
+static coroutine_fn int vmdk_co_flush(BlockDriverState *bs)
 {
     int i, ret, err;
     BDRVVmdkState *s = bs->opaque;
 
-    ret = bdrv_flush(bs->file);
+    ret = bdrv_co_flush(bs->file);
     for (i = 0; i < s->num_extents; i++) {
-        err = bdrv_flush(s->extents[i].file);
+        err = bdrv_co_flush(s->extents[i].file);
         if (err < 0) {
             ret = err;
         }
@@ -1568,7 +1568,7 @@ static BlockDriver bdrv_vmdk = {
     .bdrv_write     = vmdk_co_write,
     .bdrv_close     = vmdk_close,
     .bdrv_create    = vmdk_create,
-    .bdrv_flush     = vmdk_flush,
+    .bdrv_co_flush  = vmdk_co_flush,
     .bdrv_is_allocated  = vmdk_is_allocated,
     .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
 
diff --git a/block/vpc.c b/block/vpc.c
index 74ca642..79be7d0 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -467,9 +467,9 @@ static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
     return ret;
 }
 
-static int vpc_flush(BlockDriverState *bs)
+static coroutine_fn int vpc_co_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
+    return bdrv_co_flush(bs->file);
 }
 
 /*
@@ -665,7 +665,7 @@ static BlockDriver bdrv_vpc = {
     .bdrv_open      = vpc_open,
     .bdrv_read      = vpc_co_read,
     .bdrv_write     = vpc_co_write,
-    .bdrv_flush     = vpc_flush,
+    .bdrv_co_flush  = vpc_co_flush,
     .bdrv_close     = vpc_close,
     .bdrv_create    = vpc_create,
 
diff --git a/block_int.h b/block_int.h
index 384598f..bc3b07e 100644
--- a/block_int.h
+++ b/block_int.h
@@ -62,7 +62,6 @@ struct BlockDriver {
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
     int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
-    int (*bdrv_flush)(BlockDriverState *bs);
     int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
                         int nb_sectors);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
commit e183ef75cc28d31addbb937a4680090495786944
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 20 13:16:23 2011 +0200

    block: take lock around bdrv_write implementations
    
    This does the first part of the conversion to coroutines, by
    wrapping bdrv_write implementations to take the mutex.
    
    Drivers that implement bdrv_write rather than bdrv_co_writev can
    then benefit from asynchronous operation (at least if the underlying
    protocol supports it, which is not the case for raw-win32), even
    though they still operate with a bounce buffer.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/cow.c b/block/cow.c
index a5fcd20..29fa844 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -226,6 +226,17 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num,
     return cow_update_bitmap(bs, sector_num, nb_sectors);
 }
 
+static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCowState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cow_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void cow_close(BlockDriverState *bs)
 {
 }
@@ -320,7 +331,7 @@ static BlockDriver bdrv_cow = {
     .bdrv_probe		= cow_probe,
     .bdrv_open		= cow_open,
     .bdrv_read          = cow_co_read,
-    .bdrv_write		= cow_write,
+    .bdrv_write         = cow_co_write,
     .bdrv_close		= cow_close,
     .bdrv_create	= cow_create,
     .bdrv_flush		= cow_flush,
diff --git a/block/nbd.c b/block/nbd.c
index 6b22ae1..882b2dc 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -251,6 +251,17 @@ static coroutine_fn int nbd_co_read(BlockDriverState *bs, int64_t sector_num,
     return ret;
 }
 
+static coroutine_fn int nbd_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVNBDState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = nbd_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void nbd_close(BlockDriverState *bs)
 {
     BDRVNBDState *s = bs->opaque;
@@ -272,7 +283,7 @@ static BlockDriver bdrv_nbd = {
     .instance_size	= sizeof(BDRVNBDState),
     .bdrv_file_open	= nbd_open,
     .bdrv_read          = nbd_co_read,
-    .bdrv_write		= nbd_write,
+    .bdrv_write         = nbd_co_write,
     .bdrv_close		= nbd_close,
     .bdrv_getlength	= nbd_getlength,
     .protocol_name	= "nbd",
diff --git a/block/vmdk.c b/block/vmdk.c
index 0e791f2..3b376ed 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1116,6 +1116,17 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
+                                      const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVmdkState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vmdk_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 
 static int vmdk_create_extent(const char *filename, int64_t filesize,
                               bool flat, bool compress)
@@ -1554,7 +1565,7 @@ static BlockDriver bdrv_vmdk = {
     .bdrv_probe     = vmdk_probe,
     .bdrv_open      = vmdk_open,
     .bdrv_read      = vmdk_co_read,
-    .bdrv_write     = vmdk_write,
+    .bdrv_write     = vmdk_co_write,
     .bdrv_close     = vmdk_close,
     .bdrv_create    = vmdk_create,
     .bdrv_flush     = vmdk_flush,
diff --git a/block/vpc.c b/block/vpc.c
index 0941533..74ca642 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -456,6 +456,17 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
+                                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vpc_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vpc_flush(BlockDriverState *bs)
 {
     return bdrv_flush(bs->file);
@@ -653,7 +664,7 @@ static BlockDriver bdrv_vpc = {
     .bdrv_probe     = vpc_probe,
     .bdrv_open      = vpc_open,
     .bdrv_read      = vpc_co_read,
-    .bdrv_write     = vpc_write,
+    .bdrv_write     = vpc_co_write,
     .bdrv_flush     = vpc_flush,
     .bdrv_close     = vpc_close,
     .bdrv_create    = vpc_create,
diff --git a/block/vvfat.c b/block/vvfat.c
index 970cccf..e1fcdbc 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -2727,6 +2727,17 @@ DLOG(checkpoint());
     return 0;
 }
 
+static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
+                                       const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVVFATState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vvfat_write(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vvfat_is_allocated(BlockDriverState *bs,
 	int64_t sector_num, int nb_sectors, int* n)
 {
@@ -2817,7 +2828,7 @@ static BlockDriver bdrv_vvfat = {
     .instance_size	= sizeof(BDRVVVFATState),
     .bdrv_file_open	= vvfat_open,
     .bdrv_read          = vvfat_co_read,
-    .bdrv_write		= vvfat_write,
+    .bdrv_write         = vvfat_co_write,
     .bdrv_close		= vvfat_close,
     .bdrv_is_allocated	= vvfat_is_allocated,
     .protocol_name	= "fat",
commit 2914caa088e3fbbdbfd73106af0cae49af1d472e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 20 13:16:22 2011 +0200

    block: take lock around bdrv_read implementations
    
    This does the first part of the conversion to coroutines, by
    wrapping bdrv_read implementations to take the mutex.
    
    Drivers that implement bdrv_read rather than bdrv_co_readv can
    then benefit from asynchronous operation (at least if the underlying
    protocol supports it, which is not the case for raw-win32), even
    though they still operate with a bounce buffer.
    
    raw-win32 does not need the lock, because it cannot yield.
    nbd also doesn't probably, but better be safe.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/bochs.c b/block/bochs.c
index b0f8072..ab7944d 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -209,6 +209,17 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int bochs_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVBochsState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = bochs_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void bochs_close(BlockDriverState *bs)
 {
     BDRVBochsState *s = bs->opaque;
@@ -220,7 +231,7 @@ static BlockDriver bdrv_bochs = {
     .instance_size	= sizeof(BDRVBochsState),
     .bdrv_probe		= bochs_probe,
     .bdrv_open		= bochs_open,
-    .bdrv_read		= bochs_read,
+    .bdrv_read          = bochs_co_read,
     .bdrv_close		= bochs_close,
 };
 
diff --git a/block/cloop.c b/block/cloop.c
index a91f372..775f8a9 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -146,6 +146,17 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCloopState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cloop_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void cloop_close(BlockDriverState *bs)
 {
     BDRVCloopState *s = bs->opaque;
@@ -161,7 +172,7 @@ static BlockDriver bdrv_cloop = {
     .instance_size	= sizeof(BDRVCloopState),
     .bdrv_probe		= cloop_probe,
     .bdrv_open		= cloop_open,
-    .bdrv_read		= cloop_read,
+    .bdrv_read          = cloop_co_read,
     .bdrv_close		= cloop_close,
 };
 
diff --git a/block/cow.c b/block/cow.c
index 2f426e7..a5fcd20 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -201,6 +201,17 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVCowState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = cow_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int cow_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
@@ -308,7 +319,7 @@ static BlockDriver bdrv_cow = {
     .instance_size	= sizeof(BDRVCowState),
     .bdrv_probe		= cow_probe,
     .bdrv_open		= cow_open,
-    .bdrv_read		= cow_read,
+    .bdrv_read          = cow_co_read,
     .bdrv_write		= cow_write,
     .bdrv_close		= cow_close,
     .bdrv_create	= cow_create,
diff --git a/block/dmg.c b/block/dmg.c
index 111aeae..37902a4 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -282,6 +282,17 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVDMGState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = dmg_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void dmg_close(BlockDriverState *bs)
 {
     BDRVDMGState *s = bs->opaque;
@@ -302,7 +313,7 @@ static BlockDriver bdrv_dmg = {
     .instance_size	= sizeof(BDRVDMGState),
     .bdrv_probe		= dmg_probe,
     .bdrv_open		= dmg_open,
-    .bdrv_read		= dmg_read,
+    .bdrv_read          = dmg_co_read,
     .bdrv_close		= dmg_close,
 };
 
diff --git a/block/nbd.c b/block/nbd.c
index 14ab225..6b22ae1 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -240,6 +240,17 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int nbd_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVNBDState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = nbd_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void nbd_close(BlockDriverState *bs)
 {
     BDRVNBDState *s = bs->opaque;
@@ -260,7 +271,7 @@ static BlockDriver bdrv_nbd = {
     .format_name	= "nbd",
     .instance_size	= sizeof(BDRVNBDState),
     .bdrv_file_open	= nbd_open,
-    .bdrv_read		= nbd_read,
+    .bdrv_read          = nbd_co_read,
     .bdrv_write		= nbd_write,
     .bdrv_close		= nbd_close,
     .bdrv_getlength	= nbd_getlength,
diff --git a/block/parallels.c b/block/parallels.c
index b86e87e..d30f0ec 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -136,6 +136,17 @@ static int parallels_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int parallels_co_read(BlockDriverState *bs, int64_t sector_num,
+                                          uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVParallelsState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = parallels_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static void parallels_close(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
@@ -147,7 +158,7 @@ static BlockDriver bdrv_parallels = {
     .instance_size	= sizeof(BDRVParallelsState),
     .bdrv_probe		= parallels_probe,
     .bdrv_open		= parallels_open,
-    .bdrv_read		= parallels_read,
+    .bdrv_read          = parallels_co_read,
     .bdrv_close		= parallels_close,
 };
 
diff --git a/block/vmdk.c b/block/vmdk.c
index 1ce220d..0e791f2 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1024,6 +1024,17 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num,
+                                     uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVmdkState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vmdk_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
@@ -1542,7 +1553,7 @@ static BlockDriver bdrv_vmdk = {
     .instance_size  = sizeof(BDRVVmdkState),
     .bdrv_probe     = vmdk_probe,
     .bdrv_open      = vmdk_open,
-    .bdrv_read      = vmdk_read,
+    .bdrv_read      = vmdk_co_read,
     .bdrv_write     = vmdk_write,
     .bdrv_close     = vmdk_close,
     .bdrv_create    = vmdk_create,
diff --git a/block/vpc.c b/block/vpc.c
index 9155ee1..0941533 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -409,6 +409,17 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
+static coroutine_fn int vpc_co_read(BlockDriverState *bs, int64_t sector_num,
+                                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vpc_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     const uint8_t *buf, int nb_sectors)
 {
@@ -641,7 +652,7 @@ static BlockDriver bdrv_vpc = {
     .instance_size  = sizeof(BDRVVPCState),
     .bdrv_probe     = vpc_probe,
     .bdrv_open      = vpc_open,
-    .bdrv_read      = vpc_read,
+    .bdrv_read      = vpc_co_read,
     .bdrv_write     = vpc_write,
     .bdrv_flush     = vpc_flush,
     .bdrv_close     = vpc_close,
diff --git a/block/vvfat.c b/block/vvfat.c
index 864bfcf..970cccf 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1281,6 +1281,17 @@ DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
     return 0;
 }
 
+static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
+                                      uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    BDRVVVFATState *s = bs->opaque;
+    qemu_co_mutex_lock(&s->lock);
+    ret = vvfat_read(bs, sector_num, buf, nb_sectors);
+    qemu_co_mutex_unlock(&s->lock);
+    return ret;
+}
+
 /* LATER TODO: statify all functions */
 
 /*
@@ -2805,7 +2816,7 @@ static BlockDriver bdrv_vvfat = {
     .format_name	= "vvfat",
     .instance_size	= sizeof(BDRVVVFATState),
     .bdrv_file_open	= vvfat_open,
-    .bdrv_read		= vvfat_read,
+    .bdrv_read          = vvfat_co_read,
     .bdrv_write		= vvfat_write,
     .bdrv_close		= vvfat_close,
     .bdrv_is_allocated	= vvfat_is_allocated,
commit 848c66e8f5b631961580f7f010a5831430dc84c2
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 20 13:16:21 2011 +0200

    block: add a CoMutex to synchronous read drivers
    
    The big conversion of bdrv_read/write to coroutines caused the two
    homonymous callbacks in BlockDriver to become reentrant.  It goes
    like this:
    
    1) bdrv_read is now called in a coroutine, and calls bdrv_read or
    bdrv_pread.
    
    2) the nested bdrv_read goes through the fast path in bdrv_rw_co_entry;
    
    3) in the common case when the protocol is file, bdrv_co_do_readv calls
    bdrv_co_readv_em (and from here goes to bdrv_co_io_em), which yields
    until the AIO operation is complete;
    
    4) if bdrv_read had been called from a bottom half, the main loop
    is free to iterate again: a device model or another bottom half
    can then come and call bdrv_read again.
    
    This applies to all four of read/write/flush/discard.  It would also
    apply to is_allocated, but it is not used from within coroutines:
    besides qemu-img.c and qemu-io.c, which operate synchronously, the
    only user is the monitor.  Copy-on-read will introduce a use in the
    block layer, and will require converting it.
    
    The solution is "simply" to convert all drivers to coroutines!  We
    just need to add a CoMutex that is taken around affected operations.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/bochs.c b/block/bochs.c
index 3c2f8d1..b0f8072 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -80,6 +80,7 @@ struct bochs_header {
 };
 
 typedef struct BDRVBochsState {
+    CoMutex lock;
     uint32_t *catalog_bitmap;
     int catalog_size;
 
@@ -150,6 +151,7 @@ static int bochs_open(BlockDriverState *bs, int flags)
 
     s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
diff --git a/block/cloop.c b/block/cloop.c
index 8cff9f2..a91f372 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -27,6 +27,7 @@
 #include <zlib.h>
 
 typedef struct BDRVCloopState {
+    CoMutex lock;
     uint32_t block_size;
     uint32_t n_blocks;
     uint64_t* offsets;
@@ -93,6 +94,7 @@ static int cloop_open(BlockDriverState *bs, int flags)
 
     s->sectors_per_block = s->block_size/512;
     bs->total_sectors = s->n_blocks*s->sectors_per_block;
+    qemu_co_mutex_init(&s->lock);
     return 0;
 
 cloop_close:
diff --git a/block/cow.c b/block/cow.c
index 4cf543c..2f426e7 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -42,6 +42,7 @@ struct cow_header_v2 {
 };
 
 typedef struct BDRVCowState {
+    CoMutex lock;
     int64_t cow_sectors_offset;
 } BDRVCowState;
 
@@ -84,6 +85,7 @@ static int cow_open(BlockDriverState *bs, int flags)
 
     bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
     s->cow_sectors_offset = (bitmap_size + 511) & ~511;
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
diff --git a/block/dmg.c b/block/dmg.c
index 64c3cce..111aeae 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -28,6 +28,7 @@
 #include <zlib.h>
 
 typedef struct BDRVDMGState {
+    CoMutex lock;
     /* each chunk contains a certain number of sectors,
      * offsets[i] is the offset in the .dmg file,
      * lengths[i] is the length of the compressed chunk,
@@ -177,6 +178,7 @@ static int dmg_open(BlockDriverState *bs, int flags)
 
     s->current_chunk = s->n_chunks;
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
 fail:
     return -1;
diff --git a/block/nbd.c b/block/nbd.c
index 76f04d8..14ab225 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -47,6 +47,7 @@
 #endif
 
 typedef struct BDRVNBDState {
+    CoMutex lock;
     int sock;
     uint32_t nbdflags;
     off_t size;
@@ -175,6 +176,7 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
      */
     result = nbd_establish_connection(bs);
 
+    qemu_co_mutex_init(&s->lock);
     return result;
 }
 
diff --git a/block/parallels.c b/block/parallels.c
index c64103d..b86e87e 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -46,6 +46,7 @@ struct parallels_header {
 } QEMU_PACKED;
 
 typedef struct BDRVParallelsState {
+    CoMutex lock;
 
     uint32_t *catalog_bitmap;
     int catalog_size;
@@ -95,6 +96,7 @@ static int parallels_open(BlockDriverState *bs, int flags)
     for (i = 0; i < s->catalog_size; i++)
 	le32_to_cpus(&s->catalog_bitmap[i]);
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
 fail:
     if (s->catalog_bitmap)
diff --git a/block/vmdk.c b/block/vmdk.c
index ace2977..1ce220d 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -90,6 +90,7 @@ typedef struct VmdkExtent {
 } VmdkExtent;
 
 typedef struct BDRVVmdkState {
+    CoMutex lock;
     int desc_offset;
     bool cid_updated;
     uint32_t parent_cid;
@@ -646,6 +647,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
         goto fail;
     }
     s->parent_cid = vmdk_read_cid(bs, 1);
+    qemu_co_mutex_init(&s->lock);
     return ret;
 
 fail:
diff --git a/block/vpc.c b/block/vpc.c
index cb6c570..9155ee1 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -110,6 +110,7 @@ struct vhd_dyndisk_header {
 };
 
 typedef struct BDRVVPCState {
+    CoMutex lock;
     uint8_t footer_buf[HEADER_SIZE];
     uint64_t free_data_block_offset;
     int max_table_entries;
@@ -226,6 +227,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
     s->last_pagetable = -1;
 #endif
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return err;
diff --git a/block/vvfat.c b/block/vvfat.c
index 7e9e35a..864bfcf 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -317,6 +317,7 @@ static void print_mapping(const struct mapping_t* mapping);
 /* here begins the real VVFAT driver */
 
 typedef struct BDRVVVFATState {
+    CoMutex lock;
     BlockDriverState* bs; /* pointer to parent */
     unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
     unsigned char first_sectors[0x40*0x200];
@@ -1065,6 +1066,7 @@ DLOG(if (stderr == NULL) {
 	bs->heads = bs->cyls = bs->secs = 0;
 
     //    assert(is_consistent(s));
+    qemu_co_mutex_init(&s->lock);
     return 0;
 }
 
commit bae0a0cc38d324c83ba737b92215f3447981d73b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 20 13:16:20 2011 +0200

    vmdk: clean up open
    
    Move vmdk_parent_open to vmdk_open.  There's another path how
    vmdk_parent_open can be reached:
    
      vmdk_parse_extents() ->  vmdk_open_sparse() ->  vmdk_open_vmdk4() ->
      vmdk_open_desc_file().
    
    If that can happen, however, the code is bogus.  vmdk_parent_open
    reads from bs->file:
    
        if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
    
    but it is always called with s->desc_offset == 0 and with the same
    bs->file.  So the data that vmdk_parent_open reads comes always from the
    same place, and anyway there is only one place where it can write it,
    namely bs->backing_file.
    
    So, if it cannot happen, the patched code is okay.
    
    It is also possible that the recursive call can happen, but only once.  In
    that case there would still be a bug in vmdk_open_desc_file setting
    s->desc_offset = 0, but the patched code is okay.
    
    Finally, in the case where multiple recursive calls can happen the code
    would need to be rewritten anyway.  It is likely that this would anyway
    involve adding several parameters to vmdk_parent_open, and calling it from
    vmdk_open_vmdk4.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index ea00938..ace2977 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -624,20 +624,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
         return -ENOTSUP;
     }
     s->desc_offset = 0;
-    ret = vmdk_parse_extents(buf, bs, bs->file->filename);
-    if (ret) {
-        vmdk_free_extents(bs);
-        return ret;
-    }
-
-    /* try to open parent images, if exist */
-    ret = vmdk_parent_open(bs);
-    if (ret) {
-        vmdk_free_extents(bs);
-        return ret;
-    }
-    s->parent_cid = vmdk_read_cid(bs, 1);
-    return 0;
+    return vmdk_parse_extents(buf, bs, bs->file->filename);
 }
 
 static int vmdk_open(BlockDriverState *bs, int flags)
@@ -647,17 +634,23 @@ static int vmdk_open(BlockDriverState *bs, int flags)
 
     if (vmdk_open_sparse(bs, bs->file, flags) == 0) {
         s->desc_offset = 0x200;
-        /* try to open parent images, if exist */
-        ret = vmdk_parent_open(bs);
+    } else {
+        ret = vmdk_open_desc_file(bs, flags, 0);
         if (ret) {
-            vmdk_free_extents(bs);
-            return ret;
+            goto fail;
         }
-        s->parent_cid = vmdk_read_cid(bs, 1);
-        return 0;
-    } else {
-        return vmdk_open_desc_file(bs, flags, 0);
     }
+    /* try to open parent images, if exist */
+    ret = vmdk_parent_open(bs);
+    if (ret) {
+        goto fail;
+    }
+    s->parent_cid = vmdk_read_cid(bs, 1);
+    return ret;
+
+fail:
+    vmdk_free_extents(bs);
+    return ret;
 }
 
 static int get_whole_cluster(BlockDriverState *bs,
commit 588b65a37abf7bbe47c3a7243a871d83fa1aa66b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Oct 20 13:16:19 2011 +0200

    vmdk: fix return values of vmdk_parent_open
    
    While vmdk_open_desc_file (touched by the patch) correctly changed -1
    to -EINVAL, vmdk_open did not.  Fix it directly in vmdk_parent_open.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 5d16ec4..ea00938 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -283,10 +283,12 @@ static int vmdk_parent_open(BlockDriverState *bs)
     char *p_name;
     char desc[DESC_SIZE + 1];
     BDRVVmdkState *s = bs->opaque;
+    int ret;
 
     desc[DESC_SIZE] = '\0';
-    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
-        return -1;
+    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    if (ret < 0) {
+        return ret;
     }
 
     p_name = strstr(desc, "parentFileNameHint");
@@ -296,10 +298,10 @@ static int vmdk_parent_open(BlockDriverState *bs)
         p_name += sizeof("parentFileNameHint") + 1;
         end_name = strchr(p_name, '\"');
         if (end_name == NULL) {
-            return -1;
+            return -EINVAL;
         }
         if ((end_name - p_name) > sizeof(bs->backing_file) - 1) {
-            return -1;
+            return -EINVAL;
         }
 
         pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
@@ -629,9 +631,10 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
     }
 
     /* try to open parent images, if exist */
-    if (vmdk_parent_open(bs)) {
+    ret = vmdk_parent_open(bs);
+    if (ret) {
         vmdk_free_extents(bs);
-        return -EINVAL;
+        return ret;
     }
     s->parent_cid = vmdk_read_cid(bs, 1);
     return 0;
commit 34d4260e1846d69d7241f690534e3dd4b3e6fd5b
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Oct 20 16:37:26 2011 +0200

    pc: Fix floppy drives with if=none
    
    Commit 63ffb564 broke floppy devices specified on the command line like
    -drive file=...,if=none,id=floppy -global isa-fdc.driveA=floppy because it
    relies on drive_get() which works only with -fda/-drive if=floppy.
    
    This patch resembles what we're already doing for IDE, i.e. remember the floppy
    device that was created and use that to extract the BlockDriverStates where
    needed.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>

diff --git a/hw/fdc.c b/hw/fdc.c
index f8af2de..ecaad09 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1947,6 +1947,18 @@ static int sun4m_fdc_init1(SysBusDevice *dev)
     return fdctrl_init_common(fdctrl);
 }
 
+void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev)
+{
+    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
+    FDCtrl *fdctrl = &isa->state;
+    int i;
+
+    for (i = 0; i < MAX_FD; i++) {
+        bs[i] = fdctrl->drives[i].bs;
+    }
+}
+
+
 static const VMStateDescription vmstate_isa_fdc ={
     .name = "fdc",
     .version_id = 2,
diff --git a/hw/fdc.h b/hw/fdc.h
index 09f73c6..506feb6 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -7,14 +7,15 @@
 /* fdc.c */
 #define MAX_FD 2
 
-static inline void fdctrl_init_isa(DriveInfo **fds)
+static inline ISADevice *fdctrl_init_isa(DriveInfo **fds)
 {
     ISADevice *dev;
 
     dev = isa_try_create("isa-fdc");
     if (!dev) {
-        return;
+        return NULL;
     }
+
     if (fds[0]) {
         qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
     }
@@ -22,10 +23,14 @@ static inline void fdctrl_init_isa(DriveInfo **fds)
         qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
     }
     qdev_init_nofail(&dev->qdev);
+
+    return dev;
 }
 
 void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
                         target_phys_addr_t mmio_base, DriveInfo **fds);
 void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
                        DriveInfo **fds, qemu_irq *fdc_tc);
+void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev);
+
 #endif
diff --git a/hw/pc.c b/hw/pc.c
index f0802b7..eb4c2d8 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -331,12 +331,12 @@ static void pc_cmos_init_late(void *opaque)
 
 void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
                   const char *boot_device,
-                  BusState *idebus0, BusState *idebus1,
+                  ISADevice *floppy, BusState *idebus0, BusState *idebus1,
                   ISADevice *s)
 {
     int val, nb, nb_heads, max_track, last_sect, i;
     FDriveType fd_type[2];
-    DriveInfo *fd[2];
+    BlockDriverState *fd[MAX_FD];
     static pc_cmos_init_late_arg arg;
 
     /* various important CMOS locations needed by PC/Bochs bios */
@@ -378,14 +378,16 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
     }
 
     /* floppy type */
-    for (i = 0; i < 2; i++) {
-        fd[i] = drive_get(IF_FLOPPY, 0, i);
-        if (fd[i] && bdrv_is_inserted(fd[i]->bdrv)) {
-            bdrv_get_floppy_geometry_hint(fd[i]->bdrv, &nb_heads, &max_track,
-                                          &last_sect, FDRIVE_DRV_NONE,
-                                          &fd_type[i]);
-        } else {
-            fd_type[i] = FDRIVE_DRV_NONE;
+    if (floppy) {
+        fdc_get_bs(fd, floppy);
+        for (i = 0; i < 2; i++) {
+            if (fd[i] && bdrv_is_inserted(fd[i])) {
+                bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track,
+                                              &last_sect, FDRIVE_DRV_NONE,
+                                              &fd_type[i]);
+            } else {
+                fd_type[i] = FDRIVE_DRV_NONE;
+            }
         }
     }
     val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
@@ -1124,6 +1126,7 @@ static void cpu_request_exit(void *opaque, int irq, int level)
 
 void pc_basic_device_init(qemu_irq *gsi,
                           ISADevice **rtc_state,
+                          ISADevice **floppy,
                           bool no_vmport)
 {
     int i;
@@ -1188,7 +1191,7 @@ void pc_basic_device_init(qemu_irq *gsi,
     for(i = 0; i < MAX_FD; i++) {
         fd[i] = drive_get(IF_FLOPPY, 0, i);
     }
-    fdctrl_init_isa(fd);
+    *floppy = fdctrl_init_isa(fd);
 }
 
 void pc_pci_device_init(PCIBus *pci_bus)
diff --git a/hw/pc.h b/hw/pc.h
index b8ad9a3..4515006 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -142,11 +142,12 @@ qemu_irq *pc_allocate_cpu_irq(void);
 void pc_vga_init(PCIBus *pci_bus);
 void pc_basic_device_init(qemu_irq *gsi,
                           ISADevice **rtc_state,
+                          ISADevice **floppy,
                           bool no_vmport);
 void pc_init_ne2k_isa(NICInfo *nd);
 void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
                   const char *boot_device,
-                  BusState *ide0, BusState *ide1,
+                  ISADevice *floppy, BusState *ide0, BusState *ide1,
                   ISADevice *s);
 void pc_pci_device_init(PCIBus *pci_bus);
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index c89042f..8c7f2b7 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -95,6 +95,7 @@ static void pc_init1(MemoryRegion *system_memory,
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     BusState *idebus[MAX_IDE_BUS];
     ISADevice *rtc_state;
+    ISADevice *floppy;
     MemoryRegion *ram_memory;
     MemoryRegion *pci_memory;
     MemoryRegion *rom_memory;
@@ -174,7 +175,7 @@ static void pc_init1(MemoryRegion *system_memory,
     }
 
     /* init basic PC hardware */
-    pc_basic_device_init(gsi, &rtc_state, xen_enabled());
+    pc_basic_device_init(gsi, &rtc_state, &floppy, xen_enabled());
 
     for(i = 0; i < nb_nics; i++) {
         NICInfo *nd = &nd_table[i];
@@ -207,7 +208,7 @@ static void pc_init1(MemoryRegion *system_memory,
     audio_init(gsi, pci_enabled ? pci_bus : NULL);
 
     pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
-                 idebus[0], idebus[1], rtc_state);
+                 floppy, idebus[0], idebus[1], rtc_state);
 
     if (pci_enabled && usb_enabled) {
         usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
commit 8f1efd00c4b2aa2b75fd20b5ee592ed47d33d5a7
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Oct 18 17:12:44 2011 +0200

    qcow2: Fix bdrv_write_compressed error handling
    
    If during allocation of compressed clusters the cluster was already allocated
    uncompressed, fail and properly release the l2_table (the latter avoids a
    failed assertion).
    
    While at it, make it return some real error numbers instead of -1.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 2f76311..f4e049f 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -568,8 +568,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
     }
 
     cluster_offset = be64_to_cpu(l2_table[l2_index]);
-    if (cluster_offset & QCOW_OFLAG_COPIED)
-        return cluster_offset & ~QCOW_OFLAG_COPIED;
+    if (cluster_offset & QCOW_OFLAG_COPIED) {
+        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+        return 0;
+    }
 
     if (cluster_offset)
         qcow2_free_any_clusters(bs, cluster_offset, 1);
diff --git a/block/qcow2.c b/block/qcow2.c
index 4dc980c..91f4f04 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1053,8 +1053,8 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
                        Z_DEFLATED, -12,
                        9, Z_DEFAULT_STRATEGY);
     if (ret != 0) {
-        g_free(out_buf);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
 
     strm.avail_in = s->cluster_size;
@@ -1064,9 +1064,9 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
 
     ret = deflate(&strm, Z_FINISH);
     if (ret != Z_STREAM_END && ret != Z_OK) {
-        g_free(out_buf);
         deflateEnd(&strm);
-        return -1;
+        ret = -EINVAL;
+        goto fail;
     }
     out_len = strm.next_out - out_buf;
 
@@ -1074,22 +1074,29 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
 
     if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
         /* could not compress: write normal cluster */
-        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+        if (ret < 0) {
+            goto fail;
+        }
     } else {
         cluster_offset = qcow2_alloc_compressed_cluster_offset(bs,
             sector_num << 9, out_len);
-        if (!cluster_offset)
-            return -1;
+        if (!cluster_offset) {
+            ret = -EIO;
+            goto fail;
+        }
         cluster_offset &= s->cluster_offset_mask;
         BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
-        if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
-            g_free(out_buf);
-            return -1;
+        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
+        if (ret < 0) {
+            goto fail;
         }
     }
 
+    ret = 0;
+fail:
     g_free(out_buf);
-    return 0;
+    return ret;
 }
 
 static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs,
commit 41521fa4a60344eaad433db1ab4597ba6bf78f69
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Oct 18 16:19:42 2011 +0200

    qemu-img: Don't allow preallocation and compression at the same time
    
    Only qcow and qcow2 can do compression at all, and they require unallocated
    clusters when writing the compressed data.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/qemu-img.c b/qemu-img.c
index 6a39731..86127f0 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -824,6 +824,8 @@ static int img_convert(int argc, char **argv)
     if (compress) {
         QEMUOptionParameter *encryption =
             get_option_parameter(param, BLOCK_OPT_ENCRYPT);
+        QEMUOptionParameter *preallocation =
+            get_option_parameter(param, BLOCK_OPT_PREALLOC);
 
         if (!drv->bdrv_write_compressed) {
             error_report("Compression not supported for this file format");
@@ -837,6 +839,15 @@ static int img_convert(int argc, char **argv)
             ret = -1;
             goto out;
         }
+
+        if (preallocation && preallocation->value.s
+            && strcmp(preallocation->value.s, "off"))
+        {
+            error_report("Compression and preallocation not supported at "
+                         "the same time");
+            ret = -1;
+            goto out;
+        }
     }
 
     /* Create the new image */
commit a18e67f5f9dc1e5e9a293a946666e2e74daa1c91
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Oct 18 16:41:45 2011 +0200

    fdc: Fix floppy port I/O
    
    The floppy device was broken by commit 212ec7ba (fdc: Convert to
    isa_register_portio_list). While the old interface provided the port number
    relative to the floppy drive's io_base, the new one provides the real port
    number, so we need to apply a bitmask now to get the register number.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/fdc.c b/hw/fdc.c
index 4b06e04..f8af2de 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -434,6 +434,7 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg)
     FDCtrl *fdctrl = opaque;
     uint32_t retval;
 
+    reg &= 7;
     switch (reg) {
     case FD_REG_SRA:
         retval = fdctrl_read_statusA(fdctrl);
@@ -471,6 +472,7 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
 
     FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
 
+    reg &= 7;
     switch (reg) {
     case FD_REG_DOR:
         fdctrl_write_dor(fdctrl, value);
commit 4265d620c5a91b58c757ce76fa2b0fff86fa1df1
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Oct 17 12:32:14 2011 +0200

    block: add bdrv_co_discard and bdrv_aio_discard support
    
    This similarly adds support for coroutine and asynchronous discard.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 7b8b14d..28508f2 100644
--- a/block.c
+++ b/block.c
@@ -1768,17 +1768,6 @@ int bdrv_has_zero_init(BlockDriverState *bs)
     return 1;
 }
 
-int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
-{
-    if (!bs->drv) {
-        return -ENOMEDIUM;
-    }
-    if (!bs->drv->bdrv_discard) {
-        return 0;
-    }
-    return bs->drv->bdrv_discard(bs, sector_num, nb_sectors);
-}
-
 /*
  * Returns true iff the specified sector is present in the disk image. Drivers
  * not implementing the functionality are assumed to not support backing files,
@@ -2754,6 +2743,34 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
     return &acb->common;
 }
 
+static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
+{
+    BlockDriverAIOCBCoroutine *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+
+    acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors);
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
+    qemu_bh_schedule(acb->bh);
+}
+
+BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
+
+    trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
+
+    acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
+    acb->req.sector = sector_num;
+    acb->req.nb_sectors = nb_sectors;
+    co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
+    qemu_coroutine_enter(co, acb);
+
+    return &acb->common;
+}
+
 void bdrv_init(void)
 {
     module_call_init(MODULE_INIT_BLOCK);
@@ -2915,6 +2932,69 @@ int bdrv_flush(BlockDriverState *bs)
     return rwco.ret;
 }
 
+static void coroutine_fn bdrv_discard_co_entry(void *opaque)
+{
+    RwCo *rwco = opaque;
+
+    rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors);
+}
+
+int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
+                                 int nb_sectors)
+{
+    if (!bs->drv) {
+        return -ENOMEDIUM;
+    } else if (bdrv_check_request(bs, sector_num, nb_sectors)) {
+        return -EIO;
+    } else if (bs->read_only) {
+        return -EROFS;
+    } else if (bs->drv->bdrv_co_discard) {
+        return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
+    } else if (bs->drv->bdrv_aio_discard) {
+        BlockDriverAIOCB *acb;
+        CoroutineIOCompletion co = {
+            .coroutine = qemu_coroutine_self(),
+        };
+
+        acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors,
+                                        bdrv_co_io_em_complete, &co);
+        if (acb == NULL) {
+            return -EIO;
+        } else {
+            qemu_coroutine_yield();
+            return co.ret;
+        }
+    } else if (bs->drv->bdrv_discard) {
+        return bs->drv->bdrv_discard(bs, sector_num, nb_sectors);
+    } else {
+        return 0;
+    }
+}
+
+int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+    Coroutine *co;
+    RwCo rwco = {
+        .bs = bs,
+        .sector_num = sector_num,
+        .nb_sectors = nb_sectors,
+        .ret = NOT_DONE,
+    };
+
+    if (qemu_in_coroutine()) {
+        /* Fast-path if already in coroutine context */
+        bdrv_discard_co_entry(&rwco);
+    } else {
+        co = qemu_coroutine_create(bdrv_discard_co_entry);
+        qemu_coroutine_enter(co, &rwco);
+        while (rwco.ret == NOT_DONE) {
+            qemu_aio_wait();
+        }
+    }
+
+    return rwco.ret;
+}
+
 /**************************************************************/
 /* removable device support */
 
diff --git a/block.h b/block.h
index 65c5166..5a042c9 100644
--- a/block.h
+++ b/block.h
@@ -166,6 +166,9 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                   BlockDriverCompletionFunc *cb, void *opaque);
 BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
                                  BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
+                                   int64_t sector_num, int nb_sectors,
+                                   BlockDriverCompletionFunc *cb, void *opaque);
 void bdrv_aio_cancel(BlockDriverAIOCB *acb);
 
 typedef struct BlockRequest {
@@ -196,6 +199,7 @@ void bdrv_flush_all(void);
 void bdrv_close_all(void);
 
 int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
+int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
 int bdrv_has_zero_init(BlockDriverState *bs);
 int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
                       int *pnum);
diff --git a/block/raw.c b/block/raw.c
index 39a3a9a..33cc471 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -45,9 +45,10 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
    return 1; /* everything can be opened as raw image */
 }
 
-static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+static int coroutine_fn raw_co_discard(BlockDriverState *bs,
+                                       int64_t sector_num, int nb_sectors)
 {
-    return bdrv_discard(bs->file, sector_num, nb_sectors);
+    return bdrv_co_discard(bs->file, sector_num, nb_sectors);
 }
 
 static int raw_is_inserted(BlockDriverState *bs)
@@ -109,15 +110,16 @@ static BlockDriver bdrv_raw = {
 
     .bdrv_open          = raw_open,
     .bdrv_close         = raw_close,
+
     .bdrv_co_readv      = raw_co_readv,
     .bdrv_co_writev     = raw_co_writev,
     .bdrv_co_flush      = raw_co_flush,
+    .bdrv_co_discard    = raw_co_discard,
+
     .bdrv_probe         = raw_probe,
     .bdrv_getlength     = raw_getlength,
     .bdrv_truncate      = raw_truncate,
 
-    .bdrv_discard       = raw_discard,
-
     .bdrv_is_inserted   = raw_is_inserted,
     .bdrv_media_changed = raw_media_changed,
     .bdrv_eject         = raw_eject,
diff --git a/block_int.h b/block_int.h
index 9cb536d..384598f 100644
--- a/block_int.h
+++ b/block_int.h
@@ -63,6 +63,8 @@ struct BlockDriver {
     void (*bdrv_close)(BlockDriverState *bs);
     int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
     int (*bdrv_flush)(BlockDriverState *bs);
+    int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
+                        int nb_sectors);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
@@ -76,14 +78,17 @@ struct BlockDriver {
         BlockDriverCompletionFunc *cb, void *opaque);
     BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque);
-    int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
-                        int nb_sectors);
+    BlockDriverAIOCB *(*bdrv_aio_discard)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
 
     int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
     int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
     int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
+    int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors);
 
     int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
         int num_reqs);
diff --git a/trace-events b/trace-events
index 7f9cec4..49ac1c1 100644
--- a/trace-events
+++ b/trace-events
@@ -61,6 +61,7 @@ multiwrite_cb(void *mcb, int ret) "mcb %p ret %d"
 bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d"
 bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p"
 bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
+bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
 bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
commit 6f6dc6565e2b65ec8c0cf47622b4f5f1468d194e
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Oct 17 12:32:13 2011 +0200

    block: drop redundant bdrv_flush implementation
    
    Block drivers now only need to provide either of .bdrv_co_flush,
    .bdrv_aio_flush() or for legacy drivers .bdrv_flush().  Remove
    the redundant .bdrv_flush() implementations.
    
    [Paolo Bonzini: change raw driver to bdrv_co_flush]
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/blkdebug.c b/block/blkdebug.c
index b3c5d42..9b88535 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -397,11 +397,6 @@ static void blkdebug_close(BlockDriverState *bs)
     }
 }
 
-static int blkdebug_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
-}
-
 static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
     BlockDriverCompletionFunc *cb, void *opaque)
 {
@@ -454,7 +449,6 @@ static BlockDriver bdrv_blkdebug = {
 
     .bdrv_file_open     = blkdebug_open,
     .bdrv_close         = blkdebug_close,
-    .bdrv_flush         = blkdebug_flush,
 
     .bdrv_aio_readv     = blkdebug_aio_readv,
     .bdrv_aio_writev    = blkdebug_aio_writev,
diff --git a/block/blkverify.c b/block/blkverify.c
index c7522b4..483f3b3 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -116,14 +116,6 @@ static void blkverify_close(BlockDriverState *bs)
     s->test_file = NULL;
 }
 
-static int blkverify_flush(BlockDriverState *bs)
-{
-    BDRVBlkverifyState *s = bs->opaque;
-
-    /* Only flush test file, the raw file is not important */
-    return bdrv_flush(s->test_file);
-}
-
 static int64_t blkverify_getlength(BlockDriverState *bs)
 {
     BDRVBlkverifyState *s = bs->opaque;
@@ -368,7 +360,6 @@ static BlockDriver bdrv_blkverify = {
 
     .bdrv_file_open     = blkverify_open,
     .bdrv_close         = blkverify_close,
-    .bdrv_flush         = blkverify_flush,
 
     .bdrv_aio_readv     = blkverify_aio_readv,
     .bdrv_aio_writev    = blkverify_aio_writev,
diff --git a/block/qcow.c b/block/qcow.c
index eba5a04..f93e3eb 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -781,11 +781,6 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
-static int qcow_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
-}
-
 static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
@@ -826,7 +821,6 @@ static BlockDriver bdrv_qcow = {
     .bdrv_open		= qcow_open,
     .bdrv_close		= qcow_close,
     .bdrv_create	= qcow_create,
-    .bdrv_flush		= qcow_flush,
     .bdrv_is_allocated	= qcow_is_allocated,
     .bdrv_set_key	= qcow_set_key,
     .bdrv_make_empty	= qcow_make_empty,
diff --git a/block/qcow2.c b/block/qcow2.c
index 510ff68..4dc980c 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1092,24 +1092,6 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
-static int qcow2_flush(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    int ret;
-
-    ret = qcow2_cache_flush(bs, s->l2_table_cache);
-    if (ret < 0) {
-        return ret;
-    }
-
-    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
-    if (ret < 0) {
-        return ret;
-    }
-
-    return bdrv_flush(bs->file);
-}
-
 static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs,
                                          BlockDriverCompletionFunc *cb,
                                          void *opaque)
@@ -1242,7 +1224,6 @@ static BlockDriver bdrv_qcow2 = {
     .bdrv_open          = qcow2_open,
     .bdrv_close         = qcow2_close,
     .bdrv_create        = qcow2_create,
-    .bdrv_flush         = qcow2_flush,
     .bdrv_is_allocated  = qcow2_is_allocated,
     .bdrv_set_key       = qcow2_set_key,
     .bdrv_make_empty    = qcow2_make_empty,
diff --git a/block/qed.c b/block/qed.c
index e87dc4d..2e06992 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -533,11 +533,6 @@ static void bdrv_qed_close(BlockDriverState *bs)
     qemu_vfree(s->l1_table);
 }
 
-static int bdrv_qed_flush(BlockDriverState *bs)
-{
-    return bdrv_flush(bs->file);
-}
-
 static int qed_create(const char *filename, uint32_t cluster_size,
                       uint64_t image_size, uint32_t table_size,
                       const char *backing_file, const char *backing_fmt)
@@ -1479,7 +1474,6 @@ static BlockDriver bdrv_qed = {
     .bdrv_open                = bdrv_qed_open,
     .bdrv_close               = bdrv_qed_close,
     .bdrv_create              = bdrv_qed_create,
-    .bdrv_flush               = bdrv_qed_flush,
     .bdrv_is_allocated        = bdrv_qed_is_allocated,
     .bdrv_make_empty          = bdrv_qed_make_empty,
     .bdrv_aio_readv           = bdrv_qed_aio_readv,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index c7f5544..afcb4c1 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -583,19 +583,6 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
     return result;
 }
 
-static int raw_flush(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    ret = qemu_fdatasync(s->fd);
-    if (ret < 0) {
-        return -errno;
-    }
-
-    return 0;
-}
-
 #ifdef CONFIG_XFS
 static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
 {
@@ -645,7 +632,6 @@ static BlockDriver bdrv_file = {
     .bdrv_file_open = raw_open,
     .bdrv_close = raw_close,
     .bdrv_create = raw_create,
-    .bdrv_flush = raw_flush,
     .bdrv_discard = raw_discard,
 
     .bdrv_aio_readv = raw_aio_readv,
@@ -915,7 +901,6 @@ static BlockDriver bdrv_host_device = {
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv	= raw_aio_readv,
     .bdrv_aio_writev	= raw_aio_writev,
@@ -1035,7 +1020,6 @@ static BlockDriver bdrv_host_floppy = {
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
@@ -1135,7 +1119,6 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
@@ -1255,7 +1238,6 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_create        = hdev_create,
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
-    .bdrv_flush         = raw_flush,
 
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
diff --git a/block/raw.c b/block/raw.c
index 5ca606b..39a3a9a 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -25,15 +25,9 @@ static void raw_close(BlockDriverState *bs)
 {
 }
 
-static int raw_flush(BlockDriverState *bs)
+static int coroutine_fn raw_co_flush(BlockDriverState *bs)
 {
-    return bdrv_flush(bs->file);
-}
-
-static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
-    BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_co_flush(bs->file);
 }
 
 static int64_t raw_getlength(BlockDriverState *bs)
@@ -117,12 +111,11 @@ static BlockDriver bdrv_raw = {
     .bdrv_close         = raw_close,
     .bdrv_co_readv      = raw_co_readv,
     .bdrv_co_writev     = raw_co_writev,
-    .bdrv_flush         = raw_flush,
+    .bdrv_co_flush      = raw_co_flush,
     .bdrv_probe         = raw_probe,
     .bdrv_getlength     = raw_getlength,
     .bdrv_truncate      = raw_truncate,
 
-    .bdrv_aio_flush     = raw_aio_flush,
     .bdrv_discard       = raw_discard,
 
     .bdrv_is_inserted   = raw_is_inserted,
commit 07f076157475e1a8ea454e304e0ea5496d05b539
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Oct 17 12:32:12 2011 +0200

    block: unify flush implementations
    
    Add coroutine support for flush and apply the same emulation that
    we already do for read/write.  bdrv_aio_flush is simplified to always
    go through a coroutine.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 7184a0f..7b8b14d 100644
--- a/block.c
+++ b/block.c
@@ -53,17 +53,12 @@ static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
 static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
-static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque);
-static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque);
 static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
                                          int64_t sector_num, int nb_sectors,
                                          QEMUIOVector *iov);
 static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
                                          int64_t sector_num, int nb_sectors,
                                          QEMUIOVector *iov);
-static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs);
 static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
 static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
@@ -203,9 +198,6 @@ void bdrv_register(BlockDriver *bdrv)
         }
     }
 
-    if (!bdrv->bdrv_aio_flush)
-        bdrv->bdrv_aio_flush = bdrv_aio_flush_em;
-
     QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
 }
 
@@ -1027,11 +1019,6 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
                                    nb_sectors * BDRV_SECTOR_SIZE);
 }
 
-static inline bool bdrv_has_async_flush(BlockDriver *drv)
-{
-    return drv->bdrv_aio_flush != bdrv_aio_flush_em;
-}
-
 typedef struct RwCo {
     BlockDriverState *bs;
     int64_t sector_num;
@@ -1759,33 +1746,6 @@ const char *bdrv_get_device_name(BlockDriverState *bs)
     return bs->device_name;
 }
 
-int bdrv_flush(BlockDriverState *bs)
-{
-    if (bs->open_flags & BDRV_O_NO_FLUSH) {
-        return 0;
-    }
-
-    if (bs->drv && bdrv_has_async_flush(bs->drv) && qemu_in_coroutine()) {
-        return bdrv_co_flush_em(bs);
-    }
-
-    if (bs->drv && bs->drv->bdrv_flush) {
-        return bs->drv->bdrv_flush(bs);
-    }
-
-    /*
-     * Some block drivers always operate in either writethrough or unsafe mode
-     * and don't support bdrv_flush therefore. Usually qemu doesn't know how
-     * the server works (because the behaviour is hardcoded or depends on
-     * server-side configuration), so we can't ensure that everything is safe
-     * on disk. Returning an error doesn't work because that would break guests
-     * even if the server operates in writethrough mode.
-     *
-     * Let's hope the user knows what he's doing.
-     */
-    return 0;
-}
-
 void bdrv_flush_all(void)
 {
     BlockDriverState *bs;
@@ -2610,22 +2570,6 @@ fail:
     return -1;
 }
 
-BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BlockDriver *drv = bs->drv;
-
-    trace_bdrv_aio_flush(bs, opaque);
-
-    if (bs->open_flags & BDRV_O_NO_FLUSH) {
-        return bdrv_aio_noop_em(bs, cb, opaque);
-    }
-
-    if (!drv)
-        return NULL;
-    return drv->bdrv_aio_flush(bs, cb, opaque);
-}
-
 void bdrv_aio_cancel(BlockDriverAIOCB *acb)
 {
     acb->pool->cancel(acb);
@@ -2785,41 +2729,28 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
     return &acb->common;
 }
 
-static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)
 {
-    BlockDriverAIOCBSync *acb;
-
-    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
-    acb->is_write = 1; /* don't bounce in the completion hadler */
-    acb->qiov = NULL;
-    acb->bounce = NULL;
-    acb->ret = 0;
-
-    if (!acb->bh)
-        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+    BlockDriverAIOCBCoroutine *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
 
-    bdrv_flush(bs);
+    acb->req.error = bdrv_co_flush(bs);
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
     qemu_bh_schedule(acb->bh);
-    return &acb->common;
 }
 
-static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
-    BlockDriverAIOCBSync *acb;
+    trace_bdrv_aio_flush(bs, opaque);
 
-    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
-    acb->is_write = 1; /* don't bounce in the completion handler */
-    acb->qiov = NULL;
-    acb->bounce = NULL;
-    acb->ret = 0;
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
 
-    if (!acb->bh) {
-        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
-    }
+    acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
+    co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
+    qemu_coroutine_enter(co, acb);
 
-    qemu_bh_schedule(acb->bh);
     return &acb->common;
 }
 
@@ -2916,19 +2847,72 @@ static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
     return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true);
 }
 
-static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs)
+static void coroutine_fn bdrv_flush_co_entry(void *opaque)
 {
-    CoroutineIOCompletion co = {
-        .coroutine = qemu_coroutine_self(),
+    RwCo *rwco = opaque;
+
+    rwco->ret = bdrv_co_flush(rwco->bs);
+}
+
+int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
+{
+    if (bs->open_flags & BDRV_O_NO_FLUSH) {
+        return 0;
+    } else if (!bs->drv) {
+        return 0;
+    } else if (bs->drv->bdrv_co_flush) {
+        return bs->drv->bdrv_co_flush(bs);
+    } else if (bs->drv->bdrv_aio_flush) {
+        BlockDriverAIOCB *acb;
+        CoroutineIOCompletion co = {
+            .coroutine = qemu_coroutine_self(),
+        };
+
+        acb = bs->drv->bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
+        if (acb == NULL) {
+            return -EIO;
+        } else {
+            qemu_coroutine_yield();
+            return co.ret;
+        }
+    } else if (bs->drv->bdrv_flush) {
+        return bs->drv->bdrv_flush(bs);
+    } else {
+        /*
+         * Some block drivers always operate in either writethrough or unsafe
+         * mode and don't support bdrv_flush therefore. Usually qemu doesn't
+         * know how the server works (because the behaviour is hardcoded or
+         * depends on server-side configuration), so we can't ensure that
+         * everything is safe on disk. Returning an error doesn't work because
+         * that would break guests even if the server operates in writethrough
+         * mode.
+         *
+         * Let's hope the user knows what he's doing.
+         */
+        return 0;
+    }
+}
+
+int bdrv_flush(BlockDriverState *bs)
+{
+    Coroutine *co;
+    RwCo rwco = {
+        .bs = bs,
+        .ret = NOT_DONE,
     };
-    BlockDriverAIOCB *acb;
 
-    acb = bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
-    if (!acb) {
-        return -EIO;
+    if (qemu_in_coroutine()) {
+        /* Fast-path if already in coroutine context */
+        bdrv_flush_co_entry(&rwco);
+    } else {
+        co = qemu_coroutine_create(bdrv_flush_co_entry);
+        qemu_coroutine_enter(co, &rwco);
+        while (rwco.ret == NOT_DONE) {
+            qemu_aio_wait();
+        }
     }
-    qemu_coroutine_yield();
-    return co.ret;
+
+    return rwco.ret;
 }
 
 /**************************************************************/
diff --git a/block.h b/block.h
index e77988e..65c5166 100644
--- a/block.h
+++ b/block.h
@@ -191,6 +191,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
 
 /* Ensure contents are flushed to disk.  */
 int bdrv_flush(BlockDriverState *bs);
+int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
 void bdrv_flush_all(void);
 void bdrv_close_all(void);
 
diff --git a/block_int.h b/block_int.h
index f2f4f2d..9cb536d 100644
--- a/block_int.h
+++ b/block_int.h
@@ -83,6 +83,7 @@ struct BlockDriver {
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
     int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
 
     int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
         int num_reqs);
commit 5cce43bb288ea22ef1c3faa77f2c5e8aa04b6236
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Oct 21 12:16:44 2011 +0200

    xen_disk: Always set feature-barrier = 1
    
    The synchronous .bdrv_flush callback doesn't exist any more and a device really
    shouldn't poke into the block layer internals anyway. All drivers are supposed
    to have a correctly working bdrv_flush, so let's just hard-code this.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 8a9fac4..286bbac 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -620,7 +620,7 @@ static void blk_alloc(struct XenDevice *xendev)
 static int blk_init(struct XenDevice *xendev)
 {
     struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-    int index, qflags, have_barriers, info = 0;
+    int index, qflags, info = 0;
 
     /* read xenstore entries */
     if (blkdev->params == NULL) {
@@ -706,7 +706,6 @@ static int blk_init(struct XenDevice *xendev)
                       blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
         blkdev->file_size = 0;
     }
-    have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0;
 
     xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
                   " size %" PRId64 " (%" PRId64 " MB)\n",
@@ -714,7 +713,7 @@ static int blk_init(struct XenDevice *xendev)
                   blkdev->file_size, blkdev->file_size >> 20);
 
     /* fill info */
-    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers);
+    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", 1);
     xenstore_write_be_int(&blkdev->xendev, "info",            info);
     xenstore_write_be_int(&blkdev->xendev, "sector-size",     blkdev->file_blk);
     xenstore_write_be_int(&blkdev->xendev, "sectors",
commit b1b1dad31f3a092e046b09795f4476705c4e564e
Author: Alex Jia <ajia at redhat.com>
Date:   Wed Sep 28 14:57:01 2011 +0800

    fix memory leak in aio_write_f
    
    Haven't released memory of 'ctx' before return.
    
    Signed-off-by: Alex Jia <ajia at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-io.c b/qemu-io.c
index e91af37..c45a413 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1248,6 +1248,7 @@ static int aio_write_f(int argc, char **argv)
         case 'P':
             pattern = parse_pattern(optarg);
             if (pattern < 0) {
+                free(ctx);
                 return 0;
             }
             break;
commit 35246a6825121f3881b8540beb731d582aa6d697
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Oct 14 10:41:29 2011 +0200

    block: rename bdrv_co_rw_bh
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 9873b57..7184a0f 100644
--- a/block.c
+++ b/block.c
@@ -2735,7 +2735,7 @@ static AIOPool bdrv_em_co_aio_pool = {
     .cancel             = bdrv_aio_co_cancel_em,
 };
 
-static void bdrv_co_rw_bh(void *opaque)
+static void bdrv_co_em_bh(void *opaque)
 {
     BlockDriverAIOCBCoroutine *acb = opaque;
 
@@ -2758,7 +2758,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
             acb->req.nb_sectors, acb->req.qiov);
     }
 
-    acb->bh = qemu_bh_new(bdrv_co_rw_bh, acb);
+    acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
     qemu_bh_schedule(acb->bh);
 }
 
commit 154b9a0cbd67be53afcb45ae84a240add8c6cb67
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 5 09:17:32 2011 +0200

    add socket_set_block
    
    Cc: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/oslib-posix.c b/oslib-posix.c
index a304fb0..dbc8ee8 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -103,6 +103,13 @@ void qemu_vfree(void *ptr)
     free(ptr);
 }
 
+void socket_set_block(int fd)
+{
+    int f;
+    f = fcntl(fd, F_GETFL);
+    fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
+}
+
 void socket_set_nonblock(int fd)
 {
     int f;
diff --git a/oslib-win32.c b/oslib-win32.c
index 5f0759f..5e3de7d 100644
--- a/oslib-win32.c
+++ b/oslib-win32.c
@@ -73,6 +73,12 @@ void qemu_vfree(void *ptr)
     VirtualFree(ptr, 0, MEM_RELEASE);
 }
 
+void socket_set_block(int fd)
+{
+    unsigned long opt = 0;
+    ioctlsocket(fd, FIONBIO, &opt);
+}
+
 void socket_set_nonblock(int fd)
 {
     unsigned long opt = 1;
diff --git a/qemu_socket.h b/qemu_socket.h
index 180e4db..9e32fac 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -35,6 +35,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
 /* misc helpers */
 int qemu_socket(int domain, int type, int protocol);
 int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+void socket_set_block(int fd);
 void socket_set_nonblock(int fd);
 int send_all(int fd, const void *buf, int len1);
 
commit d8716b41b9bd2c7ce6fe36ab388de534ce81a69a
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Oct 5 09:17:31 2011 +0200

    sheepdog: add coroutine_fn markers
    
    This makes the following patch easier to review.
    
    Cc: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/sheepdog.c b/block/sheepdog.c
index ae857e2..9f80609 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -396,7 +396,7 @@ static inline int free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
     return !QLIST_EMPTY(&acb->aioreq_head);
 }
 
-static void sd_finish_aiocb(SheepdogAIOCB *acb)
+static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb)
 {
     if (!acb->canceled) {
         qemu_coroutine_enter(acb->coroutine, NULL);
@@ -735,7 +735,7 @@ out:
     return ret;
 }
 
-static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
+static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
                            struct iovec *iov, int niov, int create,
                            enum AIOCBState aiocb_type);
 
@@ -743,7 +743,7 @@ static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
  * This function searchs pending requests to the object `oid', and
  * sends them.
  */
-static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
+static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
 {
     AIOReq *aio_req, *next;
     SheepdogAIOCB *acb;
@@ -777,7 +777,7 @@ static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id)
  * This function is registered as a fd handler, and called from the
  * main loop when s->fd is ready for reading responses.
  */
-static void aio_read_response(void *opaque)
+static void coroutine_fn aio_read_response(void *opaque)
 {
     SheepdogObjRsp rsp;
     BDRVSheepdogState *s = opaque;
@@ -1064,7 +1064,7 @@ out:
     return ret;
 }
 
-static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
+static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
                            struct iovec *iov, int niov, int create,
                            enum AIOCBState aiocb_type)
 {
@@ -1517,7 +1517,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
  * update metadata, this sends a write request to the vdi object.
  * Otherwise, this switches back to sd_co_readv/writev.
  */
-static void sd_write_done(SheepdogAIOCB *acb)
+static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
 {
     int ret;
     BDRVSheepdogState *s = acb->common.bs->opaque;
@@ -1615,7 +1615,7 @@ out:
  * Returns 1 when we need to wait a response, 0 when there is no sent
  * request and -errno in error cases.
  */
-static int sd_co_rw_vector(void *p)
+static int coroutine_fn sd_co_rw_vector(void *p)
 {
     SheepdogAIOCB *acb = p;
     int ret = 0;
commit 12b1de3a3f026a2e27993b60749122b02509533c
Author: Andreas Färber <afaerber at suse.de>
Date:   Mon Oct 10 02:52:28 2011 +0000

    target-arm: Fix use of free() in cpu_arm_close()
    
    env is allocated in cpu_arm_init() with g_malloc0(), so free with g_free().
    
    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 eddb923..97af4d0 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -475,7 +475,7 @@ static uint32_t cpu_arm_find_by_name(const char *name)
 
 void cpu_arm_close(CPUARMState *env)
 {
-    free(env);
+    g_free(env);
 }
 
 uint32_t cpsr_read(CPUARMState *env)
commit 1518025641c6c067518c871be7f72a524dc68711
Author: Dmitry Koshelev <karaghiozis at gmail.com>
Date:   Wed Oct 19 16:14:07 2011 +0000

    target-arm/machine.c: Restore VFP registers correctly
    
    Fix the restoring of VFP registers on vmload.
    
    Signed-off-by: Dmitry Koshelev <karaghiozis at gmail.com>
    Reviewed-by: Juan Quintela <quintela at redhat.com>
    [peter.maydell: improved commit message a little]
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/machine.c b/target-arm/machine.c
index 7d4fc54..aaee9b9 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -189,7 +189,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         env->vfp.vec_stride = qemu_get_be32(f);
 
         if (arm_feature(env, ARM_FEATURE_VFP3)) {
-            for (i = 0;  i < 16; i++) {
+            for (i = 16;  i < 32; i++) {
                 CPU_DoubleU u;
                 u.l.upper = qemu_get_be32(f);
                 u.l.lower = qemu_get_be32(f);
commit da97f52cb35ccf72a4a3d745926ee5e3c263ed07
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Oct 19 16:14:07 2011 +0000

    target-arm: Implement VFPv4 fused multiply-accumulate insns
    
    Implement the fused multiply-accumulate instructions (VFMA, VFMS,
    VFNMA, VFNMS) which are new in VFPv4.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index af3904d..c4d742f 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -376,6 +376,7 @@ enum arm_features {
     ARM_FEATURE_STRONGARM,
     ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
     ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */
+    ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3a51fd7..eddb923 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -204,6 +204,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_VFP3);
+        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);
@@ -3084,6 +3085,19 @@ uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env)
     return 0x80000000 | ((float64_val(f64) >> 21) & 0x7fffffff);
 }
 
+/* VFPv4 fused multiply-accumulate */
+float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return float32_muladd(a, b, c, 0, fpst);
+}
+
+float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, void *fpstp)
+{
+    float_status *fpst = fpstp;
+    return float64_muladd(a, b, c, 0, fpst);
+}
+
 void HELPER(set_teecr)(CPUState *env, uint32_t val)
 {
     val &= 1;
diff --git a/target-arm/helper.h b/target-arm/helper.h
index 3ad1cb0..16dd5fc 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -132,6 +132,9 @@ DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env)
 DEF_HELPER_2(neon_fcvt_f16_to_f32, f32, i32, env)
 DEF_HELPER_2(neon_fcvt_f32_to_f16, i32, f32, env)
 
+DEF_HELPER_4(vfp_muladdd, f64, f64, f64, f64, ptr)
+DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, ptr)
+
 DEF_HELPER_3(recps_f32, f32, f32, f32, env)
 DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env)
 DEF_HELPER_2(recpe_f32, f32, f32, env)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 812a9e7..0f35b60 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -3141,6 +3141,57 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 case 8: /* div: fn / fm */
                     gen_vfp_div(dp);
                     break;
+                case 10: /* VFNMA : fd = muladd(-fd,  fn, fm) */
+                case 11: /* VFNMS : fd = muladd(-fd, -fn, fm) */
+                case 12: /* VFMA  : fd = muladd( fd,  fn, fm) */
+                case 13: /* VFMS  : fd = muladd( fd, -fn, fm) */
+                    /* These are fused multiply-add, and must be done as one
+                     * floating point operation with no rounding between the
+                     * multiplication and addition steps.
+                     * NB that doing the negations here as separate steps is
+                     * correct : an input NaN should come out with its sign bit
+                     * flipped if it is a negated-input.
+                     */
+                    if (!arm_feature(env, ARM_FEATURE_VFP4)) {
+                        return 1;
+                    }
+                    if (dp) {
+                        TCGv_ptr fpst;
+                        TCGv_i64 frd;
+                        if (op & 1) {
+                            /* VFNMS, VFMS */
+                            gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
+                        }
+                        frd = tcg_temp_new_i64();
+                        tcg_gen_ld_f64(frd, cpu_env, vfp_reg_offset(dp, rd));
+                        if (op & 2) {
+                            /* VFNMA, VFNMS */
+                            gen_helper_vfp_negd(frd, frd);
+                        }
+                        fpst = get_fpstatus_ptr(0);
+                        gen_helper_vfp_muladdd(cpu_F0d, cpu_F0d,
+                                               cpu_F1d, frd, fpst);
+                        tcg_temp_free_ptr(fpst);
+                        tcg_temp_free_i64(frd);
+                    } else {
+                        TCGv_ptr fpst;
+                        TCGv_i32 frd;
+                        if (op & 1) {
+                            /* VFNMS, VFMS */
+                            gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
+                        }
+                        frd = tcg_temp_new_i32();
+                        tcg_gen_ld_f32(frd, cpu_env, vfp_reg_offset(dp, rd));
+                        if (op & 2) {
+                            gen_helper_vfp_negs(frd, frd);
+                        }
+                        fpst = get_fpstatus_ptr(0);
+                        gen_helper_vfp_muladds(cpu_F0s, cpu_F0s,
+                                               cpu_F1s, frd, fpst);
+                        tcg_temp_free_ptr(fpst);
+                        tcg_temp_free_i32(frd);
+                    }
+                    break;
                 case 14: /* fconst */
                     if (!arm_feature(env, ARM_FEATURE_VFP3))
                       return 1;
@@ -4417,6 +4468,7 @@ static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src)
 #define NEON_3R_VPMIN 21
 #define NEON_3R_VQDMULH_VQRDMULH 22
 #define NEON_3R_VPADD 23
+#define NEON_3R_VFM 25 /* VFMA, VFMS : float fused multiply-add */
 #define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */
 #define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */
 #define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */
@@ -4449,6 +4501,7 @@ static const uint8_t neon_3r_sizes[] = {
     [NEON_3R_VPMIN] = 0x7,
     [NEON_3R_VQDMULH_VQRDMULH] = 0x6,
     [NEON_3R_VPADD] = 0x7,
+    [NEON_3R_VFM] = 0x5, /* size bit 1 encodes op */
     [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */
     [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */
     [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */
@@ -4726,6 +4779,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 return 1;
             }
             break;
+        case NEON_3R_VFM:
+            if (!arm_feature(env, ARM_FEATURE_VFP4) || u) {
+                return 1;
+            }
+            break;
         default:
             break;
         }
@@ -5006,6 +5064,20 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
             else
                 gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
             break;
+        case NEON_3R_VFM:
+        {
+            /* VFMA, VFMS: fused multiply-add */
+            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+            TCGv_i32 tmp3 = neon_load_reg(rd, pass);
+            if (size) {
+                /* VFMS */
+                gen_helper_vfp_negs(tmp, tmp);
+            }
+            gen_helper_vfp_muladds(tmp, tmp, tmp2, tmp3, fpstatus);
+            tcg_temp_free_i32(tmp3);
+            tcg_temp_free_ptr(fpstatus);
+            break;
+        }
         default:
             abort();
         }
commit 369be8f618ac145d2421ea4bfff86ee774ad618c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Oct 19 16:14:06 2011 +0000

    softfloat: Implement fused multiply-add
    
    Implement fused multiply-add as a softfloat primitive. This implements
    "a+b*c" as a single step without any intermediate rounding; it is
    specified in IEEE 754-2008 and implemented in a number of CPUs.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index c165205..c5e2dab 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -420,6 +420,82 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
 #endif
 
 /*----------------------------------------------------------------------------
+| Select which NaN to propagate for a three-input operation.
+| For the moment we assume that no CPU needs the 'larger significand'
+| information.
+| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_ARM)
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                         flag cIsQNaN, flag cIsSNaN, flag infzero STATUS_PARAM)
+{
+    /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
+     * the default NaN
+     */
+    if (infzero && cIsQNaN) {
+        float_raise(float_flag_invalid STATUS_VAR);
+        return 3;
+    }
+
+    /* This looks different from the ARM ARM pseudocode, because the ARM ARM
+     * puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
+     */
+    if (cIsSNaN) {
+        return 2;
+    } else if (aIsSNaN) {
+        return 0;
+    } else if (bIsSNaN) {
+        return 1;
+    } else if (cIsQNaN) {
+        return 2;
+    } else if (aIsQNaN) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+#elif defined(TARGET_PPC)
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                         flag cIsQNaN, flag cIsSNaN, flag infzero STATUS_PARAM)
+{
+    /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
+     * to return an input NaN if we have one (ie c) rather than generating
+     * a default NaN
+     */
+    if (infzero) {
+        float_raise(float_flag_invalid STATUS_VAR);
+        return 2;
+    }
+
+    /* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
+     * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
+     */
+    if (aIsSNaN || aIsQNaN) {
+        return 0;
+    } else if (cIsSNaN || cIsQNaN) {
+        return 2;
+    } else {
+        return 1;
+    }
+}
+#else
+/* A default implementation: prefer a to b to c.
+ * This is unlikely to actually match any real implementation.
+ */
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                         flag cIsQNaN, flag cIsSNaN, flag infzero STATUS_PARAM)
+{
+    if (aIsSNaN || aIsQNaN) {
+        return 0;
+    } else if (bIsSNaN || bIsQNaN) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+#endif
+
+/*----------------------------------------------------------------------------
 | Takes two single-precision floating-point values `a' and `b', one of which
 | is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
 | signaling NaN, the invalid exception is raised.
@@ -460,6 +536,57 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 }
 
 /*----------------------------------------------------------------------------
+| Takes three single-precision floating-point values `a', `b' and `c', one of
+| which is a NaN, and returns the appropriate NaN result.  If any of  `a',
+| `b' or `c' is a signaling NaN, the invalid exception is raised.
+| The input infzero indicates whether a*b was 0*inf or inf*0 (in which case
+| obviously c is a NaN, and whether to propagate c or some other NaN is
+| implementation defined).
+*----------------------------------------------------------------------------*/
+
+static float32 propagateFloat32MulAddNaN(float32 a, float32 b,
+                                         float32 c, flag infzero STATUS_PARAM)
+{
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+        cIsQuietNaN, cIsSignalingNaN;
+    int which;
+
+    aIsQuietNaN = float32_is_quiet_nan(a);
+    aIsSignalingNaN = float32_is_signaling_nan(a);
+    bIsQuietNaN = float32_is_quiet_nan(b);
+    bIsSignalingNaN = float32_is_signaling_nan(b);
+    cIsQuietNaN = float32_is_quiet_nan(c);
+    cIsSignalingNaN = float32_is_signaling_nan(c);
+
+    if (aIsSignalingNaN | bIsSignalingNaN | cIsSignalingNaN) {
+        float_raise(float_flag_invalid STATUS_VAR);
+    }
+
+    which = pickNaNMulAdd(aIsQuietNaN, aIsSignalingNaN,
+                          bIsQuietNaN, bIsSignalingNaN,
+                          cIsQuietNaN, cIsSignalingNaN, infzero STATUS_VAR);
+
+    if (STATUS(default_nan_mode)) {
+        /* Note that this check is after pickNaNMulAdd so that function
+         * has an opportunity to set the Invalid flag.
+         */
+        return float32_default_nan;
+    }
+
+    switch (which) {
+    case 0:
+        return float32_maybe_silence_nan(a);
+    case 1:
+        return float32_maybe_silence_nan(b);
+    case 2:
+        return float32_maybe_silence_nan(c);
+    case 3:
+    default:
+        return float32_default_nan;
+    }
+}
+
+/*----------------------------------------------------------------------------
 | Returns 1 if the double-precision floating-point value `a' is a quiet
 | NaN; otherwise returns 0.
 *----------------------------------------------------------------------------*/
@@ -596,6 +723,57 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
 }
 
 /*----------------------------------------------------------------------------
+| Takes three double-precision floating-point values `a', `b' and `c', one of
+| which is a NaN, and returns the appropriate NaN result.  If any of  `a',
+| `b' or `c' is a signaling NaN, the invalid exception is raised.
+| The input infzero indicates whether a*b was 0*inf or inf*0 (in which case
+| obviously c is a NaN, and whether to propagate c or some other NaN is
+| implementation defined).
+*----------------------------------------------------------------------------*/
+
+static float64 propagateFloat64MulAddNaN(float64 a, float64 b,
+                                         float64 c, flag infzero STATUS_PARAM)
+{
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+        cIsQuietNaN, cIsSignalingNaN;
+    int which;
+
+    aIsQuietNaN = float64_is_quiet_nan(a);
+    aIsSignalingNaN = float64_is_signaling_nan(a);
+    bIsQuietNaN = float64_is_quiet_nan(b);
+    bIsSignalingNaN = float64_is_signaling_nan(b);
+    cIsQuietNaN = float64_is_quiet_nan(c);
+    cIsSignalingNaN = float64_is_signaling_nan(c);
+
+    if (aIsSignalingNaN | bIsSignalingNaN | cIsSignalingNaN) {
+        float_raise(float_flag_invalid STATUS_VAR);
+    }
+
+    which = pickNaNMulAdd(aIsQuietNaN, aIsSignalingNaN,
+                          bIsQuietNaN, bIsSignalingNaN,
+                          cIsQuietNaN, cIsSignalingNaN, infzero STATUS_VAR);
+
+    if (STATUS(default_nan_mode)) {
+        /* Note that this check is after pickNaNMulAdd so that function
+         * has an opportunity to set the Invalid flag.
+         */
+        return float64_default_nan;
+    }
+
+    switch (which) {
+    case 0:
+        return float64_maybe_silence_nan(a);
+    case 1:
+        return float64_maybe_silence_nan(b);
+    case 2:
+        return float64_maybe_silence_nan(c);
+    case 3:
+    default:
+        return float64_default_nan;
+    }
+}
+
+/*----------------------------------------------------------------------------
 | Returns 1 if the extended double-precision floating-point value `a' is a
 | quiet NaN; otherwise returns 0. This slightly differs from the same
 | function for other types as floatx80 has an explicit bit.
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 3aafa81..81a7d1a 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -2118,6 +2118,213 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM )
 }
 
 /*----------------------------------------------------------------------------
+| Returns the result of multiplying the single-precision floating-point values
+| `a' and `b' then adding 'c', with no intermediate rounding step after the
+| multiplication.  The operation is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic 754-2008.
+| The flags argument allows the caller to select negation of the
+| addend, the intermediate product, or the final result. (The difference
+| between this and having the caller do a separate negation is that negating
+| externally will flip the sign bit on NaNs.)
+*----------------------------------------------------------------------------*/
+
+float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
+{
+    flag aSign, bSign, cSign, zSign;
+    int aExp, bExp, cExp, pExp, zExp, expDiff;
+    uint32_t aSig, bSig, cSig;
+    flag pInf, pZero, pSign;
+    uint64_t pSig64, cSig64, zSig64;
+    uint32_t pSig;
+    int shiftcount;
+    flag signflip, infzero;
+
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+    c = float32_squash_input_denormal(c STATUS_VAR);
+    aSig = extractFloat32Frac(a);
+    aExp = extractFloat32Exp(a);
+    aSign = extractFloat32Sign(a);
+    bSig = extractFloat32Frac(b);
+    bExp = extractFloat32Exp(b);
+    bSign = extractFloat32Sign(b);
+    cSig = extractFloat32Frac(c);
+    cExp = extractFloat32Exp(c);
+    cSign = extractFloat32Sign(c);
+
+    infzero = ((aExp == 0 && aSig == 0 && bExp == 0xff && bSig == 0) ||
+               (aExp == 0xff && aSig == 0 && bExp == 0 && bSig == 0));
+
+    /* It is implementation-defined whether the cases of (0,inf,qnan)
+     * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN
+     * they return if they do), so we have to hand this information
+     * off to the target-specific pick-a-NaN routine.
+     */
+    if (((aExp == 0xff) && aSig) ||
+        ((bExp == 0xff) && bSig) ||
+        ((cExp == 0xff) && cSig)) {
+        return propagateFloat32MulAddNaN(a, b, c, infzero STATUS_VAR);
+    }
+
+    if (infzero) {
+        float_raise(float_flag_invalid STATUS_VAR);
+        return float32_default_nan;
+    }
+
+    if (flags & float_muladd_negate_c) {
+        cSign ^= 1;
+    }
+
+    signflip = (flags & float_muladd_negate_result) ? 1 : 0;
+
+    /* Work out the sign and type of the product */
+    pSign = aSign ^ bSign;
+    if (flags & float_muladd_negate_product) {
+        pSign ^= 1;
+    }
+    pInf = (aExp == 0xff) || (bExp == 0xff);
+    pZero = ((aExp | aSig) == 0) || ((bExp | bSig) == 0);
+
+    if (cExp == 0xff) {
+        if (pInf && (pSign ^ cSign)) {
+            /* addition of opposite-signed infinities => InvalidOperation */
+            float_raise(float_flag_invalid STATUS_VAR);
+            return float32_default_nan;
+        }
+        /* Otherwise generate an infinity of the same sign */
+        return packFloat32(cSign ^ signflip, 0xff, 0);
+    }
+
+    if (pInf) {
+        return packFloat32(pSign ^ signflip, 0xff, 0);
+    }
+
+    if (pZero) {
+        if (cExp == 0) {
+            if (cSig == 0) {
+                /* Adding two exact zeroes */
+                if (pSign == cSign) {
+                    zSign = pSign;
+                } else if (STATUS(float_rounding_mode) == float_round_down) {
+                    zSign = 1;
+                } else {
+                    zSign = 0;
+                }
+                return packFloat32(zSign ^ signflip, 0, 0);
+            }
+            /* Exact zero plus a denorm */
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat32(cSign ^ signflip, 0, 0);
+            }
+        }
+        /* Zero plus something non-zero : just return the something */
+        return c ^ (signflip << 31);
+    }
+
+    if (aExp == 0) {
+        normalizeFloat32Subnormal(aSig, &aExp, &aSig);
+    }
+    if (bExp == 0) {
+        normalizeFloat32Subnormal(bSig, &bExp, &bSig);
+    }
+
+    /* Calculate the actual result a * b + c */
+
+    /* Multiply first; this is easy. */
+    /* NB: we subtract 0x7e where float32_mul() subtracts 0x7f
+     * because we want the true exponent, not the "one-less-than"
+     * flavour that roundAndPackFloat32() takes.
+     */
+    pExp = aExp + bExp - 0x7e;
+    aSig = (aSig | 0x00800000) << 7;
+    bSig = (bSig | 0x00800000) << 8;
+    pSig64 = (uint64_t)aSig * bSig;
+    if ((int64_t)(pSig64 << 1) >= 0) {
+        pSig64 <<= 1;
+        pExp--;
+    }
+
+    zSign = pSign ^ signflip;
+
+    /* Now pSig64 is the significand of the multiply, with the explicit bit in
+     * position 62.
+     */
+    if (cExp == 0) {
+        if (!cSig) {
+            /* Throw out the special case of c being an exact zero now */
+            shift64RightJamming(pSig64, 32, &pSig64);
+            pSig = pSig64;
+            return roundAndPackFloat32(zSign, pExp - 1,
+                                       pSig STATUS_VAR);
+        }
+        normalizeFloat32Subnormal(cSig, &cExp, &cSig);
+    }
+
+    cSig64 = (uint64_t)cSig << (62 - 23);
+    cSig64 |= LIT64(0x4000000000000000);
+    expDiff = pExp - cExp;
+
+    if (pSign == cSign) {
+        /* Addition */
+        if (expDiff > 0) {
+            /* scale c to match p */
+            shift64RightJamming(cSig64, expDiff, &cSig64);
+            zExp = pExp;
+        } else if (expDiff < 0) {
+            /* scale p to match c */
+            shift64RightJamming(pSig64, -expDiff, &pSig64);
+            zExp = cExp;
+        } else {
+            /* no scaling needed */
+            zExp = cExp;
+        }
+        /* Add significands and make sure explicit bit ends up in posn 62 */
+        zSig64 = pSig64 + cSig64;
+        if ((int64_t)zSig64 < 0) {
+            shift64RightJamming(zSig64, 1, &zSig64);
+        } else {
+            zExp--;
+        }
+    } else {
+        /* Subtraction */
+        if (expDiff > 0) {
+            shift64RightJamming(cSig64, expDiff, &cSig64);
+            zSig64 = pSig64 - cSig64;
+            zExp = pExp;
+        } else if (expDiff < 0) {
+            shift64RightJamming(pSig64, -expDiff, &pSig64);
+            zSig64 = cSig64 - pSig64;
+            zExp = cExp;
+            zSign ^= 1;
+        } else {
+            zExp = pExp;
+            if (cSig64 < pSig64) {
+                zSig64 = pSig64 - cSig64;
+            } else if (pSig64 < cSig64) {
+                zSig64 = cSig64 - pSig64;
+                zSign ^= 1;
+            } else {
+                /* Exact zero */
+                zSign = signflip;
+                if (STATUS(float_rounding_mode) == float_round_down) {
+                    zSign ^= 1;
+                }
+                return packFloat32(zSign, 0, 0);
+            }
+        }
+        --zExp;
+        /* Normalize to put the explicit bit back into bit 62. */
+        shiftcount = countLeadingZeros64(zSig64) - 1;
+        zSig64 <<= shiftcount;
+        zExp -= shiftcount;
+    }
+    shift64RightJamming(zSig64, 32, &zSig64);
+    return roundAndPackFloat32(zSign, zExp, zSig64 STATUS_VAR);
+}
+
+
+/*----------------------------------------------------------------------------
 | Returns the square root of the single-precision floating-point value `a'.
 | The operation is performed according to the IEC/IEEE Standard for Binary
 | Floating-Point Arithmetic.
@@ -3465,6 +3672,226 @@ float64 float64_rem( float64 a, float64 b STATUS_PARAM )
 }
 
 /*----------------------------------------------------------------------------
+| Returns the result of multiplying the double-precision floating-point values
+| `a' and `b' then adding 'c', with no intermediate rounding step after the
+| multiplication.  The operation is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic 754-2008.
+| The flags argument allows the caller to select negation of the
+| addend, the intermediate product, or the final result. (The difference
+| between this and having the caller do a separate negation is that negating
+| externally will flip the sign bit on NaNs.)
+*----------------------------------------------------------------------------*/
+
+float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
+{
+    flag aSign, bSign, cSign, zSign;
+    int aExp, bExp, cExp, pExp, zExp, expDiff;
+    uint64_t aSig, bSig, cSig;
+    flag pInf, pZero, pSign;
+    uint64_t pSig0, pSig1, cSig0, cSig1, zSig0, zSig1;
+    int shiftcount;
+    flag signflip, infzero;
+
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+    c = float64_squash_input_denormal(c STATUS_VAR);
+    aSig = extractFloat64Frac(a);
+    aExp = extractFloat64Exp(a);
+    aSign = extractFloat64Sign(a);
+    bSig = extractFloat64Frac(b);
+    bExp = extractFloat64Exp(b);
+    bSign = extractFloat64Sign(b);
+    cSig = extractFloat64Frac(c);
+    cExp = extractFloat64Exp(c);
+    cSign = extractFloat64Sign(c);
+
+    infzero = ((aExp == 0 && aSig == 0 && bExp == 0x7ff && bSig == 0) ||
+               (aExp == 0x7ff && aSig == 0 && bExp == 0 && bSig == 0));
+
+    /* It is implementation-defined whether the cases of (0,inf,qnan)
+     * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN
+     * they return if they do), so we have to hand this information
+     * off to the target-specific pick-a-NaN routine.
+     */
+    if (((aExp == 0x7ff) && aSig) ||
+        ((bExp == 0x7ff) && bSig) ||
+        ((cExp == 0x7ff) && cSig)) {
+        return propagateFloat64MulAddNaN(a, b, c, infzero STATUS_VAR);
+    }
+
+    if (infzero) {
+        float_raise(float_flag_invalid STATUS_VAR);
+        return float64_default_nan;
+    }
+
+    if (flags & float_muladd_negate_c) {
+        cSign ^= 1;
+    }
+
+    signflip = (flags & float_muladd_negate_result) ? 1 : 0;
+
+    /* Work out the sign and type of the product */
+    pSign = aSign ^ bSign;
+    if (flags & float_muladd_negate_product) {
+        pSign ^= 1;
+    }
+    pInf = (aExp == 0x7ff) || (bExp == 0x7ff);
+    pZero = ((aExp | aSig) == 0) || ((bExp | bSig) == 0);
+
+    if (cExp == 0x7ff) {
+        if (pInf && (pSign ^ cSign)) {
+            /* addition of opposite-signed infinities => InvalidOperation */
+            float_raise(float_flag_invalid STATUS_VAR);
+            return float64_default_nan;
+        }
+        /* Otherwise generate an infinity of the same sign */
+        return packFloat64(cSign ^ signflip, 0x7ff, 0);
+    }
+
+    if (pInf) {
+        return packFloat64(pSign ^ signflip, 0x7ff, 0);
+    }
+
+    if (pZero) {
+        if (cExp == 0) {
+            if (cSig == 0) {
+                /* Adding two exact zeroes */
+                if (pSign == cSign) {
+                    zSign = pSign;
+                } else if (STATUS(float_rounding_mode) == float_round_down) {
+                    zSign = 1;
+                } else {
+                    zSign = 0;
+                }
+                return packFloat64(zSign ^ signflip, 0, 0);
+            }
+            /* Exact zero plus a denorm */
+            if (STATUS(flush_to_zero)) {
+                float_raise(float_flag_output_denormal STATUS_VAR);
+                return packFloat64(cSign ^ signflip, 0, 0);
+            }
+        }
+        /* Zero plus something non-zero : just return the something */
+        return c ^ ((uint64_t)signflip << 63);
+    }
+
+    if (aExp == 0) {
+        normalizeFloat64Subnormal(aSig, &aExp, &aSig);
+    }
+    if (bExp == 0) {
+        normalizeFloat64Subnormal(bSig, &bExp, &bSig);
+    }
+
+    /* Calculate the actual result a * b + c */
+
+    /* Multiply first; this is easy. */
+    /* NB: we subtract 0x3fe where float64_mul() subtracts 0x3ff
+     * because we want the true exponent, not the "one-less-than"
+     * flavour that roundAndPackFloat64() takes.
+     */
+    pExp = aExp + bExp - 0x3fe;
+    aSig = (aSig | LIT64(0x0010000000000000))<<10;
+    bSig = (bSig | LIT64(0x0010000000000000))<<11;
+    mul64To128(aSig, bSig, &pSig0, &pSig1);
+    if ((int64_t)(pSig0 << 1) >= 0) {
+        shortShift128Left(pSig0, pSig1, 1, &pSig0, &pSig1);
+        pExp--;
+    }
+
+    zSign = pSign ^ signflip;
+
+    /* Now [pSig0:pSig1] is the significand of the multiply, with the explicit
+     * bit in position 126.
+     */
+    if (cExp == 0) {
+        if (!cSig) {
+            /* Throw out the special case of c being an exact zero now */
+            shift128RightJamming(pSig0, pSig1, 64, &pSig0, &pSig1);
+            return roundAndPackFloat64(zSign, pExp - 1,
+                                       pSig1 STATUS_VAR);
+        }
+        normalizeFloat64Subnormal(cSig, &cExp, &cSig);
+    }
+
+    /* Shift cSig and add the explicit bit so [cSig0:cSig1] is the
+     * significand of the addend, with the explicit bit in position 126.
+     */
+    cSig0 = cSig << (126 - 64 - 52);
+    cSig1 = 0;
+    cSig0 |= LIT64(0x4000000000000000);
+    expDiff = pExp - cExp;
+
+    if (pSign == cSign) {
+        /* Addition */
+        if (expDiff > 0) {
+            /* scale c to match p */
+            shift128RightJamming(cSig0, cSig1, expDiff, &cSig0, &cSig1);
+            zExp = pExp;
+        } else if (expDiff < 0) {
+            /* scale p to match c */
+            shift128RightJamming(pSig0, pSig1, -expDiff, &pSig0, &pSig1);
+            zExp = cExp;
+        } else {
+            /* no scaling needed */
+            zExp = cExp;
+        }
+        /* Add significands and make sure explicit bit ends up in posn 126 */
+        add128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
+        if ((int64_t)zSig0 < 0) {
+            shift128RightJamming(zSig0, zSig1, 1, &zSig0, &zSig1);
+        } else {
+            zExp--;
+        }
+        shift128RightJamming(zSig0, zSig1, 64, &zSig0, &zSig1);
+        return roundAndPackFloat64(zSign, zExp, zSig1 STATUS_VAR);
+    } else {
+        /* Subtraction */
+        if (expDiff > 0) {
+            shift128RightJamming(cSig0, cSig1, expDiff, &cSig0, &cSig1);
+            sub128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
+            zExp = pExp;
+        } else if (expDiff < 0) {
+            shift128RightJamming(pSig0, pSig1, -expDiff, &pSig0, &pSig1);
+            sub128(cSig0, cSig1, pSig0, pSig1, &zSig0, &zSig1);
+            zExp = cExp;
+            zSign ^= 1;
+        } else {
+            zExp = pExp;
+            if (lt128(cSig0, cSig1, pSig0, pSig1)) {
+                sub128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
+            } else if (lt128(pSig0, pSig1, cSig0, cSig1)) {
+                sub128(cSig0, cSig1, pSig0, pSig1, &zSig0, &zSig1);
+                zSign ^= 1;
+            } else {
+                /* Exact zero */
+                zSign = signflip;
+                if (STATUS(float_rounding_mode) == float_round_down) {
+                    zSign ^= 1;
+                }
+                return packFloat64(zSign, 0, 0);
+            }
+        }
+        --zExp;
+        /* Do the equivalent of normalizeRoundAndPackFloat64() but
+         * starting with the significand in a pair of uint64_t.
+         */
+        if (zSig0) {
+            shiftcount = countLeadingZeros64(zSig0) - 1;
+            shortShift128Left(zSig0, zSig1, shiftcount, &zSig0, &zSig1);
+            if (zSig1) {
+                zSig0 |= 1;
+            }
+            zExp -= shiftcount;
+        } else {
+            shiftcount = countLeadingZeros64(zSig1) - 1;
+            zSig0 = zSig1 << shiftcount;
+            zExp -= (shiftcount + 64);
+        }
+        return roundAndPackFloat64(zSign, zExp, zSig0 STATUS_VAR);
+    }
+}
+
+/*----------------------------------------------------------------------------
 | Returns the square root of the double-precision floating-point value `a'.
 | The operation is performed according to the IEC/IEEE Standard for Binary
 | Floating-Point Arithmetic.
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 618ddee..07c2929 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -212,6 +212,18 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM);
 void float_raise( int8 flags STATUS_PARAM);
 
 /*----------------------------------------------------------------------------
+| Options to indicate which negations to perform in float*_muladd()
+| Using these differs from negating an input or output before calling
+| the muladd function in that this means that a NaN doesn't have its
+| sign bit inverted before it is propagated.
+*----------------------------------------------------------------------------*/
+enum {
+    float_muladd_negate_c = 1,
+    float_muladd_negate_product = 2,
+    float_muladd_negate_result = 3,
+};
+
+/*----------------------------------------------------------------------------
 | Software IEC/IEEE integer-to-floating-point conversion routines.
 *----------------------------------------------------------------------------*/
 float32 int32_to_float32( int32 STATUS_PARAM );
@@ -269,6 +281,7 @@ float32 float32_sub( float32, float32 STATUS_PARAM );
 float32 float32_mul( float32, float32 STATUS_PARAM );
 float32 float32_div( float32, float32 STATUS_PARAM );
 float32 float32_rem( float32, float32 STATUS_PARAM );
+float32 float32_muladd(float32, float32, float32, int STATUS_PARAM);
 float32 float32_sqrt( float32 STATUS_PARAM );
 float32 float32_exp2( float32 STATUS_PARAM );
 float32 float32_log2( float32 STATUS_PARAM );
@@ -375,6 +388,7 @@ float64 float64_sub( float64, float64 STATUS_PARAM );
 float64 float64_mul( float64, float64 STATUS_PARAM );
 float64 float64_div( float64, float64 STATUS_PARAM );
 float64 float64_rem( float64, float64 STATUS_PARAM );
+float64 float64_muladd(float64, float64, float64, int STATUS_PARAM);
 float64 float64_sqrt( float64 STATUS_PARAM );
 float64 float64_log2( float64 STATUS_PARAM );
 int float64_eq( float64, float64 STATUS_PARAM );
commit b8b8ea05c4008343afcedf99b9c91fd750ea90e5
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Oct 19 16:14:06 2011 +0000

    target-arm: Add ARM UDIV/SDIV support
    
    Add support for UDIV and SDIV in ARM mode. This is a new optional
    feature for A profile cores (Thumb mode has had UDIV and SDIV for
    M profile cores for some time).
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 00e012e..af3904d 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -375,6 +375,7 @@ enum arm_features {
     ARM_FEATURE_V5,
     ARM_FEATURE_STRONGARM,
     ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
+    ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index faf0283..3a51fd7 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -207,7 +207,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_VFP_FP16);
         set_feature(env, ARM_FEATURE_NEON);
         set_feature(env, ARM_FEATURE_THUMB2EE);
-        set_feature(env, ARM_FEATURE_THUMB_DIV);
+        set_feature(env, ARM_FEATURE_ARM_DIV);
         set_feature(env, ARM_FEATURE_V7MP);
         break;
     case ARM_CPUID_TI915T:
@@ -261,6 +261,9 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     if (arm_feature(env, ARM_FEATURE_V7)) {
         set_feature(env, ARM_FEATURE_VAPA);
     }
+    if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
+        set_feature(env, ARM_FEATURE_THUMB_DIV);
+    }
 }
 
 void cpu_reset(CPUARMState *env)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index deb0bcf..812a9e7 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7639,6 +7639,25 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             store_reg(s, rn, tmp);
                         }
                         break;
+                    case 1:
+                    case 3:
+                        /* SDIV, UDIV */
+                        if (!arm_feature(env, ARM_FEATURE_ARM_DIV)) {
+                            goto illegal_op;
+                        }
+                        if (((insn >> 5) & 7) || (rd != 15)) {
+                            goto illegal_op;
+                        }
+                        tmp = load_reg(s, rm);
+                        tmp2 = load_reg(s, rs);
+                        if (insn & (1 << 21)) {
+                            gen_helper_udiv(tmp, tmp, tmp2);
+                        } else {
+                            gen_helper_sdiv(tmp, tmp, tmp2);
+                        }
+                        tcg_temp_free_i32(tmp2);
+                        store_reg(s, rn, tmp);
+                        break;
                     default:
                         goto illegal_op;
                     }
commit 477899908fd2e6ed72faf18ef5ab09f2ae746a8a
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Oct 19 16:14:06 2011 +0000

    target-arm: Rename ARM_FEATURE_DIV to _THUMB_DIV
    
    Rename the ARM_FEATURE_DIV feature bit to _THUMB_DIV, to
    make room for a new feature switch enabling DIV in the ARM
    encoding. (Cores may implement either (a) no divide insns
    (b) divide insns in Thumb encodings only (c) divide insns
    in both ARM and Thumb encodings.)
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 6ab780d..00e012e 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -366,7 +366,7 @@ enum arm_features {
     ARM_FEATURE_VFP3,
     ARM_FEATURE_VFP_FP16,
     ARM_FEATURE_NEON,
-    ARM_FEATURE_DIV,
+    ARM_FEATURE_THUMB_DIV, /* divide supported in Thumb encoding */
     ARM_FEATURE_M, /* Microcontroller profile.  */
     ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
     ARM_FEATURE_THUMB2EE,
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 17ef98b..faf0283 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -193,7 +193,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_V7);
         set_feature(env, ARM_FEATURE_M);
-        set_feature(env, ARM_FEATURE_DIV);
+        set_feature(env, ARM_FEATURE_THUMB_DIV);
         break;
     case ARM_CPUID_ANY: /* For userspace emulation.  */
         set_feature(env, ARM_FEATURE_V4T);
@@ -207,7 +207,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_VFP_FP16);
         set_feature(env, ARM_FEATURE_NEON);
         set_feature(env, ARM_FEATURE_THUMB2EE);
-        set_feature(env, ARM_FEATURE_DIV);
+        set_feature(env, ARM_FEATURE_THUMB_DIV);
         set_feature(env, ARM_FEATURE_V7MP);
         break;
     case ARM_CPUID_TI915T:
diff --git a/target-arm/translate.c b/target-arm/translate.c
index e99fc18..deb0bcf 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -8513,8 +8513,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             tmp2 = load_reg(s, rm);
             if ((op & 0x50) == 0x10) {
                 /* sdiv, udiv */
-                if (!arm_feature(env, ARM_FEATURE_DIV))
+                if (!arm_feature(env, ARM_FEATURE_THUMB_DIV)) {
                     goto illegal_op;
+                }
                 if (op & 0x20)
                     gen_helper_udiv(tmp, tmp, tmp2);
                 else
commit 41e9564df650ddedbdab27283ebcb0173adf024f
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Oct 19 16:14:05 2011 +0000

    target-arm: v6 media multiply space: UNDEF on unassigned encodings
    
    Clean up the decoding of the v6 media multiply space so that we UNDEF
    on unassigned encodings rather than randomly interpreting them as
    some instruction in this space.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 75c0ad4..e99fc18 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7569,11 +7569,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     }
                     break;
                 case 2: /* Multiplies (Type 3).  */
-                    tmp = load_reg(s, rm);
-                    tmp2 = load_reg(s, rs);
-                    if (insn & (1 << 20)) {
+                    switch ((insn >> 20) & 0x7) {
+                    case 5:
+                        if (((insn >> 6) ^ (insn >> 7)) & 1) {
+                            /* op2 not 00x or 11x : UNDEF */
+                            goto illegal_op;
+                        }
                         /* Signed multiply most significant [accumulate].
                            (SMMUL, SMMLA, SMMLS) */
+                        tmp = load_reg(s, rm);
+                        tmp2 = load_reg(s, rs);
                         tmp64 = gen_muls_i64_i32(tmp, tmp2);
 
                         if (rd != 15) {
@@ -7592,7 +7597,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         tcg_gen_trunc_i64_i32(tmp, tmp64);
                         tcg_temp_free_i64(tmp64);
                         store_reg(s, rn, tmp);
-                    } else {
+                        break;
+                    case 0:
+                    case 4:
+                        /* SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD */
+                        if (insn & (1 << 7)) {
+                            goto illegal_op;
+                        }
+                        tmp = load_reg(s, rm);
+                        tmp2 = load_reg(s, rs);
                         if (insn & (1 << 5))
                             gen_swap_half(tmp2);
                         gen_smul_dual(tmp, tmp2);
@@ -7625,6 +7638,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                               }
                             store_reg(s, rn, tmp);
                         }
+                        break;
+                    default:
+                        goto illegal_op;
                     }
                     break;
                 case 3:
commit 26cc6abf61cc2bf68eaeb89b1497c12330e6b73c
Author: Christophe LYON <christophe.lyon at st.com>
Date:   Wed Oct 19 16:14:05 2011 +0000

    rsqrte_f32: No need to copy sign bit.
    
    Indeed, the result is known to be always positive.
    
    Signed-off-by: Christophe Lyon <christophe.lyon at st.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index e2428eb..17ef98b 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3039,8 +3039,7 @@ float32 HELPER(rsqrte_f32)(float32 a, CPUState *env)
 
     val64 = float64_val(f64);
 
-    val = ((val64 >> 63)  & 0x80000000)
-        | ((result_exp & 0xff) << 23)
+    val = ((result_exp & 0xff) << 23)
         | ((val64 >> 29)  & 0x7fffff);
     return make_float32(val);
 }


More information about the Spice-commits mailing list