diff options
123 files changed, 5678 insertions, 991 deletions
diff --git a/aio-posix.c b/aio-posix.c index d3ac06e238..cbd4c3438c 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -73,7 +73,7 @@ void aio_set_fd_handler(AioContext *ctx, } else { if (node == NULL) { /* Alloc and insert if it's not already there */ - node = g_malloc0(sizeof(AioHandler)); + node = g_new0(AioHandler, 1); node->pfd.fd = fd; QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node); diff --git a/aio-win32.c b/aio-win32.c index d81313b00b..e6f4cedf48 100644 --- a/aio-win32.c +++ b/aio-win32.c @@ -67,7 +67,7 @@ void aio_set_fd_handler(AioContext *ctx, if (node == NULL) { /* Alloc and insert if it's not already there */ - node = g_malloc0(sizeof(AioHandler)); + node = g_new0(AioHandler, 1); node->pfd.fd = fd; QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node); } @@ -129,7 +129,7 @@ void aio_set_event_notifier(AioContext *ctx, } else { if (node == NULL) { /* Alloc and insert if it's not already there */ - node = g_malloc0(sizeof(AioHandler)); + node = g_new0(AioHandler, 1); node->e = e; node->pfd.fd = (uintptr_t)event_notifier_get_handle(e); node->pfd.events = G_IO_IN; @@ -44,7 +44,7 @@ struct QEMUBH { QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque) { QEMUBH *bh; - bh = g_malloc0(sizeof(QEMUBH)); + bh = g_new0(QEMUBH, 1); bh->ctx = ctx; bh->cb = cb; bh->opaque = opaque; @@ -629,7 +629,7 @@ BlockDriver *bdrv_find_protocol(const char *filename, } if (!path_has_protocol(filename) || !allow_protocol_prefix) { - return bdrv_find_format("file"); + return &bdrv_file; } p = strchr(filename, ':'); @@ -648,22 +648,49 @@ BlockDriver *bdrv_find_protocol(const char *filename, return NULL; } +/* + * Guess image format by probing its contents. + * This is not a good idea when your image is raw (CVE-2008-2004), but + * we do it anyway for backward compatibility. + * + * @buf contains the image's first @buf_size bytes. + * @buf_size is the buffer size in bytes (generally BLOCK_PROBE_BUF_SIZE, + * but can be smaller if the image file is smaller) + * @filename is its filename. + * + * For all block drivers, call the bdrv_probe() method to get its + * probing score. + * Return the first block driver with the highest probing score. + */ +BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, + const char *filename) +{ + int score_max = 0, score; + BlockDriver *drv = NULL, *d; + + QLIST_FOREACH(d, &bdrv_drivers, list) { + if (d->bdrv_probe) { + score = d->bdrv_probe(buf, buf_size, filename); + if (score > score_max) { + score_max = score; + drv = d; + } + } + } + + return drv; +} + static int find_image_format(BlockDriverState *bs, const char *filename, BlockDriver **pdrv, Error **errp) { - int score, score_max; - BlockDriver *drv1, *drv; - uint8_t buf[2048]; + BlockDriver *drv; + uint8_t buf[BLOCK_PROBE_BUF_SIZE]; int ret = 0; /* Return the raw BlockDriver * to scsi-generic devices or empty drives */ if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) { - drv = bdrv_find_format("raw"); - if (!drv) { - error_setg(errp, "Could not find raw image format"); - ret = -ENOENT; - } - *pdrv = drv; + *pdrv = &bdrv_raw; return ret; } @@ -675,17 +702,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename, return ret; } - score_max = 0; - drv = NULL; - QLIST_FOREACH(drv1, &bdrv_drivers, list) { - if (drv1->bdrv_probe) { - score = drv1->bdrv_probe(buf, ret, filename); - if (score > score_max) { - score_max = score; - drv = drv1; - } - } - } + drv = bdrv_probe_all(buf, ret, filename); if (!drv) { error_setg(errp, "Could not determine image format: No compatible " "driver found"); @@ -1180,7 +1197,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) { char *backing_filename = g_malloc0(PATH_MAX); int ret = 0; - BlockDriver *back_drv = NULL; BlockDriverState *backing_hd; Error *local_err = NULL; @@ -1213,14 +1229,14 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) backing_hd = bdrv_new(); - if (bs->backing_format[0] != '\0') { - back_drv = bdrv_find_format(bs->backing_format); + if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) { + qdict_put(options, "driver", qstring_from_str(bs->backing_format)); } assert(bs->backing_hd == NULL); ret = bdrv_open(&backing_hd, *backing_filename ? backing_filename : NULL, NULL, options, - bdrv_backing_flags(bs->open_flags), back_drv, &local_err); + bdrv_backing_flags(bs->open_flags), NULL, &local_err); if (ret < 0) { bdrv_unref(backing_hd); backing_hd = NULL; @@ -1294,7 +1310,6 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ char *tmp_filename = g_malloc0(PATH_MAX + 1); int64_t total_size; - BlockDriver *bdrv_qcow2; QemuOpts *opts = NULL; QDict *snapshot_options; BlockDriverState *bs_snapshot; @@ -1319,11 +1334,10 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) goto out; } - bdrv_qcow2 = bdrv_find_format("qcow2"); - opts = qemu_opts_create(bdrv_qcow2->create_opts, NULL, 0, + opts = qemu_opts_create(bdrv_qcow2.create_opts, NULL, 0, &error_abort); qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size); - ret = bdrv_create(bdrv_qcow2, tmp_filename, opts, &local_err); + ret = bdrv_create(&bdrv_qcow2, tmp_filename, opts, &local_err); qemu_opts_del(opts); if (ret < 0) { error_setg_errno(errp, -ret, "Could not create temporary overlay " @@ -1343,7 +1357,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) bs_snapshot = bdrv_new(); ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options, - flags, bdrv_qcow2, &local_err); + flags, &bdrv_qcow2, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; @@ -1467,6 +1481,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, } /* Image format probing */ + bs->probed = !drv; if (!drv && file) { ret = find_image_format(file, filename, &drv, &local_err); if (ret < 0) { @@ -3801,6 +3816,14 @@ bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base) return top != NULL; } +BlockDriverState *bdrv_next_node(BlockDriverState *bs) +{ + if (!bs) { + return QTAILQ_FIRST(&graph_bdrv_states); + } + return QTAILQ_NEXT(bs, node_list); +} + BlockDriverState *bdrv_next(BlockDriverState *bs) { if (!bs) { @@ -3809,6 +3832,11 @@ BlockDriverState *bdrv_next(BlockDriverState *bs) return QTAILQ_NEXT(bs, device_list); } +const char *bdrv_get_node_name(const BlockDriverState *bs) +{ + return bs->node_name; +} + /* TODO check what callers really want: bs->node_name or blk_name() */ const char *bdrv_get_device_name(const BlockDriverState *bs) { @@ -5541,6 +5569,18 @@ void bdrv_img_create(const char *filename, const char *fmt, return; } + if (!drv->create_opts) { + error_setg(errp, "Format driver '%s' does not support image creation", + drv->format_name); + return; + } + + if (!proto_drv->create_opts) { + error_setg(errp, "Protocol driver '%s' does not support image creation", + proto_drv->format_name); + return; + } + create_opts = qemu_opts_append(create_opts, drv->create_opts); create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); diff --git a/block/accounting.c b/block/accounting.c index edbb1cc89f..18102f015d 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -24,6 +24,7 @@ #include "block/accounting.h" #include "block/block_int.h" +#include "qemu/timer.h" void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, int64_t bytes, enum BlockAcctType type) @@ -31,7 +32,7 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, assert(type < BLOCK_MAX_IOTYPE); cookie->bytes = bytes; - cookie->start_time_ns = get_clock(); + cookie->start_time_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); cookie->type = type; } @@ -41,7 +42,8 @@ void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie) stats->nr_bytes[cookie->type] += cookie->bytes; stats->nr_ops[cookie->type]++; - stats->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns; + stats->total_time_ns[cookie->type] += + qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - cookie->start_time_ns; } diff --git a/block/blkdebug.c b/block/blkdebug.c index 862d93b59b..9ce35cd035 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -721,93 +721,50 @@ static int64_t blkdebug_getlength(BlockDriverState *bs) static void blkdebug_refresh_filename(BlockDriverState *bs) { - BDRVBlkdebugState *s = bs->opaque; - struct BlkdebugRule *rule; QDict *opts; - QList *inject_error_list = NULL, *set_state_list = NULL; - QList *suspend_list = NULL; - int event; + const QDictEntry *e; + bool force_json = false; + + for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) { + if (strcmp(qdict_entry_key(e), "config") && + strcmp(qdict_entry_key(e), "x-image") && + strcmp(qdict_entry_key(e), "image") && + strncmp(qdict_entry_key(e), "image.", strlen("image."))) + { + force_json = true; + break; + } + } - if (!bs->file->full_open_options) { + if (force_json && !bs->file->full_open_options) { /* The config file cannot be recreated, so creating a plain filename * is impossible */ return; } + if (!force_json && bs->file->exact_filename[0]) { + snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "blkdebug:%s:%s", + qdict_get_try_str(bs->options, "config") ?: "", + bs->file->exact_filename); + } + opts = qdict_new(); qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug"))); QINCREF(bs->file->full_open_options); qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options)); - for (event = 0; event < BLKDBG_EVENT_MAX; event++) { - QLIST_FOREACH(rule, &s->rules[event], next) { - if (rule->action == ACTION_INJECT_ERROR) { - QDict *inject_error = qdict_new(); - - qdict_put_obj(inject_error, "event", QOBJECT(qstring_from_str( - BlkdebugEvent_lookup[rule->event]))); - qdict_put_obj(inject_error, "state", - QOBJECT(qint_from_int(rule->state))); - qdict_put_obj(inject_error, "errno", QOBJECT(qint_from_int( - rule->options.inject.error))); - qdict_put_obj(inject_error, "sector", QOBJECT(qint_from_int( - rule->options.inject.sector))); - qdict_put_obj(inject_error, "once", QOBJECT(qbool_from_int( - rule->options.inject.once))); - qdict_put_obj(inject_error, "immediately", - QOBJECT(qbool_from_int( - rule->options.inject.immediately))); - - if (!inject_error_list) { - inject_error_list = qlist_new(); - } - - qlist_append_obj(inject_error_list, QOBJECT(inject_error)); - } else if (rule->action == ACTION_SET_STATE) { - QDict *set_state = qdict_new(); - - qdict_put_obj(set_state, "event", QOBJECT(qstring_from_str( - BlkdebugEvent_lookup[rule->event]))); - qdict_put_obj(set_state, "state", - QOBJECT(qint_from_int(rule->state))); - qdict_put_obj(set_state, "new_state", QOBJECT(qint_from_int( - rule->options.set_state.new_state))); - - if (!set_state_list) { - set_state_list = qlist_new(); - } - - qlist_append_obj(set_state_list, QOBJECT(set_state)); - } else if (rule->action == ACTION_SUSPEND) { - QDict *suspend = qdict_new(); - - qdict_put_obj(suspend, "event", QOBJECT(qstring_from_str( - BlkdebugEvent_lookup[rule->event]))); - qdict_put_obj(suspend, "state", - QOBJECT(qint_from_int(rule->state))); - qdict_put_obj(suspend, "tag", QOBJECT(qstring_from_str( - rule->options.suspend.tag))); - - if (!suspend_list) { - suspend_list = qlist_new(); - } - - qlist_append_obj(suspend_list, QOBJECT(suspend)); - } + for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) { + if (strcmp(qdict_entry_key(e), "x-image") && + strcmp(qdict_entry_key(e), "image") && + strncmp(qdict_entry_key(e), "image.", strlen("image."))) + { + qobject_incref(qdict_entry_value(e)); + qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); } } - if (inject_error_list) { - qdict_put_obj(opts, "inject-error", QOBJECT(inject_error_list)); - } - if (set_state_list) { - qdict_put_obj(opts, "set-state", QOBJECT(set_state_list)); - } - if (suspend_list) { - qdict_put_obj(opts, "suspend", QOBJECT(suspend_list)); - } - bs->full_open_options = opts; } diff --git a/block/block-backend.c b/block/block-backend.c index d0692b18e9..ef16d7356a 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -497,6 +497,16 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque); } +int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors) +{ + return bdrv_co_discard(blk->bs, sector_num, nb_sectors); +} + +int blk_co_flush(BlockBackend *blk) +{ + return bdrv_co_flush(blk->bs); +} + int blk_flush(BlockBackend *blk) { return bdrv_flush(blk->bs); @@ -549,6 +559,11 @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce) bdrv_set_enable_write_cache(blk->bs, wce); } +void blk_invalidate_cache(BlockBackend *blk, Error **errp) +{ + bdrv_invalidate_cache(blk->bs, errp); +} + int blk_is_inserted(BlockBackend *blk) { return bdrv_is_inserted(blk->bs); @@ -609,6 +624,29 @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) bdrv_set_aio_context(blk->bs, new_context); } +void blk_add_aio_context_notifier(BlockBackend *blk, + void (*attached_aio_context)(AioContext *new_context, void *opaque), + void (*detach_aio_context)(void *opaque), void *opaque) +{ + bdrv_add_aio_context_notifier(blk->bs, attached_aio_context, + detach_aio_context, opaque); +} + +void blk_remove_aio_context_notifier(BlockBackend *blk, + void (*attached_aio_context)(AioContext *, + void *), + void (*detach_aio_context)(void *), + void *opaque) +{ + bdrv_remove_aio_context_notifier(blk->bs, attached_aio_context, + detach_aio_context, opaque); +} + +void blk_add_close_notifier(BlockBackend *blk, Notifier *notify) +{ + bdrv_add_close_notifier(blk->bs, notify); +} + void blk_io_plug(BlockBackend *blk) { bdrv_io_plug(blk->bs); diff --git a/block/nfs.c b/block/nfs.c index c76e368b95..ca9e24efe5 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -409,6 +409,19 @@ out: return ret; } +static QemuOptsList nfs_create_opts = { + .name = "nfs-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(nfs_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { /* end of list */ } + } +}; + static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp) { int ret = 0; @@ -470,6 +483,8 @@ static BlockDriver bdrv_nfs = { .instance_size = sizeof(NFSClient), .bdrv_needs_filename = true, + .create_opts = &nfs_create_opts, + .bdrv_has_zero_init = nfs_has_zero_init, .bdrv_get_allocated_file_size = nfs_get_allocated_file_size, .bdrv_truncate = nfs_file_truncate, diff --git a/block/qapi.c b/block/qapi.c index a87a34a8b4..fa68ba731f 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -40,6 +40,13 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs) info->encrypted = bs->encrypted; info->encryption_key_missing = bdrv_key_required(bs); + info->cache = g_new(BlockdevCacheInfo, 1); + *info->cache = (BlockdevCacheInfo) { + .writeback = bdrv_enable_write_cache(bs), + .direct = !!(bs->open_flags & BDRV_O_NOCACHE), + .no_flush = !!(bs->open_flags & BDRV_O_NO_FLUSH), + }; + if (bs->node_name[0]) { info->has_node_name = true; info->node_name = g_strdup(bs->node_name); @@ -300,7 +307,8 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, qapi_free_BlockInfo(info); } -static BlockStats *bdrv_query_stats(const BlockDriverState *bs) +static BlockStats *bdrv_query_stats(const BlockDriverState *bs, + bool query_backing) { BlockStats *s; @@ -311,6 +319,11 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs) s->device = g_strdup(bdrv_get_device_name(bs)); } + if (bdrv_get_node_name(bs)[0]) { + s->has_node_name = true; + s->node_name = g_strdup(bdrv_get_node_name(bs)); + } + s->stats = g_malloc0(sizeof(*s->stats)); s->stats->rd_bytes = bs->stats.nr_bytes[BLOCK_ACCT_READ]; s->stats->wr_bytes = bs->stats.nr_bytes[BLOCK_ACCT_WRITE]; @@ -325,12 +338,12 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs) if (bs->file) { s->has_parent = true; - s->parent = bdrv_query_stats(bs->file); + s->parent = bdrv_query_stats(bs->file, query_backing); } - if (bs->backing_hd) { + if (query_backing && bs->backing_hd) { s->has_backing = true; - s->backing = bdrv_query_stats(bs->backing_hd); + s->backing = bdrv_query_stats(bs->backing_hd, query_backing); } return s; @@ -361,17 +374,22 @@ BlockInfoList *qmp_query_block(Error **errp) return NULL; } -BlockStatsList *qmp_query_blockstats(Error **errp) +BlockStatsList *qmp_query_blockstats(bool has_query_nodes, + bool query_nodes, + Error **errp) { BlockStatsList *head = NULL, **p_next = &head; BlockDriverState *bs = NULL; - while ((bs = bdrv_next(bs))) { + /* Just to be safe if query_nodes is not always initialized */ + query_nodes = has_query_nodes && query_nodes; + + while ((bs = query_nodes ? bdrv_next_node(bs) : bdrv_next(bs))) { BlockStatsList *info = g_malloc0(sizeof(*info)); AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); - info->value = bdrv_query_stats(bs); + info->value = bdrv_query_stats(bs, !query_nodes); aio_context_release(ctx); *p_next = info; diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index df0b2c9cec..1fea5142d0 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1263,7 +1263,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, again: start = offset; - remaining = *num << BDRV_SECTOR_BITS; + remaining = (uint64_t)*num << BDRV_SECTOR_BITS; cluster_offset = 0; *host_offset = 0; cur_bytes = 0; diff --git a/block/qcow2.c b/block/qcow2.c index d12049451a..e4e690a42b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -117,7 +117,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, #ifdef DEBUG_EXT printf("ext.magic = 0x%x\n", ext.magic); #endif - if (ext.len > end_offset - offset) { + if (offset > end_offset || ext.len > end_offset - offset) { error_setg(errp, "Header extension too large"); return -EINVAL; } @@ -1428,10 +1428,23 @@ static void qcow2_close(BlockDriverState *bs) s->l1_table = NULL; if (!(bs->open_flags & BDRV_O_INCOMING)) { - qcow2_cache_flush(bs, s->l2_table_cache); - qcow2_cache_flush(bs, s->refcount_block_cache); + int ret1, ret2; - qcow2_mark_clean(bs); + ret1 = qcow2_cache_flush(bs, s->l2_table_cache); + ret2 = qcow2_cache_flush(bs, s->refcount_block_cache); + + if (ret1) { + error_report("Failed to flush the L2 table cache: %s", + strerror(-ret1)); + } + if (ret2) { + error_report("Failed to flush the refcount block cache: %s", + strerror(-ret2)); + } + + if (!ret1 && !ret2) { + qcow2_mark_clean(bs); + } } qcow2_cache_destroy(bs, s->l2_table_cache); @@ -1915,10 +1928,9 @@ static int qcow2_create2(const char *filename, int64_t total_size, * refcount of the cluster that is occupied by the header and the refcount * table) */ - BlockDriver* drv = bdrv_find_format("qcow2"); - assert(drv != NULL); ret = bdrv_open(&bs, filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err); + BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, + &bdrv_qcow2, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; @@ -1970,7 +1982,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */ ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING, - drv, &local_err); + &bdrv_qcow2, &local_err); if (local_err) { error_propagate(errp, local_err); goto out; @@ -2150,8 +2162,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num, /* align end of file to a sector boundary to ease reading with sector based I/Os */ cluster_offset = bdrv_getlength(bs->file); - bdrv_truncate(bs->file, cluster_offset); - return 0; + return bdrv_truncate(bs->file, cluster_offset); } if (nb_sectors != s->cluster_sectors) { @@ -2847,7 +2858,7 @@ static QemuOptsList qcow2_create_opts = { } }; -static BlockDriver bdrv_qcow2 = { +BlockDriver bdrv_qcow2 = { .format_name = "qcow2", .instance_size = sizeof(BDRVQcowState), .bdrv_probe = qcow2_probe, diff --git a/block/raw-posix.c b/block/raw-posix.c index b1af77e47f..e51293a455 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -446,6 +446,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, } if (fstat(s->fd, &st) < 0) { + ret = -errno; error_setg_errno(errp, errno, "Could not stat file"); goto fail; } @@ -1684,7 +1685,7 @@ static QemuOptsList raw_create_opts = { } }; -static BlockDriver bdrv_file = { +BlockDriver bdrv_file = { .format_name = "file", .protocol_name = "file", .instance_size = sizeof(BDRVRawState), @@ -1922,7 +1923,7 @@ static int fd_open(BlockDriverState *bs) return 0; last_media_present = (s->fd >= 0); if (s->fd >= 0 && - (get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) { + (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_open_time) >= FD_OPEN_TIMEOUT) { qemu_close(s->fd); s->fd = -1; #ifdef DEBUG_FLOPPY @@ -1931,7 +1932,7 @@ static int fd_open(BlockDriverState *bs) } if (s->fd < 0) { if (s->fd_got_error && - (get_clock() - s->fd_error_time) < FD_OPEN_TIMEOUT) { + (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_error_time) < FD_OPEN_TIMEOUT) { #ifdef DEBUG_FLOPPY printf("No floppy (open delayed)\n"); #endif @@ -1939,7 +1940,7 @@ static int fd_open(BlockDriverState *bs) } s->fd = qemu_open(bs->filename, s->open_flags & ~O_NONBLOCK); if (s->fd < 0) { - s->fd_error_time = get_clock(); + s->fd_error_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); s->fd_got_error = 1; if (last_media_present) s->fd_media_changed = 1; @@ -1954,7 +1955,7 @@ static int fd_open(BlockDriverState *bs) } if (!last_media_present) s->fd_media_changed = 1; - s->fd_open_time = get_clock(); + s->fd_open_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); s->fd_got_error = 0; return 0; } diff --git a/block/raw-win32.c b/block/raw-win32.c index 7b588815b9..06243d76df 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -540,7 +540,7 @@ static QemuOptsList raw_create_opts = { } }; -static BlockDriver bdrv_file = { +BlockDriver bdrv_file = { .format_name = "file", .protocol_name = "file", .instance_size = sizeof(BDRVRawState), diff --git a/block/raw_bsd.c b/block/raw_bsd.c index 401b967e85..05b02c76d4 100644 --- a/block/raw_bsd.c +++ b/block/raw_bsd.c @@ -58,8 +58,58 @@ static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) { + void *buf = NULL; + BlockDriver *drv; + QEMUIOVector local_qiov; + int ret; + + if (bs->probed && sector_num == 0) { + /* As long as these conditions are true, we can't get partial writes to + * the probe buffer and can just directly check the request. */ + QEMU_BUILD_BUG_ON(BLOCK_PROBE_BUF_SIZE != 512); + QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != 512); + + if (nb_sectors == 0) { + /* qemu_iovec_to_buf() would fail, but we want to return success + * instead of -EINVAL in this case. */ + return 0; + } + + buf = qemu_try_blockalign(bs->file, 512); + if (!buf) { + ret = -ENOMEM; + goto fail; + } + + ret = qemu_iovec_to_buf(qiov, 0, buf, 512); + if (ret != 512) { + ret = -EINVAL; + goto fail; + } + + drv = bdrv_probe_all(buf, 512, NULL); + if (drv != bs->drv) { + ret = -EPERM; + goto fail; + } + + /* Use the checked buffer, a malicious guest might be overwriting its + * original buffer in the background. */ + qemu_iovec_init(&local_qiov, qiov->niov + 1); + qemu_iovec_add(&local_qiov, buf, 512); + qemu_iovec_concat(&local_qiov, qiov, 512, qiov->size - 512); + qiov = &local_qiov; + } + BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); - return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov); + ret = bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov); + +fail: + if (qiov == &local_qiov) { + qemu_iovec_destroy(&local_qiov); + } + qemu_vfree(buf); + return ret; } static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, @@ -158,6 +208,18 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { bs->sg = bs->file->sg; + + if (bs->probed && !bdrv_is_read_only(bs)) { + fprintf(stderr, + "WARNING: Image format was not specified for '%s' and probing " + "guessed raw.\n" + " Automatically detecting the format is dangerous for " + "raw images, write operations on block 0 will be restricted.\n" + " Specify the 'raw' format explicitly to remove the " + "restrictions.\n", + bs->file->filename); + } + return 0; } @@ -173,7 +235,7 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) return 1; } -static BlockDriver bdrv_raw = { +BlockDriver bdrv_raw = { .format_name = "raw", .bdrv_probe = &raw_probe, .bdrv_reopen_prepare = &raw_reopen_prepare, diff --git a/block/vdi.c b/block/vdi.c index 39070b75e8..74030c6e30 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -852,11 +852,6 @@ static QemuOptsList vdi_create_opts = { .def_value_str = "off" }, #endif - { - .name = BLOCK_OPT_NOCOW, - .type = QEMU_OPT_BOOL, - .help = "Turn off copy-on-write (valid only on btrfs)" - }, /* TODO: An additional option to set UUID values might be useful. */ { /* end of list */ } } diff --git a/block/vmdk.c b/block/vmdk.c index 2cbfd3e72e..65af414f3c 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -28,6 +28,7 @@ #include "qemu/module.h" #include "migration/migration.h" #include <zlib.h> +#include <glib.h> #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') @@ -556,8 +557,16 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, return NULL; } - size = MIN(size, 1 << 20); /* avoid unbounded allocation */ - buf = g_malloc0(size + 1); + if (size < 4) { + /* Both descriptor file and sparse image must be much larger than 4 + * bytes, also callers of vmdk_read_desc want to compare the first 4 + * bytes with VMDK4_MAGIC, let's error out if less is read. */ + error_setg(errp, "File is too small, not a valid image"); + return NULL; + } + + size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */ + buf = g_malloc(size + 1); ret = bdrv_pread(file, desc_offset, buf, size); if (ret < 0) { @@ -565,6 +574,7 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, g_free(buf); return NULL; } + buf[ret] = 0; return buf; } @@ -635,6 +645,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, bs->file->total_sectors * 512 - 1536, &footer, sizeof(footer)); if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to read footer"); return ret; } @@ -646,6 +657,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, le32_to_cpu(footer.eos_marker.size) != 0 || le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM) { + error_setg(errp, "Invalid footer"); return -EINVAL; } @@ -676,6 +688,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt) * le64_to_cpu(header.granularity); if (l1_entry_sectors == 0) { + error_setg(errp, "L1 entry size is invalid"); return -EINVAL; } l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) @@ -784,10 +797,12 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, VmdkExtent *extent; while (*p) { - /* parse extent line: + /* parse extent line in one of below formats: + * * RW [size in sectors] FLAT "file-name.vmdk" OFFSET - * or * RW [size in sectors] SPARSE "file-name.vmdk" + * RW [size in sectors] VMFS "file-name.vmdk" + * RW [size in sectors] VMFSSPARSE "file-name.vmdk" */ flat_offset = -1; ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, @@ -902,7 +917,7 @@ exit: static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { - char *buf = NULL; + char *buf; int ret; BDRVVmdkState *s = bs->opaque; uint32_t magic; @@ -1538,7 +1553,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, /* update CID on the first write every time the virtual disk is * opened */ if (!s->cid_updated) { - ret = vmdk_write_cid(bs, time(NULL)); + ret = vmdk_write_cid(bs, g_random_int()); if (ret < 0) { return ret; } @@ -1922,7 +1937,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) } /* generate descriptor file */ desc = g_strdup_printf(desc_template, - (uint32_t)time(NULL), + g_random_int(), parent_cid, fmt, parent_desc_line, diff --git a/block/vpc.c b/block/vpc.c index 38c4f02fff..46803b14be 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -893,11 +893,6 @@ static QemuOptsList vpc_create_opts = { "Type of virtual hard disk format. Supported formats are " "{dynamic (default) | fixed} " }, - { - .name = BLOCK_OPT_NOCOW, - .type = QEMU_OPT_BOOL, - .help = "Turn off copy-on-write (valid only on btrfs)" - }, { /* end of list */ } } }; diff --git a/block/vvfat.c b/block/vvfat.c index cefe3a4f79..e34a789699 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2917,6 +2917,12 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp) } bdrv_qcow = bdrv_find_format("qcow"); + if (!bdrv_qcow) { + error_setg(errp, "Failed to locate qcow driver"); + ret = -ENOENT; + goto err; + } + opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort); qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512); qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:"); diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 06f901ef6f..22e95d17ee 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -10,6 +10,7 @@ */ #include "sysemu/blockdev.h" +#include "sysemu/block-backend.h" #include "hw/block/block.h" #include "monitor/monitor.h" #include "qapi/qmp/qerror.h" @@ -73,7 +74,7 @@ static void nbd_close_notifier(Notifier *n, void *data) void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, Error **errp) { - BlockDriverState *bs; + BlockBackend *blk; NBDExport *exp; NBDCloseNotifier *n; @@ -87,12 +88,12 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, return; } - bs = bdrv_find(device); - if (!bs) { + blk = blk_by_name(device); + if (!blk) { error_set(errp, QERR_DEVICE_NOT_FOUND, device); return; } - if (!bdrv_is_inserted(bs)) { + if (!blk_is_inserted(blk)) { error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); return; } @@ -100,18 +101,18 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, if (!has_writable) { writable = false; } - if (bdrv_is_read_only(bs)) { + if (blk_is_read_only(blk)) { writable = false; } - exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL); + exp = nbd_export_new(blk, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL); nbd_export_set_name(exp, device); n = g_new0(NBDCloseNotifier, 1); n->n.notify = nbd_close_notifier; n->exp = exp; - bdrv_add_close_notifier(bs, &n->n); + blk_add_close_notifier(blk, &n->n); QTAILQ_INSERT_TAIL(&close_notifiers, n, next); } diff --git a/blockdev.c b/blockdev.c index 57910b82c7..5651a8e140 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1105,6 +1105,7 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, Error **errp) { BlockDriverState *bs = bdrv_find(device); + AioContext *aio_context; QEMUSnapshotInfo sn; Error *local_err = NULL; SnapshotInfo *info = NULL; @@ -1128,25 +1129,34 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, return NULL; } + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, errp)) { + goto out_aio_context; + } + ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err); if (local_err) { error_propagate(errp, local_err); - return NULL; + goto out_aio_context; } if (!ret) { error_setg(errp, "Snapshot with id '%s' and name '%s' does not exist on " "device '%s'", STR_OR_NULL(id), STR_OR_NULL(name), device); - return NULL; + goto out_aio_context; } bdrv_snapshot_delete(bs, id, name, &local_err); if (local_err) { error_propagate(errp, local_err); - return NULL; + goto out_aio_context; } + aio_context_release(aio_context); + info = g_new0(SnapshotInfo, 1); info->id = g_strdup(sn.id_str); info->name = g_strdup(sn.name); @@ -1157,9 +1167,13 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, info->vm_clock_sec = sn.vm_clock_nsec / 1000000000; return info; + +out_aio_context: + aio_context_release(aio_context); + return NULL; } -/* New and old BlockDriverState structs for group snapshots */ +/* New and old BlockDriverState structs for atomic group operations */ typedef struct BlkTransactionState BlkTransactionState; @@ -1193,6 +1207,7 @@ struct BlkTransactionState { typedef struct InternalSnapshotState { BlkTransactionState common; BlockDriverState *bs; + AioContext *aio_context; QEMUSnapshotInfo sn; } InternalSnapshotState; @@ -1226,11 +1241,19 @@ static void internal_snapshot_prepare(BlkTransactionState *common, return; } + /* AioContext is released in .clean() */ + state->aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(state->aio_context); + if (!bdrv_is_inserted(bs)) { error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); return; } + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) { + return; + } + if (bdrv_is_read_only(bs)) { error_set(errp, QERR_DEVICE_IS_READ_ONLY, device); return; @@ -1303,11 +1326,22 @@ static void internal_snapshot_abort(BlkTransactionState *common) } } +static void internal_snapshot_clean(BlkTransactionState *common) +{ + InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState, + common, common); + + if (state->aio_context) { + aio_context_release(state->aio_context); + } +} + /* external snapshot private data */ typedef struct ExternalSnapshotState { BlkTransactionState common; BlockDriverState *old_bs; BlockDriverState *new_bs; + AioContext *aio_context; } ExternalSnapshotState; static void external_snapshot_prepare(BlkTransactionState *common, @@ -1374,6 +1408,10 @@ static void external_snapshot_prepare(BlkTransactionState *common, return; } + /* Acquire AioContext now so any threads operating on old_bs stop */ + state->aio_context = bdrv_get_aio_context(state->old_bs); + aio_context_acquire(state->aio_context); + if (!bdrv_is_inserted(state->old_bs)) { error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); return; @@ -1432,6 +1470,8 @@ static void external_snapshot_commit(BlkTransactionState *common) ExternalSnapshotState *state = DO_UPCAST(ExternalSnapshotState, common, common); + bdrv_set_aio_context(state->new_bs, state->aio_context); + /* This removes our old bs and adds the new bs */ bdrv_append(state->new_bs, state->old_bs); /* We don't need (or want) to use the transactional @@ -1439,6 +1479,8 @@ static void external_snapshot_commit(BlkTransactionState *common) * don't want to abort all of them if one of them fails the reopen */ bdrv_reopen(state->new_bs, state->new_bs->open_flags & ~BDRV_O_RDWR, NULL); + + aio_context_release(state->aio_context); } static void external_snapshot_abort(BlkTransactionState *common) @@ -1448,23 +1490,38 @@ static void external_snapshot_abort(BlkTransactionState *common) if (state->new_bs) { bdrv_unref(state->new_bs); } + if (state->aio_context) { + aio_context_release(state->aio_context); + } } typedef struct DriveBackupState { BlkTransactionState common; BlockDriverState *bs; + AioContext *aio_context; BlockJob *job; } DriveBackupState; static void drive_backup_prepare(BlkTransactionState *common, Error **errp) { DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); + BlockDriverState *bs; DriveBackup *backup; Error *local_err = NULL; assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP); backup = common->action->drive_backup; + bs = bdrv_find(backup->device); + if (!bs) { + error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device); + return; + } + + /* AioContext is released in .clean() */ + state->aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(state->aio_context); + qmp_drive_backup(backup->device, backup->target, backup->has_format, backup->format, backup->sync, @@ -1475,12 +1532,10 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp) &local_err); if (local_err) { error_propagate(errp, local_err); - state->bs = NULL; - state->job = NULL; return; } - state->bs = bdrv_find(backup->device); + state->bs = bs; state->job = state->bs->job; } @@ -1495,6 +1550,15 @@ static void drive_backup_abort(BlkTransactionState *common) } } +static void drive_backup_clean(BlkTransactionState *common) +{ + DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); + + if (state->aio_context) { + aio_context_release(state->aio_context); + } +} + static void abort_prepare(BlkTransactionState *common, Error **errp) { error_setg(errp, "Transaction aborted using Abort action"); @@ -1516,6 +1580,7 @@ static const BdrvActionOps actions[] = { .instance_size = sizeof(DriveBackupState), .prepare = drive_backup_prepare, .abort = drive_backup_abort, + .clean = drive_backup_clean, }, [TRANSACTION_ACTION_KIND_ABORT] = { .instance_size = sizeof(BlkTransactionState), @@ -1526,13 +1591,13 @@ static const BdrvActionOps actions[] = { .instance_size = sizeof(InternalSnapshotState), .prepare = internal_snapshot_prepare, .abort = internal_snapshot_abort, + .clean = internal_snapshot_clean, }, }; /* - * 'Atomic' group snapshots. The snapshots are taken as a set, and if any fail - * then we do not pivot any of the devices in the group, and abandon the - * snapshots + * 'Atomic' group operations. The operations are performed as a set, and if + * any fail then we roll back all operations in the group. */ void qmp_transaction(TransactionActionList *dev_list, Error **errp) { @@ -1543,10 +1608,10 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp) QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionState) snap_bdrv_states; QSIMPLEQ_INIT(&snap_bdrv_states); - /* drain all i/o before any snapshots */ + /* drain all i/o before any operations */ bdrv_drain_all(); - /* We don't do anything in this loop that commits us to the snapshot */ + /* We don't do anything in this loop that commits us to the operations */ while (NULL != dev_entry) { TransactionAction *dev_info = NULL; const BdrvActionOps *ops; @@ -1581,10 +1646,7 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp) goto exit; delete_and_fail: - /* - * failure, and it is all-or-none; abandon each new bs, and keep using - * the original bs for all images - */ + /* failure, and it is all-or-none; roll back all operations */ QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) { if (state->ops->abort) { state->ops->abort(state); @@ -1603,14 +1665,18 @@ exit: static void eject_device(BlockBackend *blk, int force, Error **errp) { BlockDriverState *bs = blk_bs(blk); + AioContext *aio_context; + + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) { - return; + goto out; } if (!blk_dev_has_removable_media(blk)) { error_setg(errp, "Device '%s' is not removable", bdrv_get_device_name(bs)); - return; + goto out; } if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) { @@ -1618,11 +1684,14 @@ static void eject_device(BlockBackend *blk, int force, Error **errp) if (!force) { error_setg(errp, "Device '%s' is locked", bdrv_get_device_name(bs)); - return; + goto out; } } bdrv_close(bs); + +out: + aio_context_release(aio_context); } void qmp_eject(const char *device, bool has_force, bool force, Error **errp) @@ -1644,6 +1713,7 @@ void qmp_block_passwd(bool has_device, const char *device, { Error *local_err = NULL; BlockDriverState *bs; + AioContext *aio_context; int err; bs = bdrv_lookup_bs(has_device ? device : NULL, @@ -1654,16 +1724,23 @@ void qmp_block_passwd(bool has_device, const char *device, return; } + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + err = bdrv_set_key(bs, password); if (err == -EINVAL) { error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs)); - return; + goto out; } else if (err < 0) { error_set(errp, QERR_INVALID_PASSWORD); - return; + goto out; } + +out: + aio_context_release(aio_context); } +/* Assumes AioContext is held */ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename, int bdrv_flags, BlockDriver *drv, const char *password, Error **errp) @@ -1696,6 +1773,7 @@ void qmp_change_blockdev(const char *device, const char *filename, { BlockBackend *blk; BlockDriverState *bs; + AioContext *aio_context; BlockDriver *drv = NULL; int bdrv_flags; Error *err = NULL; @@ -1707,24 +1785,30 @@ void qmp_change_blockdev(const char *device, const char *filename, } bs = blk_bs(blk); + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + if (format) { drv = bdrv_find_whitelisted_format(format, bs->read_only); if (!drv) { error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); - return; + goto out; } } eject_device(blk, 0, &err); if (err) { error_propagate(errp, err); - return; + goto out; } bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR; bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0; qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp); + +out: + aio_context_release(aio_context); } /* throttling disk I/O limits */ @@ -2548,6 +2632,7 @@ void qmp_change_backing_file(const char *device, Error **errp) { BlockDriverState *bs = NULL; + AioContext *aio_context; BlockDriverState *image_bs = NULL; Error *local_err = NULL; bool ro; @@ -2561,34 +2646,37 @@ void qmp_change_backing_file(const char *device, return; } + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + goto out; } if (!image_bs) { error_setg(errp, "image file not found"); - return; + goto out; } if (bdrv_find_base(image_bs) == image_bs) { error_setg(errp, "not allowing backing file change on an image " "without a backing file"); - return; + goto out; } /* even though we are not necessarily operating on bs, we need it to * determine if block ops are currently prohibited on the chain */ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) { - return; + goto out; } /* final sanity check */ if (!bdrv_chain_contains(bs, image_bs)) { error_setg(errp, "'%s' and image file are not in the same chain", device); - return; + goto out; } /* if not r/w, reopen to make r/w */ @@ -2599,7 +2687,7 @@ void qmp_change_backing_file(const char *device, bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + goto out; } } @@ -2619,6 +2707,9 @@ void qmp_change_backing_file(const char *device, error_propagate(errp, local_err); /* will preserve prior errp */ } } + +out: + aio_context_release(aio_context); } void qmp_blockdev_add(BlockdevOptions *options, Error **errp) @@ -317,6 +317,8 @@ static GDBState *gdbserver_state; bool gdb_has_xml; +int semihosting_target = SEMIHOSTING_TARGET_AUTO; + #ifdef CONFIG_USER_ONLY /* XXX: This is not thread safe. Do we care? */ static int gdbserver_fd = -1; @@ -351,10 +353,19 @@ static enum { GDB_SYS_DISABLED, } gdb_syscall_mode; -/* If gdb is connected when the first semihosting syscall occurs then use - remote gdb syscalls. Otherwise use native file IO. */ +/* Decide if either remote gdb syscalls or native file IO should be used. */ int use_gdb_syscalls(void) { + if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) { + /* -semihosting-config target=native */ + return false; + } else if (semihosting_target == SEMIHOSTING_TARGET_GDB) { + /* -semihosting-config target=gdb */ + return true; + } + + /* -semihosting-config target=auto */ + /* On the first call check if gdb is connected and remember. */ if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED : GDB_SYS_DISABLED); @@ -290,14 +290,131 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict) qapi_free_CpuInfoList(cpu_list); } +static void print_block_info(Monitor *mon, BlockInfo *info, + BlockDeviceInfo *inserted, bool verbose) +{ + ImageInfo *image_info; + + assert(!info || !info->has_inserted || info->inserted == inserted); + + if (info) { + monitor_printf(mon, "%s", info->device); + if (inserted && inserted->has_node_name) { + monitor_printf(mon, " (%s)", inserted->node_name); + } + } else { + assert(inserted); + monitor_printf(mon, "%s", + inserted->has_node_name + ? inserted->node_name + : "<anonymous>"); + } + + if (inserted) { + monitor_printf(mon, ": %s (%s%s%s)\n", + inserted->file, + inserted->drv, + inserted->ro ? ", read-only" : "", + inserted->encrypted ? ", encrypted" : ""); + } else { + monitor_printf(mon, ": [not inserted]\n"); + } + + if (info) { + if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) { + monitor_printf(mon, " I/O status: %s\n", + BlockDeviceIoStatus_lookup[info->io_status]); + } + + if (info->removable) { + monitor_printf(mon, " Removable device: %slocked, tray %s\n", + info->locked ? "" : "not ", + info->tray_open ? "open" : "closed"); + } + } + + + if (!inserted) { + return; + } + + monitor_printf(mon, " Cache mode: %s%s%s\n", + inserted->cache->writeback ? "writeback" : "writethrough", + inserted->cache->direct ? ", direct" : "", + inserted->cache->no_flush ? ", ignore flushes" : ""); + + if (inserted->has_backing_file) { + monitor_printf(mon, + " Backing file: %s " + "(chain depth: %" PRId64 ")\n", + inserted->backing_file, + inserted->backing_file_depth); + } + + if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) { + monitor_printf(mon, " Detect zeroes: %s\n", + BlockdevDetectZeroesOptions_lookup[inserted->detect_zeroes]); + } + + if (inserted->bps || inserted->bps_rd || inserted->bps_wr || + inserted->iops || inserted->iops_rd || inserted->iops_wr) + { + monitor_printf(mon, " I/O throttling: bps=%" PRId64 + " bps_rd=%" PRId64 " bps_wr=%" PRId64 + " bps_max=%" PRId64 + " bps_rd_max=%" PRId64 + " bps_wr_max=%" PRId64 + " iops=%" PRId64 " iops_rd=%" PRId64 + " iops_wr=%" PRId64 + " iops_max=%" PRId64 + " iops_rd_max=%" PRId64 + " iops_wr_max=%" PRId64 + " iops_size=%" PRId64 "\n", + inserted->bps, + inserted->bps_rd, + inserted->bps_wr, + inserted->bps_max, + inserted->bps_rd_max, + inserted->bps_wr_max, + inserted->iops, + inserted->iops_rd, + inserted->iops_wr, + inserted->iops_max, + inserted->iops_rd_max, + inserted->iops_wr_max, + inserted->iops_size); + } + + if (verbose) { + monitor_printf(mon, "\nImages:\n"); + image_info = inserted->image; + while (1) { + bdrv_image_info_dump((fprintf_function)monitor_printf, + mon, image_info); + if (image_info->has_backing_image) { + image_info = image_info->backing_image; + } else { + break; + } + } + } +} + void hmp_info_block(Monitor *mon, const QDict *qdict) { BlockInfoList *block_list, *info; - ImageInfo *image_info; + BlockDeviceInfoList *blockdev_list, *blockdev; const char *device = qdict_get_try_str(qdict, "device"); bool verbose = qdict_get_try_bool(qdict, "verbose", 0); + bool nodes = qdict_get_try_bool(qdict, "nodes", 0); + bool printed = false; - block_list = qmp_query_block(NULL); + /* Print BlockBackend information */ + if (!nodes) { + block_list = qmp_query_block(false); + } else { + block_list = NULL; + } for (info = block_list; info; info = info->next) { if (device && strcmp(device, info->value->device)) { @@ -308,102 +425,40 @@ void hmp_info_block(Monitor *mon, const QDict *qdict) monitor_printf(mon, "\n"); } - monitor_printf(mon, "%s", info->value->device); - if (info->value->has_inserted) { - monitor_printf(mon, ": %s (%s%s%s)\n", - info->value->inserted->file, - info->value->inserted->drv, - info->value->inserted->ro ? ", read-only" : "", - info->value->inserted->encrypted ? ", encrypted" : ""); - } else { - monitor_printf(mon, ": [not inserted]\n"); - } - - if (info->value->has_io_status && info->value->io_status != BLOCK_DEVICE_IO_STATUS_OK) { - monitor_printf(mon, " I/O status: %s\n", - BlockDeviceIoStatus_lookup[info->value->io_status]); - } + print_block_info(mon, info->value, info->value->has_inserted + ? info->value->inserted : NULL, + verbose); + printed = true; + } - if (info->value->removable) { - monitor_printf(mon, " Removable device: %slocked, tray %s\n", - info->value->locked ? "" : "not ", - info->value->tray_open ? "open" : "closed"); - } + qapi_free_BlockInfoList(block_list); + if ((!device && !nodes) || printed) { + return; + } - if (!info->value->has_inserted) { + /* Print node information */ + blockdev_list = qmp_query_named_block_nodes(NULL); + for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) { + assert(blockdev->value->has_node_name); + if (device && strcmp(device, blockdev->value->node_name)) { continue; } - if (info->value->inserted->has_backing_file) { - monitor_printf(mon, - " Backing file: %s " - "(chain depth: %" PRId64 ")\n", - info->value->inserted->backing_file, - info->value->inserted->backing_file_depth); - } - - if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) { - monitor_printf(mon, " Detect zeroes: %s\n", - BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]); - } - - if (info->value->inserted->bps - || info->value->inserted->bps_rd - || info->value->inserted->bps_wr - || info->value->inserted->iops - || info->value->inserted->iops_rd - || info->value->inserted->iops_wr) - { - monitor_printf(mon, " I/O throttling: bps=%" PRId64 - " bps_rd=%" PRId64 " bps_wr=%" PRId64 - " bps_max=%" PRId64 - " bps_rd_max=%" PRId64 - " bps_wr_max=%" PRId64 - " iops=%" PRId64 " iops_rd=%" PRId64 - " iops_wr=%" PRId64 - " iops_max=%" PRId64 - " iops_rd_max=%" PRId64 - " iops_wr_max=%" PRId64 - " iops_size=%" PRId64 "\n", - info->value->inserted->bps, - info->value->inserted->bps_rd, - info->value->inserted->bps_wr, - info->value->inserted->bps_max, - info->value->inserted->bps_rd_max, - info->value->inserted->bps_wr_max, - info->value->inserted->iops, - info->value->inserted->iops_rd, - info->value->inserted->iops_wr, - info->value->inserted->iops_max, - info->value->inserted->iops_rd_max, - info->value->inserted->iops_wr_max, - info->value->inserted->iops_size); + if (blockdev != blockdev_list) { + monitor_printf(mon, "\n"); } - if (verbose) { - monitor_printf(mon, "\nImages:\n"); - image_info = info->value->inserted->image; - while (1) { - bdrv_image_info_dump((fprintf_function)monitor_printf, - mon, image_info); - if (image_info->has_backing_image) { - image_info = image_info->backing_image; - } else { - break; - } - } - } + print_block_info(mon, NULL, blockdev->value, verbose); } - - qapi_free_BlockInfoList(block_list); + qapi_free_BlockDeviceInfoList(blockdev_list); } void hmp_info_blockstats(Monitor *mon, const QDict *qdict) { BlockStatsList *stats_list, *stats; - stats_list = qmp_query_blockstats(NULL); + stats_list = qmp_query_blockstats(false, false, NULL); for (stats = stats_list; stats; stats = stats->next) { if (!stats->value->has_device) { diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 0014c34ddd..e6a3c5bcfb 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -329,6 +329,8 @@ static void set_kernel_args_old(const struct arm_boot_info *info) * Returns: the size of the device tree image on success, * 0 if the image size exceeds the limit, * -1 on errors. + * + * Note: Must not be called unless have_dtb(binfo) is true. */ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, hwaddr addr_limit) @@ -352,7 +354,7 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, goto fail; } g_free(filename); - } else if (binfo->get_dtb) { + } else { fdt = binfo->get_dtb(binfo, &size); if (!fdt) { fprintf(stderr, "Board was unable to create a dtb blob\n"); diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 693dfec9f2..8967cc4e0b 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -273,10 +273,10 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, case 3: s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC; s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I; - s->cpu->env.cp15.c1_sys = 0; + s->cpu->env.cp15.sctlr_ns = 0; s->cpu->env.cp15.c1_coproc = 0; - s->cpu->env.cp15.ttbr0_el1 = 0; - s->cpu->env.cp15.c3 = 0; + s->cpu->env.cp15.ttbr0_el[1] = 0; + s->cpu->env.cp15.dacr_ns = 0; s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ diff --git a/hw/arm/realview.c b/hw/arm/realview.c index af65aa4082..d41ec97a23 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -52,7 +52,7 @@ static void realview_init(MachineState *machine, CPUARMState *env; ObjectClass *cpu_oc; MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram_lo = g_new(MemoryRegion, 1); + MemoryRegion *ram_lo; MemoryRegion *ram_hi = g_new(MemoryRegion, 1); MemoryRegion *ram_alias = g_new(MemoryRegion, 1); MemoryRegion *ram_hack = g_new(MemoryRegion, 1); @@ -135,6 +135,7 @@ static void realview_init(MachineState *machine, if (is_pb && ram_size > 0x20000000) { /* Core tile RAM. */ + ram_lo = g_new(MemoryRegion, 1); low_ram_size = ram_size - 0x20000000; ram_size = 0x20000000; memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size, diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 1222a37f4f..2a28978cba 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -197,7 +197,13 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, + s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker); diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 13276589e4..aa1ed986d2 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -811,6 +811,7 @@ static int nvme_init(PCIDevice *pci_dev) NVME_CAP_SET_AMS(n->bar.cap, 1); NVME_CAP_SET_TO(n->bar.cap, 0xf); NVME_CAP_SET_CSS(n->bar.cap, 1); + NVME_CAP_SET_MPSMAX(n->bar.cap, 4); n->bar.vs = 0x00010001; n->bar.intmc = n->bar.intms = 0; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 993c51131c..b6ccb655a6 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -688,7 +688,7 @@ typedef struct NvmeCtrl { NvmeBar bar; BlockConf conf; - uint16_t page_size; + uint32_t page_size; uint16_t page_bits; uint16_t max_prp_ents; uint16_t cqe_size; diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 94f28e6bac..5651372be3 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -34,15 +34,15 @@ #include <hw/ide/pci.h> #include <hw/ide/ahci.h> -/* #define DEBUG_AHCI */ +#define DEBUG_AHCI 0 -#ifdef DEBUG_AHCI #define DPRINTF(port, fmt, ...) \ -do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \ - fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(port, fmt, ...) do {} while(0) -#endif +do { \ + if (DEBUG_AHCI) { \ + fprintf(stderr, "ahci: %s: [%d] ", __func__, port); \ + fprintf(stderr, fmt, ## __VA_ARGS__); \ + } \ +} while (0) static void check_cmd(AHCIState *s, int port); static int handle_cmd(AHCIState *s,int port,int slot); @@ -551,7 +551,7 @@ static void ahci_reset_port(AHCIState *s, int port) static void debug_print_fis(uint8_t *fis, int cmd_len) { -#ifdef DEBUG_AHCI +#if DEBUG_AHCI int i; fprintf(stderr, "fis:"); @@ -580,7 +580,7 @@ static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished) sdb_fis = (SDBFIS *)&ad->res_fis[RES_FIS_SDBFIS]; ide_state = &ad->port.ifs[0]; - sdb_fis->type = 0xA1; + sdb_fis->type = SATA_FIS_TYPE_SDB; /* Interrupt pending & Notification bit */ sdb_fis->flags = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); sdb_fis->status = ide_state->status & 0x77; @@ -631,7 +631,7 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len) pio_fis = &ad->res_fis[RES_FIS_PSFIS]; - pio_fis[0] = 0x5f; + pio_fis[0] = SATA_FIS_TYPE_PIO_SETUP; pio_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); pio_fis[2] = s->status; pio_fis[3] = s->error; @@ -690,7 +690,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) d2h_fis = &ad->res_fis[RES_FIS_RFIS]; - d2h_fis[0] = 0x34; + d2h_fis[0] = SATA_FIS_TYPE_REGISTER_D2H; d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); d2h_fis[2] = s->status; d2h_fis[3] = s->error; @@ -1154,9 +1154,7 @@ out: static void ahci_start_dma(IDEDMA *dma, IDEState *s, BlockCompletionFunc *dma_cb) { -#ifdef DEBUG_AHCI AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); -#endif DPRINTF(ad->port_no, "\n"); s->io_buffer_offset = 0; dma_cb(s, 0); diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index e0d2eb8f15..99aa0c967f 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -156,7 +156,10 @@ #define AHCI_SCR_SCTL_DET 0xf #define SATA_FIS_TYPE_REGISTER_H2D 0x27 -#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80 +#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80 +#define SATA_FIS_TYPE_REGISTER_D2H 0x34 +#define SATA_FIS_TYPE_PIO_SETUP 0x5f +#define SATA_FIS_TYPE_SDB 0xA1 #define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f #define AHCI_CMD_HDR_PRDT_LEN 16 diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index b4f096e12e..1ebb58d36d 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -163,6 +163,11 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind) return -1; } + if (dev->conf.logical_block_size != 512) { + error_report("logical_block_size must be 512 for IDE"); + return -1; + } + blkconf_serial(&dev->conf, &dev->serial); if (kind != IDE_CD) { blkconf_geometry(&dev->conf, &dev->chs_trans, 65536, 16, 255, &err); diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 5038885afd..1ad3eb0ff8 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -92,6 +92,21 @@ static bool kvm_arm_gic_can_save_restore(GICState *s) return s->dev_fd >= 0; } +static bool kvm_gic_supports_attr(GICState *s, int group, int attrnum) +{ + struct kvm_device_attr attr = { + .group = group, + .attr = attrnum, + .flags = 0, + }; + + if (s->dev_fd == -1) { + return false; + } + + return kvm_device_ioctl(s->dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0; +} + static void kvm_gic_access(GICState *s, int group, int offset, int cpu, uint32_t *val, bool write) { @@ -553,6 +568,11 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } + if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { + uint32_t numirqs = s->num_irq; + kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, 0, &numirqs, 1); + } + /* Distributor */ memory_region_init_reservation(&s->iomem, OBJECT(s), "kvm-gic_dist", 0x1000); diff --git a/include/block/block.h b/include/block/block.h index 5450610bc1..610be9ff04 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -374,6 +374,7 @@ BlockDriverState *bdrv_lookup_bs(const char *device, const char *node_name, Error **errp); bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base); +BlockDriverState *bdrv_next_node(BlockDriverState *bs); BlockDriverState *bdrv_next(BlockDriverState *bs); int bdrv_is_encrypted(BlockDriverState *bs); int bdrv_key_required(BlockDriverState *bs); @@ -381,6 +382,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key); int bdrv_query_missing_keys(void); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque); +const char *bdrv_get_node_name(const BlockDriverState *bs); const char *bdrv_get_device_name(const BlockDriverState *bs); int bdrv_get_flags(BlockDriverState *bs); int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, diff --git a/include/block/block_int.h b/include/block/block_int.h index a1c17b9578..06a21dd13d 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -57,6 +57,8 @@ #define BLOCK_OPT_REDUNDANCY "redundancy" #define BLOCK_OPT_NOCOW "nocow" +#define BLOCK_PROBE_BUF_SIZE 512 + typedef struct BdrvTrackedRequest { BlockDriverState *bs; int64_t offset; @@ -324,6 +326,7 @@ struct BlockDriverState { int sg; /* if true, the device is a /dev/sg* */ int copy_on_read; /* if true, copy read backing sectors into image note this is a reference count */ + bool probed; BlockDriver *drv; /* NULL means no media */ void *opaque; @@ -411,7 +414,17 @@ struct BlockDriverState { Error *backing_blocker; }; + +/* Essential block drivers which must always be statically linked into qemu, and + * which therefore can be accessed without using bdrv_find_format() */ +extern BlockDriver bdrv_file; +extern BlockDriver bdrv_raw; +extern BlockDriver bdrv_qcow2; + + int get_tmp_filename(char *filename, int size); +BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, + const char *filename); void bdrv_set_io_limits(BlockDriverState *bs, ThrottleConfig *cfg); diff --git a/include/block/nbd.h b/include/block/nbd.h index 9e835d2cbb..348302c90b 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -85,14 +85,13 @@ int nbd_disconnect(int fd); typedef struct NBDExport NBDExport; typedef struct NBDClient NBDClient; -NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, - off_t size, uint32_t nbdflags, - void (*close)(NBDExport *)); +NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size, + uint32_t nbdflags, void (*close)(NBDExport *)); void nbd_export_close(NBDExport *exp); void nbd_export_get(NBDExport *exp); void nbd_export_put(NBDExport *exp); -BlockDriverState *nbd_export_get_blockdev(NBDExport *exp); +BlockBackend *nbd_export_get_blockdev(NBDExport *exp); NBDExport *nbd_export_find(const char *name); void nbd_export_set_name(NBDExport *exp, const char *name); diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index a608a26c30..c6332489a7 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -95,4 +95,10 @@ extern bool gdb_has_xml; /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ extern const char *const xml_builtin[][2]; +/* Command line option defining whether semihosting should go via gdb or not */ +extern int semihosting_target; +#define SEMIHOSTING_TARGET_AUTO 0 +#define SEMIHOSTING_TARGET_NATIVE 1 +#define SEMIHOSTING_TARGET_GDB 2 + #endif diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 52d13c1c0e..8871a021d0 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -108,6 +108,8 @@ int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs); int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf); BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, BlockCompletionFunc *cb, void *opaque); +int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors); +int blk_co_flush(BlockBackend *blk); int blk_flush(BlockBackend *blk); int blk_flush_all(void); void blk_drain_all(void); @@ -120,6 +122,7 @@ int blk_is_read_only(BlockBackend *blk); int blk_is_sg(BlockBackend *blk); int blk_enable_write_cache(BlockBackend *blk); void blk_set_enable_write_cache(BlockBackend *blk, bool wce); +void blk_invalidate_cache(BlockBackend *blk, Error **errp); int blk_is_inserted(BlockBackend *blk); void blk_lock_medium(BlockBackend *blk, bool locked); void blk_eject(BlockBackend *blk, bool eject_flag); @@ -132,6 +135,15 @@ void blk_op_block_all(BlockBackend *blk, Error *reason); void blk_op_unblock_all(BlockBackend *blk, Error *reason); AioContext *blk_get_aio_context(BlockBackend *blk); void blk_set_aio_context(BlockBackend *blk, AioContext *new_context); +void blk_add_aio_context_notifier(BlockBackend *blk, + void (*attached_aio_context)(AioContext *new_context, void *opaque), + void (*detach_aio_context)(void *opaque), void *opaque); +void blk_remove_aio_context_notifier(BlockBackend *blk, + void (*attached_aio_context)(AioContext *, + void *), + void (*detach_aio_context)(void *), + void *opaque); +void blk_add_close_notifier(BlockBackend *blk, Notifier *notify); void blk_io_plug(BlockBackend *blk); void blk_io_unplug(BlockBackend *blk); BlockAcctStats *blk_get_stats(BlockBackend *blk); diff --git a/linux-user/aarch64/target_cpu.h b/linux-user/aarch64/target_cpu.h index 21560ef832..b5593dc5ad 100644 --- a/linux-user/aarch64/target_cpu.h +++ b/linux-user/aarch64/target_cpu.h @@ -32,7 +32,7 @@ static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) /* Note that AArch64 Linux keeps the TLS pointer in TPIDR; this is * different from AArch32 Linux, which uses TPIDRRO. */ - env->cp15.tpidr_el0 = newtls; + env->cp15.tpidr_el[0] = newtls; } #endif diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h index 39d65b692b..d8a534d7b1 100644 --- a/linux-user/arm/target_cpu.h +++ b/linux-user/arm/target_cpu.h @@ -29,7 +29,7 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp) static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) { - env->cp15.tpidrro_el0 = newtls; + env->cp15.tpidrro_el[0] = newtls; } #endif diff --git a/linux-user/main.c b/linux-user/main.c index 5c14c1e874..186ee4d54f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -564,7 +564,7 @@ do_kernel_trap(CPUARMState *env) end_exclusive(); break; case 0xffff0fe0: /* __kernel_get_tls */ - env->regs[0] = env->cp15.tpidrro_el0; + env->regs[0] = env->cp15.tpidrro_el[0]; break; case 0xffff0f60: /* __kernel_cmpxchg64 */ arm_kernel_cmpxchg64_helper(env); @@ -2628,10 +2628,10 @@ static mon_cmd_t info_cmds[] = { }, { .name = "block", - .args_type = "verbose:-v,device:B?", - .params = "[-v] [device]", + .args_type = "nodes:-n,verbose:-v,device:B?", + .params = "[-n] [-v] [device]", .help = "show info of one block device or all block devices " - "(and details of images with -v option)", + "(-n: show named nodes; -v: show details)", .mhandler.cmd = hmp_info_block, }, { @@ -4695,7 +4695,7 @@ static void monitor_find_completion_by_table(Monitor *mon, } } str = args[nb_args - 1]; - if (*ptype == '-' && ptype[1] != '\0') { + while (*ptype == '-' && ptype[1] != '\0') { ptype = next_arg_type(ptype); } switch(*ptype) { @@ -17,8 +17,7 @@ */ #include "block/nbd.h" -#include "block/block.h" -#include "block/block_int.h" +#include "sysemu/block-backend.h" #include "block/coroutine.h" @@ -101,7 +100,7 @@ struct NBDExport { int refcount; void (*close)(NBDExport *exp); - BlockDriverState *bs; + BlockBackend *blk; char *name; off_t dev_offset; off_t size; @@ -929,7 +928,7 @@ static void nbd_request_put(NBDRequest *req) nbd_client_put(client); } -static void bs_aio_attached(AioContext *ctx, void *opaque) +static void blk_aio_attached(AioContext *ctx, void *opaque) { NBDExport *exp = opaque; NBDClient *client; @@ -943,7 +942,7 @@ static void bs_aio_attached(AioContext *ctx, void *opaque) } } -static void bs_aio_detach(void *opaque) +static void blk_aio_detach(void *opaque) { NBDExport *exp = opaque; NBDClient *client; @@ -957,27 +956,26 @@ static void bs_aio_detach(void *opaque) exp->ctx = NULL; } -NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, - off_t size, uint32_t nbdflags, - void (*close)(NBDExport *)) +NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size, + uint32_t nbdflags, void (*close)(NBDExport *)) { NBDExport *exp = g_malloc0(sizeof(NBDExport)); exp->refcount = 1; QTAILQ_INIT(&exp->clients); - exp->bs = bs; + exp->blk = blk; exp->dev_offset = dev_offset; exp->nbdflags = nbdflags; - exp->size = size == -1 ? bdrv_getlength(bs) : size; + exp->size = size == -1 ? blk_getlength(blk) : size; exp->close = close; - exp->ctx = bdrv_get_aio_context(bs); - bdrv_ref(bs); - bdrv_add_aio_context_notifier(bs, bs_aio_attached, bs_aio_detach, exp); + exp->ctx = blk_get_aio_context(blk); + blk_ref(blk); + blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp); /* * NBD exports are used for non-shared storage migration. Make sure * that BDRV_O_INCOMING is cleared and the image is ready for write * access since the export could be available before migration handover. */ - bdrv_invalidate_cache(bs, NULL); + blk_invalidate_cache(blk, NULL); return exp; } @@ -1024,11 +1022,11 @@ void nbd_export_close(NBDExport *exp) } nbd_export_set_name(exp, NULL); nbd_export_put(exp); - if (exp->bs) { - bdrv_remove_aio_context_notifier(exp->bs, bs_aio_attached, - bs_aio_detach, exp); - bdrv_unref(exp->bs); - exp->bs = NULL; + if (exp->blk) { + blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, + blk_aio_detach, exp); + blk_unref(exp->blk); + exp->blk = NULL; } } @@ -1056,9 +1054,9 @@ void nbd_export_put(NBDExport *exp) } } -BlockDriverState *nbd_export_get_blockdev(NBDExport *exp) +BlockBackend *nbd_export_get_blockdev(NBDExport *exp) { - return exp->bs; + return exp->blk; } void nbd_export_close_all(void) @@ -1137,7 +1135,7 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *reque command = request->type & NBD_CMD_MASK_COMMAND; if (command == NBD_CMD_READ || command == NBD_CMD_WRITE) { - req->data = qemu_blockalign(client->exp->bs, request->len); + req->data = blk_blockalign(client->exp->blk, request->len); } if (command == NBD_CMD_WRITE) { TRACE("Reading %u byte(s)", request->len); @@ -1203,7 +1201,7 @@ static void nbd_trip(void *opaque) TRACE("Request type is READ"); if (request.type & NBD_CMD_FLAG_FUA) { - ret = bdrv_co_flush(exp->bs); + ret = blk_co_flush(exp->blk); if (ret < 0) { LOG("flush failed"); reply.error = -ret; @@ -1211,8 +1209,9 @@ static void nbd_trip(void *opaque) } } - ret = bdrv_read(exp->bs, (request.from + exp->dev_offset) / 512, - req->data, request.len / 512); + ret = blk_read(exp->blk, + (request.from + exp->dev_offset) / BDRV_SECTOR_SIZE, + req->data, request.len / BDRV_SECTOR_SIZE); if (ret < 0) { LOG("reading from file failed"); reply.error = -ret; @@ -1234,8 +1233,9 @@ static void nbd_trip(void *opaque) TRACE("Writing to device"); - ret = bdrv_write(exp->bs, (request.from + exp->dev_offset) / 512, - req->data, request.len / 512); + ret = blk_write(exp->blk, + (request.from + exp->dev_offset) / BDRV_SECTOR_SIZE, + req->data, request.len / BDRV_SECTOR_SIZE); if (ret < 0) { LOG("writing to file failed"); reply.error = -ret; @@ -1243,7 +1243,7 @@ static void nbd_trip(void *opaque) } if (request.type & NBD_CMD_FLAG_FUA) { - ret = bdrv_co_flush(exp->bs); + ret = blk_co_flush(exp->blk); if (ret < 0) { LOG("flush failed"); reply.error = -ret; @@ -1262,7 +1262,7 @@ static void nbd_trip(void *opaque) case NBD_CMD_FLUSH: TRACE("Request type is FLUSH"); - ret = bdrv_co_flush(exp->bs); + ret = blk_co_flush(exp->blk); if (ret < 0) { LOG("flush failed"); reply.error = -ret; @@ -1273,8 +1273,9 @@ static void nbd_trip(void *opaque) break; case NBD_CMD_TRIM: TRACE("Request type is TRIM"); - ret = bdrv_co_discard(exp->bs, (request.from + exp->dev_offset) / 512, - request.len / 512); + ret = blk_co_discard(exp->blk, (request.from + exp->dev_offset) + / BDRV_SECTOR_SIZE, + request.len / BDRV_SECTOR_SIZE); if (ret < 0) { LOG("discard failed"); reply.error = -ret; diff --git a/qapi/block-core.json b/qapi/block-core.json index a14e6ab1fd..6e8db15861 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -183,6 +183,22 @@ '*fragmented-clusters': 'int', '*compressed-clusters': 'int' } } ## +# @BlockdevCacheInfo +# +# Cache mode information for a block device +# +# @writeback: true if writeback mode is enabled +# @direct: true if the host page cache is bypassed (O_DIRECT) +# @no-flush: true if flush requests are ignored for the device +# +# Since: 2.3 +## +{ 'type': 'BlockdevCacheInfo', + 'data': { 'writeback': 'bool', + 'direct': 'bool', + 'no-flush': 'bool' } } + +## # @BlockDeviceInfo: # # Information about the backing device for a block device. @@ -239,6 +255,8 @@ # # @iops_size: #optional an I/O size in bytes (Since 1.7) # +# @cache: the cache mode used for the block device (since: 2.3) +# # Since: 0.14.0 # ## @@ -253,7 +271,7 @@ '*bps_max': 'int', '*bps_rd_max': 'int', '*bps_wr_max': 'int', '*iops_max': 'int', '*iops_rd_max': 'int', '*iops_wr_max': 'int', - '*iops_size': 'int' } } + '*iops_size': 'int', 'cache': 'BlockdevCacheInfo' } } ## # @BlockDeviceIoStatus: @@ -405,6 +423,8 @@ # @device: #optional If the stats are for a virtual block device, the name # corresponding to the virtual block device. # +# @device: #optional The node name of the device. (Since 2.3) +# # @stats: A @BlockDeviceStats for the device. # # @parent: #optional This describes the file block device if it has one. @@ -415,7 +435,8 @@ # Since: 0.14.0 ## { 'type': 'BlockStats', - 'data': {'*device': 'str', 'stats': 'BlockDeviceStats', + 'data': {'*device': 'str', '*node-name': 'str', + 'stats': 'BlockDeviceStats', '*parent': 'BlockStats', '*backing': 'BlockStats'} } @@ -424,11 +445,20 @@ # # Query the @BlockStats for all virtual block devices. # +# @query-nodes: #optional If true, the command will query all the block nodes +# that have a node name, in a list which will include "parent" +# information, but not "backing". +# If false or omitted, the behavior is as before - query all the +# device backends, recursively including their "parent" and +# "backing". (Since 2.3) +# # Returns: A list of @BlockStats for each virtual block devices. # # Since: 0.14.0 ## -{ 'command': 'query-blockstats', 'returns': ['BlockStats'] } +{ 'command': 'query-blockstats', + 'data': { '*query-nodes': 'bool' }, + 'returns': ['BlockStats'] } ## # @BlockdevOnError: diff --git a/qemu-img.c b/qemu-img.c index a42335c632..7876258fa9 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1531,6 +1531,20 @@ static int img_convert(int argc, char **argv) goto out; } + if (!drv->create_opts) { + error_report("Format driver '%s' does not support image creation", + drv->format_name); + ret = -1; + goto out; + } + + if (!proto_drv->create_opts) { + error_report("Protocol driver '%s' does not support image creation", + proto_drv->format_name); + ret = -1; + goto out; + } + create_opts = qemu_opts_append(create_opts, drv->create_opts); create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); @@ -2972,6 +2986,13 @@ static int img_amend(int argc, char **argv) goto out; } + if (!bs->drv->create_opts) { + error_report("Format driver '%s' does not support any options to amend", + fmt); + ret = -1; + goto out; + } + create_opts = qemu_opts_append(create_opts, bs->drv->create_opts); opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); if (options && qemu_opts_do_parse(opts, options, NULL)) { @@ -51,7 +51,8 @@ static const cmdinfo_t close_cmd = { .oneline = "close the current open file", }; -static int openfile(char *name, int flags, int growable, QDict *opts) +static int openfile(char *name, BlockDriver *drv, int flags, int growable, + QDict *opts) { Error *local_err = NULL; @@ -68,7 +69,7 @@ static int openfile(char *name, int flags, int growable, QDict *opts) flags |= BDRV_O_PROTOCOL; } - if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, NULL, &local_err) < 0) { + if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, drv, &local_err) < 0) { fprintf(stderr, "%s: can't open%s%s: %s\n", progname, name ? " device " : "", name ?: "", error_get_pretty(local_err)); @@ -169,9 +170,9 @@ static int open_f(BlockDriverState *bs, int argc, char **argv) qemu_opts_reset(&empty_opts); if (optind == argc - 1) { - return openfile(argv[optind], flags, growable, opts); + return openfile(argv[optind], NULL, flags, growable, opts); } else if (optind == argc) { - return openfile(NULL, flags, growable, opts); + return openfile(NULL, NULL, flags, growable, opts); } else { QDECREF(opts); return qemuio_command_usage(&open_cmd); @@ -196,11 +197,12 @@ static const cmdinfo_t quit_cmd = { static void usage(const char *name) { printf( -"Usage: %s [-h] [-V] [-rsnm] [-c STRING] ... [file]\n" +"Usage: %s [-h] [-V] [-rsnm] [-f FMT] [-c STRING] ... [file]\n" "QEMU Disk exerciser\n" "\n" " -c, --cmd STRING execute command with its arguments\n" " from the given string\n" +" -f, --format FMT specifies the block driver to use\n" " -r, --read-only export read-only\n" " -s, --snapshot use snapshot file\n" " -n, --nocache disable host cache\n" @@ -364,12 +366,13 @@ int main(int argc, char **argv) { int readonly = 0; int growable = 0; - const char *sopt = "hVc:d:rsnmgkt:T:"; + const char *sopt = "hVc:d:f:rsnmgkt:T:"; const struct option lopt[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "offset", 1, NULL, 'o' }, { "cmd", 1, NULL, 'c' }, + { "format", 1, NULL, 'f' }, { "read-only", 0, NULL, 'r' }, { "snapshot", 0, NULL, 's' }, { "nocache", 0, NULL, 'n' }, @@ -384,6 +387,7 @@ int main(int argc, char **argv) int c; int opt_index = 0; int flags = BDRV_O_UNMAP; + BlockDriver *drv = NULL; Error *local_error = NULL; #ifdef CONFIG_POSIX @@ -393,6 +397,8 @@ int main(int argc, char **argv) progname = basename(argv[0]); qemu_init_exec_dir(argv[0]); + bdrv_init(); + while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { switch (c) { case 's': @@ -407,6 +413,13 @@ int main(int argc, char **argv) exit(1); } break; + case 'f': + drv = bdrv_find_format(optarg); + if (!drv) { + error_report("Invalid format '%s'", optarg); + exit(EXIT_FAILURE); + } + break; case 'c': add_user_command(optarg); break; @@ -455,7 +468,6 @@ int main(int argc, char **argv) error_free(local_error); exit(1); } - bdrv_init(); /* initialize commands */ qemuio_add_command(&quit_cmd); @@ -477,7 +489,7 @@ int main(int argc, char **argv) } if ((argc - optind) == 1) { - openfile(argv[optind], flags, growable, NULL); + openfile(argv[optind], drv, flags, growable, NULL); } command_loop(); diff --git a/qemu-nbd.c b/qemu-nbd.c index 5cd6c6d187..d222512412 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -146,7 +146,7 @@ static void read_partition(uint8_t *p, struct partition_record *r) r->nb_sectors_abs = p[12] | p[13] << 8 | p[14] << 16 | p[15] << 24; } -static int find_partition(BlockDriverState *bs, int partition, +static int find_partition(BlockBackend *blk, int partition, off_t *offset, off_t *size) { struct partition_record mbr[4]; @@ -155,7 +155,7 @@ static int find_partition(BlockDriverState *bs, int partition, int ext_partnum = 4; int ret; - if ((ret = bdrv_read(bs, 0, data, 1)) < 0) { + if ((ret = blk_read(blk, 0, data, 1)) < 0) { errno = -ret; err(EXIT_FAILURE, "error while reading"); } @@ -175,7 +175,7 @@ static int find_partition(BlockDriverState *bs, int partition, uint8_t data1[512]; int j; - if ((ret = bdrv_read(bs, mbr[i].start_sector_abs, data1, 1)) < 0) { + if ((ret = blk_read(blk, mbr[i].start_sector_abs, data1, 1)) < 0) { errno = -ret; err(EXIT_FAILURE, "error while reading"); } @@ -720,17 +720,17 @@ int main(int argc, char **argv) } bs->detect_zeroes = detect_zeroes; - fd_size = bdrv_getlength(bs); + fd_size = blk_getlength(blk); if (partition != -1) { - ret = find_partition(bs, partition, &dev_offset, &fd_size); + ret = find_partition(blk, partition, &dev_offset, &fd_size); if (ret < 0) { errno = -ret; err(EXIT_FAILURE, "Could not find partition %d", partition); } } - exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags, nbd_export_closed); + exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed); if (sockpath) { fd = unix_socket_incoming(sockpath); diff --git a/qemu-options.hx b/qemu-options.hx index 64af16d64c..10b9568815 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2790,6 +2790,14 @@ STEXI @findex -qmp Like -monitor but opens in 'control' mode. ETEXI +DEF("qmp-pretty", HAS_ARG, QEMU_OPTION_qmp_pretty, \ + "-qmp-pretty dev like -qmp but uses pretty JSON formatting\n", + QEMU_ARCH_ALL) +STEXI +@item -qmp-pretty @var{dev} +@findex -qmp-pretty +Like -qmp but uses pretty JSON formatting. +ETEXI DEF("mon", HAS_ARG, QEMU_OPTION_mon, \ "-mon [chardev=]name[,mode=readline|control][,default]\n", QEMU_ARCH_ALL) @@ -3218,7 +3226,17 @@ DEF("semihosting", 0, QEMU_OPTION_semihosting, STEXI @item -semihosting @findex -semihosting -Semihosting mode (ARM, M68K, Xtensa only). +Enable semihosting mode (ARM, M68K, Xtensa only). +ETEXI +DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, + "-semihosting-config [enable=on|off,]target=native|gdb|auto semihosting configuration\n", +QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32) +STEXI +@item -semihosting-config [enable=on|off,]target=native|gdb|auto +@findex -semihosting-config +Enable semihosting and define where the semihosting calls will be addressed, +to QEMU (@code{native}) or to GDB (@code{gdb}). The default is @code{auto}, which means +@code{gdb} during debug sessions and @code{native} otherwise (ARM, M68K, Xtensa only). ETEXI DEF("old-param", 0, QEMU_OPTION_old_param, "-old-param old param mode\n", QEMU_ARCH_ARM) diff --git a/qmp-commands.hx b/qmp-commands.hx index 47bcf87ee6..33487820a4 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2347,7 +2347,7 @@ EQMP { .name = "query-blockstats", - .args_type = "", + .args_type = "query-nodes:b?", .mhandler.cmd_new = qmp_marshal_input_query_blockstats, }, diff --git a/qobject/qjson.c b/qobject/qjson.c index 6cf2511580..12c576d548 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -86,8 +86,9 @@ static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) QString *qkey; int j; - if (s->count) - qstring_append(s->str, ", "); + if (s->count) { + qstring_append(s->str, s->pretty ? "," : ", "); + } if (s->pretty) { qstring_append(s->str, "\n"); @@ -109,8 +110,9 @@ static void to_json_list_iter(QObject *obj, void *opaque) ToJsonIterState *s = opaque; int j; - if (s->count) - qstring_append(s->str, ", "); + if (s->count) { + qstring_append(s->str, s->pretty ? "," : ", "); + } if (s->pretty) { qstring_append(s->str, "\n"); diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c index ebb5235521..a8b83e6912 100644 --- a/target-arm/arm-semi.c +++ b/target-arm/arm-semi.c @@ -58,6 +58,10 @@ #define TARGET_SYS_HEAPINFO 0x16 #define TARGET_SYS_EXIT 0x18 +/* ADP_Stopped_ApplicationExit is used for exit(0), + * anything else is implemented as exit(1) */ +#define ADP_Stopped_ApplicationExit (0x20026) + #ifndef O_BINARY #define O_BINARY 0 #endif @@ -551,8 +555,11 @@ uint32_t do_arm_semihosting(CPUARMState *env) return 0; } case TARGET_SYS_EXIT: - gdb_exit(env, 0); - exit(0); + /* ARM specifies only Stopped_ApplicationExit as normal + * exit, everything else is considered an error */ + ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1; + gdb_exit(env, ret); + exit(ret); default: fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); cpu_dump_state(cs, stderr, fprintf, 0); diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 5ce7350ce6..d3db279e1b 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -109,7 +109,7 @@ static void arm_cpu_reset(CPUState *s) #if defined(CONFIG_USER_ONLY) env->pstate = PSTATE_MODE_EL0t; /* Userspace expects access to DC ZVA, CTL_EL0 and the cache ops */ - env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE; + env->cp15.sctlr_el[1] |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE; /* and to the FP/Neon instructions */ env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3); #else @@ -167,7 +167,11 @@ static void arm_cpu_reset(CPUState *s) env->thumb = initial_pc & 1; } - if (env->cp15.c1_sys & SCTLR_V) { + /* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently + * executing as AArch32 then check if highvecs are enabled and + * adjust the PC accordingly. + */ + if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) { env->regs[15] = 0xFFFF0000; } @@ -548,7 +552,7 @@ static void arm1026_initfn(Object *obj) ARMCPRegInfo ifar = { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, - .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]), + .fieldoffset = offsetof(CPUARMState, cp15.ifar_ns), .resetvalue = 0 }; define_one_arm_cp_reg(cpu, &ifar); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7f800908f4..7ba55f0c2e 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -120,6 +120,12 @@ typedef struct ARMGenericTimer { #define GTIMER_VIRT 1 #define NUM_GTIMERS 2 +typedef struct { + uint64_t raw_tcr; + uint32_t mask; + uint32_t base_mask; +} TCR; + typedef struct CPUARMState { /* Regs for current mode. */ uint32_t regs[16]; @@ -177,28 +183,111 @@ typedef struct CPUARMState { /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; - uint64_t c0_cssel; /* Cache size selection. */ - uint64_t c1_sys; /* System control register. */ + union { /* Cache size selection */ + struct { + uint64_t _unused_csselr0; + uint64_t csselr_ns; + uint64_t _unused_csselr1; + uint64_t csselr_s; + }; + uint64_t csselr_el[4]; + }; + union { /* System control register. */ + struct { + uint64_t _unused_sctlr; + uint64_t sctlr_ns; + uint64_t hsctlr; + uint64_t sctlr_s; + }; + uint64_t sctlr_el[4]; + }; uint64_t c1_coproc; /* Coprocessor access register. */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ - uint64_t ttbr0_el1; /* MMU translation table base 0. */ - uint64_t ttbr1_el1; /* MMU translation table base 1. */ - uint64_t c2_control; /* MMU translation table base control. */ - uint32_t c2_mask; /* MMU translation table base selection mask. */ - uint32_t c2_base_mask; /* MMU translation table base 0 mask. */ + uint64_t sder; /* Secure debug enable register. */ + uint32_t nsacr; /* Non-secure access control register. */ + union { /* MMU translation table base 0. */ + struct { + uint64_t _unused_ttbr0_0; + uint64_t ttbr0_ns; + uint64_t _unused_ttbr0_1; + uint64_t ttbr0_s; + }; + uint64_t ttbr0_el[4]; + }; + union { /* MMU translation table base 1. */ + struct { + uint64_t _unused_ttbr1_0; + uint64_t ttbr1_ns; + uint64_t _unused_ttbr1_1; + uint64_t ttbr1_s; + }; + uint64_t ttbr1_el[4]; + }; + /* MMU translation table base control. */ + TCR tcr_el[4]; uint32_t c2_data; /* MPU data cachable bits. */ uint32_t c2_insn; /* MPU instruction cachable bits. */ - uint32_t c3; /* MMU domain access control register - MPU write buffer control. */ + union { /* MMU domain access control register + * MPU write buffer control. + */ + struct { + uint64_t dacr_ns; + uint64_t dacr_s; + }; + struct { + uint64_t dacr32_el2; + }; + }; uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */ uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */ uint64_t hcr_el2; /* Hypervisor configuration register */ uint64_t scr_el3; /* Secure configuration register. */ - uint32_t ifsr_el2; /* Fault status registers. */ - uint64_t esr_el[4]; + union { /* Fault status registers. */ + struct { + uint64_t ifsr_ns; + uint64_t ifsr_s; + }; + struct { + uint64_t ifsr32_el2; + }; + }; + union { + struct { + uint64_t _unused_dfsr; + uint64_t dfsr_ns; + uint64_t hsr; + uint64_t dfsr_s; + }; + uint64_t esr_el[4]; + }; uint32_t c6_region[8]; /* MPU base/size registers. */ - uint64_t far_el[4]; /* Fault address registers. */ - uint64_t par_el1; /* Translation result. */ + union { /* Fault address registers. */ + struct { + uint64_t _unused_far0; +#ifdef HOST_WORDS_BIGENDIAN + uint32_t ifar_ns; + uint32_t dfar_ns; + uint32_t ifar_s; + uint32_t dfar_s; +#else + uint32_t dfar_ns; + uint32_t ifar_ns; + uint32_t dfar_s; + uint32_t ifar_s; +#endif + uint64_t _unused_far3; + }; + uint64_t far_el[4]; + }; + union { /* Translation result. */ + struct { + uint64_t _unused_par_0; + uint64_t par_ns; + uint64_t _unused_par_1; + uint64_t par_s; + }; + uint64_t par_el[4]; + }; uint32_t c9_insn; /* Cache lockdown registers. */ uint32_t c9_data; uint64_t c9_pmcr; /* performance monitor control register */ @@ -207,13 +296,67 @@ typedef struct CPUARMState { uint32_t c9_pmxevtyper; /* perf monitor event type */ uint32_t c9_pmuserenr; /* perf monitor user enable */ uint32_t c9_pminten; /* perf monitor interrupt enables */ - uint64_t mair_el1; - uint64_t vbar_el[4]; /* vector base address register */ - uint32_t c13_fcse; /* FCSE PID. */ - uint64_t contextidr_el1; /* Context ID. */ - uint64_t tpidr_el0; /* User RW Thread register. */ - uint64_t tpidrro_el0; /* User RO Thread register. */ - uint64_t tpidr_el1; /* Privileged Thread register. */ + union { /* Memory attribute redirection */ + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint64_t _unused_mair_0; + uint32_t mair1_ns; + uint32_t mair0_ns; + uint64_t _unused_mair_1; + uint32_t mair1_s; + uint32_t mair0_s; +#else + uint64_t _unused_mair_0; + uint32_t mair0_ns; + uint32_t mair1_ns; + uint64_t _unused_mair_1; + uint32_t mair0_s; + uint32_t mair1_s; +#endif + }; + uint64_t mair_el[4]; + }; + union { /* vector base address register */ + struct { + uint64_t _unused_vbar; + uint64_t vbar_ns; + uint64_t hvbar; + uint64_t vbar_s; + }; + uint64_t vbar_el[4]; + }; + uint32_t mvbar; /* (monitor) vector base address register */ + struct { /* FCSE PID. */ + uint32_t fcseidr_ns; + uint32_t fcseidr_s; + }; + union { /* Context ID. */ + struct { + uint64_t _unused_contextidr_0; + uint64_t contextidr_ns; + uint64_t _unused_contextidr_1; + uint64_t contextidr_s; + }; + uint64_t contextidr_el[4]; + }; + union { /* User RW Thread register. */ + struct { + uint64_t tpidrurw_ns; + uint64_t tpidrprw_ns; + uint64_t htpidr; + uint64_t _tpidr_el3; + }; + uint64_t tpidr_el[4]; + }; + /* The secure banks of these registers don't map anywhere */ + uint64_t tpidrurw_s; + uint64_t tpidrprw_s; + uint64_t tpidruro_s; + + union { /* User RO Thread register. */ + uint64_t tpidruro_ns; + uint64_t tpidrro_el[1]; + }; uint64_t c14_cntfrq; /* Counter Frequency register */ uint64_t c14_cntkctl; /* Timer Control register */ ARMGenericTimer c14_timer[NUM_GTIMERS]; @@ -817,6 +960,49 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el) return arm_feature(env, ARM_FEATURE_AARCH64); } +/* Function for determing whether guest cp register reads and writes should + * access the secure or non-secure bank of a cp register. When EL3 is + * operating in AArch32 state, the NS-bit determines whether the secure + * instance of a cp register should be used. When EL3 is AArch64 (or if + * it doesn't exist at all) then there is no register banking, and all + * accesses are to the non-secure version. + */ +static inline bool access_secure_reg(CPUARMState *env) +{ + bool ret = (arm_feature(env, ARM_FEATURE_EL3) && + !arm_el_is_aa64(env, 3) && + !(env->cp15.scr_el3 & SCR_NS)); + + return ret; +} + +/* Macros for accessing a specified CP register bank */ +#define A32_BANKED_REG_GET(_env, _regname, _secure) \ + ((_secure) ? (_env)->cp15._regname##_s : (_env)->cp15._regname##_ns) + +#define A32_BANKED_REG_SET(_env, _regname, _secure, _val) \ + do { \ + if (_secure) { \ + (_env)->cp15._regname##_s = (_val); \ + } else { \ + (_env)->cp15._regname##_ns = (_val); \ + } \ + } while (0) + +/* Macros for automatically accessing a specific CP register bank depending on + * the current secure state of the system. These macros are not intended for + * supporting instruction translation reads/writes as these are dependent + * solely on the SCR.NS bit and not the mode. + */ +#define A32_BANKED_CURRENT_REG_GET(_env, _regname) \ + A32_BANKED_REG_GET((_env), _regname, \ + ((!arm_el_is_aa64((_env), 3) && arm_is_secure(_env)))) + +#define A32_BANKED_CURRENT_REG_SET(_env, _regname, _val) \ + A32_BANKED_REG_SET((_env), _regname, \ + ((!arm_el_is_aa64((_env), 3) && arm_is_secure(_env))), \ + (_val)) + void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf); unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx); @@ -836,6 +1022,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq); * Crn, Crm, opc1, opc2 fields * 32 or 64 bit register (ie is it accessed via MRC/MCR * or via MRRC/MCRR?) + * non-secure/secure bank (AArch32 only) * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field. * (In this case crn and opc2 should be zero.) * For AArch64, there is no 32/64 bit size distinction; @@ -853,9 +1040,16 @@ void armv7m_nvic_complete_irq(void *opaque, int irq); #define CP_REG_AA64_SHIFT 28 #define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT) -#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \ - (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \ - ((crm) << 7) | ((opc1) << 3) | (opc2)) +/* To enable banking of coprocessor registers depending on ns-bit we + * add a bit to distinguish between secure and non-secure cpregs in the + * hashtable. + */ +#define CP_REG_NS_SHIFT 29 +#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT) + +#define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2) \ + ((ns) << CP_REG_NS_SHIFT | ((cp) << 16) | ((is64) << 15) | \ + ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2)) #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \ (CP_REG_AA64_MASK | \ @@ -874,8 +1068,15 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid) uint32_t cpregid = kvmid; if ((kvmid & CP_REG_ARCH_MASK) == CP_REG_ARM64) { cpregid |= CP_REG_AA64_MASK; - } else if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) { - cpregid |= (1 << 15); + } else { + if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) { + cpregid |= (1 << 15); + } + + /* KVM is always non-secure so add the NS flag on AArch32 register + * entries. + */ + cpregid |= 1 << CP_REG_NS_SHIFT; } return cpregid; } @@ -950,6 +1151,21 @@ enum { ARM_CP_STATE_BOTH = 2, }; +/* ARM CP register secure state flags. These flags identify security state + * attributes for a given CP register entry. + * The existence of both or neither secure and non-secure flags indicates that + * the register has both a secure and non-secure hash entry. A single one of + * these flags causes the register to only be hashed for the specified + * security state. + * Although definitions may have any combination of the S/NS bits, each + * registered entry will only have one to identify whether the entry is secure + * or non-secure. + */ +enum { + ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */ + ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */ +}; + /* Return true if cptype is a valid type field. This is used to try to * catch errors where the sentinel has been accidentally left off the end * of a list of registers. @@ -1084,6 +1300,8 @@ struct ARMCPRegInfo { int type; /* Access rights: PL*_[RW] */ int access; + /* Security state: ARM_CP_SECSTATE_* bits/values */ + int secure; /* The opaque pointer passed to define_arm_cp_regs_with_opaque() when * this register was defined: can be used to hand data through to the * register read/write functions, since they are passed the ARMCPRegInfo*. @@ -1093,12 +1311,27 @@ struct ARMCPRegInfo { * fieldoffset is non-zero, the reset value of the register. */ uint64_t resetvalue; - /* Offset of the field in CPUARMState for this register. This is not - * needed if either: + /* Offset of the field in CPUARMState for this register. + * + * This is not needed if either: * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs * 2. both readfn and writefn are specified */ ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */ + + /* Offsets of the secure and non-secure fields in CPUARMState for the + * register if it is banked. These fields are only used during the static + * registration of a register. During hashing the bank associated + * with a given security state is copied to fieldoffset which is used from + * there on out. + * + * It is expected that register definitions use either fieldoffset or + * bank_fieldoffsets in the definition but not both. It is also expected + * that both bank offsets are set when defining a banked register. This + * use indicates that a register is banked. + */ + ptrdiff_t bank_fieldoffsets[2]; + /* Function for making any access checks for this register in addition to * those specified by the 'access' permissions bits. If NULL, no extra * checks required. The access check is performed at runtime, not at @@ -1247,27 +1480,50 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx) CPUARMState *env = cs->env_ptr; unsigned int cur_el = arm_current_el(env); unsigned int target_el = arm_excp_target_el(cs, excp_idx); - /* FIXME: Use actual secure state. */ - bool secure = false; - /* If in EL1/0, Physical IRQ routing to EL2 only happens from NS state. */ - bool irq_can_hyp = !secure && cur_el < 2 && target_el == 2; - - /* Don't take exceptions if they target a lower EL. */ + bool secure = arm_is_secure(env); + uint32_t scr; + uint32_t hcr; + bool pstate_unmasked; + int8_t unmasked = 0; + + /* Don't take exceptions if they target a lower EL. + * This check should catch any exceptions that would not be taken but left + * pending. + */ if (cur_el > target_el) { return false; } switch (excp_idx) { case EXCP_FIQ: - if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_FMO)) { - return true; - } - return !(env->daif & PSTATE_F); + /* If FIQs are routed to EL3 or EL2 then there are cases where we + * override the CPSR.F in determining if the exception is masked or + * not. If neither of these are set then we fall back to the CPSR.F + * setting otherwise we further assess the state below. + */ + hcr = (env->cp15.hcr_el2 & HCR_FMO); + scr = (env->cp15.scr_el3 & SCR_FIQ); + + /* When EL3 is 32-bit, the SCR.FW bit controls whether the CPSR.F bit + * masks FIQ interrupts when taken in non-secure state. If SCR.FW is + * set then FIQs can be masked by CPSR.F when non-secure but only + * when FIQs are only routed to EL3. + */ + scr &= !((env->cp15.scr_el3 & SCR_FW) && !hcr); + pstate_unmasked = !(env->daif & PSTATE_F); + break; + case EXCP_IRQ: - if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_IMO)) { - return true; - } - return !(env->daif & PSTATE_I); + /* When EL3 execution state is 32-bit, if HCR.IMO is set then we may + * override the CPSR.I masking when in non-secure state. The SCR.IRQ + * setting has already been taken into consideration when setting the + * target EL, so it does not have a further affect here. + */ + hcr = (env->cp15.hcr_el2 & HCR_IMO); + scr = false; + pstate_unmasked = !(env->daif & PSTATE_I); + break; + case EXCP_VFIQ: if (secure || !(env->cp15.hcr_el2 & HCR_FMO)) { /* VFIQs are only taken when hypervized and non-secure. */ @@ -1283,6 +1539,21 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx) default: g_assert_not_reached(); } + + /* Use the target EL, current execution state and SCR/HCR settings to + * determine whether the corresponding CPSR bit is used to mask the + * interrupt. + */ + if ((target_el > cur_el) && (target_el != 1)) { + if (arm_el_is_aa64(env, 3) || ((scr || hcr) && (!secure))) { + unmasked = 1; + } + } + + /* The PSTATE bits only mask the interrupt if we have not overriden the + * ability above. + */ + return unmasked || pstate_unmasked; } static inline CPUARMState *cpu_init(const char *cpu_model) @@ -1402,6 +1673,12 @@ static inline bool arm_singlestep_active(CPUARMState *env) */ #define ARM_TBFLAG_XSCALE_CPAR_SHIFT 20 #define ARM_TBFLAG_XSCALE_CPAR_MASK (3 << ARM_TBFLAG_XSCALE_CPAR_SHIFT) +/* Indicates whether cp register reads and writes by guest code should access + * the secure or nonsecure bank of banked registers; note that this is not + * the same thing as the current security state of the processor! + */ +#define ARM_TBFLAG_NS_SHIFT 22 +#define ARM_TBFLAG_NS_MASK (1 << ARM_TBFLAG_NS_SHIFT) /* Bit usage when in AArch64 state */ #define ARM_TBFLAG_AA64_EL_SHIFT 0 @@ -1446,6 +1723,8 @@ static inline bool arm_singlestep_active(CPUARMState *env) (((F) & ARM_TBFLAG_AA64_SS_ACTIVE_MASK) >> ARM_TBFLAG_AA64_SS_ACTIVE_SHIFT) #define ARM_TBFLAG_AA64_PSTATE_SS(F) \ (((F) & ARM_TBFLAG_AA64_PSTATE_SS_MASK) >> ARM_TBFLAG_AA64_PSTATE_SS_SHIFT) +#define ARM_TBFLAG_NS(F) \ + (((F) & ARM_TBFLAG_NS_MASK) >> ARM_TBFLAG_NS_SHIFT) static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, target_ulong *cs_base, int *flags) @@ -1495,6 +1774,9 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, if (privmode) { *flags |= ARM_TBFLAG_PRIV_MASK; } + 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; diff --git a/target-arm/helper.c b/target-arm/helper.c index b74d348a3b..96abbed935 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -136,6 +136,11 @@ static void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, } } +static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return (char *)env + ri->fieldoffset; +} + static uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri) { /* Raw read of a coprocessor register (as needed for migration, etc). */ @@ -419,13 +424,36 @@ static void tlbimvaa_is_write(CPUARMState *env, const ARMCPRegInfo *ri, } static const ARMCPRegInfo cp_reginfo[] = { - { .name = "FCSEIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse), + /* Define the secure and non-secure FCSE identifier CP registers + * separately because there is no secure bank in V8 (no _EL3). This allows + * the secure register to be properly reset and migrated. There is also no + * v8 EL1 version of the register so the non-secure instance stands alone. + */ + { .name = "FCSEIDR(NS)", + .cp = 15, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 0, + .access = PL1_RW, .secure = ARM_CP_SECSTATE_NS, + .fieldoffset = offsetof(CPUARMState, cp15.fcseidr_ns), + .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write, }, + { .name = "FCSEIDR(S)", + .cp = 15, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 0, + .access = PL1_RW, .secure = ARM_CP_SECSTATE_S, + .fieldoffset = offsetof(CPUARMState, cp15.fcseidr_s), .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write, }, - { .name = "CONTEXTIDR", .state = ARM_CP_STATE_BOTH, + /* Define the secure and non-secure context identifier CP registers + * separately because there is no secure bank in V8 (no _EL3). This allows + * the secure register to be properly reset and migrated. In the + * non-secure case, the 32-bit register will have reset and migration + * disabled during registration as it is handled by the 64-bit instance. + */ + { .name = "CONTEXTIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1, - .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el1), + .access = PL1_RW, .secure = ARM_CP_SECSTATE_NS, + .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]), + .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, + { .name = "CONTEXTIDR(S)", .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1, + .access = PL1_RW, .secure = ARM_CP_SECSTATE_S, + .fieldoffset = offsetof(CPUARMState, cp15.contextidr_s), .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, REGINFO_SENTINEL }; @@ -435,10 +463,12 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = { * definitions that don't use CP_ANY wildcards (mostly in v8_cp_reginfo[]). */ /* MMU Domain access control / MPU write buffer control */ - { .name = "DACR", .cp = 15, - .crn = 3, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c3), - .resetvalue = 0, .writefn = dacr_write, .raw_writefn = raw_write, }, + { .name = "DACR", + .cp = 15, .opc1 = CP_ANY, .crn = 3, .crm = CP_ANY, .opc2 = CP_ANY, + .access = PL1_RW, .resetvalue = 0, + .writefn = dacr_write, .raw_writefn = raw_write, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s), + offsetoflow32(CPUARMState, cp15.dacr_ns) } }, /* ??? This covers not just the impdef TLB lockdown registers but also * some v7VMSA registers relating to TEX remap, so it is overly broad. */ @@ -552,7 +582,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { .access = PL0_W, .type = ARM_CP_NOP }, { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, - .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ifar_s), + offsetof(CPUARMState, cp15.ifar_ns) }, .resetvalue = 0, }, /* Watchpoint Fault Address Register : should actually only be present * for 1136, 1176, 11MPCore. @@ -776,7 +807,14 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri) { ARMCPU *cpu = arm_env_get_cpu(env); - return cpu->ccsidr[env->cp15.c0_cssel]; + + /* Acquire the CSSELR index from the bank corresponding to the CCSIDR + * bank + */ + uint32_t index = A32_BANKED_REG_GET(env, csselr, + ri->secure & ARM_CP_SECSTATE_S); + + return cpu->ccsidr[index]; } static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -896,18 +934,17 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "VBAR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .writefn = vbar_write, - .fieldoffset = offsetof(CPUARMState, cp15.vbar_el[1]), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), + offsetof(CPUARMState, cp15.vbar_ns) }, .resetvalue = 0 }, - { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3), - .resetvalue = 0, .writefn = scr_write }, { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE }, { .name = "CSSELR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c0_cssel), - .writefn = csselr_write, .resetvalue = 0 }, + .access = PL1_RW, .writefn = csselr_write, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.csselr_s), + offsetof(CPUARMState, cp15.csselr_ns) } }, /* Auxiliary ID register: this actually has an IMPDEF value but for now * just RAZ for all cores: */ @@ -928,20 +965,26 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { */ { .name = "MAIR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el1), + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]), .resetvalue = 0 }, /* For non-long-descriptor page tables these are PRRR and NMRR; * regardless they still act as reads-as-written for QEMU. * The override is necessary because of the overly-broad TLB_LOCKDOWN * definition. */ + /* MAIR0/1 are defined seperately from their 64-bit counterpart which + * allows them to assign the correct fieldoffset based on the endianness + * handled in the field definitions. + */ { .name = "MAIR0", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE, .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, .access = PL1_RW, - .fieldoffset = offsetoflow32(CPUARMState, cp15.mair_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair0_s), + offsetof(CPUARMState, cp15.mair0_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "MAIR1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE, .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1, .access = PL1_RW, - .fieldoffset = offsetofhigh32(CPUARMState, cp15.mair_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair1_s), + offsetof(CPUARMState, cp15.mair1_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "ISR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 0, @@ -1017,23 +1060,31 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { { .name = "TPIDR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 2, .crn = 13, .crm = 0, .access = PL0_RW, - .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el0), .resetvalue = 0 }, + .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[0]), .resetvalue = 0 }, { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL0_RW, - .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidr_el0), + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidrurw_s), + offsetoflow32(CPUARMState, cp15.tpidrurw_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "TPIDRRO_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 3, .crn = 13, .crm = 0, .access = PL0_R|PL1_W, - .fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el0), .resetvalue = 0 }, + .fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el[0]), + .resetvalue = 0}, { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 3, .access = PL0_R|PL1_W, - .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidrro_el0), + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidruro_s), + offsetoflow32(CPUARMState, cp15.tpidruro_ns) }, .resetfn = arm_cp_reset_ignore }, - { .name = "TPIDR_EL1", .state = ARM_CP_STATE_BOTH, + { .name = "TPIDR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .opc2 = 4, .crn = 13, .crm = 0, .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el1), .resetvalue = 0 }, + .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[1]), .resetvalue = 0 }, + { .name = "TPIDRPRW", .opc1 = 0, .cp = 15, .crn = 13, .crm = 0, .opc2 = 4, + .access = PL1_RW, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidrprw_s), + offsetoflow32(CPUARMState, cp15.tpidrprw_ns) }, + .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -1391,6 +1442,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) int prot; int ret, is_user = ri->opc2 & 2; int access_type = ri->opc2 & 1; + uint64_t par64; ret = get_phys_addr(env, value, access_type, is_user, &phys_addr, &prot, &page_size); @@ -1399,7 +1451,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) * translation table format, but with WnR always clear. * Convert it to a 64-bit PAR. */ - uint64_t par64 = (1 << 11); /* LPAE bit always set */ + par64 = (1 << 11); /* LPAE bit always set */ if (ret == 0) { par64 |= phys_addr & ~0xfffULL; /* We don't set the ATTR or SH fields in the PAR. */ @@ -1411,7 +1463,6 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) * fault. */ } - env->cp15.par_el1 = par64; } else { /* ret is a DFSR/IFSR value for the short descriptor * translation table format (with WnR always clear). @@ -1421,23 +1472,25 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) /* We do not set any attribute bits in the PAR */ if (page_size == (1 << 24) && arm_feature(env, ARM_FEATURE_V7)) { - env->cp15.par_el1 = (phys_addr & 0xff000000) | 1 << 1; + par64 = (phys_addr & 0xff000000) | (1 << 1); } else { - env->cp15.par_el1 = phys_addr & 0xfffff000; + par64 = phys_addr & 0xfffff000; } } else { - env->cp15.par_el1 = ((ret & (1 << 10)) >> 5) | - ((ret & (1 << 12)) >> 6) | - ((ret & 0xf) << 1) | 1; + par64 = ((ret & (1 << 10)) >> 5) | ((ret & (1 << 12)) >> 6) | + ((ret & 0xf) << 1) | 1; } } + + A32_BANKED_CURRENT_REG_SET(env, par, par64); } #endif static const ARMCPRegInfo vapa_cp_reginfo[] = { { .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .resetvalue = 0, - .fieldoffset = offsetoflow32(CPUARMState, cp15.par_el1), + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.par_s), + offsetoflow32(CPUARMState, cp15.par_ns) }, .writefn = par_write }, #ifndef CONFIG_USER_ONLY { .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY, @@ -1555,6 +1608,7 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + TCR *tcr = raw_ptr(env, ri); int maskshift = extract32(value, 0, 3); if (!arm_feature(env, ARM_FEATURE_V8)) { @@ -1573,14 +1627,15 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, } } - /* Note that we always calculate c2_mask and c2_base_mask, but + /* Update the masks corresponding to the the TCR bank being written + * Note that we always calculate mask and base_mask, but * they are only used for short-descriptor tables (ie if EAE is 0); - * for long-descriptor tables the TTBCR fields are used differently - * and the c2_mask and c2_base_mask values are meaningless. + * for long-descriptor tables the TCR fields are used differently + * and the mask and base_mask values are meaningless. */ - raw_write(env, ri, value); - env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift); - env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift); + tcr->raw_tcr = value; + tcr->mask = ~(((uint32_t)0xffffffffu) >> maskshift); + tcr->base_mask = ~((uint32_t)0x3fffu >> maskshift); } static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -1599,19 +1654,25 @@ static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void vmsa_ttbcr_reset(CPUARMState *env, const ARMCPRegInfo *ri) { - env->cp15.c2_base_mask = 0xffffc000u; - raw_write(env, ri, 0); - env->cp15.c2_mask = 0; + TCR *tcr = raw_ptr(env, ri); + + /* Reset both the TCR as well as the masks corresponding to the bank of + * the TCR being reset. + */ + tcr->raw_tcr = 0; + tcr->mask = 0; + tcr->base_mask = 0xffffc000u; } static void vmsa_tcr_el1_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = arm_env_get_cpu(env); + TCR *tcr = raw_ptr(env, ri); /* For AArch64 the A1 bit could result in a change of ASID, so TLB flush. */ tlb_flush(CPU(cpu), 1); - raw_write(env, ri, value); + tcr->raw_tcr = value; } static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -1631,37 +1692,45 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, static const ARMCPRegInfo vmsa_cp_reginfo[] = { { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NO_MIGRATE, - .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el[1]), + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dfsr_s), + offsetoflow32(CPUARMState, cp15.dfsr_ns) }, .resetfn = arm_cp_reset_ignore, }, { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2), .resetvalue = 0, }, + .access = PL1_RW, .resetvalue = 0, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.ifsr_s), + offsetoflow32(CPUARMState, cp15.ifsr_ns) } }, { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, }, { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1), - .writefn = vmsa_ttbr_write, .resetvalue = 0 }, + .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0, + .access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), + offsetof(CPUARMState, cp15.ttbr0_ns) } }, { .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1), - .writefn = vmsa_ttbr_write, .resetvalue = 0 }, + .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1, + .access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), + offsetof(CPUARMState, cp15.ttbr1_ns) } }, { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .writefn = vmsa_tcr_el1_write, .resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write, - .fieldoffset = offsetof(CPUARMState, cp15.c2_control) }, + .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[1]) }, { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .type = ARM_CP_NO_MIGRATE, .writefn = vmsa_ttbcr_write, .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write, - .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) }, - /* 64-bit FAR; this entry also gives us the AArch32 DFAR */ - { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]), + offsetoflow32(CPUARMState, cp15.tcr_el[1])} }, + { .name = "FAR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), .resetvalue = 0, }, + { .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s), + offsetof(CPUARMState, cp15.dfar_ns) } }, REGINFO_SENTINEL }; @@ -1874,15 +1943,18 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE, .resetvalue = 0 }, { .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0, - .access = PL1_RW, .type = ARM_CP_64BIT, - .fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_64BIT, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.par_s), + offsetof(CPUARMState, cp15.par_ns)} }, { .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0, .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE, - .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), + offsetof(CPUARMState, cp15.ttbr0_ns) }, .writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore }, { .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1, .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE, - .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), + offsetof(CPUARMState, cp15.ttbr1_ns) }, .writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore }, REGINFO_SENTINEL }; @@ -1911,7 +1983,7 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri, static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri) { - if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) { return CP_ACCESS_TRAP; } return CP_ACCESS_OK; @@ -1929,7 +2001,7 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env, /* Cache invalidate/clean: NOP, but EL0 must UNDEF unless * SCTLR_EL1.UCI is set. */ - if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCI)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UCI)) { return CP_ACCESS_TRAP; } return CP_ACCESS_OK; @@ -2006,7 +2078,7 @@ static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri) /* We don't implement EL2, so the only control on DC ZVA is the * bit in the SCTLR which can prohibit access for EL0. */ - if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_DZE)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_DZE)) { return CP_ACCESS_TRAP; } return CP_ACCESS_OK; @@ -2045,6 +2117,24 @@ static void spsel_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val) update_spsel(env, val); } +static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + + if (raw_read(env, ri) == value) { + /* Skip the TLB flush if nothing actually changed; Linux likes + * to do a lot of pointless SCTLR writes. + */ + return; + } + + raw_write(env, ri, value); + /* ??? Lots of these bits are not implemented. */ + /* This may enable/disable the MMU, so do a TLB flush. */ + tlb_flush(CPU(cpu), 1); +} + static const ARMCPRegInfo v8_cp_reginfo[] = { /* Minimal set of EL0-visible registers. This will need to be expanded * significantly for system emulation of AArch64 CPUs. @@ -2216,10 +2306,11 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DCCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, .type = ARM_CP_NOP, .access = PL1_W }, /* MMU Domain access control / MPU write buffer control */ - { .name = "DACR", .cp = 15, - .opc1 = 0, .crn = 3, .crm = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c3), - .resetvalue = 0, .writefn = dacr_write, .raw_writefn = raw_write, }, + { .name = "DACR", .cp = 15, .opc1 = 0, .crn = 3, .crm = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .writefn = dacr_write, .raw_writefn = raw_write, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s), + offsetoflow32(CPUARMState, cp15.dacr_ns) } }, { .name = "ELR_EL1", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1, @@ -2289,6 +2380,11 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = { .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2), .writefn = hcr_write }, + { .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0, + .access = PL2_RW, .resetvalue = 0, + .writefn = dacr_write, .raw_writefn = raw_write, + .fieldoffset = offsetof(CPUARMState, cp15.dacr32_el2) }, { .name = "ELR_EL2", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1, @@ -2298,6 +2394,10 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = { .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[2]) }, + { .name = "IFSR32_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 0, .opc2 = 1, + .access = PL2_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.ifsr32_el2) }, { .name = "FAR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[2]) }, @@ -2314,6 +2414,19 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = { }; static const ARMCPRegInfo v8_el3_cp_reginfo[] = { + { .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0, + .access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write, + .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]) }, + { .name = "TTBR0_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 0, + .access = PL3_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) }, + { .name = "TCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 2, + .access = PL3_RW, .writefn = vmsa_tcr_el1_write, + .resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write, + .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[3]) }, { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1, @@ -2335,38 +2448,42 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = { .access = PL3_RW, .writefn = vbar_write, .fieldoffset = offsetof(CPUARMState, cp15.vbar_el[3]), .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo el3_cp_reginfo[] = { { .name = "SCR_EL3", .state = ARM_CP_STATE_AA64, - .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0, .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.scr_el3), - .writefn = scr_write }, + .resetvalue = 0, .writefn = scr_write }, + { .name = "SCR", .type = ARM_CP_NO_MIGRATE, + .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0, + .access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3), + .resetfn = arm_cp_reset_ignore, .writefn = scr_write }, + { .name = "SDER32_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 1, + .access = PL3_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.sder) }, + { .name = "SDER", + .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 1, + .access = PL3_RW, .resetvalue = 0, + .fieldoffset = offsetoflow32(CPUARMState, cp15.sder) }, + /* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */ + { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, + .access = PL3_W | PL1_R, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.nsacr) }, + { .name = "MVBAR", .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1, + .access = PL3_RW, .writefn = vbar_write, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.mvbar) }, REGINFO_SENTINEL }; -static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - ARMCPU *cpu = arm_env_get_cpu(env); - - if (raw_read(env, ri) == value) { - /* Skip the TLB flush if nothing actually changed; Linux likes - * to do a lot of pointless SCTLR writes. - */ - return; - } - - raw_write(env, ri, value); - /* ??? Lots of these bits are not implemented. */ - /* This may enable/disable the MMU, so do a TLB flush. */ - tlb_flush(CPU(cpu), 1); -} - static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri) { /* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64, * but the AArch32 CTR has its own reginfo struct) */ - if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCT)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UCT)) { return CP_ACCESS_TRAP; } return CP_ACCESS_OK; @@ -2960,7 +3077,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) } } if (arm_feature(env, ARM_FEATURE_EL3)) { - define_arm_cp_regs(cpu, v8_el3_cp_reginfo); + if (arm_feature(env, ARM_FEATURE_V8)) { + define_arm_cp_regs(cpu, v8_el3_cp_reginfo); + } + define_arm_cp_regs(cpu, el3_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_MPU)) { /* These are the MPU registers prior to PMSAv6. Any new @@ -3160,8 +3280,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) { ARMCPRegInfo sctlr = { .name = "SCTLR", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_sys), + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0, + .access = PL1_RW, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s), + offsetof(CPUARMState, cp15.sctlr_ns) }, .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr, .raw_writefn = raw_write, }; @@ -3287,7 +3409,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) } static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, - void *opaque, int state, + void *opaque, int state, int secstate, int crm, int opc1, int opc2) { /* Private utility function for define_one_arm_cp_reg_with_opaque(): @@ -3296,22 +3418,59 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, uint32_t *key = g_new(uint32_t, 1); ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; - if (r->state == ARM_CP_STATE_BOTH && state == ARM_CP_STATE_AA32) { - /* The AArch32 view of a shared register sees the lower 32 bits - * of a 64 bit backing field. It is not migratable as the AArch64 - * view handles that. AArch64 also handles reset. - * We assume it is a cp15 register if the .cp field is left unset. + int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0; + + /* Reset the secure state to the specific incoming state. This is + * necessary as the register may have been defined with both states. + */ + r2->secure = secstate; + + if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { + /* Register is banked (using both entries in array). + * Overwriting fieldoffset as the array is only used to define + * banked registers but later only fieldoffset is used. */ - if (r2->cp == 0) { - r2->cp = 15; + r2->fieldoffset = r->bank_fieldoffsets[ns]; + } + + if (state == ARM_CP_STATE_AA32) { + if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { + /* If the register is banked then we don't need to migrate or + * reset the 32-bit instance in certain cases: + * + * 1) If the register has both 32-bit and 64-bit instances then we + * can count on the 64-bit instance taking care of the + * non-secure bank. + * 2) If ARMv8 is enabled then we can count on a 64-bit version + * taking care of the secure bank. This requires that separate + * 32 and 64-bit definitions are provided. + */ + if ((r->state == ARM_CP_STATE_BOTH && ns) || + (arm_feature(&cpu->env, ARM_FEATURE_V8) && !ns)) { + r2->type |= ARM_CP_NO_MIGRATE; + r2->resetfn = arm_cp_reset_ignore; + } + } else if ((secstate != r->secure) && !ns) { + /* The register is not banked so we only want to allow migration of + * the non-secure instance. + */ + r2->type |= ARM_CP_NO_MIGRATE; + r2->resetfn = arm_cp_reset_ignore; } - r2->type |= ARM_CP_NO_MIGRATE; - r2->resetfn = arm_cp_reset_ignore; + + if (r->state == ARM_CP_STATE_BOTH) { + /* We assume it is a cp15 register if the .cp field is left unset. + */ + if (r2->cp == 0) { + r2->cp = 15; + } + #ifdef HOST_WORDS_BIGENDIAN - if (r2->fieldoffset) { - r2->fieldoffset += sizeof(uint32_t); - } + if (r2->fieldoffset) { + r2->fieldoffset += sizeof(uint32_t); + } #endif + } } if (state == ARM_CP_STATE_AA64) { /* To allow abbreviation of ARMCPRegInfo @@ -3327,7 +3486,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm, r2->opc0, opc1, opc2); } else { - *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2); + *key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2); } if (opaque) { r2->opaque = opaque; @@ -3460,10 +3619,14 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, */ if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) { if (r->access & PL3_R) { - assert(r->fieldoffset || r->readfn); + assert((r->fieldoffset || + (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) || + r->readfn); } if (r->access & PL3_W) { - assert(r->fieldoffset || r->writefn); + assert((r->fieldoffset || + (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) || + r->writefn); } } /* Bad type field probably means missing sentinel at end of reg list */ @@ -3476,8 +3639,32 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, if (r->state != state && r->state != ARM_CP_STATE_BOTH) { continue; } - add_cpreg_to_hashtable(cpu, r, opaque, state, - crm, opc1, opc2); + if (state == ARM_CP_STATE_AA32) { + /* Under AArch32 CP registers can be common + * (same for secure and non-secure world) or banked. + */ + switch (r->secure) { + case ARM_CP_SECSTATE_S: + case ARM_CP_SECSTATE_NS: + add_cpreg_to_hashtable(cpu, r, opaque, state, + r->secure, crm, opc1, opc2); + break; + default: + add_cpreg_to_hashtable(cpu, r, opaque, state, + ARM_CP_SECSTATE_S, + crm, opc1, opc2); + add_cpreg_to_hashtable(cpu, r, opaque, state, + ARM_CP_SECSTATE_NS, + crm, opc1, opc2); + break; + } + } else { + /* AArch64 registers get mapped to non-secure instance + * of AArch32 */ + add_cpreg_to_hashtable(cpu, r, opaque, state, + ARM_CP_SECSTATE_NS, + crm, opc1, opc2); + } } } } @@ -3551,6 +3738,8 @@ uint32_t cpsr_read(CPUARMState *env) void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) { + uint32_t changed_daif; + if (mask & CPSR_NZCV) { env->ZF = (~val) & CPSR_Z; env->NF = val; @@ -3573,6 +3762,58 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) env->GE = (val >> 16) & 0xf; } + /* In a V7 implementation that includes the security extensions but does + * not include Virtualization Extensions the SCR.FW and SCR.AW bits control + * whether non-secure software is allowed to change the CPSR_F and CPSR_A + * bits respectively. + * + * In a V8 implementation, it is permitted for privileged software to + * change the CPSR A/F bits regardless of the SCR.AW/FW bits. + */ + if (!arm_feature(env, ARM_FEATURE_V8) && + arm_feature(env, ARM_FEATURE_EL3) && + !arm_feature(env, ARM_FEATURE_EL2) && + !arm_is_secure(env)) { + + changed_daif = (env->daif ^ val) & mask; + + if (changed_daif & CPSR_A) { + /* Check to see if we are allowed to change the masking of async + * abort exceptions from a non-secure state. + */ + if (!(env->cp15.scr_el3 & SCR_AW)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Ignoring attempt to switch CPSR_A flag from " + "non-secure world with SCR.AW bit clear\n"); + mask &= ~CPSR_A; + } + } + + if (changed_daif & CPSR_F) { + /* Check to see if we are allowed to change the masking of FIQ + * exceptions from a non-secure state. + */ + if (!(env->cp15.scr_el3 & SCR_FW)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Ignoring attempt to switch CPSR_F flag from " + "non-secure world with SCR.FW bit clear\n"); + mask &= ~CPSR_F; + } + + /* Check whether non-maskable FIQ (NMFI) support is enabled. + * If this bit is set software is not allowed to mask + * FIQs, but is allowed to set CPSR_F to 0. + */ + if ((A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_NMFI) && + (val & CPSR_F)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Ignoring attempt to enable CPSR_F flag " + "(non-maskable FIQ [NMFI] support enabled)\n"); + mask &= ~CPSR_F; + } + } + } + env->daif &= ~(CPSR_AIF & mask); env->daif |= val & CPSR_AIF & mask; @@ -3761,6 +4002,101 @@ void switch_mode(CPUARMState *env, int mode) env->spsr = env->banked_spsr[i]; } +/* Physical Interrupt Target EL Lookup Table + * + * [ From ARM ARM section G1.13.4 (Table G1-15) ] + * + * The below multi-dimensional table is used for looking up the target + * exception level given numerous condition criteria. Specifically, the + * target EL is based on SCR and HCR routing controls as well as the + * currently executing EL and secure state. + * + * Dimensions: + * target_el_table[2][2][2][2][2][4] + * | | | | | +--- Current EL + * | | | | +------ Non-secure(0)/Secure(1) + * | | | +--------- HCR mask override + * | | +------------ SCR exec state control + * | +--------------- SCR mask override + * +------------------ 32-bit(0)/64-bit(1) EL3 + * + * The table values are as such: + * 0-3 = EL0-EL3 + * -1 = Cannot occur + * + * The ARM ARM target EL table includes entries indicating that an "exception + * is not taken". The two cases where this is applicable are: + * 1) An exception is taken from EL3 but the SCR does not have the exception + * routed to EL3. + * 2) An exception is taken from EL2 but the HCR does not have the exception + * routed to EL2. + * In these two cases, the below table contain a target of EL1. This value is + * returned as it is expected that the consumer of the table data will check + * for "target EL >= current EL" to ensure the exception is not taken. + * + * SCR HCR + * 64 EA AMO From + * BIT IRQ IMO Non-secure Secure + * EL3 FIQ RW FMO EL0 EL1 EL2 EL3 EL0 EL1 EL2 EL3 + */ +const int8_t target_el_table[2][2][2][2][2][4] = { + {{{{/* 0 0 0 0 */{ 1, 1, 2, -1 },{ 3, -1, -1, 3 },}, + {/* 0 0 0 1 */{ 2, 2, 2, -1 },{ 3, -1, -1, 3 },},}, + {{/* 0 0 1 0 */{ 1, 1, 2, -1 },{ 3, -1, -1, 3 },}, + {/* 0 0 1 1 */{ 2, 2, 2, -1 },{ 3, -1, -1, 3 },},},}, + {{{/* 0 1 0 0 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },}, + {/* 0 1 0 1 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },},}, + {{/* 0 1 1 0 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },}, + {/* 0 1 1 1 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },},},},}, + {{{{/* 1 0 0 0 */{ 1, 1, 2, -1 },{ 1, 1, -1, 1 },}, + {/* 1 0 0 1 */{ 2, 2, 2, -1 },{ 1, 1, -1, 1 },},}, + {{/* 1 0 1 0 */{ 1, 1, 1, -1 },{ 1, 1, -1, 1 },}, + {/* 1 0 1 1 */{ 2, 2, 2, -1 },{ 1, 1, -1, 1 },},},}, + {{{/* 1 1 0 0 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },}, + {/* 1 1 0 1 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},}, + {{/* 1 1 1 0 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },}, + {/* 1 1 1 1 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},},},}, +}; + +/* + * Determine the target EL for physical exceptions + */ +static inline uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, + uint32_t cur_el, bool secure) +{ + CPUARMState *env = cs->env_ptr; + int rw = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW); + int scr; + int hcr; + int target_el; + int is64 = arm_el_is_aa64(env, 3); + + switch (excp_idx) { + case EXCP_IRQ: + scr = ((env->cp15.scr_el3 & SCR_IRQ) == SCR_IRQ); + hcr = ((env->cp15.hcr_el2 & HCR_IMO) == HCR_IMO); + break; + case EXCP_FIQ: + scr = ((env->cp15.scr_el3 & SCR_FIQ) == SCR_FIQ); + hcr = ((env->cp15.hcr_el2 & HCR_FMO) == HCR_FMO); + break; + default: + scr = ((env->cp15.scr_el3 & SCR_EA) == SCR_EA); + hcr = ((env->cp15.hcr_el2 & HCR_AMO) == HCR_AMO); + break; + }; + + /* If HCR.TGE is set then HCR is treated as being 1 */ + hcr |= ((env->cp15.hcr_el2 & HCR_TGE) == HCR_TGE); + + /* Perform a table-lookup for the target EL given the current state */ + target_el = target_el_table[is64][scr][rw][hcr][secure][cur_el]; + + assert(target_el > 0); + + return target_el; +} + /* * Determine the target EL for a given exception type. */ @@ -3770,13 +4106,7 @@ unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx) CPUARMState *env = &cpu->env; unsigned int cur_el = arm_current_el(env); unsigned int target_el; - /* FIXME: Use actual secure state. */ - bool secure = false; - - if (!env->aarch64) { - /* TODO: Add EL2 and 3 exception handling for AArch32. */ - return 1; - } + bool secure = arm_is_secure(env); switch (excp_idx) { case EXCP_HVC: @@ -3788,19 +4118,8 @@ unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx) break; case EXCP_FIQ: case EXCP_IRQ: - { - const uint64_t hcr_mask = excp_idx == EXCP_FIQ ? HCR_FMO : HCR_IMO; - const uint32_t scr_mask = excp_idx == EXCP_FIQ ? SCR_FIQ : SCR_IRQ; - - target_el = 1; - if (!secure && (env->cp15.hcr_el2 & hcr_mask)) { - target_el = 2; - } - if (env->cp15.scr_el3 & scr_mask) { - target_el = 3; - } + target_el = arm_phys_excp_target_el(cs, excp_idx, cur_el, secure); break; - } case EXCP_VIRQ: case EXCP_VFIQ: target_el = 1; @@ -4055,22 +4374,20 @@ void arm_cpu_do_interrupt(CPUState *cs) env->exception.fsr = 2; /* Fall through to prefetch abort. */ case EXCP_PREFETCH_ABORT: - env->cp15.ifsr_el2 = env->exception.fsr; - env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 32, 32, - env->exception.vaddress); + A32_BANKED_CURRENT_REG_SET(env, ifsr, env->exception.fsr); + A32_BANKED_CURRENT_REG_SET(env, ifar, env->exception.vaddress); qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n", - env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress); + env->exception.fsr, (uint32_t)env->exception.vaddress); new_mode = ARM_CPU_MODE_ABT; addr = 0x0c; mask = CPSR_A | CPSR_I; offset = 4; break; case EXCP_DATA_ABORT: - env->cp15.esr_el[1] = env->exception.fsr; - env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 0, 32, - env->exception.vaddress); + A32_BANKED_CURRENT_REG_SET(env, dfsr, env->exception.fsr); + A32_BANKED_CURRENT_REG_SET(env, dfar, env->exception.vaddress); qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n", - (uint32_t)env->cp15.esr_el[1], + env->exception.fsr, (uint32_t)env->exception.vaddress); new_mode = ARM_CPU_MODE_ABT; addr = 0x10; @@ -4083,12 +4400,21 @@ void arm_cpu_do_interrupt(CPUState *cs) /* Disable IRQ and imprecise data aborts. */ mask = CPSR_A | CPSR_I; offset = 4; + if (env->cp15.scr_el3 & SCR_IRQ) { + /* IRQ routed to monitor mode */ + new_mode = ARM_CPU_MODE_MON; + mask |= CPSR_F; + } break; case EXCP_FIQ: new_mode = ARM_CPU_MODE_FIQ; addr = 0x1c; /* Disable FIQ, IRQ and imprecise data aborts. */ mask = CPSR_A | CPSR_I | CPSR_F; + if (env->cp15.scr_el3 & SCR_FIQ) { + /* FIQ routed to monitor mode */ + new_mode = ARM_CPU_MODE_MON; + } offset = 4; break; case EXCP_SMC: @@ -4101,19 +4427,19 @@ void arm_cpu_do_interrupt(CPUState *cs) cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); return; /* Never happens. Keep compiler happy. */ } - /* High vectors. */ - if (env->cp15.c1_sys & SCTLR_V) { - /* when enabled, base address cannot be remapped. */ + + if (new_mode == ARM_CPU_MODE_MON) { + addr += env->cp15.mvbar; + } else if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) { + /* High vectors. When enabled, base address cannot be remapped. */ addr += 0xffff0000; } else { /* ARM v7 architectures provide a vector base address register to remap * the interrupt vector table. - * This register is only followed in non-monitor mode, and has a secure - * and un-secure copy. Since the cpu is always in a un-secure operation - * and is never in monitor mode this feature is always active. + * This register is only followed in non-monitor mode, and is banked. * Note: only bits 31:5 are valid. */ - addr += env->cp15.vbar_el[1]; + addr += A32_BANKED_CURRENT_REG_GET(env, vbar); } if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) { @@ -4134,7 +4460,7 @@ void arm_cpu_do_interrupt(CPUState *cs) /* this is a lie, as the was no c1_sys on V4T/V5, but who cares * and we should just guard the thumb mode on V4 */ if (arm_feature(env, ARM_FEATURE_V4T)) { - env->thumb = (env->cp15.c1_sys & SCTLR_TE) != 0; + env->thumb = (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0; } env->regs[14] = env->regs[15] + offset; env->regs[15] = addr; @@ -4165,7 +4491,7 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot, } if (access_type == 1) return 0; - switch (env->cp15.c1_sys & (SCTLR_S | SCTLR_R)) { + switch (A32_BANKED_CURRENT_REG_GET(env, sctlr) & (SCTLR_S | SCTLR_R)) { case SCTLR_S: return is_user ? 0 : PAGE_READ; case SCTLR_R: @@ -4200,18 +4526,25 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot, static bool get_level1_table_address(CPUARMState *env, uint32_t *table, uint32_t address) { - if (address & env->cp15.c2_mask) { - if ((env->cp15.c2_control & TTBCR_PD1)) { + /* Get the TCR bank based on our security state */ + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; + + /* We only get here if EL1 is running in AArch32. If EL3 is running in + * AArch32 there is a secure and non-secure instance of the translation + * table registers. + */ + if (address & tcr->mask) { + if (tcr->raw_tcr & TTBCR_PD1) { /* Translation table walk disabled for TTBR1 */ return false; } - *table = env->cp15.ttbr1_el1 & 0xffffc000; + *table = A32_BANKED_CURRENT_REG_GET(env, ttbr1) & 0xffffc000; } else { - if ((env->cp15.c2_control & TTBCR_PD0)) { + if (tcr->raw_tcr & TTBCR_PD0) { /* Translation table walk disabled for TTBR0 */ return false; } - *table = env->cp15.ttbr0_el1 & env->cp15.c2_base_mask; + *table = A32_BANKED_CURRENT_REG_GET(env, ttbr0) & tcr->base_mask; } *table |= (address >> 18) & 0x3ffc; return true; @@ -4241,7 +4574,7 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type, desc = ldl_phys(cs->as, table); type = (desc & 3); domain = (desc >> 5) & 0x0f; - domain_prot = (env->cp15.c3 >> (domain * 2)) & 3; + domain_prot = (A32_BANKED_CURRENT_REG_GET(env, dacr) >> (domain * 2)) & 3; if (type == 0) { /* Section translation fault. */ code = 5; @@ -4353,7 +4686,7 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type, /* Page or Section. */ domain = (desc >> 5) & 0x0f; } - domain_prot = (env->cp15.c3 >> (domain * 2)) & 3; + domain_prot = (A32_BANKED_CURRENT_REG_GET(env, dacr) >> (domain * 2)) & 3; if (domain_prot == 0 || domain_prot == 2) { if (type != 1) { code = 9; /* Section domain fault. */ @@ -4414,7 +4747,8 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type, goto do_fault; /* The simplified model uses AP[0] as an access control bit. */ - if ((env->cp15.c1_sys & SCTLR_AFE) && (ap & 1) == 0) { + if ((A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_AFE) + && (ap & 1) == 0) { /* Access flag fault. */ code = (code == 15) ? 6 : 3; goto do_fault; @@ -4464,13 +4798,14 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, int32_t granule_sz = 9; int32_t va_size = 32; int32_t tbi = 0; + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; if (arm_el_is_aa64(env, 1)) { va_size = 64; if (extract64(address, 55, 1)) - tbi = extract64(env->cp15.c2_control, 38, 1); + tbi = extract64(tcr->raw_tcr, 38, 1); else - tbi = extract64(env->cp15.c2_control, 37, 1); + tbi = extract64(tcr->raw_tcr, 37, 1); tbi *= 8; } @@ -4479,12 +4814,12 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, * This is a Non-secure PL0/1 stage 1 translation, so controlled by * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32: */ - uint32_t t0sz = extract32(env->cp15.c2_control, 0, 6); + uint32_t t0sz = extract32(tcr->raw_tcr, 0, 6); if (arm_el_is_aa64(env, 1)) { t0sz = MIN(t0sz, 39); t0sz = MAX(t0sz, 16); } - uint32_t t1sz = extract32(env->cp15.c2_control, 16, 6); + uint32_t t1sz = extract32(tcr->raw_tcr, 16, 6); if (arm_el_is_aa64(env, 1)) { t1sz = MIN(t1sz, 39); t1sz = MAX(t1sz, 16); @@ -4515,11 +4850,11 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, * we will always flush the TLB any time the ASID is changed). */ if (ttbr_select == 0) { - ttbr = env->cp15.ttbr0_el1; - epd = extract32(env->cp15.c2_control, 7, 1); + ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr0); + epd = extract32(tcr->raw_tcr, 7, 1); tsz = t0sz; - tg = extract32(env->cp15.c2_control, 14, 2); + tg = extract32(tcr->raw_tcr, 14, 2); if (tg == 1) { /* 64KB pages */ granule_sz = 13; } @@ -4527,11 +4862,11 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, granule_sz = 11; } } else { - ttbr = env->cp15.ttbr1_el1; - epd = extract32(env->cp15.c2_control, 23, 1); + ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr1); + epd = extract32(tcr->raw_tcr, 23, 1); tsz = t1sz; - tg = extract32(env->cp15.c2_control, 30, 2); + tg = extract32(tcr->raw_tcr, 30, 2); if (tg == 3) { /* 64KB pages */ granule_sz = 13; } @@ -4747,11 +5082,17 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address, hwaddr *phys_ptr, int *prot, target_ulong *page_size) { + /* This is not entirely correct as get_phys_addr() can also be called + * from ats_write() for an address translation of a specific regime. + */ + uint32_t sctlr = A32_BANKED_CURRENT_REG_GET(env, sctlr); + /* Fast Context Switch Extension. */ - if (address < 0x02000000) - address += env->cp15.c13_fcse; + if (address < 0x02000000) { + address += A32_BANKED_CURRENT_REG_GET(env, fcseidr); + } - if ((env->cp15.c1_sys & SCTLR_M) == 0) { + if ((sctlr & SCTLR_M) == 0) { /* MMU/MPU disabled. */ *phys_ptr = address; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -4764,7 +5105,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address, } else if (extended_addresses_enabled(env)) { return get_phys_addr_lpae(env, address, access_type, is_user, phys_ptr, prot, page_size); - } else if (env->cp15.c1_sys & SCTLR_XP) { + } else if (sctlr & SCTLR_XP) { return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr, prot, page_size); } else { diff --git a/target-arm/internals.h b/target-arm/internals.h index 2dff4ffb19..bb171a73bd 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -153,9 +153,9 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm) */ static inline bool extended_addresses_enabled(CPUARMState *env) { - return arm_el_is_aa64(env, 1) - || ((arm_feature(env, ARM_FEATURE_LPAE) - && (env->cp15.c2_control & TTBCR_EAE))); + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; + return arm_el_is_aa64(env, 1) || + (arm_feature(env, ARM_FEATURE_LPAE) && (tcr->raw_tcr & TTBCR_EAE)); } /* Valid Syndrome Register EC field values */ diff --git a/target-arm/kvm.c b/target-arm/kvm.c index 319784d689..4d81f3d765 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -21,6 +21,7 @@ #include "sysemu/kvm.h" #include "kvm_arm.h" #include "cpu.h" +#include "internals.h" #include "hw/arm/arm.h" const KVMCapabilityInfo kvm_arch_required_capabilities[] = { @@ -279,6 +280,94 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, memory_region_ref(kd->mr); } +static int compare_u64(const void *a, const void *b) +{ + if (*(uint64_t *)a > *(uint64_t *)b) { + return 1; + } + if (*(uint64_t *)a < *(uint64_t *)b) { + return -1; + } + return 0; +} + +/* Initialize the CPUState's cpreg list according to the kernel's + * definition of what CPU registers it knows about (and throw away + * the previous TCG-created cpreg list). + */ +int kvm_arm_init_cpreg_list(ARMCPU *cpu) +{ + struct kvm_reg_list rl; + struct kvm_reg_list *rlp; + int i, ret, arraylen; + CPUState *cs = CPU(cpu); + + rl.n = 0; + ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl); + if (ret != -E2BIG) { + return ret; + } + rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t)); + rlp->n = rl.n; + ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp); + if (ret) { + goto out; + } + /* Sort the list we get back from the kernel, since cpreg_tuples + * must be in strictly ascending order. + */ + qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64); + + for (i = 0, arraylen = 0; i < rlp->n; i++) { + if (!kvm_arm_reg_syncs_via_cpreg_list(rlp->reg[i])) { + continue; + } + switch (rlp->reg[i] & KVM_REG_SIZE_MASK) { + case KVM_REG_SIZE_U32: + case KVM_REG_SIZE_U64: + break; + default: + fprintf(stderr, "Can't handle size of register in kernel list\n"); + ret = -EINVAL; + goto out; + } + + arraylen++; + } + + cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen); + cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen); + cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes, + arraylen); + cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values, + arraylen); + cpu->cpreg_array_len = arraylen; + cpu->cpreg_vmstate_array_len = arraylen; + + for (i = 0, arraylen = 0; i < rlp->n; i++) { + uint64_t regidx = rlp->reg[i]; + if (!kvm_arm_reg_syncs_via_cpreg_list(regidx)) { + continue; + } + cpu->cpreg_indexes[arraylen] = regidx; + arraylen++; + } + assert(cpu->cpreg_array_len == arraylen); + + if (!write_kvmstate_to_list(cpu)) { + /* Shouldn't happen unless kernel is inconsistent about + * what registers exist. + */ + fprintf(stderr, "Initial read of kernel register state failed\n"); + ret = -EINVAL; + goto out; + } + +out: + g_free(rlp); + return ret; +} + bool write_kvmstate_to_list(ARMCPU *cpu) { CPUState *cs = CPU(cpu); @@ -351,6 +440,24 @@ bool write_list_to_kvmstate(ARMCPU *cpu) return ok; } +void kvm_arm_reset_vcpu(ARMCPU *cpu) +{ + int ret; + + /* Re-init VCPU so that all registers are set to + * their respective reset values. + */ + ret = kvm_arm_vcpu_init(CPU(cpu)); + if (ret < 0) { + fprintf(stderr, "kvm_arm_vcpu_init failed: %s\n", strerror(-ret)); + abort(); + } + if (!write_kvmstate_to_list(cpu)) { + fprintf(stderr, "write_kvmstate_to_list failed\n"); + abort(); + } +} + void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { } diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index 5ec4eb1f32..94030d1acb 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -51,17 +51,17 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) struct kvm_one_reg idregs[] = { { .id = KVM_REG_ARM | KVM_REG_SIZE_U32 - | ENCODE_CP_REG(15, 0, 0, 0, 0, 0), + | ENCODE_CP_REG(15, 0, 0, 0, 0, 0, 0), .addr = (uintptr_t)&midr, }, { .id = KVM_REG_ARM | KVM_REG_SIZE_U32 - | ENCODE_CP_REG(15, 0, 0, 1, 0, 0), + | ENCODE_CP_REG(15, 0, 0, 0, 1, 0, 0), .addr = (uintptr_t)&id_pfr0, }, { .id = KVM_REG_ARM | KVM_REG_SIZE_U32 - | ENCODE_CP_REG(15, 0, 0, 2, 0, 0), + | ENCODE_CP_REG(15, 0, 0, 0, 2, 0, 0), .addr = (uintptr_t)&id_isar0, }, { @@ -138,7 +138,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) return true; } -static bool reg_syncs_via_tuple_list(uint64_t regidx) +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx) { /* Return true if the regidx is a register we should synchronize * via the cpreg_tuples array (ie is not a core reg we sync by @@ -153,24 +153,11 @@ static bool reg_syncs_via_tuple_list(uint64_t regidx) } } -static int compare_u64(const void *a, const void *b) -{ - if (*(uint64_t *)a > *(uint64_t *)b) { - return 1; - } - if (*(uint64_t *)a < *(uint64_t *)b) { - return -1; - } - return 0; -} - int kvm_arch_init_vcpu(CPUState *cs) { - int i, ret, arraylen; + int ret; uint64_t v; struct kvm_one_reg r; - struct kvm_reg_list rl; - struct kvm_reg_list *rlp; ARMCPU *cpu = ARM_CPU(cs); if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) { @@ -206,73 +193,7 @@ int kvm_arch_init_vcpu(CPUState *cs) return -EINVAL; } - /* Populate the cpreg list based on the kernel's idea - * of what registers exist (and throw away the TCG-created list). - */ - rl.n = 0; - ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl); - if (ret != -E2BIG) { - return ret; - } - rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t)); - rlp->n = rl.n; - ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp); - if (ret) { - goto out; - } - /* Sort the list we get back from the kernel, since cpreg_tuples - * must be in strictly ascending order. - */ - qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64); - - for (i = 0, arraylen = 0; i < rlp->n; i++) { - if (!reg_syncs_via_tuple_list(rlp->reg[i])) { - continue; - } - switch (rlp->reg[i] & KVM_REG_SIZE_MASK) { - case KVM_REG_SIZE_U32: - case KVM_REG_SIZE_U64: - break; - default: - fprintf(stderr, "Can't handle size of register in kernel list\n"); - ret = -EINVAL; - goto out; - } - - arraylen++; - } - - cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen); - cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen); - cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes, - arraylen); - cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values, - arraylen); - cpu->cpreg_array_len = arraylen; - cpu->cpreg_vmstate_array_len = arraylen; - - for (i = 0, arraylen = 0; i < rlp->n; i++) { - uint64_t regidx = rlp->reg[i]; - if (!reg_syncs_via_tuple_list(regidx)) { - continue; - } - cpu->cpreg_indexes[arraylen] = regidx; - arraylen++; - } - assert(cpu->cpreg_array_len == arraylen); - - if (!write_kvmstate_to_list(cpu)) { - /* Shouldn't happen unless kernel is inconsistent about - * what registers exist. - */ - fprintf(stderr, "Initial read of kernel register state failed\n"); - ret = -EINVAL; - goto out; - } - -out: - g_free(rlp); - return ret; + return kvm_arm_init_cpreg_list(cpu); } typedef struct Reg { @@ -508,12 +429,3 @@ int kvm_arch_get_registers(CPUState *cs) return 0; } - -void kvm_arm_reset_vcpu(ARMCPU *cpu) -{ - /* Re-init VCPU so that all registers are set to - * their respective reset values. - */ - kvm_arm_vcpu_init(CPU(cpu)); - write_kvmstate_to_list(cpu); -} diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index c615286158..ba16821737 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -103,9 +103,21 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } - /* TODO : support for save/restore/reset of system regs via tuple list */ + return kvm_arm_init_cpreg_list(cpu); +} - return 0; +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx) +{ + /* Return true if the regidx is a register we should synchronize + * via the cpreg_tuples array (ie is not a core reg we sync by + * hand in kvm_arch_get/put_registers()) + */ + switch (regidx & KVM_REG_ARM_COPROC_MASK) { + case KVM_REG_ARM_CORE: + return false; + default: + return true; + } } #define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ @@ -260,11 +272,3 @@ int kvm_arch_get_registers(CPUState *cs) /* TODO: other registers */ return ret; } - -void kvm_arm_reset_vcpu(ARMCPU *cpu) -{ - /* Re-init VCPU so that all registers are set to - * their respective reset values. - */ - kvm_arm_vcpu_init(CPU(cpu)); -} diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index af93105517..455dea3f3f 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -47,6 +47,28 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, uint64_t attr, int dev_fd); /** + * kvm_arm_init_cpreg_list: + * @cs: CPUState + * + * Initialize the CPUState's cpreg list according to the kernel's + * definition of what CPU registers it knows about (and throw away + * the previous TCG-created cpreg list). + * + * Returns: 0 if success, else < 0 error code + */ +int kvm_arm_init_cpreg_list(ARMCPU *cpu); + +/** + * kvm_arm_reg_syncs_via_cpreg_list + * regidx: KVM register index + * + * Return true if this KVM register should be synchronized via the + * cpreg list of arbitrary system registers, false if it is synchronized + * by hand using code in kvm_arch_get/put_registers(). + */ +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx); + +/** * write_list_to_kvmstate: * @cpu: ARMCPU * diff --git a/target-arm/machine.c b/target-arm/machine.c index 6437690af7..c29e7a2ac1 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -127,6 +127,13 @@ static int get_cpsr(QEMUFile *f, void *opaque, size_t size) CPUARMState *env = &cpu->env; uint32_t val = qemu_get_be32(f); + env->aarch64 = ((val & PSTATE_nRW) == 0); + + if (is_a64(env)) { + pstate_write(env, val); + return 0; + } + /* Avoid mode switch when restoring CPSR */ env->uncached_cpsr = val & CPSR_M; cpsr_write(env, val, 0xffffffff); @@ -137,8 +144,15 @@ static void put_cpsr(QEMUFile *f, void *opaque, size_t size) { ARMCPU *cpu = opaque; CPUARMState *env = &cpu->env; + uint32_t val; + + if (is_a64(env)) { + val = pstate_read(env); + } else { + val = cpsr_read(env); + } - qemu_put_be32(f, cpsr_read(env)); + qemu_put_be32(f, val); } static const VMStateInfo vmstate_cpsr = { @@ -222,12 +236,14 @@ static int cpu_post_load(void *opaque, int version_id) const VMStateDescription vmstate_arm_cpu = { .name = "cpu", - .version_id = 21, - .minimum_version_id = 21, + .version_id = 22, + .minimum_version_id = 22, .pre_save = cpu_pre_save, .post_load = cpu_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), + VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32), + VMSTATE_UINT64(env.pc, ARMCPU), { .name = "cpsr", .version_id = 0, diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 62012c3a6e..2bed914770 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -361,7 +361,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm) * Note that SPSel is never OK from EL0; we rely on handle_msr_i() * to catch that case at translate time. */ - if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) { raise_exception(env, EXCP_UDEF); } @@ -575,7 +575,7 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn) * short descriptor format (in which case it holds both PROCID and ASID), * since we don't implement the optional v7 context ID masking. */ - contextidr = extract64(env->cp15.contextidr_el1, 0, 32); + contextidr = extract64(env->cp15.contextidr_el[1], 0, 32); switch (bt) { case 3: /* linked context ID match */ diff --git a/target-arm/translate.c b/target-arm/translate.c index af5156857e..b52c758698 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -7091,7 +7091,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) rt = (insn >> 12) & 0xf; ri = get_arm_cp_reginfo(s->cp_regs, - ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2)); + ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2)); if (ri) { /* Check access permissions */ if (!cp_access_ok(s->current_el, ri, isread)) { @@ -7281,12 +7281,16 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) */ if (is64) { qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 " - "64 bit system register cp:%d opc1: %d crm:%d\n", - isread ? "read" : "write", cpnum, opc1, crm); + "64 bit system register cp:%d opc1: %d crm:%d " + "(%s)\n", + isread ? "read" : "write", cpnum, opc1, crm, + s->ns ? "non-secure" : "secure"); } else { qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 " - "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n", - isread ? "read" : "write", cpnum, opc1, crn, crm, opc2); + "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d " + "(%s)\n", + isread ? "read" : "write", cpnum, opc1, crn, crm, opc2, + s->ns ? "non-secure" : "secure"); } return 1; @@ -11031,6 +11035,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, #if !defined(CONFIG_USER_ONLY) dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0); #endif + dc->ns = ARM_TBFLAG_NS(tb->flags); dc->cpacr_fpen = ARM_TBFLAG_CPACR_FPEN(tb->flags); dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags); dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags); diff --git a/target-arm/translate.h b/target-arm/translate.h index 41a907157f..f6ee7892ba 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -20,6 +20,7 @@ typedef struct DisasContext { #if !defined(CONFIG_USER_ONLY) int user; #endif + bool ns; /* Use non-secure CPREG bank on access */ bool cpacr_fpen; /* FP enabled via CPACR.FPEN */ bool vfp_enabled; /* FP enabled via FPSCR.EN */ int vec_len; diff --git a/target-tricore/cpu.c b/target-tricore/cpu.c index 7bf041afb9..abe16fa7e6 100644 --- a/target-tricore/cpu.c +++ b/target-tricore/cpu.c @@ -63,8 +63,17 @@ static bool tricore_cpu_has_work(CPUState *cs) static void tricore_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); + TriCoreCPU *cpu = TRICORE_CPU(dev); TriCoreCPUClass *tcc = TRICORE_CPU_GET_CLASS(dev); + CPUTriCoreState *env = &cpu->env; + /* Some features automatically imply others */ + if (tricore_feature(env, TRICORE_FEATURE_16)) { + set_feature(env, TRICORE_FEATURE_131); + } + if (tricore_feature(env, TRICORE_FEATURE_131)) { + set_feature(env, TRICORE_FEATURE_13); + } cpu_reset(cs); qemu_init_vcpu(cs); diff --git a/target-tricore/csfr.def b/target-tricore/csfr.def new file mode 100644 index 0000000000..5b219b4bf1 --- /dev/null +++ b/target-tricore/csfr.def @@ -0,0 +1,124 @@ +/* A(ll) access permited + R(ead only) access + E(nd init protected) access + + A|R|E(offset, register, feature introducing reg) + + NOTE: PSW is handled as a special case in gen_mtcr/mfcr */ + +A(0xfe00, PCXI, TRICORE_FEATURE_13) +A(0xfe08, PC, TRICORE_FEATURE_13) +A(0xfe14, SYSCON, TRICORE_FEATURE_13) +R(0xfe18, CPU_ID, TRICORE_FEATURE_13) +E(0xfe20, BIV, TRICORE_FEATURE_13) +E(0xfe24, BTV, TRICORE_FEATURE_13) +E(0xfe28, ISP, TRICORE_FEATURE_13) +A(0xfe2c, ICR, TRICORE_FEATURE_13) +A(0xfe38, FCX, TRICORE_FEATURE_13) +A(0xfe3c, LCX, TRICORE_FEATURE_13) +E(0x9400, COMPAT, TRICORE_FEATURE_131) +/* memory protection register */ +A(0xC000, DPR0_0L, TRICORE_FEATURE_13) +A(0xC004, DPR0_0U, TRICORE_FEATURE_13) +A(0xC008, DPR0_1L, TRICORE_FEATURE_13) +A(0xC00C, DPR0_1U, TRICORE_FEATURE_13) +A(0xC010, DPR0_2L, TRICORE_FEATURE_13) +A(0xC014, DPR0_2U, TRICORE_FEATURE_13) +A(0xC018, DPR0_3L, TRICORE_FEATURE_13) +A(0xC01C, DPR0_3U, TRICORE_FEATURE_13) +A(0xC400, DPR1_0L, TRICORE_FEATURE_13) +A(0xC404, DPR1_0U, TRICORE_FEATURE_13) +A(0xC408, DPR1_1L, TRICORE_FEATURE_13) +A(0xC40C, DPR1_1U, TRICORE_FEATURE_13) +A(0xC410, DPR1_2L, TRICORE_FEATURE_13) +A(0xC414, DPR1_2U, TRICORE_FEATURE_13) +A(0xC418, DPR1_3L, TRICORE_FEATURE_13) +A(0xC41C, DPR1_3U, TRICORE_FEATURE_13) +A(0xC800, DPR2_0L, TRICORE_FEATURE_13) +A(0xC804, DPR2_0U, TRICORE_FEATURE_13) +A(0xC808, DPR2_1L, TRICORE_FEATURE_13) +A(0xC80C, DPR2_1U, TRICORE_FEATURE_13) +A(0xC810, DPR2_2L, TRICORE_FEATURE_13) +A(0xC814, DPR2_2U, TRICORE_FEATURE_13) +A(0xC818, DPR2_3L, TRICORE_FEATURE_13) +A(0xC81C, DPR2_3U, TRICORE_FEATURE_13) +A(0xCC00, DPR3_0L, TRICORE_FEATURE_13) +A(0xCC04, DPR3_0U, TRICORE_FEATURE_13) +A(0xCC08, DPR3_1L, TRICORE_FEATURE_13) +A(0xCC0C, DPR3_1U, TRICORE_FEATURE_13) +A(0xCC10, DPR3_2L, TRICORE_FEATURE_13) +A(0xCC14, DPR3_2U, TRICORE_FEATURE_13) +A(0xCC18, DPR3_3L, TRICORE_FEATURE_13) +A(0xCC1C, DPR3_3U, TRICORE_FEATURE_13) +A(0xD000, CPR0_0L, TRICORE_FEATURE_13) +A(0xD004, CPR0_0U, TRICORE_FEATURE_13) +A(0xD008, CPR0_1L, TRICORE_FEATURE_13) +A(0xD00C, CPR0_1U, TRICORE_FEATURE_13) +A(0xD010, CPR0_2L, TRICORE_FEATURE_13) +A(0xD014, CPR0_2U, TRICORE_FEATURE_13) +A(0xD018, CPR0_3L, TRICORE_FEATURE_13) +A(0xD01C, CPR0_3U, TRICORE_FEATURE_13) +A(0xD400, CPR1_0L, TRICORE_FEATURE_13) +A(0xD404, CPR1_0U, TRICORE_FEATURE_13) +A(0xD408, CPR1_1L, TRICORE_FEATURE_13) +A(0xD40C, CPR1_1U, TRICORE_FEATURE_13) +A(0xD410, CPR1_2L, TRICORE_FEATURE_13) +A(0xD414, CPR1_2U, TRICORE_FEATURE_13) +A(0xD418, CPR1_3L, TRICORE_FEATURE_13) +A(0xD41C, CPR1_3U, TRICORE_FEATURE_13) +A(0xD800, CPR2_0L, TRICORE_FEATURE_13) +A(0xD804, CPR2_0U, TRICORE_FEATURE_13) +A(0xD808, CPR2_1L, TRICORE_FEATURE_13) +A(0xD80C, CPR2_1U, TRICORE_FEATURE_13) +A(0xD810, CPR2_2L, TRICORE_FEATURE_13) +A(0xD814, CPR2_2U, TRICORE_FEATURE_13) +A(0xD818, CPR2_3L, TRICORE_FEATURE_13) +A(0xD81C, CPR2_3U, TRICORE_FEATURE_13) +A(0xDC00, CPR3_0L, TRICORE_FEATURE_13) +A(0xDC04, CPR3_0U, TRICORE_FEATURE_13) +A(0xDC08, CPR3_1L, TRICORE_FEATURE_13) +A(0xDC0C, CPR3_1U, TRICORE_FEATURE_13) +A(0xDC10, CPR3_2L, TRICORE_FEATURE_13) +A(0xDC14, CPR3_2U, TRICORE_FEATURE_13) +A(0xDC18, CPR3_3L, TRICORE_FEATURE_13) +A(0xDC1C, CPR3_3U, TRICORE_FEATURE_13) +A(0xE000, DPM0, TRICORE_FEATURE_13) +A(0xE080, DPM1, TRICORE_FEATURE_13) +A(0xE100, DPM2, TRICORE_FEATURE_13) +A(0xE180, DPM3, TRICORE_FEATURE_13) +A(0xE200, CPM0, TRICORE_FEATURE_13) +A(0xE280, CPM1, TRICORE_FEATURE_13) +A(0xE300, CPM2, TRICORE_FEATURE_13) +A(0xE380, CPM3, TRICORE_FEATURE_13) +/* memory Managment Registers */ +A(0x8000, MMU_CON, TRICORE_FEATURE_13) +A(0x8004, MMU_ASI, TRICORE_FEATURE_13) +A(0x800C, MMU_TVA, TRICORE_FEATURE_13) +A(0x8010, MMU_TPA, TRICORE_FEATURE_13) +A(0x8014, MMU_TPX, TRICORE_FEATURE_13) +A(0x8018, MMU_TFA, TRICORE_FEATURE_13) +E(0x9004, BMACON, TRICORE_FEATURE_131) +E(0x900C, SMACON, TRICORE_FEATURE_131) +A(0x9020, DIEAR, TRICORE_FEATURE_131) +A(0x9024, DIETR, TRICORE_FEATURE_131) +A(0x9028, CCDIER, TRICORE_FEATURE_131) +E(0x9044, MIECON, TRICORE_FEATURE_131) +A(0x9210, PIEAR, TRICORE_FEATURE_131) +A(0x9214, PIETR, TRICORE_FEATURE_131) +A(0x9218, CCPIER, TRICORE_FEATURE_131) +/* debug registers */ +A(0xFD00, DBGSR, TRICORE_FEATURE_13) +A(0xFD08, EXEVT, TRICORE_FEATURE_13) +A(0xFD0C, CREVT, TRICORE_FEATURE_13) +A(0xFD10, SWEVT, TRICORE_FEATURE_13) +A(0xFD20, TR0EVT, TRICORE_FEATURE_13) +A(0xFD24, TR1EVT, TRICORE_FEATURE_13) +A(0xFD40, DMS, TRICORE_FEATURE_13) +A(0xFD44, DCX, TRICORE_FEATURE_13) +A(0xFD48, DBGTCR, TRICORE_FEATURE_131) +A(0xFC00, CCTRL, TRICORE_FEATURE_131) +A(0xFC04, CCNT, TRICORE_FEATURE_131) +A(0xFC08, ICNT, TRICORE_FEATURE_131) +A(0xFC0C, M1CNT, TRICORE_FEATURE_131) +A(0xFC10, M2CNT, TRICORE_FEATURE_131) +A(0xFC14, M3CNT, TRICORE_FEATURE_131) diff --git a/target-tricore/helper.h b/target-tricore/helper.h index b3fc33ceae..6c07bd7f28 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -17,7 +17,21 @@ /* Arithmetic */ DEF_HELPER_3(add_ssov, i32, env, i32, i32) +DEF_HELPER_3(add_suov, i32, env, i32, i32) DEF_HELPER_3(sub_ssov, i32, env, i32, i32) +DEF_HELPER_3(sub_suov, i32, env, i32, i32) +DEF_HELPER_3(mul_ssov, i32, env, i32, i32) +DEF_HELPER_3(mul_suov, i32, env, i32, i32) +DEF_HELPER_3(sha_ssov, i32, env, i32, i32) +DEF_HELPER_3(absdif_ssov, i32, env, i32, i32) +DEF_HELPER_4(madd32_ssov, i32, env, i32, i32, i32) +DEF_HELPER_4(madd32_suov, i32, env, i32, i32, i32) +DEF_HELPER_4(madd64_ssov, i64, env, i32, i64, i32) +DEF_HELPER_4(madd64_suov, i64, env, i32, i64, i32) +DEF_HELPER_4(msub32_ssov, i32, env, i32, i32, i32) +DEF_HELPER_4(msub32_suov, i32, env, i32, i32, i32) +DEF_HELPER_4(msub64_ssov, i64, env, i32, i64, i32) +DEF_HELPER_4(msub64_suov, i64, env, i32, i64, i32) /* CSA */ DEF_HELPER_2(call, void, env, i32) DEF_HELPER_1(ret, void, env) @@ -30,3 +44,6 @@ DEF_HELPER_2(stucx, void, env, i32) /* Address mode helper */ DEF_HELPER_1(br_update, i32, i32) DEF_HELPER_2(circ_update, i32, i32, i32) +/* PSW cache helper */ +DEF_HELPER_2(psw_write, void, env, i32) +DEF_HELPER_1(psw_read, i32, env) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index a36988aa1b..4da76ff232 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -77,6 +77,27 @@ uint32_t helper_circ_update(uint32_t reg, uint32_t off) env->PSW_USB_SAV |= env->PSW_USB_AV; \ } while (0) +#define SUOV(env, ret, arg, len) do { \ + int64_t max_pos = UINT##len ##_MAX; \ + if (arg > max_pos) { \ + env->PSW_USB_V = (1 << 31); \ + env->PSW_USB_SV = (1 << 31); \ + ret = (target_ulong)max_pos; \ + } else { \ + if (arg < 0) { \ + env->PSW_USB_V = (1 << 31); \ + env->PSW_USB_SV = (1 << 31); \ + ret = 0; \ + } else { \ + env->PSW_USB_V = 0; \ + ret = (target_ulong)arg; \ + } \ + } \ + env->PSW_USB_AV = arg ^ arg * 2u; \ + env->PSW_USB_SAV |= env->PSW_USB_AV; \ +} while (0) + + target_ulong helper_add_ssov(CPUTriCoreState *env, target_ulong r1, target_ulong r2) { @@ -88,6 +109,17 @@ target_ulong helper_add_ssov(CPUTriCoreState *env, target_ulong r1, return ret; } +target_ulong helper_add_suov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2) +{ + target_ulong ret; + int64_t t1 = extract64(r1, 0, 32); + int64_t t2 = extract64(r2, 0, 32); + int64_t result = t1 + t2; + SUOV(env, ret, result, 32); + return ret; +} + target_ulong helper_sub_ssov(CPUTriCoreState *env, target_ulong r1, target_ulong r2) { @@ -99,6 +131,241 @@ target_ulong helper_sub_ssov(CPUTriCoreState *env, target_ulong r1, return ret; } +target_ulong helper_sub_suov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2) +{ + target_ulong ret; + int64_t t1 = extract64(r1, 0, 32); + int64_t t2 = extract64(r2, 0, 32); + int64_t result = t1 - t2; + SUOV(env, ret, result, 32); + return ret; +} + +target_ulong helper_mul_ssov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2) +{ + target_ulong ret; + int64_t t1 = sextract64(r1, 0, 32); + int64_t t2 = sextract64(r2, 0, 32); + int64_t result = t1 * t2; + SSOV(env, ret, result, 32); + return ret; +} + +target_ulong helper_mul_suov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2) +{ + target_ulong ret; + int64_t t1 = extract64(r1, 0, 32); + int64_t t2 = extract64(r2, 0, 32); + int64_t result = t1 * t2; + SUOV(env, ret, result, 32); + return ret; +} + +target_ulong helper_sha_ssov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2) +{ + target_ulong ret; + int64_t t1 = sextract64(r1, 0, 32); + int32_t t2 = sextract64(r2, 0, 6); + int64_t result; + if (t2 == 0) { + result = t1; + } else if (t2 > 0) { + result = t1 << t2; + } else { + result = t1 >> -t2; + } + SSOV(env, ret, result, 32); + return ret; +} + +target_ulong helper_absdif_ssov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2) +{ + target_ulong ret; + int64_t t1 = sextract64(r1, 0, 32); + int64_t t2 = sextract64(r2, 0, 32); + int64_t result; + + if (t1 > t2) { + result = t1 - t2; + } else { + result = t2 - t1; + } + SSOV(env, ret, result, 32); + return ret; +} + +target_ulong helper_madd32_ssov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2, target_ulong r3) +{ + target_ulong ret; + int64_t t1 = sextract64(r1, 0, 32); + int64_t t2 = sextract64(r2, 0, 32); + int64_t t3 = sextract64(r3, 0, 32); + int64_t result; + + result = t2 + (t1 * t3); + SSOV(env, ret, result, 32); + return ret; +} + +target_ulong helper_madd32_suov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2, target_ulong r3) +{ + target_ulong ret; + uint64_t t1 = extract64(r1, 0, 32); + uint64_t t2 = extract64(r2, 0, 32); + uint64_t t3 = extract64(r3, 0, 32); + int64_t result; + + result = t2 + (t1 * t3); + SUOV(env, ret, result, 32); + return ret; +} + +uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1, + uint64_t r2, target_ulong r3) +{ + uint64_t ret, ovf; + int64_t t1 = sextract64(r1, 0, 32); + int64_t t3 = sextract64(r3, 0, 32); + int64_t mul; + + mul = t1 * t3; + ret = mul + r2; + ovf = (ret ^ mul) & ~(mul ^ r2); + + if ((int64_t)ovf < 0) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + /* ext_ret > MAX_INT */ + if (mul >= 0) { + ret = INT64_MAX; + /* ext_ret < MIN_INT */ + } else { + ret = INT64_MIN; + } + } else { + env->PSW_USB_V = 0; + } + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + + return ret; +} + +uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1, + uint64_t r2, target_ulong r3) +{ + uint64_t ret, mul; + uint64_t t1 = extract64(r1, 0, 32); + uint64_t t3 = extract64(r3, 0, 32); + + mul = t1 * t3; + ret = mul + r2; + + if (ret < r2) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + /* saturate */ + ret = UINT64_MAX; + } else { + env->PSW_USB_V = 0; + } + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + return ret; +} + +target_ulong helper_msub32_ssov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2, target_ulong r3) +{ + target_ulong ret; + int64_t t1 = sextract64(r1, 0, 32); + int64_t t2 = sextract64(r2, 0, 32); + int64_t t3 = sextract64(r3, 0, 32); + int64_t result; + + result = t2 - (t1 * t3); + SSOV(env, ret, result, 32); + return ret; +} + +target_ulong helper_msub32_suov(CPUTriCoreState *env, target_ulong r1, + target_ulong r2, target_ulong r3) +{ + target_ulong ret; + int64_t t1 = extract64(r1, 0, 32); + int64_t t2 = extract64(r2, 0, 32); + int64_t t3 = extract64(r3, 0, 32); + int64_t result; + + result = t2 - (t1 * t3); + SUOV(env, ret, result, 32); + return ret; +} + +uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1, + uint64_t r2, target_ulong r3) +{ + uint64_t ret, ovf; + int64_t t1 = sextract64(r1, 0, 32); + int64_t t3 = sextract64(r3, 0, 32); + int64_t mul; + + mul = t1 * t3; + ret = r2 - mul; + ovf = (ret ^ r2) & (mul ^ r2); + + if ((int64_t)ovf < 0) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + /* ext_ret > MAX_INT */ + if (mul < 0) { + ret = INT64_MAX; + /* ext_ret < MIN_INT */ + } else { + ret = INT64_MIN; + } + } else { + env->PSW_USB_V = 0; + } + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + return ret; +} + +uint64_t helper_msub64_suov(CPUTriCoreState *env, target_ulong r1, + uint64_t r2, target_ulong r3) +{ + uint64_t ret, mul; + uint64_t t1 = extract64(r1, 0, 32); + uint64_t t3 = extract64(r3, 0, 32); + + mul = t1 * t3; + ret = r2 - mul; + + if (ret > r2) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + /* saturate */ + ret = 0; + } else { + env->PSW_USB_V = 0; + } + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + return ret; +} + /* context save area (CSA) related helpers */ static int cdc_increment(target_ulong *psw) @@ -437,6 +704,17 @@ void helper_stucx(CPUTriCoreState *env, uint32_t ea) save_context_upper(env, ea); } +void helper_psw_write(CPUTriCoreState *env, uint32_t arg) +{ + psw_write(env, arg); +} + +uint32_t helper_psw_read(CPUTriCoreState *env) +{ + return psw_read(env); +} + + static inline void QEMU_NORETURN do_raise_exception_err(CPUTriCoreState *env, uint32_t exception, int error_code, diff --git a/target-tricore/translate.c b/target-tricore/translate.c index d5a95969bb..65abf453f0 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -233,6 +233,63 @@ static void gen_swap(DisasContext *ctx, int reg, TCGv ea) tcg_temp_free(temp); } +/* We generate loads and store to core special function register (csfr) through + the function gen_mfcr and gen_mtcr. To handle access permissions, we use 3 + makros R, A and E, which allow read-only, all and endinit protected access. + These makros also specify in which ISA version the csfr was introduced. */ +#define R(ADDRESS, REG, FEATURE) \ + case ADDRESS: \ + if (tricore_feature(env, FEATURE)) { \ + tcg_gen_ld_tl(ret, cpu_env, offsetof(CPUTriCoreState, REG)); \ + } \ + break; +#define A(ADDRESS, REG, FEATURE) R(ADDRESS, REG, FEATURE) +#define E(ADDRESS, REG, FEATURE) R(ADDRESS, REG, FEATURE) +static inline void gen_mfcr(CPUTriCoreState *env, TCGv ret, int32_t offset) +{ + /* since we're caching PSW make this a special case */ + if (offset == 0xfe04) { + gen_helper_psw_read(ret, cpu_env); + } else { + switch (offset) { +#include "csfr.def" + } + } +} +#undef R +#undef A +#undef E + +#define R(ADDRESS, REG, FEATURE) /* don't gen writes to read-only reg, + since no execption occurs */ +#define A(ADDRESS, REG, FEATURE) R(ADDRESS, REG, FEATURE) \ + case ADDRESS: \ + if (tricore_feature(env, FEATURE)) { \ + tcg_gen_st_tl(r1, cpu_env, offsetof(CPUTriCoreState, REG)); \ + } \ + break; +/* Endinit protected registers + TODO: Since the endinit bit is in a register of a not yet implemented + watchdog device, we handle endinit protected registers like + all-access registers for now. */ +#define E(ADDRESS, REG, FEATURE) A(ADDRESS, REG, FEATURE) +static inline void gen_mtcr(CPUTriCoreState *env, DisasContext *ctx, TCGv r1, + int32_t offset) +{ + if (ctx->hflags & TRICORE_HFLAG_SM) { + /* since we're caching PSW make this a special case */ + if (offset == 0xfe04) { + gen_helper_psw_write(cpu_env, r1); + } else { + switch (offset) { +#include "csfr.def" + } + } + } else { + /* generate privilege trap */ + } +} + /* Functions for arithmetic instructions */ static inline void gen_add_d(TCGv ret, TCGv r1, TCGv r2) @@ -259,12 +316,337 @@ static inline void gen_add_d(TCGv ret, TCGv r1, TCGv r2) tcg_temp_free(t0); } +/* ret = r2 + (r1 * r3); */ +static inline void gen_madd32_d(TCGv ret, TCGv r1, TCGv r2, TCGv r3) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(t1, r1); + tcg_gen_ext_i32_i64(t2, r2); + tcg_gen_ext_i32_i64(t3, r3); + + tcg_gen_mul_i64(t1, t1, t3); + tcg_gen_add_i64(t1, t2, t1); + + tcg_gen_trunc_i64_i32(ret, t1); + /* calc V + t1 > 0x7fffffff */ + tcg_gen_setcondi_i64(TCG_COND_GT, t3, t1, 0x7fffffffLL); + /* t1 < -0x80000000 */ + tcg_gen_setcondi_i64(TCG_COND_LT, t2, t1, -0x80000000LL); + tcg_gen_or_i64(t2, t2, t3); + tcg_gen_trunc_i64_i32(cpu_PSW_V, t2); + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, ret, ret); + tcg_gen_xor_tl(cpu_PSW_AV, ret, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); +} + +static inline void gen_maddi32_d(TCGv ret, TCGv r1, TCGv r2, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_madd32_d(ret, r1, r2, temp); + tcg_temp_free(temp); +} + +static inline void +gen_madd64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + TCGv r3) +{ + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + TCGv t4 = tcg_temp_new(); + + tcg_gen_muls2_tl(t1, t2, r1, r3); + /* only the add can overflow */ + tcg_gen_add2_tl(t3, t4, r2_low, r2_high, t1, t2); + /* calc V bit */ + tcg_gen_xor_tl(cpu_PSW_V, t4, r2_high); + tcg_gen_xor_tl(t1, r2_high, t2); + tcg_gen_andc_tl(cpu_PSW_V, cpu_PSW_V, t1); + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, t4, t4); + tcg_gen_xor_tl(cpu_PSW_AV, t4, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* write back the result */ + tcg_gen_mov_tl(ret_low, t3); + tcg_gen_mov_tl(ret_high, t4); + + tcg_temp_free(t1); + tcg_temp_free(t2); + tcg_temp_free(t3); + tcg_temp_free(t4); +} + +static inline void +gen_maddu64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + TCGv r3) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(t1, r1); + tcg_gen_concat_i32_i64(t2, r2_low, r2_high); + tcg_gen_extu_i32_i64(t3, r3); + + tcg_gen_mul_i64(t1, t1, t3); + tcg_gen_add_i64(t2, t2, t1); + /* write back result */ + tcg_gen_extr_i64_i32(ret_low, ret_high, t2); + /* only the add overflows, if t2 < t1 + calc V bit */ + tcg_gen_setcond_i64(TCG_COND_LTU, t2, t2, t1); + tcg_gen_trunc_i64_i32(cpu_PSW_V, t2); + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, ret_high, ret_high); + tcg_gen_xor_tl(cpu_PSW_AV, ret_high, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); +} + +static inline void +gen_maddi64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_madd64_d(ret_low, ret_high, r1, r2_low, r2_high, temp); + tcg_temp_free(temp); +} + +static inline void +gen_maddui64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_maddu64_d(ret_low, ret_high, r1, r2_low, r2_high, temp); + tcg_temp_free(temp); +} + +/* ret = r2 - (r1 * r3); */ +static inline void gen_msub32_d(TCGv ret, TCGv r1, TCGv r2, TCGv r3) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(t1, r1); + tcg_gen_ext_i32_i64(t2, r2); + tcg_gen_ext_i32_i64(t3, r3); + + tcg_gen_mul_i64(t1, t1, t3); + tcg_gen_sub_i64(t1, t2, t1); + + tcg_gen_trunc_i64_i32(ret, t1); + /* calc V + t2 > 0x7fffffff */ + tcg_gen_setcondi_i64(TCG_COND_GT, t3, t1, 0x7fffffffLL); + /* result < -0x80000000 */ + tcg_gen_setcondi_i64(TCG_COND_LT, t2, t1, -0x80000000LL); + tcg_gen_or_i64(t2, t2, t3); + tcg_gen_trunc_i64_i32(cpu_PSW_V, t2); + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, ret, ret); + tcg_gen_xor_tl(cpu_PSW_AV, ret, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); +} + +static inline void gen_msubi32_d(TCGv ret, TCGv r1, TCGv r2, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_msub32_d(ret, r1, r2, temp); + tcg_temp_free(temp); +} + +static inline void +gen_msub64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + TCGv r3) +{ + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + TCGv t4 = tcg_temp_new(); + + tcg_gen_muls2_tl(t1, t2, r1, r3); + /* only the sub can overflow */ + tcg_gen_sub2_tl(t3, t4, r2_low, r2_high, t1, t2); + /* calc V bit */ + tcg_gen_xor_tl(cpu_PSW_V, t4, r2_high); + tcg_gen_xor_tl(t1, r2_high, t2); + tcg_gen_and_tl(cpu_PSW_V, cpu_PSW_V, t1); + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, t4, t4); + tcg_gen_xor_tl(cpu_PSW_AV, t4, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* write back the result */ + tcg_gen_mov_tl(ret_low, t3); + tcg_gen_mov_tl(ret_high, t4); + + tcg_temp_free(t1); + tcg_temp_free(t2); + tcg_temp_free(t3); + tcg_temp_free(t4); +} + +static inline void +gen_msubi64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_msub64_d(ret_low, ret_high, r1, r2_low, r2_high, temp); + tcg_temp_free(temp); +} + +static inline void +gen_msubu64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + TCGv r3) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(t1, r1); + tcg_gen_concat_i32_i64(t2, r2_low, r2_high); + tcg_gen_extu_i32_i64(t3, r3); + + tcg_gen_mul_i64(t1, t1, t3); + tcg_gen_sub_i64(t3, t2, t1); + tcg_gen_extr_i64_i32(ret_low, ret_high, t3); + /* calc V bit, only the sub can overflow, if t1 > t2 */ + tcg_gen_setcond_i64(TCG_COND_GTU, t1, t1, t2); + tcg_gen_trunc_i64_i32(cpu_PSW_V, t1); + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, ret_high, ret_high); + tcg_gen_xor_tl(cpu_PSW_AV, ret_high, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); +} + +static inline void +gen_msubui64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_msubu64_d(ret_low, ret_high, r1, r2_low, r2_high, temp); + tcg_temp_free(temp); +} + static inline void gen_addi_d(TCGv ret, TCGv r1, target_ulong r2) { TCGv temp = tcg_const_i32(r2); gen_add_d(ret, r1, temp); tcg_temp_free(temp); } +/* calculate the carry bit too */ +static inline void gen_add_CC(TCGv ret, TCGv r1, TCGv r2) +{ + TCGv t0 = tcg_temp_new_i32(); + TCGv result = tcg_temp_new_i32(); + + tcg_gen_movi_tl(t0, 0); + /* Addition and set C/V/SV bits */ + tcg_gen_add2_i32(result, cpu_PSW_C, r1, t0, r2, t0); + /* calc V bit */ + tcg_gen_xor_tl(cpu_PSW_V, result, r1); + tcg_gen_xor_tl(t0, r1, r2); + tcg_gen_andc_tl(cpu_PSW_V, cpu_PSW_V, t0); + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, result, result); + tcg_gen_xor_tl(cpu_PSW_AV, result, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* write back result */ + tcg_gen_mov_tl(ret, result); + + tcg_temp_free(result); + tcg_temp_free(t0); +} + +static inline void gen_addi_CC(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_add_CC(ret, r1, temp); + tcg_temp_free(temp); +} + +static inline void gen_addc_CC(TCGv ret, TCGv r1, TCGv r2) +{ + TCGv carry = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + TCGv result = tcg_temp_new_i32(); + + tcg_gen_movi_tl(t0, 0); + tcg_gen_setcondi_tl(TCG_COND_NE, carry, cpu_PSW_C, 0); + /* Addition, carry and set C/V/SV bits */ + tcg_gen_add2_i32(result, cpu_PSW_C, r1, t0, carry, t0); + tcg_gen_add2_i32(result, cpu_PSW_C, result, cpu_PSW_C, r2, t0); + /* calc V bit */ + tcg_gen_xor_tl(cpu_PSW_V, result, r1); + tcg_gen_xor_tl(t0, r1, r2); + tcg_gen_andc_tl(cpu_PSW_V, cpu_PSW_V, t0); + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, result, result); + tcg_gen_xor_tl(cpu_PSW_AV, result, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* write back result */ + tcg_gen_mov_tl(ret, result); + + tcg_temp_free(result); + tcg_temp_free(t0); + tcg_temp_free(carry); +} + +static inline void gen_addci_CC(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_addc_CC(ret, r1, temp); + tcg_temp_free(temp); +} static inline void gen_cond_add(TCGCond cond, TCGv r1, TCGv r2, TCGv r3, TCGv r4) @@ -337,6 +719,49 @@ static inline void gen_sub_d(TCGv ret, TCGv r1, TCGv r2) tcg_temp_free(result); } +static inline void gen_absdif(TCGv ret, TCGv r1, TCGv r2) +{ + TCGv temp = tcg_temp_new_i32(); + TCGv result = tcg_temp_new_i32(); + + tcg_gen_sub_tl(result, r1, r2); + tcg_gen_sub_tl(temp, r2, r1); + tcg_gen_movcond_tl(TCG_COND_GT, result, r1, r2, result, temp); + + /* calc V bit */ + tcg_gen_xor_tl(cpu_PSW_V, result, r1); + tcg_gen_xor_tl(temp, result, r2); + tcg_gen_movcond_tl(TCG_COND_GT, cpu_PSW_V, r1, r2, cpu_PSW_V, temp); + tcg_gen_xor_tl(temp, r1, r2); + tcg_gen_and_tl(cpu_PSW_V, cpu_PSW_V, temp); + /* calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV bit */ + tcg_gen_add_tl(cpu_PSW_AV, result, result); + tcg_gen_xor_tl(cpu_PSW_AV, result, cpu_PSW_AV); + /* calc SAV bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* write back result */ + tcg_gen_mov_tl(ret, result); + + tcg_temp_free(temp); + tcg_temp_free(result); +} + +static inline void gen_absdifi(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_absdif(ret, r1, temp); + tcg_temp_free(temp); +} + +static inline void gen_absdifsi(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_absdif_ssov(ret, cpu_env, r1, temp); + tcg_temp_free(temp); +} + static inline void gen_mul_i32s(TCGv ret, TCGv r1, TCGv r2) { TCGv high = tcg_temp_new(); @@ -360,6 +785,151 @@ static inline void gen_mul_i32s(TCGv ret, TCGv r1, TCGv r2) tcg_temp_free(low); } +static inline void gen_muli_i32s(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_mul_i32s(ret, r1, temp); + tcg_temp_free(temp); +} + +static inline void gen_mul_i64s(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2) +{ + tcg_gen_muls2_tl(ret_low, ret_high, r1, r2); + /* clear V bit */ + tcg_gen_movi_tl(cpu_PSW_V, 0); + /* calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV bit */ + tcg_gen_add_tl(cpu_PSW_AV, ret_high, ret_high); + tcg_gen_xor_tl(cpu_PSW_AV, ret_high, cpu_PSW_AV); + /* calc SAV bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); +} + +static inline void gen_muli_i64s(TCGv ret_low, TCGv ret_high, TCGv r1, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_mul_i64s(ret_low, ret_high, r1, temp); + tcg_temp_free(temp); +} + +static inline void gen_mul_i64u(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2) +{ + tcg_gen_mulu2_tl(ret_low, ret_high, r1, r2); + /* clear V bit */ + tcg_gen_movi_tl(cpu_PSW_V, 0); + /* calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV bit */ + tcg_gen_add_tl(cpu_PSW_AV, ret_high, ret_high); + tcg_gen_xor_tl(cpu_PSW_AV, ret_high, cpu_PSW_AV); + /* calc SAV bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); +} + +static inline void gen_muli_i64u(TCGv ret_low, TCGv ret_high, TCGv r1, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_mul_i64u(ret_low, ret_high, r1, temp); + tcg_temp_free(temp); +} + +static inline void gen_mulsi_i32(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_mul_ssov(ret, cpu_env, r1, temp); + tcg_temp_free(temp); +} + +static inline void gen_mulsui_i32(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_mul_suov(ret, cpu_env, r1, temp); + tcg_temp_free(temp); +} +/* gen_maddsi_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); */ +static inline void gen_maddsi_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_madd32_ssov(ret, cpu_env, r1, r2, temp); + tcg_temp_free(temp); +} + +static inline void gen_maddsui_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_madd32_suov(ret, cpu_env, r1, r2, temp); + tcg_temp_free(temp); +} + +static inline void +gen_maddsi_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + TCGv_i64 temp64 = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); + gen_helper_madd64_ssov(temp64, cpu_env, r1, temp64, temp); + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); +} + +static inline void +gen_maddsui_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + TCGv_i64 temp64 = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); + gen_helper_madd64_suov(temp64, cpu_env, r1, temp64, temp); + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); +} + +static inline void gen_msubsi_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_msub32_ssov(ret, cpu_env, r1, r2, temp); + tcg_temp_free(temp); +} + +static inline void gen_msubsui_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_msub32_suov(ret, cpu_env, r1, r2, temp); + tcg_temp_free(temp); +} + +static inline void +gen_msubsi_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + TCGv_i64 temp64 = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); + gen_helper_msub64_ssov(temp64, cpu_env, r1, temp64, temp); + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); +} + +static inline void +gen_msubsui_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + int32_t con) +{ + TCGv temp = tcg_const_i32(con); + TCGv_i64 temp64 = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); + gen_helper_msub64_suov(temp64, cpu_env, r1, temp64, temp); + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); +} + static void gen_saturate(TCGv ret, TCGv arg, int32_t up, int32_t low) { TCGv sat_neg = tcg_const_i32(low); @@ -394,6 +964,27 @@ static void gen_shi(TCGv ret, TCGv r1, int32_t shift_count) } } +static void gen_sh_hi(TCGv ret, TCGv r1, int32_t shiftcount) +{ + TCGv temp_low, temp_high; + + if (shiftcount == -16) { + tcg_gen_movi_tl(ret, 0); + } else { + temp_high = tcg_temp_new(); + temp_low = tcg_temp_new(); + + tcg_gen_andi_tl(temp_low, r1, 0xffff); + tcg_gen_andi_tl(temp_high, r1, 0xffff0000); + gen_shi(temp_low, temp_low, shiftcount); + gen_shi(ret, temp_high, shiftcount); + tcg_gen_deposit_tl(ret, ret, temp_low, 0, 16); + + tcg_temp_free(temp_low); + tcg_temp_free(temp_high); + } +} + static void gen_shaci(TCGv ret, TCGv r1, int32_t shift_count) { uint32_t msk, msk_start; @@ -453,16 +1044,100 @@ static void gen_shaci(TCGv ret, TCGv r1, int32_t shift_count) tcg_temp_free(t_0); } +static void gen_shas(TCGv ret, TCGv r1, TCGv r2) +{ + gen_helper_sha_ssov(ret, cpu_env, r1, r2); +} + +static void gen_shasi(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_shas(ret, r1, temp); + tcg_temp_free(temp); +} + +static void gen_sha_hi(TCGv ret, TCGv r1, int32_t shift_count) +{ + TCGv low, high; + + if (shift_count == 0) { + tcg_gen_mov_tl(ret, r1); + } else if (shift_count > 0) { + low = tcg_temp_new(); + high = tcg_temp_new(); + + tcg_gen_andi_tl(high, r1, 0xffff0000); + tcg_gen_shli_tl(low, r1, shift_count); + tcg_gen_shli_tl(ret, high, shift_count); + tcg_gen_deposit_tl(ret, ret, low, 0, 16); + + tcg_temp_free(low); + tcg_temp_free(high); + } else { + low = tcg_temp_new(); + high = tcg_temp_new(); + + tcg_gen_ext16s_tl(low, r1); + tcg_gen_sari_tl(low, low, -shift_count); + tcg_gen_sari_tl(ret, r1, -shift_count); + tcg_gen_deposit_tl(ret, ret, low, 0, 16); + + tcg_temp_free(low); + tcg_temp_free(high); + } + +} + +/* ret = {ret[30:0], (r1 cond r2)}; */ +static void gen_sh_cond(int cond, TCGv ret, TCGv r1, TCGv r2) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + + tcg_gen_shli_tl(temp, ret, 1); + tcg_gen_setcond_tl(cond, temp2, r1, r2); + tcg_gen_or_tl(ret, temp, temp2); + + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +static void gen_sh_condi(int cond, TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_sh_cond(cond, ret, r1, temp); + tcg_temp_free(temp); +} + static inline void gen_adds(TCGv ret, TCGv r1, TCGv r2) { gen_helper_add_ssov(ret, cpu_env, r1, r2); } +static inline void gen_addsi(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_add_ssov(ret, cpu_env, r1, temp); + tcg_temp_free(temp); +} + +static inline void gen_addsui(TCGv ret, TCGv r1, int32_t con) +{ + TCGv temp = tcg_const_i32(con); + gen_helper_add_suov(ret, cpu_env, r1, temp); + tcg_temp_free(temp); +} + static inline void gen_subs(TCGv ret, TCGv r1, TCGv r2) { gen_helper_sub_ssov(ret, cpu_env, r1, r2); } +static inline void gen_subsu(TCGv ret, TCGv r1, TCGv r2) +{ + gen_helper_sub_suov(ret, cpu_env, r1, r2); +} + static inline void gen_bit_2op(TCGv ret, TCGv r1, TCGv r2, int pos1, int pos2, void(*op1)(TCGv, TCGv, TCGv), @@ -506,6 +1181,109 @@ static inline void gen_bit_1op(TCGv ret, TCGv r1, TCGv r2, tcg_temp_free(temp2); } +static inline void gen_accumulating_cond(int cond, TCGv ret, TCGv r1, TCGv r2, + void(*op)(TCGv, TCGv, TCGv)) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + /* temp = (arg1 cond arg2 )*/ + tcg_gen_setcond_tl(cond, temp, r1, r2); + /* temp2 = ret[0]*/ + tcg_gen_andi_tl(temp2, ret, 0x1); + /* temp = temp insn temp2 */ + (*op)(temp, temp, temp2); + /* ret = {ret[31:1], temp} */ + tcg_gen_deposit_tl(ret, ret, temp, 0, 1); + + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +static inline void +gen_accumulating_condi(int cond, TCGv ret, TCGv r1, int32_t con, + void(*op)(TCGv, TCGv, TCGv)) +{ + TCGv temp = tcg_const_i32(con); + gen_accumulating_cond(cond, ret, r1, temp, op); + tcg_temp_free(temp); +} + +static inline void gen_eqany_bi(TCGv ret, TCGv r1, int32_t con) +{ + TCGv b0 = tcg_temp_new(); + TCGv b1 = tcg_temp_new(); + TCGv b2 = tcg_temp_new(); + TCGv b3 = tcg_temp_new(); + + /* byte 0 */ + tcg_gen_andi_tl(b0, r1, 0xff); + tcg_gen_setcondi_tl(TCG_COND_EQ, b0, b0, con & 0xff); + + /* byte 1 */ + tcg_gen_andi_tl(b1, r1, 0xff00); + tcg_gen_setcondi_tl(TCG_COND_EQ, b1, b1, con & 0xff00); + + /* byte 2 */ + tcg_gen_andi_tl(b2, r1, 0xff0000); + tcg_gen_setcondi_tl(TCG_COND_EQ, b2, b2, con & 0xff0000); + + /* byte 3 */ + tcg_gen_andi_tl(b3, r1, 0xff000000); + tcg_gen_setcondi_tl(TCG_COND_EQ, b3, b3, con & 0xff000000); + + /* combine them */ + tcg_gen_or_tl(ret, b0, b1); + tcg_gen_or_tl(ret, ret, b2); + tcg_gen_or_tl(ret, ret, b3); + + tcg_temp_free(b0); + tcg_temp_free(b1); + tcg_temp_free(b2); + tcg_temp_free(b3); +} + +static inline void gen_eqany_hi(TCGv ret, TCGv r1, int32_t con) +{ + TCGv h0 = tcg_temp_new(); + TCGv h1 = tcg_temp_new(); + + /* halfword 0 */ + tcg_gen_andi_tl(h0, r1, 0xffff); + tcg_gen_setcondi_tl(TCG_COND_EQ, h0, h0, con & 0xffff); + + /* halfword 1 */ + tcg_gen_andi_tl(h1, r1, 0xffff0000); + tcg_gen_setcondi_tl(TCG_COND_EQ, h1, h1, con & 0xffff0000); + + /* combine them */ + tcg_gen_or_tl(ret, h0, h1); + + tcg_temp_free(h0); + tcg_temp_free(h1); +} +/* mask = ((1 << width) -1) << pos; + ret = (r1 & ~mask) | (r2 << pos) & mask); */ +static inline void gen_insert(TCGv ret, TCGv r1, TCGv r2, TCGv width, TCGv pos) +{ + TCGv mask = tcg_temp_new(); + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + + tcg_gen_movi_tl(mask, 1); + tcg_gen_shl_tl(mask, mask, width); + tcg_gen_subi_tl(mask, mask, 1); + tcg_gen_shl_tl(mask, mask, pos); + + tcg_gen_shl_tl(temp, r2, pos); + tcg_gen_and_tl(temp, temp, mask); + tcg_gen_andc_tl(temp2, r1, mask); + tcg_gen_or_tl(ret, temp, temp2); + + tcg_temp_free(mask); + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + /* helpers for generating program flow micro-ops */ static inline void gen_save_pc(target_ulong pc) @@ -567,7 +1345,8 @@ static void gen_loop(DisasContext *ctx, int r1, int32_t offset) static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, int r2 , int32_t constant , int32_t offset) { - TCGv temp; + TCGv temp, temp2; + int n; switch (opc) { /* SB-format jumps */ @@ -665,6 +1444,134 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, tcg_gen_movi_tl(cpu_gpr_a[11], ctx->next_pc); gen_goto_tb(ctx, 0, ctx->pc + offset * 2); break; +/* BOL format */ + case OPCM_32_BRC_EQ_NEQ: + if (MASK_OP_BRC_OP2(ctx->opcode) == OPC2_32_BRC_JEQ) { + gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_d[r1], constant, offset); + } else { + gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_d[r1], constant, offset); + } + break; + case OPCM_32_BRC_GE: + if (MASK_OP_BRC_OP2(ctx->opcode) == OP2_32_BRC_JGE) { + gen_branch_condi(ctx, TCG_COND_GE, cpu_gpr_d[r1], constant, offset); + } else { + constant = MASK_OP_BRC_CONST4(ctx->opcode); + gen_branch_condi(ctx, TCG_COND_GEU, cpu_gpr_d[r1], constant, + offset); + } + break; + case OPCM_32_BRC_JLT: + if (MASK_OP_BRC_OP2(ctx->opcode) == OPC2_32_BRC_JLT) { + gen_branch_condi(ctx, TCG_COND_LT, cpu_gpr_d[r1], constant, offset); + } else { + constant = MASK_OP_BRC_CONST4(ctx->opcode); + gen_branch_condi(ctx, TCG_COND_LTU, cpu_gpr_d[r1], constant, + offset); + } + break; + case OPCM_32_BRC_JNE: + temp = tcg_temp_new(); + if (MASK_OP_BRC_OP2(ctx->opcode) == OPC2_32_BRC_JNED) { + tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); + /* subi is unconditional */ + tcg_gen_subi_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 1); + gen_branch_condi(ctx, TCG_COND_NE, temp, constant, offset); + } else { + tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); + /* addi is unconditional */ + tcg_gen_addi_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 1); + gen_branch_condi(ctx, TCG_COND_NE, temp, constant, offset); + } + tcg_temp_free(temp); + break; +/* BRN format */ + case OPCM_32_BRN_JTT: + n = MASK_OP_BRN_N(ctx->opcode); + + temp = tcg_temp_new(); + tcg_gen_andi_tl(temp, cpu_gpr_d[r1], (1 << n)); + + if (MASK_OP_BRN_OP2(ctx->opcode) == OPC2_32_BRN_JNZ_T) { + gen_branch_condi(ctx, TCG_COND_NE, temp, 0, offset); + } else { + gen_branch_condi(ctx, TCG_COND_EQ, temp, 0, offset); + } + tcg_temp_free(temp); + break; +/* BRR Format */ + case OPCM_32_BRR_EQ_NEQ: + if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JEQ) { + gen_branch_cond(ctx, TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[r2], + offset); + } else { + gen_branch_cond(ctx, TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[r2], + offset); + } + break; + case OPCM_32_BRR_ADDR_EQ_NEQ: + if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JEQ_A) { + gen_branch_cond(ctx, TCG_COND_EQ, cpu_gpr_a[r1], cpu_gpr_a[r2], + offset); + } else { + gen_branch_cond(ctx, TCG_COND_NE, cpu_gpr_a[r1], cpu_gpr_a[r2], + offset); + } + break; + case OPCM_32_BRR_GE: + if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JGE) { + gen_branch_cond(ctx, TCG_COND_GE, cpu_gpr_d[r1], cpu_gpr_d[r2], + offset); + } else { + gen_branch_cond(ctx, TCG_COND_GEU, cpu_gpr_d[r1], cpu_gpr_d[r2], + offset); + } + break; + case OPCM_32_BRR_JLT: + if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JLT) { + gen_branch_cond(ctx, TCG_COND_LT, cpu_gpr_d[r1], cpu_gpr_d[r2], + offset); + } else { + gen_branch_cond(ctx, TCG_COND_LTU, cpu_gpr_d[r1], cpu_gpr_d[r2], + offset); + } + break; + case OPCM_32_BRR_LOOP: + if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_LOOP) { + gen_loop(ctx, r1, offset * 2); + } else { + /* OPC2_32_BRR_LOOPU */ + gen_goto_tb(ctx, 0, ctx->pc + offset * 2); + } + break; + case OPCM_32_BRR_JNE: + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + if (MASK_OP_BRC_OP2(ctx->opcode) == OPC2_32_BRR_JNED) { + tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); + /* also save r2, in case of r1 == r2, so r2 is not decremented */ + tcg_gen_mov_tl(temp2, cpu_gpr_d[r2]); + /* subi is unconditional */ + tcg_gen_subi_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 1); + gen_branch_cond(ctx, TCG_COND_NE, temp, temp2, offset); + } else { + tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); + /* also save r2, in case of r1 == r2, so r2 is not decremented */ + tcg_gen_mov_tl(temp2, cpu_gpr_d[r2]); + /* addi is unconditional */ + tcg_gen_addi_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 1); + gen_branch_cond(ctx, TCG_COND_NE, temp, temp2, offset); + } + tcg_temp_free(temp); + tcg_temp_free(temp2); + break; + case OPCM_32_BRR_JNZ: + if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JNZ_A) { + gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_a[r1], 0, offset); + } else { + gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_a[r1], 0, offset); + } + break; default: printf("Branch Error at %x\n", ctx->pc); } @@ -1712,17 +2619,17 @@ static void decode_bo_addrmode_post_pre_base(CPUTriCoreState *env, case OPC2_32_BO_CACHEI_WI_SHORTOFF: case OPC2_32_BO_CACHEI_W_SHORTOFF: /* TODO: Raise illegal opcode trap, - if tricore_feature(TRICORE_FEATURE_13) */ + if !tricore_feature(TRICORE_FEATURE_131) */ break; case OPC2_32_BO_CACHEI_W_POSTINC: case OPC2_32_BO_CACHEI_WI_POSTINC: - if (!tricore_feature(env, TRICORE_FEATURE_13)) { + if (tricore_feature(env, TRICORE_FEATURE_131)) { tcg_gen_addi_tl(cpu_gpr_d[r2], cpu_gpr_d[r2], off10); } /* TODO: else raise illegal opcode trap */ break; case OPC2_32_BO_CACHEI_W_PREINC: case OPC2_32_BO_CACHEI_WI_PREINC: - if (!tricore_feature(env, TRICORE_FEATURE_13)) { + if (tricore_feature(env, TRICORE_FEATURE_131)) { tcg_gen_addi_tl(cpu_gpr_d[r2], cpu_gpr_d[r2], off10); } /* TODO: else raise illegal opcode trap */ break; @@ -2279,17 +3186,633 @@ static void decode_bo_addrmode_ldmst_bitreverse_circular(CPUTriCoreState *env, tcg_temp_free(temp3); } +static void decode_bol_opc(CPUTriCoreState *env, DisasContext *ctx, int32_t op1) +{ + int r1, r2; + int32_t address; + TCGv temp; + + r1 = MASK_OP_BOL_S1D(ctx->opcode); + r2 = MASK_OP_BOL_S2(ctx->opcode); + address = MASK_OP_BOL_OFF16_SEXT(ctx->opcode); + + switch (op1) { + case OPC1_32_BOL_LD_A_LONGOFF: + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, cpu_gpr_a[r2], address); + tcg_gen_qemu_ld_tl(cpu_gpr_a[r1], temp, ctx->mem_idx, MO_LEUL); + tcg_temp_free(temp); + break; + case OPC1_32_BOL_LD_W_LONFOFF: + temp = tcg_temp_new(); + tcg_gen_addi_tl(temp, cpu_gpr_a[r2], address); + tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUL); + tcg_temp_free(temp); + break; + case OPC1_32_BOL_LEA_LONGOFF: + tcg_gen_addi_tl(cpu_gpr_a[r1], cpu_gpr_a[r2], address); + break; + case OPC1_32_BOL_ST_A_LONGOFF: + if (tricore_feature(env, TRICORE_FEATURE_16)) { + gen_offset_st(ctx, cpu_gpr_a[r1], cpu_gpr_a[r2], address, MO_LEUL); + } else { + /* raise illegal opcode trap */ + } + break; + case OPC1_32_BOL_ST_W_LONGOFF: + gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LEUL); + break; + } + +} + +/* RC format */ +static void decode_rc_logical_shift(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2; + int32_t const9; + TCGv temp; + + r2 = MASK_OP_RC_D(ctx->opcode); + r1 = MASK_OP_RC_S1(ctx->opcode); + const9 = MASK_OP_RC_CONST9(ctx->opcode); + op2 = MASK_OP_RC_OP2(ctx->opcode); + + temp = tcg_temp_new(); + + switch (op2) { + case OPC2_32_RC_AND: + tcg_gen_andi_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_ANDN: + tcg_gen_andi_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], ~const9); + break; + case OPC2_32_RC_NAND: + tcg_gen_movi_tl(temp, const9); + tcg_gen_nand_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], temp); + break; + case OPC2_32_RC_NOR: + tcg_gen_movi_tl(temp, const9); + tcg_gen_nor_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], temp); + break; + case OPC2_32_RC_OR: + tcg_gen_ori_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_ORN: + tcg_gen_ori_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], ~const9); + break; + case OPC2_32_RC_SH: + const9 = sextract32(const9, 0, 6); + gen_shi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SH_H: + const9 = sextract32(const9, 0, 5); + gen_sh_hi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SHA: + const9 = sextract32(const9, 0, 6); + gen_shaci(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SHA_H: + const9 = sextract32(const9, 0, 5); + gen_sha_hi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SHAS: + gen_shasi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_XNOR: + tcg_gen_xori_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + tcg_gen_not_tl(cpu_gpr_d[r2], cpu_gpr_d[r2]); + break; + case OPC2_32_RC_XOR: + tcg_gen_xori_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + } + tcg_temp_free(temp); +} + +static void decode_rc_accumulator(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2; + int16_t const9; + + TCGv temp; + + r2 = MASK_OP_RC_D(ctx->opcode); + r1 = MASK_OP_RC_S1(ctx->opcode); + const9 = MASK_OP_RC_CONST9_SEXT(ctx->opcode); + + op2 = MASK_OP_RC_OP2(ctx->opcode); + + temp = tcg_temp_new(); + + switch (op2) { + case OPC2_32_RC_ABSDIF: + gen_absdifi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_ABSDIFS: + gen_absdifsi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_ADD: + gen_addi_d(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_ADDC: + gen_addci_CC(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_ADDS: + gen_addsi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_ADDS_U: + gen_addsui(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_ADDX: + gen_addi_CC(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_AND_EQ: + gen_accumulating_condi(TCG_COND_EQ, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_and_tl); + break; + case OPC2_32_RC_AND_GE: + gen_accumulating_condi(TCG_COND_GE, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_and_tl); + break; + case OPC2_32_RC_AND_GE_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_accumulating_condi(TCG_COND_GEU, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_and_tl); + break; + case OPC2_32_RC_AND_LT: + gen_accumulating_condi(TCG_COND_LT, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_and_tl); + break; + case OPC2_32_RC_AND_LT_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_accumulating_condi(TCG_COND_LTU, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_and_tl); + break; + case OPC2_32_RC_AND_NE: + gen_accumulating_condi(TCG_COND_NE, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_and_tl); + break; + case OPC2_32_RC_EQ: + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_EQANY_B: + gen_eqany_bi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_EQANY_H: + gen_eqany_hi(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_GE: + tcg_gen_setcondi_tl(TCG_COND_GE, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_GE_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_LT: + tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_LT_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_MAX: + tcg_gen_movi_tl(temp, const9); + tcg_gen_movcond_tl(TCG_COND_GT, cpu_gpr_d[r2], cpu_gpr_d[r1], temp, + cpu_gpr_d[r1], temp); + break; + case OPC2_32_RC_MAX_U: + tcg_gen_movi_tl(temp, MASK_OP_RC_CONST9(ctx->opcode)); + tcg_gen_movcond_tl(TCG_COND_GTU, cpu_gpr_d[r2], cpu_gpr_d[r1], temp, + cpu_gpr_d[r1], temp); + break; + case OPC2_32_RC_MIN: + tcg_gen_movi_tl(temp, const9); + tcg_gen_movcond_tl(TCG_COND_LT, cpu_gpr_d[r2], cpu_gpr_d[r1], temp, + cpu_gpr_d[r1], temp); + break; + case OPC2_32_RC_MIN_U: + tcg_gen_movi_tl(temp, MASK_OP_RC_CONST9(ctx->opcode)); + tcg_gen_movcond_tl(TCG_COND_LTU, cpu_gpr_d[r2], cpu_gpr_d[r1], temp, + cpu_gpr_d[r1], temp); + break; + case OPC2_32_RC_NE: + tcg_gen_setcondi_tl(TCG_COND_NE, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_OR_EQ: + gen_accumulating_condi(TCG_COND_EQ, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_or_tl); + break; + case OPC2_32_RC_OR_GE: + gen_accumulating_condi(TCG_COND_GE, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_or_tl); + break; + case OPC2_32_RC_OR_GE_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_accumulating_condi(TCG_COND_GEU, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_or_tl); + break; + case OPC2_32_RC_OR_LT: + gen_accumulating_condi(TCG_COND_LT, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_or_tl); + break; + case OPC2_32_RC_OR_LT_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_accumulating_condi(TCG_COND_LTU, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_or_tl); + break; + case OPC2_32_RC_OR_NE: + gen_accumulating_condi(TCG_COND_NE, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_or_tl); + break; + case OPC2_32_RC_RSUB: + tcg_gen_movi_tl(temp, const9); + gen_sub_d(cpu_gpr_d[r2], temp, cpu_gpr_d[r1]); + break; + case OPC2_32_RC_RSUBS: + tcg_gen_movi_tl(temp, const9); + gen_subs(cpu_gpr_d[r2], temp, cpu_gpr_d[r1]); + break; + case OPC2_32_RC_RSUBS_U: + tcg_gen_movi_tl(temp, const9); + gen_subsu(cpu_gpr_d[r2], temp, cpu_gpr_d[r1]); + break; + case OPC2_32_RC_SH_EQ: + gen_sh_condi(TCG_COND_EQ, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SH_GE: + gen_sh_condi(TCG_COND_GE, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SH_GE_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_sh_condi(TCG_COND_GEU, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SH_LT: + gen_sh_condi(TCG_COND_LT, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SH_LT_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_sh_condi(TCG_COND_LTU, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_SH_NE: + gen_sh_condi(TCG_COND_NE, cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_XOR_EQ: + gen_accumulating_condi(TCG_COND_EQ, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_xor_tl); + break; + case OPC2_32_RC_XOR_GE: + gen_accumulating_condi(TCG_COND_GE, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_xor_tl); + break; + case OPC2_32_RC_XOR_GE_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_accumulating_condi(TCG_COND_GEU, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_xor_tl); + break; + case OPC2_32_RC_XOR_LT: + gen_accumulating_condi(TCG_COND_LT, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_xor_tl); + break; + case OPC2_32_RC_XOR_LT_U: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_accumulating_condi(TCG_COND_LTU, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_xor_tl); + break; + case OPC2_32_RC_XOR_NE: + gen_accumulating_condi(TCG_COND_NE, cpu_gpr_d[r2], cpu_gpr_d[r1], + const9, &tcg_gen_xor_tl); + break; + } + tcg_temp_free(temp); +} + +static void decode_rc_serviceroutine(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + uint32_t const9; + + op2 = MASK_OP_RC_OP2(ctx->opcode); + const9 = MASK_OP_RC_CONST9(ctx->opcode); + + switch (op2) { + case OPC2_32_RC_BISR: + gen_helper_1arg(bisr, const9); + break; + case OPC2_32_RC_SYSCALL: + /* TODO: Add exception generation */ + break; + } +} + +static void decode_rc_mul(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2; + int16_t const9; + + r2 = MASK_OP_RC_D(ctx->opcode); + r1 = MASK_OP_RC_S1(ctx->opcode); + const9 = MASK_OP_RC_CONST9_SEXT(ctx->opcode); + + op2 = MASK_OP_RC_OP2(ctx->opcode); + + switch (op2) { + case OPC2_32_RC_MUL_32: + gen_muli_i32s(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_MUL_64: + gen_muli_i64s(cpu_gpr_d[r2], cpu_gpr_d[r2+1], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_MULS_32: + gen_mulsi_i32(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_MUL_U_64: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_muli_i64u(cpu_gpr_d[r2], cpu_gpr_d[r2+1], cpu_gpr_d[r1], const9); + break; + case OPC2_32_RC_MULS_U_32: + const9 = MASK_OP_RC_CONST9(ctx->opcode); + gen_mulsui_i32(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); + break; + } +} + +/* RCPW format */ +static void decode_rcpw_insert(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2; + int32_t pos, width, const4; + + TCGv temp; + + op2 = MASK_OP_RCPW_OP2(ctx->opcode); + r1 = MASK_OP_RCPW_S1(ctx->opcode); + r2 = MASK_OP_RCPW_D(ctx->opcode); + const4 = MASK_OP_RCPW_CONST4(ctx->opcode); + width = MASK_OP_RCPW_WIDTH(ctx->opcode); + pos = MASK_OP_RCPW_POS(ctx->opcode); + + switch (op2) { + case OPC2_32_RCPW_IMASK: + /* if pos + width > 31 undefined result */ + if (pos + width <= 31) { + tcg_gen_movi_tl(cpu_gpr_d[r2+1], ((1u << width) - 1) << pos); + tcg_gen_movi_tl(cpu_gpr_d[r2], (const4 << pos)); + } + break; + case OPC2_32_RCPW_INSERT: + /* if pos + width > 32 undefined result */ + if (pos + width <= 32) { + temp = tcg_const_i32(const4); + tcg_gen_deposit_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], temp, pos, width); + tcg_temp_free(temp); + } + break; + } +} + +/* RCRW format */ + +static void decode_rcrw_insert(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r3, r4; + int32_t width, const4; + + TCGv temp, temp2, temp3; + + op2 = MASK_OP_RCRW_OP2(ctx->opcode); + r1 = MASK_OP_RCRW_S1(ctx->opcode); + r3 = MASK_OP_RCRW_S3(ctx->opcode); + r4 = MASK_OP_RCRW_D(ctx->opcode); + width = MASK_OP_RCRW_WIDTH(ctx->opcode); + const4 = MASK_OP_RCRW_CONST4(ctx->opcode); + + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + + switch (op2) { + case OPC2_32_RCRW_IMASK: + tcg_gen_andi_tl(temp, cpu_gpr_d[r4], 0x1f); + tcg_gen_movi_tl(temp2, (1 << width) - 1); + tcg_gen_shl_tl(cpu_gpr_d[r3 + 1], temp2, temp); + tcg_gen_movi_tl(temp2, const4); + tcg_gen_shl_tl(cpu_gpr_d[r3], temp2, temp); + break; + case OPC2_32_RCRW_INSERT: + temp3 = tcg_temp_new(); + + tcg_gen_movi_tl(temp, width); + tcg_gen_movi_tl(temp2, const4); + tcg_gen_andi_tl(temp3, cpu_gpr_d[r4], 0x1f); + gen_insert(cpu_gpr_d[r3], cpu_gpr_d[r1], temp2, temp, temp3); + + tcg_temp_free(temp3); + break; + } + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +/* RCR format */ + +static void decode_rcr_cond_select(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r3, r4; + int32_t const9; + + TCGv temp, temp2; + + op2 = MASK_OP_RCR_OP2(ctx->opcode); + r1 = MASK_OP_RCR_S1(ctx->opcode); + const9 = MASK_OP_RCR_CONST9_SEXT(ctx->opcode); + r3 = MASK_OP_RCR_S3(ctx->opcode); + r4 = MASK_OP_RCR_D(ctx->opcode); + + switch (op2) { + case OPC2_32_RCR_CADD: + gen_condi_add(TCG_COND_NE, cpu_gpr_d[r1], const9, cpu_gpr_d[r3], + cpu_gpr_d[r4]); + break; + case OPC2_32_RCR_CADDN: + gen_condi_add(TCG_COND_EQ, cpu_gpr_d[r1], const9, cpu_gpr_d[r3], + cpu_gpr_d[r4]); + break; + case OPC2_32_RCR_SEL: + temp = tcg_const_i32(0); + temp2 = tcg_const_i32(const9); + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r4], temp, + cpu_gpr_d[r1], temp2); + tcg_temp_free(temp); + tcg_temp_free(temp2); + break; + case OPC2_32_RCR_SELN: + temp = tcg_const_i32(0); + temp2 = tcg_const_i32(const9); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r4], temp, + cpu_gpr_d[r1], temp2); + tcg_temp_free(temp); + tcg_temp_free(temp2); + break; + } +} + +static void decode_rcr_madd(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r3, r4; + int32_t const9; + + + op2 = MASK_OP_RCR_OP2(ctx->opcode); + r1 = MASK_OP_RCR_S1(ctx->opcode); + const9 = MASK_OP_RCR_CONST9_SEXT(ctx->opcode); + r3 = MASK_OP_RCR_S3(ctx->opcode); + r4 = MASK_OP_RCR_D(ctx->opcode); + + switch (op2) { + case OPC2_32_RCR_MADD_32: + gen_maddi32_d(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); + break; + case OPC2_32_RCR_MADD_64: + gen_maddi64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); + break; + case OPC2_32_RCR_MADDS_32: + gen_maddsi_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); + break; + case OPC2_32_RCR_MADDS_64: + gen_maddsi_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); + break; + case OPC2_32_RCR_MADD_U_64: + const9 = MASK_OP_RCR_CONST9(ctx->opcode); + gen_maddui64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); + break; + case OPC2_32_RCR_MADDS_U_32: + const9 = MASK_OP_RCR_CONST9(ctx->opcode); + gen_maddsui_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); + break; + case OPC2_32_RCR_MADDS_U_64: + const9 = MASK_OP_RCR_CONST9(ctx->opcode); + gen_maddsui_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); + break; + } +} + +static void decode_rcr_msub(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r3, r4; + int32_t const9; + + + op2 = MASK_OP_RCR_OP2(ctx->opcode); + r1 = MASK_OP_RCR_S1(ctx->opcode); + const9 = MASK_OP_RCR_CONST9_SEXT(ctx->opcode); + r3 = MASK_OP_RCR_S3(ctx->opcode); + r4 = MASK_OP_RCR_D(ctx->opcode); + + switch (op2) { + case OPC2_32_RCR_MSUB_32: + gen_msubi32_d(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); + break; + case OPC2_32_RCR_MSUB_64: + gen_msubi64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); + break; + case OPC2_32_RCR_MSUBS_32: + gen_msubsi_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); + break; + case OPC2_32_RCR_MSUBS_64: + gen_msubsi_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); + break; + case OPC2_32_RCR_MSUB_U_64: + const9 = MASK_OP_RCR_CONST9(ctx->opcode); + gen_msubui64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); + break; + case OPC2_32_RCR_MSUBS_U_32: + const9 = MASK_OP_RCR_CONST9(ctx->opcode); + gen_msubsui_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); + break; + case OPC2_32_RCR_MSUBS_U_64: + const9 = MASK_OP_RCR_CONST9(ctx->opcode); + gen_msubsui_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); + break; + } +} + +/* RLC format */ + +static void decode_rlc_opc(CPUTriCoreState *env, DisasContext *ctx, + uint32_t op1) +{ + int32_t const16; + int r1, r2; + + const16 = MASK_OP_RLC_CONST16_SEXT(ctx->opcode); + r1 = MASK_OP_RLC_S1(ctx->opcode); + r2 = MASK_OP_RLC_D(ctx->opcode); + + switch (op1) { + case OPC1_32_RLC_ADDI: + gen_addi_CC(cpu_gpr_d[r2], cpu_gpr_d[r1], const16); + break; + case OPC1_32_RLC_ADDIH: + gen_addi_CC(cpu_gpr_d[r2], cpu_gpr_d[r1], const16 << 16); + break; + case OPC1_32_RLC_ADDIH_A: + tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r1], const16 << 16); + break; + case OPC1_32_RLC_MFCR: + gen_mfcr(env, cpu_gpr_d[r2], const16); + break; + case OPC1_32_RLC_MOV: + tcg_gen_movi_tl(cpu_gpr_d[r2], const16); + break; + case OPC1_32_RLC_MOV_U: + const16 = MASK_OP_RLC_CONST16(ctx->opcode); + tcg_gen_movi_tl(cpu_gpr_d[r2], const16); + break; + case OPC1_32_RLC_MOV_H: + tcg_gen_movi_tl(cpu_gpr_d[r2], const16 << 16); + break; + case OPC1_32_RLC_MOVH_A: + tcg_gen_movi_tl(cpu_gpr_a[r2], const16 << 16); + break; + case OPC1_32_RLC_MTCR: + gen_mtcr(env, ctx, cpu_gpr_d[r2], const16); + break; + } +} + static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) { int op1; - int32_t r1; - int32_t address; - int8_t b; + int32_t r1, r2, r3; + int32_t address, const16; + int8_t b, const4; int32_t bpos; - TCGv temp, temp2; + TCGv temp, temp2, temp3; op1 = MASK_OP_MAJOR(ctx->opcode); + /* handle JNZ.T opcode only being 6 bit long */ + if (unlikely((op1 & 0x3f) == OPCM_32_BRN_JTT)) { + op1 = OPCM_32_BRN_JTT; + } + switch (op1) { /* ABS-format */ case OPCM_32_ABS_LDW: @@ -2405,6 +3928,105 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) case OPCM_32_BO_ADDRMODE_LDMST_BITREVERSE_CIRCULAR: decode_bo_addrmode_ldmst_bitreverse_circular(env, ctx); break; +/* BOL-format */ + case OPC1_32_BOL_LD_A_LONGOFF: + case OPC1_32_BOL_LD_W_LONFOFF: + case OPC1_32_BOL_LEA_LONGOFF: + case OPC1_32_BOL_ST_W_LONGOFF: + case OPC1_32_BOL_ST_A_LONGOFF: + decode_bol_opc(env, ctx, op1); + break; +/* BRC Format */ + case OPCM_32_BRC_EQ_NEQ: + case OPCM_32_BRC_GE: + case OPCM_32_BRC_JLT: + case OPCM_32_BRC_JNE: + const4 = MASK_OP_BRC_CONST4_SEXT(ctx->opcode); + address = MASK_OP_BRC_DISP15_SEXT(ctx->opcode); + r1 = MASK_OP_BRC_S1(ctx->opcode); + gen_compute_branch(ctx, op1, r1, 0, const4, address); + break; +/* BRN Format */ + case OPCM_32_BRN_JTT: + address = MASK_OP_BRN_DISP15_SEXT(ctx->opcode); + r1 = MASK_OP_BRN_S1(ctx->opcode); + gen_compute_branch(ctx, op1, r1, 0, 0, address); + break; +/* BRR Format */ + case OPCM_32_BRR_EQ_NEQ: + case OPCM_32_BRR_ADDR_EQ_NEQ: + case OPCM_32_BRR_GE: + case OPCM_32_BRR_JLT: + case OPCM_32_BRR_JNE: + case OPCM_32_BRR_JNZ: + case OPCM_32_BRR_LOOP: + address = MASK_OP_BRR_DISP15_SEXT(ctx->opcode); + r2 = MASK_OP_BRR_S2(ctx->opcode); + r1 = MASK_OP_BRR_S1(ctx->opcode); + gen_compute_branch(ctx, op1, r1, r2, 0, address); + break; +/* RC Format */ + case OPCM_32_RC_LOGICAL_SHIFT: + decode_rc_logical_shift(env, ctx); + break; + case OPCM_32_RC_ACCUMULATOR: + decode_rc_accumulator(env, ctx); + break; + case OPCM_32_RC_SERVICEROUTINE: + decode_rc_serviceroutine(env, ctx); + break; + case OPCM_32_RC_MUL: + decode_rc_mul(env, ctx); + break; +/* RCPW Format */ + case OPCM_32_RCPW_MASK_INSERT: + decode_rcpw_insert(env, ctx); + break; +/* RCRR Format */ + case OPC1_32_RCRR_INSERT: + r1 = MASK_OP_RCRR_S1(ctx->opcode); + r2 = MASK_OP_RCRR_S3(ctx->opcode); + r3 = MASK_OP_RCRR_D(ctx->opcode); + const16 = MASK_OP_RCRR_CONST4(ctx->opcode); + temp = tcg_const_i32(const16); + temp2 = tcg_temp_new(); /* width*/ + temp3 = tcg_temp_new(); /* pos */ + + tcg_gen_andi_tl(temp2, cpu_gpr_d[r3+1], 0x1f); + tcg_gen_andi_tl(temp3, cpu_gpr_d[r3], 0x1f); + + gen_insert(cpu_gpr_d[r2], cpu_gpr_d[r1], temp, temp2, temp3); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free(temp3); + break; +/* RCRW Format */ + case OPCM_32_RCRW_MASK_INSERT: + decode_rcrw_insert(env, ctx); + break; +/* RCR Format */ + case OPCM_32_RCR_COND_SELECT: + decode_rcr_cond_select(env, ctx); + break; + case OPCM_32_RCR_MADD: + decode_rcr_madd(env, ctx); + break; + case OPCM_32_RCR_MSUB: + decode_rcr_msub(env, ctx); + break; +/* RLC Format */ + case OPC1_32_RLC_ADDI: + case OPC1_32_RLC_ADDIH: + case OPC1_32_RLC_ADDIH_A: + case OPC1_32_RLC_MFCR: + case OPC1_32_RLC_MOV: + case OPC1_32_RLC_MOV_U: + case OPC1_32_RLC_MOV_H: + case OPC1_32_RLC_MOVH_A: + case OPC1_32_RLC_MTCR: + decode_rlc_opc(env, ctx, op1); + break; } } diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h index 7e6f33bd62..0a9122cfb9 100644 --- a/target-tricore/tricore-opcodes.h +++ b/target-tricore/tricore-opcodes.h @@ -115,25 +115,31 @@ #define MASK_OP_BOL_OFF16(op) ((MASK_BITS_SHIFT(op, 16, 21) + \ (MASK_BITS_SHIFT(op, 28, 31) << 6)) + \ (MASK_BITS_SHIFT(op, 22, 27) >> 10)) - +#define MASK_OP_BOL_OFF16_SEXT(op) ((MASK_BITS_SHIFT(op, 16, 21) + \ + (MASK_BITS_SHIFT(op, 28, 31) << 6)) + \ + (MASK_BITS_SHIFT_SEXT(op, 22, 27) << 10)) #define MASK_OP_BOL_S2(op) MASK_BITS_SHIFT(op, 12, 15) #define MASK_OP_BOL_S1D(op) MASK_BITS_SHIFT(op, 8, 11) /* BRC Format */ #define MASK_OP_BRC_OP2(op) MASK_BITS_SHIFT(op, 31, 31) #define MASK_OP_BRC_DISP15(op) MASK_BITS_SHIFT(op, 16, 30) +#define MASK_OP_BRC_DISP15_SEXT(op) MASK_BITS_SHIFT_SEXT(op, 16, 30) #define MASK_OP_BRC_CONST4(op) MASK_BITS_SHIFT(op, 12, 15) +#define MASK_OP_BRC_CONST4_SEXT(op) MASK_BITS_SHIFT_SEXT(op, 12, 15) #define MASK_OP_BRC_S1(op) MASK_BITS_SHIFT(op, 8, 11) /* BRN Format */ #define MASK_OP_BRN_OP2(op) MASK_BITS_SHIFT(op, 31, 31) #define MASK_OP_BRN_DISP15(op) MASK_BITS_SHIFT(op, 16, 30) +#define MASK_OP_BRN_DISP15_SEXT(op) MASK_BITS_SHIFT_SEXT(op, 16, 30) #define MASK_OP_BRN_N(op) (MASK_BITS_SHIFT(op, 12, 15) + \ (MASK_BITS_SHIFT(op, 7, 7) << 4)) #define MASK_OP_BRN_S1(op) MASK_BITS_SHIFT(op, 8, 11) /* BRR Format */ #define MASK_OP_BRR_OP2(op) MASK_BITS_SHIFT(op, 31, 31) #define MASK_OP_BRR_DISP15(op) MASK_BITS_SHIFT(op, 16, 30) +#define MASK_OP_BRR_DISP15_SEXT(op) MASK_BITS_SHIFT_SEXT(op, 16, 30) #define MASK_OP_BRR_S2(op) MASK_BITS_SHIFT(op, 12, 15) #define MASK_OP_BRR_S1(op) MASK_BITS_SHIFT(op, 8, 11) @@ -145,6 +151,7 @@ #define MASK_OP_RC_D(op) MASK_OP_META_D(op) #define MASK_OP_RC_OP2(op) MASK_BITS_SHIFT(op, 21, 27) #define MASK_OP_RC_CONST9(op) MASK_BITS_SHIFT(op, 12, 20) +#define MASK_OP_RC_CONST9_SEXT(op) MASK_BITS_SHIFT_SEXT(op, 12, 20) #define MASK_OP_RC_S1(op) MASK_OP_META_S1(op) /* RCPW Format */ @@ -162,6 +169,7 @@ #define MASK_OP_RCR_S3(op) MASK_BITS_SHIFT(op, 24, 27) #define MASK_OP_RCR_OP2(op) MASK_BITS_SHIFT(op, 21, 23) #define MASK_OP_RCR_CONST9(op) MASK_BITS_SHIFT(op, 12, 20) +#define MASK_OP_RCR_CONST9_SEXT(op) MASK_BITS_SHIFT_SEXT(op, 12, 20) #define MASK_OP_RCR_S1(op) MASK_OP_META_S1(op) /* RCRR Format */ @@ -185,6 +193,7 @@ #define MASK_OP_RLC_D(op) MASK_OP_META_D(op) #define MASK_OP_RLC_CONST16(op) MASK_BITS_SHIFT(op, 12, 27) +#define MASK_OP_RLC_CONST16_SEXT(op) MASK_BITS_SHIFT_SEXT(op, 12, 27) #define MASK_OP_RLC_S1(op) MASK_OP_META_S1(op) /* RR Format */ @@ -763,8 +772,8 @@ enum { }; /* OPCM_32_BRC_GE */ enum { - OP2_BRC_JGE = 0x00, - OPC_BRC_JGE_U = 0x01, + OP2_32_BRC_JGE = 0x00, + OPC_32_BRC_JGE_U = 0x01, }; /* OPCM_32_BRC_JLT */ enum { @@ -937,7 +946,7 @@ enum { OPC2_32_RCR_MSUB_64 = 0x03, OPC2_32_RCR_MSUBS_32 = 0x05, OPC2_32_RCR_MSUBS_64 = 0x07, - OPC2_32_RCR_MSUB_U_32 = 0x02, + OPC2_32_RCR_MSUB_U_64 = 0x02, OPC2_32_RCR_MSUBS_U_32 = 0x04, OPC2_32_RCR_MSUBS_U_64 = 0x06, }; diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 4c77ebec7a..e77fa3a25c 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -487,7 +487,8 @@ static void qtest_shutdown(void) */ static QPCIDevice *ahci_boot(void) { - qtest_boot("-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s" + qtest_boot("-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s," + "format=raw" " -M q35 " "-device ide-hd,drive=drive0 " "-global ide-hd.ver=%s", diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 9e4d20592b..2519f7d0e2 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -716,7 +716,7 @@ static void test_acpi_one(const char *params, test_data *data) int i; args = g_strdup_printf("-net none -display none %s " - "-drive id=hd0,if=none,file=%s " + "-drive id=hd0,if=none,file=%s,format=raw " "-device ide-hd,drive=hd0 ", params ? params : "", disk); diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c index 53fa969260..8951f6f610 100644 --- a/tests/drive_del-test.c +++ b/tests/drive_del-test.c @@ -103,7 +103,7 @@ static void test_after_failed_device_add(void) static void test_drive_del_device_del(void) { /* Start with a drive used by a device that unplugs instantaneously */ - qtest_start("-drive if=none,id=drive0,file=/dev/null" + qtest_start("-drive if=none,id=drive0,file=/dev/null,format=raw" " -device virtio-scsi-pci" " -device scsi-hd,drive=drive0,id=dev0"); diff --git a/tests/fdc-test.c b/tests/fdc-test.c index 203074cdad..3c6c83cac4 100644 --- a/tests/fdc-test.c +++ b/tests/fdc-test.c @@ -291,7 +291,7 @@ static void test_media_insert(void) /* Insert media in drive. DSKCHK should not be reset until a step pulse * is sent. */ qmp_discard_response("{'execute':'change', 'arguments':{" - " 'device':'floppy0', 'target': %s }}", + " 'device':'floppy0', 'target': %s, 'arg': 'raw' }}", test_image); qmp_discard_response(""); /* ignore event (FIXME open -> open transition?!) */ diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c index c84d1e75e0..7cc8dfff16 100644 --- a/tests/hd-geo-test.c +++ b/tests/hd-geo-test.c @@ -208,7 +208,7 @@ static int setup_ide(int argc, char *argv[], int argv_sz, { char *s1, *s2, *s3; - s1 = g_strdup_printf("-drive id=drive%d,if=%s", + s1 = g_strdup_printf("-drive id=drive%d,if=%s,format=raw", ide_idx, dev ? "none" : "ide"); s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx); diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c index ad232b561c..a3f72790ea 100644 --- a/tests/i440fx-test.c +++ b/tests/i440fx-test.c @@ -342,8 +342,9 @@ static void test_i440fx_firmware(FirmwareTestFixture *fixture, g_assert(fw_pathname != NULL); /* Better hope the user didn't put metacharacters in TMPDIR and co. */ - cmdline = g_strdup_printf("-S %s %s", - fixture->is_bios ? "-bios" : "-pflash", + cmdline = g_strdup_printf("-S %s%s", fixture->is_bios + ? "-bios " + : "-drive if=pflash,format=raw,file=", fw_pathname); g_test_message("qemu cmdline: %s", cmdline); qtest_start(cmdline); diff --git a/tests/ide-test.c b/tests/ide-test.c index b7a97e9362..29f4039bd5 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -385,7 +385,7 @@ static void test_bmdma_no_busmaster(void) static void test_bmdma_setup(void) { ide_test_start( - "-drive file=%s,if=ide,serial=%s,cache=writeback " + "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw " "-global ide-hd.ver=%s", tmp_path, "testdisk", "version"); } @@ -414,7 +414,7 @@ static void test_identify(void) int ret; ide_test_start( - "-drive file=%s,if=ide,serial=%s,cache=writeback " + "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw " "-global ide-hd.ver=%s", tmp_path, "testdisk", "version"); @@ -458,7 +458,7 @@ static void test_flush(void) uint8_t data; ide_test_start( - "-drive file=blkdebug::%s,if=ide,cache=writeback", + "-drive file=blkdebug::%s,if=ide,cache=writeback,format=raw", tmp_path); /* Delay the completion of the flush request until we explicitly do it */ @@ -526,7 +526,8 @@ static void test_retry_flush(void) ide_test_start( "-vnc none " - "-drive file=blkdebug:%s:%s,if=ide,cache=writeback,rerror=stop,werror=stop", + "-drive file=blkdebug:%s:%s,if=ide,cache=writeback,format=raw," + "rerror=stop,werror=stop", debug_path, tmp_path); /* FLUSH CACHE command on device 0*/ diff --git a/tests/nvme-test.c b/tests/nvme-test.c index 85768e837b..ff38b5e48f 100644 --- a/tests/nvme-test.c +++ b/tests/nvme-test.c @@ -24,7 +24,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); qtest_add_func("/nvme/nop", nop); - qtest_start("-drive id=drv0,if=none,file=/dev/null " + qtest_start("-drive id=drv0,if=none,file=/dev/null,format=raw " "-device nvme,drive=drv0,serial=foo"); ret = g_test_run(); diff --git a/tests/qemu-iotests/016 b/tests/qemu-iotests/016 index 7ea9e94b5d..52397aa80e 100755 --- a/tests/qemu-iotests/016 +++ b/tests/qemu-iotests/016 @@ -43,25 +43,28 @@ _supported_proto file sheepdog nfs _supported_os Linux +# No -f, use probing for the protocol driver +QEMU_IO_PROTO="$QEMU_IO_PROG -g --cache $CACHEMODE" + size=128M _make_test_img $size echo echo "== reading at EOF ==" -$QEMU_IO -g -c "read -P 0 $size 512" "$TEST_IMG" | _filter_qemu_io +$QEMU_IO_PROTO -c "read -P 0 $size 512" "$TEST_IMG" | _filter_qemu_io echo echo "== reading far past EOF ==" -$QEMU_IO -g -c "read -P 0 256M 512" "$TEST_IMG" | _filter_qemu_io +$QEMU_IO_PROTO -c "read -P 0 256M 512" "$TEST_IMG" | _filter_qemu_io echo echo "== writing at EOF ==" -$QEMU_IO -g -c "write -P 66 $size 512" "$TEST_IMG" | _filter_qemu_io +$QEMU_IO_PROTO -c "write -P 66 $size 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -P 66 $size 512" "$TEST_IMG" | _filter_qemu_io echo echo "== writing far past EOF ==" -$QEMU_IO -g -c "write -P 66 256M 512" "$TEST_IMG" | _filter_qemu_io +$QEMU_IO_PROTO -c "write -P 66 256M 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -P 66 256M 512" "$TEST_IMG" | _filter_qemu_io # success, all done diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out index f7c78e712a..ad84ac2b1b 100644 --- a/tests/qemu-iotests/026.out +++ b/tests/qemu-iotests/026.out @@ -14,6 +14,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 1 leaked clusters were found on the image. @@ -21,6 +23,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 1 leaked clusters were found on the image. @@ -38,6 +42,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 1 leaked clusters were found on the image. @@ -45,6 +51,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 1 leaked clusters were found on the image. @@ -70,7 +78,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 5; imm: off; once: off; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error read failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -78,7 +90,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 5; imm: off; once: off; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error read failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -102,7 +118,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 28; imm: off; once: off; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device read failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -110,12 +130,17 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 28; imm: off; once: off; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device read failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: on; write +Failed to flush the L2 table cache: Input/output error write failed: Input/output error 127 leaked clusters were found on the image. @@ -123,6 +148,7 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: on; write -b +Failed to flush the L2 table cache: Input/output error write failed: Input/output error 127 leaked clusters were found on the image. @@ -130,6 +156,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 127 leaked clusters were found on the image. @@ -137,6 +165,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 127 leaked clusters were found on the image. @@ -144,6 +174,7 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: on; write +Failed to flush the L2 table cache: No space left on device write failed: No space left on device 127 leaked clusters were found on the image. @@ -151,6 +182,7 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: on; write -b +Failed to flush the L2 table cache: No space left on device write failed: No space left on device 127 leaked clusters were found on the image. @@ -158,6 +190,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 127 leaked clusters were found on the image. @@ -165,6 +199,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 127 leaked clusters were found on the image. @@ -182,11 +218,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc.write; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 1 leaked clusters were found on the image. @@ -204,11 +244,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc.write; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 1 leaked clusters were found on the image. @@ -226,11 +270,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -246,11 +294,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -266,11 +318,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -286,51 +342,67 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: on; write +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: on; write -b +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: on; write +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: on; write -b +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -346,11 +418,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -366,11 +442,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -386,11 +466,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -406,11 +490,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. @@ -429,6 +517,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 55 leaked clusters were found on the image. @@ -436,6 +526,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 251 leaked clusters were found on the image. @@ -453,11 +545,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.write; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -473,6 +569,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 11 leaked clusters were found on the image. @@ -480,6 +578,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 23 leaked clusters were found on the image. @@ -497,6 +597,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 11 leaked clusters were found on the image. @@ -504,6 +606,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 23 leaked clusters were found on the image. @@ -521,6 +625,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 11 leaked clusters were found on the image. @@ -528,6 +634,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 23 leaked clusters were found on the image. @@ -543,6 +651,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow.alloc_table; errno: 5; imm: off; once: off +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -553,6 +663,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow.alloc_table; errno: 28; imm: off; once: off +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -563,6 +675,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow.write_table; errno: 5; imm: off; once: off +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -573,6 +687,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow.write_table; errno: 28; imm: off; once: off +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -583,6 +699,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow.activate_table; errno: 5; imm: off; once: off +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 96 leaked clusters were found on the image. @@ -595,6 +713,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_grow.activate_table; errno: 28; imm: off; once: off +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 96 leaked clusters were found on the image. diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 8ce2373cf5..952a524ec7 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -34,7 +34,7 @@ class TestSingleDrive(iotests.QMPTestCase): iotests.create_image(backing_img, TestSingleDrive.image_len) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) - qemu_io('-c', 'write -P 0x1 0 512', backing_img) + qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 512', backing_img) self.vm = iotests.VM().add_drive("blkdebug::" + test_img) self.vm.launch() @@ -55,8 +55,8 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-c', 'map', backing_img), - qemu_io('-c', 'map', test_img), + self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 'image file map does not match backing file after streaming') def test_stream_pause(self): @@ -86,8 +86,8 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-c', 'map', backing_img), - qemu_io('-c', 'map', test_img), + self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 'image file map does not match backing file after streaming') def test_stream_partial(self): @@ -101,8 +101,8 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() - self.assertEqual(qemu_io('-c', 'map', mid_img), - qemu_io('-c', 'map', test_img), + self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 'image file map does not match backing file after streaming') def test_device_not_found(self): @@ -359,9 +359,9 @@ class TestStreamStop(iotests.QMPTestCase): def setUp(self): qemu_img('create', backing_img, str(TestStreamStop.image_len)) - qemu_io('-c', 'write -P 0x1 0 32M', backing_img) + qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 32M', backing_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) - qemu_io('-c', 'write -P 0x1 32M 32M', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 32M 32M', test_img) self.vm = iotests.VM().add_drive("blkdebug::" + test_img) self.vm.launch() @@ -388,9 +388,9 @@ class TestSetSpeed(iotests.QMPTestCase): def setUp(self): qemu_img('create', backing_img, str(TestSetSpeed.image_len)) - qemu_io('-c', 'write -P 0x1 0 32M', backing_img) + qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 32M', backing_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) - qemu_io('-c', 'write -P 0x1 32M 32M', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 32M 32M', test_img) self.vm = iotests.VM().add_drive('blkdebug::' + test_img) self.vm.launch() diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 2b432ad7a1..ea2f98e51d 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -76,8 +76,8 @@ class TestSingleDrive(ImageCommitTestCase): iotests.create_image(backing_img, self.image_len) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) - qemu_io('-c', 'write -P 0xab 0 524288', backing_img) - qemu_io('-c', 'write -P 0xef 524288 524288', mid_img) + qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -89,8 +89,8 @@ class TestSingleDrive(ImageCommitTestCase): def test_commit(self): self.run_commit_test(mid_img, backing_img) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) def test_device_not_found(self): result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % mid_img) @@ -116,13 +116,13 @@ class TestSingleDrive(ImageCommitTestCase): def test_top_is_active(self): self.run_commit_test(test_img, backing_img, need_ready=True) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) def test_top_is_default_active(self): self.run_default_commit_test() - self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) def test_top_and_base_reversed(self): self.assert_no_active_block_jobs() @@ -159,8 +159,8 @@ class TestRelativePaths(ImageCommitTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.mid_img_abs, self.test_img) qemu_img('rebase', '-u', '-b', self.backing_img, self.mid_img_abs) qemu_img('rebase', '-u', '-b', self.mid_img, self.test_img) - qemu_io('-c', 'write -P 0xab 0 524288', self.backing_img_abs) - qemu_io('-c', 'write -P 0xef 524288 524288', self.mid_img_abs) + qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', self.backing_img_abs) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', self.mid_img_abs) self.vm = iotests.VM().add_drive(self.test_img) self.vm.launch() @@ -179,8 +179,8 @@ class TestRelativePaths(ImageCommitTestCase): def test_commit(self): self.run_commit_test(self.mid_img, self.backing_img) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) def test_device_not_found(self): result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % self.mid_img) @@ -206,8 +206,8 @@ class TestRelativePaths(ImageCommitTestCase): def test_top_is_active(self): self.run_commit_test(self.test_img, self.backing_img) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) - self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) def test_top_and_base_reversed(self): self.assert_no_active_block_jobs() @@ -223,8 +223,8 @@ class TestSetSpeed(ImageCommitTestCase): qemu_img('create', backing_img, str(TestSetSpeed.image_len)) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) - qemu_io('-c', 'write -P 0x1 0 512', test_img) - qemu_io('-c', 'write -P 0xef 524288 524288', mid_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.launch() diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048 index 65da46d6f5..e1eeac2a31 100755 --- a/tests/qemu-iotests/048 +++ b/tests/qemu-iotests/048 @@ -64,7 +64,7 @@ _compare _compare -q # Compare images with different size -$QEMU_IMG resize "$TEST_IMG" +512M +$QEMU_IMG resize -f $IMGFMT "$TEST_IMG" +512M _compare _compare -s diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 2c7e808765..7f161342a2 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -50,6 +50,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DI QEMU X.Y.Z monitor - type 'help' for more information (qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K ide0-hd0: TEST_DIR/t.qcow2 (qcow2) + Cache mode: writeback Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index 451b67ddfb..0872444811 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -34,10 +34,10 @@ class TestSingleDrive(iotests.QMPTestCase): def setUp(self): # Write data to the image so we can compare later qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len)) - qemu_io('-c', 'write -P0x5d 0 64k', test_img) - qemu_io('-c', 'write -P0xd5 1M 32k', test_img) - qemu_io('-c', 'write -P0xdc 32M 124k', test_img) - qemu_io('-c', 'write -P0xdc 67043328 64k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 64k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 67043328 64k', test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -115,7 +115,7 @@ class TestSetSpeed(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSetSpeed.image_len)) - qemu_io('-c', 'write -P1 0 512', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P1 0 512', test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -186,10 +186,10 @@ class TestSingleTransaction(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleTransaction.image_len)) - qemu_io('-c', 'write -P0x5d 0 64k', test_img) - qemu_io('-c', 'write -P0xd5 1M 32k', test_img) - qemu_io('-c', 'write -P0xdc 32M 124k', test_img) - qemu_io('-c', 'write -P0xdc 67043328 64k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 64k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 67043328 64k', test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058 index 14584cdea2..2d5ca85ddc 100755 --- a/tests/qemu-iotests/058 +++ b/tests/qemu-iotests/058 @@ -89,6 +89,9 @@ _supported_fmt qcow2 _supported_proto file _require_command QEMU_NBD +# Use -f raw instead of -f $IMGFMT for the NBD connection +QEMU_IO_NBD="$QEMU_IO -f raw --cache=$CACHEMODE" + echo echo "== preparing image ==" _make_test_img 64M @@ -108,15 +111,15 @@ _export_nbd_snapshot sn1 echo echo "== verifying the exported snapshot with patterns, method 1 ==" -$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io -$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$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 _export_nbd_snapshot1 sn1 echo echo "== verifying the exported snapshot with patterns, method 2 ==" -$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io -$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io +$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_IMG convert "$TEST_IMG" -l sn1 -O qcow2 "$converted_image" diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 3c053c29b4..2ed1a7ffe6 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -106,8 +106,8 @@ _img_info echo echo "=== Converting to streamOptimized from image with small cluster size===" TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 IMGOPTS="cluster_size=4096" _make_test_img 1G -$QEMU_IO -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io -$QEMU_IO -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io +$QEMU_IO -f qcow2 -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io +$QEMU_IO -f qcow2 -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io $QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2" "$TEST_IMG" 2>&1 echo diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index 9772d365ae..73863bf1f6 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -77,7 +77,7 @@ $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # This information should be available through qemu-img info -$QEMU_IMG info "$TEST_IMG" | _filter_testdir +_img_info --format-specific # Try to open the image R/W (which should fail) $QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \ diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index 9419da1b41..4cdf62bde0 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -11,10 +11,9 @@ incompatible_features 0x0 qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L1 table); further corruption events will be suppressed write failed: Input/output error incompatible_features 0x2 -image: TEST_DIR/t.qcow2 -file format: qcow2 +image: TEST_DIR/t.IMGFMT +file format: IMGFMT virtual size: 64M (67108864 bytes) -disk size: 196K cluster_size: 65536 Format specific information: compat: 1.1 diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 index d025192c83..29cd6b5aff 100755 --- a/tests/qemu-iotests/067 +++ b/tests/qemu-iotests/067 @@ -39,7 +39,7 @@ _supported_os Linux function do_run_qemu() { echo Testing: "$@" - $QEMU -nographic -qmp stdio -serial none "$@" + $QEMU -nographic -qmp-pretty stdio -serial none "$@" echo } diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out index 0f72dcf63a..7c3735f181 100644 --- a/tests/qemu-iotests/067.out +++ b/tests/qemu-iotests/067.out @@ -4,77 +4,767 @@ 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-pci,drive=disk,id=virtio0 -QMP_VERSION -{"return": {}} -{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} -{"return": {}} -{"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} -{"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +{ + QMP_VERSION +} +{ + "return": { + } +} +{ + "return": [ + { + "io-status": "ok", + "device": "disk", + "locked": false, + "removable": false, + "inserted": { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 134217728, + "filename": "TEST_DIR/t.qcow2", + "cluster-size": 65536, + "format": "qcow2", + "actual-size": SIZE, + "format-specific": { + "type": "qcow2", + "data": { + "compat": "1.1", + "lazy-refcounts": false, + "corrupt": false + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "backing_file_depth": 0, + "drv": "qcow2", + "iops": 0, + "bps_wr": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "TEST_DIR/t.qcow2", + "encryption_key_missing": false + }, + "type": "unknown" + }, + { + "io-status": "ok", + "device": "ide1-cd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "floppy0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "sd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + } + ] +} +{ + "return": { + } +} +{ + "return": { + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_DELETED", + "data": { + "path": "/machine/peripheral/virtio0/virtio-backend" + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_DELETED", + "data": { + "device": "virtio0", + "path": "/machine/peripheral/virtio0" + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "RESET" +} +{ + "return": [ + { + "io-status": "ok", + "device": "ide1-cd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "floppy0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "sd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + } + ] +} +{ + "return": { + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "SHUTDOWN" +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_TRAY_MOVED", + "data": { + "device": "ide1-cd0", + "tray-open": true + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_TRAY_MOVED", + "data": { + "device": "floppy0", + "tray-open": true + } +} === -drive/device_add and device_del === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -QMP_VERSION -{"return": {}} -{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} -{"return": {}} -{"return": {}} -{"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} -{"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +{ + QMP_VERSION +} +{ + "return": { + } +} +{ + "return": [ + { + "device": "disk", + "locked": false, + "removable": true, + "inserted": { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 134217728, + "filename": "TEST_DIR/t.qcow2", + "cluster-size": 65536, + "format": "qcow2", + "actual-size": SIZE, + "format-specific": { + "type": "qcow2", + "data": { + "compat": "1.1", + "lazy-refcounts": false, + "corrupt": false + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "backing_file_depth": 0, + "drv": "qcow2", + "iops": 0, + "bps_wr": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "TEST_DIR/t.qcow2", + "encryption_key_missing": false + }, + "tray_open": false, + "type": "unknown" + }, + { + "io-status": "ok", + "device": "ide1-cd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "floppy0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "sd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + } + ] +} +{ + "return": { + } +} +{ + "return": { + } +} +{ + "return": { + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_DELETED", + "data": { + "path": "/machine/peripheral/virtio0/virtio-backend" + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_DELETED", + "data": { + "device": "virtio0", + "path": "/machine/peripheral/virtio0" + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "RESET" +} +{ + "return": [ + { + "io-status": "ok", + "device": "ide1-cd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "floppy0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "sd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + } + ] +} +{ + "return": { + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "SHUTDOWN" +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_TRAY_MOVED", + "data": { + "device": "ide1-cd0", + "tray-open": true + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_TRAY_MOVED", + "data": { + "device": "floppy0", + "tray-open": true + } +} === drive_add/device_add and device_del === Testing: -QMP_VERSION -{"return": {}} -{"return": "OK\r\n"} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} -{"return": {}} -{"return": {}} -{"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} -{"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +{ + QMP_VERSION +} +{ + "return": { + } +} +{ + "return": "OK\r\n" +} +{ + "return": [ + { + "io-status": "ok", + "device": "ide1-cd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "floppy0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "sd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "disk", + "locked": false, + "removable": true, + "inserted": { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 134217728, + "filename": "TEST_DIR/t.qcow2", + "cluster-size": 65536, + "format": "qcow2", + "actual-size": SIZE, + "format-specific": { + "type": "qcow2", + "data": { + "compat": "1.1", + "lazy-refcounts": false, + "corrupt": false + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "backing_file_depth": 0, + "drv": "qcow2", + "iops": 0, + "bps_wr": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "TEST_DIR/t.qcow2", + "encryption_key_missing": false + }, + "tray_open": false, + "type": "unknown" + } + ] +} +{ + "return": { + } +} +{ + "return": { + } +} +{ + "return": { + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_DELETED", + "data": { + "path": "/machine/peripheral/virtio0/virtio-backend" + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_DELETED", + "data": { + "device": "virtio0", + "path": "/machine/peripheral/virtio0" + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "RESET" +} +{ + "return": [ + { + "io-status": "ok", + "device": "ide1-cd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "floppy0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "sd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + } + ] +} +{ + "return": { + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "SHUTDOWN" +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_TRAY_MOVED", + "data": { + "device": "ide1-cd0", + "tray-open": true + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_TRAY_MOVED", + "data": { + "device": "floppy0", + "tray-open": true + } +} === blockdev_add/device_add and device_del === Testing: -QMP_VERSION -{"return": {}} -{"return": {}} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} -{"return": {}} -{"return": {}} -{"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} -{"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +{ + QMP_VERSION +} +{ + "return": { + } +} +{ + "return": { + } +} +{ + "return": [ + { + "io-status": "ok", + "device": "ide1-cd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "floppy0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "sd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "disk", + "locked": false, + "removable": true, + "inserted": { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 134217728, + "filename": "TEST_DIR/t.qcow2", + "cluster-size": 65536, + "format": "qcow2", + "actual-size": SIZE, + "format-specific": { + "type": "qcow2", + "data": { + "compat": "1.1", + "lazy-refcounts": false, + "corrupt": false + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "backing_file_depth": 0, + "drv": "qcow2", + "iops": 0, + "bps_wr": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "TEST_DIR/t.qcow2", + "encryption_key_missing": false + }, + "tray_open": false, + "type": "unknown" + } + ] +} +{ + "return": { + } +} +{ + "return": { + } +} +{ + "return": { + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_DELETED", + "data": { + "path": "/machine/peripheral/virtio0/virtio-backend" + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_DELETED", + "data": { + "device": "virtio0", + "path": "/machine/peripheral/virtio0" + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "RESET" +} +{ + "return": [ + { + "io-status": "ok", + "device": "ide1-cd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "floppy0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "device": "sd0", + "locked": false, + "removable": true, + "tray_open": false, + "type": "unknown" + }, + { + "io-status": "ok", + "device": "disk", + "locked": false, + "removable": true, + "inserted": { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 134217728, + "filename": "TEST_DIR/t.qcow2", + "cluster-size": 65536, + "format": "qcow2", + "actual-size": SIZE, + "format-specific": { + "type": "qcow2", + "data": { + "compat": "1.1", + "lazy-refcounts": false, + "corrupt": false + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "backing_file_depth": 0, + "drv": "qcow2", + "iops": 0, + "bps_wr": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "TEST_DIR/t.qcow2", + "encryption_key_missing": false + }, + "tray_open": false, + "type": "unknown" + } + ] +} +{ + "return": { + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "SHUTDOWN" +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_TRAY_MOVED", + "data": { + "device": "ide1-cd0", + "tray-open": true + } +} +{ + "timestamp": { + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, + "event": "DEVICE_TRAY_MOVED", + "data": { + "device": "floppy0", + "tray-open": true + } +} *** done diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 index 3924e51f51..5d61ef6d81 100755 --- a/tests/qemu-iotests/071 +++ b/tests/qemu-iotests/071 @@ -63,12 +63,12 @@ echo TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\ _filter_imgfmt _make_test_img $IMG_SIZE -$QEMU_IO -c "open -o file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ +$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ -c 'read 0 512' -c 'write -P 42 0x38000 512' -c 'read -P 42 0x38000 512' | _filter_qemu_io $QEMU_IO -c 'write -P 42 0 512' "$TEST_IMG" | _filter_qemu_io -$QEMU_IO -c "open -o file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ +$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ -c 'read -P 42 0 512' | _filter_qemu_io echo @@ -78,12 +78,12 @@ echo TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\ _filter_imgfmt _make_test_img $IMG_SIZE -$QEMU_IO -c "open -o file.driver=blkverify,file.raw.filename=$TEST_IMG.base,file.test.driver=$IMGFMT,file.test.file.filename=$TEST_IMG" \ +$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base,file.test.driver=$IMGFMT,file.test.file.filename=$TEST_IMG" \ -c 'read 0 512' -c 'write -P 42 0x38000 512' -c 'read -P 42 0x38000 512' | _filter_qemu_io $QEMU_IO -c 'write -P 42 0 512' "$TEST_IMG" | _filter_qemu_io -$QEMU_IO -c "open -o file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ +$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ -c 'read -P 42 0 512' | _filter_qemu_io echo @@ -163,7 +163,7 @@ echo echo "=== Testing blkverify on existing raw block device ===" echo -run_qemu -drive "file=$TEST_IMG.base,if=none,id=drive0" <<EOF +run_qemu -drive "file=$TEST_IMG.base,format=raw,if=none,id=drive0" <<EOF { "execute": "qmp_capabilities" } { "execute": "blockdev-add", "arguments": { diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out index 5f840a9980..ffd7032118 100644 --- a/tests/qemu-iotests/071.out +++ b/tests/qemu-iotests/071.out @@ -12,7 +12,7 @@ read 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0 +blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 === Testing blkverify through file blockref === @@ -26,14 +26,18 @@ read 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0 +blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 === Testing blkdebug through filename === +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error read failed: Input/output error === Testing blkdebug through file blockref === +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error read failed: Input/output error === Testing blkdebug on existing block device === @@ -48,6 +52,8 @@ read failed: Input/output error {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +qemu-system-x86_64: Failed to flush the L2 table cache: Input/output error +qemu-system-x86_64: Failed to flush the refcount block cache: Input/output error === Testing blkverify on existing block device === @@ -61,7 +67,7 @@ blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 === Testing blkverify on existing raw block device === -Testing: -drive file=TEST_DIR/t.IMGFMT.base,if=none,id=drive0 +Testing: -drive file=TEST_DIR/t.IMGFMT.base,format=raw,if=none,id=drive0 QMP_VERSION {"return": {}} {"return": {}} @@ -86,5 +92,7 @@ read failed: Input/output error {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +qemu-system-x86_64: Failed to flush the L2 table cache: Input/output error +qemu-system-x86_64: Failed to flush the refcount block cache: Input/output error *** done diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077 index 4dd1bdde20..42a90850c7 100755 --- a/tests/qemu-iotests/077 +++ b/tests/qemu-iotests/077 @@ -52,7 +52,7 @@ echo "== Some concurrent requests involving RMW ==" function test_io() { -echo "open -o file.align=4k blkdebug::$TEST_IMG" +echo "open -o driver=$IMGFMT,file.align=4k blkdebug::$TEST_IMG" # A simple RMW request cat <<EOF aio_write -P 10 0x200 0x200 diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080 index 9de337c407..73795f198f 100755 --- a/tests/qemu-iotests/080 +++ b/tests/qemu-iotests/080 @@ -78,6 +78,8 @@ poke_file "$TEST_IMG" "$offset_backing_file_offset" "\xff\xff\xff\xff\xff\xff\xf poke_file "$TEST_IMG" "$offset_ext_magic" "\x12\x34\x56\x78" poke_file "$TEST_IMG" "$offset_ext_size" "\x7f\xff\xff\xff" { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\x00\x00\x00\x00\x$(printf %x $offset_ext_size)" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\x00\x00\x00\x00\x00" { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out index f7a943c7a4..33d1f71232 100644 --- a/tests/qemu-iotests/080.out +++ b/tests/qemu-iotests/080.out @@ -13,6 +13,8 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Invalid backing file offset no file open, try 'help open' qemu-io: can't open device TEST_DIR/t.qcow2: Header extension too large no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow2: Header extension too large +no file open, try 'help open' == Huge refcount table size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 index ed3c29e13c..9ab93ff89e 100755 --- a/tests/qemu-iotests/081 +++ b/tests/qemu-iotests/081 @@ -59,9 +59,13 @@ function run_qemu() test_quorum=$($QEMU_IMG --help|grep quorum) [ "$test_quorum" = "" ] && _supported_fmt quorum -quorum="file.driver=quorum,file.children.0.file.filename=$TEST_DIR/1.raw" +quorum="driver=raw,file.driver=quorum,file.vote-threshold=2" +quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw" quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw" -quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw,file.vote-threshold=2" +quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw" +quorum="$quorum,file.children.0.driver=raw" +quorum="$quorum,file.children.1.driver=raw" +quorum="$quorum,file.children.2.driver=raw" echo echo "== creating quorum files ==" diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out index 073515ea50..190905a084 100644 --- a/tests/qemu-iotests/081.out +++ b/tests/qemu-iotests/081.out @@ -55,5 +55,5 @@ wrote 10485760/10485760 bytes at offset 0 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == checking that quorum is broken == -qemu-io: can't open: Could not read image for determining its format: Input/output error +read failed: Input/output error *** done diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 index e64de27733..c83e01e7cd 100755 --- a/tests/qemu-iotests/082 +++ b/tests/qemu-iotests/082 @@ -60,11 +60,11 @@ _img_info # Multiple -o should be merged run_qemu_img create -f $IMGFMT -o cluster_size=4k -o lazy_refcounts=on "$TEST_IMG" $size -run_qemu_img info "$TEST_IMG" +_img_info --format-specific # If the same -o key is specified more than once, the last one wins run_qemu_img create -f $IMGFMT -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k "$TEST_IMG" $size -run_qemu_img info "$TEST_IMG" +_img_info --format-specific run_qemu_img create -f $IMGFMT -o cluster_size=4k,cluster_size=8k "$TEST_IMG" $size _img_info @@ -114,11 +114,11 @@ TEST_IMG="${TEST_IMG}.base" _img_info # Multiple -o should be merged run_qemu_img convert -O $IMGFMT -o cluster_size=4k -o lazy_refcounts=on "$TEST_IMG" "$TEST_IMG".base -run_qemu_img info "$TEST_IMG".base +TEST_IMG="${TEST_IMG}.base" _img_info --format-specific # If the same -o key is specified more than once, the last one wins run_qemu_img convert -O $IMGFMT -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k "$TEST_IMG" "$TEST_IMG".base -run_qemu_img info "$TEST_IMG".base +TEST_IMG="${TEST_IMG}.base" _img_info --format-specific run_qemu_img convert -O $IMGFMT -o cluster_size=4k,cluster_size=8k "$TEST_IMG" "$TEST_IMG".base TEST_IMG="${TEST_IMG}.base" _img_info @@ -157,15 +157,15 @@ echo === amend: Options specified more than once === # Last -f should win run_qemu_img amend -f foo -f $IMGFMT -o lazy_refcounts=on "$TEST_IMG" -run_qemu_img info "$TEST_IMG" +_img_info --format-specific # Multiple -o should be merged run_qemu_img amend -f $IMGFMT -o size=130M -o lazy_refcounts=off "$TEST_IMG" -run_qemu_img info "$TEST_IMG" +_img_info --format-specific # If the same -o key is specified more than once, the last one wins run_qemu_img amend -f $IMGFMT -o size=8M -o lazy_refcounts=on -o size=132M "$TEST_IMG" -run_qemu_img info "$TEST_IMG" +_img_info --format-specific run_qemu_img amend -f $IMGFMT -o size=4M,size=148M "$TEST_IMG" _img_info diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 0a3ab5ac90..5adfd08f9b 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -11,12 +11,9 @@ cluster_size: 65536 Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=4096 lazy_refcounts=on - -Testing: info TEST_DIR/t.qcow2 -image: TEST_DIR/t.qcow2 -file format: qcow2 +image: TEST_DIR/t.IMGFMT +file format: IMGFMT virtual size: 128M (134217728 bytes) -disk size: 16K cluster_size: 4096 Format specific information: compat: 1.1 @@ -25,12 +22,9 @@ Format specific information: Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=on - -Testing: info TEST_DIR/t.qcow2 -image: TEST_DIR/t.qcow2 -file format: qcow2 +image: TEST_DIR/t.IMGFMT +file format: IMGFMT virtual size: 128M (134217728 bytes) -disk size: 28K cluster_size: 8192 Format specific information: compat: 1.1 @@ -189,12 +183,9 @@ virtual size: 128M (134217728 bytes) cluster_size: 65536 Testing: convert -O qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base - -Testing: info TEST_DIR/t.qcow2.base -image: TEST_DIR/t.qcow2.base -file format: qcow2 +image: TEST_DIR/t.IMGFMT.base +file format: IMGFMT virtual size: 128M (134217728 bytes) -disk size: 16K cluster_size: 4096 Format specific information: compat: 1.1 @@ -202,12 +193,9 @@ Format specific information: corrupt: false Testing: convert -O qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base - -Testing: info TEST_DIR/t.qcow2.base -image: TEST_DIR/t.qcow2.base -file format: qcow2 +image: TEST_DIR/t.IMGFMT.base +file format: IMGFMT virtual size: 128M (134217728 bytes) -disk size: 28K cluster_size: 8192 Format specific information: compat: 1.1 @@ -351,12 +339,9 @@ size Virtual disk size === amend: Options specified more than once === Testing: amend -f foo -f qcow2 -o lazy_refcounts=on TEST_DIR/t.qcow2 - -Testing: info TEST_DIR/t.qcow2 -image: TEST_DIR/t.qcow2 -file format: qcow2 +image: TEST_DIR/t.IMGFMT +file format: IMGFMT virtual size: 128M (134217728 bytes) -disk size: 196K cluster_size: 65536 Format specific information: compat: 1.1 @@ -364,12 +349,9 @@ Format specific information: corrupt: false Testing: amend -f qcow2 -o size=130M -o lazy_refcounts=off TEST_DIR/t.qcow2 - -Testing: info TEST_DIR/t.qcow2 -image: TEST_DIR/t.qcow2 -file format: qcow2 +image: TEST_DIR/t.IMGFMT +file format: IMGFMT virtual size: 130M (136314880 bytes) -disk size: 196K cluster_size: 65536 Format specific information: compat: 1.1 @@ -377,12 +359,9 @@ Format specific information: corrupt: false Testing: amend -f qcow2 -o size=8M -o lazy_refcounts=on -o size=132M TEST_DIR/t.qcow2 - -Testing: info TEST_DIR/t.qcow2 -image: TEST_DIR/t.qcow2 -file format: qcow2 +image: TEST_DIR/t.IMGFMT +file format: IMGFMT virtual size: 132M (138412032 bytes) -disk size: 196K cluster_size: 65536 Format specific information: compat: 1.1 diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089 index dffc977e1c..6f74cecde2 100755 --- a/tests/qemu-iotests/089 +++ b/tests/qemu-iotests/089 @@ -65,7 +65,8 @@ $QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \ $QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG" -$QEMU_IO -c 'read -P 42 0 512' -c 'read -P 23 512 512' \ +$QEMU_IO_PROG --cache $CACHEMODE \ + -c 'read -P 42 0 512' -c 'read -P 23 512 512' \ -c 'read -P 66 1024 512' "json:{ \"driver\": \"$IMGFMT\", \"file\": { @@ -91,7 +92,8 @@ $QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io # The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do # the same (which they should). -$QEMU_IO -c 'read -P 42 0x38000 512' "json:{ +$QEMU_IO_PROG --cache $CACHEMODE \ + -c 'read -P 42 0x38000 512' "json:{ \"driver\": \"$IMGFMT\", \"file\": { \"driver\": \"blkdebug\", diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out index b2b0390818..bf3b8a0aae 100644 --- a/tests/qemu-iotests/089.out +++ b/tests/qemu-iotests/089.out @@ -24,6 +24,8 @@ read 512/512 bytes at offset 0 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 wrote 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error read failed: Input/output error === Testing qemu-img info output === diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099 index ffc7ea795a..948afff28b 100755 --- a/tests/qemu-iotests/099 +++ b/tests/qemu-iotests/099 @@ -44,7 +44,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 qed vdi vhdx vmdk vpc _supported_proto file _supported_os Linux - +_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" function do_run_qemu() { @@ -107,8 +108,21 @@ echo # generate a JSON object here as well test_qemu "file.driver=blkverify,file.raw.filename=$TEST_IMG.compare,file.test.file.driver=blkdebug,file.test.file.image.filename=$TEST_IMG,file.test.file.inject-error.0.event=l1_update" +echo +echo '=== Testing plain filename for blkdebug ===' +echo + +touch "$TEST_DIR/blkdebug.conf" +test_qemu "file.driver=blkdebug,file.config=$TEST_DIR/blkdebug.conf,file.image.filename=$TEST_IMG" + +echo +echo '=== Testing plain filename for blkdebug without configuration file ===' +echo + +test_qemu "file.driver=blkdebug,file.image.filename=$TEST_IMG" + -rm -f "$TEST_IMG.compare" +rm -f "$TEST_IMG.compare" "$TEST_DIR/blkdebug.conf" # success, all done echo "*** done" diff --git a/tests/qemu-iotests/099.out b/tests/qemu-iotests/099.out index 55be4d4c56..2fa06ff3a0 100644 --- a/tests/qemu-iotests/099.out +++ b/tests/qemu-iotests/099.out @@ -12,9 +12,17 @@ blkverify:TEST_DIR/t.IMGFMT.compare:TEST_DIR/t.IMGFMT === Testing JSON filename for blkdebug === -json:{"driver": "IMGFMT", "file": {"inject-error": [{"immediately": false, "once": false, "state": 0, "sector": -1, "event": "l1_update", "errno": 5}], "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug"}} +json:{"driver": "IMGFMT", "file": {"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "l1_update"}} === Testing indirectly enforced JSON filename === -json:{"driver": "raw", "file": {"test": {"driver": "IMGFMT", "file": {"inject-error": [{"immediately": false, "once": false, "state": 0, "sector": -1, "event": "l1_update", "errno": 5}], "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug"}}, "driver": "blkverify", "raw": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.compare"}}} +json:{"driver": "raw", "file": {"test": {"driver": "IMGFMT", "file": {"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "l1_update"}}, "driver": "blkverify", "raw": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.compare"}}} + +=== Testing plain filename for blkdebug === + +blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT + +=== Testing plain filename for blkdebug without configuration file === + +blkdebug::TEST_DIR/t.IMGFMT *** done diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 new file mode 100755 index 0000000000..0b668da850 --- /dev/null +++ b/tests/qemu-iotests/109 @@ -0,0 +1,132 @@ +#!/bin/bash +# +# Test writing image headers of other formats into raw images +# +# Copyright (C) 2014 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=kwolf@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + rm -f $TEST_IMG.src + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt raw +_supported_proto file +_supported_os Linux + +qemu_comm_method=qmp + +function run_qemu() +{ + local raw_img="$1" + local source_img="$2" + local qmp_format="$3" + local qmp_event="$4" + + _launch_qemu -drive file="${source_img}",format=raw,cache=${CACHEMODE},id=src + _send_qemu_cmd $QEMU_HANDLE "{ 'execute': 'qmp_capabilities' }" "return" + + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute':'drive-mirror', 'arguments':{ + 'device': 'src', 'target': '$raw_img', $qmp_format + 'mode': 'existing', 'sync': 'full'}}" \ + "return" + + _send_qemu_cmd $QEMU_HANDLE '' "$qmp_event" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"query-block-jobs"}' "return" + _cleanup_qemu +} + +for fmt in qcow qcow2 qed vdi vmdk vpc; do + + echo + echo "=== Writing a $fmt header into raw ===" + echo + + _make_test_img 64M + TEST_IMG="$TEST_IMG.src" IMGFMT=$fmt _make_test_img 64M + + # This first test should fail: The image format was probed, we may not + # write an image header at the start of the image + run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" + $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io + + + # When raw was explicitly specified, the same must succeed + run_qemu "$TEST_IMG" "$TEST_IMG.src" "'format': 'raw'," "BLOCK_JOB_READY" + $QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src" + +done + + +for sample_img in empty.bochs iotest-dirtylog-10G-4M.vhdx parallels-v1 \ + simple-pattern.cloop; do + + echo + echo "=== Copying sample image $sample_img into raw ===" + echo + + # Can't use _use_sample_img because that isn't designed to be used multiple + # times and it overwrites $TEST_IMG (both breaks cleanup) + _make_test_img 64M + bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src" + + run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" + $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io + + run_qemu "$TEST_IMG" "$TEST_IMG.src" "'format': 'raw'," "BLOCK_JOB_READY" + # qemu-img compare can't handle unaligned file sizes + $QEMU_IMG resize -f raw "$TEST_IMG.src" +0 + $QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src" +done + +echo +echo "=== Write legitimate MBR into raw ===" +echo + +for sample_img in grub_mbr.raw; do + _make_test_img 64M + bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src" + + run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_READY" + $QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src" + + run_qemu "$TEST_IMG" "$TEST_IMG.src" "'format': 'raw'," "BLOCK_JOB_READY" + $QEMU_IMG compare -f raw -F raw "$TEST_IMG" "$TEST_IMG.src" +done + + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out new file mode 100644 index 0000000000..7db92c9ce8 --- /dev/null +++ b/tests/qemu-iotests/109.out @@ -0,0 +1,231 @@ +QA output created by 109 + +=== Writing a qcow header into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 1024, "offset": 1024, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Warning: Image size mismatch! +Images are identical. + +=== Writing a qcow2 header into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 197120, "offset": 197120, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Warning: Image size mismatch! +Images are identical. + +=== Writing a qed header into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 327680, "offset": 327680, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Warning: Image size mismatch! +Images are identical. + +=== Writing a vdi header into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 1024, "offset": 1024, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Warning: Image size mismatch! +Images are identical. + +=== Writing a vmdk header into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 65536, "offset": 65536, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Warning: Image size mismatch! +Images are identical. + +=== Writing a vpc header into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2560, "offset": 2560, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Warning: Image size mismatch! +Images are identical. + +=== Copying sample image empty.bochs into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2560, "offset": 2560, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Image resized. +Warning: Image size mismatch! +Images are identical. + +=== Copying sample image iotest-dirtylog-10G-4M.vhdx into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 31457280, "offset": 31457280, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Image resized. +Warning: Image size mismatch! +Images are identical. + +=== Copying sample image parallels-v1 into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 327680, "offset": 327680, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Image resized. +Warning: Image size mismatch! +Images are identical. + +=== Copying sample image simple-pattern.cloop into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"return": []} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2048, "offset": 2048, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Image resized. +Warning: Image size mismatch! +Images are identical. + +=== Write legitimate MBR into raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +{"return": {}} +WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +Specify the 'raw' format explicitly to remove the restrictions. +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 512, "offset": 512, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Warning: Image size mismatch! +Images are identical. +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} +{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 512, "offset": 512, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} +Warning: Image size mismatch! +Images are identical. +*** done diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113 new file mode 100755 index 0000000000..a2cd96b176 --- /dev/null +++ b/tests/qemu-iotests/113 @@ -0,0 +1,76 @@ +#!/bin/bash +# +# Test case for accessing creation options on image formats and +# protocols not supporting image creation +# +# Copyright (C) 2014 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=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +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 + +# We can only test one format here because we need its sample file +_supported_fmt bochs +_supported_proto nbd +_supported_os Linux + +echo +echo '=== Unsupported image creation in qemu-img create ===' +echo + +$QEMU_IMG create -f $IMGFMT nbd://example.com 2>&1 64M | _filter_imgfmt + +echo +echo '=== Unsupported image creation in qemu-img convert ===' +echo + +# We could use any input image format here, but this is a bochs test, so just +# use the bochs image +_use_sample_img empty.bochs.bz2 +$QEMU_IMG convert -f $IMGFMT -O $IMGFMT "$TEST_IMG" nbd://example.com 2>&1 \ + | _filter_imgfmt + +echo +echo '=== Unsupported format in qemu-img amend ===' +echo + +# The protocol does not matter here +_use_sample_img empty.bochs.bz2 +$QEMU_IMG amend -f $IMGFMT -o foo=bar "$TEST_IMG" 2>&1 | _filter_imgfmt + + +# success, all done +echo +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/113.out b/tests/qemu-iotests/113.out new file mode 100644 index 0000000000..00bdfd6887 --- /dev/null +++ b/tests/qemu-iotests/113.out @@ -0,0 +1,15 @@ +QA output created by 113 + +=== Unsupported image creation in qemu-img create === + +qemu-img: nbd://example.com: Format driver 'IMGFMT' does not support image creation + +=== Unsupported image creation in qemu-img convert === + +qemu-img: Format driver 'IMGFMT' does not support image creation + +=== Unsupported format in qemu-img amend === + +qemu-img: Format driver 'IMGFMT' does not support any options to amend + +*** done diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 new file mode 100755 index 0000000000..d02e7ffbe3 --- /dev/null +++ b/tests/qemu-iotests/114 @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Test invalid backing file format in qcow2 images +# +# Copyright (C) 2014 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=kwolf@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +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 generic +_supported_os Linux + + +TEST_IMG="$TEST_IMG.base" _make_test_img 64M +_make_test_img -b "$TEST_IMG.base" 64M + +# Set an invalid backing file format +$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0xE2792ACA "foo" +_img_info + +# Try opening the image. Should fail (and not probe) in the first case, but +# overriding the backing file format should be possible. +$QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -o backing.driver=$IMGFMT $TEST_IMG" -c "read 0 4k" | _filter_qemu_io + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out new file mode 100644 index 0000000000..6c6b21085a --- /dev/null +++ b/tests/qemu-iotests/114.out @@ -0,0 +1,13 @@ +QA output created by 114 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base' +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +backing file: TEST_DIR/t.IMGFMT.base +backing file format: foo +qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknown driver 'foo' +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common index 9e12bec2bf..1e556bbb7d 100644 --- a/tests/qemu-iotests/common +++ b/tests/qemu-iotests/common @@ -289,10 +289,10 @@ testlist options if [ ! -z "$DISPLAY" ] then - which xdiff >/dev/null 2>&1 && diff=xdiff - which gdiff >/dev/null 2>&1 && diff=gdiff - which tkdiff >/dev/null 2>&1 && diff=tkdiff - which xxdiff >/dev/null 2>&1 && diff=xxdiff + command -v xdiff >/dev/null 2>&1 && diff=xdiff + command -v gdiff >/dev/null 2>&1 && diff=gdiff + command -v tkdiff >/dev/null 2>&1 && diff=tkdiff + command -v xxdiff >/dev/null 2>&1 && diff=xxdiff fi ;; @@ -391,7 +391,7 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \ done # Set qemu-io cache mode with $CACHEMODE we have -QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE" +QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT --cache $CACHEMODE" # Set default options for qemu-img create -o if they were not specified _set_default_imgopts diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config index bd6790be63..91a5ef696b 100644 --- a/tests/qemu-iotests/common.config +++ b/tests/qemu-iotests/common.config @@ -47,7 +47,7 @@ export PWD=`pwd` # $1 = prog to look for, $2* = default pathnames if not found in $PATH set_prog_path() { - p=`which $1 2> /dev/null` + p=`command -v $1 2> /dev/null` if [ -n "$p" -a -x "$p" ]; then echo $p return 0 diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 3acdb307f4..dfb9726f6c 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -167,7 +167,9 @@ _filter_qmp() { _filter_win32 | \ sed -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \ - -e 's#^{"QMP":.*}$#QMP_VERSION#' + -e 's#^{"QMP":.*}$#QMP_VERSION#' \ + -e '/^ "QMP": {\s*$/, /^ }\s*$/ c\' \ + -e ' QMP_VERSION' } # replace driver-specific options in the "Formatting..." line diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu index ee7ebb4c1d..8e618b5149 100644 --- a/tests/qemu-iotests/common.qemu +++ b/tests/qemu-iotests/common.qemu @@ -153,8 +153,9 @@ function _launch_qemu() mkfifo "${fifo_out}" mkfifo "${fifo_in}" - "${QEMU}" -nographic -serial none ${comm} -machine accel=qtest "${@}" 2>&1 \ + "${QEMU}" -nographic -serial none ${comm} -machine accel=qtest "${@}" \ >"${fifo_out}" \ + 2>&1 \ <"${fifo_in}" & QEMU_PID[${_QEMU_HANDLE}]=$! diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 9c49deb3dd..3b14053790 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -175,7 +175,9 @@ _cleanup_test_img() case "$IMGPROTO" in nbd) - kill $QEMU_NBD_PID + if [ -n "$QEMU_NBD_PID" ]; then + kill $QEMU_NBD_PID + fi rm -f "$TEST_IMG_FILE" ;; file) @@ -213,6 +215,13 @@ _check_test_img() _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": \{' $QEMU_IMG info "$@" "$TEST_IMG" 2>&1 | \ @@ -222,7 +231,9 @@ _img_info() -e "/^disk size:/ D" \ -e "/actual-size/ D" | \ while IFS='' read line; do - if [[ $line == "Format specific information:" ]]; then + if [[ $format_specific == 1 ]]; then + discard=0 + elif [[ $line == "Format specific information:" ]]; then discard=1 elif [[ $line =~ $regex_json_spec_start ]]; then discard=2 diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 7dfe46940a..a4742c6d01 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -111,4 +111,7 @@ 105 rw auto quick 107 rw auto quick 108 rw auto quick +109 rw auto 111 rw auto quick +113 rw auto quick +114 rw auto quick diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index 2058596964..9cc4cf7d08 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -7,6 +7,10 @@ import string class QcowHeaderExtension: def __init__(self, magic, length, data): + if length % 8 != 0: + padding = 8 - (length % 8) + data += "\0" * padding + self.magic = magic self.length = length self.data = data diff --git a/tests/qemu-iotests/sample_images/grub_mbr.raw.bz2 b/tests/qemu-iotests/sample_images/grub_mbr.raw.bz2 Binary files differnew file mode 100644 index 0000000000..8585878bcd --- /dev/null +++ b/tests/qemu-iotests/sample_images/grub_mbr.raw.bz2 diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c index 8cf2c5bcaa..6d631cf366 100644 --- a/tests/usb-hcd-uhci-test.c +++ b/tests/usb-hcd-uhci-test.c @@ -87,7 +87,7 @@ int main(int argc, char **argv) qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug); qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0" - " -drive id=drive0,if=none,file=/dev/null" + " -drive id=drive0,if=none,file=/dev/null,format=raw" " -device usb-tablet,bus=uhci.0,port=1"); ret = g_test_run(); qtest_end(); diff --git a/tests/usb-hcd-xhci-test.c b/tests/usb-hcd-xhci-test.c index b1a7dec5bb..adf261e963 100644 --- a/tests/usb-hcd-xhci-test.c +++ b/tests/usb-hcd-xhci-test.c @@ -91,7 +91,7 @@ int main(int argc, char **argv) qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug); qtest_start("-device nec-usb-xhci,id=xhci" - " -drive id=drive0,if=none,file=/dev/null"); + " -drive id=drive0,if=none,file=/dev/null,format=raw"); ret = g_test_run(); qtest_end(); diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index ead3911e28..89d7cbf919 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -68,8 +68,8 @@ static QPCIBus *test_start(void) g_assert_cmpint(ret, ==, 0); close(fd); - cmdline = g_strdup_printf("-drive if=none,id=drive0,file=%s " - "-drive if=none,id=drive1,file=/dev/null " + cmdline = g_strdup_printf("-drive if=none,id=drive0,file=%s,format=raw " + "-drive if=none,id=drive1,file=/dev/null,format=raw " "-device virtio-blk-pci,id=drv0,drive=drive0," "addr=%x.%x", tmp_path, PCI_SLOT, PCI_FN); diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index 41f9602e44..989f8251c4 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -52,8 +52,8 @@ int main(int argc, char **argv) qtest_add_func("/virtio/scsi/pci/nop", pci_nop); qtest_add_func("/virtio/scsi/pci/hotplug", hotplug); - qtest_start("-drive id=drv0,if=none,file=/dev/null " - "-drive id=drv1,if=none,file=/dev/null " + qtest_start("-drive id=drv0,if=none,file=/dev/null,format=raw " + "-drive id=drv1,if=none,file=/dev/null,format=raw " "-device virtio-scsi-pci,id=vscsi0 " "-device scsi-hd,bus=vscsi0.0,drive=drv0"); ret = g_test_run(); diff --git a/ui/keymaps.c b/ui/keymaps.c index 80d658d907..49410ae9d1 100644 --- a/ui/keymaps.c +++ b/ui/keymaps.c @@ -26,18 +26,20 @@ #include "sysemu/sysemu.h" static int get_keysym(const name2keysym_t *table, - const char *name) + const char *name) { const name2keysym_t *p; for(p = table; p->name != NULL; p++) { - if (!strcmp(p->name, name)) + if (!strcmp(p->name, name)) { return p->keysym; + } } if (name[0] == 'U' && strlen(name) == 5) { /* try unicode Uxxxx */ char *end; int ret = (int)strtoul(name + 1, &end, 16); - if (*end == '\0' && ret > 0) - return ret; + if (*end == '\0' && ret > 0) { + return ret; + } } return 0; } @@ -46,19 +48,20 @@ static int get_keysym(const name2keysym_t *table, static void add_to_key_range(struct key_range **krp, int code) { struct key_range *kr; for (kr = *krp; kr; kr = kr->next) { - if (code >= kr->start && code <= kr->end) - break; - if (code == kr->start - 1) { - kr->start--; - break; - } - if (code == kr->end + 1) { - kr->end++; - break; - } + if (code >= kr->start && code <= kr->end) { + break; + } + if (code == kr->start - 1) { + kr->start--; + break; + } + if (code == kr->end + 1) { + kr->end++; + break; + } } if (kr == NULL) { - kr = g_malloc0(sizeof(*kr)); + kr = g_malloc0(sizeof(*kr)); kr->start = kr->end = code; kr->next = *krp; *krp = kr; @@ -67,30 +70,30 @@ static void add_to_key_range(struct key_range **krp, int code) { static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) { if (keysym < MAX_NORMAL_KEYCODE) { - //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode); - k->keysym2keycode[keysym] = keycode; + /* fprintf(stderr,"Setting keysym %s (%d) to %d\n", + line, keysym, keycode); */ + k->keysym2keycode[keysym] = keycode; } else { - if (k->extra_count >= MAX_EXTRA_COUNT) { - fprintf(stderr, - "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n", - line, keysym); - } else { + if (k->extra_count >= MAX_EXTRA_COUNT) { + fprintf(stderr, "Warning: Could not assign keysym %s (0x%x)" + " because of memory constraints.\n", line, keysym); + } else { #if 0 - fprintf(stderr, "Setting %d: %d,%d\n", - k->extra_count, keysym, keycode); + fprintf(stderr, "Setting %d: %d,%d\n", + k->extra_count, keysym, keycode); #endif - k->keysym2keycode_extra[k->extra_count]. - keysym = keysym; - k->keysym2keycode_extra[k->extra_count]. - keycode = keycode; - k->extra_count++; - } + k->keysym2keycode_extra[k->extra_count]. + keysym = keysym; + k->keysym2keycode_extra[k->extra_count]. + keycode = keycode; + k->extra_count++; + } } } static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, - const char *language, - kbd_layout_t * k) + const char *language, + kbd_layout_t *k) { FILE *f; char * filename; @@ -101,69 +104,78 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, f = filename ? fopen(filename, "r") : NULL; g_free(filename); if (!f) { - fprintf(stderr, - "Could not read keymap file: '%s'\n", language); - return NULL; + fprintf(stderr, "Could not read keymap file: '%s'\n", language); + return NULL; } - if (!k) - k = g_malloc0(sizeof(kbd_layout_t)); + if (!k) { + k = g_malloc0(sizeof(kbd_layout_t)); + } for(;;) { - if (fgets(line, 1024, f) == NULL) + if (fgets(line, 1024, f) == NULL) { break; + } len = strlen(line); - if (len > 0 && line[len - 1] == '\n') + if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; - if (line[0] == '#') - continue; - if (!strncmp(line, "map ", 4)) - continue; - if (!strncmp(line, "include ", 8)) { - parse_keyboard_layout(table, line + 8, k); + } + if (line[0] == '#') { + continue; + } + if (!strncmp(line, "map ", 4)) { + continue; + } + if (!strncmp(line, "include ", 8)) { + parse_keyboard_layout(table, line + 8, k); } else { - char *end_of_keysym = line; - while (*end_of_keysym != 0 && *end_of_keysym != ' ') - end_of_keysym++; - if (*end_of_keysym) { - int keysym; - *end_of_keysym = 0; - keysym = get_keysym(table, line); - if (keysym == 0) { - // fprintf(stderr, "Warning: unknown keysym %s\n", line); - } else { - const char *rest = end_of_keysym + 1; + char *end_of_keysym = line; + while (*end_of_keysym != 0 && *end_of_keysym != ' ') { + end_of_keysym++; + } + if (*end_of_keysym) { + int keysym; + *end_of_keysym = 0; + keysym = get_keysym(table, line); + if (keysym == 0) { + /* fprintf(stderr, "Warning: unknown keysym %s\n", line);*/ + } else { + const char *rest = end_of_keysym + 1; int keycode = strtol(rest, NULL, 0); if (strstr(rest, "numlock")) { - add_to_key_range(&k->keypad_range, keycode); - add_to_key_range(&k->numlock_range, keysym); - //fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode); - } + add_to_key_range(&k->keypad_range, keycode); + add_to_key_range(&k->numlock_range, keysym); + /* fprintf(stderr, "keypad keysym %04x keycode %d\n", + keysym, keycode); */ + } if (strstr(rest, "shift")) { - keycode |= SCANCODE_SHIFT; + keycode |= SCANCODE_SHIFT; } if (strstr(rest, "altgr")) { - keycode |= SCANCODE_ALTGR; + keycode |= SCANCODE_ALTGR; } if (strstr(rest, "ctrl")) { - keycode |= SCANCODE_CTRL; + keycode |= SCANCODE_CTRL; } - add_keysym(line, keysym, keycode, k); + add_keysym(line, keysym, keycode, k); if (strstr(rest, "addupper")) { - char *c; - for (c = line; *c; c++) - *c = qemu_toupper(*c); - keysym = get_keysym(table, line); - if (keysym) - add_keysym(line, keysym, keycode | SCANCODE_SHIFT, k); - } - } - } - } + char *c; + for (c = line; *c; c++) { + *c = qemu_toupper(*c); + } + keysym = get_keysym(table, line); + if (keysym) { + add_keysym(line, keysym, + keycode | SCANCODE_SHIFT, k); + } + } + } + } + } } fclose(f); return k; @@ -180,19 +192,23 @@ int keysym2scancode(void *kbd_layout, int keysym) { kbd_layout_t *k = kbd_layout; if (keysym < MAX_NORMAL_KEYCODE) { - if (k->keysym2keycode[keysym] == 0) - fprintf(stderr, "Warning: no scancode found for keysym %d\n", - keysym); - return k->keysym2keycode[keysym]; + if (k->keysym2keycode[keysym] == 0) { + fprintf(stderr, "Warning: no scancode found for keysym %d\n", + keysym); + } + return k->keysym2keycode[keysym]; } else { - int i; + int i; #ifdef XK_ISO_Left_Tab - if (keysym == XK_ISO_Left_Tab) - keysym = XK_Tab; + if (keysym == XK_ISO_Left_Tab) { + keysym = XK_Tab; + } #endif - for (i = 0; i < k->extra_count; i++) - if (k->keysym2keycode_extra[i].keysym == keysym) - return k->keysym2keycode_extra[i].keycode; + for (i = 0; i < k->extra_count; i++) { + if (k->keysym2keycode_extra[i].keysym == keysym) { + return k->keysym2keycode_extra[i].keycode; + } + } } return 0; } @@ -202,9 +218,11 @@ int keycode_is_keypad(void *kbd_layout, int keycode) kbd_layout_t *k = kbd_layout; struct key_range *kr; - for (kr = k->keypad_range; kr; kr = kr->next) - if (keycode >= kr->start && keycode <= kr->end) + for (kr = k->keypad_range; kr; kr = kr->next) { + if (keycode >= kr->start && keycode <= kr->end) { return 1; + } + } return 0; } @@ -213,8 +231,10 @@ int keysym_is_numlock(void *kbd_layout, int keysym) kbd_layout_t *k = kbd_layout; struct key_range *kr; - for (kr = k->numlock_range; kr; kr = kr->next) - if (keysym >= kr->start && keysym <= kr->end) + for (kr = k->numlock_range; kr; kr = kr->next) { + if (keysym >= kr->start && keysym <= kr->end) { return 1; + } + } return 0; } diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 3d1b5cd066..9a9ddf2e3c 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -1489,7 +1489,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) } #endif - colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette); + colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, &palette); #ifdef CONFIG_VNC_JPEG if (allow_jpeg && vs->tight.quality != (uint8_t)-1) { @@ -554,6 +554,22 @@ static QemuOptsList qemu_icount_opts = { }, }; +static QemuOptsList qemu_semihosting_config_opts = { + .name = "semihosting-config", + .implied_opt_name = "enable", + .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head), + .desc = { + { + .name = "enable", + .type = QEMU_OPT_BOOL, + }, { + .name = "target", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + /** * Get machine options * @@ -2284,7 +2300,7 @@ static int mon_init_func(QemuOpts *opts, void *opaque) return 0; } -static void monitor_parse(const char *optarg, const char *mode) +static void monitor_parse(const char *optarg, const char *mode, bool pretty) { static int monitor_device_index = 0; QemuOpts *opts; @@ -2314,6 +2330,7 @@ static void monitor_parse(const char *optarg, const char *mode) } qemu_opt_set(opts, "mode", mode); qemu_opt_set(opts, "chardev", label); + qemu_opt_set_bool(opts, "pretty", pretty); if (def) qemu_opt_set(opts, "default", "on"); monitor_device_index++; @@ -2811,6 +2828,7 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_name_opts); qemu_add_opts(&qemu_numa_opts); qemu_add_opts(&qemu_icount_opts); + qemu_add_opts(&qemu_semihosting_config_opts); runstate_init(); @@ -3292,11 +3310,15 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_monitor: default_monitor = 0; if (strncmp(optarg, "none", 4)) { - monitor_parse(optarg, "readline"); + monitor_parse(optarg, "readline", false); } break; case QEMU_OPTION_qmp: - monitor_parse(optarg, "control"); + monitor_parse(optarg, "control", false); + default_monitor = 0; + break; + case QEMU_OPTION_qmp_pretty: + monitor_parse(optarg, "control", true); default_monitor = 0; break; case QEMU_OPTION_mon: @@ -3618,6 +3640,37 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_semihosting: semihosting_enabled = 1; + semihosting_target = SEMIHOSTING_TARGET_AUTO; + break; + case QEMU_OPTION_semihosting_config: + semihosting_enabled = 1; + opts = qemu_opts_parse(qemu_find_opts("semihosting-config"), + optarg, 0); + if (opts != NULL) { + semihosting_enabled = qemu_opt_get_bool(opts, "enable", + true); + const char *target = qemu_opt_get(opts, "target"); + if (target != NULL) { + if (strcmp("native", target) == 0) { + semihosting_target = SEMIHOSTING_TARGET_NATIVE; + } else if (strcmp("gdb", target) == 0) { + semihosting_target = SEMIHOSTING_TARGET_GDB; + } else if (strcmp("auto", target) == 0) { + semihosting_target = SEMIHOSTING_TARGET_AUTO; + } else { + fprintf(stderr, "Unsupported semihosting-config" + " %s\n", + optarg); + exit(1); + } + } else { + semihosting_target = SEMIHOSTING_TARGET_AUTO; + } + } else { + fprintf(stderr, "Unsupported semihosting-config %s\n", + optarg); + exit(1); + } break; case QEMU_OPTION_tdf: fprintf(stderr, "Warning: user space PIT time drift fix " @@ -3994,7 +4047,7 @@ int main(int argc, char **argv, char **envp) add_device_config(DEV_SCLP, "stdio"); } if (default_monitor) - monitor_parse("stdio", "readline"); + monitor_parse("stdio", "readline", false); } } else { if (default_serial) @@ -4002,7 +4055,7 @@ int main(int argc, char **argv, char **envp) if (default_parallel) add_device_config(DEV_PARALLEL, "vc:80Cx24C"); if (default_monitor) - monitor_parse("vc:80Cx24C", "readline"); + monitor_parse("vc:80Cx24C", "readline", false); if (default_virtcon) add_device_config(DEV_VIRTCON, "vc:80Cx24C"); if (default_sclp) { |