diff options
83 files changed, 844 insertions, 227 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 0cd4d028aa..ffd77b461c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -564,6 +564,23 @@ M: Alistair Francis <alistair@alistair23.me> S: Maintained F: hw/arm/netduino2.c +SmartFusion2 +M: Subbaraya Sundeep <sundeep.lkml@gmail.com> +S: Maintained +F: hw/arm/msf2-soc.c +F: hw/misc/msf2-sysreg.c +F: hw/timer/mss-timer.c +F: hw/ssi/mss-spi.c +F: include/hw/arm/msf2-soc.h +F: include/hw/misc/msf2-sysreg.h +F: include/hw/timer/mss-timer.h +F: include/hw/ssi/mss-spi.h + +Emcraft M2S-FG484 +M: Subbaraya Sundeep <sundeep.lkml@gmail.com> +S: Maintained +F: hw/arm/msf2-som.c + CRIS Machines ------------- Axis Dev88 diff --git a/Makefile b/Makefile index 0496c5057a..814f6820d9 100644 --- a/Makefile +++ b/Makefile @@ -405,7 +405,7 @@ CAP_CFLAGS += -DCAPSTONE_HAS_POWERPC CAP_CFLAGS += -DCAPSTONE_HAS_X86 subdir-capstone: .git-submodule-status - $(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE)) + $(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE)) $(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) \ $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY)) diff --git a/VERSION b/VERSION index 098bbf1d3c..2b4095bb41 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.10.90 +2.10.91 diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 34c5e28d07..e7f0329a52 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -352,36 +352,42 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, return 0; } -bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr) +bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc) { TranslationBlock *tb; bool r = false; + uintptr_t check_offset; - /* A retaddr of zero is invalid so we really shouldn't have ended - * up here. The target code has likely forgotten to check retaddr - * != 0 before attempting to restore state. We return early to - * avoid blowing up on a recursive tb_lock(). The target must have - * previously survived a failed cpu_restore_state because - * tb_find_pc(0) would have failed anyway. It still should be - * fixed though. + /* The host_pc has to be in the region of current code buffer. If + * it is not we will not be able to resolve it here. The two cases + * where host_pc will not be correct are: + * + * - fault during translation (instruction fetch) + * - fault from helper (not using GETPC() macro) + * + * Either way we need return early to avoid blowing up on a + * recursive tb_lock() as we can't resolve it here. + * + * We are using unsigned arithmetic so if host_pc < + * tcg_init_ctx.code_gen_buffer check_offset will wrap to way + * above the code_gen_buffer_size */ - - if (!retaddr) { - return r; - } - - tb_lock(); - tb = tb_find_pc(retaddr); - if (tb) { - cpu_restore_state_from_tb(cpu, tb, retaddr); - if (tb->cflags & CF_NOCACHE) { - /* one-shot translation, invalidate it immediately */ - tb_phys_invalidate(tb, -1); - tb_remove(tb); + check_offset = host_pc - (uintptr_t) tcg_init_ctx.code_gen_buffer; + + if (check_offset < tcg_init_ctx.code_gen_buffer_size) { + tb_lock(); + tb = tb_find_pc(host_pc); + if (tb) { + cpu_restore_state_from_tb(cpu, tb, host_pc); + if (tb->cflags & CF_NOCACHE) { + /* one-shot translation, invalidate it immediately */ + tb_phys_invalidate(tb, -1); + tb_remove(tb); + } + r = true; } - r = true; + tb_unlock(); } - tb_unlock(); return r; } diff --git a/block/block-backend.c b/block/block-backend.c index 45d9101be3..f10b1db612 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -655,12 +655,16 @@ BlockBackend *blk_by_public(BlockBackendPublic *public) */ void blk_remove_bs(BlockBackend *blk) { - ThrottleTimers *tt; + ThrottleGroupMember *tgm = &blk->public.throttle_group_member; + BlockDriverState *bs; notifier_list_notify(&blk->remove_bs_notifiers, blk); - if (blk->public.throttle_group_member.throttle_state) { - tt = &blk->public.throttle_group_member.throttle_timers; - throttle_timers_detach_aio_context(tt); + if (tgm->throttle_state) { + bs = blk_bs(blk); + bdrv_drained_begin(bs); + throttle_group_detach_aio_context(tgm); + throttle_group_attach_aio_context(tgm, qemu_get_aio_context()); + bdrv_drained_end(bs); } blk_update_root_state(blk); @@ -674,6 +678,7 @@ void blk_remove_bs(BlockBackend *blk) */ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) { + ThrottleGroupMember *tgm = &blk->public.throttle_group_member; blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->perm, blk->shared_perm, blk, errp); if (blk->root == NULL) { @@ -682,10 +687,9 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) bdrv_ref(bs); notifier_list_notify(&blk->insert_bs_notifiers, blk); - if (blk->public.throttle_group_member.throttle_state) { - throttle_timers_attach_aio_context( - &blk->public.throttle_group_member.throttle_timers, - bdrv_get_aio_context(bs)); + if (tgm->throttle_state) { + throttle_group_detach_aio_context(tgm); + throttle_group_attach_aio_context(tgm, bdrv_get_aio_context(bs)); } return 0; @@ -1748,8 +1752,10 @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) if (bs) { if (tgm->throttle_state) { + bdrv_drained_begin(bs); throttle_group_detach_aio_context(tgm); throttle_group_attach_aio_context(tgm, new_context); + bdrv_drained_end(bs); } bdrv_set_aio_context(bs, new_context); } @@ -1974,10 +1980,16 @@ void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg) void blk_io_limits_disable(BlockBackend *blk) { - assert(blk->public.throttle_group_member.throttle_state); - bdrv_drained_begin(blk_bs(blk)); - throttle_group_unregister_tgm(&blk->public.throttle_group_member); - bdrv_drained_end(blk_bs(blk)); + BlockDriverState *bs = blk_bs(blk); + ThrottleGroupMember *tgm = &blk->public.throttle_group_member; + assert(tgm->throttle_state); + if (bs) { + bdrv_drained_begin(bs); + } + throttle_group_unregister_tgm(tgm); + if (bs) { + bdrv_drained_end(bs); + } } /* should be called before blk_set_io_limits if a limit is set */ diff --git a/block/nbd-client.c b/block/nbd-client.c index b44d4d4a01..bcfed0133d 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -216,7 +216,7 @@ static int nbd_parse_offset_hole_payload(NBDStructuredReplyChunk *chunk, offset = payload_advance64(&payload); hole_size = payload_advance32(&payload); - if (offset < orig_offset || hole_size > qiov->size || + if (!hole_size || offset < orig_offset || hole_size > qiov->size || offset > orig_offset + qiov->size - hole_size) { error_setg(errp, "Protocol error: server sent chunk exceeding requested" " region"); @@ -248,7 +248,7 @@ static int nbd_parse_error_payload(NBDStructuredReplyChunk *chunk, error = nbd_errno_to_system_errno(payload_advance32(&payload)); if (error == 0) { - error_setg(errp, "Protocol error: server sent structured error chunk" + error_setg(errp, "Protocol error: server sent structured error chunk " "with error = 0"); return -EINVAL; } @@ -257,7 +257,7 @@ static int nbd_parse_error_payload(NBDStructuredReplyChunk *chunk, message_size = payload_advance16(&payload); if (message_size > chunk->length - sizeof(error) - sizeof(message_size)) { - error_setg(errp, "Protocol error: server sent structured error chunk" + error_setg(errp, "Protocol error: server sent structured error chunk " "with incorrect message size"); return -EINVAL; } @@ -281,7 +281,8 @@ static int nbd_co_receive_offset_data_payload(NBDClientSession *s, assert(nbd_reply_is_structured(&s->reply)); - if (chunk->length < sizeof(offset)) { + /* The NBD spec requires at least one byte of payload */ + if (chunk->length <= sizeof(offset)) { error_setg(errp, "Protocol error: invalid payload for " "NBD_REPLY_TYPE_OFFSET_DATA"); return -EINVAL; @@ -293,6 +294,7 @@ static int nbd_co_receive_offset_data_payload(NBDClientSession *s, be64_to_cpus(&offset); data_size = chunk->length - sizeof(offset); + assert(data_size); if (offset < orig_offset || data_size > qiov->size || offset > orig_offset + qiov->size - data_size) { error_setg(errp, "Protocol error: server sent chunk exceeding requested" @@ -408,7 +410,12 @@ static coroutine_fn int nbd_co_do_receive_one_chunk( if (chunk->type == NBD_REPLY_TYPE_NONE) { if (!(chunk->flags & NBD_REPLY_FLAG_DONE)) { error_setg(errp, "Protocol error: NBD_REPLY_TYPE_NONE chunk without" - "NBD_REPLY_FLAG_DONE flag set"); + " NBD_REPLY_FLAG_DONE flag set"); + return -EINVAL; + } + if (chunk->length) { + error_setg(errp, "Protocol error: NBD_REPLY_TYPE_NONE chunk with" + " nonzero length"); return -EINVAL; } return 0; @@ -674,6 +681,9 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, assert(bytes <= NBD_MAX_BUFFER_SIZE); assert(!flags); + if (!bytes) { + return 0; + } ret = nbd_co_send_request(bs, &request, NULL); if (ret < 0) { return ret; @@ -697,6 +707,7 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, .len = bytes, }; + assert(!(client->info.flags & NBD_FLAG_READ_ONLY)); if (flags & BDRV_REQ_FUA) { assert(client->info.flags & NBD_FLAG_SEND_FUA); request.flags |= NBD_CMD_FLAG_FUA; @@ -704,6 +715,9 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, assert(bytes <= NBD_MAX_BUFFER_SIZE); + if (!bytes) { + return 0; + } return nbd_co_request(bs, &request, qiov); } @@ -717,6 +731,7 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, .len = bytes, }; + assert(!(client->info.flags & NBD_FLAG_READ_ONLY)); if (!(client->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) { return -ENOTSUP; } @@ -729,6 +744,9 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, request.flags |= NBD_CMD_FLAG_NO_HOLE; } + if (!bytes) { + return 0; + } return nbd_co_request(bs, &request, NULL); } @@ -756,7 +774,8 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes) .len = bytes, }; - if (!(client->info.flags & NBD_FLAG_SEND_TRIM)) { + assert(!(client->info.flags & NBD_FLAG_READ_ONLY)); + if (!(client->info.flags & NBD_FLAG_SEND_TRIM) || !bytes) { return 0; } @@ -814,6 +833,12 @@ int nbd_client_init(BlockDriverState *bs, logout("Failed to negotiate with the NBD server\n"); return ret; } + if (client->info.flags & NBD_FLAG_READ_ONLY && + !bdrv_is_read_only(bs)) { + error_setg(errp, + "request for write access conflicts with read-only export"); + return -EACCES; + } if (client->info.flags & NBD_FLAG_SEND_FUA) { bs->supported_write_flags = BDRV_REQ_FUA; bs->supported_zero_flags |= BDRV_REQ_FUA; diff --git a/block/parallels.c b/block/parallels.c index 2b6c6e5709..9545761f49 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -35,6 +35,7 @@ #include "qemu/module.h" #include "qemu/bswap.h" #include "qemu/bitmap.h" +#include "migration/blocker.h" /**************************************************************/ @@ -100,6 +101,7 @@ typedef struct BDRVParallelsState { unsigned int tracks; unsigned int off_multiplier; + Error *migration_blocker; } BDRVParallelsState; @@ -708,7 +710,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE; } - if (flags & BDRV_O_RDWR) { + if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_INACTIVE)) { s->header->inuse = cpu_to_le32(HEADER_INUSE_MAGIC); ret = parallels_update_header(bs); if (ret < 0) { @@ -720,6 +722,16 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, s->bat_dirty_bmap = bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block)); + /* Disable migration until bdrv_invalidate_cache method is added */ + error_setg(&s->migration_blocker, "The Parallels format used by node '%s' " + "does not support live migration", + bdrv_get_device_or_node_name(bs)); + ret = migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(s->migration_blocker); + goto fail; + } qemu_co_mutex_init(&s->lock); return 0; @@ -741,18 +753,18 @@ static void parallels_close(BlockDriverState *bs) { BDRVParallelsState *s = bs->opaque; - if (bs->open_flags & BDRV_O_RDWR) { + if ((bs->open_flags & BDRV_O_RDWR) && !(bs->open_flags & BDRV_O_INACTIVE)) { s->header->inuse = 0; parallels_update_header(bs); - } - - if (bs->open_flags & BDRV_O_RDWR) { bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, PREALLOC_MODE_OFF, NULL); } g_free(s->bat_dirty_bmap); qemu_vfree(s->header); + + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); } static QemuOptsList parallels_create_opts = { diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index fb10e26068..2e072ed155 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -278,6 +278,14 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table) goto fail; } + /* If we're allocating the table at offset 0 then something is wrong */ + if (l2_offset == 0) { + qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid " + "allocation of L2 table at offset 0"); + ret = -EIO; + goto fail; + } + ret = qcow2_cache_flush(bs, s->refcount_block_cache); if (ret < 0) { goto fail; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index aa3fd6cf17..60b8eef3e8 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -367,6 +367,13 @@ static int alloc_refcount_block(BlockDriverState *bs, return new_block; } + /* If we're allocating the block at offset 0 then something is wrong */ + if (new_block == 0) { + qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid " + "allocation of refcount block at offset 0"); + return -EIO; + } + #ifdef DEBUG_ALLOC2 fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64 " at %" PRIx64 "\n", @@ -1075,6 +1082,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) return new_cluster; } + if (new_cluster == 0) { + qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid " + "allocation of compressed cluster " + "at offset 0"); + return -EIO; + } + if (!offset || ROUND_UP(offset, s->cluster_size) != new_cluster) { offset = new_cluster; free_in_cluster = s->cluster_size; diff --git a/block/qcow2.c b/block/qcow2.c index 92cb9f9bfa..b3d66a0e88 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -126,6 +126,7 @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, /* Zero fill remaining space in cluster so it has predictable * content in case of future spec changes */ clusterlen = size_to_clusters(s, headerlen) * s->cluster_size; + assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen) == 0); ret = bdrv_pwrite_zeroes(bs->file, ret + headerlen, clusterlen - headerlen, 0); @@ -1280,6 +1281,12 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } + if (header.refcount_table_clusters == 0 && !(flags & BDRV_O_CHECK)) { + error_setg(errp, "Image does not contain a reference count table"); + ret = -EINVAL; + goto fail; + } + ret = validate_table_offset(bs, s->refcount_table_offset, s->refcount_table_size, sizeof(uint64_t)); if (ret < 0) { diff --git a/block/snapshot.c b/block/snapshot.c index a46564e7b7..1d5ab5f90f 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -181,10 +181,24 @@ int bdrv_snapshot_goto(BlockDriverState *bs, { BlockDriver *drv = bs->drv; int ret, open_ret; + int64_t len; if (!drv) { return -ENOMEDIUM; } + + len = bdrv_getlength(bs); + if (len < 0) { + return len; + } + /* We should set all bits in all enabled dirty bitmaps, because dirty + * bitmaps reflect active state of disk and snapshot switch operation + * actually dirties active state. + * TODO: It may make sense not to set all bits but analyze block status of + * current state and destination snapshot and do not set bits corresponding + * to both-zero or both-unallocated areas. */ + bdrv_set_dirty(bs, 0, len); + if (drv->bdrv_snapshot_goto) { return drv->bdrv_snapshot_goto(bs, snapshot_id); } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index b291a88481..2587f19ca3 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -594,6 +594,12 @@ void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, void throttle_group_detach_aio_context(ThrottleGroupMember *tgm) { ThrottleTimers *tt = &tgm->throttle_timers; + + /* Requests must have been drained */ + assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0); + assert(qemu_co_queue_empty(&tgm->throttled_reqs[0])); + assert(qemu_co_queue_empty(&tgm->throttled_reqs[1])); + throttle_timers_detach_aio_context(tt); tgm->aio_context = NULL; } diff --git a/block/vhdx.c b/block/vhdx.c index 7ae4589879..9956933da6 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1008,13 +1008,6 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - if (flags & BDRV_O_RDWR) { - ret = vhdx_update_headers(bs, s, false, NULL); - if (ret < 0) { - goto fail; - } - } - /* TODO: differencing files */ return 0; diff --git a/configure b/configure index a6055c0710..0e856bbc04 100755 --- a/configure +++ b/configure @@ -482,6 +482,7 @@ ccas="${CCAS-$cc}" cpp="${CPP-$cc -E}" objcopy="${OBJCOPY-${cross_prefix}objcopy}" ld="${LD-${cross_prefix}ld}" +ranlib="${RANLIB-${cross_prefix}ranlib}" nm="${NM-${cross_prefix}nm}" strip="${STRIP-${cross_prefix}strip}" windres="${WINDRES-${cross_prefix}windres}" @@ -6288,6 +6289,7 @@ echo "CCAS=$ccas" >> $config_host_mak echo "CPP=$cpp" >> $config_host_mak echo "OBJCOPY=$objcopy" >> $config_host_mak echo "LD=$ld" >> $config_host_mak +echo "RANLIB=$ranlib" >> $config_host_mak echo "NM=$nm" >> $config_host_mak echo "WINDRES=$windres" >> $config_host_mak echo "CFLAGS=$CFLAGS" >> $config_host_mak @@ -6782,6 +6784,7 @@ for rom in seabios vgabios ; do echo "OBJCOPY=objcopy" >> $config_mak echo "IASL=$iasl" >> $config_mak echo "LD=$ld" >> $config_mak + echo "RANLIB=$ranlib" >> $config_mak done # set up tests data directory diff --git a/disas.c b/disas.c index 92b389d25f..d4ad1089ef 100644 --- a/disas.c +++ b/disas.c @@ -220,6 +220,77 @@ static cs_err cap_disas_start(disassemble_info *info, csh *handle) return CS_ERR_OK; } +static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn, + int i, int n) +{ + fprintf_function print = info->fprintf_func; + FILE *stream = info->stream; + + switch (info->cap_insn_unit) { + case 4: + if (info->endian == BFD_ENDIAN_BIG) { + for (; i < n; i += 4) { + print(stream, " %08x", ldl_be_p(insn->bytes + i)); + + } + } else { + for (; i < n; i += 4) { + print(stream, " %08x", ldl_le_p(insn->bytes + i)); + } + } + break; + + case 2: + if (info->endian == BFD_ENDIAN_BIG) { + for (; i < n; i += 2) { + print(stream, " %04x", lduw_be_p(insn->bytes + i)); + } + } else { + for (; i < n; i += 2) { + print(stream, " %04x", lduw_le_p(insn->bytes + i)); + } + } + break; + + default: + for (; i < n; i++) { + print(stream, " %02x", insn->bytes[i]); + } + break; + } +} + +static void cap_dump_insn(disassemble_info *info, cs_insn *insn) +{ + fprintf_function print = info->fprintf_func; + int i, n, split; + + print(info->stream, "0x%08" PRIx64 ": ", insn->address); + + n = insn->size; + split = info->cap_insn_split; + + /* Dump the first SPLIT bytes of the instruction. */ + cap_dump_insn_units(info, insn, 0, MIN(n, split)); + + /* Add padding up to SPLIT so that mnemonics line up. */ + if (n < split) { + int width = (split - n) / info->cap_insn_unit; + width *= (2 * info->cap_insn_unit + 1); + print(info->stream, "%*s", width, ""); + } + + /* Print the actual instruction. */ + print(info->stream, " %-8s %s\n", insn->mnemonic, insn->op_str); + + /* Dump any remaining part of the insn on subsequent lines. */ + for (i = split; i < n; i += split) { + print(info->stream, "0x%08" PRIx64 ": ", insn->address + i); + cap_dump_insn_units(info, insn, i, MIN(n, i + split)); + print(info->stream, "\n"); + } +} + /* Disassemble SIZE bytes at PC for the target. */ static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size) { @@ -242,10 +313,7 @@ static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size) size -= tsize; while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { - (*info->fprintf_func)(info->stream, - "0x%08" PRIx64 ": %-12s %s\n", - insn->address, insn->mnemonic, - insn->op_str); + cap_dump_insn(info, insn); } /* If the target memory is not consumed, go back for more... */ @@ -290,10 +358,7 @@ static bool cap_disas_host(disassemble_info *info, void *code, size_t size) pc = (uintptr_t)code; while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) { - (*info->fprintf_func)(info->stream, - "0x%08" PRIx64 ": %-12s %s\n", - insn->address, insn->mnemonic, - insn->op_str); + cap_dump_insn(info, insn); } if (size != 0) { (*info->fprintf_func)(info->stream, @@ -337,10 +402,7 @@ static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count) csize += tsize; if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { - (*info->fprintf_func)(info->stream, - "0x%08" PRIx64 ": %-12s %s\n", - insn->address, insn->mnemonic, - insn->op_str); + cap_dump_insn(info, insn); if (--count <= 0) { break; } @@ -376,6 +438,8 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code, s.info.print_address_func = generic_print_address; s.info.cap_arch = -1; s.info.cap_mode = 0; + s.info.cap_insn_unit = 4; + s.info.cap_insn_split = 4; #ifdef TARGET_WORDS_BIGENDIAN s.info.endian = BFD_ENDIAN_BIG; @@ -427,6 +491,8 @@ void disas(FILE *out, void *code, unsigned long size) s.info.buffer_length = size; s.info.cap_arch = -1; s.info.cap_mode = 0; + s.info.cap_insn_unit = 4; + s.info.cap_insn_split = 4; #ifdef HOST_WORDS_BIGENDIAN s.info.endian = BFD_ENDIAN_BIG; @@ -440,11 +506,15 @@ void disas(FILE *out, void *code, unsigned long size) print_insn = print_insn_i386; s.info.cap_arch = CS_ARCH_X86; s.info.cap_mode = CS_MODE_32; + s.info.cap_insn_unit = 1; + s.info.cap_insn_split = 8; #elif defined(__x86_64__) s.info.mach = bfd_mach_x86_64; print_insn = print_insn_i386; s.info.cap_arch = CS_ARCH_X86; s.info.cap_mode = CS_MODE_64; + s.info.cap_insn_unit = 1; + s.info.cap_insn_split = 8; #elif defined(_ARCH_PPC) s.info.disassembler_options = (char *)"any"; print_insn = print_insn_ppc; @@ -537,6 +607,8 @@ void monitor_disas(Monitor *mon, CPUState *cpu, s.info.buffer_vma = pc; s.info.cap_arch = -1; s.info.cap_mode = 0; + s.info.cap_insn_unit = 4; + s.info.cap_insn_split = 4; #ifdef TARGET_WORDS_BIGENDIAN s.info.endian = BFD_ENDIAN_BIG; diff --git a/exec.c b/exec.c index 97a24a875e..8b579c0cd9 100644 --- a/exec.c +++ b/exec.c @@ -792,11 +792,12 @@ void cpu_exec_initfn(CPUState *cpu) void cpu_exec_realizefn(CPUState *cpu, Error **errp) { CPUClass *cc = CPU_GET_CLASS(cpu); + static bool tcg_target_initialized; cpu_list_add(cpu); - if (tcg_enabled() && !cc->tcg_initialized) { - cc->tcg_initialized = true; + if (tcg_enabled() && !tcg_target_initialized) { + tcg_target_initialized = true; cc->tcg_initialize(); } diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index f1441ec6cf..750162cc95 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -27,7 +27,6 @@ #include "qemu-common.h" #include "cpu.h" #include "sysemu/sysemu.h" -#include "sysemu/qtest.h" #include "hw/sysbus.h" #include "net/net.h" #include "hw/arm/arm.h" @@ -129,13 +128,6 @@ exynos4_boards_init_common(MachineState *machine, Exynos4BoardType board_type) { Exynos4BoardState *s = g_new(Exynos4BoardState, 1); - MachineClass *mc = MACHINE_GET_CLASS(machine); - - if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) { - error_report("%s board supports only %d CPU cores, ignoring smp_cpus" - " value", - mc->name, EXYNOS4210_NCPUS); - } exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type]; exynos4_board_binfo.board_id = exynos4_board_id[board_type]; @@ -189,6 +181,8 @@ static void nuri_class_init(ObjectClass *oc, void *data) mc->desc = "Samsung NURI board (Exynos4210)"; mc->init = nuri_init; mc->max_cpus = EXYNOS4210_NCPUS; + mc->min_cpus = EXYNOS4210_NCPUS; + mc->default_cpus = EXYNOS4210_NCPUS; mc->ignore_memory_transaction_failures = true; } @@ -205,6 +199,8 @@ static void smdkc210_class_init(ObjectClass *oc, void *data) mc->desc = "Samsung SMDKC210 board (Exynos4210)"; mc->init = smdkc210_init; mc->max_cpus = EXYNOS4210_NCPUS; + mc->min_cpus = EXYNOS4210_NCPUS; + mc->default_cpus = EXYNOS4210_NCPUS; mc->ignore_memory_transaction_failures = true; } diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 354c6b25a8..287392bbdc 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -34,6 +34,7 @@ #include "hw/ide/ahci.h" #include "hw/cpu/a9mpcore.h" #include "hw/cpu/a15mpcore.h" +#include "qemu/log.h" #define SMP_BOOT_ADDR 0x100 #define SMP_BOOT_REG 0x40 @@ -117,14 +118,26 @@ static void hb_regs_write(void *opaque, hwaddr offset, } } - regs[offset/4] = value; + if (offset / 4 >= NUM_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "highbank: bad write offset 0x%" HWADDR_PRIx "\n", offset); + return; + } + regs[offset / 4] = value; } static uint64_t hb_regs_read(void *opaque, hwaddr offset, unsigned size) { + uint32_t value; uint32_t *regs = opaque; - uint32_t value = regs[offset/4]; + + if (offset / 4 >= NUM_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "highbank: bad read offset 0x%" HWADDR_PRIx "\n", offset); + return 0; + } + value = regs[offset / 4]; if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) { value |= 0x30000000; diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 5941c9f751..cd5fa8c3dc 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -167,6 +167,8 @@ static void raspi2_machine_init(MachineClass *mc) mc->no_floppy = 1; mc->no_cdrom = 1; mc->max_cpus = BCM2836_NCPUS; + mc->min_cpus = BCM2836_NCPUS; + mc->default_cpus = BCM2836_NCPUS; mc->default_ram_size = 1024 * 1024 * 1024; mc->ignore_memory_transaction_failures = true; }; diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index e2d15a1c9d..9631a53847 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -164,6 +164,9 @@ static void xlnx_ep108_init(MachineState *machine) { XlnxZCU102 *s = EP108_MACHINE(machine); + info_report("The Xilinx EP108 machine is deprecated, please use the " + "ZCU102 machine instead. It has the same features supported."); + xlnx_zynqmp_init(s, machine); } @@ -185,6 +188,8 @@ static void xlnx_ep108_machine_class_init(ObjectClass *oc, void *data) mc->block_default_type = IF_IDE; mc->units_per_default_bus = 1; mc->ignore_memory_transaction_failures = true; + mc->max_cpus = XLNX_ZYNQMP_NUM_APU_CPUS + XLNX_ZYNQMP_NUM_RPU_CPUS; + mc->default_cpus = XLNX_ZYNQMP_NUM_APU_CPUS; } static const TypeInfo xlnx_ep108_machine_init_typeinfo = { @@ -235,12 +240,14 @@ static void xlnx_zcu102_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->desc = "Xilinx ZynqMP ZCU102 board"; + mc->desc = "Xilinx ZynqMP ZCU102 board with 4xA53s and 2xR5s based on " \ + "the value of smp"; mc->init = xlnx_zcu102_init; mc->block_default_type = IF_IDE; mc->units_per_default_bus = 1; mc->ignore_memory_transaction_failures = true; mc->max_cpus = XLNX_ZYNQMP_NUM_APU_CPUS + XLNX_ZYNQMP_NUM_RPU_CPUS; + mc->default_cpus = XLNX_ZYNQMP_NUM_APU_CPUS; } static const TypeInfo xlnx_zcu102_machine_init_typeinfo = { diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index d4b6560194..c707c66322 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -98,8 +98,9 @@ static void xlnx_zynqmp_create_rpu(XlnxZynqMPState *s, const char *boot_cpu, { Error *err = NULL; int i; + int num_rpus = MIN(smp_cpus - XLNX_ZYNQMP_NUM_APU_CPUS, XLNX_ZYNQMP_NUM_RPU_CPUS); - for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { + for (i = 0; i < num_rpus; i++) { char *name; object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), @@ -132,8 +133,9 @@ static void xlnx_zynqmp_init(Object *obj) { XlnxZynqMPState *s = XLNX_ZYNQMP(obj); int i; + int num_apus = MIN(smp_cpus, XLNX_ZYNQMP_NUM_APU_CPUS); - for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { + for (i = 0; i < num_apus; i++) { object_initialize(&s->apu_cpu[i], sizeof(s->apu_cpu[i]), "cortex-a53-" TYPE_ARM_CPU); object_property_add_child(obj, "apu-cpu[*]", OBJECT(&s->apu_cpu[i]), @@ -182,6 +184,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) MemoryRegion *system_memory = get_system_memory(); uint8_t i; uint64_t ram_size; + int num_apus = MIN(smp_cpus, XLNX_ZYNQMP_NUM_APU_CPUS); const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]"; ram_addr_t ddr_low_size, ddr_high_size; qemu_irq gic_spi[GIC_NUM_SPI_INTR]; @@ -233,10 +236,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32); qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2); - qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS); + qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", num_apus); /* Realize APUs before realizing the GIC. KVM requires this. */ - for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { + for (i = 0; i < num_apus; i++) { char *name; object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC, @@ -292,7 +295,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } } - for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { + for (i = 0; i < num_apus; i++) { qemu_irq irq; sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i, @@ -307,11 +310,14 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } if (s->has_rpu) { - xlnx_zynqmp_create_rpu(s, boot_cpu, &err); - if (err) { - error_propagate(errp, err); - return; - } + info_report("The 'has_rpu' property is no longer required, to use the " + "RPUs just use -smp 6."); + } + + xlnx_zynqmp_create_rpu(s, boot_cpu, &err); + if (err) { + error_propagate(errp, err); + return; } if (!s->boot_cpu_ptr) { diff --git a/hw/display/vga.c b/hw/display/vga.c index 1d19f6bc48..a64a0942da 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1666,9 +1666,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) /* scanline wraps from end of video memory to the start */ assert(force_shadow); update = memory_region_snapshot_get_dirty(&s->vram, snap, - page0, 0); + page0, s->vbe_size - page0); update |= memory_region_snapshot_get_dirty(&s->vram, snap, - page1, 0); + 0, page1); } else { update = memory_region_snapshot_get_dirty(&s->vram, snap, page0, page1 - page0); diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 43bbe09ea0..274e365713 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -322,6 +322,18 @@ static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format) } } +static uint32_t calc_image_hostmem(pixman_format_code_t pformat, + uint32_t width, uint32_t height) +{ + /* Copied from pixman/pixman-bits-image.c, skip integer overflow check. + * pixman_image_create_bits will fail in case it overflow. + */ + + int bpp = PIXMAN_FORMAT_BPP(pformat); + int stride = ((width * bpp + 0x1f) >> 5) * sizeof(uint32_t); + return height * stride; +} + static void virtio_gpu_resource_create_2d(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -366,7 +378,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, return; } - res->hostmem = PIXMAN_FORMAT_BPP(pformat) * c2d.width * c2d.height; + res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height); if (res->hostmem + g->hostmem < g->conf.max_hostmem) { res->image = pixman_image_create_bits(pformat, c2d.width, @@ -1087,7 +1099,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, return -EINVAL; } - res->hostmem = PIXMAN_FORMAT_BPP(pformat) * res->width * res->height; + res->hostmem = calc_image_hostmem(pformat, res->width, res->height); res->addrs = g_new(uint64_t, res->iov_cnt); res->iov = g_new(struct iovec, res->iov_cnt); diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index cdc3fed6ca..0e6673a911 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -679,10 +679,9 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) if (cursor.width > 256 || cursor.height > 256 || cursor.bpp > 32 - || SVGA_BITMAP_SIZE(x, y) - > sizeof(cursor.mask) / sizeof(cursor.mask[0]) + || SVGA_BITMAP_SIZE(x, y) > ARRAY_SIZE(cursor.mask) || SVGA_PIXMAP_SIZE(x, y, cursor.bpp) - > sizeof(cursor.image) / sizeof(cursor.image[0])) { + > ARRAY_SIZE(cursor.image)) { goto badcmd; } diff --git a/hw/intc/xics.c b/hw/intc/xics.c index cc9816e7f2..a1cc0e420c 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -40,11 +40,17 @@ void icp_pic_print_info(ICPState *icp, Monitor *mon) { + ICPStateClass *icpc = ICP_GET_CLASS(icp); int cpu_index = icp->cs ? icp->cs->cpu_index : -1; if (!icp->output) { return; } + + if (icpc->synchronize_state) { + icpc->synchronize_state(icp); + } + monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n", cpu_index, icp->xirr, icp->xirr_owner, icp->pending_priority, icp->mfrr); @@ -52,6 +58,7 @@ void icp_pic_print_info(ICPState *icp, Monitor *mon) void ics_pic_print_info(ICSState *ics, Monitor *mon) { + ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics); uint32_t i; monitor_printf(mon, "ICS %4x..%4x %p\n", @@ -61,6 +68,10 @@ void ics_pic_print_info(ICSState *ics, Monitor *mon) return; } + if (icsc->synchronize_state) { + icsc->synchronize_state(ics); + } + for (i = 0; i < ics->nr_irqs; i++) { ICSIRQState *irq = ics->irqs + i; diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 3091ad3ac2..89fb20e2c5 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -81,6 +81,18 @@ static void icp_get_kvm_state(ICPState *icp) & KVM_REG_PPC_ICP_PPRI_MASK; } +static void do_icp_synchronize_state(CPUState *cpu, run_on_cpu_data arg) +{ + icp_get_kvm_state(arg.host_ptr); +} + +static void icp_synchronize_state(ICPState *icp) +{ + if (icp->cs) { + run_on_cpu(icp->cs, do_icp_synchronize_state, RUN_ON_CPU_HOST_PTR(icp)); + } +} + static int icp_set_kvm_state(ICPState *icp, int version_id) { uint64_t state; @@ -156,6 +168,7 @@ static void icp_kvm_class_init(ObjectClass *klass, void *data) icpc->post_load = icp_set_kvm_state; icpc->realize = icp_kvm_realize; icpc->reset = icp_kvm_reset; + icpc->synchronize_state = icp_synchronize_state; } static const TypeInfo icp_kvm_info = { @@ -234,6 +247,11 @@ static void ics_get_kvm_state(ICSState *ics) } } +static void ics_synchronize_state(ICSState *ics) +{ + ics_get_kvm_state(ics); +} + static int ics_set_kvm_state(ICSState *ics, int version_id) { uint64_t state; @@ -347,6 +365,7 @@ static void ics_kvm_class_init(ObjectClass *klass, void *data) icsc->realize = ics_kvm_realize; icsc->pre_save = ics_get_kvm_state; icsc->post_load = ics_set_kvm_state; + icsc->synchronize_state = ics_synchronize_state; } static const TypeInfo ics_kvm_info = { diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index 80b8f47c4b..a63ed2ca3b 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -132,6 +132,7 @@ typedef struct { const char *name; const char *desc; uint16_t device_id; + uint16_t alt_device_id; uint8_t revision; uint16_t subsystem_vendor_id; uint16_t subsystem_id; @@ -276,6 +277,7 @@ typedef struct { /* Quasi static device properties (no need to save them). */ uint16_t stats_size; bool has_extended_tcb_support; + bool use_alt_device_id; } EEPRO100State; /* Word indices in EEPROM. */ @@ -774,23 +776,11 @@ static void tx_command(EEPRO100State *s) } assert(tcb_bytes <= sizeof(buf)); while (size < tcb_bytes) { - uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address); - uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4); -#if 0 - uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6); -#endif - if (tx_buffer_size == 0) { - /* Prevent an endless loop. */ - logout("loop in %s:%u\n", __FILE__, __LINE__); - break; - } - tbd_address += 8; TRACE(RXTX, logout ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n", - tx_buffer_address, tx_buffer_size)); - tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size); - pci_dma_read(&s->dev, tx_buffer_address, &buf[size], tx_buffer_size); - size += tx_buffer_size; + tbd_address, tcb_bytes)); + pci_dma_read(&s->dev, tbd_address, &buf[size], tcb_bytes); + size += tcb_bytes; } if (tbd_array == 0xffffffff) { /* Simplified mode. Was already handled by code above. */ @@ -1867,6 +1857,14 @@ static void e100_nic_realize(PCIDevice *pci_dev, Error **errp) TRACE(OTHER, logout("\n")); + /* By default, the i82559a adapter uses the legacy PCI ID (for the + * i82557). This allows the PCI ID to be changed to the alternate + * i82559 ID if needed. + */ + if (s->use_alt_device_id && strcmp(info->name, "i82559a") == 0) { + pci_config_set_device_id(s->dev.config, info->alt_device_id); + } + s->device = info->device; e100_pci_reset(s, &local_err); @@ -1986,6 +1984,7 @@ static E100PCIDeviceInfo e100_devices[] = { .desc = "Intel i82559A Ethernet", .device = i82559A, .device_id = PCI_DEVICE_ID_INTEL_82557, + .alt_device_id = PCI_DEVICE_ID_INTEL_82559, .revision = 0x06, .stats_size = 80, .has_extended_tcb_support = true, @@ -2079,6 +2078,8 @@ static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s) static Property e100_properties[] = { DEFINE_NIC_PROPERTIES(EEPRO100State, conf), + DEFINE_PROP_BOOL("x-use-alt-device-id", EEPRO100State, use_alt_device_id, + true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 0d59d1534d..be22a6b289 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1636,6 +1636,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00); if (!spapr->cas_reboot) { + /* If ppc_spapr_reset() did not set up a HPT but one is necessary + * (because the guest isn't going to use radix) then set it up here. */ + if ((spapr->patb_entry & PATBE1_GR) && !guest_radix) { + /* legacy hash or new hash: */ + spapr_setup_hpt_and_vrma(spapr); + } spapr->cas_reboot = (spapr_h_cas_compose_response(spapr, args[1], args[2], ov5_updates) != 0); @@ -1644,13 +1650,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, if (spapr->cas_reboot) { qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - } else { - /* If ppc_spapr_reset() did not set up a HPT but one is necessary - * (because the guest isn't going to use radix) then set it up here. */ - if ((spapr->patb_entry & PATBE1_GR) && !guest_radix) { - /* legacy hash or new hash: */ - spapr_setup_hpt_and_vrma(spapr); - } } return H_SUCCESS; diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index e7a58e81f7..2b1e1409bf 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -715,7 +715,7 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, pbdev->pdev = pdev; pbdev->iommu = s390_pci_get_iommu(s, pdev->bus, pdev->devfn); pbdev->iommu->pbdev = pbdev; - pbdev->state = ZPCI_FS_STANDBY; + pbdev->state = ZPCI_FS_DISABLED; if (s390_pci_msix_init(pbdev)) { error_setg(errp, "MSI-X support is mandatory " diff --git a/include/block/nbd.h b/include/block/nbd.h index 92d1723d7c..113c707a5e 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -86,15 +86,23 @@ typedef union NBDReply { } QEMU_PACKED; } NBDReply; -/* Header of NBD_REPLY_TYPE_OFFSET_DATA, complete NBD_REPLY_TYPE_OFFSET_HOLE */ -typedef struct NBDStructuredRead { - NBDStructuredReplyChunk h; +/* Header of chunk for NBD_REPLY_TYPE_OFFSET_DATA */ +typedef struct NBDStructuredReadData { + NBDStructuredReplyChunk h; /* h.length >= 9 */ uint64_t offset; -} QEMU_PACKED NBDStructuredRead; + /* At least one byte of data payload follows, calculated from h.length */ +} QEMU_PACKED NBDStructuredReadData; + +/* Complete chunk for NBD_REPLY_TYPE_OFFSET_HOLE */ +typedef struct NBDStructuredReadHole { + NBDStructuredReplyChunk h; /* h.length == 12 */ + uint64_t offset; + uint32_t length; +} QEMU_PACKED NBDStructuredReadHole; /* Header of all NBD_REPLY_TYPE_ERROR* errors */ typedef struct NBDStructuredError { - NBDStructuredReplyChunk h; + NBDStructuredReplyChunk h; /* h.length >= 6 */ uint32_t error; uint16_t message_length; } QEMU_PACKED NBDStructuredError; diff --git a/include/disas/bfd.h b/include/disas/bfd.h index 1f88c9e9d5..46c7ec3376 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -374,6 +374,8 @@ typedef struct disassemble_info { /* Options for Capstone disassembly. */ int cap_arch; int cap_mode; + int cap_insn_unit; + int cap_insn_split; } disassemble_info; diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 923ece3e9b..0f51c92adb 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -45,6 +45,17 @@ void restore_state_to_opc(CPUArchState *env, struct TranslationBlock *tb, target_ulong *data); void cpu_gen_init(void); + +/** + * cpu_restore_state: + * @cpu: the vCPU state is to be restore to + * @searched_pc: the host PC the fault occurred at + * @return: true if state was restored, false otherwise + * + * Attempt to restore the state for a fault occurring in translated + * code. If the searched_pc is not in translated code no state is + * restored and the function returns false. + */ bool cpu_restore_state(CPUState *cpu, uintptr_t searched_pc); void QEMU_NORETURN cpu_loop_exit_noexc(CPUState *cpu); diff --git a/include/hw/boards.h b/include/hw/boards.h index 191a5b3cd8..62f160e0aa 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -102,6 +102,9 @@ typedef struct { /** * MachineClass: + * @max_cpus: maximum number of CPUs supported. Default: 1 + * @min_cpus: minimum number of CPUs supported. Default: 1 + * @default_cpus: number of CPUs instantiated if none are specified. Default: 1 * @get_hotplug_handler: this function is called during bus-less * device hotplug. If defined it returns pointer to an instance * of HotplugHandler object, which handles hotplug operation @@ -167,6 +170,8 @@ struct MachineClass { BlockInterfaceType block_default_type; int units_per_default_bus; int max_cpus; + int min_cpus; + int default_cpus; unsigned int no_serial:1, no_parallel:1, use_virtcon:1, diff --git a/include/hw/compat.h b/include/hw/compat.h index cf389b4e85..f96212c49c 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -10,6 +10,10 @@ .driver = "virtio-tablet-device",\ .property = "wheel-axis",\ .value = "false",\ + },{\ + .driver = "i82559a",\ + .property = "x-use-alt-device-id",\ + .value = "false",\ }, #define HW_COMPAT_2_9 \ diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 8d02a0a383..f30e2cfb72 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -70,6 +70,7 @@ extern bool pci_available; /* Intel (0x8086) */ #define PCI_DEVICE_ID_INTEL_82551IT 0x1209 #define PCI_DEVICE_ID_INTEL_82557 0x1229 +#define PCI_DEVICE_ID_INTEL_82559 0x1030 #define PCI_DEVICE_ID_INTEL_82801IR 0x2922 /* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 28d248abad..2df99be111 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -69,6 +69,7 @@ struct ICPStateClass { void (*pre_save)(ICPState *icp); int (*post_load)(ICPState *icp, int version_id); void (*reset)(ICPState *icp); + void (*synchronize_state)(ICPState *icp); }; struct ICPState { @@ -119,6 +120,7 @@ struct ICSStateClass { void (*reject)(ICSState *s, uint32_t irq); void (*resend)(ICSState *s); void (*eoi)(ICSState *s, uint32_t irq); + void (*synchronize_state)(ICSState *s); }; struct ICSState { diff --git a/include/qom/cpu.h b/include/qom/cpu.h index fa4b0c9dba..c2fa151228 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -209,7 +209,6 @@ typedef struct CPUClass { /* Keep non-pointer data at the end to minimize holes. */ int gdb_num_core_regs; bool gdb_stop_before_watchpoint; - bool tcg_initialized; } CPUClass; #ifdef HOST_WORDS_BIGENDIAN diff --git a/nbd/client.c b/nbd/client.c index 3d680e63e1..1880103d2a 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -979,6 +979,7 @@ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) { int ret; + const char *type; ret = nbd_read_eof(ioc, &reply->magic, sizeof(reply->magic), errp); if (ret <= 0) { @@ -1008,8 +1009,9 @@ int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) if (ret < 0) { break; } + type = nbd_reply_type_lookup(reply->structured.type); trace_nbd_receive_structured_reply_chunk(reply->structured.flags, - reply->structured.type, + reply->structured.type, type, reply->structured.handle, reply->structured.length); break; diff --git a/nbd/server.c b/nbd/server.c index 70b40ed27e..df771fd42f 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -423,6 +423,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint32_t length, break; } } + assert(length == 0); exp = nbd_export_find(name); if (!exp) { @@ -433,7 +434,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint32_t length, /* Don't bother sending NBD_INFO_NAME unless client requested it */ if (sendname) { - rc = nbd_negotiate_send_info(client, opt, NBD_INFO_NAME, length, name, + rc = nbd_negotiate_send_info(client, opt, NBD_INFO_NAME, namelen, name, errp); if (rc < 0) { return rc; @@ -1272,6 +1273,21 @@ static inline void set_be_chunk(NBDStructuredReplyChunk *chunk, uint16_t flags, stl_be_p(&chunk->length, length); } +static int coroutine_fn nbd_co_send_structured_done(NBDClient *client, + uint64_t handle, + Error **errp) +{ + NBDStructuredReplyChunk chunk; + struct iovec iov[] = { + {.iov_base = &chunk, .iov_len = sizeof(chunk)}, + }; + + trace_nbd_co_send_structured_done(handle); + set_be_chunk(&chunk, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_NONE, handle, 0); + + return nbd_co_send_iov(client, iov, 1, errp); +} + static int coroutine_fn nbd_co_send_structured_read(NBDClient *client, uint64_t handle, uint64_t offset, @@ -1279,12 +1295,13 @@ static int coroutine_fn nbd_co_send_structured_read(NBDClient *client, size_t size, Error **errp) { - NBDStructuredRead chunk; + NBDStructuredReadData chunk; struct iovec iov[] = { {.iov_base = &chunk, .iov_len = sizeof(chunk)}, {.iov_base = data, .iov_len = size} }; + assert(size); trace_nbd_co_send_structured_read(handle, offset, data, size); set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_OFFSET_DATA, handle, sizeof(chunk) - sizeof(chunk.h) + size); @@ -1543,10 +1560,13 @@ reply: if (ret < 0) { ret = nbd_co_send_structured_error(req->client, request.handle, -ret, msg, &local_err); - } else { + } else if (reply_data_len) { ret = nbd_co_send_structured_read(req->client, request.handle, request.from, req->data, reply_data_len, &local_err); + } else { + ret = nbd_co_send_structured_done(req->client, request.handle, + &local_err); } } else { ret = nbd_co_send_simple_reply(req->client, request.handle, diff --git a/nbd/trace-events b/nbd/trace-events index 4a13757524..92568edce5 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -27,7 +27,7 @@ nbd_client_clear_queue(void) "Clearing NBD queue" nbd_client_clear_socket(void) "Clearing NBD socket" nbd_send_request(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name) "Sending request to server: { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) }" nbd_receive_simple_reply(int32_t error, const char *errname, uint64_t handle) "Got simple reply: { .error = %" PRId32 " (%s), handle = %" PRIu64" }" -nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, uint64_t handle, uint32_t length) "Got structured reply chunk: { flags = 0x%" PRIx16 ", type = %d, handle = %" PRIu64 ", length = %" PRIu32 " }" +nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, const char *name, uint64_t handle, uint32_t length) "Got structured reply chunk: { flags = 0x%" PRIx16 ", type = %d (%s), handle = %" PRIu64 ", length = %" PRIu32 " }" # nbd/common.c nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL" @@ -55,6 +55,7 @@ nbd_receive_request(uint32_t magic, uint16_t flags, uint16_t type, uint64_t from nbd_blk_aio_attached(const char *name, void *ctx) "Export %s: Attaching clients to AIO context %p\n" nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clients from AIO context %p\n" nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errname, int len) "Send simple reply: handle = %" PRIu64 ", error = %" PRIu32 " (%s), len = %d" +nbd_co_send_structured_done(uint64_t handle) "Send structured reply done: handle = %" PRIu64 nbd_co_send_structured_read(uint64_t handle, uint64_t offset, void *data, size_t size) "Send structured read data reply: handle = %" PRIu64 ", offset = %" PRIu64 ", data = %p, len = %zu" nbd_co_send_structured_error(uint64_t handle, int err, const char *errname, const char *msg) "Send structured error reply: handle = %" PRIu64 ", error = %d (%s), msg = '%s'" nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const char *name) "Decoding type: handle = %" PRIu64 ", type = %" PRIu16 " (%s)" diff --git a/net/colo-compare.c b/net/colo-compare.c index b3f35d729a..ccdcba2691 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -113,10 +113,30 @@ static gint seq_sorter(Packet *a, Packet *b, gpointer data) } /* + * Return 1 on success, if return 0 means the + * packet will be dropped + */ +static int colo_insert_packet(GQueue *queue, Packet *pkt) +{ + if (g_queue_get_length(queue) <= MAX_QUEUE_SIZE) { + if (pkt->ip->ip_p == IPPROTO_TCP) { + g_queue_insert_sorted(queue, + pkt, + (GCompareDataFunc)seq_sorter, + NULL); + } else { + g_queue_push_tail(queue, pkt); + } + return 1; + } + return 0; +} + +/* * Return 0 on success, if return -1 means the pkt * is unsupported(arp and ipv6) and will be sent later */ -static int packet_enqueue(CompareState *s, int mode) +static int packet_enqueue(CompareState *s, int mode, Connection **con) { ConnectionKey key; Packet *pkt = NULL; @@ -149,32 +169,17 @@ static int packet_enqueue(CompareState *s, int mode) } if (mode == PRIMARY_IN) { - if (g_queue_get_length(&conn->primary_list) <= - MAX_QUEUE_SIZE) { - g_queue_push_tail(&conn->primary_list, pkt); - if (conn->ip_proto == IPPROTO_TCP) { - g_queue_sort(&conn->primary_list, - (GCompareDataFunc)seq_sorter, - NULL); - } - } else { + if (!colo_insert_packet(&conn->primary_list, pkt)) { error_report("colo compare primary queue size too big," "drop packet"); } } else { - if (g_queue_get_length(&conn->secondary_list) <= - MAX_QUEUE_SIZE) { - g_queue_push_tail(&conn->secondary_list, pkt); - if (conn->ip_proto == IPPROTO_TCP) { - g_queue_sort(&conn->secondary_list, - (GCompareDataFunc)seq_sorter, - NULL); - } - } else { + if (!colo_insert_packet(&conn->secondary_list, pkt)) { error_report("colo compare secondary queue size too big," "drop packet"); } } + con = &conn; return 0; } @@ -475,7 +480,9 @@ static void colo_old_packet_check(void *opaque) /* * Called from the compare thread on the primary - * for compare connection + * for compare packet with secondary list of the + * specified connection when a new packet was + * queued to it. */ static void colo_compare_connection(void *opaque, void *user_data) { @@ -724,28 +731,30 @@ static void compare_set_vnet_hdr(Object *obj, static void compare_pri_rs_finalize(SocketReadState *pri_rs) { CompareState *s = container_of(pri_rs, CompareState, pri_rs); + Connection *conn = NULL; - if (packet_enqueue(s, PRIMARY_IN)) { + if (packet_enqueue(s, PRIMARY_IN, &conn)) { trace_colo_compare_main("primary: unsupported packet in"); compare_chr_send(s, pri_rs->buf, pri_rs->packet_len, pri_rs->vnet_hdr_len); } else { - /* compare connection */ - g_queue_foreach(&s->conn_list, colo_compare_connection, s); + /* compare packet in the specified connection */ + colo_compare_connection(conn, s); } } static void compare_sec_rs_finalize(SocketReadState *sec_rs) { CompareState *s = container_of(sec_rs, CompareState, sec_rs); + Connection *conn = NULL; - if (packet_enqueue(s, SECONDARY_IN)) { + if (packet_enqueue(s, SECONDARY_IN, &conn)) { trace_colo_compare_main("secondary: unsupported packet in"); } else { - /* compare connection */ - g_queue_foreach(&s->conn_list, colo_compare_connection, s); + /* compare packet in the specified connection */ + colo_compare_connection(conn, s); } } diff --git a/net/colo.c b/net/colo.c index 28ce7c8ae0..a39d600f34 100644 --- a/net/colo.c +++ b/net/colo.c @@ -82,6 +82,14 @@ int parse_packet_early(Packet *pkt) return 0; } +void extract_ip_and_port(uint32_t tmp_ports, ConnectionKey *key, Packet *pkt) +{ + key->src = pkt->ip->ip_src; + key->dst = pkt->ip->ip_dst; + key->src_port = ntohs(tmp_ports >> 16); + key->dst_port = ntohs(tmp_ports & 0xffff); +} + void fill_connection_key(Packet *pkt, ConnectionKey *key) { uint32_t tmp_ports; @@ -97,17 +105,11 @@ void fill_connection_key(Packet *pkt, ConnectionKey *key) case IPPROTO_SCTP: case IPPROTO_UDPLITE: tmp_ports = *(uint32_t *)(pkt->transport_header); - key->src = pkt->ip->ip_src; - key->dst = pkt->ip->ip_dst; - key->src_port = ntohs(tmp_ports & 0xffff); - key->dst_port = ntohs(tmp_ports >> 16); + extract_ip_and_port(tmp_ports, key, pkt); break; case IPPROTO_AH: tmp_ports = *(uint32_t *)(pkt->transport_header + 4); - key->src = pkt->ip->ip_src; - key->dst = pkt->ip->ip_dst; - key->src_port = ntohs(tmp_ports & 0xffff); - key->dst_port = ntohs(tmp_ports >> 16); + extract_ip_and_port(tmp_ports, key, pkt); break; default: break; diff --git a/net/colo.h b/net/colo.h index caedb0dca7..0658e869b4 100644 --- a/net/colo.h +++ b/net/colo.h @@ -76,6 +76,7 @@ typedef struct Connection { uint32_t connection_key_hash(const void *opaque); int connection_key_equal(const void *opaque1, const void *opaque2); int parse_packet_early(Packet *pkt); +void extract_ip_and_port(uint32_t tmp_ports, ConnectionKey *key, Packet *pkt); void fill_connection_key(Packet *pkt, ConnectionKey *key); void reverse_connection_key(ConnectionKey *key); Connection *connection_new(ConnectionKey *key); diff --git a/net/socket.c b/net/socket.c index e6b471c63d..6917fbcbf5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -373,7 +373,7 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, net_socket_read_poll(s, true); /* mcast: save bound address as dst */ - if (is_connected) { + if (is_connected && mcast != NULL) { s->dgram_dst = saddr; snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d (cloned mcast=%s:%d)", @@ -695,8 +695,8 @@ int net_init_socket(const Netdev *netdev, const char *name, assert(netdev->type == NET_CLIENT_DRIVER_SOCKET); sock = &netdev->u.socket; - if (sock->has_listen + sock->has_connect + sock->has_mcast + - sock->has_udp > 1) { + if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + + sock->has_udp != 1) { error_setg(errp, "exactly one of listen=, connect=, mcast= or udp=" " is required"); return -1; diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin index 343146819f..e1d6b15927 100644 --- a/pc-bios/bios-256k.bin +++ b/pc-bios/bios-256k.bin Binary files differdiff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 0de6417b65..140e33c6b6 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin Binary files differdiff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 1ea28f20bb..3c8d507c7a 100644 --- a/pc-bios/vgabios-cirrus.bin +++ b/pc-bios/vgabios-cirrus.bin Binary files differdiff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin index 32bda237fe..1c9ec0f92d 100644 --- a/pc-bios/vgabios-qxl.bin +++ b/pc-bios/vgabios-qxl.bin Binary files differdiff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin index bda19982ae..b84ae22de7 100644 --- a/pc-bios/vgabios-stdvga.bin +++ b/pc-bios/vgabios-stdvga.bin Binary files differdiff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin index 16c7c7d8d2..aebc7f820f 100644 --- a/pc-bios/vgabios-virtio.bin +++ b/pc-bios/vgabios-virtio.bin Binary files differdiff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin index b08fdf4ee1..76314aa323 100644 --- a/pc-bios/vgabios-vmware.bin +++ b/pc-bios/vgabios-vmware.bin Binary files differdiff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index b1c1942979..066a40b4da 100644 --- a/pc-bios/vgabios.bin +++ b/pc-bios/vgabios.bin Binary files differdiff --git a/qemu-doc.texi b/qemu-doc.texi index 8c10956a66..d383ac44d4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2537,6 +2537,13 @@ or ``ivshmem-doorbell`` device types. The ``spapr-pci-vfio-host-bridge'' device type is replaced by the ``spapr-pci-host-bridge'' device type. +@section System emulator machines + +@subsection Xilinx EP108 (since 2.11.0) + +The ``xlnx-ep108'' machine has been replaced by the ``xlnx-zcu102'' machine. +The ``xlnx-zcu102'' machine has the same features and capabilites in QEMU. + @node License @appendix License diff --git a/qemu-options.hx b/qemu-options.hx index 3728e9b4dd..a39c7e44b3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2047,7 +2047,7 @@ that the card should have; this option currently only affects virtio cards; set @var{v} = 0 to disable MSI-X. If no @option{-net} option is specified, a single NIC is created. QEMU can emulate several different models of network card. Valid values for @var{type} are -@code{virtio}, @code{i82551}, @code{i82557b}, @code{i82559er}, +@code{virtio}, @code{i82551}, @code{i82557b}, @code{i82559a}, @code{i82559er}, @code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139}, @code{e1000}, @code{smc91c111}, @code{lance} and @code{mcf_fec}. Not all devices are supported on all targets. Use @code{-net nic,model=help} diff --git a/roms/seabios b/roms/seabios -Subproject cd47172a673762a05a0c7bd27df6e3cc8febe8d +Subproject 63451fca13c75870e1703eb3e20584d91179aeb diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index dc8b4bbb50..da0d53743f 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -148,7 +148,16 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, m->m_data += IF_MAXLINKHDR; *mtod(m, struct tcpiphdr *) = *ti; ti = mtod(m, struct tcpiphdr *); - memset(&ti->ti, 0, sizeof(ti->ti)); + switch (af) { + case AF_INET: + ti->ti.ti_i4.ih_x1 = 0; + break; + case AF_INET6: + ti->ti.ti_i6.ih_x1 = 0; + break; + default: + g_assert_not_reached(); + } flags = TH_ACK; } else { /* diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 47c8b2a85c..7f7a3d1e32 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -489,13 +489,19 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) info->print_insn = print_insn_arm_a64; #endif info->cap_arch = CS_ARCH_ARM64; + info->cap_insn_unit = 4; + info->cap_insn_split = 4; } else { int cap_mode; if (env->thumb) { info->print_insn = print_insn_thumb1; + info->cap_insn_unit = 2; + info->cap_insn_split = 4; cap_mode = CS_MODE_THUMB; } else { info->print_insn = print_insn_arm; + info->cap_insn_unit = 4; + info->cap_insn_split = 4; cap_mode = CS_MODE_ARM; } if (arm_feature(env, ARM_FEATURE_V8)) { diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index caca05aa41..625ef2dfd2 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2351,6 +2351,8 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, post_index = false; writeback = true; break; + default: + g_assert_not_reached(); } if (rn == 31) { diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6f21a5e518..1edcf29e27 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4109,6 +4109,8 @@ static void x86_disas_set_info(CPUState *cs, disassemble_info *info) info->cap_mode = (env->hflags & HF_CS64_MASK ? CS_MODE_64 : env->hflags & HF_CS32_MASK ? CS_MODE_32 : CS_MODE_16); + info->cap_insn_unit = 1; + info->cap_insn_split = 8; } static Property x86_cpu_properties[] = { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index dee72a787d..85d0a6c3af 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3432,6 +3432,7 @@ static ExitStatus op_risbg(DisasContext *s, DisasOps *o) /* Adjust the arguments for the specific insn. */ switch (s->fields->op2) { case 0x55: /* risbg */ + case 0x59: /* risbgn */ i3 &= 63; i4 &= 63; pmask = ~0; @@ -3447,7 +3448,7 @@ static ExitStatus op_risbg(DisasContext *s, DisasOps *o) pmask = 0x00000000ffffffffull; break; default: - abort(); + g_assert_not_reached(); } /* MASK is the set of bits to be inserted from R2. @@ -3464,11 +3465,7 @@ static ExitStatus op_risbg(DisasContext *s, DisasOps *o) insns, we need to keep the other half of the register. */ imask = ~mask | ~pmask; if (do_zero) { - if (s->fields->op2 == 0x55) { - imask = 0; - } else { - imask = ~pmask; - } + imask = ~pmask; } len = i4 - i3 + 1; diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index f1a398e9fa..de87341528 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -109,7 +109,7 @@ docker: @echo ' DEBUG=1 Stop and drop to shell in the created container' @echo ' before running the command.' @echo ' NETWORK=1 Enable virtual network interface with default backend.' - @echo ' NETWORK=$BACKEND Enable virtual network interface with $BACKEND.' + @echo ' NETWORK=$$BACKEND Enable virtual network interface with $$BACKEND.' @echo ' NOUSER Define to disable adding current user to containers passwd.' @echo ' NOCACHE=1 Ignore cache when build images.' @echo ' EXECUTABLE=<path> Include executable in image.' diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 08122ca17d..1246ba9578 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -105,6 +105,28 @@ def _copy_binary_with_libs(src, dest_dir): so_path = os.path.dirname(l) _copy_with_mkdir(l , dest_dir, so_path) +def _read_qemu_dockerfile(img_name): + df = os.path.join(os.path.dirname(__file__), "dockerfiles", + img_name + ".docker") + return open(df, "r").read() + +def _dockerfile_preprocess(df): + out = "" + for l in df.splitlines(): + if len(l.strip()) == 0 or l.startswith("#"): + continue + from_pref = "FROM qemu:" + if l.startswith(from_pref): + # TODO: Alternatively we could replace this line with "FROM $ID" + # where $ID is the image's hex id obtained with + # $ docker images $IMAGE --format="{{.Id}}" + # but unfortunately that's not supported by RHEL 7. + inlining = _read_qemu_dockerfile(l[len(from_pref):]) + out += _dockerfile_preprocess(inlining) + continue + out += l + "\n" + return out + class Docker(object): """ Running Docker commands """ def __init__(self): @@ -196,7 +218,7 @@ class Docker(object): checksum = self.get_image_dockerfile_checksum(tag) except Exception: return False - return checksum == _text_checksum(dockerfile) + return checksum == _text_checksum(_dockerfile_preprocess(dockerfile)) def run(self, cmd, keep, quiet): label = uuid.uuid1().hex diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 18838948fa..457984b8e9 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -666,6 +666,7 @@ class TestENOSPC(TestErrors): if event['event'] == 'BLOCK_JOB_ERROR': self.assert_qmp(event, 'data/device', 'drive0') self.assert_qmp(event, 'data/operation', 'read') + error = True result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/paused', True) @@ -676,9 +677,11 @@ class TestENOSPC(TestErrors): self.assert_qmp(result, 'return', {}) result = self.vm.qmp('query-block-jobs') + if result == {'return': []}: + # Race; likely already finished. Check. + continue self.assert_qmp(result, 'return[0]/paused', False) self.assert_qmp(result, 'return[0]/io-status', 'ok') - error = True elif event['event'] == 'BLOCK_JOB_COMPLETED': self.assertTrue(error, 'job completed unexpectedly') self.assert_qmp(event, 'data/type', 'stream') @@ -792,13 +795,14 @@ class TestSetSpeed(iotests.QMPTestCase): self.assert_no_active_block_jobs() + self.vm.pause_drive('drive0') result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) self.assert_qmp(result, 'error/class', 'GenericError') - self.cancel_and_wait() + self.cancel_and_wait(resume=True) if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'qed']) diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index c284d08796..90b5b4f2ad 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -289,7 +289,7 @@ class TestSetSpeed(ImageCommitTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 0 512', test_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img) - self.vm = iotests.VM().add_drive(test_img) + self.vm = iotests.VM().add_drive('blkdebug::' + test_img) self.vm.launch() def tearDown(self): diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index e1206caf9b..8a5d9fd269 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -48,7 +48,7 @@ class TestSingleDrive(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) - self.vm = iotests.VM().add_drive(test_img) + self.vm = iotests.VM().add_drive('blkdebug::' + test_img) self.vm.add_drive(blockdev_target_img, interface="none") if iotests.qemu_default_machine == 'pc': self.vm.add_drive(None, 'media=cdrom', 'ide') @@ -65,10 +65,11 @@ class TestSingleDrive(iotests.QMPTestCase): def do_test_cancel(self, cmd, target): self.assert_no_active_block_jobs() + self.vm.pause_drive('drive0') result = self.vm.qmp(cmd, device='drive0', target=target, sync='full') self.assert_qmp(result, 'return', {}) - event = self.cancel_and_wait() + event = self.cancel_and_wait(resume=True) self.assert_qmp(event, 'data/type', 'backup') def test_cancel_drive_backup(self): @@ -166,7 +167,7 @@ class TestSetSpeed(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) - self.vm = iotests.VM().add_drive(test_img) + self.vm = iotests.VM().add_drive('blkdebug::' + test_img) self.vm.add_drive(blockdev_target_img, interface="none") self.vm.launch() @@ -246,6 +247,8 @@ class TestSetSpeed(iotests.QMPTestCase): def test_set_speed_invalid_blockdev_backup(self): self.do_test_set_speed_invalid('blockdev-backup', 'drive1') +# Note: We cannot use pause_drive() here, or the transaction command +# would stall. Instead, we limit the block job speed here. class TestSingleTransaction(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) @@ -271,7 +274,8 @@ class TestSingleTransaction(iotests.QMPTestCase): 'type': cmd, 'data': { 'device': 'drive0', 'target': target, - 'sync': 'full' }, + 'sync': 'full', + 'speed': 64 * 1024 }, } ]) @@ -289,12 +293,12 @@ class TestSingleTransaction(iotests.QMPTestCase): def do_test_pause(self, cmd, target, image): self.assert_no_active_block_jobs() - self.vm.pause_drive('drive0') result = self.vm.qmp('transaction', actions=[{ 'type': cmd, 'data': { 'device': 'drive0', 'target': target, - 'sync': 'full' }, + 'sync': 'full', + 'speed': 64 * 1024 }, } ]) self.assert_qmp(result, 'return', {}) @@ -302,7 +306,9 @@ class TestSingleTransaction(iotests.QMPTestCase): result = self.vm.qmp('block-job-pause', device='drive0') self.assert_qmp(result, 'return', {}) - self.vm.resume_drive('drive0') + result = self.vm.qmp('block-job-set-speed', device='drive0', speed=0) + self.assert_qmp(result, 'return', {}) + self.pause_job('drive0') result = self.vm.qmp('query-block-jobs') @@ -461,7 +467,7 @@ class TestDriveCompression(iotests.QMPTestCase): pass def do_prepare_drives(self, fmt, args, attach_target): - self.vm = iotests.VM().add_drive(test_img) + self.vm = iotests.VM().add_drive('blkdebug::' + test_img) qemu_img('create', '-f', fmt, blockdev_target_img, str(TestDriveCompression.image_len), *args) @@ -500,10 +506,11 @@ class TestDriveCompression(iotests.QMPTestCase): self.assert_no_active_block_jobs() + self.vm.pause_drive('drive0') result = self.vm.qmp(cmd, device='drive0', sync='full', compress=True, **args) self.assert_qmp(result, 'return', {}) - event = self.cancel_and_wait() + event = self.cancel_and_wait(resume=True) self.assert_qmp(event, 'data/type', 'backup') self.vm.shutdown() diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058 index 2253c6a6d1..5eb8784669 100755 --- a/tests/qemu-iotests/058 +++ b/tests/qemu-iotests/058 @@ -117,15 +117,15 @@ _export_nbd_snapshot sn1 echo echo "== verifying the exported snapshot with patterns, method 1 ==" -$QEMU_IO_NBD -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io -$QEMU_IO_NBD -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$QEMU_IO_NBD -r -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$QEMU_IO_NBD -r -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io _export_nbd_snapshot1 sn1 echo echo "== verifying the exported snapshot with patterns, method 2 ==" -$QEMU_IO_NBD -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io -$QEMU_IO_NBD -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$QEMU_IO_NBD -r -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$QEMU_IO_NBD -r -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io $QEMU_IMG convert "$TEST_IMG" -l sn1 -O qcow2 "$converted_image" diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index 8e95c450eb..fae08b03bf 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -242,6 +242,65 @@ poke_file "$TEST_IMG" "$(($l2_offset+8))" "\x80\x00\x00\x00\x00\x06\x2a\x00" # Should emit two error messages $QEMU_IO -c "discard 0 64k" -c "read 64k 64k" "$TEST_IMG" | _filter_qemu_io +echo +echo "=== Testing empty refcount table ===" +echo +_make_test_img 64M +poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x00\x00\x00" +$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io +# Repair the image +_check_test_img -r all + +echo +echo "=== Testing empty refcount table with valid L1 and L2 tables ===" +echo +_make_test_img 64M +$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io +poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x00\x00\x00" +# Since the first data cluster is already allocated this triggers an +# allocation with an explicit offset (using qcow2_alloc_clusters_at()) +# causing a refcount block to be allocated at offset 0 +$QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io +# Repair the image +_check_test_img -r all + +echo +echo "=== Testing empty refcount block ===" +echo +_make_test_img 64M +poke_file "$TEST_IMG" "$rb_offset" "\x00\x00\x00\x00\x00\x00\x00\x00" +$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io +# Repair the image +_check_test_img -r all + +echo +echo "=== Testing empty refcount block with compressed write ===" +echo +_make_test_img 64M +$QEMU_IO -c "write 64k 64k" "$TEST_IMG" | _filter_qemu_io +poke_file "$TEST_IMG" "$rb_offset" "\x00\x00\x00\x00\x00\x00\x00\x00" +# The previous write already allocated an L2 table, so now this new +# write will try to allocate a compressed data cluster at offset 0. +$QEMU_IO -c "write -c 0k 64k" "$TEST_IMG" | _filter_qemu_io +# Repair the image +_check_test_img -r all + +echo +echo "=== Testing zero refcount table size ===" +echo +_make_test_img 64M +poke_file "$TEST_IMG" "56" "\x00\x00\x00\x00" +$QEMU_IO -c "write 0 64k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt +# Repair the image +_check_test_img -r all + +echo +echo "=== Testing incorrect refcount table offset ===" +echo +_make_test_img 64M +poke_file "$TEST_IMG" "48" "\x00\x00\x00\x00\x00\x00\x00\x00" +$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index 5ca3af491f..62c22701b8 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -181,4 +181,107 @@ qcow2: Marking image as corrupt: Cluster allocation offset 0x62a00 unaligned (L2 discard 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read failed: Input/output error + +=== Testing empty refcount table === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount table); further corruption events will be suppressed +write failed: Input/output error +ERROR cluster 0 refcount=0 reference=1 +ERROR cluster 1 refcount=0 reference=1 +ERROR cluster 3 refcount=0 reference=1 +Rebuilding refcount structure +Repairing cluster 1 refcount=1 reference=0 +The following inconsistencies were found and repaired: + + 0 leaked clusters + 3 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +=== Testing empty refcount table with valid L1 and L2 tables === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 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: Preventing invalid allocation of refcount block at offset 0; further corruption events will be suppressed +write failed: Input/output error +ERROR cluster 0 refcount=0 reference=1 +ERROR cluster 1 refcount=0 reference=1 +ERROR cluster 3 refcount=0 reference=1 +ERROR cluster 4 refcount=0 reference=1 +ERROR cluster 5 refcount=0 reference=1 +Rebuilding refcount structure +Repairing cluster 1 refcount=1 reference=0 +The following inconsistencies were found and repaired: + + 0 leaked clusters + 5 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +=== Testing empty refcount block === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed +write failed: Input/output error +ERROR cluster 0 refcount=0 reference=1 +ERROR cluster 1 refcount=0 reference=1 +ERROR cluster 2 refcount=0 reference=1 +ERROR cluster 3 refcount=0 reference=1 +Rebuilding refcount structure +Repairing cluster 1 refcount=1 reference=0 +Repairing cluster 2 refcount=1 reference=0 +The following inconsistencies were found and repaired: + + 0 leaked clusters + 4 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +=== Testing empty refcount block with compressed write === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qcow2: Marking image as corrupt: Preventing invalid allocation of compressed cluster at offset 0; further corruption events will be suppressed +write failed: Input/output error +ERROR cluster 0 refcount=0 reference=1 +ERROR cluster 1 refcount=0 reference=1 +ERROR cluster 2 refcount=0 reference=1 +ERROR cluster 3 refcount=0 reference=1 +Rebuilding refcount structure +Repairing cluster 1 refcount=1 reference=0 +Repairing cluster 2 refcount=1 reference=0 +The following inconsistencies were found and repaired: + + 0 leaked clusters + 4 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +=== Testing zero refcount table size === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +can't open device TEST_DIR/t.IMGFMT: Image does not contain a reference count table +ERROR cluster 0 refcount=0 reference=1 +ERROR cluster 3 refcount=0 reference=1 +Rebuilding refcount structure +The following inconsistencies were found and repaired: + + 0 leaked clusters + 2 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +=== Testing incorrect refcount table offset === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed +write failed: Input/output error *** done diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077 index d2d2a2d687..b3c6fb1370 100755 --- a/tests/qemu-iotests/077 +++ b/tests/qemu-iotests/077 @@ -188,7 +188,8 @@ EOF test_io | $QEMU_IO | _filter_qemu_io | \ sed -e 's,[0-9/]* bytes at offset [0-9]*,XXX/XXX bytes at offset XXX,g' \ -e 's/^[0-9]* \(bytes\|KiB\)/XXX bytes/' \ - -e '/Suspended/d' + -e '/Suspended/d' \ + -e '/blkdebug: Resuming request/d' echo echo "== Verify image content ==" diff --git a/tests/qemu-iotests/077.out b/tests/qemu-iotests/077.out index 16f951fd3d..4aae82f2e2 100644 --- a/tests/qemu-iotests/077.out +++ b/tests/qemu-iotests/077.out @@ -4,17 +4,14 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 == Some concurrent requests involving RMW == wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX @@ -31,51 +28,38 @@ wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'B' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'B' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'B' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'B' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' -blkdebug: Resuming request 'C' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'B' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkdebug: Resuming request 'A' wrote XXX/XXX bytes at offset XXX XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote XXX/XXX bytes at offset XXX diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 index 0306f112da..3c1adbf0fb 100755 --- a/tests/qemu-iotests/083 +++ b/tests/qemu-iotests/083 @@ -86,6 +86,7 @@ EOF rm -f "$TEST_DIR/nbd.sock" + echo > "$TEST_DIR/nbd-fault-injector.out" $PYTHON nbd-fault-injector.py $extra_args "$nbd_addr" "$TEST_DIR/nbd-fault-injector.conf" >"$TEST_DIR/nbd-fault-injector.out" 2>&1 & # Wait for server to be ready @@ -94,7 +95,8 @@ EOF done # Extract the final address (port number has now been assigned in tcp case) - nbd_addr=$(sed 's/Listening on \(.*\)$/\1/' "$TEST_DIR/nbd-fault-injector.out") + nbd_addr=$(sed -n 's/^Listening on //p' \ + "$TEST_DIR/nbd-fault-injector.out") if [ "$proto" = "tcp" ]; then nbd_url="nbd+tcp://$nbd_addr/$export_name" diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093 index ef3997206b..5c36a5fb4d 100755 --- a/tests/qemu-iotests/093 +++ b/tests/qemu-iotests/093 @@ -308,6 +308,68 @@ class ThrottleTestGroupNames(iotests.QMPTestCase): groupname = "group%d" % i self.verify_name(devname, groupname) +class ThrottleTestRemovableMedia(iotests.QMPTestCase): + def setUp(self): + self.vm = iotests.VM() + if iotests.qemu_default_machine == 's390-ccw-virtio': + self.vm.add_device("virtio-scsi-ccw,id=virtio-scsi") + else: + self.vm.add_device("virtio-scsi-pci,id=virtio-scsi") + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + + def test_removable_media(self): + # Add a couple of dummy nodes named cd0 and cd1 + result = self.vm.qmp("blockdev-add", driver="null-aio", + node_name="cd0") + self.assert_qmp(result, 'return', {}) + result = self.vm.qmp("blockdev-add", driver="null-aio", + node_name="cd1") + self.assert_qmp(result, 'return', {}) + + # Attach a CD drive with cd0 inserted + result = self.vm.qmp("device_add", driver="scsi-cd", + id="dev0", drive="cd0") + self.assert_qmp(result, 'return', {}) + + # Set I/O limits + args = { "id": "dev0", "iops": 100, "iops_rd": 0, "iops_wr": 0, + "bps": 50, "bps_rd": 0, "bps_wr": 0 } + result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **args) + self.assert_qmp(result, 'return', {}) + + # Check that the I/O limits have been set + result = self.vm.qmp("query-block") + self.assert_qmp(result, 'return[0]/inserted/iops', 100) + self.assert_qmp(result, 'return[0]/inserted/bps', 50) + + # 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') + self.assert_qmp(result, 'return', {}) + result = self.vm.qmp("x-blockdev-insert-medium", id='dev0', node_name='cd1') + self.assert_qmp(result, 'return', {}) + + # Check that the I/O limits are still the same + result = self.vm.qmp("query-block") + self.assert_qmp(result, 'return[0]/inserted/iops', 100) + self.assert_qmp(result, 'return[0]/inserted/bps', 50) + + # Eject cd1 + result = self.vm.qmp("x-blockdev-remove-medium", id='dev0') + self.assert_qmp(result, 'return', {}) + + # Check that we can't set limits if the device has no medium + result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **args) + self.assert_qmp(result, 'error/class', 'GenericError') + + # Remove the CD drive + result = self.vm.qmp("device_del", id='dev0') + self.assert_qmp(result, 'return', {}) + if __name__ == '__main__': iotests.main(supported_fmts=["raw"]) diff --git a/tests/qemu-iotests/093.out b/tests/qemu-iotests/093.out index 2f7d3902f2..594c16f49f 100644 --- a/tests/qemu-iotests/093.out +++ b/tests/qemu-iotests/093.out @@ -1,5 +1,5 @@ -....... +........ ---------------------------------------------------------------------- -Ran 7 tests +Ran 8 tests OK diff --git a/tests/qemu-iotests/136 b/tests/qemu-iotests/136 index 4b994897af..88b97ea7c6 100644 --- a/tests/qemu-iotests/136 +++ b/tests/qemu-iotests/136 @@ -238,6 +238,18 @@ sector = "%d" for i in range(failed_wr_ops): ops.append("aio_write %d 512" % bad_offset) + # We need an extra aio_flush to settle all outstanding AIO + # operations before we can advance the virtual clock, so that + # the last access happens before clock_step and idle_time_ns + # will be greater than 0 + extra_flush = 0 + if rd_ops + wr_ops + invalid_rd_ops + invalid_wr_ops + \ + failed_rd_ops + failed_wr_ops > 0: + extra_flush = 1 + + if extra_flush > 0: + ops.append("aio_flush") + if failed_wr_ops > 0: highest_offset = max(highest_offset, bad_offset + 512) @@ -251,7 +263,7 @@ sector = "%d" self.total_wr_bytes += wr_ops * wr_size self.total_wr_ops += wr_ops self.total_wr_merged += wr_merged - self.total_flush_ops += flush_ops + self.total_flush_ops += flush_ops + extra_flush self.invalid_rd_ops += invalid_rd_ops self.invalid_wr_ops += invalid_wr_ops self.failed_rd_ops += failed_rd_ops diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140 index f89d0d6789..a8fc95145c 100755 --- a/tests/qemu-iotests/140 +++ b/tests/qemu-iotests/140 @@ -78,7 +78,7 @@ _send_qemu_cmd $QEMU_HANDLE \ 'arguments': { 'device': 'drv' }}" \ 'return' -$QEMU_IO_PROG -f raw -c 'read -P 42 0 64k' \ +$QEMU_IO_PROG -f raw -r -c 'read -P 42 0 64k' \ "nbd+unix:///drv?socket=$TEST_DIR/nbd" 2>&1 \ | _filter_qemu_io | _filter_nbd @@ -87,7 +87,7 @@ _send_qemu_cmd $QEMU_HANDLE \ 'arguments': { 'device': 'drv' }}" \ 'return' -$QEMU_IO_PROG -f raw -c close \ +$QEMU_IO_PROG -f raw -r -c close \ "nbd+unix:///drv?socket=$TEST_DIR/nbd" 2>&1 \ | _filter_qemu_io | _filter_nbd diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147 index db34838cd0..90f40ed245 100755 --- a/tests/qemu-iotests/147 +++ b/tests/qemu-iotests/147 @@ -43,6 +43,7 @@ class NBDBlockdevAddBase(iotests.QMPTestCase): 'driver': 'raw', 'file': { 'driver': 'nbd', + 'read-only': True, 'server': address } } if export is not None: diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194 index 8d973b440f..1d4214aca3 100755 --- a/tests/qemu-iotests/194 +++ b/tests/qemu-iotests/194 @@ -21,7 +21,7 @@ import iotests -iotests.verify_image_format(unsupported_fmts=['luks']) +iotests.verify_image_format(supported_fmts=['qcow2', 'qed', 'raw', 'dmg']) iotests.verify_platform(['linux']) with iotests.FilePath('source.img') as source_img_path, \ diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 0e8a33c696..dbae7d74ba 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -242,7 +242,7 @@ _make_test_img() if [ $IMGPROTO = "nbd" ]; then # Pass a sufficiently high number to -e that should be enough for all # tests - eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT -e 42 $TEST_IMG_FILE >/dev/null &" + eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT -e 42 -x '' $TEST_IMG_FILE >/dev/null &" sleep 1 # FIXME: qemu-nbd needs to be listening before we continue fi diff --git a/tests/test-aio-multithread.c b/tests/test-aio-multithread.c index 549d784915..d396185972 100644 --- a/tests/test-aio-multithread.c +++ b/tests/test-aio-multithread.c @@ -144,17 +144,16 @@ static void finish_cb(void *opaque) static coroutine_fn void test_multi_co_schedule_entry(void *opaque) { g_assert(to_schedule[id] == NULL); - atomic_mb_set(&to_schedule[id], qemu_coroutine_self()); while (!atomic_mb_read(&now_stopping)) { int n; n = g_test_rand_int_range(0, NUM_CONTEXTS); schedule_next(n); - qemu_coroutine_yield(); - g_assert(to_schedule[id] == NULL); atomic_mb_set(&to_schedule[id], qemu_coroutine_self()); + qemu_coroutine_yield(); + g_assert(to_schedule[id] == NULL); } } diff --git a/ui/console-gl.c b/ui/console-gl.c index 5b77e7aa88..a56e1cd8eb 100644 --- a/ui/console-gl.c +++ b/ui/console-gl.c @@ -48,7 +48,7 @@ void surface_gl_create_texture(QemuGLShader *gls, DisplaySurface *surface) { assert(gls); - assert(surface_stride(surface) % surface_bytes_per_pixel(surface) == 0); + assert(QEMU_IS_ALIGNED(surface_stride(surface), surface_bytes_per_pixel(surface))); switch (surface->format) { case PIXMAN_BE_b8g8r8x8: diff --git a/ui/console.c b/ui/console.c index eca854cbd5..c4c95abed7 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1471,6 +1471,7 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl) dcl->con->dcls--; } QLIST_REMOVE(dcl, next); + dcl->ds = NULL; gui_setup_refresh(ds); } diff --git a/util/async.c b/util/async.c index 355af73ee7..0e1bd8780a 100644 --- a/util/async.c +++ b/util/async.c @@ -174,7 +174,7 @@ void qemu_bh_schedule(QEMUBH *bh) */ void qemu_bh_cancel(QEMUBH *bh) { - bh->scheduled = 0; + atomic_mb_set(&bh->scheduled, 0); } /* This func is async.The bottom half will do the delete action at the finial diff --git a/vl.c b/vl.c index ec299099ff..7372424fa7 100644 --- a/vl.c +++ b/vl.c @@ -160,8 +160,8 @@ Chardev *virtcon_hds[MAX_VIRTIO_CONSOLES]; Chardev *sclp_hds[MAX_SCLP_CONSOLES]; int win2k_install_hack = 0; int singlestep = 0; -int smp_cpus = 1; -unsigned int max_cpus = 1; +int smp_cpus; +unsigned int max_cpus; int smp_cores = 1; int smp_threads = 1; int acpi_enabled = 1; @@ -4327,9 +4327,24 @@ int main(int argc, char **argv, char **envp) exit(0); } + /* machine_class: default to UP */ + machine_class->max_cpus = machine_class->max_cpus ?: 1; + machine_class->min_cpus = machine_class->min_cpus ?: 1; + machine_class->default_cpus = machine_class->default_cpus ?: 1; + + /* default to machine_class->default_cpus */ + smp_cpus = machine_class->default_cpus; + max_cpus = machine_class->default_cpus; + smp_parse(qemu_opts_find(qemu_find_opts("smp-opts"), NULL)); - machine_class->max_cpus = machine_class->max_cpus ?: 1; /* Default to UP */ + /* sanity-check smp_cpus and max_cpus against machine_class */ + if (smp_cpus < machine_class->min_cpus) { + error_report("Invalid SMP CPUs %d. The min CPUs " + "supported by machine '%s' is %d", smp_cpus, + machine_class->name, machine_class->min_cpus); + exit(1); + } if (max_cpus > machine_class->max_cpus) { error_report("Invalid SMP CPUs %d. The max CPUs " "supported by machine '%s' is %d", max_cpus, |