diff options
144 files changed, 1634 insertions, 693 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index b287ef8939..97c9fa1f7f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -52,6 +52,13 @@ General Project Administration ------------------------------ M: Anthony Liguori <aliguori@amazon.com> +Responsible Disclosure, Reporting Security Issues +------------------------------ +W: http://wiki.qemu.org/SecurityProcess +M: Michael S. Tsirkin <mst@redhat.com> +M: Anthony Liguori <aliguori@amazon.com> +L: secalert@redhat.com + Guest CPU cores (TCG): ---------------------- Alpha @@ -601,6 +608,7 @@ USB M: Gerd Hoffmann <kraxel@redhat.com> S: Maintained F: hw/usb/* +F: tests/usb-hcd-ehci-test.c VFIO M: Alex Williamson <alex.williamson@redhat.com> @@ -666,6 +674,9 @@ M: Gerd Hoffmann <kraxel@redhat.com> S: Maintained F: audio/ F: hw/audio/ +F: tests/ac97-test.c +F: tests/es1370-test.c +F: tests/intel-hda-test.c Block M: Kevin Wolf <kwolf@redhat.com> @@ -780,6 +791,17 @@ S: Supported F: qapi-schema.json T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp +QOM +M: Anthony Liguori <aliguori@amazon.com> +M: Andreas Färber <afaerber@suse.de> +S: Supported +T: git git://github.com/afaerber/qemu-cpu.git qom-next +F: include/qom/ +X: include/qom/cpu.h +F: qom/ +X: qom/cpu.c +F: tests/qom-test.c + QMP M: Luiz Capitulino <lcapitulino@redhat.com> S: Maintained diff --git a/Makefile.target b/Makefile.target index ba1234063e..6d8fde8b9e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -120,8 +120,10 @@ obj-y += dump.o LIBS+=$(libs_softmmu) # xen support -obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o -obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o +obj-$(CONFIG_XEN) += xen-common.o +obj-$(CONFIG_XEN_I386) += xen-hvm.o xen-mapcache.o +obj-$(call lnot,$(CONFIG_XEN)) += xen-common-stub.o +obj-$(call lnot,$(CONFIG_XEN_I386)) += xen-hvm-stub.o # Hardware support ifeq ($(TARGET_NAME), sparc64) diff --git a/arch_init.c b/arch_init.c index 60c975db2b..995f56d504 100644 --- a/arch_init.c +++ b/arch_init.c @@ -45,6 +45,7 @@ #include "hw/audio/pcspk.h" #include "migration/page_cache.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include "qmp-commands.h" #include "trace.h" #include "exec/cpu-all.h" @@ -110,6 +111,8 @@ static bool mig_throttle_on; static int dirty_rate_high_cnt; static void check_guest_throttling(void); +static uint64_t bitmap_sync_count; + /***********************************************************/ /* ram save/restore */ @@ -167,11 +170,8 @@ static struct { /* Cache for XBZRLE, Protected by lock. */ PageCache *cache; QemuMutex lock; -} XBZRLE = { - .encoded_buf = NULL, - .current_buf = NULL, - .cache = NULL, -}; +} XBZRLE; + /* buffer used for XBZRLE decoding */ static uint8_t *xbzrle_decoded_buf; @@ -187,41 +187,44 @@ static void XBZRLE_cache_unlock(void) qemu_mutex_unlock(&XBZRLE.lock); } +/* + * called from qmp_migrate_set_cache_size in main thread, possibly while + * a migration is in progress. + * A running migration maybe using the cache and might finish during this + * call, hence changes to the cache are protected by XBZRLE.lock(). + */ int64_t xbzrle_cache_resize(int64_t new_size) { - PageCache *new_cache, *cache_to_free; + PageCache *new_cache; + int64_t ret; if (new_size < TARGET_PAGE_SIZE) { return -1; } - /* no need to lock, the current thread holds qemu big lock */ + XBZRLE_cache_lock(); + if (XBZRLE.cache != NULL) { - /* check XBZRLE.cache again later */ if (pow2floor(new_size) == migrate_xbzrle_cache_size()) { - return pow2floor(new_size); + goto out_new_size; } new_cache = cache_init(new_size / TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); if (!new_cache) { - DPRINTF("Error creating cache\n"); - return -1; + error_report("Error creating cache"); + ret = -1; + goto out; } - XBZRLE_cache_lock(); - /* the XBZRLE.cache may have be destroyed, check it again */ - if (XBZRLE.cache != NULL) { - cache_to_free = XBZRLE.cache; - XBZRLE.cache = new_cache; - } else { - cache_to_free = new_cache; - } - XBZRLE_cache_unlock(); - - cache_fini(cache_to_free); + cache_fini(XBZRLE.cache); + XBZRLE.cache = new_cache; } - return pow2floor(new_size); +out_new_size: + ret = pow2floor(new_size); +out: + XBZRLE_cache_unlock(); + return ret; } /* accounting for migration statistics */ @@ -233,6 +236,7 @@ typedef struct AccountingInfo { uint64_t xbzrle_bytes; uint64_t xbzrle_pages; uint64_t xbzrle_cache_miss; + double xbzrle_cache_miss_rate; uint64_t xbzrle_overflows; } AccountingInfo; @@ -288,6 +292,11 @@ uint64_t xbzrle_mig_pages_cache_miss(void) return acct_info.xbzrle_cache_miss; } +double xbzrle_mig_cache_miss_rate(void) +{ + return acct_info.xbzrle_cache_miss_rate; +} + uint64_t xbzrle_mig_pages_overflow(void) { return acct_info.xbzrle_overflows; @@ -340,7 +349,7 @@ static void xbzrle_cache_zero_page(ram_addr_t current_addr) #define ENCODING_FLAG_XBZRLE 0x1 -static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, +static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data, ram_addr_t current_addr, RAMBlock *block, ram_addr_t offset, int cont, bool last_stage) { @@ -348,19 +357,23 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, uint8_t *prev_cached_page; if (!cache_is_cached(XBZRLE.cache, current_addr)) { + acct_info.xbzrle_cache_miss++; if (!last_stage) { - if (cache_insert(XBZRLE.cache, current_addr, current_data) == -1) { + if (cache_insert(XBZRLE.cache, current_addr, *current_data) == -1) { return -1; + } else { + /* update *current_data when the page has been + inserted into cache */ + *current_data = get_cached_data(XBZRLE.cache, current_addr); } } - acct_info.xbzrle_cache_miss++; return -1; } prev_cached_page = get_cached_data(XBZRLE.cache, current_addr); /* save current buffer into memory */ - memcpy(XBZRLE.current_buf, current_data, TARGET_PAGE_SIZE); + memcpy(XBZRLE.current_buf, *current_data, TARGET_PAGE_SIZE); /* XBZRLE encoding (if there is no overflow) */ encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf, @@ -373,7 +386,10 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, DPRINTF("Overflow\n"); acct_info.xbzrle_overflows++; /* update data in the cache */ - memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE); + if (!last_stage) { + memcpy(prev_cached_page, *current_data, TARGET_PAGE_SIZE); + *current_data = prev_cached_page; + } return -1; } @@ -479,6 +495,10 @@ static void migration_bitmap_sync(void) static int64_t num_dirty_pages_period; int64_t end_time; int64_t bytes_xfer_now; + static uint64_t xbzrle_cache_miss_prev; + static uint64_t iterations_prev; + + bitmap_sync_count++; if (!bytes_xfer_prev) { bytes_xfer_prev = ram_bytes_transferred(); @@ -520,11 +540,22 @@ static void migration_bitmap_sync(void) } else { mig_throttle_on = false; } + if (migrate_use_xbzrle()) { + if (iterations_prev != 0) { + acct_info.xbzrle_cache_miss_rate = + (double)(acct_info.xbzrle_cache_miss - + xbzrle_cache_miss_prev) / + (acct_info.iterations - iterations_prev); + } + iterations_prev = acct_info.iterations; + xbzrle_cache_miss_prev = acct_info.xbzrle_cache_miss; + } s->dirty_pages_rate = num_dirty_pages_period * 1000 / (end_time - start_time); s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE; start_time = end_time; num_dirty_pages_period = 0; + s->dirty_sync_count = bitmap_sync_count; } } @@ -598,15 +629,9 @@ static int ram_save_block(QEMUFile *f, bool last_stage) */ xbzrle_cache_zero_page(current_addr); } else if (!ram_bulk_stage && migrate_use_xbzrle()) { - bytes_sent = save_xbzrle_page(f, p, current_addr, block, + bytes_sent = save_xbzrle_page(f, &p, current_addr, block, offset, cont, last_stage); if (!last_stage) { - /* We must send exactly what's in the xbzrle cache - * even if the page wasn't xbzrle compressed, so that - * it's right next time. - */ - p = get_cached_data(XBZRLE.cache, current_addr); - /* Can't send this cached data async, since the cache page * might get updated before it gets to the wire */ @@ -726,37 +751,34 @@ static void reset_ram_globals(void) static int ram_save_setup(QEMUFile *f, void *opaque) { RAMBlock *block; - int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS; + int64_t ram_bitmap_pages; /* Size of bitmap in pages, including gaps */ - migration_bitmap = bitmap_new(ram_pages); - bitmap_set(migration_bitmap, 0, ram_pages); - migration_dirty_pages = ram_pages; mig_throttle_on = false; dirty_rate_high_cnt = 0; + bitmap_sync_count = 0; if (migrate_use_xbzrle()) { - qemu_mutex_lock_iothread(); + XBZRLE_cache_lock(); XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() / TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); if (!XBZRLE.cache) { - qemu_mutex_unlock_iothread(); - DPRINTF("Error creating cache\n"); + XBZRLE_cache_unlock(); + error_report("Error creating cache"); return -1; } - qemu_mutex_init(&XBZRLE.lock); - qemu_mutex_unlock_iothread(); + XBZRLE_cache_unlock(); /* We prefer not to abort if there is no memory */ XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE); if (!XBZRLE.encoded_buf) { - DPRINTF("Error allocating encoded_buf\n"); + error_report("Error allocating encoded_buf"); return -1; } XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE); if (!XBZRLE.current_buf) { - DPRINTF("Error allocating current_buf\n"); + error_report("Error allocating current_buf"); g_free(XBZRLE.encoded_buf); XBZRLE.encoded_buf = NULL; return -1; @@ -770,6 +792,22 @@ static int ram_save_setup(QEMUFile *f, void *opaque) bytes_transferred = 0; reset_ram_globals(); + ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS; + migration_bitmap = bitmap_new(ram_bitmap_pages); + bitmap_set(migration_bitmap, 0, ram_bitmap_pages); + + /* + * Count the total number of pages used by ram blocks not including any + * gaps due to alignment or unplugs. + */ + migration_dirty_pages = 0; + QTAILQ_FOREACH(block, &ram_list.blocks, next) { + uint64_t block_pages; + + block_pages = block->length >> TARGET_PAGE_BITS; + migration_dirty_pages += block_pages; + } + memory_global_dirty_log_start(); migration_bitmap_sync(); qemu_mutex_unlock_iothread(); @@ -997,8 +1035,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) seq_iter++; - if (version_id < 4 || version_id > 4) { - return -EINVAL; + if (version_id != 4) { + ret = -EINVAL; + goto done; } do { @@ -1008,44 +1047,42 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) addr &= TARGET_PAGE_MASK; if (flags & RAM_SAVE_FLAG_MEM_SIZE) { - if (version_id == 4) { - /* Synchronize RAM block list */ - char id[256]; - ram_addr_t length; - ram_addr_t total_ram_bytes = addr; - - while (total_ram_bytes) { - RAMBlock *block; - uint8_t len; - - len = qemu_get_byte(f); - qemu_get_buffer(f, (uint8_t *)id, len); - id[len] = 0; - length = qemu_get_be64(f); - - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - if (!strncmp(id, block->idstr, sizeof(id))) { - if (block->length != length) { - fprintf(stderr, - "Length mismatch: %s: " RAM_ADDR_FMT - " in != " RAM_ADDR_FMT "\n", id, length, - block->length); - ret = -EINVAL; - goto done; - } - break; + /* Synchronize RAM block list */ + char id[256]; + ram_addr_t length; + ram_addr_t total_ram_bytes = addr; + + while (total_ram_bytes) { + RAMBlock *block; + uint8_t len; + + len = qemu_get_byte(f); + qemu_get_buffer(f, (uint8_t *)id, len); + id[len] = 0; + length = qemu_get_be64(f); + + QTAILQ_FOREACH(block, &ram_list.blocks, next) { + if (!strncmp(id, block->idstr, sizeof(id))) { + if (block->length != length) { + fprintf(stderr, + "Length mismatch: %s: " RAM_ADDR_FMT + " in != " RAM_ADDR_FMT "\n", id, length, + block->length); + ret = -EINVAL; + goto done; } + break; } + } - if (!block) { - fprintf(stderr, "Unknown ramblock \"%s\", cannot " - "accept migration\n", id); - ret = -EINVAL; - goto done; - } - - total_ram_bytes -= length; + if (!block) { + fprintf(stderr, "Unknown ramblock \"%s\", cannot " + "accept migration\n", id); + ret = -EINVAL; + goto done; } + + total_ram_bytes -= length; } } @@ -1055,7 +1092,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) host = host_from_stream_offset(f, addr, flags); if (!host) { - return -EINVAL; + ret = -EINVAL; + goto done; } ch = qemu_get_byte(f); @@ -1065,14 +1103,16 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) host = host_from_stream_offset(f, addr, flags); if (!host) { - return -EINVAL; + ret = -EINVAL; + goto done; } qemu_get_buffer(f, host, TARGET_PAGE_SIZE); } else if (flags & RAM_SAVE_FLAG_XBZRLE) { void *host = host_from_stream_offset(f, addr, flags); if (!host) { - return -EINVAL; + ret = -EINVAL; + goto done; } if (load_xbzrle(f, addr, host) < 0) { @@ -1095,7 +1135,7 @@ done: return ret; } -SaveVMHandlers savevm_ram_handlers = { +static SaveVMHandlers savevm_ram_handlers = { .save_live_setup = ram_save_setup, .save_live_iterate = ram_save_iterate, .save_live_complete = ram_save_complete, @@ -1104,6 +1144,12 @@ SaveVMHandlers savevm_ram_handlers = { .cancel = ram_migration_cancel, }; +void ram_mig_init(void) +{ + qemu_mutex_init(&XBZRLE.lock); + register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL); +} + struct soundhw { const char *name; const char *descr; diff --git a/backends/rng.c b/backends/rng.c index 8b8d5a4973..0f2fc11dd8 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -50,6 +50,7 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp) { RngBackend *s = RNG_BACKEND(obj); RngBackendClass *k = RNG_BACKEND_GET_CLASS(s); + Error *local_err = NULL; if (value == s->opened) { return; @@ -61,12 +62,14 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp) } if (k->opened) { - k->opened(s, errp); + k->opened(s, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } } - if (!error_is_set(errp)) { - s->opened = value; - } + s->opened = true; } static void rng_backend_init(Object *obj) diff --git a/backends/tpm.c b/backends/tpm.c index b73580134c..01860c4acb 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -112,6 +112,7 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp) { TPMBackend *s = TPM_BACKEND(obj); TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + Error *local_err = NULL; if (value == s->opened) { return; @@ -123,12 +124,14 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp) } if (k->opened) { - k->opened(s, errp); + k->opened(s, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } } - if (!error_is_set(errp)) { - s->opened = value; - } + s->opened = true; } static void tpm_backend_instance_init(Object *obj) @@ -403,6 +403,14 @@ fi # make source path absolute source_path=`cd "$source_path"; pwd` +# running configure in the source tree? +# we know that's the case if configure is there. +if test -f "./configure"; then + pwd_is_source_path="y" +else + pwd_is_source_path="n" +fi + check_define() { cat > $TMPC <<EOF #if !defined($1) @@ -2624,7 +2632,7 @@ done if test "$modules" = yes; then shacmd_probe="sha1sum sha1 shasum" for c in $shacmd_probe; do - if which $c &>/dev/null; then + if which $c >/dev/null 2>&1; then shacmd="$c" break fi @@ -2940,7 +2948,7 @@ EOF fdt=yes dtc_internal="yes" mkdir -p dtc - if [ "$source_path" != `pwd` ] ; then + if [ "$pwd_is_source_path" != "y" ] ; then symlink "$source_path/dtc/Makefile" "dtc/Makefile" symlink "$source_path/dtc/scripts" "dtc/scripts" fi @@ -5178,7 +5186,7 @@ do done mkdir -p $DIRS for f in $FILES ; do - if [ -e "$source_path/$f" ] && [ "$source_path" != `pwd` ]; then + if [ -e "$source_path/$f" ] && [ "$pwd_is_source_path" != "y" ]; then symlink "$source_path/$f" "$f" fi done diff --git a/coroutine-gthread.c b/coroutine-gthread.c index d3e5b991f7..a61efe01dc 100644 --- a/coroutine-gthread.c +++ b/coroutine-gthread.c @@ -115,14 +115,11 @@ static inline GThread *create_thread(GThreadFunc func, gpointer data) static void __attribute__((constructor)) coroutine_init(void) { - if (!g_thread_supported()) { #if !GLIB_CHECK_VERSION(2, 31, 0) + if (!g_thread_supported()) { g_thread_init(NULL); -#else - fprintf(stderr, "glib threading failed to initialize.\n"); - exit(1); -#endif } +#endif init_coroutine_cond(); } diff --git a/device-hotplug.c b/device-hotplug.c index ebfa6b1016..eecb08e2b1 100644 --- a/device-hotplug.c +++ b/device-hotplug.c @@ -40,7 +40,7 @@ DriveInfo *add_init_drive(const char *optstr) return NULL; mc = MACHINE_GET_CLASS(current_machine); - dinfo = drive_init(opts, mc->qemu_machine->block_default_type); + dinfo = drive_init(opts, mc->block_default_type); if (!dinfo) { qemu_opts_del(opts); return NULL; diff --git a/docs/memory.txt b/docs/memory.txt index 22eaec780e..5bdbdb3691 100644 --- a/docs/memory.txt +++ b/docs/memory.txt @@ -232,8 +232,8 @@ various constraints can be supplied to control how these callbacks are called: (in bytes) supported by the *implementation*; other access sizes will be emulated using the ones available. For example a 4-byte write will be emulated using four 1-byte writes, if .impl.max_access_size = 1. - - .impl.valid specifies that the *implementation* only supports unaligned - accesses; unaligned accesses will be emulated by two aligned accesses. - - .old_portio and .old_mmio can be used to ease porting from code using - cpu_register_io_memory() and register_ioport(). They should not be used - in new code. + - .impl.unaligned specifies that the *implementation* supports unaligned + accesses; if false, unaligned accesses will be emulated by two aligned + accesses. + - .old_mmio can be used to ease porting from code using + cpu_register_io_memory(). It should not be used in new code. diff --git a/docs/migration.txt b/docs/migration.txt index 0e0a1d44da..fe1f2bb738 100644 --- a/docs/migration.txt +++ b/docs/migration.txt @@ -139,7 +139,6 @@ static const VMStateDescription vmstate_kbd = { .name = "pckbd", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, .fields = (VMStateField []) { VMSTATE_UINT8(write_cmd, KBDState), VMSTATE_UINT8(status, KBDState), @@ -168,12 +167,13 @@ You can see that there are several version fields: - minimum_version_id: the minimum version_id that VMState is able to understand for that device. - minimum_version_id_old: For devices that were not able to port to vmstate, we can - assign a function that knows how to read this old state. + assign a function that knows how to read this old state. This field is + ignored if there is no load_state_old handler. So, VMState is able to read versions from minimum_version_id to -version_id. And the function load_state_old() is able to load state -from minimum_version_id_old to minimum_version_id. This function is -deprecated and will be removed when no more users are left. +version_id. And the function load_state_old() (if present) is able to +load state from minimum_version_id_old to minimum_version_id. This +function is deprecated and will be removed when no more users are left. === Massaging functions === @@ -255,7 +255,6 @@ const VMStateDescription vmstate_ide_drive_pio_state = { .name = "ide_drive/pio_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = ide_drive_pio_pre_save, .post_load = ide_drive_pio_post_load, .fields = (VMStateField []) { @@ -275,7 +274,6 @@ const VMStateDescription vmstate_ide_drive = { .name = "ide_drive", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = ide_drive_post_load, .fields = (VMStateField []) { .... several fields .... @@ -380,7 +380,7 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, as = iotlb.target_as; } - if (memory_access_is_direct(mr, is_write)) { + if (xen_enabled() && memory_access_is_direct(mr, is_write)) { hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr; len = MIN(page, len); } @@ -188,6 +188,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->ram->normal); monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n", info->ram->normal_bytes >> 10); + monitor_printf(mon, "dirty sync count: %" PRIu64 "\n", + info->ram->dirty_sync_count); if (info->ram->dirty_pages_rate) { monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n", info->ram->dirty_pages_rate); @@ -212,6 +214,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->xbzrle_cache->pages); monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n", info->xbzrle_cache->cache_miss); + monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n", + info->xbzrle_cache->cache_miss_rate); monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n", info->xbzrle_cache->overflow); } diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 56b302c122..3b0b6a9b1d 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -14,6 +14,7 @@ #include "hw/virtio/virtio.h" #include "virtio-9p.h" #include "virtio-9p-xattr.h" +#include "fsdev/qemu-fsdev.h" /* local_ops */ #include <arpa/inet.h> #include <pwd.h> #include <grp.h> diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c index 840e4ebb5a..71262bccd2 100644 --- a/hw/9pfs/virtio-9p-synth.c +++ b/hw/9pfs/virtio-9p-synth.c @@ -21,7 +21,7 @@ #include <sys/stat.h> /* Root node for synth file system */ -V9fsSynthNode v9fs_synth_root = { +static V9fsSynthNode v9fs_synth_root = { .name = "/", .actual_attr = { .mode = 0555 | S_IFDIR, diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index f80c48008c..3b143b371b 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -63,16 +63,18 @@ typedef struct AcpiPciHpFind { static int acpi_pcihp_get_bsel(PCIBus *bus) { - QObject *o = object_property_get_qobject(OBJECT(bus), - ACPI_PCIHP_PROP_BSEL, NULL); - int64_t bsel = -1; - if (o) { - bsel = qint_get_int(qobject_to_qint(o)); - } - if (bsel < 0) { + Error *local_err = NULL; + int64_t bsel = object_property_get_int(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, + &local_err); + + if (local_err || bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) { + if (local_err) { + error_free(local_err); + } return -1; + } else { + return bsel; } - return bsel; } static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 04291488e4..e0cd847b95 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -732,7 +732,7 @@ static void pxa2xx_ssp_save(QEMUFile *f, void *opaque) static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) { PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - int i; + int i, v; s->enable = qemu_get_be32(f); @@ -746,7 +746,11 @@ static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->ssrsa); qemu_get_8s(f, &s->ssacd); - s->rx_level = qemu_get_byte(f); + v = qemu_get_byte(f); + if (v < 0 || v > ARRAY_SIZE(s->rx_fifo)) { + return -EINVAL; + } + s->rx_level = v; s->rx_start = 0; for (i = 0; i < s->rx_level; i ++) s->rx_fifo[i] = qemu_get_byte(f); diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 28eed81280..5dd739e541 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -86,6 +86,7 @@ typedef struct { #ifndef HAS_YMF262 FM_OPL *opl; #endif + PortioList port_list; } AdlibState; static AdlibState *glob_adlib; @@ -293,7 +294,6 @@ static MemoryRegionPortio adlib_portio_list[] = { static void adlib_realizefn (DeviceState *dev, Error **errp) { AdlibState *s = ADLIB(dev); - PortioList *port_list = g_new(PortioList, 1); struct audsettings as; if (glob_adlib) { @@ -349,8 +349,8 @@ static void adlib_realizefn (DeviceState *dev, Error **errp) adlib_portio_list[0].offset = s->port; adlib_portio_list[1].offset = s->port + 8; - portio_list_init (port_list, OBJECT(s), adlib_portio_list, s, "adlib"); - portio_list_add (port_list, isa_address_space_io(&s->parent_obj), 0); + portio_list_init (&s->port_list, OBJECT(s), adlib_portio_list, s, "adlib"); + portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0); } static Property adlib_properties[] = { diff --git a/hw/block/xen_blkif.h b/hw/block/xen_blkif.h index c0f4136228..711b692742 100644 --- a/hw/block/xen_blkif.h +++ b/hw/block/xen_blkif.h @@ -79,6 +79,12 @@ static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_reque dst->handle = src->handle; dst->id = src->id; dst->sector_number = src->sector_number; + if (src->operation == BLKIF_OP_DISCARD) { + struct blkif_request_discard *s = (void *)src; + struct blkif_request_discard *d = (void *)dst; + d->nr_sectors = s->nr_sectors; + return; + } if (n > src->nr_segments) n = src->nr_segments; for (i = 0; i < n; i++) @@ -94,6 +100,12 @@ static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_reque dst->handle = src->handle; dst->id = src->id; dst->sector_number = src->sector_number; + if (src->operation == BLKIF_OP_DISCARD) { + struct blkif_request_discard *s = (void *)src; + struct blkif_request_discard *d = (void *)dst; + d->nr_sectors = s->nr_sectors; + return; + } if (n > src->nr_segments) n = src->nr_segments; for (i = 0; i < n; i++) diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index a8fea72edf..aed5b5b3e9 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -114,6 +114,7 @@ struct XenBlkDev { int requests_finished; /* Persistent grants extension */ + gboolean feature_discard; gboolean feature_persistent; GTree *persistent_gnts; unsigned int persistent_gnt_count; @@ -253,6 +254,8 @@ static int ioreq_parse(struct ioreq *ioreq) case BLKIF_OP_WRITE: ioreq->prot = PROT_READ; /* from memory */ break; + case BLKIF_OP_DISCARD: + return 0; default: xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n", ioreq->req.operation); @@ -492,6 +495,7 @@ static void qemu_aio_complete(void *opaque, int ret) case BLKIF_OP_READ: bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct); break; + case BLKIF_OP_DISCARD: default: break; } @@ -532,6 +536,15 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) &ioreq->v, ioreq->v.size / BLOCK_SIZE, qemu_aio_complete, ioreq); break; + case BLKIF_OP_DISCARD: + { + struct blkif_request_discard *discard_req = (void *)&ioreq->req; + ioreq->aio_inflight++; + bdrv_aio_discard(blkdev->bs, + discard_req->sector_number, discard_req->nr_sectors, + qemu_aio_complete, ioreq); + break; + } default: /* unknown operation (shouldn't happen -- parse catches this) */ goto err; @@ -710,6 +723,21 @@ static void blk_alloc(struct XenDevice *xendev) } } +static void blk_parse_discard(struct XenBlkDev *blkdev) +{ + int enable; + + blkdev->feature_discard = true; + + if (xenstore_read_be_int(&blkdev->xendev, "discard-enable", &enable) == 0) { + blkdev->feature_discard = !!enable; + } + + if (blkdev->feature_discard) { + xenstore_write_be_int(&blkdev->xendev, "feature-discard", 1); + } +} + static int blk_init(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); @@ -777,6 +805,8 @@ static int blk_init(struct XenDevice *xendev) xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1); xenstore_write_be_int(&blkdev->xendev, "info", info); + blk_parse_discard(blkdev); + g_free(directiosafe); return 0; @@ -812,6 +842,9 @@ static int blk_connect(struct XenDevice *xendev) qflags |= BDRV_O_RDWR; readonly = false; } + if (blkdev->feature_discard) { + qflags |= BDRV_O_UNMAP; + } /* init qemu block driver */ index = (blkdev->xendev.dev - 202 * 256) / 16; diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index de835612f0..404cf1843d 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -338,13 +338,13 @@ PropertyInfo qdev_prop_vlan = { int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) { - Error *errp = NULL; + Error *err = NULL; const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; object_property_set_str(OBJECT(dev), bdrv_name, - name, &errp); - if (errp) { - qerror_report_err(errp); - error_free(errp); + name, &err); + if (err) { + qerror_report_err(err); + error_free(err); return -1; } return 0; diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 585a8e902e..d8cb5408c3 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -751,6 +751,7 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque, Property *prop = opaque; uint32_t *alenptr = qdev_get_prop_ptr(dev, prop); void **arrayptr = (void *)dev + prop->arrayoffset; + Error *local_err = NULL; void *eltptr; const char *arrayname; int i; @@ -764,8 +765,9 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque, name); return; } - visit_type_uint32(v, alenptr, name, errp); - if (error_is_set(errp)) { + visit_type_uint32(v, alenptr, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (!*alenptr) { @@ -802,8 +804,9 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque, arrayprop->prop.info->get, arrayprop->prop.info->set, array_element_release, - arrayprop, errp); - if (error_is_set(errp)) { + arrayprop, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } } diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 60f9df1ed9..936eae6412 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -174,14 +174,14 @@ int qdev_init(DeviceState *dev) return 0; } -static void device_realize(DeviceState *dev, Error **err) +static void device_realize(DeviceState *dev, Error **errp) { DeviceClass *dc = DEVICE_GET_CLASS(dev); if (dc->init) { int rc = dc->init(dev); if (rc < 0) { - error_setg(err, "Device initialization failed."); + error_setg(errp, "Device initialization failed."); return; } } @@ -504,14 +504,14 @@ static void bus_unparent(Object *obj) } } -static bool bus_get_realized(Object *obj, Error **err) +static bool bus_get_realized(Object *obj, Error **errp) { BusState *bus = BUS(obj); return bus->realized; } -static void bus_set_realized(Object *obj, bool value, Error **err) +static void bus_set_realized(Object *obj, bool value, Error **errp) { BusState *bus = BUS(obj); BusClass *bc = BUS_GET_CLASS(bus); @@ -540,7 +540,7 @@ static void bus_set_realized(Object *obj, bool value, Error **err) return; error: - error_propagate(err, local_err); + error_propagate(errp, local_err); } void qbus_create_inplace(void *bus, size_t size, const char *typename, @@ -660,8 +660,8 @@ static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, * Legacy properties are string versions of other OOM properties. The format * of the string depends on the property type. */ -void qdev_property_add_legacy(DeviceState *dev, Property *prop, - Error **errp) +static void qdev_property_add_legacy(DeviceState *dev, Property *prop, + Error **errp) { gchar *name; @@ -724,13 +724,13 @@ void qdev_property_add_static(DeviceState *dev, Property *prop, } } -static bool device_get_realized(Object *obj, Error **err) +static bool device_get_realized(Object *obj, Error **errp) { DeviceState *dev = DEVICE(obj); return dev->realized; } -static void device_set_realized(Object *obj, bool value, Error **err) +static void device_set_realized(Object *obj, bool value, Error **errp) { DeviceState *dev = DEVICE(obj); DeviceClass *dc = DEVICE_GET_CLASS(dev); @@ -738,7 +738,7 @@ static void device_set_realized(Object *obj, bool value, Error **err) Error *local_err = NULL; if (dev->hotplugged && !dc->hotpluggable) { - error_set(err, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj)); + error_set(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj)); return; } @@ -797,14 +797,14 @@ static void device_set_realized(Object *obj, bool value, Error **err) } if (local_err != NULL) { - error_propagate(err, local_err); + error_propagate(errp, local_err); return; } dev->realized = value; } -static bool device_get_hotpluggable(Object *obj, Error **err) +static bool device_get_hotpluggable(Object *obj, Error **errp) { DeviceClass *dc = DEVICE_GET_CLASS(obj); DeviceState *dev = DEVICE(obj); diff --git a/hw/display/qxl.c b/hw/display/qxl.c index e9c54d7399..7fb83e4eaf 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2055,7 +2055,6 @@ static int qxl_init_primary(PCIDevice *dev) { PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; - PortioList *qxl_vga_port_list = g_new(PortioList, 1); int rc; qxl->id = 0; @@ -2064,10 +2063,10 @@ static int qxl_init_primary(PCIDevice *dev) vga_common_init(vga, OBJECT(dev), true); vga_init(vga, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev), false); - portio_list_init(qxl_vga_port_list, OBJECT(dev), qxl_vga_portio_list, + portio_list_init(&qxl->vga_port_list, OBJECT(dev), qxl_vga_portio_list, vga, "vga"); - portio_list_set_flush_coalesced(qxl_vga_port_list); - portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); + portio_list_set_flush_coalesced(&qxl->vga_port_list); + portio_list_add(&qxl->vga_port_list, pci_address_space_io(dev), 0x3b0); vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl); qemu_spice_display_init_common(&qxl->ssd); diff --git a/hw/display/qxl.h b/hw/display/qxl.h index c5de3d7075..412e346b68 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -32,6 +32,7 @@ enum qxl_mode { typedef struct PCIQXLDevice { PCIDevice pci; + PortioList vga_port_list; SimpleSpiceDisplay ssd; int id; uint32_t debug; diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 971152edbd..97270077e2 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -312,18 +312,42 @@ static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) return -EINVAL; s->cmd_len = qemu_get_be32(f); + if (s->cmd_len < 0 || s->cmd_len > ARRAY_SIZE(s->cmd_data)) { + return -EINVAL; + } s->cmd = qemu_get_be32(f); for (i = 0; i < 8; i++) s->cmd_data[i] = qemu_get_be32(f); s->row = qemu_get_be32(f); + if (s->row < 0 || s->row >= 80) { + return -EINVAL; + } s->row_start = qemu_get_be32(f); + if (s->row_start < 0 || s->row_start >= 80) { + return -EINVAL; + } s->row_end = qemu_get_be32(f); + if (s->row_end < 0 || s->row_end >= 80) { + return -EINVAL; + } s->col = qemu_get_be32(f); + if (s->col < 0 || s->col >= 64) { + return -EINVAL; + } s->col_start = qemu_get_be32(f); + if (s->col_start < 0 || s->col_start >= 64) { + return -EINVAL; + } s->col_end = qemu_get_be32(f); + if (s->col_end < 0 || s->col_end >= 64) { + return -EINVAL; + } s->redraw = qemu_get_be32(f); s->remap = qemu_get_be32(f); s->mode = qemu_get_be32(f); + if (s->mode != SSD0323_CMD && s->mode != SSD0323_DATA) { + return -EINVAL; + } qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); ss->cs = qemu_get_be32(f); diff --git a/hw/display/vga.c b/hw/display/vga.c index c4c3238d5f..8cd6afe83a 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -2355,8 +2355,6 @@ void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space, { MemoryRegion *vga_io_memory; const MemoryRegionPortio *vga_ports, *vbe_ports; - PortioList *vga_port_list = g_new(PortioList, 1); - PortioList *vbe_port_list = g_new(PortioList, 1); qemu_register_reset(vga_reset, s); @@ -2371,13 +2369,13 @@ void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space, 1); memory_region_set_coalescing(vga_io_memory); if (init_vga_ports) { - portio_list_init(vga_port_list, obj, vga_ports, s, "vga"); - portio_list_set_flush_coalesced(vga_port_list); - portio_list_add(vga_port_list, address_space_io, 0x3b0); + portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga"); + portio_list_set_flush_coalesced(&s->vga_port_list); + portio_list_add(&s->vga_port_list, address_space_io, 0x3b0); } if (vbe_ports) { - portio_list_init(vbe_port_list, obj, vbe_ports, s, "vbe"); - portio_list_add(vbe_port_list, address_space_io, 0x1ce); + portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe"); + portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce); } } diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index d42ac926e3..5320abdc07 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -124,6 +124,8 @@ typedef struct VGACommonState { void (*get_resolution)(struct VGACommonState *s, int *pwidth, int *pheight); + PortioList vga_port_list; + PortioList vbe_port_list; /* bochs vbe state */ uint16_t vbe_index; uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; diff --git a/hw/dma/i82374.c b/hw/dma/i82374.c index dc7a767ee2..b8ad2e64ec 100644 --- a/hw/dma/i82374.c +++ b/hw/dma/i82374.c @@ -39,6 +39,7 @@ do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0) typedef struct I82374State { uint8_t commands[8]; qemu_irq out; + PortioList port_list; } I82374State; static const VMStateDescription vmstate_i82374 = { @@ -137,10 +138,10 @@ static void i82374_isa_realize(DeviceState *dev, Error **errp) { ISAi82374State *isa = I82374(dev); I82374State *s = &isa->state; - PortioList *port_list = g_new(PortioList, 1); - portio_list_init(port_list, OBJECT(isa), i82374_portio_list, s, "i82374"); - portio_list_add(port_list, isa_address_space_io(&isa->parent_obj), + portio_list_init(&s->port_list, OBJECT(isa), i82374_portio_list, s, + "i82374"); + portio_list_add(&s->port_list, isa_address_space_io(&isa->parent_obj), isa->iobase); i82374_realize(s, errp); diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 14b887bfa8..cc90eb5110 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -534,24 +534,24 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev); XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM( &s->rx_control_dev); - Error *local_errp = NULL; + Error *local_err = NULL; object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, (Object **)&ds->dma, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, - &local_errp); + &local_err); object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA, (Object **)&cs->dma, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, - &local_errp); - if (local_errp) { + &local_err); + if (local_err) { goto xilinx_axidma_realize_fail; } - object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_errp); - object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_errp); - if (local_errp) { + object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_err); + object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_err); + if (local_err) { goto xilinx_axidma_realize_fail; } @@ -567,7 +567,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) xilinx_axidma_realize_fail: if (!*errp) { - *errp = local_errp; + *errp = local_err; } } diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index dc79a8baa6..8e2ce049de 100644 --- a/hw/gpio/zaurus.c +++ b/hw/gpio/zaurus.c @@ -203,6 +203,15 @@ static bool is_version_0 (void *opaque, int version_id) return version_id == 0; } +static bool vmstate_scoop_validate(void *opaque, int version_id) +{ + ScoopInfo *s = opaque; + + return !(s->prev_level & 0xffff0000) && + !(s->gpio_level & 0xffff0000) && + !(s->gpio_dir & 0xffff0000); +} + static const VMStateDescription vmstate_scoop_regs = { .name = "scoop", .version_id = 1, @@ -215,6 +224,7 @@ static const VMStateDescription vmstate_scoop_regs = { VMSTATE_UINT32(gpio_level, ScoopInfo), VMSTATE_UINT32(gpio_dir, ScoopInfo), VMSTATE_UINT32(prev_level, ScoopInfo), + VMSTATE_VALIDATE("irq levels are 16 bit", vmstate_scoop_validate), VMSTATE_UINT16(mcr, ScoopInfo), VMSTATE_UINT16(cdr, ScoopInfo), VMSTATE_UINT16(ccr, ScoopInfo), diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index 9f50067735..fedb5fb4d4 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -60,59 +60,78 @@ static void smb_transaction(PMSMBus *s) uint8_t cmd = s->smb_cmd; uint8_t addr = s->smb_addr >> 1; I2CBus *bus = s->smbus; + int ret; SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); /* Transaction isn't exec if STS_DEV_ERR bit set */ if ((s->smb_stat & STS_DEV_ERR) != 0) { - goto error; - } + goto error; + } switch(prot) { case 0x0: - smbus_quick_command(bus, addr, read); - s->smb_stat |= STS_BYTE_DONE | STS_INTR; - break; + ret = smbus_quick_command(bus, addr, read); + goto done; case 0x1: if (read) { - s->smb_data0 = smbus_receive_byte(bus, addr); + ret = smbus_receive_byte(bus, addr); + goto data8; } else { - smbus_send_byte(bus, addr, cmd); + ret = smbus_send_byte(bus, addr, cmd); + goto done; } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; - break; case 0x2: if (read) { - s->smb_data0 = smbus_read_byte(bus, addr, cmd); + ret = smbus_read_byte(bus, addr, cmd); + goto data8; } else { - smbus_write_byte(bus, addr, cmd, s->smb_data0); + ret = smbus_write_byte(bus, addr, cmd, s->smb_data0); + goto done; } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; case 0x3: if (read) { - uint16_t val; - val = smbus_read_word(bus, addr, cmd); - s->smb_data0 = val; - s->smb_data1 = val >> 8; + ret = smbus_read_word(bus, addr, cmd); + goto data16; } else { - smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); + ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); + goto done; } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; case 0x5: if (read) { - s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data); + ret = smbus_read_block(bus, addr, cmd, s->smb_data); + goto data8; } else { - smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); + ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); + goto done; } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; default: goto error; } + abort(); + +data16: + if (ret < 0) { + goto error; + } + s->smb_data1 = ret >> 8; +data8: + if (ret < 0) { + goto error; + } + s->smb_data0 = ret; +done: + if (ret < 0) { + goto error; + } + s->smb_stat |= STS_BYTE_DONE | STS_INTR; return; - error: +error: s->smb_stat |= STS_DEV_ERR; + return; + } static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c index 3febf3c258..6e27ae8bd2 100644 --- a/hw/i2c/smbus.c +++ b/hw/i2c/smbus.c @@ -208,34 +208,44 @@ static int smbus_device_init(I2CSlave *i2c) } /* Master device commands. */ -void smbus_quick_command(I2CBus *bus, uint8_t addr, int read) +int smbus_quick_command(I2CBus *bus, uint8_t addr, int read) { - i2c_start_transfer(bus, addr, read); + if (i2c_start_transfer(bus, addr, read)) { + return -1; + } i2c_end_transfer(bus); + return 0; } -uint8_t smbus_receive_byte(I2CBus *bus, uint8_t addr) +int smbus_receive_byte(I2CBus *bus, uint8_t addr) { uint8_t data; - i2c_start_transfer(bus, addr, 1); + if (i2c_start_transfer(bus, addr, 1)) { + return -1; + } data = i2c_recv(bus); i2c_nack(bus); i2c_end_transfer(bus); return data; } -void smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data) +int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data) { - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, data); i2c_end_transfer(bus); + return 0; } -uint8_t smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) +int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) { uint8_t data; - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); data = i2c_recv(bus); @@ -244,18 +254,23 @@ uint8_t smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) return data; } -void smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data) +int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data) { - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_send(bus, data); i2c_end_transfer(bus); + return 0; } -uint16_t smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) +int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) { uint16_t data; - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); data = i2c_recv(bus); @@ -265,13 +280,16 @@ uint16_t smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) return data; } -void smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) +int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) { - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_send(bus, data & 0xff); i2c_send(bus, data >> 8); i2c_end_transfer(bus); + return 0; } int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) @@ -279,33 +297,41 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) int len; int i; - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); len = i2c_recv(bus); - if (len > 32) + if (len > 32) { len = 0; - for (i = 0; i < len; i++) + } + for (i = 0; i < len; i++) { data[i] = i2c_recv(bus); + } i2c_nack(bus); i2c_end_transfer(bus); return len; } -void smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, - int len) +int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, + int len) { int i; if (len > 32) len = 32; - i2c_start_transfer(bus, addr, 0); + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } i2c_send(bus, command); i2c_send(bus, len); - for (i = 0; i < len; i++) + for (i = 0; i < len; i++) { i2c_send(bus, data[i]); + } i2c_end_transfer(bus); + return 0; } static void smbus_device_class_init(ObjectClass *klass, void *data) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 3df1612651..f66c349508 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -2,7 +2,7 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += multiboot.o smbios.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o -obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o +obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o obj-y += acpi-build.o diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index c98df88cd2..9fac589033 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -156,18 +156,21 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) } else { pm->s3_disabled = false; } + qobject_decref(o); o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_DISABLED, NULL); if (o) { pm->s4_disabled = qint_get_int(qobject_to_qint(o)); } else { pm->s4_disabled = false; } + qobject_decref(o); o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_VAL, NULL); if (o) { pm->s4_val = qint_get_int(qobject_to_qint(o)); } else { pm->s4_val = false; } + qobject_decref(o); /* Fill in mandatory properties */ pm->sci_int = object_property_get_int(obj, ACPI_PM_PROP_SCI_INT, NULL); @@ -973,6 +976,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state) } } + qobject_decref(bsel); build_free_array(bus_table); build_pci_bus_state_cleanup(child); g_free(child); @@ -1362,10 +1366,12 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return false; } mcfg->mcfg_base = qint_get_int(qobject_to_qint(o)); + qobject_decref(o); o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL); assert(o); mcfg->mcfg_size = qint_get_int(qobject_to_qint(o)); + qobject_decref(o); return true; } @@ -1410,15 +1416,16 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) /* ACPI tables pointed to by RSDT */ acpi_add_table(table_offsets, tables->table_data); build_fadt(tables->table_data, tables->linker, &pm, facs, dsdt); - acpi_add_table(table_offsets, tables->table_data); + acpi_add_table(table_offsets, tables->table_data); build_ssdt(tables->table_data, tables->linker, &cpu, &pm, &misc, &pci, guest_info); - acpi_add_table(table_offsets, tables->table_data); - build_madt(tables->table_data, tables->linker, &cpu, guest_info); acpi_add_table(table_offsets, tables->table_data); + build_madt(tables->table_data, tables->linker, &cpu, guest_info); + if (misc.has_hpet) { + acpi_add_table(table_offsets, tables->table_data); build_hpet(tables->table_data, tables->linker); } if (guest_info->numa_nodes) { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index ea72502420..eaf3e61994 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -414,6 +414,10 @@ static QEMUMachine pc_i440fx_machine_v2_0 = { PC_I440FX_2_0_MACHINE_OPTIONS, .name = "pc-i440fx-2.0", .init = pc_init_pci_2_0, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_2_0, + { /* end of list */ } + }, }; #define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 3306f89b9e..9517ec653f 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -327,6 +327,10 @@ static QEMUMachine pc_q35_machine_v2_0 = { PC_Q35_2_0_MACHINE_OPTIONS, .name = "pc-q35-2.0", .init = pc_q35_init_2_0, + .compat_props = (GlobalProperty[]) { + PC_Q35_COMPAT_2_0, + { /* end of list */ } + }, }; #define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS diff --git a/hw/i386/xen/Makefile.objs b/hw/i386/xen/Makefile.objs new file mode 100644 index 0000000000..801a68d326 --- /dev/null +++ b/hw/i386/xen/Makefile.objs @@ -0,0 +1 @@ +obj-y += xen_platform.o xen_apic.o xen_pvdevice.o diff --git a/hw/xen/xen_apic.c b/hw/i386/xen/xen_apic.c index 63bb7f77c6..63bb7f77c6 100644 --- a/hw/xen/xen_apic.c +++ b/hw/i386/xen/xen_apic.c diff --git a/hw/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 1d9d0e9f25..1d9d0e9f25 100644 --- a/hw/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c diff --git a/hw/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c index c2189473ba..c2189473ba 100644 --- a/hw/xen/xen_pvdevice.c +++ b/hw/i386/xen/xen_pvdevice.c diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 50327ffdf1..e57c5837d2 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1293,7 +1293,7 @@ const VMStateDescription vmstate_ahci = { VMSTATE_UINT32(control_regs.impl, AHCIState), VMSTATE_UINT32(control_regs.version, AHCIState), VMSTATE_UINT32(idp_index, AHCIState), - VMSTATE_INT32(ports, AHCIState), + VMSTATE_INT32_EQUAL(ports, AHCIState), VMSTATE_END_OF_LIST() }, }; diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index 485c9e5753..aa5b6886ea 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -1070,9 +1070,21 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) s->enabled = qemu_get_byte(f); s->host_mode = qemu_get_byte(f); s->function = qemu_get_byte(f); + if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) { + return -EINVAL; + } s->nextfunction = qemu_get_byte(f); + if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) { + return -EINVAL; + } s->precision = qemu_get_byte(f); + if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) { + return -EINVAL; + } s->nextprecision = qemu_get_byte(f); + if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) { + return -EINVAL; + } s->filter = qemu_get_byte(f); s->pin_func = qemu_get_byte(f); s->ref = qemu_get_byte(f); diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 2f40cbad2d..ef19e5515c 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -675,7 +675,7 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr) val = s->id << 24; break; case 0x03: /* version */ - val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */ + val = s->version | ((APIC_LVT_NB - 1) << 16); break; case 0x08: apic_sync_vapic(s, SYNC_FROM_VAPIC); diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 7ecce2dcce..71376533ca 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -380,6 +380,7 @@ static const VMStateDescription vmstate_apic_common = { static Property apic_properties_common[] = { DEFINE_PROP_UINT8("id", APICCommonState, id, -1), + DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14), DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT, true), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 955b8d4945..1532ef9482 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -797,9 +797,11 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) GICState *s = ARM_GIC(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); ARMGICClass *agc = ARM_GIC_GET_CLASS(s); + Error *local_err = NULL; - agc->parent_realize(dev, errp); - if (error_is_set(errp)) { + agc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 719d2277ec..5038885afd 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -517,10 +517,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) GICState *s = KVM_ARM_GIC(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); + Error *local_err = NULL; int ret; - kgc->parent_realize(dev, errp); - if (error_is_set(errp)) { + kgc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index f5b0c3be6f..9aa8ab208f 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -474,14 +474,16 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) { nvic_state *s = NVIC(dev); NVICClass *nc = NVIC_GET_CLASS(s); + Error *local_err = NULL; /* The NVIC always has only one CPU */ s->gic.num_cpu = 1; /* Tell the common code we're an NVIC */ s->gic.revision = 0xffffffff; s->num_irq = s->gic.num_irq; - nc->parent_realize(dev, errp); - if (error_is_set(errp)) { + nc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } gic_init_irqs_and_distributor(&s->gic, s->num_irq); diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index c6f248b145..d0b0c52b97 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -265,7 +265,8 @@ static void pic_ioport_write(void *opaque, hwaddr addr64, s->init4 = val & 1; s->single_mode = val & 2; if (val & 0x08) { - hw_error("level sensitive irq not supported"); + qemu_log_mask(LOG_UNIMP, + "i8259: level sensitive irq not supported\n"); } } else if (val & 0x08) { if (val & 0x04) { @@ -412,7 +413,7 @@ static const MemoryRegionOps pic_elcr_ioport_ops = { }, }; -static void pic_realize(DeviceState *dev, Error **err) +static void pic_realize(DeviceState *dev, Error **errp) { PICCommonState *s = PIC_COMMON(dev); PICClass *pc = PIC_GET_CLASS(dev); @@ -425,7 +426,7 @@ static void pic_realize(DeviceState *dev, Error **err) qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out)); qdev_init_gpio_in(dev, pic_set_irq, 8); - pc->parent_realize(dev, err); + pc->parent_realize(dev, errp); } void pic_info(Monitor *mon, const QDict *qdict) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index be76fbd78f..17136c9333 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -41,6 +41,7 @@ #include "hw/sysbus.h" #include "hw/pci/msi.h" #include "qemu/bitops.h" +#include "qapi/qmp/qerror.h" //#define DEBUG_OPENPIC @@ -1416,7 +1417,7 @@ static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) static int openpic_load(QEMUFile* f, void *opaque, int version_id) { OpenPICState *opp = (OpenPICState *)opaque; - unsigned int i; + unsigned int i, nb_cpus; if (version_id != 1) { return -EINVAL; @@ -1428,7 +1429,11 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->spve); qemu_get_be32s(f, &opp->tfrr); - qemu_get_be32s(f, &opp->nb_cpus); + qemu_get_be32s(f, &nb_cpus); + if (opp->nb_cpus != nb_cpus) { + return -EINVAL; + } + assert(nb_cpus > 0 && nb_cpus <= MAX_CPU); for (i = 0; i < opp->nb_cpus; i++) { qemu_get_sbe32s(f, &opp->dst[i].ctpr); @@ -1567,6 +1572,13 @@ static void openpic_realize(DeviceState *dev, Error **errp) {NULL} }; + if (opp->nb_cpus > MAX_CPU) { + error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, + TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus, + (uint64_t)0, (uint64_t)MAX_CPU); + return; + } + switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: default: diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 55d01008d3..b28981bfde 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -108,15 +108,20 @@ void isa_register_portio_list(ISADevice *dev, uint16_t start, const MemoryRegionPortio *pio_start, void *opaque, const char *name) { - PortioList *piolist = g_new(PortioList, 1); + PortioList piolist; /* START is how we should treat DEV, regardless of the actual contents of the portio array. This is how the old code actually handled e.g. the FDC device. */ isa_init_ioport(dev, start); - portio_list_init(piolist, OBJECT(dev), pio_start, opaque, name); - portio_list_add(piolist, isabus->address_space_io, start); + /* FIXME: the device should store created PortioList in its state. Note + that DEV can be NULL here and that single device can register several + portio lists. Current implementation is leaking memory allocated + in portio_list_init. The leak is not critical because it happens only + at initialization time. */ + portio_list_init(&piolist, OBJECT(dev), pio_start, opaque, name); + portio_list_add(&piolist, isabus->address_space_io, start); } static void isa_device_init(Object *obj) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index e1551aabe2..30d9f19df7 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -211,7 +211,7 @@ static void main_cpu_reset(void *opaque) } } -uint8_t eeprom_spd[0x80] = { +static const uint8_t eeprom_spd[0x80] = { 0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70, 0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01, 0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50, diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index 63aa3d6277..636ee97b16 100644 --- a/hw/misc/tmp105.c +++ b/hw/misc/tmp105.c @@ -68,10 +68,12 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { TMP105State *s = TMP105(obj); + Error *local_err = NULL; int64_t temp; - visit_type_int(v, &temp, name, errp); - if (error_is_set(errp)) { + visit_type_int(v, &temp, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (temp >= 128000 || temp < -128000) { diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index e34b25e734..cdb18253b6 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -388,7 +388,7 @@ typedef struct GemState { } GemState; /* The broadcast MAC address: 0xFFFFFFFFFFFF */ -const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* * gem_init_register_masks: diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 33bd233a2d..940a7cfe54 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1362,10 +1362,17 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) { qemu_get_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); - } else if (n->mac_table.in_use) { - uint8_t *buf = g_malloc0(n->mac_table.in_use); - qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN); - g_free(buf); + } else { + int64_t i; + + /* Overflow detected - can happen if source has a larger MAC table. + * We simply set overflow flag so there's no need to maintain the + * table of addresses, discard them all. + * Note: 64 bit math to avoid integer overflow. + */ + for (i = 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) { + qemu_get_byte(f); + } n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; n->mac_table.in_use = 0; } @@ -1407,6 +1414,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } n->curr_queues = qemu_get_be16(f); + if (n->curr_queues > n->max_queues) { + error_report("virtio-net: curr_queues %x > max_queues %x", + n->curr_queues, n->max_queues); + return -1; + } for (i = 1; i < n->curr_queues; i++) { n->vqs[i].tx_waiting = qemu_get_be32(f); } diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index ddcee4bd21..1bb9259df2 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2305,7 +2305,7 @@ static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size) vmxnet3_put_tx_stats_to_file(f, &r->txq_stats); } -const VMStateInfo txq_descr_info = { +static const VMStateInfo txq_descr_info = { .name = "txq_descr", .get = vmxnet3_get_txq_descr, .put = vmxnet3_put_txq_descr @@ -2397,7 +2397,7 @@ static int vmxnet3_post_load(void *opaque, int version_id) return 0; } -const VMStateInfo rxq_descr_info = { +static const VMStateInfo rxq_descr_info = { .name = "rxq_descr", .get = vmxnet3_get_rxq_descr, .put = vmxnet3_put_rxq_descr @@ -2423,7 +2423,7 @@ static void vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size) qemu_put_byte(f, r->is_asserted); } -const VMStateInfo int_state_info = { +static const VMStateInfo int_state_info = { .name = "int_state", .get = vmxnet3_get_int_state, .put = vmxnet3_put_int_state diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index 9384fa0c5c..88349ac6a2 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -152,7 +152,7 @@ typedef struct XgmacState { uint32_t regs[R_MAX]; } XgmacState; -const VMStateDescription vmstate_rxtx_stats = { +static const VMStateDescription vmstate_rxtx_stats = { .name = "xgmac_stats", .version_id = 1, .minimum_version_id = 1, diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index dbeb3c9a25..cd952d2514 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -945,24 +945,24 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev); XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM( &s->rx_control_dev); - Error *local_errp = NULL; + Error *local_err = NULL; object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", (Object **) &ds->enet, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, - &local_errp); + &local_err); object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet", (Object **) &cs->enet, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, - &local_errp); - if (local_errp) { + &local_err); + if (local_err) { goto xilinx_enet_realize_fail; } - object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_errp); - object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_errp); - if (local_errp) { + object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_err); + object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_err); + if (local_err) { goto xilinx_enet_realize_fail; } @@ -981,7 +981,7 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) xilinx_enet_realize_fail: if (!*errp) { - *errp = local_errp; + *errp = local_err; } } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2a9f08eb0a..517ff2a21b 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -475,7 +475,7 @@ const VMStateDescription vmstate_pci_device = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_INT32_LE(version_id, PCIDevice), + VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice), VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, vmstate_info_pci_config, PCI_CONFIG_SPACE_SIZE), @@ -492,7 +492,7 @@ const VMStateDescription vmstate_pcie_device = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_INT32_LE(version_id, PCIDevice), + VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice), VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0, vmstate_info_pci_config, PCIE_CONFIG_SPACE_SIZE), diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index 991502e517..535be2c08a 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -795,6 +795,13 @@ static const VMStateDescription vmstate_pcie_aer_err = { } }; +static bool pcie_aer_state_log_num_valid(void *opaque, int version_id) +{ + PCIEAERLog *s = opaque; + + return s->log_num <= s->log_max; +} + const VMStateDescription vmstate_pcie_aer_log = { .name = "PCIE_AER_ERROR_LOG", .version_id = 1, @@ -802,7 +809,8 @@ const VMStateDescription vmstate_pcie_aer_log = { .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT16(log_num, PCIEAERLog), - VMSTATE_UINT16(log_max, PCIEAERLog), + VMSTATE_UINT16_EQUAL(log_max, PCIEAERLog), + VMSTATE_VALIDATE("log_num <= log_max", pcie_aer_state_log_num_valid), VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, vmstate_pcie_aer_err, PCIEAERErr), VMSTATE_END_OF_LIST() diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index e2436512f7..585937321f 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -361,6 +361,8 @@ static const MemoryRegionPortio prep_portio_list[] = { PORTIO_END_OF_LIST(), }; +static PortioList prep_port_list; + /* PowerPC PREP hardware initialisation */ static void ppc_prep_init(QEMUMachineInitArgs *args) { @@ -375,7 +377,6 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) CPUPPCState *env = NULL; nvram_t nvram; M48t59State *m48t59; - PortioList *port_list = g_new(PortioList, 1); #if 0 MemoryRegion *xcsr = g_new(MemoryRegion, 1); #endif @@ -542,8 +543,8 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) cpu = POWERPC_CPU(first_cpu); sysctrl->reset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET]; - portio_list_init(port_list, NULL, prep_portio_list, sysctrl, "prep"); - portio_list_add(port_list, isa_address_space_io(isa), 0x0); + portio_list_init(&prep_port_list, NULL, prep_portio_list, sysctrl, "prep"); + portio_list_add(&prep_port_list, isa_address_space_io(isa), 0x0); /* PowerPC control and status register group */ #if 0 diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index a11e1217b9..b4ce950bbd 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1419,19 +1419,6 @@ static int spapr_kvm_type(const char *vm_type) exit(1); } -static QEMUMachine spapr_machine = { - .name = "pseries", - .desc = "pSeries Logical Partition (PAPR compliant)", - .is_default = 1, - .init = ppc_spapr_init, - .reset = ppc_spapr_reset, - .block_default_type = IF_SCSI, - .max_cpus = MAX_CPUS, - .no_parallel = 1, - .default_boot_order = NULL, - .kvm_type = spapr_kvm_type, -}; - /* * Implementation of an interface to adjust firmware patch * for the bootindex property handling. @@ -1494,7 +1481,17 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) MachineClass *mc = MACHINE_CLASS(oc); FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); - mc->qemu_machine = data; + mc->name = "pseries"; + mc->desc = "pSeries Logical Partition (PAPR compliant)"; + mc->is_default = 1; + mc->init = ppc_spapr_init; + mc->reset = ppc_spapr_reset; + mc->block_default_type = IF_SCSI; + mc->max_cpus = MAX_CPUS; + mc->no_parallel = 1; + mc->default_boot_order = NULL; + mc->kvm_type = spapr_kvm_type; + fwc->get_dev_path = spapr_get_fw_dev_path; } @@ -1502,7 +1499,6 @@ static const TypeInfo spapr_machine_info = { .name = TYPE_SPAPR_MACHINE, .parent = TYPE_MACHINE, .class_init = spapr_machine_class_init, - .class_data = &spapr_machine, .interfaces = (InterfaceInfo[]) { { TYPE_FW_PATH_PROVIDER }, { } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index d9fe946818..72493d802a 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -35,7 +35,7 @@ enum sPAPRTCEAccess { SPAPR_TCE_RW = 3, }; -QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; +static QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) { diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 73860d0486..ea4a2b2698 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -272,7 +272,7 @@ static struct rtas_call { spapr_rtas_fn fn; } rtas_table[TOKEN_MAX]; -struct rtas_call *rtas_next = rtas_table; +static struct rtas_call *rtas_next = rtas_table; target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 7074d2b3d5..122cc7e66f 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -140,7 +140,6 @@ static void sch_handle_clear_func(SubchDev *sch) s->flags &= ~SCSW_FLAGS_MASK_PNO; /* We always 'attempt to issue the clear signal', and we always succeed. */ - sch->orb = NULL; sch->channel_prog = 0x0; sch->last_cmd_valid = false; s->ctrl &= ~SCSW_ACTL_CLEAR_PEND; @@ -163,7 +162,6 @@ static void sch_handle_halt_func(SubchDev *sch) path = 0x80; /* We always 'attempt to issue the halt signal', and we always succeed. */ - sch->orb = NULL; sch->channel_prog = 0x0; sch->last_cmd_valid = false; s->ctrl &= ~SCSW_ACTL_HALT_PEND; @@ -317,12 +315,11 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) return ret; } -static void sch_handle_start_func(SubchDev *sch) +static void sch_handle_start_func(SubchDev *sch, ORB *orb) { PMCW *p = &sch->curr_status.pmcw; SCSW *s = &sch->curr_status.scsw; - ORB *orb = sch->orb; int path; int ret; @@ -331,6 +328,7 @@ static void sch_handle_start_func(SubchDev *sch) if (!(s->ctrl & SCSW_ACTL_SUSP)) { /* Look at the orb and try to execute the channel program. */ + assert(orb != NULL); /* resume does not pass an orb */ p->intparm = orb->intparm; if (!(orb->lpm & path)) { /* Generate a deferred cc 3 condition. */ @@ -406,7 +404,7 @@ static void sch_handle_start_func(SubchDev *sch) * read/writes) asynchronous later on if we start supporting more than * our current very simple devices. */ -static void do_subchannel_work(SubchDev *sch) +static void do_subchannel_work(SubchDev *sch, ORB *orb) { SCSW *s = &sch->curr_status.scsw; @@ -416,7 +414,7 @@ static void do_subchannel_work(SubchDev *sch) } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) { sch_handle_halt_func(sch); } else if (s->ctrl & SCSW_FCTL_START_FUNC) { - sch_handle_start_func(sch); + sch_handle_start_func(sch, orb); } else { /* Cannot happen. */ return; @@ -594,7 +592,6 @@ int css_do_xsch(SubchDev *sch) SCSW_ACTL_SUSP); sch->channel_prog = 0x0; sch->last_cmd_valid = false; - sch->orb = NULL; s->dstat = 0; s->cstat = 0; ret = 0; @@ -618,7 +615,7 @@ int css_do_csch(SubchDev *sch) s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL); s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_CLEAR_FUNC; - do_subchannel_work(sch); + do_subchannel_work(sch, NULL); ret = 0; out: @@ -659,7 +656,7 @@ int css_do_hsch(SubchDev *sch) } s->ctrl |= SCSW_ACTL_HALT_PEND; - do_subchannel_work(sch); + do_subchannel_work(sch, NULL); ret = 0; out: @@ -721,13 +718,12 @@ int css_do_ssch(SubchDev *sch, ORB *orb) if (channel_subsys->chnmon_active) { css_update_chnmon(sch); } - sch->orb = orb; sch->channel_prog = orb->cpa; /* Trigger the start function. */ s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); s->flags &= ~SCSW_FLAGS_MASK_PNO; - do_subchannel_work(sch); + do_subchannel_work(sch, orb); ret = 0; out: @@ -957,7 +953,7 @@ int css_do_rsch(SubchDev *sch) } s->ctrl |= SCSW_ACTL_RESUME_PEND; - do_subchannel_work(sch); + do_subchannel_work(sch, NULL); ret = 0; out: @@ -1267,7 +1263,6 @@ void css_reset_sch(SubchDev *sch) sch->channel_prog = 0x0; sch->last_cmd_valid = false; - sch->orb = NULL; sch->thinint_active = false; } diff --git a/hw/s390x/css.h b/hw/s390x/css.h index e9b440540d..220169e7c3 100644 --- a/hw/s390x/css.h +++ b/hw/s390x/css.h @@ -76,7 +76,6 @@ struct SubchDev { hwaddr channel_prog; CCW1 last_cmd; bool last_cmd_valid; - ORB *orb; bool thinint_active; /* transport-provided data: */ int (*ccw_cb) (SubchDev *, CCW1); diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 0777a93916..2e9e62fe1f 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -32,7 +32,7 @@ struct SCLPEventFacility { unsigned int receive_mask; }; -SCLPEvent cpu_hotplug; +static SCLPEvent cpu_hotplug; /* return true if any child has event pending set */ static bool event_pending(SCLPEventFacility *ef) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 2bf0af8f0a..1cb4e2c2f8 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -559,7 +559,6 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev) /* Initialize subchannel structure. */ sch->channel_prog = 0x0; sch->last_cmd_valid = false; - sch->orb = NULL; sch->thinint_active = false; /* * Use a device number if provided. Otherwise, fall back to subchannel diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index ae921a6a75..abe73022c0 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1179,7 +1179,7 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd) return lba; } -int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) { int rc; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index b0d7517cb1..175219376c 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -147,6 +147,15 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) qemu_get_be32s(f, &n); assert(n < vs->conf.num_queues); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); + /* TODO: add a way for SCSIBusInfo's load_request to fail, + * and fail migration instead of asserting here. + * When we do, we might be able to re-enable NDEBUG below. + */ +#ifdef NDEBUG +#error building with NDEBUG is not supported +#endif + assert(req->elem.in_num <= ARRAY_SIZE(req->elem.in_sg)); + assert(req->elem.out_num <= ARRAY_SIZE(req->elem.out_sg)); virtio_scsi_parse_req(s, vs->cmd_vqs[n], req); scsi_req_ref(sreq); diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 3273c8a31f..b012e57f64 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -230,8 +230,17 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) for (i = 0; i < 5; i++) s->response[i] = qemu_get_be32(f); s->arglen = qemu_get_be32(f); + if (s->mode == SSI_SD_CMDARG && + (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) { + return -EINVAL; + } s->response_pos = qemu_get_be32(f); s->stopping = qemu_get_be32(f); + if (s->mode == SSI_SD_RESPONSE && + (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) || + (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) { + return -EINVAL; + } ss->cs = qemu_get_be32(f); diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c index fd479effb9..b19bc7174a 100644 --- a/hw/ssi/pl022.c +++ b/hw/ssi/pl022.c @@ -240,11 +240,25 @@ static const MemoryRegionOps pl022_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static int pl022_post_load(void *opaque, int version_id) +{ + PL022State *s = opaque; + + if (s->tx_fifo_head < 0 || + s->tx_fifo_head >= ARRAY_SIZE(s->tx_fifo) || + s->rx_fifo_head < 0 || + s->rx_fifo_head >= ARRAY_SIZE(s->rx_fifo)) { + return -1; + } + return 0; +} + static const VMStateDescription vmstate_pl022 = { .name = "pl022_ssp", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, + .post_load = pl022_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32(cr0, PL022State), VMSTATE_UINT32(cr1, PL022State), diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index e15d6bcac7..2792f89c66 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -239,6 +239,18 @@ static int hpet_pre_load(void *opaque) return 0; } +static bool hpet_validate_num_timers(void *opaque, int version_id) +{ + HPETState *s = opaque; + + if (s->num_timers < HPET_MIN_TIMERS) { + return false; + } else if (s->num_timers > HPET_MAX_TIMERS) { + return false; + } + return true; +} + static int hpet_post_load(void *opaque, int version_id) { HPETState *s = opaque; @@ -307,6 +319,7 @@ static const VMStateDescription vmstate_hpet = { VMSTATE_UINT64(isr, HPETState), VMSTATE_UINT64(hpet_counter, HPETState), VMSTATE_UINT8_V(num_timers, HPETState, 2), + VMSTATE_VALIDATE("num_timers in range", hpet_validate_num_timers), VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0, vmstate_hpet_timer, HPETTimer), VMSTATE_END_OF_LIST() diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c index 28152d88ea..3450c98637 100644 --- a/hw/timer/i8254.c +++ b/hw/timer/i8254.c @@ -322,7 +322,7 @@ static void pit_post_load(PITCommonState *s) } } -static void pit_realizefn(DeviceState *dev, Error **err) +static void pit_realizefn(DeviceState *dev, Error **errp) { PITCommonState *pit = PIT_COMMON(dev); PITClass *pc = PIT_GET_CLASS(dev); @@ -338,7 +338,7 @@ static void pit_realizefn(DeviceState *dev, Error **err) qdev_init_gpio_in(dev, pit_irq_control, 1); - pc->parent_realize(dev, err); + pc->parent_realize(dev, errp); } static Property pit_properties[] = { diff --git a/hw/usb/bus.c b/hw/usb/bus.c index fe70429304..e48b19fc29 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -49,7 +49,9 @@ static int usb_device_post_load(void *opaque, int version_id) } else { dev->attached = 1; } - if (dev->setup_index >= sizeof(dev->data_buf) || + if (dev->setup_index < 0 || + dev->setup_len < 0 || + dev->setup_index >= sizeof(dev->data_buf) || dev->setup_len >= sizeof(dev->data_buf)) { return -EINVAL; } diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 8b44032900..943f930404 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -50,6 +50,7 @@ enum mtp_code { RES_INVALID_TRANSACTION_ID = 0x2004, RES_OPERATION_NOT_SUPPORTED = 0x2005, RES_PARAMETER_NOT_SUPPORTED = 0x2006, + RES_INCOMPLETE_TRANSFER = 0x2007, RES_INVALID_STORAGE_ID = 0x2008, RES_INVALID_OBJECT_HANDLE = 0x2009, RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014, @@ -294,7 +295,7 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle, goto ignore; } - fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path); + trace_usb_mtp_object_alloc(s->dev.addr, o->handle, o->path); QTAILQ_INSERT_TAIL(&s->objects, o, next); return o; @@ -310,7 +311,7 @@ static void usb_mtp_object_free(MTPState *s, MTPObject *o) { int i; - fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path); + trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path); QTAILQ_REMOVE(&s->objects, o, next); for (i = 0; i < o->nchildren; i++) { @@ -416,7 +417,7 @@ static void usb_mtp_add_u32(MTPData *data, uint32_t val) static void usb_mtp_add_u64(MTPData *data, uint64_t val) { - usb_mtp_realloc(data, 4); + usb_mtp_realloc(data, 8); data->data[data->length++] = (val >> 0) & 0xff; data->data[data->length++] = (val >> 8) & 0xff; data->data[data->length++] = (val >> 16) & 0xff; @@ -424,7 +425,7 @@ static void usb_mtp_add_u64(MTPData *data, uint64_t val) data->data[data->length++] = (val >> 32) & 0xff; data->data[data->length++] = (val >> 40) & 0xff; data->data[data->length++] = (val >> 48) & 0xff; - data->data[data->length++] = (val >> 54) & 0xff; + data->data[data->length++] = (val >> 56) & 0xff; } static void usb_mtp_add_u16_array(MTPData *data, uint32_t len, @@ -533,7 +534,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) trace_usb_mtp_op_get_device_info(s->dev.addr); - usb_mtp_add_u16(d, 0x0100); + usb_mtp_add_u16(d, 100); usb_mtp_add_u32(d, 0xffffffff); usb_mtp_add_u16(d, 0x0101); usb_mtp_add_wstr(d, L""); @@ -548,7 +549,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER); usb_mtp_add_wstr(d, L"" MTP_PRODUCT); usb_mtp_add_wstr(d, L"0.1"); - usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef"); + usb_mtp_add_wstr(d, L"0123456789abcdef0123456789abcdef"); return d; } @@ -669,6 +670,7 @@ static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c, d->fd = open(o->path, O_RDONLY); if (d->fd == -1) { + usb_mtp_data_free(d); return NULL; } d->length = o->stat.st_size; @@ -688,6 +690,7 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, d->fd = open(o->path, O_RDONLY); if (d->fd == -1) { + usb_mtp_data_free(d); return NULL; } @@ -843,8 +846,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) res0 = data_in->length; break; default: - fprintf(stderr, "%s: unknown command code 0x%04x\n", - __func__, c->code); + trace_usb_mtp_op_unknown(s->dev.addr, c->code); usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED, c->trans, 0, 0, 0); return; @@ -892,6 +894,7 @@ static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p, static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p) { + /* we don't use async packets, so this should never be called */ fprintf(stderr, "%s\n", __func__); } @@ -944,7 +947,8 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) } rc = read(d->fd, d->data, dlen); if (rc != dlen) { - fprintf(stderr, "%s: TODO: handle read error\n", __func__); + memset(d->data, 0, dlen); + s->result->code = RES_INCOMPLETE_TRANSFER; } usb_packet_copy(p, d->data, dlen); } @@ -996,6 +1000,14 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) cmd.argc = (le32_to_cpu(container.length) - sizeof(container)) / sizeof(uint32_t); cmd.trans = le32_to_cpu(container.trans); + if (cmd.argc > ARRAY_SIZE(cmd.argv)) { + cmd.argc = ARRAY_SIZE(cmd.argv); + } + if (p->iov.size < sizeof(container) + cmd.argc * sizeof(uint32_t)) { + trace_usb_mtp_stall(s->dev.addr, "packet too small"); + p->status = USB_RET_STALL; + return; + } usb_packet_copy(p, ¶ms, cmd.argc * sizeof(uint32_t)); for (i = 0; i < cmd.argc; i++) { cmd.argv[i] = le32_to_cpu(params[i]); @@ -1009,8 +1021,7 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) usb_mtp_command(s, &cmd); break; default: - iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32); - trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out"); + /* not needed as long as the mtp device is read-only */ p->status = USB_RET_STALL; return; } @@ -1044,7 +1055,7 @@ static int usb_mtp_initfn(USBDevice *dev) QTAILQ_INIT(&s->objects); if (s->desc == NULL) { s->desc = strrchr(s->root, '/'); - if (s->desc) { + if (s->desc && s->desc[0]) { s->desc = g_strdup(s->desc + 1); } else { s->desc = g_strdup("none"); diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 93f186f5e7..cd87074862 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -80,13 +80,13 @@ typedef struct { uint32_t bulk_head, bulk_cur; uint32_t per_cur; uint32_t done; - int done_count; + int32_t done_count; /* Frame counter partition */ - uint32_t fsmps:15; - uint32_t fit:1; - uint32_t fi:14; - uint32_t frt:1; + uint16_t fsmps; + uint8_t fit; + uint16_t fi; + uint8_t frt; uint16_t frame_number; uint16_t padding; uint32_t pstart; @@ -111,7 +111,7 @@ typedef struct { USBPacket usb_packet; uint8_t usb_buf[8192]; uint32_t async_td; - int async_complete; + bool async_complete; } OHCIState; @@ -693,7 +693,7 @@ static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) #ifdef DEBUG_PACKET DPRINTF("Async packet complete\n"); #endif - ohci->async_complete = 1; + ohci->async_complete = true; ohci_process_lists(ohci, 1); } @@ -1058,7 +1058,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) #endif if (completion) { ohci->async_td = 0; - ohci->async_complete = 0; + ohci->async_complete = false; } else { if (ohci->async_td) { /* ??? The hardware should allow one active packet per @@ -1984,6 +1984,108 @@ static Property ohci_pci_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_ohci_state_port = { + .name = "ohci-core/port", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(ctrl, OHCIPort), + VMSTATE_END_OF_LIST() + }, +}; + +static bool ohci_eof_timer_needed(void *opaque) +{ + OHCIState *ohci = opaque; + + return ohci->eof_timer != NULL; +} + +static int ohci_eof_timer_pre_load(void *opaque) +{ + OHCIState *ohci = opaque; + + ohci_bus_start(ohci); + + return 0; +} + +static const VMStateDescription vmstate_ohci_eof_timer = { + .name = "ohci-core/eof-timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_load = ohci_eof_timer_pre_load, + .fields = (VMStateField []) { + VMSTATE_TIMER(eof_timer, OHCIState), + VMSTATE_END_OF_LIST() + }, +}; + +const VMStateDescription vmstate_ohci_state = { + .name = "ohci-core", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(sof_time, OHCIState), + VMSTATE_UINT32(ctl, OHCIState), + VMSTATE_UINT32(status, OHCIState), + VMSTATE_UINT32(intr_status, OHCIState), + VMSTATE_UINT32(intr, OHCIState), + VMSTATE_UINT32(hcca, OHCIState), + VMSTATE_UINT32(ctrl_head, OHCIState), + VMSTATE_UINT32(ctrl_cur, OHCIState), + VMSTATE_UINT32(bulk_head, OHCIState), + VMSTATE_UINT32(bulk_cur, OHCIState), + VMSTATE_UINT32(per_cur, OHCIState), + VMSTATE_UINT32(done, OHCIState), + VMSTATE_INT32(done_count, OHCIState), + VMSTATE_UINT16(fsmps, OHCIState), + VMSTATE_UINT8(fit, OHCIState), + VMSTATE_UINT16(fi, OHCIState), + VMSTATE_UINT8(frt, OHCIState), + VMSTATE_UINT16(frame_number, OHCIState), + VMSTATE_UINT16(padding, OHCIState), + VMSTATE_UINT32(pstart, OHCIState), + VMSTATE_UINT32(lst, OHCIState), + VMSTATE_UINT32(rhdesc_a, OHCIState), + VMSTATE_UINT32(rhdesc_b, OHCIState), + VMSTATE_UINT32(rhstatus, OHCIState), + VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0, + vmstate_ohci_state_port, OHCIPort), + VMSTATE_UINT32(hstatus, OHCIState), + VMSTATE_UINT32(hmask, OHCIState), + VMSTATE_UINT32(hreset, OHCIState), + VMSTATE_UINT32(htest, OHCIState), + VMSTATE_UINT32(old_ctl, OHCIState), + VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192), + VMSTATE_UINT32(async_td, OHCIState), + VMSTATE_BOOL(async_complete, OHCIState), + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_ohci_eof_timer, + .needed = ohci_eof_timer_needed, + } , { + /* empty */ + } + } +}; + +static const VMStateDescription vmstate_ohci = { + .name = "ohci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), + VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState), + VMSTATE_END_OF_LIST() + } +}; + static void ohci_pci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1997,6 +2099,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) dc->desc = "Apple USB Controller"; dc->props = ohci_pci_properties; dc->hotpluggable = false; + dc->vmsd = &vmstate_ohci; } static const TypeInfo ohci_pci_info = { diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index a470a0b3a6..971a921777 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -142,10 +142,12 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, Error **errp) { VirtIOBalloon *s = opaque; + Error *local_err = NULL; int64_t value; - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { + visit_type_int(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index aeabf3a459..7f4e7eca0e 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -430,6 +430,12 @@ void virtqueue_map_sg(struct iovec *sg, hwaddr *addr, unsigned int i; hwaddr len; + if (num_sg >= VIRTQUEUE_MAX_SIZE) { + error_report("virtio: map attempt out of bounds: %zd > %d", + num_sg, VIRTQUEUE_MAX_SIZE); + exit(1); + } + for (i = 0; i < num_sg; i++) { len = sg[i].iov_len; sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write); @@ -891,7 +897,9 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val) int virtio_load(VirtIODevice *vdev, QEMUFile *f) { - int num, i, ret; + int i, ret; + int32_t config_len; + uint32_t num; uint32_t features; uint32_t supported_features; BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); @@ -906,6 +914,9 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) qemu_get_8s(f, &vdev->status); qemu_get_8s(f, &vdev->isr); qemu_get_be16s(f, &vdev->queue_sel); + if (vdev->queue_sel >= VIRTIO_PCI_QUEUE_MAX) { + return -1; + } qemu_get_be32s(f, &features); if (virtio_set_features(vdev, features) < 0) { @@ -914,11 +925,21 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) features, supported_features); return -1; } - vdev->config_len = qemu_get_be32(f); + config_len = qemu_get_be32(f); + if (config_len != vdev->config_len) { + error_report("Unexpected config length 0x%x. Expected 0x%zx", + config_len, vdev->config_len); + return -1; + } qemu_get_buffer(f, vdev->config, vdev->config_len); num = qemu_get_be32(f); + if (num > VIRTIO_PCI_QUEUE_MAX) { + error_report("Invalid number of PCI queues: 0x%x", num); + return -1; + } + for (i = 0; i < num; i++) { vdev->vq[i].vring.num = qemu_get_be32(f); if (k->has_variable_vring_alignment) { diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index bc994a4c32..68b33e12be 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -42,6 +42,8 @@ typedef struct IB700state { ISADevice parent_obj; QEMUTimer *timer; + + PortioList port_list; } IB700State; /* This is the timer. We use a global here because the watchdog @@ -106,14 +108,13 @@ static const MemoryRegionPortio wdt_portio_list[] = { static void wdt_ib700_realize(DeviceState *dev, Error **errp) { IB700State *s = IB700(dev); - PortioList *port_list = g_new(PortioList, 1); ib700_debug("watchdog init\n"); s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ib700_timer_expired, s); - portio_list_init(port_list, OBJECT(s), wdt_portio_list, s, "ib700"); - portio_list_add(port_list, isa_address_space_io(&s->parent_obj), 0); + portio_list_init(&s->port_list, OBJECT(s), wdt_portio_list, s, "ib700"); + portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj), 0); } static void wdt_ib700_reset(DeviceState *dev) diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index ce640c61a5..a0ca0aa3df 100644 --- a/hw/xen/Makefile.objs +++ b/hw/xen/Makefile.objs @@ -1,6 +1,5 @@ # xen backend driver support common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o -obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o xen_pvdevice.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index 197795ffe1..3cd45b407c 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -45,7 +45,6 @@ /* public */ XenXC xen_xc = XC_HANDLER_INITIAL_VALUE; -XenGnttab xen_xcg = XC_HANDLER_INITIAL_VALUE; struct xs_handle *xenstore = NULL; const char *xen_protocol; diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index 8ccc2e4b9c..de9a20f437 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -1123,8 +1123,8 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s, msi->mapped = true; } msi->flags |= PCI_MSI_FLAGS_ENABLE; - } else { - msi->flags &= ~PCI_MSI_FLAGS_ENABLE; + } else if (msi->mapped) { + xen_pt_msi_disable(s); } /* pass through MSI_ENABLE bit */ @@ -1397,6 +1397,8 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s, if ((*val & PCI_MSIX_FLAGS_ENABLE) && !(*val & PCI_MSIX_FLAGS_MASKALL)) { xen_pt_msix_update(s); + } else if (!(*val & PCI_MSIX_FLAGS_ENABLE) && s->msix->enabled) { + xen_pt_msix_disable(s); } debug_msix_enabled_old = s->msix->enabled; diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c index 6fbe0cc86b..12b4c4560c 100644 --- a/hw/xen/xen_pt_msi.c +++ b/hw/xen/xen_pt_msi.c @@ -282,7 +282,8 @@ void xen_pt_msi_disable(XenPCIPassthroughState *s) msi->initialized); /* clear msi info */ - msi->flags = 0; + msi->flags &= ~PCI_MSI_FLAGS_ENABLE; + msi->initialized = false; msi->mapped = false; msi->pirq = XEN_PT_UNASSIGNED_PIRQ; } @@ -446,7 +447,8 @@ static void pci_msix_write(void *opaque, hwaddr addr, if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) { const volatile uint32_t *vec_ctrl; - if (get_entry_value(entry, offset) == val) { + if (get_entry_value(entry, offset) == val + && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) { return; } diff --git a/hw/xenpv/Makefile.objs b/hw/xenpv/Makefile.objs new file mode 100644 index 0000000000..49f6e9e3c5 --- /dev/null +++ b/hw/xenpv/Makefile.objs @@ -0,0 +1,2 @@ +# Xen PV machine support +obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o diff --git a/hw/i386/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c index c0ab7537df..c0ab7537df 100644 --- a/hw/i386/xen_domainbuild.c +++ b/hw/xenpv/xen_domainbuild.c diff --git a/hw/i386/xen_domainbuild.h b/hw/xenpv/xen_domainbuild.h index 29a91ea7b1..29a91ea7b1 100644 --- a/hw/i386/xen_domainbuild.h +++ b/hw/xenpv/xen_domainbuild.h diff --git a/hw/i386/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 9adb57fc14..9adb57fc14 100644 --- a/hw/i386/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c diff --git a/include/exec/memory.h b/include/exec/memory.h index c084db2d9d..1d55ad94a4 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -110,7 +110,7 @@ struct MemoryRegionOps { /* If true, unaligned accesses are supported. Otherwise all accesses * are converted to (possibly multiple) naturally aligned accesses. */ - bool unaligned; + bool unaligned; } impl; /* If .read and .write are not present, old_mmio may be used for diff --git a/include/glib-compat.h b/include/glib-compat.h index 8aa77afd62..8d25900700 100644 --- a/include/glib-compat.h +++ b/include/glib-compat.h @@ -24,4 +24,16 @@ static inline guint g_timeout_add_seconds(guint interval, GSourceFunc function, } #endif +#if !GLIB_CHECK_VERSION(2, 20, 0) +/* + * Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly + * on older systems. + */ +static inline gint g_poll(GPollFD *fds, guint nfds, gint timeout) +{ + GMainContext *ctx = g_main_context_default(); + return g_main_context_get_poll_func(ctx)(fds, nfds, timeout); +} +#endif + #endif diff --git a/include/hw/boards.h b/include/hw/boards.h index dd2c70da36..4345bd04fa 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -3,12 +3,13 @@ #ifndef HW_BOARDS_H #define HW_BOARDS_H +#include "qemu/typedefs.h" #include "sysemu/blockdev.h" #include "hw/qdev.h" #include "qom/object.h" typedef struct QEMUMachineInitArgs { - const QEMUMachine *machine; + const MachineClass *machine; ram_addr_t ram_size; const char *boot_order; const char *kernel_filename; @@ -46,7 +47,6 @@ struct QEMUMachine { const char *default_machine_opts; const char *default_boot_order; GlobalProperty *compat_props; - struct QEMUMachine *next; const char *hw_version; }; @@ -63,7 +63,6 @@ int qemu_register_machine(QEMUMachine *m); OBJECT_CLASS_CHECK(MachineClass, (klass), TYPE_MACHINE) typedef struct MachineState MachineState; -typedef struct MachineClass MachineClass; MachineClass *find_default_machine(void); extern MachineState *current_machine; @@ -77,7 +76,29 @@ struct MachineClass { ObjectClass parent_class; /*< public >*/ - QEMUMachine *qemu_machine; + const char *name; + const char *alias; + const char *desc; + + void (*init)(QEMUMachineInitArgs *args); + void (*reset)(void); + void (*hot_add_cpu)(const int64_t id, Error **errp); + int (*kvm_type)(const char *arg); + + BlockInterfaceType block_default_type; + int max_cpus; + unsigned int no_serial:1, + no_parallel:1, + use_virtcon:1, + use_sclp:1, + no_floppy:1, + no_cdrom:1, + no_sdcard:1; + int is_default; + const char *default_machine_opts; + const char *default_boot_order; + GlobalProperty *compat_props; + const char *hw_version; }; /** diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h index 63f0cc4788..544bbc1957 100644 --- a/include/hw/i2c/smbus.h +++ b/include/hw/i2c/smbus.h @@ -66,16 +66,16 @@ struct SMBusDevice { }; /* Master device commands. */ -void smbus_quick_command(I2CBus *bus, uint8_t addr, int read); -uint8_t smbus_receive_byte(I2CBus *bus, uint8_t addr); -void smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data); -uint8_t smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command); -void smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data); -uint16_t smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command); -void smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data); +int smbus_quick_command(I2CBus *bus, uint8_t addr, int read); +int smbus_receive_byte(I2CBus *bus, uint8_t addr); +int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data); +int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command); +int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data); +int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command); +int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data); int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data); -void smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, - int len); +int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, + int len); void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, const uint8_t *eeprom_spd, int size); diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index 70542a6f43..83e2a42cc1 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -98,6 +98,7 @@ struct APICCommonState { X86CPU *cpu; uint32_t apicbase; uint8_t id; + uint8_t version; uint8_t arb_id; uint8_t tpr; uint32_t spurious_vec; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 9f26e14bef..32a76876c7 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -242,8 +242,12 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t); int e820_get_num_entries(void); bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); +#define PC_Q35_COMPAT_2_0 \ + PC_COMPAT_2_0 + #define PC_Q35_COMPAT_1_7 \ PC_COMPAT_1_7, \ + PC_Q35_COMPAT_2_0, \ {\ .driver = "hpet",\ .property = HPET_INTCAP,\ @@ -262,7 +266,15 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); PC_COMPAT_1_4, \ PC_Q35_COMPAT_1_5 +#define PC_COMPAT_2_0 \ + {\ + .driver = "apic",\ + .property = "version",\ + .value = stringify(0x11),\ + } + #define PC_COMPAT_1_7 \ + PC_COMPAT_2_0, \ {\ .driver = TYPE_USB_DEVICE,\ .property = "msos-desc",\ diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index df60f16a3e..4b32440837 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -176,8 +176,8 @@ typedef struct VirtIONet { uint8_t nobcast; uint8_t vhost_started; struct { - int in_use; - int first_multi; + uint32_t in_use; + uint32_t first_multi; uint8_t multi_overflow; uint8_t uni_overflow; uint8_t *macs; diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 9d549fc83d..85fda3dee4 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -36,7 +36,7 @@ void xen_cmos_set_s3_resume(void *opaque, int irq, int level); qemu_irq *xen_interrupt_controller_init(void); -int xen_init(QEMUMachine *machine); +int xen_init(MachineClass *mc); int xen_hvm_init(MemoryRegion **ram_memory); void xenstore_store_pv_console_info(int i, struct CharDriverState *chr); diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 2d5a25bf40..07731b9289 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -144,6 +144,13 @@ static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom, { return -ENOSYS; } +/* The followings are only to compile op_discard related code on older + * Xen releases. */ +#define BLKIF_OP_DISCARD 5 +struct blkif_request_discard { + uint64_t nr_sectors; + uint64_t sector_number; +}; #else static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom, uint64_t addr, uint32_t data) diff --git a/include/migration/migration.h b/include/migration/migration.h index 3e1e6c72bf..3cb5ba80c3 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -61,6 +61,7 @@ struct MigrationState bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; int64_t setup_time; + int64_t dirty_sync_count; }; void process_incoming_migration(QEMUFile *f); @@ -113,8 +114,6 @@ void free_xbzrle_decoded_buf(void); void acct_update_position(QEMUFile *f, size_t size, bool zero); -extern SaveVMHandlers savevm_ram_handlers; - uint64_t dup_mig_bytes_transferred(void); uint64_t dup_mig_pages_transferred(void); uint64_t skipped_mig_bytes_transferred(void); @@ -125,6 +124,7 @@ uint64_t xbzrle_mig_bytes_transferred(void); uint64_t xbzrle_mig_pages_transferred(void); uint64_t xbzrle_mig_pages_overflow(void); uint64_t xbzrle_mig_pages_cache_miss(void); +double xbzrle_mig_cache_miss_rate(void); void ram_handle_compressed(void *host, uint8_t ch, uint64_t size); diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index a191fb6d8d..c90f5298ab 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -123,6 +123,11 @@ void qemu_put_be32(QEMUFile *f, unsigned int v); void qemu_put_be64(QEMUFile *f, uint64_t v); int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset); int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); +/* + * Note that you can only peek continuous bytes from where the current pointer + * is; you aren't guaranteed to be able to peak to +n bytes unless you've + * previously peeked +n-1. + */ int qemu_peek_byte(QEMUFile *f, int offset); int qemu_get_byte(QEMUFile *f); void qemu_file_skip(QEMUFile *f, int size); diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index e7e170561d..7e45048355 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -100,6 +100,7 @@ enum VMStateFlags { VMS_MULTIPLY = 0x200, /* multiply "size" field by field_size */ VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/ VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/ + VMS_MUST_EXIST = 0x1000, /* Field must exist in input */ }; typedef struct { @@ -203,6 +204,14 @@ extern const VMStateInfo vmstate_info_bitmap; .offset = vmstate_offset_value(_state, _field, _type), \ } +/* Validate state using a boolean predicate. */ +#define VMSTATE_VALIDATE(_name, _test) { \ + .name = (_name), \ + .field_exists = (_test), \ + .flags = VMS_ARRAY | VMS_MUST_EXIST, \ + .num = 0, /* 0 elements: no data, only run _test */ \ +} + #define VMSTATE_POINTER(_field, _state, _version, _info, _type) { \ .name = (stringify(_field)), \ .version_id = (_version), \ @@ -592,7 +601,7 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_UINT64_EQUAL(_f, _s) \ VMSTATE_UINT64_EQUAL_V(_f, _s, 0) -#define VMSTATE_INT32_LE(_f, _s) \ +#define VMSTATE_INT32_POSITIVE_LE(_f, _s) \ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t) #define VMSTATE_UINT8_TEST(_f, _s, _t) \ diff --git a/include/qemu-common.h b/include/qemu-common.h index a998e8d36c..3f3fd60f5b 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -124,18 +124,6 @@ int qemu_main(int argc, char **argv, char **envp); void qemu_get_timedate(struct tm *tm, int offset); int qemu_timedate_diff(struct tm *tm); -#if !GLIB_CHECK_VERSION(2, 20, 0) -/* - * Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly - * on older systems. - */ -static inline gint g_poll(GPollFD *fds, guint nfds, gint timeout) -{ - GMainContext *ctx = g_main_context_default(); - return g_main_context_get_poll_func(ctx)(fds, nfds, timeout); -} -#endif - /** * is_help_option: * @s: string to test diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index bf8daac659..86bab123a4 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -31,6 +31,7 @@ typedef struct MemoryListener MemoryListener; typedef struct MemoryMappingList MemoryMappingList; typedef struct QEMUMachine QEMUMachine; +typedef struct MachineClass MachineClass; typedef struct NICInfo NICInfo; typedef struct HCIInfo HCIInfo; typedef struct AudioState AudioState; diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index be71bcac2d..182d48d8c3 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -29,6 +29,7 @@ extern const uint32_t arch_type; void select_soundhw(const char *optarg); void do_acpitable_option(const QemuOpts *opts); void do_smbios_option(QemuOpts *opts); +void ram_mig_init(void); void cpudef_init(void); void audio_init(void); int tcg_available(void); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 192fe893b7..5ad4e0e1e2 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -152,7 +152,7 @@ extern KVMState *kvm_state; /* external API */ -int kvm_init(QEMUMachine *machine); +int kvm_init(MachineClass *mc); int kvm_has_sync_mmu(void); int kvm_has_vcpu_events(void); diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h index 224131f298..95c9ade778 100644 --- a/include/sysemu/qtest.h +++ b/include/sysemu/qtest.h @@ -26,7 +26,7 @@ static inline bool qtest_enabled(void) bool qtest_driver(void); -int qtest_init_accel(QEMUMachine *machine); +int qtest_init_accel(MachineClass *mc); void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp); static inline int qtest_available(void) @@ -1341,7 +1341,7 @@ static int kvm_max_vcpus(KVMState *s) return (ret) ? ret : kvm_recommended_vcpus(s); } -int kvm_init(QEMUMachine *machine) +int kvm_init(MachineClass *mc) { static const char upgrade_note[] = "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n" @@ -1433,8 +1433,8 @@ int kvm_init(QEMUMachine *machine) } kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type"); - if (machine->kvm_type) { - type = machine->kvm_type(kvm_type); + if (mc->kvm_type) { + type = mc->kvm_type(kvm_type); } else if (kvm_type) { fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type); goto err; diff --git a/kvm-stub.c b/kvm-stub.c index ccdba62d67..8acda86ced 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -34,7 +34,7 @@ int kvm_init_vcpu(CPUState *cpu) return -ENOSYS; } -int kvm_init(QEMUMachine *machine) +int kvm_init(MachineClass *mc) { return -ENOSYS; } diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index ee2dfaee82..e2b196d8c5 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -1162,7 +1162,8 @@ vcard_emul_options(const char *args) NEXT_TOKEN(vname) NEXT_TOKEN(type_params) type_params_length = MIN(type_params_length, sizeof(type_str)-1); - pstrcpy(type_str, type_params_length, type_params); + memcpy(type_str, type_params, type_params_length); + type_str[type_params_length] = '\0'; type = vcard_emul_type_from_string(type_str); NEXT_TOKEN(type_params) diff --git a/libcacard/vreader.c b/libcacard/vreader.c index 5793d73ff5..77202951fb 100644 --- a/libcacard/vreader.c +++ b/libcacard/vreader.c @@ -273,12 +273,12 @@ vreader_xfr_bytes(VReader *reader, response = vcard_make_response(status); card_status = VCARD_DONE; } else { - g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n", + g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s", __func__, apdu->a_cla, apdu->a_ins, apdu->a_p1, apdu->a_p2, apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->a_ins)); card_status = vcard_process_apdu(card, apdu, &response); if (response) { - g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n", + g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)", __func__, response->b_status, response->b_sw1, response->b_sw2, response->b_len, response->b_total_len); } diff --git a/migration-tcp.c b/migration-tcp.c index 782572de82..2e34517bb9 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -13,7 +13,10 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include <string.h> + #include "qemu-common.h" +#include "qemu/error-report.h" #include "qemu/sockets.h" #include "migration/migration.h" #include "migration/qemu-file.h" @@ -56,24 +59,26 @@ static void tcp_accept_incoming_migration(void *opaque) socklen_t addrlen = sizeof(addr); int s = (intptr_t)opaque; QEMUFile *f; - int c; + int c, err; do { c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen); - } while (c == -1 && socket_error() == EINTR); + err = socket_error(); + } while (c < 0 && err == EINTR); qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); closesocket(s); DPRINTF("accepted migration\n"); - if (c == -1) { - fprintf(stderr, "could not accept migration connection\n"); - goto out; + if (c < 0) { + error_report("could not accept migration connection (%s)", + strerror(err)); + return; } f = qemu_fopen_socket(c, "rb"); if (f == NULL) { - fprintf(stderr, "could not qemu_fopen socket\n"); + error_report("could not qemu_fopen socket"); goto out; } diff --git a/migration-unix.c b/migration-unix.c index 651fc5b707..0a5f8a1332 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -13,7 +13,10 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include <string.h> + #include "qemu-common.h" +#include "qemu/error-report.h" #include "qemu/sockets.h" #include "qemu/main-loop.h" #include "migration/migration.h" @@ -56,24 +59,26 @@ static void unix_accept_incoming_migration(void *opaque) socklen_t addrlen = sizeof(addr); int s = (intptr_t)opaque; QEMUFile *f; - int c; + int c, err; do { c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen); - } while (c == -1 && errno == EINTR); + err = errno; + } while (c < 0 && err == EINTR); qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); close(s); DPRINTF("accepted migration\n"); - if (c == -1) { - fprintf(stderr, "could not accept migration connection\n"); - goto out; + if (c < 0) { + error_report("could not accept migration connection (%s)", + strerror(err)); + return; } f = qemu_fopen_socket(c, "rb"); if (f == NULL) { - fprintf(stderr, "could not qemu_fopen socket\n"); + error_report("could not qemu_fopen socket"); goto out; } diff --git a/migration.c b/migration.c index bd1fb912ae..52cda279af 100644 --- a/migration.c +++ b/migration.c @@ -174,6 +174,7 @@ static void get_xbzrle_cache_stats(MigrationInfo *info) info->xbzrle_cache->bytes = xbzrle_mig_bytes_transferred(); info->xbzrle_cache->pages = xbzrle_mig_pages_transferred(); info->xbzrle_cache->cache_miss = xbzrle_mig_pages_cache_miss(); + info->xbzrle_cache->cache_miss_rate = xbzrle_mig_cache_miss_rate(); info->xbzrle_cache->overflow = xbzrle_mig_pages_overflow(); } } @@ -215,6 +216,7 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->ram->normal_bytes = norm_mig_bytes_transferred(); info->ram->dirty_pages_rate = s->dirty_pages_rate; info->ram->mbps = s->mbps; + info->ram->dirty_sync_count = s->dirty_sync_count; if (blk_mig_active()) { info->has_disk = true; @@ -248,6 +250,7 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->ram->normal = norm_mig_pages_transferred(); info->ram->normal_bytes = norm_mig_bytes_transferred(); info->ram->mbps = s->mbps; + info->ram->dirty_sync_count = s->dirty_sync_count; break; case MIG_STATE_ERROR: info->has_status = true; @@ -419,6 +422,11 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, return; } + if (runstate_check(RUN_STATE_INMIGRATE)) { + error_setg(errp, "Guest is waiting for an incoming migration"); + return; + } + if (qemu_savevm_state_blocked(errp)) { return; } @@ -488,7 +488,7 @@ static const char *monitor_event_names[] = { }; QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) -MonitorEventState monitor_event_state[QEVENT_MAX]; +static MonitorEventState monitor_event_state[QEVENT_MAX]; /* * Emits the event to every monitor instance diff --git a/qapi-schema.json b/qapi-schema.json index 0b00427c8c..36cb964dfd 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -651,13 +651,15 @@ # # @mbps: throughput in megabits/sec. (since 1.6) # +# @dirty-sync-count: number of times that dirty ram was synchronized (since 2.1) +# # Since: 0.14.0 ## { 'type': 'MigrationStats', 'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' , 'duplicate': 'int', 'skipped': 'int', 'normal': 'int', 'normal-bytes': 'int', 'dirty-pages-rate' : 'int', - 'mbps' : 'number' } } + 'mbps' : 'number', 'dirty-sync-count' : 'int' } } ## # @XBZRLECacheStats @@ -672,13 +674,16 @@ # # @cache-miss: number of cache miss # +# @cache-miss-rate: rate of cache miss (since 2.1) +# # @overflow: number of overflows # # Since: 1.2 ## { 'type': 'XBZRLECacheStats', 'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int', - 'cache-miss': 'int', 'overflow': 'int' } } + 'cache-miss': 'int', 'cache-miss-rate': 'number', + 'overflow': 'int' } } ## # @MigrationInfo diff --git a/qdev-monitor.c b/qdev-monitor.c index 6189780fd7..02cbe43bce 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -206,7 +206,7 @@ int qdev_device_help(QemuOpts *opts) } } - if (!klass) { + if (!object_class_dynamic_cast(klass, TYPE_DEVICE)) { return 0; } do { diff --git a/qemu-file.c b/qemu-file.c index 8d5f45dcb0..a8e39127f2 100644 --- a/qemu-file.c +++ b/qemu-file.c @@ -530,7 +530,15 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, return RAM_SAVE_CONTROL_NOT_SUPP; } -static void qemu_fill_buffer(QEMUFile *f) +/* + * Attempt to fill the buffer from the underlying file + * Returns the number of bytes read, or negative value for an error. + * + * Note that it can return a partially full buffer even in a not error/not EOF + * case if the underlying file descriptor gives a short read, and that can + * happen even on a blocking fd. + */ +static ssize_t qemu_fill_buffer(QEMUFile *f) { int len; int pending; @@ -554,6 +562,8 @@ static void qemu_fill_buffer(QEMUFile *f) } else if (len != -EAGAIN) { qemu_file_set_error(f, len); } + + return len; } int qemu_get_fd(QEMUFile *f) @@ -685,17 +695,39 @@ void qemu_file_skip(QEMUFile *f, int size) } } +/* + * Read 'size' bytes from file (at 'offset') into buf without moving the + * pointer. + * + * It will return size bytes unless there was an error, in which case it will + * return as many as it managed to read (assuming blocking fd's which + * all current QEMUFile are) + */ int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) { int pending; int index; assert(!qemu_file_is_writable(f)); + assert(offset < IO_BUF_SIZE); + assert(size <= IO_BUF_SIZE - offset); + /* The 1st byte to read from */ index = f->buf_index + offset; + /* The number of available bytes starting at index */ pending = f->buf_size - index; - if (pending < size) { - qemu_fill_buffer(f); + + /* + * qemu_fill_buffer might return just a few bytes, even when there isn't + * an error, so loop collecting them until we get enough. + */ + while (pending < size) { + int received = qemu_fill_buffer(f); + + if (received <= 0) { + break; + } + index = f->buf_index + offset; pending = f->buf_size - index; } @@ -711,6 +743,14 @@ int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) return size; } +/* + * Read 'size' bytes of data from the file into buf. + * 'size' can be larger than the internal buffer. + * + * It will return size bytes unless there was an error, in which case it will + * return as many as it managed to read (assuming blocking fd's which + * all current QEMUFile are) + */ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) { int pending = size; @@ -719,7 +759,7 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) while (pending > 0) { int res; - res = qemu_peek_buffer(f, buf, pending, 0); + res = qemu_peek_buffer(f, buf, MIN(pending, IO_BUF_SIZE), 0); if (res == 0) { return done; } @@ -731,11 +771,16 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) return done; } +/* + * Peeks a single byte from the buffer; this isn't guaranteed to work if + * offset leaves a gap after the previous read/peeked data. + */ int qemu_peek_byte(QEMUFile *f, int offset) { int index = f->buf_index + offset; assert(!qemu_file_is_writable(f)); + assert(offset < IO_BUF_SIZE); if (index >= f->buf_size) { qemu_fill_buffer(f); diff --git a/qemu-timer.c b/qemu-timer.c index e15ce477cc..9be1a4131d 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -56,7 +56,7 @@ typedef struct QEMUClock { } QEMUClock; QEMUTimerListGroup main_loop_tlg; -QEMUClock qemu_clocks[QEMU_CLOCK_MAX]; +static QEMUClock qemu_clocks[QEMU_CLOCK_MAX]; /* A QEMUTimerList is a list of timers attached to a clock. More * than one QEMUTimerList can be attached to each clock, for instance diff --git a/qga/main.c b/qga/main.c index d838c3e32a..38219c9d77 100644 --- a/qga/main.c +++ b/qga/main.c @@ -1110,7 +1110,7 @@ int main(int argc, char **argv) if (ga_is_frozen(s)) { if (daemonize) { - /* delay opening/locking of pidfile till filesystem are unfrozen */ + /* delay opening/locking of pidfile till filesystems are unfrozen */ s->deferred_options.pid_filepath = pid_filepath; become_daemon(NULL); } diff --git a/qmp-commands.hx b/qmp-commands.hx index ed3ab9225b..f437937e2c 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2967,6 +2967,7 @@ The main json-object contains the following: pages. This is just normal pages times size of one page, but this way upper levels don't need to care about page size (json-int) + - "dirty-sync-count": times that dirty ram was synchronized (json-int) - "disk": only present if "status" is "active" and it is a block migration, it is a json-object with the following disk information: - "transferred": amount transferred in bytes (json-int) @@ -2978,6 +2979,7 @@ The main json-object contains the following: - "bytes": number of bytes transferred for XBZRLE compressed pages - "pages": number of XBZRLE compressed pages - "cache-miss": number of XBRZRLE page cache misses + - "cache-miss-rate": rate of XBRZRLE page cache misses - "overflow": number of times XBZRLE overflows. This means that the XBZRLE encoding was bigger than just sent the whole page, and then we sent the whole page instead (as as @@ -3004,7 +3006,8 @@ Examples: "downtime":12345, "duplicate":123, "normal":123, - "normal-bytes":123456 + "normal-bytes":123456, + "dirty-sync-count":15 } } } @@ -3029,7 +3032,8 @@ Examples: "expected-downtime":12345, "duplicate":123, "normal":123, - "normal-bytes":123456 + "normal-bytes":123456, + "dirty-sync-count":15 } } } @@ -3049,7 +3053,8 @@ Examples: "expected-downtime":12345, "duplicate":123, "normal":123, - "normal-bytes":123456 + "normal-bytes":123456, + "dirty-sync-count":15 }, "disk":{ "total":20971520, @@ -3075,13 +3080,15 @@ Examples: "expected-downtime":12345, "duplicate":10, "normal":3333, - "normal-bytes":3412992 + "normal-bytes":3412992, + "dirty-sync-count":15 }, "xbzrle-cache":{ "cache-size":67108864, "bytes":20971520, "pages":2444343, "cache-miss":2244, + "cache-miss-rate":0.123, "overflow":34434 } } @@ -117,8 +117,8 @@ void qmp_cpu_add(int64_t id, Error **errp) MachineClass *mc; mc = MACHINE_GET_CLASS(current_machine); - if (mc->qemu_machine->hot_add_cpu) { - mc->qemu_machine->hot_add_cpu(id, errp); + if (mc->hot_add_cpu) { + mc->hot_add_cpu(id, errp); } else { error_setg(errp, "Not supported"); } @@ -200,7 +200,11 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) obj = object_resolve_path(path, &ambiguous); if (obj == NULL) { - error_set(errp, QERR_DEVICE_NOT_FOUND, path); + if (ambiguous) { + error_setg(errp, "Path '%s' is ambiguous", path); + } else { + error_set(errp, QERR_DEVICE_NOT_FOUND, path); + } return NULL; } @@ -500,7 +500,7 @@ static void qtest_event(void *opaque, int event) } } -int qtest_init_accel(QEMUMachine *machine) +int qtest_init_accel(MachineClass *mc) { configure_icount("0"); diff --git a/target-arm/machine.c b/target-arm/machine.c index b967223fc0..810ba27f40 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -248,7 +248,7 @@ const VMStateDescription vmstate_arm_cpu = { /* The length-check must come before the arrays to avoid * incoming data possibly overflowing the array. */ - VMSTATE_INT32_LE(cpreg_vmstate_array_len, ARMCPU), + VMSTATE_INT32_POSITIVE_LE(cpreg_vmstate_array_len, ARMCPU), VMSTATE_VARRAY_INT32(cpreg_vmstate_indexes, ARMCPU, cpreg_vmstate_array_len, 0, vmstate_info_uint64, uint64_t), diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 8fd1497dc4..8f193a9330 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1300,10 +1300,12 @@ static void x86_cpuid_version_set_family(Object *obj, Visitor *v, void *opaque, CPUX86State *env = &cpu->env; const int64_t min = 0; const int64_t max = 0xff + 0xf; + Error *local_err = NULL; int64_t value; - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { + visit_type_int(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (value < min || value > max) { @@ -1339,10 +1341,12 @@ static void x86_cpuid_version_set_model(Object *obj, Visitor *v, void *opaque, CPUX86State *env = &cpu->env; const int64_t min = 0; const int64_t max = 0xff; + Error *local_err = NULL; int64_t value; - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { + visit_type_int(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (value < min || value > max) { @@ -1375,10 +1379,12 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v, CPUX86State *env = &cpu->env; const int64_t min = 0; const int64_t max = 0xf; + Error *local_err = NULL; int64_t value; - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { + visit_type_int(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (value < min || value > max) { @@ -1511,10 +1517,12 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque, X86CPU *cpu = X86_CPU(obj); const int64_t min = 0; const int64_t max = INT64_MAX; + Error *local_err = NULL; int64_t value; - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { + visit_type_int(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } if (value < min || value > max) { diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 41903a93fb..aad277af49 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -270,6 +270,9 @@ typedef struct CPUS390XState { #define FLAG_MASK_64 (PSW_MASK_64 >> 32) #define FLAG_MASK_32 0x00001000 +/* Control register 0 bits */ +#define CR0_EDAT 0x0000000000800000ULL + static inline int cpu_mmu_index (CPUS390XState *env) { if (env->psw.mask & PSW_MASK_PSTATE) { @@ -927,6 +930,7 @@ struct sysib_322 { #define _REGION_ENTRY_LENGTH 0x03 /* region third length */ #define _SEGMENT_ENTRY_ORIGIN ~0x7ffULL /* segment table origin */ +#define _SEGMENT_ENTRY_FC 0x400 /* format control */ #define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ diff --git a/target-s390x/helper.c b/target-s390x/helper.c index aa628b8fe2..7c76fc149b 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -170,6 +170,64 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, trigger_pgm_exception(env, type, ilen); } +/** + * Translate real address to absolute (= physical) + * address by taking care of the prefix mapping. + */ +static target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr) +{ + if (raddr < 0x2000) { + return raddr + env->psa; /* Map the lowcore. */ + } else if (raddr >= env->psa && raddr < env->psa + 0x2000) { + return raddr - env->psa; /* Map the 0 page. */ + } + return raddr; +} + +/* Decode page table entry (normal 4KB page) */ +static int mmu_translate_pte(CPUS390XState *env, target_ulong vaddr, + uint64_t asc, uint64_t asce, + target_ulong *raddr, int *flags, int rw) +{ + if (asce & _PAGE_INVALID) { + DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, asce); + trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw); + return -1; + } + + if (asce & _PAGE_RO) { + *flags &= ~PAGE_WRITE; + } + + *raddr = asce & _ASCE_ORIGIN; + + PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, asce); + + return 0; +} + +/* Decode EDAT1 segment frame absolute address (1MB page) */ +static int mmu_translate_sfaa(CPUS390XState *env, target_ulong vaddr, + uint64_t asc, uint64_t asce, target_ulong *raddr, + int *flags, int rw) +{ + if (asce & _SEGMENT_ENTRY_INV) { + DPRINTF("%s: SEG=0x%" PRIx64 " invalid\n", __func__, asce); + trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw); + return -1; + } + + if (asce & _SEGMENT_ENTRY_RO) { + *flags &= ~PAGE_WRITE; + } + + *raddr = (asce & 0xfffffffffff00000ULL) | (vaddr & 0xfffff); + + PTE_DPRINTF("%s: SEG=0x%" PRIx64 "\n", __func__, asce); + + return 0; +} + static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t asc, uint64_t asce, int level, target_ulong *raddr, int *flags, int rw) @@ -229,28 +287,18 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n", __func__, origin, offs, new_asce); - if (level != _ASCE_TYPE_SEGMENT) { + if (level == _ASCE_TYPE_SEGMENT) { + /* 4KB page */ + return mmu_translate_pte(env, vaddr, asc, new_asce, raddr, flags, rw); + } else if (level - 4 == _ASCE_TYPE_SEGMENT && + (new_asce & _SEGMENT_ENTRY_FC) && (env->cregs[0] & CR0_EDAT)) { + /* 1MB page */ + return mmu_translate_sfaa(env, vaddr, asc, new_asce, raddr, flags, rw); + } else { /* yet another region */ return mmu_translate_asce(env, vaddr, asc, new_asce, level - 4, raddr, flags, rw); } - - /* PTE */ - if (new_asce & _PAGE_INVALID) { - DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, new_asce); - trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw); - return -1; - } - - if (new_asce & _PAGE_RO) { - *flags &= ~PAGE_WRITE; - } - - *raddr = new_asce & _ASCE_ORIGIN; - - PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, new_asce); - - return 0; } static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, @@ -363,9 +411,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, out: /* Convert real address -> absolute address */ - if (*raddr < 0x2000) { - *raddr = *raddr + env->psa; - } + *raddr = mmu_real2abs(env, *raddr); if (*raddr <= ram_size) { sk = &env->storage_keys[*raddr / TARGET_PAGE_SIZE]; diff --git a/tests/Makefile b/tests/Makefile index c6b661472b..14ecf05b5d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -107,6 +107,10 @@ check-qtest-pci-y += tests/ne2000-test$(EXESUF) gcov-files-pci-y += hw/net/ne2000.c check-qtest-pci-y += tests/nvme-test$(EXESUF) gcov-files-pci-y += hw/block/nvme.c +check-qtest-pci-y += tests/ac97-test$(EXESUF) +gcov-files-pci-y += hw/audio/ac97.c +check-qtest-pci-y += tests/es1370-test$(EXESUF) +gcov-files-pci-y += hw/audio/es1370.c check-qtest-pci-y += $(check-qtest-virtio-y) gcov-files-pci-y += $(gcov-files-virtio-y) hw/virtio/virtio-pci.c check-qtest-pci-y += tests/tpci200-test$(EXESUF) @@ -117,6 +121,8 @@ check-qtest-pci-y += tests/display-vga-test$(EXESUF) gcov-files-pci-y += hw/display/vga.c gcov-files-pci-y += hw/display/cirrus_vga.c gcov-files-pci-y += hw/display/vga-pci.c +check-qtest-pci-y += tests/intel-hda-test$(EXESUF) +gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c check-qtest-i386-y = tests/endianness-test$(EXESUF) check-qtest-i386-y += tests/fdc-test$(EXESUF) @@ -141,6 +147,11 @@ check-qtest-i386-y += tests/pvpanic-test$(EXESUF) gcov-files-i386-y += i386-softmmu/hw/misc/pvpanic.c check-qtest-i386-y += tests/i82801b11-test$(EXESUF) gcov-files-i386-y += hw/pci-bridge/i82801b11.c +check-qtest-i386-y += tests/ioh3420-test$(EXESUF) +gcov-files-i386-y += hw/pci-bridge/ioh3420.c +check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF) +gcov-files-i386-y += hw/usb/hcd-ehci.c +gcov-files-i386-y += hw/usb/hcd-uhci.c check-qtest-x86_64-y = $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) @@ -292,6 +303,11 @@ tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y) tests/nvme-test$(EXESUF): tests/nvme-test.o tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o +tests/ac97-test$(EXESUF): tests/ac97-test.o +tests/es1370-test$(EXESUF): tests/es1370-test.o +tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o +tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o +tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o # QTest rules diff --git a/tests/ac97-test.c b/tests/ac97-test.c new file mode 100644 index 0000000000..af30ea1dd6 --- /dev/null +++ b/tests/ac97-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for AC97 + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/ac97/nop", nop); + + qtest_start("-device AC97"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/es1370-test.c b/tests/es1370-test.c new file mode 100644 index 0000000000..cc23fb5c67 --- /dev/null +++ b/tests/es1370-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for ES1370 + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/es1370/nop", nop); + + qtest_start("-device ES1370"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/intel-hda-test.c b/tests/intel-hda-test.c new file mode 100644 index 0000000000..d89b407dcc --- /dev/null +++ b/tests/intel-hda-test.c @@ -0,0 +1,45 @@ +/* + * QTest testcase for Intel HDA + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +#define HDA_ID "hda0" +#define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \ + " -device hda-micro,bus=" HDA_ID ".0" \ + " -device hda-duplex,bus=" HDA_ID ".0" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void ich6_test(void) +{ + qtest_start("-device intel-hda,id=" HDA_ID CODEC_DEVICES); + qtest_end(); +} + +static void ich9_test(void) +{ + qtest_start("-machine q35 -device ich9-intel-hda,bus=pcie.0,addr=1b.0,id=" + HDA_ID CODEC_DEVICES); + qtest_end(); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/intel-hda/ich6", ich6_test); + qtest_add_func("/intel-hda/ich9", ich9_test); + + ret = g_test_run(); + + return ret; +} diff --git a/tests/ioh3420-test.c b/tests/ioh3420-test.c new file mode 100644 index 0000000000..c991a5f873 --- /dev/null +++ b/tests/ioh3420-test.c @@ -0,0 +1,34 @@ +/* + * QTest testcase for Intel X58 north bridge IOH + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/ioh3420/nop", nop); + + qtest_start("-machine q35 -device ioh3420,bus=pcie.0,addr=1c.0,port=1," + "chassis=1,multifunction=on"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/libqtest.c b/tests/libqtest.c index 8155695848..71468ac9c7 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -72,7 +72,8 @@ static int init_socket(const char *socket_path) ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); } while (ret == -1 && errno == EINTR); g_assert_no_errno(ret); - listen(sock, 1); + ret = listen(sock, 1); + g_assert_no_errno(ret); return sock; } @@ -88,10 +89,13 @@ static int socket_accept(int sock) setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout)); - addrlen = sizeof(addr); do { + addrlen = sizeof(addr); ret = accept(sock, (struct sockaddr *)&addr, &addrlen); } while (ret == -1 && errno == EINTR); + if (ret == -1) { + fprintf(stderr, "%s failed: %s\n", __func__, strerror(errno)); + } close(sock); return ret; diff --git a/tests/tcg/Makefile b/tests/tcg/Makefile index 24e3154cae..89e3342f3d 100644 --- a/tests/tcg/Makefile +++ b/tests/tcg/Makefile @@ -81,10 +81,8 @@ run-test_path: test_path # rules to compile tests test_path: test_path.o - $(CC_I386) $(LDFLAGS) -o $@ $^ $(LIBS) test_path.o: test_path.c - $(CC_I386) $(QEMU_INCLUDES) $(GLIB_CFLAGS) $(CFLAGS) -c -o $@ $^ hello-i386: hello-i386.c $(CC_I386) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< diff --git a/tests/tcg/test_path.c b/tests/tcg/test_path.c index f8dd36aab2..1c29bce263 100644 --- a/tests/tcg/test_path.c +++ b/tests/tcg/test_path.c @@ -1,17 +1,10 @@ /* Test path override code */ -#define _GNU_SOURCE #include "config-host.h" #include "util/cutils.c" #include "util/hexdump.c" #include "util/iov.c" #include "util/path.c" #include "util/qemu-timer-common.c" -#include "trace/control.c" -#include "../trace/generated-events.c" -#ifdef CONFIG_TRACE_SIMPLE -#include "trace/simple.c" -#endif - #include <stdarg.h> #include <sys/stat.h> #include <fcntl.h> diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c new file mode 100644 index 0000000000..bc56ba7707 --- /dev/null +++ b/tests/usb-hcd-ehci-test.c @@ -0,0 +1,40 @@ +/* + * QTest testcase for USB EHCI + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/ehci/pci/nop", pci_nop); + + qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7," + "multifunction=on,id=ich9-ehci-1 " + "-device ich9-usb-uhci1,bus=pcie.0,addr=1d.0," + "multifunction=on,masterbus=ich9-ehci-1.0,firstport=0 " + "-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1," + "multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 " + "-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2," + "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/trace-events b/trace-events index a5218ba393..af4449d2ba 100644 --- a/trace-events +++ b/trace-events @@ -453,6 +453,9 @@ usb_mtp_op_get_object_handles(int dev, uint32_t handle, const char *path) "dev % usb_mtp_op_get_object_info(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" usb_mtp_op_get_object(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" usb_mtp_op_get_partial_object(int dev, uint32_t handle, const char *path, uint32_t offset, uint32_t length) "dev %d, handle 0x%x, path %s, off %d, len %d" +usb_mtp_op_unknown(int dev, uint32_t code) "dev %d, command code 0x%x" +usb_mtp_object_alloc(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" +usb_mtp_object_free(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" # hw/usb/host-libusb.c usb_host_open_started(int bus, int addr) "dev %d:%d" diff --git a/ui/console.c b/ui/console.c index e057755c04..34d1eaa955 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1407,7 +1407,7 @@ void dpy_gfx_replace_surface(QemuConsole *con, qemu_free_displaysurface(old_surface); } -void dpy_refresh(DisplayState *s) +static void dpy_refresh(DisplayState *s) { DisplayChangeListener *dcl; diff --git a/ui/spice-core.c b/ui/spice-core.c index 4cce3b38c0..d10818a925 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -48,6 +48,7 @@ static char *auth_passwd; static time_t auth_expires = TIME_MAX; static int spice_migration_completed; static int spice_display_is_running; +static int spice_have_target_host; int using_spice = 0; static QemuThread me; @@ -532,7 +533,7 @@ SpiceInfo *qmp_query_spice(Error **errp) info->auth = g_strdup(auth); info->has_host = true; - info->host = g_strdup(addr ? addr : "0.0.0.0"); + info->host = g_strdup(addr ? addr : "*"); info->has_compiled_version = true; major = (SPICE_SERVER_VERSION & 0xff0000) >> 16; @@ -564,12 +565,18 @@ static void migration_state_notifier(Notifier *notifier, void *data) { MigrationState *s = data; + if (!spice_have_target_host) { + return; + } + if (migration_in_setup(s)) { spice_server_migrate_start(spice_server); } else if (migration_has_finished(s)) { spice_server_migrate_end(spice_server, true); + spice_have_target_host = false; } else if (migration_has_failed(s)) { spice_server_migrate_end(spice_server, false); + spice_have_target_host = false; } } @@ -583,6 +590,7 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, spice_migrate.connect_complete.opaque = opaque; ret = spice_server_migrate_connect(spice_server, hostname, port, tls_port, subject); + spice_have_target_host = true; return ret; } diff --git a/util/osdep.c b/util/osdep.c index a9029f8894..b2bd1542c5 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -436,23 +436,20 @@ int socket_init(void) return 0; } -/* Ensure that glib is running in multi-threaded mode */ +#if !GLIB_CHECK_VERSION(2, 31, 0) +/* Ensure that glib is running in multi-threaded mode + * Old versions of glib require explicit initialization. Failure to do + * this results in the single-threaded code paths being taken inside + * glib. For example, the g_slice allocator will not be thread-safe + * and cause crashes. + */ static void __attribute__((constructor)) thread_init(void) { if (!g_thread_supported()) { -#if !GLIB_CHECK_VERSION(2, 31, 0) - /* Old versions of glib require explicit initialization. Failure to do - * this results in the single-threaded code paths being taken inside - * glib. For example, the g_slice allocator will not be thread-safe - * and cause crashes. - */ - g_thread_init(NULL); -#else - fprintf(stderr, "glib threading failed to initialize.\n"); - exit(1); -#endif + g_thread_init(NULL); } } +#endif #ifndef CONFIG_IOVEC /* helper function for iov_send_recv() */ diff --git a/util/readline.c b/util/readline.c index 8441be484c..8baec55509 100644 --- a/util/readline.c +++ b/util/readline.c @@ -272,6 +272,11 @@ void readline_set_completion_index(ReadLineState *rs, int index) rs->completion_index = index; } +static int completion_comp(const void *a, const void *b) +{ + return strcmp(*(const char **) a, *(const char **) b); +} + static void readline_completion(ReadLineState *rs) { int len, i, j, max_width, nb_cols, max_prefix; @@ -279,9 +284,7 @@ static void readline_completion(ReadLineState *rs) rs->nb_completions = 0; - cmdline = g_malloc(rs->cmd_buf_index + 1); - memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index); - cmdline[rs->cmd_buf_index] = '\0'; + cmdline = g_strndup(rs->cmd_buf, rs->cmd_buf_index); rs->completion_finder(rs->opaque, cmdline); g_free(cmdline); @@ -297,6 +300,8 @@ static void readline_completion(ReadLineState *rs) if (len > 0 && rs->completions[0][len - 1] != '/') readline_insert_char(rs, ' '); } else { + qsort(rs->completions, rs->nb_completions, sizeof(char *), + completion_comp); rs->printf_func(rs->opaque, "\n"); max_width = 0; max_prefix = 0; @@ -1588,8 +1588,29 @@ MachineState *current_machine; static void machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - - mc->qemu_machine = data; + QEMUMachine *qm = data; + + mc->name = qm->name; + mc->alias = qm->alias; + mc->desc = qm->desc; + mc->init = qm->init; + mc->reset = qm->reset; + mc->hot_add_cpu = qm->hot_add_cpu; + mc->kvm_type = qm->kvm_type; + mc->block_default_type = qm->block_default_type; + mc->max_cpus = qm->max_cpus; + mc->no_serial = qm->no_serial; + mc->no_parallel = qm->no_parallel; + mc->use_virtcon = qm->use_virtcon; + mc->use_sclp = qm->use_sclp; + mc->no_floppy = qm->no_floppy; + mc->no_cdrom = qm->no_cdrom; + mc->no_sdcard = qm->no_sdcard; + mc->is_default = qm->is_default; + mc->default_machine_opts = qm->default_machine_opts; + mc->default_boot_order = qm->default_boot_order; + mc->compat_props = qm->compat_props; + mc->hw_version = qm->hw_version; } int qemu_register_machine(QEMUMachine *m) @@ -1616,12 +1637,12 @@ static MachineClass *find_machine(const char *name) for (el = machines; el; el = el->next) { MachineClass *temp = el->data; - if (!strcmp(temp->qemu_machine->name, name)) { + if (!strcmp(temp->name, name)) { mc = temp; break; } - if (temp->qemu_machine->alias && - !strcmp(temp->qemu_machine->alias, name)) { + if (temp->alias && + !strcmp(temp->alias, name)) { mc = temp; break; } @@ -1639,7 +1660,7 @@ MachineClass *find_default_machine(void) for (el = machines; el; el = el->next) { MachineClass *temp = el->data; - if (temp->qemu_machine->is_default) { + if (temp->is_default) { mc = temp; break; } @@ -1653,27 +1674,25 @@ MachineInfoList *qmp_query_machines(Error **errp) { GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); MachineInfoList *mach_list = NULL; - QEMUMachine *m; for (el = machines; el; el = el->next) { MachineClass *mc = el->data; MachineInfoList *entry; MachineInfo *info; - m = mc->qemu_machine; info = g_malloc0(sizeof(*info)); - if (m->is_default) { + if (mc->is_default) { info->has_is_default = true; info->is_default = true; } - if (m->alias) { + if (mc->alias) { info->has_alias = true; - info->alias = g_strdup(m->alias); + info->alias = g_strdup(mc->alias); } - info->name = g_strdup(m->name); - info->cpu_max = !m->max_cpus ? 1 : m->max_cpus; + info->name = g_strdup(mc->name); + info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus; entry = g_malloc0(sizeof(*entry)); entry->value = info; @@ -1879,8 +1898,8 @@ void qemu_system_reset(bool report) mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; - if (mc && mc->qemu_machine->reset) { - mc->qemu_machine->reset(); + if (mc && mc->reset) { + mc->reset(); } else { qemu_devices_reset(); } @@ -2689,12 +2708,11 @@ static MachineClass *machine_parse(const char *name) printf("Supported machines are:\n"); for (el = machines; el; el = el->next) { MachineClass *mc = el->data; - QEMUMachine *m = mc->qemu_machine; - if (m->alias) { - printf("%-20s %s (alias of %s)\n", m->alias, m->desc, m->name); + if (mc->alias) { + printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name); } - printf("%-20s %s%s\n", m->name, m->desc, - m->is_default ? " (default)" : ""); + printf("%-20s %s%s\n", mc->name, mc->desc, + mc->is_default ? " (default)" : ""); } } @@ -2702,7 +2720,7 @@ static MachineClass *machine_parse(const char *name) exit(!name || !is_help_option(name)); } -static int tcg_init(QEMUMachine *machine) +static int tcg_init(MachineClass *mc) { tcg_exec_init(tcg_tb_size * 1024 * 1024); return 0; @@ -2712,7 +2730,7 @@ static struct { const char *opt_name; const char *name; int (*available)(void); - int (*init)(QEMUMachine *); + int (*init)(MachineClass *mc); bool *allowed; } accel_list[] = { { "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed }, @@ -2721,7 +2739,7 @@ static struct { { "qtest", "QTest", qtest_available, qtest_init_accel, &qtest_allowed }, }; -static int configure_accelerator(QEMUMachine *machine) +static int configure_accelerator(MachineClass *mc) { const char *p; char buf[10]; @@ -2748,7 +2766,7 @@ static int configure_accelerator(QEMUMachine *machine) break; } *(accel_list[i].allowed) = true; - ret = accel_list[i].init(machine); + ret = accel_list[i].init(mc); if (ret < 0) { init_failed = true; fprintf(stderr, "failed to initialize %s: %s\n", @@ -2948,7 +2966,6 @@ int main(int argc, char **argv, char **envp) const char *optarg; const char *loadvm = NULL; MachineClass *machine_class; - QEMUMachine *machine; const char *cpu_model; const char *vga_model = NULL; const char *qtest_chrdev = NULL; @@ -3976,9 +3993,8 @@ int main(int argc, char **argv, char **envp) object_property_add_child(object_get_root(), "machine", OBJECT(current_machine), &error_abort); - machine = machine_class->qemu_machine; - if (machine->hw_version) { - qemu_set_version(machine->hw_version); + if (machine_class->hw_version) { + qemu_set_version(machine_class->hw_version); } if (qemu_opts_foreach(qemu_find_opts("object"), @@ -4038,11 +4054,11 @@ int main(int argc, char **argv, char **envp) smp_parse(qemu_opts_find(qemu_find_opts("smp-opts"), NULL)); - machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */ - if (smp_cpus > machine->max_cpus) { + machine_class->max_cpus = machine_class->max_cpus ?: 1; /* Default to UP */ + if (smp_cpus > machine_class->max_cpus) { fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus " - "supported by machine `%s' (%d)\n", smp_cpus, machine->name, - machine->max_cpus); + "supported by machine `%s' (%d)\n", smp_cpus, + machine_class->name, machine_class->max_cpus); exit(1); } @@ -4050,9 +4066,9 @@ int main(int argc, char **argv, char **envp) * Get the default machine options from the machine if it is not already * specified either by the configuration file or by the command line. */ - if (machine->default_machine_opts) { + if (machine_class->default_machine_opts) { qemu_opts_set_defaults(qemu_find_opts("machine"), - machine->default_machine_opts, 0); + machine_class->default_machine_opts, 0); } qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0); @@ -4061,25 +4077,25 @@ int main(int argc, char **argv, char **envp) if (!vga_model && !default_vga) { vga_interface_type = VGA_DEVICE; } - if (!has_defaults || machine->no_serial) { + if (!has_defaults || machine_class->no_serial) { default_serial = 0; } - if (!has_defaults || machine->no_parallel) { + if (!has_defaults || machine_class->no_parallel) { default_parallel = 0; } - if (!has_defaults || !machine->use_virtcon) { + if (!has_defaults || !machine_class->use_virtcon) { default_virtcon = 0; } - if (!has_defaults || !machine->use_sclp) { + if (!has_defaults || !machine_class->use_sclp) { default_sclp = 0; } - if (!has_defaults || machine->no_floppy) { + if (!has_defaults || machine_class->no_floppy) { default_floppy = 0; } - if (!has_defaults || machine->no_cdrom) { + if (!has_defaults || machine_class->no_cdrom) { default_cdrom = 0; } - if (!has_defaults || machine->no_sdcard) { + if (!has_defaults || machine_class->no_sdcard) { default_sdcard = 0; } if (!has_defaults) { @@ -4199,7 +4215,7 @@ int main(int argc, char **argv, char **envp) exit(0); } - configure_accelerator(machine); + configure_accelerator(machine_class); if (qtest_chrdev) { Error *local_err = NULL; @@ -4217,7 +4233,7 @@ int main(int argc, char **argv, char **envp) kernel_cmdline = qemu_opt_get(machine_opts, "append"); bios_name = qemu_opt_get(machine_opts, "firmware"); - boot_order = machine->default_boot_order; + boot_order = machine_class->default_boot_order; opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL); if (opts) { char *normal_boot_order; @@ -4306,22 +4322,21 @@ int main(int argc, char **argv, char **envp) cpu_exec_init_all(); blk_mig_init(); + ram_mig_init(); /* open the virtual block devices */ if (snapshot) qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0); if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, - &machine->block_default_type, 1) != 0) { + &machine_class->block_default_type, 1) != 0) { exit(1); } - default_drive(default_cdrom, snapshot, machine->block_default_type, 2, + default_drive(default_cdrom, snapshot, machine_class->block_default_type, 2, CDROM_OPTS); default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS); default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS); - register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL); - if (nb_numa_nodes > 0) { int i; @@ -4399,15 +4414,15 @@ int main(int argc, char **argv, char **envp) exit (i == 1 ? 1 : 0); } - if (machine->compat_props) { - qdev_prop_register_global_list(machine->compat_props); + if (machine_class->compat_props) { + qdev_prop_register_global_list(machine_class->compat_props); } qemu_add_globals(); qdev_machine_init(); current_machine->init_args = (QEMUMachineInitArgs) { - .machine = machine, + .machine = machine_class, .ram_size = ram_size, .boot_order = boot_order, .kernel_filename = kernel_filename, @@ -4415,7 +4430,7 @@ int main(int argc, char **argv, char **envp) .initrd_filename = initrd_filename, .cpu_model = cpu_model }; - machine->init(¤t_machine->init_args); + machine_class->init(¤t_machine->init_args); audio_init(); @@ -10,6 +10,50 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, void *opaque); +static int vmstate_n_elems(void *opaque, VMStateField *field) +{ + int n_elems = 1; + + if (field->flags & VMS_ARRAY) { + n_elems = field->num; + } else if (field->flags & VMS_VARRAY_INT32) { + n_elems = *(int32_t *)(opaque+field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT32) { + n_elems = *(uint32_t *)(opaque+field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT16) { + n_elems = *(uint16_t *)(opaque+field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT8) { + n_elems = *(uint8_t *)(opaque+field->num_offset); + } + + return n_elems; +} + +static int vmstate_size(void *opaque, VMStateField *field) +{ + int size = field->size; + + if (field->flags & VMS_VBUFFER) { + size = *(int32_t *)(opaque+field->size_offset); + if (field->flags & VMS_MULTIPLY) { + size *= field->size; + } + } + + return size; +} + +static void *vmstate_base_addr(void *opaque, VMStateField *field) +{ + void *base_addr = opaque + field->offset; + + if (field->flags & VMS_POINTER) { + base_addr = *(void **)base_addr + field->start; + } + + return base_addr; +} + int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, int version_id) { @@ -19,11 +63,12 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, if (version_id > vmsd->version_id) { return -EINVAL; } - if (version_id < vmsd->minimum_version_id_old) { - return -EINVAL; - } if (version_id < vmsd->minimum_version_id) { - return vmsd->load_state_old(f, opaque, version_id); + if (vmsd->load_state_old && + version_id >= vmsd->minimum_version_id_old) { + return vmsd->load_state_old(f, opaque, version_id); + } + return -EINVAL; } if (vmsd->pre_load) { int ret = vmsd->pre_load(opaque); @@ -36,30 +81,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, field->field_exists(opaque, version_id)) || (!field->field_exists && field->version_id <= version_id)) { - void *base_addr = opaque + field->offset; - int i, n_elems = 1; - int size = field->size; - - if (field->flags & VMS_VBUFFER) { - size = *(int32_t *)(opaque+field->size_offset); - if (field->flags & VMS_MULTIPLY) { - size *= field->size; - } - } - if (field->flags & VMS_ARRAY) { - n_elems = field->num; - } else if (field->flags & VMS_VARRAY_INT32) { - n_elems = *(int32_t *)(opaque+field->num_offset); - } else if (field->flags & VMS_VARRAY_UINT32) { - n_elems = *(uint32_t *)(opaque+field->num_offset); - } else if (field->flags & VMS_VARRAY_UINT16) { - n_elems = *(uint16_t *)(opaque+field->num_offset); - } else if (field->flags & VMS_VARRAY_UINT8) { - n_elems = *(uint8_t *)(opaque+field->num_offset); - } - if (field->flags & VMS_POINTER) { - base_addr = *(void **)base_addr + field->start; - } + void *base_addr = vmstate_base_addr(opaque, field); + int i, n_elems = vmstate_n_elems(opaque, field); + int size = vmstate_size(opaque, field); + for (i = 0; i < n_elems; i++) { void *addr = base_addr + size * i; @@ -78,6 +103,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, return ret; } } + } else if (field->flags & VMS_MUST_EXIST) { + fprintf(stderr, "Input validation failed: %s/%s\n", + vmsd->name, field->name); + return -1; } field++; } @@ -102,30 +131,10 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, while (field->name) { if (!field->field_exists || field->field_exists(opaque, vmsd->version_id)) { - void *base_addr = opaque + field->offset; - int i, n_elems = 1; - int size = field->size; - - if (field->flags & VMS_VBUFFER) { - size = *(int32_t *)(opaque+field->size_offset); - if (field->flags & VMS_MULTIPLY) { - size *= field->size; - } - } - if (field->flags & VMS_ARRAY) { - n_elems = field->num; - } else if (field->flags & VMS_VARRAY_INT32) { - n_elems = *(int32_t *)(opaque+field->num_offset); - } else if (field->flags & VMS_VARRAY_UINT32) { - n_elems = *(uint32_t *)(opaque+field->num_offset); - } else if (field->flags & VMS_VARRAY_UINT16) { - n_elems = *(uint16_t *)(opaque+field->num_offset); - } else if (field->flags & VMS_VARRAY_UINT8) { - n_elems = *(uint8_t *)(opaque+field->num_offset); - } - if (field->flags & VMS_POINTER) { - base_addr = *(void **)base_addr + field->start; - } + void *base_addr = vmstate_base_addr(opaque, field); + int i, n_elems = vmstate_n_elems(opaque, field); + int size = vmstate_size(opaque, field); + for (i = 0; i < n_elems; i++) { void *addr = base_addr + size * i; @@ -138,6 +147,12 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, field->info->put(f, addr, size); } } + } else { + if (field->flags & VMS_MUST_EXIST) { + fprintf(stderr, "Output state validation failed: %s/%s\n", + vmsd->name, field->name); + assert(!(field->flags & VMS_MUST_EXIST)); + } } field++; } @@ -323,8 +338,9 @@ const VMStateInfo vmstate_info_int32_equal = { .put = put_int32, }; -/* 32 bit int. Check that the received value is less than or equal to - the one in the field */ +/* 32 bit int. Check that the received value is non-negative + * and less than or equal to the one in the field. + */ static int get_int32_le(QEMUFile *f, void *pv, size_t size) { @@ -332,7 +348,7 @@ static int get_int32_le(QEMUFile *f, void *pv, size_t size) int32_t loaded; qemu_get_sbe32s(f, &loaded); - if (loaded <= *cur) { + if (loaded >= 0 && loaded <= *cur) { *cur = loaded; return 0; } diff --git a/xen-common-stub.c b/xen-common-stub.c new file mode 100644 index 0000000000..bd56ca2ce5 --- /dev/null +++ b/xen-common-stub.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 Citrix Systems UK Ltd. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu-common.h" +#include "hw/xen/xen.h" + +void xenstore_store_pv_console_info(int i, CharDriverState *chr) +{ +} + +int xen_init(MachineClass *mc) +{ + return -ENOSYS; +} + diff --git a/xen-common.c b/xen-common.c new file mode 100644 index 0000000000..f07b35e471 --- /dev/null +++ b/xen-common.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2014 Citrix Systems UK Ltd. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/xen/xen_backend.h" +#include "qmp-commands.h" +#include "sysemu/char.h" + +//#define DEBUG_XEN + +#ifdef DEBUG_XEN +#define DPRINTF(fmt, ...) \ + do { fprintf(stderr, "xen: " fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +static int store_dev_info(int domid, CharDriverState *cs, const char *string) +{ + struct xs_handle *xs = NULL; + char *path = NULL; + char *newpath = NULL; + char *pts = NULL; + int ret = -1; + + /* Only continue if we're talking to a pty. */ + if (strncmp(cs->filename, "pty:", 4)) { + return 0; + } + pts = cs->filename + 4; + + /* We now have everything we need to set the xenstore entry. */ + xs = xs_open(0); + if (xs == NULL) { + fprintf(stderr, "Could not contact XenStore\n"); + goto out; + } + + path = xs_get_domain_path(xs, domid); + if (path == NULL) { + fprintf(stderr, "xs_get_domain_path() error\n"); + goto out; + } + newpath = realloc(path, (strlen(path) + strlen(string) + + strlen("/tty") + 1)); + if (newpath == NULL) { + fprintf(stderr, "realloc error\n"); + goto out; + } + path = newpath; + + strcat(path, string); + strcat(path, "/tty"); + if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) { + fprintf(stderr, "xs_write for '%s' fail", string); + goto out; + } + ret = 0; + +out: + free(path); + xs_close(xs); + + return ret; +} + +void xenstore_store_pv_console_info(int i, CharDriverState *chr) +{ + if (i == 0) { + store_dev_info(xen_domid, chr, "/console"); + } else { + char buf[32]; + snprintf(buf, sizeof(buf), "/device/console/%d", i); + store_dev_info(xen_domid, chr, buf); + } +} + + +static void xenstore_record_dm_state(struct xs_handle *xs, const char *state) +{ + char path[50]; + + if (xs == NULL) { + fprintf(stderr, "xenstore connection not initialized\n"); + exit(1); + } + + snprintf(path, sizeof (path), "device-model/%u/state", xen_domid); + if (!xs_write(xs, XBT_NULL, path, state, strlen(state))) { + fprintf(stderr, "error recording dm state\n"); + exit(1); + } +} + + +static void xen_change_state_handler(void *opaque, int running, + RunState state) +{ + if (running) { + /* record state running */ + xenstore_record_dm_state(xenstore, "running"); + } +} + +int xen_init(MachineClass *mc) +{ + xen_xc = xen_xc_interface_open(0, 0, 0); + if (xen_xc == XC_HANDLER_INITIAL_VALUE) { + xen_be_printf(NULL, 0, "can't open xen interface\n"); + return -1; + } + qemu_add_vm_change_state_handler(xen_change_state_handler, NULL); + + return 0; +} + diff --git a/xen-stub.c b/xen-hvm-stub.c index 59927cb5d6..4eb27b5f2b 100644 --- a/xen-stub.c +++ b/xen-hvm-stub.c @@ -13,10 +13,6 @@ #include "exec/memory.h" #include "qmp-commands.h" -void xenstore_store_pv_console_info(int i, CharDriverState *chr) -{ -} - int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) { return -1; @@ -47,19 +43,10 @@ qemu_irq *xen_interrupt_controller_init(void) return NULL; } -int xen_init(QEMUMachine *machine) -{ - return -ENOSYS; -} - void xen_register_framebuffer(MemoryRegion *mr) { } -void qmp_xen_set_global_dirty_log(bool enable, Error **errp) -{ -} - void xen_modified_memory(ram_addr_t start, ram_addr_t length) { } @@ -68,3 +55,7 @@ int xen_hvm_init(MemoryRegion **ram_memory) { return 0; } + +void qmp_xen_set_global_dirty_log(bool enable, Error **errp) +{ +} @@ -26,9 +26,9 @@ #include <xen/hvm/params.h> #include <xen/hvm/e820.h> -//#define DEBUG_XEN +//#define DEBUG_XEN_HVM -#ifdef DEBUG_XEN +#ifdef DEBUG_XEN_HVM #define DPRINTF(fmt, ...) \ do { fprintf(stderr, "xen: " fmt, ## __VA_ARGS__); } while (0) #else @@ -323,7 +323,7 @@ go_physmap: xc_domain_pin_memory_cacheattr(xen_xc, xen_domid, start_addr >> TARGET_PAGE_BITS, - (start_addr + size) >> TARGET_PAGE_BITS, + (start_addr + size - 1) >> TARGET_PAGE_BITS, XEN_DOMCTL_MEM_CACHEATTR_WB); snprintf(path, sizeof(path), @@ -569,15 +569,6 @@ static MemoryListener xen_memory_listener = { .priority = 10, }; -void qmp_xen_set_global_dirty_log(bool enable, Error **errp) -{ - if (enable) { - memory_global_dirty_log_start(); - } else { - memory_global_dirty_log_stop(); - } -} - /* get the ioreq packets from share mem */ static ioreq_t *cpu_get_ioreq_from_shared_memory(XenIOState *state, int vcpu) { @@ -880,82 +871,6 @@ static void cpu_handle_ioreq(void *opaque) } } -static int store_dev_info(int domid, CharDriverState *cs, const char *string) -{ - struct xs_handle *xs = NULL; - char *path = NULL; - char *newpath = NULL; - char *pts = NULL; - int ret = -1; - - /* Only continue if we're talking to a pty. */ - if (strncmp(cs->filename, "pty:", 4)) { - return 0; - } - pts = cs->filename + 4; - - /* We now have everything we need to set the xenstore entry. */ - xs = xs_open(0); - if (xs == NULL) { - fprintf(stderr, "Could not contact XenStore\n"); - goto out; - } - - path = xs_get_domain_path(xs, domid); - if (path == NULL) { - fprintf(stderr, "xs_get_domain_path() error\n"); - goto out; - } - newpath = realloc(path, (strlen(path) + strlen(string) + - strlen("/tty") + 1)); - if (newpath == NULL) { - fprintf(stderr, "realloc error\n"); - goto out; - } - path = newpath; - - strcat(path, string); - strcat(path, "/tty"); - if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) { - fprintf(stderr, "xs_write for '%s' fail", string); - goto out; - } - ret = 0; - -out: - free(path); - xs_close(xs); - - return ret; -} - -void xenstore_store_pv_console_info(int i, CharDriverState *chr) -{ - if (i == 0) { - store_dev_info(xen_domid, chr, "/console"); - } else { - char buf[32]; - snprintf(buf, sizeof(buf), "/device/console/%d", i); - store_dev_info(xen_domid, chr, buf); - } -} - -static void xenstore_record_dm_state(struct xs_handle *xs, const char *state) -{ - char path[50]; - - if (xs == NULL) { - fprintf(stderr, "xenstore connection not initialized\n"); - exit(1); - } - - snprintf(path, sizeof (path), "device-model/%u/state", xen_domid); - if (!xs_write(xs, XBT_NULL, path, state, strlen(state))) { - fprintf(stderr, "error recording dm state\n"); - exit(1); - } -} - static void xen_main_loop_prepare(XenIOState *state) { int evtchn_fd = -1; @@ -973,17 +888,6 @@ static void xen_main_loop_prepare(XenIOState *state) } -/* Initialise Xen */ - -static void xen_change_state_handler(void *opaque, int running, - RunState state) -{ - if (running) { - /* record state running */ - xenstore_record_dm_state(xenstore, "running"); - } -} - static void xen_hvm_change_state_handler(void *opaque, int running, RunState rstate) { @@ -1001,18 +905,6 @@ static void xen_exit_notifier(Notifier *n, void *data) xs_daemon_close(state->xenstore); } -int xen_init(QEMUMachine *machine) -{ - xen_xc = xen_xc_interface_open(0, 0, 0); - if (xen_xc == XC_HANDLER_INITIAL_VALUE) { - xen_be_printf(NULL, 0, "can't open xen interface\n"); - return -1; - } - qemu_add_vm_change_state_handler(xen_change_state_handler, NULL); - - return 0; -} - static void xen_read_physmap(XenIOState *state) { XenPhysmap *physmap = NULL; @@ -1226,3 +1118,12 @@ void xen_modified_memory(ram_addr_t start, ram_addr_t length) } } } + +void qmp_xen_set_global_dirty_log(bool enable, Error **errp) +{ + if (enable) { + memory_global_dirty_log_start(); + } else { + memory_global_dirty_log_stop(); + } +} |