[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [qemu-upstream-unstable] Merge tag 'v2.0.2' into master
=== This changeset includes merge from high-traffic branch === Commits on that branch are not reported individually. commit c9d8f8b755e8960edf7725e05f3e6ac743a5e12e Merge: ea772ca487e219e5d5b82d50da460c4145238038 f053f6b83d01b47adf3b8f29eb0c0769755d1f9c Author: Anthony PERARD <anthony.perard@xxxxxxxxxx> AuthorDate: Wed Sep 24 15:25:27 2014 +0100 Commit: Anthony PERARD <anthony.perard@xxxxxxxxxx> CommitDate: Wed Sep 24 15:25:27 2014 +0100 Merge tag 'v2.0.2' into master VERSION | 2 +- arch_init.c | 110 ++++++++++++----------- async.c | 14 ++- block.c | 34 ++++--- block/mirror.c | 19 +++- block/qapi.c | 1 + block/qcow.c | 44 ++++++++-- block/qcow2.c | 3 +- block/sheepdog.c | 4 +- block/vvfat.c | 6 +- blockdev-nbd.c | 9 ++- blockdev.c | 23 ++++- blockjob.c | 14 +++ configure | 2 +- coroutine-win32.c | 13 +++- cputlb.c | 6 +- disas/Makefile.objs | 2 +- hw/arm/boot.c | 8 ++- hw/arm/omap1.c | 14 ++-- hw/arm/omap2.c | 2 +- hw/arm/pxa2xx.c | 12 ++- hw/arm/spitz.c | 4 +- hw/arm/z2.c | 2 +- hw/char/cadence_uart.c | 15 +++- hw/char/virtio-serial-bus.c | 16 ++-- hw/core/irq.c | 4 +- hw/core/qdev.c | 45 +++++----- hw/display/ssd0323.c | 24 +++++ hw/dma/omap_dma.c | 4 +- hw/gpio/zaurus.c | 10 ++ hw/i386/acpi-build.c | 7 +- hw/i386/kvm/pci-assign.c | 12 ++-- hw/i386/pc.c | 2 +- hw/i386/pc_piix.c | 20 +++-- hw/i386/pc_q35.c | 12 ++-- hw/i386/smbios.c | 18 +++-- hw/ide/ahci.c | 2 +- hw/ide/microdrive.c | 2 +- hw/input/tsc210x.c | 12 +++ hw/intc/i8259.c | 4 +- hw/intc/openpic.c | 16 +++- hw/misc/cbus.c | 6 +- hw/misc/imx_ccm.c | 1 + hw/net/stellaris_enet.c | 23 ++++-- hw/net/virtio-net.c | 37 +++++++- hw/pci/pci.c | 2 +- hw/pci/pcie_aer.c | 10 ++- hw/pcmcia/pxa2xx.c | 2 +- hw/ppc/spapr_pci.c | 15 +++ hw/s390x/css.c | 24 ++++- hw/scsi/megasas.c | 17 ++++ hw/scsi/mfi.h | 9 ++ hw/scsi/scsi-disk.c | 2 +- hw/scsi/vhost-scsi.c | 8 ++- hw/scsi/virtio-scsi.c | 26 ++++-- hw/sd/omap_mmc.c | 2 +- hw/sd/sdhci.c | 8 +- hw/sd/ssi-sd.c | 9 ++ hw/sh4/sh7750.c | 3 +- hw/ssi/pl022.c | 14 +++ hw/timer/hpet.c | 13 +++ hw/timer/i8254.c | 4 +- hw/timer/mc146818rtc.c | 2 +- hw/timer/omap_gptimer.c | 4 +- hw/usb/bus.c | 4 +- hw/usb/dev-bluetooth.c | 24 ++++-- hw/usb/hcd-xhci.c | 1 + hw/virtio/vhost.c | 10 ++- hw/virtio/virtio.c | 33 ++++++- hw/xtensa/xtensa_lx60.c | 8 +- include/block/blockjob.h | 8 ++ include/hw/i386/smbios.h | 6 +- include/hw/virtio/virtio-net.h | 4 +- include/hw/virtio/virtio-scsi.h | 7 ++- include/migration/vmstate.h | 9 ++ kvm-all.c | 7 +- linux-user/elfload.c | 117 ++++++++++++++++++++---- linux-user/syscall.c | 16 ++++ migration-rdma.c | 20 ++-- migration.c | 2 +- nbd.c | 7 +- po/Makefile | 4 +- qapi-schema.json | 7 +- qapi/qapi-dealloc-visitor.c | 4 +- qdev-monitor.c | 2 +- qemu-img.c | 2 +- qemu-io.c | 2 + qemu-nbd.c | 5 +- qga/commands-win32.c | 6 +- qmp-commands.hx | 5 +- target-arm/helper.c | 8 +- target-arm/translate-a64.c | 5 +- target-arm/translate.c | 34 +++++--- target-i386/cpu.c | 22 +++-- target-i386/cpu.h | 11 ++- target-s390x/kvm.c | 190 +++++++++++++++++++++++---------------- target-xtensa/translate.c | 4 +- tcg/i386/tcg-target.c | 3 +- tests/qemu-iotests/040 | 38 ++++++--- tests/qemu-iotests/040.out | 4 +- tests/qemu-iotests/041 | 16 +++- tests/qemu-iotests/041.out | 4 +- tests/qemu-iotests/092 | 98 ++++++++++++++++++++ tests/qemu-iotests/092.out | 38 ++++++++ tests/qemu-iotests/group | 1 + trace-events | 5 + ui/curses.c | 4 +- vmstate.c | 117 ++++++++++++++----------- 108 files changed, 1248 insertions(+), 488 deletions(-) diff --git a/VERSION b/VERSION index 227cea2..e9307ca 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0.0 +2.0.2 diff --git a/arch_init.c b/arch_init.c index 60c975d..3ec70de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -992,70 +992,68 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) { ram_addr_t addr; int flags, ret = 0; - int error; static uint64_t seq_iter; seq_iter++; - if (version_id < 4 || version_id > 4) { - return -EINVAL; + if (version_id != 4) { + ret = -EINVAL; } - do { + while (!ret) { addr = qemu_get_be64(f); flags = addr & ~TARGET_PAGE_MASK; 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; } + 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; + } + if (ret) { + break; } - } - } - if (flags & RAM_SAVE_FLAG_COMPRESS) { + total_ram_bytes -= length; + } + } else if (flags & RAM_SAVE_FLAG_COMPRESS) { void *host; uint8_t ch; host = host_from_stream_offset(f, addr, flags); if (!host) { - return -EINVAL; + error_report("Illegal RAM offset " RAM_ADDR_FMT, addr); + ret = -EINVAL; + break; } ch = qemu_get_byte(f); @@ -1065,31 +1063,39 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) host = host_from_stream_offset(f, addr, flags); if (!host) { - return -EINVAL; + error_report("Illegal RAM offset " RAM_ADDR_FMT, addr); + ret = -EINVAL; + break; } 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; + error_report("Illegal RAM offset " RAM_ADDR_FMT, addr); + ret = -EINVAL; + break; } if (load_xbzrle(f, addr, host) < 0) { + error_report("Failed to decompress XBZRLE page at " + RAM_ADDR_FMT, addr); ret = -EINVAL; - goto done; + break; } } else if (flags & RAM_SAVE_FLAG_HOOK) { ram_control_load_hook(f, flags); + } else if (flags & RAM_SAVE_FLAG_EOS) { + /* normal exit */ + break; + } else { + error_report("Unknown migration flags: %#x", flags); + ret = -EINVAL; + break; } - error = qemu_file_get_error(f); - if (error) { - ret = error; - goto done; - } - } while (!(flags & RAM_SAVE_FLAG_EOS)); + ret = qemu_file_get_error(f); + } -done: DPRINTF("Completed load of VM with exit code %d seq iteration " "%" PRIu64 "\n", ret, seq_iter); return ret; diff --git a/async.c b/async.c index 6930185..5b6fe6b 100644 --- a/async.c +++ b/async.c @@ -117,15 +117,21 @@ void qemu_bh_schedule_idle(QEMUBH *bh) void qemu_bh_schedule(QEMUBH *bh) { + AioContext *ctx; + if (bh->scheduled) return; + ctx = bh->ctx; bh->idle = 0; - /* Make sure that idle & any writes needed by the callback are done - * before the locations are read in the aio_bh_poll. + /* Make sure that: + * 1. idle & any writes needed by the callback are done before the + * locations are read in the aio_bh_poll. + * 2. ctx is loaded before scheduled is set and the callback has a chance + * to execute. */ - smp_wmb(); + smp_mb(); bh->scheduled = 1; - aio_notify(bh->ctx); + aio_notify(ctx); } diff --git a/block.c b/block.c index 990a754..5448430 100644 --- a/block.c +++ b/block.c @@ -1058,14 +1058,14 @@ fail: */ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) { - char backing_filename[PATH_MAX]; - int back_flags, ret; + char *backing_filename = g_malloc0(PATH_MAX); + int back_flags, ret = 0; BlockDriver *back_drv = NULL; Error *local_err = NULL; if (bs->backing_hd != NULL) { QDECREF(options); - return 0; + goto free_exit; } /* NULL means an empty set of options */ @@ -1078,10 +1078,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) backing_filename[0] = '\0'; } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) { QDECREF(options); - return 0; + goto free_exit; } else { - bdrv_get_full_backing_filename(bs, backing_filename, - sizeof(backing_filename)); + bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX); } if (bs->backing_format[0] != '\0') { @@ -1102,7 +1101,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) error_setg(errp, "Could not open backing file: %s", error_get_pretty(local_err)); error_free(local_err); - return ret; + goto free_exit; } if (bs->backing_hd->file) { @@ -1113,7 +1112,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) /* Recalculate the BlockLimits with the backing file */ bdrv_refresh_limits(bs); - return 0; +free_exit: + g_free(backing_filename); + return ret; } /* @@ -1157,6 +1158,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, bdref_key); ret = -EINVAL; } + QDECREF(image_options); goto done; } @@ -1170,8 +1172,7 @@ done: void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) { /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ - char tmp_filename[PATH_MAX + 1]; - + char *tmp_filename = g_malloc0(PATH_MAX + 1); int64_t total_size; BlockDriver *bdrv_qcow2; QEMUOptionParameter *create_options; @@ -1187,15 +1188,15 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) total_size = bdrv_getlength(bs); if (total_size < 0) { error_setg_errno(errp, -total_size, "Could not get image size"); - return; + goto out; } total_size &= BDRV_SECTOR_MASK; /* Create the temporary image */ - ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename)); + ret = get_tmp_filename(tmp_filename, PATH_MAX + 1); if (ret < 0) { error_setg_errno(errp, -ret, "Could not get temporary filename"); - return; + goto out; } bdrv_qcow2 = bdrv_find_format("qcow2"); @@ -1211,7 +1212,7 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) "'%s': %s", tmp_filename, error_get_pretty(local_err)); error_free(local_err); - return; + goto out; } /* Prepare a new options QDict for the temporary file */ @@ -1228,10 +1229,13 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) bs->open_flags & ~BDRV_O_SNAPSHOT, bdrv_qcow2, &local_err); if (ret < 0) { error_propagate(errp, local_err); - return; + goto out; } bdrv_append(bs_snapshot, bs); + +out: + g_free(tmp_filename); } /* diff --git a/block/mirror.c b/block/mirror.c index 0ef41f9..6e502e3 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -259,9 +259,11 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) next_sector = sector_num; while (nb_chunks-- > 0) { MirrorBuffer *buf = QSIMPLEQ_FIRST(&s->buf_free); + size_t remaining = (nb_sectors * BDRV_SECTOR_SIZE) - op->qiov.size; + QSIMPLEQ_REMOVE_HEAD(&s->buf_free, next); s->buf_free_count--; - qemu_iovec_add(&op->qiov, buf, s->granularity); + qemu_iovec_add(&op->qiov, buf, MIN(s->granularity, remaining)); /* Advance the HBitmapIter in parallel, so that we do not examine * the same sector twice. @@ -324,9 +326,18 @@ static void coroutine_fn mirror_run(void *opaque) } s->common.len = bdrv_getlength(bs); - if (s->common.len <= 0) { - block_job_completed(&s->common, s->common.len); - return; + if (s->common.len < 0) { + ret = s->common.len; + goto immediate_exit; + } else if (s->common.len == 0) { + /* Report BLOCK_JOB_READY and wait for complete. */ + block_job_ready(&s->common); + s->synced = true; + while (!block_job_is_cancelled(&s->common) && !s->should_complete) { + block_job_yield(&s->common); + } + s->common.cancelled = false; + goto immediate_exit; } length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity; diff --git a/block/qapi.c b/block/qapi.c index 8f2b4db..a69c00d 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -474,6 +474,7 @@ static void dump_qobject(fprintf_function func_fprintf, void *f, case QTYPE_QERROR: { QString *value = qerror_human((QError *)obj); func_fprintf(f, "%s", qstring_get_str(value)); + QDECREF(value); break; } case QTYPE_NONE: diff --git a/block/qcow.c b/block/qcow.c index d5a7d5f..c0a3b89 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -48,9 +48,10 @@ typedef struct QCowHeader { uint64_t size; /* in bytes */ uint8_t cluster_bits; uint8_t l2_bits; + uint16_t padding; uint32_t crypt_method; uint64_t l1_table_offset; -} QCowHeader; +} QEMU_PACKED QCowHeader; #define L2_CACHE_SIZE 16 @@ -60,7 +61,7 @@ typedef struct BDRVQcowState { int cluster_sectors; int l2_bits; int l2_size; - int l1_size; + unsigned int l1_size; uint64_t cluster_offset_mask; uint64_t l1_table_offset; uint64_t *l1_table; @@ -96,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVQcowState *s = bs->opaque; - int len, i, shift, ret; + unsigned int len, i, shift; + int ret; QCowHeader header; ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); @@ -126,11 +128,25 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - if (header.size <= 1 || header.cluster_bits < 9) { - error_setg(errp, "invalid value in qcow header"); + if (header.size <= 1) { + error_setg(errp, "Image size is too small (must be at least 2 bytes)"); + ret = -EINVAL; + goto fail; + } + if (header.cluster_bits < 9 || header.cluster_bits > 16) { + error_setg(errp, "Cluster size must be between 512 and 64k"); + ret = -EINVAL; + goto fail; + } + + /* l2_bits specifies number of entries; storing a uint64_t in each entry, + * so bytes = num_entries << 3. */ + if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) { + error_setg(errp, "L2 table size must be between 512 and 64k"); ret = -EINVAL; goto fail; } + if (header.crypt_method > QCOW_CRYPT_AES) { error_setg(errp, "invalid encryption method in qcow header"); ret = -EINVAL; @@ -150,7 +166,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, /* read the level 1 table */ shift = s->cluster_bits + s->l2_bits; - s->l1_size = (header.size + (1LL << shift) - 1) >> shift; + if (header.size > UINT64_MAX - (1LL << shift)) { + error_setg(errp, "Image too large"); + ret = -EINVAL; + goto fail; + } else { + uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift; + if (l1_size > INT_MAX / sizeof(uint64_t)) { + error_setg(errp, "Image too large"); + ret = -EINVAL; + goto fail; + } + s->l1_size = l1_size; + } s->l1_table_offset = header.l1_table_offset; s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t)); @@ -174,7 +202,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, if (header.backing_file_offset != 0) { len = header.backing_file_size; if (len > 1023) { - len = 1023; + error_setg(errp, "Backing file name too long"); + ret = -EINVAL; + goto fail; } ret = bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len); diff --git a/block/qcow2.c b/block/qcow2.c index e903d97..57c353d 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1306,6 +1306,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) options = qdict_clone_shallow(bs->options); ret = qcow2_open(bs, options, flags, &local_err); + QDECREF(options); if (local_err) { error_setg(errp, "Could not reopen qcow2 layer: %s", error_get_pretty(local_err)); @@ -1316,8 +1317,6 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) return; } - QDECREF(options); - if (crypt_method) { s->crypt_method = crypt_method; memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key)); diff --git a/block/sheepdog.c b/block/sheepdog.c index 0eb33ee..7dcebce 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -2149,6 +2149,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag)); /* we don't need to update entire object */ datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id); + inode = g_malloc(datalen); /* refresh inode. */ fd = connect_to_sdog(s); @@ -2171,8 +2172,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) goto cleanup; } - inode = (SheepdogInode *)g_malloc(datalen); - ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid), s->inode.nr_copies, datalen, 0, s->cache_flags); @@ -2186,6 +2185,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) s->inode.name, s->inode.snap_id, s->inode.vdi_id); cleanup: + g_free(inode); closesocket(fd); return ret; } diff --git a/block/vvfat.c b/block/vvfat.c index 1978c9e..91c63f7 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -787,7 +787,9 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) s->current_mapping->path=buffer; s->current_mapping->read_only = (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0; - } + } else { + g_free(buffer); + } } closedir(dir); @@ -1864,7 +1866,7 @@ static int check_directory_consistency(BDRVVVFATState *s, if (s->used_clusters[cluster_num] & USED_ANY) { fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num); - return 0; + goto fail; } s->used_clusters[cluster_num] = USED_DIRECTORY; diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 922cf56..b3a2474 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -27,8 +27,9 @@ static void nbd_accept(void *opaque) socklen_t addr_len = sizeof(addr); int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); - if (fd >= 0) { - nbd_client_new(NULL, fd, nbd_client_put); + if (fd >= 0 && !nbd_client_new(NULL, fd, nbd_client_put)) { + shutdown(fd, 2); + close(fd); } } @@ -91,6 +92,10 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, error_set(errp, QERR_DEVICE_NOT_FOUND, device); return; } + if (!bdrv_is_inserted(bs)) { + error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); + return; + } if (!has_writable) { writable = false; diff --git a/blockdev.c b/blockdev.c index 5dd01ea..4d98224 100644 --- a/blockdev.c +++ b/blockdev.c @@ -332,7 +332,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error); if (error) { error_propagate(errp, error); - return NULL; + goto err_no_opts; } qemu_opts_absorb_qdict(opts, bs_opts, &error); @@ -527,8 +527,9 @@ err: QTAILQ_REMOVE(&drives, dinfo, next); g_free(dinfo); early_err: - QDECREF(bs_opts); qemu_opts_del(opts); +err_no_opts: + QDECREF(bs_opts); return NULL; } @@ -902,6 +903,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) /* Actual block device init: Functionality shared with blockdev-add */ dinfo = blockdev_init(filename, bs_opts, &local_err); + bs_opts = NULL; if (dinfo == NULL) { if (local_err) { qerror_report_err(local_err); @@ -939,6 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) fail: qemu_opts_del(legacy_opts); + QDECREF(bs_opts); return dinfo; } @@ -1864,7 +1867,8 @@ void qmp_block_stream(const char *device, bool has_base, } void qmp_block_commit(const char *device, - bool has_base, const char *base, const char *top, + bool has_base, const char *base, + bool has_top, const char *top, bool has_speed, int64_t speed, Error **errp) { @@ -1883,6 +1887,11 @@ void qmp_block_commit(const char *device, /* drain all i/o before commits */ bdrv_drain_all(); + /* Important Note: + * libvirt relies on the DeviceNotFound error class in order to probe for + * live commit feature versions; for this to work, we must make sure to + * perform the device lookup before any generic errors that may occur in a + * scenario in which all optional arguments are omitted. */ bs = bdrv_find(device); if (!bs) { error_set(errp, QERR_DEVICE_NOT_FOUND, device); @@ -1892,7 +1901,7 @@ void qmp_block_commit(const char *device, /* default top_bs is the active layer */ top_bs = bs; - if (top) { + if (has_top && top) { if (strcmp(bs->filename, top) != 0) { top_bs = bdrv_find_backing_image(bs, top); } @@ -1914,6 +1923,12 @@ void qmp_block_commit(const char *device, return; } + /* Do not allow attempts to commit an image into itself */ + if (top_bs == base_bs) { + error_setg(errp, "cannot commit an image into itself"); + return; + } + if (top_bs == bs) { commit_active_start(bs, base_bs, speed, on_error, block_job_cb, bs, &local_err); diff --git a/blockjob.c b/blockjob.c index b3ce14c..bf10f82 100644 --- a/blockjob.c +++ b/blockjob.c @@ -206,6 +206,20 @@ void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns) job->busy = true; } +void block_job_yield(BlockJob *job) +{ + assert(job->busy); + + /* Check cancellation *before* setting busy = false, too! */ + if (block_job_is_cancelled(job)) { + return; + } + + job->busy = false; + qemu_coroutine_yield(); + job->busy = true; +} + BlockJobInfo *block_job_query(BlockJob *job) { BlockJobInfo *info = g_new0(BlockJobInfo, 1); diff --git a/configure b/configure index 69b9f56..ffce604 100755 --- a/configure +++ b/configure @@ -2624,7 +2624,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 diff --git a/coroutine-win32.c b/coroutine-win32.c index edc1f72..17ace37 100644 --- a/coroutine-win32.c +++ b/coroutine-win32.c @@ -36,8 +36,17 @@ typedef struct static __thread CoroutineWin32 leader; static __thread Coroutine *current; -CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, - CoroutineAction action) +/* This function is marked noinline to prevent GCC from inlining it + * into coroutine_trampoline(). If we allow it to do that then it + * hoists the code to get the address of the TLS variable "current" + * out of the while() loop. This is an invalid transformation because + * the SwitchToFiber() call may be called when running thread A but + * return in thread B, and so we might be in a different thread + * context each time round the loop. + */ +CoroutineAction __attribute__((noinline)) +qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, + CoroutineAction action) { CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_); CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_); diff --git a/cputlb.c b/cputlb.c index 7bd3573..214c945 100644 --- a/cputlb.c +++ b/cputlb.c @@ -331,8 +331,10 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) } #define MMUSUFFIX _cmmu -#undef GETPC -#define GETPC() ((uintptr_t)0) +#undef GETPC_ADJ +#define GETPC_ADJ 0 +#undef GETRA +#define GETRA() ((uintptr_t)0) #define SOFTMMU_CODE_ACCESS #define SHIFT 0 diff --git a/disas/Makefile.objs b/disas/Makefile.objs index 41c2374..a70c592 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -4,7 +4,7 @@ common-obj-$(CONFIG_ARM_DIS) += arm.o common-obj-$(CONFIG_ARM_A64_DIS) += arm-a64.o common-obj-$(CONFIG_ARM_A64_DIS) += libvixl/ libvixldir = $(SRC_PATH)/disas/libvixl -$(obj)/arm-a64.o: QEMU_CFLAGS += -I$(libvixldir) +$(obj)/arm-a64.o: QEMU_CFLAGS := -I$(libvixldir) $(QEMU_CFLAGS) common-obj-$(CONFIG_CRIS_DIS) += cris.o common-obj-$(CONFIG_HPPA_DIS) += hppa.o common-obj-$(CONFIG_I386_DIS) += i386.o diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 3d1f4a2..1241761 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -417,8 +417,12 @@ static void do_cpu_reset(void *opaque) if (info) { if (!info->is_linux) { /* Jump to the entry point. */ - env->regs[15] = info->entry & 0xfffffffe; - env->thumb = info->entry & 1; + if (env->aarch64) { + env->pc = info->entry; + } else { + env->regs[15] = info->entry & 0xfffffffe; + env->thumb = info->entry & 1; + } } else { if (CPU(cpu) == first_cpu) { if (env->aarch64) { diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index b433748..9f5d159 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -172,7 +172,7 @@ static void omap_timer_clk_update(void *opaque, int line, int on) static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) { omap_clk_adduser(timer->clk, - qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]); + qemu_allocate_irq(omap_timer_clk_update, timer, 0)); timer->rate = omap_clk_getrate(timer->clk); } @@ -2098,7 +2098,7 @@ static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory, "omap-mpuio", 0x800); memory_region_add_subregion(memory, base, &s->iomem); - omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]); + omap_clk_adduser(clk, qemu_allocate_irq(omap_mpuio_onoff, s, 0)); return s; } @@ -2401,7 +2401,7 @@ static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory, "omap-pwl", 0x800); memory_region_add_subregion(system_memory, base, &s->iomem); - omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); + omap_clk_adduser(clk, qemu_allocate_irq(omap_pwl_clk_update, s, 0)); return s; } @@ -3485,8 +3485,8 @@ static void omap_mcbsp_i2s_start(void *opaque, int line, int level) void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave) { s->codec = slave; - slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0]; - slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0]; + slave->rx_swallow = qemu_allocate_irq(omap_mcbsp_i2s_swallow, s, 0); + slave->tx_start = qemu_allocate_irq(omap_mcbsp_i2s_start, s, 0); } /* LED Pulse Generators */ @@ -3634,7 +3634,7 @@ static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, memory_region_init_io(&s->iomem, NULL, &omap_lpg_ops, s, "omap-lpg", 0x800); memory_region_add_subregion(system_memory, base, &s->iomem); - omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]); + omap_clk_adduser(clk, qemu_allocate_irq(omap_lpg_clk_update, s, 0)); return s; } @@ -3848,7 +3848,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, s->sdram_size = sdram_size; s->sram_size = OMAP15XX_SRAM_SIZE; - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; + s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0); /* Clocks */ omap_clk_init(s); diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index 36efde0..dc53a7a 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -2260,7 +2260,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, s->sdram_size = sdram_size; s->sram_size = OMAP242X_SRAM_SIZE; - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; + s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0); /* Clocks */ omap_clk_init(s); diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 0429148..c652147 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); @@ -2055,7 +2059,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; + s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0); /* SDRAM & Internal Memory Storage */ memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size); @@ -2186,7 +2190,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; + s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0); /* SDRAM & Internal Memory Storage */ memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size); diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 392ca84..713d021 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -744,7 +744,7 @@ static void spitz_i2c_setup(PXA2xxState *cpu) spitz_wm8750_addr(wm, 0, 0); qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM, - qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]); + qemu_allocate_irq(spitz_wm8750_addr, wm, 0)); /* .. and to the sound interface. */ cpu->i2s->opaque = wm; cpu->i2s->codec_out = wm8750_dac_dat; @@ -850,7 +850,7 @@ static void spitz_gpio_setup(PXA2xxState *cpu, int slots) * wouldn't guarantee that a guest ever exits the loop. */ spitz_hsync = 0; - lcd_hsync = qemu_allocate_irqs(spitz_lcd_hsync_handler, cpu, 1)[0]; + lcd_hsync = qemu_allocate_irq(spitz_lcd_hsync_handler, cpu, 0); pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync); pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync); diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 67c1be8..ef5424d 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -365,7 +365,7 @@ static void z2_init(QEMUMachineInitArgs *args) wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s); qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS, - qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]); + qemu_allocate_irq(z2_lcd_cs, z2_lcd, 0)); z2_binfo.kernel_filename = kernel_filename; z2_binfo.kernel_cmdline = kernel_cmdline; diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 1f3d162..ce20e1a 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -175,8 +175,10 @@ static void uart_send_breaks(UartState *s) { int break_enabled = 1; - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, - &break_enabled); + if (s->chr) { + qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, + &break_enabled); + } } static void uart_parameters_setup(UartState *s) @@ -227,7 +229,9 @@ static void uart_parameters_setup(UartState *s) packet_size += ssp.data_bits + ssp.stop_bits; s->char_tx_time = (get_ticks_per_sec() / ssp.speed) * packet_size; - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); + if (s->chr) { + qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); + } } static int uart_can_receive(void *opaque) @@ -295,6 +299,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond, /* instant drain the fifo when there's no back-end */ if (!s->chr) { s->tx_count = 0; + return FALSE; } if (!s->tx_count) { @@ -375,7 +380,9 @@ static void uart_read_rx_fifo(UartState *s, uint32_t *c) *c = s->rx_fifo[rx_rpos]; s->rx_count--; - qemu_chr_accept_input(s->chr); + if (s->chr) { + qemu_chr_accept_input(s->chr); + } } else { *c = 0; } diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 2b647b6..ee1ba16 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -670,6 +670,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) uint32_t max_nr_ports, nr_active_ports, ports_map; unsigned int i; int ret; + uint32_t tmp; if (version_id > 3) { return -EINVAL; @@ -685,17 +686,12 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) return 0; } - /* The config space */ - qemu_get_be16s(f, &s->config.cols); - qemu_get_be16s(f, &s->config.rows); - - qemu_get_be32s(f, &max_nr_ports); - tswap32s(&max_nr_ports); - if (max_nr_ports > tswap32(s->config.max_nr_ports)) { - /* Source could have had more ports than us. Fail migration. */ - return -EINVAL; - } + /* Unused */ + qemu_get_be16s(f, (uint16_t *) &tmp); + qemu_get_be16s(f, (uint16_t *) &tmp); + qemu_get_be32s(f, &tmp); + max_nr_ports = tswap32(s->config.max_nr_ports); for (i = 0; i < (max_nr_ports + 31) / 32; i++) { qemu_get_be32s(f, &ports_map); diff --git a/hw/core/irq.c b/hw/core/irq.c index 03c8cb3..3d284c6 100644 --- a/hw/core/irq.c +++ b/hw/core/irq.c @@ -102,7 +102,7 @@ qemu_irq qemu_irq_invert(qemu_irq irq) { /* The default state for IRQs is low, so raise the output now. */ qemu_irq_raise(irq); - return qemu_allocate_irqs(qemu_notirq, irq, 1)[0]; + return qemu_allocate_irq(qemu_notirq, irq, 0); } static void qemu_splitirq(void *opaque, int line, int level) @@ -117,7 +117,7 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2) qemu_irq *s = g_malloc0(2 * sizeof(qemu_irq)); s[0] = irq1; s[1] = irq2; - return qemu_allocate_irqs(qemu_splitirq, s, 1)[0]; + return qemu_allocate_irq(qemu_splitirq, s, 0); } static void proxy_irq_handler(void *opaque, int n, int level) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 60f9df1..79db470 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,43 +504,46 @@ 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); + BusChild *kid; Error *local_err = NULL; if (value && !bus->realized) { if (bc->realize) { bc->realize(bus, &local_err); + } + /* TODO: recursive realization */ + } else if (!value && bus->realized) { + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + object_property_set_bool(OBJECT(dev), false, "realized", + &local_err); if (local_err != NULL) { - goto error; + break; } - } - } else if (!value && bus->realized) { - if (bc->unrealize) { + if (bc->unrealize && local_err == NULL) { bc->unrealize(bus, &local_err); - - if (local_err != NULL) { - goto error; - } } } - bus->realized = value; - return; + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } -error: - error_propagate(err, local_err); + bus->realized = value; } void qbus_create_inplace(void *bus, size_t size, const char *typename, @@ -724,13 +727,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 +741,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 +800,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/ssd0323.c b/hw/display/ssd0323.c index 971152e..9727007 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/dma/omap_dma.c b/hw/dma/omap_dma.c index 0e8cccd..bb02279 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -1660,7 +1660,7 @@ struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs, } omap_dma_setcaps(s); - omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); + omap_clk_adduser(s->clk, qemu_allocate_irq(omap_dma_clk_update, s, 0)); omap_dma_reset(s->dma); omap_dma_clk_update(s, 0, 1); @@ -2082,7 +2082,7 @@ struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs, s->intr_update = omap_dma_interrupts_4_update; omap_dma_setcaps(s); - omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); + omap_clk_adduser(s->clk, qemu_allocate_irq(omap_dma_clk_update, s, 0)); omap_dma_reset(s->dma); omap_dma_clk_update(s, 0, !!s->dma->freq); diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index dc79a8b..8e2ce04 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/i386/acpi-build.c b/hw/i386/acpi-build.c index c98df88..985a188 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1410,15 +1410,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/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index a825871..76aa86e 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -1258,6 +1258,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) if (pos != 0 && kvm_device_msix_supported(kvm_state)) { int bar_nr; uint32_t msix_table_entry; + uint16_t msix_max; if (!check_irqchip_in_kernel()) { return -ENOTSUP; @@ -1269,9 +1270,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) } pci_dev->msix_cap = pos; - pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, - pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) & - PCI_MSIX_FLAGS_QSIZE); + msix_max = (pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) & + PCI_MSIX_FLAGS_QSIZE) + 1; + msix_max = MIN(msix_max, KVM_MAX_MSIX_PER_DEV); + pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, msix_max - 1); /* Only enable and function mask bits are writable */ pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS, @@ -1281,9 +1283,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK; msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK; dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry; - dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS); - dev->msix_max &= PCI_MSIX_FLAGS_QSIZE; - dev->msix_max += 1; + dev->msix_max = msix_max; } /* Minimal PM support, nothing writable, device appears to NAK changes */ diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 30d3bfa..c9dcd98 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -655,7 +655,7 @@ static FWCfgState *bochs_bios_init(void) acpi_tables, acpi_tables_len); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); - smbios_table = smbios_get_table(&smbios_len); + smbios_table = smbios_get_table_legacy(&smbios_len); if (smbios_table) fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, smbios_table, smbios_len); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 1b3cd18..ce708c7 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -63,7 +63,7 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; static bool has_pci_info; static bool has_acpi_build = true; -static bool smbios_type1_defaults = true; +static bool smbios_defaults = true; /* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to * host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte * pages in the host. @@ -166,10 +166,10 @@ static void pc_init1(QEMUMachineInitArgs *args, guest_info->has_pci_info = has_pci_info; guest_info->isapc_ram_fw = !pci_enabled; - if (smbios_type1_defaults) { + if (smbios_defaults) { /* These values are guest ABI, do not change */ - smbios_set_type1_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", - args->machine->name); + smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", + args->machine->name); } /* allocate ram and load rom/bios */ @@ -294,7 +294,7 @@ static void pc_init_pci(QEMUMachineInitArgs *args) static void pc_compat_1_7(QEMUMachineInitArgs *args) { - smbios_type1_defaults = false; + smbios_defaults = false; gigabyte_align = false; option_rom_has_mr = true; x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC); @@ -375,7 +375,10 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) { has_pci_info = false; has_acpi_build = false; - smbios_type1_defaults = false; + smbios_defaults = false; + gigabyte_align = false; + option_rom_has_mr = true; + rom_file_has_mr = false; x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); enable_compat_apic_id_mode(); pc_init1(args, 1, 0); @@ -385,7 +388,10 @@ static void pc_init_isa(QEMUMachineInitArgs *args) { has_pci_info = false; has_acpi_build = false; - smbios_type1_defaults = false; + smbios_defaults = false; + gigabyte_align = false; + option_rom_has_mr = true; + rom_file_has_mr = false; if (!args->cpu_model) { args->cpu_model = "486"; } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index c529e02..c6187a4 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -53,7 +53,7 @@ extern uint64_t max_ram_below_4g; static bool has_pci_info; static bool has_acpi_build = true; -static bool smbios_type1_defaults = true; +static bool smbios_defaults = true; /* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to * host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte * pages in the host. @@ -153,10 +153,10 @@ static void pc_q35_init(QEMUMachineInitArgs *args) guest_info->isapc_ram_fw = false; guest_info->has_acpi_build = has_acpi_build; - if (smbios_type1_defaults) { + if (smbios_defaults) { /* These values are guest ABI, do not change */ - smbios_set_type1_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", - args->machine->name); + smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", + args->machine->name); } /* allocate ram and load rom/bios */ @@ -265,7 +265,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) static void pc_compat_1_7(QEMUMachineInitArgs *args) { - smbios_type1_defaults = false; + smbios_defaults = false; gigabyte_align = false; option_rom_has_mr = true; x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC); @@ -374,7 +374,7 @@ static QEMUMachine pc_q35_machine_v1_4 = { .name = "pc-q35-1.4", .init = pc_q35_init_1_4, .compat_props = (GlobalProperty[]) { - PC_COMPAT_1_4, + PC_Q35_COMPAT_1_4, { /* end of list */ } }, }; diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index e8f41ad..e734d4c 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -21,9 +21,8 @@ #include "hw/i386/smbios.h" #include "hw/loader.h" -/* - * Structures shared with the BIOS - */ + +/* legacy structures and constants for <= 2.0 machines */ struct smbios_header { uint16_t length; uint8_t type; @@ -46,6 +45,9 @@ struct smbios_table { static uint8_t *smbios_entries; static size_t smbios_entries_len; +/* end: legacy structures & constants for <= 2.0 machines */ + + static int smbios_type4_count = 0; static bool smbios_immutable; @@ -187,6 +189,8 @@ static void smbios_check_collision(int type, int entry) } } + +/* legacy setup functions for <= 2.0 machines */ static void smbios_add_field(int type, int offset, const void *data, size_t len) { struct smbios_field *field; @@ -256,8 +260,8 @@ static void smbios_build_type_1_fields(void) } } -void smbios_set_type1_defaults(const char *manufacturer, - const char *product, const char *version) +void smbios_set_defaults(const char *manufacturer, const char *product, + const char *version) { if (!type1.manufacturer) { type1.manufacturer = manufacturer; @@ -270,7 +274,7 @@ void smbios_set_type1_defaults(const char *manufacturer, } } -uint8_t *smbios_get_table(size_t *length) +uint8_t *smbios_get_table_legacy(size_t *length) { if (!smbios_immutable) { smbios_build_type_0_fields(); @@ -281,6 +285,8 @@ uint8_t *smbios_get_table(size_t *length) *length = smbios_entries_len; return smbios_entries; } +/* end: legacy setup functions for <= 2.0 machines */ + static void save_opt(const char **dest, QemuOpts *opts, const char *name) { diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index bfe633f..457a7a1 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/ide/microdrive.c b/hw/ide/microdrive.c index 21d6495..c73c5a7 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -594,7 +594,7 @@ static void microdrive_realize(DeviceState *dev, Error **errp) { MicroDriveState *md = MICRODRIVE(dev); - ide_init2(&md->bus, qemu_allocate_irqs(md_set_irq, md, 1)[0]); + ide_init2(&md->bus, qemu_allocate_irq(md_set_irq, md, 0)); } static void microdrive_init(Object *obj) diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index 485c9e5..aa5b688 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/i8259.c b/hw/intc/i8259.c index c6f248b..ec01393 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -412,7 +412,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 +425,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 be76fbd..17136c9 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/misc/cbus.c b/hw/misc/cbus.c index 29b467b..495d507 100644 --- a/hw/misc/cbus.c +++ b/hw/misc/cbus.c @@ -135,9 +135,9 @@ CBus *cbus_init(qemu_irq dat) CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s)); s->dat_out = dat; - s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0]; - s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0]; - s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0]; + s->cbus.clk = qemu_allocate_irq(cbus_clk, s, 0); + s->cbus.dat = qemu_allocate_irq(cbus_dat, s, 0); + s->cbus.sel = qemu_allocate_irq(cbus_sel, s, 0); s->sel = 1; s->clk = 0; diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index 63e33a4..449183d 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -68,6 +68,7 @@ static const VMStateDescription vmstate_imx_ccm = { VMSTATE_UINT32(pmcr0, IMXCCMState), VMSTATE_UINT32(pmcr1, IMXCCMState), VMSTATE_UINT32(pll_refclk_freq, IMXCCMState), + VMSTATE_END_OF_LIST() }, .post_load = imx_ccm_post_load, }; diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index d04e6a4..9cc6262 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -8,6 +8,7 @@ */ #include "hw/sysbus.h" #include "net/net.h" +#include "migration/migration.h" #include <zlib.h> //#define DEBUG_STELLARIS_ENET 1 @@ -75,6 +76,7 @@ typedef struct { NICConf conf; qemu_irq irq; MemoryRegion mmio; + Error *migration_blocker; } stellaris_enet_state; static void stellaris_enet_update(stellaris_enet_state *s) @@ -253,17 +255,19 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, s->tx_fifo[s->tx_fifo_len++] = value >> 24; } } else { - s->tx_fifo[s->tx_fifo_len++] = value; - s->tx_fifo[s->tx_fifo_len++] = value >> 8; - s->tx_fifo[s->tx_fifo_len++] = value >> 16; - s->tx_fifo[s->tx_fifo_len++] = value >> 24; + if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) { + s->tx_fifo[s->tx_fifo_len++] = value; + s->tx_fifo[s->tx_fifo_len++] = value >> 8; + s->tx_fifo[s->tx_fifo_len++] = value >> 16; + s->tx_fifo[s->tx_fifo_len++] = value >> 24; + } if (s->tx_fifo_len >= s->tx_frame_len) { /* We don't implement explicit CRC, so just chop it off. */ if ((s->tctl & SE_TCTL_CRC) == 0) s->tx_frame_len -= 4; if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) { memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len); - s->tx_fifo_len = 60; + s->tx_frame_len = 60; } qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo, s->tx_frame_len); @@ -360,7 +364,7 @@ static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) stellaris_enet_state *s = (stellaris_enet_state *)opaque; int i; - if (version_id != 1) + if (1) return -EINVAL; s->ris = qemu_get_be32(f); @@ -421,6 +425,10 @@ static int stellaris_enet_init(SysBusDevice *sbd) stellaris_enet_reset(s); register_savevm(dev, "stellaris_enet", -1, 1, stellaris_enet_save, stellaris_enet_load, s); + + error_setg(&s->migration_blocker, + "stellaris_enet does not support migration"); + migrate_add_blocker(s->migration_blocker); return 0; } @@ -428,6 +436,9 @@ static void stellaris_enet_unrealize(DeviceState *dev, Error **errp) { stellaris_enet_state *s = STELLARIS_ENET(dev); + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); + unregister_savevm(DEVICE(s), "stellaris_enet", s); memory_region_destroy(&s->mmio); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 33bd233..2ac6ce5 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -863,6 +863,14 @@ static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) return 1; } +static void virtio_net_hdr_swap(struct virtio_net_hdr *hdr) +{ + tswap16s(&hdr->hdr_len); + tswap16s(&hdr->gso_size); + tswap16s(&hdr->csum_start); + tswap16s(&hdr->csum_offset); +} + /* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so * it never finds out that the packets don't have valid checksums. This * causes dhclient to get upset. Fedora's carried a patch for ages to @@ -898,6 +906,7 @@ static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, void *wbuf = (void *)buf; work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, size - n->host_hdr_len); + virtio_net_hdr_swap(wbuf); iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); } else { struct virtio_net_hdr hdr = { @@ -1106,6 +1115,14 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) exit(1); } + if (n->has_vnet_hdr) { + if (out_sg[0].iov_len < n->guest_hdr_len) { + error_report("virtio-net header incorrect"); + exit(1); + } + virtio_net_hdr_swap((void *) out_sg[0].iov_base); + } + /* * If host wants to see the guest header as is, we can * pass it on unchanged. Otherwise, copy just the parts @@ -1362,10 +1379,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 +1431,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/pci/pci.c b/hw/pci/pci.c index 2a9f08e..e05d60c 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -830,6 +830,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, } pci_dev->bus = bus; + pci_dev->devfn = devfn; dma_as = pci_device_iommu_address_space(pci_dev); memory_region_init_alias(&pci_dev->bus_master_enable_region, @@ -839,7 +840,6 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region, name); - pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); pci_dev->irq_state = 0; pci_config_alloc(pci_dev); diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index 991502e..535be2c 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/pcmcia/pxa2xx.c b/hw/pcmcia/pxa2xx.c index 96f3774..55e8a2a 100644 --- a/hw/pcmcia/pxa2xx.c +++ b/hw/pcmcia/pxa2xx.c @@ -195,7 +195,7 @@ static void pxa2xx_pcmcia_initfn(Object *obj) memory_region_add_subregion(&s->container_mem, 0x0c000000, &s->common_iomem); - s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0]; + s->slot.irq = qemu_allocate_irq(pxa2xx_pcmcia_set_irq, s, 0); object_property_add_link(obj, "card", TYPE_PCMCIA_CARD, (Object **)&s->card, diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index cbef095..000c94f 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -343,6 +343,21 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, /* There is no cached config, allocate MSIs */ if (!phb->msi_table[ndev].nvec) { + int max_irqs = 0; + if (ret_intr_type == RTAS_TYPE_MSI) { + max_irqs = msi_nr_vectors_allocated(pdev); + } else if (ret_intr_type == RTAS_TYPE_MSIX) { + max_irqs = pdev->msix_entries_nr; + } + if (!max_irqs) { + error_report("Requested interrupt type %d is not enabled for device#%d", + ret_intr_type, ndev); + rtas_st(rets, 0, -1); /* Hardware error */ + return; + } + if (req_num > max_irqs) { + req_num = max_irqs; + } irq = spapr_allocate_irq_block(req_num, false, ret_intr_type == RTAS_TYPE_MSI); if (irq < 0) { diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 7074d2b..d68a29a 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -734,9 +734,11 @@ out: return ret; } -static void copy_irb_to_guest(IRB *dest, const IRB *src) +static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw) { int i; + uint16_t stctl = src->scsw.ctrl & SCSW_CTRL_MASK_STCTL; + uint16_t actl = src->scsw.ctrl & SCSW_CTRL_MASK_ACTL; copy_scsw_to_guest(&dest->scsw, &src->scsw); @@ -746,8 +748,22 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src) for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) { dest->ecw[i] = cpu_to_be32(src->ecw[i]); } - for (i = 0; i < ARRAY_SIZE(dest->emw); i++) { - dest->emw[i] = cpu_to_be32(src->emw[i]); + /* extended measurements enabled? */ + if ((src->scsw.flags & SCSW_FLAGS_MASK_ESWF) || + !(pmcw->flags & PMCW_FLAGS_MASK_TF) || + !(pmcw->chars & PMCW_CHARS_MASK_XMWME)) { + return; + } + /* extended measurements pending? */ + if (!(stctl & SCSW_STCTL_STATUS_PEND)) { + return; + } + if ((stctl & SCSW_STCTL_PRIMARY) || + (stctl == SCSW_STCTL_SECONDARY) || + ((stctl & SCSW_STCTL_INTERMEDIATE) && (actl & SCSW_ACTL_SUSP))) { + for (i = 0; i < ARRAY_SIZE(dest->emw); i++) { + dest->emw[i] = cpu_to_be32(src->emw[i]); + } } } @@ -793,7 +809,7 @@ int css_do_tsch(SubchDev *sch, IRB *target_irb) } } /* Store the irb to the guest. */ - copy_irb_to_guest(target_irb, &irb); + copy_irb_to_guest(target_irb, &irb, p); /* Clear conditions on subchannel, if applicable. */ if (stctl & SCSW_STCTL_STATUS_PEND) { diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index e6e1ffd..1781525 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1106,6 +1106,21 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) return MFI_STAT_OK; } +static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd) +{ + uint16_t flags; + + /* mbox0 contains flags */ + flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]); + trace_megasas_dcmd_ld_list_query(cmd->index, flags); + if (flags == MR_LD_QUERY_TYPE_ALL || + flags == MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) { + return megasas_dcmd_ld_get_list(s, cmd); + } + + return MFI_STAT_OK; +} + static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, MegasasCmd *cmd) { @@ -1409,6 +1424,8 @@ static const struct dcmd_cmd_tbl_t { megasas_dcmd_dummy }, { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST", megasas_dcmd_ld_get_list}, + { MFI_DCMD_LD_LIST_QUERY, "LD_LIST_QUERY", + megasas_dcmd_ld_list_query }, { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO", megasas_dcmd_ld_get_info }, { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP", diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index cd8355b..a3034f6 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -164,6 +164,7 @@ typedef enum { MFI_DCMD_PD_BLINK = 0x02070100, MFI_DCMD_PD_UNBLINK = 0x02070200, MFI_DCMD_LD_GET_LIST = 0x03010000, + MFI_DCMD_LD_LIST_QUERY = 0x03010100, MFI_DCMD_LD_GET_INFO = 0x03020000, MFI_DCMD_LD_GET_PROP = 0x03030000, MFI_DCMD_LD_SET_PROP = 0x03040000, @@ -411,6 +412,14 @@ typedef enum { MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */ } mfi_pd_query_type; +typedef enum { + MR_LD_QUERY_TYPE_ALL = 0, + MR_LD_QUERY_TYPE_EXPOSED_TO_HOST = 1, + MR_LD_QUERY_TYPE_USED_TGT_IDS = 2, + MR_LD_QUERY_TYPE_CLUSTER_ACCESS = 3, + MR_LD_QUERY_TYPE_CLUSTER_LOCALE = 4, +} mfi_ld_query_type; + /* * Other propertities and definitions */ diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 48a28ae..da8c436 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2520,7 +2520,7 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, * ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without * O_DIRECT everything must go through SG_IO. */ - if (bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE) { + if (!(bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE)) { break; } diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 3983a5b..9099192 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -196,6 +196,10 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) } } +static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ +} + static void vhost_scsi_realize(DeviceState *dev, Error **errp) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); @@ -217,7 +221,9 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) } } - virtio_scsi_common_realize(dev, &err); + virtio_scsi_common_realize(dev, &err, vhost_dummy_handle_output, + vhost_dummy_handle_output, + vhost_dummy_handle_output); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index b0d7517..d183cd0 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); @@ -489,7 +498,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, uint32_t event, uint32_t reason) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); - VirtIOSCSIReq *req = virtio_scsi_pop_req(s, vs->event_vq); + VirtIOSCSIReq *req; VirtIOSCSIEvent *evt; VirtIODevice *vdev = VIRTIO_DEVICE(s); int in_size; @@ -498,6 +507,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, return; } + req = virtio_scsi_pop_req(s, vs->event_vq); if (!req) { s->events_dropped = true; return; @@ -595,7 +605,9 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { .load_request = virtio_scsi_load_request, }; -void virtio_scsi_common_realize(DeviceState *dev, Error **errp) +void virtio_scsi_common_realize(DeviceState *dev, Error **errp, + HandleOutput ctrl, HandleOutput evt, + HandleOutput cmd) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev); @@ -609,12 +621,12 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp) s->cdb_size = VIRTIO_SCSI_CDB_SIZE; s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, - virtio_scsi_handle_ctrl); + ctrl); s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, - virtio_scsi_handle_event); + evt); for (i = 0; i < s->conf.num_queues; i++) { s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, - virtio_scsi_handle_cmd); + cmd); } } @@ -625,7 +637,9 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) static int virtio_scsi_id; Error *err = NULL; - virtio_scsi_common_realize(dev, &err); + virtio_scsi_common_realize(dev, &err, virtio_scsi_handle_ctrl, + virtio_scsi_handle_event, + virtio_scsi_handle_cmd); if (err != NULL) { error_propagate(errp, err); return; diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index 937a478..6c92149 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -625,7 +625,7 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, exit(1); } - s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0]; + s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0); sd_set_cb(s->card, NULL, s->cdet); return s; diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 843e697..e79a886 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1168,8 +1168,8 @@ static void sdhci_initfn(Object *obj) if (s->card == NULL) { exit(1); } - s->eject_cb = qemu_allocate_irqs(sdhci_insert_eject_cb, s, 1)[0]; - s->ro_cb = qemu_allocate_irqs(sdhci_card_readonly_cb, s, 1)[0]; + s->eject_cb = qemu_allocate_irq(sdhci_insert_eject_cb, s, 0); + s->ro_cb = qemu_allocate_irq(sdhci_card_readonly_cb, s, 0); sd_set_cb(s->card, s->ro_cb, s->eject_cb); s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); @@ -1184,8 +1184,8 @@ static void sdhci_uninitfn(Object *obj) timer_free(s->insert_timer); timer_del(s->transfer_timer); timer_free(s->transfer_timer); - qemu_free_irqs(&s->eject_cb); - qemu_free_irqs(&s->ro_cb); + qemu_free_irq(s->eject_cb); + qemu_free_irq(s->ro_cb); if (s->fifo_buffer) { g_free(s->fifo_buffer); diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 3273c8a..b012e57 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/sh4/sh7750.c b/hw/sh4/sh7750.c index 4a39357..5dda5de 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -838,6 +838,5 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem) qemu_irq sh7750_irl(SH7750State *s) { sh_intc_toggle_source(sh_intc_source(&s->intc, IRL), 1, 0); /* enable */ - return qemu_allocate_irqs(sh_intc_set_irl, sh_intc_source(&s->intc, IRL), - 1)[0]; + return qemu_allocate_irq(sh_intc_set_irl, sh_intc_source(&s->intc, IRL), 0); } diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c index fd479ef..b19bc71 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 e15d6bc..2792f89 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 28152d8..3450c98 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/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 8509309..abcbcae 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -852,7 +852,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) check_update_timer(s); s->clock_reset_notifier.notify = rtc_notify_clock_reset; - qemu_clock_register_reset_notifier(QEMU_CLOCK_REALTIME, + qemu_clock_register_reset_notifier(rtc_clock, &s->clock_reset_notifier); s->suspend_notifier.notify = rtc_notify_suspend; diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c index 016207f..b7f3d49 100644 --- a/hw/timer/omap_gptimer.c +++ b/hw/timer/omap_gptimer.c @@ -227,7 +227,7 @@ static void omap_gp_timer_clk_update(void *opaque, int line, int on) static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer) { omap_clk_adduser(timer->clk, - qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]); + qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0)); timer->rate = omap_clk_getrate(timer->clk); } @@ -476,7 +476,7 @@ struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, s->clk = fclk; s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s); s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s); - s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0]; + s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0); omap_gp_timer_reset(s); omap_gp_timer_clk_setup(s); diff --git a/hw/usb/bus.c b/hw/usb/bus.c index fe70429..e48b19f 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-bluetooth.c b/hw/usb/dev-bluetooth.c index a9661d2..a76e581 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -19,6 +19,7 @@ */ #include "qemu-common.h" +#include "qemu/error-report.h" #include "hw/usb.h" #include "hw/usb/desc.h" #include "sysemu/bt.h" @@ -506,6 +507,14 @@ static int usb_bt_initfn(USBDevice *dev) usb_desc_create_serial(dev); usb_desc_init(dev); + s->dev.opaque = s; + if (!s->hci) { + s->hci = bt_new_hci(qemu_find_bt_vlan(0)); + } + s->hci->opaque = s; + s->hci->evt_recv = usb_bt_out_hci_packet_event; + s->hci->acl_recv = usb_bt_out_hci_packet_acl; + usb_bt_handle_reset(&s->dev); s->intr = usb_ep_get(dev, USB_TOKEN_IN, USB_EVT_EP); return 0; @@ -516,6 +525,7 @@ static USBDevice *usb_bt_init(USBBus *bus, const char *cmdline) USBDevice *dev; struct USBBtState *s; HCIInfo *hci; + const char *name = "usb-bt-dongle"; if (*cmdline) { hci = hci_init(cmdline); @@ -525,19 +535,17 @@ static USBDevice *usb_bt_init(USBBus *bus, const char *cmdline) if (!hci) return NULL; - dev = usb_create_simple(bus, "usb-bt-dongle"); + dev = usb_create(bus, name); if (!dev) { + error_report("Failed to create USB device '%s'", name); return NULL; } s = DO_UPCAST(struct USBBtState, dev, dev); - s->dev.opaque = s; - s->hci = hci; - s->hci->opaque = s; - s->hci->evt_recv = usb_bt_out_hci_packet_event; - s->hci->acl_recv = usb_bt_out_hci_packet_acl; - - usb_bt_handle_reset(&s->dev); + if (qdev_init(&dev->qdev) < 0) { + error_report("Failed to initialize USB device '%s'", name); + return NULL; + } return dev; } diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index ef3177a..0ceb10d 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3703,6 +3703,7 @@ static const VMStateDescription vmstate_xhci_event = { VMSTATE_UINT32(flags, XHCIEvent), VMSTATE_UINT8(slotid, XHCIEvent), VMSTATE_UINT8(epid, XHCIEvent), + VMSTATE_END_OF_LIST() } }; diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 9e336ad..1d349e0 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -309,7 +309,9 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, uint64_t size) { int i; - for (i = 0; i < dev->nvqs; ++i) { + int r = 0; + + for (i = 0; !r && i < dev->nvqs; ++i) { struct vhost_virtqueue *vq = dev->vqs + i; hwaddr l; void *p; @@ -321,15 +323,15 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, p = cpu_physical_memory_map(vq->ring_phys, &l, 1); if (!p || l != vq->ring_size) { fprintf(stderr, "Unable to map ring buffer for ring %d\n", i); - return -ENOMEM; + r = -ENOMEM; } if (p != vq->ring) { fprintf(stderr, "Ring buffer relocated for ring %d\n", i); - return -EBUSY; + r = -EBUSY; } cpu_physical_memory_unmap(p, l, 0, 0); } - return 0; + return r; } static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev, diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index aeabf3a..3e4b70c 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,27 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) features, supported_features); return -1; } - vdev->config_len = qemu_get_be32(f); - qemu_get_buffer(f, vdev->config, vdev->config_len); + config_len = qemu_get_be32(f); + + /* + * There are cases where the incoming config can be bigger or smaller + * than what we have; so load what we have space for, and skip + * any excess that's in the stream. + */ + qemu_get_buffer(f, vdev->config, MIN(config_len, vdev->config_len)); + + while (config_len > vdev->config_len) { + qemu_get_byte(f); + 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/xtensa/xtensa_lx60.c b/hw/xtensa/xtensa_lx60.c index 49c58d1..fc6a513 100644 --- a/hw/xtensa/xtensa_lx60.c +++ b/hw/xtensa/xtensa_lx60.c @@ -42,6 +42,7 @@ typedef struct LxBoardDesc { hwaddr flash_base; size_t flash_size; + size_t flash_boot_base; size_t flash_sector_size; size_t sram_size; } LxBoardDesc; @@ -266,9 +267,9 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) MemoryRegion *flash_io = g_malloc(sizeof(*flash_io)); memory_region_init_alias(flash_io, NULL, "lx60.flash", - flash_mr, 0, - board->flash_size < 0x02000000 ? - board->flash_size : 0x02000000); + flash_mr, board->flash_boot_base, + board->flash_size - board->flash_boot_base < 0x02000000 ? + board->flash_size - board->flash_boot_base : 0x02000000); memory_region_add_subregion(system_memory, 0xfe000000, flash_io); } @@ -313,6 +314,7 @@ static void xtensa_kc705_init(QEMUMachineInitArgs *args) static const LxBoardDesc kc705_board = { .flash_base = 0xf0000000, .flash_size = 0x08000000, + .flash_boot_base = 0x06000000, .flash_sector_size = 0x20000, .sram_size = 0x2000000, }; diff --git a/include/block/blockjob.h b/include/block/blockjob.h index d76de62..395be5b 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -144,6 +144,14 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs, void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns); /** + * block_job_yield: + * @job: The job that calls the function. + * + * Yield the block job coroutine. + */ +void block_job_yield(BlockJob *job); + +/** * block_job_completed: * @job: The job being completed. * @ret: The status code. diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h index 18fb970..f808199 100644 --- a/include/hw/i386/smbios.h +++ b/include/hw/i386/smbios.h @@ -16,9 +16,9 @@ #include "qemu/option.h" void smbios_entry_add(QemuOpts *opts); -void smbios_set_type1_defaults(const char *manufacturer, - const char *product, const char *version); -uint8_t *smbios_get_table(size_t *length); +void smbios_set_defaults(const char *manufacturer, const char *product, + const char *version); +uint8_t *smbios_get_table_legacy(size_t *length); /* * SMBIOS spec defined tables diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index df60f16..4b32440 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/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 42b1024..e81a643 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -186,7 +186,12 @@ typedef struct { DEFINE_PROP_BIT("param_change", _state, _feature_field, \ VIRTIO_SCSI_F_CHANGE, true) -void virtio_scsi_common_realize(DeviceState *dev, Error **errp); +typedef void (*HandleOutput)(VirtIODevice *, VirtQueue *); + +void virtio_scsi_common_realize(DeviceState *dev, Error **errp, + HandleOutput ctrl, HandleOutput evt, + HandleOutput cmd); + void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); #endif /* _QEMU_VIRTIO_SCSI_H */ diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index e7e1705..5b71370 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), \ diff --git a/kvm-all.c b/kvm-all.c index 82a9119..2754c15 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -948,7 +948,7 @@ void kvm_init_irq_routing(KVMState *s) { int gsi_count, i; - gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING); + gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING) - 1; if (gsi_count > 0) { unsigned int gsi_bits, i; @@ -2022,12 +2022,13 @@ void kvm_remove_all_breakpoints(CPUState *cpu) { struct kvm_sw_breakpoint *bp, *next; KVMState *s = cpu->kvm_state; + CPUState *tmpcpu; QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) { if (kvm_arch_remove_sw_breakpoint(cpu, bp) != 0) { /* Try harder to find a CPU that currently sees the breakpoint. */ - CPU_FOREACH(cpu) { - if (kvm_arch_remove_sw_breakpoint(cpu, bp) == 0) { + CPU_FOREACH(tmpcpu) { + if (kvm_arch_remove_sw_breakpoint(tmpcpu, bp) == 0) { break; } } diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d2380b6..e1ff346 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -267,17 +267,15 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en #ifdef TARGET_ARM +#ifndef TARGET_AARCH64 +/* 32 bit ARM definitions */ + #define ELF_START_MMAP 0x80000000 #define elf_check_arch(x) ((x) == ELF_MACHINE) #define ELF_ARCH ELF_MACHINE - -#ifdef TARGET_AARCH64 -#define ELF_CLASS ELFCLASS64 -#else #define ELF_CLASS ELFCLASS32 -#endif static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) @@ -285,10 +283,6 @@ static inline void init_thread(struct target_pt_regs *regs, abi_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); -#ifdef TARGET_AARCH64 - regs->pc = infop->entry & ~0x3ULL; - regs->sp = stack; -#else regs->ARM_cpsr = 0x10; if (infop->entry & 1) regs->ARM_cpsr |= CPSR_T; @@ -302,7 +296,6 @@ static inline void init_thread(struct target_pt_regs *regs, /* For uClinux PIC binaries. */ /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ regs->ARM_r10 = infop->start_data; -#endif } #define ELF_NREG 18 @@ -346,13 +339,20 @@ enum ARM_HWCAP_ARM_EDSP = 1 << 7, ARM_HWCAP_ARM_JAVA = 1 << 8, ARM_HWCAP_ARM_IWMMXT = 1 << 9, - ARM_HWCAP_ARM_THUMBEE = 1 << 10, - ARM_HWCAP_ARM_NEON = 1 << 11, - ARM_HWCAP_ARM_VFPv3 = 1 << 12, - ARM_HWCAP_ARM_VFPv3D16 = 1 << 13, + ARM_HWCAP_ARM_CRUNCH = 1 << 10, + ARM_HWCAP_ARM_THUMBEE = 1 << 11, + ARM_HWCAP_ARM_NEON = 1 << 12, + ARM_HWCAP_ARM_VFPv3 = 1 << 13, + ARM_HWCAP_ARM_VFPv3D16 = 1 << 14, + ARM_HWCAP_ARM_TLS = 1 << 15, + ARM_HWCAP_ARM_VFPv4 = 1 << 16, + ARM_HWCAP_ARM_IDIVA = 1 << 17, + ARM_HWCAP_ARM_IDIVT = 1 << 18, + ARM_HWCAP_ARM_VFPD32 = 1 << 19, + ARM_HWCAP_ARM_LPAE = 1 << 20, + ARM_HWCAP_ARM_EVTSTRM = 1 << 21, }; -#ifndef TARGET_AARCH64 /* The commpage only exists for 32 bit kernels */ #define TARGET_HAS_VALIDATE_GUEST_SPACE @@ -414,7 +414,6 @@ static int validate_guest_space(unsigned long guest_base, return 1; /* All good */ } -#endif #define ELF_HWCAP get_elf_hwcap() @@ -427,23 +426,103 @@ static uint32_t get_elf_hwcap(void) hwcaps |= ARM_HWCAP_ARM_HALF; hwcaps |= ARM_HWCAP_ARM_THUMB; hwcaps |= ARM_HWCAP_ARM_FAST_MULT; - hwcaps |= ARM_HWCAP_ARM_FPA; /* probe for the extra features */ #define GET_FEATURE(feat, hwcap) \ do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) + /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */ + GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP); GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP); GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT); GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE); GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON); GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3); - GET_FEATURE(ARM_FEATURE_VFP_FP16, ARM_HWCAP_ARM_VFPv3D16); + GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS); + GET_FEATURE(ARM_FEATURE_VFP4, ARM_HWCAP_ARM_VFPv4); + GET_FEATURE(ARM_FEATURE_ARM_DIV, ARM_HWCAP_ARM_IDIVA); + GET_FEATURE(ARM_FEATURE_THUMB_DIV, ARM_HWCAP_ARM_IDIVT); + /* All QEMU's VFPv3 CPUs have 32 registers, see VFP_DREG in translate.c. + * Note that the ARM_HWCAP_ARM_VFPv3D16 bit is always the inverse of + * ARM_HWCAP_ARM_VFPD32 (and so always clear for QEMU); it is unrelated + * to our VFP_FP16 feature bit. + */ + GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32); + GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); #undef GET_FEATURE return hwcaps; } -#endif +#else +/* 64 bit ARM definitions */ +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ((x) == ELF_MACHINE) + +#define ELF_ARCH ELF_MACHINE +#define ELF_CLASS ELFCLASS64 +#define ELF_PLATFORM "aarch64" + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + abi_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + + regs->pc = infop->entry & ~0x3ULL; + regs->sp = stack; +} + +#define ELF_NREG 34 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPUARMState *env) +{ + int i; + + for (i = 0; i < 32; i++) { + (*regs)[i] = tswapreg(env->xregs[i]); + } + (*regs)[32] = tswapreg(env->pc); + (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env)); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +enum { + ARM_HWCAP_A64_FP = 1 << 0, + ARM_HWCAP_A64_ASIMD = 1 << 1, + ARM_HWCAP_A64_EVTSTRM = 1 << 2, + ARM_HWCAP_A64_AES = 1 << 3, + ARM_HWCAP_A64_PMULL = 1 << 4, + ARM_HWCAP_A64_SHA1 = 1 << 5, + ARM_HWCAP_A64_SHA2 = 1 << 6, + ARM_HWCAP_A64_CRC32 = 1 << 7, +}; + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + hwcaps |= ARM_HWCAP_A64_FP; + hwcaps |= ARM_HWCAP_A64_ASIMD; + + /* probe for the extra features */ +#define GET_FEATURE(feat, hwcap) \ + do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) + GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP_A64_PMULL); +#undef GET_FEATURE + + return hwcaps; +} + +#endif /* not TARGET_AARCH64 */ +#endif /* TARGET_ARM */ #ifdef TARGET_UNICORE32 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9864813..2d28bdb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7499,6 +7499,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask)); if (!is_error(ret)) { + if (ret > arg2) { + /* More data returned than the caller's buffer will fit. + * This only happens if sizeof(abi_long) < sizeof(long) + * and the caller passed us a buffer holding an odd number + * of abi_longs. If the host kernel is actually using the + * extra 4 bytes then fail EINVAL; otherwise we can just + * ignore them and only copy the interesting part. + */ + int numcpus = sysconf(_SC_NPROCESSORS_CONF); + if (numcpus > arg2 * 8) { + ret = -TARGET_EINVAL; + break; + } + ret = arg2; + } + if (copy_to_user(arg3, mask, ret)) { goto efault; } diff --git a/migration-rdma.c b/migration-rdma.c index eeb4302..5cd90bd 100644 --- a/migration-rdma.c +++ b/migration-rdma.c @@ -1589,13 +1589,11 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf, } - if (ibv_post_send(rdma->qp, &send_wr, &bad_wr)) { - return -1; - } + ret = ibv_post_send(rdma->qp, &send_wr, &bad_wr); - if (ret < 0) { + if (ret > 0) { fprintf(stderr, "Failed to use post IB SEND for control!\n"); - return ret; + return -ret; } ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_SEND_CONTROL, NULL); @@ -2237,10 +2235,6 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) } } - if (rdma->qp) { _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |