diff options
113 files changed, 2830 insertions, 1901 deletions
@@ -318,13 +318,21 @@ endif install-datadir: $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)" +install-localstatedir: +ifdef CONFIG_POSIX +ifneq (,$(findstring qemu-ga,$(TOOLS))) + $(INSTALL_DIR) "$(DESTDIR)$(qemu_localstatedir)"/run +endif +endif + install-confdir: $(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)" install-sysconfig: install-datadir install-confdir $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)" -install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig install-datadir +install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \ +install-datadir install-localstatedir $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ifneq ($(TOOLS),) $(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)" @@ -99,9 +99,6 @@ static QTAILQ_HEAD(, BlockDriverState) bdrv_states = static QLIST_HEAD(, BlockDriver) bdrv_drivers = QLIST_HEAD_INITIALIZER(bdrv_drivers); -/* The device to use for VM snapshots */ -static BlockDriverState *bs_snapshots; - /* If non-zero, use only whitelisted block drivers */ static int use_bdrv_whitelist; @@ -328,28 +325,40 @@ BlockDriver *bdrv_find_format(const char *format_name) return NULL; } -static int bdrv_is_whitelisted(BlockDriver *drv) +static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) { - static const char *whitelist[] = { - CONFIG_BDRV_WHITELIST + static const char *whitelist_rw[] = { + CONFIG_BDRV_RW_WHITELIST + }; + static const char *whitelist_ro[] = { + CONFIG_BDRV_RO_WHITELIST }; const char **p; - if (!whitelist[0]) + if (!whitelist_rw[0] && !whitelist_ro[0]) { return 1; /* no whitelist, anything goes */ + } - for (p = whitelist; *p; p++) { + for (p = whitelist_rw; *p; p++) { if (!strcmp(drv->format_name, *p)) { return 1; } } + if (read_only) { + for (p = whitelist_ro; *p; p++) { + if (!strcmp(drv->format_name, *p)) { + return 1; + } + } + } return 0; } -BlockDriver *bdrv_find_whitelisted_format(const char *format_name) +BlockDriver *bdrv_find_whitelisted_format(const char *format_name, + bool read_only) { BlockDriver *drv = bdrv_find_format(format_name); - return drv && bdrv_is_whitelisted(drv) ? drv : NULL; + return drv && bdrv_is_whitelisted(drv, read_only) ? drv : NULL; } typedef struct CreateCo { @@ -684,10 +693,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name); - if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) { - return -ENOTSUP; - } - /* bdrv_open() with directly using a protocol as drv. This layer is already * opened, so assign it to bs (while file becomes a closed BlockDriverState) * and return immediately. */ @@ -698,9 +703,15 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, bs->open_flags = flags; bs->buffer_alignment = 512; + open_flags = bdrv_open_flags(bs, flags); + bs->read_only = !(open_flags & BDRV_O_RDWR); + + if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) { + return -ENOTSUP; + } assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */ - if ((flags & BDRV_O_RDWR) && (flags & BDRV_O_COPY_ON_READ)) { + if (!bs->read_only && (flags & BDRV_O_COPY_ON_READ)) { bdrv_enable_copy_on_read(bs); } @@ -714,9 +725,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, bs->opaque = g_malloc0(drv->instance_size); bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB); - open_flags = bdrv_open_flags(bs, flags); - - bs->read_only = !(open_flags & BDRV_O_RDWR); /* Open the image, either directly or using a protocol */ if (drv->bdrv_file_open) { @@ -801,7 +809,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, /* Find the right block driver */ drvname = qdict_get_try_str(options, "driver"); if (drvname) { - drv = bdrv_find_whitelisted_format(drvname); + drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR)); qdict_del(options, "driver"); } else if (filename) { drv = bdrv_find_protocol(filename); @@ -1357,9 +1365,6 @@ void bdrv_close(BlockDriverState *bs) notifier_list_notify(&bs->close_notifiers, bs); if (bs->drv) { - if (bs == bs_snapshots) { - bs_snapshots = NULL; - } if (bs->backing_hd) { bdrv_delete(bs->backing_hd); bs->backing_hd = NULL; @@ -1591,7 +1596,6 @@ void bdrv_delete(BlockDriverState *bs) bdrv_close(bs); - assert(bs != bs_snapshots); g_free(bs); } @@ -1635,9 +1639,6 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops, { bs->dev_ops = ops; bs->dev_opaque = opaque; - if (bdrv_dev_has_removable_media(bs) && bs == bs_snapshots) { - bs_snapshots = NULL; - } } void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv, @@ -3099,128 +3100,6 @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, return data.ret; } -BlockInfo *bdrv_query_info(BlockDriverState *bs) -{ - BlockInfo *info = g_malloc0(sizeof(*info)); - info->device = g_strdup(bs->device_name); - info->type = g_strdup("unknown"); - info->locked = bdrv_dev_is_medium_locked(bs); - info->removable = bdrv_dev_has_removable_media(bs); - - if (bdrv_dev_has_removable_media(bs)) { - info->has_tray_open = true; - info->tray_open = bdrv_dev_is_tray_open(bs); - } - - if (bdrv_iostatus_is_enabled(bs)) { - info->has_io_status = true; - info->io_status = bs->iostatus; - } - - if (bs->dirty_bitmap) { - info->has_dirty = true; - info->dirty = g_malloc0(sizeof(*info->dirty)); - info->dirty->count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE; - info->dirty->granularity = - ((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bs->dirty_bitmap)); - } - - if (bs->drv) { - info->has_inserted = true; - info->inserted = g_malloc0(sizeof(*info->inserted)); - info->inserted->file = g_strdup(bs->filename); - info->inserted->ro = bs->read_only; - info->inserted->drv = g_strdup(bs->drv->format_name); - info->inserted->encrypted = bs->encrypted; - info->inserted->encryption_key_missing = bdrv_key_required(bs); - - if (bs->backing_file[0]) { - info->inserted->has_backing_file = true; - info->inserted->backing_file = g_strdup(bs->backing_file); - } - - info->inserted->backing_file_depth = bdrv_get_backing_file_depth(bs); - - if (bs->io_limits_enabled) { - info->inserted->bps = - bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]; - info->inserted->bps_rd = - bs->io_limits.bps[BLOCK_IO_LIMIT_READ]; - info->inserted->bps_wr = - bs->io_limits.bps[BLOCK_IO_LIMIT_WRITE]; - info->inserted->iops = - bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]; - info->inserted->iops_rd = - bs->io_limits.iops[BLOCK_IO_LIMIT_READ]; - info->inserted->iops_wr = - bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE]; - } - } - return info; -} - -BlockInfoList *qmp_query_block(Error **errp) -{ - BlockInfoList *head = NULL, **p_next = &head; - BlockDriverState *bs; - - QTAILQ_FOREACH(bs, &bdrv_states, list) { - BlockInfoList *info = g_malloc0(sizeof(*info)); - info->value = bdrv_query_info(bs); - - *p_next = info; - p_next = &info->next; - } - - return head; -} - -BlockStats *bdrv_query_stats(const BlockDriverState *bs) -{ - BlockStats *s; - - s = g_malloc0(sizeof(*s)); - - if (bs->device_name[0]) { - s->has_device = true; - s->device = g_strdup(bs->device_name); - } - - s->stats = g_malloc0(sizeof(*s->stats)); - s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ]; - s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE]; - s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ]; - s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE]; - s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE; - s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH]; - s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE]; - s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ]; - s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH]; - - if (bs->file) { - s->has_parent = true; - s->parent = bdrv_query_stats(bs->file); - } - - return s; -} - -BlockStatsList *qmp_query_blockstats(Error **errp) -{ - BlockStatsList *head = NULL, **p_next = &head; - BlockDriverState *bs; - - QTAILQ_FOREACH(bs, &bdrv_states, list) { - BlockStatsList *info = g_malloc0(sizeof(*info)); - info->value = bdrv_query_stats(bs); - - *p_next = info; - p_next = &info->next; - } - - return head; -} - const char *bdrv_get_encrypted_filename(BlockDriverState *bs) { if (bs->backing_hd && bs->backing_hd->encrypted) @@ -3356,129 +3235,11 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag) return false; } -/**************************************************************/ -/* handling of snapshots */ - -int bdrv_can_snapshot(BlockDriverState *bs) -{ - BlockDriver *drv = bs->drv; - if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { - return 0; - } - - if (!drv->bdrv_snapshot_create) { - if (bs->file != NULL) { - return bdrv_can_snapshot(bs->file); - } - return 0; - } - - return 1; -} - int bdrv_is_snapshot(BlockDriverState *bs) { return !!(bs->open_flags & BDRV_O_SNAPSHOT); } -BlockDriverState *bdrv_snapshots(void) -{ - BlockDriverState *bs; - - if (bs_snapshots) { - return bs_snapshots; - } - - bs = NULL; - while ((bs = bdrv_next(bs))) { - if (bdrv_can_snapshot(bs)) { - bs_snapshots = bs; - return bs; - } - } - return NULL; -} - -int bdrv_snapshot_create(BlockDriverState *bs, - QEMUSnapshotInfo *sn_info) -{ - BlockDriver *drv = bs->drv; - if (!drv) - return -ENOMEDIUM; - if (drv->bdrv_snapshot_create) - return drv->bdrv_snapshot_create(bs, sn_info); - if (bs->file) - return bdrv_snapshot_create(bs->file, sn_info); - return -ENOTSUP; -} - -int bdrv_snapshot_goto(BlockDriverState *bs, - const char *snapshot_id) -{ - BlockDriver *drv = bs->drv; - int ret, open_ret; - - if (!drv) - return -ENOMEDIUM; - if (drv->bdrv_snapshot_goto) - return drv->bdrv_snapshot_goto(bs, snapshot_id); - - if (bs->file) { - drv->bdrv_close(bs); - ret = bdrv_snapshot_goto(bs->file, snapshot_id); - open_ret = drv->bdrv_open(bs, NULL, bs->open_flags); - if (open_ret < 0) { - bdrv_delete(bs->file); - bs->drv = NULL; - return open_ret; - } - return ret; - } - - return -ENOTSUP; -} - -int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) -{ - BlockDriver *drv = bs->drv; - if (!drv) - return -ENOMEDIUM; - if (drv->bdrv_snapshot_delete) - return drv->bdrv_snapshot_delete(bs, snapshot_id); - if (bs->file) - return bdrv_snapshot_delete(bs->file, snapshot_id); - return -ENOTSUP; -} - -int bdrv_snapshot_list(BlockDriverState *bs, - QEMUSnapshotInfo **psn_info) -{ - BlockDriver *drv = bs->drv; - if (!drv) - return -ENOMEDIUM; - if (drv->bdrv_snapshot_list) - return drv->bdrv_snapshot_list(bs, psn_info); - if (bs->file) - return bdrv_snapshot_list(bs->file, psn_info); - return -ENOTSUP; -} - -int bdrv_snapshot_load_tmp(BlockDriverState *bs, - const char *snapshot_name) -{ - BlockDriver *drv = bs->drv; - if (!drv) { - return -ENOMEDIUM; - } - if (!bs->read_only) { - return -EINVAL; - } - if (drv->bdrv_snapshot_load_tmp) { - return drv->bdrv_snapshot_load_tmp(bs, snapshot_name); - } - return -ENOTSUP; -} - /* backing_file can either be relative, or absolute, or a protocol. If it is * relative, it must be relative to the chain. So, passing in bs->filename * from a BDS as backing_file should not be done, as that may be relative to @@ -3574,69 +3335,6 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs) return curr_bs; } -#define NB_SUFFIXES 4 - -char *get_human_readable_size(char *buf, int buf_size, int64_t size) -{ - static const char suffixes[NB_SUFFIXES] = "KMGT"; - int64_t base; - int i; - - if (size <= 999) { - snprintf(buf, buf_size, "%" PRId64, size); - } else { - base = 1024; - for(i = 0; i < NB_SUFFIXES; i++) { - if (size < (10 * base)) { - snprintf(buf, buf_size, "%0.1f%c", - (double)size / base, - suffixes[i]); - break; - } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { - snprintf(buf, buf_size, "%" PRId64 "%c", - ((size + (base >> 1)) / base), - suffixes[i]); - break; - } - base = base * 1024; - } - } - return buf; -} - -char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) -{ - char buf1[128], date_buf[128], clock_buf[128]; - struct tm tm; - time_t ti; - int64_t secs; - - if (!sn) { - snprintf(buf, buf_size, - "%-10s%-20s%7s%20s%15s", - "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); - } else { - ti = sn->date_sec; - localtime_r(&ti, &tm); - strftime(date_buf, sizeof(date_buf), - "%Y-%m-%d %H:%M:%S", &tm); - secs = sn->vm_clock_nsec / 1000000000; - snprintf(clock_buf, sizeof(clock_buf), - "%02d:%02d:%02d.%03d", - (int)(secs / 3600), - (int)((secs / 60) % 60), - (int)(secs % 60), - (int)((sn->vm_clock_nsec / 1000000) % 1000)); - snprintf(buf, buf_size, - "%-10s%-20s%7s%20s%15s", - sn->id_str, sn->name, - get_human_readable_size(buf1, sizeof(buf1), sn->vm_state_size), - date_buf, - clock_buf); - } - return buf; -} - /**************************************************************/ /* async I/Os */ diff --git a/block/Makefile.objs b/block/Makefile.objs index 5f0358a3d7..2981654846 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -4,6 +4,7 @@ block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-obj-y += qed-check.o block-obj-y += vhdx.o block-obj-y += parallels.o blkdebug.o blkverify.o +block-obj-y += snapshot.o qapi.o block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o block-obj-$(CONFIG_POSIX) += raw-posix.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o diff --git a/block/qapi.c b/block/qapi.c new file mode 100644 index 0000000000..794dbf8fe8 --- /dev/null +++ b/block/qapi.c @@ -0,0 +1,366 @@ +/* + * Block layer qmp and info dump related functions + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "block/qapi.h" +#include "block/block_int.h" +#include "qmp-commands.h" + +void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info) +{ + int i, sn_count; + QEMUSnapshotInfo *sn_tab = NULL; + SnapshotInfoList *info_list, *cur_item = NULL; + sn_count = bdrv_snapshot_list(bs, &sn_tab); + + for (i = 0; i < sn_count; i++) { + info->has_snapshots = true; + info_list = g_new0(SnapshotInfoList, 1); + + info_list->value = g_new0(SnapshotInfo, 1); + info_list->value->id = g_strdup(sn_tab[i].id_str); + info_list->value->name = g_strdup(sn_tab[i].name); + info_list->value->vm_state_size = sn_tab[i].vm_state_size; + info_list->value->date_sec = sn_tab[i].date_sec; + info_list->value->date_nsec = sn_tab[i].date_nsec; + info_list->value->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; + info_list->value->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; + + /* XXX: waiting for the qapi to support qemu-queue.h types */ + if (!cur_item) { + info->snapshots = cur_item = info_list; + } else { + cur_item->next = info_list; + cur_item = info_list; + } + + } + + g_free(sn_tab); +} + +void bdrv_collect_image_info(BlockDriverState *bs, + ImageInfo *info, + const char *filename) +{ + uint64_t total_sectors; + char backing_filename[1024]; + char backing_filename2[1024]; + BlockDriverInfo bdi; + + bdrv_get_geometry(bs, &total_sectors); + + info->filename = g_strdup(filename); + info->format = g_strdup(bdrv_get_format_name(bs)); + info->virtual_size = total_sectors * 512; + info->actual_size = bdrv_get_allocated_file_size(bs); + info->has_actual_size = info->actual_size >= 0; + if (bdrv_is_encrypted(bs)) { + info->encrypted = true; + info->has_encrypted = true; + } + if (bdrv_get_info(bs, &bdi) >= 0) { + if (bdi.cluster_size != 0) { + info->cluster_size = bdi.cluster_size; + info->has_cluster_size = true; + } + info->dirty_flag = bdi.is_dirty; + info->has_dirty_flag = true; + } + bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); + if (backing_filename[0] != '\0') { + info->backing_filename = g_strdup(backing_filename); + info->has_backing_filename = true; + bdrv_get_full_backing_filename(bs, backing_filename2, + sizeof(backing_filename2)); + + if (strcmp(backing_filename, backing_filename2) != 0) { + info->full_backing_filename = + g_strdup(backing_filename2); + info->has_full_backing_filename = true; + } + + if (bs->backing_format[0]) { + info->backing_filename_format = g_strdup(bs->backing_format); + info->has_backing_filename_format = true; + } + } +} + +BlockInfo *bdrv_query_info(BlockDriverState *bs) +{ + BlockInfo *info = g_malloc0(sizeof(*info)); + info->device = g_strdup(bs->device_name); + info->type = g_strdup("unknown"); + info->locked = bdrv_dev_is_medium_locked(bs); + info->removable = bdrv_dev_has_removable_media(bs); + + if (bdrv_dev_has_removable_media(bs)) { + info->has_tray_open = true; + info->tray_open = bdrv_dev_is_tray_open(bs); + } + + if (bdrv_iostatus_is_enabled(bs)) { + info->has_io_status = true; + info->io_status = bs->iostatus; + } + + if (bs->dirty_bitmap) { + info->has_dirty = true; + info->dirty = g_malloc0(sizeof(*info->dirty)); + info->dirty->count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE; + info->dirty->granularity = + ((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bs->dirty_bitmap)); + } + + if (bs->drv) { + info->has_inserted = true; + info->inserted = g_malloc0(sizeof(*info->inserted)); + info->inserted->file = g_strdup(bs->filename); + info->inserted->ro = bs->read_only; + info->inserted->drv = g_strdup(bs->drv->format_name); + info->inserted->encrypted = bs->encrypted; + info->inserted->encryption_key_missing = bdrv_key_required(bs); + + if (bs->backing_file[0]) { + info->inserted->has_backing_file = true; + info->inserted->backing_file = g_strdup(bs->backing_file); + } + + info->inserted->backing_file_depth = bdrv_get_backing_file_depth(bs); + + if (bs->io_limits_enabled) { + info->inserted->bps = + bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]; + info->inserted->bps_rd = + bs->io_limits.bps[BLOCK_IO_LIMIT_READ]; + info->inserted->bps_wr = + bs->io_limits.bps[BLOCK_IO_LIMIT_WRITE]; + info->inserted->iops = + bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]; + info->inserted->iops_rd = + bs->io_limits.iops[BLOCK_IO_LIMIT_READ]; + info->inserted->iops_wr = + bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE]; + } + } + return info; +} + +BlockStats *bdrv_query_stats(const BlockDriverState *bs) +{ + BlockStats *s; + + s = g_malloc0(sizeof(*s)); + + if (bs->device_name[0]) { + s->has_device = true; + s->device = g_strdup(bs->device_name); + } + + s->stats = g_malloc0(sizeof(*s->stats)); + s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ]; + s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE]; + s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ]; + s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE]; + s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE; + s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH]; + s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE]; + s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ]; + s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH]; + + if (bs->file) { + s->has_parent = true; + s->parent = bdrv_query_stats(bs->file); + } + + return s; +} + +BlockInfoList *qmp_query_block(Error **errp) +{ + BlockInfoList *head = NULL, **p_next = &head; + BlockDriverState *bs = NULL; + + while ((bs = bdrv_next(bs))) { + BlockInfoList *info = g_malloc0(sizeof(*info)); + info->value = bdrv_query_info(bs); + + *p_next = info; + p_next = &info->next; + } + + return head; +} + +BlockStatsList *qmp_query_blockstats(Error **errp) +{ + BlockStatsList *head = NULL, **p_next = &head; + BlockDriverState *bs = NULL; + + while ((bs = bdrv_next(bs))) { + BlockStatsList *info = g_malloc0(sizeof(*info)); + info->value = bdrv_query_stats(bs); + + *p_next = info; + p_next = &info->next; + } + + return head; +} + +#define NB_SUFFIXES 4 + +static char *get_human_readable_size(char *buf, int buf_size, int64_t size) +{ + static const char suffixes[NB_SUFFIXES] = "KMGT"; + int64_t base; + int i; + + if (size <= 999) { + snprintf(buf, buf_size, "%" PRId64, size); + } else { + base = 1024; + for (i = 0; i < NB_SUFFIXES; i++) { + if (size < (10 * base)) { + snprintf(buf, buf_size, "%0.1f%c", + (double)size / base, + suffixes[i]); + break; + } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { + snprintf(buf, buf_size, "%" PRId64 "%c", + ((size + (base >> 1)) / base), + suffixes[i]); + break; + } + base = base * 1024; + } + } + return buf; +} + +void bdrv_snapshot_dump(fprintf_function func_fprintf, void *f, + QEMUSnapshotInfo *sn) +{ + char buf1[128], date_buf[128], clock_buf[128]; + struct tm tm; + time_t ti; + int64_t secs; + + if (!sn) { + func_fprintf(f, + "%-10s%-20s%7s%20s%15s", + "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); + } else { + ti = sn->date_sec; + localtime_r(&ti, &tm); + strftime(date_buf, sizeof(date_buf), + "%Y-%m-%d %H:%M:%S", &tm); + secs = sn->vm_clock_nsec / 1000000000; + snprintf(clock_buf, sizeof(clock_buf), + "%02d:%02d:%02d.%03d", + (int)(secs / 3600), + (int)((secs / 60) % 60), + (int)(secs % 60), + (int)((sn->vm_clock_nsec / 1000000) % 1000)); + func_fprintf(f, + "%-10s%-20s%7s%20s%15s", + sn->id_str, sn->name, + get_human_readable_size(buf1, sizeof(buf1), + sn->vm_state_size), + date_buf, + clock_buf); + } +} + +void bdrv_image_info_dump(fprintf_function func_fprintf, void *f, + ImageInfo *info) +{ + char size_buf[128], dsize_buf[128]; + if (!info->has_actual_size) { + snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); + } else { + get_human_readable_size(dsize_buf, sizeof(dsize_buf), + info->actual_size); + } + get_human_readable_size(size_buf, sizeof(size_buf), info->virtual_size); + func_fprintf(f, + "image: %s\n" + "file format: %s\n" + "virtual size: %s (%" PRId64 " bytes)\n" + "disk size: %s\n", + info->filename, info->format, size_buf, + info->virtual_size, + dsize_buf); + + if (info->has_encrypted && info->encrypted) { + func_fprintf(f, "encrypted: yes\n"); + } + + if (info->has_cluster_size) { + func_fprintf(f, "cluster_size: %" PRId64 "\n", + info->cluster_size); + } + + if (info->has_dirty_flag && info->dirty_flag) { + func_fprintf(f, "cleanly shut down: no\n"); + } + + if (info->has_backing_filename) { + func_fprintf(f, "backing file: %s", info->backing_filename); + if (info->has_full_backing_filename) { + func_fprintf(f, " (actual path: %s)", info->full_backing_filename); + } + func_fprintf(f, "\n"); + if (info->has_backing_filename_format) { + func_fprintf(f, "backing file format: %s\n", + info->backing_filename_format); + } + } + + if (info->has_snapshots) { + SnapshotInfoList *elem; + + func_fprintf(f, "Snapshot list:\n"); + bdrv_snapshot_dump(func_fprintf, f, NULL); + func_fprintf(f, "\n"); + + /* Ideally bdrv_snapshot_dump() would operate on SnapshotInfoList but + * we convert to the block layer's native QEMUSnapshotInfo for now. + */ + for (elem = info->snapshots; elem; elem = elem->next) { + QEMUSnapshotInfo sn = { + .vm_state_size = elem->value->vm_state_size, + .date_sec = elem->value->date_sec, + .date_nsec = elem->value->date_nsec, + .vm_clock_nsec = elem->value->vm_clock_sec * 1000000000ULL + + elem->value->vm_clock_nsec, + }; + + pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id); + pstrcpy(sn.name, sizeof(sn.name), elem->value->name); + bdrv_snapshot_dump(func_fprintf, f, &sn); + func_fprintf(f, "\n"); + } + } +} diff --git a/block/snapshot.c b/block/snapshot.c new file mode 100644 index 0000000000..6c6d9deea1 --- /dev/null +++ b/block/snapshot.c @@ -0,0 +1,157 @@ +/* + * Block layer snapshot related functions + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "block/snapshot.h" +#include "block/block_int.h" + +int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, + const char *name) +{ + QEMUSnapshotInfo *sn_tab, *sn; + int nb_sns, i, ret; + + ret = -ENOENT; + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + if (nb_sns < 0) { + return ret; + } + for (i = 0; i < nb_sns; i++) { + sn = &sn_tab[i]; + if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { + *sn_info = *sn; + ret = 0; + break; + } + } + g_free(sn_tab); + return ret; +} + +int bdrv_can_snapshot(BlockDriverState *bs) +{ + BlockDriver *drv = bs->drv; + if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { + return 0; + } + + if (!drv->bdrv_snapshot_create) { + if (bs->file != NULL) { + return bdrv_can_snapshot(bs->file); + } + return 0; + } + + return 1; +} + +int bdrv_snapshot_create(BlockDriverState *bs, + QEMUSnapshotInfo *sn_info) +{ + BlockDriver *drv = bs->drv; + if (!drv) { + return -ENOMEDIUM; + } + if (drv->bdrv_snapshot_create) { + return drv->bdrv_snapshot_create(bs, sn_info); + } + if (bs->file) { + return bdrv_snapshot_create(bs->file, sn_info); + } + return -ENOTSUP; +} + +int bdrv_snapshot_goto(BlockDriverState *bs, + const char *snapshot_id) +{ + BlockDriver *drv = bs->drv; + int ret, open_ret; + + if (!drv) { + return -ENOMEDIUM; + } + if (drv->bdrv_snapshot_goto) { + return drv->bdrv_snapshot_goto(bs, snapshot_id); + } + + if (bs->file) { + drv->bdrv_close(bs); + ret = bdrv_snapshot_goto(bs->file, snapshot_id); + open_ret = drv->bdrv_open(bs, NULL, bs->open_flags); + if (open_ret < 0) { + bdrv_delete(bs->file); + bs->drv = NULL; + return open_ret; + } + return ret; + } + + return -ENOTSUP; +} + +int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) +{ + BlockDriver *drv = bs->drv; + if (!drv) { + return -ENOMEDIUM; + } + if (drv->bdrv_snapshot_delete) { + return drv->bdrv_snapshot_delete(bs, snapshot_id); + } + if (bs->file) { + return bdrv_snapshot_delete(bs->file, snapshot_id); + } + return -ENOTSUP; +} + +int bdrv_snapshot_list(BlockDriverState *bs, + QEMUSnapshotInfo **psn_info) +{ + BlockDriver *drv = bs->drv; + if (!drv) { + return -ENOMEDIUM; + } + if (drv->bdrv_snapshot_list) { + return drv->bdrv_snapshot_list(bs, psn_info); + } + if (bs->file) { + return bdrv_snapshot_list(bs->file, psn_info); + } + return -ENOTSUP; +} + +int bdrv_snapshot_load_tmp(BlockDriverState *bs, + const char *snapshot_name) +{ + BlockDriver *drv = bs->drv; + if (!drv) { + return -ENOMEDIUM; + } + if (!bs->read_only) { + return -EINVAL; + } + if (drv->bdrv_snapshot_load_tmp) { + return drv->bdrv_snapshot_load_tmp(bs, snapshot_name); + } + return -ENOTSUP; +} diff --git a/blockdev.c b/blockdev.c index d1ec99af73..b9b2d10e6b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -477,7 +477,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) error_printf("\n"); return NULL; } - drv = bdrv_find_whitelisted_format(buf); + drv = bdrv_find_whitelisted_format(buf, ro); if (!drv) { error_report("'%s' invalid format", buf); return NULL; @@ -1096,7 +1096,7 @@ void qmp_change_blockdev(const char *device, const char *filename, } if (format) { - drv = bdrv_find_whitelisted_format(format); + drv = bdrv_find_whitelisted_format(format, bs->read_only); if (!drv) { error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); return; @@ -123,7 +123,8 @@ interp_prefix="/usr/gnemul/qemu-%M" static="no" cross_prefix="" audio_drv_list="" -block_drv_whitelist="" +block_drv_rw_whitelist="" +block_drv_ro_whitelist="" host_cc="cc" libs_softmmu="" libs_tools="" @@ -546,7 +547,7 @@ Haiku) if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then audio_possible_drivers="$audio_possible_drivers fmod" fi - QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers $QEMU_INCLUDES" + QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$(pwd)/linux-headers $QEMU_INCLUDES" ;; esac @@ -587,7 +588,7 @@ EOF qemu_docdir="\${prefix}" bindir="\${prefix}" sysconfdir="\${prefix}" - local_statedir="\${prefix}" + local_statedir= confsuffix="" libs_qga="-lws2_32 -lwinmm -lpowrprof $libs_qga" fi @@ -708,7 +709,9 @@ for opt do ;; --audio-drv-list=*) audio_drv_list="$optarg" ;; - --block-drv-whitelist=*) block_drv_whitelist=`echo "$optarg" | sed -e 's/,/ /g'` + --block-drv-rw-whitelist=*|--block-drv-whitelist=*) block_drv_rw_whitelist=`echo "$optarg" | sed -e 's/,/ /g'` + ;; + --block-drv-ro-whitelist=*) block_drv_ro_whitelist=`echo "$optarg" | sed -e 's/,/ /g'` ;; --enable-debug-tcg) debug_tcg="yes" ;; @@ -974,78 +977,22 @@ EXTRA_CFLAGS="$CPU_CFLAGS $EXTRA_CFLAGS" default_target_list="" -# these targets are portable -if [ "$softmmu" = "yes" ] ; then - default_target_list="\ -i386-softmmu \ -x86_64-softmmu \ -alpha-softmmu \ -arm-softmmu \ -cris-softmmu \ -lm32-softmmu \ -m68k-softmmu \ -microblaze-softmmu \ -microblazeel-softmmu \ -mips-softmmu \ -mipsel-softmmu \ -mips64-softmmu \ -mips64el-softmmu \ -moxie-softmmu \ -or32-softmmu \ -ppc-softmmu \ -ppcemb-softmmu \ -ppc64-softmmu \ -sh4-softmmu \ -sh4eb-softmmu \ -sparc-softmmu \ -sparc64-softmmu \ -s390x-softmmu \ -xtensa-softmmu \ -xtensaeb-softmmu \ -unicore32-softmmu \ -" -fi -# the following are Linux specific -if [ "$linux_user" = "yes" ] ; then - default_target_list="${default_target_list}\ -i386-linux-user \ -x86_64-linux-user \ -alpha-linux-user \ -arm-linux-user \ -armeb-linux-user \ -cris-linux-user \ -m68k-linux-user \ -microblaze-linux-user \ -microblazeel-linux-user \ -mips-linux-user \ -mipsel-linux-user \ -mips64-linux-user \ -mips64el-linux-user \ -mipsn32-linux-user \ -mipsn32el-linux-user \ -or32-linux-user \ -ppc-linux-user \ -ppc64-linux-user \ -ppc64abi32-linux-user \ -sh4-linux-user \ -sh4eb-linux-user \ -sparc-linux-user \ -sparc64-linux-user \ -sparc32plus-linux-user \ -unicore32-linux-user \ -s390x-linux-user \ -" -fi -# the following are BSD specific -if [ "$bsd_user" = "yes" ] ; then - default_target_list="${default_target_list}\ -i386-bsd-user \ -x86_64-bsd-user \ -sparc-bsd-user \ -sparc64-bsd-user \ -" +mak_wilds="" + +if [ "$softmmu" = "yes" ]; then + mak_wilds="${mak_wilds} $source_path/default-configs/*-softmmu.mak" +fi +if [ "$linux_user" = "yes" ]; then + mak_wilds="${mak_wilds} $source_path/default-configs/*-linux-user.mak" +fi +if [ "$bsd_user" = "yes" ]; then + mak_wilds="${mak_wilds} $source_path/default-configs/*-bsd-user.mak" fi +for config in $mak_wilds; do + default_target_list="${default_target_list} $(basename "$config" .mak)" +done + if test x"$show_help" = x"yes" ; then cat << EOF @@ -1082,7 +1029,7 @@ echo " --docdir=PATH install documentation in PATH$confsuffix" echo " --bindir=PATH install binaries in PATH" echo " --libdir=PATH install libraries in PATH" echo " --sysconfdir=PATH install config in PATH$confsuffix" -echo " --localstatedir=PATH install local state in PATH" +echo " --localstatedir=PATH install local state in PATH (set at runtime on win32)" echo " --with-confsuffix=SUFFIX suffix for QEMU data inside datadir and sysconfdir [$confsuffix]" echo " --enable-debug-tcg enable TCG debugging" echo " --disable-debug-tcg disable TCG debugging (default)" @@ -1105,7 +1052,12 @@ echo " --disable-cocoa disable Cocoa (Mac OS X only)" echo " --enable-cocoa enable Cocoa (default on Mac OS X)" echo " --audio-drv-list=LIST set audio drivers list:" echo " Available drivers: $audio_possible_drivers" -echo " --block-drv-whitelist=L set block driver whitelist" +echo " --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L" +echo " --block-drv-rw-whitelist=L" +echo " set block driver read-write whitelist" +echo " (affects only QEMU, not qemu-img)" +echo " --block-drv-ro-whitelist=L" +echo " set block driver read-only whitelist" echo " (affects only QEMU, not qemu-img)" echo " --enable-mixemu enable mixer emulation" echo " --disable-xen disable xen backend driver support" @@ -1399,6 +1351,19 @@ if test -z "${target_list+xxx}" ; then else target_list=`echo "$target_list" | sed -e 's/,/ /g'` fi + +# Check that we recognised the target name; this allows a more +# friendly error message than if we let it fall through. +for target in $target_list; do + case " $default_target_list " in + *" $target "*) + ;; + *) + error_exit "Unknown target name '$target'" + ;; + esac +done + # see if system emulation was really requested case " $target_list " in *"-softmmu "*) softmmu=yes @@ -2153,13 +2118,12 @@ fi ########################################## # curses probe -if test "$mingw32" = "yes" ; then - curses_list="-lpdcurses" -else - curses_list="-lncurses:-lcurses:$($pkg_config --libs ncurses 2>/dev/null)" -fi - if test "$curses" != "no" ; then + if test "$mingw32" = "yes" ; then + curses_list="-lpdcurses" + else + curses_list="$($pkg_config --libs ncurses 2>/dev/null):-lncurses:-lcurses" + fi curses_found=no cat > $TMPC << EOF #include <curses.h> @@ -2191,14 +2155,12 @@ fi ########################################## # curl probe - -if $pkg_config libcurl --modversion >/dev/null 2>&1; then - curlconfig="$pkg_config libcurl" -else - curlconfig=curl-config -fi - if test "$curl" != "no" ; then + if $pkg_config libcurl --modversion >/dev/null 2>&1; then + curlconfig="$pkg_config libcurl" + else + curlconfig=curl-config + fi cat > $TMPC << EOF #include <curl/curl.h> int main(void) { curl_easy_init(); curl_multi_setopt(0, 0, 0); return 0; } @@ -3487,10 +3449,12 @@ echo "library directory `eval echo $libdir`" echo "libexec directory `eval echo $libexecdir`" echo "include directory `eval echo $includedir`" echo "config directory `eval echo $sysconfdir`" -echo "local state directory `eval echo $local_statedir`" if test "$mingw32" = "no" ; then +echo "local state directory `eval echo $local_statedir`" echo "Manual directory `eval echo $mandir`" echo "ELF interp prefix $interp_prefix" +else +echo "local state directory queried at runtime" fi echo "Source path $source_path" echo "C compiler $cc" @@ -3525,7 +3489,8 @@ echo "curses support $curses" echo "curl support $curl" echo "mingw32 support $mingw32" echo "Audio drivers $audio_drv_list" -echo "Block whitelist $block_drv_whitelist" +echo "Block whitelist (rw) $block_drv_rw_whitelist" +echo "Block whitelist (ro) $block_drv_ro_whitelist" echo "Mixer emulation $mixemu" echo "VirtFS support $virtfs" echo "VNC support $vnc" @@ -3611,7 +3576,9 @@ echo "sysconfdir=$sysconfdir" >> $config_host_mak echo "qemu_confdir=$qemu_confdir" >> $config_host_mak echo "qemu_datadir=$qemu_datadir" >> $config_host_mak echo "qemu_docdir=$qemu_docdir" >> $config_host_mak -echo "qemu_localstatedir=$local_statedir" >> $config_host_mak +if test "$mingw32" = "no" ; then + echo "qemu_localstatedir=$local_statedir" >> $config_host_mak +fi echo "qemu_helperdir=$libexecdir" >> $config_host_mak echo "extra_cflags=$EXTRA_CFLAGS" >> $config_host_mak echo "extra_ldflags=$EXTRA_LDFLAGS" >> $config_host_mak @@ -3704,7 +3671,8 @@ fi if test "$audio_win_int" = "yes" ; then echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak fi -echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak +echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak +echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak if test "$mixemu" = "yes" ; then echo "CONFIG_MIXEMU=y" >> $config_host_mak fi @@ -4103,17 +4071,8 @@ if test "$gcov" = "yes" ; then fi # generate list of library paths for linker script - $ld --verbose -v 2> /dev/null | grep SEARCH_DIR > ${config_host_ld} -if test -f ${config_host_ld}~ ; then - if cmp -s $config_host_ld ${config_host_ld}~ ; then - mv ${config_host_ld}~ $config_host_ld - else - rm ${config_host_ld}~ - fi -fi - # use included Linux headers if test "$linux" = "yes" ; then mkdir -p linux-headers @@ -248,13 +248,18 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr, target_ulong code_address; uintptr_t addend; CPUTLBEntry *te; - hwaddr iotlb; + hwaddr iotlb, xlat, sz; assert(size >= TARGET_PAGE_SIZE); if (size != TARGET_PAGE_SIZE) { tlb_add_large_page(env, vaddr, size); } - section = phys_page_find(address_space_memory.dispatch, paddr >> TARGET_PAGE_BITS); + + sz = size; + section = address_space_translate(&address_space_memory, paddr, &xlat, &sz, + false); + assert(sz >= TARGET_PAGE_SIZE); + #if defined(DEBUG_TLB) printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx " prot=%x idx=%d pd=0x%08lx\n", @@ -262,22 +267,18 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr, #endif address = vaddr; - if (!(memory_region_is_ram(section->mr) || - memory_region_is_romd(section->mr))) { - /* IO memory case (romd handled later) */ + if (!memory_region_is_ram(section->mr) && !memory_region_is_romd(section->mr)) { + /* IO memory case */ address |= TLB_MMIO; - } - if (memory_region_is_ram(section->mr) || - memory_region_is_romd(section->mr)) { - addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) - + memory_region_section_addr(section, paddr); - } else { addend = 0; + } else { + /* TLB_MMIO for rom/romd handled below */ + addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat; } code_address = address; - iotlb = memory_region_section_get_iotlb(env, section, vaddr, paddr, prot, - &address); + iotlb = memory_region_section_get_iotlb(env, section, vaddr, paddr, xlat, + prot, &address); index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); env->iotlb[mmu_idx][index] = iotlb - vaddr; @@ -300,9 +301,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr, /* Write access calls the I/O callback. */ te->addr_write = address | TLB_MMIO; } else if (memory_region_is_ram(section->mr) - && !cpu_physical_memory_is_dirty( - section->mr->ram_addr - + memory_region_section_addr(section, paddr))) { + && !cpu_physical_memory_is_dirty(section->mr->ram_addr + xlat)) { te->addr_write = address | TLB_NOTDIRTY; } else { te->addr_write = address; diff --git a/dma-helpers.c b/dma-helpers.c index 272632f367..2e298b6ebb 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -298,6 +298,11 @@ bool iommu_dma_memory_valid(DMAContext *dma, dma_addr_t addr, dma_addr_t len, plen = len; } + if (!address_space_access_valid(dma->as, paddr, len, + dir == DMA_DIRECTION_FROM_DEVICE)) { + return false; + } + len -= plen; addr += plen; } diff --git a/docs/migration.txt b/docs/migration.txt index 0719a55002..0e0a1d44da 100644 --- a/docs/migration.txt +++ b/docs/migration.txt @@ -41,7 +41,7 @@ All these four migration protocols use the same infrastructure to save/restore state devices. This infrastructure is shared with the savevm/loadvm functionality. -=== State Live Migration == +=== State Live Migration === This is used for RAM and block devices. It is not yet ported to vmstate. <Fill more information here> @@ -83,7 +83,7 @@ pointer that is passed to all functions. The important functions for us are put_buffer()/get_buffer() that allow to write/read a buffer into the QEMUFile. -=== How to save the state of one device == +=== How to save the state of one device === The state of a device is saved using intermediate buffers. There are some helper functions to assist this saving. @@ -97,7 +97,7 @@ associated with a series of fields saved. The save_state always saves the state as the newer version. But load_state sometimes is able to load state from an older version. - === Legacy way === +=== Legacy way === This way is going to disappear as soon as all current users are ported to VMSTATE. @@ -133,7 +133,7 @@ to interpret that definition to be able to load/save the state. As the state is declared only once, it can't go out of sync in the save/load functions. -An example (from hw/pckbd.c) +An example (from hw/input/pckbd.c) static const VMStateDescription vmstate_kbd = { .name = "pckbd", @@ -158,9 +158,9 @@ We registered this with: Note: talk about how vmstate <-> qdev interact, and what the instance ids mean. You can search for VMSTATE_* macros for lots of types used in QEMU in -hw/hw.h. +include/hw/hw.h. -=== More about versions == +=== More about versions === You can see that there are several version fields: @@ -227,7 +227,7 @@ using a specific functionality, .... It is impossible to create a way to make migration from any version to any other version to work. But we can do better than only allowing -migration from older versions no newer ones. For that fields that are +migration from older versions to newer ones. For that fields that are only needed sometimes, we add the idea of subsections. A subsection is "like" a device vmstate, but with a particularity, it has a Boolean function that tells if that values are needed to be sent or not. If @@ -247,7 +247,8 @@ static bool ide_drive_pio_state_needed(void *opaque) { IDEState *s = opaque; - return (s->status & DRQ_STAT) != 0; + return ((s->status & DRQ_STAT) != 0) + || (s->bus->error_status & BM_STATUS_PIO_RETRY); } const VMStateDescription vmstate_ide_drive_pio_state = { @@ -50,7 +50,6 @@ #include "exec/memory-internal.h" -//#define DEBUG_UNASSIGNED //#define DEBUG_SUBPAGE #if !defined(CONFIG_USER_ONLY) @@ -66,8 +65,8 @@ AddressSpace address_space_io; AddressSpace address_space_memory; DMAContext dma_context_memory; -MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty; -static MemoryRegion io_mem_subpage_ram; +MemoryRegion io_mem_rom, io_mem_notdirty; +static MemoryRegion io_mem_unassigned, io_mem_subpage_ram; #endif @@ -182,7 +181,7 @@ static void phys_page_set(AddressSpaceDispatch *d, phys_page_set_level(&d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1); } -MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr index) +static MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr index) { PhysPageEntry lp = d->phys_map; PhysPageEntry *p; @@ -200,10 +199,28 @@ MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr index) bool memory_region_is_unassigned(MemoryRegion *mr) { - return mr != &io_mem_ram && mr != &io_mem_rom - && mr != &io_mem_notdirty && !mr->rom_device + return mr != &io_mem_rom && mr != &io_mem_notdirty && !mr->rom_device && mr != &io_mem_watch; } + +MemoryRegionSection *address_space_translate(AddressSpace *as, hwaddr addr, + hwaddr *xlat, hwaddr *plen, + bool is_write) +{ + MemoryRegionSection *section; + Int128 diff; + + section = phys_page_find(as->dispatch, addr >> TARGET_PAGE_BITS); + /* Compute offset within MemoryRegionSection */ + addr -= section->offset_within_address_space; + + /* Compute offset within MemoryRegion */ + *xlat = addr + section->offset_within_region; + + diff = int128_sub(section->mr->size, int128_make64(addr)); + *plen = MIN(int128_get64(diff), *plen); + return section; +} #endif void cpu_exec_init_all(void) @@ -616,11 +633,11 @@ static int cpu_physical_memory_set_dirty_tracking(int enable) } hwaddr memory_region_section_get_iotlb(CPUArchState *env, - MemoryRegionSection *section, - target_ulong vaddr, - hwaddr paddr, - int prot, - target_ulong *address) + MemoryRegionSection *section, + target_ulong vaddr, + hwaddr paddr, hwaddr xlat, + int prot, + target_ulong *address) { hwaddr iotlb; CPUWatchpoint *wp; @@ -628,7 +645,7 @@ hwaddr memory_region_section_get_iotlb(CPUArchState *env, if (memory_region_is_ram(section->mr)) { /* Normal RAM. */ iotlb = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK) - + memory_region_section_addr(section, paddr); + + xlat; if (!section->readonly) { iotlb |= phys_section_notdirty; } else { @@ -636,7 +653,7 @@ hwaddr memory_region_section_get_iotlb(CPUArchState *env, } } else { iotlb = section - phys_sections; - iotlb += memory_region_section_addr(section, paddr); + iotlb += xlat; } /* Make accesses to pages with watchpoints go via the @@ -1384,69 +1401,14 @@ ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr) return ram_addr; } -static uint64_t unassigned_mem_read(void *opaque, hwaddr addr, - unsigned size) -{ -#ifdef DEBUG_UNASSIGNED - printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); -#endif -#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) - cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size); -#endif - return 0; -} - -static void unassigned_mem_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ -#ifdef DEBUG_UNASSIGNED - printf("Unassigned mem write " TARGET_FMT_plx " = 0x%"PRIx64"\n", addr, val); -#endif -#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) - cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size); -#endif -} - -static const MemoryRegionOps unassigned_mem_ops = { - .read = unassigned_mem_read, - .write = unassigned_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static uint64_t error_mem_read(void *opaque, hwaddr addr, - unsigned size) -{ - abort(); -} - -static void error_mem_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - abort(); -} - -static const MemoryRegionOps error_mem_ops = { - .read = error_mem_read, - .write = error_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const MemoryRegionOps rom_mem_ops = { - .read = error_mem_read, - .write = unassigned_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - static void notdirty_mem_write(void *opaque, hwaddr ram_addr, uint64_t val, unsigned size) { int dirty_flags; dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr); if (!(dirty_flags & CODE_DIRTY_FLAG)) { -#if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(ram_addr, size); dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr); -#endif } switch (size) { case 1: @@ -1469,9 +1431,15 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr, tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr); } +static bool notdirty_mem_accepts(void *opaque, hwaddr addr, + unsigned size, bool is_write) +{ + return is_write; +} + static const MemoryRegionOps notdirty_mem_ops = { - .read = error_mem_read, .write = notdirty_mem_write, + .valid.accepts = notdirty_mem_accepts, .endianness = DEVICE_NATIVE_ENDIAN, }; @@ -1558,6 +1526,8 @@ static uint64_t subpage_read(void *opaque, hwaddr addr, { subpage_t *mmio = opaque; unsigned int idx = SUBPAGE_IDX(addr); + uint64_t val; + MemoryRegionSection *section; #if defined(DEBUG_SUBPAGE) printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__, @@ -1568,7 +1538,8 @@ static uint64_t subpage_read(void *opaque, hwaddr addr, addr += mmio->base; addr -= section->offset_within_address_space; addr += section->offset_within_region; - return io_mem_read(section->mr, addr, len); + io_mem_read(section->mr, addr, &val, len); + return val; } static void subpage_write(void *opaque, hwaddr addr, @@ -1590,9 +1561,29 @@ static void subpage_write(void *opaque, hwaddr addr, io_mem_write(section->mr, addr, value, len); } +static bool subpage_accepts(void *opaque, hwaddr addr, + unsigned size, bool is_write) +{ + subpage_t *mmio = opaque; + unsigned int idx = SUBPAGE_IDX(addr); + MemoryRegionSection *section; +#if defined(DEBUG_SUBPAGE) + printf("%s: subpage %p %c len %d addr " TARGET_FMT_plx + " idx %d\n", __func__, mmio, + is_write ? 'w' : 'r', len, addr, idx); +#endif + + section = &phys_sections[mmio->sub_section[idx]]; + addr += mmio->base; + addr -= section->offset_within_address_space; + addr += section->offset_within_region; + return memory_region_access_valid(section->mr, addr, size, is_write); +} + static const MemoryRegionOps subpage_ops = { .read = subpage_read, .write = subpage_write, + .valid.accepts = subpage_accepts, .endianness = DEVICE_NATIVE_ENDIAN, }; @@ -1691,8 +1682,7 @@ MemoryRegion *iotlb_to_region(hwaddr index) static void io_mem_init(void) { - memory_region_init_io(&io_mem_ram, &error_mem_ops, NULL, "ram", UINT64_MAX); - memory_region_init_io(&io_mem_rom, &rom_mem_ops, NULL, "rom", UINT64_MAX); + memory_region_init_io(&io_mem_rom, &unassigned_mem_ops, NULL, "rom", UINT64_MAX); memory_region_init_io(&io_mem_unassigned, &unassigned_mem_ops, NULL, "unassigned", UINT64_MAX); memory_region_init_io(&io_mem_notdirty, ¬dirty_mem_ops, NULL, @@ -1889,81 +1879,88 @@ static void invalidate_and_set_dirty(hwaddr addr, xen_modified_memory(addr, length); } -void address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, +static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) +{ + if (memory_region_is_ram(mr)) { + return !(is_write && mr->readonly); + } + if (memory_region_is_romd(mr)) { + return !is_write; + } + + return false; +} + +static inline int memory_access_size(int l, hwaddr addr) +{ + if (l >= 4 && ((addr & 3) == 0)) { + return 4; + } + if (l >= 2 && ((addr & 1) == 0)) { + return 2; + } + return 1; +} + +bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, int len, bool is_write) { - AddressSpaceDispatch *d = as->dispatch; - int l; + hwaddr l; uint8_t *ptr; - uint32_t val; - hwaddr page; + uint64_t val; + hwaddr addr1; MemoryRegionSection *section; + bool error = false; while (len > 0) { - page = addr & TARGET_PAGE_MASK; - l = (page + TARGET_PAGE_SIZE) - addr; - if (l > len) - l = len; - section = phys_page_find(d, page >> TARGET_PAGE_BITS); + l = len; + section = address_space_translate(as, addr, &addr1, &l, is_write); if (is_write) { - if (!memory_region_is_ram(section->mr)) { - hwaddr addr1; - addr1 = memory_region_section_addr(section, addr); + if (!memory_access_is_direct(section->mr, is_write)) { + l = memory_access_size(l, addr1); /* XXX: could force cpu_single_env to NULL to avoid potential bugs */ - if (l >= 4 && ((addr1 & 3) == 0)) { + if (l == 4) { /* 32 bit write access */ val = ldl_p(buf); - io_mem_write(section->mr, addr1, val, 4); - l = 4; - } else if (l >= 2 && ((addr1 & 1) == 0)) { + error |= io_mem_write(section->mr, addr1, val, 4); + } else if (l == 2) { /* 16 bit write access */ val = lduw_p(buf); - io_mem_write(section->mr, addr1, val, 2); - l = 2; + error |= io_mem_write(section->mr, addr1, val, 2); } else { /* 8 bit write access */ val = ldub_p(buf); - io_mem_write(section->mr, addr1, val, 1); - l = 1; + error |= io_mem_write(section->mr, addr1, val, 1); } - } else if (!section->readonly) { - ram_addr_t addr1; - addr1 = memory_region_get_ram_addr(section->mr) - + memory_region_section_addr(section, addr); + } else { + addr1 += memory_region_get_ram_addr(section->mr); /* RAM case */ ptr = qemu_get_ram_ptr(addr1); memcpy(ptr, buf, l); invalidate_and_set_dirty(addr1, l); } } else { - if (!(memory_region_is_ram(section->mr) || - memory_region_is_romd(section->mr))) { - hwaddr addr1; + if (!memory_access_is_direct(section->mr, is_write)) { /* I/O case */ - addr1 = memory_region_section_addr(section, addr); - if (l >= 4 && ((addr1 & 3) == 0)) { + l = memory_access_size(l, addr1); + if (l == 4) { /* 32 bit read access */ - val = io_mem_read(section->mr, addr1, 4); + error |= io_mem_read(section->mr, addr1, &val, 4); stl_p(buf, val); - l = 4; - } else if (l >= 2 && ((addr1 & 1) == 0)) { + } else if (l == 2) { /* 16 bit read access */ - val = io_mem_read(section->mr, addr1, 2); + error |= io_mem_read(section->mr, addr1, &val, 2); stw_p(buf, val); - l = 2; } else { /* 8 bit read access */ - val = io_mem_read(section->mr, addr1, 1); + error |= io_mem_read(section->mr, addr1, &val, 1); stb_p(buf, val); - l = 1; } } else { /* RAM case */ - ptr = qemu_get_ram_ptr(section->mr->ram_addr - + memory_region_section_addr(section, - addr)); + ptr = qemu_get_ram_ptr(section->mr->ram_addr + addr1); memcpy(buf, ptr, l); } } @@ -1971,57 +1968,47 @@ void address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, buf += l; addr += l; } + + return error; } -void address_space_write(AddressSpace *as, hwaddr addr, +bool address_space_write(AddressSpace *as, hwaddr addr, const uint8_t *buf, int len) { - address_space_rw(as, addr, (uint8_t *)buf, len, true); + return address_space_rw(as, addr, (uint8_t *)buf, len, true); } -/** - * address_space_read: read from an address space. - * - * @as: #AddressSpace to be accessed - * @addr: address within that address space - * @buf: buffer with the data transferred - */ -void address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len) +bool address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len) { - address_space_rw(as, addr, buf, len, false); + return address_space_rw(as, addr, buf, len, false); } void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf, int len, int is_write) { - return address_space_rw(&address_space_memory, addr, buf, len, is_write); + address_space_rw(&address_space_memory, addr, buf, len, is_write); } /* used for ROM loading : can write in RAM and ROM */ void cpu_physical_memory_write_rom(hwaddr addr, const uint8_t *buf, int len) { - AddressSpaceDispatch *d = address_space_memory.dispatch; - int l; + hwaddr l; uint8_t *ptr; - hwaddr page; + hwaddr addr1; MemoryRegionSection *section; while (len > 0) { - page = addr & TARGET_PAGE_MASK; - l = (page + TARGET_PAGE_SIZE) - addr; - if (l > len) - l = len; - section = phys_page_find(d, page >> TARGET_PAGE_BITS); + l = len; + section = address_space_translate(&address_space_memory, + addr, &addr1, &l, true); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { /* do nothing */ } else { - unsigned long addr1; - addr1 = memory_region_get_ram_addr(section->mr) - + memory_region_section_addr(section, addr); + addr1 += memory_region_get_ram_addr(section->mr); /* ROM/RAM case */ ptr = qemu_get_ram_ptr(addr1); memcpy(ptr, buf, l); @@ -2079,6 +2066,27 @@ static void cpu_notify_map_clients(void) } } +bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write) +{ + MemoryRegionSection *section; + hwaddr l, xlat; + + while (len > 0) { + l = len; + section = address_space_translate(as, addr, &xlat, &l, is_write); + if (!memory_access_is_direct(section->mr, is_write)) { + l = memory_access_size(l, addr); + if (!memory_region_access_valid(section->mr, xlat, l, is_write)) { + return false; + } + } + + len -= l; + addr += l; + } + return true; +} + /* Map a physical memory region into a host virtual address. * May map a subset of the requested range, given by and returned in *plen. * May return NULL if resources needed to perform the mapping are exhausted. @@ -2091,24 +2099,19 @@ void *address_space_map(AddressSpace *as, hwaddr *plen, bool is_write) { - AddressSpaceDispatch *d = as->dispatch; hwaddr len = *plen; hwaddr todo = 0; - int l; - hwaddr page; + hwaddr l, xlat; MemoryRegionSection *section; ram_addr_t raddr = RAM_ADDR_MAX; ram_addr_t rlen; void *ret; while (len > 0) { - page = addr & TARGET_PAGE_MASK; - l = (page + TARGET_PAGE_SIZE) - addr; - if (l > len) - l = len; - section = phys_page_find(d, page >> TARGET_PAGE_BITS); + l = len; + section = address_space_translate(as, addr, &xlat, &l, is_write); - if (!(memory_region_is_ram(section->mr) && !section->readonly)) { + if (!memory_access_is_direct(section->mr, is_write)) { if (todo || bounce.buffer) { break; } @@ -2123,8 +2126,11 @@ void *address_space_map(AddressSpace *as, return bounce.buffer; } if (!todo) { - raddr = memory_region_get_ram_addr(section->mr) - + memory_region_section_addr(section, addr); + raddr = memory_region_get_ram_addr(section->mr) + xlat; + } else { + if (memory_region_get_ram_addr(section->mr) + xlat != raddr + todo) { + break; + } } len -= l; @@ -2188,16 +2194,16 @@ static inline uint32_t ldl_phys_internal(hwaddr addr, enum device_endian endian) { uint8_t *ptr; - uint32_t val; + uint64_t val; MemoryRegionSection *section; + hwaddr l = 4; + hwaddr addr1; - section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); - - if (!(memory_region_is_ram(section->mr) || - memory_region_is_romd(section->mr))) { + section = address_space_translate(&address_space_memory, addr, &addr1, &l, + false); + if (l < 4 || !memory_access_is_direct(section->mr, false)) { /* I/O case */ - addr = memory_region_section_addr(section, addr); - val = io_mem_read(section->mr, addr, 4); + io_mem_read(section->mr, addr1, &val, 4); #if defined(TARGET_WORDS_BIGENDIAN) if (endian == DEVICE_LITTLE_ENDIAN) { val = bswap32(val); @@ -2211,7 +2217,7 @@ static inline uint32_t ldl_phys_internal(hwaddr addr, /* RAM case */ ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK) - + memory_region_section_addr(section, addr)); + + addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: val = ldl_le_p(ptr); @@ -2249,28 +2255,28 @@ static inline uint64_t ldq_phys_internal(hwaddr addr, uint8_t *ptr; uint64_t val; MemoryRegionSection *section; + hwaddr l = 8; + hwaddr addr1; - section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); - - if (!(memory_region_is_ram(section->mr) || - memory_region_is_romd(section->mr))) { + section = address_space_translate(&address_space_memory, addr, &addr1, &l, + false); + if (l < 8 || !memory_access_is_direct(section->mr, false)) { /* I/O case */ - addr = memory_region_section_addr(section, addr); - - /* XXX This is broken when device endian != cpu endian. - Fix and add "endian" variable check */ -#ifdef TARGET_WORDS_BIGENDIAN - val = io_mem_read(section->mr, addr, 4) << 32; - val |= io_mem_read(section->mr, addr + 4, 4); + io_mem_read(section->mr, addr1, &val, 8); +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap64(val); + } #else - val = io_mem_read(section->mr, addr, 4); - val |= io_mem_read(section->mr, addr + 4, 4) << 32; + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap64(val); + } #endif } else { /* RAM case */ ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK) - + memory_region_section_addr(section, addr)); + + addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: val = ldq_le_p(ptr); @@ -2316,14 +2322,14 @@ static inline uint32_t lduw_phys_internal(hwaddr addr, uint8_t *ptr; uint64_t val; MemoryRegionSection *section; + hwaddr l = 2; + hwaddr addr1; - section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); - - if (!(memory_region_is_ram(section->mr) || - memory_region_is_romd(section->mr))) { + section = address_space_translate(&address_space_memory, addr, &addr1, &l, + false); + if (l < 2 || !memory_access_is_direct(section->mr, false)) { /* I/O case */ - addr = memory_region_section_addr(section, addr); - val = io_mem_read(section->mr, addr, 2); + io_mem_read(section->mr, addr1, &val, 2); #if defined(TARGET_WORDS_BIGENDIAN) if (endian == DEVICE_LITTLE_ENDIAN) { val = bswap16(val); @@ -2337,7 +2343,7 @@ static inline uint32_t lduw_phys_internal(hwaddr addr, /* RAM case */ ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK) - + memory_region_section_addr(section, addr)); + + addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: val = lduw_le_p(ptr); @@ -2375,19 +2381,15 @@ void stl_phys_notdirty(hwaddr addr, uint32_t val) { uint8_t *ptr; MemoryRegionSection *section; + hwaddr l = 4; + hwaddr addr1; - section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); - - if (!memory_region_is_ram(section->mr) || section->readonly) { - addr = memory_region_section_addr(section, addr); - if (memory_region_is_ram(section->mr)) { - section = &phys_sections[phys_section_rom]; - } - io_mem_write(section->mr, addr, val, 4); + section = address_space_translate(&address_space_memory, addr, &addr1, &l, + true); + if (l < 4 || !memory_access_is_direct(section->mr, true)) { + io_mem_write(section->mr, addr1, val, 4); } else { - unsigned long addr1 = (memory_region_get_ram_addr(section->mr) - & TARGET_PAGE_MASK) - + memory_region_section_addr(section, addr); + addr1 += memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK; ptr = qemu_get_ram_ptr(addr1); stl_p(ptr, val); @@ -2409,14 +2411,12 @@ static inline void stl_phys_internal(hwaddr addr, uint32_t val, { uint8_t *ptr; MemoryRegionSection *section; + hwaddr l = 4; + hwaddr addr1; - section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); - - if (!memory_region_is_ram(section->mr) || section->readonly) { - addr = memory_region_section_addr(section, addr); - if (memory_region_is_ram(section->mr)) { - section = &phys_sections[phys_section_rom]; - } + section = address_space_translate(&address_space_memory, addr, &addr1, &l, + true); + if (l < 4 || !memory_access_is_direct(section->mr, true)) { #if defined(TARGET_WORDS_BIGENDIAN) if (endian == DEVICE_LITTLE_ENDIAN) { val = bswap32(val); @@ -2426,12 +2426,10 @@ static inline void stl_phys_internal(hwaddr addr, uint32_t val, val = bswap32(val); } #endif - io_mem_write(section->mr, addr, val, 4); + io_mem_write(section->mr, addr1, val, 4); } else { - unsigned long addr1; - addr1 = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK) - + memory_region_section_addr(section, addr); /* RAM case */ + addr1 += memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK; ptr = qemu_get_ram_ptr(addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: @@ -2476,14 +2474,12 @@ static inline void stw_phys_internal(hwaddr addr, uint32_t val, { uint8_t *ptr; MemoryRegionSection *section; + hwaddr l = 2; + hwaddr addr1; - section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); - - if (!memory_region_is_ram(section->mr) || section->readonly) { - addr = memory_region_section_addr(section, addr); - if (memory_region_is_ram(section->mr)) { - section = &phys_sections[phys_section_rom]; - } + section = address_space_translate(&address_space_memory, addr, &addr1, &l, + true); + if (l < 2 || !memory_access_is_direct(section->mr, true)) { #if defined(TARGET_WORDS_BIGENDIAN) if (endian == DEVICE_LITTLE_ENDIAN) { val = bswap16(val); @@ -2493,12 +2489,10 @@ static inline void stw_phys_internal(hwaddr addr, uint32_t val, val = bswap16(val); } #endif - io_mem_write(section->mr, addr, val, 2); + io_mem_write(section->mr, addr1, val, 2); } else { - unsigned long addr1; - addr1 = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK) - + memory_region_section_addr(section, addr); /* RAM case */ + addr1 += memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK; ptr = qemu_get_ram_ptr(addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: @@ -2601,9 +2595,10 @@ bool virtio_is_big_endian(void) bool cpu_physical_memory_is_io(hwaddr phys_addr) { MemoryRegionSection *section; + hwaddr l = 1; - section = phys_page_find(address_space_memory.dispatch, - phys_addr >> TARGET_PAGE_BITS); + section = address_space_translate(&address_space_memory, + phys_addr, &phys_addr, &l, false); return !(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr)); @@ -371,7 +371,9 @@ static inline void gdb_continue(GDBState *s) #ifdef CONFIG_USER_ONLY s->running_state = 1; #else - vm_start(); + if (runstate_check(RUN_STATE_DEBUG)) { + vm_start(); + } #endif } diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 2efebf3571..194c1306c6 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -38,6 +38,10 @@ int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, }); v9fs_path_unlock(s); } + /* The ioctl may not be supported depending on the path */ + if (err == -ENOTTY) { + err = 0; + } return err; } diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 6ece6f7d1c..fc93e9e6e8 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -59,6 +59,33 @@ static const char *local_mapped_attr_path(FsContext *ctx, return buffer; } +static FILE *local_fopen(const char *path, const char *mode) +{ + int fd, o_mode = 0; + FILE *fp; + int flags = O_NOFOLLOW; + /* + * only supports two modes + */ + if (mode[0] == 'r') { + flags |= O_RDONLY; + } else if (mode[0] == 'w') { + flags |= O_WRONLY | O_TRUNC | O_CREAT; + o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + } else { + return NULL; + } + fd = open(path, flags, o_mode); + if (fd == -1) { + return NULL; + } + fp = fdopen(fd, mode); + if (!fp) { + close(fd); + } + return fp; +} + #define ATTR_MAX 100 static void local_mapped_file_attr(FsContext *ctx, const char *path, struct stat *stbuf) @@ -68,7 +95,7 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path, char attr_path[PATH_MAX]; local_mapped_attr_path(ctx, path, attr_path); - fp = fopen(attr_path, "r"); + fp = local_fopen(attr_path, "r"); if (!fp) { return; } @@ -152,7 +179,7 @@ static int local_set_mapped_file_attr(FsContext *ctx, char attr_path[PATH_MAX]; int uid = -1, gid = -1, mode = -1, rdev = -1; - fp = fopen(local_mapped_attr_path(ctx, path, attr_path), "r"); + fp = local_fopen(local_mapped_attr_path(ctx, path, attr_path), "r"); if (!fp) { goto create_map_file; } @@ -179,7 +206,7 @@ create_map_file: } update_map_file: - fp = fopen(attr_path, "w"); + fp = local_fopen(attr_path, "w"); if (!fp) { ret = -1; goto err_out; @@ -284,7 +311,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, if ((fs_ctx->export_flags & V9FS_SM_MAPPED) || (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) { int fd; - fd = open(rpath(fs_ctx, path, buffer), O_RDONLY); + fd = open(rpath(fs_ctx, path, buffer), O_RDONLY | O_NOFOLLOW); if (fd == -1) { return -1; } @@ -316,7 +343,7 @@ static int local_open(FsContext *ctx, V9fsPath *fs_path, char buffer[PATH_MAX]; char *path = fs_path->data; - fs->fd = open(rpath(ctx, path, buffer), flags); + fs->fd = open(rpath(ctx, path, buffer), flags | O_NOFOLLOW); return fs->fd; } @@ -601,6 +628,11 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, V9fsString fullname; char buffer[PATH_MAX]; + /* + * Mark all the open to not follow symlinks + */ + flags |= O_NOFOLLOW; + v9fs_string_init(&fullname); v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); path = fullname.data; @@ -676,8 +708,9 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, if (fs_ctx->export_flags & V9FS_SM_MAPPED) { int fd; ssize_t oldpath_size, write_size; - fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, - SM_LOCAL_MODE_BITS); + fd = open(rpath(fs_ctx, newpath, buffer), + O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, + SM_LOCAL_MODE_BITS); if (fd == -1) { err = fd; goto out; @@ -705,7 +738,8 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { int fd; ssize_t oldpath_size, write_size; - fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, + fd = open(rpath(fs_ctx, newpath, buffer), + O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); if (fd == -1) { err = fd; diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 296f66f293..8cbb8ae32a 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -658,7 +658,7 @@ static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension) ret |= S_IFIFO; } if (mode & P9_STAT_MODE_DEVICE) { - if (extension && extension->data[0] == 'c') { + if (extension->size && extension->data[0] == 'c') { ret |= S_IFCHR; } else { ret |= S_IFBLK; diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index c4af1ccbb0..e6525ac3ba 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -447,7 +447,7 @@ static int piix4_pm_initfn(PCIDevice *dev) i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, qemu_irq sci_irq, qemu_irq smi_irq, - int kvm_enabled, void *fw_cfg) + int kvm_enabled, FWCfgState *fw_cfg) { PCIDevice *dev; PIIX4PMState *s; diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index c8101d3e84..8186f1486b 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -79,6 +79,28 @@ static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; +static uint64_t exynos4210_chipid_and_omr_read(void *opaque, hwaddr offset, + unsigned size) +{ + assert(offset < sizeof(chipid_and_omr)); + return chipid_and_omr[offset]; +} + +static void exynos4210_chipid_and_omr_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + return; +} + +static const MemoryRegionOps exynos4210_chipid_and_omr_ops = { + .read = exynos4210_chipid_and_omr_read, + .write = exynos4210_chipid_and_omr_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .max_access_size = 1, + } +}; + void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { @@ -219,15 +241,15 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, /*** Memory ***/ /* Chip-ID and OMR */ - memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid", - sizeof(chipid_and_omr), chipid_and_omr); - memory_region_set_readonly(&s->chipid_mem, true); + memory_region_init_io(&s->chipid_mem, &exynos4210_chipid_and_omr_ops, + NULL, "exynos4210.chipid", sizeof(chipid_and_omr)); memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR, &s->chipid_mem); /* Internal ROM */ memory_region_init_ram(&s->irom_mem, "exynos4210.irom", EXYNOS4210_IROM_SIZE); + vmstate_register_ram_global(&s->irom_mem); memory_region_set_readonly(&s->irom_mem, true); memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR, &s->irom_mem); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 41505c32ba..4602a6f579 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -66,7 +66,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1; int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES; - dev = qdev_create(NULL, "xilinx,spips"); + dev = qdev_create(NULL, is_qspi ? "xlnx.ps7-qspi" : "xlnx.ps7-spi"); qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1); qdev_prop_set_uint8(dev, "num-ss-bits", num_ss); qdev_prop_set_uint8(dev, "num-busses", num_busses); diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 759c84d140..a927a6bc21 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -123,6 +123,7 @@ static const FlashPartInfo known_devices[] = { { INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) }, /* Micron */ + { INFO("n25q032a", 0x20bb16, 0, 64 << 10, 64, ER_4K) }, { INFO("n25q128a11", 0x20bb18, 0, 64 << 10, 256, 0) }, { INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, 0) }, { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) }, diff --git a/hw/block/pc_sysfw.c b/hw/block/pc_sysfw.c index 4f17668503..412d1b0f77 100644 --- a/hw/block/pc_sysfw.c +++ b/hw/block/pc_sysfw.c @@ -39,6 +39,7 @@ typedef struct PcSysFwDevice { SysBusDevice busdev; uint8_t rom_only; + uint8_t isapc_ram_fw; } PcSysFwDevice; static void pc_isa_bios_init(MemoryRegion *rom_memory, @@ -139,7 +140,7 @@ static void pc_system_flash_init(MemoryRegion *rom_memory, pc_isa_bios_init(rom_memory, flash_mem, size); } -static void old_pc_system_rom_init(MemoryRegion *rom_memory) +static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) { char *filename; MemoryRegion *bios, *isa_bios; @@ -163,7 +164,9 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory) bios = g_malloc(sizeof(*bios)); memory_region_init_ram(bios, "pc.bios", bios_size); vmstate_register_ram_global(bios); - memory_region_set_readonly(bios, true); + if (!isapc_ram_fw) { + memory_region_set_readonly(bios, true); + } ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); if (ret != 0) { bios_error: @@ -186,7 +189,9 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory) 0x100000 - isa_bios_size, isa_bios, 1); - memory_region_set_readonly(isa_bios, true); + if (!isapc_ram_fw) { + memory_region_set_readonly(isa_bios, true); + } /* map all the bios at the top of memory */ memory_region_add_subregion(rom_memory, @@ -215,28 +220,40 @@ void pc_system_firmware_init(MemoryRegion *rom_memory) qdev_init_nofail(DEVICE(sysfw_dev)); - if (sysfw_dev->rom_only) { - old_pc_system_rom_init(rom_memory); - return; - } - pflash_drv = drive_get(IF_PFLASH, 0, 0); - /* Currently KVM cannot execute from device memory. - Use old rom based firmware initialization for KVM. */ - /* - * This is a Bad Idea, because it makes enabling/disabling KVM - * guest-visible. Let's fix it for real in QEMU 1.6. - */ - if (kvm_enabled()) { - if (pflash_drv != NULL) { - fprintf(stderr, "qemu: pflash cannot be used with kvm enabled\n"); - exit(1); - } else { - sysfw_dev->rom_only = 1; - old_pc_system_rom_init(rom_memory); - return; + if (pc_sysfw_flash_vs_rom_bug_compatible) { + /* + * This is a Bad Idea, because it makes enabling/disabling KVM + * guest-visible. Do it only in bug-compatibility mode. + */ + if (kvm_enabled()) { + if (pflash_drv != NULL) { + fprintf(stderr, "qemu: pflash cannot be used with kvm enabled\n"); + exit(1); + } else { + /* In old pc_sysfw_flash_vs_rom_bug_compatible mode, we assume + * that KVM cannot execute from device memory. In this case, we + * use old rom based firmware initialization for KVM. But, since + * this is different from non-kvm mode, this behavior is + * undesirable */ + sysfw_dev->rom_only = 1; + } } + } else if (pflash_drv == NULL) { + /* When a pflash drive is not found, use rom-mode */ + sysfw_dev->rom_only = 1; + } else if (kvm_enabled() && !kvm_readonly_mem_enabled()) { + /* Older KVM cannot execute from device memory. So, flash memory + * cannot be used unless the readonly memory kvm capability is present. */ + fprintf(stderr, "qemu: pflash with kvm requires KVM readonly memory support\n"); + exit(1); + } + + /* If rom-mode is active, use the old pc system rom initialization. */ + if (sysfw_dev->rom_only) { + old_pc_system_rom_init(rom_memory, sysfw_dev->isapc_ram_fw); + return; } /* If a pflash drive is not found, then create one using @@ -255,6 +272,7 @@ void pc_system_firmware_init(MemoryRegion *rom_memory) } static Property pcsysfw_properties[] = { + DEFINE_PROP_UINT8("isapc_ram_fw", PcSysFwDevice, isapc_ram_fw, 0), DEFINE_PROP_UINT8("rom_only", PcSysFwDevice, rom_only, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 0ac65d4e8f..247f32f4ee 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -780,11 +780,13 @@ static int blk_connect(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); int pers, index, qflags; + bool readonly = true; /* read-only ? */ qflags = BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO; if (strcmp(blkdev->mode, "w") == 0) { qflags |= BDRV_O_RDWR; + readonly = false; } /* init qemu block driver */ @@ -795,8 +797,10 @@ static int blk_connect(struct XenDevice *xendev) xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); blkdev->bs = bdrv_new(blkdev->dev); if (blkdev->bs) { - if (bdrv_open(blkdev->bs, blkdev->filename, NULL, qflags, - bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) { + BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto, + readonly); + if (bdrv_open(blkdev->bs, + blkdev->filename, NULL, qflags, drv) != 0) { bdrv_delete(blkdev->bs); blkdev->bs = NULL; } diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c index 02c9577024..3b0637d44f 100644 --- a/hw/char/debugcon.c +++ b/hw/char/debugcon.c @@ -55,7 +55,7 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, unsigned char ch = val; #ifdef DEBUG_DEBUGCON - printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val); + printf(" [debugcon: write addr=0x%04" HWADDR_PRIx " val=0x%02" PRIx64 "]\n", addr, val); #endif qemu_chr_fe_write(s->chr, &ch, 1); @@ -67,7 +67,7 @@ static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width) DebugconState *s = opaque; #ifdef DEBUG_DEBUGCON - printf("debugcon: read addr=0x%04x\n", addr); + printf("debugcon: read addr=0x%04" HWADDR_PRIx "\n", addr); #endif return s->readback; diff --git a/hw/core/loader.c b/hw/core/loader.c index 7507914297..a711145178 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -733,7 +733,7 @@ int rom_load_all(void) return 0; } -void rom_set_fw(void *f) +void rom_set_fw(FWCfgState *f) { fw_cfg = f; } diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 6985ad870c..9190a7ee76 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -515,7 +515,7 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size) l += snprintf(p + l, size - l, "%s", d); g_free(d); } else { - l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev))); + return l; } } l += snprintf(p + l , size - l, "/"); @@ -867,9 +867,17 @@ static void qbus_initfn(Object *obj) QTAILQ_INIT(&bus->children); } +static char *default_bus_get_fw_dev_path(DeviceState *dev) +{ + return g_strdup(object_get_typename(OBJECT(dev))); +} + static void bus_class_init(ObjectClass *class, void *data) { + BusClass *bc = BUS_CLASS(class); + class->unparent = bus_unparent; + bc->get_fw_dev_path = default_bus_get_fw_dev_path; } static void qbus_finalize(Object *obj) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 64bfe2be4a..a5dbc39c21 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2600,7 +2600,6 @@ static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val, #endif cirrus_vga_write_sr(c, val); break; - break; case 0x3c6: cirrus_write_hidden_dac(c, val); break; diff --git a/hw/display/tcx.c b/hw/display/tcx.c index fc27f45e4e..995641c745 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -193,15 +193,16 @@ static inline void reset_dirty(TCXState *ts, ram_addr_t page_min, ram_addr_t cpage) { memory_region_reset_dirty(&ts->vram_mem, - page_min, page_max + TARGET_PAGE_SIZE, + page_min, + (page_max - page_min) + TARGET_PAGE_SIZE, DIRTY_MEMORY_VGA); memory_region_reset_dirty(&ts->vram_mem, page24 + page_min * 4, - page24 + page_max * 4 + TARGET_PAGE_SIZE, + (page_max - page_min) * 4 + TARGET_PAGE_SIZE, DIRTY_MEMORY_VGA); memory_region_reset_dirty(&ts->vram_mem, cpage + page_min * 4, - cpage + page_max * 4 + TARGET_PAGE_SIZE, + (page_max - page_min) * 4 + TARGET_PAGE_SIZE, DIRTY_MEMORY_VGA); } @@ -285,7 +286,8 @@ static void tcx_update_display(void *opaque) /* reset modified pages */ if (page_max >= page_min) { memory_region_reset_dirty(&ts->vram_mem, - page_min, page_max + TARGET_PAGE_SIZE, + page_min, + (page_max - page_min) + TARGET_PAGE_SIZE, DIRTY_MEMORY_VGA); } } diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index d696507940..09211e0534 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -124,7 +124,7 @@ static void mb_add_mod(MultibootState *s, s->mb_mods_count++; } -int load_multiboot(void *fw_cfg, +int load_multiboot(FWCfgState *fw_cfg, FILE *f, const char *kernel_filename, const char *initrd_filename, diff --git a/hw/i386/multiboot.h b/hw/i386/multiboot.h index 98fb1b776c..60de309cd1 100644 --- a/hw/i386/multiboot.h +++ b/hw/i386/multiboot.h @@ -1,7 +1,9 @@ #ifndef QEMU_MULTIBOOT_H #define QEMU_MULTIBOOT_H -int load_multiboot(void *fw_cfg, +#include "hw/nvram/fw_cfg.h" + +int load_multiboot(FWCfgState *fw_cfg, FILE *f, const char *kernel_filename, const char *initrd_filename, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 197d218715..4844a6b370 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -595,9 +595,9 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus) return x86_cpu_apic_id_from_index(max_cpus - 1) + 1; } -static void *bochs_bios_init(void) +static FWCfgState *bochs_bios_init(void) { - void *fw_cfg; + FWCfgState *fw_cfg; uint8_t *smbios_table; size_t smbios_len; uint64_t *numa_fw_cfg; @@ -674,7 +674,7 @@ static long get_file_size(FILE *f) return size; } -static void load_linux(void *fw_cfg, +static void load_linux(FWCfgState *fw_cfg, const char *kernel_filename, const char *initrd_filename, const char *kernel_cmdline, @@ -1012,19 +1012,19 @@ void pc_acpi_init(const char *default_dsdt) } } -void *pc_memory_init(MemoryRegion *system_memory, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, - MemoryRegion *rom_memory, - MemoryRegion **ram_memory) +FWCfgState *pc_memory_init(MemoryRegion *system_memory, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + ram_addr_t below_4g_mem_size, + ram_addr_t above_4g_mem_size, + MemoryRegion *rom_memory, + MemoryRegion **ram_memory) { int linux_boot, i; MemoryRegion *ram, *option_rom_mr; MemoryRegion *ram_below_4g, *ram_above_4g; - void *fw_cfg; + FWCfgState *fw_cfg; linux_boot = (kernel_filename != NULL); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2653502c08..d6185705a6 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -89,7 +89,7 @@ static void pc_init1(MemoryRegion *system_memory, MemoryRegion *pci_memory; MemoryRegion *rom_memory; DeviceState *icc_bridge; - void *fw_cfg = NULL; + FWCfgState *fw_cfg = NULL; icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE); object_property_add_child(qdev_get_machine(), "icc-bridge", @@ -712,6 +712,11 @@ static QEMUMachine isapc_machine = { .property = "rom_only", .value = stringify(1), }, + { + .driver = "pc-sysfw", + .property = "isapc_ram_fw", + .value = stringify(1), + }, { /* end of list */ } }, DEFAULT_MACHINE_OPTIONS, diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 756dff008d..46cb0975d9 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -40,18 +40,18 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, uint8_t dest, uint8_t dest_mode); /* Find first bit starting from msb */ -static int fls_bit(uint32_t value) +static int apic_fls_bit(uint32_t value) { return 31 - clz32(value); } /* Find first bit starting from lsb */ -static int ffs_bit(uint32_t value) +static int apic_ffs_bit(uint32_t value) { return ctz32(value); } -static inline void set_bit(uint32_t *tab, int index) +static inline void apic_set_bit(uint32_t *tab, int index) { int i, mask; i = index >> 5; @@ -59,7 +59,7 @@ static inline void set_bit(uint32_t *tab, int index) tab[i] |= mask; } -static inline void reset_bit(uint32_t *tab, int index) +static inline void apic_reset_bit(uint32_t *tab, int index) { int i, mask; i = index >> 5; @@ -67,7 +67,7 @@ static inline void reset_bit(uint32_t *tab, int index) tab[i] &= ~mask; } -static inline int get_bit(uint32_t *tab, int index) +static inline int apic_get_bit(uint32_t *tab, int index) { int i, mask; i = index >> 5; @@ -81,7 +81,7 @@ static int get_highest_priority_int(uint32_t *tab) int i; for (i = 7; i >= 0; i--) { if (tab[i] != 0) { - return i * 32 + fls_bit(tab[i]); + return i * 32 + apic_fls_bit(tab[i]); } } return -1; @@ -184,7 +184,7 @@ void apic_deliver_pic_intr(DeviceState *d, int level) case APIC_DM_FIXED: if (!(lvt & APIC_LVT_LEVEL_TRIGGER)) break; - reset_bit(s->irr, lvt & 0xff); + apic_reset_bit(s->irr, lvt & 0xff); /* fall through */ case APIC_DM_EXTINT: cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD); @@ -230,7 +230,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, d = -1; for(i = 0; i < MAX_APIC_WORDS; i++) { if (deliver_bitmask[i]) { - d = i * 32 + ffs_bit(deliver_bitmask[i]); + d = i * 32 + apic_ffs_bit(deliver_bitmask[i]); break; } } @@ -386,13 +386,13 @@ void apic_poll_irq(DeviceState *d) static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode) { - apic_report_irq_delivered(!get_bit(s->irr, vector_num)); + apic_report_irq_delivered(!apic_get_bit(s->irr, vector_num)); - set_bit(s->irr, vector_num); + apic_set_bit(s->irr, vector_num); if (trigger_mode) - set_bit(s->tmr, vector_num); + apic_set_bit(s->tmr, vector_num); else - reset_bit(s->tmr, vector_num); + apic_reset_bit(s->tmr, vector_num); if (s->vapic_paddr) { apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC); /* @@ -412,8 +412,8 @@ static void apic_eoi(APICCommonState *s) isrv = get_highest_priority_int(s->isr); if (isrv < 0) return; - reset_bit(s->isr, isrv); - if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) { + apic_reset_bit(s->isr, isrv); + if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && apic_get_bit(s->tmr, isrv)) { ioapic_eoi_broadcast(isrv); } apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC); @@ -452,7 +452,7 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, int idx = apic_find_dest(dest); memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); if (idx >= 0) - set_bit(deliver_bitmask, idx); + apic_set_bit(deliver_bitmask, idx); } } else { /* XXX: cluster mode */ @@ -462,11 +462,11 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, if (apic_iter) { if (apic_iter->dest_mode == 0xf) { if (dest & apic_iter->log_dest) - set_bit(deliver_bitmask, i); + apic_set_bit(deliver_bitmask, i); } else if (apic_iter->dest_mode == 0x0) { if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) && (dest & apic_iter->log_dest & 0x0f)) { - set_bit(deliver_bitmask, i); + apic_set_bit(deliver_bitmask, i); } } } else { @@ -509,14 +509,14 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode, break; case 1: memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); - set_bit(deliver_bitmask, s->idx); + apic_set_bit(deliver_bitmask, s->idx); break; case 2: memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); break; case 3: memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); - reset_bit(deliver_bitmask, s->idx); + apic_reset_bit(deliver_bitmask, s->idx); break; } @@ -573,8 +573,8 @@ int apic_get_interrupt(DeviceState *d) apic_sync_vapic(s, SYNC_TO_VAPIC); return s->spurious_vec & 0xff; } - reset_bit(s->irr, intno); - set_bit(s->isr, intno); + apic_reset_bit(s->irr, intno); + apic_set_bit(s->isr, intno); apic_sync_vapic(s, SYNC_TO_VAPIC); /* re-inject if there is still a pending PIC interrupt */ diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c index 31e1b1d8e3..910e44f9d2 100644 --- a/hw/misc/pvpanic.c +++ b/hw/misc/pvpanic.c @@ -90,13 +90,13 @@ static int pvpanic_isa_initfn(ISADevice *dev) { PVPanicState *s = ISA_PVPANIC_DEVICE(dev); static bool port_configured; - void *fw_cfg; + FWCfgState *fw_cfg; memory_region_init_io(&s->io, &pvpanic_ops, s, "pvpanic", 1); isa_register_ioport(dev, &s->io, s->ioport); if (!port_configured) { - fw_cfg = object_resolve_path("/machine/fw_cfg", NULL); + fw_cfg = fw_cfg_find(); if (fw_cfg) { fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", g_memdup(&s->ioport, sizeof(s->ioport)), diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 479113bd81..3c255cec01 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -32,6 +32,9 @@ #define FW_CFG_SIZE 2 #define FW_CFG_DATA_SIZE 1 +#define TYPE_FW_CFG "fw_cfg" +#define FW_CFG_NAME "fw_cfg" +#define FW_CFG_PATH "/machine/" FW_CFG_NAME typedef struct FWCfgEntry { uint32_t len; @@ -493,10 +496,9 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, s = DO_UPCAST(FWCfgState, busdev.qdev, dev); - if (!object_resolve_path("/machine/fw_cfg", NULL)) { - object_property_add_child(qdev_get_machine(), "fw_cfg", OBJECT(s), - NULL); - } + assert(!object_resolve_path(FW_CFG_PATH, NULL)); + + object_property_add_child(qdev_get_machine(), FW_CFG_NAME, OBJECT(s), NULL); qdev_init_nofail(dev); @@ -553,6 +555,12 @@ static Property fw_cfg_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +FWCfgState *fw_cfg_find(void) +{ + return OBJECT_CHECK(FWCfgState, object_resolve_path(FW_CFG_PATH, NULL), + TYPE_FW_CFG); +} + static void fw_cfg_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -566,7 +574,7 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data) } static const TypeInfo fw_cfg_info = { - .name = "fw_cfg", + .name = TYPE_FW_CFG, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(FWCfgState), .class_init = fw_cfg_class_init, diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index 5223330838..d76a06c486 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include "hw/hw.h" -#include "hw/sparc/firmware_abi.h" +#include "hw/nvram/openbios_firmware_abi.h" #include "sysemu/sysemu.h" #include "hw/ppc/mac.h" diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs index 5dd92d28a0..968b3694ab 100644 --- a/hw/pci-bridge/Makefile.objs +++ b/hw/pci-bridge/Makefile.objs @@ -1,3 +1,5 @@ common-obj-y += pci_bridge_dev.o common-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o common-obj-y += i82801b11.o +# NewWorld PowerMac +common-obj-$(CONFIG_DEC_PCI) += dec.o diff --git a/hw/pci-host/dec.c b/hw/pci-bridge/dec.c index cff458b574..cff458b574 100644 --- a/hw/pci-host/dec.c +++ b/hw/pci-bridge/dec.c diff --git a/hw/pci-host/dec.h b/hw/pci-bridge/dec.h index 17dc0c2b0a..17dc0c2b0a 100644 --- a/hw/pci-host/dec.h +++ b/hw/pci-bridge/dec.h diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs index 909e702eef..bb65f9c4d2 100644 --- a/hw/pci-host/Makefile.objs +++ b/hw/pci-host/Makefile.objs @@ -5,7 +5,6 @@ common-obj-$(CONFIG_PREP_PCI) += prep.o common-obj-$(CONFIG_GRACKLE_PCI) += grackle.o # NewWorld PowerMac common-obj-$(CONFIG_UNIN_PCI) += uninorth.o -common-obj-$(CONFIG_DEC_PCI) += dec.o # PowerPC E500 boards common-obj-$(CONFIG_PPCE500_PCI) += ppce500.o diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 8467f86450..24df6b55cb 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -76,6 +76,7 @@ static void q35_host_class_init(ObjectClass *klass, void *data) k->init = q35_host_init; dc->props = mch_props; + dc->fw_name = "pci"; } static void q35_host_initfn(Object *obj) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index e231a0dc4b..6da75ec693 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -569,3 +569,36 @@ void msix_unset_vector_notifiers(PCIDevice *dev) dev->msix_vector_release_notifier = NULL; dev->msix_vector_poll_notifier = NULL; } + +static void put_msix_state(QEMUFile *f, void *pv, size_t size) +{ + msix_save(pv, f); +} + +static int get_msix_state(QEMUFile *f, void *pv, size_t size) +{ + msix_load(pv, f); + return 0; +} + +static VMStateInfo vmstate_info_msix = { + .name = "msix state", + .get = get_msix_state, + .put = put_msix_state, +}; + +const VMStateDescription vmstate_msix = { + .name = "msix", + .fields = (VMStateField[]) { + { + .name = "msix", + .version_id = 0, + .field_exists = NULL, + .size = 0, /* ouch */ + .info = &vmstate_info_msix, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_END_OF_LIST() + } +}; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 2e0ef3e5aa..346d86f69c 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -43,6 +43,8 @@ do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif +#define ACMD41_ENQUIRY_MASK 0x00ffffff + typedef enum { sd_r0 = 0, /* no response */ sd_r1, /* normal response command */ @@ -1277,9 +1279,14 @@ static sd_rsp_type_t sd_app_command(SDState *sd, } switch (sd->state) { case sd_idle_state: - /* We accept any voltage. 10000 V is nothing. */ - if (req.arg) + /* We accept any voltage. 10000 V is nothing. + * + * We don't model init delay so just advance straight to ready state + * unless it's an enquiry ACMD41 (bits 23:0 == 0). + */ + if (req.arg & ACMD41_ENQUIRY_MASK) { sd->state = sd_ready_state; + } return sd_r3; diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 91dc9b082d..e64899cafb 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -260,6 +260,7 @@ static void sdhci_send_command(SDHCIState *s) sdhci_update_irq(s); if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { + s->data_count = 0; sdhci_do_data_transfer(s); } } @@ -404,15 +405,14 @@ static void sdhci_write_block_to_card(SDHCIState *s) /* Next data can be written through BUFFER DATORT register */ s->prnsts |= SDHC_SPACE_AVAILABLE; - if (s->norintstsen & SDHC_NISEN_WBUFRDY) { - s->norintsts |= SDHC_NIS_WBUFRDY; - } /* Finish transfer if that was the last block of data */ if ((s->trnmod & SDHC_TRNS_MULTI) == 0 || ((s->trnmod & SDHC_TRNS_MULTI) && (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0))) { SDHCI_GET_CLASS(s)->end_data_transfer(s); + } else if (s->norintstsen & SDHC_NISEN_WBUFRDY) { + s->norintsts |= SDHC_NIS_WBUFRDY; } /* Generate Block Gap Event if requested and if not the last block */ @@ -730,6 +730,15 @@ static void sdhci_do_adma(SDHCIState *s) break; } + if (dscr.attr & SDHC_ADMA_ATTR_INT) { + DPRINT_L1("ADMA interrupt: admasysaddr=0x%lx\n", s->admasysaddr); + if (s->norintstsen & SDHC_NISEN_DMA) { + s->norintsts |= SDHC_NIS_DMA; + } + + sdhci_update_irq(s); + } + /* ADMA transfer terminates if blkcnt == 0 or by END attribute */ if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) { @@ -752,15 +761,6 @@ static void sdhci_do_adma(SDHCIState *s) return; } - if (dscr.attr & SDHC_ADMA_ATTR_INT) { - DPRINT_L1("ADMA interrupt: admasysaddr=0x%lx\n", s->admasysaddr); - if (s->norintstsen & SDHC_NISEN_DMA) { - s->norintsts |= SDHC_NIS_DMA; - } - - sdhci_update_irq(s); - return; - } } /* we have unfinished business - reschedule to continue ADMA */ @@ -773,7 +773,6 @@ static void sdhci_do_adma(SDHCIState *s) static void sdhci_data_transfer(SDHCIState *s) { SDHCIClass *k = SDHCI_GET_CLASS(s); - s->data_count = 0; if (s->trnmod & SDHC_TRNS_DMA) { switch (SDHC_DMA_TYPE(s->hostctl)) { @@ -881,7 +880,8 @@ static uint32_t sdhci_read(SDHCIState *s, unsigned int offset, unsigned size) case SDHC_BDATA: if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) { ret = SDHCI_GET_CLASS(s)->bdata_read(s, size); - DPRINT_L2("read %ub: addr[0x%04x] -> %u\n", size, offset, ret); + DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, offset, + ret, ret); return ret; } break; diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 884088150b..0e86ca765d 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -30,7 +30,7 @@ #include "sysemu/sysemu.h" #include "net/net.h" #include "hw/boards.h" -#include "hw/sparc/firmware_abi.h" +#include "hw/nvram/openbios_firmware_abi.h" #include "hw/scsi/esp.h" #include "hw/i386/pc.h" #include "hw/isa/isa.h" @@ -831,7 +831,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, qemu_irq *cpu_halt; unsigned long kernel_size; DriveInfo *fd[MAX_FD]; - void *fw_cfg; + FWCfgState *fw_cfg; unsigned int num_vsimms; /* init CPUs */ diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 5c2bbd44f5..2c2a111711 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -32,7 +32,7 @@ #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "hw/boards.h" -#include "hw/sparc/firmware_abi.h" +#include "hw/nvram/openbios_firmware_abi.h" #include "hw/nvram/fw_cfg.h" #include "hw/sysbus.h" #include "hw/ide.h" @@ -818,7 +818,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, qemu_irq *ivec_irqs, *pbm_irqs; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *fd[MAX_FD]; - void *fw_cfg; + FWCfgState *fw_cfg; /* init CPUs */ cpu = cpu_devinit(cpu_model, hwdef); diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index b2397f4a42..05a3adaa90 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -30,15 +30,17 @@ #include "hw/ssi.h" #include "qemu/bitops.h" -#ifdef XILINX_SPIPS_ERR_DEBUG -#define DB_PRINT(...) do { \ - fprintf(stderr, ": %s: ", __func__); \ - fprintf(stderr, ## __VA_ARGS__); \ - } while (0); -#else - #define DB_PRINT(...) +#ifndef XILINX_SPIPS_ERR_DEBUG +#define XILINX_SPIPS_ERR_DEBUG 0 #endif +#define DB_PRINT_L(level, ...) do { \ + if (XILINX_SPIPS_ERR_DEBUG > (level)) { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } \ +} while (0); + /* config register */ #define R_CONFIG (0x00 / 4) #define IFMODE (1 << 31) @@ -56,6 +58,7 @@ #define CLK_PH (1 << 2) #define CLK_POL (1 << 1) #define MODE_SEL (1 << 0) +#define R_CONFIG_RSVD (0x7bf40000) /* interrupt mechanism */ #define R_INTR_STATUS (0x04 / 4) @@ -106,6 +109,9 @@ #define RXFF_A 32 #define TXFF_A 32 +#define RXFF_A_Q (64 * 4) +#define TXFF_A_Q (64 * 4) + /* 16MB per linear region */ #define LQSPI_ADDRESS_BITS 24 /* Bite off 4k chunks at a time */ @@ -129,7 +135,8 @@ typedef enum { } FlashCMD; typedef struct { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; MemoryRegion mmlqspi; @@ -149,15 +156,36 @@ typedef struct { uint8_t num_txrx_bytes; uint32_t regs[R_MAX]; +} XilinxSPIPS; + +typedef struct { + XilinxSPIPS parent_obj; - uint32_t lqspi_buf[LQSPI_CACHE_SIZE]; + uint8_t lqspi_buf[LQSPI_CACHE_SIZE]; hwaddr lqspi_cached_addr; -} XilinxSPIPS; +} XilinxQSPIPS; + +typedef struct XilinxSPIPSClass { + SysBusDeviceClass parent_class; + + const MemoryRegionOps *reg_ops; + + uint32_t rx_fifo_size; + uint32_t tx_fifo_size; +} XilinxSPIPSClass; -#define TYPE_XILINX_SPIPS "xilinx,spips" +#define TYPE_XILINX_SPIPS "xlnx.ps7-spi" +#define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi" #define XILINX_SPIPS(obj) \ OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS) +#define XILINX_SPIPS_CLASS(klass) \ + OBJECT_CLASS_CHECK(XilinxSPIPSClass, (klass), TYPE_XILINX_SPIPS) +#define XILINX_SPIPS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XilinxSPIPSClass, (obj), TYPE_XILINX_SPIPS) + +#define XILINX_QSPIPS(obj) \ + OBJECT_CHECK(XilinxQSPIPS, (obj), TYPE_XILINX_QSPIPS) static inline int num_effective_busses(XilinxSPIPS *s) { @@ -165,6 +193,12 @@ static inline int num_effective_busses(XilinxSPIPS *s) s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1; } +static inline bool xilinx_spips_cs_is_set(XilinxSPIPS *s, int i, int field) +{ + return ~field & (1 << i) && (s->regs[R_CONFIG] & MANUAL_CS + || !fifo8_is_empty(&s->tx_fifo)); +} + static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) { int i, j; @@ -177,24 +211,29 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) int cs_to_set = (j * s->num_cs + i + upage) % (s->num_cs * s->num_busses); - if (~field & (1 << i) && !found) { - DB_PRINT("selecting slave %d\n", i); + if (xilinx_spips_cs_is_set(s, i, field) && !found) { + DB_PRINT_L(0, "selecting slave %d\n", i); qemu_set_irq(s->cs_lines[cs_to_set], 0); } else { + DB_PRINT_L(0, "deselecting slave %d\n", i); qemu_set_irq(s->cs_lines[cs_to_set], 1); } } - if (~field & (1 << i)) { + if (xilinx_spips_cs_is_set(s, i, field)) { found = true; } } if (!found) { s->snoop_state = SNOOP_CHECKING; + DB_PRINT_L(1, "moving to snoop check state\n"); } } static void xilinx_spips_update_ixr(XilinxSPIPS *s) { + if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE) { + return; + } /* These are set/cleared as they occur */ s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW | IXR_TX_FIFO_MODE_FAIL); @@ -237,35 +276,83 @@ static void xilinx_spips_reset(DeviceState *d) xilinx_spips_update_cs_lines(s); } +/* N way (num) in place bit striper. Lay out row wise bits (LSB to MSB) + * column wise (from element 0 to N-1). num is the length of x, and dir + * reverses the direction of the transform. Best illustrated by example: + * Each digit in the below array is a single bit (num == 3): + * + * {{ 76543210, } ----- stripe (dir == false) -----> {{ FCheb630, } + * { hgfedcba, } { GDAfc741, } + * { HGFEDCBA, }} <---- upstripe (dir == true) ----- { HEBgda52, }} + */ + +static inline void stripe8(uint8_t *x, int num, bool dir) +{ + uint8_t r[num]; + memset(r, 0, sizeof(uint8_t) * num); + int idx[2] = {0, 0}; + int bit[2] = {0, 0}; + int d = dir; + + for (idx[0] = 0; idx[0] < num; ++idx[0]) { + for (bit[0] = 0; bit[0] < 8; ++bit[0]) { + r[idx[d]] |= x[idx[!d]] & 1 << bit[!d] ? 1 << bit[d] : 0; + idx[1] = (idx[1] + 1) % num; + if (!idx[1]) { + bit[1]++; + } + } + } + memcpy(x, r, sizeof(uint8_t) * num); +} + static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) { + int debug_level = 0; + for (;;) { int i; - uint8_t rx; uint8_t tx = 0; + uint8_t tx_rx[num_effective_busses(s)]; - for (i = 0; i < num_effective_busses(s); ++i) { - if (!i || s->snoop_state == SNOOP_STRIPING) { - if (fifo8_is_empty(&s->tx_fifo)) { - s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW; - xilinx_spips_update_ixr(s); - return; - } else { - tx = fifo8_pop(&s->tx_fifo); - } + if (fifo8_is_empty(&s->tx_fifo)) { + if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) { + s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW; + } + xilinx_spips_update_ixr(s); + return; + } else if (s->snoop_state == SNOOP_STRIPING) { + for (i = 0; i < num_effective_busses(s); ++i) { + tx_rx[i] = fifo8_pop(&s->tx_fifo); } - rx = ssi_transfer(s->spi[i], (uint32_t)tx); - DB_PRINT("tx = %02x rx = %02x\n", tx, rx); - if (!i || s->snoop_state == SNOOP_STRIPING) { - if (fifo8_is_full(&s->rx_fifo)) { - s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW; - DB_PRINT("rx FIFO overflow"); - } else { - fifo8_push(&s->rx_fifo, (uint8_t)rx); - } + stripe8(tx_rx, num_effective_busses(s), false); + } else { + tx = fifo8_pop(&s->tx_fifo); + for (i = 0; i < num_effective_busses(s); ++i) { + tx_rx[i] = tx; + } + } + + for (i = 0; i < num_effective_busses(s); ++i) { + DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]); + tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]); + DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]); + } + + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW; + DB_PRINT_L(0, "rx FIFO overflow"); + } else if (s->snoop_state == SNOOP_STRIPING) { + stripe8(tx_rx, num_effective_busses(s), true); + for (i = 0; i < num_effective_busses(s); ++i) { + fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]); } + } else { + fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]); } + DB_PRINT_L(debug_level, "initial snoop state: %x\n", + (unsigned)s->snoop_state); switch (s->snoop_state) { case (SNOOP_CHECKING): switch (tx) { /* new instruction code */ @@ -290,21 +377,26 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) break; case (SNOOP_STRIPING): case (SNOOP_NONE): + /* Once we hit the boring stuff - squelch debug noise */ + if (!debug_level) { + DB_PRINT_L(0, "squelching debug info ....\n"); + debug_level = 1; + } break; default: s->snoop_state--; } + DB_PRINT_L(debug_level, "final snoop state: %x\n", + (unsigned)s->snoop_state); } } -static inline void rx_data_bytes(XilinxSPIPS *s, uint32_t *value, int max) +static inline void rx_data_bytes(XilinxSPIPS *s, uint8_t *value, int max) { int i; - *value = 0; for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) { - uint32_t next = fifo8_pop(&s->rx_fifo) & 0xFF; - *value |= next << 8 * (s->regs[R_CONFIG] & ENDIAN ? 3-i : i); + value[i] = fifo8_pop(&s->rx_fifo); } } @@ -314,13 +406,18 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, XilinxSPIPS *s = opaque; uint32_t mask = ~0; uint32_t ret; + uint8_t rx_buf[4]; addr >>= 2; switch (addr) { case R_CONFIG: - mask = 0x0002FFFF; + mask = ~(R_CONFIG_RSVD | MAN_START_COM); break; case R_INTR_STATUS: + ret = s->regs[addr] & IXR_ALL; + s->regs[addr] = 0; + DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + return ret; case R_INTR_MASK: mask = IXR_ALL; break; @@ -339,12 +436,16 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, mask = 0; break; case R_RX_DATA: - rx_data_bytes(s, &ret, s->num_txrx_bytes); - DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + memset(rx_buf, 0, sizeof(rx_buf)); + rx_data_bytes(s, rx_buf, s->num_txrx_bytes); + ret = s->regs[R_CONFIG] & ENDIAN ? cpu_to_be32(*(uint32_t *)rx_buf) + : cpu_to_le32(*(uint32_t *)rx_buf); + DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); xilinx_spips_update_ixr(s); return ret; } - DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask); + DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, + s->regs[addr] & mask); return s->regs[addr] & mask; } @@ -370,11 +471,11 @@ static void xilinx_spips_write(void *opaque, hwaddr addr, int man_start_com = 0; XilinxSPIPS *s = opaque; - DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value); + DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value); addr >>= 2; switch (addr) { case R_CONFIG: - mask = 0x0002FFFF; + mask = ~(R_CONFIG_RSVD | MAN_START_COM); if (value & MAN_START_COM) { man_start_com = 1; } @@ -417,11 +518,13 @@ static void xilinx_spips_write(void *opaque, hwaddr addr, } s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask); no_reg_update: - if (man_start_com) { + xilinx_spips_update_cs_lines(s); + if ((man_start_com && s->regs[R_CONFIG] & MAN_START_EN) || + (fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG] & MAN_START_EN)) { xilinx_spips_flush_txfifo(s); } - xilinx_spips_update_ixr(s); xilinx_spips_update_cs_lines(s); + xilinx_spips_update_ixr(s); } static const MemoryRegionOps spips_ops = { @@ -430,37 +533,63 @@ static const MemoryRegionOps spips_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static void xilinx_qspips_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + XilinxQSPIPS *q = XILINX_QSPIPS(opaque); + + xilinx_spips_write(opaque, addr, value, size); + addr >>= 2; + + if (addr == R_LQSPI_CFG) { + q->lqspi_cached_addr = ~0ULL; + } +} + +static const MemoryRegionOps qspips_ops = { + .read = xilinx_spips_read, + .write = xilinx_qspips_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + #define LQSPI_CACHE_SIZE 1024 static uint64_t lqspi_read(void *opaque, hwaddr addr, unsigned int size) { int i; + XilinxQSPIPS *q = opaque; XilinxSPIPS *s = opaque; + uint32_t ret; - if (addr >= s->lqspi_cached_addr && - addr <= s->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) { - return s->lqspi_buf[(addr - s->lqspi_cached_addr) >> 2]; + if (addr >= q->lqspi_cached_addr && + addr <= q->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) { + uint8_t *retp = &q->lqspi_buf[addr - q->lqspi_cached_addr]; + ret = cpu_to_le32(*(uint32_t *)retp); + DB_PRINT_L(1, "addr: %08x, data: %08x\n", (unsigned)addr, + (unsigned)ret); + return ret; } else { int flash_addr = (addr / num_effective_busses(s)); int slave = flash_addr >> LQSPI_ADDRESS_BITS; int cache_entry = 0; + uint32_t u_page_save = s->regs[R_LQSPI_STS] & ~LQSPI_CFG_U_PAGE; - DB_PRINT("config reg status: %08x\n", s->regs[R_LQSPI_CFG]); + s->regs[R_LQSPI_STS] &= ~LQSPI_CFG_U_PAGE; + s->regs[R_LQSPI_STS] |= slave ? LQSPI_CFG_U_PAGE : 0; + + DB_PRINT_L(0, "config reg status: %08x\n", s->regs[R_LQSPI_CFG]); fifo8_reset(&s->tx_fifo); fifo8_reset(&s->rx_fifo); - s->regs[R_CONFIG] &= ~CS; - s->regs[R_CONFIG] |= (~(1 << slave) << CS_SHIFT) & CS; - xilinx_spips_update_cs_lines(s); - /* instruction */ - DB_PRINT("pushing read instruction: %02x\n", - (uint8_t)(s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE)); + DB_PRINT_L(0, "pushing read instruction: %02x\n", + (unsigned)(uint8_t)(s->regs[R_LQSPI_CFG] & + LQSPI_CFG_INST_CODE)); fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE); /* read address */ - DB_PRINT("pushing read address %06x\n", flash_addr); + DB_PRINT_L(0, "pushing read address %06x\n", flash_addr); fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16)); fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8)); fifo8_push(&s->tx_fifo, (uint8_t)flash_addr); @@ -473,25 +602,30 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size) /* dummy bytes */ for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT, LQSPI_CFG_DUMMY_WIDTH)); ++i) { - DB_PRINT("pushing dummy byte\n"); + DB_PRINT_L(0, "pushing dummy byte\n"); fifo8_push(&s->tx_fifo, 0); } + xilinx_spips_update_cs_lines(s); xilinx_spips_flush_txfifo(s); fifo8_reset(&s->rx_fifo); - DB_PRINT("starting QSPI data read\n"); + DB_PRINT_L(0, "starting QSPI data read\n"); - for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) { - tx_data_bytes(s, 0, 4); + while (cache_entry < LQSPI_CACHE_SIZE) { + for (i = 0; i < 64; ++i) { + tx_data_bytes(s, 0, 1); + } xilinx_spips_flush_txfifo(s); - rx_data_bytes(s, &s->lqspi_buf[cache_entry], 4); - cache_entry++; + for (i = 0; i < 64; ++i) { + rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 1); + } } - s->regs[R_CONFIG] |= CS; + s->regs[R_LQSPI_STS] &= ~LQSPI_CFG_U_PAGE; + s->regs[R_LQSPI_STS] |= u_page_save; xilinx_spips_update_cs_lines(s); - s->lqspi_cached_addr = addr; + q->lqspi_cached_addr = flash_addr * num_effective_busses(s); return lqspi_read(opaque, addr, size); } } @@ -500,7 +634,7 @@ static const MemoryRegionOps lqspi_ops = { .read = lqspi_read, .endianness = DEVICE_NATIVE_ENDIAN, .valid = { - .min_access_size = 4, + .min_access_size = 1, .max_access_size = 4 } }; @@ -509,9 +643,10 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp) { XilinxSPIPS *s = XILINX_SPIPS(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s); int i; - DB_PRINT("inited device model\n"); + DB_PRINT_L(0, "realized spips\n"); s->spi = g_new(SSIBus *, s->num_busses); for (i = 0; i < s->num_busses; ++i) { @@ -528,18 +663,33 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp) sysbus_init_irq(sbd, &s->cs_lines[i]); } - memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4); + memory_region_init_io(&s->iomem, xsc->reg_ops, s, "spi", R_MAX*4); sysbus_init_mmio(sbd, &s->iomem); + s->irqline = -1; + + fifo8_create(&s->rx_fifo, xsc->rx_fifo_size); + fifo8_create(&s->tx_fifo, xsc->tx_fifo_size); +} + +static void xilinx_qspips_realize(DeviceState *dev, Error **errp) +{ + XilinxSPIPS *s = XILINX_SPIPS(dev); + XilinxQSPIPS *q = XILINX_QSPIPS(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + DB_PRINT_L(0, "realized qspips\n"); + + s->num_busses = 2; + s->num_cs = 2; + s->num_txrx_bytes = 4; + + xilinx_spips_realize(dev, errp); memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi", (1 << LQSPI_ADDRESS_BITS) * 2); sysbus_init_mmio(sbd, &s->mmlqspi); - s->irqline = -1; - s->lqspi_cached_addr = ~0ULL; - - fifo8_create(&s->rx_fifo, RXFF_A); - fifo8_create(&s->tx_fifo, TXFF_A); + q->lqspi_cached_addr = ~0ULL; } static int xilinx_spips_post_load(void *opaque, int version_id) @@ -570,14 +720,31 @@ static Property xilinx_spips_properties[] = { DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1), DEFINE_PROP_END_OF_LIST(), }; + +static void xilinx_qspips_class_init(ObjectClass *klass, void * data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass); + + dc->realize = xilinx_qspips_realize; + xsc->reg_ops = &qspips_ops; + xsc->rx_fifo_size = RXFF_A_Q; + xsc->tx_fifo_size = TXFF_A_Q; +} + static void xilinx_spips_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass); dc->realize = xilinx_spips_realize; dc->reset = xilinx_spips_reset; dc->props = xilinx_spips_properties; dc->vmsd = &vmstate_xilinx_spips; + + xsc->reg_ops = &spips_ops; + xsc->rx_fifo_size = RXFF_A; + xsc->tx_fifo_size = TXFF_A; } static const TypeInfo xilinx_spips_info = { @@ -585,11 +752,20 @@ static const TypeInfo xilinx_spips_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(XilinxSPIPS), .class_init = xilinx_spips_class_init, + .class_size = sizeof(XilinxSPIPSClass), +}; + +static const TypeInfo xilinx_qspips_info = { + .name = TYPE_XILINX_QSPIPS, + .parent = TYPE_XILINX_SPIPS, + .instance_size = sizeof(XilinxQSPIPS), + .class_init = xilinx_qspips_class_init, }; static void xilinx_spips_register_types(void) { type_register_static(&xilinx_spips_info); + type_register_static(&xilinx_qspips_info); } type_init(xilinx_spips_register_types) diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index e4bd17fbb7..32b5c1a9ba 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -11,7 +11,8 @@ common-obj-$(CONFIG_XILINX) += xilinx_timer.o common-obj-$(CONFIG_SLAVIO) += slavio_timer.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_timer.o common-obj-$(CONFIG_GRLIB) += grlib_gptimer.o -common-obj-$(CONFIG_IMX) += imx_timer.o +common-obj-$(CONFIG_IMX) += imx_epit.o +common-obj-$(CONFIG_IMX) += imx_gpt.o common-obj-$(CONFIG_LM32) += lm32_timer.o common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 87ce75b643..38dcc1ac64 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1030,7 +1030,6 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, case G_INT_ENB: value = s->g_timer.reg.int_enb; break; - break; case G_WSTAT: value = s->g_timer.reg.wstat; break; diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c new file mode 100644 index 0000000000..7cdb0060ab --- /dev/null +++ b/hw/timer/imx_epit.c @@ -0,0 +1,432 @@ +/* + * IMX EPIT Timer + * + * Copyright (c) 2008 OK Labs + * Copyright (c) 2011 NICTA Pty Ltd + * Originally written by Hans Jiang + * Updated by Peter Chubb + * Updated by Jean-Christophe Dubois + * + * This code is licensed under GPL version 2 or later. See + * the COPYING file in the top-level directory. + * + */ + +#include "hw/hw.h" +#include "qemu/bitops.h" +#include "qemu/timer.h" +#include "hw/ptimer.h" +#include "hw/sysbus.h" +#include "hw/arm/imx.h" + +#define TYPE_IMX_EPIT "imx.epit" + +#define DEBUG_TIMER 0 +#if DEBUG_TIMER + +static char const *imx_epit_reg_name(uint32_t reg) +{ + switch (reg) { + case 0: + return "CR"; + case 1: + return "SR"; + case 2: + return "LR"; + case 3: + return "CMP"; + case 4: + return "CNT"; + default: + return "[?]"; + } +} + +# define DPRINTF(fmt, args...) \ + do { printf("%s: " fmt , __func__, ##args); } while (0) +#else +# define DPRINTF(fmt, args...) do {} while (0) +#endif + +/* + * Define to 1 for messages about attempts to + * access unimplemented registers or similar. + */ +#define DEBUG_IMPLEMENTATION 1 +#if DEBUG_IMPLEMENTATION +# define IPRINTF(fmt, args...) \ + do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0) +#else +# define IPRINTF(fmt, args...) do {} while (0) +#endif + +#define IMX_EPIT(obj) \ + OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT) + +/* + * EPIT: Enhanced periodic interrupt timer + */ + +#define CR_EN (1 << 0) +#define CR_ENMOD (1 << 1) +#define CR_OCIEN (1 << 2) +#define CR_RLD (1 << 3) +#define CR_PRESCALE_SHIFT (4) +#define CR_PRESCALE_MASK (0xfff) +#define CR_SWR (1 << 16) +#define CR_IOVW (1 << 17) +#define CR_DBGEN (1 << 18) +#define CR_WAITEN (1 << 19) +#define CR_DOZEN (1 << 20) +#define CR_STOPEN (1 << 21) +#define CR_CLKSRC_SHIFT (24) +#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) + +#define TIMER_MAX 0XFFFFFFFFUL + +/* + * Exact clock frequencies vary from board to board. + * These are typical. + */ +static const IMXClk imx_epit_clocks[] = { + 0, /* 00 disabled */ + IPG, /* 01 ipg_clk, ~532MHz */ + IPG, /* 10 ipg_clk_highfreq */ + CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */ +}; + +typedef struct { + SysBusDevice busdev; + ptimer_state *timer_reload; + ptimer_state *timer_cmp; + MemoryRegion iomem; + DeviceState *ccm; + + uint32_t cr; + uint32_t sr; + uint32_t lr; + uint32_t cmp; + uint32_t cnt; + + uint32_t freq; + qemu_irq irq; +} IMXEPITState; + +/* + * Update interrupt status + */ +static void imx_epit_update_int(IMXEPITState *s) +{ + if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) { + qemu_irq_raise(s->irq); + } else { + qemu_irq_lower(s->irq); + } +} + +static void imx_epit_set_freq(IMXEPITState *s) +{ + uint32_t clksrc; + uint32_t prescaler; + uint32_t freq; + + clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2); + prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12); + + freq = imx_clock_frequency(s->ccm, imx_epit_clocks[clksrc]) / prescaler; + + s->freq = freq; + + DPRINTF("Setting ptimer frequency to %u\n", freq); + + if (freq) { + ptimer_set_freq(s->timer_reload, freq); + ptimer_set_freq(s->timer_cmp, freq); + } +} + +static void imx_epit_reset(DeviceState *dev) +{ + IMXEPITState *s = IMX_EPIT(dev); + + /* + * Soft reset doesn't touch some bits; hard reset clears them + */ + s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); + s->sr = 0; + s->lr = TIMER_MAX; + s->cmp = 0; + s->cnt = 0; + /* stop both timers */ + ptimer_stop(s->timer_cmp); + ptimer_stop(s->timer_reload); + /* compute new frequency */ + imx_epit_set_freq(s); + /* init both timers to TIMER_MAX */ + ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1); + ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); + if (s->freq && (s->cr & CR_EN)) { + /* if the timer is still enabled, restart it */ + ptimer_run(s->timer_reload, 1); + } +} + +static uint32_t imx_epit_update_count(IMXEPITState *s) +{ + s->cnt = ptimer_get_count(s->timer_reload); + + return s->cnt; +} + +static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) +{ + IMXEPITState *s = IMX_EPIT(opaque); + uint32_t reg_value = 0; + uint32_t reg = offset >> 2; + + switch (reg) { + case 0: /* Control Register */ + reg_value = s->cr; + break; + + case 1: /* Status Register */ + reg_value = s->sr; + break; + + case 2: /* LR - ticks*/ + reg_value = s->lr; + break; + + case 3: /* CMP */ + reg_value = s->cmp; + break; + + case 4: /* CNT */ + imx_epit_update_count(s); + reg_value = s->cnt; + break; + + default: + IPRINTF("Bad offset %x\n", reg); + break; + } + + DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(reg), reg_value); + + return reg_value; +} + +static void imx_epit_reload_compare_timer(IMXEPITState *s) +{ + if ((s->cr & CR_OCIEN) && s->cmp) { + /* if the compare feature is on */ + uint32_t tmp = imx_epit_update_count(s); + if (tmp > s->cmp) { + /* reinit the cmp timer if required */ + ptimer_set_count(s->timer_cmp, tmp - s->cmp); + if ((s->cr & CR_EN)) { + /* Restart the cmp timer if required */ + ptimer_run(s->timer_cmp, 0); + } + } + } +} + +static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + IMXEPITState *s = IMX_EPIT(opaque); + uint32_t reg = offset >> 2; + + DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value); + + switch (reg) { + case 0: /* CR */ + s->cr = value & 0x03ffffff; + if (s->cr & CR_SWR) { + /* handle the reset */ + imx_epit_reset(DEVICE(s)); + } else { + imx_epit_set_freq(s); + } + + if (s->freq && (s->cr & CR_EN)) { + if (s->cr & CR_ENMOD) { + if (s->cr & CR_RLD) { + ptimer_set_limit(s->timer_reload, s->lr, 1); + } else { + ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); + } + } + + imx_epit_reload_compare_timer(s); + + ptimer_run(s->timer_reload, 1); + } else { + /* stop both timers */ + ptimer_stop(s->timer_reload); + ptimer_stop(s->timer_cmp); + } + break; + + case 1: /* SR - ACK*/ + /* writing 1 to OCIF clear the OCIF bit */ + if (value & 0x01) { + s->sr = 0; + imx_epit_update_int(s); + } + break; + + case 2: /* LR - set ticks */ + s->lr = value; + + if (s->cr & CR_RLD) { + /* Also set the limit if the LRD bit is set */ + /* If IOVW bit is set then set the timer value */ + ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); + } else if (s->cr & CR_IOVW) { + /* If IOVW bit is set then set the timer value */ + ptimer_set_count(s->timer_reload, s->lr); + } + + imx_epit_reload_compare_timer(s); + + break; + + case 3: /* CMP */ + s->cmp = value; + + imx_epit_reload_compare_timer(s); + + break; + + default: + IPRINTF("Bad offset %x\n", reg); + + break; + } +} + +static void imx_epit_timeout(void *opaque) +{ + IMXEPITState *s = IMX_EPIT(opaque); + + DPRINTF("\n"); + + if (!(s->cr & CR_EN)) { + return; + } + + if (s->cr & CR_RLD) { + ptimer_set_limit(s->timer_reload, s->lr, 1); + } else { + ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); + } + + if (s->cr & CR_OCIEN) { + /* if compare register is 0 then we handle the interrupt here */ + if (s->cmp == 0) { + s->sr = 1; + imx_epit_update_int(s); + } else if (s->cmp <= s->lr) { + /* We should launch the compare register */ + ptimer_set_count(s->timer_cmp, s->lr - s->cmp); + ptimer_run(s->timer_cmp, 0); + } else { + IPRINTF("s->lr < s->cmp\n"); + } + } +} + +static void imx_epit_cmp(void *opaque) +{ + IMXEPITState *s = IMX_EPIT(opaque); + + DPRINTF("\n"); + + ptimer_stop(s->timer_cmp); + + /* compare register is not 0 */ + if (s->cmp) { + s->sr = 1; + imx_epit_update_int(s); + } +} + +void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) +{ + IMXEPITState *pp; + DeviceState *dev; + + dev = sysbus_create_simple(TYPE_IMX_EPIT, addr, irq); + pp = IMX_EPIT(dev); + pp->ccm = ccm; +} + +static const MemoryRegionOps imx_epit_ops = { + .read = imx_epit_read, + .write = imx_epit_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_imx_timer_epit = { + .name = TYPE_IMX_EPIT, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cr, IMXEPITState), + VMSTATE_UINT32(sr, IMXEPITState), + VMSTATE_UINT32(lr, IMXEPITState), + VMSTATE_UINT32(cmp, IMXEPITState), + VMSTATE_UINT32(cnt, IMXEPITState), + VMSTATE_UINT32(freq, IMXEPITState), + VMSTATE_PTIMER(timer_reload, IMXEPITState), + VMSTATE_PTIMER(timer_cmp, IMXEPITState), + VMSTATE_END_OF_LIST() + } +}; + +static void imx_epit_realize(DeviceState *dev, Error **errp) +{ + IMXEPITState *s = IMX_EPIT(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + QEMUBH *bh; + + DPRINTF("\n"); + + sysbus_init_irq(sbd, &s->irq); + memory_region_init_io(&s->iomem, &imx_epit_ops, s, TYPE_IMX_EPIT, + 0x00001000); + sysbus_init_mmio(sbd, &s->iomem); + + bh = qemu_bh_new(imx_epit_timeout, s); + s->timer_reload = ptimer_init(bh); + + bh = qemu_bh_new(imx_epit_cmp, s); + s->timer_cmp = ptimer_init(bh); +} + +static void imx_epit_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = imx_epit_realize; + dc->reset = imx_epit_reset; + dc->vmsd = &vmstate_imx_timer_epit; + dc->desc = "i.MX periodic timer"; +} + +static const TypeInfo imx_epit_info = { + .name = TYPE_IMX_EPIT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMXEPITState), + .class_init = imx_epit_class_init, +}; + +static void imx_epit_register_types(void) +{ + type_register_static(&imx_epit_info); +} + +type_init(imx_epit_register_types) diff --git a/hw/timer/imx_timer.c b/hw/timer/imx_gpt.c index 7693bb7364..d8c4f0baee 100644 --- a/hw/timer/imx_timer.c +++ b/hw/timer/imx_gpt.c @@ -1,5 +1,5 @@ /* - * IMX31 Timer + * IMX GPT Timer * * Copyright (c) 2008 OK Labs * Copyright (c) 2011 NICTA Pty Ltd @@ -12,6 +12,7 @@ */ #include "hw/hw.h" +#include "qemu/bitops.h" #include "qemu/timer.h" #include "hw/ptimer.h" #include "hw/sysbus.h" @@ -54,7 +55,6 @@ * (free-running timer from 0 to OCR1 or TIMER_MAX) . */ - #define TIMER_MAX 0XFFFFFFFFUL /* Control register. Not all of these bits have any effect (yet) */ @@ -148,6 +148,7 @@ static void imx_timerg_set_freq(IMXTimerGState *s) freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr); DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq); + if (freq) { ptimer_set_freq(s->timer, freq); } @@ -206,7 +207,7 @@ static uint64_t imx_timerg_read(void *opaque, hwaddr offset, { IMXTimerGState *s = (IMXTimerGState *)opaque; - DPRINTF("g-read(offset=%x)", offset >> 2); + DPRINTF("g-read(offset=%x)", (unsigned int)(offset >> 2)); switch (offset >> 2) { case 0: /* Control Register */ DPRINTF(" cr = %x\n", s->cr); @@ -427,347 +428,6 @@ static int imx_timerg_init(SysBusDevice *dev) return 0; } - - -/* - * EPIT: Enhanced periodic interrupt timer - */ - -#define CR_EN (1 << 0) -#define CR_ENMOD (1 << 1) -#define CR_OCIEN (1 << 2) -#define CR_RLD (1 << 3) -#define CR_PRESCALE_SHIFT (4) -#define CR_PRESCALE_MASK (0xfff) -#define CR_SWR (1 << 16) -#define CR_IOVW (1 << 17) -#define CR_DBGEN (1 << 18) -#define CR_WAITEN (1 << 19) -#define CR_DOZEN (1 << 20) -#define CR_STOPEN (1 << 21) -#define CR_CLKSRC_SHIFT (24) -#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) - - -/* - * Exact clock frequencies vary from board to board. - * These are typical. - */ -static const IMXClk imx_timerp_clocks[] = { - 0, /* 00 disabled */ - IPG, /* 01 ipg_clk, ~532MHz */ - IPG, /* 10 ipg_clk_highfreq */ - CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */ -}; - -typedef struct { - SysBusDevice busdev; - ptimer_state *timer_reload; - ptimer_state *timer_cmp; - MemoryRegion iomem; - DeviceState *ccm; - - uint32_t cr; - uint32_t sr; - uint32_t lr; - uint32_t cmp; - uint32_t cnt; - - uint32_t freq; - qemu_irq irq; -} IMXTimerPState; - -/* - * Update interrupt status - */ -static void imx_timerp_update(IMXTimerPState *s) -{ - if (s->sr && (s->cr & CR_OCIEN)) { - qemu_irq_raise(s->irq); - } else { - qemu_irq_lower(s->irq); - } -} - -static void set_timerp_freq(IMXTimerPState *s) -{ - int clksrc; - unsigned prescaler; - uint32_t freq; - - clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT; - prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK); - freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler; - - s->freq = freq; - DPRINTF("Setting ptimer frequency to %u\n", freq); - - if (freq) { - ptimer_set_freq(s->timer_reload, freq); - ptimer_set_freq(s->timer_cmp, freq); - } -} - -static void imx_timerp_reset(DeviceState *dev) -{ - IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev); - - /* - * Soft reset doesn't touch some bits; hard reset clears them - */ - s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); - s->sr = 0; - s->lr = TIMER_MAX; - s->cmp = 0; - s->cnt = 0; - /* stop both timers */ - ptimer_stop(s->timer_cmp); - ptimer_stop(s->timer_reload); - /* compute new frequency */ - set_timerp_freq(s); - /* init both timers to TIMER_MAX */ - ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1); - ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); - if (s->freq && (s->cr & CR_EN)) { - /* if the timer is still enabled, restart it */ - ptimer_run(s->timer_reload, 1); - } -} - -static uint32_t imx_timerp_update_counts(IMXTimerPState *s) -{ - s->cnt = ptimer_get_count(s->timer_reload); - - return s->cnt; -} - -static uint64_t imx_timerp_read(void *opaque, hwaddr offset, - unsigned size) -{ - IMXTimerPState *s = (IMXTimerPState *)opaque; - - DPRINTF("p-read(offset=%x)", offset >> 2); - switch (offset >> 2) { - case 0: /* Control Register */ - DPRINTF("cr %x\n", s->cr); - return s->cr; - - case 1: /* Status Register */ - DPRINTF("sr %x\n", s->sr); - return s->sr; - - case 2: /* LR - ticks*/ - DPRINTF("lr %x\n", s->lr); - return s->lr; - - case 3: /* CMP */ - DPRINTF("cmp %x\n", s->cmp); - return s->cmp; - - case 4: /* CNT */ - imx_timerp_update_counts(s); - DPRINTF(" cnt = %x\n", s->cnt); - return s->cnt; - } - - IPRINTF("imx_timerp_read: Bad offset %x\n", - (int)offset >> 2); - return 0; -} - -static void imx_reload_compare_timer(IMXTimerPState *s) -{ - if ((s->cr & CR_OCIEN) && s->cmp) { - /* if the compare feature is on */ - uint32_t tmp = imx_timerp_update_counts(s); - if (tmp > s->cmp) { - /* reinit the cmp timer if required */ - ptimer_set_count(s->timer_cmp, tmp - s->cmp); - if ((s->cr & CR_EN)) { - /* Restart the cmp timer if required */ - ptimer_run(s->timer_cmp, 0); - } - } - } -} - -static void imx_timerp_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - IMXTimerPState *s = (IMXTimerPState *)opaque; - DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2, - (unsigned int)value); - - switch (offset >> 2) { - case 0: /* CR */ - s->cr = value & 0x03ffffff; - if (s->cr & CR_SWR) { - /* handle the reset */ - imx_timerp_reset(&s->busdev.qdev); - } else { - set_timerp_freq(s); - } - - if (s->freq && (s->cr & CR_EN)) { - if (s->cr & CR_ENMOD) { - if (s->cr & CR_RLD) { - ptimer_set_limit(s->timer_reload, s->lr, 1); - } else { - ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); - } - } - - imx_reload_compare_timer(s); - - ptimer_run(s->timer_reload, 1); - } else { - /* stop both timers */ - ptimer_stop(s->timer_reload); - ptimer_stop(s->timer_cmp); - } - break; - - case 1: /* SR - ACK*/ - /* writing 1 to OCIF clear the OCIF bit */ - if (value & 0x01) { - s->sr = 0; - imx_timerp_update(s); - } - break; - - case 2: /* LR - set ticks */ - s->lr = value; - - if (s->cr & CR_RLD) { - /* Also set the limit if the LRD bit is set */ - /* If IOVW bit is set then set the timer value */ - ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); - } else if (s->cr & CR_IOVW) { - /* If IOVW bit is set then set the timer value */ - ptimer_set_count(s->timer_reload, s->lr); - } - - imx_reload_compare_timer(s); - - break; - - case 3: /* CMP */ - s->cmp = value; - - imx_reload_compare_timer(s); - - break; - - default: - IPRINTF("imx_timerp_write: Bad offset %x\n", - (int)offset >> 2); - } -} - -static void imx_timerp_reload(void *opaque) -{ - IMXTimerPState *s = (IMXTimerPState *)opaque; - - DPRINTF("imxp reload\n"); - - if (!(s->cr & CR_EN)) { - return; - } - - if (s->cr & CR_RLD) { - ptimer_set_limit(s->timer_reload, s->lr, 1); - } else { - ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); - } - - if (s->cr & CR_OCIEN) { - /* if compare register is 0 then we handle the interrupt here */ - if (s->cmp == 0) { - s->sr = 1; - imx_timerp_update(s); - } else if (s->cmp <= s->lr) { - /* We should launch the compare register */ - ptimer_set_count(s->timer_cmp, s->lr - s->cmp); - ptimer_run(s->timer_cmp, 0); - } else { - IPRINTF("imxp reload: s->lr < s->cmp\n"); - } - } -} - -static void imx_timerp_cmp(void *opaque) -{ - IMXTimerPState *s = (IMXTimerPState *)opaque; - - DPRINTF("imxp compare\n"); - - ptimer_stop(s->timer_cmp); - - /* compare register is not 0 */ - if (s->cmp) { - s->sr = 1; - imx_timerp_update(s); - } -} - -void imx_timerp_create(const hwaddr addr, - qemu_irq irq, - DeviceState *ccm) -{ - IMXTimerPState *pp; - DeviceState *dev; - - dev = sysbus_create_simple("imx_timerp", addr, irq); - pp = container_of(dev, IMXTimerPState, busdev.qdev); - pp->ccm = ccm; -} - -static const MemoryRegionOps imx_timerp_ops = { - .read = imx_timerp_read, - .write = imx_timerp_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_imx_timerp = { - .name = "imx-timerp", - .version_id = 2, - .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(cr, IMXTimerPState), - VMSTATE_UINT32(sr, IMXTimerPState), - VMSTATE_UINT32(lr, IMXTimerPState), - VMSTATE_UINT32(cmp, IMXTimerPState), - VMSTATE_UINT32(cnt, IMXTimerPState), - VMSTATE_UINT32(freq, IMXTimerPState), - VMSTATE_PTIMER(timer_reload, IMXTimerPState), - VMSTATE_PTIMER(timer_cmp, IMXTimerPState), - VMSTATE_END_OF_LIST() - } -}; - -static int imx_timerp_init(SysBusDevice *dev) -{ - IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev); - QEMUBH *bh; - - DPRINTF("imx_timerp_init\n"); - sysbus_init_irq(dev, &s->irq); - memory_region_init_io(&s->iomem, &imx_timerp_ops, - s, "imxp-timer", - 0x00001000); - sysbus_init_mmio(dev, &s->iomem); - - bh = qemu_bh_new(imx_timerp_reload, s); - s->timer_reload = ptimer_init(bh); - - bh = qemu_bh_new(imx_timerp_cmp, s); - s->timer_cmp = ptimer_init(bh); - - return 0; -} - - void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) @@ -790,23 +450,6 @@ static void imx_timerg_class_init(ObjectClass *klass, void *data) dc->desc = "i.MX general timer"; } -static void imx_timerp_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = imx_timerp_init; - dc->vmsd = &vmstate_imx_timerp; - dc->reset = imx_timerp_reset; - dc->desc = "i.MX periodic timer"; -} - -static const TypeInfo imx_timerp_info = { - .name = "imx_timerp", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMXTimerPState), - .class_init = imx_timerp_class_init, -}; - static const TypeInfo imx_timerg_info = { .name = "imx_timerg", .parent = TYPE_SYS_BUS_DEVICE, @@ -816,7 +459,6 @@ static const TypeInfo imx_timerg_info = { static void imx_timer_register_types(void) { - type_register_static(&imx_timerp_info); type_register_static(&imx_timerg_info); } diff --git a/hw/usb/core.c b/hw/usb/core.c index 15a150aea0..05948ca9a4 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -410,7 +410,7 @@ void usb_handle_packet(USBDevice *dev, USBPacket *p) assert(p->ep->type != USB_ENDPOINT_XFER_ISOC); /* using async for interrupt packets breaks migration */ assert(p->ep->type != USB_ENDPOINT_XFER_INT || - (dev->flags & USB_DEV_FLAG_IS_HOST)); + (dev->flags & (1 << USB_DEV_FLAG_IS_HOST))); usb_packet_set_state(p, USB_PACKET_ASYNC); QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); } else if (p->status == USB_RET_ADD_TO_QUEUE) { diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 8813bdf904..91633edbc6 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -405,6 +405,7 @@ struct XHCIEPContext { typedef struct XHCISlot { bool enabled; + bool addressed; dma_addr_t ctx; USBPort *uport; XHCIEPContext * eps[31]; @@ -1197,31 +1198,30 @@ static void xhci_ep_kick_timer(void *opaque) xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0); } -static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, - unsigned int epid, dma_addr_t pctx, - uint32_t *ctx) +static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci, + unsigned int slotid, + unsigned int epid) { - XHCISlot *slot; XHCIEPContext *epctx; - dma_addr_t dequeue; int i; - trace_usb_xhci_ep_enable(slotid, epid); - assert(slotid >= 1 && slotid <= xhci->numslots); - assert(epid >= 1 && epid <= 31); - - slot = &xhci->slots[slotid-1]; - if (slot->eps[epid-1]) { - xhci_disable_ep(xhci, slotid, epid); - } - - epctx = g_malloc(sizeof(XHCIEPContext)); - memset(epctx, 0, sizeof(XHCIEPContext)); + epctx = g_new0(XHCIEPContext, 1); epctx->xhci = xhci; epctx->slotid = slotid; epctx->epid = epid; - slot->eps[epid-1] = epctx; + for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { + usb_packet_init(&epctx->transfers[i].packet); + } + epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx); + + return epctx; +} + +static void xhci_init_epctx(XHCIEPContext *epctx, + dma_addr_t pctx, uint32_t *ctx) +{ + dma_addr_t dequeue; dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]); @@ -1237,16 +1237,34 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, if (epctx->max_pstreams) { xhci_alloc_streams(epctx, dequeue); } else { - xhci_ring_init(xhci, &epctx->ring, dequeue); + xhci_ring_init(epctx->xhci, &epctx->ring, dequeue); epctx->ring.ccs = ctx[2] & 1; } - for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { - usb_packet_init(&epctx->transfers[i].packet); - } epctx->interval = 1 << (ctx[0] >> 16) & 0xff; +} + +static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid, dma_addr_t pctx, + uint32_t *ctx) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + + trace_usb_xhci_ep_enable(slotid, epid); + assert(slotid >= 1 && slotid <= xhci->numslots); + assert(epid >= 1 && epid <= 31); + + slot = &xhci->slots[slotid-1]; + if (slot->eps[epid-1]) { + xhci_disable_ep(xhci, slotid, epid); + } + + epctx = xhci_alloc_epctx(xhci, slotid, epid); + slot->eps[epid-1] = epctx; + xhci_init_epctx(epctx, pctx, ctx); + epctx->mfindex_last = 0; - epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx); epctx->state = EP_RUNNING; ctx[0] &= ~EP_STATE_MASK; @@ -2041,6 +2059,7 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid) } xhci->slots[slotid-1].enabled = 0; + xhci->slots[slotid-1].addressed = 0; return CC_SUCCESS; } @@ -2167,6 +2186,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx)); + xhci->slots[slotid-1].addressed = 1; return res; } @@ -3366,9 +3386,171 @@ static int usb_xhci_initfn(struct PCIDevice *dev) return 0; } +static int usb_xhci_post_load(void *opaque, int version_id) +{ + XHCIState *xhci = opaque; + XHCISlot *slot; + XHCIEPContext *epctx; + dma_addr_t dcbaap, pctx; + uint32_t slot_ctx[4]; + uint32_t ep_ctx[5]; + int slotid, epid, state, intr; + + dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); + + for (slotid = 1; slotid <= xhci->numslots; slotid++) { + slot = &xhci->slots[slotid-1]; + if (!slot->addressed) { + continue; + } + slot->ctx = + xhci_mask64(ldq_le_pci_dma(&xhci->pci_dev, dcbaap + 8*slotid)); + xhci_dma_read_u32s(xhci, slot->ctx, slot_ctx, sizeof(slot_ctx)); + slot->uport = xhci_lookup_uport(xhci, slot_ctx); + assert(slot->uport && slot->uport->dev); + + for (epid = 1; epid <= 32; epid++) { + pctx = slot->ctx + 32 * epid; + xhci_dma_read_u32s(xhci, pctx, ep_ctx, sizeof(ep_ctx)); + state = ep_ctx[0] & EP_STATE_MASK; + if (state == EP_DISABLED) { + continue; + } + epctx = xhci_alloc_epctx(xhci, slotid, epid); + slot->eps[epid-1] = epctx; + xhci_init_epctx(epctx, pctx, ep_ctx); + epctx->state = state; + if (state == EP_RUNNING) { + /* kick endpoint after vmload is finished */ + qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock)); + } + } + } + + for (intr = 0; intr < xhci->numintrs; intr++) { + if (xhci->intr[intr].msix_used) { + msix_vector_use(&xhci->pci_dev, intr); + } else { + msix_vector_unuse(&xhci->pci_dev, intr); + } + } + + return 0; +} + +static const VMStateDescription vmstate_xhci_ring = { + .name = "xhci-ring", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(dequeue, XHCIRing), + VMSTATE_BOOL(ccs, XHCIRing), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_xhci_port = { + .name = "xhci-port", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(portsc, XHCIPort), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_xhci_slot = { + .name = "xhci-slot", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(enabled, XHCISlot), + VMSTATE_BOOL(addressed, XHCISlot), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_xhci_event = { + .name = "xhci-event", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(type, XHCIEvent), + VMSTATE_UINT32(ccode, XHCIEvent), + VMSTATE_UINT64(ptr, XHCIEvent), + VMSTATE_UINT32(length, XHCIEvent), + VMSTATE_UINT32(flags, XHCIEvent), + VMSTATE_UINT8(slotid, XHCIEvent), + VMSTATE_UINT8(epid, XHCIEvent), + } +}; + +static bool xhci_er_full(void *opaque, int version_id) +{ + struct XHCIInterrupter *intr = opaque; + return intr->er_full; +} + +static const VMStateDescription vmstate_xhci_intr = { + .name = "xhci-intr", + .version_id = 1, + .fields = (VMStateField[]) { + /* registers */ + VMSTATE_UINT32(iman, XHCIInterrupter), + VMSTATE_UINT32(imod, XHCIInterrupter), + VMSTATE_UINT32(erstsz, XHCIInterrupter), + VMSTATE_UINT32(erstba_low, XHCIInterrupter), + VMSTATE_UINT32(erstba_high, XHCIInterrupter), + VMSTATE_UINT32(erdp_low, XHCIInterrupter), + VMSTATE_UINT32(erdp_high, XHCIInterrupter), + + /* state */ + VMSTATE_BOOL(msix_used, XHCIInterrupter), + VMSTATE_BOOL(er_pcs, XHCIInterrupter), + VMSTATE_UINT64(er_start, XHCIInterrupter), + VMSTATE_UINT32(er_size, XHCIInterrupter), + VMSTATE_UINT32(er_ep_idx, XHCIInterrupter), + + /* event queue (used if ring is full) */ + VMSTATE_BOOL(er_full, XHCIInterrupter), + VMSTATE_UINT32_TEST(ev_buffer_put, XHCIInterrupter, xhci_er_full), + VMSTATE_UINT32_TEST(ev_buffer_get, XHCIInterrupter, xhci_er_full), + VMSTATE_STRUCT_ARRAY_TEST(ev_buffer, XHCIInterrupter, EV_QUEUE, + xhci_er_full, 1, + vmstate_xhci_event, XHCIEvent), + + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_xhci = { .name = "xhci", - .unmigratable = 1, + .version_id = 1, + .post_load = usb_xhci_post_load, + .fields = (VMStateField[]) { + VMSTATE_PCIE_DEVICE(pci_dev, XHCIState), + VMSTATE_MSIX(pci_dev, XHCIState), + + VMSTATE_STRUCT_VARRAY_UINT32(ports, XHCIState, numports, 1, + vmstate_xhci_port, XHCIPort), + VMSTATE_STRUCT_VARRAY_UINT32(slots, XHCIState, numslots, 1, + vmstate_xhci_slot, XHCISlot), + VMSTATE_STRUCT_VARRAY_UINT32(intr, XHCIState, numintrs, 1, + vmstate_xhci_intr, XHCIInterrupter), + + /* Operational Registers */ + VMSTATE_UINT32(usbcmd, XHCIState), + VMSTATE_UINT32(usbsts, XHCIState), + VMSTATE_UINT32(dnctrl, XHCIState), + VMSTATE_UINT32(crcr_low, XHCIState), + VMSTATE_UINT32(crcr_high, XHCIState), + VMSTATE_UINT32(dcbaap_low, XHCIState), + VMSTATE_UINT32(dcbaap_high, XHCIState), + VMSTATE_UINT32(config, XHCIState), + + /* Runtime Registers & state */ + VMSTATE_INT64(mfindex_start, XHCIState), + VMSTATE_TIMER(mfwrap_timer, XHCIState), + VMSTATE_STRUCT(cmd_ring, XHCIState, 1, vmstate_xhci_ring, XHCIRing), + + VMSTATE_END_OF_LIST() + } }; static Property xhci_properties[] = { diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index f3de4591fd..3a582c526d 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -385,7 +385,7 @@ out: static void usb_host_req_abort(USBHostRequest *r) { USBHostDevice *s = r->host; - bool inflight = (r->p && r->p->state == USB_RET_ASYNC); + bool inflight = (r->p && r->p->state == USB_PACKET_ASYNC); if (inflight) { r->p->status = USB_RET_NODEV; diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index ea2e11ae95..6849a018a9 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -161,10 +161,16 @@ static char *virtio_bus_get_dev_path(DeviceState *dev) return qdev_get_dev_path(proxy); } +static char *virtio_bus_get_fw_dev_path(DeviceState *dev) +{ + return NULL; +} + static void virtio_bus_class_init(ObjectClass *klass, void *data) { BusClass *bus_class = BUS_CLASS(klass); bus_class->get_dev_path = virtio_bus_get_dev_path; + bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path; } static const TypeInfo virtio_bus_info = { diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 70d2c6b5e3..444b71aab0 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -89,12 +89,6 @@ /* Flags track per-device state like workarounds for quirks in older guests. */ #define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0) -/* QEMU doesn't strictly need write barriers since everything runs in - * lock-step. We'll leave the calls to wmb() in though to make it obvious for - * KVM or if kqemu gets SMP support. - */ -#define wmb() do { } while (0) - /* HACK for virtio to determine if it's running a big endian guest */ bool virtio_is_big_endian(void); diff --git a/include/block/block.h b/include/block/block.h index 1251c5cf9f..dc5b388d87 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -27,17 +27,6 @@ typedef struct BlockFragInfo { uint64_t compressed_clusters; } BlockFragInfo; -typedef struct QEMUSnapshotInfo { - char id_str[128]; /* unique snapshot id */ - /* the following fields are informative. They are not needed for - the consistency of the snapshot */ - char name[256]; /* user chosen name */ - uint64_t vm_state_size; /* VM state info size */ - uint32_t date_sec; /* UTC date of the snapshot */ - uint32_t date_nsec; - uint64_t vm_clock_nsec; /* VM clock relative to boot */ -} QEMUSnapshotInfo; - /* Callbacks for block device models */ typedef struct BlockDevOps { /* @@ -124,7 +113,8 @@ void bdrv_init(void); void bdrv_init_with_whitelist(void); BlockDriver *bdrv_find_protocol(const char *filename); BlockDriver *bdrv_find_format(const char *format_name); -BlockDriver *bdrv_find_whitelisted_format(const char *format_name); +BlockDriver *bdrv_find_whitelisted_format(const char *format_name, + bool readonly); int bdrv_create(BlockDriver *drv, const char* filename, QEMUOptionParameter *options); int bdrv_create_file(const char* filename, QEMUOptionParameter *options); @@ -328,23 +318,8 @@ void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size); void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz); -BlockInfo *bdrv_query_info(BlockDriverState *s); -BlockStats *bdrv_query_stats(const BlockDriverState *bs); -int bdrv_can_snapshot(BlockDriverState *bs); int bdrv_is_snapshot(BlockDriverState *bs); -BlockDriverState *bdrv_snapshots(void); -int bdrv_snapshot_create(BlockDriverState *bs, - QEMUSnapshotInfo *sn_info); -int bdrv_snapshot_goto(BlockDriverState *bs, - const char *snapshot_id); -int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); -int bdrv_snapshot_list(BlockDriverState *bs, - QEMUSnapshotInfo **psn_info); -int bdrv_snapshot_load_tmp(BlockDriverState *bs, - const char *snapshot_name); -char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); - -char *get_human_readable_size(char *buf, int buf_size, int64_t size); + int path_is_absolute(const char *path); void path_combine(char *dest, int dest_size, const char *base_path, diff --git a/include/block/block_int.h b/include/block/block_int.h index 6078dd389f..ba52247c1a 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -33,6 +33,7 @@ #include "qapi/qmp/qerror.h" #include "monitor/monitor.h" #include "qemu/hbitmap.h" +#include "block/snapshot.h" #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPAT6 4 diff --git a/include/block/qapi.h b/include/block/qapi.h new file mode 100644 index 0000000000..e6e568da94 --- /dev/null +++ b/include/block/qapi.h @@ -0,0 +1,43 @@ +/* + * Block layer qmp and info dump related functions + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef BLOCK_QAPI_H +#define BLOCK_QAPI_H + +#include "qapi-types.h" +#include "block/block.h" +#include "block/snapshot.h" + +void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info); +void bdrv_collect_image_info(BlockDriverState *bs, + ImageInfo *info, + const char *filename); +BlockInfo *bdrv_query_info(BlockDriverState *s); +BlockStats *bdrv_query_stats(const BlockDriverState *bs); + +void bdrv_snapshot_dump(fprintf_function func_fprintf, void *f, + QEMUSnapshotInfo *sn); +void bdrv_image_info_dump(fprintf_function func_fprintf, void *f, + ImageInfo *info); +#endif diff --git a/include/block/snapshot.h b/include/block/snapshot.h new file mode 100644 index 0000000000..eaf61f0326 --- /dev/null +++ b/include/block/snapshot.h @@ -0,0 +1,53 @@ +/* + * Block layer snapshot related functions + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SNAPSHOT_H +#define SNAPSHOT_H + +#include "qemu-common.h" + +typedef struct QEMUSnapshotInfo { + char id_str[128]; /* unique snapshot id */ + /* the following fields are informative. They are not needed for + the consistency of the snapshot */ + char name[256]; /* user chosen name */ + uint64_t vm_state_size; /* VM state info size */ + uint32_t date_sec; /* UTC date of the snapshot */ + uint32_t date_nsec; + uint64_t vm_clock_nsec; /* VM clock relative to boot */ +} QEMUSnapshotInfo; + +int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, + const char *name); +int bdrv_can_snapshot(BlockDriverState *bs); +int bdrv_snapshot_create(BlockDriverState *bs, + QEMUSnapshotInfo *sn_info); +int bdrv_snapshot_goto(BlockDriverState *bs, + const char *snapshot_id); +int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); +int bdrv_snapshot_list(BlockDriverState *bs, + QEMUSnapshotInfo **psn_info); +int bdrv_snapshot_load_tmp(BlockDriverState *bs, + const char *snapshot_name); +#endif diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index af5258d414..e061e21093 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -110,9 +110,7 @@ void stq_phys(hwaddr addr, uint64_t val); void cpu_physical_memory_write_rom(hwaddr addr, const uint8_t *buf, int len); -extern struct MemoryRegion io_mem_ram; extern struct MemoryRegion io_mem_rom; -extern struct MemoryRegion io_mem_unassigned; extern struct MemoryRegion io_mem_notdirty; #endif diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h index 733c885a1f..e8216602d0 100644 --- a/include/exec/cputlb.h +++ b/include/exec/cputlb.h @@ -26,8 +26,6 @@ void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr, target_ulong vaddr); void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start, uintptr_t length); -MemoryRegionSection *phys_page_find(struct AddressSpaceDispatch *d, - hwaddr index); void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length); void tlb_set_dirty(CPUArchState *env, target_ulong vaddr); extern int tlb_flush_count; @@ -35,11 +33,11 @@ extern int tlb_flush_count; /* exec.c */ void tb_flush_jmp_cache(CPUArchState *env, target_ulong addr); hwaddr memory_region_section_get_iotlb(CPUArchState *env, - MemoryRegionSection *section, - target_ulong vaddr, - hwaddr paddr, - int prot, - target_ulong *address); + MemoryRegionSection *section, + target_ulong vaddr, + hwaddr paddr, hwaddr xlat, + int prot, + target_ulong *address); bool memory_region_is_unassigned(MemoryRegion *mr); #endif diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 6362074e9c..17fde25c74 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -367,9 +367,9 @@ bool is_tcg_gen_code(uintptr_t pc_ptr); #if !defined(CONFIG_USER_ONLY) struct MemoryRegion *iotlb_to_region(hwaddr index); -uint64_t io_mem_read(struct MemoryRegion *mr, hwaddr addr, - unsigned size); -void io_mem_write(struct MemoryRegion *mr, hwaddr addr, +bool io_mem_read(struct MemoryRegion *mr, hwaddr addr, + uint64_t *pvalue, unsigned size); +bool io_mem_write(struct MemoryRegion *mr, hwaddr addr, uint64_t value, unsigned size); void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx, diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h index 8d15f90417..799c02a63c 100644 --- a/include/exec/memory-internal.h +++ b/include/exec/memory-internal.h @@ -43,6 +43,11 @@ struct AddressSpaceDispatch { void address_space_init_dispatch(AddressSpace *as); void address_space_destroy_dispatch(AddressSpace *as); +extern const MemoryRegionOps unassigned_mem_ops; + +bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, + unsigned size, bool is_write); + ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, MemoryRegion *mr); ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr); diff --git a/include/exec/memory.h b/include/exec/memory.h index fdf55feea1..d53a6a1b88 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -752,23 +752,6 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr, hwaddr addr, uint64_t size); /** - * memory_region_section_addr: get offset within MemoryRegionSection - * - * Returns offset within MemoryRegionSection - * - * @section: the memory region section being queried - * @addr: address in address space - */ -static inline hwaddr -memory_region_section_addr(MemoryRegionSection *section, - hwaddr addr) -{ - addr -= section->offset_within_address_space; - addr += section->offset_within_region; - return addr; -} - -/** * address_space_sync_dirty_bitmap: synchronize the dirty log for all memory * * Synchronizes the dirty page log for an entire address space. @@ -842,32 +825,67 @@ void address_space_destroy(AddressSpace *as); /** * address_space_rw: read from or write to an address space. * + * Return true if the operation hit any unassigned memory. + * * @as: #AddressSpace to be accessed * @addr: address within that address space * @buf: buffer with the data transferred * @is_write: indicates the transfer direction */ -void address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, +bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, int len, bool is_write); /** * address_space_write: write to address space. * + * Return true if the operation hit any unassigned memory. + * * @as: #AddressSpace to be accessed * @addr: address within that address space * @buf: buffer with the data transferred */ -void address_space_write(AddressSpace *as, hwaddr addr, +bool address_space_write(AddressSpace *as, hwaddr addr, const uint8_t *buf, int len); /** * address_space_read: read from an address space. * + * Return true if the operation hit any unassigned memory. + * * @as: #AddressSpace to be accessed * @addr: address within that address space * @buf: buffer with the data transferred */ -void address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len); +bool address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len); + +/* address_space_translate: translate an address range into an address space + * into a MemoryRegionSection and an address range into that section + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @xlat: pointer to address within the returned memory region section's + * #MemoryRegion. + * @len: pointer to length + * @is_write: indicates the transfer direction + */ +MemoryRegionSection *address_space_translate(AddressSpace *as, hwaddr addr, + hwaddr *xlat, hwaddr *len, + bool is_write); + +/* address_space_access_valid: check for validity of accessing an address + * space range + * + * Check whether memory is assigned to the given address space range. + * + * For now, addr and len should be aligned to a page size. This limitation + * will be lifted in the future. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @len: length of the area to be checked + * @is_write: indicates the transfer direction + */ +bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write); /* address_space_map: map a physical memory region into a host virtual address * diff --git a/include/exec/softmmu_template.h b/include/exec/softmmu_template.h index b219191abd..8584902cbe 100644 --- a/include/exec/softmmu_template.h +++ b/include/exec/softmmu_template.h @@ -63,31 +63,18 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, target_ulong addr, uintptr_t retaddr) { - DATA_TYPE res; + uint64_t val; MemoryRegion *mr = iotlb_to_region(physaddr); physaddr = (physaddr & TARGET_PAGE_MASK) + addr; env->mem_io_pc = retaddr; - if (mr != &io_mem_ram && mr != &io_mem_rom - && mr != &io_mem_unassigned - && mr != &io_mem_notdirty - && !can_do_io(env)) { + if (mr != &io_mem_rom && mr != &io_mem_notdirty && !can_do_io(env)) { cpu_io_recompile(env, retaddr); } env->mem_io_vaddr = addr; -#if SHIFT <= 2 - res = io_mem_read(mr, physaddr, 1 << SHIFT); -#else -#ifdef TARGET_WORDS_BIGENDIAN - res = io_mem_read(mr, physaddr, 4) << 32; - res |= io_mem_read(mr, physaddr + 4, 4); -#else - res = io_mem_read(mr, physaddr, 4); - res |= io_mem_read(mr, physaddr + 4, 4) << 32; -#endif -#endif /* SHIFT > 2 */ - return res; + io_mem_read(mr, physaddr, &val, 1 << SHIFT); + return val; } /* handle all cases except unaligned access which span two pages */ @@ -218,26 +205,13 @@ static inline void glue(io_write, SUFFIX)(CPUArchState *env, MemoryRegion *mr = iotlb_to_region(physaddr); physaddr = (physaddr & TARGET_PAGE_MASK) + addr; - if (mr != &io_mem_ram && mr != &io_mem_rom - && mr != &io_mem_unassigned - && mr != &io_mem_notdirty - && !can_do_io(env)) { + if (mr != &io_mem_rom && mr != &io_mem_notdirty && !can_do_io(env)) { cpu_io_recompile(env, retaddr); } env->mem_io_vaddr = addr; env->mem_io_pc = retaddr; -#if SHIFT <= 2 io_mem_write(mr, physaddr, val, 1 << SHIFT); -#else -#ifdef TARGET_WORDS_BIGENDIAN - io_mem_write(mr, physaddr, (val >> 32), 4); - io_mem_write(mr, physaddr + 4, (uint32_t)val, 4); -#else - io_mem_write(mr, physaddr, (uint32_t)val, 4); - io_mem_write(mr, physaddr + 4, val >> 32, 4); -#endif -#endif /* SHIFT > 2 */ } void glue(glue(helper_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 626442b116..61540587a4 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -83,14 +83,14 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level); void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge); void pc_hot_add_cpu(const int64_t id, Error **errp); void pc_acpi_init(const char *default_dsdt); -void *pc_memory_init(MemoryRegion *system_memory, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, - MemoryRegion *rom_memory, - MemoryRegion **ram_memory); +FWCfgState *pc_memory_init(MemoryRegion *system_memory, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + ram_addr_t below_4g_mem_size, + ram_addr_t above_4g_mem_size, + MemoryRegion *rom_memory, + MemoryRegion **ram_memory); qemu_irq *pc_allocate_cpu_irq(void); DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, @@ -114,7 +114,7 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name); i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, qemu_irq sci_irq, qemu_irq smi_irq, - int kvm_enabled, void *fw_cfg); + int kvm_enabled, FWCfgState *fw_cfg); void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); /* hpet.c */ diff --git a/include/hw/loader.h b/include/hw/loader.h index 0958f06934..15d4cc9a55 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -1,6 +1,7 @@ #ifndef LOADER_H #define LOADER_H #include "qapi/qmp/qdict.h" +#include "hw/nvram/fw_cfg.h" /* loader.c */ int get_image_size(const char *filename); @@ -30,7 +31,7 @@ int rom_add_blob(const char *name, const void *blob, size_t len, int rom_add_elf_program(const char *name, void *data, size_t datasize, size_t romsize, hwaddr addr); int rom_load_all(void); -void rom_set_fw(void *f); +void rom_set_fw(FWCfgState *f); int rom_copy(uint8_t *dest, hwaddr addr, size_t size); void *rom_ptr(hwaddr addr); void do_info_roms(Monitor *mon, const QDict *qdict); diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 3e4a3347e8..f60dd676c8 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -6,6 +6,7 @@ #include <stddef.h> #include "exec/hwaddr.h" +#include "qemu/typedefs.h" #endif #define FW_CFG_SIGNATURE 0x00 @@ -60,7 +61,6 @@ typedef struct FWCfgFiles { typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); -typedef struct FWCfgState FWCfgState; void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len); void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value); void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value); @@ -73,6 +73,8 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, hwaddr crl_addr, hwaddr data_addr); +FWCfgState *fw_cfg_find(void); + #endif /* NO_QEMU_PROTOS */ #endif diff --git a/include/hw/sparc/firmware_abi.h b/include/hw/nvram/openbios_firmware_abi.h index 5e6e5d4d34..5e6e5d4d34 100644 --- a/include/hw/sparc/firmware_abi.h +++ b/include/hw/nvram/openbios_firmware_abi.h diff --git a/include/hw/pci/msix.h b/include/hw/pci/msix.h index e648410535..954d82b350 100644 --- a/include/hw/pci/msix.h +++ b/include/hw/pci/msix.h @@ -43,4 +43,15 @@ int msix_set_vector_notifiers(PCIDevice *dev, MSIVectorReleaseNotifier release_notifier, MSIVectorPollNotifier poll_notifier); void msix_unset_vector_notifiers(PCIDevice *dev); + +extern const VMStateDescription vmstate_msix; + +#define VMSTATE_MSIX(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(PCIDevice), \ + .vmsd = &vmstate_msix, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, PCIDevice), \ +} + #endif diff --git a/include/hw/timer/mc146818rtc.h b/include/hw/timer/mc146818rtc.h index 753dda6ae7..eaf649767f 100644 --- a/include/hw/timer/mc146818rtc.h +++ b/include/hw/timer/mc146818rtc.h @@ -9,6 +9,5 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); int rtc_get_memory(ISADevice *dev, int addr); -void rtc_set_date(ISADevice *dev, const struct tm *tm); #endif /* !MC146818RTC_H */ diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 1fef18c08f..28c21d8338 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -18,7 +18,10 @@ typedef struct GenericList { - void *value; + union { + void *value; + uint64_t padding; + }; struct GenericList *next; } GenericList; diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 57d7b1fb4d..26136f16ec 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -204,4 +204,15 @@ const char *qemu_get_version(void); void fips_set_state(bool requested); bool fips_get_state(void); +/* Return a dynamically allocated pathname denoting a file or directory that is + * appropriate for storing local state. + * + * @relative_pathname need not start with a directory separator; one will be + * added automatically. + * + * The caller is responsible for releasing the value returned with g_free() + * after use. + */ +char *qemu_get_local_state_pathname(const char *relative_pathname); + #endif diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 93aae81a82..afe4ec76e1 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -61,5 +61,6 @@ typedef struct EventNotifier EventNotifier; typedef struct VirtIODevice VirtIODevice; typedef struct QEMUSGList QEMUSGList; typedef struct SHPCDevice SHPCDevice; +typedef struct FWCfgState FWCfgState; #endif /* QEMU_TYPEDEFS_H */ diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h index a52c93a553..02e0dcdfeb 100644 --- a/include/sysemu/dma.h +++ b/include/sysemu/dma.h @@ -113,7 +113,8 @@ static inline bool dma_memory_valid(DMAContext *dma, DMADirection dir) { if (!dma_has_iommu(dma)) { - return true; + return address_space_access_valid(dma->as, addr, len, + dir == DMA_DIRECTION_FROM_DEVICE); } else { return iommu_dma_memory_valid(dma, addr, len, dir); } diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 08284ef770..8b19322c0a 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -45,6 +45,7 @@ extern bool kvm_async_interrupts_allowed; extern bool kvm_irqfds_allowed; extern bool kvm_msi_via_irqfd_allowed; extern bool kvm_gsi_routing_allowed; +extern bool kvm_readonly_mem_allowed; #if defined CONFIG_KVM || !defined NEED_CPU_H #define kvm_enabled() (kvm_allowed) @@ -97,6 +98,14 @@ extern bool kvm_gsi_routing_allowed; */ #define kvm_gsi_routing_enabled() (kvm_gsi_routing_allowed) +/** + * kvm_readonly_mem_enabled: + * + * Returns: true if KVM readonly memory is enabled (ie the kernel + * supports it and we're running in a configuration that permits it). + */ +#define kvm_readonly_mem_enabled() (kvm_readonly_mem_allowed) + #else #define kvm_enabled() (0) #define kvm_irqchip_in_kernel() (false) @@ -104,6 +113,7 @@ extern bool kvm_gsi_routing_allowed; #define kvm_irqfds_enabled() (false) #define kvm_msi_via_irqfd_enabled() (false) #define kvm_gsi_routing_allowed() (false) +#define kvm_readonly_mem_enabled() (false) #endif struct kvm_run; @@ -111,6 +111,7 @@ bool kvm_irqfds_allowed; bool kvm_msi_via_irqfd_allowed; bool kvm_gsi_routing_allowed; bool kvm_allowed; +bool kvm_readonly_mem_allowed; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -200,12 +201,19 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) mem.slot = slot->slot; mem.guest_phys_addr = slot->start_addr; - mem.memory_size = slot->memory_size; mem.userspace_addr = (unsigned long)slot->ram; mem.flags = slot->flags; if (s->migration_log) { mem.flags |= KVM_MEM_LOG_DIRTY_PAGES; } + + if (slot->memory_size && mem.flags & KVM_MEM_READONLY) { + /* Set the slot size to 0 before setting the slot to the desired + * value. This is needed based on KVM commit 75d61fbc. */ + mem.memory_size = 0; + kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); + } + mem.memory_size = slot->memory_size; return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); } @@ -267,9 +275,14 @@ err: * dirty pages logging control */ -static int kvm_mem_flags(KVMState *s, bool log_dirty) +static int kvm_mem_flags(KVMState *s, bool log_dirty, bool readonly) { - return log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0; + int flags = 0; + flags = log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0; + if (readonly && kvm_readonly_mem_allowed) { + flags |= KVM_MEM_READONLY; + } + return flags; } static int kvm_slot_dirty_pages_log_change(KVMSlot *mem, bool log_dirty) @@ -280,7 +293,7 @@ static int kvm_slot_dirty_pages_log_change(KVMSlot *mem, bool log_dirty) old_flags = mem->flags; - flags = (mem->flags & ~mask) | kvm_mem_flags(s, log_dirty); + flags = (mem->flags & ~mask) | kvm_mem_flags(s, log_dirty, false); mem->flags = flags; /* If nothing changed effectively, no need to issue ioctl */ @@ -618,6 +631,8 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) int err; MemoryRegion *mr = section->mr; bool log_dirty = memory_region_is_logging(mr); + bool writeable = !mr->readonly && !mr->rom_device; + bool readonly_flag = mr->readonly || memory_region_is_romd(mr); hwaddr start_addr = section->offset_within_address_space; ram_addr_t size = section->size; void *ram = NULL; @@ -637,7 +652,13 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) } if (!memory_region_is_ram(mr)) { - return; + if (writeable || !kvm_readonly_mem_allowed) { + return; + } else if (!mr->romd_mode) { + /* If the memory device is not in romd_mode, then we actually want + * to remove the kvm memory slot so all accesses will trap. */ + add = false; + } } ram = memory_region_get_ram_ptr(mr) + section->offset_within_region + delta; @@ -686,7 +707,7 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) mem->memory_size = old.memory_size; mem->start_addr = old.start_addr; mem->ram = old.ram; - mem->flags = kvm_mem_flags(s, log_dirty); + mem->flags = kvm_mem_flags(s, log_dirty, readonly_flag); err = kvm_set_user_memory_region(s, mem); if (err) { @@ -707,7 +728,7 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) mem->memory_size = start_addr - old.start_addr; mem->start_addr = old.start_addr; mem->ram = old.ram; - mem->flags = kvm_mem_flags(s, log_dirty); + mem->flags = kvm_mem_flags(s, log_dirty, readonly_flag); err = kvm_set_user_memory_region(s, mem); if (err) { @@ -731,7 +752,7 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) size_delta = mem->start_addr - old.start_addr; mem->memory_size = old.memory_size - size_delta; mem->ram = old.ram + size_delta; - mem->flags = kvm_mem_flags(s, log_dirty); + mem->flags = kvm_mem_flags(s, log_dirty, readonly_flag); err = kvm_set_user_memory_region(s, mem); if (err) { @@ -753,7 +774,7 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) mem->memory_size = size; mem->start_addr = start_addr; mem->ram = ram; - mem->flags = kvm_mem_flags(s, log_dirty); + mem->flags = kvm_mem_flags(s, log_dirty, readonly_flag); err = kvm_set_user_memory_region(s, mem); if (err) { @@ -1425,6 +1446,11 @@ int kvm_init(void) s->irq_set_ioctl = KVM_IRQ_LINE_STATUS; } +#ifdef KVM_CAP_READONLY_MEM + kvm_readonly_mem_allowed = + (kvm_check_extension(s, KVM_CAP_READONLY_MEM) > 0); +#endif + ret = kvm_arch_init(s); if (ret < 0) { goto err; diff --git a/kvm-stub.c b/kvm-stub.c index b2c8f9b02d..22eaff0671 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -26,6 +26,7 @@ bool kvm_irqfds_allowed; bool kvm_msi_via_irqfd_allowed; bool kvm_gsi_routing_allowed; bool kvm_allowed; +bool kvm_readonly_mem_allowed; int kvm_init_vcpu(CPUState *cpu) { diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1b3c0ed5f7..0099d64a9c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8236,7 +8236,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_madvise case TARGET_NR_madvise: /* A straight passthrough may not be safe because qemu sometimes - turns private flie-backed mappings into anonymous mappings. + turns private file-backed mappings into anonymous mappings. This will break MADV_DONTNEED. This is a hint, so ignoring and returning success is ok. */ ret = get_errno(0); @@ -22,6 +22,8 @@ #include "exec/memory-internal.h" +//#define DEBUG_UNASSIGNED + static unsigned memory_region_transaction_depth; static bool memory_region_update_pending; static bool global_dirty_log = false; @@ -300,6 +302,20 @@ static void flatview_simplify(FlatView *view) } } +static void memory_region_oldmmio_read_accessor(void *opaque, + hwaddr addr, + uint64_t *value, + unsigned size, + unsigned shift, + uint64_t mask) +{ + MemoryRegion *mr = opaque; + uint64_t tmp; + + tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr); + *value |= (tmp & mask) << shift; +} + static void memory_region_read_accessor(void *opaque, hwaddr addr, uint64_t *value, @@ -317,6 +333,20 @@ static void memory_region_read_accessor(void *opaque, *value |= (tmp & mask) << shift; } +static void memory_region_oldmmio_write_accessor(void *opaque, + hwaddr addr, + uint64_t *value, + unsigned size, + unsigned shift, + uint64_t mask) +{ + MemoryRegion *mr = opaque; + uint64_t tmp; + + tmp = (*value >> shift) & mask; + mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, tmp); +} + static void memory_region_write_accessor(void *opaque, hwaddr addr, uint64_t *value, @@ -357,11 +387,17 @@ static void access_with_adjusted_size(hwaddr addr, if (!access_size_max) { access_size_max = 4; } + + /* FIXME: support unaligned access? */ access_size = MAX(MIN(size, access_size_max), access_size_min); access_mask = -1ULL >> (64 - access_size * 8); for (i = 0; i < size; i += access_size) { - /* FIXME: big-endian support */ +#ifdef TARGET_WORDS_BIGENDIAN + access(opaque, addr + i, value, access_size, + (size - access_size - i) * 8, access_mask); +#else access(opaque, addr + i, value, access_size, i * 8, access_mask); +#endif } } @@ -786,7 +822,8 @@ void memory_region_init(MemoryRegion *mr, const char *name, uint64_t size) { - mr->ops = NULL; + mr->ops = &unassigned_mem_ops; + mr->opaque = NULL; mr->parent = NULL; mr->size = int128_make64(size); if (size == UINT64_MAX) { @@ -814,29 +851,74 @@ void memory_region_init(MemoryRegion *mr, mr->flush_coalesced_mmio = false; } -static bool memory_region_access_valid(MemoryRegion *mr, - hwaddr addr, - unsigned size, - bool is_write) +static uint64_t unassigned_mem_read(void *opaque, hwaddr addr, + unsigned size) { - if (mr->ops->valid.accepts - && !mr->ops->valid.accepts(mr->opaque, addr, size, is_write)) { - return false; - } +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); +#endif +#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size); +#endif + return 0; +} + +static void unassigned_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%"PRIx64"\n", addr, val); +#endif +#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) + cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size); +#endif +} + +static bool unassigned_mem_accepts(void *opaque, hwaddr addr, + unsigned size, bool is_write) +{ + return false; +} + +const MemoryRegionOps unassigned_mem_ops = { + .valid.accepts = unassigned_mem_accepts, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +bool memory_region_access_valid(MemoryRegion *mr, + hwaddr addr, + unsigned size, + bool is_write) +{ + int access_size_min, access_size_max; + int access_size, i; if (!mr->ops->valid.unaligned && (addr & (size - 1))) { return false; } - /* Treat zero as compatibility all valid */ - if (!mr->ops->valid.max_access_size) { + if (!mr->ops->valid.accepts) { return true; } - if (size > mr->ops->valid.max_access_size - || size < mr->ops->valid.min_access_size) { - return false; + access_size_min = mr->ops->valid.min_access_size; + if (!mr->ops->valid.min_access_size) { + access_size_min = 1; + } + + access_size_max = mr->ops->valid.max_access_size; + if (!mr->ops->valid.max_access_size) { + access_size_max = 4; } + + access_size = MAX(MIN(size, access_size_max), access_size_min); + for (i = 0; i < size; i += access_size) { + if (!mr->ops->valid.accepts(mr->opaque, addr + i, access_size, + is_write)) { + return false; + } + } + return true; } @@ -846,20 +928,16 @@ static uint64_t memory_region_dispatch_read1(MemoryRegion *mr, { uint64_t data = 0; - if (!memory_region_access_valid(mr, addr, size, false)) { - return -1U; /* FIXME: better signalling */ - } - - if (!mr->ops->read) { - return mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr); + if (mr->ops->read) { + access_with_adjusted_size(addr, &data, size, + mr->ops->impl.min_access_size, + mr->ops->impl.max_access_size, + memory_region_read_accessor, mr); + } else { + access_with_adjusted_size(addr, &data, size, 1, 4, + memory_region_oldmmio_read_accessor, mr); } - /* FIXME: support unaligned access */ - access_with_adjusted_size(addr, &data, size, - mr->ops->impl.min_access_size, - mr->ops->impl.max_access_size, - memory_region_read_accessor, mr); - return data; } @@ -875,44 +953,52 @@ static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size) case 4: *data = bswap32(*data); break; + case 8: + *data = bswap64(*data); + break; default: abort(); } } } -static uint64_t memory_region_dispatch_read(MemoryRegion *mr, - hwaddr addr, - unsigned size) +static bool memory_region_dispatch_read(MemoryRegion *mr, + hwaddr addr, + uint64_t *pval, + unsigned size) { - uint64_t ret; + if (!memory_region_access_valid(mr, addr, size, false)) { + *pval = unassigned_mem_read(mr, addr, size); + return true; + } - ret = memory_region_dispatch_read1(mr, addr, size); - adjust_endianness(mr, &ret, size); - return ret; + *pval = memory_region_dispatch_read1(mr, addr, size); + adjust_endianness(mr, pval, size); + return false; } -static void memory_region_dispatch_write(MemoryRegion *mr, +static bool memory_region_dispatch_write(MemoryRegion *mr, hwaddr addr, uint64_t data, unsigned size) { if (!memory_region_access_valid(mr, addr, size, true)) { - return; /* FIXME: better signalling */ + unassigned_mem_write(mr, addr, data, size); + return true; } adjust_endianness(mr, &data, size); - if (!mr->ops->write) { - mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, data); - return; + if (mr->ops->write) { + access_with_adjusted_size(addr, &data, size, + mr->ops->impl.min_access_size, + mr->ops->impl.max_access_size, + memory_region_write_accessor, mr); + } else { + access_with_adjusted_size(addr, &data, size, 1, 4, + memory_region_oldmmio_write_accessor, mr); } - - /* FIXME: support unaligned access */ - access_with_adjusted_size(addr, &data, size, - mr->ops->impl.min_access_size, - mr->ops->impl.max_access_size, - memory_region_write_accessor, mr); + return false; } void memory_region_init_io(MemoryRegion *mr, @@ -977,40 +1063,11 @@ void memory_region_init_rom_device(MemoryRegion *mr, mr->ram_addr = qemu_ram_alloc(size, mr); } -static uint64_t invalid_read(void *opaque, hwaddr addr, - unsigned size) -{ - MemoryRegion *mr = opaque; - - if (!mr->warning_printed) { - fprintf(stderr, "Invalid read from memory region %s\n", mr->name); - mr->warning_printed = true; - } - return -1U; -} - -static void invalid_write(void *opaque, hwaddr addr, uint64_t data, - unsigned size) -{ - MemoryRegion *mr = opaque; - - if (!mr->warning_printed) { - fprintf(stderr, "Invalid write to memory region %s\n", mr->name); - mr->warning_printed = true; - } -} - -static const MemoryRegionOps reservation_ops = { - .read = invalid_read, - .write = invalid_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - void memory_region_init_reservation(MemoryRegion *mr, const char *name, uint64_t size) { - memory_region_init_io(mr, &reservation_ops, mr, name, size); + memory_region_init_io(mr, &unassigned_mem_ops, mr, name, size); } void memory_region_destroy(MemoryRegion *mr) @@ -1594,15 +1651,15 @@ void address_space_destroy(AddressSpace *as) g_free(as->ioeventfds); } -uint64_t io_mem_read(MemoryRegion *mr, hwaddr addr, unsigned size) +bool io_mem_read(MemoryRegion *mr, hwaddr addr, uint64_t *pval, unsigned size) { - return memory_region_dispatch_read(mr, addr, size); + return memory_region_dispatch_read(mr, addr, pval, size); } -void io_mem_write(MemoryRegion *mr, hwaddr addr, +bool io_mem_write(MemoryRegion *mr, hwaddr addr, uint64_t val, unsigned size) { - memory_region_dispatch_write(mr, addr, val, size); + return memory_region_dispatch_write(mr, addr, val, size); } typedef struct MemoryRegionList MemoryRegionList; diff --git a/migration.c b/migration.c index bfbc34544a..058f9e69f4 100644 --- a/migration.c +++ b/migration.c @@ -349,7 +349,6 @@ static MigrationState *migrate_init(const MigrationParams *params) sizeof(enabled_capabilities)); memset(s, 0, sizeof(*s)); - s->bandwidth_limit = bandwidth_limit; s->params = *params; memcpy(s->enabled_capabilities, enabled_capabilities, sizeof(enabled_capabilities)); @@ -280,7 +280,7 @@ void monitor_flush(Monitor *mon) buf = qstring_get_str(mon->outbuf); len = qstring_get_length(mon->outbuf); - if (mon && len && !mon->mux_out) { + if (len && !mon->mux_out) { rc = qemu_chr_fe_write(mon->chr, (const uint8_t *) buf, len); if (rc == len) { /* all flushed */ diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex ec9eeb12c6..c2a19b8930 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index 5b9e1dc107..f438af15aa 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -114,8 +114,13 @@ static void vring_init(struct vring *vr, unsigned int num, void *p, vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1) & ~(align - 1)); + /* Zero out all relevant field */ + vr->avail->flags = 0; + vr->avail->idx = 0; + /* We're running with interrupts off anyways, so don't bother */ vr->used->flags = VRING_USED_F_NO_NOTIFY; + vr->used->idx = 0; debug_print_addr("init vr", vr); } diff --git a/po/hu.po b/po/hu.po new file mode 100644 index 0000000000..debba96923 --- /dev/null +++ b/po/hu.po @@ -0,0 +1,63 @@ +# Hungarian translation for QEMU. +# This file is put in the public domain. +# Ákos Kovács <akoskovacs@gmx.com>, 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: QEMU 1.4.50\n" +"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" +"POT-Creation-Date: 2013-05-06 20:42+0200\n" +"PO-Revision-Date: 2013-05-06 20:42+0200\n" +"Last-Translator: Ákos Kovács <akoskovacs@gmx.com>\n" +"Language-Team: Hungarian <hu@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../ui/gtk.c:213 +msgid " - Press Ctrl+Alt+G to release grab" +msgstr " - Nyomj Ctrl+Alt+G-t a bemeneti eszközök elengedéséhez" + +#: ../ui/gtk.c:217 +msgid " [Paused]" +msgstr " [Megállítva]" + +#: ../ui/gtk.c:1250 +msgid "_Machine" +msgstr "_Gép" + +#: ../ui/gtk.c:1252 +msgid "_Pause" +msgstr "_Megállítás" + +#: ../ui/gtk.c:1258 +msgid "_Reset" +msgstr "Új_raindítás" + +#: ../ui/gtk.c:1261 +msgid "Power _Down" +msgstr "_Leállítás" + +#: ../ui/gtk.c:1276 +msgid "_View" +msgstr "_Nézet" + +#: ../ui/gtk.c:1306 +msgid "Zoom To _Fit" +msgstr "Ablakmérethez _igazítás" + +#: ../ui/gtk.c:1312 +msgid "Grab On _Hover" +msgstr "Automatikus _elfogás" + +#: ../ui/gtk.c:1315 +msgid "_Grab Input" +msgstr "_Bemeneti eszközök megragadása" + +#: ../ui/gtk.c:1341 +msgid "Show _Tabs" +msgstr "_Fülek megjelenítése" + +#~ msgid "_File" +#~ msgstr "_File" diff --git a/qemu-char.c b/qemu-char.c index 4f8382e540..d04b429a03 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3276,7 +3276,6 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, ChardevReturn *ret = NULL; const char *id = qemu_opts_id(opts); const char *bid = NULL; - char *filename = g_strdup(qemu_opt_get(opts, "backend")); if (qemu_opt_get_bool(opts, "mux", 0)) { bid = g_strdup_printf("%s-base", id); @@ -3309,7 +3308,6 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, } chr = qemu_chr_find(id); - chr->filename = filename; qapi_out: qapi_free_ChardevBackend(backend); @@ -3803,6 +3801,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, chr->label = g_strdup(id); chr->avail_connections = (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1; + if (!chr->filename) { + chr->filename = g_strdup(ChardevBackendKind_lookup[backend->kind]); + } QTAILQ_INSERT_TAIL(&chardevs, chr, next); return ret; } else { diff --git a/qemu-img.c b/qemu-img.c index cd096a1361..82c7977353 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -30,6 +30,7 @@ #include "qemu/osdep.h" #include "sysemu/sysemu.h" #include "block/block_int.h" +#include "block/qapi.h" #include <getopt.h> #include <stdio.h> #include <stdarg.h> @@ -1553,16 +1554,17 @@ static void dump_snapshots(BlockDriverState *bs) { QEMUSnapshotInfo *sn_tab, *sn; int nb_sns, i; - char buf[256]; nb_sns = bdrv_snapshot_list(bs, &sn_tab); if (nb_sns <= 0) return; printf("Snapshot list:\n"); - printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); + bdrv_snapshot_dump(fprintf, stdout, NULL); + printf("\n"); for(i = 0; i < nb_sns; i++) { sn = &sn_tab[i]; - printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); + bdrv_snapshot_dump(fprintf, stdout, sn); + printf("\n"); } g_free(sn_tab); } @@ -1584,39 +1586,6 @@ static void dump_json_image_info_list(ImageInfoList *list) QDECREF(str); } -static void collect_snapshots(BlockDriverState *bs , ImageInfo *info) -{ - int i, sn_count; - QEMUSnapshotInfo *sn_tab = NULL; - SnapshotInfoList *info_list, *cur_item = NULL; - sn_count = bdrv_snapshot_list(bs, &sn_tab); - - for (i = 0; i < sn_count; i++) { - info->has_snapshots = true; - info_list = g_new0(SnapshotInfoList, 1); - - info_list->value = g_new0(SnapshotInfo, 1); - info_list->value->id = g_strdup(sn_tab[i].id_str); - info_list->value->name = g_strdup(sn_tab[i].name); - info_list->value->vm_state_size = sn_tab[i].vm_state_size; - info_list->value->date_sec = sn_tab[i].date_sec; - info_list->value->date_nsec = sn_tab[i].date_nsec; - info_list->value->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; - info_list->value->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; - - /* XXX: waiting for the qapi to support qemu-queue.h types */ - if (!cur_item) { - info->snapshots = cur_item = info_list; - } else { - cur_item->next = info_list; - cur_item = info_list; - } - - } - - g_free(sn_tab); -} - static void dump_json_image_info(ImageInfo *info) { Error *errp = NULL; @@ -1634,122 +1603,6 @@ static void dump_json_image_info(ImageInfo *info) QDECREF(str); } -static void collect_image_info(BlockDriverState *bs, - ImageInfo *info, - const char *filename, - const char *fmt) -{ - uint64_t total_sectors; - char backing_filename[1024]; - char backing_filename2[1024]; - BlockDriverInfo bdi; - - bdrv_get_geometry(bs, &total_sectors); - - info->filename = g_strdup(filename); - info->format = g_strdup(bdrv_get_format_name(bs)); - info->virtual_size = total_sectors * 512; - info->actual_size = bdrv_get_allocated_file_size(bs); - info->has_actual_size = info->actual_size >= 0; - if (bdrv_is_encrypted(bs)) { - info->encrypted = true; - info->has_encrypted = true; - } - if (bdrv_get_info(bs, &bdi) >= 0) { - if (bdi.cluster_size != 0) { - info->cluster_size = bdi.cluster_size; - info->has_cluster_size = true; - } - info->dirty_flag = bdi.is_dirty; - info->has_dirty_flag = true; - } - bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); - if (backing_filename[0] != '\0') { - info->backing_filename = g_strdup(backing_filename); - info->has_backing_filename = true; - bdrv_get_full_backing_filename(bs, backing_filename2, - sizeof(backing_filename2)); - - if (strcmp(backing_filename, backing_filename2) != 0) { - info->full_backing_filename = - g_strdup(backing_filename2); - info->has_full_backing_filename = true; - } - - if (bs->backing_format[0]) { - info->backing_filename_format = g_strdup(bs->backing_format); - info->has_backing_filename_format = true; - } - } -} - -static void dump_human_image_info(ImageInfo *info) -{ - char size_buf[128], dsize_buf[128]; - if (!info->has_actual_size) { - snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); - } else { - get_human_readable_size(dsize_buf, sizeof(dsize_buf), - info->actual_size); - } - get_human_readable_size(size_buf, sizeof(size_buf), info->virtual_size); - printf("image: %s\n" - "file format: %s\n" - "virtual size: %s (%" PRId64 " bytes)\n" - "disk size: %s\n", - info->filename, info->format, size_buf, - info->virtual_size, - dsize_buf); - - if (info->has_encrypted && info->encrypted) { - printf("encrypted: yes\n"); - } - - if (info->has_cluster_size) { - printf("cluster_size: %" PRId64 "\n", info->cluster_size); - } - - if (info->has_dirty_flag && info->dirty_flag) { - printf("cleanly shut down: no\n"); - } - - if (info->has_backing_filename) { - printf("backing file: %s", info->backing_filename); - if (info->has_full_backing_filename) { - printf(" (actual path: %s)", info->full_backing_filename); - } - putchar('\n'); - if (info->has_backing_filename_format) { - printf("backing file format: %s\n", info->backing_filename_format); - } - } - - if (info->has_snapshots) { - SnapshotInfoList *elem; - char buf[256]; - - printf("Snapshot list:\n"); - printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); - - /* Ideally bdrv_snapshot_dump() would operate on SnapshotInfoList but - * we convert to the block layer's native QEMUSnapshotInfo for now. - */ - for (elem = info->snapshots; elem; elem = elem->next) { - QEMUSnapshotInfo sn = { - .vm_state_size = elem->value->vm_state_size, - .date_sec = elem->value->date_sec, - .date_nsec = elem->value->date_nsec, - .vm_clock_nsec = elem->value->vm_clock_sec * 1000000000ULL + - elem->value->vm_clock_nsec, - }; - - pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id); - pstrcpy(sn.name, sizeof(sn.name), elem->value->name); - printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), &sn)); - } - } -} - static void dump_human_image_info_list(ImageInfoList *list) { ImageInfoList *elem; @@ -1761,7 +1614,7 @@ static void dump_human_image_info_list(ImageInfoList *list) } delim = true; - dump_human_image_info(elem->value); + bdrv_image_info_dump(fprintf, stdout, elem->value); } } @@ -1811,8 +1664,8 @@ static ImageInfoList *collect_image_info_list(const char *filename, } info = g_new0(ImageInfo, 1); - collect_image_info(bs, info, filename, fmt); - collect_snapshots(bs, info); + bdrv_collect_image_info(bs, info, filename); + bdrv_collect_snapshots(bs, info); elem = g_new0(ImageInfoList, 1); elem->value = info; diff --git a/qemu-seccomp.c b/qemu-seccomp.c index 031da1dfee..ca123bfeba 100644 --- a/qemu-seccomp.c +++ b/qemu-seccomp.c @@ -87,6 +87,7 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(stat), 245 }, { SCMP_SYS(uname), 245 }, { SCMP_SYS(eventfd2), 245 }, + { SCMP_SYS(io_getevents), 245 }, { SCMP_SYS(dup), 245 }, { SCMP_SYS(dup2), 245 }, { SCMP_SYS(dup3), 245 }, @@ -229,7 +230,9 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(sendmmsg), 241 }, { SCMP_SYS(recvmmsg), 241 }, { SCMP_SYS(prlimit64), 241 }, - { SCMP_SYS(waitid), 241 } + { SCMP_SYS(waitid), 241 }, + { SCMP_SYS(io_setup), 241 }, + { SCMP_SYS(io_destroy), 241 } }; int seccomp_start(void) diff --git a/qga/main.c b/qga/main.c index 44a283686b..0e04e7395c 100644 --- a/qga/main.c +++ b/qga/main.c @@ -45,16 +45,21 @@ #ifndef _WIN32 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0" +#define QGA_STATE_RELATIVE_DIR "run" #else #define QGA_VIRTIO_PATH_DEFAULT "\\\\.\\Global\\org.qemu.guest_agent.0" +#define QGA_STATE_RELATIVE_DIR "qemu-ga" #endif -#define QGA_STATEDIR_DEFAULT CONFIG_QEMU_LOCALSTATEDIR "/run" -#define QGA_PIDFILE_DEFAULT QGA_STATEDIR_DEFAULT "/qemu-ga.pid" #ifdef CONFIG_FSFREEZE #define QGA_FSFREEZE_HOOK_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze-hook" #endif #define QGA_SENTINEL_BYTE 0xFF +static struct { + const char *state_dir; + const char *pidfile; +} dfl_pathnames; + typedef struct GAPersistentState { #define QGA_PSTATE_DEFAULT_FD_COUNTER 1000 int64_t fd_counter; @@ -106,6 +111,17 @@ DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data, VOID WINAPI service_main(DWORD argc, TCHAR *argv[]); #endif +static void +init_dfl_pathnames(void) +{ + g_assert(dfl_pathnames.state_dir == NULL); + g_assert(dfl_pathnames.pidfile == NULL); + dfl_pathnames.state_dir = qemu_get_local_state_pathname( + QGA_STATE_RELATIVE_DIR); + dfl_pathnames.pidfile = qemu_get_local_state_pathname( + QGA_STATE_RELATIVE_DIR G_DIR_SEPARATOR_S "qemu-ga.pid"); +} + static void quit_handler(int sig) { /* if we're frozen, don't exit unless we're absolutely forced to, @@ -198,11 +214,11 @@ static void usage(const char *cmd) " -h, --help display this help and exit\n" "\n" "Report bugs to <mdroth@linux.vnet.ibm.com>\n" - , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT, + , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, dfl_pathnames.pidfile, #ifdef CONFIG_FSFREEZE QGA_FSFREEZE_HOOK_DEFAULT, #endif - QGA_STATEDIR_DEFAULT); + dfl_pathnames.state_dir); } static const char *ga_log_level_str(GLogLevelFlags level) @@ -908,11 +924,11 @@ int main(int argc, char **argv) const char *sopt = "hVvdm:p:l:f:F::b:s:t:"; const char *method = NULL, *path = NULL; const char *log_filepath = NULL; - const char *pid_filepath = QGA_PIDFILE_DEFAULT; + const char *pid_filepath; #ifdef CONFIG_FSFREEZE const char *fsfreeze_hook = NULL; #endif - const char *state_dir = QGA_STATEDIR_DEFAULT; + const char *state_dir; #ifdef _WIN32 const char *service = NULL; #endif @@ -942,6 +958,10 @@ int main(int argc, char **argv) module_call_init(MODULE_INIT_QAPI); + init_dfl_pathnames(); + pid_filepath = dfl_pathnames.pidfile; + state_dir = dfl_pathnames.state_dir; + while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { switch (ch) { case 'm': @@ -1002,7 +1022,16 @@ int main(int argc, char **argv) case 's': service = optarg; if (strcmp(service, "install") == 0) { - return ga_install_service(path, log_filepath); + const char *fixed_state_dir; + + /* If the user passed the "-t" option, we save that state dir + * in the service. Otherwise we let the service fetch the state + * dir from the environment when it starts. + */ + fixed_state_dir = (state_dir == dfl_pathnames.state_dir) ? + NULL : + state_dir; + return ga_install_service(path, log_filepath, fixed_state_dir); } else if (strcmp(service, "uninstall") == 0) { return ga_uninstall_service(); } else { @@ -1021,6 +1050,20 @@ int main(int argc, char **argv) } } +#ifdef _WIN32 + /* On win32 the state directory is application specific (be it the default + * or a user override). We got past the command line parsing; let's create + * the directory (with any intermediate directories). If we run into an + * error later on, we won't try to clean up the directory, it is considered + * persistent. + */ + if (g_mkdir_with_parents(state_dir, S_IRWXU) == -1) { + g_critical("unable to create (an ancestor of) the state directory" + " '%s': %s", state_dir, strerror(errno)); + return EXIT_FAILURE; + } +#endif + s = g_malloc0(sizeof(GAState)); s->log_level = log_level; s->log_file = stderr; diff --git a/qga/service-win32.c b/qga/service-win32.c index 843398a6c6..02926abb28 100644 --- a/qga/service-win32.c +++ b/qga/service-win32.c @@ -35,38 +35,44 @@ static int printf_win_error(const char *text) return n; } -int ga_install_service(const char *path, const char *logfile) +int ga_install_service(const char *path, const char *logfile, + const char *state_dir) { SC_HANDLE manager; SC_HANDLE service; - TCHAR cmdline[MAX_PATH]; + TCHAR module_fname[MAX_PATH]; + GString *cmdline; - if (GetModuleFileName(NULL, cmdline, MAX_PATH) == 0) { + if (GetModuleFileName(NULL, module_fname, MAX_PATH) == 0) { printf_win_error("No full path to service's executable"); return EXIT_FAILURE; } - _snprintf(cmdline, MAX_PATH - strlen(cmdline), "%s -d", cmdline); + cmdline = g_string_new(module_fname); + g_string_append(cmdline, " -d"); if (path) { - _snprintf(cmdline, MAX_PATH - strlen(cmdline), "%s -p %s", cmdline, path); + g_string_append_printf(cmdline, " -p %s", path); } if (logfile) { - _snprintf(cmdline, MAX_PATH - strlen(cmdline), "%s -l %s -v", - cmdline, logfile); + g_string_append_printf(cmdline, " -l %s -v", logfile); + } + if (state_dir) { + g_string_append_printf(cmdline, " -t %s", state_dir); } - g_debug("service's cmdline: %s", cmdline); + g_debug("service's cmdline: %s", cmdline->str); manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (manager == NULL) { printf_win_error("No handle to service control manager"); + g_string_free(cmdline, TRUE); return EXIT_FAILURE; } service = CreateService(manager, QGA_SERVICE_NAME, QGA_SERVICE_DISPLAY_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, - SERVICE_ERROR_NORMAL, cmdline, NULL, NULL, NULL, NULL, NULL); + SERVICE_ERROR_NORMAL, cmdline->str, NULL, NULL, NULL, NULL, NULL); if (service) { SERVICE_DESCRIPTION desc = { (char *)QGA_SERVICE_DESCRIPTION }; @@ -80,6 +86,7 @@ int ga_install_service(const char *path, const char *logfile) CloseServiceHandle(service); CloseServiceHandle(manager); + g_string_free(cmdline, TRUE); return (service == NULL); } diff --git a/qga/service-win32.h b/qga/service-win32.h index 99dfc53348..3b9e87024b 100644 --- a/qga/service-win32.h +++ b/qga/service-win32.h @@ -24,7 +24,8 @@ typedef struct GAService { SERVICE_STATUS_HANDLE status_handle; } GAService; -int ga_install_service(const char *path, const char *logfile); +int ga_install_service(const char *path, const char *logfile, + const char *state_dir); int ga_uninstall_service(void); #endif diff --git a/roms/configure-seabios.sh b/roms/configure-seabios.sh index 4bb6c2b90f..98f59a24ba 100755 --- a/roms/configure-seabios.sh +++ b/roms/configure-seabios.sh @@ -2,4 +2,4 @@ config="$1" make -C seabios clean distclean cp "$config" seabios/.config -make -C seabios olddefconfig +make -C seabios oldnoconfig diff --git a/roms/seabios b/roms/seabios -Subproject 88cb66ea542906ffff8a80ef397b9e3adbb3311 +Subproject d4f7d90f47462b4e8836899adc5060fbde5253e @@ -40,6 +40,8 @@ #include "trace.h" #include "qemu/bitops.h" #include "qemu/iov.h" +#include "block/snapshot.h" +#include "block/qapi.h" #define SELF_ANNOUNCE_ROUNDS 5 @@ -322,13 +324,13 @@ QEMUFile *qemu_popen_cmd(const char *command, const char *mode) FILE *stdio_file; QEMUFileStdio *s; - stdio_file = popen(command, mode); - if (stdio_file == NULL) { + if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { + fprintf(stderr, "qemu_popen: Argument validity check failed\n"); return NULL; } - if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { - fprintf(stderr, "qemu_popen: Argument validity check failed\n"); + stdio_file = popen(command, mode); + if (stdio_file == NULL) { return NULL; } @@ -2262,26 +2264,15 @@ out: return ret; } -static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, - const char *name) +static BlockDriverState *find_vmstate_bs(void) { - QEMUSnapshotInfo *sn_tab, *sn; - int nb_sns, i, ret; - - ret = -ENOENT; - nb_sns = bdrv_snapshot_list(bs, &sn_tab); - if (nb_sns < 0) - return ret; - for(i = 0; i < nb_sns; i++) { - sn = &sn_tab[i]; - if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { - *sn_info = *sn; - ret = 0; - break; + BlockDriverState *bs = NULL; + while ((bs = bdrv_next(bs))) { + if (bdrv_can_snapshot(bs)) { + return bs; } } - g_free(sn_tab); - return ret; + return NULL; } /* @@ -2338,7 +2329,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) } } - bs = bdrv_snapshots(); + bs = find_vmstate_bs(); if (!bs) { monitor_printf(mon, "No block device can accept snapshots\n"); return; @@ -2440,7 +2431,7 @@ int load_vmstate(const char *name) QEMUFile *f; int ret; - bs_vm_state = bdrv_snapshots(); + bs_vm_state = find_vmstate_bs(); if (!bs_vm_state) { error_report("No block device supports snapshots"); return -ENOTSUP; @@ -2519,7 +2510,7 @@ void do_delvm(Monitor *mon, const QDict *qdict) int ret; const char *name = qdict_get_str(qdict, "name"); - bs = bdrv_snapshots(); + bs = find_vmstate_bs(); if (!bs) { monitor_printf(mon, "No block device supports snapshots\n"); return; @@ -2549,9 +2540,8 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict) int nb_sns, i, ret, available; int total; int *available_snapshots; - char buf[256]; - bs = bdrv_snapshots(); + bs = find_vmstate_bs(); if (!bs) { monitor_printf(mon, "No available block device supports snapshots\n"); return; @@ -2592,10 +2582,12 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict) } if (total > 0) { - monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); + bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL); + monitor_printf(mon, "\n"); for (i = 0; i < total; i++) { sn = &sn_tab[available_snapshots[i]]; - monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); + bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn); + monitor_printf(mon, "\n"); } } else { monitor_printf(mon, "There is no suitable snapshot available\n"); diff --git a/scripts/create_config b/scripts/create_config index c471e8caf9..258513a887 100755 --- a/scripts/create_config +++ b/scripts/create_config @@ -34,8 +34,15 @@ case $line in done echo "" ;; - CONFIG_BDRV_WHITELIST=*) - echo "#define CONFIG_BDRV_WHITELIST \\" + CONFIG_BDRV_RW_WHITELIST=*) + echo "#define CONFIG_BDRV_RW_WHITELIST\\" + for drv in ${line#*=}; do + echo " \"${drv}\",\\" + done + echo " NULL" + ;; + CONFIG_BDRV_RO_WHITELIST=*) + echo "#define CONFIG_BDRV_RO_WHITELIST\\" for drv in ${line#*=}; do echo " \"${drv}\",\\" done diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index fd42d71da1..ddcfed9f4b 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -22,7 +22,10 @@ def generate_fwd_struct(name, members, builtin_type=False): typedef struct %(name)sList { - %(type)s value; + union { + %(type)s value; + uint64_t padding; + }; struct %(name)sList *next; } %(name)sList; ''', @@ -35,7 +38,10 @@ typedef struct %(name)s %(name)s; typedef struct %(name)sList { - %(name)s *value; + union { + %(name)s *value; + uint64_t padding; + }; struct %(name)sList *next; } %(name)sList; ''', diff --git a/slirp/misc.h b/slirp/misc.h index cc36aeb959..ba8beb1b17 100644 --- a/slirp/misc.h +++ b/slirp/misc.h @@ -20,8 +20,6 @@ struct ex_list { char *strdup(const char *); #endif -void do_wait(int); - #define EMU_NONE 0x0 /* TCP emulations */ @@ -51,21 +49,9 @@ struct emu_t { struct emu_t *next; }; -extern int x_port, x_server, x_display; - -int show_x(char *, struct socket *); -void redir_x(uint32_t, int, int, int); void slirp_insque(void *, void *); void slirp_remque(void *); int add_exec(struct ex_list **, int, char *, struct in_addr, int); -int slirp_openpty(int *, int *); int fork_exec(struct socket *so, const char *ex, int do_pty); -void snooze_hup(int); -void snooze(void); -void relay(int); -void add_emu(char *); -void fd_nonblock(int); -void fd_block(int); -int rsh_exec(struct socket *, struct socket *, char *, char *, char *); #endif diff --git a/target-arm/translate.c b/target-arm/translate.c index 71135bdef1..b3f26d6205 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9916,7 +9916,6 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, invalidate this TB. */ dc->pc += 2; goto done_generating; - break; } } } diff --git a/target-i386/arch_memory_mapping.c b/target-i386/arch_memory_mapping.c index 844893f44d..5096fbdf44 100644 --- a/target-i386/arch_memory_mapping.c +++ b/target-i386/arch_memory_mapping.c @@ -38,7 +38,7 @@ static void walk_pte(MemoryMappingList *list, hwaddr pte_start_addr, continue; } - start_vaddr = start_line_addr | ((i & 0x1fff) << 12); + start_vaddr = start_line_addr | ((i & 0x1ff) << 12); memory_mapping_list_add_merge_sorted(list, start_paddr, start_vaddr, 1 << 12); } @@ -75,6 +75,8 @@ static void walk_pte2(MemoryMappingList *list, } /* PAE Paging or IA-32e Paging */ +#define PLM4_ADDR_MASK 0xffffffffff000 /* selects bits 51:12 */ + static void walk_pde(MemoryMappingList *list, hwaddr pde_start_addr, int32_t a20_mask, target_ulong start_line_addr) { @@ -105,7 +107,7 @@ static void walk_pde(MemoryMappingList *list, hwaddr pde_start_addr, continue; } - pte_start_addr = (pde & ~0xfff) & a20_mask; + pte_start_addr = (pde & PLM4_ADDR_MASK) & a20_mask; walk_pte(list, pte_start_addr, a20_mask, line_addr); } } @@ -208,7 +210,7 @@ static void walk_pdpe(MemoryMappingList *list, continue; } - pde_start_addr = (pdpe & ~0xfff) & a20_mask; + pde_start_addr = (pdpe & PLM4_ADDR_MASK) & a20_mask; walk_pde(list, pde_start_addr, a20_mask, line_addr); } } @@ -231,7 +233,7 @@ static void walk_pml4e(MemoryMappingList *list, } line_addr = ((i & 0x1ffULL) << 39) | (0xffffULL << 48); - pdpe_start_addr = (pml4e & ~0xfff) & a20_mask; + pdpe_start_addr = (pml4e & PLM4_ADDR_MASK) & a20_mask; walk_pdpe(list, pdpe_start_addr, a20_mask, line_addr); } } @@ -249,7 +251,7 @@ int cpu_get_memory_mapping(MemoryMappingList *list, CPUArchState *env) if (env->hflags & HF_LMA_MASK) { hwaddr pml4e_addr; - pml4e_addr = (env->cr[3] & ~0xfff) & env->a20_mask; + pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask; walk_pml4e(list, pml4e_addr, env->a20_mask); } else #endif diff --git a/target-i386/translate.c b/target-i386/translate.c index 0aeccdbc59..14b0298749 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4677,8 +4677,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } s->pc = pc_start; prefixes = 0; - aflag = s->code32; - dflag = s->code32; s->override = -1; rex_w = -1; rex_r = 0; @@ -4801,23 +4799,25 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } /* Post-process prefixes. */ - if (prefixes & PREFIX_DATA) { - dflag ^= 1; - } - if (prefixes & PREFIX_ADR) { - aflag ^= 1; - } -#ifdef TARGET_X86_64 if (CODE64(s)) { - if (rex_w == 1) { - /* 0x66 is ignored if rex.w is set */ - dflag = 2; + /* In 64-bit mode, the default data size is 32-bit. Select 64-bit + data with rex_w, and 16-bit data with 0x66; rex_w takes precedence + over 0x66 if both are present. */ + dflag = (rex_w > 0 ? 2 : prefixes & PREFIX_DATA ? 0 : 1); + /* In 64-bit mode, 0x67 selects 32-bit addressing. */ + aflag = (prefixes & PREFIX_ADR ? 1 : 2); + } else { + /* In 16/32-bit mode, 0x66 selects the opposite data size. */ + dflag = s->code32; + if (prefixes & PREFIX_DATA) { + dflag ^= 1; } - if (!(prefixes & PREFIX_ADR)) { - aflag = 2; + /* In 16/32-bit mode, 0x67 selects the opposite addressing. */ + aflag = s->code32; + if (prefixes & PREFIX_ADR) { + aflag ^= 1; } } -#endif s->prefix = prefixes; s->aflag = aflag; diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 02bc432ce7..1422ae97a8 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -515,7 +515,6 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, break; default: goto abort; - break; } } else if ((insn & 0xff00) == 0x0a00) { /* supervisor call */ diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index 151e35e6bb..3dc7856e22 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -1933,7 +1933,6 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env, invalidate this TB. */ dc->pc += 2; /* FIXME */ goto done_generating; - break; } } } diff --git a/tests/Makefile b/tests/Makefile index a307d5a952..c107489f44 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -171,6 +171,7 @@ GCOV_OPTIONS = -n $(if $(V),-f,) $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y) $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ + MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@") $(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \ echo Gcov report for $$f:;\ @@ -180,7 +181,9 @@ $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y) .PHONY: $(patsubst %, check-%, $(check-unit-y)) $(patsubst %, check-%, $(check-unit-y)): check-%: % $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,) - $(call quiet-command,gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*") + $(call quiet-command, \ + MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ + gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*") $(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y); do \ echo Gcov report for $$f:;\ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index dd4ef11996..ae56f3b808 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -22,49 +22,16 @@ import time import os import iotests from iotests import qemu_img, qemu_io -import struct backing_img = os.path.join(iotests.test_dir, 'backing.img') mid_img = os.path.join(iotests.test_dir, 'mid.img') test_img = os.path.join(iotests.test_dir, 'test.img') -class ImageStreamingTestCase(iotests.QMPTestCase): - '''Abstract base class for image streaming test cases''' - - def assert_no_active_streams(self): - result = self.vm.qmp('query-block-jobs') - self.assert_qmp(result, 'return', []) - - def cancel_and_wait(self, drive='drive0'): - '''Cancel a block job and wait for it to finish''' - result = self.vm.qmp('block-job-cancel', device=drive) - self.assert_qmp(result, 'return', {}) - - cancelled = False - while not cancelled: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_CANCELLED': - self.assert_qmp(event, 'data/type', 'stream') - self.assert_qmp(event, 'data/device', drive) - cancelled = True - - self.assert_no_active_streams() - - def create_image(self, name, size): - file = open(name, 'w') - i = 0 - while i < size: - sector = struct.pack('>l504xl', i / 512, i / 512) - file.write(sector) - i = i + 512 - file.close() - - -class TestSingleDrive(ImageStreamingTestCase): +class TestSingleDrive(iotests.QMPTestCase): image_len = 1 * 1024 * 1024 # MB def setUp(self): - self.create_image(backing_img, TestSingleDrive.image_len) + 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) self.vm = iotests.VM().add_drive(test_img) @@ -77,7 +44,7 @@ class TestSingleDrive(ImageStreamingTestCase): os.remove(backing_img) def test_stream(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) @@ -92,7 +59,7 @@ class TestSingleDrive(ImageStreamingTestCase): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() self.assertEqual(qemu_io('-c', 'map', backing_img), @@ -100,7 +67,7 @@ class TestSingleDrive(ImageStreamingTestCase): 'image file map does not match backing file after streaming') def test_stream_pause(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) @@ -129,7 +96,7 @@ class TestSingleDrive(ImageStreamingTestCase): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() self.assertEqual(qemu_io('-c', 'map', backing_img), @@ -137,7 +104,7 @@ class TestSingleDrive(ImageStreamingTestCase): 'image file map does not match backing file after streaming') def test_stream_partial(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0', base=mid_img) self.assert_qmp(result, 'return', {}) @@ -152,7 +119,7 @@ class TestSingleDrive(ImageStreamingTestCase): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() self.assertEqual(qemu_io('-c', 'map', mid_img), @@ -164,12 +131,12 @@ class TestSingleDrive(ImageStreamingTestCase): self.assert_qmp(result, 'error/class', 'DeviceNotFound') -class TestSmallerBackingFile(ImageStreamingTestCase): +class TestSmallerBackingFile(iotests.QMPTestCase): backing_len = 1 * 1024 * 1024 # MB image_len = 2 * backing_len def setUp(self): - self.create_image(backing_img, self.backing_len) + iotests.create_image(backing_img, self.backing_len) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len)) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -177,7 +144,7 @@ class TestSmallerBackingFile(ImageStreamingTestCase): # If this hangs, then you are missing a fix to complete streaming when the # end of the backing file is reached. def test_stream(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) @@ -192,10 +159,10 @@ class TestSmallerBackingFile(ImageStreamingTestCase): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() -class TestErrors(ImageStreamingTestCase): +class TestErrors(iotests.QMPTestCase): image_len = 2 * 1024 * 1024 # MB # this should match STREAM_BUFFER_SIZE/512 in block/stream.c @@ -227,7 +194,7 @@ new_state = "1" class TestEIO(TestErrors): def setUp(self): self.blkdebug_file = backing_img + ".blkdebug" - self.create_image(backing_img, TestErrors.image_len) + iotests.create_image(backing_img, TestErrors.image_len) self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' @@ -243,7 +210,7 @@ class TestEIO(TestErrors): os.remove(self.blkdebug_file) def test_report(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) @@ -265,11 +232,11 @@ class TestEIO(TestErrors): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() def test_ignore(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0', on_error='ignore') self.assert_qmp(result, 'return', {}) @@ -293,11 +260,11 @@ class TestEIO(TestErrors): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() def test_stop(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0', on_error='stop') self.assert_qmp(result, 'return', {}) @@ -331,11 +298,11 @@ class TestEIO(TestErrors): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() def test_enospc(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') self.assert_qmp(result, 'return', {}) @@ -357,13 +324,13 @@ class TestEIO(TestErrors): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() class TestENOSPC(TestErrors): def setUp(self): self.blkdebug_file = backing_img + ".blkdebug" - self.create_image(backing_img, TestErrors.image_len) + iotests.create_image(backing_img, TestErrors.image_len) self.create_blkdebug_file(self.blkdebug_file, "read_aio", 28) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' @@ -379,7 +346,7 @@ class TestENOSPC(TestErrors): os.remove(self.blkdebug_file) def test_enospc(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') self.assert_qmp(result, 'return', {}) @@ -413,10 +380,10 @@ class TestENOSPC(TestErrors): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() self.vm.shutdown() -class TestStreamStop(ImageStreamingTestCase): +class TestStreamStop(iotests.QMPTestCase): image_len = 8 * 1024 * 1024 * 1024 # GB def setUp(self): @@ -431,7 +398,7 @@ class TestStreamStop(ImageStreamingTestCase): os.remove(backing_img) def test_stream_stop(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) @@ -442,7 +409,7 @@ class TestStreamStop(ImageStreamingTestCase): self.cancel_and_wait() -class TestSetSpeed(ImageStreamingTestCase): +class TestSetSpeed(iotests.QMPTestCase): image_len = 80 * 1024 * 1024 # MB def setUp(self): @@ -459,7 +426,7 @@ class TestSetSpeed(ImageStreamingTestCase): # This is a short performance test which is not run by default. # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" def perf_test_throughput(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) @@ -477,10 +444,10 @@ class TestSetSpeed(ImageStreamingTestCase): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_streams() + self.assert_no_active_block_jobs() def test_set_speed(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) @@ -511,12 +478,12 @@ class TestSetSpeed(ImageStreamingTestCase): self.cancel_and_wait() def test_set_speed_invalid(self): - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0', speed=-1) self.assert_qmp(result, 'error/class', 'GenericError') - self.assert_no_active_streams() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 720eeff921..1e923e70ca 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -22,7 +22,6 @@ import time import os import iotests from iotests import qemu_img, qemu_io -import struct backing_img = os.path.join(iotests.test_dir, 'backing.img') target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img') @@ -32,50 +31,28 @@ target_img = os.path.join(iotests.test_dir, 'target.img') class ImageMirroringTestCase(iotests.QMPTestCase): '''Abstract base class for image mirroring test cases''' - def assert_no_active_mirrors(self): - result = self.vm.qmp('query-block-jobs') - self.assert_qmp(result, 'return', []) - - def cancel_and_wait(self, drive='drive0', wait_ready=True): - '''Cancel a block job and wait for it to finish''' - if wait_ready: - ready = False - while not ready: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_READY': - self.assert_qmp(event, 'data/type', 'mirror') - self.assert_qmp(event, 'data/device', drive) - ready = True - - result = self.vm.qmp('block-job-cancel', device=drive, - force=not wait_ready) - self.assert_qmp(result, 'return', {}) - - cancelled = False - while not cancelled: + def wait_ready(self, drive='drive0'): + '''Wait until a block job BLOCK_JOB_READY event''' + ready = False + while not ready: for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED' or \ - event['event'] == 'BLOCK_JOB_CANCELLED': + if event['event'] == 'BLOCK_JOB_READY': self.assert_qmp(event, 'data/type', 'mirror') self.assert_qmp(event, 'data/device', drive) - if wait_ready: - self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED') - self.assert_qmp(event, 'data/offset', self.image_len) - self.assert_qmp(event, 'data/len', self.image_len) - cancelled = True + ready = True - self.assert_no_active_mirrors() + def wait_ready_and_cancel(self, drive='drive0'): + self.wait_ready(drive) + event = self.cancel_and_wait() + self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED') + self.assert_qmp(event, 'data/type', 'mirror') + self.assert_qmp(event, 'data/offset', self.image_len) + self.assert_qmp(event, 'data/len', self.image_len) def complete_and_wait(self, drive='drive0', wait_ready=True): '''Complete a block job and wait for it to finish''' if wait_ready: - ready = False - while not ready: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_READY': - self.assert_qmp(event, 'data/type', 'mirror') - self.assert_qmp(event, 'data/device', drive) - ready = True + self.wait_ready() result = self.vm.qmp('block-job-complete', device=drive) self.assert_qmp(result, 'return', {}) @@ -91,43 +68,13 @@ class ImageMirroringTestCase(iotests.QMPTestCase): self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_mirrors() - - def create_image(self, name, size): - file = open(name, 'w') - i = 0 - while i < size: - sector = struct.pack('>l504xl', i / 512, i / 512) - file.write(sector) - i = i + 512 - file.close() - - def compare_images(self, img1, img2): - try: - qemu_img('convert', '-f', iotests.imgfmt, '-O', 'raw', img1, img1 + '.raw') - qemu_img('convert', '-f', iotests.imgfmt, '-O', 'raw', img2, img2 + '.raw') - file1 = open(img1 + '.raw', 'r') - file2 = open(img2 + '.raw', 'r') - return file1.read() == file2.read() - finally: - if file1 is not None: - file1.close() - if file2 is not None: - file2.close() - try: - os.remove(img1 + '.raw') - except OSError: - pass - try: - os.remove(img2 + '.raw') - except OSError: - pass + self.assert_no_active_block_jobs() class TestSingleDrive(ImageMirroringTestCase): image_len = 1 * 1024 * 1024 # MB def setUp(self): - self.create_image(backing_img, TestSingleDrive.image_len) + iotests.create_image(backing_img, TestSingleDrive.image_len) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -142,7 +89,7 @@ class TestSingleDrive(ImageMirroringTestCase): pass def test_complete(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img) @@ -152,37 +99,37 @@ class TestSingleDrive(ImageMirroringTestCase): result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', target_img) self.vm.shutdown() - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') def test_cancel(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img) self.assert_qmp(result, 'return', {}) - self.cancel_and_wait(wait_ready=False) + self.cancel_and_wait(force=True) result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', test_img) self.vm.shutdown() def test_cancel_after_ready(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img) self.assert_qmp(result, 'return', {}) - self.cancel_and_wait() + self.wait_ready_and_cancel() result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', test_img) self.vm.shutdown() - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') def test_pause(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img) @@ -204,11 +151,11 @@ class TestSingleDrive(ImageMirroringTestCase): self.complete_and_wait() self.vm.shutdown() - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') def test_small_buffer(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() # A small buffer is rounded up automatically result = self.vm.qmp('drive-mirror', device='drive0', sync='full', @@ -219,11 +166,11 @@ class TestSingleDrive(ImageMirroringTestCase): result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', target_img) self.vm.shutdown() - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') def test_small_buffer2(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' % (TestSingleDrive.image_len, TestSingleDrive.image_len), target_img) @@ -235,11 +182,11 @@ class TestSingleDrive(ImageMirroringTestCase): result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', target_img) self.vm.shutdown() - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') def test_large_cluster(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' % (TestSingleDrive.image_len, backing_img), target_img) @@ -251,7 +198,7 @@ class TestSingleDrive(ImageMirroringTestCase): result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', target_img) self.vm.shutdown() - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') def test_medium_not_found(self): @@ -273,15 +220,15 @@ class TestMirrorNoBacking(ImageMirroringTestCase): image_len = 2 * 1024 * 1024 # MB def complete_and_wait(self, drive='drive0', wait_ready=True): - self.create_image(target_backing_img, TestMirrorNoBacking.image_len) + iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len) return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready) def compare_images(self, img1, img2): - self.create_image(target_backing_img, TestMirrorNoBacking.image_len) - return ImageMirroringTestCase.compare_images(self, img1, img2) + iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len) + return iotests.compare_images(img1, img2) def setUp(self): - self.create_image(backing_img, TestMirrorNoBacking.image_len) + iotests.create_image(backing_img, TestMirrorNoBacking.image_len) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -294,7 +241,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase): os.remove(target_img) def test_complete(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) result = self.vm.qmp('drive-mirror', device='drive0', sync='full', @@ -309,14 +256,14 @@ class TestMirrorNoBacking(ImageMirroringTestCase): 'target image does not match source after mirroring') def test_cancel(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) result = self.vm.qmp('drive-mirror', device='drive0', sync='full', mode='existing', target=target_img) self.assert_qmp(result, 'return', {}) - self.cancel_and_wait() + self.wait_ready_and_cancel() result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', test_img) self.vm.shutdown() @@ -324,7 +271,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase): 'target image does not match source after mirroring') def test_large_cluster(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() # qemu-img create fails if the image is not there qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d' @@ -349,7 +296,7 @@ class TestMirrorResized(ImageMirroringTestCase): image_len = 2 * 1024 * 1024 # MB def setUp(self): - self.create_image(backing_img, TestMirrorResized.backing_len) + iotests.create_image(backing_img, TestMirrorResized.backing_len) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) qemu_img('resize', test_img, '2M') self.vm = iotests.VM().add_drive(test_img) @@ -365,7 +312,7 @@ class TestMirrorResized(ImageMirroringTestCase): pass def test_complete_top(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='top', target=target_img) @@ -375,11 +322,11 @@ class TestMirrorResized(ImageMirroringTestCase): result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', target_img) self.vm.shutdown() - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') def test_complete_full(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img) @@ -389,7 +336,7 @@ class TestMirrorResized(ImageMirroringTestCase): result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/file', target_img) self.vm.shutdown() - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') class TestReadErrors(ImageMirroringTestCase): @@ -424,7 +371,7 @@ new_state = "1" def setUp(self): self.blkdebug_file = backing_img + ".blkdebug" - self.create_image(backing_img, TestReadErrors.image_len) + iotests.create_image(backing_img, TestReadErrors.image_len) self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' @@ -443,7 +390,7 @@ new_state = "1" os.remove(self.blkdebug_file) def test_report_read(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img) @@ -467,11 +414,11 @@ new_state = "1" self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() self.vm.shutdown() def test_ignore_read(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img, on_source_error='ignore') @@ -487,7 +434,7 @@ new_state = "1" self.vm.shutdown() def test_large_cluster(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() # Test COW into the target image. The first half of the # cluster at MIRROR_GRANULARITY has to be copied from @@ -509,11 +456,11 @@ new_state = "1" # Detach blkdebug to compare images successfully qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img) - self.assertTrue(self.compare_images(test_img, target_img), + self.assertTrue(iotests.compare_images(test_img, target_img), 'target image does not match source after mirroring') def test_stop_read(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img, on_source_error='stop') @@ -544,7 +491,7 @@ new_state = "1" self.assert_qmp(result, 'return[0]/io-status', 'ok') self.complete_and_wait(wait_ready=False) - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() self.vm.shutdown() class TestWriteErrors(ImageMirroringTestCase): @@ -579,7 +526,7 @@ new_state = "1" def setUp(self): self.blkdebug_file = target_img + ".blkdebug" - self.create_image(backing_img, TestWriteErrors.image_len) + iotests.create_image(backing_img, TestWriteErrors.image_len) self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5) qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img) self.vm = iotests.VM().add_drive(test_img) @@ -594,7 +541,7 @@ new_state = "1" os.remove(self.blkdebug_file) def test_report_write(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', mode='existing', target=self.target_img) @@ -618,11 +565,11 @@ new_state = "1" self.assert_qmp(event, 'data/len', self.image_len) completed = True - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() self.vm.shutdown() def test_ignore_write(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', mode='existing', target=self.target_img, @@ -639,7 +586,7 @@ new_state = "1" self.vm.shutdown() def test_stop_write(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', mode='existing', target=self.target_img, @@ -671,7 +618,7 @@ new_state = "1" ready = True self.complete_and_wait(wait_ready=False) - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() self.vm.shutdown() class TestSetSpeed(ImageMirroringTestCase): @@ -690,7 +637,7 @@ class TestSetSpeed(ImageMirroringTestCase): os.remove(target_img) def test_set_speed(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img) @@ -709,7 +656,7 @@ class TestSetSpeed(ImageMirroringTestCase): self.assert_qmp(result, 'return[0]/device', 'drive0') self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) - self.cancel_and_wait() + self.wait_ready_and_cancel() # Check setting speed in drive-mirror works result = self.vm.qmp('drive-mirror', device='drive0', sync='full', @@ -720,16 +667,16 @@ class TestSetSpeed(ImageMirroringTestCase): self.assert_qmp(result, 'return[0]/device', 'drive0') self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) - self.cancel_and_wait() + self.wait_ready_and_cancel() def test_set_speed_invalid(self): - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img, speed=-1) self.assert_qmp(result, 'error/class', 'GenericError') - self.assert_no_active_mirrors() + self.assert_no_active_block_jobs() result = self.vm.qmp('drive-mirror', device='drive0', sync='full', target=target_img) @@ -738,7 +685,7 @@ class TestSetSpeed(ImageMirroringTestCase): result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) self.assert_qmp(result, 'error/class', 'GenericError') - self.cancel_and_wait() + self.wait_ready_and_cancel() if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'qed']) diff --git a/tests/qemu-iotests/054.out b/tests/qemu-iotests/054.out index 0b2fe301ea..2f357c271d 100644 --- a/tests/qemu-iotests/054.out +++ b/tests/qemu-iotests/054.out @@ -1,7 +1,7 @@ QA output created by 054 creating too large image (1 EB) -qemu-img: The image size is too large for file format 'qcow2' +qemu-img: The image size is too large for file format 'qcow2' (try using a larger cluster size) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1152921504606846976 creating too large image (1 EB) using qcow2.py diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 432732cfc3..74628ae637 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -214,7 +214,8 @@ do start=`_wallclock` $timestamp && echo -n " ["`date "+%T"`"]" [ ! -x $seq ] && chmod u+x $seq # ensure we can run it - ./$seq >$tmp.out 2>&1 + MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \ + ./$seq >$tmp.out 2>&1 sts=$? $timestamp && _timestamp stop=`_wallclock` diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 569ca3d804..8a8f1814bd 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -23,6 +23,7 @@ import string import unittest import sys; sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'QMP')) import qmp +import struct __all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io', 'VM', 'QMPTestCase', 'notrun', 'main'] @@ -51,6 +52,21 @@ def qemu_io(*args): args = qemu_io_args + list(args) return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0] +def compare_images(img1, img2): + '''Return True if two image files are identical''' + return qemu_img('compare', '-f', imgfmt, + '-F', imgfmt, img1, img2) == 0 + +def create_image(name, size): + '''Create a fully-allocated raw image with sector markers''' + file = open(name, 'w') + i = 0 + while i < size: + sector = struct.pack('>l504xl', i / 512, i / 512) + file.write(sector) + i = i + 512 + file.close() + class VM(object): '''A QEMU VM''' @@ -170,6 +186,28 @@ class QMPTestCase(unittest.TestCase): result = self.dictpath(d, path) self.assertEqual(result, value, 'values not equal "%s" and "%s"' % (str(result), str(value))) + def assert_no_active_block_jobs(self): + result = self.vm.qmp('query-block-jobs') + self.assert_qmp(result, 'return', []) + + def cancel_and_wait(self, drive='drive0', force=False): + '''Cancel a block job and wait for it to finish, returning the event''' + result = self.vm.qmp('block-job-cancel', device=drive, force=force) + self.assert_qmp(result, 'return', {}) + + cancelled = False + result = None + while not cancelled: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'BLOCK_JOB_COMPLETED' or \ + event['event'] == 'BLOCK_JOB_CANCELLED': + self.assert_qmp(event, 'data/device', drive) + result = event + cancelled = True + + self.assert_no_active_block_jobs() + return result + def notrun(reason): '''Skip this test suite''' # Each test in qemu-iotests has a number ("seq") diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index 0942a41875..b2fa9a74f6 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -295,7 +295,10 @@ static void test_visitor_out_struct_errors(TestOutputVisitorData *data, typedef struct TestStructList { - TestStruct *value; + union { + TestStruct *value; + uint64_t padding; + }; struct TestStructList *next; } TestStructList; diff --git a/translate-all.c b/translate-all.c index 211be314cb..40b8f3d2b5 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1354,15 +1354,15 @@ void tb_invalidate_phys_addr(hwaddr addr) { ram_addr_t ram_addr; MemoryRegionSection *section; + hwaddr l = 1; - section = phys_page_find(address_space_memory.dispatch, - addr >> TARGET_PAGE_BITS); + section = address_space_translate(&address_space_memory, addr, &addr, &l, false); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { return; } ram_addr = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK) - + memory_region_section_addr(section, addr); + + addr; tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0); } #endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */ diff --git a/ui/cocoa.m b/ui/cocoa.m index 1971d9cb09..be491794dc 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -35,6 +35,9 @@ #ifndef MAC_OS_X_VERSION_10_5 #define MAC_OS_X_VERSION_10_5 1050 #endif +#ifndef MAC_OS_X_VERSION_10_6 +#define MAC_OS_X_VERSION_10_6 1060 +#endif //#define DEBUG @@ -771,9 +774,20 @@ QemuCocoaView *cocoaView; NSOpenPanel *op = [[NSOpenPanel alloc] init]; [op setPrompt:@"Boot image"]; [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"]; - [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil] + NSArray *filetypes = [NSArray arrayWithObjects:@"img", @"iso", @"dmg", + @"qcow", @"cow", @"cloop", @"vmdk", nil]; +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) + [op setAllowedFileTypes:filetypes]; + [op beginSheetModalForWindow:normalWindow + completionHandler:^(NSInteger returnCode) + { [self openPanelDidEnd:op + returnCode:returnCode contextInfo:NULL ]; } ]; +#else + // Compatibility code for pre-10.6, using deprecated method + [op beginSheetForDirectory:nil file:nil types:filetypes modalForWindow:normalWindow modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; +#endif } else { // or launch QEMU, with the global args [self startEmulationWithArgc:gArgc argv:(char **)gArgv]; @@ -810,7 +824,7 @@ QemuCocoaView *cocoaView; exit(0); } else if(returnCode == NSOKButton) { const char *bin = "qemu"; - char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding]; + char *img = (char*)[ [ [ sheet URL ] path ] cStringUsingEncoding:NSASCIIStringEncoding]; char **argv = (char**)malloc( sizeof(char*)*3 ); @@ -851,22 +865,10 @@ QemuCocoaView *cocoaView; -// Dock Connection -typedef struct CPSProcessSerNum -{ - UInt32 lo; - UInt32 hi; -} CPSProcessSerNum; - -OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); -OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); -OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); - int main (int argc, const char * argv[]) { gArgc = argc; gArgv = (char **)argv; - CPSProcessSerNum PSN; int i; /* In case we don't need to display a window, let's not do that */ @@ -890,12 +892,13 @@ int main (int argc, const char * argv[]) { } NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - [NSApplication sharedApplication]; - if (!CPSGetCurrentProcess(&PSN)) - if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) - if (!CPSSetFrontProcess(&PSN)) - [NSApplication sharedApplication]; + // Pull this console process up to being a fully-fledged graphical + // app with a menubar and Dock icon + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + + [NSApplication sharedApplication]; // Add menus NSMenu *menu; @@ -960,6 +963,8 @@ int main (int argc, const char * argv[]) { static void cocoa_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + COCOA_DEBUG("qemu_cocoa: cocoa_update\n"); NSRect rect; @@ -973,18 +978,24 @@ static void cocoa_update(DisplayChangeListener *dcl, h * [cocoaView cdy]); } [cocoaView setNeedsDisplayInRect:rect]; + + [pool release]; } static void cocoa_switch(DisplayChangeListener *dcl, DisplaySurface *surface) { - COCOA_DEBUG("qemu_cocoa: cocoa_resize\n"); + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + COCOA_DEBUG("qemu_cocoa: cocoa_switch\n"); [cocoaView switchSurface:surface]; + [pool release]; } static void cocoa_refresh(DisplayChangeListener *dcl) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n"); if (kbd_mouse_is_absolute()) { @@ -1007,6 +1018,7 @@ static void cocoa_refresh(DisplayChangeListener *dcl) } } while(event != nil); graphic_hw_update(NULL); + [pool release]; } static void cocoa_cleanup(void) @@ -377,7 +377,7 @@ static void gd_cursor_define(DisplayChangeListener *dcl, pixbuf, c->hot_x, c->hot_y); gdk_window_set_cursor(gtk_widget_get_window(s->drawing_area), cursor); g_object_unref(pixbuf); - g_object_unref(cursor); + gdk_cursor_unref(cursor); } static void gd_switch(DisplayChangeListener *dcl, @@ -885,9 +885,11 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) s->free_scale = TRUE; } else { s->free_scale = FALSE; + s->scale_x = 1.0; + s->scale_y = 1.0; + gd_update_windowsize(s); } - gd_update_windowsize(s); gd_update_full_redraw(s); } diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 631a1dea33..3dc8b1b074 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -47,6 +47,8 @@ extern int daemon(int, int); # define QEMU_VMALLOC_ALIGN getpagesize() #endif +#include <glib/gprintf.h> + #include "config-host.h" #include "sysemu/sysemu.h" #include "trace.h" @@ -232,3 +234,10 @@ int qemu_utimens(const char *path, const struct timespec *times) return utimes(path, &tv[0]); } + +char * +qemu_get_local_state_pathname(const char *relative_pathname) +{ + return g_strdup_printf("%s/%s", CONFIG_QEMU_LOCALSTATEDIR, + relative_pathname); +} diff --git a/util/oslib-win32.c b/util/oslib-win32.c index df2ecbdffb..961fbf5e3d 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -26,12 +26,17 @@ * THE SOFTWARE. */ #include <windows.h> +#include <glib.h> +#include <stdlib.h> #include "config-host.h" #include "sysemu/sysemu.h" #include "qemu/main-loop.h" #include "trace.h" #include "qemu/sockets.h" +/* this must come after including "trace.h" */ +#include <shlobj.h> + void *qemu_oom_check(void *ptr) { if (ptr == NULL) { @@ -160,3 +165,20 @@ int qemu_get_thread_id(void) { return GetCurrentThreadId(); } + +char * +qemu_get_local_state_pathname(const char *relative_pathname) +{ + HRESULT result; + char base_path[MAX_PATH+1] = ""; + + result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, + /* SHGFP_TYPE_CURRENT */ 0, base_path); + if (result != S_OK) { + /* misconfigured environment */ + g_critical("CSIDL_COMMON_APPDATA unavailable: %ld", (long)result); + abort(); + } + return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", base_path, + relative_pathname); +} |