summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs1
-rw-r--r--accel/tcg/translate-all.c50
-rw-r--r--accel/tcg/user-exec.c52
-rw-r--r--block/qcow.c16
-rw-r--r--block/qcow2-bitmap.c10
-rw-r--r--block/qcow2-refcount.c70
-rw-r--r--block/qcow2.c14
-rw-r--r--block/vmdk.c18
-rw-r--r--blockdev.c30
-rw-r--r--default-configs/sparc64-softmmu.mak3
-rw-r--r--hw/arm/virt.c2
-rw-r--r--hw/block/nvme.c39
-rw-r--r--hw/block/nvme.h1
-rw-r--r--hw/core/Makefile.objs5
-rw-r--r--hw/core/qdev-fw.c96
-rw-r--r--hw/core/qdev.c77
-rw-r--r--hw/display/pl110.c30
-rw-r--r--hw/display/vga.c3
-rw-r--r--hw/intc/arm_gic.c25
-rw-r--r--hw/intc/grlib_irqmp.c17
-rw-r--r--hw/net/imx_fec.c8
-rw-r--r--hw/pci-bridge/Makefile.objs2
-rw-r--r--hw/pci-bridge/simba.c101
-rw-r--r--hw/pci-host/Makefile.objs2
-rw-r--r--hw/pci-host/sabre.c (renamed from hw/pci-host/apb.c)270
-rw-r--r--hw/pci-host/trace-events11
-rw-r--r--hw/sd/sdhci.c1
-rw-r--r--hw/sparc64/sparc64.c85
-rw-r--r--hw/sparc64/sun4u.c109
-rw-r--r--hw/sparc64/trace-events18
-rw-r--r--hw/ssi/xilinx_spips.c18
-rw-r--r--include/hw/pci-bridge/simba.h38
-rw-r--r--include/hw/pci-host/sabre.h (renamed from include/hw/pci-host/apb.h)26
-rw-r--r--include/hw/sd/sdhci.h1
-rw-r--r--include/migration/vmstate.h9
-rw-r--r--linux-user/elfload.c3
-rw-r--r--linux-user/main.c9
-rw-r--r--linux-user/mmap.c2
-rw-r--r--linux-user/signal.c22
-rw-r--r--linux-user/syscall.c177
-rw-r--r--linux-user/syscall_defs.h6
-rw-r--r--qapi/block-core.json42
-rw-r--r--target/arm/arch_dump.c8
-rw-r--r--target/arm/cpu.h157
-rw-r--r--target/arm/crypto_helper.c184
-rw-r--r--target/arm/helper-a64.c5
-rw-r--r--target/arm/helper.c164
-rw-r--r--target/arm/helper.h46
-rw-r--r--target/arm/kvm32.c4
-rw-r--r--target/arm/kvm64.c31
-rw-r--r--target/arm/machine.c2
-rw-r--r--target/arm/neon_helper.c162
-rw-r--r--target/arm/op_helper.c17
-rw-r--r--target/arm/translate-a64.c100
-rw-r--r--target/arm/translate.c134
-rw-r--r--target/arm/translate.h2
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/ahci-test.c16
-rwxr-xr-xtests/qemu-iotests/02017
-rw-r--r--tests/qemu-iotests/020.out6
-rwxr-xr-xtests/qemu-iotests/0512
-rw-r--r--tests/qemu-iotests/051.out1
-rw-r--r--tests/qemu-iotests/051.pc.out1
-rwxr-xr-xtests/qemu-iotests/0594
-rw-r--r--tests/qemu-iotests/059.out2
-rwxr-xr-xtests/qemu-iotests/0603
-rw-r--r--tests/qemu-iotests/060.out9
-rwxr-xr-xtests/qemu-iotests/0673
-rw-r--r--tests/qemu-iotests/067.out97
-rwxr-xr-xtests/qemu-iotests/0805
-rwxr-xr-xtests/qemu-iotests/0894
-rw-r--r--tests/qemu-iotests/089.out10
-rwxr-xr-xtests/qemu-iotests/0936
-rwxr-xr-xtests/qemu-iotests/1027
-rw-r--r--tests/qemu-iotests/102.out3
-rwxr-xr-xtests/qemu-iotests/1032
-rwxr-xr-xtests/qemu-iotests/118184
-rwxr-xr-xtests/qemu-iotests/1302
-rwxr-xr-xtests/qemu-iotests/1372
-rw-r--r--tests/qemu-iotests/1392
-rwxr-xr-xtests/qemu-iotests/15560
-rwxr-xr-xtests/qemu-iotests/1762
-rwxr-xr-xtests/qemu-iotests/17720
-rw-r--r--tests/qemu-iotests/177.out22
-rwxr-xr-xtests/qemu-iotests/18425
-rw-r--r--tests/qemu-iotests/184.out63
-rwxr-xr-xtests/qemu-iotests/1915
-rw-r--r--tests/qemu-iotests/191.out313
-rwxr-xr-xtests/qemu-iotests/1988
-rw-r--r--tests/qemu-iotests/198.out8
-rwxr-xr-xtests/qemu-iotests/201120
-rw-r--r--tests/qemu-iotests/201.out23
-rwxr-xr-xtests/qemu-iotests/204119
-rw-r--r--tests/qemu-iotests/204.out63
-rw-r--r--tests/qemu-iotests/common.filter29
-rw-r--r--tests/qemu-iotests/common.rc2
-rw-r--r--tests/qemu-iotests/group2
-rw-r--r--util/osdep.c4
98 files changed, 2224 insertions, 1588 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 669d8d684d..323ef12384 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -150,6 +150,7 @@ trace-events-subdirs += hw/i386/xen
 trace-events-subdirs += hw/9pfs
 trace-events-subdirs += hw/ppc
 trace-events-subdirs += hw/pci
+trace-events-subdirs += hw/pci-host
 trace-events-subdirs += hw/s390x
 trace-events-subdirs += hw/vfio
 trace-events-subdirs += hw/acpi
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 7736257085..67795cd78c 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -2181,29 +2181,41 @@ int page_unprotect(target_ulong address, uintptr_t pc)
 
     /* if the page was really writable, then we change its
        protection back to writable */
-    if ((p->flags & PAGE_WRITE_ORG) && !(p->flags & PAGE_WRITE)) {
-        host_start = address & qemu_host_page_mask;
-        host_end = host_start + qemu_host_page_size;
-
-        prot = 0;
+    if (p->flags & PAGE_WRITE_ORG) {
         current_tb_invalidated = false;
-        for (addr = host_start ; addr < host_end ; addr += TARGET_PAGE_SIZE) {
-            p = page_find(addr >> TARGET_PAGE_BITS);
-            p->flags |= PAGE_WRITE;
-            prot |= p->flags;
-
-            /* and since the content will be modified, we must invalidate
-               the corresponding translated code. */
-            current_tb_invalidated |= tb_invalidate_phys_page(addr, pc);
-#ifdef CONFIG_USER_ONLY
-            if (DEBUG_TB_CHECK_GATE) {
-                tb_invalidate_check(addr);
+        if (p->flags & PAGE_WRITE) {
+            /* If the page is actually marked WRITE then assume this is because
+             * this thread raced with another one which got here first and
+             * set the page to PAGE_WRITE and did the TB invalidate for us.
+             */
+#ifdef TARGET_HAS_PRECISE_SMC
+            TranslationBlock *current_tb = tb_find_pc(pc);
+            if (current_tb) {
+                current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID;
             }
 #endif
+        } else {
+            host_start = address & qemu_host_page_mask;
+            host_end = host_start + qemu_host_page_size;
+
+            prot = 0;
+            for (addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) {
+                p = page_find(addr >> TARGET_PAGE_BITS);
+                p->flags |= PAGE_WRITE;
+                prot |= p->flags;
+
+                /* and since the content will be modified, we must invalidate
+                   the corresponding translated code. */
+                current_tb_invalidated |= tb_invalidate_phys_page(addr, pc);
+#ifdef CONFIG_USER_ONLY
+                if (DEBUG_TB_CHECK_GATE) {
+                    tb_invalidate_check(addr);
+                }
+#endif
+            }
+            mprotect((void *)g2h(host_start), qemu_host_page_size,
+                     prot & PAGE_BITS);
         }
-        mprotect((void *)g2h(host_start), qemu_host_page_size,
-                 prot & PAGE_BITS);
-
         mmap_unlock();
         /* If current TB was invalidated return to main loop */
         return current_tb_invalidated ? 2 : 1;
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index f42285ea1c..c973752562 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -57,12 +57,13 @@ static void cpu_exit_tb_from_sighandler(CPUState *cpu, sigset_t *old_set)
    the effective address of the memory exception. 'is_write' is 1 if a
    write caused the exception and otherwise 0'. 'old_set' is the
    signal set which should be restored */
-static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
+static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
                                     int is_write, sigset_t *old_set)
 {
     CPUState *cpu = current_cpu;
     CPUClass *cc;
     int ret;
+    unsigned long address = (unsigned long)info->si_addr;
 
     /* We must handle PC addresses from two different sources:
      * a call return address and a signal frame address.
@@ -103,7 +104,18 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
     /* XXX: locking issue */
-    if (is_write && h2g_valid(address)) {
+    /* Note that it is important that we don't call page_unprotect() unless
+     * this is really a "write to nonwriteable page" fault, because
+     * page_unprotect() assumes that if it is called for an access to
+     * a page that's writeable this means we had two threads racing and
+     * another thread got there first and already made the page writeable;
+     * so we will retry the access. If we were to call page_unprotect()
+     * for some other kind of fault that should really be passed to the
+     * guest, we'd end up in an infinite loop of retrying the faulting
+     * access.
+     */
+    if (is_write && info->si_signo == SIGSEGV && info->si_code == SEGV_ACCERR &&
+        h2g_valid(address)) {
         switch (page_unprotect(h2g(address), pc)) {
         case 0:
             /* Fault not caused by a page marked unwritable to protect
@@ -215,9 +227,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
 #endif
     pc = EIP_sig(uc);
     trapno = TRAP_sig(uc);
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             trapno == 0xe ?
-                             (ERROR_sig(uc) >> 1) & 1 : 0,
+    return handle_cpu_signal(pc, info,
+                             trapno == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0,
                              &MASK_sig(uc));
 }
 
@@ -261,9 +272,8 @@ int cpu_signal_handler(int host_signum, void *pinfo,
 #endif
 
     pc = PC_sig(uc);
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             TRAP_sig(uc) == 0xe ?
-                             (ERROR_sig(uc) >> 1) & 1 : 0,
+    return handle_cpu_signal(pc, info,
+                             TRAP_sig(uc) == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0,
                              &MASK_sig(uc));
 }
 
@@ -341,8 +351,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
         is_write = 1;
     }
 #endif
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, &uc->uc_sigmask);
+    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
 }
 
 #elif defined(__alpha__)
@@ -372,8 +381,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
         is_write = 1;
     }
 
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, &uc->uc_sigmask);
+    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
 }
 #elif defined(__sparc__)
 
@@ -432,8 +440,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
             break;
         }
     }
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, sigmask);
+    return handle_cpu_signal(pc, info, is_write, sigmask);
 }
 
 #elif defined(__arm__)
@@ -466,9 +473,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
      * later processor; on v5 we will always report this as a read).
      */
     is_write = extract32(uc->uc_mcontext.error_code, 11, 1);
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write,
-                             &uc->uc_sigmask);
+    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
 }
 
 #elif defined(__aarch64__)
@@ -495,8 +500,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
                 /* Ignore bits 23 & 24, controlling indexing.  */
                 || (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */
 
-    return handle_cpu_signal(pc, (uintptr_t)info->si_addr,
-                             is_write, &uc->uc_sigmask);
+    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
 }
 
 #elif defined(__ia64)
@@ -529,9 +533,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
     default:
         break;
     }
-    return handle_cpu_signal(ip, (unsigned long)info->si_addr,
-                             is_write,
-                             (sigset_t *)&uc->uc_sigmask);
+    return handle_cpu_signal(ip, info, is_write, (sigset_t *)&uc->uc_sigmask);
 }
 
 #elif defined(__s390__)
@@ -583,8 +585,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
         }
         break;
     }
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, &uc->uc_sigmask);
+    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
 }
 
 #elif defined(__mips__)
@@ -599,8 +600,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
 
     /* XXX: compute is_write */
     is_write = 0;
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             is_write, &uc->uc_sigmask);
+    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
 }
 
 #else
diff --git a/block/qcow.c b/block/qcow.c
index 9569deeaf0..d552a6eba8 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -379,6 +379,7 @@ static int get_cluster_offset(BlockDriverState *bs,
         /* update the L1 entry */
         s->l1_table[l1_index] = l2_offset;
         tmp = cpu_to_be64(l2_offset);
+        BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
         ret = bdrv_pwrite_sync(bs->file,
                                s->l1_table_offset + l1_index * sizeof(tmp),
                                &tmp, sizeof(tmp));
@@ -409,6 +410,7 @@ static int get_cluster_offset(BlockDriverState *bs,
         }
     }
     l2_table = s->l2_cache + (min_index << s->l2_bits);
+    BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
     if (new_l2_table) {
         memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
         ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
@@ -432,6 +434,7 @@ static int get_cluster_offset(BlockDriverState *bs,
         ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
         if (!allocate)
             return 0;
+        BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
         /* allocate a new cluster */
         if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
             (n_end - n_start) < s->cluster_sectors) {
@@ -447,6 +450,7 @@ static int get_cluster_offset(BlockDriverState *bs,
             }
             cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
             /* write the cluster content */
+            BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
             ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
                               s->cluster_size);
             if (ret < 0) {
@@ -486,6 +490,7 @@ static int get_cluster_offset(BlockDriverState *bs,
                                                       NULL) < 0) {
                                 return -EIO;
                             }
+                            BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
                             ret = bdrv_pwrite(bs->file,
                                               cluster_offset + i * 512,
                                               s->cluster_data, 512);
@@ -503,6 +508,11 @@ static int get_cluster_offset(BlockDriverState *bs,
         /* update L2 table */
         tmp = cpu_to_be64(cluster_offset);
         l2_table[l2_index] = tmp;
+        if (allocate == 2) {
+            BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
+        } else {
+            BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
+        }
         ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
                                &tmp, sizeof(tmp));
         if (ret < 0) {
@@ -579,6 +589,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
     if (s->cluster_cache_offset != coffset) {
         csize = cluster_offset >> (63 - s->cluster_bits);
         csize &= (s->cluster_size - 1);
+        BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
         ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
         if (ret != csize)
             return -1;
@@ -635,6 +646,8 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
                 hd_iov.iov_len = n * 512;
                 qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
                 qemu_co_mutex_unlock(&s->lock);
+                /* qcow2 emits this on bs->file instead of bs->backing */
+                BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
                 ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
                 qemu_co_mutex_lock(&s->lock);
                 if (ret < 0) {
@@ -661,6 +674,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
             hd_iov.iov_len = n * 512;
             qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
             qemu_co_mutex_unlock(&s->lock);
+            BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
             ret = bdrv_co_readv(bs->file,
                                 (cluster_offset >> 9) + index_in_cluster,
                                 n, &hd_qiov);
@@ -754,6 +768,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
         hd_iov.iov_len = n * 512;
         qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
         qemu_co_mutex_unlock(&s->lock);
+        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
         ret = bdrv_co_writev(bs->file,
                              (cluster_offset >> 9) + index_in_cluster,
                              n, &hd_qiov);
@@ -1048,6 +1063,7 @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
         .iov_len    = out_len,
     };
     qemu_iovec_init_external(&hd_qiov, &iov, 1);
+    BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
     ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
     if (ret < 0) {
         goto fail;
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index f45e46cfbd..efa10c6663 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -1449,6 +1449,16 @@ bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
     bool found;
     Qcow2BitmapList *bm_list;
 
+    if (s->qcow_version < 3) {
+        /* Without autoclear_features, we would always have to assume
+         * that a program without persistent dirty bitmap support has
+         * accessed this qcow2 file when opening it, and would thus
+         * have to drop all dirty bitmaps (defeating their purpose).
+         */
+        error_setg(errp, "Cannot store dirty bitmaps in qcow2 v2 files");
+        goto fail;
+    }
+
     if (check_constraints_on_bitmap(bs, name, granularity, errp) != 0) {
         goto fail;
     }
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 3de1ab51ba..92701ab7af 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1508,7 +1508,7 @@ enum {
 static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
                               void **refcount_table,
                               int64_t *refcount_table_size, int64_t l2_offset,
-                              int flags)
+                              int flags, BdrvCheckMode fix)
 {
     BDRVQcow2State *s = bs->opaque;
     uint64_t *l2_table, l2_entry;
@@ -1579,6 +1579,57 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
                 next_contiguous_offset = offset + s->cluster_size;
             }
 
+            /* Correct offsets are cluster aligned */
+            if (offset_into_cluster(s, offset)) {
+                if (qcow2_get_cluster_type(l2_entry) ==
+                    QCOW2_CLUSTER_ZERO_ALLOC)
+                {
+                    fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero "
+                            "cluster is not properly aligned; L2 entry "
+                            "corrupted.\n",
+                            fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
+                            offset);
+                    if (fix & BDRV_FIX_ERRORS) {
+                        uint64_t l2e_offset =
+                            l2_offset + (uint64_t)i * sizeof(uint64_t);
+
+                        l2_entry = QCOW_OFLAG_ZERO;
+                        l2_table[i] = cpu_to_be64(l2_entry);
+                        ret = qcow2_pre_write_overlap_check(bs,
+                                QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2,
+                                l2e_offset, sizeof(uint64_t));
+                        if (ret < 0) {
+                            fprintf(stderr, "ERROR: Overlap check failed\n");
+                            res->check_errors++;
+                            /* Something is seriously wrong, so abort checking
+                             * this L2 table */
+                            goto fail;
+                        }
+
+                        ret = bdrv_pwrite_sync(bs->file, l2e_offset,
+                                               &l2_table[i], sizeof(uint64_t));
+                        if (ret < 0) {
+                            fprintf(stderr, "ERROR: Failed to overwrite L2 "
+                                    "table entry: %s\n", strerror(-ret));
+                            res->check_errors++;
+                            /* Do not abort, continue checking the rest of this
+                             * L2 table's entries */
+                        } else {
+                            res->corruptions_fixed++;
+                            /* Skip marking the cluster as used
+                             * (it is unused now) */
+                            continue;
+                        }
+                    } else {
+                        res->corruptions++;
+                    }
+                } else {
+                    fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
+                        "not properly aligned; L2 entry corrupted.\n", offset);
+                    res->corruptions++;
+                }
+            }
+
             /* Mark cluster as used */
             ret = qcow2_inc_refcounts_imrt(bs, res,
                                            refcount_table, refcount_table_size,
@@ -1586,13 +1637,6 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
             if (ret < 0) {
                 goto fail;
             }
-
-            /* Correct offsets are cluster aligned */
-            if (offset_into_cluster(s, offset)) {
-                fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
-                    "properly aligned; L2 entry corrupted.\n", offset);
-                res->corruptions++;
-            }
             break;
         }
 
@@ -1626,7 +1670,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
                               void **refcount_table,
                               int64_t *refcount_table_size,
                               int64_t l1_table_offset, int l1_size,
-                              int flags)
+                              int flags, BdrvCheckMode fix)
 {
     BDRVQcow2State *s = bs->opaque;
     uint64_t *l1_table = NULL, l2_offset, l1_size2;
@@ -1681,7 +1725,8 @@ static int check_refcounts_l1(BlockDriverState *bs,
 
             /* Process and check L2 entries */
             ret = check_refcounts_l2(bs, res, refcount_table,
-                                     refcount_table_size, l2_offset, flags);
+                                     refcount_table_size, l2_offset, flags,
+                                     fix);
             if (ret < 0) {
                 goto fail;
             }
@@ -1957,7 +2002,8 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
 
     /* current L1 table */
     ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
-                             s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO);
+                             s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO,
+                             fix);
     if (ret < 0) {
         return ret;
     }
@@ -1966,7 +2012,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
     for (i = 0; i < s->nb_snapshots; i++) {
         sn = s->snapshots + i;
         ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
-                                 sn->l1_table_offset, sn->l1_size, 0);
+                                 sn->l1_table_offset, sn->l1_size, 0, fix);
         if (ret < 0) {
             return ret;
         }
diff --git a/block/qcow2.c b/block/qcow2.c
index 4348b2c0c5..1f80961e1b 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -302,9 +302,17 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
             }
 
             if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) {
-                warn_report("a program lacking bitmap support "
-                            "modified this file, so all bitmaps are now "
-                            "considered inconsistent");
+                if (s->qcow_version < 3) {
+                    /* Let's be a bit more specific */
+                    warn_report("This qcow2 v2 image contains bitmaps, but "
+                                "they may have been modified by a program "
+                                "without persistent bitmap support; so now "
+                                "they must all be considered inconsistent");
+                } else {
+                    warn_report("a program lacking bitmap support "
+                                "modified this file, so all bitmaps are now "
+                                "considered inconsistent");
+                }
                 error_printf("Some clusters may be leaked, "
                              "run 'qemu-img check -r' on the image "
                              "file to fix.");
diff --git a/block/vmdk.c b/block/vmdk.c
index c665bcc977..d71cec4f31 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1075,6 +1075,8 @@ static int get_whole_cluster(BlockDriverState *bs,
     /* Read backing data before skip range */
     if (skip_start_bytes > 0) {
         if (bs->backing) {
+            /* qcow2 emits this on bs->file instead of bs->backing */
+            BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
             ret = bdrv_pread(bs->backing, offset, whole_grain,
                              skip_start_bytes);
             if (ret < 0) {
@@ -1082,6 +1084,7 @@ static int get_whole_cluster(BlockDriverState *bs,
                 goto exit;
             }
         }
+        BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
         ret = bdrv_pwrite(extent->file, cluster_offset, whole_grain,
                           skip_start_bytes);
         if (ret < 0) {
@@ -1092,6 +1095,8 @@ static int get_whole_cluster(BlockDriverState *bs,
     /* Read backing data after skip range */
     if (skip_end_bytes < cluster_bytes) {
         if (bs->backing) {
+            /* qcow2 emits this on bs->file instead of bs->backing */
+            BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
             ret = bdrv_pread(bs->backing, offset + skip_end_bytes,
                              whole_grain + skip_end_bytes,
                              cluster_bytes - skip_end_bytes);
@@ -1100,6 +1105,7 @@ static int get_whole_cluster(BlockDriverState *bs,
                 goto exit;
             }
         }
+        BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
         ret = bdrv_pwrite(extent->file, cluster_offset + skip_end_bytes,
                           whole_grain + skip_end_bytes,
                           cluster_bytes - skip_end_bytes);
@@ -1120,6 +1126,7 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
 {
     offset = cpu_to_le32(offset);
     /* update L2 table */
+    BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE);
     if (bdrv_pwrite_sync(extent->file,
                 ((int64_t)m_data->l2_offset * 512)
                     + (m_data->l2_index * sizeof(offset)),
@@ -1218,6 +1225,7 @@ static int get_cluster_offset(BlockDriverState *bs,
         }
     }
     l2_table = extent->l2_cache + (min_index * extent->l2_size);
+    BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
     if (bdrv_pread(extent->file,
                 (int64_t)l2_offset * 512,
                 l2_table,
@@ -1393,12 +1401,16 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
             .iov_len    = n_bytes,
         };
         qemu_iovec_init_external(&local_qiov, &iov, 1);
+
+        BLKDBG_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED);
     } else {
         qemu_iovec_init(&local_qiov, qiov->niov);
         qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes);
+
+        BLKDBG_EVENT(extent->file, BLKDBG_WRITE_AIO);
     }
 
-    write_offset = cluster_offset + offset_in_cluster,
+    write_offset = cluster_offset + offset_in_cluster;
     ret = bdrv_co_pwritev(extent->file, write_offset, n_bytes,
                           &local_qiov, 0);
 
@@ -1437,6 +1449,7 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
 
 
     if (!extent->compressed) {
+        BLKDBG_EVENT(extent->file, BLKDBG_READ_AIO);
         ret = bdrv_co_preadv(extent->file,
                              cluster_offset + offset_in_cluster, bytes,
                              qiov, 0);
@@ -1450,6 +1463,7 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
     buf_bytes = cluster_bytes * 2;
     cluster_buf = g_malloc(buf_bytes);
     uncomp_buf = g_malloc(cluster_bytes);
+    BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED);
     ret = bdrv_pread(extent->file,
                 cluster_offset,
                 cluster_buf, buf_bytes);
@@ -1527,6 +1541,8 @@ vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
                 qemu_iovec_reset(&local_qiov);
                 qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
 
+                /* qcow2 emits this on bs->file instead of bs->backing */
+                BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
                 ret = bdrv_co_preadv(bs->backing, offset, n_bytes,
                                      &local_qiov, 0);
                 if (ret < 0) {
diff --git a/blockdev.c b/blockdev.c
index 29d569a24e..8e977eef11 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -60,6 +60,11 @@ static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
 
 static int do_open_tray(const char *blk_name, const char *qdev_id,
                         bool force, Error **errp);
+static void blockdev_remove_medium(bool has_device, const char *device,
+                                   bool has_id, const char *id, Error **errp);
+static void blockdev_insert_medium(bool has_device, const char *device,
+                                   bool has_id, const char *id,
+                                   const char *node_name, Error **errp);
 
 static const char *const if_name[IF_COUNT] = {
     [IF_NONE] = "none",
@@ -2323,7 +2328,7 @@ void qmp_eject(bool has_device, const char *device,
     }
     error_free(local_err);
 
-    qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp);
+    blockdev_remove_medium(has_device, device, has_id, id, errp);
 }
 
 void qmp_block_passwd(bool has_device, const char *device,
@@ -2446,8 +2451,8 @@ void qmp_blockdev_close_tray(bool has_device, const char *device,
     }
 }
 
-void qmp_x_blockdev_remove_medium(bool has_device, const char *device,
-                                  bool has_id, const char *id, Error **errp)
+static void blockdev_remove_medium(bool has_device, const char *device,
+                                   bool has_id, const char *id, Error **errp)
 {
     BlockBackend *blk;
     BlockDriverState *bs;
@@ -2503,6 +2508,11 @@ out:
     aio_context_release(aio_context);
 }
 
+void qmp_blockdev_remove_medium(const char *id, Error **errp)
+{
+    blockdev_remove_medium(false, NULL, true, id, errp);
+}
+
 static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
                                             BlockDriverState *bs, Error **errp)
 {
@@ -2548,9 +2558,9 @@ static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
     }
 }
 
-void qmp_x_blockdev_insert_medium(bool has_device, const char *device,
-                                  bool has_id, const char *id,
-                                  const char *node_name, Error **errp)
+static void blockdev_insert_medium(bool has_device, const char *device,
+                                   bool has_id, const char *id,
+                                   const char *node_name, Error **errp)
 {
     BlockBackend *blk;
     BlockDriverState *bs;
@@ -2576,6 +2586,12 @@ void qmp_x_blockdev_insert_medium(bool has_device, const char *device,
     qmp_blockdev_insert_anon_medium(blk, bs, errp);
 }
 
+void qmp_blockdev_insert_medium(const char *id, const char *node_name,
+                                Error **errp)
+{
+    blockdev_insert_medium(false, NULL, true, id, node_name, errp);
+}
+
 void qmp_blockdev_change_medium(bool has_device, const char *device,
                                 bool has_id, const char *id,
                                 const char *filename,
@@ -2650,7 +2666,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
     error_free(err);
     err = NULL;
 
-    qmp_x_blockdev_remove_medium(has_device, device, has_id, id, &err);
+    blockdev_remove_medium(has_device, device, has_id, id, &err);
     if (err) {
         error_propagate(errp, err);
         goto fail;
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index 3e177bbd7b..52edafe547 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -11,7 +11,8 @@ CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_CMD646=y
-CONFIG_PCI_APB=y
+CONFIG_PCI_SABRE=y
+CONFIG_SIMBA=y
 CONFIG_SUNHME=y
 CONFIG_MC146818RTC=y
 CONFIG_ISA_TESTDEV=y
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a4537af400..b334c82eda 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1404,7 +1404,7 @@ static void machvirt_init(MachineState *machine)
                                      "secure-memory", &error_abort);
         }
 
-        object_property_set_bool(cpuobj, true, "realized", NULL);
+        object_property_set_bool(cpuobj, true, "realized", &error_fatal);
         object_unref(cpuobj);
     }
     fdt_add_timer_nodes(vms);
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 1ac356d3a5..51a58fefba 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -91,7 +91,19 @@ static uint8_t nvme_sq_empty(NvmeSQueue *sq)
     return sq->head == sq->tail;
 }
 
-static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
+static void nvme_irq_check(NvmeCtrl *n)
+{
+    if (msix_enabled(&(n->parent_obj))) {
+        return;
+    }
+    if (~n->bar.intms & n->irq_status) {
+        pci_irq_assert(&n->parent_obj);
+    } else {
+        pci_irq_deassert(&n->parent_obj);
+    }
+}
+
+static void nvme_irq_assert(NvmeCtrl *n, NvmeCQueue *cq)
 {
     if (cq->irq_enabled) {
         if (msix_enabled(&(n->parent_obj))) {
@@ -99,13 +111,28 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
             msix_notify(&(n->parent_obj), cq->vector);
         } else {
             trace_nvme_irq_pin();
-            pci_irq_pulse(&n->parent_obj);
+            assert(cq->cqid < 64);
+            n->irq_status |= 1 << cq->cqid;
+            nvme_irq_check(n);
         }
     } else {
         trace_nvme_irq_masked();
     }
 }
 
+static void nvme_irq_deassert(NvmeCtrl *n, NvmeCQueue *cq)
+{
+    if (cq->irq_enabled) {
+        if (msix_enabled(&(n->parent_obj))) {
+            return;
+        } else {
+            assert(cq->cqid < 64);
+            n->irq_status &= ~(1 << cq->cqid);
+            nvme_irq_check(n);
+        }
+    }
+}
+
 static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
                              uint64_t prp2, uint32_t len, NvmeCtrl *n)
 {
@@ -242,7 +269,7 @@ static void nvme_post_cqes(void *opaque)
             sizeof(req->cqe));
         QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
     }
-    nvme_isr_notify(n, cq);
+    nvme_irq_assert(n, cq);
 }
 
 static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
@@ -905,6 +932,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
         n->bar.intmc = n->bar.intms;
         trace_nvme_mmio_intm_set(data & 0xffffffff,
                                  n->bar.intmc);
+        nvme_irq_check(n);
         break;
     case 0x10:  /* INTMC */
         if (unlikely(msix_enabled(&(n->parent_obj)))) {
@@ -917,6 +945,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
         n->bar.intmc = n->bar.intms;
         trace_nvme_mmio_intm_clr(data & 0xffffffff,
                                  n->bar.intmc);
+        nvme_irq_check(n);
         break;
     case 0x14:  /* CC */
         trace_nvme_mmio_cfg(data & 0xffffffff);
@@ -1085,8 +1114,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
             timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
         }
 
-        if (cq->tail != cq->head) {
-            nvme_isr_notify(n, cq);
+        if (cq->tail == cq->head) {
+            nvme_irq_deassert(n, cq);
         }
     } else {
         /* Submission queue doorbell write */
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 6aab338ff5..7b62dad072 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -775,6 +775,7 @@ typedef struct NvmeCtrl {
     uint32_t    cmbsz;
     uint32_t    cmbloc;
     uint8_t     *cmbuf;
+    uint64_t    irq_status;
 
     char            *serial;
     NvmeNamespace   *namespaces;
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index f8d7a4aaed..1240728c87 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -1,11 +1,12 @@
 # core qdev-related obj files, also used by *-user:
 common-obj-y += qdev.o qdev-properties.o
 common-obj-y += bus.o reset.o
-common-obj-y += fw-path-provider.o
+common-obj-$(CONFIG_SOFTMMU) += qdev-fw.o
+common-obj-$(CONFIG_SOFTMMU) += fw-path-provider.o
 # irq.o needed for qdev GPIO handling:
 common-obj-y += irq.o
 common-obj-y += hotplug.o
-common-obj-y += nmi.o
+common-obj-$(CONFIG_SOFTMMU) += nmi.o
 
 common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
 common-obj-$(CONFIG_XILINX_AXI) += stream.o
diff --git a/hw/core/qdev-fw.c b/hw/core/qdev-fw.c
new file mode 100644
index 0000000000..aa35e9d0ac
--- /dev/null
+++ b/hw/core/qdev-fw.c
@@ -0,0 +1,96 @@
+/*
+ *  qdev fw helpers
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License,
+ *  or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev.h"
+#include "hw/fw-path-provider.h"
+
+const char *qdev_fw_name(DeviceState *dev)
+{
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+    if (dc->fw_name) {
+        return dc->fw_name;
+    }
+
+    return object_get_typename(OBJECT(dev));
+}
+
+static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
+{
+    BusClass *bc = BUS_GET_CLASS(bus);
+
+    if (bc->get_fw_dev_path) {
+        return bc->get_fw_dev_path(dev);
+    }
+
+    return NULL;
+}
+
+static char *qdev_get_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
+{
+    Object *obj = OBJECT(dev);
+    char *d = NULL;
+
+    while (!d && obj->parent) {
+        obj = obj->parent;
+        d = fw_path_provider_try_get_dev_path(obj, bus, dev);
+    }
+    return d;
+}
+
+char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
+{
+    Object *obj = OBJECT(dev);
+
+    return fw_path_provider_try_get_dev_path(obj, bus, dev);
+}
+
+static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
+{
+    int l = 0;
+
+    if (dev && dev->parent_bus) {
+        char *d;
+        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
+        d = qdev_get_fw_dev_path_from_handler(dev->parent_bus, dev);
+        if (!d) {
+            d = bus_get_fw_dev_path(dev->parent_bus, dev);
+        }
+        if (d) {
+            l += snprintf(p + l, size - l, "%s", d);
+            g_free(d);
+        } else {
+            return l;
+        }
+    }
+    l += snprintf(p + l , size - l, "/");
+
+    return l;
+}
+
+char *qdev_get_fw_dev_path(DeviceState *dev)
+{
+    char path[128];
+    int l;
+
+    l = qdev_get_fw_dev_path_helper(dev, path, 128);
+
+    path[l - 1] = '\0';
+
+    return g_strdup(path);
+}
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index f739753e3a..2456035d1a 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -27,7 +27,6 @@
 
 #include "qemu/osdep.h"
 #include "hw/qdev.h"
-#include "hw/fw-path-provider.h"
 #include "sysemu/sysemu.h"
 #include "qapi/qmp/qerror.h"
 #include "qapi/visitor.h"
@@ -48,17 +47,6 @@ const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
     return dc->vmsd;
 }
 
-const char *qdev_fw_name(DeviceState *dev)
-{
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
-    if (dc->fw_name) {
-        return dc->fw_name;
-    }
-
-    return object_get_typename(OBJECT(dev));
-}
-
 static void bus_remove_child(BusState *bus, DeviceState *child)
 {
     BusChild *kid;
@@ -631,71 +619,6 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
     return NULL;
 }
 
-static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
-{
-    BusClass *bc = BUS_GET_CLASS(bus);
-
-    if (bc->get_fw_dev_path) {
-        return bc->get_fw_dev_path(dev);
-    }
-
-    return NULL;
-}
-
-static char *qdev_get_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
-{
-    Object *obj = OBJECT(dev);
-    char *d = NULL;
-
-    while (!d && obj->parent) {
-        obj = obj->parent;
-        d = fw_path_provider_try_get_dev_path(obj, bus, dev);
-    }
-    return d;
-}
-
-char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
-{
-    Object *obj = OBJECT(dev);
-
-    return fw_path_provider_try_get_dev_path(obj, bus, dev);
-}
-
-static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
-{
-    int l = 0;
-
-    if (dev && dev->parent_bus) {
-        char *d;
-        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
-        d = qdev_get_fw_dev_path_from_handler(dev->parent_bus, dev);
-        if (!d) {
-            d = bus_get_fw_dev_path(dev->parent_bus, dev);
-        }
-        if (d) {
-            l += snprintf(p + l, size - l, "%s", d);
-            g_free(d);
-        } else {
-            return l;
-        }
-    }
-    l += snprintf(p + l , size - l, "/");
-
-    return l;
-}
-
-char* qdev_get_fw_dev_path(DeviceState *dev)
-{
-    char path[128];
-    int l;
-
-    l = qdev_get_fw_dev_path_helper(dev, path, 128);
-
-    path[l-1] = '\0';
-
-    return g_strdup(path);
-}
-
 char *qdev_get_dev_path(DeviceState *dev)
 {
     BusClass *bc;
diff --git a/hw/display/pl110.c b/hw/display/pl110.c
index 8c7dcc6f0a..cf68457fd1 100644
--- a/hw/display/pl110.c
+++ b/hw/display/pl110.c
@@ -12,6 +12,7 @@
 #include "ui/console.h"
 #include "framebuffer.h"
 #include "ui/pixel_ops.h"
+#include "qemu/timer.h"
 #include "qemu/log.h"
 
 #define PL110_CR_EN   0x001
@@ -19,6 +20,8 @@
 #define PL110_CR_BEBO 0x200
 #define PL110_CR_BEPO 0x400
 #define PL110_CR_PWR  0x800
+#define PL110_IE_NB   0x004
+#define PL110_IE_VC   0x008
 
 enum pl110_bppmode
 {
@@ -50,6 +53,7 @@ typedef struct PL110State {
     MemoryRegion iomem;
     MemoryRegionSection fbsection;
     QemuConsole *con;
+    QEMUTimer *vblank_timer;
 
     int version;
     uint32_t timing[4];
@@ -320,7 +324,24 @@ static void pl110_resize(PL110State *s, int width, int height)
 /* Update interrupts.  */
 static void pl110_update(PL110State *s)
 {
-  /* TODO: Implement interrupts.  */
+    /* Raise IRQ if enabled and any status bit is 1 */
+    if (s->int_status & s->int_mask) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void pl110_vblank_interrupt(void *opaque)
+{
+    PL110State *s = opaque;
+
+    /* Fire the vertical compare and next base IRQs and re-arm */
+    s->int_status |= (PL110_IE_NB | PL110_IE_VC);
+    timer_mod(s->vblank_timer,
+              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+                                NANOSECONDS_PER_SECOND / 60);
+    pl110_update(s);
 }
 
 static uint64_t pl110_read(void *opaque, hwaddr offset,
@@ -429,6 +450,11 @@ static void pl110_write(void *opaque, hwaddr offset,
         s->bpp = (val >> 1) & 7;
         if (pl110_enabled(s)) {
             qemu_console_resize(s->con, s->cols, s->rows);
+            timer_mod(s->vblank_timer,
+                      qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+                                        NANOSECONDS_PER_SECOND / 60);
+        } else {
+            timer_del(s->vblank_timer);
         }
         break;
     case 10: /* LCDICR */
@@ -474,6 +500,8 @@ static void pl110_realize(DeviceState *dev, Error **errp)
     memory_region_init_io(&s->iomem, OBJECT(s), &pl110_ops, s, "pl110", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->irq);
+    s->vblank_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                   pl110_vblank_interrupt, s);
     qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
     s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
 }
diff --git a/hw/display/vga.c b/hw/display/vga.c
index a0412000a5..6e78a4e156 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1279,6 +1279,9 @@ static void vga_draw_text(VGACommonState *s, int full_update)
         cx_min = width;
         cx_max = -1;
         for(cx = 0; cx < width; cx++) {
+            if (src + sizeof(uint16_t) > s->vram_ptr + s->vram_size) {
+                break;
+            }
             ch_attr = *(uint16_t *)src;
             if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
                 if (cx < cx_min)
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index d701e49ff9..724bc9fa61 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -93,6 +93,7 @@ void gic_update(GICState *s)
         best_irq = 1023;
         for (irq = 0; irq < s->num_irq; irq++) {
             if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) &&
+                (!GIC_TEST_ACTIVE(irq, cm)) &&
                 (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) {
                 if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                     best_prio = GIC_GET_PRIORITY(irq, cpu);
@@ -255,7 +256,8 @@ static int gic_get_group_priority(GICState *s, int cpu, int irq)
     if (gic_has_groups(s) &&
         !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) &&
         GIC_TEST_GROUP(irq, (1 << cpu))) {
-        bpr = s->abpr[cpu];
+        bpr = s->abpr[cpu] - 1;
+        assert(bpr >= 0);
     } else {
         bpr = s->bpr[cpu];
     }
@@ -503,6 +505,11 @@ static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value,
 
 static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs)
 {
+    if ((s->revision != REV_11MPCORE) && (s->running_priority[cpu] > 0xff)) {
+        /* Idle priority */
+        return 0xff;
+    }
+
     if (s->security_extn && !attrs.secure) {
         if (s->running_priority[cpu] & 0x80) {
             /* Running priority in upper half of range: return the Non-secure
@@ -1205,8 +1212,13 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
         break;
     case 0x08: /* Binary Point */
         if (s->security_extn && !attrs.secure) {
-            /* BPR is banked. Non-secure copy stored in ABPR. */
-            *data = s->abpr[cpu];
+            if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) {
+                /* NS view of BPR when CBPR is 1 */
+                *data = MIN(s->bpr[cpu] + 1, 7);
+            } else {
+                /* BPR is banked. Non-secure copy stored in ABPR. */
+                *data = s->abpr[cpu];
+            }
         } else {
             *data = s->bpr[cpu];
         }
@@ -1279,7 +1291,12 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
         break;
     case 0x08: /* Binary Point */
         if (s->security_extn && !attrs.secure) {
-            s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR);
+            if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) {
+                /* WI when CBPR is 1 */
+                return MEMTX_OK;
+            } else {
+                s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR);
+            }
         } else {
             s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR);
         }
diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c
index 94659ee256..d6f9cb3692 100644
--- a/hw/intc/grlib_irqmp.c
+++ b/hw/intc/grlib_irqmp.c
@@ -106,6 +106,15 @@ static void grlib_irqmp_check_irqs(IRQMPState *state)
     }
 }
 
+static void grlib_irqmp_ack_mask(IRQMPState *state, uint32_t mask)
+{
+    /* Clear registers */
+    state->pending  &= ~mask;
+    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
+
+    grlib_irqmp_check_irqs(state);
+}
+
 void grlib_irqmp_ack(DeviceState *dev, int intno)
 {
     IRQMP        *irqmp = GRLIB_IRQMP(dev);
@@ -120,11 +129,7 @@ void grlib_irqmp_ack(DeviceState *dev, int intno)
 
     trace_grlib_irqmp_ack(intno);
 
-    /* Clear registers */
-    state->pending  &= ~mask;
-    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
-
-    grlib_irqmp_check_irqs(state);
+    grlib_irqmp_ack_mask(state, mask);
 }
 
 void grlib_irqmp_set_irq(void *opaque, int irq, int level)
@@ -251,7 +256,7 @@ static void grlib_irqmp_write(void *opaque, hwaddr addr,
 
     case CLEAR_OFFSET:
         value &= ~1; /* clean up the value */
-        state->pending &= ~value;
+        grlib_irqmp_ack_mask(state, value);
         return;
 
     case MP_STATUS_OFFSET:
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 4fb48f62ba..9506f9b69f 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -595,19 +595,16 @@ static void imx_eth_do_tx(IMXFECState *s, uint32_t index)
 static void imx_eth_enable_rx(IMXFECState *s, bool flush)
 {
     IMXFECBufDesc bd;
-    bool rx_ring_full;
 
     imx_fec_read_bd(&bd, s->rx_descriptor);
 
-    rx_ring_full = !(bd.flags & ENET_BD_E);
+    s->regs[ENET_RDAR] = (bd.flags & ENET_BD_E) ? ENET_RDAR_RDAR : 0;
 
-    if (rx_ring_full) {
+    if (!s->regs[ENET_RDAR]) {
         FEC_PRINTF("RX buffer full\n");
     } else if (flush) {
         qemu_flush_queued_packets(qemu_get_queue(s->nic));
     }
-
-    s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR;
 }
 
 static void imx_eth_reset(DeviceState *d)
@@ -866,7 +863,6 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
     case ENET_RDAR:
         if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) {
             if (!s->regs[index]) {
-                s->regs[index] = ENET_RDAR_RDAR;
                 imx_eth_enable_rx(s, true);
             }
         } else {
diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
index 1b05023662..47065f87d9 100644
--- a/hw/pci-bridge/Makefile.objs
+++ b/hw/pci-bridge/Makefile.objs
@@ -6,3 +6,5 @@ common-obj-$(CONFIG_IOH3420) += ioh3420.o
 common-obj-$(CONFIG_I82801B11) += i82801b11.o
 # NewWorld PowerMac
 common-obj-$(CONFIG_DEC_PCI) += dec.o
+# Sun4u
+common-obj-$(CONFIG_SIMBA) += simba.o
diff --git a/hw/pci-bridge/simba.c b/hw/pci-bridge/simba.c
new file mode 100644
index 0000000000..dea4c8c5e7
--- /dev/null
+++ b/hw/pci-bridge/simba.c
@@ -0,0 +1,101 @@
+/*
+ * QEMU Simba PCI bridge
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2012,2013 Artyom Tarasenko
+ * Copyright (c) 2018 Mark Cave-Ayland
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci-bridge/simba.h"
+
+/*
+ * Chipset docs:
+ * APB: "Advanced PCI Bridge (APB) User's Manual",
+ * http://www.sun.com/processors/manuals/805-1251.pdf
+ */
+
+static void simba_pci_bridge_realize(PCIDevice *dev, Error **errp)
+{
+    /*
+     * command register:
+     * According to PCI bridge spec, after reset
+     *   bus master bit is off
+     *   memory space enable bit is off
+     * According to manual (805-1251.pdf).
+     *   the reset value should be zero unless the boot pin is tied high
+     *   (which is true) and thus it should be PCI_COMMAND_MEMORY.
+     */
+    SimbaPCIBridge *br = SIMBA_PCI_BRIDGE(dev);
+
+    pci_bridge_initfn(dev, TYPE_PCI_BUS);
+
+    pci_set_word(dev->config + PCI_COMMAND, PCI_COMMAND_MEMORY);
+    pci_set_word(dev->config + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+
+    /* Allow 32-bit IO addresses */
+    pci_set_word(dev->config + PCI_IO_BASE, PCI_IO_RANGE_TYPE_32);
+    pci_set_word(dev->config + PCI_IO_LIMIT, PCI_IO_RANGE_TYPE_32);
+    pci_set_word(dev->wmask + PCI_IO_BASE_UPPER16, 0xffff);
+    pci_set_word(dev->wmask + PCI_IO_LIMIT_UPPER16, 0xffff);
+
+    pci_bridge_update_mappings(PCI_BRIDGE(br));
+}
+
+static void simba_pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->realize = simba_pci_bridge_realize;
+    k->exit = pci_bridge_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_SUN;
+    k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
+    k->revision = 0x11;
+    k->config_write = pci_bridge_write_config;
+    k->is_bridge = 1;
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+    dc->reset = pci_bridge_reset;
+    dc->vmsd = &vmstate_pci_device;
+}
+
+static const TypeInfo simba_pci_bridge_info = {
+    .name          = TYPE_SIMBA_PCI_BRIDGE,
+    .parent        = TYPE_PCI_BRIDGE,
+    .class_init    = simba_pci_bridge_class_init,
+    .instance_size = sizeof(SimbaPCIBridge),
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void simba_register_types(void)
+{
+    type_register_static(&simba_pci_bridge_info);
+}
+
+type_init(simba_register_types)
diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs
index 9c7909cf44..4b69f737b5 100644
--- a/hw/pci-host/Makefile.objs
+++ b/hw/pci-host/Makefile.objs
@@ -11,7 +11,7 @@ common-obj-$(CONFIG_PPCE500_PCI) += ppce500.o
 # ARM devices
 common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o
 
-common-obj-$(CONFIG_PCI_APB) += apb.o
+common-obj-$(CONFIG_PCI_SABRE) += sabre.o
 common-obj-$(CONFIG_FULONG) += bonito.o
 common-obj-$(CONFIG_PCI_PIIX) += piix.o
 common-obj-$(CONFIG_PCI_Q35) += q35.o
diff --git a/hw/pci-host/apb.c b/hw/pci-host/sabre.c
index ec676f94b6..2268a41dd9 100644
--- a/hw/pci-host/apb.c
+++ b/hw/pci-host/sabre.c
@@ -1,8 +1,9 @@
 /*
- * QEMU Ultrasparc APB PCI host
+ * QEMU Ultrasparc Sabre PCI host (PBM)
  *
  * Copyright (c) 2006 Fabrice Bellard
  * Copyright (c) 2012,2013 Artyom Tarasenko
+ * Copyright (c) 2018 Mark Cave-Ayland
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -23,39 +24,24 @@
  * THE SOFTWARE.
  */
 
-/* XXX This file and most of its contents are somewhat misnamed.  The
-   Ultrasparc PCI host is called the PCI Bus Module (PBM).  The APB is
-   the secondary PCI bridge.  */
-
 #include "qemu/osdep.h"
 #include "hw/sysbus.h"
 #include "hw/pci/pci.h"
 #include "hw/pci/pci_host.h"
 #include "hw/pci/pci_bridge.h"
 #include "hw/pci/pci_bus.h"
-#include "hw/pci-host/apb.h"
+#include "hw/pci-bridge/simba.h"
+#include "hw/pci-host/sabre.h"
 #include "sysemu/sysemu.h"
 #include "exec/address-spaces.h"
 #include "qapi/error.h"
 #include "qemu/log.h"
-
-/* debug APB */
-//#define DEBUG_APB
-
-#ifdef DEBUG_APB
-#define APB_DPRINTF(fmt, ...) \
-do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define APB_DPRINTF(fmt, ...)
-#endif
+#include "trace.h"
 
 /*
  * Chipset docs:
  * PBM: "UltraSPARC IIi User's Manual",
  * http://www.sun.com/processors/manuals/805-0087.pdf
- *
- * APB: "Advanced PCI Bridge (APB) User's Manual",
- * http://www.sun.com/processors/manuals/805-1251.pdf
  */
 
 #define PBM_PCI_IMR_MASK    0x7fffffff
@@ -72,22 +58,20 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
 
 #define NO_IRQ_REQUEST (MAX_IVEC + 1)
 
-static inline void pbm_set_request(APBState *s, unsigned int irq_num)
+static inline void sabre_set_request(SabreState *s, unsigned int irq_num)
 {
-    APB_DPRINTF("%s: request irq %d\n", __func__, irq_num);
-
+    trace_sabre_set_request(irq_num);
     s->irq_request = irq_num;
     qemu_set_irq(s->ivec_irqs[irq_num], 1);
 }
 
-static inline void pbm_check_irqs(APBState *s)
+static inline void sabre_check_irqs(SabreState *s)
 {
-
     unsigned int i;
 
     /* Previous request is not acknowledged, resubmit */
     if (s->irq_request != NO_IRQ_REQUEST) {
-        pbm_set_request(s, s->irq_request);
+        sabre_set_request(s, s->irq_request);
         return;
     }
     /* no request pending */
@@ -97,7 +81,7 @@ static inline void pbm_check_irqs(APBState *s)
     for (i = 0; i < 32; i++) {
         if (s->pci_irq_in & (1ULL << i)) {
             if (s->pci_irq_map[i >> 2] & PBM_PCI_IMR_ENABLED) {
-                pbm_set_request(s, i);
+                sabre_set_request(s, i);
                 return;
             }
         }
@@ -105,33 +89,33 @@ static inline void pbm_check_irqs(APBState *s)
     for (i = 32; i < 64; i++) {
         if (s->pci_irq_in & (1ULL << i)) {
             if (s->obio_irq_map[i - 32] & PBM_PCI_IMR_ENABLED) {
-                pbm_set_request(s, i);
+                sabre_set_request(s, i);
                 break;
             }
         }
     }
 }
 
-static inline void pbm_clear_request(APBState *s, unsigned int irq_num)
+static inline void sabre_clear_request(SabreState *s, unsigned int irq_num)
 {
-    APB_DPRINTF("%s: clear request irq %d\n", __func__, irq_num);
+    trace_sabre_clear_request(irq_num);
     qemu_set_irq(s->ivec_irqs[irq_num], 0);
     s->irq_request = NO_IRQ_REQUEST;
 }
 
-static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
+static AddressSpace *sabre_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
 {
     IOMMUState *is = opaque;
 
     return &is->iommu_as;
 }
 
-static void apb_config_writel (void *opaque, hwaddr addr,
+static void sabre_config_write(void *opaque, hwaddr addr,
                                uint64_t val, unsigned size)
 {
-    APBState *s = opaque;
+    SabreState *s = opaque;
 
-    APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
+    trace_sabre_config_write(addr, val);
 
     switch (addr & 0xffff) {
     case 0x30 ... 0x4f: /* DMA error registers */
@@ -143,9 +127,9 @@ static void apb_config_writel (void *opaque, hwaddr addr,
             s->pci_irq_map[ino] &= PBM_PCI_IMR_MASK;
             s->pci_irq_map[ino] |= val & ~PBM_PCI_IMR_MASK;
             if ((s->irq_request == ino) && !(val & ~PBM_PCI_IMR_MASK)) {
-                pbm_clear_request(s, ino);
+                sabre_clear_request(s, ino);
             }
-            pbm_check_irqs(s);
+            sabre_check_irqs(s);
         }
         break;
     case 0x1000 ... 0x107f: /* OBIO interrupt control */
@@ -155,17 +139,17 @@ static void apb_config_writel (void *opaque, hwaddr addr,
             s->obio_irq_map[ino] |= val & ~PBM_PCI_IMR_MASK;
             if ((s->irq_request == (ino | 0x20))
                  && !(val & ~PBM_PCI_IMR_MASK)) {
-                pbm_clear_request(s, ino | 0x20);
+                sabre_clear_request(s, ino | 0x20);
             }
-            pbm_check_irqs(s);
+            sabre_check_irqs(s);
         }
         break;
     case 0x1400 ... 0x14ff: /* PCI interrupt clear */
         if (addr & 4) {
             unsigned int ino = (addr & 0xff) >> 5;
             if ((s->irq_request / 4)  == ino) {
-                pbm_clear_request(s, s->irq_request);
-                pbm_check_irqs(s);
+                sabre_clear_request(s, s->irq_request);
+                sabre_check_irqs(s);
             }
         }
         break;
@@ -173,8 +157,8 @@ static void apb_config_writel (void *opaque, hwaddr addr,
         if (addr & 4) {
             unsigned int ino = ((addr & 0xff) >> 3) | 0x20;
             if (s->irq_request == ino) {
-                pbm_clear_request(s, ino);
-                pbm_check_irqs(s);
+                sabre_clear_request(s, ino);
+                sabre_check_irqs(s);
             }
         }
         break;
@@ -204,10 +188,10 @@ static void apb_config_writel (void *opaque, hwaddr addr,
     }
 }
 
-static uint64_t apb_config_readl (void *opaque,
+static uint64_t sabre_config_read(void *opaque,
                                   hwaddr addr, unsigned size)
 {
-    APBState *s = opaque;
+    SabreState *s = opaque;
     uint32_t val;
 
     switch (addr & 0xffff) {
@@ -255,47 +239,47 @@ static uint64_t apb_config_readl (void *opaque,
         val = 0;
         break;
     }
-    APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, val);
+    trace_sabre_config_read(addr, val);
 
     return val;
 }
 
-static const MemoryRegionOps apb_config_ops = {
-    .read = apb_config_readl,
-    .write = apb_config_writel,
+static const MemoryRegionOps sabre_config_ops = {
+    .read = sabre_config_read,
+    .write = sabre_config_write,
     .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static void apb_pci_config_write(void *opaque, hwaddr addr,
-                                 uint64_t val, unsigned size)
+static void sabre_pci_config_write(void *opaque, hwaddr addr,
+                                   uint64_t val, unsigned size)
 {
-    APBState *s = opaque;
+    SabreState *s = opaque;
     PCIHostState *phb = PCI_HOST_BRIDGE(s);
 
-    APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
+    trace_sabre_pci_config_write(addr, val);
     pci_data_write(phb->bus, addr, val, size);
 }
 
-static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
-                                    unsigned size)
+static uint64_t sabre_pci_config_read(void *opaque, hwaddr addr,
+                                      unsigned size)
 {
     uint32_t ret;
-    APBState *s = opaque;
+    SabreState *s = opaque;
     PCIHostState *phb = PCI_HOST_BRIDGE(s);
 
     ret = pci_data_read(phb->bus, addr, size);
-    APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, ret);
+    trace_sabre_pci_config_read(addr, ret);
     return ret;
 }
 
-/* The APB host has an IRQ line for each IRQ line of each slot.  */
-static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
+/* The sabre host has an IRQ line for each IRQ line of each slot.  */
+static int pci_sabre_map_irq(PCIDevice *pci_dev, int irq_num)
 {
     /* Return the irq as swizzled by the PBM */
     return irq_num;
 }
 
-static int pci_pbmA_map_irq(PCIDevice *pci_dev, int irq_num)
+static int pci_simbaA_map_irq(PCIDevice *pci_dev, int irq_num)
 {
     /* The on-board devices have fixed (legacy) OBIO intnos */
     switch (PCI_SLOT(pci_dev->devfn)) {
@@ -313,22 +297,23 @@ static int pci_pbmA_map_irq(PCIDevice *pci_dev, int irq_num)
     return ((PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
 }
 
-static int pci_pbmB_map_irq(PCIDevice *pci_dev, int irq_num)
+static int pci_simbaB_map_irq(PCIDevice *pci_dev, int irq_num)
 {
     return (0x10 + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
 }
 
-static void pci_apb_set_irq(void *opaque, int irq_num, int level)
+static void pci_sabre_set_irq(void *opaque, int irq_num, int level)
 {
-    APBState *s = opaque;
+    SabreState *s = opaque;
+
+    trace_sabre_pci_set_irq(irq_num, level);
 
-    APB_DPRINTF("%s: set irq_in %d level %d\n", __func__, irq_num, level);
     /* PCI IRQ map onto the first 32 INO.  */
     if (irq_num < 32) {
         if (level) {
             s->pci_irq_in |= 1ULL << irq_num;
             if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
-                pbm_set_request(s, irq_num);
+                sabre_set_request(s, irq_num);
             }
         } else {
             s->pci_irq_in &= ~(1ULL << irq_num);
@@ -336,11 +321,11 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
     } else {
         /* OBIO IRQ map onto the next 32 INO.  */
         if (level) {
-            APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
+            trace_sabre_pci_set_obio_irq(irq_num, level);
             s->pci_irq_in |= 1ULL << irq_num;
             if ((s->irq_request == NO_IRQ_REQUEST)
                 && (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED)) {
-                pbm_set_request(s, irq_num);
+                sabre_set_request(s, irq_num);
             }
         } else {
             s->pci_irq_in &= ~(1ULL << irq_num);
@@ -348,38 +333,9 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
     }
 }
 
-static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp)
+static void sabre_reset(DeviceState *d)
 {
-    /*
-     * command register:
-     * According to PCI bridge spec, after reset
-     *   bus master bit is off
-     *   memory space enable bit is off
-     * According to manual (805-1251.pdf).
-     *   the reset value should be zero unless the boot pin is tied high
-     *   (which is true) and thus it should be PCI_COMMAND_MEMORY.
-     */
-    PBMPCIBridge *br = PBM_PCI_BRIDGE(dev);
-
-    pci_bridge_initfn(dev, TYPE_PCI_BUS);
-
-    pci_set_word(dev->config + PCI_COMMAND, PCI_COMMAND_MEMORY);
-    pci_set_word(dev->config + PCI_STATUS,
-                 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
-                 PCI_STATUS_DEVSEL_MEDIUM);
-
-    /* Allow 32-bit IO addresses */
-    pci_set_word(dev->config + PCI_IO_BASE, PCI_IO_RANGE_TYPE_32);
-    pci_set_word(dev->config + PCI_IO_LIMIT, PCI_IO_RANGE_TYPE_32);
-    pci_set_word(dev->wmask + PCI_IO_BASE_UPPER16, 0xffff);
-    pci_set_word(dev->wmask + PCI_IO_LIMIT_UPPER16, 0xffff);
-
-    pci_bridge_update_mappings(PCI_BRIDGE(br));
-}
-
-static void pci_pbm_reset(DeviceState *d)
-{
-    APBState *s = APB_DEVICE(d);
+    SabreState *s = SABRE_DEVICE(d);
     PCIDevice *pci_dev;
     unsigned int i;
     uint16_t cmd;
@@ -410,19 +366,19 @@ static void pci_pbm_reset(DeviceState *d)
 }
 
 static const MemoryRegionOps pci_config_ops = {
-    .read = apb_pci_config_read,
-    .write = apb_pci_config_write,
+    .read = sabre_pci_config_read,
+    .write = sabre_pci_config_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void pci_pbm_realize(DeviceState *dev, Error **errp)
+static void sabre_realize(DeviceState *dev, Error **errp)
 {
-    APBState *s = APB_DEVICE(dev);
+    SabreState *s = SABRE_DEVICE(dev);
     PCIHostState *phb = PCI_HOST_BRIDGE(dev);
     SysBusDevice *sbd = SYS_BUS_DEVICE(s);
     PCIDevice *pci_dev;
 
-    /* apb_config */
+    /* sabre_config */
     sysbus_mmio_map(sbd, 0, s->special_base);
     /* PCI configuration space */
     sysbus_mmio_map(sbd, 1, s->special_base + 0x1000000ULL);
@@ -434,35 +390,35 @@ static void pci_pbm_realize(DeviceState *dev, Error **errp)
                                 &s->pci_mmio);
 
     phb->bus = pci_register_root_bus(dev, "pci",
-                                     pci_apb_set_irq, pci_apb_map_irq, s,
+                                     pci_sabre_set_irq, pci_sabre_map_irq, s,
                                      &s->pci_mmio,
                                      &s->pci_ioport,
                                      0, 32, TYPE_PCI_BUS);
 
-    pci_create_simple(phb->bus, 0, "pbm-pci");
+    pci_create_simple(phb->bus, 0, TYPE_SABRE_PCI_DEVICE);
 
-    /* APB IOMMU */
-    memory_region_add_subregion_overlap(&s->apb_config, 0x200,
+    /* IOMMU */
+    memory_region_add_subregion_overlap(&s->sabre_config, 0x200,
                     sysbus_mmio_get_region(SYS_BUS_DEVICE(s->iommu), 0), 1);
-    pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, s->iommu);
+    pci_setup_iommu(phb->bus, sabre_pci_dma_iommu, s->iommu);
 
     /* APB secondary busses */
     pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
-                                   TYPE_PBM_PCI_BRIDGE);
+                                       TYPE_SIMBA_PCI_BRIDGE);
     s->bridgeB = PCI_BRIDGE(pci_dev);
-    pci_bridge_map_irq(s->bridgeB, "pciB", pci_pbmB_map_irq);
+    pci_bridge_map_irq(s->bridgeB, "pciB", pci_simbaB_map_irq);
     qdev_init_nofail(&pci_dev->qdev);
 
     pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true,
-                                   TYPE_PBM_PCI_BRIDGE);
+                                       TYPE_SIMBA_PCI_BRIDGE);
     s->bridgeA = PCI_BRIDGE(pci_dev);
-    pci_bridge_map_irq(s->bridgeA, "pciA", pci_pbmA_map_irq);
+    pci_bridge_map_irq(s->bridgeA, "pciA", pci_simbaA_map_irq);
     qdev_init_nofail(&pci_dev->qdev);
 }
 
-static void pci_pbm_init(Object *obj)
+static void sabre_init(Object *obj)
 {
-    APBState *s = APB_DEVICE(obj);
+    SabreState *s = SABRE_DEVICE(obj);
     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     unsigned int i;
 
@@ -475,7 +431,7 @@ static void pci_pbm_init(Object *obj)
     for (i = 0; i < 32; i++) {
         s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i;
     }
-    qdev_init_gpio_in_named(DEVICE(s), pci_apb_set_irq, "pbm-irq", MAX_IVEC);
+    qdev_init_gpio_in_named(DEVICE(s), pci_sabre_set_irq, "pbm-irq", MAX_IVEC);
     qdev_init_gpio_out_named(DEVICE(s), s->ivec_irqs, "ivec-irq", MAX_IVEC);
     s->irq_request = NO_IRQ_REQUEST;
     s->pci_irq_in = 0ULL;
@@ -486,25 +442,26 @@ static void pci_pbm_init(Object *obj)
                              qdev_prop_allow_set_link_before_realize,
                              0, NULL);
 
-    /* apb_config */
-    memory_region_init_io(&s->apb_config, OBJECT(s), &apb_config_ops, s,
-                          "apb-config", 0x10000);
+    /* sabre_config */
+    memory_region_init_io(&s->sabre_config, OBJECT(s), &sabre_config_ops, s,
+                          "sabre-config", 0x10000);
     /* at region 0 */
-    sysbus_init_mmio(sbd, &s->apb_config);
+    sysbus_init_mmio(sbd, &s->sabre_config);
 
     memory_region_init_io(&s->pci_config, OBJECT(s), &pci_config_ops, s,
-                          "apb-pci-config", 0x1000000);
+                          "sabre-pci-config", 0x1000000);
     /* at region 1 */
     sysbus_init_mmio(sbd, &s->pci_config);
 
     /* pci_ioport */
-    memory_region_init(&s->pci_ioport, OBJECT(s), "apb-pci-ioport", 0x1000000);
+    memory_region_init(&s->pci_ioport, OBJECT(s), "sabre-pci-ioport",
+                       0x1000000);
 
     /* at region 2 */
     sysbus_init_mmio(sbd, &s->pci_ioport);
 }
 
-static void pbm_pci_host_realize(PCIDevice *d, Error **errp)
+static void sabre_pci_realize(PCIDevice *d, Error **errp)
 {
     pci_set_word(d->config + PCI_COMMAND,
                  PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
@@ -513,12 +470,12 @@ static void pbm_pci_host_realize(PCIDevice *d, Error **errp)
                  PCI_STATUS_DEVSEL_MEDIUM);
 }
 
-static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
+static void sabre_pci_class_init(ObjectClass *klass, void *data)
 {
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
 
-    k->realize = pbm_pci_host_realize;
+    k->realize = sabre_pci_realize;
     k->vendor_id = PCI_VENDOR_ID_SUN;
     k->device_id = PCI_DEVICE_ID_SUN_SABRE;
     k->class_id = PCI_CLASS_BRIDGE_HOST;
@@ -529,74 +486,45 @@ static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
     dc->user_creatable = false;
 }
 
-static const TypeInfo pbm_pci_host_info = {
-    .name          = "pbm-pci",
+static const TypeInfo sabre_pci_info = {
+    .name          = TYPE_SABRE_PCI_DEVICE,
     .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init    = pbm_pci_host_class_init,
+    .instance_size = sizeof(SabrePCIState),
+    .class_init    = sabre_pci_class_init,
     .interfaces = (InterfaceInfo[]) {
         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
         { },
     },
 };
 
-static Property pbm_pci_host_properties[] = {
-    DEFINE_PROP_UINT64("special-base", APBState, special_base, 0),
-    DEFINE_PROP_UINT64("mem-base", APBState, mem_base, 0),
+static Property sabre_properties[] = {
+    DEFINE_PROP_UINT64("special-base", SabreState, special_base, 0),
+    DEFINE_PROP_UINT64("mem-base", SabreState, mem_base, 0),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void pbm_host_class_init(ObjectClass *klass, void *data)
+static void sabre_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
 
-    dc->realize = pci_pbm_realize;
-    dc->reset = pci_pbm_reset;
-    dc->props = pbm_pci_host_properties;
+    dc->realize = sabre_realize;
+    dc->reset = sabre_reset;
+    dc->props = sabre_properties;
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 }
 
-static const TypeInfo pbm_host_info = {
-    .name          = TYPE_APB,
+static const TypeInfo sabre_info = {
+    .name          = TYPE_SABRE,
     .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(APBState),
-    .instance_init = pci_pbm_init,
-    .class_init    = pbm_host_class_init,
-};
-
-static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->realize = apb_pci_bridge_realize;
-    k->exit = pci_bridge_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_SUN;
-    k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
-    k->revision = 0x11;
-    k->config_write = pci_bridge_write_config;
-    k->is_bridge = 1;
-    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-    dc->reset = pci_bridge_reset;
-    dc->vmsd = &vmstate_pci_device;
-}
-
-static const TypeInfo pbm_pci_bridge_info = {
-    .name          = TYPE_PBM_PCI_BRIDGE,
-    .parent        = TYPE_PCI_BRIDGE,
-    .class_init    = pbm_pci_bridge_class_init,
-    .instance_size = sizeof(PBMPCIBridge),
-    .interfaces = (InterfaceInfo[]) {
-        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
-        { },
-    },
+    .instance_size = sizeof(SabreState),
+    .instance_init = sabre_init,
+    .class_init    = sabre_class_init,
 };
 
-static void pbm_register_types(void)
+static void sabre_register_types(void)
 {
-    type_register_static(&pbm_host_info);
-    type_register_static(&pbm_pci_host_info);
-    type_register_static(&pbm_pci_bridge_info);
+    type_register_static(&sabre_info);
+    type_register_static(&sabre_pci_info);
 }
 
-type_init(pbm_register_types)
+type_init(sabre_register_types)
diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events
new file mode 100644
index 0000000000..32dfc84692
--- /dev/null
+++ b/hw/pci-host/trace-events
@@ -0,0 +1,11 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# hw/pci-host/sabre.c
+sabre_set_request(int irq_num) "request irq %d"
+sabre_clear_request(int irq_num) "clear request irq %d"
+sabre_config_write(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" val 0x%"PRIx64
+sabre_config_read(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" val 0x%"PRIx64
+sabre_pci_config_write(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" val 0x%"PRIx64
+sabre_pci_config_read(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" val 0x%"PRIx64
+sabre_pci_set_irq(int irq_num, int level) "set irq_in %d level %d"
+sabre_pci_set_obio_irq(int irq_num, int level) "set irq %d level %d"
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index f9264d3be5..fac7fa5c72 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -1388,6 +1388,7 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp)
     }
 
     if (s->dma_mr) {
+        s->dma_as = &s->sysbus_dma_as;
         address_space_init(s->dma_as, s->dma_mr, "sdhci-dma");
     } else {
         /* use system_memory() if property "dma" not set */
diff --git a/hw/sparc64/sparc64.c b/hw/sparc64/sparc64.c
index 95a06f00b2..408388945e 100644
--- a/hw/sparc64/sparc64.c
+++ b/hw/sparc64/sparc64.c
@@ -28,25 +28,9 @@
 #include "hw/char/serial.h"
 #include "hw/sparc/sparc64.h"
 #include "qemu/timer.h"
+#include "trace.h"
 
 
-//#define DEBUG_IRQ
-//#define DEBUG_TIMER
-
-#ifdef DEBUG_IRQ
-#define CPUIRQ_DPRINTF(fmt, ...)                                \
-    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define CPUIRQ_DPRINTF(fmt, ...)
-#endif
-
-#ifdef DEBUG_TIMER
-#define TIMER_DPRINTF(fmt, ...)                                  \
-    do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define TIMER_DPRINTF(fmt, ...)
-#endif
-
 #define TICK_MAX             0x7fffffffffffffffULL
 
 void cpu_check_irqs(CPUSPARCState *env)
@@ -73,8 +57,7 @@ void cpu_check_irqs(CPUSPARCState *env)
        is (2 << psrpil). */
     if (pil < (2 << env->psrpil)) {
         if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
-            CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
-                           env->interrupt_index);
+            trace_sparc64_cpu_check_irqs_reset_irq(env->interrupt_index);
             env->interrupt_index = 0;
             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
         }
@@ -92,22 +75,21 @@ void cpu_check_irqs(CPUSPARCState *env)
 
                 if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
                   && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
-                    CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
-                                   "current %x >= pending %x\n",
-                                   env->tl, cpu_tsptr(env)->tt, new_interrupt);
+                    trace_sparc64_cpu_check_irqs_noset_irq(env->tl,
+                                                      cpu_tsptr(env)->tt,
+                                                      new_interrupt);
                 } else if (old_interrupt != new_interrupt) {
                     env->interrupt_index = new_interrupt;
-                    CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
-                                   old_interrupt, new_interrupt);
+                    trace_sparc64_cpu_check_irqs_set_irq(i, old_interrupt,
+                                                         new_interrupt);
                     cpu_interrupt(cs, CPU_INTERRUPT_HARD);
                 }
                 break;
             }
         }
     } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
-        CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
-                       "current interrupt %x\n",
-                       pil, env->pil_in, env->softint, env->interrupt_index);
+        trace_sparc64_cpu_check_irqs_disabled(pil, env->pil_in, env->softint,
+                                              env->interrupt_index);
         env->interrupt_index = 0;
         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
     }
@@ -131,7 +113,7 @@ void sparc64_cpu_set_ivec_irq(void *opaque, int irq, int level)
 
     if (level) {
         if (!(env->ivec_status & 0x20)) {
-            CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
+            trace_sparc64_cpu_ivec_raise_irq(irq);
             cs = CPU(cpu);
             cs->halted = 0;
             env->interrupt_index = TT_IVEC;
@@ -143,7 +125,7 @@ void sparc64_cpu_set_ivec_irq(void *opaque, int irq, int level)
         }
     } else {
         if (env->ivec_status & 0x20) {
-            CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
+            trace_sparc64_cpu_ivec_lower_irq(irq);
             cs = CPU(cpu);
             env->ivec_status &= ~0x20;
             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
@@ -216,10 +198,10 @@ static void tick_irq(void *opaque)
     CPUTimer *timer = env->tick;
 
     if (timer->disabled) {
-        CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
+        trace_sparc64_cpu_tick_irq_disabled();
         return;
     } else {
-        CPUIRQ_DPRINTF("tick: fire\n");
+        trace_sparc64_cpu_tick_irq_fire();
     }
 
     env->softint |= SOFTINT_TIMER;
@@ -234,10 +216,10 @@ static void stick_irq(void *opaque)
     CPUTimer *timer = env->stick;
 
     if (timer->disabled) {
-        CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
+        trace_sparc64_cpu_stick_irq_disabled();
         return;
     } else {
-        CPUIRQ_DPRINTF("stick: fire\n");
+        trace_sparc64_cpu_stick_irq_fire();
     }
 
     env->softint |= SOFTINT_STIMER;
@@ -252,10 +234,10 @@ static void hstick_irq(void *opaque)
     CPUTimer *timer = env->hstick;
 
     if (timer->disabled) {
-        CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
+        trace_sparc64_cpu_hstick_irq_disabled();
         return;
     } else {
-        CPUIRQ_DPRINTF("hstick: fire\n");
+        trace_sparc64_cpu_hstick_irq_fire();
     }
 
     env->softint |= SOFTINT_STIMER;
@@ -280,9 +262,9 @@ void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
     int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
                     cpu_to_timer_ticks(real_count, timer->frequency);
 
-    TIMER_DPRINTF("%s set_count count=0x%016lx (npt %s) p=%p\n",
-                  timer->name, real_count,
-                  timer->npt ? "disabled" : "enabled", timer);
+    trace_sparc64_cpu_tick_set_count(timer->name, real_count,
+                                     timer->npt ? "disabled" : "enabled",
+                                     timer);
 
     timer->npt = npt_bit ? 1 : 0;
     timer->clock_offset = vm_clock_offset;
@@ -294,9 +276,9 @@ uint64_t cpu_tick_get_count(CPUTimer *timer)
                     qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset,
                     timer->frequency);
 
-    TIMER_DPRINTF("%s get_count count=0x%016lx (npt %s) p=%p\n",
-           timer->name, real_count,
-           timer->npt ? "disabled" : "enabled", timer);
+    trace_sparc64_cpu_tick_get_count(timer->name, real_count,
+                                     timer->npt ? "disabled" : "enabled",
+                                     timer);
 
     if (timer->npt) {
         real_count |= timer->npt_mask;
@@ -319,18 +301,19 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
         expires = now + 1;
     }
 
-    TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
-                  "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
-                  timer->name, real_limit,
-                  timer->disabled ? "disabled" : "enabled",
-                  timer, limit,
-                  timer_to_cpu_ticks(now - timer->clock_offset,
-                                     timer->frequency),
-                  timer_to_cpu_ticks(expires - now, timer->frequency));
+    trace_sparc64_cpu_tick_set_limit(timer->name, real_limit,
+                                     timer->disabled ? "disabled" : "enabled",
+                                     timer, limit,
+                                     timer_to_cpu_ticks(
+                                         now - timer->clock_offset,
+                                         timer->frequency
+                                     ),
+                                     timer_to_cpu_ticks(
+                                         expires - now, timer->frequency
+                                     ));
 
     if (!real_limit) {
-        TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
-                timer->name);
+        trace_sparc64_cpu_tick_set_limit_zero(timer->name);
         timer_del(timer->qtimer);
     } else if (timer->disabled) {
         timer_del(timer->qtimer);
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index ec45ec2801..a23cb26b0d 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -30,7 +30,7 @@
 #include "hw/pci/pci_bridge.h"
 #include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
-#include "hw/pci-host/apb.h"
+#include "hw/pci-host/sabre.h"
 #include "hw/i386/pc.h"
 #include "hw/char/serial.h"
 #include "hw/timer/m48t59.h"
@@ -55,9 +55,9 @@
 #define CMDLINE_ADDR         0x003ff000
 #define PROM_SIZE_MAX        (4 * 1024 * 1024)
 #define PROM_VADDR           0x000ffd00000ULL
-#define APB_SPECIAL_BASE     0x1fe00000000ULL
-#define APB_MEM_BASE         0x1ff00000000ULL
-#define APB_PCI_IO_BASE      (APB_SPECIAL_BASE + 0x02000000ULL)
+#define PBM_SPECIAL_BASE     0x1fe00000000ULL
+#define PBM_MEM_BASE         0x1ff00000000ULL
+#define PBM_PCI_IO_BASE      (PBM_SPECIAL_BASE + 0x02000000ULL)
 #define PROM_FILENAME        "openbios-sparc64"
 #define NVRAM_SIZE           0x2000
 #define MAX_IDE_BUS          2
@@ -205,6 +205,59 @@ typedef struct ResetData {
     uint64_t prom_addr;
 } ResetData;
 
+#define TYPE_SUN4U_POWER "power"
+#define SUN4U_POWER(obj) OBJECT_CHECK(PowerDevice, (obj), TYPE_SUN4U_POWER)
+
+typedef struct PowerDevice {
+    SysBusDevice parent_obj;
+
+    MemoryRegion power_mmio;
+} PowerDevice;
+
+/* Power */
+static void power_mem_write(void *opaque, hwaddr addr,
+                            uint64_t val, unsigned size)
+{
+    /* According to a real Ultra 5, bit 24 controls the power */
+    if (val & 0x1000000) {
+        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+    }
+}
+
+static const MemoryRegionOps power_mem_ops = {
+    .write = power_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void power_realize(DeviceState *dev, Error **errp)
+{
+    PowerDevice *d = SUN4U_POWER(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&d->power_mmio, OBJECT(dev), &power_mem_ops, d,
+                          "power", sizeof(uint32_t));
+
+    sysbus_init_mmio(sbd, &d->power_mmio);
+}
+
+static void power_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = power_realize;
+}
+
+static const TypeInfo power_info = {
+    .name          = TYPE_SUN4U_POWER,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PowerDevice),
+    .class_init    = power_class_init,
+};
+
 static void ebus_isa_irq_handler(void *opaque, int n, int level)
 {
     EbusState *s = EBUS(opaque);
@@ -221,6 +274,7 @@ static void ebus_isa_irq_handler(void *opaque, int n, int level)
 static void ebus_realize(PCIDevice *pci_dev, Error **errp)
 {
     EbusState *s = EBUS(pci_dev);
+    SysBusDevice *sbd;
     DeviceState *dev;
     qemu_irq *isa_irq;
     DriveInfo *fd[MAX_FD];
@@ -270,6 +324,13 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
     qdev_prop_set_uint32(dev, "dma", -1);
     qdev_init_nofail(dev);
 
+    /* Power */
+    dev = qdev_create(NULL, TYPE_SUN4U_POWER);
+    qdev_init_nofail(dev);
+    sbd = SYS_BUS_DEVICE(dev);
+    memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240,
+                                sysbus_mmio_get_region(sbd, 0));
+
     /* PCI */
     pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
     pci_dev->config[0x05] = 0x00;
@@ -282,7 +343,7 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
                              0, 0x1000000);
     pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
     memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
-                             0, 0x4000);
+                             0, 0x8000);
     pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
 }
 
@@ -465,7 +526,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
     Nvram *nvram;
     unsigned int i;
     uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
-    APBState *apb;
+    SabreState *sabre;
     PCIBus *pci_bus, *pci_busA, *pci_busB;
     PCIDevice *ebus, *pci_dev;
     SysBusDevice *s;
@@ -488,24 +549,25 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
 
     prom_init(hwdef->prom_addr, bios_name);
 
-    /* Init APB (PCI host bridge) */
-    apb = APB_DEVICE(qdev_create(NULL, TYPE_APB));
-    qdev_prop_set_uint64(DEVICE(apb), "special-base", APB_SPECIAL_BASE);
-    qdev_prop_set_uint64(DEVICE(apb), "mem-base", APB_MEM_BASE);
-    object_property_set_link(OBJECT(apb), OBJECT(iommu), "iommu", &error_abort);
-    qdev_init_nofail(DEVICE(apb));
+    /* Init sabre (PCI host bridge) */
+    sabre = SABRE_DEVICE(qdev_create(NULL, TYPE_SABRE));
+    qdev_prop_set_uint64(DEVICE(sabre), "special-base", PBM_SPECIAL_BASE);
+    qdev_prop_set_uint64(DEVICE(sabre), "mem-base", PBM_MEM_BASE);
+    object_property_set_link(OBJECT(sabre), OBJECT(iommu), "iommu",
+                             &error_abort);
+    qdev_init_nofail(DEVICE(sabre));
 
     /* Wire up PCI interrupts to CPU */
     for (i = 0; i < IVEC_MAX; i++) {
-        qdev_connect_gpio_out_named(DEVICE(apb), "ivec-irq", i,
+        qdev_connect_gpio_out_named(DEVICE(sabre), "ivec-irq", i,
             qdev_get_gpio_in_named(DEVICE(cpu), "ivec-irq", i));
     }
 
-    pci_bus = PCI_HOST_BRIDGE(apb)->bus;
-    pci_busA = pci_bridge_get_sec_bus(apb->bridgeA);
-    pci_busB = pci_bridge_get_sec_bus(apb->bridgeB);
+    pci_bus = PCI_HOST_BRIDGE(sabre)->bus;
+    pci_busA = pci_bridge_get_sec_bus(sabre->bridgeA);
+    pci_busB = pci_bridge_get_sec_bus(sabre->bridgeB);
 
-    /* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is
+    /* Only in-built Simba APBs can exist on the root bus, slot 0 on busA is
        reserved (leaving no slots free after on-board devices) however slots
        0-3 are free on busB */
     pci_bus->slot_reserved_mask = 0xfffffffc;
@@ -517,17 +579,17 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
                          hwdef->console_serial_base);
     qdev_init_nofail(DEVICE(ebus));
 
-    /* Wire up "well-known" ISA IRQs to APB legacy obio IRQs */
+    /* Wire up "well-known" ISA IRQs to PBM legacy obio IRQs */
     qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 7,
-        qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_LPT_IRQ));
+        qdev_get_gpio_in_named(DEVICE(sabre), "pbm-irq", OBIO_LPT_IRQ));
     qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 6,
-        qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_FDD_IRQ));
+        qdev_get_gpio_in_named(DEVICE(sabre), "pbm-irq", OBIO_FDD_IRQ));
     qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 1,
-        qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_KBD_IRQ));
+        qdev_get_gpio_in_named(DEVICE(sabre), "pbm-irq", OBIO_KBD_IRQ));
     qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 12,
-        qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_MSE_IRQ));
+        qdev_get_gpio_in_named(DEVICE(sabre), "pbm-irq", OBIO_MSE_IRQ));
     qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 4,
-        qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_SER_IRQ));
+        qdev_get_gpio_in_named(DEVICE(sabre), "pbm-irq", OBIO_SER_IRQ));
 
     pci_dev = pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA");
 
@@ -693,6 +755,7 @@ static const TypeInfo sun4v_type = {
 
 static void sun4u_register_types(void)
 {
+    type_register_static(&power_info);
     type_register_static(&ebus_info);
     type_register_static(&prom_info);
     type_register_static(&ram_info);
diff --git a/hw/sparc64/trace-events b/hw/sparc64/trace-events
index 2ee2d75f70..ce597a6e9d 100644
--- a/hw/sparc64/trace-events
+++ b/hw/sparc64/trace-events
@@ -7,3 +7,21 @@ ebus_isa_irq_handler(int n, int level) "Set ISA IRQ %d level %d"
 sun4u_iommu_mem_read(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d"
 sun4u_iommu_mem_write(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d"
 sun4u_iommu_translate(uint64_t addr, uint64_t trans_addr, uint64_t tte) "xlate 0x%"PRIx64" => pa 0x%"PRIx64" tte: 0x%"PRIx64
+
+# hw/sparc64/sparc64.c
+sparc64_cpu_check_irqs_reset_irq(int intno) "Reset CPU IRQ (current interrupt 0x%x)"
+sparc64_cpu_check_irqs_noset_irq(uint32_t tl, uint32_t tt, int intno) "Not setting CPU IRQ: TL=%d current 0x%x >= pending 0x%x"
+sparc64_cpu_check_irqs_set_irq(unsigned int i, int old, int new) "Set CPU IRQ %d old=0x%x new=0x%x"
+sparc64_cpu_check_irqs_disabled(uint32_t pil, uint32_t pil_in, uint32_t softint, int intno) "Interrupts disabled, pil=0x%08x pil_in=0x%08x softint=0x%08x current interrupt 0x%x"
+sparc64_cpu_ivec_raise_irq(int irq) "Raise IVEC IRQ %d"
+sparc64_cpu_ivec_lower_irq(int irq) "Lower IVEC IRQ %d"
+sparc64_cpu_tick_irq_disabled(void) "tick_irq: softint disabled"
+sparc64_cpu_tick_irq_fire(void) "tick_irq: fire"
+sparc64_cpu_stick_irq_disabled(void) "stick_irq: softint disabled"
+sparc64_cpu_stick_irq_fire(void) "stick_irq: fire"
+sparc64_cpu_hstick_irq_disabled(void) "hstick_irq: softint disabled"
+sparc64_cpu_hstick_irq_fire(void) "hstick_irq: fire"
+sparc64_cpu_tick_set_count(const char *name, uint64_t real_count, const char *npt, void *p) "%s set_count count=0x%"PRIx64" (npt %s) p=%p"
+sparc64_cpu_tick_get_count(const char *name, uint64_t real_count, const char *npt, void *p) "%s get_count count=0x%"PRIx64" (npt %s) p=%p"
+sparc64_cpu_tick_set_limit(const char *name, uint64_t real_limit, const char *dis, void *p, uint64_t limit, uint64_t t, uint64_t dt) "%s set_limit limit=0x%"PRIx64 " (%s) p=%p called with limit=0x%"PRIx64" at 0x%"PRIx64" (delta=0x%"PRIx64")"
+sparc64_cpu_tick_set_limit_zero(const char *name) "%s set_limit limit=ZERO - not starting timer"
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 85c5d0cb92..8af36ca3d4 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -210,6 +210,9 @@
 #define SNOOP_NONE 0xEE
 #define SNOOP_STRIPING 0
 
+#define MIN_NUM_BUSSES 1
+#define MAX_NUM_BUSSES 2
+
 static inline int num_effective_busses(XilinxSPIPS *s)
 {
     return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
@@ -573,7 +576,7 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
     for (;;) {
         int i;
         uint8_t tx = 0;
-        uint8_t tx_rx[num_effective_busses(s)];
+        uint8_t tx_rx[MAX_NUM_BUSSES] = { 0 };
         uint8_t dummy_cycles = 0;
         uint8_t addr_length;
 
@@ -1221,6 +1224,19 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
 
     DB_PRINT_L(0, "realized spips\n");
 
+    if (s->num_busses > MAX_NUM_BUSSES) {
+        error_setg(errp,
+                   "requested number of SPI busses %u exceeds maximum %d",
+                   s->num_busses, MAX_NUM_BUSSES);
+        return;
+    }
+    if (s->num_busses < MIN_NUM_BUSSES) {
+        error_setg(errp,
+                   "requested number of SPI busses %u is below minimum %d",
+                   s->num_busses, MIN_NUM_BUSSES);
+        return;
+    }
+
     s->spi = g_new(SSIBus *, s->num_busses);
     for (i = 0; i < s->num_busses; ++i) {
         char bus_name[16];
diff --git a/include/hw/pci-bridge/simba.h b/include/hw/pci-bridge/simba.h
new file mode 100644
index 0000000000..fac56ab1cf
--- /dev/null
+++ b/include/hw/pci-bridge/simba.h
@@ -0,0 +1,38 @@
+/*
+ * QEMU Simba PCI bridge
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2012,2013 Artyom Tarasenko
+ * Copyright (c) 2017 Mark Cave-Ayland
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/pci/pci_bridge.h"
+
+
+typedef struct SimbaPCIBridge {
+    /*< private >*/
+    PCIBridge parent_obj;
+} SimbaPCIBridge;
+
+#define TYPE_SIMBA_PCI_BRIDGE "pbm-bridge"
+#define SIMBA_PCI_BRIDGE(obj) \
+    OBJECT_CHECK(SimbaPCIBridge, (obj), TYPE_SIMBA_PCI_BRIDGE)
diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/sabre.h
index 604d899b1e..0f2ccc01c6 100644
--- a/include/hw/pci-host/apb.h
+++ b/include/hw/pci-host/sabre.h
@@ -14,17 +14,20 @@
 #define OBIO_MSE_IRQ         0x2a
 #define OBIO_SER_IRQ         0x2b
 
-#define TYPE_APB "pbm"
+typedef struct SabrePCIState {
+    PCIDevice parent_obj;
+} SabrePCIState;
 
-#define APB_DEVICE(obj) \
-    OBJECT_CHECK(APBState, (obj), TYPE_APB)
+#define TYPE_SABRE_PCI_DEVICE "sabre-pci"
+#define SABRE_PCI_DEVICE(obj) \
+    OBJECT_CHECK(SabrePCIState, (obj), TYPE_SABRE_PCI_DEVICE)
 
-typedef struct APBState {
+typedef struct SabreState {
     PCIHostState parent_obj;
 
     hwaddr special_base;
     hwaddr mem_base;
-    MemoryRegion apb_config;
+    MemoryRegion sabre_config;
     MemoryRegion pci_config;
     MemoryRegion pci_mmio;
     MemoryRegion pci_ioport;
@@ -40,15 +43,10 @@ typedef struct APBState {
     unsigned int irq_request;
     uint32_t reset_control;
     unsigned int nr_resets;
-} APBState;
+} SabreState;
 
-typedef struct PBMPCIBridge {
-    /*< private >*/
-    PCIBridge parent_obj;
-} PBMPCIBridge;
-
-#define TYPE_PBM_PCI_BRIDGE "pbm-bridge"
-#define PBM_PCI_BRIDGE(obj) \
-    OBJECT_CHECK(PBMPCIBridge, (obj), TYPE_PBM_PCI_BRIDGE)
+#define TYPE_SABRE "sabre"
+#define SABRE_DEVICE(obj) \
+    OBJECT_CHECK(SabreState, (obj), TYPE_SABRE)
 
 #endif
diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h
index cb37182536..1cf70f8c23 100644
--- a/include/hw/sd/sdhci.h
+++ b/include/hw/sd/sdhci.h
@@ -41,6 +41,7 @@ typedef struct SDHCIState {
     /*< public >*/
     SDBus sdbus;
     MemoryRegion iomem;
+    AddressSpace sysbus_dma_as;
     AddressSpace *dma_as;
     MemoryRegion *dma_mr;
 
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 88b55df5ae..8c3889433c 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -905,6 +905,9 @@ extern const VMStateInfo vmstate_info_qtailq;
 #define VMSTATE_UINT32_ARRAY(_f, _s, _n)                              \
     VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
 
+#define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num)                \
+    VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t)
+
 #define VMSTATE_UINT32_2DARRAY(_f, _s, _n1, _n2)                      \
     VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, 0)
 
@@ -914,6 +917,9 @@ extern const VMStateInfo vmstate_info_qtailq;
 #define VMSTATE_UINT64_ARRAY(_f, _s, _n)                              \
     VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0)
 
+#define VMSTATE_UINT64_SUB_ARRAY(_f, _s, _start, _num)                \
+    VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint64, uint64_t)
+
 #define VMSTATE_UINT64_2DARRAY(_f, _s, _n1, _n2)                      \
     VMSTATE_UINT64_2DARRAY_V(_f, _s, _n1, _n2, 0)
 
@@ -932,9 +938,6 @@ extern const VMStateInfo vmstate_info_qtailq;
 #define VMSTATE_INT32_ARRAY(_f, _s, _n)                               \
     VMSTATE_INT32_ARRAY_V(_f, _s, _n, 0)
 
-#define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num)                \
-    VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t)
-
 #define VMSTATE_INT64_ARRAY_V(_f, _s, _n, _v)                         \
     VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int64, int64_t)
 
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 20f3d8c2c3..32a47674e6 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1354,7 +1354,7 @@ struct exec
                                  ~(abi_ulong)(TARGET_ELF_EXEC_PAGESIZE-1))
 #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
 
-#define DLINFO_ITEMS 14
+#define DLINFO_ITEMS 15
 
 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
@@ -1786,6 +1786,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
+    NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
 
 #ifdef ELF_HWCAP2
     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
diff --git a/linux-user/main.c b/linux-user/main.c
index 450eb3ce65..2140465709 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -127,9 +127,10 @@ int cpu_get_pic_interrupt(CPUX86State *env)
 /* Make sure everything is in a consistent state for calling fork().  */
 void fork_start(void)
 {
-    cpu_list_lock();
-    qemu_mutex_lock(&tb_ctx.tb_lock);
+    start_exclusive();
     mmap_fork_start();
+    qemu_mutex_lock(&tb_ctx.tb_lock);
+    cpu_list_lock();
 }
 
 void fork_end(int child)
@@ -147,9 +148,13 @@ void fork_end(int child)
         qemu_mutex_init(&tb_ctx.tb_lock);
         qemu_init_cpu_list();
         gdbserver_fork(thread_cpu);
+        /* qemu_init_cpu_list() takes care of reinitializing the
+         * exclusive state, so we don't need to end_exclusive() here.
+         */
     } else {
         qemu_mutex_unlock(&tb_ctx.tb_lock);
         cpu_list_unlock();
+        end_exclusive();
     }
 }
 
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 4888f53139..0fbfd6dff2 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -234,7 +234,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
         if (prot) {
             end_addr = addr;
         }
-        if (addr + size == end_addr) {
+        if (addr && addr + size == end_addr) {
             break;
         }
         addr -= qemu_host_page_size;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index f85f0dd780..5321f9e795 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1487,12 +1487,13 @@ static int target_setup_sigframe(struct target_rt_sigframe *sf,
     }
 
     for (i = 0; i < 32; i++) {
+        uint64_t *q = aa64_vfp_qreg(env, i);
 #ifdef TARGET_WORDS_BIGENDIAN
-        __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
-        __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
+        __put_user(q[0], &aux->fpsimd.vregs[i * 2 + 1]);
+        __put_user(q[1], &aux->fpsimd.vregs[i * 2]);
 #else
-        __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
-        __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
+        __put_user(q[0], &aux->fpsimd.vregs[i * 2]);
+        __put_user(q[1], &aux->fpsimd.vregs[i * 2 + 1]);
 #endif
     }
     __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
@@ -1539,12 +1540,13 @@ static int target_restore_sigframe(CPUARMState *env,
     }
 
     for (i = 0; i < 32; i++) {
+        uint64_t *q = aa64_vfp_qreg(env, i);
 #ifdef TARGET_WORDS_BIGENDIAN
-        __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
-        __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
+        __get_user(q[0], &aux->fpsimd.vregs[i * 2 + 1]);
+        __get_user(q[1], &aux->fpsimd.vregs[i * 2]);
 #else
-        __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
-        __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
+        __get_user(q[0], &aux->fpsimd.vregs[i * 2]);
+        __get_user(q[1], &aux->fpsimd.vregs[i * 2 + 1]);
 #endif
     }
     __get_user(fpsr, &aux->fpsimd.fpsr);
@@ -1903,7 +1905,7 @@ static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
     __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
     __put_user(sizeof(*vfpframe), &vfpframe->size);
     for (i = 0; i < 32; i++) {
-        __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
+        __put_user(*aa32_vfp_dreg(env, i), &vfpframe->ufp.fpregs[i]);
     }
     __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
     __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
@@ -2210,7 +2212,7 @@ static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
         return 0;
     }
     for (i = 0; i < 32; i++) {
-        __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
+        __get_user(*aa32_vfp_dreg(env, i), &vfpframe->ufp.fpregs[i]);
     }
     __get_user(fpscr, &vfpframe->ufp.fpscr);
     vfp_set_fpscr(env, fpscr);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 11c9116c4a..74378947f0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -296,6 +296,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);
+#define __NR_sys_getcpu __NR_getcpu
+_syscall3(int, sys_getcpu, unsigned *, cpu, unsigned *, node, void *, tcache);
 _syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
           void *, arg);
 _syscall2(int, capget, struct __user_cap_header_struct *, header,
@@ -598,6 +600,24 @@ static int sys_utimensat(int dirfd, const char *pathname,
 #endif
 #endif /* TARGET_NR_utimensat */
 
+#ifdef TARGET_NR_renameat2
+#if defined(__NR_renameat2)
+#define __NR_sys_renameat2 __NR_renameat2
+_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
+          const char *, new, unsigned int, flags)
+#else
+static int sys_renameat2(int oldfd, const char *old,
+                         int newfd, const char *new, int flags)
+{
+    if (flags == 0) {
+        return renameat(oldfd, old, newfd, new);
+    }
+    errno = ENOSYS;
+    return -1;
+}
+#endif
+#endif /* TARGET_NR_renameat2 */
+
 #ifdef CONFIG_INOTIFY
 #include <sys/inotify.h>
 
@@ -1692,7 +1712,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
         void *target_data = TARGET_CMSG_DATA(target_cmsg);
 
         int len = tswapal(target_cmsg->cmsg_len)
-                  - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
+            - sizeof(struct target_cmsghdr);
 
         space += CMSG_SPACE(len);
         if (space > msgh->msg_controllen) {
@@ -1773,7 +1793,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
         void *data = CMSG_DATA(cmsg);
         void *target_data = TARGET_CMSG_DATA(target_cmsg);
 
-        int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
+        int len = cmsg->cmsg_len - sizeof(struct cmsghdr);
         int tgt_len, tgt_space;
 
         /* We never copy a half-header but may copy half-data;
@@ -1782,7 +1802,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
          * to the guest via the CTRUNC bit), unlike truncation
          * in target_to_host_cmsg, which is a QEMU bug.
          */
-        if (msg_controllen < sizeof(struct cmsghdr)) {
+        if (msg_controllen < sizeof(struct target_cmsghdr)) {
             target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
             break;
         }
@@ -1794,8 +1814,6 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
         }
         target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
 
-        tgt_len = TARGET_CMSG_LEN(len);
-
         /* Payload types which need a different size of payload on
          * the target must adjust tgt_len here.
          */
@@ -1809,12 +1827,13 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                 break;
             }
         default:
+            tgt_len = len;
             break;
         }
 
-        if (msg_controllen < tgt_len) {
+        if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
             target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
-            tgt_len = msg_controllen;
+            tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
         }
 
         /* We must now copy-and-convert len bytes of payload
@@ -1875,6 +1894,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                 uint32_t *v = (uint32_t *)data;
                 uint32_t *t_int = (uint32_t *)target_data;
 
+                if (len != sizeof(uint32_t) ||
+                    tgt_len != sizeof(uint32_t)) {
+                    goto unimplemented;
+                }
                 __put_user(*v, t_int);
                 break;
             }
@@ -1888,6 +1911,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                 struct errhdr_t *target_errh =
                     (struct errhdr_t *)target_data;
 
+                if (len != sizeof(struct errhdr_t) ||
+                    tgt_len != sizeof(struct errhdr_t)) {
+                    goto unimplemented;
+                }
                 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
                 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
                 __put_user(errh->ee.ee_type,  &target_errh->ee.ee_type);
@@ -1911,6 +1938,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                 uint32_t *v = (uint32_t *)data;
                 uint32_t *t_int = (uint32_t *)target_data;
 
+                if (len != sizeof(uint32_t) ||
+                    tgt_len != sizeof(uint32_t)) {
+                    goto unimplemented;
+                }
                 __put_user(*v, t_int);
                 break;
             }
@@ -1924,6 +1955,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
                 struct errhdr6_t *target_errh =
                     (struct errhdr6_t *)target_data;
 
+                if (len != sizeof(struct errhdr6_t) ||
+                    tgt_len != sizeof(struct errhdr6_t)) {
+                    goto unimplemented;
+                }
                 __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
                 __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
                 __put_user(errh->ee.ee_type,  &target_errh->ee.ee_type);
@@ -1950,8 +1985,8 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
             }
         }
 
-        target_cmsg->cmsg_len = tswapal(tgt_len);
-        tgt_space = TARGET_CMSG_SPACE(len);
+        target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(tgt_len));
+        tgt_space = TARGET_CMSG_SPACE(tgt_len);
         if (msg_controllen < tgt_space) {
             tgt_space = msg_controllen;
         }
@@ -7716,6 +7751,73 @@ static TargetFdTrans target_inotify_trans = {
 };
 #endif
 
+static int target_to_host_cpu_mask(unsigned long *host_mask,
+                                   size_t host_size,
+                                   abi_ulong target_addr,
+                                   size_t target_size)
+{
+    unsigned target_bits = sizeof(abi_ulong) * 8;
+    unsigned host_bits = sizeof(*host_mask) * 8;
+    abi_ulong *target_mask;
+    unsigned i, j;
+
+    assert(host_size >= target_size);
+
+    target_mask = lock_user(VERIFY_READ, target_addr, target_size, 1);
+    if (!target_mask) {
+        return -TARGET_EFAULT;
+    }
+    memset(host_mask, 0, host_size);
+
+    for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
+        unsigned bit = i * target_bits;
+        abi_ulong val;
+
+        __get_user(val, &target_mask[i]);
+        for (j = 0; j < target_bits; j++, bit++) {
+            if (val & (1UL << j)) {
+                host_mask[bit / host_bits] |= 1UL << (bit % host_bits);
+            }
+        }
+    }
+
+    unlock_user(target_mask, target_addr, 0);
+    return 0;
+}
+
+static int host_to_target_cpu_mask(const unsigned long *host_mask,
+                                   size_t host_size,
+                                   abi_ulong target_addr,
+                                   size_t target_size)
+{
+    unsigned target_bits = sizeof(abi_ulong) * 8;
+    unsigned host_bits = sizeof(*host_mask) * 8;
+    abi_ulong *target_mask;
+    unsigned i, j;
+
+    assert(host_size >= target_size);
+
+    target_mask = lock_user(VERIFY_WRITE, target_addr, target_size, 0);
+    if (!target_mask) {
+        return -TARGET_EFAULT;
+    }
+
+    for (i = 0 ; i < target_size / sizeof(abi_ulong); i++) {
+        unsigned bit = i * target_bits;
+        abi_ulong val = 0;
+
+        for (j = 0; j < target_bits; j++, bit++) {
+            if (host_mask[bit / host_bits] & (1UL << (bit % host_bits))) {
+                val |= 1UL << j;
+            }
+        }
+        __put_user(val, &target_mask[i]);
+    }
+
+    unlock_user(target_mask, target_addr, target_size);
+    return 0;
+}
+
 /* do_syscall() should always have a single exit point at the end so
    that actions, such as logging of syscall results, can be performed.
    All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -8342,6 +8444,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         }
         break;
 #endif
+#if defined(TARGET_NR_renameat2)
+    case TARGET_NR_renameat2:
+        {
+            void *p2;
+            p  = lock_user_string(arg2);
+            p2 = lock_user_string(arg4);
+            if (!p || !p2) {
+                ret = -TARGET_EFAULT;
+            } else {
+                ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
+            }
+            unlock_user(p2, arg4, 0);
+            unlock_user(p, arg2, 0);
+        }
+        break;
+#endif
 #ifdef TARGET_NR_mkdir
     case TARGET_NR_mkdir:
         if (!(p = lock_user_string(arg1)))
@@ -8475,11 +8593,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
 #if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
     case TARGET_NR_dup3:
-        ret = get_errno(dup3(arg1, arg2, arg3));
+    {
+        int host_flags;
+
+        if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
+            return -EINVAL;
+        }
+        host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
+        ret = get_errno(dup3(arg1, arg2, host_flags));
         if (ret >= 0) {
             fd_trans_dup(arg1, arg2);
         }
         break;
+    }
 #endif
 #ifdef TARGET_NR_getppid /* not on alpha */
     case TARGET_NR_getppid:
@@ -10353,6 +10479,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
 
             mask = alloca(mask_size);
+            memset(mask, 0, mask_size);
             ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
 
             if (!is_error(ret)) {
@@ -10372,9 +10499,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                     ret = arg2;
                 }
 
-                if (copy_to_user(arg3, mask, ret)) {
-                    goto efault;
-                }
+                ret = host_to_target_cpu_mask(mask, mask_size, arg3, arg2);
             }
         }
         break;
@@ -10392,17 +10517,33 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 break;
             }
             mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
-
             mask = alloca(mask_size);
-            if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) {
-                goto efault;
+
+            ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
+            if (ret) {
+                break;
             }
-            memcpy(mask, p, arg2);
-            unlock_user_struct(p, arg2, 0);
 
             ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
         }
         break;
+    case TARGET_NR_getcpu:
+        {
+            unsigned cpu, node;
+            ret = get_errno(sys_getcpu(arg1 ? &cpu : NULL,
+                                       arg2 ? &node : NULL,
+                                       NULL));
+            if (is_error(ret)) {
+                goto fail;
+            }
+            if (arg1 && put_user_u32(cpu, arg1)) {
+                goto efault;
+            }
+            if (arg2 && put_user_u32(node, arg2)) {
+                goto efault;
+            }
+        }
+        break;
     case TARGET_NR_sched_setparam:
         {
             struct sched_param *target_schp;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index bec3680b94..a35c52a60a 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -303,9 +303,9 @@ struct target_cmsghdr {
                                __target_cmsg_nxthdr(mhdr, cmsg, cmsg_start)
 #define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \
                                & (size_t) ~(sizeof (abi_long) - 1))
-#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \
-                               + TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)))
-#define TARGET_CMSG_LEN(len)   (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len))
+#define TARGET_CMSG_SPACE(len) (sizeof(struct target_cmsghdr) + \
+                                TARGET_CMSG_ALIGN(len))
+#define TARGET_CMSG_LEN(len) (sizeof(struct target_cmsghdr) + (len))
 
 static __inline__ struct target_cmsghdr *
 __target_cmsg_nxthdr(struct target_msghdr *__mhdr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 4e84cf29db..8225308904 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3421,7 +3421,7 @@
             '*id': 'str' } }
 
 ##
-# @x-blockdev-remove-medium:
+# @blockdev-remove-medium:
 #
 # Removes a medium (a block driver state tree) from a block device. That block
 # device's tray must currently be open (unless there is no attached guest
@@ -3429,18 +3429,13 @@
 #
 # If the tray is open and there is no medium inserted, this will be a no-op.
 #
-# @device: Block device name (deprecated, use @id instead)
-#
-# @id:     The name or QOM path of the guest device (since: 2.8)
-#
-# Note: This command is still a work in progress and is considered experimental.
-# Stay away from it unless you want to help with its development.
+# @id:     The name or QOM path of the guest device
 #
-# Since: 2.5
+# Since: 2.12
 #
 # Example:
 #
-# -> { "execute": "x-blockdev-remove-medium",
+# -> { "execute": "blockdev-remove-medium",
 #      "arguments": { "id": "ide0-1-0" } }
 #
 # <- { "error": { "class": "GenericError",
@@ -3458,33 +3453,27 @@
 #
 # <- { "return": {} }
 #
-# -> { "execute": "x-blockdev-remove-medium",
+# -> { "execute": "blockdev-remove-medium",
 #      "arguments": { "id": "ide0-1-0" } }
 #
 # <- { "return": {} }
 #
 ##
-{ 'command': 'x-blockdev-remove-medium',
-  'data': { '*device': 'str',
-            '*id': 'str' } }
+{ 'command': 'blockdev-remove-medium',
+  'data': { 'id': 'str' } }
 
 ##
-# @x-blockdev-insert-medium:
+# @blockdev-insert-medium:
 #
 # Inserts a medium (a block driver state tree) into a block device. That block
 # device's tray must currently be open (unless there is no attached guest
 # device) and there must be no medium inserted already.
 #
-# @device:    Block device name (deprecated, use @id instead)
-#
-# @id:        The name or QOM path of the guest device (since: 2.8)
+# @id:        The name or QOM path of the guest device
 #
 # @node-name: name of a node in the block driver state graph
 #
-# Note: This command is still a work in progress and is considered experimental.
-# Stay away from it unless you want to help with its development.
-#
-# Since: 2.5
+# Since: 2.12
 #
 # Example:
 #
@@ -3496,16 +3485,15 @@
 #                    "filename": "fedora.iso" } } }
 # <- { "return": {} }
 #
-# -> { "execute": "x-blockdev-insert-medium",
+# -> { "execute": "blockdev-insert-medium",
 #      "arguments": { "id": "ide0-1-0",
 #                     "node-name": "node0" } }
 #
 # <- { "return": {} }
 #
 ##
-{ 'command': 'x-blockdev-insert-medium',
-  'data': { '*device': 'str',
-            '*id': 'str',
+{ 'command': 'blockdev-insert-medium',
+  'data': { 'id': 'str',
             'node-name': 'str'} }
 
 
@@ -3533,8 +3521,8 @@
 #
 # Changes the medium inserted into a block device by ejecting the current medium
 # and loading a new image file which is inserted as the new medium (this command
-# combines blockdev-open-tray, x-blockdev-remove-medium,
-# x-blockdev-insert-medium and blockdev-close-tray).
+# combines blockdev-open-tray, blockdev-remove-medium, blockdev-insert-medium
+# and blockdev-close-tray).
 #
 # @device:          Block device name (deprecated, use @id instead)
 #
diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c
index 9e5b2fb31c..26a2c09868 100644
--- a/target/arm/arch_dump.c
+++ b/target/arm/arch_dump.c
@@ -99,8 +99,10 @@ static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f,
 
     aarch64_note_init(&note, s, "CORE", 5, NT_PRFPREG, sizeof(note.vfp));
 
-    for (i = 0; i < 64; ++i) {
-        note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
+    for (i = 0; i < 32; ++i) {
+        uint64_t *q = aa64_vfp_qreg(env, i);
+        note.vfp.vregs[2*i + 0] = cpu_to_dump64(s, q[0]);
+        note.vfp.vregs[2*i + 1] = cpu_to_dump64(s, q[1]);
     }
 
     if (s->dump_info.d_endian == ELFDATA2MSB) {
@@ -229,7 +231,7 @@ static int arm_write_elf32_vfp(WriteCoreDumpFunction f, CPUARMState *env,
     arm_note_init(&note, s, "LINUX", 6, NT_ARM_VFP, sizeof(note.vfp));
 
     for (i = 0; i < 32; ++i) {
-        note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
+        note.vfp.vregs[i] = cpu_to_dump64(s, *aa32_vfp_dreg(env, i));
     }
 
     note.vfp.fpscr = cpu_to_dump32(s, vfp_get_fpscr(env));
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 96316700dd..d2bb59eded 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -492,7 +492,7 @@ typedef struct CPUARMState {
          * the two execution states, and means we do not need to explicitly
          * map these registers when changing states.
          */
-        float64 regs[64];
+        uint64_t regs[64];
 
         uint32_t xregs[16];
         /* We store these fpcsr fields separately for convenience.  */
@@ -1340,6 +1340,7 @@ enum arm_features {
     ARM_FEATURE_VBAR, /* has cp15 VBAR */
     ARM_FEATURE_M_SECURITY, /* M profile Security Extension */
     ARM_FEATURE_JAZELLE, /* has (trivial) Jazelle implementation */
+    ARM_FEATURE_SVE, /* has Scalable Vector Extension */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -2666,71 +2667,6 @@ static inline bool bswap_code(bool sctlr_b)
 #endif
 }
 
-/* Return the exception level to which FP-disabled exceptions should
- * be taken, or 0 if FP is enabled.
- */
-static inline int fp_exception_el(CPUARMState *env)
-{
-    int fpen;
-    int cur_el = arm_current_el(env);
-
-    /* CPACR and the CPTR registers don't exist before v6, so FP is
-     * always accessible
-     */
-    if (!arm_feature(env, ARM_FEATURE_V6)) {
-        return 0;
-    }
-
-    /* The CPACR controls traps to EL1, or PL1 if we're 32 bit:
-     * 0, 2 : trap EL0 and EL1/PL1 accesses
-     * 1    : trap only EL0 accesses
-     * 3    : trap no accesses
-     */
-    fpen = extract32(env->cp15.cpacr_el1, 20, 2);
-    switch (fpen) {
-    case 0:
-    case 2:
-        if (cur_el == 0 || cur_el == 1) {
-            /* Trap to PL1, which might be EL1 or EL3 */
-            if (arm_is_secure(env) && !arm_el_is_aa64(env, 3)) {
-                return 3;
-            }
-            return 1;
-        }
-        if (cur_el == 3 && !is_a64(env)) {
-            /* Secure PL1 running at EL3 */
-            return 3;
-        }
-        break;
-    case 1:
-        if (cur_el == 0) {
-            return 1;
-        }
-        break;
-    case 3:
-        break;
-    }
-
-    /* For the CPTR registers we don't need to guard with an ARM_FEATURE
-     * check because zero bits in the registers mean "don't trap".
-     */
-
-    /* CPTR_EL2 : present in v7VE or v8 */
-    if (cur_el <= 2 && extract32(env->cp15.cptr_el[2], 10, 1)
-        && !arm_is_secure_below_el3(env)) {
-        /* Trap FP ops at EL2, NS-EL1 or NS-EL0 to EL2 */
-        return 2;
-    }
-
-    /* CPTR_EL3 : present in v8 */
-    if (extract32(env->cp15.cptr_el[3], 10, 1)) {
-        /* Trap all FP ops to EL3 */
-        return 3;
-    }
-
-    return 0;
-}
-
 #ifdef CONFIG_USER_ONLY
 static inline bool arm_cpu_bswap_data(CPUARMState *env)
 {
@@ -2777,66 +2713,8 @@ static inline uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx)
 }
 #endif
 
-static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
-                                        target_ulong *cs_base, uint32_t *flags)
-{
-    ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
-    if (is_a64(env)) {
-        *pc = env->pc;
-        *flags = ARM_TBFLAG_AARCH64_STATE_MASK;
-        /* Get control bits for tagged addresses */
-        *flags |= (arm_regime_tbi0(env, mmu_idx) << ARM_TBFLAG_TBI0_SHIFT);
-        *flags |= (arm_regime_tbi1(env, mmu_idx) << ARM_TBFLAG_TBI1_SHIFT);
-    } else {
-        *pc = env->regs[15];
-        *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
-            | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
-            | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
-            | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
-            | (arm_sctlr_b(env) << ARM_TBFLAG_SCTLR_B_SHIFT);
-        if (!(access_secure_reg(env))) {
-            *flags |= ARM_TBFLAG_NS_MASK;
-        }
-        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
-            || arm_el_is_aa64(env, 1)) {
-            *flags |= ARM_TBFLAG_VFPEN_MASK;
-        }
-        *flags |= (extract32(env->cp15.c15_cpar, 0, 2)
-                   << ARM_TBFLAG_XSCALE_CPAR_SHIFT);
-    }
-
-    *flags |= (arm_to_core_mmu_idx(mmu_idx) << ARM_TBFLAG_MMUIDX_SHIFT);
-
-    /* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
-     * states defined in the ARM ARM for software singlestep:
-     *  SS_ACTIVE   PSTATE.SS   State
-     *     0            x       Inactive (the TB flag for SS is always 0)
-     *     1            0       Active-pending
-     *     1            1       Active-not-pending
-     */
-    if (arm_singlestep_active(env)) {
-        *flags |= ARM_TBFLAG_SS_ACTIVE_MASK;
-        if (is_a64(env)) {
-            if (env->pstate & PSTATE_SS) {
-                *flags |= ARM_TBFLAG_PSTATE_SS_MASK;
-            }
-        } else {
-            if (env->uncached_cpsr & PSTATE_SS) {
-                *flags |= ARM_TBFLAG_PSTATE_SS_MASK;
-            }
-        }
-    }
-    if (arm_cpu_data_is_big_endian(env)) {
-        *flags |= ARM_TBFLAG_BE_DATA_MASK;
-    }
-    *flags |= fp_exception_el(env) << ARM_TBFLAG_FPEXC_EL_SHIFT;
-
-    if (arm_v7m_is_handler_mode(env)) {
-        *flags |= ARM_TBFLAG_HANDLER_MASK;
-    }
-
-    *cs_base = 0;
-}
+void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
+                          target_ulong *cs_base, uint32_t *flags);
 
 enum {
     QEMU_PSCI_CONDUIT_DISABLED = 0,
@@ -2885,4 +2763,31 @@ static inline void *arm_get_el_change_hook_opaque(ARMCPU *cpu)
     return cpu->el_change_hook_opaque;
 }
 
+/**
+ * aa32_vfp_dreg:
+ * Return a pointer to the Dn register within env in 32-bit mode.
+ */
+static inline uint64_t *aa32_vfp_dreg(CPUARMState *env, unsigned regno)
+{
+    return &env->vfp.regs[regno];
+}
+
+/**
+ * aa32_vfp_qreg:
+ * Return a pointer to the Qn register within env in 32-bit mode.
+ */
+static inline uint64_t *aa32_vfp_qreg(CPUARMState *env, unsigned regno)
+{
+    return &env->vfp.regs[2 * regno];
+}
+
+/**
+ * aa64_vfp_qreg:
+ * Return a pointer to the Qn register within env in 64-bit mode.
+ */
+static inline uint64_t *aa64_vfp_qreg(CPUARMState *env, unsigned regno)
+{
+    return &env->vfp.regs[2 * regno];
+}
+
 #endif
diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c
index 3b6df3f41a..9ca0bdead7 100644
--- a/target/arm/crypto_helper.c
+++ b/target/arm/crypto_helper.c
@@ -30,20 +30,14 @@ union CRYPTO_STATE {
 #define CR_ST_WORD(state, i)   (state.words[i])
 #endif
 
-void HELPER(crypto_aese)(CPUARMState *env, uint32_t rd, uint32_t rm,
-                         uint32_t decrypt)
+void HELPER(crypto_aese)(void *vd, void *vm, uint32_t decrypt)
 {
     static uint8_t const * const sbox[2] = { AES_sbox, AES_isbox };
     static uint8_t const * const shift[2] = { AES_shifts, AES_ishifts };
-
-    union CRYPTO_STATE rk = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
-    union CRYPTO_STATE st = { .l = {
-        float64_val(env->vfp.regs[rd]),
-        float64_val(env->vfp.regs[rd + 1])
-    } };
+    uint64_t *rd = vd;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE rk = { .l = { rm[0], rm[1] } };
+    union CRYPTO_STATE st = { .l = { rd[0], rd[1] } };
     int i;
 
     assert(decrypt < 2);
@@ -57,12 +51,11 @@ void HELPER(crypto_aese)(CPUARMState *env, uint32_t rd, uint32_t rm,
         CR_ST_BYTE(st, i) = sbox[decrypt][CR_ST_BYTE(rk, shift[decrypt][i])];
     }
 
-    env->vfp.regs[rd] = make_float64(st.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(st.l[1]);
+    rd[0] = st.l[0];
+    rd[1] = st.l[1];
 }
 
-void HELPER(crypto_aesmc)(CPUARMState *env, uint32_t rd, uint32_t rm,
-                          uint32_t decrypt)
+void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t decrypt)
 {
     static uint32_t const mc[][256] = { {
         /* MixColumns lookup table */
@@ -197,10 +190,10 @@ void HELPER(crypto_aesmc)(CPUARMState *env, uint32_t rd, uint32_t rm,
         0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5,
         0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d,
     } };
-    union CRYPTO_STATE st = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
+
+    uint64_t *rd = vd;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE st = { .l = { rm[0], rm[1] } };
     int i;
 
     assert(decrypt < 2);
@@ -213,8 +206,8 @@ void HELPER(crypto_aesmc)(CPUARMState *env, uint32_t rd, uint32_t rm,
             rol32(mc[decrypt][CR_ST_BYTE(st, i + 3)], 24);
     }
 
-    env->vfp.regs[rd] = make_float64(st.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(st.l[1]);
+    rd[0] = st.l[0];
+    rd[1] = st.l[1];
 }
 
 /*
@@ -236,21 +229,14 @@ static uint32_t maj(uint32_t x, uint32_t y, uint32_t z)
     return (x & y) | ((x | y) & z);
 }
 
-void HELPER(crypto_sha1_3reg)(CPUARMState *env, uint32_t rd, uint32_t rn,
-                              uint32_t rm, uint32_t op)
+void HELPER(crypto_sha1_3reg)(void *vd, void *vn, void *vm, uint32_t op)
 {
-    union CRYPTO_STATE d = { .l = {
-        float64_val(env->vfp.regs[rd]),
-        float64_val(env->vfp.regs[rd + 1])
-    } };
-    union CRYPTO_STATE n = { .l = {
-        float64_val(env->vfp.regs[rn]),
-        float64_val(env->vfp.regs[rn + 1])
-    } };
-    union CRYPTO_STATE m = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
+    uint64_t *rd = vd;
+    uint64_t *rn = vn;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
+    union CRYPTO_STATE n = { .l = { rn[0], rn[1] } };
+    union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
 
     if (op == 3) { /* sha1su0 */
         d.l[0] ^= d.l[1] ^ m.l[0];
@@ -284,42 +270,37 @@ void HELPER(crypto_sha1_3reg)(CPUARMState *env, uint32_t rd, uint32_t rn,
             CR_ST_WORD(d, 0) = t;
         }
     }
-    env->vfp.regs[rd] = make_float64(d.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(d.l[1]);
+    rd[0] = d.l[0];
+    rd[1] = d.l[1];
 }
 
-void HELPER(crypto_sha1h)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(crypto_sha1h)(void *vd, void *vm)
 {
-    union CRYPTO_STATE m = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
+    uint64_t *rd = vd;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
 
     CR_ST_WORD(m, 0) = ror32(CR_ST_WORD(m, 0), 2);
     CR_ST_WORD(m, 1) = CR_ST_WORD(m, 2) = CR_ST_WORD(m, 3) = 0;
 
-    env->vfp.regs[rd] = make_float64(m.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(m.l[1]);
+    rd[0] = m.l[0];
+    rd[1] = m.l[1];
 }
 
-void HELPER(crypto_sha1su1)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(crypto_sha1su1)(void *vd, void *vm)
 {
-    union CRYPTO_STATE d = { .l = {
-        float64_val(env->vfp.regs[rd]),
-        float64_val(env->vfp.regs[rd + 1])
-    } };
-    union CRYPTO_STATE m = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
+    uint64_t *rd = vd;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
+    union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
 
     CR_ST_WORD(d, 0) = rol32(CR_ST_WORD(d, 0) ^ CR_ST_WORD(m, 1), 1);
     CR_ST_WORD(d, 1) = rol32(CR_ST_WORD(d, 1) ^ CR_ST_WORD(m, 2), 1);
     CR_ST_WORD(d, 2) = rol32(CR_ST_WORD(d, 2) ^ CR_ST_WORD(m, 3), 1);
     CR_ST_WORD(d, 3) = rol32(CR_ST_WORD(d, 3) ^ CR_ST_WORD(d, 0), 1);
 
-    env->vfp.regs[rd] = make_float64(d.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(d.l[1]);
+    rd[0] = d.l[0];
+    rd[1] = d.l[1];
 }
 
 /*
@@ -347,21 +328,14 @@ static uint32_t s1(uint32_t x)
     return ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10);
 }
 
-void HELPER(crypto_sha256h)(CPUARMState *env, uint32_t rd, uint32_t rn,
-                            uint32_t rm)
+void HELPER(crypto_sha256h)(void *vd, void *vn, void *vm)
 {
-    union CRYPTO_STATE d = { .l = {
-        float64_val(env->vfp.regs[rd]),
-        float64_val(env->vfp.regs[rd + 1])
-    } };
-    union CRYPTO_STATE n = { .l = {
-        float64_val(env->vfp.regs[rn]),
-        float64_val(env->vfp.regs[rn + 1])
-    } };
-    union CRYPTO_STATE m = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
+    uint64_t *rd = vd;
+    uint64_t *rn = vn;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
+    union CRYPTO_STATE n = { .l = { rn[0], rn[1] } };
+    union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
     int i;
 
     for (i = 0; i < 4; i++) {
@@ -383,25 +357,18 @@ void HELPER(crypto_sha256h)(CPUARMState *env, uint32_t rd, uint32_t rn,
         CR_ST_WORD(d, 0) = t;
     }
 
-    env->vfp.regs[rd] = make_float64(d.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(d.l[1]);
+    rd[0] = d.l[0];
+    rd[1] = d.l[1];
 }
 
-void HELPER(crypto_sha256h2)(CPUARMState *env, uint32_t rd, uint32_t rn,
-                             uint32_t rm)
+void HELPER(crypto_sha256h2)(void *vd, void *vn, void *vm)
 {
-    union CRYPTO_STATE d = { .l = {
-        float64_val(env->vfp.regs[rd]),
-        float64_val(env->vfp.regs[rd + 1])
-    } };
-    union CRYPTO_STATE n = { .l = {
-        float64_val(env->vfp.regs[rn]),
-        float64_val(env->vfp.regs[rn + 1])
-    } };
-    union CRYPTO_STATE m = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
+    uint64_t *rd = vd;
+    uint64_t *rn = vn;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
+    union CRYPTO_STATE n = { .l = { rn[0], rn[1] } };
+    union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
     int i;
 
     for (i = 0; i < 4; i++) {
@@ -415,51 +382,40 @@ void HELPER(crypto_sha256h2)(CPUARMState *env, uint32_t rd, uint32_t rn,
         CR_ST_WORD(d, 0) = CR_ST_WORD(n, 3 - i) + t;
     }
 
-    env->vfp.regs[rd] = make_float64(d.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(d.l[1]);
+    rd[0] = d.l[0];
+    rd[1] = d.l[1];
 }
 
-void HELPER(crypto_sha256su0)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(crypto_sha256su0)(void *vd, void *vm)
 {
-    union CRYPTO_STATE d = { .l = {
-        float64_val(env->vfp.regs[rd]),
-        float64_val(env->vfp.regs[rd + 1])
-    } };
-    union CRYPTO_STATE m = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
+    uint64_t *rd = vd;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
+    union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
 
     CR_ST_WORD(d, 0) += s0(CR_ST_WORD(d, 1));
     CR_ST_WORD(d, 1) += s0(CR_ST_WORD(d, 2));
     CR_ST_WORD(d, 2) += s0(CR_ST_WORD(d, 3));
     CR_ST_WORD(d, 3) += s0(CR_ST_WORD(m, 0));
 
-    env->vfp.regs[rd] = make_float64(d.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(d.l[1]);
+    rd[0] = d.l[0];
+    rd[1] = d.l[1];
 }
 
-void HELPER(crypto_sha256su1)(CPUARMState *env, uint32_t rd, uint32_t rn,
-                              uint32_t rm)
+void HELPER(crypto_sha256su1)(void *vd, void *vn, void *vm)
 {
-    union CRYPTO_STATE d = { .l = {
-        float64_val(env->vfp.regs[rd]),
-        float64_val(env->vfp.regs[rd + 1])
-    } };
-    union CRYPTO_STATE n = { .l = {
-        float64_val(env->vfp.regs[rn]),
-        float64_val(env->vfp.regs[rn + 1])
-    } };
-    union CRYPTO_STATE m = { .l = {
-        float64_val(env->vfp.regs[rm]),
-        float64_val(env->vfp.regs[rm + 1])
-    } };
+    uint64_t *rd = vd;
+    uint64_t *rn = vn;
+    uint64_t *rm = vm;
+    union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
+    union CRYPTO_STATE n = { .l = { rn[0], rn[1] } };
+    union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
 
     CR_ST_WORD(d, 0) += s1(CR_ST_WORD(m, 2)) + CR_ST_WORD(n, 1);
     CR_ST_WORD(d, 1) += s1(CR_ST_WORD(m, 3)) + CR_ST_WORD(n, 2);
     CR_ST_WORD(d, 2) += s1(CR_ST_WORD(d, 0)) + CR_ST_WORD(n, 3);
     CR_ST_WORD(d, 3) += s1(CR_ST_WORD(d, 1)) + CR_ST_WORD(m, 0);
 
-    env->vfp.regs[rd] = make_float64(d.l[0]);
-    env->vfp.regs[rd + 1] = make_float64(d.l[1]);
+    rd[0] = d.l[0];
+    rd[1] = d.l[1];
 }
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
index 3e00a9ead1..06fd321fae 100644
--- a/target/arm/helper-a64.c
+++ b/target/arm/helper-a64.c
@@ -153,13 +153,14 @@ uint64_t HELPER(simd_tbl)(CPUARMState *env, uint64_t result, uint64_t indices,
         if (index < 16 * numregs) {
             /* Convert index (a byte offset into the virtual table
              * which is a series of 128-bit vectors concatenated)
-             * into the correct vfp.regs[] element plus a bit offset
+             * into the correct register element plus a bit offset
              * into that element, bearing in mind that the table
              * can wrap around from V31 to V0.
              */
             int elt = (rn * 2 + (index >> 3)) % 64;
             int bitidx = (index & 7) * 8;
-            uint64_t val = extract64(env->vfp.regs[elt], bitidx, 8);
+            uint64_t *q = aa64_vfp_qreg(env, elt >> 1);
+            uint64_t val = extract64(q[elt & 1], bitidx, 8);
 
             result = deposit64(result, shift, 8, val);
         }
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c83c901a86..bfce09643b 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -64,15 +64,16 @@ static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
     /* VFP data registers are always little-endian.  */
     nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
     if (reg < nregs) {
-        stfq_le_p(buf, env->vfp.regs[reg]);
+        stq_le_p(buf, *aa32_vfp_dreg(env, reg));
         return 8;
     }
     if (arm_feature(env, ARM_FEATURE_NEON)) {
         /* Aliases for Q regs.  */
         nregs += 16;
         if (reg < nregs) {
-            stfq_le_p(buf, env->vfp.regs[(reg - 32) * 2]);
-            stfq_le_p(buf + 8, env->vfp.regs[(reg - 32) * 2 + 1]);
+            uint64_t *q = aa32_vfp_qreg(env, reg - 32);
+            stq_le_p(buf, q[0]);
+            stq_le_p(buf + 8, q[1]);
             return 16;
         }
     }
@@ -90,14 +91,15 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
 
     nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
     if (reg < nregs) {
-        env->vfp.regs[reg] = ldfq_le_p(buf);
+        *aa32_vfp_dreg(env, reg) = ldq_le_p(buf);
         return 8;
     }
     if (arm_feature(env, ARM_FEATURE_NEON)) {
         nregs += 16;
         if (reg < nregs) {
-            env->vfp.regs[(reg - 32) * 2] = ldfq_le_p(buf);
-            env->vfp.regs[(reg - 32) * 2 + 1] = ldfq_le_p(buf + 8);
+            uint64_t *q = aa32_vfp_qreg(env, reg - 32);
+            q[0] = ldq_le_p(buf);
+            q[1] = ldq_le_p(buf + 8);
             return 16;
         }
     }
@@ -114,9 +116,12 @@ static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
     switch (reg) {
     case 0 ... 31:
         /* 128 bit FP register */
-        stfq_le_p(buf, env->vfp.regs[reg * 2]);
-        stfq_le_p(buf + 8, env->vfp.regs[reg * 2 + 1]);
-        return 16;
+        {
+            uint64_t *q = aa64_vfp_qreg(env, reg);
+            stq_le_p(buf, q[0]);
+            stq_le_p(buf + 8, q[1]);
+            return 16;
+        }
     case 32:
         /* FPSR */
         stl_p(buf, vfp_get_fpsr(env));
@@ -135,9 +140,12 @@ static int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
     switch (reg) {
     case 0 ... 31:
         /* 128 bit FP register */
-        env->vfp.regs[reg * 2] = ldfq_le_p(buf);
-        env->vfp.regs[reg * 2 + 1] = ldfq_le_p(buf + 8);
-        return 16;
+        {
+            uint64_t *q = aa64_vfp_qreg(env, reg);
+            q[0] = ldq_le_p(buf);
+            q[1] = ldq_le_p(buf + 8);
+            return 16;
+        }
     case 32:
         /* FPSR */
         vfp_set_fpsr(env, ldl_p(buf));
@@ -8360,7 +8368,7 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
     MemTxAttrs attrs = {};
     MemTxResult result = MEMTX_OK;
     AddressSpace *as;
-    uint32_t data;
+    uint64_t data;
 
     attrs.secure = is_secure;
     as = arm_addressspace(cs, attrs);
@@ -11613,3 +11621,133 @@ uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes)
     /* Linux crc32c converts the output to one's complement.  */
     return crc32c(acc, buf, bytes) ^ 0xffffffff;
 }
+
+/* Return the exception level to which FP-disabled exceptions should
+ * be taken, or 0 if FP is enabled.
+ */
+static inline int fp_exception_el(CPUARMState *env)
+{
+#ifndef CONFIG_USER_ONLY
+    int fpen;
+    int cur_el = arm_current_el(env);
+
+    /* CPACR and the CPTR registers don't exist before v6, so FP is
+     * always accessible
+     */
+    if (!arm_feature(env, ARM_FEATURE_V6)) {
+        return 0;
+    }
+
+    /* The CPACR controls traps to EL1, or PL1 if we're 32 bit:
+     * 0, 2 : trap EL0 and EL1/PL1 accesses
+     * 1    : trap only EL0 accesses
+     * 3    : trap no accesses
+     */
+    fpen = extract32(env->cp15.cpacr_el1, 20, 2);
+    switch (fpen) {
+    case 0:
+    case 2:
+        if (cur_el == 0 || cur_el == 1) {
+            /* Trap to PL1, which might be EL1 or EL3 */
+            if (arm_is_secure(env) && !arm_el_is_aa64(env, 3)) {
+                return 3;
+            }
+            return 1;
+        }
+        if (cur_el == 3 && !is_a64(env)) {
+            /* Secure PL1 running at EL3 */
+            return 3;
+        }
+        break;
+    case 1:
+        if (cur_el == 0) {
+            return 1;
+        }
+        break;
+    case 3:
+        break;
+    }
+
+    /* For the CPTR registers we don't need to guard with an ARM_FEATURE
+     * check because zero bits in the registers mean "don't trap".
+     */
+
+    /* CPTR_EL2 : present in v7VE or v8 */
+    if (cur_el <= 2 && extract32(env->cp15.cptr_el[2], 10, 1)
+        && !arm_is_secure_below_el3(env)) {
+        /* Trap FP ops at EL2, NS-EL1 or NS-EL0 to EL2 */
+        return 2;
+    }
+
+    /* CPTR_EL3 : present in v8 */
+    if (extract32(env->cp15.cptr_el[3], 10, 1)) {
+        /* Trap all FP ops to EL3 */
+        return 3;
+    }
+#endif
+    return 0;
+}
+
+void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
+                          target_ulong *cs_base, uint32_t *pflags)
+{
+    ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
+    uint32_t flags;
+
+    if (is_a64(env)) {
+        *pc = env->pc;
+        flags = ARM_TBFLAG_AARCH64_STATE_MASK;
+        /* Get control bits for tagged addresses */
+        flags |= (arm_regime_tbi0(env, mmu_idx) << ARM_TBFLAG_TBI0_SHIFT);
+        flags |= (arm_regime_tbi1(env, mmu_idx) << ARM_TBFLAG_TBI1_SHIFT);
+    } else {
+        *pc = env->regs[15];
+        flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
+            | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
+            | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
+            | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
+            | (arm_sctlr_b(env) << ARM_TBFLAG_SCTLR_B_SHIFT);
+        if (!(access_secure_reg(env))) {
+            flags |= ARM_TBFLAG_NS_MASK;
+        }
+        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
+            || arm_el_is_aa64(env, 1)) {
+            flags |= ARM_TBFLAG_VFPEN_MASK;
+        }
+        flags |= (extract32(env->cp15.c15_cpar, 0, 2)
+                  << ARM_TBFLAG_XSCALE_CPAR_SHIFT);
+    }
+
+    flags |= (arm_to_core_mmu_idx(mmu_idx) << ARM_TBFLAG_MMUIDX_SHIFT);
+
+    /* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
+     * states defined in the ARM ARM for software singlestep:
+     *  SS_ACTIVE   PSTATE.SS   State
+     *     0            x       Inactive (the TB flag for SS is always 0)
+     *     1            0       Active-pending
+     *     1            1       Active-not-pending
+     */
+    if (arm_singlestep_active(env)) {
+        flags |= ARM_TBFLAG_SS_ACTIVE_MASK;
+        if (is_a64(env)) {
+            if (env->pstate & PSTATE_SS) {
+                flags |= ARM_TBFLAG_PSTATE_SS_MASK;
+            }
+        } else {
+            if (env->uncached_cpsr & PSTATE_SS) {
+                flags |= ARM_TBFLAG_PSTATE_SS_MASK;
+            }
+        }
+    }
+    if (arm_cpu_data_is_big_endian(env)) {
+        flags |= ARM_TBFLAG_BE_DATA_MASK;
+    }
+    flags |= fp_exception_el(env) << ARM_TBFLAG_FPEXC_EL_SHIFT;
+
+    if (arm_v7m_is_handler_mode(env)) {
+        flags |= ARM_TBFLAG_HANDLER_MASK;
+    }
+
+    *pflags = flags;
+    *cs_base = 0;
+}
diff --git a/target/arm/helper.h b/target/arm/helper.h
index 066729e8ad..5dec2e6262 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -188,7 +188,7 @@ DEF_HELPER_FLAGS_2(rsqrte_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
 DEF_HELPER_FLAGS_2(rsqrte_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
 DEF_HELPER_2(recpe_u32, i32, i32, ptr)
 DEF_HELPER_FLAGS_2(rsqrte_u32, TCG_CALL_NO_RWG, i32, i32, ptr)
-DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_4(neon_tbl, TCG_CALL_NO_RWG, i32, i32, i32, ptr, i32)
 
 DEF_HELPER_3(shl_cc, i32, env, i32, i32)
 DEF_HELPER_3(shr_cc, i32, env, i32, i32)
@@ -511,28 +511,28 @@ DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32)
 DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32)
 DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32)
 
-DEF_HELPER_3(neon_unzip8, void, env, i32, i32)
-DEF_HELPER_3(neon_unzip16, void, env, i32, i32)
-DEF_HELPER_3(neon_qunzip8, void, env, i32, i32)
-DEF_HELPER_3(neon_qunzip16, void, env, i32, i32)
-DEF_HELPER_3(neon_qunzip32, void, env, i32, i32)
-DEF_HELPER_3(neon_zip8, void, env, i32, i32)
-DEF_HELPER_3(neon_zip16, void, env, i32, i32)
-DEF_HELPER_3(neon_qzip8, void, env, i32, i32)
-DEF_HELPER_3(neon_qzip16, void, env, i32, i32)
-DEF_HELPER_3(neon_qzip32, void, env, i32, i32)
-
-DEF_HELPER_4(crypto_aese, void, env, i32, i32, i32)
-DEF_HELPER_4(crypto_aesmc, void, env, i32, i32, i32)
-
-DEF_HELPER_5(crypto_sha1_3reg, void, env, i32, i32, i32, i32)
-DEF_HELPER_3(crypto_sha1h, void, env, i32, i32)
-DEF_HELPER_3(crypto_sha1su1, void, env, i32, i32)
-
-DEF_HELPER_4(crypto_sha256h, void, env, i32, i32, i32)
-DEF_HELPER_4(crypto_sha256h2, void, env, i32, i32, i32)
-DEF_HELPER_3(crypto_sha256su0, void, env, i32, i32)
-DEF_HELPER_4(crypto_sha256su1, void, env, i32, i32, i32)
+DEF_HELPER_FLAGS_2(neon_unzip8, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_unzip16, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_qunzip8, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_qunzip16, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_qunzip32, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_zip8, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_zip16, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_qzip8, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_qzip16, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(neon_qzip32, TCG_CALL_NO_RWG, void, ptr, ptr)
+
+DEF_HELPER_FLAGS_3(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(crypto_aesmc, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+
+DEF_HELPER_FLAGS_4(crypto_sha1_3reg, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_2(crypto_sha1h, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_2(crypto_sha1su1, TCG_CALL_NO_RWG, void, ptr, ptr)
+
+DEF_HELPER_FLAGS_3(crypto_sha256h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
+DEF_HELPER_FLAGS_3(crypto_sha256h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
+DEF_HELPER_FLAGS_2(crypto_sha256su0, TCG_CALL_NO_RWG, void, ptr, ptr)
+DEF_HELPER_FLAGS_3(crypto_sha256su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
 
 DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
 DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
index f925a21481..f77c9c494b 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -358,7 +358,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
     /* VFP registers */
     r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
     for (i = 0; i < 32; i++) {
-        r.addr = (uintptr_t)(&env->vfp.regs[i]);
+        r.addr = (uintptr_t)aa32_vfp_dreg(env, i);
         ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
         if (ret) {
             return ret;
@@ -445,7 +445,7 @@ int kvm_arch_get_registers(CPUState *cs)
     /* VFP registers */
     r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
     for (i = 0; i < 32; i++) {
-        r.addr = (uintptr_t)(&env->vfp.regs[i]);
+        r.addr = (uintptr_t)aa32_vfp_dreg(env, i);
         ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
         if (ret) {
             return ret;
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 6554c30007..ac728494a4 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -696,21 +696,16 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         }
     }
 
-    /* Advanced SIMD and FP registers
-     * We map Qn = regs[2n+1]:regs[2n]
-     */
+    /* Advanced SIMD and FP registers. */
     for (i = 0; i < 32; i++) {
-        int rd = i << 1;
-        uint64_t fp_val[2];
+        uint64_t *q = aa64_vfp_qreg(env, i);
 #ifdef HOST_WORDS_BIGENDIAN
-        fp_val[0] = env->vfp.regs[rd + 1];
-        fp_val[1] = env->vfp.regs[rd];
+        uint64_t fp_val[2] = { q[1], q[0] };
+        reg.addr = (uintptr_t)fp_val;
 #else
-        fp_val[1] = env->vfp.regs[rd + 1];
-        fp_val[0] = env->vfp.regs[rd];
+        reg.addr = (uintptr_t)q;
 #endif
         reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
-        reg.addr = (uintptr_t)(&fp_val);
         ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
         if (ret) {
             return ret;
@@ -837,24 +832,18 @@ int kvm_arch_get_registers(CPUState *cs)
         env->spsr = env->banked_spsr[i];
     }
 
-    /* Advanced SIMD and FP registers
-     * We map Qn = regs[2n+1]:regs[2n]
-     */
+    /* Advanced SIMD and FP registers */
     for (i = 0; i < 32; i++) {
-        uint64_t fp_val[2];
+        uint64_t *q = aa64_vfp_qreg(env, i);
         reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
-        reg.addr = (uintptr_t)(&fp_val);
+        reg.addr = (uintptr_t)q;
         ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
         if (ret) {
             return ret;
         } else {
-            int rd = i << 1;
 #ifdef HOST_WORDS_BIGENDIAN
-            env->vfp.regs[rd + 1] = fp_val[0];
-            env->vfp.regs[rd] = fp_val[1];
-#else
-            env->vfp.regs[rd + 1] = fp_val[1];
-            env->vfp.regs[rd] = fp_val[0];
+            uint64_t t;
+            t = q[0], q[0] = q[1], q[1] = t;
 #endif
         }
     }
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 176274629c..a85c2430d3 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -50,7 +50,7 @@ static const VMStateDescription vmstate_vfp = {
     .minimum_version_id = 3,
     .needed = vfp_needed,
     .fields = (VMStateField[]) {
-        VMSTATE_FLOAT64_ARRAY(env.vfp.regs, ARMCPU, 64),
+        VMSTATE_UINT64_ARRAY(env.vfp.regs, ARMCPU, 64),
         /* The xregs array is a little awkward because element 1 (FPSCR)
          * requires a specific accessor, so we have to split it up in
          * the vmstate:
diff --git a/target/arm/neon_helper.c b/target/arm/neon_helper.c
index ebdf7c9b10..689491cad3 100644
--- a/target/arm/neon_helper.c
+++ b/target/arm/neon_helper.c
@@ -2027,12 +2027,12 @@ uint64_t HELPER(neon_acgt_f64)(uint64_t a, uint64_t b, void *fpstp)
 
 #define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
 
-void HELPER(neon_qunzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qunzip8)(void *vd, void *vm)
 {
-    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
-    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
-    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
-    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd0 = rd[0], zd1 = rd[1];
+    uint64_t zm0 = rm[0], zm1 = rm[1];
+
     uint64_t d0 = ELEM(zd0, 0, 8) | (ELEM(zd0, 2, 8) << 8)
         | (ELEM(zd0, 4, 8) << 16) | (ELEM(zd0, 6, 8) << 24)
         | (ELEM(zd1, 0, 8) << 32) | (ELEM(zd1, 2, 8) << 40)
@@ -2049,18 +2049,19 @@ void HELPER(neon_qunzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
         | (ELEM(zm0, 5, 8) << 16) | (ELEM(zm0, 7, 8) << 24)
         | (ELEM(zm1, 1, 8) << 32) | (ELEM(zm1, 3, 8) << 40)
         | (ELEM(zm1, 5, 8) << 48) | (ELEM(zm1, 7, 8) << 56);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rm + 1] = make_float64(m1);
-    env->vfp.regs[rd] = make_float64(d0);
-    env->vfp.regs[rd + 1] = make_float64(d1);
+
+    rm[0] = m0;
+    rm[1] = m1;
+    rd[0] = d0;
+    rd[1] = d1;
 }
 
-void HELPER(neon_qunzip16)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qunzip16)(void *vd, void *vm)
 {
-    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
-    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
-    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
-    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd0 = rd[0], zd1 = rd[1];
+    uint64_t zm0 = rm[0], zm1 = rm[1];
+
     uint64_t d0 = ELEM(zd0, 0, 16) | (ELEM(zd0, 2, 16) << 16)
         | (ELEM(zd1, 0, 16) << 32) | (ELEM(zd1, 2, 16) << 48);
     uint64_t d1 = ELEM(zm0, 0, 16) | (ELEM(zm0, 2, 16) << 16)
@@ -2069,32 +2070,35 @@ void HELPER(neon_qunzip16)(CPUARMState *env, uint32_t rd, uint32_t rm)
         | (ELEM(zd1, 1, 16) << 32) | (ELEM(zd1, 3, 16) << 48);
     uint64_t m1 = ELEM(zm0, 1, 16) | (ELEM(zm0, 3, 16) << 16)
         | (ELEM(zm1, 1, 16) << 32) | (ELEM(zm1, 3, 16) << 48);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rm + 1] = make_float64(m1);
-    env->vfp.regs[rd] = make_float64(d0);
-    env->vfp.regs[rd + 1] = make_float64(d1);
+
+    rm[0] = m0;
+    rm[1] = m1;
+    rd[0] = d0;
+    rd[1] = d1;
 }
 
-void HELPER(neon_qunzip32)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qunzip32)(void *vd, void *vm)
 {
-    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
-    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
-    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
-    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd0 = rd[0], zd1 = rd[1];
+    uint64_t zm0 = rm[0], zm1 = rm[1];
+
     uint64_t d0 = ELEM(zd0, 0, 32) | (ELEM(zd1, 0, 32) << 32);
     uint64_t d1 = ELEM(zm0, 0, 32) | (ELEM(zm1, 0, 32) << 32);
     uint64_t m0 = ELEM(zd0, 1, 32) | (ELEM(zd1, 1, 32) << 32);
     uint64_t m1 = ELEM(zm0, 1, 32) | (ELEM(zm1, 1, 32) << 32);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rm + 1] = make_float64(m1);
-    env->vfp.regs[rd] = make_float64(d0);
-    env->vfp.regs[rd + 1] = make_float64(d1);
+
+    rm[0] = m0;
+    rm[1] = m1;
+    rd[0] = d0;
+    rd[1] = d1;
 }
 
-void HELPER(neon_unzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_unzip8)(void *vd, void *vm)
 {
-    uint64_t zm = float64_val(env->vfp.regs[rm]);
-    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd = rd[0], zm = rm[0];
+
     uint64_t d0 = ELEM(zd, 0, 8) | (ELEM(zd, 2, 8) << 8)
         | (ELEM(zd, 4, 8) << 16) | (ELEM(zd, 6, 8) << 24)
         | (ELEM(zm, 0, 8) << 32) | (ELEM(zm, 2, 8) << 40)
@@ -2103,28 +2107,31 @@ void HELPER(neon_unzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
         | (ELEM(zd, 5, 8) << 16) | (ELEM(zd, 7, 8) << 24)
         | (ELEM(zm, 1, 8) << 32) | (ELEM(zm, 3, 8) << 40)
         | (ELEM(zm, 5, 8) << 48) | (ELEM(zm, 7, 8) << 56);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rd] = make_float64(d0);
+
+    rm[0] = m0;
+    rd[0] = d0;
 }
 
-void HELPER(neon_unzip16)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_unzip16)(void *vd, void *vm)
 {
-    uint64_t zm = float64_val(env->vfp.regs[rm]);
-    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd = rd[0], zm = rm[0];
+
     uint64_t d0 = ELEM(zd, 0, 16) | (ELEM(zd, 2, 16) << 16)
         | (ELEM(zm, 0, 16) << 32) | (ELEM(zm, 2, 16) << 48);
     uint64_t m0 = ELEM(zd, 1, 16) | (ELEM(zd, 3, 16) << 16)
         | (ELEM(zm, 1, 16) << 32) | (ELEM(zm, 3, 16) << 48);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rd] = make_float64(d0);
+
+    rm[0] = m0;
+    rd[0] = d0;
 }
 
-void HELPER(neon_qzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qzip8)(void *vd, void *vm)
 {
-    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
-    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
-    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
-    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd0 = rd[0], zd1 = rd[1];
+    uint64_t zm0 = rm[0], zm1 = rm[1];
+
     uint64_t d0 = ELEM(zd0, 0, 8) | (ELEM(zm0, 0, 8) << 8)
         | (ELEM(zd0, 1, 8) << 16) | (ELEM(zm0, 1, 8) << 24)
         | (ELEM(zd0, 2, 8) << 32) | (ELEM(zm0, 2, 8) << 40)
@@ -2141,18 +2148,19 @@ void HELPER(neon_qzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
         | (ELEM(zd1, 5, 8) << 16) | (ELEM(zm1, 5, 8) << 24)
         | (ELEM(zd1, 6, 8) << 32) | (ELEM(zm1, 6, 8) << 40)
         | (ELEM(zd1, 7, 8) << 48) | (ELEM(zm1, 7, 8) << 56);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rm + 1] = make_float64(m1);
-    env->vfp.regs[rd] = make_float64(d0);
-    env->vfp.regs[rd + 1] = make_float64(d1);
+
+    rm[0] = m0;
+    rm[1] = m1;
+    rd[0] = d0;
+    rd[1] = d1;
 }
 
-void HELPER(neon_qzip16)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qzip16)(void *vd, void *vm)
 {
-    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
-    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
-    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
-    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd0 = rd[0], zd1 = rd[1];
+    uint64_t zm0 = rm[0], zm1 = rm[1];
+
     uint64_t d0 = ELEM(zd0, 0, 16) | (ELEM(zm0, 0, 16) << 16)
         | (ELEM(zd0, 1, 16) << 32) | (ELEM(zm0, 1, 16) << 48);
     uint64_t d1 = ELEM(zd0, 2, 16) | (ELEM(zm0, 2, 16) << 16)
@@ -2161,32 +2169,35 @@ void HELPER(neon_qzip16)(CPUARMState *env, uint32_t rd, uint32_t rm)
         | (ELEM(zd1, 1, 16) << 32) | (ELEM(zm1, 1, 16) << 48);
     uint64_t m1 = ELEM(zd1, 2, 16) | (ELEM(zm1, 2, 16) << 16)
         | (ELEM(zd1, 3, 16) << 32) | (ELEM(zm1, 3, 16) << 48);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rm + 1] = make_float64(m1);
-    env->vfp.regs[rd] = make_float64(d0);
-    env->vfp.regs[rd + 1] = make_float64(d1);
+
+    rm[0] = m0;
+    rm[1] = m1;
+    rd[0] = d0;
+    rd[1] = d1;
 }
 
-void HELPER(neon_qzip32)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_qzip32)(void *vd, void *vm)
 {
-    uint64_t zm0 = float64_val(env->vfp.regs[rm]);
-    uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
-    uint64_t zd0 = float64_val(env->vfp.regs[rd]);
-    uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd0 = rd[0], zd1 = rd[1];
+    uint64_t zm0 = rm[0], zm1 = rm[1];
+
     uint64_t d0 = ELEM(zd0, 0, 32) | (ELEM(zm0, 0, 32) << 32);
     uint64_t d1 = ELEM(zd0, 1, 32) | (ELEM(zm0, 1, 32) << 32);
     uint64_t m0 = ELEM(zd1, 0, 32) | (ELEM(zm1, 0, 32) << 32);
     uint64_t m1 = ELEM(zd1, 1, 32) | (ELEM(zm1, 1, 32) << 32);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rm + 1] = make_float64(m1);
-    env->vfp.regs[rd] = make_float64(d0);
-    env->vfp.regs[rd + 1] = make_float64(d1);
+
+    rm[0] = m0;
+    rm[1] = m1;
+    rd[0] = d0;
+    rd[1] = d1;
 }
 
-void HELPER(neon_zip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_zip8)(void *vd, void *vm)
 {
-    uint64_t zm = float64_val(env->vfp.regs[rm]);
-    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd = rd[0], zm = rm[0];
+
     uint64_t d0 = ELEM(zd, 0, 8) | (ELEM(zm, 0, 8) << 8)
         | (ELEM(zd, 1, 8) << 16) | (ELEM(zm, 1, 8) << 24)
         | (ELEM(zd, 2, 8) << 32) | (ELEM(zm, 2, 8) << 40)
@@ -2195,20 +2206,23 @@ void HELPER(neon_zip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
         | (ELEM(zd, 5, 8) << 16) | (ELEM(zm, 5, 8) << 24)
         | (ELEM(zd, 6, 8) << 32) | (ELEM(zm, 6, 8) << 40)
         | (ELEM(zd, 7, 8) << 48) | (ELEM(zm, 7, 8) << 56);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rd] = make_float64(d0);
+
+    rm[0] = m0;
+    rd[0] = d0;
 }
 
-void HELPER(neon_zip16)(CPUARMState *env, uint32_t rd, uint32_t rm)
+void HELPER(neon_zip16)(void *vd, void *vm)
 {
-    uint64_t zm = float64_val(env->vfp.regs[rm]);
-    uint64_t zd = float64_val(env->vfp.regs[rd]);
+    uint64_t *rd = vd, *rm = vm;
+    uint64_t zd = rd[0], zm = rm[0];
+
     uint64_t d0 = ELEM(zd, 0, 16) | (ELEM(zm, 0, 16) << 16)
         | (ELEM(zd, 1, 16) << 32) | (ELEM(zm, 1, 16) << 48);
     uint64_t m0 = ELEM(zd, 2, 16) | (ELEM(zm, 2, 16) << 16)
         | (ELEM(zd, 3, 16) << 32) | (ELEM(zm, 3, 16) << 48);
-    env->vfp.regs[rm] = make_float64(m0);
-    env->vfp.regs[rd] = make_float64(d0);
+
+    rm[0] = m0;
+    rd[0] = d0;
 }
 
 /* Helper function for 64 bit polynomial multiply case:
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 712c5c55b6..a937e76710 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -54,20 +54,17 @@ static int exception_target_el(CPUARMState *env)
     return target_el;
 }
 
-uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
-                          uint32_t rn, uint32_t maxindex)
+uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, void *vn,
+                          uint32_t maxindex)
 {
-    uint32_t val;
-    uint32_t tmp;
-    int index;
-    int shift;
-    uint64_t *table;
-    table = (uint64_t *)&env->vfp.regs[rn];
+    uint32_t val, shift;
+    uint64_t *table = vn;
+
     val = 0;
     for (shift = 0; shift < 32; shift += 8) {
-        index = (ireg >> shift) & 0xff;
+        uint32_t index = (ireg >> shift) & 0xff;
         if (index < maxindex) {
-            tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
+            uint32_t tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
             val |= tmp << shift;
         } else {
             val |= def & (0xff << shift);
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 70c1e08a36..eed64c73e5 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -80,8 +80,9 @@ typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
 typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
 typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
 typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64);
-typedef void CryptoTwoOpEnvFn(TCGv_ptr, TCGv_i32, TCGv_i32);
-typedef void CryptoThreeOpEnvFn(TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32);
+typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
+typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
+typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
 
 /* initialize TCG globals.  */
 void a64_translate_init(void)
@@ -163,15 +164,12 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
 
     if (flags & CPU_DUMP_FPU) {
         int numvfpregs = 32;
-        for (i = 0; i < numvfpregs; i += 2) {
-            uint64_t vlo = float64_val(env->vfp.regs[i * 2]);
-            uint64_t vhi = float64_val(env->vfp.regs[(i * 2) + 1]);
-            cpu_fprintf(f, "q%02d=%016" PRIx64 ":%016" PRIx64 " ",
-                        i, vhi, vlo);
-            vlo = float64_val(env->vfp.regs[(i + 1) * 2]);
-            vhi = float64_val(env->vfp.regs[((i + 1) * 2) + 1]);
-            cpu_fprintf(f, "q%02d=%016" PRIx64 ":%016" PRIx64 "\n",
-                        i + 1, vhi, vlo);
+        for (i = 0; i < numvfpregs; i++) {
+            uint64_t *q = aa64_vfp_qreg(env, i);
+            uint64_t vlo = q[0];
+            uint64_t vhi = q[1];
+            cpu_fprintf(f, "q%02d=%016" PRIx64 ":%016" PRIx64 "%c",
+                        i, vhi, vlo, (i & 1 ? '\n' : ' '));
         }
         cpu_fprintf(f, "FPCR: %08x  FPSR: %08x\n",
                     vfp_get_fpcr(env), vfp_get_fpsr(env));
@@ -535,6 +533,21 @@ static inline int vec_reg_offset(DisasContext *s, int regno,
     return offs;
 }
 
+/* Return the offset info CPUARMState of the "whole" vector register Qn.  */
+static inline int vec_full_reg_offset(DisasContext *s, int regno)
+{
+    assert_fp_access_checked(s);
+    return offsetof(CPUARMState, vfp.regs[regno * 2]);
+}
+
+/* Return a newly allocated pointer to the vector register.  */
+static TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno)
+{
+    TCGv_ptr ret = tcg_temp_new_ptr();
+    tcg_gen_addi_ptr(ret, cpu_env, vec_full_reg_offset(s, regno));
+    return ret;
+}
+
 /* Return the offset into CPUARMState of a slice (from
  * the least significant end) of FP register Qn (ie
  * Dn, Sn, Hn or Bn).
@@ -542,19 +555,13 @@ static inline int vec_reg_offset(DisasContext *s, int regno,
  */
 static inline int fp_reg_offset(DisasContext *s, int regno, TCGMemOp size)
 {
-    int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
-#ifdef HOST_WORDS_BIGENDIAN
-    offs += (8 - (1 << size));
-#endif
-    assert_fp_access_checked(s);
-    return offs;
+    return vec_reg_offset(s, regno, 0, size);
 }
 
 /* Offset of the high half of the 128 bit vector Qn */
 static inline int fp_reg_hi_offset(DisasContext *s, int regno)
 {
-    assert_fp_access_checked(s);
-    return offsetof(CPUARMState, vfp.regs[regno * 2 + 1]);
+    return vec_reg_offset(s, regno, 1, MO_64);
 }
 
 /* Convenience accessors for reading and writing single and double
@@ -10949,8 +10956,9 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn)
     int rn = extract32(insn, 5, 5);
     int rd = extract32(insn, 0, 5);
     int decrypt;
-    TCGv_i32 tcg_rd_regno, tcg_rn_regno, tcg_decrypt;
-    CryptoThreeOpEnvFn *genfn;
+    TCGv_ptr tcg_rd_ptr, tcg_rn_ptr;
+    TCGv_i32 tcg_decrypt;
+    CryptoThreeOpIntFn *genfn;
 
     if (!arm_dc_feature(s, ARM_FEATURE_V8_AES)
         || size != 0) {
@@ -10984,18 +10992,14 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn)
         return;
     }
 
-    /* Note that we convert the Vx register indexes into the
-     * index within the vfp.regs[] array, so we can share the
-     * helper with the AArch32 instructions.
-     */
-    tcg_rd_regno = tcg_const_i32(rd << 1);
-    tcg_rn_regno = tcg_const_i32(rn << 1);
+    tcg_rd_ptr = vec_full_reg_ptr(s, rd);
+    tcg_rn_ptr = vec_full_reg_ptr(s, rn);
     tcg_decrypt = tcg_const_i32(decrypt);
 
-    genfn(cpu_env, tcg_rd_regno, tcg_rn_regno, tcg_decrypt);
+    genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_decrypt);
 
-    tcg_temp_free_i32(tcg_rd_regno);
-    tcg_temp_free_i32(tcg_rn_regno);
+    tcg_temp_free_ptr(tcg_rd_ptr);
+    tcg_temp_free_ptr(tcg_rn_ptr);
     tcg_temp_free_i32(tcg_decrypt);
 }
 
@@ -11012,8 +11016,8 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
     int rm = extract32(insn, 16, 5);
     int rn = extract32(insn, 5, 5);
     int rd = extract32(insn, 0, 5);
-    CryptoThreeOpEnvFn *genfn;
-    TCGv_i32 tcg_rd_regno, tcg_rn_regno, tcg_rm_regno;
+    CryptoThreeOpFn *genfn;
+    TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr;
     int feature = ARM_FEATURE_V8_SHA256;
 
     if (size != 0) {
@@ -11052,23 +11056,23 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
         return;
     }
 
-    tcg_rd_regno = tcg_const_i32(rd << 1);
-    tcg_rn_regno = tcg_const_i32(rn << 1);
-    tcg_rm_regno = tcg_const_i32(rm << 1);
+    tcg_rd_ptr = vec_full_reg_ptr(s, rd);
+    tcg_rn_ptr = vec_full_reg_ptr(s, rn);
+    tcg_rm_ptr = vec_full_reg_ptr(s, rm);
 
     if (genfn) {
-        genfn(cpu_env, tcg_rd_regno, tcg_rn_regno, tcg_rm_regno);
+        genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr);
     } else {
         TCGv_i32 tcg_opcode = tcg_const_i32(opcode);
 
-        gen_helper_crypto_sha1_3reg(cpu_env, tcg_rd_regno,
-                                    tcg_rn_regno, tcg_rm_regno, tcg_opcode);
+        gen_helper_crypto_sha1_3reg(tcg_rd_ptr, tcg_rn_ptr,
+                                    tcg_rm_ptr, tcg_opcode);
         tcg_temp_free_i32(tcg_opcode);
     }
 
-    tcg_temp_free_i32(tcg_rd_regno);
-    tcg_temp_free_i32(tcg_rn_regno);
-    tcg_temp_free_i32(tcg_rm_regno);
+    tcg_temp_free_ptr(tcg_rd_ptr);
+    tcg_temp_free_ptr(tcg_rn_ptr);
+    tcg_temp_free_ptr(tcg_rm_ptr);
 }
 
 /* Crypto two-reg SHA
@@ -11083,9 +11087,9 @@ static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
     int opcode = extract32(insn, 12, 5);
     int rn = extract32(insn, 5, 5);
     int rd = extract32(insn, 0, 5);
-    CryptoTwoOpEnvFn *genfn;
+    CryptoTwoOpFn *genfn;
     int feature;
-    TCGv_i32 tcg_rd_regno, tcg_rn_regno;
+    TCGv_ptr tcg_rd_ptr, tcg_rn_ptr;
 
     if (size != 0) {
         unallocated_encoding(s);
@@ -11119,13 +11123,13 @@ static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
         return;
     }
 
-    tcg_rd_regno = tcg_const_i32(rd << 1);
-    tcg_rn_regno = tcg_const_i32(rn << 1);
+    tcg_rd_ptr = vec_full_reg_ptr(s, rd);
+    tcg_rn_ptr = vec_full_reg_ptr(s, rn);
 
-    genfn(cpu_env, tcg_rd_regno, tcg_rn_regno);
+    genfn(tcg_rd_ptr, tcg_rn_ptr);
 
-    tcg_temp_free_i32(tcg_rd_regno);
-    tcg_temp_free_i32(tcg_rn_regno);
+    tcg_temp_free_ptr(tcg_rd_ptr);
+    tcg_temp_free_ptr(tcg_rn_ptr);
 }
 
 /* C3.6 Data processing - SIMD, inc Crypto
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 781be1e219..55826b7e5a 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -1515,14 +1515,16 @@ static inline void gen_vfp_st(DisasContext *s, int dp, TCGv_i32 addr)
 static inline long
 vfp_reg_offset (int dp, int reg)
 {
-    if (dp)
+    if (dp) {
         return offsetof(CPUARMState, vfp.regs[reg]);
-    else if (reg & 1) {
-        return offsetof(CPUARMState, vfp.regs[reg >> 1])
-          + offsetof(CPU_DoubleU, l.upper);
     } else {
-        return offsetof(CPUARMState, vfp.regs[reg >> 1])
-          + offsetof(CPU_DoubleU, l.lower);
+        long ofs = offsetof(CPUARMState, vfp.regs[reg >> 1]);
+        if (reg & 1) {
+            ofs += offsetof(CPU_DoubleU, l.upper);
+        } else {
+            ofs += offsetof(CPU_DoubleU, l.lower);
+        }
+        return ofs;
     }
 }
 
@@ -1559,6 +1561,13 @@ static inline void neon_store_reg64(TCGv_i64 var, int reg)
     tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
 }
 
+static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
+{
+    TCGv_ptr ret = tcg_temp_new_ptr();
+    tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg));
+    return ret;
+}
+
 #define tcg_gen_ld_f32 tcg_gen_ld_i32
 #define tcg_gen_ld_f64 tcg_gen_ld_i64
 #define tcg_gen_st_f32 tcg_gen_st_i32
@@ -4680,22 +4689,23 @@ static inline TCGv_i32 neon_get_scalar(int size, int reg)
 
 static int gen_neon_unzip(int rd, int rm, int size, int q)
 {
-    TCGv_i32 tmp, tmp2;
+    TCGv_ptr pd, pm;
+    
     if (!q && size == 2) {
         return 1;
     }
-    tmp = tcg_const_i32(rd);
-    tmp2 = tcg_const_i32(rm);
+    pd = vfp_reg_ptr(true, rd);
+    pm = vfp_reg_ptr(true, rm);
     if (q) {
         switch (size) {
         case 0:
-            gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
+            gen_helper_neon_qunzip8(pd, pm);
             break;
         case 1:
-            gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
+            gen_helper_neon_qunzip16(pd, pm);
             break;
         case 2:
-            gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
+            gen_helper_neon_qunzip32(pd, pm);
             break;
         default:
             abort();
@@ -4703,38 +4713,39 @@ static int gen_neon_unzip(int rd, int rm, int size, int q)
     } else {
         switch (size) {
         case 0:
-            gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
+            gen_helper_neon_unzip8(pd, pm);
             break;
         case 1:
-            gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
+            gen_helper_neon_unzip16(pd, pm);
             break;
         default:
             abort();
         }
     }
-    tcg_temp_free_i32(tmp);
-    tcg_temp_free_i32(tmp2);
+    tcg_temp_free_ptr(pd);
+    tcg_temp_free_ptr(pm);
     return 0;
 }
 
 static int gen_neon_zip(int rd, int rm, int size, int q)
 {
-    TCGv_i32 tmp, tmp2;
+    TCGv_ptr pd, pm;
+
     if (!q && size == 2) {
         return 1;
     }
-    tmp = tcg_const_i32(rd);
-    tmp2 = tcg_const_i32(rm);
+    pd = vfp_reg_ptr(true, rd);
+    pm = vfp_reg_ptr(true, rm);
     if (q) {
         switch (size) {
         case 0:
-            gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
+            gen_helper_neon_qzip8(pd, pm);
             break;
         case 1:
-            gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
+            gen_helper_neon_qzip16(pd, pm);
             break;
         case 2:
-            gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
+            gen_helper_neon_qzip32(pd, pm);
             break;
         default:
             abort();
@@ -4742,17 +4753,17 @@ static int gen_neon_zip(int rd, int rm, int size, int q)
     } else {
         switch (size) {
         case 0:
-            gen_helper_neon_zip8(cpu_env, tmp, tmp2);
+            gen_helper_neon_zip8(pd, pm);
             break;
         case 1:
-            gen_helper_neon_zip16(cpu_env, tmp, tmp2);
+            gen_helper_neon_zip16(pd, pm);
             break;
         default:
             abort();
         }
     }
-    tcg_temp_free_i32(tmp);
-    tcg_temp_free_i32(tmp2);
+    tcg_temp_free_ptr(pd);
+    tcg_temp_free_ptr(pm);
     return 0;
 }
 
@@ -5597,6 +5608,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
     int u;
     uint32_t imm, mask;
     TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5;
+    TCGv_ptr ptr1, ptr2, ptr3;
     TCGv_i64 tmp64;
 
     /* FIXME: this access check should not take precedence over UNDEF
@@ -5643,34 +5655,34 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
                 if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)) {
                     return 1;
                 }
-                tmp = tcg_const_i32(rd);
-                tmp2 = tcg_const_i32(rn);
-                tmp3 = tcg_const_i32(rm);
+                ptr1 = vfp_reg_ptr(true, rd);
+                ptr2 = vfp_reg_ptr(true, rn);
+                ptr3 = vfp_reg_ptr(true, rm);
                 tmp4 = tcg_const_i32(size);
-                gen_helper_crypto_sha1_3reg(cpu_env, tmp, tmp2, tmp3, tmp4);
+                gen_helper_crypto_sha1_3reg(ptr1, ptr2, ptr3, tmp4);
                 tcg_temp_free_i32(tmp4);
             } else { /* SHA-256 */
                 if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA256) || size == 3) {
                     return 1;
                 }
-                tmp = tcg_const_i32(rd);
-                tmp2 = tcg_const_i32(rn);
-                tmp3 = tcg_const_i32(rm);
+                ptr1 = vfp_reg_ptr(true, rd);
+                ptr2 = vfp_reg_ptr(true, rn);
+                ptr3 = vfp_reg_ptr(true, rm);
                 switch (size) {
                 case 0:
-                    gen_helper_crypto_sha256h(cpu_env, tmp, tmp2, tmp3);
+                    gen_helper_crypto_sha256h(ptr1, ptr2, ptr3);
                     break;
                 case 1:
-                    gen_helper_crypto_sha256h2(cpu_env, tmp, tmp2, tmp3);
+                    gen_helper_crypto_sha256h2(ptr1, ptr2, ptr3);
                     break;
                 case 2:
-                    gen_helper_crypto_sha256su1(cpu_env, tmp, tmp2, tmp3);
+                    gen_helper_crypto_sha256su1(ptr1, ptr2, ptr3);
                     break;
                 }
             }
-            tcg_temp_free_i32(tmp);
-            tcg_temp_free_i32(tmp2);
-            tcg_temp_free_i32(tmp3);
+            tcg_temp_free_ptr(ptr1);
+            tcg_temp_free_ptr(ptr2);
+            tcg_temp_free_ptr(ptr3);
             return 0;
         }
         if (size == 3 && op != NEON_3R_LOGIC) {
@@ -7159,8 +7171,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
                         || ((rm | rd) & 1)) {
                         return 1;
                     }
-                    tmp = tcg_const_i32(rd);
-                    tmp2 = tcg_const_i32(rm);
+                    ptr1 = vfp_reg_ptr(true, rd);
+                    ptr2 = vfp_reg_ptr(true, rm);
 
                      /* Bit 6 is the lowest opcode bit; it distinguishes between
                       * encryption (AESE/AESMC) and decryption (AESD/AESIMC)
@@ -7168,12 +7180,12 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
                     tmp3 = tcg_const_i32(extract32(insn, 6, 1));
 
                     if (op == NEON_2RM_AESE) {
-                        gen_helper_crypto_aese(cpu_env, tmp, tmp2, tmp3);
+                        gen_helper_crypto_aese(ptr1, ptr2, tmp3);
                     } else {
-                        gen_helper_crypto_aesmc(cpu_env, tmp, tmp2, tmp3);
+                        gen_helper_crypto_aesmc(ptr1, ptr2, tmp3);
                     }
-                    tcg_temp_free_i32(tmp);
-                    tcg_temp_free_i32(tmp2);
+                    tcg_temp_free_ptr(ptr1);
+                    tcg_temp_free_ptr(ptr2);
                     tcg_temp_free_i32(tmp3);
                     break;
                 case NEON_2RM_SHA1H:
@@ -7181,13 +7193,13 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
                         || ((rm | rd) & 1)) {
                         return 1;
                     }
-                    tmp = tcg_const_i32(rd);
-                    tmp2 = tcg_const_i32(rm);
+                    ptr1 = vfp_reg_ptr(true, rd);
+                    ptr2 = vfp_reg_ptr(true, rm);
 
-                    gen_helper_crypto_sha1h(cpu_env, tmp, tmp2);
+                    gen_helper_crypto_sha1h(ptr1, ptr2);
 
-                    tcg_temp_free_i32(tmp);
-                    tcg_temp_free_i32(tmp2);
+                    tcg_temp_free_ptr(ptr1);
+                    tcg_temp_free_ptr(ptr2);
                     break;
                 case NEON_2RM_SHA1SU1:
                     if ((rm | rd) & 1) {
@@ -7201,15 +7213,15 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
                     } else if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)) {
                         return 1;
                     }
-                    tmp = tcg_const_i32(rd);
-                    tmp2 = tcg_const_i32(rm);
+                    ptr1 = vfp_reg_ptr(true, rd);
+                    ptr2 = vfp_reg_ptr(true, rm);
                     if (q) {
-                        gen_helper_crypto_sha256su0(cpu_env, tmp, tmp2);
+                        gen_helper_crypto_sha256su0(ptr1, ptr2);
                     } else {
-                        gen_helper_crypto_sha1su1(cpu_env, tmp, tmp2);
+                        gen_helper_crypto_sha1su1(ptr1, ptr2);
                     }
-                    tcg_temp_free_i32(tmp);
-                    tcg_temp_free_i32(tmp2);
+                    tcg_temp_free_ptr(ptr1);
+                    tcg_temp_free_ptr(ptr2);
                     break;
                 default:
                 elementwise:
@@ -7534,9 +7546,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
                     tcg_gen_movi_i32(tmp, 0);
                 }
                 tmp2 = neon_load_reg(rm, 0);
-                tmp4 = tcg_const_i32(rn);
+                ptr1 = vfp_reg_ptr(true, rn);
                 tmp5 = tcg_const_i32(n);
-                gen_helper_neon_tbl(tmp2, cpu_env, tmp2, tmp, tmp4, tmp5);
+                gen_helper_neon_tbl(tmp2, tmp2, tmp, ptr1, tmp5);
                 tcg_temp_free_i32(tmp);
                 if (insn & (1 << 6)) {
                     tmp = neon_load_reg(rd, 1);
@@ -7545,9 +7557,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
                     tcg_gen_movi_i32(tmp, 0);
                 }
                 tmp3 = neon_load_reg(rm, 1);
-                gen_helper_neon_tbl(tmp3, cpu_env, tmp3, tmp, tmp4, tmp5);
+                gen_helper_neon_tbl(tmp3, tmp3, tmp, ptr1, tmp5);
                 tcg_temp_free_i32(tmp5);
-                tcg_temp_free_i32(tmp4);
+                tcg_temp_free_ptr(ptr1);
                 neon_store_reg(rd, 0, tmp2);
                 neon_store_reg(rd, 1, tmp3);
                 tcg_temp_free_i32(tmp);
@@ -12562,7 +12574,7 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
             numvfpregs += 16;
         }
         for (i = 0; i < numvfpregs; i++) {
-            uint64_t v = float64_val(env->vfp.regs[i]);
+            uint64_t v = *aa32_vfp_dreg(env, i);
             cpu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
                         i * 2, (uint32_t)v,
                         i * 2 + 1, (uint32_t)(v >> 32),
diff --git a/target/arm/translate.h b/target/arm/translate.h
index cd7313ace7..3f4df91e5e 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -108,7 +108,7 @@ static inline int default_exception_el(DisasContext *s)
             ? 3 : MAX(1, s->current_el);
 }
 
-static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
+static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
 {
     /* We don't need to save all of the syndrome so we mask and shift
      * out unneeded bits to help the sleb128 encoder do a better job.
diff --git a/tests/.gitignore b/tests/.gitignore
index 74e55d7264..e5c744b7ed 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -18,6 +18,7 @@ test-aio
 test-aio-multithread
 test-arm-mptimer
 test-base64
+test-bdrv-drain
 test-bitops
 test-bitcnt
 test-blockjob
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index cb84edc8fb..3934e62ef7 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -1578,9 +1578,9 @@ static void test_atapi_tray(void)
     QDict *rsp;
 
     fd = prepare_iso(iso_size, &tx, &iso);
-    ahci = ahci_boot_and_enable("-drive if=none,id=drive0,file=%s,format=raw "
+    ahci = ahci_boot_and_enable("-blockdev node-name=drive0,driver=file,filename=%s "
                                 "-M q35 "
-                                "-device ide-cd,drive=drive0 ", iso);
+                                "-device ide-cd,id=cd0,drive=drive0 ", iso);
     port = ahci_port_select(ahci);
 
     ahci_atapi_eject(ahci, port);
@@ -1591,13 +1591,13 @@ static void test_atapi_tray(void)
 
     /* Remove media */
     qmp_async("{'execute': 'blockdev-open-tray', "
-               "'arguments': {'device': 'drive0'}}");
+               "'arguments': {'id': 'cd0'}}");
     atapi_wait_tray(true);
     rsp = qmp_receive();
     QDECREF(rsp);
 
-    qmp_discard_response("{'execute': 'x-blockdev-remove-medium', "
-                         "'arguments': {'device': 'drive0'}}");
+    qmp_discard_response("{'execute': 'blockdev-remove-medium', "
+                         "'arguments': {'id': 'cd0'}}");
 
     /* Test the tray without a medium */
     ahci_atapi_load(ahci, port);
@@ -1612,13 +1612,13 @@ static void test_atapi_tray(void)
                                         "'driver': 'raw', "
                                         "'file': { 'driver': 'file', "
                                                   "'filename': %s }}}", iso);
-    qmp_discard_response("{'execute': 'x-blockdev-insert-medium',"
-                          "'arguments': { 'device': 'drive0', "
+    qmp_discard_response("{'execute': 'blockdev-insert-medium',"
+                          "'arguments': { 'id': 'cd0', "
                                          "'node-name': 'node0' }}");
 
     /* Again, the event shows up first */
     qmp_async("{'execute': 'blockdev-close-tray', "
-               "'arguments': {'device': 'drive0'}}");
+               "'arguments': {'id': 'cd0'}}");
     atapi_wait_tray(false);
     rsp = qmp_receive();
     QDECREF(rsp);
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
index cefe3a830e..eac5080f83 100755
--- a/tests/qemu-iotests/020
+++ b/tests/qemu-iotests/020
@@ -42,18 +42,12 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Any format supporting backing files
 _supported_fmt qcow qcow2 vmdk qed
-_supported_proto generic
-_unsupported_proto vxhs
+_supported_proto file
 _supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" \
                      "subformat=twoGbMaxExtentFlat" \
                      "subformat=twoGbMaxExtentSparse"
 
-# NFS does not support bdrv_reopen_prepare thus qemu-img commit fails.
-if [ "$IMGPROTO" = "nfs" ]; then
-    _notrun "image protocol $IMGPROTO does not support bdrv_commit"
-fi
-
 TEST_OFFSETS="0 4294967296"
 
 TEST_IMG_SAVE="$TEST_IMG"
@@ -117,10 +111,12 @@ echo
 echo 'Testing failing commit'
 echo
 
+TEST_IMG="$TEST_IMG.base" _make_test_img 1M
+
 # Create an image with a null backing file to which committing will fail (with
 # ENOSPC so we can distinguish the result from some generic EIO which may be
 # generated anywhere in the block layer)
-_make_test_img -b "json:{'driver': 'raw',
+_make_test_img -b "json:{'driver': '$IMGFMT',
                          'file': {
                              'driver': 'blkdebug',
                              'inject-error': [{
@@ -129,14 +125,15 @@ _make_test_img -b "json:{'driver': 'raw',
                                  'once': true
                              }],
                              'image': {
-                                 'driver': 'null-co'
+                                 'driver': 'file',
+                                 'filename': '$TEST_IMG.base'
                              }}}"
 
 # Just write anything so committing will not be a no-op
 $QEMU_IO -c 'writev 0 64k' "$TEST_IMG" | _filter_qemu_io
 
 $QEMU_IMG commit "$TEST_IMG"
-_cleanup_test_img
+_cleanup
 
 # success, all done
 echo "*** done"
diff --git a/tests/qemu-iotests/020.out b/tests/qemu-iotests/020.out
index 165b70aa49..4b722b2dd0 100644
--- a/tests/qemu-iotests/020.out
+++ b/tests/qemu-iotests/020.out
@@ -1078,7 +1078,8 @@ No errors were found on the image.
 
 Testing failing commit
 
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file=json:{'driver': 'raw',,
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=json:{'driver': 'IMGFMT',,
                          'file': {
                              'driver': 'blkdebug',,
                              'inject-error': [{
@@ -1087,7 +1088,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file=json:{'d
                                  'once': true
                              }],,
                              'image': {
-                                 'driver': 'null-co'
+                                 'driver': 'file',,
+                                 'filename': 'TEST_DIR/t.IMGFMT.base'
                              }}}
 wrote 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index dba8816c9f..0c3be16489 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -131,6 +131,8 @@ echo
 echo === Enable and disable lazy refcounting on the command line, plus some invalid values ===
 echo
 
+_make_test_img -o compat=1.1 "$size"
+
 run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=on
 run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=off
 run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index e3c6eaba57..dd9846d1ce 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -77,6 +77,7 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.f
 
 === Enable and disable lazy refcounting on the command line, plus some invalid values ===
 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
 QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) quit
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
index f2c5622cee..830c11880a 100644
--- a/tests/qemu-iotests/051.pc.out
+++ b/tests/qemu-iotests/051.pc.out
@@ -77,6 +77,7 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.f
 
 === Enable and disable lazy refcounting on the command line, plus some invalid values ===
 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
 QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) quit
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
index a1c34eeb7c..40f89eae18 100755
--- a/tests/qemu-iotests/059
+++ b/tests/qemu-iotests/059
@@ -152,7 +152,9 @@ done
 echo
 echo "=== Testing afl image with a very large capacity ==="
 _use_sample_img afl9.vmdk.bz2
-_img_info
+# The sed makes this test pass on machines with little RAM
+# (and also with 32 bit builds)
+_img_info | sed -e 's/Cannot allocate memory/Invalid argument/'
 _cleanup_test_img
 
 # success, all done
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index f6dce7947c..1ac5d56233 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -2358,5 +2358,5 @@ Offset          Length          Mapped to       File
 0x140000000     0x10000         0x50000         TEST_DIR/t-s003.vmdk
 
 === Testing afl image with a very large capacity ===
-qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large
+qemu-img: Could not open 'TEST_DIR/afl9.IMGFMT': Could not open 'TEST_DIR/afl9.IMGFMT': Invalid argument
 *** done
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
index 14797dd3b0..6c7407f499 100755
--- a/tests/qemu-iotests/060
+++ b/tests/qemu-iotests/060
@@ -335,7 +335,8 @@ poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x00\x2a\x01"
 # Let's write to it!
 $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
 
-# Can't repair this yet (TODO: We can just deallocate the cluster)
+echo '--- Repairing ---'
+_check_test_img -r all
 
 echo
 echo '=== Discarding with an unaligned refblock ==='
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
index c4cb7c665e..25d5c3938b 100644
--- a/tests/qemu-iotests/060.out
+++ b/tests/qemu-iotests/060.out
@@ -317,6 +317,15 @@ discard 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 qcow2: Marking image as corrupt: Preallocated zero cluster offset 0x2a00 unaligned (guest offset: 0); further corruption events will be suppressed
 write failed: Input/output error
+--- Repairing ---
+Repairing offset=2a00: Preallocated zero cluster is not properly aligned; L2 entry corrupted.
+The following inconsistencies were found and repaired:
+
+    0 leaked clusters
+    1 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
 
 === Discarding with an unaligned refblock ===
 
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
index 9d561ef786..fe259f6165 100755
--- a/tests/qemu-iotests/067
+++ b/tests/qemu-iotests/067
@@ -57,7 +57,8 @@ function run_qemu()
 {
     do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \
                           | _filter_actual_image_size \
-                          | _filter_generated_node_ids | _filter_qmp_events
+                          | _filter_generated_node_ids | _filter_qmp_events \
+                          | _filter_img_info
 }
 
 size=128M
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 58e83c4505..2e71cff3ce 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -3,7 +3,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 
 === -drive/-device and device_del ===
 
-Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk,drive=disk,id=virtio0
+Testing: -drive file=TEST_DIR/t.IMGFMT,format=IMGFMT,if=none,id=disk -device virtio-blk,drive=disk,id=virtio0
 {
     QMP_VERSION
 }
@@ -23,26 +23,17 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
                 "detect_zeroes": "off",
                 "image": {
                     "virtual-size": 134217728,
-                    "filename": "TEST_DIR/t.qcow2",
+                    "filename": "TEST_DIR/t.IMGFMT",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
                     "dirty-flag": false
                 },
                 "iops_wr": 0,
                 "ro": false,
                 "node-name": "NODE_NAME",
                 "backing_file_depth": 0,
-                "drv": "qcow2",
+                "drv": "IMGFMT",
                 "iops": 0,
                 "bps_wr": 0,
                 "write_threshold": 0,
@@ -54,7 +45,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
                     "direct": false,
                     "writeback": true
                 },
-                "file": "TEST_DIR/t.qcow2",
+                "file": "TEST_DIR/t.IMGFMT",
                 "encryption_key_missing": false
             },
             "qdev": "/machine/peripheral/virtio0/virtio-backend",
@@ -81,7 +72,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
 
 === -drive/device_add and device_del ===
 
-Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
+Testing: -drive file=TEST_DIR/t.IMGFMT,format=IMGFMT,if=none,id=disk
 {
     QMP_VERSION
 }
@@ -100,26 +91,17 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
                 "detect_zeroes": "off",
                 "image": {
                     "virtual-size": 134217728,
-                    "filename": "TEST_DIR/t.qcow2",
+                    "filename": "TEST_DIR/t.IMGFMT",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
                     "dirty-flag": false
                 },
                 "iops_wr": 0,
                 "ro": false,
                 "node-name": "NODE_NAME",
                 "backing_file_depth": 0,
-                "drv": "qcow2",
+                "drv": "IMGFMT",
                 "iops": 0,
                 "bps_wr": 0,
                 "write_threshold": 0,
@@ -131,7 +113,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
                     "direct": false,
                     "writeback": true
                 },
-                "file": "TEST_DIR/t.qcow2",
+                "file": "TEST_DIR/t.IMGFMT",
                 "encryption_key_missing": false
             },
             "type": "unknown"
@@ -183,26 +165,17 @@ Testing:
                 "detect_zeroes": "off",
                 "image": {
                     "virtual-size": 134217728,
-                    "filename": "TEST_DIR/t.qcow2",
+                    "filename": "TEST_DIR/t.IMGFMT",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
                     "dirty-flag": false
                 },
                 "iops_wr": 0,
                 "ro": false,
                 "node-name": "NODE_NAME",
                 "backing_file_depth": 0,
-                "drv": "qcow2",
+                "drv": "IMGFMT",
                 "iops": 0,
                 "bps_wr": 0,
                 "write_threshold": 0,
@@ -214,7 +187,7 @@ Testing:
                     "direct": false,
                     "writeback": true
                 },
-                "file": "TEST_DIR/t.qcow2",
+                "file": "TEST_DIR/t.IMGFMT",
                 "encryption_key_missing": false
             },
             "type": "unknown"
@@ -263,26 +236,17 @@ Testing:
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 134217728,
-                "filename": "TEST_DIR/t.qcow2",
+                "filename": "TEST_DIR/t.IMGFMT",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "disk",
             "backing_file_depth": 0,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
@@ -294,7 +258,7 @@ Testing:
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "TEST_DIR/t.IMGFMT",
             "encryption_key_missing": false
         },
         {
@@ -302,7 +266,7 @@ Testing:
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 197120,
-                "filename": "TEST_DIR/t.qcow2",
+                "filename": "TEST_DIR/t.IMGFMT",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -323,7 +287,7 @@ Testing:
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "TEST_DIR/t.IMGFMT",
             "encryption_key_missing": false
         }
     ]
@@ -347,26 +311,17 @@ Testing:
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 134217728,
-                "filename": "TEST_DIR/t.qcow2",
+                "filename": "TEST_DIR/t.IMGFMT",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "disk",
             "backing_file_depth": 0,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
@@ -378,7 +333,7 @@ Testing:
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "TEST_DIR/t.IMGFMT",
             "encryption_key_missing": false
         },
         {
@@ -386,7 +341,7 @@ Testing:
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 197120,
-                "filename": "TEST_DIR/t.qcow2",
+                "filename": "TEST_DIR/t.IMGFMT",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -407,7 +362,7 @@ Testing:
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "TEST_DIR/t.IMGFMT",
             "encryption_key_missing": false
         }
     ]
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
index 55044c700b..1c2bd85742 100755
--- a/tests/qemu-iotests/080
+++ b/tests/qemu-iotests/080
@@ -41,8 +41,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto file
 _supported_os Linux
-# Internal snapshots are (currently) impossible with refcount_bits=1
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# - Internal snapshots are (currently) impossible with refcount_bits=1
+# - This is generally a test for compat=1.1 images
+_unsupported_imgopts 'refcount_bits=1[^0-9]' 'compat=0.10'
 
 header_size=104
 
diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089
index 9bfe2307b3..0b059aba90 100755
--- a/tests/qemu-iotests/089
+++ b/tests/qemu-iotests/089
@@ -119,11 +119,11 @@ echo
 
 # Both options given directly and those given in the filename should be used
 $QEMU_IO -c "open -o driver=qcow2 json:{\"file.filename\":\"$TEST_IMG\"}" \
-         -c "info" 2>&1 | _filter_testdir | _filter_imgfmt
+         -c "info" 2>&1 | _filter_img_info
 
 # Options given directly should be prioritized over those given in the filename
 $QEMU_IO -c "open -o driver=qcow2 json:{\"driver\":\"raw\",\"file.filename\":\"$TEST_IMG\"}" \
-         -c "info" 2>&1 | _filter_testdir | _filter_imgfmt
+         -c "info" 2>&1 | _filter_img_info
 
 
 # success, all done
diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out
index 18f5fdda7a..0bf5a13ec1 100644
--- a/tests/qemu-iotests/089.out
+++ b/tests/qemu-iotests/089.out
@@ -38,17 +38,7 @@ cluster_size: 65536
 format name: IMGFMT
 cluster size: 64 KiB
 vm state offset: 512 MiB
-Format specific information:
-    compat: 1.1
-    lazy refcounts: false
-    refcount bits: 16
-    corrupt: false
 format name: IMGFMT
 cluster size: 64 KiB
 vm state offset: 512 MiB
-Format specific information:
-    compat: 1.1
-    lazy refcounts: false
-    refcount bits: 16
-    corrupt: false
 *** done
diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093
index 5c36a5fb4d..c3404a3171 100755
--- a/tests/qemu-iotests/093
+++ b/tests/qemu-iotests/093
@@ -348,9 +348,9 @@ class ThrottleTestRemovableMedia(iotests.QMPTestCase):
         # Now eject cd0 and insert cd1
         result = self.vm.qmp("blockdev-open-tray", id='dev0')
         self.assert_qmp(result, 'return', {})
-        result = self.vm.qmp("x-blockdev-remove-medium", id='dev0')
+        result = self.vm.qmp("blockdev-remove-medium", id='dev0')
         self.assert_qmp(result, 'return', {})
-        result = self.vm.qmp("x-blockdev-insert-medium", id='dev0', node_name='cd1')
+        result = self.vm.qmp("blockdev-insert-medium", id='dev0', node_name='cd1')
         self.assert_qmp(result, 'return', {})
 
         # Check that the I/O limits are still the same
@@ -359,7 +359,7 @@ class ThrottleTestRemovableMedia(iotests.QMPTestCase):
         self.assert_qmp(result, 'return[0]/inserted/bps',   50)
 
         # Eject cd1
-        result = self.vm.qmp("x-blockdev-remove-medium", id='dev0')
+        result = self.vm.qmp("blockdev-remove-medium", id='dev0')
         self.assert_qmp(result, 'return', {})
 
         # Check that we can't set limits if the device has no medium
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
index d7ad8d9840..04b3f28445 100755
--- a/tests/qemu-iotests/102
+++ b/tests/qemu-iotests/102
@@ -69,7 +69,12 @@ $QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io
 
 qemu_comm_method=monitor _launch_qemu -drive if=none,file="$TEST_IMG",id=drv0
 
-$QEMU_IMG resize -f raw --shrink "$TEST_IMG" $((5 * 64 * 1024))
+# Wait for a prompt to appear (so we know qemu has opened the image)
+_send_qemu_cmd '' '(qemu)'
+
+$QEMU_IMG resize --shrink --image-opts \
+    "driver=raw,file.driver=file,file.filename=$TEST_IMG,file.locking=off" \
+    $((5 * 64 * 1024))
 
 _send_qemu_cmd $QEMU_HANDLE 'qemu-io drv0 map' 'allocated' \
     | sed -e 's/^(qemu).*qemu-io drv0 map...$/(qemu) qemu-io drv0 map/'
diff --git a/tests/qemu-iotests/102.out b/tests/qemu-iotests/102.out
index ccf172abd9..4401b08fee 100644
--- a/tests/qemu-iotests/102.out
+++ b/tests/qemu-iotests/102.out
@@ -14,8 +14,9 @@ Offset          Length          Mapped to       File
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
 wrote 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Image resized.
 QEMU X.Y.Z monitor - type 'help' for more information
+Image resized.
+(qemu)
 (qemu) qemu-io drv0 map
 64 KiB (0x10000) bytes     allocated at offset 0 bytes (0x0)
 *** done
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
index ecbd8ebd71..d0cfab8844 100755
--- a/tests/qemu-iotests/103
+++ b/tests/qemu-iotests/103
@@ -40,6 +40,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto file nfs
 _supported_os Linux
+# Internal snapshots are (currently) impossible with refcount_bits=1
+_unsupported_imgopts 'refcount_bits=1[^0-9]'
 
 IMG_SIZE=64K
 
diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118
index 8a9e838c90..a0469b570e 100755
--- a/tests/qemu-iotests/118
+++ b/tests/qemu-iotests/118
@@ -28,6 +28,14 @@ from iotests import qemu_img
 old_img = os.path.join(iotests.test_dir, 'test0.img')
 new_img = os.path.join(iotests.test_dir, 'test1.img')
 
+def interface_to_device_name(interface):
+    if interface == 'ide':
+        return 'ide-cd'
+    elif interface == 'floppy':
+        return 'floppy'
+    else:
+        return None
+
 class ChangeBaseClass(iotests.QMPTestCase):
     has_opened = False
     has_closed = False
@@ -63,7 +71,7 @@ class ChangeBaseClass(iotests.QMPTestCase):
 
 class GeneralChangeTestsBaseClass(ChangeBaseClass):
 
-    device_name = None
+    device_name = 'qdev0'
 
     def test_change(self):
         result = self.vm.qmp('change', device='drive0', target=new_img,
@@ -79,14 +87,9 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 
     def test_blockdev_change_medium(self):
-        if self.device_name is not None:
-            result = self.vm.qmp('blockdev-change-medium',
-                                 id=self.device_name, filename=new_img,
-                                 format=iotests.imgfmt)
-        else:
-            result = self.vm.qmp('blockdev-change-medium',
-                                 device='drive0', filename=new_img,
-                                 format=iotests.imgfmt)
+        result = self.vm.qmp('blockdev-change-medium',
+                             id=self.device_name, filename=new_img,
+                             format=iotests.imgfmt)
 
         self.assert_qmp(result, 'return', {})
 
@@ -99,10 +102,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 
     def test_eject(self):
-        if self.device_name is not None:
-            result = self.vm.qmp('eject', id=self.device_name, force=True)
-        else:
-            result = self.vm.qmp('eject', device='drive0', force=True)
+        result = self.vm.qmp('eject', id=self.device_name, force=True)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_open()
@@ -113,10 +113,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         self.assert_qmp_absent(result, 'return[0]/inserted')
 
     def test_tray_eject_change(self):
-        if self.device_name is not None:
-            result = self.vm.qmp('eject', id=self.device_name, force=True)
-        else:
-            result = self.vm.qmp('eject', device='drive0', force=True)
+        result = self.vm.qmp('eject', id=self.device_name, force=True)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_open()
@@ -126,12 +123,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
             self.assert_qmp(result, 'return[0]/tray_open', True)
         self.assert_qmp_absent(result, 'return[0]/inserted')
 
-        if self.device_name is not None:
-            result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
-                                 filename=new_img, format=iotests.imgfmt)
-        else:
-            result = self.vm.qmp('blockdev-change-medium', device='drive0',
-                                 filename=new_img, format=iotests.imgfmt)
+        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
+                             filename=new_img, format=iotests.imgfmt)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_close()
@@ -142,12 +135,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 
     def test_tray_open_close(self):
-        if self.device_name is not None:
-            result = self.vm.qmp('blockdev-open-tray',
-                                 id=self.device_name, force=True)
-        else:
-            result = self.vm.qmp('blockdev-open-tray',
-                                 device='drive0', force=True)
+        result = self.vm.qmp('blockdev-open-tray',
+                             id=self.device_name, force=True)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_open()
@@ -160,10 +149,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         else:
             self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        if self.device_name is not None:
-            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
-        else:
-            result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
         self.assert_qmp(result, 'return', {})
 
         if self.has_real_tray or not self.was_empty:
@@ -178,7 +164,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
             self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
     def test_tray_eject_close(self):
-        result = self.vm.qmp('eject', device='drive0', force=True)
+        result = self.vm.qmp('eject', id=self.device_name, force=True)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_open()
@@ -188,10 +174,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
             self.assert_qmp(result, 'return[0]/tray_open', True)
         self.assert_qmp_absent(result, 'return[0]/inserted')
 
-        if self.device_name is not None:
-            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
-        else:
-            result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_close()
@@ -202,7 +185,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         self.assert_qmp_absent(result, 'return[0]/inserted')
 
     def test_tray_open_change(self):
-        result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+        result = self.vm.qmp('blockdev-open-tray', id=self.device_name,
+                                                   force=True)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_open()
@@ -215,7 +199,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         else:
             self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
                                                        filename=new_img,
                                                        format=iotests.imgfmt)
         self.assert_qmp(result, 'return', {})
@@ -235,12 +219,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
                                     'driver': 'file'})
         self.assert_qmp(result, 'return', {})
 
-        if self.device_name is not None:
-            result = self.vm.qmp('blockdev-open-tray',
-                                 id=self.device_name, force=True)
-        else:
-            result = self.vm.qmp('blockdev-open-tray',
-                                 device='drive0', force=True)
+        result = self.vm.qmp('blockdev-open-tray',
+                             id=self.device_name, force=True)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_open()
@@ -253,11 +233,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         else:
             self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        if self.device_name is not None:
-            result = self.vm.qmp('x-blockdev-remove-medium',
-                                 id=self.device_name)
-        else:
-            result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+        result = self.vm.qmp('blockdev-remove-medium',
+                             id=self.device_name)
         self.assert_qmp(result, 'return', {})
 
         result = self.vm.qmp('query-block')
@@ -265,12 +242,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
             self.assert_qmp(result, 'return[0]/tray_open', True)
         self.assert_qmp_absent(result, 'return[0]/inserted')
 
-        if self.device_name is not None:
-            result = self.vm.qmp('x-blockdev-insert-medium',
-                                 id=self.device_name, node_name='new')
-        else:
-            result = self.vm.qmp('x-blockdev-insert-medium',
-                                 device='drive0', node_name='new')
+        result = self.vm.qmp('blockdev-insert-medium',
+                             id=self.device_name, node_name='new')
         self.assert_qmp(result, 'return', {})
 
         result = self.vm.qmp('query-block')
@@ -278,10 +251,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
             self.assert_qmp(result, 'return[0]/tray_open', True)
         self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 
-        if self.device_name is not None:
-            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
-        else:
-            result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_close()
@@ -292,7 +262,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 
     def test_close_on_closed(self):
-        result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
         # Should be a no-op
         self.assert_qmp(result, 'return', {})
         self.assertEquals(self.vm.get_qmp_events(wait=False), [])
@@ -301,7 +271,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
         if not self.has_real_tray:
             return
 
-        result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
         self.assert_qmp(result, 'error/class', 'GenericError')
 
     def test_insert_on_closed(self):
@@ -315,7 +285,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
                                    'driver': 'file'})
         self.assert_qmp(result, 'return', {})
 
-        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
                                                        node_name='new')
         self.assert_qmp(result, 'error/class', 'GenericError')
 
@@ -326,12 +296,10 @@ class TestInitiallyFilled(GeneralChangeTestsBaseClass):
         qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
         qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
         self.vm = iotests.VM()
-        if interface == 'ide':
-            self.device_name = 'qdev0'
-            self.vm.add_drive(old_img, 'media=%s' % media, 'none')
-            self.vm.add_device('ide-cd,drive=drive0,id=%s' % self.device_name)
-        else:
-            self.vm.add_drive(old_img, 'media=%s' % media, interface)
+        self.vm.add_drive(old_img, 'media=%s' % media, 'none')
+        self.vm.add_device('%s,drive=drive0,id=%s' %
+                           (interface_to_device_name(interface),
+                            self.device_name))
         self.vm.launch()
 
     def tearDown(self):
@@ -347,12 +315,12 @@ class TestInitiallyFilled(GeneralChangeTestsBaseClass):
                                    'driver': 'file'})
         self.assert_qmp(result, 'return', {})
 
-        result = self.vm.qmp('blockdev-open-tray', device='drive0')
+        result = self.vm.qmp('blockdev-open-tray', id=self.device_name)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_open()
 
-        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
                                                        node_name='new')
         self.assert_qmp(result, 'error/class', 'GenericError')
 
@@ -361,7 +329,10 @@ class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
 
     def setUp(self, media, interface):
         qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
-        self.vm = iotests.VM().add_drive(None, 'media=%s' % media, interface)
+        self.vm = iotests.VM().add_drive(None, 'media=%s' % media, 'none')
+        self.vm.add_device('%s,drive=drive0,id=%s' %
+                           (interface_to_device_name(interface),
+                            self.device_name))
         self.vm.launch()
 
     def tearDown(self):
@@ -369,12 +340,12 @@ class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
         os.remove(new_img)
 
     def test_remove_on_empty(self):
-        result = self.vm.qmp('blockdev-open-tray', device='drive0')
+        result = self.vm.qmp('blockdev-open-tray', id=self.device_name)
         self.assert_qmp(result, 'return', {})
 
         self.wait_for_open()
 
-        result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
         # Should be a no-op
         self.assert_qmp(result, 'return', {})
 
@@ -410,6 +381,8 @@ class TestFloppyInitiallyEmpty(TestInitiallyEmpty):
         self.has_opened = True
 
 class TestChangeReadOnly(ChangeBaseClass):
+    device_name = 'qdev0'
+
     def setUp(self):
         qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
         qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
@@ -425,14 +398,15 @@ class TestChangeReadOnly(ChangeBaseClass):
     def test_ro_ro_retain(self):
         os.chmod(old_img, 0444)
         os.chmod(new_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
         self.assert_qmp(result, 'return[0]/inserted/ro', True)
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
                                                        filename=new_img,
                                                        format=iotests.imgfmt,
                                                        read_only_mode='retain')
@@ -444,14 +418,15 @@ class TestChangeReadOnly(ChangeBaseClass):
 
     def test_ro_rw_retain(self):
         os.chmod(old_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
         self.assert_qmp(result, 'return[0]/inserted/ro', True)
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
                                                        filename=new_img,
                                                        format=iotests.imgfmt,
                                                        read_only_mode='retain')
@@ -463,14 +438,15 @@ class TestChangeReadOnly(ChangeBaseClass):
 
     def test_rw_ro_retain(self):
         os.chmod(new_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
         self.assert_qmp(result, 'return[0]/inserted/ro', False)
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
                                                        filename=new_img,
                                                        format=iotests.imgfmt,
                                                        read_only_mode='retain')
@@ -484,7 +460,8 @@ class TestChangeReadOnly(ChangeBaseClass):
 
     def test_ro_rw(self):
         os.chmod(old_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
@@ -492,7 +469,7 @@ class TestChangeReadOnly(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
         result = self.vm.qmp('blockdev-change-medium',
-                             device='drive0',
+                             id=self.device_name,
                              filename=new_img,
                              format=iotests.imgfmt,
                              read_only_mode='read-write')
@@ -504,7 +481,8 @@ class TestChangeReadOnly(ChangeBaseClass):
 
     def test_rw_ro(self):
         os.chmod(new_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
@@ -512,7 +490,7 @@ class TestChangeReadOnly(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
         result = self.vm.qmp('blockdev-change-medium',
-                             device='drive0',
+                             id=self.device_name,
                              filename=new_img,
                              format=iotests.imgfmt,
                              read_only_mode='read-only')
@@ -523,7 +501,8 @@ class TestChangeReadOnly(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
 
     def test_make_rw_ro(self):
-        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
@@ -531,7 +510,7 @@ class TestChangeReadOnly(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
         result = self.vm.qmp('blockdev-change-medium',
-                             device='drive0',
+                             id=self.device_name,
                              filename=new_img,
                              format=iotests.imgfmt,
                              read_only_mode='read-only')
@@ -543,7 +522,8 @@ class TestChangeReadOnly(ChangeBaseClass):
 
     def test_make_ro_rw(self):
         os.chmod(new_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
@@ -551,7 +531,7 @@ class TestChangeReadOnly(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
         result = self.vm.qmp('blockdev-change-medium',
-                             device='drive0',
+                             id=self.device_name,
                              filename=new_img,
                              format=iotests.imgfmt,
                              read_only_mode='read-write')
@@ -563,14 +543,15 @@ class TestChangeReadOnly(ChangeBaseClass):
 
     def test_make_rw_ro_by_retain(self):
         os.chmod(old_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
         self.assert_qmp(result, 'return[0]/inserted/ro', True)
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
                                                        filename=new_img,
                                                        format=iotests.imgfmt,
                                                        read_only_mode='retain')
@@ -582,14 +563,15 @@ class TestChangeReadOnly(ChangeBaseClass):
 
     def test_make_ro_rw_by_retain(self):
         os.chmod(new_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
         self.assert_qmp(result, 'return[0]/inserted/ro', False)
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
                                                        filename=new_img,
                                                        format=iotests.imgfmt,
                                                        read_only_mode='retain')
@@ -601,7 +583,8 @@ class TestChangeReadOnly(ChangeBaseClass):
 
     def test_rw_ro_cycle(self):
         os.chmod(new_img, 0444)
-        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.add_drive(old_img, 'media=disk', 'none')
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
@@ -620,13 +603,13 @@ class TestChangeReadOnly(ChangeBaseClass):
         self.assert_qmp(result, 'return[0]/inserted/ro', False)
         self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
 
-        result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
         self.assert_qmp(result, 'return', {})
 
         result = self.vm.qmp('query-block')
         self.assert_qmp_absent(result, 'return[0]/inserted')
 
-        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
                                                        node_name='new')
         self.assert_qmp(result, 'return', {})
 
@@ -644,11 +627,14 @@ TestInitiallyEmpty = None
 
 
 class TestBlockJobsAfterCycle(ChangeBaseClass):
+    device_name = 'qdev0'
+
     def setUp(self):
-        qemu_img('create', '-f', iotests.imgfmt, old_img, '1M')
+        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K')
 
         self.vm = iotests.VM()
         self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
+        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
         self.vm.launch()
 
         result = self.vm.qmp('query-block')
@@ -656,7 +642,7 @@ class TestBlockJobsAfterCycle(ChangeBaseClass):
 
         # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
         # is not necessary
-        result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
         self.assert_qmp(result, 'return', {})
 
         result = self.vm.qmp('query-block')
@@ -669,7 +655,7 @@ class TestBlockJobsAfterCycle(ChangeBaseClass):
                                    'driver': 'file'})
         self.assert_qmp(result, 'return', {})
 
-        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
                                                        node_name='node0')
         self.assert_qmp(result, 'return', {})
 
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
index e7e43de6d6..2c4b94da1b 100755
--- a/tests/qemu-iotests/130
+++ b/tests/qemu-iotests/130
@@ -45,6 +45,8 @@ _supported_fmt qcow2
 _supported_proto generic
 _unsupported_proto vxhs
 _supported_os Linux
+# We are going to use lazy-refcounts
+_unsupported_imgopts 'compat=0.10'
 
 qemu_comm_method="monitor"
 
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
index eb91e517d7..5a01250005 100755
--- a/tests/qemu-iotests/137
+++ b/tests/qemu-iotests/137
@@ -41,6 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto file
 _supported_os Linux
+# We are going to use lazy-refcounts
+_unsupported_imgopts 'compat=0.10'
 
 
 _make_test_img 64M
diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139
index f8f02808a9..cc7fe337f3 100644
--- a/tests/qemu-iotests/139
+++ b/tests/qemu-iotests/139
@@ -133,7 +133,7 @@ class TestBlockdevDel(iotests.QMPTestCase):
     # Insert a BlockDriverState
     def insertDrive(self, device, node):
         self.checkBlockDriverState(node)
-        result = self.vm.qmp('x-blockdev-insert-medium',
+        result = self.vm.qmp('blockdev-insert-medium',
                              id = device, node_name = node)
         self.assert_qmp(result, 'return', {})
         self.checkBlockDriverState(node)
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
index 0b86ea4e5c..fc9fa975be 100755
--- a/tests/qemu-iotests/155
+++ b/tests/qemu-iotests/155
@@ -51,36 +51,30 @@ class BaseClass(iotests.QMPTestCase):
     target_real_backing = None
 
     def setUp(self):
-        qemu_img('create', '-f', iotests.imgfmt, back0_img, '1M')
+        qemu_img('create', '-f', iotests.imgfmt, back0_img, '1440K')
         qemu_img('create', '-f', iotests.imgfmt, '-b', back0_img, back1_img)
         qemu_img('create', '-f', iotests.imgfmt, '-b', back1_img, back2_img)
         qemu_img('create', '-f', iotests.imgfmt, '-b', back2_img, source_img)
 
         self.vm = iotests.VM()
-        self.vm.add_drive(None, '', 'none')
-        self.vm.launch()
-
         # Add the BDS via blockdev-add so it stays around after the mirror block
         # job has been completed
-        result = self.vm.qmp('blockdev-add',
-                             node_name='source',
-                             driver=iotests.imgfmt,
-                             file={'driver': 'file',
-                                   'filename': source_img})
-        self.assert_qmp(result, 'return', {})
-
-        result = self.vm.qmp('x-blockdev-insert-medium',
-                             device='drive0', node_name='source')
-        self.assert_qmp(result, 'return', {})
+        blockdev = {'node-name': 'source',
+                    'driver': iotests.imgfmt,
+                    'file': {'driver': 'file',
+                             'filename': source_img}}
+        self.vm.add_blockdev(self.qmp_to_opts(blockdev))
+        self.vm.add_device('floppy,id=qdev0,drive=source')
+        self.vm.launch()
 
         self.assertIntactSourceBackingChain()
 
         if self.existing:
             if self.target_backing:
                 qemu_img('create', '-f', iotests.imgfmt,
-                         '-b', self.target_backing, target_img, '1M')
+                         '-b', self.target_backing, target_img, '1440K')
             else:
-                qemu_img('create', '-f', iotests.imgfmt, target_img, '1M')
+                qemu_img('create', '-f', iotests.imgfmt, target_img, '1440K')
 
             if self.cmd == 'blockdev-mirror':
                 options = { 'node-name': 'target',
@@ -104,11 +98,11 @@ class BaseClass(iotests.QMPTestCase):
         except OSError:
             pass
 
-    def findBlockNode(self, node_name, id=None):
-        if id:
+    def findBlockNode(self, node_name, qdev=None):
+        if qdev:
             result = self.vm.qmp('query-block')
             for device in result['return']:
-                if device['device'] == id:
+                if device['qdev'] == qdev:
                     if node_name:
                         self.assert_qmp(device, 'inserted/node-name', node_name)
                     return device['inserted']
@@ -118,7 +112,7 @@ class BaseClass(iotests.QMPTestCase):
                 if node['node-name'] == node_name:
                     return node
 
-        self.fail('Cannot find node %s/%s' % (id, node_name))
+        self.fail('Cannot find node %s/%s' % (qdev, node_name))
 
     def assertIntactSourceBackingChain(self):
         node = self.findBlockNode('source')
@@ -155,22 +149,23 @@ class BaseClass(iotests.QMPTestCase):
 class MirrorBaseClass(BaseClass):
     def runMirror(self, sync):
         if self.cmd == 'blockdev-mirror':
-            result = self.vm.qmp(self.cmd, device='drive0', sync=sync,
-                                 target='target')
+            result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source',
+                                 sync=sync, target='target')
         else:
             if self.existing:
                 mode = 'existing'
             else:
                 mode = 'absolute-paths'
-            result = self.vm.qmp(self.cmd, device='drive0', sync=sync,
-                                 target=target_img, format=iotests.imgfmt,
-                                 mode=mode, node_name='target')
+            result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source',
+                                 sync=sync, target=target_img,
+                                 format=iotests.imgfmt, mode=mode,
+                                 node_name='target')
 
         self.assert_qmp(result, 'return', {})
 
         self.vm.event_wait('BLOCK_JOB_READY')
 
-        result = self.vm.qmp('block-job-complete', device='drive0')
+        result = self.vm.qmp('block-job-complete', device='mirror-job')
         self.assert_qmp(result, 'return', {})
 
         self.vm.event_wait('BLOCK_JOB_COMPLETED')
@@ -178,21 +173,21 @@ class MirrorBaseClass(BaseClass):
     def testFull(self):
         self.runMirror('full')
 
-        node = self.findBlockNode('target', 'drive0')
+        node = self.findBlockNode('target', 'qdev0')
         self.assertCorrectBackingImage(node, None)
         self.assertIntactSourceBackingChain()
 
     def testTop(self):
         self.runMirror('top')
 
-        node = self.findBlockNode('target', 'drive0')
+        node = self.findBlockNode('target', 'qdev0')
         self.assertCorrectBackingImage(node, back2_img)
         self.assertIntactSourceBackingChain()
 
     def testNone(self):
         self.runMirror('none')
 
-        node = self.findBlockNode('target', 'drive0')
+        node = self.findBlockNode('target', 'qdev0')
         self.assertCorrectBackingImage(node, source_img)
         self.assertIntactSourceBackingChain()
 
@@ -233,17 +228,18 @@ class TestCommit(BaseClass):
     existing = False
 
     def testCommit(self):
-        result = self.vm.qmp('block-commit', device='drive0', base=back1_img)
+        result = self.vm.qmp('block-commit', job_id='commit-job',
+                             device='source', base=back1_img)
         self.assert_qmp(result, 'return', {})
 
         self.vm.event_wait('BLOCK_JOB_READY')
 
-        result = self.vm.qmp('block-job-complete', device='drive0')
+        result = self.vm.qmp('block-job-complete', device='commit-job')
         self.assert_qmp(result, 'return', {})
 
         self.vm.event_wait('BLOCK_JOB_COMPLETED')
 
-        node = self.findBlockNode(None, 'drive0')
+        node = self.findBlockNode(None, 'qdev0')
         self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename',
                         back1_img)
         self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename',
diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176
index b8dc17c592..d38b3aeb91 100755
--- a/tests/qemu-iotests/176
+++ b/tests/qemu-iotests/176
@@ -48,6 +48,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto file
 _supported_os Linux
+# Persistent dirty bitmaps require compat=1.1
+_unsupported_imgopts 'compat=0.10'
 
 function run_qemu()
 {
diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177
index 28990977f1..396986da89 100755
--- a/tests/qemu-iotests/177
+++ b/tests/qemu-iotests/177
@@ -2,7 +2,7 @@
 #
 # Test corner cases with unusual block geometries
 #
-# Copyright (C) 2016-2017 Red Hat, Inc.
+# Copyright (C) 2016-2018 Red Hat, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -37,13 +37,15 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.rc
 . ./common.filter
 
+# This test is runnable under compat=0.10; see test 204 for additional
+# tests specific to compat=1.1.
+
 _supported_fmt qcow2
 _supported_proto file
 
 CLUSTER_SIZE=1M
 size=128M
 options=driver=blkdebug,image.driver=qcow2
-nested_opts=image.file.driver=file,image.file.filename=$TEST_IMG
 
 echo
 echo "== setting up files =="
@@ -51,7 +53,7 @@ echo "== setting up files =="
 TEST_IMG="$TEST_IMG.base" _make_test_img $size
 $QEMU_IO -c "write -P 11 0 $size" "$TEST_IMG.base" | _filter_qemu_io
 _make_test_img -b "$TEST_IMG.base"
-$QEMU_IO -c "write -P 22 0 110M" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "write -P 22 0 $size" "$TEST_IMG" | _filter_qemu_io
 
 # Limited to 64k max-transfer
 echo
@@ -82,13 +84,6 @@ $QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
          -c "discard 80000001 30M" | _filter_qemu_io
 
 echo
-echo "== block status smaller than alignment =="
-limits=align=4k
-$QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
-	 -c "alloc 1 1" -c "alloc 0x6dffff0 1000" -c "alloc 127m 5P" \
-	 -c map | _filter_qemu_io
-
-echo
 echo "== verify image content =="
 
 function verify_io()
@@ -110,13 +105,10 @@ function verify_io()
     echo read -P 0 32M 32M
     echo read -P 22 64M 13M
     echo read -P $discarded 77M 29M
-    echo read -P 22 106M 4M
-    echo read -P 11 110M 18M
+    echo read -P 22 106M 22M
 }
 
 verify_io | $QEMU_IO -r "$TEST_IMG" | _filter_qemu_io
-$QEMU_IMG map --image-opts "$options,$nested_opts,align=4k" \
-    | _filter_qemu_img_map
 
 _check_test_img
 
diff --git a/tests/qemu-iotests/177.out b/tests/qemu-iotests/177.out
index f788b55e20..e887542678 100644
--- a/tests/qemu-iotests/177.out
+++ b/tests/qemu-iotests/177.out
@@ -5,8 +5,8 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
 wrote 134217728/134217728 bytes at offset 0
 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
-wrote 115343360/115343360 bytes at offset 0
-110 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
 == constrained alignment and max-transfer ==
 wrote 131072/131072 bytes at offset 1000
@@ -26,13 +26,6 @@ wrote 33554432/33554432 bytes at offset 33554432
 discard 31457280/31457280 bytes at offset 80000001
 30 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
-== block status smaller than alignment ==
-1/1 bytes allocated at offset 1 bytes
-16/1000 bytes allocated at offset 110 MiB
-0/1048576 bytes allocated at offset 127 MiB
-110 MiB (0x6e00000) bytes     allocated at offset 0 bytes (0x0)
-18 MiB (0x1200000) bytes not allocated at offset 110 MiB (0x6e00000)
-
 == verify image content ==
 read 1000/1000 bytes at offset 0
 1000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -50,14 +43,7 @@ read 13631488/13631488 bytes at offset 67108864
 13 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 read 30408704/30408704 bytes at offset 80740352
 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-read 4194304/4194304 bytes at offset 111149056
-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-read 18874368/18874368 bytes at offset 115343360
-18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Offset          Length          File
-0               0x800000        TEST_DIR/t.IMGFMT
-0x900000        0x2400000       TEST_DIR/t.IMGFMT
-0x3c00000       0x1100000       TEST_DIR/t.IMGFMT
-0x6a00000       0x400000        TEST_DIR/t.IMGFMT
+read 23068672/23068672 bytes at offset 111149056
+22 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
 *** done
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
index ee96c99af3..2b68284d58 100755
--- a/tests/qemu-iotests/184
+++ b/tests/qemu-iotests/184
@@ -27,18 +27,12 @@ echo "QA output created by $seq"
 here=`pwd`
 status=1	# failure is the default!
 
-_cleanup()
-{
-    _cleanup_test_img
-}
-trap "_cleanup; exit \$status" 0 1 2 3 15
+trap "exit \$status" 0 1 2 3 15
 
 # get standard environment, filters and checks
 . ./common.rc
 . ./common.filter
 
-_supported_fmt qcow2
-_supported_proto file
 _supported_os Linux
 
 function do_run_qemu()
@@ -55,7 +49,6 @@ function run_qemu()
                           | _filter_actual_image_size
 }
 
-_make_test_img 64M
 test_throttle=$($QEMU_IMG --help|grep throttle)
 [ "$test_throttle" = "" ] && _supported_fmt throttle
 
@@ -66,12 +59,8 @@ run_qemu <<EOF
 { "execute": "qmp_capabilities" }
 { "execute": "blockdev-add",
   "arguments": {
-    "driver": "$IMGFMT",
-    "node-name": "disk0",
-    "file": {
-      "driver": "file",
-      "filename": "$TEST_IMG"
-    }
+    "driver": "null-co",
+    "node-name": "disk0"
   }
 }
 { "execute": "object-add",
@@ -181,12 +170,8 @@ run_qemu <<EOF
 { "execute": "qmp_capabilities" }
 { "execute": "blockdev-add",
   "arguments": {
-    "driver": "$IMGFMT",
-    "node-name": "disk0",
-    "file": {
-      "driver": "file",
-      "filename": "$TEST_IMG"
-    }
+    "driver": "null-co",
+    "node-name": "disk0"
   }
 }
 { "execute": "blockdev-add",
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
index 4dc7984a85..672650cde8 100644
--- a/tests/qemu-iotests/184.out
+++ b/tests/qemu-iotests/184.out
@@ -1,5 +1,4 @@
 QA output created by 184
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
 
 == checking interface ==
 Testing:
@@ -28,12 +27,9 @@ Testing:
             "iops_rd": 0,
             "detect_zeroes": "off",
             "image": {
-                "virtual-size": 67108864,
-                "filename": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"qcow2\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/t.qcow2\"}}}",
-                "cluster-size": 65536,
-                "format": "throttle",
-                "actual-size": SIZE,
-                "dirty-flag": false
+                "virtual-size": 1073741824,
+                "filename": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"null-co\"}}",
+                "format": "throttle"
             },
             "iops_wr": 0,
             "ro": false,
@@ -51,34 +47,22 @@ Testing:
                 "direct": false,
                 "writeback": true
             },
-            "file": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"qcow2\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/t.qcow2\"}}}",
+            "file": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"null-co\"}}",
             "encryption_key_missing": false
         },
         {
             "iops_rd": 0,
             "detect_zeroes": "off",
             "image": {
-                "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2",
-                "cluster-size": 65536,
-                "format": "qcow2",
-                "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
-                "dirty-flag": false
+                "virtual-size": 1073741824,
+                "filename": "null-co://",
+                "format": "null-co"
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "disk0",
             "backing_file_depth": 0,
-            "drv": "qcow2",
+            "drv": "null-co",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
@@ -90,36 +74,7 @@ Testing:
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
-            "encryption_key_missing": false
-        },
-        {
-            "iops_rd": 0,
-            "detect_zeroes": "off",
-            "image": {
-                "virtual-size": 197120,
-                "filename": "TEST_DIR/t.qcow2",
-                "format": "file",
-                "actual-size": SIZE,
-                "dirty-flag": false
-            },
-            "iops_wr": 0,
-            "ro": false,
-            "node-name": "NODE_NAME",
-            "backing_file_depth": 0,
-            "drv": "file",
-            "iops": 0,
-            "bps_wr": 0,
-            "write_threshold": 0,
-            "encrypted": false,
-            "bps": 0,
-            "bps_rd": 0,
-            "cache": {
-                "no-flush": false,
-                "direct": false,
-                "writeback": true
-            },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "null-co://",
             "encryption_key_missing": false
         }
     ]
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
index ad785e10b1..dfad6555e4 100755
--- a/tests/qemu-iotests/191
+++ b/tests/qemu-iotests/191
@@ -45,7 +45,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2
-_unsupported_imgopts compat=0.10
 _supported_proto file
 _supported_os Linux
 
@@ -92,7 +91,7 @@ echo === Check that both top and top2 point to base now ===
 echo
 
 _send_qemu_cmd $h "{ 'execute': 'query-named-block-nodes' }" "^}" |
-    _filter_generated_node_ids | _filter_actual_image_size
+    _filter_generated_node_ids | _filter_actual_image_size | _filter_img_info
 
 _send_qemu_cmd $h "{ 'execute': 'quit' }" "^}"
 wait=1 _cleanup_qemu
@@ -140,7 +139,7 @@ echo === Check that both top and top2 point to base now ===
 echo
 
 _send_qemu_cmd $h "{ 'execute': 'query-named-block-nodes' }" "^}" |
-    _filter_generated_node_ids | _filter_actual_image_size
+    _filter_generated_node_ids | _filter_actual_image_size | _filter_img_info
 
 _send_qemu_cmd $h "{ 'execute': 'quit' }" "^}"
 wait=1 _cleanup_qemu
diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out
index 73c0ed454c..190c5f049a 100644
--- a/tests/qemu-iotests/191.out
+++ b/tests/qemu-iotests/191.out
@@ -44,49 +44,31 @@ wrote 65536/65536 bytes at offset 1048576
             "image": {
                 "backing-image": {
                     "virtual-size": 67108864,
-                    "filename": "TEST_DIR/t.qcow2.base",
+                    "filename": "TEST_DIR/t.IMGFMT.base",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
                     "dirty-flag": false
                 },
-                "backing-filename-format": "qcow2",
+                "backing-filename-format": "IMGFMT",
                 "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2.ovl2",
+                "filename": "TEST_DIR/t.IMGFMT.ovl2",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
-                "full-backing-filename": "TEST_DIR/t.qcow2.base",
-                "backing-filename": "TEST_DIR/t.qcow2.base",
+                "full-backing-filename": "TEST_DIR/t.IMGFMT.base",
+                "backing-filename": "TEST_DIR/t.IMGFMT.base",
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "top2",
             "backing_file_depth": 1,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
-            "backing_file": "TEST_DIR/t.qcow2.base",
+            "backing_file": "TEST_DIR/t.IMGFMT.base",
             "encrypted": false,
             "bps": 0,
             "bps_rd": 0,
@@ -95,7 +77,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.ovl2",
+            "file": "TEST_DIR/t.IMGFMT.ovl2",
             "encryption_key_missing": false
         },
         {
@@ -103,7 +85,7 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 197120,
-                "filename": "TEST_DIR/t.qcow2.ovl2",
+                "filename": "TEST_DIR/t.IMGFMT.ovl2",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -124,7 +106,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.ovl2",
+            "file": "TEST_DIR/t.IMGFMT.ovl2",
             "encryption_key_missing": false
         },
         {
@@ -133,49 +115,31 @@ wrote 65536/65536 bytes at offset 1048576
             "image": {
                 "backing-image": {
                     "virtual-size": 67108864,
-                    "filename": "TEST_DIR/t.qcow2.base",
+                    "filename": "TEST_DIR/t.IMGFMT.base",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
                     "dirty-flag": false
                 },
-                "backing-filename-format": "qcow2",
+                "backing-filename-format": "IMGFMT",
                 "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2",
+                "filename": "TEST_DIR/t.IMGFMT",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
-                "full-backing-filename": "TEST_DIR/t.qcow2.base",
-                "backing-filename": "TEST_DIR/t.qcow2.base",
+                "full-backing-filename": "TEST_DIR/t.IMGFMT.base",
+                "backing-filename": "TEST_DIR/t.IMGFMT.base",
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "top",
             "backing_file_depth": 1,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
-            "backing_file": "TEST_DIR/t.qcow2.base",
+            "backing_file": "TEST_DIR/t.IMGFMT.base",
             "encrypted": false,
             "bps": 0,
             "bps_rd": 0,
@@ -184,7 +148,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "TEST_DIR/t.IMGFMT",
             "encryption_key_missing": false
         },
         {
@@ -192,7 +156,7 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 197120,
-                "filename": "TEST_DIR/t.qcow2",
+                "filename": "TEST_DIR/t.IMGFMT",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -213,7 +177,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "TEST_DIR/t.IMGFMT",
             "encryption_key_missing": false
         },
         {
@@ -222,49 +186,31 @@ wrote 65536/65536 bytes at offset 1048576
             "image": {
                 "backing-image": {
                     "virtual-size": 67108864,
-                    "filename": "TEST_DIR/t.qcow2.base",
+                    "filename": "TEST_DIR/t.IMGFMT.base",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
                     "dirty-flag": false
                 },
-                "backing-filename-format": "qcow2",
+                "backing-filename-format": "IMGFMT",
                 "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2.mid",
+                "filename": "TEST_DIR/t.IMGFMT.mid",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
-                "full-backing-filename": "TEST_DIR/t.qcow2.base",
-                "backing-filename": "TEST_DIR/t.qcow2.base",
+                "full-backing-filename": "TEST_DIR/t.IMGFMT.base",
+                "backing-filename": "TEST_DIR/t.IMGFMT.base",
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "mid",
             "backing_file_depth": 1,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
-            "backing_file": "TEST_DIR/t.qcow2.base",
+            "backing_file": "TEST_DIR/t.IMGFMT.base",
             "encrypted": false,
             "bps": 0,
             "bps_rd": 0,
@@ -273,7 +219,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.mid",
+            "file": "TEST_DIR/t.IMGFMT.mid",
             "encryption_key_missing": false
         },
         {
@@ -281,7 +227,7 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 393216,
-                "filename": "TEST_DIR/t.qcow2.mid",
+                "filename": "TEST_DIR/t.IMGFMT.mid",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -302,7 +248,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.mid",
+            "file": "TEST_DIR/t.IMGFMT.mid",
             "encryption_key_missing": false
         },
         {
@@ -310,26 +256,17 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2.base",
+                "filename": "TEST_DIR/t.IMGFMT.base",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "base",
             "backing_file_depth": 0,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
@@ -341,7 +278,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.base",
+            "file": "TEST_DIR/t.IMGFMT.base",
             "encryption_key_missing": false
         },
         {
@@ -349,7 +286,7 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 393216,
-                "filename": "TEST_DIR/t.qcow2.base",
+                "filename": "TEST_DIR/t.IMGFMT.base",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -370,7 +307,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.base",
+            "file": "TEST_DIR/t.IMGFMT.base",
             "encryption_key_missing": false
         }
     ]
@@ -447,49 +384,31 @@ wrote 65536/65536 bytes at offset 1048576
             "image": {
                 "backing-image": {
                     "virtual-size": 67108864,
-                    "filename": "TEST_DIR/t.qcow2.base",
+                    "filename": "TEST_DIR/t.IMGFMT.base",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
                     "dirty-flag": false
                 },
-                "backing-filename-format": "qcow2",
+                "backing-filename-format": "IMGFMT",
                 "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2.ovl2",
+                "filename": "TEST_DIR/t.IMGFMT.ovl2",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
-                "full-backing-filename": "TEST_DIR/t.qcow2.base",
-                "backing-filename": "TEST_DIR/t.qcow2.base",
+                "full-backing-filename": "TEST_DIR/t.IMGFMT.base",
+                "backing-filename": "TEST_DIR/t.IMGFMT.base",
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": true,
             "node-name": "NODE_NAME",
             "backing_file_depth": 1,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
-            "backing_file": "TEST_DIR/t.qcow2.base",
+            "backing_file": "TEST_DIR/t.IMGFMT.base",
             "encrypted": false,
             "bps": 0,
             "bps_rd": 0,
@@ -498,7 +417,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.ovl2",
+            "file": "TEST_DIR/t.IMGFMT.ovl2",
             "encryption_key_missing": false
         },
         {
@@ -506,7 +425,7 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 197120,
-                "filename": "TEST_DIR/t.qcow2.ovl2",
+                "filename": "TEST_DIR/t.IMGFMT.ovl2",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -527,7 +446,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.ovl2",
+            "file": "TEST_DIR/t.IMGFMT.ovl2",
             "encryption_key_missing": false
         },
         {
@@ -537,68 +456,41 @@ wrote 65536/65536 bytes at offset 1048576
                 "backing-image": {
                     "backing-image": {
                         "virtual-size": 67108864,
-                        "filename": "TEST_DIR/t.qcow2.base",
+                        "filename": "TEST_DIR/t.IMGFMT.base",
                         "cluster-size": 65536,
-                        "format": "qcow2",
+                        "format": "IMGFMT",
                         "actual-size": SIZE,
-                        "format-specific": {
-                            "type": "qcow2",
-                            "data": {
-                                "compat": "1.1",
-                                "lazy-refcounts": false,
-                                "refcount-bits": 16,
-                                "corrupt": false
-                            }
-                        },
                         "dirty-flag": false
                     },
-                    "backing-filename-format": "qcow2",
+                    "backing-filename-format": "IMGFMT",
                     "virtual-size": 67108864,
-                    "filename": "TEST_DIR/t.qcow2.ovl2",
+                    "filename": "TEST_DIR/t.IMGFMT.ovl2",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
-                    "full-backing-filename": "TEST_DIR/t.qcow2.base",
-                    "backing-filename": "TEST_DIR/t.qcow2.base",
+                    "full-backing-filename": "TEST_DIR/t.IMGFMT.base",
+                    "backing-filename": "TEST_DIR/t.IMGFMT.base",
                     "dirty-flag": false
                 },
-                "backing-filename-format": "qcow2",
+                "backing-filename-format": "IMGFMT",
                 "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2.ovl3",
+                "filename": "TEST_DIR/t.IMGFMT.ovl3",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
-                "full-backing-filename": "TEST_DIR/t.qcow2.ovl2",
-                "backing-filename": "TEST_DIR/t.qcow2.ovl2",
+                "full-backing-filename": "TEST_DIR/t.IMGFMT.ovl2",
+                "backing-filename": "TEST_DIR/t.IMGFMT.ovl2",
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "top2",
             "backing_file_depth": 2,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
-            "backing_file": "TEST_DIR/t.qcow2.ovl2",
+            "backing_file": "TEST_DIR/t.IMGFMT.ovl2",
             "encrypted": false,
             "bps": 0,
             "bps_rd": 0,
@@ -607,7 +499,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.ovl3",
+            "file": "TEST_DIR/t.IMGFMT.ovl3",
             "encryption_key_missing": false
         },
         {
@@ -615,7 +507,7 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 197120,
-                "filename": "TEST_DIR/t.qcow2.ovl3",
+                "filename": "TEST_DIR/t.IMGFMT.ovl3",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -636,7 +528,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.ovl3",
+            "file": "TEST_DIR/t.IMGFMT.ovl3",
             "encryption_key_missing": false
         },
         {
@@ -644,26 +536,17 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2.base",
+                "filename": "TEST_DIR/t.IMGFMT.base",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": true,
             "node-name": "NODE_NAME",
             "backing_file_depth": 0,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
@@ -675,7 +558,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.base",
+            "file": "TEST_DIR/t.IMGFMT.base",
             "encryption_key_missing": false
         },
         {
@@ -683,7 +566,7 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 393216,
-                "filename": "TEST_DIR/t.qcow2.base",
+                "filename": "TEST_DIR/t.IMGFMT.base",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -704,7 +587,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2.base",
+            "file": "TEST_DIR/t.IMGFMT.base",
             "encryption_key_missing": false
         },
         {
@@ -713,49 +596,31 @@ wrote 65536/65536 bytes at offset 1048576
             "image": {
                 "backing-image": {
                     "virtual-size": 67108864,
-                    "filename": "TEST_DIR/t.qcow2.base",
+                    "filename": "TEST_DIR/t.IMGFMT.base",
                     "cluster-size": 65536,
-                    "format": "qcow2",
+                    "format": "IMGFMT",
                     "actual-size": SIZE,
-                    "format-specific": {
-                        "type": "qcow2",
-                        "data": {
-                            "compat": "1.1",
-                            "lazy-refcounts": false,
-                            "refcount-bits": 16,
-                            "corrupt": false
-                        }
-                    },
                     "dirty-flag": false
                 },
-                "backing-filename-format": "qcow2",
+                "backing-filename-format": "IMGFMT",
                 "virtual-size": 67108864,
-                "filename": "TEST_DIR/t.qcow2",
+                "filename": "TEST_DIR/t.IMGFMT",
                 "cluster-size": 65536,
-                "format": "qcow2",
+                "format": "IMGFMT",
                 "actual-size": SIZE,
-                "format-specific": {
-                    "type": "qcow2",
-                    "data": {
-                        "compat": "1.1",
-                        "lazy-refcounts": false,
-                        "refcount-bits": 16,
-                        "corrupt": false
-                    }
-                },
-                "full-backing-filename": "TEST_DIR/t.qcow2.base",
-                "backing-filename": "TEST_DIR/t.qcow2.base",
+                "full-backing-filename": "TEST_DIR/t.IMGFMT.base",
+                "backing-filename": "TEST_DIR/t.IMGFMT.base",
                 "dirty-flag": false
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "top",
             "backing_file_depth": 1,
-            "drv": "qcow2",
+            "drv": "IMGFMT",
             "iops": 0,
             "bps_wr": 0,
             "write_threshold": 0,
-            "backing_file": "TEST_DIR/t.qcow2.base",
+            "backing_file": "TEST_DIR/t.IMGFMT.base",
             "encrypted": false,
             "bps": 0,
             "bps_rd": 0,
@@ -764,7 +629,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "TEST_DIR/t.IMGFMT",
             "encryption_key_missing": false
         },
         {
@@ -772,7 +637,7 @@ wrote 65536/65536 bytes at offset 1048576
             "detect_zeroes": "off",
             "image": {
                 "virtual-size": 197120,
-                "filename": "TEST_DIR/t.qcow2",
+                "filename": "TEST_DIR/t.IMGFMT",
                 "format": "file",
                 "actual-size": SIZE,
                 "dirty-flag": false
@@ -793,7 +658,7 @@ wrote 65536/65536 bytes at offset 1048576
                 "direct": false,
                 "writeback": true
             },
-            "file": "TEST_DIR/t.qcow2",
+            "file": "TEST_DIR/t.IMGFMT",
             "encryption_key_missing": false
         }
     ]
diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198
index 34ef666381..54eaaf5153 100755
--- a/tests/qemu-iotests/198
+++ b/tests/qemu-iotests/198
@@ -91,11 +91,15 @@ $QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0x9 0 $size" --image-op
 
 echo
 echo "== checking image base =="
-$QEMU_IMG info --image-opts $IMGSPECBASE | _filter_img_info | _filter_testdir | sed -e "/^disk size:/ D"
+$QEMU_IMG info --image-opts $IMGSPECBASE | _filter_img_info --format-specific \
+    | sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
+          -e '/lazy refcounts:/ D' -e '/corrupt:/ D'
 
 echo
 echo "== checking image layer =="
-$QEMU_IMG info --image-opts $IMGSPECLAYER | _filter_img_info | _filter_testdir | sed -e "/^disk size:/ D"
+$QEMU_IMG info --image-opts $IMGSPECLAYER | _filter_img_info --format-specific \
+    | sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
+          -e '/lazy refcounts:/ D' -e '/corrupt:/ D'
 
 
 # success, all done
diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out
index 2db565e16b..adb805cce9 100644
--- a/tests/qemu-iotests/198.out
+++ b/tests/qemu-iotests/198.out
@@ -36,9 +36,6 @@ image: json:{"encrypt.key-secret": "sec0", "driver": "IMGFMT", "file": {"driver"
 file format: IMGFMT
 virtual size: 16M (16777216 bytes)
 Format specific information:
-    compat: 1.1
-    lazy refcounts: false
-    refcount bits: 16
     encrypt:
         ivgen alg: plain64
         hash alg: sha256
@@ -75,7 +72,6 @@ Format specific information:
                 key offset: 1810432
         payload offset: 2068480
         master key iters: 1024
-    corrupt: false
 
 == checking image layer ==
 image: json:{"encrypt.key-secret": "sec1", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}}
@@ -83,9 +79,6 @@ file format: IMGFMT
 virtual size: 16M (16777216 bytes)
 backing file: TEST_DIR/t.IMGFMT.base
 Format specific information:
-    compat: 1.1
-    lazy refcounts: false
-    refcount bits: 16
     encrypt:
         ivgen alg: plain64
         hash alg: sha256
@@ -122,5 +115,4 @@ Format specific information:
                 key offset: 1810432
         payload offset: 2068480
         master key iters: 1024
-    corrupt: false
 *** done
diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201
new file mode 100755
index 0000000000..11f640f5df
--- /dev/null
+++ b/tests/qemu-iotests/201
@@ -0,0 +1,120 @@
+#!/bin/bash
+#
+# Test savevm and loadvm after live migration with postcopy flag
+#
+# Copyright (C) 2017, IBM Corporation.
+#
+# This file is derived from tests/qemu-iotests/181 by Kevin Wolf
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+status=1	# failure is the default!
+
+MIG_SOCKET="${TEST_DIR}/migrate"
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+_cleanup()
+{
+    rm -f "${MIG_SOCKET}"
+    _cleanup_test_img
+    _cleanup_qemu
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_supported_fmt qcow2
+_supported_proto generic
+_supported_os Linux
+
+# Internal snapshots are (currently) impossible with refcount_bits=1
+# This was taken from test 080
+_unsupported_imgopts 'refcount_bits=1[^0-9]'
+
+size=64M
+_make_test_img $size
+
+echo
+echo === Starting VMs ===
+echo
+
+qemu_comm_method="monitor"
+
+if [ "$IMGOPTSSYNTAX" = "true" ]; then
+    _launch_qemu \
+        -drive "${TEST_IMG}",cache=${CACHEMODE},id=disk
+else
+    _launch_qemu \
+        -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk
+fi
+src=$QEMU_HANDLE
+
+if [ "$IMGOPTSSYNTAX" = "true" ]; then
+    _launch_qemu \
+        -drive "${TEST_IMG}",cache=${CACHEMODE},id=disk \
+        -incoming "unix:${MIG_SOCKET}"
+else
+    _launch_qemu \
+        -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \
+        -incoming "unix:${MIG_SOCKET}"
+fi
+dest=$QEMU_HANDLE
+
+echo
+echo === Set \'migrate_set_capability postcopy-ram on\' and migrate ===
+echo
+
+silent=yes
+_send_qemu_cmd $dest 'migrate_set_capability postcopy-ram on' "(qemu)"
+_send_qemu_cmd $src 'migrate_set_capability postcopy-ram on' "(qemu)"
+_send_qemu_cmd $src "migrate -d unix:${MIG_SOCKET}" "(qemu)"
+
+QEMU_COMM_TIMEOUT=1 qemu_cmd_repeat=10 silent=yes \
+    _send_qemu_cmd $src "info migrate" "completed\|failed"
+silent=yes _send_qemu_cmd $src "" "(qemu)"
+
+echo
+echo === Check if migration was successful ===
+echo
+
+QEMU_COMM_TIMEOUT=1 silent=yes \
+    _send_qemu_cmd $src "info migrate" "completed"
+silent=yes _send_qemu_cmd $src "" "(qemu)"
+
+echo
+echo === On destination, execute savevm and loadvm ===
+echo
+
+silent=
+_send_qemu_cmd $dest 'savevm state1' "(qemu)"
+_send_qemu_cmd $dest 'loadvm state1' "(qemu)"
+
+echo
+echo === Shut down and check image ===
+echo
+
+_send_qemu_cmd $src 'quit' ""
+_send_qemu_cmd $dest 'quit' ""
+wait=1 _cleanup_qemu
+
+_check_test_img
+
+# success, all done
+echo "*** done"
+status=0
diff --git a/tests/qemu-iotests/201.out b/tests/qemu-iotests/201.out
new file mode 100644
index 0000000000..9faf06f996
--- /dev/null
+++ b/tests/qemu-iotests/201.out
@@ -0,0 +1,23 @@
+QA output created by 201
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+
+=== Starting VMs ===
+
+
+=== Set 'migrate_set_capability postcopy-ram on' and migrate ===
+
+
+=== Check if migration was successful ===
+
+
+=== On destination, execute savevm and loadvm ===
+
+(qemu) savevm state1
+(qemu) loadvm state1
+
+=== Shut down and check image ===
+
+(qemu) quit
+(qemu) quit
+No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/204 b/tests/qemu-iotests/204
new file mode 100755
index 0000000000..feb69d2ada
--- /dev/null
+++ b/tests/qemu-iotests/204
@@ -0,0 +1,119 @@
+#!/bin/bash
+#
+# Test corner cases with unusual block geometries
+#
+# Copyright (C) 2016-2018 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=eblake@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+# This test assumes that discard leaves zero clusters; see test 177 for
+# other tests that also work in older images
+_unsupported_imgopts 'compat=0.10'
+
+CLUSTER_SIZE=1M
+size=128M
+options=driver=blkdebug,image.driver=qcow2
+nested_opts=image.file.driver=file,image.file.filename=$TEST_IMG
+
+echo
+echo "== setting up files =="
+
+TEST_IMG="$TEST_IMG.base" _make_test_img $size
+$QEMU_IO -c "write -P 11 0 $size" "$TEST_IMG.base" | _filter_qemu_io
+_make_test_img -b "$TEST_IMG.base"
+$QEMU_IO -c "write -P 22 0 110M" "$TEST_IMG" | _filter_qemu_io
+
+# Limited to 64k max-transfer
+echo
+echo "== constrained alignment and max-transfer =="
+limits=align=4k,max-transfer=64k
+$QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
+         -c "write -P 33 1000 128k" -c "read -P 33 1000 128k" | _filter_qemu_io
+
+echo
+echo "== write zero with constrained max-transfer =="
+limits=align=512,max-transfer=64k,opt-write-zero=$CLUSTER_SIZE
+$QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
+         -c "write -z 8003584 2093056" | _filter_qemu_io
+
+# non-power-of-2 write-zero/discard alignments
+echo
+echo "== non-power-of-2 write zeroes limits =="
+
+limits=align=512,opt-write-zero=15M,max-write-zero=15M,opt-discard=15M,max-discard=15M
+$QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
+         -c "write -z 32M 32M" | _filter_qemu_io
+
+echo
+echo "== non-power-of-2 discard limits =="
+
+limits=align=512,opt-write-zero=15M,max-write-zero=15M,opt-discard=15M,max-discard=15M
+$QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
+         -c "discard 80000001 30M" | _filter_qemu_io
+
+echo
+echo "== block status smaller than alignment =="
+limits=align=4k
+$QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
+	 -c "alloc 1 1" -c "alloc 0x6dffff0 1000" -c "alloc 127m 5P" \
+	 -c map | _filter_qemu_io
+
+echo
+echo "== verify image content =="
+
+function verify_io()
+{
+    echo read -P 22 0 1000
+    echo read -P 33 1000 128k
+    echo read -P 22 132072 7871512
+    echo read -P 0 8003584 2093056
+    echo read -P 22 10096640 23457792
+    echo read -P 0 32M 32M
+    echo read -P 22 64M 13M
+    echo read -P 0 77M 29M
+    echo read -P 22 106M 4M
+    echo read -P 11 110M 18M
+}
+
+verify_io | $QEMU_IO -r "$TEST_IMG" | _filter_qemu_io
+$QEMU_IMG map --image-opts "$options,$nested_opts,align=4k" \
+    | _filter_qemu_img_map
+
+_check_test_img
+
+# success, all done
+echo "*** done"
+status=0
diff --git a/tests/qemu-iotests/204.out b/tests/qemu-iotests/204.out
new file mode 100644
index 0000000000..f3a10fbe90
--- /dev/null
+++ b/tests/qemu-iotests/204.out
@@ -0,0 +1,63 @@
+QA output created by 204
+
+== setting up files ==
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
+wrote 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
+wrote 115343360/115343360 bytes at offset 0
+110 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== constrained alignment and max-transfer ==
+wrote 131072/131072 bytes at offset 1000
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 1000
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== write zero with constrained max-transfer ==
+wrote 2093056/2093056 bytes at offset 8003584
+1.996 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== non-power-of-2 write zeroes limits ==
+wrote 33554432/33554432 bytes at offset 33554432
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== non-power-of-2 discard limits ==
+discard 31457280/31457280 bytes at offset 80000001
+30 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== block status smaller than alignment ==
+1/1 bytes allocated at offset 1 bytes
+16/1000 bytes allocated at offset 110 MiB
+0/1048576 bytes allocated at offset 127 MiB
+110 MiB (0x6e00000) bytes     allocated at offset 0 bytes (0x0)
+18 MiB (0x1200000) bytes not allocated at offset 110 MiB (0x6e00000)
+
+== verify image content ==
+read 1000/1000 bytes at offset 0
+1000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 1000
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 7871512/7871512 bytes at offset 132072
+7.507 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 2093056/2093056 bytes at offset 8003584
+1.996 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 23457792/23457792 bytes at offset 10096640
+22.371 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 33554432/33554432 bytes at offset 33554432
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 13631488/13631488 bytes at offset 67108864
+13 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 30408704/30408704 bytes at offset 80740352
+29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4194304/4194304 bytes at offset 111149056
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 18874368/18874368 bytes at offset 115343360
+18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Offset          Length          File
+0               0x800000        TEST_DIR/t.IMGFMT
+0x900000        0x2400000       TEST_DIR/t.IMGFMT
+0x3c00000       0x1100000       TEST_DIR/t.IMGFMT
+0x6a00000       0x400000        TEST_DIR/t.IMGFMT
+No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index f08248bfd9..cb2be23340 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -140,6 +140,15 @@ _filter_img_create()
 
 _filter_img_info()
 {
+    if [[ "$1" == "--format-specific" ]]; then
+        local format_specific=1
+        shift
+    else
+        local format_specific=0
+    fi
+
+    discard=0
+    regex_json_spec_start='^ *"format-specific": \{'
     sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
         -e "s#$TEST_DIR#TEST_DIR#g" \
         -e "s#$IMGFMT#IMGFMT#g" \
@@ -160,7 +169,25 @@ _filter_img_info()
         -e "/block_state_zero: \\(on\\|off\\)/d" \
         -e "/log_size: [0-9]\\+/d" \
         -e "s/iters: [0-9]\\+/iters: 1024/" \
-        -e "s/uuid: [-a-f0-9]\\+/uuid: 00000000-0000-0000-0000-000000000000/"
+        -e "s/uuid: [-a-f0-9]\\+/uuid: 00000000-0000-0000-0000-000000000000/" | \
+    while IFS='' read -r line; do
+        if [[ $format_specific == 1 ]]; then
+            discard=0
+        elif [[ $line == "Format specific information:" ]]; then
+            discard=1
+        elif [[ $line =~ $regex_json_spec_start ]]; then
+            discard=2
+            regex_json_spec_end="^${line%%[^ ]*}\\},? *$"
+        fi
+        if [[ $discard == 0 ]]; then
+            echo "$line"
+        elif [[ $discard == 1 && ! $line ]]; then
+            echo
+            discard=0
+        elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then
+            discard=0
+        fi
+    done
 }
 
 # filter out offsets and file names from qemu-img map; good for both
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index dbae7d74ba..6fa0495e10 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -338,7 +338,7 @@ _img_info()
             -e "s#$IMGFMT#IMGFMT#g" \
             -e "/^disk size:/ D" \
             -e "/actual-size/ D" | \
-        while IFS='' read line; do
+        while IFS='' read -r line; do
             if [[ $format_specific == 1 ]]; then
                 discard=0
             elif [[ $line == "Format specific information:" ]]; then
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 93d96fb22f..8fc4f62cca 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -197,5 +197,7 @@
 197 rw auto quick
 198 rw auto
 200 rw auto
+201 rw auto migration
 202 rw auto quick
 203 rw auto
+204 rw auto quick
diff --git a/util/osdep.c b/util/osdep.c
index 1231f9f876..a73de0e1ba 100644
--- a/util/osdep.c
+++ b/util/osdep.c
@@ -244,7 +244,9 @@ static int qemu_lock_fcntl(int fd, int64_t start, int64_t len, int fl_type)
         .l_type   = fl_type,
     };
     qemu_probe_lock_ops();
-    ret = fcntl(fd, fcntl_op_setlk, &fl);
+    do {
+        ret = fcntl(fd, fcntl_op_setlk, &fl);
+    } while (ret == -1 && errno == EINTR);
     return ret == -1 ? -errno : 0;
 }