diff options
43 files changed, 426 insertions, 193 deletions
@@ -168,7 +168,7 @@ check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y) test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y) $(qapi-obj-y): $(GENERATED_HEADERS) -qapi-dir := qapi-generated +qapi-dir := $(BUILD_DIR)/qapi-generated test-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir) qemu-ga$(EXESUF): LIBS = $(LIBS_QGA) @@ -1 +1 @@ -0.15.93 +1.0 diff --git a/block/qcow.c b/block/qcow.c index adecee06c..4814ed0ce 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -26,6 +26,7 @@ #include "module.h" #include <zlib.h> #include "aes.h" +#include "migration.h" /**************************************************************/ /* QEMU COW block driver with compression and encryption support */ @@ -74,6 +75,7 @@ typedef struct BDRVQcowState { AES_KEY aes_encrypt_key; AES_KEY aes_decrypt_key; CoMutex lock; + Error *migration_blocker; } BDRVQcowState; static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); @@ -160,6 +162,12 @@ static int qcow_open(BlockDriverState *bs, int flags) bs->backing_file[len] = '\0'; } + /* Disable migration when qcow images are used */ + error_set(&s->migration_blocker, + QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + "qcow", bs->device_name, "live migration"); + migrate_add_blocker(s->migration_blocker); + qemu_co_mutex_init(&s->lock); return 0; @@ -604,10 +612,14 @@ static int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, static void qcow_close(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; + g_free(s->l1_table); g_free(s->l2_cache); g_free(s->cluster_cache); g_free(s->cluster_data); + + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); } static int qcow_create(const char *filename, QEMUOptionParameter *options) diff --git a/block/sheepdog.c b/block/sheepdog.c index 9f8060960..62f1f3a0c 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1116,6 +1116,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, /* send a header */ ret = do_write(s->fd, &hdr, sizeof(hdr)); if (ret) { + qemu_co_mutex_unlock(&s->lock); error_report("failed to send a req, %s", strerror(errno)); return -EIO; } @@ -1123,6 +1124,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, if (wlen) { ret = do_writev(s->fd, iov, wlen, aio_req->iov_offset); if (ret) { + qemu_co_mutex_unlock(&s->lock); error_report("failed to send a data, %s", strerror(errno)); return -EIO; } diff --git a/block/vdi.c b/block/vdi.c index 684a4a87b..02da6b44d 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -52,6 +52,7 @@ #include "qemu-common.h" #include "block_int.h" #include "module.h" +#include "migration.h" #if defined(CONFIG_UUID) #include <uuid/uuid.h> @@ -203,6 +204,8 @@ typedef struct { uint32_t bmap_sector; /* VDI header (converted to host endianness). */ VdiHeader header; + + Error *migration_blocker; } BDRVVdiState; /* Change UUID from little endian (IPRT = VirtualBox format) to big endian @@ -454,6 +457,12 @@ static int vdi_open(BlockDriverState *bs, int flags) goto fail_free_bmap; } + /* Disable migration when vdi images are used */ + error_set(&s->migration_blocker, + QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + "vdi", bs->device_name, "live migration"); + migrate_add_blocker(s->migration_blocker); + return 0; fail_free_bmap: @@ -939,6 +948,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options) static void vdi_close(BlockDriverState *bs) { + BDRVVdiState *s = bs->opaque; + + g_free(s->bmap); + + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); } static coroutine_fn int vdi_co_flush(BlockDriverState *bs) diff --git a/block/vmdk.c b/block/vmdk.c index 96f7d5d90..f5441591d 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -26,6 +26,7 @@ #include "qemu-common.h" #include "block_int.h" #include "module.h" +#include "migration.h" #include <zlib.h> #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') @@ -97,6 +98,7 @@ typedef struct BDRVVmdkState { int num_extents; /* Extent array with num_extents entries, ascend ordered by address */ VmdkExtent *extents; + Error *migration_blocker; } BDRVVmdkState; typedef struct VmdkMetaData { @@ -659,7 +661,14 @@ static int vmdk_open(BlockDriverState *bs, int flags) } s->parent_cid = vmdk_read_cid(bs, 1); qemu_co_mutex_init(&s->lock); - return ret; + + /* Disable migration when VMDK images are used */ + error_set(&s->migration_blocker, + QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + "vmdk", bs->device_name, "live migration"); + migrate_add_blocker(s->migration_blocker); + + return 0; fail: vmdk_free_extents(bs); @@ -1504,7 +1513,12 @@ exit: static void vmdk_close(BlockDriverState *bs) { + BDRVVmdkState *s = bs->opaque; + vmdk_free_extents(bs); + + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); } static coroutine_fn int vmdk_co_flush(BlockDriverState *bs) diff --git a/block/vpc.c b/block/vpc.c index 39a324705..89a5ee266 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -25,6 +25,7 @@ #include "qemu-common.h" #include "block_int.h" #include "module.h" +#include "migration.h" /**************************************************************/ @@ -128,6 +129,8 @@ typedef struct BDRVVPCState { uint64_t last_bitmap; #endif + + Error *migration_blocker; } BDRVVPCState; static uint32_t vpc_checksum(uint8_t* buf, size_t size) @@ -228,6 +231,13 @@ static int vpc_open(BlockDriverState *bs, int flags) #endif qemu_co_mutex_init(&s->lock); + + /* Disable migration when VHD images are used */ + error_set(&s->migration_blocker, + QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + "vpc", bs->device_name, "live migration"); + migrate_add_blocker(s->migration_blocker); + return 0; fail: return err; @@ -352,8 +362,11 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num) // Initialize the block's bitmap memset(bitmap, 0xff, s->bitmap_size); - bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap, + ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap, s->bitmap_size); + if (ret < 0) { + return ret; + } // Write new footer (the old one will be overwritten) s->free_data_block_offset += s->block_size + s->bitmap_size; @@ -651,6 +664,9 @@ static void vpc_close(BlockDriverState *bs) #ifdef CACHE g_free(s->pageentry_u8); #endif + + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); } static QEMUOptionParameter vpc_create_options[] = { diff --git a/block/vvfat.c b/block/vvfat.c index 131680f6f..a310ce8c3 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -27,6 +27,7 @@ #include "qemu-common.h" #include "block_int.h" #include "module.h" +#include "migration.h" #ifndef S_IWGRP #define S_IWGRP 0 @@ -350,6 +351,8 @@ typedef struct BDRVVVFATState { array_t commits; const char* path; int downcase_short_names; + + Error *migration_blocker; } BDRVVVFATState; /* take the sector position spos and convert it to Cylinder/Head/Sector position @@ -1073,6 +1076,15 @@ DLOG(if (stderr == NULL) { // assert(is_consistent(s)); qemu_co_mutex_init(&s->lock); + + /* Disable migration when vvfat is used rw */ + if (s->qcow) { + error_set(&s->migration_blocker, + QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + "vvfat (rw)", bs->device_name, "live migration"); + migrate_add_blocker(s->migration_blocker); + } + return 0; } @@ -2829,6 +2841,11 @@ static void vvfat_close(BlockDriverState *bs) array_free(&(s->directory)); array_free(&(s->mapping)); g_free(s->cluster_buffer); + + if (s->qcow) { + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); + } } static BlockDriver bdrv_vvfat = { @@ -583,6 +583,14 @@ for opt do ;; --sysconfdir=*) sysconfdir="$optarg" ;; + --sbindir=*|--libexecdir=*|--sharedstatedir=*|--localstatedir=*|\ + --oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\ + --htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*) + # These switches are silently ignored, for compatibility with + # autoconf-generated configure scripts. This allows QEMU's + # configure to be used by RPM and similar macros that set + # lots of directory switches by default. + ;; --disable-sdl) sdl="no" ;; --enable-sdl) sdl="yes" @@ -783,8 +791,6 @@ for opt do ;; --enable-opengl) opengl="yes" ;; - --*dir) - ;; --disable-rbd) rbd="no" ;; --enable-rbd) rbd="yes" @@ -1149,7 +1155,17 @@ fi if test "$pie" != "no" ; then cat > $TMPC << EOF -int main(void) { return 0; } + +#ifdef __linux__ +# define THREAD __thread +#else +# define THREAD +#endif + +static THREAD int tls_var; + +int main(void) { return tls_var; } + EOF if compile_prog "-fPIE -DPIE" "-pie"; then QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS" @@ -315,19 +315,34 @@ int fcntl_setfl(int fd, int flag) } #endif +static int64_t suffix_mul(char suffix, int64_t unit) +{ + switch (qemu_toupper(suffix)) { + case STRTOSZ_DEFSUFFIX_B: + return 1; + case STRTOSZ_DEFSUFFIX_KB: + return unit; + case STRTOSZ_DEFSUFFIX_MB: + return unit * unit; + case STRTOSZ_DEFSUFFIX_GB: + return unit * unit * unit; + case STRTOSZ_DEFSUFFIX_TB: + return unit * unit * unit * unit; + } + return -1; +} + /* * Convert string to bytes, allowing either B/b for bytes, K/k for KB, - * M/m for MB, G/g for GB or T/t for TB. Default without any postfix - * is MB. End pointer will be returned in *end, if not NULL. A valid - * value must be terminated by whitespace, ',' or '\0'. Return -1 on - * error. + * M/m for MB, G/g for GB or T/t for TB. End pointer will be returned + * in *end, if not NULL. Return -1 on error. */ int64_t strtosz_suffix_unit(const char *nptr, char **end, const char default_suffix, int64_t unit) { int64_t retval = -1; char *endptr; - unsigned char c, d; + unsigned char c; int mul_required = 0; double val, mul, integral, fraction; @@ -340,59 +355,17 @@ int64_t strtosz_suffix_unit(const char *nptr, char **end, if (fraction != 0) { mul_required = 1; } - /* - * Any whitespace character is fine for terminating the number, - * in addition we accept ',' to handle strings where the size is - * part of a multi token argument. - */ c = *endptr; - d = c; - if (qemu_isspace(c) || c == '\0' || c == ',') { - c = 0; - if (default_suffix) { - d = default_suffix; - } else { - d = c; - } + mul = suffix_mul(c, unit); + if (mul >= 0) { + endptr++; + } else { + mul = suffix_mul(default_suffix, unit); + assert(mul >= 0); } - switch (qemu_toupper(d)) { - case STRTOSZ_DEFSUFFIX_B: - mul = 1; - if (mul_required) { - goto fail; - } - break; - case STRTOSZ_DEFSUFFIX_KB: - mul = unit; - break; - case 0: - if (mul_required) { - goto fail; - } - case STRTOSZ_DEFSUFFIX_MB: - mul = unit * unit; - break; - case STRTOSZ_DEFSUFFIX_GB: - mul = unit * unit * unit; - break; - case STRTOSZ_DEFSUFFIX_TB: - mul = unit * unit * unit * unit; - break; - default: + if (mul == 1 && mul_required) { goto fail; } - /* - * If not terminated by whitespace, ',', or \0, increment endptr - * to point to next character, then check that we are terminated - * by an appropriate separating character, ie. whitespace, ',', or - * \0. If not, we are seeing trailing garbage, thus fail. - */ - if (c != 0) { - endptr++; - if (!qemu_isspace(*endptr) && *endptr != ',' && *endptr != 0) { - goto fail; - } - } if ((val * mul >= INT64_MAX) || val < 0) { goto fail; } diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 7f1c0894d..99ef0cd33 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -583,8 +583,7 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path, char buffer[PATH_MAX]; char *path = fs_path->data; - return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf, - AT_SYMLINK_NOFOLLOW); + return qemu_utimens(rpath(s, path, buffer), buf); } static int local_remove(FsContext *ctx, const char *path) @@ -694,6 +693,7 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, mode_t st_mode, uint64_t *st_gen) { int err; +#ifdef FS_IOC_GETVERSION V9fsFidOpenState fid_open; /* @@ -709,15 +709,22 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, } err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); local_close(ctx, &fid_open); +#else + err = -ENOTTY; +#endif return err; } static int local_init(FsContext *ctx) { - int err; + int err = 0; struct statfs stbuf; ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; +#ifdef FS_IOC_GETVERSION + /* + * use ioc_getversion only if the iocl is definied + */ err = statfs(ctx->fs_root, &stbuf); if (!err) { switch (stbuf.f_type) { @@ -729,6 +736,7 @@ static int local_init(FsContext *ctx) break; } } +#endif return err; } diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c index 2cbc81b9f..9f51c6cb0 100644 --- a/hw/ccid-card-passthru.c +++ b/hw/ccid-card-passthru.c @@ -150,6 +150,7 @@ static void ccid_card_vscard_handle_message(PassthruState *card, error_report("ATR size exceeds spec, ignoring"); ccid_card_vscard_send_error(card, scr_msg_header->reader_id, VSC_GENERAL_ERROR); + break; } memcpy(card->atr, data, scr_msg_header->length); card->atr_length = scr_msg_header->length; diff --git a/hw/eepro100.c b/hw/eepro100.c index 7d59e7136..29ec5b44f 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -976,7 +976,15 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val) case CU_STATSADDR: /* Load dump counters address. */ s->statsaddr = e100_read_reg4(s, SCBPointer); - TRACE(OTHER, logout("val=0x%02x (status address)\n", val)); + TRACE(OTHER, logout("val=0x%02x (dump counters address)\n", val)); + if (s->statsaddr & 3) { + /* Memory must be Dword aligned. */ + logout("unaligned dump counters address\n"); + /* Handling of misaligned addresses is undefined. + * Here we align the address by ignoring the lower bits. */ + /* TODO: Test unaligned dump counter address on real hardware. */ + s->statsaddr &= ~3; + } break; case CU_SHOWSTATS: /* Dump statistical counters. */ diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index b59be2a59..12f61fea6 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -91,7 +91,8 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter, */ dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1); dinfo->bus = scsibus->busnr; - scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, false); + scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, + false, -1); if (!scsidev) { return -1; } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 4c379932e..aa8ed0a91 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -1971,7 +1971,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) cplus_tx_ring_desc += 16 * descriptor; DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at " - "%08x0x%08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1], + "%08x %08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc); uint32_t val, txdw0,txdw1,txbufLO,txbufHI; @@ -2713,8 +2713,6 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) { RTL8139State *s = opaque; - addr &= 0xff; - switch (addr) { case MAC0 ... MAC0+5: @@ -2800,8 +2798,6 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) { RTL8139State *s = opaque; - addr &= 0xfe; - switch (addr) { case IntrMask: @@ -2900,8 +2896,6 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) { RTL8139State *s = opaque; - addr &= 0xfc; - switch (addr) { case RxMissed: @@ -2969,8 +2963,6 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) RTL8139State *s = opaque; int ret; - addr &= 0xff; - switch (addr) { case MAC0 ... MAC0+5: @@ -3043,8 +3035,6 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) RTL8139State *s = opaque; uint32_t ret; - addr &= 0xfe; /* mask lower bit */ - switch (addr) { case IntrMask: @@ -3120,8 +3110,6 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) RTL8139State *s = opaque; uint32_t ret; - addr &= 0xfc; /* also mask low 2 bits */ - switch (addr) { case RxMissed: diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 0ce6406b6..c4b9a99e6 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -254,10 +254,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev) /* Update guest supported feature bitmap */ features = bswap32(ldl_be_phys(dev->feat_offs)); - if (vdev->set_features) { - vdev->set_features(vdev, features); - } - vdev->guest_features = features; + virtio_set_features(vdev, features); } VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 3a2a7bb72..64e709ee9 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -162,7 +162,7 @@ void scsi_qdev_register(SCSIDeviceInfo *info) /* handle legacy '-drive if=scsi,...' cmd line args */ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, - int unit, bool removable) + int unit, bool removable, int bootindex) { const char *driver; DeviceState *dev; @@ -170,6 +170,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk"; dev = qdev_create(&bus->qbus, driver); qdev_prop_set_uint32(dev, "scsi-id", unit); + if (bootindex >= 0) { + qdev_prop_set_int32(dev, "bootindex", bootindex); + } if (qdev_prop_exists(dev, "removable")) { qdev_prop_set_bit(dev, "removable", removable); } @@ -195,7 +198,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus) continue; } qemu_opts_loc_restore(dinfo->opts); - if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false)) { + if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1)) { res = -1; break; } @@ -1367,8 +1370,8 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev) SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev); char path[100]; - snprintf(path, sizeof(path), "%s@%d,%d,%d", qdev_fw_name(dev), - d->channel, d->id, d->lun); + snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel, + qdev_fw_name(dev), d->id, d->lun); return strdup(path); } diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 9594cc127..e62044f39 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -413,6 +413,10 @@ static int scsi_generic_initfn(SCSIDevice *s) /* define device state */ s->type = scsiid.scsi_type; DPRINTF("device type %d\n", s->type); + if (s->type == TYPE_DISK || s->type == TYPE_ROM) { + add_boot_device_path(s->conf.bootindex, &s->qdev, NULL); + } + switch (s->type) { case TYPE_TAPE: s->blocksize = get_stream_blocksize(s->conf.bs); @@ -459,6 +463,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, static SCSIDeviceInfo scsi_generic_info = { .qdev.name = "scsi-generic", + .qdev.fw_name = "disk", .qdev.desc = "pass through generic scsi device (/dev/sg*)", .qdev.size = sizeof(SCSIDevice), .qdev.reset = scsi_generic_reset, @@ -128,7 +128,7 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) } SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, - int unit, bool removable); + int unit, bool removable, int bootindex); int scsi_bus_legacy_handle_cmdline(SCSIBus *bus); /* diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c index 00c7be8c8..6de952c93 100644 --- a/hw/syborg_virtio.c +++ b/hw/syborg_virtio.c @@ -131,9 +131,7 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset, } switch (offset >> 2) { case SYBORG_VIRTIO_GUEST_FEATURES: - if (vdev->set_features) - vdev->set_features(vdev, value); - vdev->guest_features = value; + virtio_set_features(vdev, value); break; case SYBORG_VIRTIO_QUEUE_BASE: if (value == 0) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index 529fa3355..f30eec1ea 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -528,6 +528,9 @@ USBDevice *usb_bt_init(HCIInfo *hci) if (!hci) return NULL; dev = usb_create_simple(NULL /* FIXME */, "usb-bt-dongle"); + if (!dev) { + return NULL; + } s = DO_UPCAST(struct USBBtState, dev, dev); s->dev.opaque = s; diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 93f640d37..8cafb76ff 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -9,6 +9,7 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); static char *usb_get_dev_path(DeviceState *dev); static char *usb_get_fw_dev_path(DeviceState *qdev); +static int usb_qdev_exit(DeviceState *qdev); static struct BusInfo usb_bus_info = { .name = "USB", @@ -75,12 +76,23 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) dev->auto_attach = 1; QLIST_INIT(&dev->strings); rc = usb_claim_port(dev); - if (rc == 0) { - rc = dev->info->init(dev); + if (rc != 0) { + goto err; } - if (rc == 0 && dev->auto_attach) { + rc = dev->info->init(dev); + if (rc != 0) { + goto err; + } + if (dev->auto_attach) { rc = usb_device_attach(dev); + if (rc != 0) { + goto err; + } } + return 0; + +err: + usb_qdev_exit(qdev); return rc; } @@ -139,10 +151,17 @@ USBDevice *usb_create(USBBus *bus, const char *name) USBDevice *usb_create_simple(USBBus *bus, const char *name) { USBDevice *dev = usb_create(bus, name); + int rc; + if (!dev) { - hw_error("Failed to create USB device '%s'\n", name); + error_report("Failed to create USB device '%s'\n", name); + return NULL; + } + rc = qdev_init(&dev->qdev); + if (rc < 0) { + error_report("Failed to initialize USB device '%s'\n", name); + return NULL; } - qdev_init_nofail(&dev->qdev); return dev; } diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 3eea94d09..a946e1d1f 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -437,37 +437,39 @@ struct EHCIState { } while(0) static const char *ehci_state_names[] = { - [ EST_INACTIVE ] = "INACTIVE", - [ EST_ACTIVE ] = "ACTIVE", - [ EST_EXECUTING ] = "EXECUTING", - [ EST_SLEEPING ] = "SLEEPING", - [ EST_WAITLISTHEAD ] = "WAITLISTHEAD", - [ EST_FETCHENTRY ] = "FETCH ENTRY", - [ EST_FETCHQH ] = "FETCH QH", - [ EST_FETCHITD ] = "FETCH ITD", - [ EST_ADVANCEQUEUE ] = "ADVANCEQUEUE", - [ EST_FETCHQTD ] = "FETCH QTD", - [ EST_EXECUTE ] = "EXECUTE", - [ EST_WRITEBACK ] = "WRITEBACK", - [ EST_HORIZONTALQH ] = "HORIZONTALQH", + [EST_INACTIVE] = "INACTIVE", + [EST_ACTIVE] = "ACTIVE", + [EST_EXECUTING] = "EXECUTING", + [EST_SLEEPING] = "SLEEPING", + [EST_WAITLISTHEAD] = "WAITLISTHEAD", + [EST_FETCHENTRY] = "FETCH ENTRY", + [EST_FETCHQH] = "FETCH QH", + [EST_FETCHITD] = "FETCH ITD", + [EST_ADVANCEQUEUE] = "ADVANCEQUEUE", + [EST_FETCHQTD] = "FETCH QTD", + [EST_EXECUTE] = "EXECUTE", + [EST_WRITEBACK] = "WRITEBACK", + [EST_HORIZONTALQH] = "HORIZONTALQH", }; static const char *ehci_mmio_names[] = { - [ CAPLENGTH ] = "CAPLENGTH", - [ HCIVERSION ] = "HCIVERSION", - [ HCSPARAMS ] = "HCSPARAMS", - [ HCCPARAMS ] = "HCCPARAMS", - [ USBCMD ] = "USBCMD", - [ USBSTS ] = "USBSTS", - [ USBINTR ] = "USBINTR", - [ FRINDEX ] = "FRINDEX", - [ PERIODICLISTBASE ] = "P-LIST BASE", - [ ASYNCLISTADDR ] = "A-LIST ADDR", - [ PORTSC_BEGIN ] = "PORTSC #0", - [ PORTSC_BEGIN + 4] = "PORTSC #1", - [ PORTSC_BEGIN + 8] = "PORTSC #2", - [ PORTSC_BEGIN + 12] = "PORTSC #3", - [ CONFIGFLAG ] = "CONFIGFLAG", + [CAPLENGTH] = "CAPLENGTH", + [HCIVERSION] = "HCIVERSION", + [HCSPARAMS] = "HCSPARAMS", + [HCCPARAMS] = "HCCPARAMS", + [USBCMD] = "USBCMD", + [USBSTS] = "USBSTS", + [USBINTR] = "USBINTR", + [FRINDEX] = "FRINDEX", + [PERIODICLISTBASE] = "P-LIST BASE", + [ASYNCLISTADDR] = "A-LIST ADDR", + [PORTSC_BEGIN] = "PORTSC #0", + [PORTSC_BEGIN + 4] = "PORTSC #1", + [PORTSC_BEGIN + 8] = "PORTSC #2", + [PORTSC_BEGIN + 12] = "PORTSC #3", + [PORTSC_BEGIN + 16] = "PORTSC #4", + [PORTSC_BEGIN + 20] = "PORTSC #5", + [CONFIGFLAG] = "CONFIGFLAG", }; static const char *nr2str(const char **n, size_t len, uint32_t nr) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 3eb0f1aa0..e1959372e 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -171,6 +171,8 @@ static void usb_hub_detach(USBPort *port1) USBHubState *s = port1->opaque; USBHubPort *port = &s->ports[port1->index]; + usb_wakeup(&s->dev); + /* Let upstream know the device on this port is gone */ s->dev.port->ops->child_detach(s->dev.port, port1->dev); @@ -220,7 +222,22 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet) static void usb_hub_handle_reset(USBDevice *dev) { - /* XXX: do it */ + USBHubState *s = DO_UPCAST(USBHubState, dev, dev); + USBHubPort *port; + int i; + + for (i = 0; i < NUM_PORTS; i++) { + port = s->ports + i; + port->wPortStatus = PORT_STAT_POWER; + port->wPortChange = 0; + if (port->port.dev && port->port.dev->attached) { + port->wPortStatus |= PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (port->port.dev->speed == USB_SPEED_LOW) { + port->wPortStatus |= PORT_STAT_LOW_SPEED; + } + } + } } static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, @@ -495,9 +512,8 @@ static int usb_hub_initfn(USBDevice *dev) &port->port, s, i, &usb_hub_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); usb_port_location(&port->port, dev->port, i+1); - port->wPortStatus = PORT_STAT_POWER; - port->wPortChange = 0; } + usb_hub_handle_reset(dev); return 0; } diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 68e375678..4c0695012 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -546,7 +546,8 @@ static int usb_msd_initfn(USBDevice *dev) usb_desc_init(dev); scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info); - s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable); + s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, + s->conf.bootindex); if (!s->scsi_dev) { return -1; } @@ -562,7 +563,6 @@ static int usb_msd_initfn(USBDevice *dev) } } - add_boot_device_path(s->conf.bootindex, &dev->qdev, "/disk@0,0"); return 0; } diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 19e89e71e..d6d1f87cd 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -485,6 +485,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) struct virtio_blk_config blkcfg; uint64_t capacity; int cylinders, heads, secs; + int blk_size = s->conf->logical_block_size; bdrv_get_geometry(s->bs, &capacity); bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); @@ -492,14 +493,14 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) stq_raw(&blkcfg.capacity, capacity); stl_raw(&blkcfg.seg_max, 128 - 2); stw_raw(&blkcfg.cylinders, cylinders); + stl_raw(&blkcfg.blk_size, blk_size); + stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size); + stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size); blkcfg.heads = heads; blkcfg.sectors = secs & ~s->sector_mask; - blkcfg.blk_size = s->conf->logical_block_size; blkcfg.size_max = 0; blkcfg.physical_block_exp = get_physical_block_exp(s->conf); blkcfg.alignment_offset = 0; - blkcfg.min_io_size = s->conf->min_io_size / blkcfg.blk_size; - blkcfg.opt_io_size = s->conf->opt_io_size / blkcfg.blk_size; memcpy(config, &blkcfg, sizeof(struct virtio_blk_config)); } diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index ef8bb14d0..f13e1d59d 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -285,14 +285,9 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) case VIRTIO_PCI_GUEST_FEATURES: /* Guest does not negotiate properly? We have to assume nothing. */ if (val & (1 << VIRTIO_F_BAD_FEATURE)) { - if (vdev->bad_features) - val = proxy->host_features & vdev->bad_features(vdev); - else - val = 0; + val = vdev->bad_features ? vdev->bad_features(vdev) : 0; } - if (vdev->set_features) - vdev->set_features(vdev, val); - vdev->guest_features = val; + virtio_set_features(vdev, val); break; case VIRTIO_PCI_QUEUE_PFN: pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; diff --git a/hw/virtio.c b/hw/virtio.c index 7011b5b39..81ecc40b3 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -763,12 +763,25 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) } } +int virtio_set_features(VirtIODevice *vdev, uint32_t val) +{ + uint32_t supported_features = + vdev->binding->get_features(vdev->binding_opaque); + bool bad = (val & ~supported_features) != 0; + + val &= supported_features; + if (vdev->set_features) { + vdev->set_features(vdev, val); + } + vdev->guest_features = val; + return bad ? -1 : 0; +} + int virtio_load(VirtIODevice *vdev, QEMUFile *f) { int num, i, ret; uint32_t features; - uint32_t supported_features = - vdev->binding->get_features(vdev->binding_opaque); + uint32_t supported_features; if (vdev->binding->load_config) { ret = vdev->binding->load_config(vdev->binding_opaque, f); @@ -780,14 +793,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) qemu_get_8s(f, &vdev->isr); qemu_get_be16s(f, &vdev->queue_sel); qemu_get_be32s(f, &features); - if (features & ~supported_features) { + + if (virtio_set_features(vdev, features) < 0) { + supported_features = vdev->binding->get_features(vdev->binding_opaque); error_report("Features 0x%x unsupported. Allowed features: 0x%x", features, supported_features); return -1; } - if (vdev->set_features) - vdev->set_features(vdev, features); - vdev->guest_features = features; vdev->config_len = qemu_get_be32(f); qemu_get_buffer(f, vdev->config, vdev->config_len); diff --git a/hw/virtio.h b/hw/virtio.h index 2d18209fb..25f55647b 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -185,6 +185,7 @@ void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector); void virtio_set_status(VirtIODevice *vdev, uint8_t val); void virtio_reset(void *opaque); void virtio_update_irq(VirtIODevice *vdev); +int virtio_set_features(VirtIODevice *vdev, uint32_t val); void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, void *opaque); diff --git a/net/slirp.c b/net/slirp.c index c6cda5dcb..6646ecb1c 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -305,7 +305,7 @@ void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) { struct in_addr host_addr = { .s_addr = INADDR_ANY }; int host_port; - char buf[256] = ""; + char buf[256]; const char *src_str, *p; SlirpState *s; int is_udp = 0; @@ -325,11 +325,10 @@ void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) return; } - if (!src_str || !src_str[0]) - goto fail_syntax; - p = src_str; - get_str_sep(buf, sizeof(buf), &p, ':'); + if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } if (!strcmp(buf, "tcp") || buf[0] == '\0') { is_udp = 0; diff --git a/oslib-posix.c b/oslib-posix.c index 6f297626c..ce755496b 100644 --- a/oslib-posix.c +++ b/oslib-posix.c @@ -162,8 +162,7 @@ int qemu_pipe(int pipefd[2]) return ret; } -int qemu_utimensat(int dirfd, const char *path, const struct timespec *times, - int flags) +int qemu_utimens(const char *path, const struct timespec *times) { struct timeval tv[2], tv_now; struct stat st; @@ -171,7 +170,7 @@ int qemu_utimensat(int dirfd, const char *path, const struct timespec *times, #ifdef CONFIG_UTIMENSAT int ret; - ret = utimensat(dirfd, path, times, flags); + ret = utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW); if (ret != -1 || errno != ENOSYS) { return ret; } diff --git a/qemu-char.c b/qemu-char.c index b562bf88a..27abcb918 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -106,7 +106,7 @@ static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = QTAILQ_HEAD_INITIALIZER(chardevs); -static void qemu_chr_event(CharDriverState *s, int event) +void qemu_chr_be_event(CharDriverState *s, int event) { /* Keep track if the char device is open */ switch (event) { @@ -126,7 +126,7 @@ static void qemu_chr_event(CharDriverState *s, int event) static void qemu_chr_generic_open_bh(void *opaque) { CharDriverState *s = opaque; - qemu_chr_event(s, CHR_EVENT_OPENED); + qemu_chr_be_event(s, CHR_EVENT_OPENED); qemu_bh_delete(s->bh); s->bh = NULL; } @@ -359,7 +359,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) bdrv_commit_all(); break; case 'b': - qemu_chr_event(chr, CHR_EVENT_BREAK); + qemu_chr_be_event(chr, CHR_EVENT_BREAK); break; case 'c': /* Switch to the next registered device */ @@ -580,7 +580,7 @@ static void fd_chr_read(void *opaque) if (size == 0) { /* FD has been closed. Remove it from the active list. */ qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); return; } if (size > 0) { @@ -613,7 +613,7 @@ static void fd_chr_close(struct CharDriverState *chr) } g_free(s); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } /* open a character device to a unix fd */ @@ -715,7 +715,7 @@ static void stdio_read(void *opaque) if (size == 0) { /* stdin has been closed. Remove it from the active list. */ qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); return; } if (size > 0) { @@ -977,7 +977,7 @@ static void pty_chr_close(struct CharDriverState *chr) qemu_del_timer(s->timer); qemu_free_timer(s->timer); g_free(s); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr) @@ -1355,7 +1355,7 @@ static void pp_close(CharDriverState *chr) ioctl(fd, PPRELEASE); close(fd); g_free(drv); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr) @@ -1500,7 +1500,7 @@ static void win_chr_close(CharDriverState *chr) else qemu_del_polling_cb(win_chr_poll, chr); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static int win_chr_init(CharDriverState *chr, const char *filename) @@ -2108,7 +2108,7 @@ static void udp_chr_close(CharDriverState *chr) closesocket(s->fd); } g_free(s); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr) @@ -2213,7 +2213,7 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr, } else { if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { /* Handle IAC break commands by sending a serial break */ - qemu_chr_event(chr, CHR_EVENT_BREAK); + qemu_chr_be_event(chr, CHR_EVENT_BREAK); s->do_telnetopt++; } s->do_telnetopt++; @@ -2321,7 +2321,7 @@ static void tcp_chr_read(void *opaque) qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); s->fd = -1; - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } else if (size > 0) { if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); @@ -2433,7 +2433,7 @@ static void tcp_chr_close(CharDriverState *chr) closesocket(s->listen_fd); } g_free(s); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) diff --git a/qemu-char.h b/qemu-char.h index 7efcf99f5..8ca1e2d54 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -212,6 +212,16 @@ int qemu_chr_be_can_write(CharDriverState *s); */ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len); + +/** + * @qemu_chr_be_event: + * + * Send an event from the back end to the front end. + * + * @event the event to send + */ +void qemu_chr_be_event(CharDriverState *s, int event); + void qemu_chr_add_handlers(CharDriverState *s, IOCanReadHandler *fd_can_read, IOReadHandler *fd_read, diff --git a/qemu-img.c b/qemu-img.c index 86127f0b1..8bdae6649 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -332,8 +332,9 @@ static int img_create(int argc, char **argv) /* Get image size, if specified */ if (optind < argc) { int64_t sval; - sval = strtosz_suffix(argv[optind++], NULL, STRTOSZ_DEFSUFFIX_B); - if (sval < 0) { + char *end; + sval = strtosz_suffix(argv[optind++], &end, STRTOSZ_DEFSUFFIX_B); + if (sval < 0 || *end) { error_report("Invalid image size specified! You may use k, M, G or " "T suffixes for "); error_report("kilobytes, megabytes, gigabytes and terabytes."); @@ -710,8 +711,9 @@ static int img_convert(int argc, char **argv) case 'S': { int64_t sval; - sval = strtosz_suffix(optarg, NULL, STRTOSZ_DEFSUFFIX_B); - if (sval < 0) { + char *end; + sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B); + if (sval < 0 || *end) { error_report("Invalid minimum zero buffer size for sparse output specified"); return 1; } diff --git a/qemu-os-posix.h b/qemu-os-posix.h index 920499d83..8e1149d96 100644 --- a/qemu-os-posix.h +++ b/qemu-os-posix.h @@ -44,7 +44,6 @@ typedef struct timeval qemu_timeval; #endif #endif typedef struct timespec qemu_timespec; -int qemu_utimensat(int dirfd, const char *path, const qemu_timespec *times, - int flags); +int qemu_utimens(const char *path, const qemu_timespec *times); #endif diff --git a/scripts/qapi.py b/scripts/qapi.py index 52999763e..6e05469e6 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -200,6 +200,7 @@ def basename(filename): return filename.split("/")[-1] def guardname(filename): - if filename.startswith('./'): - filename = filename[2:] - return filename.replace("/", "_").replace("-", "_").split(".")[0].upper() + '_H' + guard = basename(filename).rsplit(".", 1)[0] + for substr in [".", " ", "-"]: + guard = guard.replace(substr, "_") + return guard.upper() + '_H' diff --git a/spice-qemu-char.c b/spice-qemu-char.c index ac522022c..7e8eaa9fd 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -69,11 +69,40 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) return bytes; } +static void vmc_state(SpiceCharDeviceInstance *sin, int connected) +{ + SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); + +#if SPICE_SERVER_VERSION < 0x000901 + /* + * spice-server calls the state callback for the agent channel when the + * spice client connects / disconnects. Given that not the client but + * the server is doing the parsing of the messages this is wrong as the + * server is still listening. Worse, this causes the parser in the server + * to go out of sync, so we ignore state calls for subtype vdagent + * spicevmc chardevs. For the full story see: + * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html + */ + if (strcmp(sin->subtype, "vdagent") == 0) { + return; + } +#endif + + if ((scd->chr->opened && connected) || + (!scd->chr->opened && !connected)) { + return; + } + + qemu_chr_be_event(scd->chr, + connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED); +} + static SpiceCharDeviceInterface vmc_interface = { .base.type = SPICE_INTERFACE_CHAR_DEVICE, .base.description = "spice virtual channel char device", .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, + .state = vmc_state, .write = vmc_write, .read = vmc_read, }; @@ -197,7 +226,12 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) chr->chr_guest_open = spice_chr_guest_open; chr->chr_guest_close = spice_chr_guest_close; - qemu_chr_generic_open(chr); +#if SPICE_SERVER_VERSION < 0x000901 + /* See comment in vmc_state() */ + if (strcmp(subtype, "vdagent") == 0) { + qemu_chr_generic_open(chr); + } +#endif *_chr = chr; return 0; diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 21e589675..0b3af9060 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -107,14 +107,33 @@ void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { #if defined(CONFIG_KVM) + uint32_t vec[4]; + +#ifdef __x86_64__ + asm volatile("cpuid" + : "=a"(vec[0]), "=b"(vec[1]), + "=c"(vec[2]), "=d"(vec[3]) + : "0"(function), "c"(count) : "cc"); +#else + asm volatile("pusha \n\t" + "cpuid \n\t" + "mov %%eax, 0(%2) \n\t" + "mov %%ebx, 4(%2) \n\t" + "mov %%ecx, 8(%2) \n\t" + "mov %%edx, 12(%2) \n\t" + "popa" + : : "a"(function), "c"(count), "S"(vec) + : "memory", "cc"); +#endif + if (eax) - *eax = kvm_arch_get_supported_cpuid(kvm_state, function, count, R_EAX); + *eax = vec[0]; if (ebx) - *ebx = kvm_arch_get_supported_cpuid(kvm_state, function, count, R_EBX); + *ebx = vec[1]; if (ecx) - *ecx = kvm_arch_get_supported_cpuid(kvm_state, function, count, R_ECX); + *ecx = vec[2]; if (edx) - *edx = kvm_arch_get_supported_cpuid(kvm_state, function, count, R_EDX); + *edx = vec[3]; #endif } @@ -692,7 +711,7 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) tsc_freq = strtosz_suffix_unit(val, &err, STRTOSZ_DEFSUFFIX_B, 1000); - if (!*val || *err) { + if (tsc_freq < 0 || *err) { fprintf(stderr, "bad numerical value %s\n", val); goto error; } diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c index 942910e14..fc0880cec 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.c @@ -373,10 +373,6 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { }; #endif -static void flush_icache_range(unsigned long start, unsigned long stop) -{ -} - static void patch_reloc(uint8_t *code_ptr, int type, tcg_target_long value, tcg_target_long addend) { diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index cb5858c9c..03e0fd1a7 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -157,4 +157,8 @@ void tci_disas(uint8_t opc); unsigned long tcg_qemu_tb_exec(CPUState *env, uint8_t *tb_ptr); #define tcg_qemu_tb_exec tcg_qemu_tb_exec +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} + #endif /* TCG_TARGET_H */ diff --git a/usb-linux.c b/usb-linux.c index d4426ea73..ab4c6930c 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -148,6 +148,25 @@ static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name); static int usb_linux_update_endp_table(USBHostDevice *s); +static int usb_host_do_reset(USBHostDevice *dev) +{ + struct timeval s, e; + uint32_t usecs; + int ret; + + gettimeofday(&s, NULL); + ret = ioctl(dev->fd, USBDEVFS_RESET); + gettimeofday(&e, NULL); + usecs = (e.tv_sec - s.tv_sec) * 1000000; + usecs += e.tv_usec - s.tv_usec; + if (usecs > 1000000) { + /* more than a second, something is fishy, broken usb device? */ + fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n", + dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000); + } + return ret; +} + static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep) { struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out; @@ -606,7 +625,7 @@ static void usb_host_handle_reset(USBDevice *dev) trace_usb_host_reset(s->bus_num, s->addr); - ioctl(s->fd, USBDEVFS_RESET); + usb_host_do_reset(s);; usb_host_claim_interfaces(s, 0); usb_linux_update_endp_table(s); @@ -1370,7 +1389,7 @@ static int usb_host_close(USBHostDevice *dev) if (dev->dev.attached) { usb_device_detach(&dev->dev); } - ioctl(dev->fd, USBDEVFS_RESET); + usb_host_do_reset(dev); close(dev->fd); dev->fd = -1; return 0; @@ -1381,7 +1400,7 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data) USBHostDevice *s = container_of(n, USBHostDevice, exit); if (s->fd != -1) { - ioctl(s->fd, USBDEVFS_RESET); + usb_host_do_reset(s);; } } diff --git a/usb-redir.c b/usb-redir.c index c74b1560b..fb91c926a 100644 --- a/usb-redir.c +++ b/usb-redir.c @@ -225,6 +225,10 @@ static int usbredir_write(void *priv, uint8_t *data, int count) { USBRedirDevice *dev = priv; + if (!dev->cs->opened) { + return 0; + } + return qemu_chr_fe_write(dev->cs, data, count); } @@ -814,6 +818,8 @@ static int usbredir_initfn(USBDevice *udev) /* We'll do the attach once we receive the speed from the usb-host */ udev->auto_attach = 0; + /* Let the backend know we are ready */ + qemu_chr_fe_open(dev->cs); qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, usbredir_chardev_read, usbredir_chardev_event, dev); @@ -837,6 +843,7 @@ static void usbredir_handle_destroy(USBDevice *udev) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + qemu_chr_fe_close(dev->cs); qemu_chr_delete(dev->cs); /* Note must be done after qemu_chr_close, as that causes a close event */ qemu_bh_delete(dev->open_close_bh); @@ -878,6 +885,11 @@ static void usbredir_device_connect(void *priv, { USBRedirDevice *dev = priv; + if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { + ERROR("Received device connect while already connected\n"); + return; + } + switch (device_connect->speed) { case usb_redir_speed_low: DPRINTF("attaching low speed device\n"); @@ -906,19 +918,26 @@ static void usbredir_device_connect(void *priv, static void usbredir_device_disconnect(void *priv) { USBRedirDevice *dev = priv; + int i; /* Stop any pending attaches */ qemu_del_timer(dev->attach_timer); if (dev->dev.attached) { usb_device_detach(&dev->dev); - usbredir_cleanup_device_queues(dev); /* * Delay next usb device attach to give the guest a chance to see * see the detach / attach in case of quick close / open succession */ dev->next_attach_time = qemu_get_clock_ms(vm_clock) + 200; } + + /* Reset state so that the next dev connected starts with a clean slate */ + usbredir_cleanup_device_queues(dev); + memset(dev->endpoint, 0, sizeof(dev->endpoint)); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } } static void usbredir_interface_info(void *priv, @@ -1010,6 +1029,10 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id, DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status, ep, id); + if (!dev->dev.attached) { + return; + } + dev->endpoint[EP2I(ep)].iso_error = iso_stream_status->status; if (iso_stream_status->status == usb_redir_stall) { DPRINTF("iso stream stopped by peer ep %02X\n", ep); @@ -1027,6 +1050,10 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, DPRINTF("interrupt recv status %d ep %02X id %u\n", interrupt_receiving_status->status, ep, id); + if (!dev->dev.attached) { + return; + } + dev->endpoint[EP2I(ep)].interrupt_error = interrupt_receiving_status->status; if (interrupt_receiving_status->status == usb_redir_stall) { @@ -954,8 +954,8 @@ static void numa_add(const char *optarg) node_mem[nodenr] = 0; } else { int64_t sval; - sval = strtosz(option, NULL); - if (sval < 0) { + sval = strtosz(option, &endptr); + if (sval < 0 || *endptr) { fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg); exit(1); } @@ -2547,9 +2547,10 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_m: { int64_t value; + char *end; - value = strtosz(optarg, NULL); - if (value < 0) { + value = strtosz(optarg, &end); + if (value < 0 || *end) { fprintf(stderr, "qemu: invalid ram size: %s\n", optarg); exit(1); } |