diff options
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(¬e, 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(¬e, 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, ®); 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, ®); 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; } |