diff options
64 files changed, 1725 insertions, 1329 deletions
diff --git a/block/sheepdog.c b/block/sheepdog.c index f35ff5bbe1..93061744d6 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -201,12 +201,12 @@ static inline uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval) return hval; } -static inline int is_data_obj_writable(SheepdogInode *inode, unsigned int idx) +static inline bool is_data_obj_writable(SheepdogInode *inode, unsigned int idx) { return inode->vdi_id == inode->data_vdi_id[idx]; } -static inline int is_data_obj(uint64_t oid) +static inline bool is_data_obj(uint64_t oid) { return !(VDI_BIT & oid); } @@ -231,7 +231,7 @@ static inline uint64_t vid_to_data_oid(uint32_t vid, uint32_t idx) return ((uint64_t)vid << VDI_SPACE_SHIFT) | idx; } -static inline int is_snapshot(struct SheepdogInode *inode) +static inline bool is_snapshot(struct SheepdogInode *inode) { return !!inode->snap_ctime; } @@ -281,7 +281,7 @@ struct SheepdogAIOCB { Coroutine *coroutine; void (*aio_done_func)(SheepdogAIOCB *); - int canceled; + bool canceled; int nr_pending; }; @@ -292,8 +292,8 @@ typedef struct BDRVSheepdogState { uint32_t max_dirty_data_idx; char name[SD_MAX_VDI_LEN]; - int is_snapshot; - uint8_t cache_enabled; + bool is_snapshot; + bool cache_enabled; char *addr; char *port; @@ -417,7 +417,7 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb) */ acb->ret = -EIO; qemu_coroutine_enter(acb->coroutine, NULL); - acb->canceled = 1; + acb->canceled = true; } static AIOPool sd_aio_pool = { @@ -439,7 +439,7 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, acb->nb_sectors = nb_sectors; acb->aio_done_func = NULL; - acb->canceled = 0; + acb->canceled = false; acb->coroutine = qemu_coroutine_self(); acb->ret = 0; acb->nr_pending = 0; @@ -613,7 +613,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, } static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, - struct iovec *iov, int niov, int create, + struct iovec *iov, int niov, bool create, enum AIOCBState aiocb_type); @@ -646,7 +646,7 @@ static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid) QLIST_REMOVE(aio_req, aio_siblings); QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); ret = add_aio_request(s, aio_req, acb->qiov->iov, - acb->qiov->niov, 0, acb->aiocb_type); + acb->qiov->niov, false, acb->aiocb_type); if (ret < 0) { error_report("add_aio_request is failed"); free_aio_req(s, aio_req); @@ -943,7 +943,7 @@ out: } static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, - struct iovec *iov, int niov, int create, + struct iovec *iov, int niov, bool create, enum AIOCBState aiocb_type) { int nr_copies = s->inode.nr_copies; @@ -1022,7 +1022,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, static int read_write_object(int fd, char *buf, uint64_t oid, int copies, unsigned int datalen, uint64_t offset, - int write, int create, uint8_t cache) + bool write, bool create, bool cache) { SheepdogObjReq hdr; SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr; @@ -1071,18 +1071,18 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies, } static int read_object(int fd, char *buf, uint64_t oid, int copies, - unsigned int datalen, uint64_t offset, uint8_t cache) + unsigned int datalen, uint64_t offset, bool cache) { - return read_write_object(fd, buf, oid, copies, datalen, offset, 0, 0, - cache); + return read_write_object(fd, buf, oid, copies, datalen, offset, false, + false, cache); } static int write_object(int fd, char *buf, uint64_t oid, int copies, - unsigned int datalen, uint64_t offset, int create, - uint8_t cache) + unsigned int datalen, uint64_t offset, bool create, + bool cache) { - return read_write_object(fd, buf, oid, copies, datalen, offset, 1, create, - cache); + return read_write_object(fd, buf, oid, copies, datalen, offset, true, + create, cache); } static int sd_open(BlockDriverState *bs, const char *filename, int flags) @@ -1117,7 +1117,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) goto out; } - s->cache_enabled = 1; + s->cache_enabled = true; s->flush_fd = connect_to_sdog(s->addr, s->port); if (s->flush_fd < 0) { error_report("failed to connect"); @@ -1127,7 +1127,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) if (snapid || tag[0] != '\0') { dprintf("%" PRIx32 " snapshot inode was open.\n", vid); - s->is_snapshot = 1; + s->is_snapshot = true; } fd = connect_to_sdog(s->addr, s->port); @@ -1270,7 +1270,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) BDRVSheepdogState *s; char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN]; uint32_t snapid; - int prealloc = 0; + bool prealloc = false; const char *vdiname; s = g_malloc0(sizeof(BDRVSheepdogState)); @@ -1292,9 +1292,9 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) backing_file = options->value.s; } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) { if (!options->value.s || !strcmp(options->value.s, "off")) { - prealloc = 0; + prealloc = false; } else if (!strcmp(options->value.s, "full")) { - prealloc = 1; + prealloc = true; } else { error_report("Invalid preallocation mode: '%s'", options->value.s); @@ -1422,7 +1422,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id); s->inode.vdi_size = offset; ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id), - s->inode.nr_copies, datalen, 0, 0, s->cache_enabled); + s->inode.nr_copies, datalen, 0, false, s->cache_enabled); close(fd); if (ret < 0) { @@ -1461,7 +1461,7 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), data_len, offset, 0, 0, offset); QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); - ret = add_aio_request(s, aio_req, &iov, 1, 0, AIOCB_WRITE_UDATA); + ret = add_aio_request(s, aio_req, &iov, 1, false, AIOCB_WRITE_UDATA); if (ret) { free_aio_req(s, aio_req); acb->ret = -EIO; @@ -1515,7 +1515,7 @@ static int sd_create_branch(BDRVSheepdogState *s) memcpy(&s->inode, buf, sizeof(s->inode)); - s->is_snapshot = 0; + s->is_snapshot = false; ret = 0; dprintf("%" PRIx32 " was newly created.\n", s->inode.vdi_id); @@ -1570,7 +1570,7 @@ static int coroutine_fn sd_co_rw_vector(void *p) while (done != total) { uint8_t flags = 0; uint64_t old_oid = 0; - int create = 0; + bool create = false; oid = vid_to_data_oid(inode->data_vdi_id[idx], idx); @@ -1585,10 +1585,10 @@ static int coroutine_fn sd_co_rw_vector(void *p) break; case AIOCB_WRITE_UDATA: if (!inode->data_vdi_id[idx]) { - create = 1; + create = true; } else if (!is_data_obj_writable(inode, idx)) { /* Copy-On-Write */ - create = 1; + create = true; old_oid = oid; flags = SD_FLAG_CMD_COW; } @@ -1722,7 +1722,7 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) if (rsp->result == SD_RES_INVALID_PARMS) { dprintf("disable write cache since the server doesn't support it\n"); - s->cache_enabled = 0; + s->cache_enabled = false; closesocket(s->flush_fd); return 0; } @@ -1773,7 +1773,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) } ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id), - s->inode.nr_copies, datalen, 0, 0, s->cache_enabled); + s->inode.nr_copies, datalen, 0, false, s->cache_enabled); if (ret < 0) { error_report("failed to write snapshot's inode."); goto cleanup; @@ -1860,7 +1860,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) goto out; } - s->is_snapshot = 1; + s->is_snapshot = true; g_free(buf); g_free(old_s); @@ -1978,8 +1978,8 @@ out: static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, int64_t pos, int size, int load) { - int fd, create; - int ret = 0, remaining = size; + bool create; + int fd, ret = 0, remaining = size; unsigned int data_len; uint64_t vmstate_oid; uint32_t vdi_index; @@ -185,6 +185,7 @@ libdir="\${prefix}/lib" libexecdir="\${prefix}/libexec" includedir="\${prefix}/include" sysconfdir="\${prefix}/etc" +local_statedir="\${prefix}/var" confsuffix="/qemu" slirp="yes" fmod_lib="" @@ -554,6 +555,7 @@ EOF qemu_docdir="\${prefix}" bindir="\${prefix}" sysconfdir="\${prefix}" + local_statedir="\${prefix}" confsuffix="" libs_qga="-lws2_32 -lwinmm -lpowrprof $libs_qga" fi @@ -630,7 +632,9 @@ for opt do ;; --sysconfdir=*) sysconfdir="$optarg" ;; - --sbindir=*|--sharedstatedir=*|--localstatedir=*|\ + --localstatedir=*) local_statedir="$optarg" + ;; + --sbindir=*|--sharedstatedir=*|\ --oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\ --htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*) # These switches are silently ignored, for compatibility with @@ -1001,6 +1005,7 @@ echo " --datadir=PATH install firmware in PATH$confsuffix" echo " --docdir=PATH install documentation in PATH$confsuffix" echo " --bindir=PATH install binaries in PATH" echo " --sysconfdir=PATH install config in PATH$confsuffix" +echo " --localstatedir=PATH install local state in PATH" echo " --with-confsuffix=SUFFIX suffix for QEMU data inside datadir and sysconfdir [$confsuffix]" echo " --enable-debug-tcg enable TCG debugging" echo " --disable-debug-tcg disable TCG debugging (default)" @@ -1291,7 +1296,7 @@ if test -z "$cross_prefix" ; then # big/little endian test cat > $TMPC << EOF #include <inttypes.h> -int main(int argc, char ** argv){ +int main(void) { volatile uint32_t i=0x01234567; return (*((uint8_t*)(&i))) == 0x67; } @@ -2689,20 +2694,14 @@ int main(void) { spice_server_new(); return 0; } 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 && \ + if $pkg_config --atleast-version=0.12.0 spice-server >/dev/null 2>&1 && \ + $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1 && \ compile_prog "$spice_cflags" "$spice_libs" ; then spice="yes" libs_softmmu="$libs_softmmu $spice_libs" QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" spice_protocol_version=$($pkg_config --modversion spice-protocol) spice_server_version=$($pkg_config --modversion spice-server) - if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then - spice_qxl_io_monitors_config_async="yes" - fi - if $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1; then - spice_qxl_client_monitors_config="yes" - fi else if test "$spice" = "yes" ; then feature_not_found "spice" @@ -2870,7 +2869,7 @@ static int sfaa(int *ptr) return __sync_fetch_and_and(ptr, 0); } -int main(int argc, char **argv) +int main(void) { int val = 42; sfaa(&val); @@ -3090,6 +3089,7 @@ echo "library directory `eval echo $libdir`" echo "libexec directory `eval echo $libexecdir`" echo "include directory `eval echo $includedir`" echo "config directory `eval echo $sysconfdir`" +echo "local state directory `eval echo $local_statedir`" if test "$mingw32" = "no" ; then echo "Manual directory `eval echo $mandir`" echo "ELF interp prefix $interp_prefix" @@ -3199,6 +3199,7 @@ echo "sysconfdir=$sysconfdir" >> $config_host_mak echo "qemu_confdir=$qemu_confdir" >> $config_host_mak echo "qemu_datadir=$qemu_datadir" >> $config_host_mak echo "qemu_docdir=$qemu_docdir" >> $config_host_mak +echo "qemu_localstatedir=$local_statedir" >> $config_host_mak echo "CONFIG_QEMU_HELPERDIR=\"$libexecdir\"" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak @@ -3447,14 +3448,6 @@ if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak fi -if test "$spice_qxl_io_monitors_config_async" = "yes" ; then - echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak -fi - -if test "$spice_qxl_client_monitors_config" = "yes" ; then - echo "CONFIG_QXL_CLIENT_MONITORS_CONFIG=y" >> $config_host_mak -fi - if test "$smartcard" = "yes" ; then echo "CONFIG_SMARTCARD=y" >> $config_host_mak fi @@ -3706,7 +3699,6 @@ case "$target_arch2" in ;; x86_64) TARGET_BASE_ARCH=i386 - target_phys_bits=64 target_long_alignment=8 ;; alpha) @@ -3809,7 +3801,6 @@ case "$target_arch2" in target_long_alignment=8 ;; unicore32) - target_phys_bits=32 ;; xtensa|xtensaeb) TARGET_ARCH=xtensa diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 55871fad19..56376c0d75 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -36,7 +36,7 @@ static const uint8_t gic_id[] = { #define NUM_CPU(s) ((s)->num_cpu) -static inline int gic_get_current_cpu(gic_state *s) +static inline int gic_get_current_cpu(GICState *s) { if (s->num_cpu > 1) { return cpu_single_env->cpu_index; @@ -46,7 +46,7 @@ static inline int gic_get_current_cpu(gic_state *s) /* TODO: Many places that call this routine could be optimized. */ /* Update interrupt status after enabled or pending bits have been changed. */ -void gic_update(gic_state *s) +void gic_update(GICState *s) { int best_irq; int best_prio; @@ -84,7 +84,7 @@ void gic_update(gic_state *s) } } -void gic_set_pending_private(gic_state *s, int cpu, int irq) +void gic_set_pending_private(GICState *s, int cpu, int irq) { int cm = 1 << cpu; @@ -105,7 +105,7 @@ static void gic_set_irq(void *opaque, int irq, int level) * [N+32..N+63] : PPI (internal interrupts for CPU 1 * ... */ - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int cm, target; if (irq < (s->num_irq - GIC_INTERNAL)) { /* The first external input line is internal interrupt 32. */ @@ -137,7 +137,7 @@ static void gic_set_irq(void *opaque, int irq, int level) gic_update(s); } -static void gic_set_running_irq(gic_state *s, int cpu, int irq) +static void gic_set_running_irq(GICState *s, int cpu, int irq) { s->running_irq[cpu] = irq; if (irq == 1023) { @@ -148,7 +148,7 @@ static void gic_set_running_irq(gic_state *s, int cpu, int irq) gic_update(s); } -uint32_t gic_acknowledge_irq(gic_state *s, int cpu) +uint32_t gic_acknowledge_irq(GICState *s, int cpu) { int new_irq; int cm = 1 << cpu; @@ -167,7 +167,7 @@ uint32_t gic_acknowledge_irq(gic_state *s, int cpu) return new_irq; } -void gic_complete_irq(gic_state *s, int cpu, int irq) +void gic_complete_irq(GICState *s, int cpu, int irq) { int update = 0; int cm = 1 << cpu; @@ -214,7 +214,7 @@ void gic_complete_irq(gic_state *s, int cpu, int irq) static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; uint32_t res; int irq; int i; @@ -347,7 +347,7 @@ static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, uint32_t value) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int irq; int i; int cpu; @@ -500,7 +500,7 @@ static void gic_dist_writew(void *opaque, target_phys_addr_t offset, static void gic_dist_writel(void *opaque, target_phys_addr_t offset, uint32_t value) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; if (offset == 0xf00) { int cpu; int irq; @@ -539,7 +539,7 @@ static const MemoryRegionOps gic_dist_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) +static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) { switch (offset) { case 0x00: /* Control */ @@ -561,12 +561,12 @@ static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) } } -static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) +static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value) { switch (offset) { case 0x00: /* Control */ s->cpu_enabled[cpu] = (value & 1); - DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled ? "En" : "Dis"); + DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis"); break; case 0x04: /* Priority mask */ s->priority_mask[cpu] = (value & 0xff); @@ -587,25 +587,25 @@ static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr, unsigned size) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; return gic_cpu_read(s, gic_get_current_cpu(s), addr); } static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; gic_cpu_write(s, gic_get_current_cpu(s), addr, value); } /* Wrappers to read/write the GIC CPU interface for a specific CPU. - * These just decode the opaque pointer into gic_state* + cpu id. + * These just decode the opaque pointer into GICState* + cpu id. */ static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr, unsigned size) { - gic_state **backref = (gic_state **)opaque; - gic_state *s = *backref; + GICState **backref = (GICState **)opaque; + GICState *s = *backref; int id = (backref - s->backref); return gic_cpu_read(s, id, addr); } @@ -613,8 +613,8 @@ static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr, static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { - gic_state **backref = (gic_state **)opaque; - gic_state *s = *backref; + GICState **backref = (GICState **)opaque; + GICState *s = *backref; int id = (backref - s->backref); gic_cpu_write(s, id, addr, value); } @@ -631,7 +631,7 @@ static const MemoryRegionOps gic_cpu_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void gic_init_irqs_and_distributor(gic_state *s, int num_irq) +void gic_init_irqs_and_distributor(GICState *s, int num_irq) { int i; @@ -657,7 +657,7 @@ static int arm_gic_init(SysBusDevice *dev) { /* Device instance init function for the GIC sysbus device */ int i; - gic_state *s = FROM_SYSBUS(gic_state, dev); + GICState *s = FROM_SYSBUS(GICState, dev); ARMGICClass *agc = ARM_GIC_GET_CLASS(s); agc->parent_init(dev); @@ -701,7 +701,7 @@ static void arm_gic_class_init(ObjectClass *klass, void *data) static TypeInfo arm_gic_info = { .name = TYPE_ARM_GIC, .parent = TYPE_ARM_GIC_COMMON, - .instance_size = sizeof(gic_state), + .instance_size = sizeof(GICState), .class_init = arm_gic_class_init, .class_size = sizeof(ARMGICClass), }; diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 360e7823f7..8369309d21 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -22,7 +22,7 @@ static void gic_save(QEMUFile *f, void *opaque) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int i; int j; @@ -56,7 +56,7 @@ static void gic_save(QEMUFile *f, void *opaque) static int gic_load(QEMUFile *f, void *opaque, int version_id) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int i; int j; @@ -96,7 +96,7 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) static int arm_gic_common_init(SysBusDevice *dev) { - gic_state *s = FROM_SYSBUS(gic_state, dev); + GICState *s = FROM_SYSBUS(GICState, dev); int num_irq = s->num_irq; if (s->num_cpu > NCPU) { @@ -123,7 +123,7 @@ static int arm_gic_common_init(SysBusDevice *dev) static void arm_gic_common_reset(DeviceState *dev) { - gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev)); + GICState *s = FROM_SYSBUS(GICState, sysbus_from_qdev(dev)); int i; memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < s->num_cpu; i++) { @@ -147,13 +147,13 @@ static void arm_gic_common_reset(DeviceState *dev) } static Property arm_gic_common_properties[] = { - DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1), - DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32), + DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1), + DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32), /* Revision can be 1 or 2 for GIC architecture specification * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC. * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".) */ - DEFINE_PROP_UINT32("revision", gic_state, revision, 1), + DEFINE_PROP_UINT32("revision", GICState, revision, 1), DEFINE_PROP_END_OF_LIST(), }; @@ -170,7 +170,7 @@ static void arm_gic_common_class_init(ObjectClass *klass, void *data) static TypeInfo arm_gic_common_type = { .name = TYPE_ARM_GIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(gic_state), + .instance_size = sizeof(GICState), .class_size = sizeof(ARMGICCommonClass), .class_init = arm_gic_common_class_init, .abstract = true, diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h index db4fad564f..699352ca8b 100644 --- a/hw/arm_gic_internal.h +++ b/hw/arm_gic_internal.h @@ -69,7 +69,7 @@ typedef struct gic_irq_state { unsigned trigger:1; /* nonzero = edge triggered. */ } gic_irq_state; -typedef struct gic_state { +typedef struct GICState { SysBusDevice busdev; qemu_irq parent_irq[NCPU]; int enabled; @@ -92,25 +92,25 @@ typedef struct gic_state { /* This is just so we can have an opaque pointer which identifies * both this GIC and which CPU interface we should be accessing. */ - struct gic_state *backref[NCPU]; + struct GICState *backref[NCPU]; MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */ uint32_t num_irq; uint32_t revision; -} gic_state; +} GICState; /* The special cases for the revision property: */ #define REV_11MPCORE 0 #define REV_NVIC 0xffffffff -void gic_set_pending_private(gic_state *s, int cpu, int irq); -uint32_t gic_acknowledge_irq(gic_state *s, int cpu); -void gic_complete_irq(gic_state *s, int cpu, int irq); -void gic_update(gic_state *s); -void gic_init_irqs_and_distributor(gic_state *s, int num_irq); +void gic_set_pending_private(GICState *s, int cpu, int irq); +uint32_t gic_acknowledge_irq(GICState *s, int cpu); +void gic_complete_irq(GICState *s, int cpu, int irq); +void gic_update(GICState *s); +void gic_init_irqs_and_distributor(GICState *s, int num_irq); #define TYPE_ARM_GIC_COMMON "arm_gic_common" #define ARM_GIC_COMMON(obj) \ - OBJECT_CHECK(gic_state, (obj), TYPE_ARM_GIC_COMMON) + OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC_COMMON) #define ARM_GIC_COMMON_CLASS(klass) \ OBJECT_CLASS_CHECK(ARMGICCommonClass, (klass), TYPE_ARM_GIC_COMMON) #define ARM_GIC_COMMON_GET_CLASS(obj) \ @@ -122,7 +122,7 @@ typedef struct ARMGICCommonClass { #define TYPE_ARM_GIC "arm_gic" #define ARM_GIC(obj) \ - OBJECT_CHECK(gic_state, (obj), TYPE_ARM_GIC) + OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC) #define ARM_GIC_CLASS(klass) \ OBJECT_CLASS_CHECK(ARMGICClass, (klass), TYPE_ARM_GIC) #define ARM_GIC_GET_CLASS(obj) \ diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 5c09116478..c449e08089 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -17,7 +17,7 @@ #include "arm_gic_internal.h" typedef struct { - gic_state gic; + GICState gic; struct { uint32_t control; uint32_t reload; @@ -505,9 +505,9 @@ static void armv7m_nvic_instance_init(Object *obj) * than our superclass. This function runs after qdev init * has set the defaults from the Property array and before * any user-specified property setting, so just modify the - * value in the gic_state struct. + * value in the GICState struct. */ - gic_state *s = ARM_GIC_COMMON(obj); + GICState *s = ARM_GIC_COMMON(obj); /* The ARM v7m may have anything from 0 to 496 external interrupt * IRQ lines. We default to 64. Other boards may differ and should * set the num-irq property appropriately. diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c index dd02f86eb9..77b6976eda 100644 --- a/hw/cadence_ttc.c +++ b/hw/cadence_ttc.c @@ -274,6 +274,7 @@ static uint32_t cadence_ttc_read_imp(void *opaque, target_phys_addr_t offset) /* cleared after read */ value = s->reg_intr; s->reg_intr = 0; + cadence_timer_update(s); return value; case 0x60: /* interrupt enable */ @@ -355,7 +356,6 @@ static void cadence_ttc_write(void *opaque, target_phys_addr_t offset, case 0x54: /* interrupt register */ case 0x58: case 0x5c: - s->reg_intr &= (~value & 0xfff); break; case 0x60: /* interrupt enable */ diff --git a/hw/ds1338.c b/hw/ds1338.c index d590d9c007..b576d56438 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -12,39 +12,84 @@ #include "i2c.h" +/* Size of NVRAM including both the user-accessible area and the + * secondary register area. + */ +#define NVRAM_SIZE 64 + typedef struct { I2CSlave i2c; - time_t offset; - struct tm now; - uint8_t nvram[56]; - int ptr; - int addr_byte; + int64_t offset; + uint8_t nvram[NVRAM_SIZE]; + int32_t ptr; + bool addr_byte; } DS1338State; +static const VMStateDescription vmstate_ds1338 = { + .name = "ds1338", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_I2C_SLAVE(i2c, DS1338State), + VMSTATE_INT64(offset, DS1338State), + VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE), + VMSTATE_INT32(ptr, DS1338State), + VMSTATE_BOOL(addr_byte, DS1338State), + VMSTATE_END_OF_LIST() + } +}; + +static void capture_current_time(DS1338State *s) +{ + /* Capture the current time into the secondary registers + * which will be actually read by the data transfer operation. + */ + struct tm now; + qemu_get_timedate(&now, s->offset); + s->nvram[0] = to_bcd(now.tm_sec); + s->nvram[1] = to_bcd(now.tm_min); + if (s->nvram[2] & 0x40) { + s->nvram[2] = (to_bcd((now.tm_hour % 12)) + 1) | 0x40; + if (now.tm_hour >= 12) { + s->nvram[2] |= 0x20; + } + } else { + s->nvram[2] = to_bcd(now.tm_hour); + } + s->nvram[3] = to_bcd(now.tm_wday) + 1; + s->nvram[4] = to_bcd(now.tm_mday); + s->nvram[5] = to_bcd(now.tm_mon) + 1; + s->nvram[6] = to_bcd(now.tm_year - 100); +} + +static void inc_regptr(DS1338State *s) +{ + /* The register pointer wraps around after 0x3F; wraparound + * causes the current time/date to be retransferred into + * the secondary registers. + */ + s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1); + if (!s->ptr) { + capture_current_time(s); + } +} + static void ds1338_event(I2CSlave *i2c, enum i2c_event event) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); switch (event) { case I2C_START_RECV: - qemu_get_timedate(&s->now, s->offset); - s->nvram[0] = to_bcd(s->now.tm_sec); - s->nvram[1] = to_bcd(s->now.tm_min); - if (s->nvram[2] & 0x40) { - s->nvram[2] = (to_bcd((s->now.tm_hour % 12)) + 1) | 0x40; - if (s->now.tm_hour >= 12) { - s->nvram[2] |= 0x20; - } - } else { - s->nvram[2] = to_bcd(s->now.tm_hour); - } - s->nvram[3] = to_bcd(s->now.tm_wday) + 1; - s->nvram[4] = to_bcd(s->now.tm_mday); - s->nvram[5] = to_bcd(s->now.tm_mon) + 1; - s->nvram[6] = to_bcd(s->now.tm_year - 100); + /* In h/w, capture happens on any START condition, not just a + * START_RECV, but there is no need to actually capture on + * START_SEND, because the guest can't get at that data + * without going through a START_RECV which would overwrite it. + */ + capture_current_time(s); break; case I2C_START_SEND: - s->addr_byte = 1; + s->addr_byte = true; break; default: break; @@ -57,7 +102,7 @@ static int ds1338_recv(I2CSlave *i2c) uint8_t res; res = s->nvram[s->ptr]; - s->ptr = (s->ptr + 1) & 0xff; + inc_regptr(s); return res; } @@ -65,20 +110,20 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); if (s->addr_byte) { - s->ptr = data; - s->addr_byte = 0; + s->ptr = data & (NVRAM_SIZE - 1); + s->addr_byte = false; return 0; } - s->nvram[s->ptr - 8] = data; - if (data < 8) { - qemu_get_timedate(&s->now, s->offset); - switch(data) { + if (s->ptr < 8) { + struct tm now; + qemu_get_timedate(&now, s->offset); + switch(s->ptr) { case 0: /* TODO: Implement CH (stop) bit. */ - s->now.tm_sec = from_bcd(data & 0x7f); + now.tm_sec = from_bcd(data & 0x7f); break; case 1: - s->now.tm_min = from_bcd(data & 0x7f); + now.tm_min = from_bcd(data & 0x7f); break; case 2: if (data & 0x40) { @@ -90,27 +135,29 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) } else { data = from_bcd(data); } - s->now.tm_hour = data; + now.tm_hour = data; break; case 3: - s->now.tm_wday = from_bcd(data & 7) - 1; + now.tm_wday = from_bcd(data & 7) - 1; break; case 4: - s->now.tm_mday = from_bcd(data & 0x3f); + now.tm_mday = from_bcd(data & 0x3f); break; case 5: - s->now.tm_mon = from_bcd(data & 0x1f) - 1; + now.tm_mon = from_bcd(data & 0x1f) - 1; break; case 6: - s->now.tm_year = from_bcd(data) + 100; + now.tm_year = from_bcd(data) + 100; break; case 7: /* Control register. Currently ignored. */ break; } - s->offset = qemu_timedate_diff(&s->now); + s->offset = qemu_timedate_diff(&now); + } else { + s->nvram[s->ptr] = data; } - s->ptr = (s->ptr + 1) & 0xff; + inc_regptr(s); return 0; } @@ -121,12 +168,14 @@ static int ds1338_init(I2CSlave *i2c) static void ds1338_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); k->init = ds1338_init; k->event = ds1338_event; k->recv = ds1338_recv; k->send = ds1338_send; + dc->vmsd = &vmstate_ds1338; } static TypeInfo ds1338_info = { diff --git a/hw/e1000.c b/hw/e1000.c index ec3a7c4ecc..63fee10794 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1079,11 +1079,23 @@ static bool is_version_1(void *opaque, int version_id) return version_id == 1; } +static int e1000_post_load(void *opaque, int version_id) +{ + E1000State *s = opaque; + + /* nc.link_down can't be migrated, so infer link_down according + * to link status bit in mac_reg[STATUS] */ + s->nic->nc.link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0; + + return 0; +} + static const VMStateDescription vmstate_e1000 = { .name = "e1000", .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, + .post_load = e1000_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, E1000State), VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */ diff --git a/hw/pc_piix.c b/hw/pc_piix.c index fd5898fba6..82364ab0d5 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -371,6 +371,14 @@ static QEMUMachine pc_machine_v1_3 = { .driver = "ivshmem",\ .property = "use64",\ .value = "0",\ + },{\ + .driver = "qxl",\ + .property = "revision",\ + .value = stringify(3),\ + },{\ + .driver = "qxl-vga",\ + .property = "revision",\ + .value = stringify(3),\ } static QEMUMachine pc_machine_v1_2 = { diff --git a/hw/qxl-render.c b/hw/qxl-render.c index e2e3fe2d37..b66c168ef6 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -99,7 +99,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) { VGACommonState *vga = &qxl->vga; int i; - DisplaySurface *surface = vga->ds->surface; if (qxl->guest_primary.resized) { qxl->guest_primary.resized = 0; @@ -112,9 +111,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.qxl_stride, qxl->guest_primary.bytes_pp, qxl->guest_primary.bits_pp); - } - if (surface->width != qxl->guest_primary.surface.width || - surface->height != qxl->guest_primary.surface.height) { if (qxl->guest_primary.qxl_stride > 0) { qemu_free_displaysurface(vga->ds); qemu_create_displaysurface_from(qxl->guest_primary.surface.width, @@ -29,11 +29,6 @@ #include "qxl.h" -#ifndef CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC -/* spice-protocol is too old, add missing definitions */ -#define QXL_IO_MONITORS_CONFIG_ASYNC (QXL_IO_FLUSH_RELEASE + 1) -#endif - /* * 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 @@ -262,9 +257,6 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) { trace_qxl_spice_monitors_config(qxl->id); -/* 0x000b01 == 0.11.1 */ -#if SPICE_SERVER_VERSION >= 0x000b01 && \ - defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC) if (replay) { /* * don't use QXL_COOKIE_TYPE_IO: @@ -286,10 +278,6 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, QXL_IO_MONITORS_CONFIG_ASYNC)); } -#else - fprintf(stderr, "qxl: too old spice-protocol/spice-server for " - "QXL_IO_MONITORS_CONFIG_ASYNC\n"); -#endif } void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) @@ -948,8 +936,6 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) } } -#if SPICE_SERVER_VERSION >= 0x000b04 - /* called from spice server thread context only */ static void interface_set_client_capabilities(QXLInstance *sin, uint8_t client_present, @@ -971,11 +957,6 @@ static void interface_set_client_capabilities(QXLInstance *sin, qxl_send_events(qxl, QXL_INTERRUPT_CLIENT); } -#endif - -#if defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) \ - && SPICE_SERVER_VERSION >= 0x000b05 - static uint32_t qxl_crc32(const uint8_t *p, unsigned len) { /* @@ -1044,7 +1025,6 @@ static int interface_client_monitors_config(QXLInstance *sin, qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG); return 1; } -#endif static const QXLInterface qxl_interface = { .base.type = SPICE_INTERFACE_QXL, @@ -1067,13 +1047,8 @@ static const QXLInterface qxl_interface = { .flush_resources = interface_flush_resources, .async_complete = interface_async_complete, .update_area_complete = interface_update_area_complete, -#if SPICE_SERVER_VERSION >= 0x000b04 .set_client_capabilities = interface_set_client_capabilities, -#endif -#if SPICE_SERVER_VERSION >= 0x000b05 && \ - defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) .client_monitors_config = interface_client_monitors_config, -#endif }; static void qxl_enter_vga_mode(PCIQXLDevice *d) @@ -1461,12 +1436,12 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, qxl_async_io async = QXL_SYNC; uint32_t orig_io_port = io_port; - if (d->guest_bug && !io_port == QXL_IO_RESET) { + if (d->guest_bug && io_port != QXL_IO_RESET) { return; } if (d->revision <= QXL_REVISION_STABLE_V10 && - io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) { + io_port > QXL_IO_FLUSH_RELEASE) { qxl_set_guest_bug(d, "unsupported io %d for revision %d\n", io_port, d->revision); return; @@ -1547,20 +1522,13 @@ async_common: if (d->ram->update_surface > d->ssd.num_surfaces) { qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", d->ram->update_surface); - return; + break; } - if (update.left >= update.right || update.top >= update.bottom) { + if (update.left >= update.right || update.top >= update.bottom || + update.left < 0 || update.top < 0) { qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n", update.left, update.top, update.right, update.bottom); - return; - } - - if (update.left < 0 || update.top < 0 || update.left >= update.right || - update.top >= update.bottom) { - qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " - "invalid area(%d,%d,%d,%d)\n", update.left, - update.right, update.top, update.bottom); break; } if (async == QXL_ASYNC) { @@ -1811,7 +1779,7 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) static void qxl_dirty_surfaces(PCIQXLDevice *qxl) { - intptr_t vram_start; + uintptr_t vram_start; int i; if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { @@ -1822,7 +1790,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, qxl->shadow_rom.surface0_area_size); - vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); + vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); /* dirty the off-screen surfaces */ for (i = 0; i < qxl->ssd.num_surfaces; i++) { @@ -1854,7 +1822,6 @@ static void qxl_vm_change_state_handler(void *opaque, int running, RunState state) { PCIQXLDevice *qxl = opaque; - qemu_spice_vm_change_state_handler(&qxl->ssd, running, state); if (running) { /* @@ -1971,14 +1938,10 @@ static int qxl_init_common(PCIQXLDevice *qxl) pci_device_rev = QXL_REVISION_STABLE_V10; io_size = 32; /* PCI region size must be pow2 */ break; -/* 0x000b01 == 0.11.1 */ -#if SPICE_SERVER_VERSION >= 0x000b01 && \ - defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC) case 4: /* qxl-4 */ pci_device_rev = QXL_REVISION_STABLE_V12; io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); break; -#endif default: error_report("Invalid revision %d for qxl device (max %d)", qxl->revision, QXL_DEFAULT_REVISION); @@ -2044,7 +2007,11 @@ static int qxl_init_common(PCIQXLDevice *qxl) qxl->ssd.qxl.base.sif = &qxl_interface.base; qxl->ssd.qxl.id = qxl->id; - qemu_spice_add_interface(&qxl->ssd.qxl.base); + if (qemu_spice_add_interface(&qxl->ssd.qxl.base) != 0) { + error_report("qxl interface %d.%d not supported by spice-server\n", + SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR); + return -1; + } qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl); init_pipe_signaling(qxl); @@ -129,12 +129,7 @@ typedef struct PCIQXLDevice { } \ } while (0) -#if 0 -/* spice-server 0.12 is still in development */ #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12 -#else -#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 -#endif /* qxl.c */ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); diff --git a/hw/rtl8139.c b/hw/rtl8139.c index b7c82ee027..6b28fea96a 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -167,7 +167,7 @@ enum IntrStatusBits { PCIErr = 0x8000, PCSTimeout = 0x4000, RxFIFOOver = 0x40, - RxUnderrun = 0x20, + RxUnderrun = 0x20, /* Packet Underrun / Link Change */ RxOverflow = 0x10, TxErr = 0x08, TxOK = 0x04, @@ -3003,7 +3003,8 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) break; case MediaStatus: - ret = 0xd0; + /* The LinkDown bit of MediaStatus is inverse with link status */ + ret = 0xd0 | (~s->BasicModeStatus & 0x04); DPRINTF("MediaStatus read 0x%x\n", ret); break; @@ -3258,6 +3259,10 @@ static int rtl8139_post_load(void *opaque, int version_id) s->cplus_enabled = s->CpCmd != 0; } + /* nc.link_down can't be migrated, so infer link_down according + * to link status bit in BasicModeStatus */ + s->nic->nc.link_down = (s->BasicModeStatus & 0x04) == 0; + return 0; } @@ -3449,12 +3454,27 @@ static void pci_rtl8139_uninit(PCIDevice *dev) qemu_del_net_client(&s->nic->nc); } +static void rtl8139_set_link_status(NetClientState *nc) +{ + RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; + + if (nc->link_down) { + s->BasicModeStatus &= ~0x04; + } else { + s->BasicModeStatus |= 0x04; + } + + s->IntrStatus |= RxUnderrun; + rtl8139_update_irq(s); +} + static NetClientInfo net_rtl8139_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = rtl8139_can_receive, .receive = rtl8139_receive, .cleanup = rtl8139_cleanup, + .link_status_changed = rtl8139_set_link_status, }; static int pci_rtl8139_init(PCIDevice *dev) diff --git a/hw/sun4m.c b/hw/sun4m.c index c98cd5ec3f..a04b485eda 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -253,8 +253,10 @@ void cpu_check_irqs(CPUSPARCState *env) } } -static void cpu_kick_irq(CPUSPARCState *env) +static void cpu_kick_irq(SPARCCPU *cpu) { + CPUSPARCState *env = &cpu->env; + env->halted = 0; cpu_check_irqs(env); qemu_cpu_kick(env); @@ -262,12 +264,13 @@ static void cpu_kick_irq(CPUSPARCState *env) static void cpu_set_irq(void *opaque, int irq, int level) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; if (level) { trace_sun4m_cpu_set_irq_raise(irq); env->pil_in |= 1 << irq; - cpu_kick_irq(env); + cpu_kick_irq(cpu); } else { trace_sun4m_cpu_set_irq_lower(irq); env->pil_in &= ~(1 << irq); @@ -840,7 +843,7 @@ static void cpu_devinit(const char *cpu_model, unsigned int id, qemu_register_reset(secondary_cpu_reset, cpu); env->halted = 1; } - *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); + *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS); env->prom_addr = prom_addr; } diff --git a/hw/sun4u.c b/hw/sun4u.c index 137a7c6666..940db3348a 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -310,8 +310,10 @@ void cpu_check_irqs(CPUSPARCState *env) } } -static void cpu_kick_irq(CPUSPARCState *env) +static void cpu_kick_irq(SPARCCPU *cpu) { + CPUSPARCState *env = &cpu->env; + env->halted = 0; cpu_check_irqs(env); qemu_cpu_kick(env); @@ -319,7 +321,8 @@ static void cpu_kick_irq(CPUSPARCState *env) static void cpu_set_ivec_irq(void *opaque, int irq, int level) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; if (level) { if (!(env->ivec_status & 0x20)) { @@ -366,7 +369,7 @@ void cpu_get_timer(QEMUFile *f, CPUTimer *s) qemu_get_timer(f, s->qtimer); } -static CPUTimer* cpu_timer_create(const char* name, CPUSPARCState *env, +static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, QEMUBHFunc *cb, uint32_t frequency, uint64_t disabled_mask) { @@ -379,7 +382,7 @@ static CPUTimer* cpu_timer_create(const char* name, CPUSPARCState *env, timer->disabled = 1; timer->clock_offset = qemu_get_clock_ns(vm_clock); - timer->qtimer = qemu_new_timer_ns(vm_clock, cb, env); + timer->qtimer = qemu_new_timer_ns(vm_clock, cb, cpu); return timer; } @@ -418,7 +421,8 @@ static void main_cpu_reset(void *opaque) static void tick_irq(void *opaque) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; CPUTimer* timer = env->tick; @@ -430,12 +434,13 @@ static void tick_irq(void *opaque) } env->softint |= SOFTINT_TIMER; - cpu_kick_irq(env); + cpu_kick_irq(cpu); } static void stick_irq(void *opaque) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; CPUTimer* timer = env->stick; @@ -447,12 +452,13 @@ static void stick_irq(void *opaque) } env->softint |= SOFTINT_STIMER; - cpu_kick_irq(env); + cpu_kick_irq(cpu); } static void hstick_irq(void *opaque) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; CPUTimer* timer = env->hstick; @@ -464,7 +470,7 @@ static void hstick_irq(void *opaque) } env->softint |= SOFTINT_STIMER; - cpu_kick_irq(env); + cpu_kick_irq(cpu); } static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency) @@ -772,13 +778,13 @@ static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) } env = &cpu->env; - env->tick = cpu_timer_create("tick", env, tick_irq, + env->tick = cpu_timer_create("tick", cpu, tick_irq, tick_frequency, TICK_NPT_MASK); - env->stick = cpu_timer_create("stick", env, stick_irq, + env->stick = cpu_timer_create("stick", cpu, stick_irq, stick_frequency, TICK_INT_DIS); - env->hstick = cpu_timer_create("hstick", env, hstick_irq, + env->hstick = cpu_timer_create("hstick", cpu, hstick_irq, hstick_frequency, TICK_INT_DIS); reset_info = g_malloc0(sizeof(ResetData)); @@ -797,7 +803,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem, const struct hwdef *hwdef) { SPARCCPU *cpu; - CPUSPARCState *env; M48t59State *nvram; unsigned int i; uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; @@ -810,14 +815,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem, /* init CPUs */ cpu = cpu_devinit(cpu_model, hwdef); - env = &cpu->env; /* set up devices */ ram_init(0, RAM_size); prom_init(hwdef->prom_addr, bios_name); - ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX); + ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX); pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, &pci_bus3, &pbm_irqs); pci_vga_init(pci_bus); diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index cdc8bc3fba..c2f08e3735 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -826,8 +826,16 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, USBEndpoint *ep; /* Is active ? */ - if (!(td->ctrl & TD_CTRL_ACTIVE)) + if (!(td->ctrl & TD_CTRL_ACTIVE)) { + /* + * ehci11d spec page 22: "Even if the Active bit in the TD is already + * cleared when the TD is fetched ... an IOC interrupt is generated" + */ + if (td->ctrl & TD_CTRL_IOC) { + *int_mask |= 0x01; + } return TD_RESULT_NEXT_QH; + } async = uhci_async_find_td(s, addr, td); if (async) { diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index b10241a139..2283565b0c 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -862,15 +862,11 @@ static void usbredir_chardev_close_bh(void *opaque) } } -static void usbredir_chardev_open(USBRedirDevice *dev) +static void usbredir_create_parser(USBRedirDevice *dev) { uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; int flags = 0; - /* Make sure any pending closes are handled (no-op if none pending) */ - usbredir_chardev_close_bh(dev); - qemu_bh_cancel(dev->chardev_close_bh); - DPRINTF("creating usbredirparser\n"); dev->parser = qemu_oom_check(usbredirparser_create()); @@ -982,7 +978,10 @@ static void usbredir_chardev_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: DPRINTF("chardev open\n"); - usbredir_chardev_open(dev); + /* Make sure any pending closes are handled (no-op if none pending) */ + usbredir_chardev_close_bh(dev); + qemu_bh_cancel(dev->chardev_close_bh); + usbredir_create_parser(dev); break; case CHR_EVENT_CLOSED: DPRINTF("chardev close\n"); @@ -1615,12 +1614,17 @@ static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) } /* - * Our chardev should be open already at this point, otherwise - * the usbredir channel will be broken (ie spice without seamless) + * If our chardev is not open already at this point the usbredir connection + * has been broken (non seamless migration, or restore from disk). + * + * In this case create a temporary parser to receive the migration data, + * and schedule the close_bh to report the device as disconnected to the + * guest and to destroy the parser again. */ if (dev->parser == NULL) { - ERROR("get_parser called with closed chardev, failing migration\n"); - return -1; + WARNING("usb-redir connection broken during migration\n"); + usbredir_create_parser(dev); + qemu_bh_schedule(dev->chardev_close_bh); } data = g_malloc(len); diff --git a/hw/versatilepb.c b/hw/versatilepb.c index b3f8077146..7b1b0256aa 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -266,6 +266,11 @@ static void versatile_init(ram_addr_t ram_size, sysbus_create_simple("sp804", 0x101e2000, pic[4]); sysbus_create_simple("sp804", 0x101e3000, pic[5]); + sysbus_create_simple("pl061", 0x101e4000, pic[6]); + sysbus_create_simple("pl061", 0x101e5000, pic[7]); + sysbus_create_simple("pl061", 0x101e6000, pic[8]); + sysbus_create_simple("pl061", 0x101e7000, pic[9]); + /* The versatile/PB actually has a modified Color LCD controller that includes hardware cursor support from the PL111. */ dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]); diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index a1eeced8fd..639371e7a2 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -33,9 +33,11 @@ #include "memory.h" #include "msi.h" #include "msix.h" +#include "pci.h" +#include "qemu-common.h" #include "qemu-error.h" +#include "qemu-queue.h" #include "range.h" -#include "vfio_pci_int.h" /* #define DEBUG_VFIO */ #ifdef DEBUG_VFIO @@ -46,6 +48,99 @@ do { } while (0) #endif +typedef struct VFIOBAR { + off_t fd_offset; /* offset of BAR within device fd */ + int fd; /* device fd, allows us to pass VFIOBAR as opaque data */ + MemoryRegion mem; /* slow, read/write access */ + MemoryRegion mmap_mem; /* direct mapped access */ + void *mmap; + size_t size; + uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ + uint8_t nr; /* cache the BAR number for debug */ +} VFIOBAR; + +typedef struct VFIOINTx { + bool pending; /* interrupt pending */ + bool kvm_accel; /* set when QEMU bypass through KVM enabled */ + uint8_t pin; /* which pin to pull for qemu_set_irq */ + EventNotifier interrupt; /* eventfd triggered on interrupt */ + EventNotifier unmask; /* eventfd for unmask on QEMU bypass */ + PCIINTxRoute route; /* routing info for QEMU bypass */ + uint32_t mmap_timeout; /* delay to re-enable mmaps after interrupt */ + QEMUTimer *mmap_timer; /* enable mmaps after periods w/o interrupts */ +} VFIOINTx; + +struct VFIODevice; + +typedef struct VFIOMSIVector { + EventNotifier interrupt; /* eventfd triggered on interrupt */ + struct VFIODevice *vdev; /* back pointer to device */ + int virq; /* KVM irqchip route for QEMU bypass */ + bool use; +} VFIOMSIVector; + +enum { + VFIO_INT_NONE = 0, + VFIO_INT_INTx = 1, + VFIO_INT_MSI = 2, + VFIO_INT_MSIX = 3, +}; + +struct VFIOGroup; + +typedef struct VFIOContainer { + int fd; /* /dev/vfio/vfio, empowered by the attached groups */ + struct { + /* enable abstraction to support various iommu backends */ + union { + MemoryListener listener; /* Used by type1 iommu */ + }; + void (*release)(struct VFIOContainer *); + } iommu_data; + QLIST_HEAD(, VFIOGroup) group_list; + QLIST_ENTRY(VFIOContainer) next; +} VFIOContainer; + +/* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */ +typedef struct VFIOMSIXInfo { + uint8_t table_bar; + uint8_t pba_bar; + uint16_t entries; + uint32_t table_offset; + uint32_t pba_offset; + MemoryRegion mmap_mem; + void *mmap; +} VFIOMSIXInfo; + +typedef struct VFIODevice { + PCIDevice pdev; + int fd; + VFIOINTx intx; + unsigned int config_size; + off_t config_offset; /* Offset of config space region within device fd */ + unsigned int rom_size; + off_t rom_offset; /* Offset of ROM region within device fd */ + int msi_cap_size; + VFIOMSIVector *msi_vectors; + VFIOMSIXInfo *msix; + int nr_vectors; /* Number of MSI/MSIX vectors currently in use */ + int interrupt; /* Current interrupt type */ + VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */ + PCIHostDeviceAddress host; + QLIST_ENTRY(VFIODevice) next; + struct VFIOGroup *group; + bool reset_works; +} VFIODevice; + +typedef struct VFIOGroup { + int fd; + int groupid; + VFIOContainer *container; + QLIST_HEAD(, VFIODevice) device_list; + QLIST_ENTRY(VFIOGroup) next; + QLIST_ENTRY(VFIOGroup) container_next; +} VFIOGroup; + #define MSIX_CAP_LENGTH 12 static QLIST_HEAD(, VFIOContainer) @@ -72,8 +167,6 @@ static void vfio_disable_irqindex(VFIODevice *vdev, int index) }; ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); - - vdev->interrupt = VFIO_INT_NONE; } /* @@ -92,6 +185,34 @@ static void vfio_unmask_intx(VFIODevice *vdev) ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); } +/* + * Disabling BAR mmaping can be slow, but toggling it around INTx can + * also be a huge overhead. We try to get the best of both worlds by + * waiting until an interrupt to disable mmaps (subsequent transitions + * to the same state are effectively no overhead). If the interrupt has + * been serviced and the time gap is long enough, we re-enable mmaps for + * performance. This works well for things like graphics cards, which + * may not use their interrupt at all and are penalized to an unusable + * level by read/write BAR traps. Other devices, like NICs, have more + * regular interrupts and see much better latency by staying in non-mmap + * mode. We therefore set the default mmap_timeout such that a ping + * is just enough to keep the mmap disabled. Users can experiment with + * other options with the x-intx-mmap-timeout-ms parameter (a value of + * zero disables the timer). + */ +static void vfio_intx_mmap_enable(void *opaque) +{ + VFIODevice *vdev = opaque; + + if (vdev->intx.pending) { + qemu_mod_timer(vdev->intx.mmap_timer, + qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout); + return; + } + + vfio_mmap_set_enabled(vdev, true); +} + static void vfio_intx_interrupt(void *opaque) { VFIODevice *vdev = opaque; @@ -106,6 +227,11 @@ static void vfio_intx_interrupt(void *opaque) vdev->intx.pending = true; qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 1); + vfio_mmap_set_enabled(vdev, false); + if (vdev->intx.mmap_timeout) { + qemu_mod_timer(vdev->intx.mmap_timer, + qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout); + } } static void vfio_eoi(VFIODevice *vdev) @@ -122,26 +248,14 @@ static void vfio_eoi(VFIODevice *vdev) vfio_unmask_intx(vdev); } -typedef struct QEMU_PACKED VFIOIRQSetFD { - struct vfio_irq_set irq_set; - int32_t fd; -} VFIOIRQSetFD; - static int vfio_enable_intx(VFIODevice *vdev) { - VFIOIRQSetFD irq_set_fd = { - .irq_set = { - .argsz = sizeof(irq_set_fd), - .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER, - .index = VFIO_PCI_INTX_IRQ_INDEX, - .start = 0, - .count = 1, - }, - }; uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1); - int ret; + int ret, argsz; + struct vfio_irq_set *irq_set; + int32_t *pfd; - if (vdev->intx.disabled || !pin) { + if (!pin) { return 0; } @@ -154,24 +268,28 @@ static int vfio_enable_intx(VFIODevice *vdev) return ret; } - irq_set_fd.fd = event_notifier_get_fd(&vdev->intx.interrupt); - qemu_set_fd_handler(irq_set_fd.fd, vfio_intx_interrupt, NULL, vdev); + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_INTX_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = event_notifier_get_fd(&vdev->intx.interrupt); + qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev); - if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set_fd)) { + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); + if (ret) { error_report("vfio: Error: Failed to setup INTx fd: %m\n"); + qemu_set_fd_handler(*pfd, NULL, NULL, vdev); + event_notifier_cleanup(&vdev->intx.interrupt); return -errno; } - /* - * Disable mmaps so we can trap on BAR accesses. We interpret any - * access as a response to an interrupt and unmask the physical - * device. The device will re-assert if the interrupt is still - * pending. We'll likely retrigger on the host multiple times per - * guest interrupt, but without EOI notification it's better than - * nothing. Acceleration paths through KVM will avoid this. - */ - vfio_mmap_set_enabled(vdev, false); - vdev->interrupt = VFIO_INT_INTx; DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, @@ -184,6 +302,7 @@ static void vfio_disable_intx(VFIODevice *vdev) { int fd; + qemu_del_timer(vdev->intx.mmap_timer); vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); vdev->intx.pending = false; qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); @@ -254,10 +373,6 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix) g_free(irq_set); - if (!ret) { - vdev->interrupt = msix ? VFIO_INT_MSIX : VFIO_INT_MSI; - } - return ret; } @@ -272,15 +387,6 @@ static int vfio_msix_vector_use(PCIDevice *pdev, vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function, nr); - if (vdev->interrupt != VFIO_INT_MSIX) { - vfio_disable_interrupts(vdev); - } - - if (!vdev->msi_vectors) { - vdev->msi_vectors = g_malloc0(vdev->msix->entries * - sizeof(VFIOMSIVector)); - } - vector = &vdev->msi_vectors[nr]; vector->vdev = vdev; vector->use = true; @@ -313,43 +419,35 @@ static int vfio_msix_vector_use(PCIDevice *pdev, * increase them as needed. */ if (vdev->nr_vectors < nr + 1) { - int i; - vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX); vdev->nr_vectors = nr + 1; ret = vfio_enable_vectors(vdev, true); if (ret) { error_report("vfio: failed to enable vectors, %d\n", ret); } - - /* We don't know if we've missed interrupts in the interim... */ - for (i = 0; i < vdev->msix->entries; i++) { - if (vdev->msi_vectors[i].use) { - msix_notify(&vdev->pdev, i); - } - } } else { - VFIOIRQSetFD irq_set_fd = { - .irq_set = { - .argsz = sizeof(irq_set_fd), - .flags = VFIO_IRQ_SET_DATA_EVENTFD | - VFIO_IRQ_SET_ACTION_TRIGGER, - .index = VFIO_PCI_MSIX_IRQ_INDEX, - .start = nr, - .count = 1, - }, - .fd = event_notifier_get_fd(&vector->interrupt), - }; - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set_fd); + int argsz; + struct vfio_irq_set *irq_set; + int32_t *pfd; + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = nr; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = event_notifier_get_fd(&vector->interrupt); + + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); if (ret) { error_report("vfio: failed to modify vector, %d\n", ret); } - - /* - * If we were connected to the hardware PBA we could skip this, - * until then, a spurious interrupt is better than starvation. - */ - msix_notify(&vdev->pdev, nr); } return 0; @@ -359,17 +457,9 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) { VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); VFIOMSIVector *vector = &vdev->msi_vectors[nr]; - VFIOIRQSetFD irq_set_fd = { - .irq_set = { - .argsz = sizeof(irq_set_fd), - .flags = VFIO_IRQ_SET_DATA_EVENTFD | - VFIO_IRQ_SET_ACTION_TRIGGER, - .index = VFIO_PCI_MSIX_IRQ_INDEX, - .start = nr, - .count = 1, - }, - .fd = -1, - }; + int argsz; + struct vfio_irq_set *irq_set; + int32_t *pfd; DPRINTF("%s(%04x:%02x:%02x.%x) vector %d released\n", __func__, vdev->host.domain, vdev->host.bus, vdev->host.slot, @@ -381,7 +471,23 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) * bouncing through userspace and let msix.c drop it? Not sure. */ msix_vector_unuse(pdev, nr); - ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set_fd); + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = nr; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = -1; + + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + + g_free(irq_set); if (vector->virq < 0) { qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), @@ -419,18 +525,21 @@ static MSIMessage msi_get_msg(PCIDevice *pdev, unsigned int vector) return msg; } -/* So should this */ -static void msi_set_qsize(PCIDevice *pdev, uint8_t size) +static void vfio_enable_msix(VFIODevice *vdev) { - uint8_t *config = pdev->config + pdev->msi_cap; - uint16_t flags; - - flags = pci_get_word(config + PCI_MSI_FLAGS); - flags = le16_to_cpu(flags); - flags &= ~PCI_MSI_FLAGS_QSIZE; - flags |= (size & 0x7) << 4; - flags = cpu_to_le16(flags); - pci_set_word(config + PCI_MSI_FLAGS, flags); + vfio_disable_interrupts(vdev); + + vdev->msi_vectors = g_malloc0(vdev->msix->entries * sizeof(VFIOMSIVector)); + + vdev->interrupt = VFIO_INT_MSIX; + + if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, + vfio_msix_vector_release)) { + error_report("vfio: msix_set_vector_notifiers failed\n"); + } + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); } static void vfio_enable_msi(VFIODevice *vdev) @@ -503,19 +612,43 @@ retry: return; } - msi_set_qsize(&vdev->pdev, vdev->nr_vectors); + vdev->interrupt = VFIO_INT_MSI; DPRINTF("%s(%04x:%02x:%02x.%x) Enabled %d MSI vectors\n", __func__, vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function, vdev->nr_vectors); } -static void vfio_disable_msi_x(VFIODevice *vdev, bool msix) +static void vfio_disable_msi_common(VFIODevice *vdev) +{ + g_free(vdev->msi_vectors); + vdev->msi_vectors = NULL; + vdev->nr_vectors = 0; + vdev->interrupt = VFIO_INT_NONE; + + vfio_enable_intx(vdev); +} + +static void vfio_disable_msix(VFIODevice *vdev) +{ + msix_unset_vector_notifiers(&vdev->pdev); + + if (vdev->nr_vectors) { + vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX); + } + + vfio_disable_msi_common(vdev); + + DPRINTF("%s(%04x:%02x:%02x.%x, msi%s)\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, msix ? "x" : ""); +} + +static void vfio_disable_msi(VFIODevice *vdev) { int i; - vfio_disable_irqindex(vdev, msix ? VFIO_PCI_MSIX_IRQ_INDEX : - VFIO_PCI_MSI_IRQ_INDEX); + vfio_disable_irqindex(vdev, VFIO_PCI_MSI_IRQ_INDEX); for (i = 0; i < vdev->nr_vectors; i++) { VFIOMSIVector *vector = &vdev->msi_vectors[i]; @@ -534,26 +667,13 @@ static void vfio_disable_msi_x(VFIODevice *vdev, bool msix) NULL, NULL, NULL); } - if (msix) { - msix_vector_unuse(&vdev->pdev, i); - } - event_notifier_cleanup(&vector->interrupt); } - g_free(vdev->msi_vectors); - vdev->msi_vectors = NULL; - vdev->nr_vectors = 0; - - if (!msix) { - msi_set_qsize(&vdev->pdev, 0); /* Actually still means 1 vector */ - } - - DPRINTF("%s(%04x:%02x:%02x.%x, msi%s)\n", __func__, - vdev->host.domain, vdev->host.bus, vdev->host.slot, - vdev->host.function, msix ? "x" : ""); + vfio_disable_msi_common(vdev); - vfio_enable_intx(vdev); + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); } /* @@ -601,7 +721,7 @@ static void vfio_bar_write(void *opaque, target_phys_addr_t addr, * which access will service the interrupt, so we're potentially * getting quite a few host interrupts per guest interrupt. */ - vfio_eoi(DO_UPCAST(VFIODevice, bars[bar->nr], bar)); + vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr])); } static uint64_t vfio_bar_read(void *opaque, @@ -641,7 +761,7 @@ static uint64_t vfio_bar_read(void *opaque, __func__, bar->nr, addr, size, data); /* Same as write above */ - vfio_eoi(DO_UPCAST(VFIODevice, bars[bar->nr], bar)); + vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr])); return data; } @@ -739,7 +859,7 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, if (!was_enabled && is_enabled) { vfio_enable_msi(vdev); } else if (was_enabled && !is_enabled) { - vfio_disable_msi_x(vdev, false); + vfio_disable_msi(vdev); } } @@ -752,9 +872,9 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, is_enabled = msix_enabled(pdev); if (!was_enabled && is_enabled) { - /* vfio_msix_vector_use handles this automatically */ + vfio_enable_msix(vdev); } else if (was_enabled && !is_enabled) { - vfio_disable_msi_x(vdev, true); + vfio_disable_msix(vdev); } } } @@ -762,45 +882,52 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, /* * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86 */ -static int vfio_dma_map(VFIOContainer *container, target_phys_addr_t iova, - ram_addr_t size, void *vaddr, bool readonly) +static int vfio_dma_unmap(VFIOContainer *container, + target_phys_addr_t iova, ram_addr_t size) { - struct vfio_iommu_type1_dma_map map = { - .argsz = sizeof(map), - .flags = VFIO_DMA_MAP_FLAG_READ, - .vaddr = (__u64)(intptr_t)vaddr, + struct vfio_iommu_type1_dma_unmap unmap = { + .argsz = sizeof(unmap), + .flags = 0, .iova = iova, .size = size, }; - if (!readonly) { - map.flags |= VFIO_DMA_MAP_FLAG_WRITE; - } - - if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map)) { - DPRINTF("VFIO_MAP_DMA: %d\n", -errno); + if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { + DPRINTF("VFIO_UNMAP_DMA: %d\n", -errno); return -errno; } return 0; } -static int vfio_dma_unmap(VFIOContainer *container, - target_phys_addr_t iova, ram_addr_t size) +static int vfio_dma_map(VFIOContainer *container, target_phys_addr_t iova, + ram_addr_t size, void *vaddr, bool readonly) { - struct vfio_iommu_type1_dma_unmap unmap = { - .argsz = sizeof(unmap), - .flags = 0, + struct vfio_iommu_type1_dma_map map = { + .argsz = sizeof(map), + .flags = VFIO_DMA_MAP_FLAG_READ, + .vaddr = (__u64)(uintptr_t)vaddr, .iova = iova, .size = size, }; - if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { - DPRINTF("VFIO_UNMAP_DMA: %d\n", -errno); - return -errno; + if (!readonly) { + map.flags |= VFIO_DMA_MAP_FLAG_WRITE; } - return 0; + /* + * Try the mapping, if it fails with EBUSY, unmap the region and try + * again. This shouldn't be necessary, but we sometimes see it in + * the the VGA ROM space. + */ + if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 || + (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 && + ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) { + return 0; + } + + DPRINTF("VFIO_MAP_DMA: %d\n", -errno); + return -errno; } static void vfio_listener_dummy1(MemoryListener *listener) @@ -942,10 +1069,10 @@ static void vfio_disable_interrupts(VFIODevice *vdev) vfio_disable_intx(vdev); break; case VFIO_INT_MSI: - vfio_disable_msi_x(vdev, false); + vfio_disable_msi(vdev); break; case VFIO_INT_MSIX: - vfio_disable_msi_x(vdev, true); + vfio_disable_msix(vdev); break; } } @@ -956,14 +1083,6 @@ static int vfio_setup_msi(VFIODevice *vdev, int pos) bool msi_64bit, msi_maskbit; int ret, entries; - /* - * TODO: don't peek into msi_supported, let msi_init fail and - * check for ENOTSUP - */ - if (!msi_supported) { - return 0; - } - if (pread(vdev->fd, &ctrl, sizeof(ctrl), vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { return -errno; @@ -979,6 +1098,9 @@ static int vfio_setup_msi(VFIODevice *vdev, int pos) ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit); if (ret < 0) { + if (ret == -ENOTSUP) { + return 0; + } error_report("vfio: msi_init failed\n"); return ret; } @@ -1045,33 +1167,19 @@ static int vfio_setup_msix(VFIODevice *vdev, int pos) { int ret; - /* - * TODO: don't peek into msi_supported, let msix_init fail and - * check for ENOTSUP - */ - if (!msi_supported) { - return 0; - } - ret = msix_init(&vdev->pdev, vdev->msix->entries, &vdev->bars[vdev->msix->table_bar].mem, vdev->msix->table_bar, vdev->msix->table_offset, &vdev->bars[vdev->msix->pba_bar].mem, vdev->msix->pba_bar, vdev->msix->pba_offset, pos); if (ret < 0) { + if (ret == -ENOTSUP) { + return 0; + } error_report("vfio: msix_init failed\n"); return ret; } - ret = msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, - vfio_msix_vector_release); - if (ret) { - error_report("vfio: msix_set_vector_notifiers failed %d\n", ret); - msix_uninit(&vdev->pdev, &vdev->bars[vdev->msix->table_bar].mem, - &vdev->bars[vdev->msix->pba_bar].mem); - return ret; - } - return 0; } @@ -1080,12 +1188,6 @@ static void vfio_teardown_msi(VFIODevice *vdev) msi_uninit(&vdev->pdev); if (vdev->msix) { - /* FIXME: Why can't unset just silently do nothing?? */ - if (vdev->pdev.msix_vector_use_notifier && - vdev->pdev.msix_vector_release_notifier) { - msix_unset_vector_notifiers(&vdev->pdev); - } - msix_uninit(&vdev->pdev, &vdev->bars[vdev->msix->table_bar].mem, &vdev->bars[vdev->msix->pba_bar].mem); } @@ -1766,17 +1868,8 @@ static int vfio_initfn(PCIDevice *pdev) } if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) { - if (vdev->intx.intx && strcmp(vdev->intx.intx, "off")) { - error_report("vfio: Unknown option x-intx=%s, " - "valid options: \"off\".\n", vdev->intx.intx); - ret = -EINVAL; - goto out_teardown; - } - - if (vdev->intx.intx && !strcmp(vdev->intx.intx, "off")) { - vdev->intx.disabled = true; - } - + vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock, + vfio_intx_mmap_enable, vdev); ret = vfio_enable_intx(vdev); if (ret) { goto out_teardown; @@ -1802,6 +1895,9 @@ static void vfio_exitfn(PCIDevice *pdev) pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); vfio_disable_interrupts(vdev); + if (vdev->intx.mmap_timer) { + qemu_free_timer(vdev->intx.mmap_timer); + } vfio_teardown_msi(vdev); vfio_unmap_bars(vdev); vfio_put_device(vdev); @@ -1812,21 +1908,37 @@ static void vfio_pci_reset(DeviceState *dev) { PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev); VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + uint16_t cmd; - if (!vdev->reset_works) { - return; - } + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + vfio_disable_interrupts(vdev); - if (ioctl(vdev->fd, VFIO_DEVICE_RESET)) { - error_report("vfio: Error unable to reset physical device " - "(%04x:%02x:%02x.%x): %m\n", vdev->host.domain, - vdev->host.bus, vdev->host.slot, vdev->host.function); + /* + * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master. + * Also put INTx Disable in known state. + */ + cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2); + cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INTX_DISABLE); + vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2); + + if (vdev->reset_works) { + if (ioctl(vdev->fd, VFIO_DEVICE_RESET)) { + error_report("vfio: Error unable to reset physical device " + "(%04x:%02x:%02x.%x): %m\n", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + } } + + vfio_enable_intx(vdev); } static Property vfio_pci_dev_properties[] = { DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host), - DEFINE_PROP_STRING("x-intx", VFIODevice, intx.intx), + DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice, + intx.mmap_timeout, 1100), /* * TODO - support passed fds... is this necessary? * DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name), diff --git a/hw/vfio_pci_int.h b/hw/vfio_pci_int.h deleted file mode 100644 index 3812d8d7f1..0000000000 --- a/hw/vfio_pci_int.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * vfio based device assignment support - * - * Copyright Red Hat, Inc. 2012 - * - * Authors: - * Alex Williamson <alex.williamson@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - */ - -#ifndef HW_VFIO_PCI_INT_H -#define HW_VFIO_PCI_INT_H - -#include "qemu-common.h" -#include "qemu-queue.h" -#include "pci.h" -#include "event_notifier.h" - -typedef struct VFIOBAR { - off_t fd_offset; /* offset of BAR within device fd */ - int fd; /* device fd, allows us to pass VFIOBAR as opaque data */ - MemoryRegion mem; /* slow, read/write access */ - MemoryRegion mmap_mem; /* direct mapped access */ - void *mmap; - size_t size; - uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ - uint8_t nr; /* cache the BAR number for debug */ -} VFIOBAR; - -typedef struct VFIOINTx { - bool pending; /* interrupt pending */ - bool kvm_accel; /* set when QEMU bypass through KVM enabled */ - uint8_t pin; /* which pin to pull for qemu_set_irq */ - EventNotifier interrupt; /* eventfd triggered on interrupt */ - EventNotifier unmask; /* eventfd for unmask on QEMU bypass */ - PCIINTxRoute route; /* routing info for QEMU bypass */ - bool disabled; - char *intx; -} VFIOINTx; - -struct VFIODevice; - -typedef struct VFIOMSIVector { - EventNotifier interrupt; /* eventfd triggered on interrupt */ - struct VFIODevice *vdev; /* back pointer to device */ - int virq; /* KVM irqchip route for QEMU bypass */ - bool use; -} VFIOMSIVector; - -enum { - VFIO_INT_NONE = 0, - VFIO_INT_INTx = 1, - VFIO_INT_MSI = 2, - VFIO_INT_MSIX = 3, -}; - -struct VFIOGroup; - -typedef struct VFIOContainer { - int fd; /* /dev/vfio/vfio, empowered by the attached groups */ - struct { - /* enable abstraction to support various iommu backends */ - union { - MemoryListener listener; /* Used by type1 iommu */ - }; - void (*release)(struct VFIOContainer *); - } iommu_data; - QLIST_HEAD(, VFIOGroup) group_list; - QLIST_ENTRY(VFIOContainer) next; -} VFIOContainer; - -/* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */ -typedef struct VFIOMSIXInfo { - uint8_t table_bar; - uint8_t pba_bar; - uint16_t entries; - uint32_t table_offset; - uint32_t pba_offset; - MemoryRegion mmap_mem; - void *mmap; -} VFIOMSIXInfo; - -typedef struct VFIODevice { - PCIDevice pdev; - int fd; - VFIOINTx intx; - unsigned int config_size; - off_t config_offset; /* Offset of config space region within device fd */ - unsigned int rom_size; - off_t rom_offset; /* Offset of ROM region within device fd */ - int msi_cap_size; - VFIOMSIVector *msi_vectors; - VFIOMSIXInfo *msix; - int nr_vectors; /* Number of MSI/MSIX vectors currently in use */ - int interrupt; /* Current interrupt type */ - VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */ - PCIHostDeviceAddress host; - QLIST_ENTRY(VFIODevice) next; - struct VFIOGroup *group; - bool reset_works; -} VFIODevice; - -typedef struct VFIOGroup { - int fd; - int groupid; - VFIOContainer *container; - QLIST_HEAD(, VFIODevice) device_list; - QLIST_ENTRY(VFIOGroup) next; - QLIST_ENTRY(VFIOGroup) container_next; -} VFIOGroup; - -#endif /* HW_VFIO_PCI_INT_H */ diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 247d7bef56..8342391d90 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -973,6 +973,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } } n->mac_table.first_multi = i; + + /* nc.link_down can't be migrated, so infer link_down according + * to link status bit in n->status */ + n->nic->nc.link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0; + return 0; } diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c index 4f97575770..8acba01c3a 100644 --- a/hw/zynq_slcr.c +++ b/hw/zynq_slcr.c @@ -91,7 +91,7 @@ typedef enum { typedef enum { PSS, DDDR, - DMAC, + DMAC = 3, USB, GEM, SDIO, diff --git a/linux-user/main.c b/linux-user/main.c index bcaadb67cb..5d20abd3e5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1114,6 +1114,11 @@ void cpu_loop (CPUSPARCState *env) while (1) { trapnr = cpu_sparc_exec (env); + /* Compute PSR before exposing state. */ + if (env->cc_op != CC_OP_FLAGS) { + cpu_get_psr(env); + } + switch (trapnr) { #ifndef TARGET_SPARC64 case 0x88: @@ -2522,6 +2527,7 @@ void cpu_loop(CPUMBState *env) case EXCP_BREAK: /* Return address is 4 bytes after the call. */ env->regs[14] += 4; + env->sregs[SR_PC] = env->regs[14]; ret = do_syscall(env, env->regs[12], env->regs[5], @@ -2532,7 +2538,6 @@ void cpu_loop(CPUMBState *env) env->regs[10], 0, 0); env->regs[3] = ret; - env->sregs[SR_PC] = env->regs[14]; break; case EXCP_HW_EXCP: env->regs[17] = env->sregs[SR_PC] + 4; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 14a6b32ab1..e4291ed776 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6942,6 +6942,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); #elif defined(TARGET_CRIS) ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5)); +#elif defined(TARGET_MICROBLAZE) + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5)); #elif defined(TARGET_S390X) ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4)); #else @@ -21,17 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "net.h" - #include "config-host.h" -#include "net/tap.h" -#include "net/socket.h" -#include "net/dump.h" -#include "net/slirp.h" -#include "net/vde.h" +#include "net.h" +#include "net/clients.h" #include "net/hub.h" +#include "net/slirp.h" #include "net/util.h" + #include "monitor.h" #include "qemu-common.h" #include "qemu_socket.h" diff --git a/net/socket.h b/net/clients.h index 3f8a092459..c58cc6087c 100644 --- a/net/socket.h +++ b/net/clients.h @@ -21,13 +21,35 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef QEMU_NET_SOCKET_H -#define QEMU_NET_SOCKET_H +#ifndef QEMU_NET_CLIENTS_H +#define QEMU_NET_CLIENTS_H #include "net.h" #include "qapi-types.h" +int net_init_dump(const NetClientOptions *opts, const char *name, + NetClientState *peer); + +#ifdef CONFIG_SLIRP +int net_init_slirp(const NetClientOptions *opts, const char *name, + NetClientState *peer); +#endif + +int net_init_hubport(const NetClientOptions *opts, const char *name, + NetClientState *peer); + int net_init_socket(const NetClientOptions *opts, const char *name, NetClientState *peer); -#endif /* QEMU_NET_SOCKET_H */ +int net_init_tap(const NetClientOptions *opts, const char *name, + NetClientState *peer); + +int net_init_bridge(const NetClientOptions *opts, const char *name, + NetClientState *peer); + +#ifdef CONFIG_VDE +int net_init_vde(const NetClientOptions *opts, const char *name, + NetClientState *peer); +#endif + +#endif /* QEMU_NET_CLIENTS_H */ diff --git a/net/dump.c b/net/dump.c index 004231d481..e0a5d74644 100644 --- a/net/dump.c +++ b/net/dump.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "dump.h" +#include "clients.h" #include "qemu-common.h" #include "qemu-error.h" #include "qemu-log.h" diff --git a/net/dump.h b/net/dump.h deleted file mode 100644 index 33f152b460..0000000000 --- a/net/dump.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_NET_DUMP_H -#define QEMU_NET_DUMP_H - -#include "net.h" -#include "qapi-types.h" - -int net_init_dump(const NetClientOptions *opts, const char *name, - NetClientState *peer); - -#endif /* QEMU_NET_DUMP_H */ @@ -14,6 +14,7 @@ #include "monitor.h" #include "net.h" +#include "clients.h" #include "hub.h" #include "iov.h" @@ -17,8 +17,6 @@ #include "qemu-common.h" -int net_init_hubport(const NetClientOptions *opts, const char *name, - NetClientState *peer); NetClientState *net_hub_add_port(int hub_id, const char *name); NetClientState *net_hub_find_client_by_name(int hub_id, const char *name); void net_hub_info(Monitor *mon); diff --git a/net/slirp.c b/net/slirp.c index 8db66ea539..bf86a446c3 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -30,7 +30,8 @@ #include <sys/wait.h> #endif #include "net.h" -#include "net/hub.h" +#include "clients.h" +#include "hub.h" #include "monitor.h" #include "qemu_socket.h" #include "slirp/libslirp.h" diff --git a/net/slirp.h b/net/slirp.h index 5f685c4fb1..2ca09b65b7 100644 --- a/net/slirp.h +++ b/net/slirp.h @@ -31,9 +31,6 @@ #ifdef CONFIG_SLIRP -int net_init_slirp(const NetClientOptions *opts, const char *name, - NetClientState *peer); - void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict); void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict); diff --git a/net/socket.c b/net/socket.c index f3d7878264..b75d567695 100644 --- a/net/socket.c +++ b/net/socket.c @@ -21,11 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "net/socket.h" - #include "config-host.h" #include "net.h" +#include "clients.h" #include "monitor.h" #include "qemu-char.h" #include "qemu-common.h" diff --git a/net/tap-win32.c b/net/tap-win32.c index c0ea954ca1..22dad3f8fb 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -26,9 +26,10 @@ * distribution); if not, see <http://www.gnu.org/licenses/>. */ -#include "net/tap.h" +#include "tap.h" #include "qemu-common.h" +#include "clients.h" /* net_init_tap */ #include "net.h" #include "sysemu.h" #include "qemu-error.h" @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "net/tap.h" +#include "tap.h" #include "config-host.h" @@ -34,6 +34,7 @@ #include <net/if.h> #include "net.h" +#include "clients.h" #include "monitor.h" #include "sysemu.h" #include "qemu-char.h" @@ -32,9 +32,6 @@ #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" -int net_init_tap(const NetClientOptions *opts, const char *name, - NetClientState *peer); - int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required); ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen); @@ -58,7 +55,4 @@ int tap_get_fd(NetClientState *nc); struct vhost_net; struct vhost_net *tap_get_vhost_net(NetClientState *nc); -int net_init_bridge(const NetClientOptions *opts, const char *name, - NetClientState *peer); - #endif /* QEMU_NET_TAP_H */ @@ -21,13 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "net/vde.h" - #include "config-host.h" #include <libvdeplug.h> #include "net.h" +#include "clients.h" #include "qemu-char.h" #include "qemu-common.h" #include "qemu-option.h" diff --git a/net/vde.h b/net/vde.h deleted file mode 100644 index 6ce6698937..0000000000 --- a/net/vde.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_NET_VDE_H -#define QEMU_NET_VDE_H - -#include "qemu-common.h" -#include "qapi-types.h" - -#ifdef CONFIG_VDE - -int net_init_vde(const NetClientOptions *opts, const char *name, - NetClientState *peer); - -#endif /* CONFIG_VDE */ - -#endif /* QEMU_NET_VDE_H */ @@ -40,8 +40,8 @@ #else #define QGA_VIRTIO_PATH_DEFAULT "\\\\.\\Global\\org.qemu.guest_agent.0" #endif -#define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid" -#define QGA_STATEDIR_DEFAULT "/tmp" +#define QGA_STATEDIR_DEFAULT CONFIG_QEMU_LOCALSTATEDIR "/run" +#define QGA_PIDFILE_DEFAULT QGA_STATEDIR_DEFAULT "/qemu-ga.pid" #define QGA_SENTINEL_BYTE 0xFF struct GAState { @@ -255,7 +255,7 @@ static bool ga_open_pidfile(const char *pidfile) g_critical("Failed to truncate pid file"); goto fail; } - sprintf(pidstr, "%d", getpid()); + snprintf(pidstr, sizeof(pidstr), "%d\n", getpid()); if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) { g_critical("Failed to write pid file"); goto fail; diff --git a/sparc-dis.c b/sparc-dis.c index cdd337a738..1d017faaa3 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -3270,6 +3270,6 @@ print_insn_sparc (bfd_vma memaddr, disassemble_info *info) } info->insn_type = dis_noninsn; /* Mark as non-valid instruction. */ - (*info->fprintf_func) (stream, _("unknown")); + (*info->fprintf_func) (stream, ".long %#08lx", insn); return sizeof (buffer); } diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 8bb5129d6a..9aa920d2ac 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -788,7 +788,6 @@ uint64_t HELPER(neon_qshlu_s64)(CPUARMState *env, uint64_t valop, uint64_t shift return helper_neon_qshl_u64(env, valop, shiftop); } -/* FIXME: This is wrong. */ #define NEON_FN(dest, src1, src2) do { \ int8_t tmp; \ tmp = (int8_t)src2; \ diff --git a/target-arm/translate.c b/target-arm/translate.c index c6840b7832..daccb15c23 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -516,10 +516,10 @@ static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) tcg_gen_rotri_i32(var, var, shift); break; } else { TCGv tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_CF, 31); if (flags) shifter_out_im(var, 0); tcg_gen_shri_i32(var, var, 1); - tcg_gen_shli_i32(tmp, cpu_CF, 31); tcg_gen_or_i32(var, var, tmp); tcg_temp_free_i32(tmp); } diff --git a/target-i386/translate.c b/target-i386/translate.c index 0a7e4e3487..ee7585044b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7768,7 +7768,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; modrm = cpu_ldub_code(cpu_single_env, s->pc++); - reg = ((modrm >> 3) & 7); + reg = ((modrm >> 3) & 7) | rex_r; if (s->prefix & PREFIX_DATA) ot = OT_WORD; diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 4968c244e8..88430b5057 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -345,6 +345,7 @@ static inline void cpu_clone_regs(CPUMBState *env, target_ulong newsp) static inline void cpu_set_tls(CPUMBState *env, target_ulong newtls) { + env->regs[21] = newtls; } static inline int cpu_interrupts_enabled(CPUMBState *env) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index ce5ddaf050..05b7730987 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -714,11 +714,13 @@ void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, #ifndef CONFIG_USER_ONLY /* SMP helpers. */ -static int mips_vpe_is_wfi(CPUMIPSState *c) +static bool mips_vpe_is_wfi(MIPSCPU *c) { + CPUMIPSState *env = &c->env; + /* If the VPE is halted but otherwise active, it means it's waiting for an interrupt. */ - return c->halted && mips_vpe_active(c); + return env->halted && mips_vpe_active(env); } static inline void mips_vpe_wake(CPUMIPSState *c) @@ -729,27 +731,33 @@ static inline void mips_vpe_wake(CPUMIPSState *c) cpu_interrupt(c, CPU_INTERRUPT_WAKE); } -static inline void mips_vpe_sleep(CPUMIPSState *c) +static inline void mips_vpe_sleep(MIPSCPU *cpu) { + CPUMIPSState *c = &cpu->env; + /* The VPE was shut off, really go to bed. Reset any old _WAKE requests. */ c->halted = 1; cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE); } -static inline void mips_tc_wake(CPUMIPSState *c, int tc) +static inline void mips_tc_wake(MIPSCPU *cpu, int tc) { + CPUMIPSState *c = &cpu->env; + /* FIXME: TC reschedule. */ - if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) { + if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) { mips_vpe_wake(c); } } -static inline void mips_tc_sleep(CPUMIPSState *c, int tc) +static inline void mips_tc_sleep(MIPSCPU *cpu, int tc) { + CPUMIPSState *c = &cpu->env; + /* FIXME: TC reschedule. */ if (!mips_vpe_active(c)) { - mips_vpe_sleep(c); + mips_vpe_sleep(cpu); } } @@ -1342,13 +1350,15 @@ void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1) { + MIPSCPU *cpu = mips_env_get_cpu(env); + env->active_tc.CP0_TCHalt = arg1 & 0x1; // TODO: Halt TC / Restart (if allocated+active) TC. if (env->active_tc.CP0_TCHalt & 1) { - mips_tc_sleep(env, env->current_tc); + mips_tc_sleep(cpu, env->current_tc); } else { - mips_tc_wake(env, env->current_tc); + mips_tc_wake(cpu, env->current_tc); } } @@ -1356,6 +1366,7 @@ void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + MIPSCPU *other_cpu = mips_env_get_cpu(other); // TODO: Halt TC / Restart (if allocated+active) TC. @@ -1365,9 +1376,9 @@ void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1) other->tcs[other_tc].CP0_TCHalt = arg1; if (arg1 & 1) { - mips_tc_sleep(other, other_tc); + mips_tc_sleep(other_cpu, other_tc); } else { - mips_tc_wake(other, other_tc); + mips_tc_wake(other_cpu, other_tc); } } @@ -1874,35 +1885,39 @@ target_ulong helper_emt(void) target_ulong helper_dvpe(CPUMIPSState *env) { - CPUMIPSState *other_cpu = first_cpu; + CPUMIPSState *other_cpu_env = first_cpu; target_ulong prev = env->mvp->CP0_MVPControl; do { /* Turn off all VPEs except the one executing the dvpe. */ - if (other_cpu != env) { - other_cpu->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP); + if (other_cpu_env != env) { + MIPSCPU *other_cpu = mips_env_get_cpu(other_cpu_env); + + other_cpu_env->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP); mips_vpe_sleep(other_cpu); } - other_cpu = other_cpu->next_cpu; - } while (other_cpu); + other_cpu_env = other_cpu_env->next_cpu; + } while (other_cpu_env); return prev; } target_ulong helper_evpe(CPUMIPSState *env) { - CPUMIPSState *other_cpu = first_cpu; + CPUMIPSState *other_cpu_env = first_cpu; target_ulong prev = env->mvp->CP0_MVPControl; do { - if (other_cpu != env - /* If the VPE is WFI, don't disturb its sleep. */ - && !mips_vpe_is_wfi(other_cpu)) { + MIPSCPU *other_cpu = mips_env_get_cpu(other_cpu_env); + + if (other_cpu_env != env + /* If the VPE is WFI, don't disturb its sleep. */ + && !mips_vpe_is_wfi(other_cpu)) { /* Enable the VPE. */ - other_cpu->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); - mips_vpe_wake(other_cpu); /* And wake it up. */ + other_cpu_env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); + mips_vpe_wake(other_cpu_env); /* And wake it up. */ } - other_cpu = other_cpu->next_cpu; - } while (other_cpu); + other_cpu_env = other_cpu_env->next_cpu; + } while (other_cpu_env); return prev; } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c index 9ac5aac33a..507c355cac 100644 --- a/target-sparc/int32_helper.c +++ b/target-sparc/int32_helper.c @@ -62,6 +62,11 @@ void do_interrupt(CPUSPARCState *env) { int cwp, intno = env->exception_index; + /* Compute PSR before exposing state. */ + if (env->cc_op != CC_OP_FLAGS) { + cpu_get_psr(env); + } + #ifdef DEBUG_PCALL if (qemu_loglevel_mask(CPU_LOG_INT)) { static int count; diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c index 5d0bc6c6d2..df37aa1d14 100644 --- a/target-sparc/int64_helper.c +++ b/target-sparc/int64_helper.c @@ -64,6 +64,11 @@ void do_interrupt(CPUSPARCState *env) int intno = env->exception_index; trap_state *tsptr; + /* Compute PSR before exposing state. */ + if (env->cc_op != CC_OP_FLAGS) { + cpu_get_psr(env); + } + #ifdef DEBUG_PCALL if (qemu_loglevel_mask(CPU_LOG_INT)) { static int count; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 472eb518cd..6cef96bfa6 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -143,7 +143,7 @@ static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) if (src & 1) { return MAKE_TCGV_I32(GET_TCGV_I64(cpu_fpr[src / 2])); } else { - TCGv_i32 ret = tcg_temp_local_new_i32(); + TCGv_i32 ret = tcg_temp_new_i32(); TCGv_i64 t = tcg_temp_new_i64(); tcg_gen_shri_i64(t, cpu_fpr[src / 2], 32); @@ -1005,14 +1005,17 @@ static inline void save_npc(DisasContext *dc) } } -static inline void save_state(DisasContext *dc) +static inline void update_psr(DisasContext *dc) { - tcg_gen_movi_tl(cpu_pc, dc->pc); - /* flush pending conditional evaluations before exposing cpu state */ if (dc->cc_op != CC_OP_FLAGS) { dc->cc_op = CC_OP_FLAGS; gen_helper_compute_psr(cpu_env); } +} + +static inline void save_state(DisasContext *dc) +{ + tcg_gen_movi_tl(cpu_pc, dc->pc); save_npc(dc); } @@ -1050,7 +1053,7 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, DisasContext *dc) { static int subcc_cond[16] = { - -1, /* never */ + TCG_COND_NEVER, TCG_COND_EQ, TCG_COND_LE, TCG_COND_LT, @@ -1058,7 +1061,7 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, TCG_COND_LTU, -1, /* neg */ -1, /* overflow */ - -1, /* always */ + TCG_COND_ALWAYS, TCG_COND_NE, TCG_COND_GT, TCG_COND_GE, @@ -1068,6 +1071,25 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, -1, /* no overflow */ }; + static int logic_cond[16] = { + TCG_COND_NEVER, + TCG_COND_EQ, /* eq: Z */ + TCG_COND_LE, /* le: Z | (N ^ V) -> Z | N */ + TCG_COND_LT, /* lt: N ^ V -> N */ + TCG_COND_EQ, /* leu: C | Z -> Z */ + TCG_COND_NEVER, /* ltu: C -> 0 */ + TCG_COND_LT, /* neg: N */ + TCG_COND_NEVER, /* vs: V -> 0 */ + TCG_COND_ALWAYS, + TCG_COND_NE, /* ne: !Z */ + TCG_COND_GT, /* gt: !(Z | (N ^ V)) -> !(Z | N) */ + TCG_COND_GE, /* ge: !(N ^ V) -> !N */ + TCG_COND_NE, /* gtu: !(C | Z) -> !Z */ + TCG_COND_ALWAYS, /* geu: !C -> 1 */ + TCG_COND_GE, /* pos: !N */ + TCG_COND_ALWAYS, /* vc: !V -> 1 */ + }; + TCGv_i32 r_src; TCGv r_dst; @@ -1082,28 +1104,31 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, #endif switch (dc->cc_op) { + case CC_OP_LOGIC: + cmp->cond = logic_cond[cond]; + do_compare_dst_0: + cmp->is_bool = false; + cmp->g2 = false; + cmp->c2 = tcg_const_tl(0); +#ifdef TARGET_SPARC64 + if (!xcc) { + cmp->g1 = false; + cmp->c1 = tcg_temp_new(); + tcg_gen_ext32s_tl(cmp->c1, cpu_cc_dst); + break; + } +#endif + cmp->g1 = true; + cmp->c1 = cpu_cc_dst; + break; + case CC_OP_SUB: switch (cond) { case 6: /* neg */ case 14: /* pos */ cmp->cond = (cond == 6 ? TCG_COND_LT : TCG_COND_GE); - cmp->is_bool = false; - cmp->g2 = false; - cmp->c2 = tcg_const_tl(0); -#ifdef TARGET_SPARC64 - if (!xcc) { - cmp->g1 = false; - cmp->c1 = tcg_temp_new(); - tcg_gen_ext32s_tl(cmp->c1, cpu_cc_dst); - break; - } -#endif - cmp->g1 = true; - cmp->c1 = cpu_cc_dst; - break; + goto do_compare_dst_0; - case 0: /* never */ - case 8: /* always */ case 7: /* overflow */ case 15: /* !overflow */ goto do_dynamic; @@ -1120,6 +1145,7 @@ static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, cmp->c2 = tcg_temp_new(); tcg_gen_ext32s_tl(cmp->c1, cpu_cc_src); tcg_gen_ext32s_tl(cmp->c2, cpu_cc_src2); + break; } #endif cmp->g1 = cmp->g2 = true; @@ -2681,7 +2707,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #ifdef TARGET_SPARC64 case 0x2: /* V9 rdccr */ - gen_helper_compute_psr(cpu_env); + update_psr(dc); gen_helper_rdccr(cpu_dst, cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; @@ -2760,10 +2786,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #if !defined(CONFIG_USER_ONLY) } else if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */ #ifndef TARGET_SPARC64 - if (!supervisor(dc)) + if (!supervisor(dc)) { goto priv_insn; - gen_helper_compute_psr(cpu_env); - dc->cc_op = CC_OP_FLAGS; + } + update_psr(dc); gen_helper_rdpsr(cpu_dst, cpu_env); #else CHECK_IU_FEATURE(dc, HYPV); @@ -3589,7 +3615,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) dc->cc_op = CC_OP_TSUBTV; break; case 0x24: /* mulscc */ - gen_helper_compute_psr(cpu_env); + update_psr(dc); gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD); @@ -3862,28 +3888,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_mov_tl(cpu_tbr, cpu_tmp0); break; case 6: // pstate - { - TCGv r_tmp = tcg_temp_local_new(); - - tcg_gen_mov_tl(r_tmp, cpu_tmp0); - save_state(dc); - gen_helper_wrpstate(cpu_env, r_tmp); - tcg_temp_free(r_tmp); - dc->npc = DYNAMIC_PC; - } + save_state(dc); + gen_helper_wrpstate(cpu_env, cpu_tmp0); + dc->npc = DYNAMIC_PC; break; case 7: // tl - { - TCGv r_tmp = tcg_temp_local_new(); - - tcg_gen_mov_tl(r_tmp, cpu_tmp0); - save_state(dc); - tcg_gen_trunc_tl_i32(cpu_tmp32, r_tmp); - tcg_temp_free(r_tmp); - tcg_gen_st_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, tl)); - dc->npc = DYNAMIC_PC; - } + save_state(dc); + tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); + tcg_gen_st_i32(cpu_tmp32, cpu_env, + offsetof(CPUSPARCState, tl)); + dc->npc = DYNAMIC_PC; break; case 8: // pil gen_helper_wrpil(cpu_env, cpu_tmp0); @@ -4640,12 +4654,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { unsigned int xop = GET_FIELD(insn, 7, 12); - /* flush pending conditional evaluations before exposing - cpu state */ - if (dc->cc_op != CC_OP_FLAGS) { - dc->cc_op = CC_OP_FLAGS; - gen_helper_compute_psr(cpu_env); - } cpu_src1 = get_src1(insn, cpu_src1); if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa rs2 = GET_FIELD(insn, 27, 31); @@ -5496,9 +5504,4 @@ void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb, int pc_pos) } else { env->npc = npc; } - - /* flush pending conditional evaluations before exposing cpu state */ - if (CC_OP != CC_OP_FLAGS) { - helper_compute_psr(env); - } } diff --git a/targphys.h b/targphys.h index 08cade9096..50911fd12f 100644 --- a/targphys.h +++ b/targphys.h @@ -3,6 +3,8 @@ #ifndef TARGPHYS_H #define TARGPHYS_H +#ifndef CONFIG_USER_ONLY + #define TARGET_PHYS_ADDR_BITS 64 /* target_phys_addr_t is the type of a physical address (its size can be different from 'target_ulong'). */ @@ -18,3 +20,5 @@ typedef uint64_t target_phys_addr_t; #define TARGET_PRIXPHYS PRIX64 #endif + +#endif diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 737200e5e6..e790bf04b4 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -467,6 +467,21 @@ static inline void tcg_out_movi32(TCGContext *s, } } +static inline void tcg_out_dat_rI(TCGContext *s, int cond, int opc, TCGArg dst, + TCGArg lhs, TCGArg rhs, int rhs_is_const) +{ + /* Emit either the reg,imm or reg,reg form of a data-processing insn. + * rhs must satisfy the "rI" constraint. + */ + if (rhs_is_const) { + int rot = encode_imm(rhs); + assert(rot >= 0); + tcg_out_dat_imm(s, cond, opc, dst, lhs, rotl(rhs, rot) | (rot << 7)); + } else { + tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0)); + } +} + static inline void tcg_out_mul32(TCGContext *s, int cond, int rd, int rs, int rm) { @@ -1557,6 +1572,15 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_movi_i32: tcg_out_movi32(s, COND_AL, args[0], args[1]); break; + case INDEX_op_movcond_i32: + /* Constraints mean that v2 is always in the same register as dest, + * so we only need to do "if condition passed, move v1 to dest". + */ + tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, + args[1], args[2], const_args[2]); + tcg_out_dat_rI(s, tcg_cond_to_arm_cond[args[5]], + ARITH_MOV, args[0], 0, args[3], const_args[3]); + break; case INDEX_op_add_i32: c = ARITH_ADD; goto gen_arith; @@ -1576,14 +1600,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, c = ARITH_EOR; /* Fall through. */ gen_arith: - if (const_args[2]) { - int rot; - rot = encode_imm(args[2]); - tcg_out_dat_imm(s, COND_AL, c, - args[0], args[1], rotl(args[2], rot) | (rot << 7)); - } else - tcg_out_dat_reg(s, COND_AL, c, - args[0], args[1], args[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_rI(s, COND_AL, c, args[0], args[1], args[2], const_args[2]); break; case INDEX_op_add2_i32: tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC, @@ -1643,15 +1660,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_brcond_i32: - if (const_args[1]) { - int rot; - rot = encode_imm(args[1]); - tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, - args[0], rotl(args[1], rot) | (rot << 7)); - } else { - tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, - args[0], args[1], SHIFT_IMM_LSL(0)); - } + tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, + args[0], args[1], const_args[1]); tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]); break; case INDEX_op_brcond2_i32: @@ -1670,15 +1680,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]); break; case INDEX_op_setcond_i32: - if (const_args[2]) { - int rot; - rot = encode_imm(args[2]); - tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, - args[1], rotl(args[2], rot) | (rot << 7)); - } else { - tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, - args[1], args[2], SHIFT_IMM_LSL(0)); - } + tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, + args[1], args[2], const_args[2]); tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]], ARITH_MOV, args[0], 0, 1); tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])], @@ -1788,6 +1791,7 @@ static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_brcond_i32, { "r", "rI" } }, { INDEX_op_setcond_i32, { "r", "r", "rI" } }, + { INDEX_op_movcond_i32, { "r", "r", "rI", "rI", "0" } }, /* TODO: "r", "r", "r", "r", "ri", "ri" */ { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 2bc7dff846..98fa11b286 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -73,7 +73,7 @@ typedef enum { #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 0 -#define TCG_TARGET_HAS_movcond_i32 0 +#define TCG_TARGET_HAS_movcond_i32 1 enum { TCG_AREG0 = TCG_REG_R6, diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 705712f775..06570bea38 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -230,6 +230,8 @@ enum { OPC_CMP4_LT_A6 = 0x18400000000ull, OPC_CMP4_LTU_A6 = 0x1a400000000ull, OPC_CMP4_EQ_A6 = 0x1c400000000ull, + OPC_DEP_I14 = 0x0ae00000000ull, + OPC_DEP_I15 = 0x08000000000ull, OPC_DEP_Z_I12 = 0x0a600000000ull, OPC_EXTR_I11 = 0x0a400002000ull, OPC_EXTR_U_I11 = 0x0a400000000ull, @@ -501,6 +503,30 @@ static inline uint64_t tcg_opc_i12(int qp, uint64_t opc, int r1, | (qp & 0x3f); } +static inline uint64_t tcg_opc_i14(int qp, uint64_t opc, int r1, uint64_t imm, + int r3, uint64_t pos, uint64_t len) +{ + return opc + | ((imm & 0x01) << 36) + | ((len & 0x3f) << 27) + | ((r3 & 0x7f) << 20) + | ((pos & 0x3f) << 14) + | ((r1 & 0x7f) << 6) + | (qp & 0x3f); +} + +static inline uint64_t tcg_opc_i15(int qp, uint64_t opc, int r1, int r2, + int r3, uint64_t pos, uint64_t len) +{ + return opc + | ((pos & 0x3f) << 31) + | ((len & 0x0f) << 27) + | ((r3 & 0x7f) << 20) + | ((r2 & 0x7f) << 13) + | ((r1 & 0x7f) << 6) + | (qp & 0x3f); +} + static inline uint64_t tcg_opc_i18(int qp, uint64_t opc, uint64_t imm) { return opc @@ -1312,6 +1338,37 @@ static inline void tcg_out_bswap64(TCGContext *s, TCGArg ret, TCGArg arg) tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, arg, 0xb)); } +static inline void tcg_out_deposit(TCGContext *s, TCGArg ret, TCGArg a1, + TCGArg a2, int const_a2, int pos, int len) +{ + uint64_t i1 = 0, i2 = 0; + int cpos = 63 - pos, lm1 = len - 1; + + if (const_a2) { + /* Truncate the value of a constant a2 to the width of the field. */ + int mask = (1u << len) - 1; + a2 &= mask; + + if (a2 == 0 || a2 == mask) { + /* 1-bit signed constant inserted into register. */ + i2 = tcg_opc_i14(TCG_REG_P0, OPC_DEP_I14, ret, a2, a1, cpos, lm1); + } else { + /* Otherwise, load any constant into a temporary. Do this into + the first I slot to help out with cross-unit delays. */ + i1 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5, + TCG_REG_R2, a2, TCG_REG_R0); + a2 = TCG_REG_R2; + } + } + if (i2 == 0) { + i2 = tcg_opc_i15(TCG_REG_P0, OPC_DEP_I15, ret, a2, a1, cpos, lm1); + } + tcg_out_bundle(s, (i1 ? mII : miI), + tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), + i1 ? i1 : tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), + i2); +} + static inline uint64_t tcg_opc_cmp_a(int qp, TCGCond cond, TCGArg arg1, TCGArg arg2, int cmp4) { @@ -1404,21 +1461,47 @@ static inline void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGArg ret, tcg_opc_a5(TCG_REG_P7, OPC_ADDL_A5, ret, 0, TCG_REG_R0)); } +static inline void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGArg ret, + TCGArg c1, TCGArg c2, + TCGArg v1, int const_v1, + TCGArg v2, int const_v2, int cmp4) +{ + uint64_t opc1, opc2; + + if (const_v1) { + opc1 = tcg_opc_a5(TCG_REG_P6, OPC_ADDL_A5, ret, v1, TCG_REG_R0); + } else if (ret == v1) { + opc1 = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0); + } else { + opc1 = tcg_opc_a4(TCG_REG_P6, OPC_ADDS_A4, ret, 0, v1); + } + if (const_v2) { + opc2 = tcg_opc_a5(TCG_REG_P7, OPC_ADDL_A5, ret, v2, TCG_REG_R0); + } else if (ret == v2) { + opc2 = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0); + } else { + opc2 = tcg_opc_a4(TCG_REG_P7, OPC_ADDS_A4, ret, 0, v2); + } + + tcg_out_bundle(s, MmI, + tcg_opc_cmp_a(TCG_REG_P0, cond, c1, c2, cmp4), + opc1, + opc2); +} + #if defined(CONFIG_SOFTMMU) #include "../../softmmu_defs.h" /* Load and compare a TLB entry, and return the result in (p6, p7). R2 is loaded with the address of the addend TLB entry. - R56 is loaded with the address, zero extented on 32-bit targets. */ + R57 is loaded with the address, zero extented on 32-bit targets. */ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, int s_bits, uint64_t offset_rw, uint64_t offset_addend) { tcg_out_bundle(s, mII, - tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R3, - TARGET_PAGE_MASK | ((1 << s_bits) - 1), - TCG_REG_R0), + tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, TCG_REG_R2, addr_reg, TARGET_PAGE_BITS, CPU_TLB_BITS - 1), tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, TCG_REG_R2, @@ -1428,9 +1511,9 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R2, offset_rw, TCG_REG_R2), #if TARGET_LONG_BITS == 32 - tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29, TCG_REG_R56, addr_reg), + tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29, TCG_REG_R57, addr_reg), #else - tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R56, + tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R57, 0, addr_reg), #endif tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2, @@ -1438,12 +1521,13 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, tcg_out_bundle(s, mII, tcg_opc_m3 (TCG_REG_P0, (TARGET_LONG_BITS == 32 - ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R57, + ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R56, TCG_REG_R2, offset_addend - offset_rw), - tcg_opc_a1 (TCG_REG_P0, OPC_AND_A1, TCG_REG_R3, - TCG_REG_R3, TCG_REG_R56), + tcg_opc_i14(TCG_REG_P0, OPC_DEP_I14, TCG_REG_R3, 0, + TCG_REG_R57, 63 - s_bits, + TARGET_PAGE_BITS - s_bits - 1), tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6, - TCG_REG_P7, TCG_REG_R3, TCG_REG_R57)); + TCG_REG_P7, TCG_REG_R3, TCG_REG_R56)); } /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, @@ -1480,8 +1564,8 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) /* P6 is the fast path, and P7 the slow path */ tcg_out_bundle(s, mLX, - tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R57, - mem_index, TCG_REG_R0), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, + TCG_REG_R56, 0, TCG_AREG0), tcg_opc_l2 ((tcg_target_long) qemu_ld_helpers[s_bits]), tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2, (tcg_target_long) qemu_ld_helpers[s_bits])); @@ -1489,7 +1573,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3, TCG_REG_R2, 8), tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3, - TCG_REG_R3, TCG_REG_R56), + TCG_REG_R3, TCG_REG_R57), tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6, TCG_REG_R3, 0)); if (bswap && s_bits == 1) { @@ -1513,23 +1597,17 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0)); } - /* XXX/FIXME: suboptimal */ - tcg_out_bundle(s, mII, - tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58, - mem_index, TCG_REG_R0), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R57, 0, TCG_REG_R56), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R56, 0, TCG_AREG0)); if (!bswap || s_bits == 0) { tcg_out_bundle(s, miB, - tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), + tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58, + mem_index, TCG_REG_R0), tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5, TCG_REG_B0, TCG_REG_B6)); } else { tcg_out_bundle(s, miB, - tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), + tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58, + mem_index, TCG_REG_R0), tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3, TCG_REG_R8, TCG_REG_R8, 0xb), tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5, @@ -1581,8 +1659,8 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) /* P6 is the fast path, and P7 the slow path */ tcg_out_bundle(s, mLX, - tcg_opc_a4(TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R57, - 0, data_reg), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, + TCG_REG_R56, 0, TCG_AREG0), tcg_opc_l2 ((tcg_target_long) qemu_st_helpers[opc]), tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2, (tcg_target_long) qemu_st_helpers[opc])); @@ -1590,31 +1668,42 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3, TCG_REG_R2, 8), tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3, - TCG_REG_R3, TCG_REG_R56), + TCG_REG_R3, TCG_REG_R57), tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6, TCG_REG_R3, 0)); if (!bswap || opc == 0) { - tcg_out_bundle(s, mII, + tcg_out_bundle(s, mii, tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), - tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R58, + 0, data_reg), tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0)); } else if (opc == 1) { - tcg_out_bundle(s, mII, + tcg_out_bundle(s, miI, tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), + tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12, - TCG_REG_R2, data_reg, 15, 15), + TCG_REG_R2, data_reg, 15, 15)); + tcg_out_bundle(s, miI, + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R58, + 0, data_reg), + tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3, TCG_REG_R2, TCG_REG_R2, 0xb)); data_reg = TCG_REG_R2; } else if (opc == 2) { - tcg_out_bundle(s, mII, + tcg_out_bundle(s, miI, tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), + tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12, - TCG_REG_R2, data_reg, 31, 31), + TCG_REG_R2, data_reg, 31, 31)); + tcg_out_bundle(s, miI, + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R58, + 0, data_reg), + tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3, TCG_REG_R2, TCG_REG_R2, 0xb)); data_reg = TCG_REG_R2; @@ -1622,25 +1711,18 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) tcg_out_bundle(s, miI, tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), - tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R58, + 0, data_reg), tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3, TCG_REG_R2, data_reg, 0xb)); data_reg = TCG_REG_R2; } - /* XXX/FIXME: suboptimal */ - tcg_out_bundle(s, mII, - tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R59, - mem_index, TCG_REG_R0), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R58, 0, TCG_REG_R57), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R57, 0, TCG_REG_R56)); tcg_out_bundle(s, miB, tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc], data_reg, TCG_REG_R3), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R56, 0, TCG_AREG0), + tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R59, + mem_index, TCG_REG_R0), tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5, TCG_REG_B0, TCG_REG_B6)); } @@ -2092,6 +2174,12 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_bswap64(s, args[0], args[1]); break; + case INDEX_op_deposit_i32: + case INDEX_op_deposit_i64: + tcg_out_deposit(s, args[0], args[1], args[2], const_args[2], + args[3], args[4]); + break; + case INDEX_op_brcond_i32: tcg_out_brcond(s, args[2], args[0], const_args[0], args[1], const_args[1], args[3], 1); @@ -2106,6 +2194,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_setcond_i64: tcg_out_setcond(s, args[3], args[0], args[1], args[2], 0); break; + case INDEX_op_movcond_i32: + tcg_out_movcond(s, args[5], args[0], args[1], args[2], + args[3], const_args[3], args[4], const_args[4], 1); + break; + case INDEX_op_movcond_i64: + tcg_out_movcond(s, args[5], args[0], args[1], args[2], + args[3], const_args[3], args[4], const_args[4], 0); + break; case INDEX_op_qemu_ld8u: tcg_out_qemu_ld(s, args, 0); @@ -2196,6 +2292,7 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_brcond_i32, { "rI", "rI" } }, { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rI", "rI" } }, { INDEX_op_mov_i64, { "r", "r" } }, { INDEX_op_movi_i64, { "r" } }, @@ -2245,6 +2342,10 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_brcond_i64, { "rI", "rI" } }, { INDEX_op_setcond_i64, { "r", "rZ", "rZ" } }, + { INDEX_op_movcond_i64, { "r", "rZ", "rZ", "rI", "rI" } }, + + { INDEX_op_deposit_i32, { "r", "rZ", "ri" } }, + { INDEX_op_deposit_i64, { "r", "rZ", "ri" } }, { INDEX_op_qemu_ld8u, { "r", "r" } }, { INDEX_op_qemu_ld8s, { "r", "r" } }, @@ -2269,9 +2370,12 @@ static void tcg_target_qemu_prologue(TCGContext *s) int frame_size; /* reserve some stack space */ - frame_size = TCG_STATIC_CALL_ARGS_SIZE; + frame_size = TCG_STATIC_CALL_ARGS_SIZE + + CPU_TEMP_BUF_NLONGS * sizeof(long); frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & ~(TCG_TARGET_STACK_ALIGN - 1); + tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE, + CPU_TEMP_BUF_NLONGS * sizeof(long)); /* First emit adhoc function descriptor */ *(uint64_t *)(s->code_ptr) = (uint64_t)s->code_ptr + 16; /* entry point */ @@ -2378,6 +2482,4 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_R6); tcg_add_target_add_op_defs(ia64_op_defs); - tcg_set_frame(s, TCG_AREG0, offsetof(CPUArchState, temp_buf), - CPU_TEMP_BUF_NLONGS * sizeof(long)); } diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index b7e01b25ae..91fe7a3b06 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -131,10 +131,13 @@ typedef enum { #define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_deposit_i32 0 -#define TCG_TARGET_HAS_deposit_i64 0 -#define TCG_TARGET_HAS_movcond_i32 0 -#define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_deposit_i32 1 +#define TCG_TARGET_HAS_deposit_i64 1 + +#define TCG_TARGET_deposit_i32_valid(ofs, len) ((len) <= 16) +#define TCG_TARGET_deposit_i64_valid(ofs, len) ((len) <= 16) /* optional instructions automatically implemented */ #define TCG_TARGET_HAS_neg_i32 0 /* sub r1, r0, r3 */ diff --git a/tcg/optimize.c b/tcg/optimize.c index edb2b0ea90..a06c8eb43e 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -292,6 +292,82 @@ static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y) return res; } +static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c) +{ + switch (c) { + case TCG_COND_EQ: + return x == y; + case TCG_COND_NE: + return x != y; + case TCG_COND_LT: + return (int32_t)x < (int32_t)y; + case TCG_COND_GE: + return (int32_t)x >= (int32_t)y; + case TCG_COND_LE: + return (int32_t)x <= (int32_t)y; + case TCG_COND_GT: + return (int32_t)x > (int32_t)y; + case TCG_COND_LTU: + return x < y; + case TCG_COND_GEU: + return x >= y; + case TCG_COND_LEU: + return x <= y; + case TCG_COND_GTU: + return x > y; + default: + tcg_abort(); + } +} + +static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c) +{ + switch (c) { + case TCG_COND_EQ: + return x == y; + case TCG_COND_NE: + return x != y; + case TCG_COND_LT: + return (int64_t)x < (int64_t)y; + case TCG_COND_GE: + return (int64_t)x >= (int64_t)y; + case TCG_COND_LE: + return (int64_t)x <= (int64_t)y; + case TCG_COND_GT: + return (int64_t)x > (int64_t)y; + case TCG_COND_LTU: + return x < y; + case TCG_COND_GEU: + return x >= y; + case TCG_COND_LEU: + return x <= y; + case TCG_COND_GTU: + return x > y; + default: + tcg_abort(); + } +} + +static bool do_constant_folding_cond_eq(TCGCond c) +{ + switch (c) { + case TCG_COND_GT: + case TCG_COND_LTU: + case TCG_COND_LT: + case TCG_COND_GTU: + case TCG_COND_NE: + return 0; + case TCG_COND_GE: + case TCG_COND_GEU: + case TCG_COND_LE: + case TCG_COND_LEU: + case TCG_COND_EQ: + return 1; + default: + tcg_abort(); + } +} + /* Return 2 if the condition can't be simplified, and the result of the condition (0 or 1) if it can */ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, @@ -300,75 +376,14 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, if (temps[x].state == TCG_TEMP_CONST && temps[y].state == TCG_TEMP_CONST) { switch (op_bits(op)) { case 32: - switch (c) { - case TCG_COND_EQ: - return (uint32_t)temps[x].val == (uint32_t)temps[y].val; - case TCG_COND_NE: - return (uint32_t)temps[x].val != (uint32_t)temps[y].val; - case TCG_COND_LT: - return (int32_t)temps[x].val < (int32_t)temps[y].val; - case TCG_COND_GE: - return (int32_t)temps[x].val >= (int32_t)temps[y].val; - case TCG_COND_LE: - return (int32_t)temps[x].val <= (int32_t)temps[y].val; - case TCG_COND_GT: - return (int32_t)temps[x].val > (int32_t)temps[y].val; - case TCG_COND_LTU: - return (uint32_t)temps[x].val < (uint32_t)temps[y].val; - case TCG_COND_GEU: - return (uint32_t)temps[x].val >= (uint32_t)temps[y].val; - case TCG_COND_LEU: - return (uint32_t)temps[x].val <= (uint32_t)temps[y].val; - case TCG_COND_GTU: - return (uint32_t)temps[x].val > (uint32_t)temps[y].val; - default: - break; - } - break; + return do_constant_folding_cond_32(temps[x].val, temps[y].val, c); case 64: - switch (c) { - case TCG_COND_EQ: - return (uint64_t)temps[x].val == (uint64_t)temps[y].val; - case TCG_COND_NE: - return (uint64_t)temps[x].val != (uint64_t)temps[y].val; - case TCG_COND_LT: - return (int64_t)temps[x].val < (int64_t)temps[y].val; - case TCG_COND_GE: - return (int64_t)temps[x].val >= (int64_t)temps[y].val; - case TCG_COND_LE: - return (int64_t)temps[x].val <= (int64_t)temps[y].val; - case TCG_COND_GT: - return (int64_t)temps[x].val > (int64_t)temps[y].val; - case TCG_COND_LTU: - return (uint64_t)temps[x].val < (uint64_t)temps[y].val; - case TCG_COND_GEU: - return (uint64_t)temps[x].val >= (uint64_t)temps[y].val; - case TCG_COND_LEU: - return (uint64_t)temps[x].val <= (uint64_t)temps[y].val; - case TCG_COND_GTU: - return (uint64_t)temps[x].val > (uint64_t)temps[y].val; - default: - break; - } - break; - } - } else if (temps_are_copies(x, y)) { - switch (c) { - case TCG_COND_GT: - case TCG_COND_LTU: - case TCG_COND_LT: - case TCG_COND_GTU: - case TCG_COND_NE: - return 0; - case TCG_COND_GE: - case TCG_COND_GEU: - case TCG_COND_LE: - case TCG_COND_LEU: - case TCG_COND_EQ: - return 1; + return do_constant_folding_cond_64(temps[x].val, temps[y].val, c); default: - break; + tcg_abort(); } + } else if (temps_are_copies(x, y)) { + return do_constant_folding_cond_eq(c); } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) { switch (c) { case TCG_COND_LTU: @@ -381,11 +396,73 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, } else { return 2; } +} - fprintf(stderr, - "Unrecognized bitness %d or condition %d in " - "do_constant_folding_cond.\n", op_bits(op), c); - tcg_abort(); +/* Return 2 if the condition can't be simplified, and the result + of the condition (0 or 1) if it can */ +static TCGArg do_constant_folding_cond2(TCGArg *p1, TCGArg *p2, TCGCond c) +{ + TCGArg al = p1[0], ah = p1[1]; + TCGArg bl = p2[0], bh = p2[1]; + + if (temps[bl].state == TCG_TEMP_CONST + && temps[bh].state == TCG_TEMP_CONST) { + uint64_t b = ((uint64_t)temps[bh].val << 32) | (uint32_t)temps[bl].val; + + if (temps[al].state == TCG_TEMP_CONST + && temps[ah].state == TCG_TEMP_CONST) { + uint64_t a; + a = ((uint64_t)temps[ah].val << 32) | (uint32_t)temps[al].val; + return do_constant_folding_cond_64(a, b, c); + } + if (b == 0) { + switch (c) { + case TCG_COND_LTU: + return 0; + case TCG_COND_GEU: + return 1; + default: + break; + } + } + } + if (temps_are_copies(al, bl) && temps_are_copies(ah, bh)) { + return do_constant_folding_cond_eq(c); + } + return 2; +} + +static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) +{ + TCGArg a1 = *p1, a2 = *p2; + int sum = 0; + sum += temps[a1].state == TCG_TEMP_CONST; + sum -= temps[a2].state == TCG_TEMP_CONST; + + /* Prefer the constant in second argument, and then the form + op a, a, b, which is better handled on non-RISC hosts. */ + if (sum > 0 || (sum == 0 && dest == a2)) { + *p1 = a2; + *p2 = a1; + return true; + } + return false; +} + +static bool swap_commutative2(TCGArg *p1, TCGArg *p2) +{ + int sum = 0; + sum += temps[p1[0]].state == TCG_TEMP_CONST; + sum += temps[p1[1]].state == TCG_TEMP_CONST; + sum -= temps[p2[0]].state == TCG_TEMP_CONST; + sum -= temps[p2[1]].state == TCG_TEMP_CONST; + if (sum > 0) { + TCGArg t; + t = p1[0], p1[0] = p2[0], p2[0] = t; + t = p1[1], p1[1] = p2[1], p2[1] = t; + return true; + } + return false; } /* Propagate constants and copies, fold constant expressions. */ @@ -397,7 +474,6 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, const TCGOpDef *def; TCGArg *gen_args; TCGArg tmp; - TCGCond cond; /* Array VALS has an element for each temp. If this temp holds a constant then its value is kept in VALS' element. @@ -440,52 +516,46 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(eqv): CASE_OP_32_64(nand): CASE_OP_32_64(nor): - /* Prefer the constant in second argument, and then the form - op a, a, b, which is better handled on non-RISC hosts. */ - if (temps[args[1]].state == TCG_TEMP_CONST || (args[0] == args[2] - && temps[args[2]].state != TCG_TEMP_CONST)) { - tmp = args[1]; - args[1] = args[2]; - args[2] = tmp; - } + swap_commutative(args[0], &args[1], &args[2]); break; CASE_OP_32_64(brcond): - if (temps[args[0]].state == TCG_TEMP_CONST - && temps[args[1]].state != TCG_TEMP_CONST) { - tmp = args[0]; - args[0] = args[1]; - args[1] = tmp; + if (swap_commutative(-1, &args[0], &args[1])) { args[2] = tcg_swap_cond(args[2]); } break; CASE_OP_32_64(setcond): - if (temps[args[1]].state == TCG_TEMP_CONST - && temps[args[2]].state != TCG_TEMP_CONST) { - tmp = args[1]; - args[1] = args[2]; - args[2] = tmp; + if (swap_commutative(args[0], &args[1], &args[2])) { args[3] = tcg_swap_cond(args[3]); } break; CASE_OP_32_64(movcond): - cond = args[5]; - if (temps[args[1]].state == TCG_TEMP_CONST - && temps[args[2]].state != TCG_TEMP_CONST) { - tmp = args[1]; - args[1] = args[2]; - args[2] = tmp; - cond = tcg_swap_cond(cond); + if (swap_commutative(-1, &args[1], &args[2])) { + args[5] = tcg_swap_cond(args[5]); } /* For movcond, we canonicalize the "false" input reg to match the destination reg so that the tcg backend can implement a "move if true" operation. */ - if (args[0] == args[3]) { - tmp = args[3]; - args[3] = args[4]; - args[4] = tmp; - cond = tcg_invert_cond(cond); + if (swap_commutative(args[0], &args[4], &args[3])) { + args[5] = tcg_invert_cond(args[5]); } - args[5] = cond; + break; + case INDEX_op_add2_i32: + swap_commutative(args[0], &args[2], &args[4]); + swap_commutative(args[1], &args[3], &args[5]); + break; + case INDEX_op_mulu2_i32: + swap_commutative(args[0], &args[2], &args[3]); + break; + case INDEX_op_brcond2_i32: + if (swap_commutative2(&args[0], &args[2])) { + args[4] = tcg_swap_cond(args[4]); + } + break; + case INDEX_op_setcond2_i32: + if (swap_commutative2(&args[1], &args[3])) { + args[5] = tcg_swap_cond(args[5]); + } + break; default: break; } @@ -622,6 +692,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, gen_args += 2; args += 2; break; + CASE_OP_32_64(not): CASE_OP_32_64(neg): CASE_OP_32_64(ext8s): @@ -634,14 +705,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, gen_opc_buf[op_index] = op_to_movi(op); tmp = do_constant_folding(op, temps[args[1]].val, 0); tcg_opt_gen_movi(gen_args, args[0], tmp); - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; + gen_args += 2; + args += 2; + break; } - gen_args += 2; - args += 2; - break; + goto do_default; + CASE_OP_32_64(add): CASE_OP_32_64(sub): CASE_OP_32_64(mul): @@ -665,15 +734,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, temps[args[2]].val); tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args += 3; + args += 3; + break; } - args += 3; - break; + goto do_default; + CASE_OP_32_64(deposit): if (temps[args[1]].state == TCG_TEMP_CONST && temps[args[2]].state == TCG_TEMP_CONST) { @@ -683,33 +748,22 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, | ((temps[args[2]].val & tmp) << args[3]); tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args[3] = args[3]; - gen_args[4] = args[4]; - gen_args += 5; + args += 5; + break; } - args += 5; - break; + goto do_default; + CASE_OP_32_64(setcond): tmp = do_constant_folding_cond(op, args[1], args[2], args[3]); if (tmp != 2) { gen_opc_buf[op_index] = op_to_movi(op); tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args[3] = args[3]; - gen_args += 4; + args += 4; + break; } - args += 4; - break; + goto do_default; + CASE_OP_32_64(brcond): tmp = do_constant_folding_cond(op, args[0], args[1], args[2]); if (tmp != 2) { @@ -721,17 +775,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, } else { gen_opc_buf[op_index] = INDEX_op_nop; } - } else { - memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args[3] = args[3]; - gen_args += 4; + args += 4; + break; } - args += 4; - break; + goto do_default; + CASE_OP_32_64(movcond): tmp = do_constant_folding_cond(op, args[1], args[2], args[5]); if (tmp != 2) { @@ -746,18 +794,125 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]); gen_args += 2; } + args += 6; + break; + } + goto do_default; + + case INDEX_op_add2_i32: + case INDEX_op_sub2_i32: + if (temps[args[2]].state == TCG_TEMP_CONST + && temps[args[3]].state == TCG_TEMP_CONST + && temps[args[4]].state == TCG_TEMP_CONST + && temps[args[5]].state == TCG_TEMP_CONST) { + uint32_t al = temps[args[2]].val; + uint32_t ah = temps[args[3]].val; + uint32_t bl = temps[args[4]].val; + uint32_t bh = temps[args[5]].val; + uint64_t a = ((uint64_t)ah << 32) | al; + uint64_t b = ((uint64_t)bh << 32) | bl; + TCGArg rl, rh; + + if (op == INDEX_op_add2_i32) { + a += b; + } else { + a -= b; + } + + /* We emit the extra nop when we emit the add2/sub2. */ + assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + + rl = args[0]; + rh = args[1]; + gen_opc_buf[op_index] = INDEX_op_movi_i32; + gen_opc_buf[++op_index] = INDEX_op_movi_i32; + tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)a); + tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(a >> 32)); + gen_args += 4; + args += 6; + break; + } + goto do_default; + + case INDEX_op_mulu2_i32: + if (temps[args[2]].state == TCG_TEMP_CONST + && temps[args[3]].state == TCG_TEMP_CONST) { + uint32_t a = temps[args[2]].val; + uint32_t b = temps[args[3]].val; + uint64_t r = (uint64_t)a * b; + TCGArg rl, rh; + + /* We emit the extra nop when we emit the mulu2. */ + assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + + rl = args[0]; + rh = args[1]; + gen_opc_buf[op_index] = INDEX_op_movi_i32; + gen_opc_buf[++op_index] = INDEX_op_movi_i32; + tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)r); + tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(r >> 32)); + gen_args += 4; + args += 4; + break; + } + goto do_default; + + case INDEX_op_brcond2_i32: + tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]); + if (tmp != 2) { + if (tmp) { + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + gen_opc_buf[op_index] = INDEX_op_br; + gen_args[0] = args[5]; + gen_args += 1; + } else { + gen_opc_buf[op_index] = INDEX_op_nop; + } + } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) + && temps[args[2]].state == TCG_TEMP_CONST + && temps[args[3]].state == TCG_TEMP_CONST + && temps[args[2]].val == 0 + && temps[args[3]].val == 0) { + /* Simplify LT/GE comparisons vs zero to a single compare + vs the high word of the input. */ + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + gen_opc_buf[op_index] = INDEX_op_brcond_i32; + gen_args[0] = args[1]; + gen_args[1] = args[3]; + gen_args[2] = args[4]; + gen_args[3] = args[5]; + gen_args += 4; } else { - reset_temp(args[0]); + goto do_default; + } + args += 6; + break; + + case INDEX_op_setcond2_i32: + tmp = do_constant_folding_cond2(&args[1], &args[3], args[5]); + if (tmp != 2) { + gen_opc_buf[op_index] = INDEX_op_movi_i32; + tcg_opt_gen_movi(gen_args, args[0], tmp); + gen_args += 2; + } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) + && temps[args[3]].state == TCG_TEMP_CONST + && temps[args[4]].state == TCG_TEMP_CONST + && temps[args[3]].val == 0 + && temps[args[4]].val == 0) { + /* Simplify LT/GE comparisons vs zero to a single compare + vs the high word of the input. */ + gen_opc_buf[op_index] = INDEX_op_setcond_i32; gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args[3] = args[3]; - gen_args[4] = args[4]; - gen_args[5] = args[5]; - gen_args += 6; + gen_args[1] = args[2]; + gen_args[2] = args[4]; + gen_args[3] = args[5]; + gen_args += 4; + } else { + goto do_default; } args += 6; break; + case INDEX_op_call: nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) { @@ -776,11 +931,13 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, i--; } break; + default: - /* Default case: we do know nothing about operation so no - propagation is done. We trash everything if the operation - is the end of a basic block, otherwise we only trash the - output args. */ + do_default: + /* Default case: we know nothing about operation (or were unable + to compute the operation result) so no propagation is done. + We trash everything if the operation is the end of a basic + block, otherwise we only trash the output args. */ if (def->flags & TCG_OPF_BB_END) { memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); } else { diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 0c32baa50e..f146647874 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -115,96 +115,6 @@ static const int tcg_target_call_oarg_regs[] = { TCG_REG_O3, }; -static inline int check_fit_tl(tcg_target_long val, unsigned int bits) -{ - return (val << ((sizeof(tcg_target_long) * 8 - bits)) - >> (sizeof(tcg_target_long) * 8 - bits)) == val; -} - -static inline int check_fit_i32(uint32_t val, unsigned int bits) -{ - return ((val << (32 - bits)) >> (32 - bits)) == val; -} - -static void patch_reloc(uint8_t *code_ptr, int type, - tcg_target_long value, tcg_target_long addend) -{ - value += addend; - switch (type) { - case R_SPARC_32: - if (value != (uint32_t)value) - tcg_abort(); - *(uint32_t *)code_ptr = value; - break; - case R_SPARC_WDISP22: - value -= (long)code_ptr; - value >>= 2; - if (!check_fit_tl(value, 22)) - tcg_abort(); - *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value; - break; - case R_SPARC_WDISP19: - value -= (long)code_ptr; - value >>= 2; - if (!check_fit_tl(value, 19)) - tcg_abort(); - *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x7ffff) | value; - break; - default: - tcg_abort(); - } -} - -/* parse target specific constraints */ -static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) -{ - const char *ct_str; - - ct_str = *pct_str; - switch (ct_str[0]) { - case 'r': - ct->ct |= TCG_CT_REG; - tcg_regset_set32(ct->u.regs, 0, 0xffffffff); - break; - case 'L': /* qemu_ld/st constraint */ - ct->ct |= TCG_CT_REG; - tcg_regset_set32(ct->u.regs, 0, 0xffffffff); - // Helper args - tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0); - tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1); - tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2); - break; - case 'I': - ct->ct |= TCG_CT_CONST_S11; - break; - case 'J': - ct->ct |= TCG_CT_CONST_S13; - break; - default: - return -1; - } - ct_str++; - *pct_str = ct_str; - return 0; -} - -/* test if a constant matches the constraint */ -static inline int tcg_target_const_match(tcg_target_long val, - const TCGArgConstraint *arg_ct) -{ - int ct; - - ct = arg_ct->ct; - if (ct & TCG_CT_CONST) - return 1; - else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11)) - return 1; - else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13)) - return 1; - else - return 0; -} - #define INSN_OP(x) ((x) << 30) #define INSN_OP2(x) ((x) << 22) #define INSN_OP3(x) ((x) << 19) @@ -214,12 +124,13 @@ static inline int tcg_target_const_match(tcg_target_long val, #define INSN_RS2(x) (x) #define INSN_ASI(x) ((x) << 5) +#define INSN_IMM10(x) ((1 << 13) | ((x) & 0x3ff)) #define INSN_IMM11(x) ((1 << 13) | ((x) & 0x7ff)) #define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff)) +#define INSN_OFF16(x) ((((x) >> 2) & 0x3fff) | ((((x) >> 16) & 3) << 20)) #define INSN_OFF19(x) (((x) >> 2) & 0x07ffff) -#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff) +#define INSN_COND(x) ((x) << 25) -#define INSN_COND(x, a) (((x) << 25) | ((a) << 29)) #define COND_N 0x0 #define COND_E 0x1 #define COND_LE 0x2 @@ -236,11 +147,26 @@ static inline int tcg_target_const_match(tcg_target_long val, #define COND_CC 0xd #define COND_POS 0xe #define COND_VC 0xf -#define BA (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2)) +#define BA (INSN_OP(0) | INSN_COND(COND_A) | INSN_OP2(0x2)) + +#define RCOND_Z 1 +#define RCOND_LEZ 2 +#define RCOND_LZ 3 +#define RCOND_NZ 5 +#define RCOND_GZ 6 +#define RCOND_GEZ 7 #define MOVCC_ICC (1 << 18) #define MOVCC_XCC (1 << 18 | 1 << 12) +#define BPCC_ICC 0 +#define BPCC_XCC (2 << 20) +#define BPCC_PT (1 << 19) +#define BPCC_PN 0 +#define BPCC_A (1 << 29) + +#define BPR_PT BPCC_PT + #define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00)) #define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10)) #define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01)) @@ -260,6 +186,7 @@ static inline int tcg_target_const_match(tcg_target_long val, #define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d)) #define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d)) #define ARITH_MOVCC (INSN_OP(2) | INSN_OP3(0x2c)) +#define ARITH_MOVR (INSN_OP(2) | INSN_OP3(0x2f)) #define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25)) #define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26)) @@ -313,6 +240,109 @@ static inline int tcg_target_const_match(tcg_target_long val, #define STW_LE (STWA | INSN_ASI(ASI_PRIMARY_LITTLE)) #define STX_LE (STXA | INSN_ASI(ASI_PRIMARY_LITTLE)) +static inline int check_fit_tl(tcg_target_long val, unsigned int bits) +{ + return (val << ((sizeof(tcg_target_long) * 8 - bits)) + >> (sizeof(tcg_target_long) * 8 - bits)) == val; +} + +static inline int check_fit_i32(uint32_t val, unsigned int bits) +{ + return ((val << (32 - bits)) >> (32 - bits)) == val; +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + uint32_t insn; + value += addend; + switch (type) { + case R_SPARC_32: + if (value != (uint32_t)value) { + tcg_abort(); + } + *(uint32_t *)code_ptr = value; + break; + case R_SPARC_WDISP16: + value -= (long)code_ptr; + if (!check_fit_tl(value >> 2, 16)) { + tcg_abort(); + } + insn = *(uint32_t *)code_ptr; + insn &= ~INSN_OFF16(-1); + insn |= INSN_OFF16(value); + *(uint32_t *)code_ptr = insn; + break; + case R_SPARC_WDISP19: + value -= (long)code_ptr; + if (!check_fit_tl(value >> 2, 19)) { + tcg_abort(); + } + insn = *(uint32_t *)code_ptr; + insn &= ~INSN_OFF19(-1); + insn |= INSN_OFF19(value); + *(uint32_t *)code_ptr = insn; + break; + default: + tcg_abort(); + } +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) +{ + const char *ct_str; + + ct_str = *pct_str; + switch (ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + break; + case 'L': /* qemu_ld/st constraint */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + // Helper args + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2); + break; + case 'I': + ct->ct |= TCG_CT_CONST_S11; + break; + case 'J': + ct->ct |= TCG_CT_CONST_S13; + break; + case 'Z': + ct->ct |= TCG_CT_CONST_ZERO; + break; + default: + return -1; + } + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct = arg_ct->ct; + + if (ct & TCG_CT_CONST) { + return 1; + } else if ((ct & TCG_CT_CONST_ZERO) && val == 0) { + return 1; + } else if ((ct & TCG_CT_CONST_S11) && check_fit_tl(val, 11)) { + return 1; + } else if ((ct & TCG_CT_CONST_S13) && check_fit_tl(val, 13)) { + return 1; + } else { + return 0; + } +} + static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2, int op) { @@ -337,7 +367,9 @@ static void tcg_out_arithc(TCGContext *s, int rd, int rs1, static inline void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) { - tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR); + if (ret != arg) { + tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR); + } } static inline void tcg_out_sethi(TCGContext *s, int ret, uint32_t arg) @@ -479,39 +511,6 @@ static inline void tcg_out_nop(TCGContext *s) tcg_out_sethi(s, TCG_REG_G0, 0); } -static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index) -{ - TCGLabel *l = &s->labels[label_index]; - uint32_t off22; - - if (l->has_value) { - off22 = INSN_OFF22(l->u.value - (unsigned long)s->code_ptr); - } else { - /* Make sure to preserve destinations during retranslation. */ - off22 = *(uint32_t *)s->code_ptr & INSN_OFF22(-1); - tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0); - } - tcg_out32(s, INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | off22); -} - -#if TCG_TARGET_REG_BITS == 64 -static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index) -{ - TCGLabel *l = &s->labels[label_index]; - uint32_t off19; - - if (l->has_value) { - off19 = INSN_OFF19(l->u.value - (unsigned long)s->code_ptr); - } else { - /* Make sure to preserve destinations during retranslation. */ - off19 = *(uint32_t *)s->code_ptr & INSN_OFF19(-1); - tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0); - } - tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | - (0x5 << 19) | off19)); -} -#endif - static const uint8_t tcg_cond_to_bcond[] = { [TCG_COND_EQ] = COND_E, [TCG_COND_NE] = COND_NE, @@ -525,70 +524,144 @@ static const uint8_t tcg_cond_to_bcond[] = { [TCG_COND_GTU] = COND_GU, }; +static const uint8_t tcg_cond_to_rcond[] = { + [TCG_COND_EQ] = RCOND_Z, + [TCG_COND_NE] = RCOND_NZ, + [TCG_COND_LT] = RCOND_LZ, + [TCG_COND_GT] = RCOND_GZ, + [TCG_COND_LE] = RCOND_LEZ, + [TCG_COND_GE] = RCOND_GEZ +}; + +static void tcg_out_bpcc0(TCGContext *s, int scond, int flags, int off19) +{ + tcg_out32(s, INSN_OP(0) | INSN_OP2(1) | INSN_COND(scond) | flags | off19); +} + +static void tcg_out_bpcc(TCGContext *s, int scond, int flags, int label) +{ + TCGLabel *l = &s->labels[label]; + int off19; + + if (l->has_value) { + off19 = INSN_OFF19(l->u.value - (unsigned long)s->code_ptr); + } else { + /* Make sure to preserve destinations during retranslation. */ + off19 = *(uint32_t *)s->code_ptr & INSN_OFF19(-1); + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label, 0); + } + tcg_out_bpcc0(s, scond, flags, off19); +} + static void tcg_out_cmp(TCGContext *s, TCGArg c1, TCGArg c2, int c2const) { tcg_out_arithc(s, TCG_REG_G0, c1, c2, c2const, ARITH_SUBCC); } -static void tcg_out_brcond_i32(TCGContext *s, TCGCond cond, - TCGArg arg1, TCGArg arg2, int const_arg2, - int label_index) +static void tcg_out_brcond_i32(TCGContext *s, TCGCond cond, TCGArg arg1, + TCGArg arg2, int const_arg2, int label) { tcg_out_cmp(s, arg1, arg2, const_arg2); - tcg_out_branch_i32(s, tcg_cond_to_bcond[cond], label_index); + tcg_out_bpcc(s, tcg_cond_to_bcond[cond], BPCC_ICC | BPCC_PT, label); tcg_out_nop(s); } +static void tcg_out_movcc(TCGContext *s, TCGCond cond, int cc, TCGArg ret, + TCGArg v1, int v1const) +{ + tcg_out32(s, ARITH_MOVCC | cc | INSN_RD(ret) + | INSN_RS1(tcg_cond_to_bcond[cond]) + | (v1const ? INSN_IMM11(v1) : INSN_RS2(v1))); +} + +static void tcg_out_movcond_i32(TCGContext *s, TCGCond cond, TCGArg ret, + TCGArg c1, TCGArg c2, int c2const, + TCGArg v1, int v1const) +{ + tcg_out_cmp(s, c1, c2, c2const); + tcg_out_movcc(s, cond, MOVCC_ICC, ret, v1, v1const); +} + #if TCG_TARGET_REG_BITS == 64 -static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, - TCGArg arg1, TCGArg arg2, int const_arg2, - int label_index) +static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, TCGArg arg1, + TCGArg arg2, int const_arg2, int label) { - tcg_out_cmp(s, arg1, arg2, const_arg2); - tcg_out_branch_i64(s, tcg_cond_to_bcond[cond], label_index); + /* For 64-bit signed comparisons vs zero, we can avoid the compare. */ + if (arg2 == 0 && !is_unsigned_cond(cond)) { + TCGLabel *l = &s->labels[label]; + int off16; + + if (l->has_value) { + off16 = INSN_OFF16(l->u.value - (unsigned long)s->code_ptr); + } else { + /* Make sure to preserve destinations during retranslation. */ + off16 = *(uint32_t *)s->code_ptr & INSN_OFF16(-1); + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP16, label, 0); + } + tcg_out32(s, INSN_OP(0) | INSN_OP2(3) | BPR_PT | INSN_RS1(arg1) + | INSN_COND(tcg_cond_to_rcond[cond]) | off16); + } else { + tcg_out_cmp(s, arg1, arg2, const_arg2); + tcg_out_bpcc(s, tcg_cond_to_bcond[cond], BPCC_XCC | BPCC_PT, label); + } tcg_out_nop(s); } + +static void tcg_out_movr(TCGContext *s, TCGCond cond, TCGArg ret, TCGArg c1, + TCGArg v1, int v1const) +{ + tcg_out32(s, ARITH_MOVR | INSN_RD(ret) | INSN_RS1(c1) + | (tcg_cond_to_rcond[cond] << 10) + | (v1const ? INSN_IMM10(v1) : INSN_RS2(v1))); +} + +static void tcg_out_movcond_i64(TCGContext *s, TCGCond cond, TCGArg ret, + TCGArg c1, TCGArg c2, int c2const, + TCGArg v1, int v1const) +{ + /* For 64-bit signed comparisons vs zero, we can avoid the compare. + Note that the immediate range is one bit smaller, so we must check + for that as well. */ + if (c2 == 0 && !is_unsigned_cond(cond) + && (!v1const || check_fit_tl(v1, 10))) { + tcg_out_movr(s, cond, ret, c1, v1, v1const); + } else { + tcg_out_cmp(s, c1, c2, c2const); + tcg_out_movcc(s, cond, MOVCC_XCC, ret, v1, v1const); + } +} #else static void tcg_out_brcond2_i32(TCGContext *s, TCGCond cond, TCGArg al, TCGArg ah, TCGArg bl, int blconst, TCGArg bh, int bhconst, int label_dest) { - int cc, label_next = gen_new_label(); + int scond, label_next = gen_new_label(); tcg_out_cmp(s, ah, bh, bhconst); /* Note that we fill one of the delay slots with the second compare. */ switch (cond) { case TCG_COND_EQ: - cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); - tcg_out_branch_i32(s, cc, label_next); + tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_next); tcg_out_cmp(s, al, bl, blconst); - cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_EQ], 0); - tcg_out_branch_i32(s, cc, label_dest); + tcg_out_bpcc(s, COND_E, BPCC_ICC | BPCC_PT, label_dest); break; case TCG_COND_NE: - cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); - tcg_out_branch_i32(s, cc, label_dest); + tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_dest); tcg_out_cmp(s, al, bl, blconst); - tcg_out_branch_i32(s, cc, label_dest); + tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_dest); break; default: - /* ??? One could fairly easily special-case 64-bit unsigned - compares against 32-bit zero-extended constants. For instance, - we know that (unsigned)AH < 0 is false and need not emit it. - Similarly, (unsigned)AH > 0 being true implies AH != 0, so the - second branch will never be taken. */ - cc = INSN_COND(tcg_cond_to_bcond[cond], 0); - tcg_out_branch_i32(s, cc, label_dest); + scond = tcg_cond_to_bcond[tcg_high_cond(cond)]; + tcg_out_bpcc(s, scond, BPCC_ICC | BPCC_PT, label_dest); tcg_out_nop(s); - cc = INSN_COND(tcg_cond_to_bcond[TCG_COND_NE], 0); - tcg_out_branch_i32(s, cc, label_next); + tcg_out_bpcc(s, COND_NE, BPCC_ICC | BPCC_PT, label_next); tcg_out_cmp(s, al, bl, blconst); - cc = INSN_COND(tcg_cond_to_bcond[tcg_unsigned_cond(cond)], 0); - tcg_out_branch_i32(s, cc, label_dest); + scond = tcg_cond_to_bcond[tcg_unsigned_cond(cond)]; + tcg_out_bpcc(s, scond, BPCC_ICC | BPCC_PT, label_dest); break; } tcg_out_nop(s); @@ -600,39 +673,42 @@ static void tcg_out_brcond2_i32(TCGContext *s, TCGCond cond, static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret, TCGArg c1, TCGArg c2, int c2const) { - TCGArg t; - /* For 32-bit comparisons, we can play games with ADDX/SUBX. */ switch (cond) { + case TCG_COND_LTU: + case TCG_COND_GEU: + /* The result of the comparison is in the carry bit. */ + break; + case TCG_COND_EQ: case TCG_COND_NE: + /* For equality, we can transform to inequality vs zero. */ if (c2 != 0) { tcg_out_arithc(s, ret, c1, c2, c2const, ARITH_XOR); } c1 = TCG_REG_G0, c2 = ret, c2const = 0; - cond = (cond == TCG_COND_EQ ? TCG_COND_LEU : TCG_COND_LTU); + cond = (cond == TCG_COND_EQ ? TCG_COND_GEU : TCG_COND_LTU); break; case TCG_COND_GTU: - case TCG_COND_GEU: - if (c2const && c2 != 0) { - tcg_out_movi_imm13(s, TCG_REG_T1, c2); - c2 = TCG_REG_T1; - } - t = c1, c1 = c2, c2 = t, c2const = 0; - cond = tcg_swap_cond(cond); - break; - - case TCG_COND_LTU: case TCG_COND_LEU: - break; + /* If we don't need to load a constant into a register, we can + swap the operands on GTU/LEU. There's no benefit to loading + the constant into a temporary register. */ + if (!c2const || c2 == 0) { + TCGArg t = c1; + c1 = c2; + c2 = t; + c2const = 0; + cond = tcg_swap_cond(cond); + break; + } + /* FALLTHRU */ default: tcg_out_cmp(s, c1, c2, c2const); tcg_out_movi_imm13(s, ret, 0); - tcg_out32(s, ARITH_MOVCC | INSN_RD(ret) - | INSN_RS1(tcg_cond_to_bcond[cond]) - | MOVCC_ICC | INSN_IMM11(1)); + tcg_out_movcc(s, cond, MOVCC_ICC, ret, 1, 1); return; } @@ -648,11 +724,16 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret, static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGArg ret, TCGArg c1, TCGArg c2, int c2const) { - tcg_out_cmp(s, c1, c2, c2const); - tcg_out_movi_imm13(s, ret, 0); - tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret) - | INSN_RS1(tcg_cond_to_bcond[cond]) - | MOVCC_XCC | INSN_IMM11(1)); + /* For 64-bit signed comparisons vs zero, we can avoid the compare + if the input does not overlap the output. */ + if (c2 == 0 && !is_unsigned_cond(cond) && c1 != ret) { + tcg_out_movi_imm13(s, ret, 0); + tcg_out_movr(s, cond, ret, c1, 1, 1); + } else { + tcg_out_cmp(s, c1, c2, c2const); + tcg_out_movi_imm13(s, ret, 0); + tcg_out_movcc(s, cond, MOVCC_XCC, ret, 1, 1); + } } #else static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret, @@ -660,35 +741,56 @@ static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret, TCGArg bl, int blconst, TCGArg bh, int bhconst) { - int lab; + int tmp = TCG_REG_T1; + + /* Note that the low parts are fully consumed before tmp is set. */ + if (ret != ah && (bhconst || ret != bh)) { + tmp = ret; + } switch (cond) { case TCG_COND_EQ: - tcg_out_setcond_i32(s, TCG_COND_EQ, TCG_REG_T1, al, bl, blconst); - tcg_out_setcond_i32(s, TCG_COND_EQ, ret, ah, bh, bhconst); - tcg_out_arith(s, ret, ret, TCG_REG_T1, ARITH_AND); - break; - case TCG_COND_NE: - tcg_out_setcond_i32(s, TCG_COND_NE, TCG_REG_T1, al, al, blconst); - tcg_out_setcond_i32(s, TCG_COND_NE, ret, ah, bh, bhconst); - tcg_out_arith(s, ret, ret, TCG_REG_T1, ARITH_OR); + if (bl == 0 && bh == 0) { + if (cond == TCG_COND_EQ) { + tcg_out_arith(s, TCG_REG_G0, al, ah, ARITH_ORCC); + tcg_out_movi(s, TCG_TYPE_I32, ret, 1); + } else { + tcg_out_arith(s, ret, al, ah, ARITH_ORCC); + } + } else { + tcg_out_setcond_i32(s, cond, tmp, al, bl, blconst); + tcg_out_cmp(s, ah, bh, bhconst); + tcg_out_mov(s, TCG_TYPE_I32, ret, tmp); + } + tcg_out_movcc(s, TCG_COND_NE, MOVCC_ICC, ret, cond == TCG_COND_NE, 1); break; default: - lab = gen_new_label(); - + /* <= : ah < bh | (ah == bh && al <= bl) */ + tcg_out_setcond_i32(s, tcg_unsigned_cond(cond), tmp, al, bl, blconst); tcg_out_cmp(s, ah, bh, bhconst); - tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), lab); - tcg_out_movi_imm13(s, ret, 1); - tcg_out_branch_i32(s, INSN_COND(COND_NE, 1), lab); - tcg_out_movi_imm13(s, ret, 0); + tcg_out_mov(s, TCG_TYPE_I32, ret, tmp); + tcg_out_movcc(s, TCG_COND_NE, MOVCC_ICC, ret, 0, 1); + tcg_out_movcc(s, tcg_high_cond(cond), MOVCC_ICC, ret, 1, 1); + break; + } +} - tcg_out_setcond_i32(s, tcg_unsigned_cond(cond), ret, al, bl, blconst); +static void tcg_out_addsub2(TCGContext *s, TCGArg rl, TCGArg rh, + TCGArg al, TCGArg ah, TCGArg bl, int blconst, + TCGArg bh, int bhconst, int opl, int oph) +{ + TCGArg tmp = TCG_REG_T1; - tcg_out_label(s, lab, s->code_ptr); - break; + /* Note that the low parts are fully consumed before tmp is set. */ + if (rl != ah && (bhconst || rl != bh)) { + tmp = rl; } + + tcg_out_arithc(s, tmp, al, bl, blconst, opl); + tcg_out_arithc(s, rh, ah, bh, bhconst, oph); + tcg_out_mov(s, TCG_TYPE_I32, rl, tmp); } #endif @@ -859,8 +961,8 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int sizeop) /* bne,pn %[xi]cc, label0 */ label_ptr[0] = (uint32_t *)s->code_ptr; - tcg_out32(s, (INSN_OP(0) | INSN_COND(COND_NE, 0) | INSN_OP2(0x1) - | ((TARGET_LONG_BITS == 64) << 21))); + tcg_out_bpcc0(s, COND_NE, BPCC_PN + | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0); /* TLB Hit. */ /* Load all 64-bits into an O/G register. */ @@ -875,8 +977,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int sizeop) /* b,a,pt label1 */ label_ptr[1] = (uint32_t *)s->code_ptr; - tcg_out32(s, (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x1) - | (1 << 29) | (1 << 19))); + tcg_out_bpcc0(s, COND_A, BPCC_A | BPCC_PT, 0); } else { /* The fast path is exactly one insn. Thus we can perform the entire TLB Hit in the (annulled) delay slot of the branch @@ -885,9 +986,8 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int sizeop) /* beq,a,pt %[xi]cc, label0 */ label_ptr[0] = NULL; label_ptr[1] = (uint32_t *)s->code_ptr; - tcg_out32(s, (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) - | ((TARGET_LONG_BITS == 64) << 21) - | (1 << 29) | (1 << 19))); + tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT + | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0); /* delay slot */ tcg_out_ldst_rr(s, datalo, addr_reg, TCG_REG_O1, qemu_ld_opc[sizeop]); } @@ -976,7 +1076,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int sizeop) { int addrlo_idx = 1, datalo, datahi, addr_reg; #if defined(CONFIG_SOFTMMU) - int memi_idx, memi, n; + int memi_idx, memi, n, datafull; uint32_t *label_ptr; #endif @@ -993,23 +1093,23 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int sizeop) addr_reg = tcg_out_tlb_load(s, addrlo_idx, memi, sizeop, args, offsetof(CPUTLBEntry, addr_write)); + datafull = datalo; if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { /* Reconstruct the full 64-bit value. */ tcg_out_arithi(s, TCG_REG_T1, datalo, 0, SHIFT_SRL); tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX); tcg_out_arith(s, TCG_REG_O2, TCG_REG_T1, TCG_REG_O2, ARITH_OR); - datalo = TCG_REG_O2; + datafull = TCG_REG_O2; } /* The fast path is exactly one insn. Thus we can perform the entire TLB Hit in the (annulled) delay slot of the branch over TLB Miss. */ /* beq,a,pt %[xi]cc, label0 */ label_ptr = (uint32_t *)s->code_ptr; - tcg_out32(s, (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) - | ((TARGET_LONG_BITS == 64) << 21) - | (1 << 29) | (1 << 19))); + tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT + | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0); /* delay slot */ - tcg_out_ldst_rr(s, datalo, addr_reg, TCG_REG_O1, qemu_st_opc[sizeop]); + tcg_out_ldst_rr(s, datafull, addr_reg, TCG_REG_O1, qemu_st_opc[sizeop]); /* TLB Miss. */ @@ -1098,7 +1198,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out_nop(s); break; case INDEX_op_br: - tcg_out_branch_i32(s, COND_A, args[0]); + tcg_out_bpcc(s, COND_A, BPCC_PT, args[0]); tcg_out_nop(s); break; case INDEX_op_movi_i32: @@ -1211,6 +1311,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out_setcond_i32(s, args[3], args[0], args[1], args[2], const_args[2]); break; + case INDEX_op_movcond_i32: + tcg_out_movcond_i32(s, args[5], args[0], args[1], + args[2], const_args[2], args[3], const_args[3]); + break; #if TCG_TARGET_REG_BITS == 32 case INDEX_op_brcond2_i32: @@ -1224,16 +1328,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, args[4], const_args[4]); break; case INDEX_op_add2_i32: - tcg_out_arithc(s, args[0], args[2], args[4], const_args[4], - ARITH_ADDCC); - tcg_out_arithc(s, args[1], args[3], args[5], const_args[5], - ARITH_ADDX); + tcg_out_addsub2(s, args[0], args[1], args[2], args[3], + args[4], const_args[4], args[5], const_args[5], + ARITH_ADDCC, ARITH_ADDX); break; case INDEX_op_sub2_i32: - tcg_out_arithc(s, args[0], args[2], args[4], const_args[4], - ARITH_SUBCC); - tcg_out_arithc(s, args[1], args[3], args[5], const_args[5], - ARITH_SUBX); + tcg_out_addsub2(s, args[0], args[1], args[2], args[3], + args[4], const_args[4], args[5], const_args[5], + ARITH_SUBCC, ARITH_SUBX); break; case INDEX_op_mulu2_i32: tcg_out_arithc(s, args[0], args[2], args[3], const_args[3], @@ -1346,7 +1448,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out_setcond_i64(s, args[3], args[0], args[1], args[2], const_args[2]); break; - + case INDEX_op_movcond_i64: + tcg_out_movcond_i64(s, args[5], args[0], args[1], + args[2], const_args[2], args[3], const_args[3]); + break; #endif gen_arith: tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c); @@ -1375,39 +1480,40 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_ld16u_i32, { "r", "r" } }, { INDEX_op_ld16s_i32, { "r", "r" } }, { INDEX_op_ld_i32, { "r", "r" } }, - { INDEX_op_st8_i32, { "r", "r" } }, - { INDEX_op_st16_i32, { "r", "r" } }, - { INDEX_op_st_i32, { "r", "r" } }, - - { INDEX_op_add_i32, { "r", "r", "rJ" } }, - { INDEX_op_mul_i32, { "r", "r", "rJ" } }, - { INDEX_op_div_i32, { "r", "r", "rJ" } }, - { INDEX_op_divu_i32, { "r", "r", "rJ" } }, - { INDEX_op_rem_i32, { "r", "r", "rJ" } }, - { INDEX_op_remu_i32, { "r", "r", "rJ" } }, - { INDEX_op_sub_i32, { "r", "r", "rJ" } }, - { INDEX_op_and_i32, { "r", "r", "rJ" } }, - { INDEX_op_andc_i32, { "r", "r", "rJ" } }, - { INDEX_op_or_i32, { "r", "r", "rJ" } }, - { INDEX_op_orc_i32, { "r", "r", "rJ" } }, - { INDEX_op_xor_i32, { "r", "r", "rJ" } }, - - { INDEX_op_shl_i32, { "r", "r", "rJ" } }, - { INDEX_op_shr_i32, { "r", "r", "rJ" } }, - { INDEX_op_sar_i32, { "r", "r", "rJ" } }, + { INDEX_op_st8_i32, { "rZ", "r" } }, + { INDEX_op_st16_i32, { "rZ", "r" } }, + { INDEX_op_st_i32, { "rZ", "r" } }, + + { INDEX_op_add_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_mul_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_div_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_divu_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_rem_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_remu_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_sub_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_and_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_andc_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_or_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_orc_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_xor_i32, { "r", "rZ", "rJ" } }, + + { INDEX_op_shl_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_shr_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_sar_i32, { "r", "rZ", "rJ" } }, { INDEX_op_neg_i32, { "r", "rJ" } }, { INDEX_op_not_i32, { "r", "rJ" } }, - { INDEX_op_brcond_i32, { "r", "rJ" } }, - { INDEX_op_setcond_i32, { "r", "r", "rJ" } }, + { INDEX_op_brcond_i32, { "rZ", "rJ" } }, + { INDEX_op_setcond_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_movcond_i32, { "r", "rZ", "rJ", "rI", "0" } }, #if TCG_TARGET_REG_BITS == 32 - { INDEX_op_brcond2_i32, { "r", "r", "rJ", "rJ" } }, - { INDEX_op_setcond2_i32, { "r", "r", "r", "rJ", "rJ" } }, - { INDEX_op_add2_i32, { "r", "r", "r", "r", "rJ", "rJ" } }, - { INDEX_op_sub2_i32, { "r", "r", "r", "r", "rJ", "rJ" } }, - { INDEX_op_mulu2_i32, { "r", "r", "r", "rJ" } }, + { INDEX_op_brcond2_i32, { "rZ", "rZ", "rJ", "rJ" } }, + { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rJ", "rJ" } }, + { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } }, + { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } }, + { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rJ" } }, #endif #if TCG_TARGET_REG_BITS == 64 @@ -1420,27 +1526,27 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_ld32u_i64, { "r", "r" } }, { INDEX_op_ld32s_i64, { "r", "r" } }, { INDEX_op_ld_i64, { "r", "r" } }, - { INDEX_op_st8_i64, { "r", "r" } }, - { INDEX_op_st16_i64, { "r", "r" } }, - { INDEX_op_st32_i64, { "r", "r" } }, - { INDEX_op_st_i64, { "r", "r" } }, - - { INDEX_op_add_i64, { "r", "r", "rJ" } }, - { INDEX_op_mul_i64, { "r", "r", "rJ" } }, - { INDEX_op_div_i64, { "r", "r", "rJ" } }, - { INDEX_op_divu_i64, { "r", "r", "rJ" } }, - { INDEX_op_rem_i64, { "r", "r", "rJ" } }, - { INDEX_op_remu_i64, { "r", "r", "rJ" } }, - { INDEX_op_sub_i64, { "r", "r", "rJ" } }, - { INDEX_op_and_i64, { "r", "r", "rJ" } }, - { INDEX_op_andc_i64, { "r", "r", "rJ" } }, - { INDEX_op_or_i64, { "r", "r", "rJ" } }, - { INDEX_op_orc_i64, { "r", "r", "rJ" } }, - { INDEX_op_xor_i64, { "r", "r", "rJ" } }, - - { INDEX_op_shl_i64, { "r", "r", "rJ" } }, - { INDEX_op_shr_i64, { "r", "r", "rJ" } }, - { INDEX_op_sar_i64, { "r", "r", "rJ" } }, + { INDEX_op_st8_i64, { "rZ", "r" } }, + { INDEX_op_st16_i64, { "rZ", "r" } }, + { INDEX_op_st32_i64, { "rZ", "r" } }, + { INDEX_op_st_i64, { "rZ", "r" } }, + + { INDEX_op_add_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_mul_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_div_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_divu_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_rem_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_remu_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_sub_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_and_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_andc_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_or_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_orc_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_xor_i64, { "r", "rZ", "rJ" } }, + + { INDEX_op_shl_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_shr_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_sar_i64, { "r", "rZ", "rJ" } }, { INDEX_op_neg_i64, { "r", "rJ" } }, { INDEX_op_not_i64, { "r", "rJ" } }, @@ -1448,8 +1554,9 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_ext32s_i64, { "r", "ri" } }, { INDEX_op_ext32u_i64, { "r", "ri" } }, - { INDEX_op_brcond_i64, { "r", "rJ" } }, - { INDEX_op_setcond_i64, { "r", "r", "rJ" } }, + { INDEX_op_brcond_i64, { "rZ", "rJ" } }, + { INDEX_op_setcond_i64, { "r", "rZ", "rJ" } }, + { INDEX_op_movcond_i64, { "r", "rZ", "rJ", "rI", "0" } }, #endif #if TCG_TARGET_REG_BITS == 64 diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index 4a17f1e118..0e7d398a41 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -62,8 +62,9 @@ typedef enum { TCG_REG_I7, } TCGReg; -#define TCG_CT_CONST_S11 0x100 -#define TCG_CT_CONST_S13 0x200 +#define TCG_CT_CONST_S11 0x100 +#define TCG_CT_CONST_S13 0x200 +#define TCG_CT_CONST_ZERO 0x400 /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_O6 @@ -99,7 +100,7 @@ typedef enum { #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 0 -#define TCG_TARGET_HAS_movcond_i32 0 +#define TCG_TARGET_HAS_movcond_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div_i64 1 @@ -121,7 +122,7 @@ typedef enum { #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 0 -#define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_movcond_i64 1 #endif #define TCG_AREG0 TCG_REG_I0 diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 551845801d..8100a5a2e0 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -25,6 +25,11 @@ int gen_new_label(void); +static inline void tcg_gen_op0(TCGOpcode opc) +{ + *gen_opc_ptr++ = opc; +} + static inline void tcg_gen_op1_i32(TCGOpcode opc, TCGv_i32 arg1) { *gen_opc_ptr++ = opc; @@ -886,6 +891,8 @@ static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op6_i32(INDEX_op_add2_i32, TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); + /* Allow the optimizer room to replace add2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); } static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) @@ -893,6 +900,8 @@ static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op6_i32(INDEX_op_sub2_i32, TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); + /* Allow the optimizer room to replace sub2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); } static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) @@ -1018,6 +1027,8 @@ static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op4_i32(INDEX_op_mulu2_i32, TCGV_LOW(t0), TCGV_HIGH(t0), TCGV_LOW(arg1), TCGV_LOW(arg2)); + /* Allow the optimizer room to replace mulu2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2)); tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); @@ -1303,8 +1303,58 @@ static void tcg_liveness_analysis(TCGContext *s) break; case INDEX_op_end: break; - /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ + + case INDEX_op_add2_i32: + case INDEX_op_sub2_i32: + args -= 6; + nb_iargs = 4; + nb_oargs = 2; + /* Test if the high part of the operation is dead, but not + the low part. The result can be optimized to a simple + add or sub. This happens often for x86_64 guest when the + cpu mode is set to 32 bit. */ + if (dead_temps[args[1]]) { + if (dead_temps[args[0]]) { + goto do_remove; + } + /* Create the single operation plus nop. */ + if (op == INDEX_op_add2_i32) { + op = INDEX_op_add_i32; + } else { + op = INDEX_op_sub_i32; + } + gen_opc_buf[op_index] = op; + args[1] = args[2]; + args[2] = args[4]; + assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + tcg_set_nop(s, gen_opc_buf + op_index + 1, args + 3, 3); + /* Fall through and mark the single-word operation live. */ + nb_iargs = 2; + nb_oargs = 1; + } + goto do_not_remove; + + case INDEX_op_mulu2_i32: + args -= 4; + nb_iargs = 2; + nb_oargs = 2; + /* Likewise, test for the high part of the operation dead. */ + if (dead_temps[args[1]]) { + if (dead_temps[args[0]]) { + goto do_remove; + } + gen_opc_buf[op_index] = op = INDEX_op_mul_i32; + args[1] = args[2]; + args[2] = args[3]; + assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + tcg_set_nop(s, gen_opc_buf + op_index + 1, args + 3, 1); + /* Fall through and mark the single-word operation live. */ + nb_oargs = 1; + } + goto do_not_remove; + default: + /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ args -= def->nb_args; nb_iargs = def->nb_iargs; nb_oargs = def->nb_oargs; @@ -1318,6 +1368,7 @@ static void tcg_liveness_analysis(TCGContext *s) if (!dead_temps[arg]) goto do_not_remove; } + do_remove: tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); #ifdef CONFIG_PROFILER s->del_op_count++; diff --git a/ui/spice-core.c b/ui/spice-core.c index ba0d0bdbc2..51473650c0 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -223,7 +223,6 @@ static void channel_event(int event, SpiceChannelEventInfo *info) client = qdict_new(); server = qdict_new(); -#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { add_addr_info(client, (struct sockaddr *)&info->paddr_ext, info->plen_ext); @@ -232,12 +231,7 @@ static void channel_event(int event, SpiceChannelEventInfo *info) } else { error_report("spice: %s, extended address is expected", __func__); -#endif - add_addr_info(client, &info->paddr, info->plen); - add_addr_info(server, &info->laddr, info->llen); -#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT } -#endif if (event == SPICE_CHANNEL_EVENT_INITIALIZED) { qdict_put(server, "auth", qstring_from_str(auth)); @@ -276,7 +270,6 @@ static SpiceCoreInterface core_interface = { .channel_event = channel_event, }; -#ifdef SPICE_INTERFACE_MIGRATION typedef struct SpiceMigration { SpiceMigrateInstance sin; struct { @@ -313,7 +306,6 @@ static void migrate_end_complete_cb(SpiceMigrateInstance *sin) monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); spice_migration_completed = true; } -#endif /* config string parsing */ @@ -393,17 +385,13 @@ static SpiceChannelList *qmp_query_spice_channels(void) chan = g_malloc0(sizeof(*chan)); chan->value = g_malloc0(sizeof(*chan->value)); -#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT if (item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { paddr = (struct sockaddr *)&item->info->paddr_ext; plen = item->info->plen_ext; } else { -#endif paddr = &item->info->paddr; plen = item->info->plen; -#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT } -#endif getnameinfo(paddr, plen, host, sizeof(host), port, sizeof(port), @@ -473,13 +461,10 @@ 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(); @@ -492,19 +477,11 @@ static void migration_state_notifier(Notifier *notifier, void *data) MigrationState *s = data; if (migration_is_active(s)) { -#ifdef SPICE_INTERFACE_MIGRATION spice_server_migrate_start(spice_server); -#endif } else if (migration_has_finished(s)) { -#ifndef SPICE_INTERFACE_MIGRATION - spice_server_migrate_switch(spice_server); - monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); - spice_migration_completed = true; -#else spice_server_migrate_end(spice_server, true); } else if (migration_has_failed(s)) { spice_server_migrate_end(spice_server, false); -#endif } } @@ -513,16 +490,11 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, MonitorCompletion *cb, void *opaque) { int ret; -#ifdef SPICE_INTERFACE_MIGRATION + spice_migrate.connect_complete.cb = cb; spice_migrate.connect_complete.opaque = opaque; ret = spice_server_migrate_connect(spice_server, hostname, port, tls_port, subject); -#else - ret = spice_server_migrate_info(spice_server, hostname, - port, tls_port, subject); - cb(opaque, NULL); -#endif return ret; } @@ -561,7 +533,6 @@ static int add_channel(const char *name, const char *value, void *opaque) static void vm_change_state_handler(void *opaque, int running, RunState state) { -#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ if (running) { qemu_spice_display_start(); spice_server_vm_start(spice_server); @@ -569,7 +540,6 @@ static void vm_change_state_handler(void *opaque, int running, spice_server_vm_stop(spice_server); qemu_spice_display_stop(); } -#endif } void qemu_spice_init(void) @@ -585,9 +555,7 @@ void qemu_spice_init(void) int port, tls_port, len, addr_flags; spice_image_compression_t compression; spice_wan_compression_t wan_compr; -#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ bool seamless_migration; -#endif qemu_thread_get_self(&me); @@ -672,16 +640,11 @@ void qemu_spice_init(void) spice_server_set_ticket(spice_server, password, 0, 0, 0); } if (qemu_opt_get_bool(opts, "sasl", 0)) { -#if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */ if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 || spice_server_set_sasl(spice_server, 1) == -1) { error_report("spice: failed to enable sasl"); exit(1); } -#else - error_report("spice: sasl is not available (spice >= 0.9 required)"); - exit(1); -#endif } if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) { auth = "none"; @@ -726,15 +689,11 @@ void qemu_spice_init(void) qemu_opt_foreach(opts, add_channel, &tls_port, 0); -#if SPICE_SERVER_VERSION >= 0x000a02 /* 0.10.2 */ spice_server_set_name(spice_server, qemu_name); spice_server_set_uuid(spice_server, qemu_uuid); -#endif -#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); spice_server_set_seamless_migration(spice_server, seamless_migration); -#endif if (0 != spice_server_init(spice_server, &core_interface)) { error_report("failed to initialize spice server"); exit(1); @@ -743,11 +702,9 @@ void qemu_spice_init(void) migration_state.notify = migration_state_notifier; add_migration_state_change_notifier(&migration_state); -#ifdef SPICE_INTERFACE_MIGRATION spice_migrate.sin.base.sif = &migrate_interface.base; spice_migrate.connect_complete.cb = NULL; qemu_spice_add_interface(&spice_migrate.sin.base); -#endif qemu_spice_input_init(); qemu_spice_audio_init(); @@ -815,15 +772,11 @@ int qemu_spice_set_pw_expire(time_t expires) int qemu_spice_display_add_client(int csock, int skipauth, int tls) { -#if SPICE_SERVER_VERSION >= 0x000a01 if (tls) { return spice_server_add_ssl_client(spice_server, csock, skipauth); } else { return spice_server_add_client(spice_server, csock, skipauth); } -#else - return -1; -#endif } static void spice_register_config(void) diff --git a/ui/spice-display.c b/ui/spice-display.c index 50fbefb067..b61764f381 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -126,21 +126,6 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) ssd->worker->wakeup(ssd->worker); } -#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ -static void qemu_spice_start(SimpleSpiceDisplay *ssd) -{ - trace_qemu_spice_start(ssd->qxl.id); - ssd->worker->start(ssd->worker); -} - -static void qemu_spice_stop(SimpleSpiceDisplay *ssd) -{ - trace_qemu_spice_stop(ssd->qxl.id); - ssd->worker->stop(ssd->worker); -} - -#else - static int spice_display_is_running; void qemu_spice_display_start(void) @@ -153,15 +138,9 @@ void qemu_spice_display_stop(void) spice_display_is_running = false; } -#endif - int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) { -#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ - return ssd->running; -#else return spice_display_is_running; -#endif } static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, @@ -364,22 +343,6 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); } -void qemu_spice_vm_change_state_handler(void *opaque, int running, - RunState state) -{ -#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ - SimpleSpiceDisplay *ssd = opaque; - - if (running) { - ssd->running = true; - qemu_spice_start(ssd); - } else { - qemu_spice_stop(ssd); - ssd->running = false; - } -#endif -} - void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) { ssd->ds = ds; @@ -623,7 +586,6 @@ void qemu_spice_display_init(DisplayState *ds) qemu_spice_add_interface(&sdpy.qxl.base); assert(sdpy.worker); - qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy); qemu_spice_create_host_memslot(&sdpy); qemu_spice_create_host_primary(&sdpy); } diff --git a/ui/spice-display.h b/ui/spice-display.h index dea41c1b71..d7669277fd 100644 --- a/ui/spice-display.h +++ b/ui/spice-display.h @@ -83,9 +83,6 @@ struct SimpleSpiceDisplay { QXLRect dirty; int notify; -#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ - int running; -#endif /* * All struct members below this comment can be accessed from @@ -133,8 +130,6 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, qxl_async_io async); void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); -#if SPICE_SERVER_VERSION >= 0x000b02 /* before 0.11.2 */ void qemu_spice_display_start(void); void qemu_spice_display_stop(void); -#endif int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd); diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index 087b84d319..3c592b3f3d 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -33,21 +33,21 @@ /* * Locking: * - * There is three levels of locking: + * There are three levels of locking: * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) * - VncDisplay global lock: mainly used for framebuffer updates to avoid * screen corruption if the framebuffer is updated - * while the worker is doing something. + * while the worker is doing something. * - VncState::output lock: used to make sure the output buffer is not corrupted - * if two threads try to write on it at the same time + * if two threads try to write on it at the same time * - * While the VNC worker thread is working, the VncDisplay global lock is hold - * to avoid screen corruptions (this does not block vnc_refresh() because it - * uses trylock()) but the output lock is not hold because the thread work on + * While the VNC worker thread is working, the VncDisplay global lock is held + * to avoid screen corruption (this does not block vnc_refresh() because it + * uses trylock()) but the output lock is not held because the thread works on * its own output buffer. * When the encoding job is done, the worker thread will hold the output lock * and copy its output buffer in vs->output. -*/ + */ struct VncJobQueue { QemuCond cond; @@ -62,7 +62,7 @@ typedef struct VncJobQueue VncJobQueue; /* * We use a single global queue, but most of the functions are - * already reetrant, so we can easilly add more than one encoding thread + * already reentrant, so we can easily add more than one encoding thread */ static VncJobQueue *queue; @@ -372,6 +372,10 @@ VncInfo *qmp_query_vnc(Error **errp) } } + if (vnc_display->lsock == -1) { + return info; + } + if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa, &salen) == -1) { error_set(errp, QERR_UNDEFINED_ERROR); @@ -1802,10 +1806,12 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) vs->features |= VNC_FEATURE_TIGHT_MASK; vs->vnc_encoding = enc; break; +#ifdef CONFIG_VNC_PNG case VNC_ENCODING_TIGHT_PNG: vs->features |= VNC_FEATURE_TIGHT_PNG_MASK; vs->vnc_encoding = enc; break; +#endif case VNC_ENCODING_ZLIB: vs->features |= VNC_FEATURE_ZLIB_MASK; vs->vnc_encoding = enc; |