[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;
+