diff options
| -rw-r--r-- | VERSION | 2 | ||||
| -rw-r--r-- | arm-semi.c | 86 | ||||
| -rw-r--r-- | block.c | 44 | ||||
| -rw-r--r-- | block/iscsi.c | 86 | ||||
| -rw-r--r-- | block/qcow2-cluster.c | 14 | ||||
| -rw-r--r-- | block/qcow2.c | 3 | ||||
| -rw-r--r-- | block/sheepdog.c | 8 | ||||
| -rwxr-xr-x | configure | 21 | ||||
| -rw-r--r-- | hmp.c | 2 | ||||
| -rw-r--r-- | hw/ac97.c | 67 | ||||
| -rw-r--r-- | hw/fdc.c | 29 | ||||
| -rw-r--r-- | hw/pc_sysfw.c | 3 | ||||
| -rw-r--r-- | hw/qdev-properties.c | 1 | ||||
| -rw-r--r-- | hw/qxl-logger.c | 51 | ||||
| -rw-r--r-- | hw/qxl-render.c | 14 | ||||
| -rw-r--r-- | hw/qxl.c | 145 | ||||
| -rw-r--r-- | hw/qxl.h | 6 | ||||
| -rw-r--r-- | hw/rtl8139.c | 2 | ||||
| -rw-r--r-- | hw/scsi-bus.c | 100 | ||||
| -rw-r--r-- | hw/scsi-defs.h | 1 | ||||
| -rw-r--r-- | hw/scsi-disk.c | 66 | ||||
| -rw-r--r-- | include/qemu/cpu.h | 4 | ||||
| -rw-r--r-- | input.c | 4 | ||||
| -rw-r--r-- | linux-user/syscall.c | 46 | ||||
| -rw-r--r-- | migration.c | 1 | ||||
| -rw-r--r-- | monitor.c | 12 | ||||
| -rw-r--r-- | qapi-schema.json | 35 | ||||
| -rw-r--r-- | qemu-timer.c | 38 | ||||
| -rw-r--r-- | qemu-timer.h | 4 | ||||
| -rw-r--r-- | qmp.c | 2 | ||||
| -rw-r--r-- | qom/container.c | 2 | ||||
| -rw-r--r-- | scripts/qemu-binfmt-conf.sh | 1 | ||||
| -rw-r--r-- | target-mips/op_helper.c | 6 | ||||
| -rw-r--r-- | tcg/ppc/tcg-target.c | 65 | ||||
| -rw-r--r-- | tci.c | 2 | ||||
| -rw-r--r-- | ui/spice-core.c | 7 | ||||
| -rw-r--r-- | user-exec.c | 3 | ||||
| -rw-r--r-- | vl.c | 14 |
38 files changed, 694 insertions, 303 deletions
diff --git a/VERSION b/VERSION index ac2282af0c..34b3170703 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.90 +1.0.91 diff --git a/arm-semi.c b/arm-semi.c index 8debd19e3a..88ca9bb1b7 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -37,26 +37,26 @@ #include "hw/arm-misc.h" #endif -#define SYS_OPEN 0x01 -#define SYS_CLOSE 0x02 -#define SYS_WRITEC 0x03 -#define SYS_WRITE0 0x04 -#define SYS_WRITE 0x05 -#define SYS_READ 0x06 -#define SYS_READC 0x07 -#define SYS_ISTTY 0x09 -#define SYS_SEEK 0x0a -#define SYS_FLEN 0x0c -#define SYS_TMPNAM 0x0d -#define SYS_REMOVE 0x0e -#define SYS_RENAME 0x0f -#define SYS_CLOCK 0x10 -#define SYS_TIME 0x11 -#define SYS_SYSTEM 0x12 -#define SYS_ERRNO 0x13 -#define SYS_GET_CMDLINE 0x15 -#define SYS_HEAPINFO 0x16 -#define SYS_EXIT 0x18 +#define TARGET_SYS_OPEN 0x01 +#define TARGET_SYS_CLOSE 0x02 +#define TARGET_SYS_WRITEC 0x03 +#define TARGET_SYS_WRITE0 0x04 +#define TARGET_SYS_WRITE 0x05 +#define TARGET_SYS_READ 0x06 +#define TARGET_SYS_READC 0x07 +#define TARGET_SYS_ISTTY 0x09 +#define TARGET_SYS_SEEK 0x0a +#define TARGET_SYS_FLEN 0x0c +#define TARGET_SYS_TMPNAM 0x0d +#define TARGET_SYS_REMOVE 0x0e +#define TARGET_SYS_RENAME 0x0f +#define TARGET_SYS_CLOCK 0x10 +#define TARGET_SYS_TIME 0x11 +#define TARGET_SYS_SYSTEM 0x12 +#define TARGET_SYS_ERRNO 0x13 +#define TARGET_SYS_GET_CMDLINE 0x15 +#define TARGET_SYS_HEAPINFO 0x16 +#define TARGET_SYS_EXIT 0x18 #ifndef O_BINARY #define O_BINARY 0 @@ -138,11 +138,11 @@ static void arm_semi_cb(CPUARMState *env, target_ulong ret, target_ulong err) } else { /* Fixup syscalls that use nonstardard return conventions. */ switch (env->regs[0]) { - case SYS_WRITE: - case SYS_READ: + case TARGET_SYS_WRITE: + case TARGET_SYS_READ: env->regs[0] = arm_semi_syscall_len - ret; break; - case SYS_SEEK: + case TARGET_SYS_SEEK: env->regs[0] = 0; break; default: @@ -190,7 +190,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) nr = env->regs[0]; args = env->regs[1]; switch (nr) { - case SYS_OPEN: + case TARGET_SYS_OPEN: if (!(s = lock_user_string(ARG(0)))) /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; @@ -211,14 +211,14 @@ uint32_t do_arm_semihosting(CPUARMState *env) } unlock_user(s, ARG(0), 0); return ret; - case SYS_CLOSE: + case TARGET_SYS_CLOSE: if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0)); return env->regs[0]; } else { return set_swi_errno(ts, close(ARG(0))); } - case SYS_WRITEC: + case TARGET_SYS_WRITEC: { char c; @@ -233,7 +233,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) return write(STDERR_FILENO, &c, 1); } } - case SYS_WRITE0: + case TARGET_SYS_WRITE0: if (!(s = lock_user_string(args))) /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; @@ -246,7 +246,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) } unlock_user(s, args, 0); return ret; - case SYS_WRITE: + case TARGET_SYS_WRITE: len = ARG(2); if (use_gdb_syscalls()) { arm_semi_syscall_len = len; @@ -262,7 +262,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) return -1; return len - ret; } - case SYS_READ: + case TARGET_SYS_READ: len = ARG(2); if (use_gdb_syscalls()) { arm_semi_syscall_len = len; @@ -280,17 +280,17 @@ uint32_t do_arm_semihosting(CPUARMState *env) return -1; return len - ret; } - case SYS_READC: + case TARGET_SYS_READC: /* XXX: Read from debug cosole. Not implemented. */ return 0; - case SYS_ISTTY: + case TARGET_SYS_ISTTY: if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0)); return env->regs[0]; } else { return isatty(ARG(0)); } - case SYS_SEEK: + case TARGET_SYS_SEEK: if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1)); return env->regs[0]; @@ -300,7 +300,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) return -1; return 0; } - case SYS_FLEN: + case TARGET_SYS_FLEN: if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x", ARG(0), env->regs[13]-64); @@ -312,10 +312,10 @@ uint32_t do_arm_semihosting(CPUARMState *env) return -1; return buf.st_size; } - case SYS_TMPNAM: + case TARGET_SYS_TMPNAM: /* XXX: Not implemented. */ return -1; - case SYS_REMOVE: + case TARGET_SYS_REMOVE: if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1); ret = env->regs[0]; @@ -327,7 +327,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) unlock_user(s, ARG(0), 0); } return ret; - case SYS_RENAME: + case TARGET_SYS_RENAME: if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "rename,%s,%s", ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1); @@ -347,11 +347,11 @@ uint32_t do_arm_semihosting(CPUARMState *env) unlock_user(s, ARG(0), 0); return ret; } - case SYS_CLOCK: + case TARGET_SYS_CLOCK: return clock() / (CLOCKS_PER_SEC / 100); - case SYS_TIME: + case TARGET_SYS_TIME: return set_swi_errno(ts, time(NULL)); - case SYS_SYSTEM: + case TARGET_SYS_SYSTEM: if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1); return env->regs[0]; @@ -363,13 +363,13 @@ uint32_t do_arm_semihosting(CPUARMState *env) unlock_user(s, ARG(0), 0); return ret; } - case SYS_ERRNO: + case TARGET_SYS_ERRNO: #ifdef CONFIG_USER_ONLY return ts->swi_errno; #else return syscall_err; #endif - case SYS_GET_CMDLINE: + case TARGET_SYS_GET_CMDLINE: { /* Build a command-line from the original argv. * @@ -452,7 +452,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) return status; } - case SYS_HEAPINFO: + case TARGET_SYS_HEAPINFO: { uint32_t *ptr; uint32_t limit; @@ -498,7 +498,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) #endif return 0; } - case SYS_EXIT: + case TARGET_SYS_EXIT: gdb_exit(env, 0); exit(0); default: diff --git a/block.c b/block.c index 43c794c4d7..ee7d8f220f 100644 --- a/block.c +++ b/block.c @@ -341,13 +341,53 @@ BlockDriver *bdrv_find_whitelisted_format(const char *format_name) return drv && bdrv_is_whitelisted(drv) ? drv : NULL; } +typedef struct CreateCo { + BlockDriver *drv; + char *filename; + QEMUOptionParameter *options; + int ret; +} CreateCo; + +static void coroutine_fn bdrv_create_co_entry(void *opaque) +{ + CreateCo *cco = opaque; + assert(cco->drv); + + cco->ret = cco->drv->bdrv_create(cco->filename, cco->options); +} + int bdrv_create(BlockDriver *drv, const char* filename, QEMUOptionParameter *options) { - if (!drv->bdrv_create) + int ret; + + Coroutine *co; + CreateCo cco = { + .drv = drv, + .filename = g_strdup(filename), + .options = options, + .ret = NOT_DONE, + }; + + if (!drv->bdrv_create) { return -ENOTSUP; + } - return drv->bdrv_create(filename, options); + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + bdrv_create_co_entry(&cco); + } else { + co = qemu_coroutine_create(bdrv_create_co_entry); + qemu_coroutine_enter(co, &cco); + while (cco.ret == NOT_DONE) { + qemu_aio_wait(); + } + } + + ret = cco.ret; + g_free(cco.filename); + + return ret; } int bdrv_create_file(const char* filename, QEMUOptionParameter *options) diff --git a/block/iscsi.c b/block/iscsi.c index 5222726d0f..d37c4ee171 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -383,6 +383,65 @@ iscsi_aio_flush(BlockDriverState *bs, return &acb->common; } +static void +iscsi_unmap_cb(struct iscsi_context *iscsi, int status, + void *command_data, void *opaque) +{ + IscsiAIOCB *acb = opaque; + + if (acb->canceled != 0) { + qemu_aio_release(acb); + scsi_free_scsi_task(acb->task); + acb->task = NULL; + return; + } + + acb->status = 0; + if (status < 0) { + error_report("Failed to unmap data on iSCSI lun. %s", + iscsi_get_error(iscsi)); + acb->status = -EIO; + } + + iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb); + scsi_free_scsi_task(acb->task); + acb->task = NULL; +} + +static BlockDriverAIOCB * +iscsi_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + IscsiLun *iscsilun = bs->opaque; + struct iscsi_context *iscsi = iscsilun->iscsi; + IscsiAIOCB *acb; + struct unmap_list list[1]; + + acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); + + acb->iscsilun = iscsilun; + acb->canceled = 0; + + list[0].lba = sector_qemu2lun(sector_num, iscsilun); + list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size; + + acb->task = iscsi_unmap_task(iscsi, iscsilun->lun, + 0, 0, &list[0], 1, + iscsi_unmap_cb, + acb); + if (acb->task == NULL) { + error_report("iSCSI: Failed to send unmap command. %s", + iscsi_get_error(iscsi)); + qemu_aio_release(acb); + return NULL; + } + + iscsi_set_events(iscsilun); + + return &acb->common; +} + static int64_t iscsi_getlength(BlockDriverState *bs) { @@ -396,11 +455,11 @@ iscsi_getlength(BlockDriverState *bs) } static void -iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status, +iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status, void *command_data, void *opaque) { struct IscsiTask *itask = opaque; - struct scsi_readcapacity10 *rc10; + struct scsi_readcapacity16 *rc16; struct scsi_task *task = command_data; if (status != 0) { @@ -412,26 +471,25 @@ iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status, return; } - rc10 = scsi_datain_unmarshall(task); - if (rc10 == NULL) { - error_report("iSCSI: Failed to unmarshall readcapacity10 data."); + rc16 = scsi_datain_unmarshall(task); + if (rc16 == NULL) { + error_report("iSCSI: Failed to unmarshall readcapacity16 data."); itask->status = 1; itask->complete = 1; scsi_free_scsi_task(task); return; } - itask->iscsilun->block_size = rc10->block_size; - itask->iscsilun->num_blocks = rc10->lba; - itask->bs->total_sectors = (uint64_t)rc10->lba * - rc10->block_size / BDRV_SECTOR_SIZE ; + itask->iscsilun->block_size = rc16->block_length; + itask->iscsilun->num_blocks = rc16->returned_lba + 1; + itask->bs->total_sectors = itask->iscsilun->num_blocks * + itask->iscsilun->block_size / BDRV_SECTOR_SIZE ; itask->status = 0; itask->complete = 1; scsi_free_scsi_task(task); } - static void iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data, void *opaque) @@ -445,10 +503,10 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data, return; } - task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, 0, 0, - iscsi_readcapacity10_cb, opaque); + task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun, + iscsi_readcapacity16_cb, opaque); if (task == NULL) { - error_report("iSCSI: failed to send readcapacity command."); + error_report("iSCSI: failed to send readcapacity16 command."); itask->status = 1; itask->complete = 1; return; @@ -700,6 +758,8 @@ static BlockDriver bdrv_iscsi = { .bdrv_aio_readv = iscsi_aio_readv, .bdrv_aio_writev = iscsi_aio_writev, .bdrv_aio_flush = iscsi_aio_flush, + + .bdrv_aio_discard = iscsi_aio_discard, }; static void iscsi_block_init(void) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 353889d41b..10c22fe12b 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -883,15 +883,19 @@ again: assert(keep_clusters <= nb_clusters); nb_clusters -= keep_clusters; } else { + keep_clusters = 0; + cluster_offset = 0; + } + + if (nb_clusters > 0) { /* For the moment, overwrite compressed clusters one by one */ - if (cluster_offset & QCOW_OFLAG_COMPRESSED) { + uint64_t entry = be64_to_cpu(l2_table[l2_index + keep_clusters]); + if (entry & QCOW_OFLAG_COMPRESSED) { nb_clusters = 1; } else { - nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, l2_index); + nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, + l2_index + keep_clusters); } - - keep_clusters = 0; - cluster_offset = 0; } cluster_offset &= L2E_OFFSET_MASK; diff --git a/block/qcow2.c b/block/qcow2.c index 8c60a6f061..ee4678f6ed 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1192,7 +1192,10 @@ static int qcow2_create2(const char *filename, int64_t total_size, /* And if we're supposed to preallocate metadata, do that now */ if (prealloc) { + BDRVQcowState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); ret = preallocate(bs); + qemu_co_mutex_unlock(&s->lock); if (ret < 0) { goto out; } diff --git a/block/sheepdog.c b/block/sheepdog.c index 0ed6b193c9..e01d371680 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1678,6 +1678,14 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) return ret; } + if (rsp->result == SD_RES_INVALID_PARMS) { + dprintf("disable write cache since the server doesn't support it\n"); + + s->cache_enabled = 0; + closesocket(s->flush_fd); + return 0; + } + if (rsp->result != SD_RES_SUCCESS) { error_report("%s", sd_strerror(rsp->result)); return -EIO; diff --git a/configure b/configure index 0111774cb0..491109d48c 100755 --- a/configure +++ b/configure @@ -2546,10 +2546,13 @@ fi ########################################## # Do we have libiscsi +# We check for iscsi_unmap_sync() to make sure we have a +# recent enough version of libiscsi. if test "$libiscsi" != "no" ; then cat > $TMPC << EOF +#include <stdio.h> #include <iscsi/iscsi.h> -int main(void) { iscsi_create_context(""); return 0; } +int main(void) { iscsi_unmap_sync(NULL,0,0,0,NULL,0); return 0; } EOF if compile_prog "-Werror" "-liscsi" ; then libiscsi="yes" @@ -2592,6 +2595,7 @@ EOF spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null) spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null) if $pkg_config --atleast-version=0.8.2 spice-server >/dev/null 2>&1 && \ + $pkg_config --atleast-version=0.8.1 spice-protocol > /dev/null 2>&1 && \ compile_prog "$spice_cflags" "$spice_libs" ; then spice="yes" libs_softmmu="$libs_softmmu $spice_libs" @@ -2891,14 +2895,15 @@ tools= if test "$softmmu" = yes ; then tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" if test "$virtfs" != no ; then - if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then - virtfs=yes - tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)" - else - if test "$virtfs" = yes; then - feature_not_found "virtfs" - fi + if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then + virtfs=yes + tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)" + else + if test "$virtfs" = yes; then + feature_not_found "virtfs" fi + virtfs=no + fi fi if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then tools="qemu-nbd\$(EXESUF) $tools" diff --git a/hmp.c b/hmp.c index eb96618e1e..1f9fe0e995 100644 --- a/hmp.c +++ b/hmp.c @@ -350,6 +350,8 @@ void hmp_info_spice(Monitor *mon) } monitor_printf(mon, " auth: %s\n", info->auth); monitor_printf(mon, " compiled: %s\n", info->compiled_version); + monitor_printf(mon, " mouse-mode: %s\n", + SpiceQueryMouseMode_lookup[info->mouse_mode]); if (!info->has_channels || info->channels == NULL) { monitor_printf(mon, "Channels: none\n"); diff --git a/hw/ac97.c b/hw/ac97.c index 177f729d48..e791b9d3e6 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -54,6 +54,8 @@ enum { AC97_6Ch_Vol_C_LFE_Mute = 0x36, AC97_6Ch_Vol_L_R_Surround_Mute = 0x38, AC97_Vendor_Reserved = 0x58, + AC97_Sigmatel_Analog = 0x6c, /* We emulate a Sigmatel codec */ + AC97_Sigmatel_Dac2Invert = 0x6e, /* We emulate a Sigmatel codec */ AC97_Vendor_ID1 = 0x7c, AC97_Vendor_ID2 = 0x7e }; @@ -342,7 +344,7 @@ static uint16_t mixer_load (AC97LinkState *s, uint32_t i) uint16_t val = 0xffff; if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %zd\n", + dolog ("mixer_load: index %d out of bounds %zd\n", i, sizeof (s->mixer_data)); } else { @@ -456,8 +458,7 @@ static void update_combined_volume_out (AC97LinkState *s) get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, &mute, &lvol, &rvol); - /* FIXME: should be 1f according to spec */ - get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, + get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, &pmute, &plvol, &prvol); mute = mute | pmute; @@ -480,11 +481,22 @@ static void update_volume_in (AC97LinkState *s) static void set_volume (AC97LinkState *s, int index, uint32_t val) { - mixer_store (s, index, val); - if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { + switch (index) { + case AC97_Master_Volume_Mute: + val &= 0xbf3f; + mixer_store (s, index, val); + update_combined_volume_out (s); + break; + case AC97_PCM_Out_Volume_Mute: + val &= 0x9f1f; + mixer_store (s, index, val); update_combined_volume_out (s); - } else if (index == AC97_Record_Gain_Mute) { + break; + case AC97_Record_Gain_Mute: + val &= 0x8f0f; + mixer_store (s, index, val); update_volume_in (s); + break; } } @@ -503,14 +515,17 @@ static void mixer_reset (AC97LinkState *s) memset (s->mixer_data, 0, sizeof (s->mixer_data)); memset (active, 0, sizeof (active)); mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ - mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000); + mixer_store (s, AC97_Headphone_Volume_Mute , 0x0000); + mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000); + mixer_store (s, AC97_Master_Tone_RL, 0x0000); mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000); - - mixer_store (s, AC97_Phone_Volume_Mute , 0x8008); - mixer_store (s, AC97_Mic_Volume_Mute , 0x8008); - mixer_store (s, AC97_CD_Volume_Mute , 0x8808); - mixer_store (s, AC97_Aux_Volume_Mute , 0x8808); - mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x8000); + mixer_store (s, AC97_Phone_Volume_Mute , 0x0000); + mixer_store (s, AC97_Mic_Volume_Mute , 0x0000); + mixer_store (s, AC97_Line_In_Volume_Mute , 0x0000); + mixer_store (s, AC97_CD_Volume_Mute , 0x0000); + mixer_store (s, AC97_Video_Volume_Mute , 0x0000); + mixer_store (s, AC97_Aux_Volume_Mute , 0x0000); + mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x0000); mixer_store (s, AC97_General_Purpose , 0x0000); mixer_store (s, AC97_3D_Control , 0x0000); mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f); @@ -532,7 +547,7 @@ static void mixer_reset (AC97LinkState *s) record_select (s, 0); set_volume (s, AC97_Master_Volume_Mute, 0x8000); set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); - set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); + set_volume (s, AC97_Record_Gain_Mute, 0x8808); reset_voices (s, active); } @@ -588,14 +603,13 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) mixer_reset (s); break; case AC97_Powerdown_Ctrl_Stat: - val &= ~0xf; + val &= ~0x800f; val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; case AC97_PCM_Out_Volume_Mute: case AC97_Master_Volume_Mute: case AC97_Record_Gain_Mute: - case AC97_Line_In_Volume_Mute: set_volume (s, index, val); break; case AC97_Record_Select: @@ -657,6 +671,23 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val); } break; + case AC97_Headphone_Volume_Mute: + case AC97_Master_Volume_Mono_Mute: + case AC97_Master_Tone_RL: + case AC97_PC_BEEP_Volume_Mute: + case AC97_Phone_Volume_Mute: + case AC97_Mic_Volume_Mute: + case AC97_Line_In_Volume_Mute: + case AC97_CD_Volume_Mute: + case AC97_Video_Volume_Mute: + case AC97_Aux_Volume_Mute: + case AC97_Record_Gain_Mic_Mute: + case AC97_General_Purpose: + case AC97_3D_Control: + case AC97_Sigmatel_Analog: + case AC97_Sigmatel_Dac2Invert: + /* None of the features in these regs are emulated, so they are RO */ + break; default: dolog ("U nam writew %#x <- %#x\n", addr, val); mixer_store (s, index, val); @@ -1158,8 +1189,8 @@ static int ac97_post_load (void *opaque, int version_id) mixer_load (s, AC97_Master_Volume_Mute)); set_volume (s, AC97_PCM_Out_Volume_Mute, mixer_load (s, AC97_PCM_Out_Volume_Mute)); - set_volume (s, AC97_Line_In_Volume_Mute, - mixer_load (s, AC97_Line_In_Volume_Mute)); + set_volume (s, AC97_Record_Gain_Mute, + mixer_load (s, AC97_Record_Gain_Mute)); active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); diff --git a/hw/fdc.c b/hw/fdc.c index 756d4cefd5..cb4cd25c11 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -705,6 +705,15 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0) qemu_set_irq(fdctrl->irq, 1); fdctrl->sra |= FD_SRA_INTPEND; } + if (status0 & FD_SR0_SEEK) { + FDrive *cur_drv; + /* A seek clears the disk change line (if a disk is inserted) */ + cur_drv = get_cur_drv(fdctrl); + if (cur_drv->max_track) { + cur_drv->media_changed = 0; + } + } + fdctrl->reset_sensei = 0; fdctrl->status0 = status0; FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0); @@ -936,23 +945,7 @@ static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value) static int fdctrl_media_changed(FDrive *drv) { - int ret; - - if (!drv->bs) - return 0; - if (drv->media_changed) { - drv->media_changed = 0; - ret = 1; - } else { - ret = bdrv_media_changed(drv->bs); - if (ret < 0) { - ret = 0; /* we don't know, assume no */ - } - } - if (ret) { - fd_revalidate(drv); - } - return ret; + return drv->media_changed; } /* Digital input register : 0x07 (read-only) */ @@ -1856,6 +1849,7 @@ static void fdctrl_change_cb(void *opaque, bool load) FDrive *drive = opaque; drive->media_changed = 1; + fd_revalidate(drive); } static const BlockDevOps fdctrl_block_ops = { @@ -1886,7 +1880,6 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl) fd_init(drive); fd_revalidate(drive); if (drive->bs) { - drive->media_changed = 1; bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive); } } diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index fafdf9b1c1..f0d7c21b5c 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -85,6 +85,9 @@ static void pc_fw_add_pflash_drv(void) filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); opts = drive_add(IF_PFLASH, -1, filename, "readonly=on"); + + g_free(filename); + if (opts == NULL) { return; } diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 98dd06aeba..c5545dcd37 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -834,6 +834,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, visit_type_str(v, &str, name, &local_err); if (local_err) { + error_free(local_err); return set_int32(obj, v, opaque, name, errp); } diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c index 367aad19f4..fe2878c836 100644 --- a/hw/qxl-logger.c +++ b/hw/qxl-logger.c @@ -100,12 +100,15 @@ static const char *qxl_v2n(const char *n[], size_t l, int v) } #define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value) -static void qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) +static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) { QXLImage *image; QXLImageDescriptor *desc; image = qxl_phys2virt(qxl, addr, group_id); + if (!image) { + return 1; + } desc = &image->descriptor; fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d", desc->id, desc->type, desc->flags, desc->width, desc->height); @@ -120,6 +123,7 @@ static void qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) break; } fprintf(stderr, ")"); + return 0; } static void qxl_log_rect(QXLRect *rect) @@ -130,17 +134,24 @@ static void qxl_log_rect(QXLRect *rect) rect->left, rect->top); } -static void qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy, int group_id) +static int qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy, + int group_id) { + int ret; + fprintf(stderr, " src %" PRIx64, copy->src_bitmap); - qxl_log_image(qxl, copy->src_bitmap, group_id); + ret = qxl_log_image(qxl, copy->src_bitmap, group_id); + if (ret != 0) { + return ret; + } fprintf(stderr, " area"); qxl_log_rect(©->src_area); fprintf(stderr, " rop %d", copy->rop_descriptor); + return 0; } -static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id) +static int qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id) { fprintf(stderr, ": surface_id %d type %s effect %s", draw->surface_id, @@ -148,13 +159,14 @@ static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id) qxl_name(qxl_draw_effect, draw->effect)); switch (draw->type) { case QXL_DRAW_COPY: - qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); + return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); break; } + return 0; } -static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw, - int group_id) +static int qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw, + int group_id) { fprintf(stderr, ": type %s effect %s", qxl_name(qxl_draw_type, draw->type), @@ -166,9 +178,10 @@ static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw, } switch (draw->type) { case QXL_DRAW_COPY: - qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); + return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); break; } + return 0; } static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd) @@ -189,7 +202,7 @@ static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd) } } -void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) +int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) { QXLCursor *cursor; @@ -203,6 +216,9 @@ void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) cmd->u.set.visible ? "yes" : "no", cmd->u.set.shape); cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); + if (!cursor) { + return 1; + } fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d" " unique 0x%" PRIx64 " data-size %d", qxl_name(spice_cursor_type, cursor->header.type), @@ -214,15 +230,17 @@ void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y); break; } + return 0; } -void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) +int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) { bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; void *data; + int ret; if (!qxl->cmdlog) { - return; + return 0; } fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock), qxl->id, ring); @@ -231,12 +249,18 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) compat ? "(compat)" : ""); data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + if (!data) { + return 1; + } switch (ext->cmd.type) { case QXL_CMD_DRAW: if (!compat) { - qxl_log_cmd_draw(qxl, data, ext->group_id); + ret = qxl_log_cmd_draw(qxl, data, ext->group_id); } else { - qxl_log_cmd_draw_compat(qxl, data, ext->group_id); + ret = qxl_log_cmd_draw_compat(qxl, data, ext->group_id); + } + if (ret) { + return ret; } break; case QXL_CMD_SURFACE: @@ -247,4 +271,5 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) break; } fprintf(stderr, "\n"); + return 0; } diff --git a/hw/qxl-render.c b/hw/qxl-render.c index f7f1bfda04..e2e3fe2d37 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -228,14 +228,18 @@ fail: /* called from spice server thread context only */ -void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) +int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) { QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); QXLCursor *cursor; QEMUCursor *c; + if (!cmd) { + return 1; + } + if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) { - return; + return 0; } if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) { @@ -246,9 +250,12 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) switch (cmd->type) { case QXL_CURSOR_SET: cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); + if (!cursor) { + return 1; + } if (cursor->chunk.data_size != cursor->data_size) { fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__); - return; + return 1; } c = qxl_cursor(qxl, cursor); if (c == NULL) { @@ -270,4 +277,5 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) qemu_mutex_unlock(&qxl->ssd.lock); break; } + return 0; } diff --git a/hw/qxl.c b/hw/qxl.c index c3540c3d50..6c11e70049 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -27,28 +27,42 @@ #include "qxl.h" +/* + * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as + * such can be changed by the guest, so to avoid a guest trigerrable + * abort we just set qxl_guest_bug and set the return to NULL. Still + * it may happen as a result of emulator bug as well. + */ #undef SPICE_RING_PROD_ITEM -#define SPICE_RING_PROD_ITEM(r, ret) { \ +#define SPICE_RING_PROD_ITEM(qxl, r, ret) { \ typeof(r) start = r; \ typeof(r) end = r + 1; \ uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \ typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \ if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ - abort(); \ + qxl_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \ + "! %p <= %p < %p", (uint8_t *)start, \ + (uint8_t *)m_item, (uint8_t *)end); \ + ret = NULL; \ + } else { \ + ret = &m_item->el; \ } \ - ret = &m_item->el; \ } #undef SPICE_RING_CONS_ITEM -#define SPICE_RING_CONS_ITEM(r, ret) { \ +#define SPICE_RING_CONS_ITEM(qxl, r, ret) { \ typeof(r) start = r; \ typeof(r) end = r + 1; \ uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \ typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \ if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ - abort(); \ + qxl_guest_bug(qxl, "SPICE_RING_CONS_ITEM indices mismatch " \ + "! %p <= %p < %p", (uint8_t *)start, \ + (uint8_t *)m_item, (uint8_t *)end); \ + ret = NULL; \ + } else { \ + ret = &m_item->el; \ } \ - ret = &m_item->el; \ } #undef ALIGN @@ -343,7 +357,8 @@ static void init_qxl_ram(PCIQXLDevice *d) SPICE_RING_INIT(&d->ram->cmd_ring); SPICE_RING_INIT(&d->ram->cursor_ring); SPICE_RING_INIT(&d->ram->release_ring); - SPICE_RING_PROD_ITEM(&d->ram->release_ring, item); + SPICE_RING_PROD_ITEM(d, &d->ram->release_ring, item); + assert(item); *item = 0; qxl_ring_set_dirty(d); } @@ -383,14 +398,22 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl) * keep track of some command state, for savevm/loadvm. * called from spice server thread context only */ -static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) +static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) { switch (le32_to_cpu(ext->cmd.type)) { case QXL_CMD_SURFACE: { QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + + if (!cmd) { + return 1; + } uint32_t id = le32_to_cpu(cmd->surface_id); - PANIC_ON(id >= NUM_SURFACES); + + if (id >= NUM_SURFACES) { + qxl_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id, NUM_SURFACES); + return 1; + } qemu_mutex_lock(&qxl->track_lock); if (cmd->type == QXL_SURFACE_CMD_CREATE) { qxl->guest_surfaces.cmds[id] = ext->cmd.data; @@ -408,6 +431,10 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) case QXL_CMD_CURSOR: { QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + + if (!cmd) { + return 1; + } if (cmd->type == QXL_CURSOR_SET) { qemu_mutex_lock(&qxl->track_lock); qxl->guest_cursor = ext->cmd.data; @@ -416,6 +443,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) break; } } + return 0; } /* spice display interface callbacks */ @@ -546,8 +574,10 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) if (SPICE_RING_IS_EMPTY(ring)) { return false; } - trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); - SPICE_RING_CONS_ITEM(ring, cmd); + SPICE_RING_CONS_ITEM(qxl, ring, cmd); + if (!cmd) { + return false; + } ext->cmd = *cmd; ext->group_id = MEMSLOT_GROUP_GUEST; ext->flags = qxl->cmdflags; @@ -559,6 +589,7 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) qxl->guest_primary.commands++; qxl_track_command(qxl, ext); qxl_log_command(qxl, "cmd", ext); + trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); return true; default: return false; @@ -617,7 +648,10 @@ static inline void qxl_push_free_res(PCIQXLDevice *d, int flush) if (notify) { qxl_send_events(d, QXL_INTERRUPT_DISPLAY); } - SPICE_RING_PROD_ITEM(ring, item); + SPICE_RING_PROD_ITEM(d, ring, item); + if (!item) { + return; + } *item = 0; d->num_free_res = 0; d->last_release = NULL; @@ -643,7 +677,10 @@ static void interface_release_resource(QXLInstance *sin, * pci bar 0, $command.release_info */ ring = &qxl->ram->release_ring; - SPICE_RING_PROD_ITEM(ring, item); + SPICE_RING_PROD_ITEM(qxl, ring, item); + if (!item) { + return; + } if (*item == 0) { /* stick head into the ring */ id = ext.info->id; @@ -682,7 +719,10 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * if (SPICE_RING_IS_EMPTY(ring)) { return false; } - SPICE_RING_CONS_ITEM(ring, cmd); + SPICE_RING_CONS_ITEM(qxl, ring, cmd); + if (!cmd) { + return false; + } ext->cmd = *cmd; ext->group_id = MEMSLOT_GROUP_GUEST; ext->flags = qxl->cmdflags; @@ -728,8 +768,13 @@ static int interface_req_cursor_notification(QXLInstance *sin) /* called from spice server thread context */ static void interface_notify_update(QXLInstance *sin, uint32_t update_id) { - fprintf(stderr, "%s: abort()\n", __FUNCTION__); - abort(); + /* + * Called by spice-server as a result of a QXL_CMD_UPDATE which is not in + * use by xf86-video-qxl and is defined out in the qxl windows driver. + * Probably was at some earlier version that is prior to git start (2009), + * and is still guest trigerrable. + */ + fprintf(stderr, "%s: deprecated\n", __func__); } /* called from spice server thread context only */ @@ -764,8 +809,8 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) } if (cookie && current_async != cookie->io) { fprintf(stderr, - "qxl: %s: error: current_async = %d != %" PRId64 " = cookie->io\n", - __func__, current_async, cookie->io); + "qxl: %s: error: current_async = %d != %" + PRId64 " = cookie->io\n", __func__, current_async, cookie->io); } switch (current_async) { case QXL_IO_MEMSLOT_ADD_ASYNC: @@ -993,8 +1038,8 @@ static const MemoryRegionPortio qxl_vga_portio_list[] = { PORTIO_END_OF_LIST(), }; -static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, - qxl_async_io async) +static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + qxl_async_io async) { static const int regions[] = { QXL_RAM_RANGE_INDEX, @@ -1015,8 +1060,16 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end); - PANIC_ON(slot_id >= NUM_MEMSLOTS); - PANIC_ON(guest_start > guest_end); + if (slot_id >= NUM_MEMSLOTS) { + qxl_guest_bug(d, "%s: slot_id >= NUM_MEMSLOTS %d >= %d", __func__, + slot_id, NUM_MEMSLOTS); + return 1; + } + if (guest_start > guest_end) { + qxl_guest_bug(d, "%s: guest_start > guest_end 0x%" PRIx64 + " > 0x%" PRIx64, __func__, guest_start, guest_end); + return 1; + } for (i = 0; i < ARRAY_SIZE(regions); i++) { pci_region = regions[i]; @@ -1037,7 +1090,10 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, /* passed */ break; } - PANIC_ON(i == ARRAY_SIZE(regions)); /* finished loop without match */ + if (i == ARRAY_SIZE(regions)) { + qxl_guest_bug(d, "%s: finished loop without match", __func__); + return 1; + } switch (pci_region) { case QXL_RAM_RANGE_INDEX: @@ -1049,7 +1105,8 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, break; default: /* should not happen */ - abort(); + qxl_guest_bug(d, "%s: pci_region = %d", __func__, pci_region); + return 1; } memslot.slot_id = slot_id; @@ -1065,6 +1122,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; d->guest_slots[slot_id].delta = delta; d->guest_slots[slot_id].active = 1; + return 0; } static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) @@ -1097,15 +1155,28 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) case MEMSLOT_GROUP_HOST: return (void *)(intptr_t)offset; case MEMSLOT_GROUP_GUEST: - PANIC_ON(slot >= NUM_MEMSLOTS); - PANIC_ON(!qxl->guest_slots[slot].active); - PANIC_ON(offset < qxl->guest_slots[slot].delta); + if (slot >= NUM_MEMSLOTS) { + qxl_guest_bug(qxl, "slot too large %d >= %d", slot, NUM_MEMSLOTS); + return NULL; + } + if (!qxl->guest_slots[slot].active) { + qxl_guest_bug(qxl, "inactive slot %d\n", slot); + return NULL; + } + if (offset < qxl->guest_slots[slot].delta) { + qxl_guest_bug(qxl, "slot %d offset %"PRIu64" < delta %"PRIu64"\n", + slot, offset, qxl->guest_slots[slot].delta); + return NULL; + } offset -= qxl->guest_slots[slot].delta; - PANIC_ON(offset > qxl->guest_slots[slot].size) + if (offset > qxl->guest_slots[slot].size) { + qxl_guest_bug(qxl, "slot %d offset %"PRIu64" > size %"PRIu64"\n", + slot, offset, qxl->guest_slots[slot].size); + return NULL; + } return qxl->guest_slots[slot].ptr + offset; - default: - PANIC_ON(1); } + return NULL; } static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl) @@ -1120,7 +1191,10 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, QXLDevSurfaceCreate surface; QXLSurfaceCreate *sc = &qxl->guest_primary.surface; - assert(qxl->mode != QXL_MODE_NATIVE); + if (qxl->mode == QXL_MODE_NATIVE) { + qxl_guest_bug(qxl, "%s: nop since already in QXL_MODE_NATIVE", + __func__); + } qxl_exit_vga_mode(qxl); surface.format = le32_to_cpu(sc->format); @@ -1192,7 +1266,7 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) } d->guest_slots[0].slot = slot; - qxl_add_memslot(d, 0, devmem, QXL_SYNC); + assert(qxl_add_memslot(d, 0, devmem, QXL_SYNC) == 0); d->guest_primary.surface = surface; qxl_create_guest_primary(d, 0, QXL_SYNC); @@ -1393,8 +1467,7 @@ async_common: qxl_spice_destroy_surfaces(d, async); break; default: - fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); - abort(); + qxl_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port); } return; cancel_async: @@ -1450,7 +1523,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) qxl_update_irq(d); } else { if (write(d->pipe[1], d, 1) != 1) { - dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__); + dprint(d, 1, "%s: write to pipe failed\n", __func__); } } } @@ -1555,10 +1628,12 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], MEMSLOT_GROUP_GUEST); + assert(cmd); assert(cmd->type == QXL_SURFACE_CMD_CREATE); surface_offset = (intptr_t)qxl_phys2virt(qxl, cmd->u.surface_create.data, MEMSLOT_GROUP_GUEST); + assert(surface_offset); surface_offset -= vram_start; surface_size = cmd->u.surface_create.height * abs(cmd->u.surface_create.stride); diff --git a/hw/qxl.h b/hw/qxl.h index cbb1e2d6d4..31029503fe 100644 --- a/hw/qxl.h +++ b/hw/qxl.h @@ -142,12 +142,12 @@ void qxl_spice_reset_image_cache(PCIQXLDevice *qxl); void qxl_spice_reset_cursor(PCIQXLDevice *qxl); /* qxl-logger.c */ -void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); -void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); +int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); +int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); /* qxl-render.c */ void qxl_render_resize(PCIQXLDevice *qxl); void qxl_render_update(PCIQXLDevice *qxl); -void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); +int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie); void qxl_render_update_area_bh(void *opaque); diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 4d0f5ba518..eb22d04fad 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -2500,7 +2500,7 @@ static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[], case 1: /* fall through */ case 2: /* fall through */ case 4: - ret = (regs[reg] >> offset * 8) & ((1 << (size * 8)) - 1); + ret = (regs[reg] >> offset * 8) & (((uint64_t)1 << (size * 8)) - 1); DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n", reg, addr, size, ret); break; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index dbdb99ce35..8ab9bcda86 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -239,6 +239,18 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus) return res; } +static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf) +{ + scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD)); + scsi_req_complete(req, CHECK_CONDITION); + return 0; +} + +static const struct SCSIReqOps reqops_invalid_field = { + .size = sizeof(SCSIRequest), + .send_command = scsi_invalid_field +}; + /* SCSIReqOps implementation for invalid commands. */ static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf) @@ -355,10 +367,6 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r) if (r->req.cmd.buf[1] & 0x1) { /* Vital product data */ uint8_t page_code = r->req.cmd.buf[2]; - if (r->req.cmd.xfer < 4) { - return false; - } - r->buf[r->len++] = page_code ; /* this page */ r->buf[r->len++] = 0x00; @@ -386,10 +394,6 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r) } /* PAGE CODE == 0 */ - if (r->req.cmd.xfer < 5) { - return false; - } - r->len = MIN(r->req.cmd.xfer, 36); memset(r->buf, 0, r->len); if (r->req.lun != 0) { @@ -423,9 +427,6 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) } break; case REQUEST_SENSE: - if (req->cmd.xfer < 4) { - goto illegal_request; - } r->len = scsi_device_get_sense(r->req.dev, r->buf, MIN(req->cmd.xfer, sizeof r->buf), (req->cmd.buf[1] & 1) == 0); @@ -517,23 +518,25 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, cmd.lba); } - if ((d->unit_attention.key == UNIT_ATTENTION || - bus->unit_attention.key == UNIT_ATTENTION) && - (buf[0] != INQUIRY && - buf[0] != REPORT_LUNS && - buf[0] != GET_CONFIGURATION && - buf[0] != GET_EVENT_STATUS_NOTIFICATION && - - /* - * If we already have a pending unit attention condition, - * report this one before triggering another one. - */ - !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) { + if (cmd.xfer > INT32_MAX) { + req = scsi_req_alloc(&reqops_invalid_field, d, tag, lun, hba_private); + } else if ((d->unit_attention.key == UNIT_ATTENTION || + bus->unit_attention.key == UNIT_ATTENTION) && + (buf[0] != INQUIRY && + buf[0] != REPORT_LUNS && + buf[0] != GET_CONFIGURATION && + buf[0] != GET_EVENT_STATUS_NOTIFICATION && + + /* + * If we already have a pending unit attention condition, + * report this one before triggering another one. + */ + !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) { req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun, hba_private); } else if (lun != d->lun || - buf[0] == REPORT_LUNS || - (buf[0] == REQUEST_SENSE && (d->sense_len || cmd.xfer < 4))) { + buf[0] == REPORT_LUNS || + (buf[0] == REQUEST_SENSE && d->sense_len)) { req = scsi_req_alloc(&reqops_target_command, d, tag, lun, hba_private); } else { @@ -646,7 +649,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag, sense.key, sense.asc, sense.ascq); memset(req->sense, 0, 18); - req->sense[0] = 0xf0; + req->sense[0] = 0x70; req->sense[2] = sense.key; req->sense[7] = 10; req->sense[12] = sense.asc; @@ -721,10 +724,6 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case 0: cmd->xfer = buf[4]; cmd->len = 6; - /* length 0 means 256 blocks */ - if (cmd->xfer == 0) { - cmd->xfer = 256; - } break; case 1: case 2: @@ -777,7 +776,8 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case MODE_SENSE: break; case WRITE_SAME_10: - cmd->xfer = 1; + case WRITE_SAME_16: + cmd->xfer = dev->blocksize; break; case READ_CAPACITY_10: cmd->xfer = 8; @@ -793,18 +793,26 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) cmd->xfer = buf[9] | (buf[8] << 8); } break; + case WRITE_6: + /* length 0 means 256 blocks */ + if (cmd->xfer == 0) { + cmd->xfer = 256; + } case WRITE_10: case WRITE_VERIFY_10: - case WRITE_6: case WRITE_12: case WRITE_VERIFY_12: case WRITE_16: case WRITE_VERIFY_16: cmd->xfer *= dev->blocksize; break; - case READ_10: case READ_6: case READ_REVERSE: + /* length 0 means 256 blocks */ + if (cmd->xfer == 0) { + cmd->xfer = 256; + } + case READ_10: case RECOVER_BUFFERED_DATA: case READ_12: case READ_16: @@ -872,6 +880,16 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu cmd->xfer *= dev->blocksize; } break; + case READ_16: + case READ_REVERSE_16: + case VERIFY_16: + case WRITE_16: + cmd->len = 16; + cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16); + if (buf[1] & 0x01) { /* fixed */ + cmd->xfer *= dev->blocksize; + } + break; case REWIND: case START_STOP: cmd->len = 6; @@ -895,6 +913,10 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu static void scsi_cmd_xfer_mode(SCSICommand *cmd) { + if (!cmd->xfer) { + cmd->mode = SCSI_XFER_NONE; + return; + } switch (cmd->buf[0]) { case WRITE_6: case WRITE_10: @@ -920,6 +942,8 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) case UPDATE_BLOCK: case WRITE_LONG_10: case WRITE_SAME_10: + case WRITE_SAME_16: + case UNMAP: case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12: @@ -929,14 +953,11 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) case SEND_DVD_STRUCTURE: case PERSISTENT_RESERVE_OUT: case MAINTENANCE_OUT: + case ATA_PASSTHROUGH: cmd->mode = SCSI_XFER_TO_DEV; break; default: - if (cmd->xfer) - cmd->mode = SCSI_XFER_FROM_DEV; - else { - cmd->mode = SCSI_XFER_NONE; - } + cmd->mode = SCSI_XFER_FROM_DEV; break; } } @@ -1127,7 +1148,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len, memset(buf, 0, len); if (fixed) { /* Return fixed format sense buffer */ - buf[0] = 0xf0; + buf[0] = 0x70; buf[2] = sense.key; buf[7] = 10; buf[12] = sense.asc; @@ -1270,6 +1291,7 @@ SCSIRequest *scsi_req_ref(SCSIRequest *req) void scsi_req_unref(SCSIRequest *req) { + assert(req->refcount > 0); if (--req->refcount == 0) { if (req->ops->free_req) { req->ops->free_req(req); diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index ca24192d53..219c84dfb1 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -92,6 +92,7 @@ #define PERSISTENT_RESERVE_OUT 0x5f #define VARLENGTH_CDB 0x7f #define WRITE_FILEMARKS_16 0x80 +#define READ_REVERSE_16 0x81 #define ALLOW_OVERWRITE 0x82 #define EXTENDED_COPY 0x83 #define ATA_PASSTHROUGH 0x85 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a029ab6e84..045c764d9b 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -28,9 +28,6 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif -#define BADF(fmt, ...) \ -do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) - #include "qemu-common.h" #include "qemu-error.h" #include "scsi.h" @@ -61,10 +58,13 @@ typedef struct SCSIDiskReq { BlockAcctCookie acct; } SCSIDiskReq; +#define SCSI_DISK_F_REMOVABLE 0 +#define SCSI_DISK_F_DPOFUA 1 + struct SCSIDiskState { SCSIDevice qdev; - uint32_t removable; + uint32_t features; bool media_changed; bool media_event; bool eject_request; @@ -296,6 +296,13 @@ static void scsi_do_read(void *opaque, int ret) } } + if (r->req.io_canceled) { + return; + } + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + if (r->req.sg) { dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ); r->req.resid -= r->req.sg->size; @@ -505,20 +512,9 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); int buflen = 0; - if (req->cmd.buf[1] & 0x2) { - /* Command support data - optional, not implemented */ - BADF("optional INQUIRY command support request not implemented\n"); - return -1; - } - if (req->cmd.buf[1] & 0x1) { /* Vital product data */ uint8_t page_code = req->cmd.buf[2]; - if (req->cmd.xfer < 4) { - BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is " - "less than 4\n", page_code, req->cmd.xfer); - return -1; - } outbuf[buflen++] = s->qdev.type & 0x1f; outbuf[buflen++] = page_code ; // this page @@ -633,8 +629,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) break; } default: - BADF("Error: unsupported Inquiry (EVPD[%02X]) " - "buffer size %zd\n", page_code, req->cmd.xfer); return -1; } /* done with EVPD */ @@ -643,18 +637,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) /* Standard INQUIRY data */ if (req->cmd.buf[2] != 0) { - BADF("Error: Inquiry (STANDARD) page or code " - "is non-zero [%02X]\n", req->cmd.buf[2]); return -1; } /* PAGE CODE == 0 */ - if (req->cmd.xfer < 5) { - BADF("Error: Inquiry (STANDARD) buffer size %zd " - "is less than 5\n", req->cmd.xfer); - return -1; - } - buflen = req->cmd.xfer; if (buflen > SCSI_MAX_INQUIRY_LEN) { buflen = SCSI_MAX_INQUIRY_LEN; @@ -662,7 +648,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) memset(outbuf, 0, buflen); outbuf[0] = s->qdev.type & 0x1f; - outbuf[1] = s->removable ? 0x80 : 0; + outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0; if (s->qdev.type == TYPE_ROM) { memcpy(&outbuf[16], "QEMU CD-ROM ", 16); } else { @@ -1094,7 +1080,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) p = outbuf; if (s->qdev.type == TYPE_DISK) { - dev_specific_param = 0x10; /* DPOFUA */ + dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0; if (bdrv_is_read_only(s->qdev.conf.bs)) { dev_specific_param |= 0x80; /* Readonly. */ } @@ -1559,8 +1545,11 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) } break; case WRITE_SAME_10: + len = lduw_be_p(&buf[7]); + goto write_same; case WRITE_SAME_16: - len = r->req.cmd.xfer / s->qdev.blocksize; + len = ldl_be_p(&buf[10]) & 0xffffffffULL; + write_same: DPRINTF("WRITE SAME() (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); @@ -1700,7 +1689,8 @@ static int scsi_initfn(SCSIDevice *dev) return -1; } - if (!s->removable && !bdrv_is_inserted(s->qdev.conf.bs)) { + if (!(s->features & (1 << SCSI_DISK_F_REMOVABLE)) && + !bdrv_is_inserted(s->qdev.conf.bs)) { error_report("Device needs media, but drive is empty"); return -1; } @@ -1722,7 +1712,7 @@ static int scsi_initfn(SCSIDevice *dev) return -1; } - if (s->removable) { + if (s->features & (1 << SCSI_DISK_F_REMOVABLE)) { bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s); } bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize); @@ -1745,7 +1735,7 @@ static int scsi_cd_initfn(SCSIDevice *dev) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); s->qdev.blocksize = 2048; s->qdev.type = TYPE_ROM; - s->removable = true; + s->features |= 1 << SCSI_DISK_F_REMOVABLE; return scsi_initfn(&s->qdev); } @@ -1818,7 +1808,9 @@ static int get_device_type(SCSIDiskState *s) return -1; } s->qdev.type = buf[0]; - s->removable = (buf[1] & 0x80) != 0; + if (buf[1] & 0x80) { + s->features |= 1 << SCSI_DISK_F_REMOVABLE; + } return 0; } @@ -1918,7 +1910,10 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, static Property scsi_hd_properties[] = { DEFINE_SCSI_DISK_PROPERTIES(), - DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), + DEFINE_PROP_BIT("removable", SCSIDiskState, features, + SCSI_DISK_F_REMOVABLE, false), + DEFINE_PROP_BIT("dpofua", SCSIDiskState, features, + SCSI_DISK_F_DPOFUA, false), DEFINE_PROP_END_OF_LIST(), }; @@ -2020,7 +2015,10 @@ static TypeInfo scsi_block_info = { static Property scsi_disk_properties[] = { DEFINE_SCSI_DISK_PROPERTIES(), - DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), + DEFINE_PROP_BIT("removable", SCSIDiskState, features, + SCSI_DISK_F_REMOVABLE, false), + DEFINE_PROP_BIT("dpofua", SCSIDiskState, features, + SCSI_DISK_F_DPOFUA, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/qemu/cpu.h b/include/qemu/cpu.h index 4291279bc5..78b65b35fc 100644 --- a/include/qemu/cpu.h +++ b/include/qemu/cpu.h @@ -39,7 +39,7 @@ typedef struct CPUState CPUState; /** * CPUClass: - * @reset: Callback to reset the #CPU to its initial state. + * @reset: Callback to reset the #CPUState to its initial state. * * Represents a CPU family or model. */ @@ -61,7 +61,7 @@ struct CPUState { Object parent_obj; /*< public >*/ - /* TODO Move common fields from CPUState here. */ + /* TODO Move common fields from CPUArchState here. */ }; diff --git a/input.c b/input.c index 6b5c2c3371..6968b31781 100644 --- a/input.c +++ b/input.c @@ -130,7 +130,7 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) void kbd_put_keycode(int keycode) { - if (!runstate_is_running()) { + if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { return; } if (qemu_put_kbd_event) { @@ -154,7 +154,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) void *mouse_event_opaque; int width, height; - if (!runstate_is_running()) { + if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { return; } if (QTAILQ_EMPTY(&mouse_handlers)) { diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 712861829a..20d2a74877 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4866,13 +4866,53 @@ int get_osversion(void) static int open_self_maps(void *cpu_env, int fd) { +#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) TaskState *ts = ((CPUArchState *)cpu_env)->opaque; +#endif + FILE *fp; + char *line = NULL; + size_t len = 0; + ssize_t read; + + fp = fopen("/proc/self/maps", "r"); + if (fp == NULL) { + return -EACCES; + } + + while ((read = getline(&line, &len, fp)) != -1) { + int fields, dev_maj, dev_min, inode; + uint64_t min, max, offset; + char flag_r, flag_w, flag_x, flag_p; + char path[512] = ""; + fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d" + " %512s", &min, &max, &flag_r, &flag_w, &flag_x, + &flag_p, &offset, &dev_maj, &dev_min, &inode, path); + if ((fields < 10) || (fields > 11)) { + continue; + } + if (!strncmp(path, "[stack]", 7)) { + continue; + } + if (h2g_valid(min) && h2g_valid(max)) { + dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx + " %c%c%c%c %08" PRIx64 " %02x:%02x %d%s%s\n", + h2g(min), h2g(max), flag_r, flag_w, + flag_x, flag_p, offset, dev_maj, dev_min, inode, + path[0] ? " " : "", path); + } + } + + free(line); + fclose(fp); + +#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n", (unsigned long long)ts->info->stack_limit, (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK, - (unsigned long long)ts->stack_base); + (unsigned long long)0); +#endif return 0; } @@ -5045,11 +5085,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, NULL, NULL, 0); } thread_env = NULL; -#ifdef ENV_GET_CPU object_delete(OBJECT(ENV_GET_CPU(cpu_env))); -#else - g_free(cpu_env); -#endif g_free(ts); pthread_exit(NULL); } diff --git a/migration.c b/migration.c index 94f7839e8b..f9e968ee2a 100644 --- a/migration.c +++ b/migration.c @@ -252,6 +252,7 @@ static void migrate_fd_put_ready(void *opaque) int old_vm_running = runstate_is_running(); DPRINTF("done iterating\n"); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); if (qemu_savevm_state_complete(s->file) < 0) { diff --git a/monitor.c b/monitor.c index 8946a100c0..12a6fe25ad 100644 --- a/monitor.c +++ b/monitor.c @@ -89,8 +89,8 @@ * TODO lift the restriction * 'i' 32 bit integer * 'l' target long (32 or 64 bit) - * 'M' just like 'l', except in user mode the value is - * multiplied by 2^20 (think Mebibyte) + * 'M' Non-negative target long (32 or 64 bit), in user mode the + * value is multiplied by 2^20 (think Mebibyte) * 'o' octets (aka bytes) * user mode accepts an optional T, t, G, g, M, m, K, k * suffix, which multiplies the value by 2^40 for @@ -3120,11 +3120,15 @@ static int64_t expr_unary(Monitor *mon) n = 0; break; default: + errno = 0; #if TARGET_PHYS_ADDR_BITS > 32 n = strtoull(pch, &p, 0); #else n = strtoul(pch, &p, 0); #endif + if (errno == ERANGE) { + expr_error(mon, "number too large"); + } if (pch == p) { expr_error(mon, "invalid char in expression"); } @@ -3618,6 +3622,10 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, monitor_printf(mon, "integer is for 32-bit values\n"); goto fail; } else if (c == 'M') { + if (val < 0) { + monitor_printf(mon, "enter a positive value\n"); + goto fail; + } val <<= 20; } qdict_put(qdict, key, qint_from_int(val)); diff --git a/qapi-schema.json b/qapi-schema.json index 9193fb9968..2ca7195d25 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -92,6 +92,8 @@ # # @debug: QEMU is running on a debugger # +# @finish-migrate: guest is paused to finish the migration process +# # @inmigrate: guest is paused waiting for an incoming migration # # @internal-error: An internal error that prevents further guest execution @@ -106,8 +108,6 @@ # # @prelaunch: QEMU was started with -S and guest has not started # -# @finish-migrate: guest is paused to finish the migration process -# # @restore-vm: guest is paused to restore VM state # # @running: guest is actively running @@ -116,12 +116,14 @@ # # @shutdown: guest is shut down (and -no-shutdown is in use) # +# @suspended: guest is suspended (ACPI S3) +# # @watchdog: the watchdog action is configured to pause and has been triggered ## { 'enum': 'RunState', 'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused', 'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm', - 'running', 'save-vm', 'shutdown', 'watchdog' ] } + 'running', 'save-vm', 'shutdown', 'suspended', 'watchdog' ] } ## # @StatusInfo: @@ -634,6 +636,25 @@ 'tls': 'bool'} } ## +# @SpiceQueryMouseMode +# +# An enumation of Spice mouse states. +# +# @client: Mouse cursor position is determined by the client. +# +# @server: Mouse cursor position is determined by the server. +# +# @unknown: No information is available about mouse mode used by +# the spice server. +# +# Note: spice/enums.h has a SpiceMouseMode already, hence the name. +# +# Since: 1.1 +## +{ 'enum': 'SpiceQueryMouseMode', + 'data': [ 'client', 'server', 'unknown' ] } + +## # @SpiceInfo # # Information about the SPICE session. @@ -654,6 +675,12 @@ # 'spice' uses SASL or direct TLS authentication, depending on command # line options # +# @mouse-mode: The mode in which the mouse cursor is displayed currently. Can +# be determined by the client or the server, or unknown if spice +# server doesn't provide this information. +# +# Since: 1.1 +# # @channels: a list of @SpiceChannel for each active spice channel # # Since: 0.14.0 @@ -661,7 +688,7 @@ { 'type': 'SpiceInfo', 'data': {'enabled': 'bool', '*host': 'str', '*port': 'int', '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str', - '*channels': ['SpiceChannel']} } + 'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} } ## # @query-spice diff --git a/qemu-timer.c b/qemu-timer.c index 8eadd16aa2..4a6fc98ca0 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -31,10 +31,6 @@ #include "qemu-timer.h" -#ifdef __FreeBSD__ -#include <sys/param.h> -#endif - #ifdef _WIN32 #include <mmsystem.h> #endif @@ -611,7 +607,7 @@ static void unix_stop_timer(struct qemu_alarm_timer *t) #ifdef _WIN32 static MMRESULT mm_timer; -static unsigned mm_period; +static TIMECAPS mm_tc; static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, @@ -628,16 +624,12 @@ static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg, static int mm_start_timer(struct qemu_alarm_timer *t) { - TIMECAPS tc; - - memset(&tc, 0, sizeof(tc)); - timeGetDevCaps(&tc, sizeof(tc)); + timeGetDevCaps(&mm_tc, sizeof(mm_tc)); - mm_period = tc.wPeriodMin; - timeBeginPeriod(mm_period); + timeBeginPeriod(mm_tc.wPeriodMin); - mm_timer = timeSetEvent(1, /* interval (ms) */ - mm_period, /* resolution */ + mm_timer = timeSetEvent(mm_tc.wPeriodMin, /* interval (ms) */ + mm_tc.wPeriodMin, /* resolution */ mm_alarm_handler, /* function */ (DWORD_PTR)t, /* parameter */ TIME_ONESHOT | TIME_CALLBACK_FUNCTION); @@ -645,7 +637,7 @@ static int mm_start_timer(struct qemu_alarm_timer *t) if (!mm_timer) { fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", GetLastError()); - timeEndPeriod(mm_period); + timeEndPeriod(mm_tc.wPeriodMin); return -1; } @@ -655,23 +647,21 @@ static int mm_start_timer(struct qemu_alarm_timer *t) static void mm_stop_timer(struct qemu_alarm_timer *t) { timeKillEvent(mm_timer); - timeEndPeriod(mm_period); + timeEndPeriod(mm_tc.wPeriodMin); } static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta) { int64_t nearest_delta_ms = delta / 1000000; - if (nearest_delta_ms < 1) { - nearest_delta_ms = 1; - } - /* UINT_MAX can be 32 bit */ - if (nearest_delta_ms > UINT_MAX) { - nearest_delta_ms = UINT_MAX; + if (nearest_delta_ms < mm_tc.wPeriodMin) { + nearest_delta_ms = mm_tc.wPeriodMin; + } else if (nearest_delta_ms > mm_tc.wPeriodMax) { + nearest_delta_ms = mm_tc.wPeriodMax; } timeKillEvent(mm_timer); - mm_timer = timeSetEvent((unsigned int) nearest_delta_ms, - mm_period, + mm_timer = timeSetEvent((UINT)nearest_delta_ms, + mm_tc.wPeriodMin, mm_alarm_handler, (DWORD_PTR)t, TIME_ONESHOT | TIME_CALLBACK_FUNCTION); @@ -680,7 +670,7 @@ static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta) fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n", GetLastError()); - timeEndPeriod(mm_period); + timeEndPeriod(mm_tc.wPeriodMin); exit(1); } } diff --git a/qemu-timer.h b/qemu-timer.h index 5175419e5f..f8af595f13 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -5,6 +5,10 @@ #include "main-loop.h" #include "notify.h" +#ifdef __FreeBSD__ +#include <sys/param.h> +#endif + /* timers */ #define SCALE_MS 1000000 diff --git a/qmp.c b/qmp.c index a182b5197e..fee9fb2a9d 100644 --- a/qmp.c +++ b/qmp.c @@ -151,6 +151,8 @@ void qmp_cont(Error **errp) runstate_check(RUN_STATE_SHUTDOWN)) { error_set(errp, QERR_RESET_REQUIRED); return; + } else if (runstate_check(RUN_STATE_SUSPENDED)) { + return; } bdrv_iterate(iostatus_bdrv_it, NULL); diff --git a/qom/container.c b/qom/container.c index c9940ab2e1..4ca8b5cba3 100644 --- a/qom/container.c +++ b/qom/container.c @@ -43,6 +43,8 @@ Object *container_get(Object *root, const char *path) } } + g_strfreev(parts); + return obj; } diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 83a44d8e2a..0da2618883 100644 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -63,6 +63,7 @@ fi if [ $cpu != "sh" ] ; then echo ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-sh4:' > /proc/sys/fs/binfmt_misc/register echo ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sh4eb:' > /proc/sys/fs/binfmt_misc/register +fi if [ $cpu != "s390x" ] ; then echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register fi diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 5627447953..66037acec5 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -192,12 +192,6 @@ static inline uint64_t get_HILO (void) return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0]; } -static inline void set_HILO (uint64_t HILO) -{ - env->active_tc.LO[0] = (int32_t)HILO; - env->active_tc.HI[0] = (int32_t)(HILO >> 32); -} - static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO) { env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index dc407166f5..4cde48d2fd 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -244,6 +244,19 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_set32(ct->u.regs, 0, 0xffffffff); tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); +#if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); +#endif +#endif +#else /* !AREG0 */ +#if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); +#endif +#endif break; case 'K': /* qemu_st[8..32] constraint */ ct->ct |= TCG_CT_REG; @@ -251,9 +264,19 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); +#if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R8); +#endif +#endif +#else /* !AREG0 */ #if TARGET_LONG_BITS == 64 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); #endif +#endif break; case 'M': /* qemu_st64 constraint */ ct->ct |= TCG_CT_REG; @@ -263,6 +286,12 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); +#if defined(CONFIG_TCG_PASS_AREG0) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R8); +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R9); +#endif +#endif break; #else case 'L': @@ -509,7 +538,6 @@ static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) #include "../../softmmu_defs.h" #ifdef CONFIG_TCG_PASS_AREG0 -#error CONFIG_TCG_PASS_AREG0 is not supported /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, int mmu_idx) */ static const void * const qemu_ld_helpers[4] = { @@ -552,7 +580,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) { int addr_reg, data_reg, data_reg2, r0, r1, rbase, bswap; #ifdef CONFIG_SOFTMMU - int mem_index, s_bits, r2; + int mem_index, s_bits, r2, ir; void *label1_ptr, *label2_ptr; #if TARGET_LONG_BITS == 64 int addr_reg2; @@ -614,14 +642,20 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) #endif /* slow path */ + ir = 3; +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_mov (s, TCG_TYPE_I32, ir++, TCG_AREG0); +#endif #if TARGET_LONG_BITS == 32 - tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg); - tcg_out_movi (s, TCG_TYPE_I32, 4, mem_index); + tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg); #else - tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg2); - tcg_out_mov (s, TCG_TYPE_I32, 4, addr_reg); - tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index); +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + ir |= 1; #endif + tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg2); + tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg); +#endif + tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index); tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); switch (opc) { @@ -810,17 +844,18 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) #endif /* slow path */ + ir = 3; +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_mov (s, TCG_TYPE_I32, ir++, TCG_AREG0); +#endif #if TARGET_LONG_BITS == 32 - tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg); - ir = 4; + tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg); #else - tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg2); - tcg_out_mov (s, TCG_TYPE_I32, 4, addr_reg); #ifdef TCG_TARGET_CALL_ALIGN_ARGS - ir = 5; -#else - ir = 4; + ir |= 1; #endif + tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg2); + tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg); #endif switch (opc) { @@ -845,7 +880,7 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) break; case 3: #ifdef TCG_TARGET_CALL_ALIGN_ARGS - ir = 5; + ir |= 1; #endif tcg_out_mov (s, TCG_TYPE_I32, ir++, data_reg2); tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg); diff --git a/tci.c b/tci.c index 71de66d508..a412a4ed93 100644 --- a/tci.c +++ b/tci.c @@ -20,7 +20,7 @@ #include "config.h" /* Defining NDEBUG disables assertions (which makes the code faster). */ -#if !defined(CONFIG_TCG_DEBUG) && !defined(NDEBUG) +#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG) # define NDEBUG #endif diff --git a/ui/spice-core.c b/ui/spice-core.c index a468524799..4fc48f8902 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -462,6 +462,13 @@ SpiceInfo *qmp_query_spice(Error **errp) info->tls_port = tls_port; } +#if SPICE_SERVER_VERSION >= 0x000a03 /* 0.10.3 */ + info->mouse_mode = spice_server_is_server_mouse(spice_server) ? + SPICE_QUERY_MOUSE_MODE_SERVER : + SPICE_QUERY_MOUSE_MODE_CLIENT; +#else + info->mouse_mode = SPICE_QUERY_MOUSE_MODE_UNKNOWN; +#endif /* for compatibility with the original command */ info->has_channels = true; info->channels = qmp_query_spice_channels(); diff --git a/user-exec.c b/user-exec.c index be6bc4f64c..d8c2ad9f2f 100644 --- a/user-exec.c +++ b/user-exec.c @@ -97,7 +97,8 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(h2g(address), pc, puc)) { + if (is_write && h2g_valid(address) + && page_unprotect(h2g(address), pc, puc)) { return 1; } diff --git a/vl.c b/vl.c index ae91a8ab01..5e0080b98f 100644 --- a/vl.c +++ b/vl.c @@ -366,6 +366,11 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED }, { RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_DEBUG, RUN_STATE_SUSPENDED }, + { RUN_STATE_RUNNING, RUN_STATE_SUSPENDED }, + { RUN_STATE_SUSPENDED, RUN_STATE_RUNNING }, + { RUN_STATE_SUSPENDED, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING }, { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE }, @@ -1288,7 +1293,6 @@ static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; static int suspend_requested; -static bool is_suspended; static NotifierList suspend_notifiers = NOTIFIER_LIST_INITIALIZER(suspend_notifiers); static NotifierList wakeup_notifiers = @@ -1420,13 +1424,13 @@ static void qemu_system_suspend(void) { pause_all_vcpus(); notifier_list_notify(&suspend_notifiers, NULL); + runstate_set(RUN_STATE_SUSPENDED); monitor_protocol_event(QEVENT_SUSPEND, NULL); - is_suspended = true; } void qemu_system_suspend_request(void) { - if (is_suspended) { + if (runstate_check(RUN_STATE_SUSPENDED)) { return; } suspend_requested = 1; @@ -1441,17 +1445,17 @@ void qemu_register_suspend_notifier(Notifier *notifier) void qemu_system_wakeup_request(WakeupReason reason) { - if (!is_suspended) { + if (!runstate_check(RUN_STATE_SUSPENDED)) { return; } if (!(wakeup_reason_mask & (1 << reason))) { return; } + runstate_set(RUN_STATE_RUNNING); monitor_protocol_event(QEVENT_WAKEUP, NULL); notifier_list_notify(&wakeup_notifiers, &reason); reset_requested = 1; qemu_notify_event(); - is_suspended = false; } void qemu_system_wakeup_enable(WakeupReason reason, bool enabled) |