diff options
98 files changed, 2526 insertions, 1521 deletions
@@ -8,6 +8,17 @@ ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. all: include config-host.mak + +# Check that we're not trying to do an out-of-tree build from +# a tree that's been used for an in-tree build. +ifneq ($(realpath $(SRC_PATH)),$(realpath .)) +ifneq ($(wildcard $(SRC_PATH)/config-host.mak),) +$(error This is an out of tree build but your source tree ($(SRC_PATH)) \ +seems to have been used for an in-tree build. You can fix this by running \ +"make distclean && rm -rf *-linux-user *-softmmu" in your source tree) +endif +endif + include $(SRC_PATH)/rules.mak config-host.mak: $(SRC_PATH)/configure @echo $@ is out-of-date, running configure @@ -161,11 +172,10 @@ qemu-img.o: qemu-img-cmds.h tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ qemu-timer-common.o main-loop.o notify.o \ - iohandler.o cutils.o iov.o async.o + iohandler.o cutils.o iov.o async.o error.o tools-obj-$(CONFIG_POSIX) += compatfd.o -qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) $(qapi-obj-y) \ - qapi-visit.o qapi-types.o +qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) diff --git a/Makefile.objs b/Makefile.objs index 74b3542..9eca179 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -43,11 +43,12 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o block-obj-y = cutils.o iov.o cache-utils.o qemu-option.o module.o async.o block-obj-y += nbd.o block.o blockjob.o aio.o aes.o qemu-config.o -block-obj-y += qemu-progress.o qemu-sockets.o uri.o +block-obj-y += qemu-progress.o qemu-sockets.o uri.o notify.o block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y) block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o block-obj-y += block/ +block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. @@ -60,7 +61,7 @@ endif # suppress *all* target specific code in case of system emulation, i.e. a # single QEMU executable should support all CPUs and machines. -common-obj-y = $(block-obj-y) blockdev.o block/ +common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net.o net/ common-obj-y += qom/ common-obj-y += readline.o console.o cursor.o @@ -93,7 +94,7 @@ common-obj-y += bt-host.o bt-vhci.o common-obj-y += dma-helpers.o common-obj-y += iov.o acl.o common-obj-$(CONFIG_POSIX) += compatfd.o -common-obj-y += notify.o event_notifier.o +common-obj-y += event_notifier.o common-obj-y += qemu-timer.o qemu-timer-common.o common-obj-y += qtest.o common-obj-y += vl.o @@ -239,9 +240,9 @@ QEMU_CFLAGS+=$(GLIB_CFLAGS) nested-vars += \ qga-obj-y \ - block-obj-y \ qom-obj-y \ qapi-obj-y \ + block-obj-y \ user-obj-y \ common-obj-y \ extra-obj-y @@ -30,6 +30,7 @@ #include "module.h" #include "qjson.h" #include "sysemu.h" +#include "notify.h" #include "qemu-coroutine.h" #include "qmp-commands.h" #include "qemu-timer.h" @@ -312,9 +313,16 @@ BlockDriverState *bdrv_new(const char *device_name) QTAILQ_INSERT_TAIL(&bdrv_states, bs, list); } bdrv_iostatus_disable(bs); + notifier_list_init(&bs->close_notifiers); + return bs; } +void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify) +{ + notifier_list_add(&bs->close_notifiers, notify); +} + BlockDriver *bdrv_find_format(const char *format_name) { BlockDriver *drv1; @@ -1120,12 +1128,13 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) void bdrv_close(BlockDriverState *bs) { bdrv_flush(bs); - if (bs->drv) { - if (bs->job) { - block_job_cancel_sync(bs->job); - } - bdrv_drain_all(); + if (bs->job) { + block_job_cancel_sync(bs->job); + } + bdrv_drain_all(); + notifier_list_notify(&bs->close_notifiers, bs); + if (bs->drv) { if (bs == bs_snapshots) { bs_snapshots = NULL; } @@ -145,6 +145,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, void bdrv_reopen_commit(BDRVReopenState *reopen_state); void bdrv_reopen_abort(BDRVReopenState *reopen_state); void bdrv_close(BlockDriverState *bs); +void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify); int bdrv_attach_dev(BlockDriverState *bs, void *dev); void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev); void bdrv_detach_dev(BlockDriverState *bs, void *dev); diff --git a/block_int.h b/block_int.h index 00204eb..9deedb8 100644 --- a/block_int.h +++ b/block_int.h @@ -233,6 +233,8 @@ struct BlockDriverState { BlockDriverState *backing_hd; BlockDriverState *file; + NotifierList close_notifiers; + /* number of in-flight copy-on-read requests */ unsigned int copy_on_read_in_flight; diff --git a/blockdev-nbd.c b/blockdev-nbd.c new file mode 100644 index 0000000..8031813 --- /dev/null +++ b/blockdev-nbd.c @@ -0,0 +1,119 @@ +/* + * Serving QEMU block devices via NBD + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "blockdev.h" +#include "hw/block-common.h" +#include "monitor.h" +#include "qerror.h" +#include "sysemu.h" +#include "qmp-commands.h" +#include "trace.h" +#include "nbd.h" +#include "qemu_socket.h" + +static int server_fd = -1; + +static void nbd_accept(void *opaque) +{ + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); + if (fd >= 0) { + nbd_client_new(NULL, fd, nbd_client_put); + } +} + +void qmp_nbd_server_start(SocketAddress *addr, Error **errp) +{ + if (server_fd != -1) { + error_setg(errp, "NBD server already running"); + return; + } + + server_fd = socket_listen(addr, errp); + if (server_fd != -1) { + qemu_set_fd_handler2(server_fd, NULL, nbd_accept, NULL, NULL); + } +} + +/* Hook into the BlockDriverState notifiers to close the export when + * the file is closed. + */ +typedef struct NBDCloseNotifier { + Notifier n; + NBDExport *exp; + QTAILQ_ENTRY(NBDCloseNotifier) next; +} NBDCloseNotifier; + +static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers = + QTAILQ_HEAD_INITIALIZER(close_notifiers); + +static void nbd_close_notifier(Notifier *n, void *data) +{ + NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n); + + notifier_remove(&cn->n); + QTAILQ_REMOVE(&close_notifiers, cn, next); + + nbd_export_close(cn->exp); + nbd_export_put(cn->exp); + g_free(cn); +} + +static void nbd_server_put_ref(NBDExport *exp) +{ + BlockDriverState *bs = nbd_export_get_blockdev(exp); + drive_put_ref(drive_get_by_blockdev(bs)); +} + +void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, + Error **errp) +{ + BlockDriverState *bs; + NBDExport *exp; + NBDCloseNotifier *n; + + if (nbd_export_find(device)) { + error_setg(errp, "NBD server already exporting device '%s'", device); + return; + } + + bs = bdrv_find(device); + if (!bs) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return; + } + + exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, + nbd_server_put_ref); + + nbd_export_set_name(exp, device); + drive_get_ref(drive_get_by_blockdev(bs)); + + n = g_malloc0(sizeof(NBDCloseNotifier)); + n->n.notify = nbd_close_notifier; + n->exp = exp; + bdrv_add_close_notifier(bs, &n->n); + QTAILQ_INSERT_TAIL(&close_notifiers, n, next); +} + +void qmp_nbd_server_stop(Error **errp) +{ + while (!QTAILQ_EMPTY(&close_notifiers)) { + NBDCloseNotifier *cn = QTAILQ_FIRST(&close_notifiers); + nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp)); + } + + qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL); + close(server_fd); + server_fd = -1; +} @@ -1160,6 +1160,7 @@ gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" gcc_flags="-fstack-protector-all -Wendif-labels $gcc_flags" +gcc_flags="-Wno-initializer-overrides $gcc_flags" # Note that we do not add -Werror to gcc_flags here, because that would # enable it for all configure tests. If a configure test failed due # to -Werror this would just silently disable some features, @@ -2398,8 +2399,7 @@ cat > $TMPC << EOF int main(void) { int pipefd[2]; - pipe2(pipefd, O_CLOEXEC); - return 0; + return pipe2(pipefd, O_CLOEXEC); } EOF if compile_prog "" "" ; then @@ -2813,6 +2813,24 @@ if compile_prog "" "" ; then fi ########################################## +# check if we have usable SIGEV_THREAD_ID + +sigev_thread_id=no +cat > $TMPC << EOF +#include <signal.h> +int main(void) { + struct sigevent ev; + ev.sigev_notify = SIGEV_THREAD_ID; + ev._sigev_un._tid = 0; + asm volatile("" : : "g"(&ev)); + return 0; +} +EOF +if compile_prog "" "" ; then + sigev_thread_id=yes +fi + +########################################## # check if trace backend exists $python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend > /dev/null 2> /dev/null @@ -3159,6 +3177,7 @@ echo "preadv support $preadv" echo "fdatasync $fdatasync" echo "madvise $madvise" echo "posix_madvise $posix_madvise" +echo "sigev_thread_id $sigev_thread_id" echo "uuid support $uuid" echo "libcap-ng support $cap_ng" echo "vhost-net support $vhost_net" @@ -3443,6 +3462,9 @@ fi if test "$posix_madvise" = "yes" ; then echo "CONFIG_POSIX_MADVISE=y" >> $config_host_mak fi +if test "$sigev_thread_id" = "yes" ; then + echo "CONFIG_SIGEV_THREAD_ID=y" >> $config_host_mak +fi if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak @@ -378,7 +378,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen); /* vnc.c */ void vnc_display_init(DisplayState *ds); void vnc_display_close(DisplayState *ds); -int vnc_display_open(DisplayState *ds, const char *display); +void vnc_display_open(DisplayState *ds, const char *display, Error **errp); void vnc_display_add_client(DisplayState *ds, int csock, int skipauth); int vnc_display_disable_login(DisplayState *ds); char *vnc_display_local_addr(DisplayState *ds); diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak index c9a36c1..03e8b42 100644 --- a/default-configs/sparc64-softmmu.mak +++ b/default-configs/sparc64-softmmu.mak @@ -6,7 +6,6 @@ CONFIG_M48T59=y CONFIG_PTIMER=y CONFIG_VGA=y CONFIG_VGA_PCI=y -CONFIG_VGA_CIRRUS=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_PCKBD=y @@ -43,6 +43,34 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) *errp = err; } +void error_set_errno(Error **errp, int os_errno, ErrorClass err_class, + const char *fmt, ...) +{ + Error *err; + char *msg1; + va_list ap; + + if (errp == NULL) { + return; + } + assert(*errp == NULL); + + err = g_malloc0(sizeof(*err)); + + va_start(ap, fmt); + msg1 = g_strdup_vprintf(fmt, ap); + if (os_errno != 0) { + err->msg = g_strdup_printf("%s: %s", msg1, strerror(os_errno)); + g_free(msg1); + } else { + err->msg = msg1; + } + va_end(ap); + err->err_class = err_class; + + *errp = err; +} + Error *error_copy(const Error *err) { Error *err_new; @@ -30,10 +30,19 @@ typedef struct Error Error; void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4); /** + * Set an indirect pointer to an error given a ErrorClass value and a + * printf-style human message, followed by a strerror() string if + * @os_error is not zero. + */ +void error_set_errno(Error **err, int os_error, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(4, 5); + +/** * Same as error_set(), but sets a generic error */ #define error_setg(err, fmt, ...) \ error_set(err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) +#define error_setg_errno(err, os_error, fmt, ...) \ + error_set_errno(err, os_error, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) /** * Returns true if an indirect pointer to an error is pointing to a valid @@ -245,20 +245,19 @@ void hmp_info_cpus(Monitor *mon) active = '*'; } - monitor_printf(mon, "%c CPU #%" PRId64 ": ", active, cpu->value->CPU); + monitor_printf(mon, "%c CPU #%" PRId64 ":", active, cpu->value->CPU); if (cpu->value->has_pc) { - monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc); + monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->pc); } if (cpu->value->has_nip) { - monitor_printf(mon, "nip=0x%016" PRIx64, cpu->value->nip); + monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->nip); } if (cpu->value->has_npc) { - monitor_printf(mon, "pc=0x%016" PRIx64, cpu->value->pc); - monitor_printf(mon, "npc=0x%016" PRIx64, cpu->value->npc); + monitor_printf(mon, " npc=0x%016" PRIx64, cpu->value->npc); } if (cpu->value->has_PC) { - monitor_printf(mon, "PC=0x%016" PRIx64, cpu->value->PC); + monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->PC); } if (cpu->value->halted) { @@ -1226,32 +1226,101 @@ static const VMStateDescription vmstate_ac97 = { } }; -static const MemoryRegionPortio nam_portio[] = { - { 0, 256 * 1, 1, .read = nam_readb, }, - { 0, 256 * 2, 2, .read = nam_readw, }, - { 0, 256 * 4, 4, .read = nam_readl, }, - { 0, 256 * 1, 1, .write = nam_writeb, }, - { 0, 256 * 2, 2, .write = nam_writew, }, - { 0, 256 * 4, 4, .write = nam_writel, }, - PORTIO_END_OF_LIST (), -}; +static uint64_t nam_read(void *opaque, hwaddr addr, unsigned size) +{ + if ((addr / size) > 256) { + return -1; + } + + switch (size) { + case 1: + return nam_readb(opaque, addr); + case 2: + return nam_readw(opaque, addr); + case 4: + return nam_readl(opaque, addr); + default: + return -1; + } +} + +static void nam_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + if ((addr / size) > 256) { + return; + } + + switch (size) { + case 1: + nam_writeb(opaque, addr, val); + break; + case 2: + nam_writew(opaque, addr, val); + break; + case 4: + nam_writel(opaque, addr, val); + break; + } +} static const MemoryRegionOps ac97_io_nam_ops = { - .old_portio = nam_portio, + .read = nam_read, + .write = nam_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; -static const MemoryRegionPortio nabm_portio[] = { - { 0, 64 * 1, 1, .read = nabm_readb, }, - { 0, 64 * 2, 2, .read = nabm_readw, }, - { 0, 64 * 4, 4, .read = nabm_readl, }, - { 0, 64 * 1, 1, .write = nabm_writeb, }, - { 0, 64 * 2, 2, .write = nabm_writew, }, - { 0, 64 * 4, 4, .write = nabm_writel, }, - PORTIO_END_OF_LIST () -}; +static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size) +{ + if ((addr / size) > 64) { + return -1; + } + + switch (size) { + case 1: + return nabm_readb(opaque, addr); + case 2: + return nabm_readw(opaque, addr); + case 4: + return nabm_readl(opaque, addr); + default: + return -1; + } +} + +static void nabm_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + if ((addr / size) > 64) { + return; + } + + switch (size) { + case 1: + nabm_writeb(opaque, addr, val); + break; + case 2: + nabm_writew(opaque, addr, val); + break; + case 4: + nabm_writel(opaque, addr, val); + break; + } +} + static const MemoryRegionOps ac97_io_nabm_ops = { - .old_portio = nabm_portio, + .read = nabm_read, + .write = nabm_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void ac97_on_reset (void *opaque) diff --git a/hw/es1370.c b/hw/es1370.c index e34234c..e0c9729 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -908,18 +908,44 @@ static void es1370_adc_callback (void *opaque, int avail) es1370_run_channel (s, ADC_CHANNEL, avail); } -static const MemoryRegionPortio es1370_portio[] = { - { 0, 0x40 * 4, 1, .write = es1370_writeb, }, - { 0, 0x40 * 2, 2, .write = es1370_writew, }, - { 0, 0x40, 4, .write = es1370_writel, }, - { 0, 0x40 * 4, 1, .read = es1370_readb, }, - { 0, 0x40 * 2, 2, .read = es1370_readw, }, - { 0, 0x40, 4, .read = es1370_readl, }, - PORTIO_END_OF_LIST () -}; +static uint64_t es1370_read(void *opaque, hwaddr addr, + unsigned size) +{ + switch (size) { + case 1: + return es1370_readb(opaque, addr); + case 2: + return es1370_readw(opaque, addr); + case 4: + return es1370_readl(opaque, addr); + default: + return -1; + } +} + +static void es1370_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + switch (size) { + case 1: + es1370_writeb(opaque, addr, val); + break; + case 2: + es1370_writew(opaque, addr, val); + break; + case 4: + es1370_writel(opaque, addr, val); + break; + } +} static const MemoryRegionOps es1370_io_ops = { - .old_portio = es1370_portio, + .read = es1370_read, + .write = es1370_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -111,7 +111,8 @@ static void pit_latch_count(PITChannelState *s) } } -static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void pit_ioport_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { PITCommonState *pit = opaque; int channel, access; @@ -178,7 +179,8 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t pit_ioport_read(void *opaque, uint32_t addr) +static uint64_t pit_ioport_read(void *opaque, hwaddr addr, + unsigned size) { PITCommonState *pit = opaque; int ret, count; @@ -290,14 +292,14 @@ static void pit_irq_control(void *opaque, int n, int enable) } } -static const MemoryRegionPortio pit_portio[] = { - { 0, 4, 1, .write = pit_ioport_write }, - { 0, 3, 1, .read = pit_ioport_read }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps pit_ioport_ops = { - .old_portio = pit_portio + .read = pit_ioport_read, + .write = pit_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void pit_post_load(PITCommonState *s) diff --git a/hw/m48t59.c b/hw/m48t59.c index 9eb1a09..9e8e692 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -27,6 +27,7 @@ #include "sysemu.h" #include "sysbus.h" #include "isa.h" +#include "exec-memory.h" //#define DEBUG_NVRAM @@ -80,6 +81,7 @@ typedef struct M48t59ISAState { typedef struct M48t59SysBusState { SysBusDevice busdev; M48t59State state; + MemoryRegion io; } M48t59SysBusState; /* Fake timer functions */ @@ -481,7 +483,8 @@ void m48t59_toggle_lock (void *opaque, int lock) } /* IO access to NVRAM */ -static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) +static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { M48t59State *NVRAM = opaque; @@ -504,7 +507,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t NVRAM_readb (void *opaque, uint32_t addr) +static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size) { M48t59State *NVRAM = opaque; uint32_t retval; @@ -626,13 +629,14 @@ static void m48t59_reset_sysbus(DeviceState *d) m48t59_reset_common(NVRAM); } -static const MemoryRegionPortio m48t59_portio[] = { - {0, 4, 1, .read = NVRAM_readb, .write = NVRAM_writeb }, - PORTIO_END_OF_LIST(), -}; - static const MemoryRegionOps m48t59_io_ops = { - .old_portio = m48t59_portio, + .read = NVRAM_readb, + .write = NVRAM_writeb, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; /* Initialisation routine */ @@ -653,9 +657,9 @@ M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base, d = FROM_SYSBUS(M48t59SysBusState, s); state = &d->state; sysbus_connect_irq(s, 0, IRQ); + memory_region_init_io(&d->io, &m48t59_io_ops, state, "m48t59", 4); if (io_base != 0) { - register_ioport_read(io_base, 0x04, 1, NVRAM_readb, state); - register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, state); + memory_region_add_subregion(get_system_io(), io_base, &d->io); } if (mem_base != 0) { sysbus_mmio_map(s, 0, mem_base); diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 332a77d..98839f2 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -383,7 +383,8 @@ static void rtc_update_timer(void *opaque) check_update_timer(s); } -static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) +static void cmos_ioport_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) { RTCState *s = opaque; @@ -595,7 +596,8 @@ static int update_in_progress(RTCState *s) return 0; } -static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) +static uint64_t cmos_ioport_read(void *opaque, hwaddr addr, + unsigned size) { RTCState *s = opaque; int ret; @@ -769,13 +771,14 @@ static void rtc_reset(void *opaque) #endif } -static const MemoryRegionPortio cmos_portio[] = { - {0, 2, 1, .read = cmos_ioport_read, .write = cmos_ioport_write }, - PORTIO_END_OF_LIST(), -}; - static const MemoryRegionOps cmos_ops = { - .old_portio = cmos_portio + .read = cmos_ioport_read, + .write = cmos_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void rtc_get_date(Object *obj, Visitor *v, void *opaque, diff --git a/hw/nseries.c b/hw/nseries.c index 7ada90d..9306aa1 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -1334,8 +1334,9 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, n8x0_dss_setup(s); n8x0_cbus_setup(s); n8x0_uart_setup(s); - if (usb_enabled) + if (usb_enabled(false)) { n8x0_usb_setup(s); + } if (kernel_filename) { /* Or at the linux loader. */ @@ -421,7 +421,8 @@ typedef struct Port92State { qemu_irq *a20_out; } Port92State; -static void port92_write(void *opaque, uint32_t addr, uint32_t val) +static void port92_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { Port92State *s = opaque; @@ -433,7 +434,8 @@ static void port92_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t port92_read(void *opaque, uint32_t addr) +static uint64_t port92_read(void *opaque, hwaddr addr, + unsigned size) { Port92State *s = opaque; uint32_t ret; @@ -468,13 +470,14 @@ static void port92_reset(DeviceState *d) s->outport &= ~1; } -static const MemoryRegionPortio port92_portio[] = { - { 0, 1, 1, .read = port92_read, .write = port92_write }, - PORTIO_END_OF_LIST(), -}; - static const MemoryRegionOps port92_ops = { - .old_portio = port92_portio + .read = port92_read, + .write = port92_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static int port92_initfn(ISADevice *dev) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 47ebc1a..c7dd75b 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -267,7 +267,7 @@ static void pc_init1(MemoryRegion *system_memory, pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, floppy, idebus[0], idebus[1], rtc_state); - if (pci_enabled && usb_enabled) { + if (pci_enabled && usb_enabled(false)) { pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); } @@ -194,7 +194,8 @@ static void kbd_update_aux_irq(void *opaque, int level) kbd_update_irq(s); } -static uint32_t kbd_read_status(void *opaque, uint32_t addr) +static uint64_t kbd_read_status(void *opaque, hwaddr addr, + unsigned size) { KBDState *s = opaque; int val; @@ -223,7 +224,8 @@ static void outport_write(KBDState *s, uint32_t val) } } -static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) +static void kbd_write_command(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { KBDState *s = opaque; @@ -303,12 +305,13 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) /* ignore that */ break; default: - fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); + fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", (int)val); break; } } -static uint32_t kbd_read_data(void *opaque, uint32_t addr) +static uint64_t kbd_read_data(void *opaque, hwaddr addr, + unsigned size) { KBDState *s = opaque; uint32_t val; @@ -322,7 +325,8 @@ static uint32_t kbd_read_data(void *opaque, uint32_t addr) return val; } -static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) +static void kbd_write_data(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { KBDState *s = opaque; @@ -385,9 +389,9 @@ static uint32_t kbd_mm_readb (void *opaque, hwaddr addr) KBDState *s = opaque; if (addr & s->mask) - return kbd_read_status(s, 0) & 0xff; + return kbd_read_status(s, 0, 1) & 0xff; else - return kbd_read_data(s, 0) & 0xff; + return kbd_read_data(s, 0, 1) & 0xff; } static void kbd_mm_writeb (void *opaque, hwaddr addr, uint32_t value) @@ -395,9 +399,9 @@ static void kbd_mm_writeb (void *opaque, hwaddr addr, uint32_t value) KBDState *s = opaque; if (addr & s->mask) - kbd_write_command(s, 0, value & 0xff); + kbd_write_command(s, 0, value & 0xff, 1); else - kbd_write_data(s, 0, value & 0xff); + kbd_write_data(s, 0, value & 0xff, 1); } static const MemoryRegionOps i8042_mmio_ops = { @@ -459,22 +463,24 @@ static const VMStateDescription vmstate_kbd_isa = { } }; -static const MemoryRegionPortio i8042_data_portio[] = { - { 0, 1, 1, .read = kbd_read_data, .write = kbd_write_data }, - PORTIO_END_OF_LIST() -}; - -static const MemoryRegionPortio i8042_cmd_portio[] = { - { 0, 1, 1, .read = kbd_read_status, .write = kbd_write_command }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps i8042_data_ops = { - .old_portio = i8042_data_portio + .read = kbd_read_data, + .write = kbd_write_data, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static const MemoryRegionOps i8042_cmd_ops = { - .old_portio = i8042_cmd_portio + .read = kbd_read_status, + .write = kbd_write_command, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static int i8042_initfn(ISADevice *dev) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 951e407..8fe2123 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -11,6 +11,7 @@ obj-y += ppc_newworld.o obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o +obj-$(CONFIG_PSERIES) += spapr_events.o # PowerPC 4xx boards obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-y += ppc440_bamboo.o diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index d655e3f..6749fff 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -52,7 +52,6 @@ #define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000ULL) #define MPC8544_PCI_REGS_SIZE 0x1000ULL #define MPC8544_PCI_IO 0xE1000000ULL -#define MPC8544_PCI_IOLEN 0x10000ULL #define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000ULL) #define MPC8544_SPIN_BASE 0xEF000000ULL @@ -496,7 +495,7 @@ void ppce500_init(PPCE500Params *params) if (serial_hds[1]) { serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE, 0, mpic[12+26], 399193, - serial_hds[0], DEVICE_BIG_ENDIAN); + serial_hds[1], DEVICE_BIG_ENDIAN); } /* General Utility device */ @@ -511,7 +510,7 @@ void ppce500_init(PPCE500Params *params) if (!pci_bus) printf("couldn't create PCI controller!\n"); - isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN); + sysbus_mmio_map(sysbus_from_qdev(dev), 1, MPC8544_PCI_IO); if (pci_bus) { /* Register network interfaces. */ diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index a6b1d51..cc85607 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -59,7 +59,7 @@ static int bamboo_load_device_tree(hwaddr addr, { int ret = -1; #ifdef CONFIG_FDT - uint32_t mem_reg_property[] = { 0, 0, ramsize }; + uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; char *filename; int fdt_size; void *fdt; diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 15f74f9..664747e 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -348,10 +348,6 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) ide_mem[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]); ide_mem[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]); - /* cuda also initialize ADB */ - if (machine_arch == ARCH_MAC99_U3) { - usb_enabled = 1; - } cuda_init(&cuda_mem, pic[0x19]); adb_kbd_init(&adb_bus); @@ -360,15 +356,14 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem, dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_bar); - if (usb_enabled) { + if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { pci_create_simple(pci_bus, -1, "pci-ohci"); - } - - /* U3 needs to use USB for input because Linux doesn't support via-cuda - on PPC64 */ - if (machine_arch == ARCH_MAC99_U3) { - usbdevice_create("keyboard"); - usbdevice_create("mouse"); + /* U3 needs to use USB for input because Linux doesn't support via-cuda + on PPC64 */ + if (machine_arch == ARCH_MAC99_U3) { + usbdevice_create("keyboard"); + usbdevice_create("mouse"); + } } if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index a4f899d..e8138c0 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -286,7 +286,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem, dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar); - if (usb_enabled) { + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 085851a..bf15730 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -661,7 +661,7 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr); #endif - if (usb_enabled) { + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 332748a..2ff7438 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -31,6 +31,8 @@ #define PCIE500_ALL_SIZE 0x1000 #define PCIE500_REG_SIZE (PCIE500_ALL_SIZE - PCIE500_REG_BASE) +#define PCIE500_PCI_IOLEN 0x10000ULL + #define PPCE500_PCI_CONFIG_ADDR 0x0 #define PPCE500_PCI_CONFIG_DATA 0x4 #define PPCE500_PCI_INTACK 0x8 @@ -87,6 +89,7 @@ struct PPCE500PCIState { /* mmio maps */ MemoryRegion container; MemoryRegion iomem; + MemoryRegion pio; }; typedef struct PPCE500PCIState PPCE500PCIState; @@ -314,7 +317,6 @@ static int e500_pcihost_initfn(SysBusDevice *dev) PCIBus *b; int i; MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *address_space_io = get_system_io(); h = PCI_HOST_BRIDGE(dev); s = PPC_E500_PCI_HOST_BRIDGE(dev); @@ -323,9 +325,11 @@ static int e500_pcihost_initfn(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq[i]); } + memory_region_init(&s->pio, "pci-pio", PCIE500_PCI_IOLEN); + b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq, mpc85xx_pci_map_irq, s->irq, address_space_mem, - address_space_io, PCI_DEVFN(0x11, 0), 4); + &s->pio, PCI_DEVFN(0x11, 0), 4); h->bus = b; pci_create_simple(b, 0, "e500-host-bridge"); @@ -341,6 +345,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem); memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem); sysbus_init_mmio(dev, &s->container); + sysbus_init_mmio(dev, &s->pio); return 0; } diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 0fb2179..e616979 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2108,7 +2108,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } - if (usb_enabled) { + if (usb_enabled(false)) { sysbus_create_simple("sysbus-ohci", 0x4c000000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); } @@ -2239,7 +2239,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } - if (usb_enabled) { + if (usb_enabled(false)) { sysbus_create_simple("sysbus-ohci", 0x4c000000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); } diff --git a/hw/realview.c b/hw/realview.c index baa92d4..b5cb08c 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -227,7 +227,7 @@ static void realview_init(ram_addr_t ram_size, sysbus_connect_irq(busdev, 2, pic[50]); sysbus_connect_irq(busdev, 3, pic[51]); pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); - if (usb_enabled) { + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } n = drive_get_max_bus(IF_SCSI); diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 10ced8b..e3aa8bf 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3187,38 +3187,6 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) /* */ -static void rtl8139_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - rtl8139_io_writeb(opaque, addr & 0xFF, val); -} - -static void rtl8139_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - rtl8139_io_writew(opaque, addr & 0xFF, val); -} - -static void rtl8139_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - rtl8139_io_writel(opaque, addr & 0xFF, val); -} - -static uint32_t rtl8139_ioport_readb(void *opaque, uint32_t addr) -{ - return rtl8139_io_readb(opaque, addr & 0xFF); -} - -static uint32_t rtl8139_ioport_readw(void *opaque, uint32_t addr) -{ - return rtl8139_io_readw(opaque, addr & 0xFF); -} - -static uint32_t rtl8139_ioport_readl(void *opaque, uint32_t addr) -{ - return rtl8139_io_readl(opaque, addr & 0xFF); -} - -/* */ - static void rtl8139_mmio_writeb(void *opaque, hwaddr addr, uint32_t val) { rtl8139_io_writeb(opaque, addr & 0xFF, val); @@ -3386,18 +3354,44 @@ static const VMStateDescription vmstate_rtl8139 = { /***********************************************************/ /* PCI RTL8139 definitions */ -static const MemoryRegionPortio rtl8139_portio[] = { - { 0, 0x100, 1, .read = rtl8139_ioport_readb, }, - { 0, 0x100, 1, .write = rtl8139_ioport_writeb, }, - { 0, 0x100, 2, .read = rtl8139_ioport_readw, }, - { 0, 0x100, 2, .write = rtl8139_ioport_writew, }, - { 0, 0x100, 4, .read = rtl8139_ioport_readl, }, - { 0, 0x100, 4, .write = rtl8139_ioport_writel, }, - PORTIO_END_OF_LIST() -}; +static void rtl8139_ioport_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + switch (size) { + case 1: + rtl8139_io_writeb(opaque, addr, val); + break; + case 2: + rtl8139_io_writew(opaque, addr, val); + break; + case 4: + rtl8139_io_writel(opaque, addr, val); + break; + } +} + +static uint64_t rtl8139_ioport_read(void *opaque, hwaddr addr, + unsigned size) +{ + switch (size) { + case 1: + return rtl8139_io_readb(opaque, addr); + case 2: + return rtl8139_io_readw(opaque, addr); + case 4: + return rtl8139_io_readl(opaque, addr); + } + + return -1; +} static const MemoryRegionOps rtl8139_io_ops = { - .old_portio = rtl8139_portio, + .read = rtl8139_ioport_read, + .write = rtl8139_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, .endianness = DEVICE_LITTLE_ENDIAN, }; diff --git a/hw/serial.c b/hw/serial.c index ae84b22..60283ea 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -26,6 +26,7 @@ #include "serial.h" #include "qemu-char.h" #include "qemu-timer.h" +#include "exec-memory.h" //#define DEBUG_SERIAL @@ -305,7 +306,8 @@ static void serial_xmit(void *opaque) } -static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { SerialState *s = opaque; @@ -451,7 +453,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t serial_ioport_read(void *opaque, uint32_t addr) +static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) { SerialState *s = opaque; uint32_t ret; @@ -620,7 +622,7 @@ static int serial_post_load(void *opaque, int version_id) s->fcr_vmstate = 0; } /* Initialize fcr via setter to perform essential side-effects */ - serial_ioport_write(s, 0x02, s->fcr_vmstate); + serial_ioport_write(s, 0x02, s->fcr_vmstate, 1); serial_update_parameters(s); return 0; } @@ -705,13 +707,14 @@ void serial_set_frequency(SerialState *s, uint32_t frequency) serial_update_parameters(s); } -static const MemoryRegionPortio serial_portio[] = { - { 0, 8, 1, .read = serial_ioport_read, .write = serial_ioport_write }, - PORTIO_END_OF_LIST() -}; - const MemoryRegionOps serial_io_ops = { - .old_portio = serial_portio + .read = serial_ioport_read, + .write = serial_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; SerialState *serial_init(int base, qemu_irq irq, int baudbase, @@ -728,8 +731,9 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase, vmstate_register(NULL, base, &vmstate_serial, s); - register_ioport_write(base, 8, 1, serial_ioport_write, s); - register_ioport_read(base, 8, 1, serial_ioport_read, s); + memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); + memory_region_add_subregion(get_system_io(), base, &s->io); + return s; } @@ -738,7 +742,7 @@ static uint64_t serial_mm_read(void *opaque, hwaddr addr, unsigned size) { SerialState *s = opaque; - return serial_ioport_read(s, addr >> s->it_shift); + return serial_ioport_read(s, addr >> s->it_shift, 1); } static void serial_mm_write(void *opaque, hwaddr addr, @@ -746,7 +750,7 @@ static void serial_mm_write(void *opaque, hwaddr addr, { SerialState *s = opaque; value &= ~0u >> (32 - (size * 8)); - serial_ioport_write(s, addr >> s->it_shift, value); + serial_ioport_write(s, addr >> s->it_shift, value, 1); } static const MemoryRegionOps serial_mm_ops[3] = { @@ -232,7 +232,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, hwaddr initrd_size, hwaddr kernel_size, const char *boot_device, - const char *kernel_cmdline) + const char *kernel_cmdline, + uint32_t epow_irq) { void *fdt; CPUPPCState *env; @@ -403,6 +404,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "ibm,associativity-reference-points", refpoints, sizeof(refpoints)))); + _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX))); + _FDT((fdt_end_node(fdt))); /* interrupt controller */ @@ -433,6 +436,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); + /* event-sources */ + spapr_events_fdt_skel(fdt, epow_irq); + _FDT((fdt_end_node(fdt))); /* close root node */ _FDT((fdt_finish(fdt))); @@ -795,6 +801,9 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) spapr->icp = xics_system_init(XICS_IRQS); spapr->next_irq = 16; + /* Set up EPOW events infrastructure */ + spapr_events_init(spapr); + /* Set up IOMMU */ spapr_iommu_init(); @@ -840,7 +849,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) spapr->has_graphics = true; } - if (usb_enabled) { + if (usb_enabled(spapr->has_graphics)) { pci_create_simple(phb->bus, -1, "pci-ohci"); if (spapr->has_graphics) { usbdevice_create("keyboard"); @@ -903,7 +912,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, initrd_base, initrd_size, kernel_size, - boot_device, kernel_cmdline); + boot_device, kernel_cmdline, + spapr->epow_irq); assert(spapr->fdt_skel != NULL); } @@ -26,6 +26,9 @@ typedef struct sPAPREnvironment { int rtc_offset; char *cpu_model; bool has_graphics; + + uint32_t epow_irq; + Notifier epow_notifier; } sPAPREnvironment; #define H_SUCCESS 0 @@ -335,7 +338,12 @@ typedef struct sPAPRTCE { #define SPAPR_VIO_BASE_LIOBN 0x00000000 #define SPAPR_PCI_BASE_LIOBN 0x80000000 +#define RTAS_ERROR_LOG_MAX 2048 + + void spapr_iommu_init(void); +void spapr_events_init(sPAPREnvironment *spapr); +void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq); DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size); void spapr_tce_free(DMAContext *dma); void spapr_tce_reset(DMAContext *dma); diff --git a/hw/spapr_events.c b/hw/spapr_events.c new file mode 100644 index 0000000..18ccd4a --- /dev/null +++ b/hw/spapr_events.c @@ -0,0 +1,321 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * RTAS events handling + * + * Copyright (c) 2012 David Gibson, IBM Corporation. + * + * 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. + * + */ +#include "cpu.h" +#include "sysemu.h" +#include "qemu-char.h" +#include "hw/qdev.h" +#include "device_tree.h" + +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +#include <libfdt.h> + +struct rtas_error_log { + uint32_t summary; +#define RTAS_LOG_VERSION_MASK 0xff000000 +#define RTAS_LOG_VERSION_6 0x06000000 +#define RTAS_LOG_SEVERITY_MASK 0x00e00000 +#define RTAS_LOG_SEVERITY_ALREADY_REPORTED 0x00c00000 +#define RTAS_LOG_SEVERITY_FATAL 0x00a00000 +#define RTAS_LOG_SEVERITY_ERROR 0x00800000 +#define RTAS_LOG_SEVERITY_ERROR_SYNC 0x00600000 +#define RTAS_LOG_SEVERITY_WARNING 0x00400000 +#define RTAS_LOG_SEVERITY_EVENT 0x00200000 +#define RTAS_LOG_SEVERITY_NO_ERROR 0x00000000 +#define RTAS_LOG_DISPOSITION_MASK 0x00180000 +#define RTAS_LOG_DISPOSITION_FULLY_RECOVERED 0x00000000 +#define RTAS_LOG_DISPOSITION_LIMITED_RECOVERY 0x00080000 +#define RTAS_LOG_DISPOSITION_NOT_RECOVERED 0x00100000 +#define RTAS_LOG_OPTIONAL_PART_PRESENT 0x00040000 +#define RTAS_LOG_INITIATOR_MASK 0x0000f000 +#define RTAS_LOG_INITIATOR_UNKNOWN 0x00000000 +#define RTAS_LOG_INITIATOR_CPU 0x00001000 +#define RTAS_LOG_INITIATOR_PCI 0x00002000 +#define RTAS_LOG_INITIATOR_MEMORY 0x00004000 +#define RTAS_LOG_INITIATOR_HOTPLUG 0x00006000 +#define RTAS_LOG_TARGET_MASK 0x00000f00 +#define RTAS_LOG_TARGET_UNKNOWN 0x00000000 +#define RTAS_LOG_TARGET_CPU 0x00000100 +#define RTAS_LOG_TARGET_PCI 0x00000200 +#define RTAS_LOG_TARGET_MEMORY 0x00000400 +#define RTAS_LOG_TARGET_HOTPLUG 0x00000600 +#define RTAS_LOG_TYPE_MASK 0x000000ff +#define RTAS_LOG_TYPE_OTHER 0x00000000 +#define RTAS_LOG_TYPE_RETRY 0x00000001 +#define RTAS_LOG_TYPE_TCE_ERR 0x00000002 +#define RTAS_LOG_TYPE_INTERN_DEV_FAIL 0x00000003 +#define RTAS_LOG_TYPE_TIMEOUT 0x00000004 +#define RTAS_LOG_TYPE_DATA_PARITY 0x00000005 +#define RTAS_LOG_TYPE_ADDR_PARITY 0x00000006 +#define RTAS_LOG_TYPE_CACHE_PARITY 0x00000007 +#define RTAS_LOG_TYPE_ADDR_INVALID 0x00000008 +#define RTAS_LOG_TYPE_ECC_UNCORR 0x00000009 +#define RTAS_LOG_TYPE_ECC_CORR 0x0000000a +#define RTAS_LOG_TYPE_EPOW 0x00000040 + uint32_t extended_length; +} QEMU_PACKED; + +struct rtas_event_log_v6 { + uint8_t b0; +#define RTAS_LOG_V6_B0_VALID 0x80 +#define RTAS_LOG_V6_B0_UNRECOVERABLE_ERROR 0x40 +#define RTAS_LOG_V6_B0_RECOVERABLE_ERROR 0x20 +#define RTAS_LOG_V6_B0_DEGRADED_OPERATION 0x10 +#define RTAS_LOG_V6_B0_PREDICTIVE_ERROR 0x08 +#define RTAS_LOG_V6_B0_NEW_LOG 0x04 +#define RTAS_LOG_V6_B0_BIGENDIAN 0x02 + uint8_t _resv1; + uint8_t b2; +#define RTAS_LOG_V6_B2_POWERPC_FORMAT 0x80 +#define RTAS_LOG_V6_B2_LOG_FORMAT_MASK 0x0f +#define RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT 0x0e + uint8_t _resv2[9]; + uint32_t company; +#define RTAS_LOG_V6_COMPANY_IBM 0x49424d00 /* IBM<null> */ +} QEMU_PACKED; + +struct rtas_event_log_v6_section_header { + uint16_t section_id; + uint16_t section_length; + uint8_t section_version; + uint8_t section_subtype; + uint16_t creator_component_id; +} QEMU_PACKED; + +struct rtas_event_log_v6_maina { +#define RTAS_LOG_V6_SECTION_ID_MAINA 0x5048 /* PH */ + struct rtas_event_log_v6_section_header hdr; + uint32_t creation_date; /* BCD: YYYYMMDD */ + uint32_t creation_time; /* BCD: HHMMSS00 */ + uint8_t _platform1[8]; + char creator_id; + uint8_t _resv1[2]; + uint8_t section_count; + uint8_t _resv2[4]; + uint8_t _platform2[8]; + uint32_t plid; + uint8_t _platform3[4]; +} QEMU_PACKED; + +struct rtas_event_log_v6_mainb { +#define RTAS_LOG_V6_SECTION_ID_MAINB 0x5548 /* UH */ + struct rtas_event_log_v6_section_header hdr; + uint8_t subsystem_id; + uint8_t _platform1; + uint8_t event_severity; + uint8_t event_subtype; + uint8_t _platform2[4]; + uint8_t _resv1[2]; + uint16_t action_flags; + uint8_t _resv2[4]; +} QEMU_PACKED; + +struct rtas_event_log_v6_epow { +#define RTAS_LOG_V6_SECTION_ID_EPOW 0x4550 /* EP */ + struct rtas_event_log_v6_section_header hdr; + uint8_t sensor_value; +#define RTAS_LOG_V6_EPOW_ACTION_RESET 0 +#define RTAS_LOG_V6_EPOW_ACTION_WARN_COOLING 1 +#define RTAS_LOG_V6_EPOW_ACTION_WARN_POWER 2 +#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN 3 +#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_HALT 4 +#define RTAS_LOG_V6_EPOW_ACTION_MAIN_ENCLOSURE 5 +#define RTAS_LOG_V6_EPOW_ACTION_POWER_OFF 7 + uint8_t event_modifier; +#define RTAS_LOG_V6_EPOW_MODIFIER_NORMAL 1 +#define RTAS_LOG_V6_EPOW_MODIFIER_ON_UPS 2 +#define RTAS_LOG_V6_EPOW_MODIFIER_CRITICAL 3 +#define RTAS_LOG_V6_EPOW_MODIFIER_TEMPERATURE 4 + uint8_t extended_modifier; +#define RTAS_LOG_V6_EPOW_XMODIFIER_SYSTEM_WIDE 0 +#define RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC 1 + uint8_t _resv; + uint64_t reason_code; +} QEMU_PACKED; + +struct epow_log_full { + struct rtas_error_log hdr; + struct rtas_event_log_v6 v6hdr; + struct rtas_event_log_v6_maina maina; + struct rtas_event_log_v6_mainb mainb; + struct rtas_event_log_v6_epow epow; +} QEMU_PACKED; + +#define EVENT_MASK_INTERNAL_ERRORS 0x80000000 +#define EVENT_MASK_EPOW 0x40000000 +#define EVENT_MASK_HOTPLUG 0x10000000 +#define EVENT_MASK_IO 0x08000000 + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + +void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq) +{ + uint32_t epow_irq_ranges[] = {cpu_to_be32(epow_irq), cpu_to_be32(1)}; + uint32_t epow_interrupts[] = {cpu_to_be32(epow_irq), 0}; + + _FDT((fdt_begin_node(fdt, "event-sources"))); + + _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); + _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2))); + _FDT((fdt_property(fdt, "interrupt-ranges", + epow_irq_ranges, sizeof(epow_irq_ranges)))); + + _FDT((fdt_begin_node(fdt, "epow-events"))); + _FDT((fdt_property(fdt, "interrupts", + epow_interrupts, sizeof(epow_interrupts)))); + _FDT((fdt_end_node(fdt))); + + _FDT((fdt_end_node(fdt))); +} + +static struct epow_log_full *pending_epow; +static uint32_t next_plid; + +static void spapr_powerdown_req(Notifier *n, void *opaque) +{ + sPAPREnvironment *spapr = container_of(n, sPAPREnvironment, epow_notifier); + struct rtas_error_log *hdr; + struct rtas_event_log_v6 *v6hdr; + struct rtas_event_log_v6_maina *maina; + struct rtas_event_log_v6_mainb *mainb; + struct rtas_event_log_v6_epow *epow; + struct tm tm; + int year; + + if (pending_epow) { + /* For now, we just throw away earlier events if two come + * along before any are consumed. This is sufficient for our + * powerdown messages, but we'll need more if we do more + * general error/event logging */ + g_free(pending_epow); + } + pending_epow = g_malloc0(sizeof(*pending_epow)); + hdr = &pending_epow->hdr; + v6hdr = &pending_epow->v6hdr; + maina = &pending_epow->maina; + mainb = &pending_epow->mainb; + epow = &pending_epow->epow; + + hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6 + | RTAS_LOG_SEVERITY_EVENT + | RTAS_LOG_DISPOSITION_NOT_RECOVERED + | RTAS_LOG_OPTIONAL_PART_PRESENT + | RTAS_LOG_TYPE_EPOW); + hdr->extended_length = cpu_to_be32(sizeof(*pending_epow) + - sizeof(pending_epow->hdr)); + + v6hdr->b0 = RTAS_LOG_V6_B0_VALID | RTAS_LOG_V6_B0_NEW_LOG + | RTAS_LOG_V6_B0_BIGENDIAN; + v6hdr->b2 = RTAS_LOG_V6_B2_POWERPC_FORMAT + | RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT; + v6hdr->company = cpu_to_be32(RTAS_LOG_V6_COMPANY_IBM); + + maina->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINA); + maina->hdr.section_length = cpu_to_be16(sizeof(*maina)); + /* FIXME: section version, subtype and creator id? */ + qemu_get_timedate(&tm, spapr->rtc_offset); + year = tm.tm_year + 1900; + maina->creation_date = cpu_to_be32((to_bcd(year / 100) << 24) + | (to_bcd(year % 100) << 16) + | (to_bcd(tm.tm_mon + 1) << 8) + | to_bcd(tm.tm_mday)); + maina->creation_time = cpu_to_be32((to_bcd(tm.tm_hour) << 24) + | (to_bcd(tm.tm_min) << 16) + | (to_bcd(tm.tm_sec) << 8)); + maina->creator_id = 'H'; /* Hypervisor */ + maina->section_count = 3; /* Main-A, Main-B and EPOW */ + maina->plid = next_plid++; + + mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB); + mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb)); + /* FIXME: section version, subtype and creator id? */ + mainb->subsystem_id = 0xa0; /* External environment */ + mainb->event_severity = 0x00; /* Informational / non-error */ + mainb->event_subtype = 0xd0; /* Normal shutdown */ + + epow->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_EPOW); + epow->hdr.section_length = cpu_to_be16(sizeof(*epow)); + epow->hdr.section_version = 2; /* includes extended modifier */ + /* FIXME: section subtype and creator id? */ + epow->sensor_value = RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN; + epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL; + epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC; + + qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->epow_irq)); +} + +static void check_exception(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t mask, buf, len; + uint64_t xinfo; + + if ((nargs < 6) || (nargs > 7) || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + + xinfo = rtas_ld(args, 1); + mask = rtas_ld(args, 2); + buf = rtas_ld(args, 4); + len = rtas_ld(args, 5); + if (nargs == 7) { + xinfo |= (uint64_t)rtas_ld(args, 6) << 32; + } + + if ((mask & EVENT_MASK_EPOW) && pending_epow) { + if (sizeof(*pending_epow) < len) { + len = sizeof(*pending_epow); + } + + cpu_physical_memory_write(buf, pending_epow, len); + g_free(pending_epow); + pending_epow = NULL; + rtas_st(rets, 0, 0); + } else { + rtas_st(rets, 0, 1); + } +} + +void spapr_events_init(sPAPREnvironment *spapr) +{ + spapr->epow_irq = spapr_allocate_msi(0); + spapr->epow_notifier.notify = spapr_powerdown_req; + qemu_register_powerdown_notifier(&spapr->epow_notifier); + spapr_rtas_register("check-exception", check_exception); +} diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 194d9c2..621dabd 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -366,26 +366,26 @@ static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa) return H_PARAMETER; } - env->vpa = vpa; + env->vpa_addr = vpa; - tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET); + tmp = ldub_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET); tmp |= VPA_SHARED_PROC_VAL; - stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp); + stb_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp); return H_SUCCESS; } static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa) { - if (env->slb_shadow) { + if (env->slb_shadow_addr) { return H_RESOURCE; } - if (env->dispatch_trace_log) { + if (env->dtl_addr) { return H_RESOURCE; } - env->vpa = 0; + env->vpa_addr = 0; return H_SUCCESS; } @@ -407,18 +407,20 @@ static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr) return H_PARAMETER; } - if (!env->vpa) { + if (!env->vpa_addr) { return H_RESOURCE; } - env->slb_shadow = addr; + env->slb_shadow_addr = addr; + env->slb_shadow_size = size; return H_SUCCESS; } static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr) { - env->slb_shadow = 0; + env->slb_shadow_addr = 0; + env->slb_shadow_size = 0; return H_SUCCESS; } @@ -437,11 +439,11 @@ static target_ulong register_dtl(CPUPPCState *env, target_ulong addr) return H_PARAMETER; } - if (!env->vpa) { + if (!env->vpa_addr) { return H_RESOURCE; } - env->dispatch_trace_log = addr; + env->dtl_addr = addr; env->dtl_size = size; return H_SUCCESS; @@ -449,7 +451,7 @@ static target_ulong register_dtl(CPUPPCState *env, target_ulong addr) static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr) { - env->dispatch_trace_log = 0; + env->dtl_addr = 0; env->dtl_size = 0; return H_SUCCESS; @@ -670,11 +672,10 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) } else { assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX)); - slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; } - assert(!(*slot) || (fn == *slot)); + assert(!(*slot)); *slot = fn; } diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index a08ed11..c2c3079 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -439,43 +439,6 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); } -static uint64_t spapr_io_read(void *opaque, hwaddr addr, - unsigned size) -{ - switch (size) { - case 1: - return cpu_inb(addr); - case 2: - return cpu_inw(addr); - case 4: - return cpu_inl(addr); - } - assert(0); -} - -static void spapr_io_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - switch (size) { - case 1: - cpu_outb(addr, data); - return; - case 2: - cpu_outw(addr, data); - return; - case 4: - cpu_outl(addr, data); - return; - } - assert(0); -} - -static const MemoryRegionOps spapr_io_ops = { - .endianness = DEVICE_LITTLE_ENDIAN, - .read = spapr_io_read, - .write = spapr_io_write -}; - /* * MSI/MSIX memory region implementation. * The handler handles both MSI and MSIX. @@ -545,14 +508,9 @@ static int spapr_phb_init(SysBusDevice *s) * old_portion are updated */ sprintf(namebuf, "%s.io", sphb->dtbusname); memory_region_init(&sphb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE); - /* FIXME: fix to support multiple PHBs */ - memory_region_add_subregion(get_system_io(), 0, &sphb->iospace); - sprintf(namebuf, "%s.io-alias", sphb->dtbusname); - memory_region_init_io(&sphb->iowindow, &spapr_io_ops, sphb, - namebuf, SPAPR_PCI_IO_WIN_SIZE); memory_region_add_subregion(get_system_memory(), sphb->io_win_addr, - &sphb->iowindow); + &sphb->iospace); /* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors, * we need to allocate some memory to catch those writes coming diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index e307ac8..a77d7d5 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -44,7 +44,7 @@ typedef struct sPAPRPHBState { MemoryRegion memspace, iospace; hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size; hwaddr msi_win_addr; - MemoryRegion memwindow, iowindow, msiwindow; + MemoryRegion memwindow, msiwindow; uint32_t dma_liobn; uint64_t dma_window_start; diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 67da27b..ce76c58 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -241,6 +241,15 @@ target_ulong spapr_rtas_call(sPAPREnvironment *spapr, void spapr_rtas_register(const char *name, spapr_rtas_fn fn) { + int i; + + for (i = 0; i < (rtas_next - rtas_table); i++) { + if (strcmp(name, rtas_table[i].name) == 0) { + fprintf(stderr, "RTAS call \"%s\" registered twice\n", name); + exit(1); + } + } + assert(rtas_next < (rtas_table + TOKEN_MAX)); rtas_next->name = name; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index f55bd0c..e85f982 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -248,7 +248,7 @@ static void versatile_init(ram_addr_t ram_size, pci_nic_init_nofail(nd, "rtl8139", NULL); } } - if (usb_enabled) { + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } n = drive_get_max_bus(IF_SCSI); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index c7f20c3..9603150 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -374,79 +374,39 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr) return ret; } -static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr) -{ - VirtIOPCIProxy *proxy = opaque; - uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); - if (addr < config) - return virtio_ioport_read(proxy, addr); - addr -= config; - return virtio_config_readb(proxy->vdev, addr); -} - -static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) -{ - VirtIOPCIProxy *proxy = opaque; - uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); - uint16_t val; - if (addr < config) - return virtio_ioport_read(proxy, addr); - addr -= config; - val = virtio_config_readw(proxy->vdev, addr); - if (virtio_is_big_endian()) { - /* - * virtio is odd, ioports are LE but config space is target native - * endian. However, in qemu, all PIO is LE, so we need to re-swap - * on BE targets - */ - val = bswap16(val); - } - return val; -} - -static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) -{ - VirtIOPCIProxy *proxy = opaque; - uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); - uint32_t val; - if (addr < config) - return virtio_ioport_read(proxy, addr); - addr -= config; - val = virtio_config_readl(proxy->vdev, addr); - if (virtio_is_big_endian()) { - val = bswap32(val); - } - return val; -} - -static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val) +static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, + unsigned size) { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); + uint64_t val = 0; if (addr < config) { - virtio_ioport_write(proxy, addr, val); - return; + return virtio_ioport_read(proxy, addr); } addr -= config; - virtio_config_writeb(proxy->vdev, addr, val); -} -static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val) -{ - VirtIOPCIProxy *proxy = opaque; - uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); - if (addr < config) { - virtio_ioport_write(proxy, addr, val); - return; - } - addr -= config; - if (virtio_is_big_endian()) { - val = bswap16(val); + switch (size) { + case 1: + val = virtio_config_readb(proxy->vdev, addr); + break; + case 2: + val = virtio_config_readw(proxy->vdev, addr); + if (virtio_is_big_endian()) { + val = bswap16(val); + } + break; + case 4: + val = virtio_config_readl(proxy->vdev, addr); + if (virtio_is_big_endian()) { + val = bswap32(val); + } + break; } - virtio_config_writew(proxy->vdev, addr, val); + return val; } -static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) +static void virtio_pci_config_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); @@ -455,24 +415,36 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) return; } addr -= config; - if (virtio_is_big_endian()) { - val = bswap32(val); + /* + * Virtio-PCI is odd. Ioports are LE but config space is target native + * endian. + */ + switch (size) { + case 1: + virtio_config_writeb(proxy->vdev, addr, val); + break; + case 2: + if (virtio_is_big_endian()) { + val = bswap16(val); + } + virtio_config_writew(proxy->vdev, addr, val); + break; + case 4: + if (virtio_is_big_endian()) { + val = bswap32(val); + } + virtio_config_writel(proxy->vdev, addr, val); + break; } - virtio_config_writel(proxy->vdev, addr, val); } -static const MemoryRegionPortio virtio_portio[] = { - { 0, 0x10000, 1, .write = virtio_pci_config_writeb, }, - { 0, 0x10000, 2, .write = virtio_pci_config_writew, }, - { 0, 0x10000, 4, .write = virtio_pci_config_writel, }, - { 0, 0x10000, 1, .read = virtio_pci_config_readb, }, - { 0, 0x10000, 2, .read = virtio_pci_config_readw, }, - { 0, 0x10000, 4, .read = virtio_pci_config_readl, }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps virtio_pci_config_ops = { - .old_portio = virtio_portio, + .read = virtio_pci_config_read, + .write = virtio_pci_config_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, .endianness = DEVICE_LITTLE_ENDIAN, }; diff --git a/hw/vmport.c b/hw/vmport.c index a4f52ee..3ab3a14 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -54,7 +54,8 @@ void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque) port_state->opaque[command] = opaque; } -static uint32_t vmport_ioport_read(void *opaque, uint32_t addr) +static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, + unsigned size) { VMPortState *s = opaque; CPUX86State *env = cpu_single_env; @@ -81,11 +82,12 @@ static uint32_t vmport_ioport_read(void *opaque, uint32_t addr) return s->func[command](s->opaque[command], addr); } -static void vmport_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void vmport_ioport_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { CPUX86State *env = cpu_single_env; - env->regs[R_EAX] = vmport_ioport_read(opaque, addr); + env->regs[R_EAX] = vmport_ioport_read(opaque, addr, 4); } static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) @@ -121,13 +123,14 @@ void vmmouse_set_data(const uint32_t *data) env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; } -static const MemoryRegionPortio vmport_portio[] = { - {0, 1, 4, .read = vmport_ioport_read, .write = vmport_ioport_write }, - PORTIO_END_OF_LIST(), -}; - static const MemoryRegionOps vmport_ops = { - .old_portio = vmport_portio + .read = vmport_ioport_read, + .write = vmport_ioport_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static int vmport_initfn(ISADevice *dev) diff --git a/hw/xen_platform.c b/hw/xen_platform.c index 890eb72..a54e7a2 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -228,18 +228,46 @@ static void platform_fixed_ioport_reset(void *opaque) platform_fixed_ioport_writeb(s, 0, 0); } -const MemoryRegionPortio xen_platform_ioport[] = { - { 0, 16, 4, .write = platform_fixed_ioport_writel, }, - { 0, 16, 2, .write = platform_fixed_ioport_writew, }, - { 0, 16, 1, .write = platform_fixed_ioport_writeb, }, - { 0, 16, 2, .read = platform_fixed_ioport_readw, }, - { 0, 16, 1, .read = platform_fixed_ioport_readb, }, - PORTIO_END_OF_LIST() -}; +static uint64_t platform_fixed_ioport_read(void *opaque, + hwaddr addr, + unsigned size) +{ + switch (size) { + case 1: + return platform_fixed_ioport_readb(opaque, addr); + case 2: + return platform_fixed_ioport_readw(opaque, addr); + default: + return -1; + } +} + +static void platform_fixed_ioport_write(void *opaque, hwaddr addr, + + uint64_t val, unsigned size) +{ + switch (size) { + case 1: + platform_fixed_ioport_writeb(opaque, addr, val); + break; + case 2: + platform_fixed_ioport_writew(opaque, addr, val); + break; + case 4: + platform_fixed_ioport_writel(opaque, addr, val); + break; + } +} + static const MemoryRegionOps platform_fixed_io_ops = { - .old_portio = xen_platform_ioport, - .endianness = DEVICE_NATIVE_ENDIAN, + .read = platform_fixed_ioport_read, + .write = platform_fixed_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void platform_fixed_ioport_init(PCIXenPlatformState* s) diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index 5dd2e08..4c42edc 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -155,10 +155,7 @@ static void lx60_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void lx_init(const LxBoardDesc *board, - ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) { #ifdef TARGET_WORDS_BIGENDIAN int be = 1; @@ -171,6 +168,9 @@ static void lx_init(const LxBoardDesc *board, MemoryRegion *ram, *rom, *system_io; DriveInfo *dinfo; pflash_t *flash = NULL; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; int n; if (!cpu_model) { @@ -194,7 +194,7 @@ static void lx_init(const LxBoardDesc *board, } ram = g_malloc(sizeof(*ram)); - memory_region_init_ram(ram, "lx60.dram", ram_size); + memory_region_init_ram(ram, "lx60.dram", args->ram_size); vmstate_register_ram_global(ram); memory_region_add_subregion(system_memory, 0, ram); @@ -271,38 +271,22 @@ static void lx_init(const LxBoardDesc *board, static void xtensa_lx60_init(QEMUMachineInitArgs *args) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; static const LxBoardDesc lx60_board = { .flash_size = 0x400000, .flash_sector_size = 0x10000, .sram_size = 0x20000, }; - lx_init(&lx60_board, ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model); + lx_init(&lx60_board, args); } static void xtensa_lx200_init(QEMUMachineInitArgs *args) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; static const LxBoardDesc lx200_board = { .flash_size = 0x1000000, .flash_sector_size = 0x20000, .sram_size = 0x2000000, }; - lx_init(&lx200_board, ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model); + lx_init(&lx200_board, args); } static QEMUMachine xtensa_lx60_machine = { diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c index 2e846d8..0d633e4 100644 --- a/hw/xtensa_sim.c +++ b/hw/xtensa_sim.c @@ -44,16 +44,20 @@ static void sim_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void sim_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void xtensa_sim_init(QEMUMachineInitArgs *args) { XtensaCPU *cpu = NULL; CPUXtensaState *env = NULL; MemoryRegion *ram, *rom; + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; int n; + if (!cpu_model) { + cpu_model = XTENSA_DEFAULT_CPU_MODEL; + } + for (n = 0; n < smp_cpus; n++) { cpu = cpu_xtensa_init(cpu_model); if (cpu == NULL) { @@ -96,21 +100,6 @@ static void sim_init(ram_addr_t ram_size, } } -static void xtensa_sim_init(QEMUMachineInitArgs *args) -{ - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_device; - if (!cpu_model) { - cpu_model = XTENSA_DEFAULT_CPU_MODEL; - } - sim_init(ram_size, boot_device, kernel_filename, kernel_cmdline, - initrd_filename, cpu_model); -} - static QEMUMachine xtensa_sim_machine = { .name = "sim", .desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")", diff --git a/migration-exec.c b/migration-exec.c index 6c97db9..519af57 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -60,22 +60,18 @@ static int exec_close(MigrationState *s) return ret; } -int exec_start_outgoing_migration(MigrationState *s, const char *command) +void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp) { FILE *f; f = popen(command, "w"); if (f == NULL) { - DPRINTF("Unable to popen exec target\n"); - goto err_after_popen; + error_setg_errno(errp, errno, "failed to popen the migration target"); + return; } s->fd = fileno(f); - if (s->fd == -1) { - DPRINTF("Unable to retrieve file descriptor for popen'd handle\n"); - goto err_after_open; - } - + assert(s->fd != -1); socket_set_nonblock(s->fd); s->opaque = qemu_popen(f, "w"); @@ -85,12 +81,6 @@ int exec_start_outgoing_migration(MigrationState *s, const char *command) s->write = file_write; migrate_fd_connect(s); - return 0; - -err_after_open: - pclose(f); -err_after_popen: - return -1; } static void exec_accept_incoming_migration(void *opaque) @@ -102,19 +92,17 @@ static void exec_accept_incoming_migration(void *opaque) qemu_fclose(f); } -int exec_start_incoming_migration(const char *command) +void exec_start_incoming_migration(const char *command, Error **errp) { QEMUFile *f; DPRINTF("Attempting to start an incoming migration\n"); f = qemu_popen_cmd(command, "r"); if(f == NULL) { - DPRINTF("Unable to apply qemu wrapper to popen file\n"); - return -errno; + error_setg_errno(errp, errno, "failed to popen the migration source"); + return; } qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, exec_accept_incoming_migration, NULL, f); - - return 0; } diff --git a/migration-fd.c b/migration-fd.c index 7335167..ce6932d 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -73,30 +73,19 @@ static int fd_close(MigrationState *s) return 0; } -int fd_start_outgoing_migration(MigrationState *s, const char *fdname) +void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp) { - s->fd = monitor_get_fd(cur_mon, fdname, NULL); + s->fd = monitor_get_fd(cur_mon, fdname, errp); if (s->fd == -1) { - DPRINTF("fd_migration: invalid file descriptor identifier\n"); - goto err_after_get_fd; - } - - if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) { - DPRINTF("Unable to set nonblocking mode on file descriptor\n"); - goto err_after_open; + return; } + fcntl(s->fd, F_SETFL, O_NONBLOCK); s->get_error = fd_errno; s->write = fd_write; s->close = fd_close; migrate_fd_connect(s); - return 0; - -err_after_open: - close(s->fd); -err_after_get_fd: - return -1; } static void fd_accept_incoming_migration(void *opaque) @@ -108,7 +97,7 @@ static void fd_accept_incoming_migration(void *opaque) qemu_fclose(f); } -int fd_start_incoming_migration(const char *infd) +void fd_start_incoming_migration(const char *infd, Error **errp) { int fd; QEMUFile *f; @@ -118,11 +107,9 @@ int fd_start_incoming_migration(const char *infd) fd = strtol(infd, NULL, 0); f = qemu_fdopen(fd, "rb"); if(f == NULL) { - DPRINTF("Unable to apply qemu wrapper to file descriptor\n"); - return -errno; + error_setg_errno(errp, errno, "failed to open the source descriptor"); + return; } qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL, f); - - return 0; } diff --git a/migration-tcp.c b/migration-tcp.c index a15c2b8..46f6ac5 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -68,21 +68,13 @@ static void tcp_wait_for_connect(int fd, void *opaque) } } -int tcp_start_outgoing_migration(MigrationState *s, const char *host_port, - Error **errp) +void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp) { s->get_error = socket_errno; s->write = socket_write; s->close = tcp_close; - s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, - errp); - if (error_is_set(errp)) { - migrate_fd_error(s); - return -1; - } - - return 0; + s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp); } static void tcp_accept_incoming_migration(void *opaque) @@ -119,18 +111,15 @@ out2: close(s); } -int tcp_start_incoming_migration(const char *host_port, Error **errp) +void tcp_start_incoming_migration(const char *host_port, Error **errp) { int s; s = inet_listen(host_port, NULL, 256, SOCK_STREAM, 0, errp); - if (s < 0) { - return -1; + return; } qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL, (void *)(intptr_t)s); - - return 0; } diff --git a/migration-unix.c b/migration-unix.c index 169de88..ed3db3a 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -53,69 +53,28 @@ static int unix_close(MigrationState *s) return r; } -static void unix_wait_for_connect(void *opaque) +static void unix_wait_for_connect(int fd, void *opaque) { MigrationState *s = opaque; - int val, ret; - socklen_t valsize = sizeof(val); - DPRINTF("connect completed\n"); - do { - ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); - } while (ret == -1 && errno == EINTR); - - if (ret < 0) { + if (fd < 0) { + DPRINTF("migrate connect error\n"); + s->fd = -1; migrate_fd_error(s); - return; - } - - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); - - if (val == 0) + } else { + DPRINTF("migrate connect success\n"); + s->fd = fd; migrate_fd_connect(s); - else { - DPRINTF("error connecting %d\n", val); - migrate_fd_error(s); } } -int unix_start_outgoing_migration(MigrationState *s, const char *path) +void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp) { - struct sockaddr_un addr; - int ret; - - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path); s->get_error = unix_errno; s->write = unix_write; s->close = unix_close; - s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0); - if (s->fd == -1) { - DPRINTF("Unable to open socket"); - return -errno; - } - - socket_set_nonblock(s->fd); - - do { - ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret == -1) { - ret = -errno; - } - if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) { - qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s); - return 0; - } - } while (ret == -EINTR); - - if (ret < 0) { - DPRINTF("connect failed\n"); - migrate_fd_error(s); - return ret; - } - migrate_fd_connect(s); - return 0; + s->fd = unix_nonblocking_connect(path, unix_wait_for_connect, s, errp); } static void unix_accept_incoming_migration(void *opaque) @@ -152,43 +111,15 @@ out2: close(s); } -int unix_start_incoming_migration(const char *path) +void unix_start_incoming_migration(const char *path, Error **errp) { - struct sockaddr_un addr; int s; - int ret; - - DPRINTF("Attempting to start an incoming migration\n"); - - s = qemu_socket(PF_UNIX, SOCK_STREAM, 0); - if (s == -1) { - fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno)); - return -errno; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path); - unlink(addr.sun_path); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - ret = -errno; - fprintf(stderr, "bind(unix:%s): %s\n", addr.sun_path, strerror(errno)); - goto err; - } - if (listen(s, 1) == -1) { - fprintf(stderr, "listen(unix:%s): %s\n", addr.sun_path, - strerror(errno)); - ret = -errno; - goto err; + s = unix_listen(path, NULL, 0, errp); + if (s < 0) { + return; } qemu_set_fd_handler2(s, NULL, unix_accept_incoming_migration, NULL, (void *)(intptr_t)s); - - return 0; - -err: - close(s); - return ret; } diff --git a/migration.c b/migration.c index 62e0304..300ab75 100644 --- a/migration.c +++ b/migration.c @@ -64,26 +64,23 @@ MigrationState *migrate_get_current(void) return ¤t_migration; } -int qemu_start_incoming_migration(const char *uri, Error **errp) +void qemu_start_incoming_migration(const char *uri, Error **errp) { const char *p; - int ret; if (strstart(uri, "tcp:", &p)) - ret = tcp_start_incoming_migration(p, errp); + tcp_start_incoming_migration(p, errp); #if !defined(WIN32) else if (strstart(uri, "exec:", &p)) - ret = exec_start_incoming_migration(p); + exec_start_incoming_migration(p, errp); else if (strstart(uri, "unix:", &p)) - ret = unix_start_incoming_migration(p); + unix_start_incoming_migration(p, errp); else if (strstart(uri, "fd:", &p)) - ret = fd_start_incoming_migration(p); + fd_start_incoming_migration(p, errp); #endif else { - fprintf(stderr, "unknown migration protocol: %s\n", uri); - ret = -EPROTONOSUPPORT; + error_setg(errp, "unknown migration protocol: %s\n", uri); } - return ret; } void process_incoming_migration(QEMUFile *f) @@ -102,7 +99,7 @@ void process_incoming_migration(QEMUFile *f) if (autostart) { vm_start(); } else { - runstate_set(RUN_STATE_PRELAUNCH); + runstate_set(RUN_STATE_PAUSED); } } @@ -483,10 +480,10 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, bool has_inc, bool inc, bool has_detach, bool detach, Error **errp) { + Error *local_err = NULL; MigrationState *s = migrate_get_current(); MigrationParams params; const char *p; - int ret; params.blk = blk; params.shared = inc; @@ -508,26 +505,23 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, s = migrate_init(¶ms); if (strstart(uri, "tcp:", &p)) { - ret = tcp_start_outgoing_migration(s, p, errp); + tcp_start_outgoing_migration(s, p, &local_err); #if !defined(WIN32) } else if (strstart(uri, "exec:", &p)) { - ret = exec_start_outgoing_migration(s, p); + exec_start_outgoing_migration(s, p, &local_err); } else if (strstart(uri, "unix:", &p)) { - ret = unix_start_outgoing_migration(s, p); + unix_start_outgoing_migration(s, p, &local_err); } else if (strstart(uri, "fd:", &p)) { - ret = fd_start_outgoing_migration(s, p); + fd_start_outgoing_migration(s, p, &local_err); #endif } else { error_set(errp, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol"); return; } - if (ret < 0) { - if (!error_is_set(errp)) { - DPRINTF("migration failed: %s\n", strerror(-ret)); - /* FIXME: we should return meaningful errors */ - error_set(errp, QERR_UNDEFINED_ERROR); - } + if (local_err) { + migrate_fd_error(s); + error_propagate(errp, local_err); return; } diff --git a/migration.h b/migration.h index 1c3e9b7..c3a23cc 100644 --- a/migration.h +++ b/migration.h @@ -49,7 +49,7 @@ struct MigrationState void process_incoming_migration(QEMUFile *f); -int qemu_start_incoming_migration(const char *uri, Error **errp); +void qemu_start_incoming_migration(const char *uri, Error **errp); uint64_t migrate_max_downtime(void); @@ -57,22 +57,21 @@ void do_info_migrate_print(Monitor *mon, const QObject *data); void do_info_migrate(Monitor *mon, QObject **ret_data); -int exec_start_incoming_migration(const char *host_port); +void exec_start_incoming_migration(const char *host_port, Error **errp); -int exec_start_outgoing_migration(MigrationState *s, const char *host_port); +void exec_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp); -int tcp_start_incoming_migration(const char *host_port, Error **errp); +void tcp_start_incoming_migration(const char *host_port, Error **errp); -int tcp_start_outgoing_migration(MigrationState *s, const char *host_port, - Error **errp); +void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp); -int unix_start_incoming_migration(const char *path); +void unix_start_incoming_migration(const char *path, Error **errp); -int unix_start_outgoing_migration(MigrationState *s, const char *path); +void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp); -int fd_start_incoming_migration(const char *path); +void fd_start_incoming_migration(const char *path, Error **errp); -int fd_start_outgoing_migration(MigrationState *s, const char *fdname); +void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp); void migrate_fd_error(MigrationState *s); @@ -208,7 +208,14 @@ int tcp_socket_outgoing(const char *address, uint16_t port) int tcp_socket_outgoing_spec(const char *address_and_port) { - return inet_connect(address_and_port, NULL); + Error *local_err = NULL; + int fd = inet_connect(address_and_port, &local_err); + + if (local_err != NULL) { + qerror_report_err(local_err); + error_free(local_err); + } + return fd; } int tcp_socket_incoming(const char *address, uint16_t port) @@ -220,22 +227,38 @@ int tcp_socket_incoming(const char *address, uint16_t port) int tcp_socket_incoming_spec(const char *address_and_port) { - char *ostr = NULL; - int olen = 0; - return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0, NULL); + Error *local_err = NULL; + int fd = inet_listen(address_and_port, NULL, 0, SOCK_STREAM, 0, &local_err); + + if (local_err != NULL) { + qerror_report_err(local_err); + error_free(local_err); + } + return fd; } int unix_socket_incoming(const char *path) { - char *ostr = NULL; - int olen = 0; + Error *local_err = NULL; + int fd = unix_listen(path, NULL, 0, &local_err); - return unix_listen(path, ostr, olen); + if (local_err != NULL) { + qerror_report_err(local_err); + error_free(local_err); + } + return fd; } int unix_socket_outgoing(const char *path) { - return unix_connect(path); + Error *local_err = NULL; + int fd = unix_connect(path, &local_err); + + if (local_err != NULL) { + qerror_report_err(local_err); + error_free(local_err); + } + return fd; } /* Basic flow for negotiation @@ -121,6 +121,7 @@ void qemu_vfree(void *ptr); #define QEMU_MADV_DONTFORK QEMU_MADV_INVALID #define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID #define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID +#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID #else /* no-op */ @@ -129,6 +130,7 @@ void qemu_vfree(void *ptr); #define QEMU_MADV_DONTFORK QEMU_MADV_INVALID #define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID #define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID +#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID #endif diff --git a/qapi-schema.json b/qapi-schema.json index 6aa443e..542e3ac 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -22,15 +22,11 @@ # @KVMMissingCap: the requested operation can't be fulfilled because a # required KVM capability is missing # -# @MigrationExpected: the requested operation can't be fulfilled because a -# migration process is expected -# # Since: 1.2 ## { 'enum': 'ErrorClass', 'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted', - 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap', - 'MigrationExpected' ] } + 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] } ## # @add_client @@ -149,7 +145,11 @@ # # @finish-migrate: guest is paused to finish the migration process # -# @inmigrate: guest is paused waiting for an incoming migration +# @inmigrate: guest is paused waiting for an incoming migration. Note +# that this state does not tell whether the machine will start at the +# end of the migration. This depends on the command-line -S option and +# any invocation of 'stop' or 'cont' that has happened since QEMU was +# started. # # @internal-error: An internal error that prevents further guest execution # has occurred @@ -1243,7 +1243,9 @@ # Since: 0.14.0 # # Notes: This function will succeed even if the guest is already in the stopped -# state +# state. In "inmigrate" state, it will ensure that the guest +# remains paused once migration finishes, as if the -S option was +# passed on the command line. ## { 'command': 'stop' } @@ -1332,11 +1334,14 @@ # Since: 0.14.0 # # Returns: If successful, nothing -# If the QEMU is waiting for an incoming migration, MigrationExpected # If QEMU was started with an encrypted block device and a key has # not yet been set, DeviceEncrypted. # -# Notes: This command will succeed if the guest is currently running. +# Notes: This command will succeed if the guest is currently running. It +# will also succeed if the guest is in the "inmigrate" state; in +# this case, the effect of the command is to make sure the guest +# starts once migration finishes, removing the effect of the -S +# command line option if it was passed. ## { 'command': 'cont' } @@ -2621,6 +2626,59 @@ 'opts': 'NetClientOptions' } } ## +# @InetSocketAddress +# +# Captures a socket address or address range in the Internet namespace. +# +# @host: host part of the address +# +# @port: port part of the address, or lowest port if @to is present +# +# @to: highest port to try +# +# @ipv4: whether to accept IPv4 addresses, default try both IPv4 and IPv6 +# #optional +# +# @ipv6: whether to accept IPv6 addresses, default try both IPv4 and IPv6 +# #optional +# +# Since 1.3 +## +{ 'type': 'InetSocketAddress', + 'data': { + 'host': 'str', + 'port': 'str', + '*to': 'uint16', + '*ipv4': 'bool', + '*ipv6': 'bool' } } + +## +# @UnixSocketAddress +# +# Captures a socket address in the local ("Unix socket") namespace. +# +# @path: filesystem path to use +# +# Since 1.3 +## +{ 'type': 'UnixSocketAddress', + 'data': { + 'path': 'str' } } + +## +# @SocketAddress +# +# Captures the address of a socket, which could also be a named file descriptor +# +# Since 1.3 +## +{ 'union': 'SocketAddress', + 'data': { + 'inet': 'InetSocketAddress', + 'unix': 'UnixSocketAddress', + 'fd': 'String' } } + +## # @getfd: # # Receive a file descriptor via SCM rights and assign it a name @@ -2912,3 +2970,46 @@ # Since: 0.14.0 ## { 'command': 'screendump', 'data': {'filename': 'str'} } + +## +# @nbd-server-start: +# +# Start an NBD server listening on the given host and port. Block +# devices can then be exported using @nbd-server-add. The NBD +# server will present them as named exports; for example, another +# QEMU instance could refer to them as "nbd:HOST:PORT:exportname=NAME". +# +# @addr: Address on which to listen. +# +# Returns: error if the server is already running. +# +# Since: 1.3.0 +## +{ 'command': 'nbd-server-start', + 'data': { 'addr': 'SocketAddress' } } + +## +# @nbd-server-add: +# +# Export a device to QEMU's embedded NBD server. +# +# @device: Block device to be exported +# +# @writable: Whether clients should be able to write to the device via the +# NBD connection (default false). #optional +# +# Returns: error if the device is already marked for export. +# +# Since: 1.3.0 +## +{ 'command': 'nbd-server-add', 'data': {'device': 'str', '*writable': 'bool'} } + +## +# @nbd-server-stop: +# +# Stop QEMU's embedded NBD server, and unregister all devices previously +# added via @nbd-server-add. +# +# Since: 1.3.0 +## +{ 'command': 'nbd-server-stop' } diff --git a/qemu-char.c b/qemu-char.c index b082bae..afe2bfb 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2097,14 +2097,14 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) { CharDriverState *chr = NULL; NetCharDriver *s = NULL; + Error *local_err = NULL; int fd = -1; chr = g_malloc0(sizeof(CharDriverState)); s = g_malloc0(sizeof(NetCharDriver)); - fd = inet_dgram_opts(opts); + fd = inet_dgram_opts(opts, &local_err); if (fd < 0) { - fprintf(stderr, "inet_dgram_opts failed\n"); goto return_err; } @@ -2118,6 +2118,10 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) return chr; return_err: + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + } g_free(chr); g_free(s); if (fd >= 0) { @@ -2428,6 +2432,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; + Error *local_err = NULL; int fd = -1; int is_listen; int is_waitconnect; @@ -2448,15 +2453,15 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (is_unix) { if (is_listen) { - fd = unix_listen_opts(opts); + fd = unix_listen_opts(opts, &local_err); } else { - fd = unix_connect_opts(opts); + fd = unix_connect_opts(opts, &local_err, NULL, NULL); } } else { if (is_listen) { - fd = inet_listen_opts(opts, 0, NULL); + fd = inet_listen_opts(opts, 0, &local_err); } else { - fd = inet_connect_opts(opts, NULL, NULL, NULL); + fd = inet_connect_opts(opts, &local_err, NULL, NULL); } } if (fd < 0) { @@ -2517,8 +2522,13 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) return chr; fail: - if (fd >= 0) + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + } + if (fd >= 0) { closesocket(fd); + } g_free(s); g_free(chr); return NULL; diff --git a/qemu-config.c b/qemu-config.c index 601237d..e854fff 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -619,6 +619,10 @@ static QemuOptsList qemu_machine_opts = { .name = "mem-merge", .type = QEMU_OPT_BOOL, .help = "enable/disable memory merge support", + },{ + .name = "usb", + .type = QEMU_OPT_BOOL, + .help = "Set on/off to enable/disable usb", }, { /* End of list */ } }, diff --git a/qemu-sockets.c b/qemu-sockets.c index 2b1ed2f..cfed9c5 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -22,6 +22,7 @@ #include <errno.h> #include <unistd.h> +#include "monitor.h" #include "qemu_socket.h" #include "qemu-common.h" /* for qemu_isdigit */ #include "main-loop.h" @@ -120,8 +121,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) if ((qemu_opt_get(opts, "host") == NULL) || (qemu_opt_get(opts, "port") == NULL)) { - fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__); - error_set(errp, QERR_SOCKET_CREATE_FAILED); + error_setg(errp, "host and/or port not specified"); return -1; } pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); @@ -138,9 +138,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); if (rc != 0) { - fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, - gai_strerror(rc)); - error_set(errp, QERR_SOCKET_CREATE_FAILED); + error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, + gai_strerror(rc)); return -1; } @@ -151,10 +150,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) NI_NUMERICHOST | NI_NUMERICSERV); slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (slisten < 0) { - fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, - inet_strfamily(e->ai_family), strerror(errno)); if (!e->ai_next) { - error_set(errp, QERR_SOCKET_CREATE_FAILED); + error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); } continue; } @@ -176,24 +173,19 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) goto listen; } if (p == port_max) { - fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, - inet_strfamily(e->ai_family), uaddr, inet_getport(e), - strerror(errno)); if (!e->ai_next) { - error_set(errp, QERR_SOCKET_BIND_FAILED); + error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); } } } closesocket(slisten); } - fprintf(stderr, "%s: FAILED\n", __FUNCTION__); freeaddrinfo(res); return -1; listen: if (listen(slisten,1) != 0) { - error_set(errp, QERR_SOCKET_LISTEN_FAILED); - perror("listen"); + error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED); closesocket(slisten); freeaddrinfo(res); return -1; @@ -225,7 +217,7 @@ typedef struct ConnectState { } ConnectState; static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, - ConnectState *connect_state); + ConnectState *connect_state, Error **errp); static void wait_for_connect(void *opaque) { @@ -252,16 +244,19 @@ static void wait_for_connect(void *opaque) } /* try to connect to the next address on the list */ - while (s->current_addr->ai_next != NULL && s->fd < 0) { - s->current_addr = s->current_addr->ai_next; - s->fd = inet_connect_addr(s->current_addr, &in_progress, s); - /* connect in progress */ - if (in_progress) { - return; + if (s->current_addr) { + while (s->current_addr->ai_next != NULL && s->fd < 0) { + s->current_addr = s->current_addr->ai_next; + s->fd = inet_connect_addr(s->current_addr, &in_progress, s, NULL); + /* connect in progress */ + if (in_progress) { + return; + } } + + freeaddrinfo(s->addr_list); } - freeaddrinfo(s->addr_list); if (s->callback) { s->callback(s->fd, s->opaque); } @@ -269,7 +264,7 @@ static void wait_for_connect(void *opaque) } static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, - ConnectState *connect_state) + ConnectState *connect_state, Error **errp) { int sock, rc; @@ -277,8 +272,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sock < 0) { - fprintf(stderr, "%s: socket(%s): %s\n", __func__, - inet_strfamily(addr->ai_family), strerror(errno)); + error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); return -1; } qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); @@ -299,6 +293,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, connect_state); *in_progress = true; } else if (rc < 0) { + error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED); closesocket(sock); return -1; } @@ -321,9 +316,7 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); if (addr == NULL || port == NULL) { - fprintf(stderr, - "inet_parse_connect_opts: host and/or port not specified\n"); - error_set(errp, QERR_SOCKET_CREATE_FAILED); + error_setg(errp, "host and/or port not specified"); return NULL; } @@ -337,9 +330,8 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) /* lookup */ rc = getaddrinfo(addr, port, &ai, &res); if (rc != 0) { - fprintf(stderr, "getaddrinfo(%s,%s): %s\n", addr, port, - gai_strerror(rc)); - error_set(errp, QERR_SOCKET_CREATE_FAILED); + error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, + gai_strerror(rc)); return NULL; } return res; @@ -384,7 +376,7 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, if (connect_state != NULL) { connect_state->current_addr = e; } - sock = inet_connect_addr(e, &in_progress, connect_state); + sock = inet_connect_addr(e, &in_progress, connect_state, errp); if (in_progress) { return sock; } else if (sock >= 0) { @@ -395,21 +387,16 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, break; } } - if (sock < 0) { - error_set(errp, QERR_SOCKET_CONNECT_FAILED); - } g_free(connect_state); freeaddrinfo(res); return sock; } -int inet_dgram_opts(QemuOpts *opts) +int inet_dgram_opts(QemuOpts *opts, Error **errp) { struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; - char uaddr[INET6_ADDRSTRLEN+1]; - char uport[33]; int sock = -1, rc; /* lookup peer addr */ @@ -424,7 +411,7 @@ int inet_dgram_opts(QemuOpts *opts) addr = "localhost"; } if (port == NULL || strlen(port) == 0) { - fprintf(stderr, "inet_dgram: port not specified\n"); + error_setg(errp, "remote port not specified"); return -1; } @@ -434,8 +421,8 @@ int inet_dgram_opts(QemuOpts *opts) ai.ai_family = PF_INET6; if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) { - fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, - gai_strerror(rc)); + error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, + gai_strerror(rc)); return -1; } @@ -454,44 +441,28 @@ int inet_dgram_opts(QemuOpts *opts) port = "0"; if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { - fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, - gai_strerror(rc)); + error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, + gai_strerror(rc)); goto err; } /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { - fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, - inet_strfamily(peer->ai_family), strerror(errno)); + error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); goto err; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); /* bind socket */ - if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen, - uaddr,INET6_ADDRSTRLEN,uport,32, - NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); - goto err; - } if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { - fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, - inet_strfamily(local->ai_family), uaddr, inet_getport(local)); + error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); goto err; } /* connect to peer */ - if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen, - uaddr, INET6_ADDRSTRLEN, uport, 32, - NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); - goto err; - } if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { - fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, - inet_strfamily(peer->ai_family), - peer->ai_canonname, uaddr, uport, strerror(errno)); + error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED); goto err; } @@ -510,59 +481,91 @@ err: } /* compatibility wrapper */ -static int inet_parse(QemuOpts *opts, const char *str) +static InetSocketAddress *inet_parse(const char *str, Error **errp) { + InetSocketAddress *addr; const char *optstr, *h; - char addr[64]; + char host[64]; char port[33]; + int to; int pos; + addr = g_new0(InetSocketAddress, 1); + /* parse address */ if (str[0] == ':') { /* no host given */ - addr[0] = '\0'; - if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { - fprintf(stderr, "%s: portonly parse error (%s)\n", - __FUNCTION__, str); - return -1; + host[0] = '\0'; + if (1 != sscanf(str, ":%32[^,]%n", port, &pos)) { + error_setg(errp, "error parsing port in address '%s'", str); + goto fail; } } else if (str[0] == '[') { /* IPv6 addr */ - if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { - fprintf(stderr, "%s: ipv6 parse error (%s)\n", - __FUNCTION__, str); - return -1; + if (2 != sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos)) { + error_setg(errp, "error parsing IPv6 address '%s'", str); + goto fail; } - qemu_opt_set(opts, "ipv6", "on"); + addr->ipv6 = addr->has_ipv6 = true; } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ - if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { - fprintf(stderr, "%s: ipv4 parse error (%s)\n", - __FUNCTION__, str); - return -1; + if (2 != sscanf(str, "%64[0-9.]:%32[^,]%n", host, port, &pos)) { + error_setg(errp, "error parsing IPv4 address '%s'", str); + goto fail; } - qemu_opt_set(opts, "ipv4", "on"); + addr->ipv4 = addr->has_ipv4 = true; } else { /* hostname */ - if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { - fprintf(stderr, "%s: hostname parse error (%s)\n", - __FUNCTION__, str); - return -1; + if (2 != sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos)) { + error_setg(errp, "error parsing address '%s'", str); + goto fail; } } - qemu_opt_set(opts, "host", addr); - qemu_opt_set(opts, "port", port); + + addr->host = g_strdup(host); + addr->port = g_strdup(port); /* parse options */ optstr = str + pos; h = strstr(optstr, ",to="); - if (h) - qemu_opt_set(opts, "to", h+4); - if (strstr(optstr, ",ipv4")) - qemu_opt_set(opts, "ipv4", "on"); - if (strstr(optstr, ",ipv6")) - qemu_opt_set(opts, "ipv6", "on"); - return 0; + if (h) { + if (1 != sscanf(str, "%d%n", &to, &pos) || + (str[pos] != '\0' && str[pos] != ',')) { + error_setg(errp, "error parsing to= argument"); + goto fail; + } + addr->has_to = true; + addr->to = to; + } + if (strstr(optstr, ",ipv4")) { + addr->ipv4 = addr->has_ipv4 = true; + } + if (strstr(optstr, ",ipv6")) { + addr->ipv6 = addr->has_ipv6 = true; + } + return addr; + +fail: + qapi_free_InetSocketAddress(addr); + return NULL; +} + +static void inet_addr_to_opts(QemuOpts *opts, InetSocketAddress *addr) +{ + bool ipv4 = addr->ipv4 || !addr->has_ipv4; + bool ipv6 = addr->ipv6 || !addr->has_ipv6; + + if (!ipv4 || !ipv6) { + qemu_opt_set_bool(opts, "ipv4", ipv4); + qemu_opt_set_bool(opts, "ipv6", ipv6); + } + if (addr->has_to) { + char to[20]; + snprintf(to, sizeof(to), "%d", addr->to); + qemu_opt_set(opts, "to", to); + } + qemu_opt_set(opts, "host", addr->host); + qemu_opt_set(opts, "port", addr->port); } int inet_listen(const char *str, char *ostr, int olen, @@ -571,9 +574,13 @@ int inet_listen(const char *str, char *ostr, int olen, QemuOpts *opts; char *optstr; int sock = -1; + InetSocketAddress *addr; - opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); - if (inet_parse(opts, str) == 0) { + addr = inet_parse(str, errp); + if (addr != NULL) { + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + inet_addr_to_opts(opts, addr); + qapi_free_InetSocketAddress(addr); sock = inet_listen_opts(opts, port_offset, errp); if (sock != -1 && ostr) { optstr = strchr(str, ','); @@ -589,10 +596,8 @@ int inet_listen(const char *str, char *ostr, int olen, optstr ? optstr : ""); } } - } else { - error_set(errp, QERR_SOCKET_CREATE_FAILED); + qemu_opts_del(opts); } - qemu_opts_del(opts); return sock; } @@ -608,14 +613,16 @@ int inet_connect(const char *str, Error **errp) { QemuOpts *opts; int sock = -1; + InetSocketAddress *addr; - opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); - if (inet_parse(opts, str) == 0) { + addr = inet_parse(str, errp); + if (addr != NULL) { + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + inet_addr_to_opts(opts, addr); + qapi_free_InetSocketAddress(addr); sock = inet_connect_opts(opts, errp, NULL, NULL); - } else { - error_set(errp, QERR_SOCKET_CREATE_FAILED); + qemu_opts_del(opts); } - qemu_opts_del(opts); return sock; } @@ -638,22 +645,24 @@ int inet_nonblocking_connect(const char *str, { QemuOpts *opts; int sock = -1; + InetSocketAddress *addr; g_assert(callback != NULL); - opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); - if (inet_parse(opts, str) == 0) { + addr = inet_parse(str, errp); + if (addr != NULL) { + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + inet_addr_to_opts(opts, addr); + qapi_free_InetSocketAddress(addr); sock = inet_connect_opts(opts, errp, callback, opaque); - } else { - error_set(errp, QERR_SOCKET_CREATE_FAILED); + qemu_opts_del(opts); } - qemu_opts_del(opts); return sock; } #ifndef _WIN32 -int unix_listen_opts(QemuOpts *opts) +int unix_listen_opts(QemuOpts *opts, Error **errp) { struct sockaddr_un un; const char *path = qemu_opt_get(opts, "path"); @@ -661,7 +670,7 @@ int unix_listen_opts(QemuOpts *opts) sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { - perror("socket(unix)"); + error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); return -1; } @@ -686,11 +695,11 @@ int unix_listen_opts(QemuOpts *opts) unlink(un.sun_path); if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { - fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); + error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); goto err; } if (listen(sock, 1) < 0) { - fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); + error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED); goto err; } @@ -701,37 +710,85 @@ err: return -1; } -int unix_connect_opts(QemuOpts *opts) +int unix_connect_opts(QemuOpts *opts, Error **errp, + NonBlockingConnectHandler *callback, void *opaque) { struct sockaddr_un un; const char *path = qemu_opt_get(opts, "path"); - int sock; + ConnectState *connect_state = NULL; + int sock, rc; if (NULL == path) { - fprintf(stderr, "unix connect: no path specified\n"); + error_setg(errp, "unix connect: no path specified\n"); return -1; } sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { - perror("socket(unix)"); + error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); return -1; } + if (callback != NULL) { + connect_state = g_malloc0(sizeof(*connect_state)); + connect_state->callback = callback; + connect_state->opaque = opaque; + socket_set_nonblock(sock); + } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); - if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { - fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); + + /* connect to peer */ + do { + rc = 0; + if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) { + rc = -socket_error(); + } + } while (rc == -EINTR); + + if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { + connect_state->fd = sock; + qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect, + connect_state); + return sock; + } else if (rc >= 0) { + /* non blocking socket immediate success, call callback */ + if (callback != NULL) { + callback(sock, opaque); + } + } + + if (rc < 0) { + error_set_errno(errp, -rc, QERR_SOCKET_CONNECT_FAILED); close(sock); - return -1; + sock = -1; } + g_free(connect_state); return sock; } +#else + +int unix_listen_opts(QemuOpts *opts, Error **errp) +{ + error_setg(errp, "unix sockets are not available on windows"); + errno = ENOTSUP; + return -1; +} + +int unix_connect_opts(QemuOpts *opts, Error **errp, + NonBlockingConnectHandler *callback, void *opaque) +{ + error_setg(errp, "unix sockets are not available on windows"); + errno = ENOTSUP; + return -1; +} +#endif + /* compatibility wrapper */ -int unix_listen(const char *str, char *ostr, int olen) +int unix_listen(const char *str, char *ostr, int olen, Error **errp) { QemuOpts *opts; char *path, *optstr; @@ -752,7 +809,7 @@ int unix_listen(const char *str, char *ostr, int olen) qemu_opt_set(opts, "path", str); } - sock = unix_listen_opts(opts); + sock = unix_listen_opts(opts, errp); if (sock != -1 && ostr) snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : ""); @@ -760,49 +817,132 @@ int unix_listen(const char *str, char *ostr, int olen) return sock; } -int unix_connect(const char *path) +int unix_connect(const char *path, Error **errp) { QemuOpts *opts; int sock; opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); qemu_opt_set(opts, "path", path); - sock = unix_connect_opts(opts); + sock = unix_connect_opts(opts, errp, NULL, NULL); qemu_opts_del(opts); return sock; } -#else -int unix_listen_opts(QemuOpts *opts) +int unix_nonblocking_connect(const char *path, + NonBlockingConnectHandler *callback, + void *opaque, Error **errp) { - fprintf(stderr, "unix sockets are not available on windows\n"); - errno = ENOTSUP; - return -1; + QemuOpts *opts; + int sock = -1; + + g_assert(callback != NULL); + + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + qemu_opt_set(opts, "path", path); + sock = unix_connect_opts(opts, errp, callback, opaque); + qemu_opts_del(opts); + return sock; } -int unix_connect_opts(QemuOpts *opts) +SocketAddress *socket_parse(const char *str, Error **errp) { - fprintf(stderr, "unix sockets are not available on windows\n"); - errno = ENOTSUP; - return -1; + SocketAddress *addr = NULL; + + addr = g_new(SocketAddress, 1); + if (strstart(str, "unix:", NULL)) { + if (str[5] == '\0') { + error_setg(errp, "invalid Unix socket address\n"); + goto fail; + } else { + addr->kind = SOCKET_ADDRESS_KIND_UNIX; + addr->q_unix = g_new(UnixSocketAddress, 1); + addr->q_unix->path = g_strdup(str + 5); + } + } else if (strstart(str, "fd:", NULL)) { + if (str[3] == '\0') { + error_setg(errp, "invalid file descriptor address\n"); + goto fail; + } else { + addr->kind = SOCKET_ADDRESS_KIND_FD; + addr->fd = g_new(String, 1); + addr->fd->str = g_strdup(str + 3); + } + } else { + addr->kind = SOCKET_ADDRESS_KIND_INET; + addr->inet = g_new(InetSocketAddress, 1); + addr->inet = inet_parse(str, errp); + if (addr->inet == NULL) { + goto fail; + } + } + return addr; + +fail: + qapi_free_SocketAddress(addr); + return NULL; } -int unix_listen(const char *path, char *ostr, int olen) +int socket_connect(SocketAddress *addr, Error **errp, + NonBlockingConnectHandler *callback, void *opaque) { - fprintf(stderr, "unix sockets are not available on windows\n"); - errno = ENOTSUP; - return -1; + QemuOpts *opts; + int fd; + + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + switch (addr->kind) { + case SOCKET_ADDRESS_KIND_INET: + inet_addr_to_opts(opts, addr->inet); + fd = inet_connect_opts(opts, errp, callback, opaque); + break; + + case SOCKET_ADDRESS_KIND_UNIX: + qemu_opt_set(opts, "path", addr->q_unix->path); + fd = unix_connect_opts(opts, errp, callback, opaque); + break; + + case SOCKET_ADDRESS_KIND_FD: + fd = monitor_get_fd(cur_mon, addr->fd->str, errp); + if (callback) { + callback(fd, opaque); + } + break; + + default: + abort(); + } + qemu_opts_del(opts); + return fd; } -int unix_connect(const char *path) +int socket_listen(SocketAddress *addr, Error **errp) { - fprintf(stderr, "unix sockets are not available on windows\n"); - errno = ENOTSUP; - return -1; -} + QemuOpts *opts; + int fd; -#endif + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + switch (addr->kind) { + case SOCKET_ADDRESS_KIND_INET: + inet_addr_to_opts(opts, addr->inet); + fd = inet_listen_opts(opts, 0, errp); + break; + + case SOCKET_ADDRESS_KIND_UNIX: + qemu_opt_set(opts, "path", addr->q_unix->path); + fd = unix_listen_opts(opts, errp); + break; + + case SOCKET_ADDRESS_KIND_FD: + fd = monitor_get_fd(cur_mon, addr->fd->str, errp); + break; + + default: + abort(); + } + qemu_opts_del(opts); + return fd; +} #ifdef _WIN32 static void socket_cleanup(void) diff --git a/qemu-timer.c b/qemu-timer.c index 908a103..ede84ff 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -494,12 +494,12 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t) memset(&ev, 0, sizeof(ev)); ev.sigev_value.sival_int = 0; ev.sigev_notify = SIGEV_SIGNAL; -#ifdef SIGEV_THREAD_ID +#ifdef CONFIG_SIGEV_THREAD_ID if (qemu_signalfd_available()) { ev.sigev_notify = SIGEV_THREAD_ID; ev._sigev_un._tid = qemu_get_thread_id(); } -#endif /* SIGEV_THREAD_ID */ +#endif /* CONFIG_SIGEV_THREAD_ID */ ev.sigev_signo = SIGALRM; if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { diff --git a/qemu-tool.c b/qemu-tool.c index f2f9813..da4c05a 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -38,6 +38,12 @@ const char *qemu_get_vm_name(void) Monitor *cur_mon; +int monitor_get_fd(Monitor *mon, const char *name, Error **errp) +{ + error_setg(errp, "only QEMU supports file descriptor passing"); + return -1; +} + void vm_stop(RunState state) { abort(); diff --git a/qemu_socket.h b/qemu_socket.h index 3e8aee9..02490ad 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -53,13 +53,22 @@ int inet_nonblocking_connect(const char *str, NonBlockingConnectHandler *callback, void *opaque, Error **errp); -int inet_dgram_opts(QemuOpts *opts); +int inet_dgram_opts(QemuOpts *opts, Error **errp); const char *inet_strfamily(int family); -int unix_listen_opts(QemuOpts *opts); -int unix_listen(const char *path, char *ostr, int olen); -int unix_connect_opts(QemuOpts *opts); -int unix_connect(const char *path); +int unix_listen_opts(QemuOpts *opts, Error **errp); +int unix_listen(const char *path, char *ostr, int olen, Error **errp); +int unix_connect_opts(QemuOpts *opts, Error **errp, + NonBlockingConnectHandler *callback, void *opaque); +int unix_connect(const char *path, Error **errp); +int unix_nonblocking_connect(const char *str, + NonBlockingConnectHandler *callback, + void *opaque, Error **errp); + +SocketAddress *socket_parse(const char *str, Error **errp); +int socket_connect(SocketAddress *addr, Error **errp, + NonBlockingConnectHandler *callback, void *opaque); +int socket_listen(SocketAddress *addr, Error **errp); /* Old, ipv4 only bits. Don't use for new code. */ int parse_host_port(struct sockaddr_in *saddr, const char *str); @@ -168,9 +168,6 @@ void assert_no_error(Error *err); #define QERR_MIGRATION_NOT_SUPPORTED \ ERROR_CLASS_GENERIC_ERROR, "State blocked by non-migratable device '%s'" -#define QERR_MIGRATION_EXPECTED \ - ERROR_CLASS_MIGRATION_EXPECTED, "An incoming migration is expected before this command can be executed" - #define QERR_MISSING_PARAMETER \ ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' is missing" @@ -240,9 +237,6 @@ void assert_no_error(Error *err); #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \ ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'" -#define QERR_VNC_SERVER_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "Could not start VNC server on %s" - #define QERR_SOCKET_CONNECT_FAILED \ ERROR_CLASS_GENERIC_ERROR, "Failed to connect to socket" diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 57eea06..d152827 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -181,9 +181,11 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod break; } case GA_CHANNEL_UNIX_LISTEN: { - int fd = unix_listen(path, NULL, strlen(path)); - if (fd == -1) { - g_critical("error opening path: %s", strerror(errno)); + Error *local_err = NULL; + int fd = unix_listen(path, NULL, strlen(path), &local_err); + if (local_err != NULL) { + g_critical("%s", error_get_pretty(local_err)); + error_free(local_err); return false; } ga_channel_listen_add(c, fd, true); diff --git a/qmp-commands.hx b/qmp-commands.hx index c31312f..5c692d0 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2605,6 +2605,22 @@ EQMP }, { + .name = "nbd-server-start", + .args_type = "addr:q", + .mhandler.cmd_new = qmp_marshal_input_nbd_server_start, + }, + { + .name = "nbd-server-add", + .args_type = "device:B,writable:b?", + .mhandler.cmd_new = qmp_marshal_input_nbd_server_add, + }, + { + .name = "nbd-server-stop", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_nbd_server_stop, + }, + + { .name = "change-vnc-password", .args_type = "password:s", .mhandler.cmd_new = qmp_marshal_input_change_vnc_password, @@ -85,7 +85,11 @@ void qmp_quit(Error **err) void qmp_stop(Error **errp) { - vm_stop(RUN_STATE_PAUSED); + if (runstate_check(RUN_STATE_INMIGRATE)) { + autostart = 0; + } else { + vm_stop(RUN_STATE_PAUSED); + } } void qmp_system_reset(Error **errp) @@ -144,10 +148,7 @@ void qmp_cont(Error **errp) { Error *local_err = NULL; - if (runstate_check(RUN_STATE_INMIGRATE)) { - error_set(errp, QERR_MIGRATION_EXPECTED); - return; - } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) || + if (runstate_check(RUN_STATE_INTERNAL_ERROR) || runstate_check(RUN_STATE_SHUTDOWN)) { error_set(errp, QERR_RESET_REQUIRED); return; @@ -162,7 +163,11 @@ void qmp_cont(Error **errp) return; } - vm_start(); + if (runstate_check(RUN_STATE_INMIGRATE)) { + autostart = 1; + } else { + vm_start(); + } } void qmp_system_wakeup(Error **errp) @@ -349,11 +354,9 @@ void qmp_change_vnc_password(const char *password, Error **errp) } } -static void qmp_change_vnc_listen(const char *target, Error **err) +static void qmp_change_vnc_listen(const char *target, Error **errp) { - if (vnc_display_open(NULL, target) < 0) { - error_set(err, QERR_VNC_SERVER_FAILED, target); - } + vnc_display_open(NULL, target, errp); } static void qmp_change_vnc(const char *target, bool has_arg, const char *arg, @@ -116,7 +116,6 @@ extern const char *keyboard_layout; extern int win2k_install_hack; extern int alt_grab; extern int ctrl_grab; -extern int usb_enabled; extern int smp_cpus; extern int max_cpus; extern int cursor_hide; @@ -186,4 +185,7 @@ void register_devices(void); void add_boot_device_path(int32_t bootindex, DeviceState *dev, const char *suffix); char *get_boot_devices_list(uint32_t *size); + +bool usb_enabled(bool default_usb); + #endif diff --git a/target-alpha/helper.h b/target-alpha/helper.h index a184def..162816f 100644 --- a/target-alpha/helper.h +++ b/target-alpha/helper.h @@ -1,7 +1,7 @@ #include "def-helper.h" DEF_HELPER_3(excp, noreturn, env, int, int) -DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64, env) +DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_3(addqv, i64, env, i64, i64) DEF_HELPER_3(addlv, i64, env, i64, i64) @@ -9,89 +9,89 @@ DEF_HELPER_3(subqv, i64, env, i64, i64) DEF_HELPER_3(sublv, i64, env, i64, i64) DEF_HELPER_3(mullv, i64, env, i64, i64) DEF_HELPER_3(mulqv, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(umulh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) - -DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) -DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) -DEF_HELPER_FLAGS_1(cttz, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) - -DEF_HELPER_FLAGS_2(zap, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) - -DEF_HELPER_FLAGS_2(cmpbge, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) - -DEF_HELPER_FLAGS_2(minub8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(minsb8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(minuw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(minsw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(maxub8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(maxsb8, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(maxuw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(maxsw4, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(perr, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_1(pklb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) -DEF_HELPER_FLAGS_1(pkwb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) -DEF_HELPER_FLAGS_1(unpkbl, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) -DEF_HELPER_FLAGS_1(unpkbw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) - -DEF_HELPER_FLAGS_1(load_fpcr, TCG_CALL_CONST | TCG_CALL_PURE, i64, env) -DEF_HELPER_FLAGS_2(store_fpcr, TCG_CALL_CONST, void, env, i64) - -DEF_HELPER_FLAGS_1(f_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64) -DEF_HELPER_FLAGS_1(memory_to_f, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32) -DEF_HELPER_FLAGS_3(addf, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(subf, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(mulf, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divf, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(sqrtf, TCG_CALL_CONST, i64, env, i64) - -DEF_HELPER_FLAGS_1(g_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) -DEF_HELPER_FLAGS_1(memory_to_g, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) -DEF_HELPER_FLAGS_3(addg, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(subg, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(mulg, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divg, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(sqrtg, TCG_CALL_CONST, i64, env, i64) - -DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64) -DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32) -DEF_HELPER_FLAGS_3(adds, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(subs, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(muls, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divs, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(sqrts, TCG_CALL_CONST, i64, env, i64) - -DEF_HELPER_FLAGS_3(addt, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(subt, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(mult, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divt, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(sqrtt, TCG_CALL_CONST, i64, env, i64) - -DEF_HELPER_FLAGS_3(cmptun, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmpteq, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmptle, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmptlt, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmpgeq, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmpgle, TCG_CALL_CONST, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmpglt, TCG_CALL_CONST, i64, env, i64, i64) - -DEF_HELPER_FLAGS_2(cvtts, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtst, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtqs, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtqt, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtqf, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtgf, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtgq, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtqg, TCG_CALL_CONST, i64, env, i64) - -DEF_HELPER_FLAGS_2(cvttq, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvttq_c, TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_2(cvttq_svic, TCG_CALL_CONST, i64, env, i64) - -DEF_HELPER_FLAGS_2(setroundmode, TCG_CALL_CONST, void, env, i32) -DEF_HELPER_FLAGS_2(setflushzero, TCG_CALL_CONST, void, env, i32) -DEF_HELPER_FLAGS_1(fp_exc_clear, TCG_CALL_CONST, void, env) -DEF_HELPER_FLAGS_1(fp_exc_get, TCG_CALL_CONST | TCG_CALL_PURE, i32, env) +DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, i64, i64, i64) + +DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_1(cttz, TCG_CALL_NO_RWG_SE, i64, i64) + +DEF_HELPER_FLAGS_2(zap, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_NO_RWG_SE, i64, i64, i64) + +DEF_HELPER_FLAGS_2(cmpbge, TCG_CALL_NO_RWG_SE, i64, i64, i64) + +DEF_HELPER_FLAGS_2(minub8, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(minsb8, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(minuw4, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(minsw4, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(maxub8, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(maxsb8, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(maxuw4, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(maxsw4, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(perr, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_1(pklb, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_1(pkwb, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_1(unpkbl, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_1(unpkbw, TCG_CALL_NO_RWG_SE, i64, i64) + +DEF_HELPER_FLAGS_1(load_fpcr, TCG_CALL_NO_RWG_SE, i64, env) +DEF_HELPER_FLAGS_2(store_fpcr, TCG_CALL_NO_RWG, void, env, i64) + +DEF_HELPER_FLAGS_1(f_to_memory, TCG_CALL_NO_RWG_SE, i32, i64) +DEF_HELPER_FLAGS_1(memory_to_f, TCG_CALL_NO_RWG_SE, i64, i32) +DEF_HELPER_FLAGS_3(addf, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(subf, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mulf, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(divf, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(sqrtf, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_1(g_to_memory, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_1(memory_to_g, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_3(addg, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(subg, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mulg, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(divg, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(sqrtg, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_NO_RWG_SE, i32, i64) +DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_NO_RWG_SE, i64, i32) +DEF_HELPER_FLAGS_3(adds, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(subs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(muls, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(sqrts, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_3(addt, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(subt, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mult, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(divt, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(sqrtt, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_3(cmptun, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(cmpteq, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(cmptle, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(cmptlt, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(cmpgeq, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(cmpgle, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(cmpglt, TCG_CALL_NO_RWG, i64, env, i64, i64) + +DEF_HELPER_FLAGS_2(cvtts, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvtst, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvtqs, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvtqt, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvtqf, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvtgf, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvtgq, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvtqg, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_2(cvttq, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvttq_c, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(cvttq_svic, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_2(setroundmode, TCG_CALL_NO_RWG, void, env, i32) +DEF_HELPER_FLAGS_2(setflushzero, TCG_CALL_NO_RWG, void, env, i32) +DEF_HELPER_FLAGS_1(fp_exc_clear, TCG_CALL_NO_RWG, void, env) +DEF_HELPER_FLAGS_1(fp_exc_get, TCG_CALL_NO_RWG_SE, i32, env) DEF_HELPER_3(fp_exc_raise, void, env, i32, i32) DEF_HELPER_3(fp_exc_raise_s, void, env, i32, i32) @@ -110,13 +110,13 @@ DEF_HELPER_2(stq_phys, void, i64, i64) DEF_HELPER_3(stl_c_phys, i64, env, i64, i64) DEF_HELPER_3(stq_c_phys, i64, env, i64, i64) -DEF_HELPER_FLAGS_1(tbia, TCG_CALL_CONST, void, env) -DEF_HELPER_FLAGS_2(tbis, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_1(tbia, TCG_CALL_NO_RWG, void, env) +DEF_HELPER_FLAGS_2(tbis, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_1(halt, void, i64); -DEF_HELPER_FLAGS_0(get_time, TCG_CALL_CONST, i64) -DEF_HELPER_FLAGS_2(set_alarm, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_0(get_time, TCG_CALL_NO_RWG, i64) +DEF_HELPER_FLAGS_2(set_alarm, TCG_CALL_NO_RWG, void, env, i64) #endif #include "def-helper.h" diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c index 73bde58..7743d67 100644 --- a/target-arm/arm-semi.c +++ b/target-arm/arm-semi.c @@ -166,17 +166,20 @@ static void arm_semi_flen_cb(CPUARMState *env, target_ulong ret, target_ulong er #endif } -#define ARG(n) \ -({ \ - target_ulong __arg; \ - /* FIXME - handle get_user() failure */ \ - get_user_ual(__arg, args + (n) * 4); \ - __arg; \ -}) +/* Read the input value from the argument block; fail the semihosting + * call if the memory read fails. + */ +#define GET_ARG(n) do { \ + if (get_user_ual(arg ## n, args + (n) * 4)) { \ + return (uint32_t)-1; \ + } \ +} while (0) + #define SET_ARG(n, val) put_user_ual(val, args + (n) * 4) uint32_t do_arm_semihosting(CPUARMState *env) { target_ulong args; + target_ulong arg0, arg1, arg2, arg3; char * s; int nr; uint32_t ret; @@ -191,33 +194,39 @@ uint32_t do_arm_semihosting(CPUARMState *env) args = env->regs[1]; switch (nr) { case TARGET_SYS_OPEN: - if (!(s = lock_user_string(ARG(0)))) + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + s = lock_user_string(arg0); + if (!s) { /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; - if (ARG(1) >= 12) { - unlock_user(s, ARG(0), 0); + } + if (arg1 >= 12) { + unlock_user(s, arg0, 0); return (uint32_t)-1; } if (strcmp(s, ":tt") == 0) { - int result_fileno = ARG(1) < 4 ? STDIN_FILENO : STDOUT_FILENO; - unlock_user(s, ARG(0), 0); + int result_fileno = arg1 < 4 ? STDIN_FILENO : STDOUT_FILENO; + unlock_user(s, arg0, 0); return result_fileno; } if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), - (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]); + gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", arg0, + (int)arg2+1, gdb_open_modeflags[arg1]); ret = env->regs[0]; } else { - ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); + ret = set_swi_errno(ts, open(s, open_modeflags[arg1], 0644)); } - unlock_user(s, ARG(0), 0); + unlock_user(s, arg0, 0); return ret; case TARGET_SYS_CLOSE: + GET_ARG(0); if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0)); + gdb_do_syscall(arm_semi_cb, "close,%x", arg0); return env->regs[0]; } else { - return set_swi_errno(ts, close(ARG(0))); + return set_swi_errno(ts, close(arg0)); } case TARGET_SYS_WRITEC: { @@ -248,35 +257,45 @@ uint32_t do_arm_semihosting(CPUARMState *env) unlock_user(s, args, 0); return ret; case TARGET_SYS_WRITE: - len = ARG(2); + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + len = arg2; if (use_gdb_syscalls()) { arm_semi_syscall_len = len; - gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len); + gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", arg0, arg1, len); return env->regs[0]; } else { - if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1))) + s = lock_user(VERIFY_READ, arg1, len, 1); + if (!s) { /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; - ret = set_swi_errno(ts, write(ARG(0), s, len)); - unlock_user(s, ARG(1), 0); + } + ret = set_swi_errno(ts, write(arg0, s, len)); + unlock_user(s, arg1, 0); if (ret == (uint32_t)-1) return -1; return len - ret; } case TARGET_SYS_READ: - len = ARG(2); + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + len = arg2; if (use_gdb_syscalls()) { arm_semi_syscall_len = len; - gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len); + gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", arg0, arg1, len); return env->regs[0]; } else { - if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0))) + s = lock_user(VERIFY_WRITE, arg1, len, 0); + if (!s) { /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; - do - ret = set_swi_errno(ts, read(ARG(0), s, len)); - while (ret == -1 && errno == EINTR); - unlock_user(s, ARG(1), len); + } + do { + ret = set_swi_errno(ts, read(arg0, s, len)); + } while (ret == -1 && errno == EINTR); + unlock_user(s, arg1, len); if (ret == (uint32_t)-1) return -1; return len - ret; @@ -285,30 +304,34 @@ uint32_t do_arm_semihosting(CPUARMState *env) /* XXX: Read from debug console. Not implemented. */ return 0; case TARGET_SYS_ISTTY: + GET_ARG(0); if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0)); + gdb_do_syscall(arm_semi_cb, "isatty,%x", arg0); return env->regs[0]; } else { - return isatty(ARG(0)); + return isatty(arg0); } case TARGET_SYS_SEEK: + GET_ARG(0); + GET_ARG(1); if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1)); + gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", arg0, arg1); return env->regs[0]; } else { - ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); + ret = set_swi_errno(ts, lseek(arg0, arg1, SEEK_SET)); if (ret == (uint32_t)-1) return -1; return 0; } case TARGET_SYS_FLEN: + GET_ARG(0); if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x", - ARG(0), env->regs[13]-64); + arg0, env->regs[13]-64); return env->regs[0]; } else { struct stat buf; - ret = set_swi_errno(ts, fstat(ARG(0), &buf)); + ret = set_swi_errno(ts, fstat(arg0, &buf)); if (ret == (uint32_t)-1) return -1; return buf.st_size; @@ -317,35 +340,43 @@ uint32_t do_arm_semihosting(CPUARMState *env) /* XXX: Not implemented. */ return -1; case TARGET_SYS_REMOVE: + GET_ARG(0); + GET_ARG(1); if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1); + gdb_do_syscall(arm_semi_cb, "unlink,%s", arg0, (int)arg1+1); ret = env->regs[0]; } else { - if (!(s = lock_user_string(ARG(0)))) + s = lock_user_string(arg0); + if (!s) { /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; + } ret = set_swi_errno(ts, remove(s)); - unlock_user(s, ARG(0), 0); + unlock_user(s, arg0, 0); } return ret; case TARGET_SYS_RENAME: + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + GET_ARG(3); if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "rename,%s,%s", - ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1); + arg0, (int)arg1+1, arg2, (int)arg3+1); return env->regs[0]; } else { char *s2; - s = lock_user_string(ARG(0)); - s2 = lock_user_string(ARG(2)); + s = lock_user_string(arg0); + s2 = lock_user_string(arg2); if (!s || !s2) /* FIXME - should this error code be -TARGET_EFAULT ? */ ret = (uint32_t)-1; else ret = set_swi_errno(ts, rename(s, s2)); if (s2) - unlock_user(s2, ARG(2), 0); + unlock_user(s2, arg2, 0); if (s) - unlock_user(s, ARG(0), 0); + unlock_user(s, arg0, 0); return ret; } case TARGET_SYS_CLOCK: @@ -353,15 +384,19 @@ uint32_t do_arm_semihosting(CPUARMState *env) case TARGET_SYS_TIME: return set_swi_errno(ts, time(NULL)); case TARGET_SYS_SYSTEM: + GET_ARG(0); + GET_ARG(1); if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1); + gdb_do_syscall(arm_semi_cb, "system,%s", arg0, (int)arg1+1); return env->regs[0]; } else { - if (!(s = lock_user_string(ARG(0)))) + s = lock_user_string(arg0); + if (!s) { /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; + } ret = set_swi_errno(ts, system(s)); - unlock_user(s, ARG(0), 0); + unlock_user(s, arg0, 0); return ret; } case TARGET_SYS_ERRNO: @@ -375,22 +410,24 @@ uint32_t do_arm_semihosting(CPUARMState *env) /* Build a command-line from the original argv. * * The inputs are: - * * ARG(0), pointer to a buffer of at least the size - * specified in ARG(1). - * * ARG(1), size of the buffer pointed to by ARG(0) in + * * arg0, pointer to a buffer of at least the size + * specified in arg1. + * * arg1, size of the buffer pointed to by arg0 in * bytes. * * The outputs are: - * * ARG(0), pointer to null-terminated string of the + * * arg0, pointer to null-terminated string of the * command line. - * * ARG(1), length of the string pointed to by ARG(0). + * * arg1, length of the string pointed to by arg0. */ char *output_buffer; - size_t input_size = ARG(1); + size_t input_size; size_t output_size; int status = 0; - + GET_ARG(0); + GET_ARG(1); + input_size = arg1; /* Compute the size of the output string. */ #if !defined(CONFIG_USER_ONLY) output_size = strlen(ts->boot_info->kernel_filename) @@ -414,10 +451,13 @@ uint32_t do_arm_semihosting(CPUARMState *env) } /* Adjust the command-line length. */ - SET_ARG(1, output_size - 1); + if (SET_ARG(1, output_size - 1)) { + /* Couldn't write back to argument block */ + return -1; + } /* Lock the buffer on the ARM side. */ - output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0); + output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0); if (!output_buffer) { return -1; } @@ -449,7 +489,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) out: #endif /* Unlock the buffer on the ARM side. */ - unlock_user(output_buffer, ARG(0), output_size); + unlock_user(output_buffer, arg0, output_size); return status; } @@ -457,6 +497,7 @@ uint32_t do_arm_semihosting(CPUARMState *env) { uint32_t *ptr; uint32_t limit; + GET_ARG(0); #ifdef CONFIG_USER_ONLY /* Some C libraries assume the heap immediately follows .bss, so @@ -477,25 +518,29 @@ uint32_t do_arm_semihosting(CPUARMState *env) ts->heap_limit = limit; } - if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0))) + ptr = lock_user(VERIFY_WRITE, arg0, 16, 0); + if (!ptr) { /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; + } ptr[0] = tswap32(ts->heap_base); ptr[1] = tswap32(ts->heap_limit); ptr[2] = tswap32(ts->stack_base); ptr[3] = tswap32(0); /* Stack limit. */ - unlock_user(ptr, ARG(0), 16); + unlock_user(ptr, arg0, 16); #else limit = ram_size; - if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0))) + ptr = lock_user(VERIFY_WRITE, arg0, 16, 0); + if (!ptr) { /* FIXME - should this error code be -TARGET_EFAULT ? */ return (uint32_t)-1; + } /* TODO: Make this use the limit of the loaded application. */ ptr[0] = tswap32(limit / 2); ptr[1] = tswap32(limit); ptr[2] = tswap32(limit); /* Stack base */ ptr[3] = tswap32(0); /* Stack limit. */ - unlock_user(ptr, ARG(0), 16); + unlock_user(ptr, arg0, 16); #endif return 0; } diff --git a/target-arm/helper.c b/target-arm/helper.c index 8f2cba6..ab8b734 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1562,11 +1562,6 @@ uint32_t HELPER(rbit)(uint32_t x) return x; } -uint32_t HELPER(abs)(uint32_t x) -{ - return ((int32_t)x < 0) ? -x : x; -} - #if defined(CONFIG_USER_ONLY) void do_interrupt (CPUARMState *env) diff --git a/target-arm/helper.h b/target-arm/helper.h index 8b9adf1..3d23ceb 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -1,8 +1,8 @@ #include "def-helper.h" -DEF_HELPER_FLAGS_1(clz, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) -DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) -DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_3(add_setq, i32, env, i32, i32) DEF_HELPER_3(add_saturate, i32, env, i32, i32) @@ -10,10 +10,9 @@ DEF_HELPER_3(sub_saturate, i32, env, i32, i32) DEF_HELPER_3(add_usaturate, i32, env, i32, i32) DEF_HELPER_3(sub_usaturate, i32, env, i32, i32) DEF_HELPER_2(double_saturate, i32, env, s32) -DEF_HELPER_FLAGS_2(sdiv, TCG_CALL_CONST | TCG_CALL_PURE, s32, s32, s32) -DEF_HELPER_FLAGS_2(udiv, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) -DEF_HELPER_FLAGS_1(rbit, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) -DEF_HELPER_FLAGS_1(abs, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_2(sdiv, TCG_CALL_NO_RWG_SE, s32, s32, s32) +DEF_HELPER_FLAGS_2(udiv, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_1(rbit, TCG_CALL_NO_RWG_SE, i32, i32) #define PAS_OP(pfx) \ DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ @@ -45,11 +44,11 @@ DEF_HELPER_3(usat, i32, env, i32, i32) DEF_HELPER_3(ssat16, i32, env, i32, i32) DEF_HELPER_3(usat16, i32, env, i32, i32) -DEF_HELPER_FLAGS_2(usad8, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_1(logicq_cc, i32, i64) -DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_CONST | TCG_CALL_PURE, +DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_2(exception, void, env, i32) DEF_HELPER_1(wfi, void, env) @@ -339,7 +338,6 @@ DEF_HELPER_2(neon_mull_s16, i64, i32, i32) DEF_HELPER_1(neon_negl_u16, i64, i64) DEF_HELPER_1(neon_negl_u32, i64, i64) -DEF_HELPER_1(neon_negl_u64, i64, i64) DEF_HELPER_2(neon_qabs_s8, i32, env, i32) DEF_HELPER_2(neon_qabs_s16, i32, env, i32) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 9aa920d..89280b6 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -1664,12 +1664,6 @@ uint64_t HELPER(neon_negl_u32)(uint64_t x) return low | ((uint64_t)high << 32); } -/* FIXME: There should be a native op for this. */ -uint64_t HELPER(neon_negl_u64)(uint64_t x) -{ - return -x; -} - /* Saturating sign manipulation. */ /* ??? Make these use NEON_VOP1 */ #define DO_QABS8(x) do { \ diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index aef592a..6e3ab90 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -93,8 +93,6 @@ void tlb_fill(CPUARMState *env, target_ulong addr, int is_write, int mmu_idx, } #endif -/* FIXME: Pass an explicit pointer to QF to CPUARMState, and move saturating - instructions into helper.c */ uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) { uint32_t res = a + b; diff --git a/target-arm/translate.c b/target-arm/translate.c index daccb15..25433da 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -462,8 +462,15 @@ static void gen_sar(TCGv dest, TCGv t0, TCGv t1) tcg_temp_free_i32(tmp1); } -/* FIXME: Implement this natively. */ -#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1) +static void tcg_gen_abs_i32(TCGv dest, TCGv src) +{ + TCGv c0 = tcg_const_i32(0); + TCGv tmp = tcg_temp_new_i32(); + tcg_gen_neg_i32(tmp, src); + tcg_gen_movcond_i32(TCG_COND_GT, dest, src, c0, src, tmp); + tcg_temp_free_i32(c0); + tcg_temp_free_i32(tmp); +} static void shifter_out_im(TCGv var, int shift) { @@ -4184,7 +4191,9 @@ static inline void gen_neon_negl(TCGv_i64 var, int size) switch (size) { case 0: gen_helper_neon_negl_u16(var, var); break; case 1: gen_helper_neon_negl_u32(var, var); break; - case 2: gen_helper_neon_negl_u64(var, var); break; + case 2: + tcg_gen_neg_i64(var, var); + break; default: abort(); } } diff --git a/target-cris/helper.h b/target-cris/helper.h index 99fb326..fe12083 100644 --- a/target-cris/helper.h +++ b/target-cris/helper.h @@ -10,19 +10,19 @@ DEF_HELPER_1(rfn, void, env); DEF_HELPER_3(movl_sreg_reg, void, env, i32, i32) DEF_HELPER_3(movl_reg_sreg, void, env, i32, i32) -DEF_HELPER_FLAGS_1(lz, TCG_CALL_PURE, i32, i32); -DEF_HELPER_FLAGS_4(btst, TCG_CALL_PURE, i32, env, i32, i32, i32); +DEF_HELPER_FLAGS_1(lz, TCG_CALL_NO_SE, i32, i32); +DEF_HELPER_FLAGS_4(btst, TCG_CALL_NO_SE, i32, env, i32, i32, i32); -DEF_HELPER_FLAGS_4(evaluate_flags_muls, TCG_CALL_PURE, i32, env, i32, i32, i32) -DEF_HELPER_FLAGS_4(evaluate_flags_mulu, TCG_CALL_PURE, i32, env, i32, i32, i32) -DEF_HELPER_FLAGS_5(evaluate_flags_mcp, TCG_CALL_PURE, i32, env, +DEF_HELPER_FLAGS_4(evaluate_flags_muls, TCG_CALL_NO_SE, i32, env, i32, i32, i32) +DEF_HELPER_FLAGS_4(evaluate_flags_mulu, TCG_CALL_NO_SE, i32, env, i32, i32, i32) +DEF_HELPER_FLAGS_5(evaluate_flags_mcp, TCG_CALL_NO_SE, i32, env, i32, i32, i32, i32) -DEF_HELPER_FLAGS_5(evaluate_flags_alu_4, TCG_CALL_PURE, i32, env, +DEF_HELPER_FLAGS_5(evaluate_flags_alu_4, TCG_CALL_NO_SE, i32, env, i32, i32, i32, i32) -DEF_HELPER_FLAGS_5(evaluate_flags_sub_4, TCG_CALL_PURE, i32, env, +DEF_HELPER_FLAGS_5(evaluate_flags_sub_4, TCG_CALL_NO_SE, i32, env, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(evaluate_flags_move_4, TCG_CALL_PURE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(evaluate_flags_move_2, TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(evaluate_flags_move_4, TCG_CALL_NO_SE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(evaluate_flags_move_2, TCG_CALL_NO_SE, i32, env, i32, i32) DEF_HELPER_1(evaluate_flags, void, env) DEF_HELPER_1(top_evaluate_flags, void, env) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index f3708e6..6411042 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -74,6 +74,7 @@ static const char *ext2_feature_name[] = { NULL /* pat */, NULL /* pse36 */, NULL, NULL /* Linux mp */, "nx|xd", NULL, "mmxext", NULL /* mmx */, NULL /* fxsr */, "fxsr_opt|ffxsr", "pdpe1gb" /* AMD Page1GB */, "rdtscp", + NULL, "lm|i64", "3dnowext", "3dnow", }; static const char *ext3_feature_name[] = { "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, diff --git a/target-i386/helper.h b/target-i386/helper.h index 93850ce..970fcd9 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -1,7 +1,7 @@ #include "def-helper.h" -DEF_HELPER_FLAGS_2(cc_compute_all, TCG_CALL_PURE, i32, env, int) -DEF_HELPER_FLAGS_2(cc_compute_c, TCG_CALL_PURE, i32, env, int) +DEF_HELPER_FLAGS_2(cc_compute_all, TCG_CALL_NO_SE, i32, env, int) +DEF_HELPER_FLAGS_2(cc_compute_c, TCG_CALL_NO_SE, i32, env, int) DEF_HELPER_0(lock, void) DEF_HELPER_0(unlock, void) diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h index a1a732c..a667122 100644 --- a/target-microblaze/helper.h +++ b/target-microblaze/helper.h @@ -2,10 +2,10 @@ DEF_HELPER_2(raise_exception, void, env, i32) DEF_HELPER_1(debug, void, env) -DEF_HELPER_FLAGS_3(carry, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(carry, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_2(cmp, i32, i32, i32) DEF_HELPER_2(cmpu, i32, i32, i32) -DEF_HELPER_FLAGS_1(clz, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_3(divs, i32, env, i32, i32) DEF_HELPER_3(divu, i32, env, i32, i32) @@ -26,7 +26,7 @@ DEF_HELPER_3(fcmp_gt, i32, env, i32, i32) DEF_HELPER_3(fcmp_ne, i32, env, i32, i32) DEF_HELPER_3(fcmp_ge, i32, env, i32, i32) -DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32) +DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_NO_RWG_SE, i32, i32, i32) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(mmu_read, i32, env, i32) DEF_HELPER_3(mmu_write, void, env, i32, i32) diff --git a/target-mips/helper.h b/target-mips/helper.h index f35ed78..43ac39f 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -23,11 +23,11 @@ DEF_HELPER_4(scd, tl, env, tl, tl, int) #endif #endif -DEF_HELPER_FLAGS_1(clo, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) -DEF_HELPER_FLAGS_1(clz, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_FLAGS_1(clo, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl) #ifdef TARGET_MIPS64 -DEF_HELPER_FLAGS_1(dclo, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) -DEF_HELPER_FLAGS_1(dclz, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_FLAGS_1(dclo, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(dclz, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_3(dmult, void, env, tl, tl) DEF_HELPER_3(dmultu, void, env, tl, tl) #endif @@ -304,62 +304,62 @@ DEF_HELPER_2(pmon, void, env, int) DEF_HELPER_1(wait, void, env) /* Loongson multimedia functions. */ -DEF_HELPER_FLAGS_2(paddsh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(paddush, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(paddh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(paddw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(paddsb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(paddusb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(paddb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddush, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddsb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddusb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(paddb, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psubsh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psubush, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psubh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psubw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psubsb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psubusb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psubb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubush, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubsb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubusb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psubb, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pshufh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(packsswh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(packsshb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(packushb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pshufh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(packsswh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(packsshb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(packushb, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(punpcklhw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(punpckhhw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(punpcklbh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(punpckhbh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(punpcklwd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(punpckhwd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpcklhw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpckhhw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpcklbh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpckhbh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpcklwd, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(punpckhwd, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pavgh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pavgb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pmaxsh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pminsh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pmaxub, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pminub, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pavgh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pavgb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaxsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pminsh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaxub, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pminub, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pcmpeqw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pcmpgtw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pcmpeqh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pcmpgth, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pcmpeqb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pcmpgtb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpeqw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpgtw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpeqh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpgth, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpeqb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pcmpgtb, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psllw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psllh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psrlw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psrlh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psraw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(psrah, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psllw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psllh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psrlw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psrlh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psraw, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(psrah, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pmullh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pmulhh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pmulhuh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pmaddhw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmullh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmulhh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmulhuh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(pmaddhw, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(pasubub, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_1(biadd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) -DEF_HELPER_FLAGS_1(pmovmskb, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64) +DEF_HELPER_FLAGS_2(pasubub, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_1(biadd, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_1(pmovmskb, TCG_CALL_NO_RWG_SE, i64, i64) #include "def-helper.h" diff --git a/target-mips/translate.c b/target-mips/translate.c index 454e5cc..ed55e26 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -575,6 +575,7 @@ static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], cpu_ACX[MIPS_DSP_ACC]; static TCGv cpu_dspctrl, btarget, bcond; static TCGv_i32 hflags; static TCGv_i32 fpu_fcr0, fpu_fcr31; +static TCGv_i64 fpu_f64[32]; static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; @@ -642,26 +643,31 @@ enum { BS_EXCP = 3, /* We reached an exception condition */ }; -static const char *regnames[] = - { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; +static const char * const regnames[] = { + "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", +}; -static const char *regnames_HI[] = - { "HI0", "HI1", "HI2", "HI3", }; +static const char * const regnames_HI[] = { + "HI0", "HI1", "HI2", "HI3", +}; -static const char *regnames_LO[] = - { "LO0", "LO1", "LO2", "LO3", }; +static const char * const regnames_LO[] = { + "LO0", "LO1", "LO2", "LO3", +}; -static const char *regnames_ACX[] = - { "ACX0", "ACX1", "ACX2", "ACX3", }; +static const char * const regnames_ACX[] = { + "ACX0", "ACX1", "ACX2", "ACX3", +}; -static const char *fregnames[] = - { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; +static const char * const fregnames[] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", +}; #define MIPS_DEBUG(fmt, ...) \ do { \ @@ -758,54 +764,54 @@ static inline void gen_store_srsgpr (int from, int to) } /* Floating point register moves. */ -static inline void gen_load_fpr32 (TCGv_i32 t, int reg) +static void gen_load_fpr32(TCGv_i32 t, int reg) { - tcg_gen_ld_i32(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].w[FP_ENDIAN_IDX])); + tcg_gen_trunc_i64_i32(t, fpu_f64[reg]); } -static inline void gen_store_fpr32 (TCGv_i32 t, int reg) +static void gen_store_fpr32(TCGv_i32 t, int reg) { - tcg_gen_st_i32(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].w[FP_ENDIAN_IDX])); + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t64, t); + tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 0, 32); + tcg_temp_free_i64(t64); } -static inline void gen_load_fpr32h (TCGv_i32 t, int reg) +static void gen_load_fpr32h(TCGv_i32 t, int reg) { - tcg_gen_ld_i32(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].w[!FP_ENDIAN_IDX])); + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_shri_i64(t64, fpu_f64[reg], 32); + tcg_gen_trunc_i64_i32(t, t64); + tcg_temp_free_i64(t64); } -static inline void gen_store_fpr32h (TCGv_i32 t, int reg) +static void gen_store_fpr32h(TCGv_i32 t, int reg) { - tcg_gen_st_i32(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].w[!FP_ENDIAN_IDX])); + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t64, t); + tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 32, 32); + tcg_temp_free_i64(t64); } -static inline void gen_load_fpr64 (DisasContext *ctx, TCGv_i64 t, int reg) +static void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) { if (ctx->hflags & MIPS_HFLAG_F64) { - tcg_gen_ld_i64(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].d)); + tcg_gen_mov_i64(t, fpu_f64[reg]); } else { - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv_i32 t1 = tcg_temp_new_i32(); - gen_load_fpr32(t0, reg & ~1); - gen_load_fpr32(t1, reg | 1); - tcg_gen_concat_i32_i64(t, t0, t1); - tcg_temp_free_i32(t0); - tcg_temp_free_i32(t1); + tcg_gen_concat32_i64(t, fpu_f64[reg & ~1], fpu_f64[reg | 1]); } } -static inline void gen_store_fpr64 (DisasContext *ctx, TCGv_i64 t, int reg) +static void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) { if (ctx->hflags & MIPS_HFLAG_F64) { - tcg_gen_st_i64(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].d)); + tcg_gen_mov_i64(fpu_f64[reg], t); } else { - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i32 t1 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(t1, t); - gen_store_fpr32(t1, reg & ~1); + TCGv_i64 t0; + tcg_gen_deposit_i64(fpu_f64[reg & ~1], fpu_f64[reg & ~1], t, 0, 32); + t0 = tcg_temp_new_i64(); tcg_gen_shri_i64(t0, t, 32); - tcg_gen_trunc_i64_i32(t1, t0); - gen_store_fpr32(t1, reg | 1); - tcg_temp_free_i32(t1); + tcg_gen_deposit_i64(fpu_f64[reg | 1], fpu_f64[reg | 1], t0, 0, 32); tcg_temp_free_i64(t0); } } @@ -13073,6 +13079,12 @@ static void mips_tcg_init(void) cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUMIPSState, active_tc.gpr[i]), regnames[i]); + + for (i = 0; i < 32; i++) { + int off = offsetof(CPUMIPSState, active_fpu.fpr[i]); + fpu_f64[i] = tcg_global_mem_new_i64(TCG_AREG0, off, fregnames[i]); + } + cpu_PC = tcg_global_mem_new(TCG_AREG0, offsetof(CPUMIPSState, active_tc.PC), "PC"); for (i = 0; i < MIPS_DSP_ACC; i++) { diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3f114c9..286f42a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1045,10 +1045,9 @@ struct CPUPPCState { #endif #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) - hwaddr vpa; - hwaddr slb_shadow; - hwaddr dispatch_trace_log; - uint32_t dtl_size; + hwaddr vpa_addr; + hwaddr slb_shadow_addr, slb_shadow_size; + hwaddr dtl_addr, dtl_size; #endif /* TARGET_PPC64 */ int error_code; diff --git a/target-ppc/helper.h b/target-ppc/helper.h index fd04c06..e588370 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -31,24 +31,24 @@ DEF_HELPER_2(icbi, void, env, tl) DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) #if defined(TARGET_PPC64) -DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(mulhdu, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) +DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(mulhdu, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_3(mulldo, i64, env, i64, i64) #endif -DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) -DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) -DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_3(sraw, tl, env, tl, tl) #if defined(TARGET_PPC64) -DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) -DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_3(srad, tl, env, tl, tl) #endif -DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) -DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) -DEF_HELPER_FLAGS_2(brinc, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl) +DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_2(brinc, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_1(float_check_status, void, env) DEF_HELPER_1(reset_fpstatus, void, env) @@ -345,25 +345,25 @@ DEF_HELPER_2(6xx_tlbd, void, env, tl) DEF_HELPER_2(6xx_tlbi, void, env, tl) DEF_HELPER_2(74xx_tlbd, void, env, tl) DEF_HELPER_2(74xx_tlbi, void, env, tl) -DEF_HELPER_FLAGS_1(tlbia, TCG_CALL_CONST, void, env) -DEF_HELPER_FLAGS_2(tlbie, TCG_CALL_CONST, void, env, tl) +DEF_HELPER_FLAGS_1(tlbia, TCG_CALL_NO_RWG, void, env) +DEF_HELPER_FLAGS_2(tlbie, TCG_CALL_NO_RWG, void, env, tl) #if defined(TARGET_PPC64) -DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_CONST, void, env, tl, tl) +DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_NO_RWG, void, env, tl, tl) DEF_HELPER_2(load_slb_esid, tl, env, tl) DEF_HELPER_2(load_slb_vsid, tl, env, tl) -DEF_HELPER_FLAGS_1(slbia, TCG_CALL_CONST, void, env) -DEF_HELPER_FLAGS_2(slbie, TCG_CALL_CONST, void, env, tl) +DEF_HELPER_FLAGS_1(slbia, TCG_CALL_NO_RWG, void, env) +DEF_HELPER_FLAGS_2(slbie, TCG_CALL_NO_RWG, void, env, tl) #endif -DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_CONST, tl, env, tl); -DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_CONST, void, env, tl, tl) +DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl); +DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl) -DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_1(msgsnd, void, tl) DEF_HELPER_2(msgclr, void, env, tl) #endif DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32) -DEF_HELPER_FLAGS_2(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, env, i32) +DEF_HELPER_FLAGS_2(clcs, TCG_CALL_NO_RWG_SE, tl, env, i32) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(rac, tl, env, tl) #endif diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 4a9bb5b..811f47f 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -1509,10 +1509,8 @@ static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf, mask = ~(entry->size - 1); ea = entry->EPN & mask; pa = entry->RPN & mask; -#if (TARGET_PHYS_ADDR_SPACE_BITS >= 36) /* Extend the physical address to 36 bits */ pa |= (hwaddr)(entry->RPN & 0xF) << 32; -#endif size /= 1024; if (size >= 1024) { snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index a972287..e63627c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1498,7 +1498,7 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask) /* XXX : not implemented */ spr_register(env, SPR_BOOKE_DBCR0, "DBCR0", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_40x_dbcr0, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_BOOKE_DBCR1, "DBCR1", @@ -10425,9 +10425,10 @@ static void ppc_cpu_reset(CPUState *s) env->error_code = 0; #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) - env->vpa = 0; - env->slb_shadow = 0; - env->dispatch_trace_log = 0; + env->vpa_addr = 0; + env->slb_shadow_addr = 0; + env->slb_shadow_size = 0; + env->dtl_addr = 0; env->dtl_size = 0; #endif /* TARGET_PPC64 */ diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 5419f37..ac44eab 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -7,21 +7,21 @@ DEF_HELPER_4(xc, i32, env, i32, i64, i64) DEF_HELPER_4(mvc, void, env, i32, i64, i64) DEF_HELPER_4(clc, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) -DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) -DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) -DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) +DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_NO_RWG_SE, i32, s32) +DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_NO_RWG_SE, i32, s64) +DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) DEF_HELPER_4(stcm, void, env, i32, i32, i64) DEF_HELPER_3(mlg, void, env, i32, i64) DEF_HELPER_3(dlg, void, env, i32, i64) -DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) -DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) -DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) -DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) -DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) -DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) -DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_NO_RWG_SE, i32, s64, s64, s64) +DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) +DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_NO_RWG_SE, i32, s32, s32, s32) +DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_NO_RWG_SE, i32, s64, s64, s64) +DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) +DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_NO_RWG_SE, i32, s32, s32, s32) +DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) @@ -30,15 +30,15 @@ DEF_HELPER_4(csg, i32, env, i32, i64, i32) DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) DEF_HELPER_4(cs, i32, env, i32, i64, i32) DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) -DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) -DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_PURE|TCG_CALL_CONST, s32, s32) -DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_PURE|TCG_CALL_CONST, i64, s64) -DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_PURE|TCG_CALL_CONST, s64, s64) +DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) +DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) +DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) +DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) DEF_HELPER_4(stcmh, void, env, i32, i64, i32) DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) -DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) +DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) @@ -82,9 +82,9 @@ DEF_HELPER_3(seb, void, env, i32, i32) DEF_HELPER_3(sdb, i32, env, i32, i64) DEF_HELPER_3(mdb, void, env, i32, i64) DEF_HELPER_3(ddb, void, env, i32, i64) -DEF_HELPER_FLAGS_3(cebr, TCG_CALL_PURE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_PURE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(cebr, TCG_CALL_NO_SE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_NO_SE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_NO_SE, i32, env, i32, i32) DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) @@ -104,12 +104,12 @@ DEF_HELPER_4(madbr, void, env, i32, i32, i32) DEF_HELPER_4(msdbr, void, env, i32, i32, i32) DEF_HELPER_3(ldeb, void, env, i32, i64) DEF_HELPER_3(lxdb, void, env, i32, i64) -DEF_HELPER_FLAGS_3(tceb, TCG_CALL_PURE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_PURE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_SE, i32, env, i32, i64) DEF_HELPER_3(flogr, i32, env, i32, i64) DEF_HELPER_3(sqdbr, void, env, i32, i32) -DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) +DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) @@ -117,36 +117,36 @@ DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_1(program_interrupt, void, i32) -DEF_HELPER_FLAGS_2(stidp, TCG_CALL_CONST, void, env, i64) -DEF_HELPER_FLAGS_2(spx, TCG_CALL_CONST, void, env, i64) -DEF_HELPER_FLAGS_1(sck, TCG_CALL_CONST, i32, i64) +DEF_HELPER_FLAGS_2(stidp, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(sck, TCG_CALL_NO_RWG, i32, i64) DEF_HELPER_2(stck, i32, env, i64) DEF_HELPER_2(stcke, i32, env, i64) -DEF_HELPER_FLAGS_2(sckc, TCG_CALL_CONST, void, env, i64) -DEF_HELPER_FLAGS_2(stckc, TCG_CALL_CONST, void, env, i64) -DEF_HELPER_FLAGS_2(spt, TCG_CALL_CONST, void, env, i64) -DEF_HELPER_FLAGS_2(stpt, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(stckc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(stpt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_4(stsi, i32, env, i64, i32, i32) DEF_HELPER_4(lctl, void, env, i32, i64, i32) DEF_HELPER_4(lctlg, void, env, i32, i64, i32) DEF_HELPER_4(stctl, void, env, i32, i64, i32) DEF_HELPER_4(stctg, void, env, i32, i64, i32) -DEF_HELPER_FLAGS_2(tprot, TCG_CALL_CONST, i32, i64, i64) -DEF_HELPER_FLAGS_2(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, env, i64) -DEF_HELPER_FLAGS_3(sske, TCG_CALL_CONST, void, env, i32, i64) -DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_CONST, i32, env, i32, i64) +DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) +DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) +DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i32, i64) +DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_NO_RWG, i32, env, i32, i64) DEF_HELPER_3(csp, i32, env, i32, i32) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) DEF_HELPER_2(sacf, void, env, i64) -DEF_HELPER_FLAGS_3(ipte, TCG_CALL_CONST, void, env, i64, i64) -DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_CONST, void, env) +DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) +DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_3(lra, i32, env, i64, i32) DEF_HELPER_3(stura, void, env, i64, i32) DEF_HELPER_3(cksm, void, env, i32, i32) -DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, +DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) #include "def-helper.h" diff --git a/target-sh4/helper.h b/target-sh4/helper.h index 6c1a47d..304b77b 100644 --- a/target-sh4/helper.h +++ b/target-sh4/helper.h @@ -19,8 +19,8 @@ DEF_HELPER_3(macw, void, env, i32, i32) DEF_HELPER_2(ld_fpscr, void, env, i32) -DEF_HELPER_FLAGS_1(fabs_FT, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32) -DEF_HELPER_FLAGS_1(fabs_DT, TCG_CALL_CONST | TCG_CALL_PURE, f64, f64) +DEF_HELPER_FLAGS_1(fabs_FT, TCG_CALL_NO_RWG_SE, f32, f32) +DEF_HELPER_FLAGS_1(fabs_DT, TCG_CALL_NO_RWG_SE, f64, f64) DEF_HELPER_3(fadd_FT, f32, env, f32, f32) DEF_HELPER_3(fadd_DT, f64, env, f64, f64) DEF_HELPER_2(fcnvsd_FT_DT, f64, env, f32) @@ -37,7 +37,7 @@ DEF_HELPER_2(float_DT, f64, env, i32) DEF_HELPER_4(fmac_FT, f32, env, f32, f32, f32) DEF_HELPER_3(fmul_FT, f32, env, f32, f32) DEF_HELPER_3(fmul_DT, f64, env, f64, f64) -DEF_HELPER_FLAGS_1(fneg_T, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32) +DEF_HELPER_FLAGS_1(fneg_T, TCG_CALL_NO_RWG_SE, f32, f32) DEF_HELPER_3(fsub_FT, f32, env, f32, f32) DEF_HELPER_3(fsub_DT, f64, env, f64, f64) DEF_HELPER_2(fsqrt_FT, f32, env, f32) diff --git a/target-sparc/helper.h b/target-sparc/helper.h index e1ae3c7..098c482 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -16,7 +16,7 @@ DEF_HELPER_1(rdccr, tl, env) DEF_HELPER_2(wrccr, void, env, tl) DEF_HELPER_1(rdcwp, tl, env) DEF_HELPER_2(wrcwp, void, env, tl) -DEF_HELPER_FLAGS_2(array8, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl) +DEF_HELPER_FLAGS_2(array8, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_1(popc, tl, tl) DEF_HELPER_4(ldda_asi, void, env, tl, int, int) DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int) @@ -51,7 +51,7 @@ DEF_HELPER_5(ld_asi, i64, env, tl, int, int, int) DEF_HELPER_5(st_asi, void, env, tl, i64, int, int) #endif DEF_HELPER_2(ldfsr, void, env, i32) -DEF_HELPER_FLAGS_1(fabss, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32) +DEF_HELPER_FLAGS_1(fabss, TCG_CALL_NO_RWG_SE, f32, f32) DEF_HELPER_2(fsqrts, f32, env, f32) DEF_HELPER_2(fsqrtd, f64, env, f64) DEF_HELPER_3(fcmps, void, env, f32, f32) @@ -63,7 +63,7 @@ DEF_HELPER_1(fcmpq, void, env) DEF_HELPER_1(fcmpeq, void, env) #ifdef TARGET_SPARC64 DEF_HELPER_2(ldxfsr, void, env, i64) -DEF_HELPER_FLAGS_1(fabsd, TCG_CALL_CONST | TCG_CALL_PURE, f64, f64) +DEF_HELPER_FLAGS_1(fabsd, TCG_CALL_NO_RWG_SE, f64, f64) DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32) DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32) DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32) @@ -104,14 +104,14 @@ DEF_HELPER_3(fdivs, f32, env, f32, f32) DEF_HELPER_3(fsmuld, f64, env, f32, f32) DEF_HELPER_3(fdmulq, void, env, f64, f64); -DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32) +DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_NO_RWG_SE, f32, f32) DEF_HELPER_2(fitod, f64, env, s32) DEF_HELPER_2(fitoq, void, env, s32) DEF_HELPER_2(fitos, f32, env, s32) #ifdef TARGET_SPARC64 -DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_CONST | TCG_CALL_PURE, f64, f64) +DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_NO_RWG_SE, f64, f64) DEF_HELPER_1(fnegq, void, env) DEF_HELPER_2(fxtos, f32, env, s64) DEF_HELPER_2(fxtod, f64, env, s64) @@ -131,36 +131,36 @@ DEF_HELPER_2(fstox, s64, env, f32) DEF_HELPER_2(fdtox, s64, env, f64) DEF_HELPER_1(fqtox, s64, env) -DEF_HELPER_FLAGS_2(fpmerge, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(fmul8x16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(fmul8x16al, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(fmul8x16au, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(fmul8sux16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(fmul8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_FLAGS_3(pdist, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64) -DEF_HELPER_FLAGS_2(fpack16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64, i64) -DEF_HELPER_FLAGS_3(fpack32, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64) -DEF_HELPER_FLAGS_2(fpackfix, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64, i64) -DEF_HELPER_FLAGS_3(bshuffle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64, i64) +DEF_HELPER_FLAGS_2(fpmerge, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(fmul8x16, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(fmul8x16al, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(fmul8x16au, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(fmul8sux16, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(fmul8ulx16, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_3(pdist, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) +DEF_HELPER_FLAGS_2(fpack16, TCG_CALL_NO_RWG_SE, i32, i64, i64) +DEF_HELPER_FLAGS_3(fpack32, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) +DEF_HELPER_FLAGS_2(fpackfix, TCG_CALL_NO_RWG_SE, i32, i64, i64) +DEF_HELPER_FLAGS_3(bshuffle, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) #define VIS_HELPER(name) \ - DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_CONST | TCG_CALL_PURE, \ + DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_NO_RWG_SE, \ i64, i64, i64) \ - DEF_HELPER_FLAGS_2(f ## name ## 16s, TCG_CALL_CONST | TCG_CALL_PURE, \ + DEF_HELPER_FLAGS_2(f ## name ## 16s, TCG_CALL_NO_RWG_SE, \ i32, i32, i32) \ - DEF_HELPER_FLAGS_2(f ## name ## 32, TCG_CALL_CONST | TCG_CALL_PURE, \ + DEF_HELPER_FLAGS_2(f ## name ## 32, TCG_CALL_NO_RWG_SE, \ i64, i64, i64) \ - DEF_HELPER_FLAGS_2(f ## name ## 32s, TCG_CALL_CONST | TCG_CALL_PURE, \ + DEF_HELPER_FLAGS_2(f ## name ## 32s, TCG_CALL_NO_RWG_SE, \ i32, i32, i32) VIS_HELPER(padd); VIS_HELPER(psub); #define VIS_CMPHELPER(name) \ - DEF_HELPER_FLAGS_2(f##name##16, TCG_CALL_CONST | TCG_CALL_PURE, \ + DEF_HELPER_FLAGS_2(f##name##16, TCG_CALL_NO_RWG_SE, \ i64, i64, i64) \ - DEF_HELPER_FLAGS_2(f##name##32, TCG_CALL_CONST | TCG_CALL_PURE, \ + DEF_HELPER_FLAGS_2(f##name##32, TCG_CALL_NO_RWG_SE, \ i64, i64, i64) VIS_CMPHELPER(cmpgt); VIS_CMPHELPER(cmpeq); diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h index 4cc0088..1163c09 100644 --- a/target-xtensa/helper.h +++ b/target-xtensa/helper.h @@ -5,8 +5,8 @@ DEF_HELPER_3(exception_cause, noreturn, env, i32, i32) DEF_HELPER_4(exception_cause_vaddr, noreturn, env, i32, i32, i32) DEF_HELPER_3(debug_exception, noreturn, env, i32, i32) -DEF_HELPER_FLAGS_1(nsa, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) -DEF_HELPER_FLAGS_1(nsau, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(nsa, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(nsau, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_2(wsr_windowbase, void, env, i32) DEF_HELPER_4(entry, void, env, i32, i32, i32) DEF_HELPER_2(retw, i32, env, i32) @@ -25,8 +25,8 @@ DEF_HELPER_2(advance_ccount, void, env, i32) DEF_HELPER_1(check_interrupts, void, env) DEF_HELPER_2(wsr_rasid, void, env, i32) -DEF_HELPER_FLAGS_3(rtlb0, TCG_CALL_CONST | TCG_CALL_PURE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(rtlb1, TCG_CALL_CONST | TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(rtlb0, TCG_CALL_NO_RWG_SE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(rtlb1, TCG_CALL_NO_RWG_SE, i32, env, i32, i32) DEF_HELPER_3(itlb, void, env, i32, i32) DEF_HELPER_3(ptlb, i32, env, i32, i32) DEF_HELPER_4(wtlb, void, env, i32, i32, i32) @@ -37,15 +37,15 @@ DEF_HELPER_3(wsr_dbreaka, void, env, i32, i32) DEF_HELPER_3(wsr_dbreakc, void, env, i32, i32) DEF_HELPER_2(wur_fcr, void, env, i32) -DEF_HELPER_FLAGS_1(abs_s, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32) -DEF_HELPER_FLAGS_1(neg_s, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32) +DEF_HELPER_FLAGS_1(abs_s, TCG_CALL_NO_RWG_SE, f32, f32) +DEF_HELPER_FLAGS_1(neg_s, TCG_CALL_NO_RWG_SE, f32, f32) DEF_HELPER_3(add_s, f32, env, f32, f32) DEF_HELPER_3(sub_s, f32, env, f32, f32) DEF_HELPER_3(mul_s, f32, env, f32, f32) DEF_HELPER_4(madd_s, f32, env, f32, f32, f32) DEF_HELPER_4(msub_s, f32, env, f32, f32, f32) -DEF_HELPER_FLAGS_3(ftoi, TCG_CALL_CONST | TCG_CALL_PURE, i32, f32, i32, i32) -DEF_HELPER_FLAGS_3(ftoui, TCG_CALL_CONST | TCG_CALL_PURE, i32, f32, i32, i32) +DEF_HELPER_FLAGS_3(ftoi, TCG_CALL_NO_RWG_SE, i32, f32, i32, i32) +DEF_HELPER_FLAGS_3(ftoui, TCG_CALL_NO_RWG_SE, i32, f32, i32, i32) DEF_HELPER_3(itof, f32, env, i32, i32) DEF_HELPER_3(uitof, f32, env, i32, i32) @@ -77,11 +77,20 @@ destroyed, but local temporaries and globals are preserved. Using the tcg_gen_helper_x_y it is possible to call any function taking i32, i64 or pointer types. By default, before calling a helper, all globals are stored at their canonical location and it is assumed -that the function can modify them. This can be overridden by the -TCG_CALL_CONST function modifier. By default, the helper is allowed to -modify the CPU state or raise an exception. This can be overridden by -the TCG_CALL_PURE function modifier, in which case the call to the -function is removed if the return value is not used. +that the function can modify them. By default, the helper is allowed to +modify the CPU state or raise an exception. + +This can be overridden using the following function modifiers: +- TCG_CALL_NO_READ_GLOBALS means that the helper does not read globals, + either directly or via an exception. They will not be saved to their + canonical locations before calling the helper. +- TCG_CALL_NO_WRITE_GLOBALS means that the helper does not modify any globals. + They will only be saved to their canonical location before calling helpers, + but they won't be reloaded afterwise. +- TCG_CALL_NO_SIDE_EFFECTS means that the call to the function is removed if + the return value is not used. + +Note that TCG_CALL_NO_READ_GLOBALS implies TCG_CALL_NO_WRITE_GLOBALS. On some TCG targets (e.g. x86), several calling conventions are supported. @@ -349,6 +358,9 @@ st32_i64 t0, t1, offset write(t0, t1 + offset) Write 8, 16, 32 or 64 bits to host memory. +All this opcodes assume that the pointed host memory doesn't correspond +to a global. In the latter case the behaviour is unpredictable. + ********* 64-bit target on 32-bit host support The following opcodes are internal to TCG. Thus they are to be implemented by diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 4952c05..e45a5a0 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -92,7 +92,6 @@ static const int tcg_target_call_oarg_regs[] = { #if TCG_TARGET_REG_BITS == 64 # define TCG_REG_L0 tcg_target_call_iarg_regs[0] # define TCG_REG_L1 tcg_target_call_iarg_regs[1] -# define TCG_REG_L2 tcg_target_call_iarg_regs[2] #else # define TCG_REG_L0 TCG_REG_EAX # define TCG_REG_L1 TCG_REG_EDX @@ -181,14 +180,11 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) ct->ct |= TCG_CT_REG; #if TCG_TARGET_REG_BITS == 64 tcg_regset_set32(ct->u.regs, 0, 0xffff); - tcg_regset_reset_reg(ct->u.regs, TCG_REG_L0); - tcg_regset_reset_reg(ct->u.regs, TCG_REG_L1); - tcg_regset_reset_reg(ct->u.regs, TCG_REG_L2); #else tcg_regset_set32(ct->u.regs, 0, 0xff); - tcg_regset_reset_reg(ct->u.regs, TCG_REG_L0); - tcg_regset_reset_reg(ct->u.regs, TCG_REG_L1); #endif + tcg_regset_reset_reg(ct->u.regs, TCG_REG_L0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_L1); break; case 'e': @@ -236,11 +232,13 @@ static inline int tcg_target_const_match(tcg_target_long val, # define P_REXW 0x800 /* Set REX.W = 1 */ # define P_REXB_R 0x1000 /* REG field as byte register */ # define P_REXB_RM 0x2000 /* R/M field as byte register */ +# define P_GS 0x4000 /* gs segment override */ #else # define P_ADDR32 0 # define P_REXW 0 # define P_REXB_R 0 # define P_REXB_RM 0 +# define P_GS 0 #endif #define OPC_ARITH_EvIz (0x81) @@ -356,6 +354,9 @@ static void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x) { int rex; + if (opc & P_GS) { + tcg_out8(s, 0x65); + } if (opc & P_DATA16) { /* We should never be asking for both 16 and 64-bit operation. */ assert((opc & P_REXW) == 0); @@ -1016,12 +1017,12 @@ static const void *qemu_st_helpers[4] = { LABEL_PTRS is filled with 1 (32-bit addresses) or 2 (64-bit addresses) positions of the displacements of forward jumps to the TLB miss case. - First argument register is loaded with the low part of the address. + Second argument register is loaded with the low part of the address. In the TLB hit case, it has been adjusted as indicated by the TLB and so is a host address. In the TLB miss case, it continues to hold a guest address. - Second argument register is clobbered. */ + First argument register is clobbered. */ static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx, int mem_index, int s_bits, @@ -1039,25 +1040,25 @@ static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx, rexw = P_REXW; } - tcg_out_mov(s, type, r1, addrlo); tcg_out_mov(s, type, r0, addrlo); + tcg_out_mov(s, type, r1, addrlo); - tcg_out_shifti(s, SHIFT_SHR + rexw, r1, + tcg_out_shifti(s, SHIFT_SHR + rexw, r0, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); - tgen_arithi(s, ARITH_AND + rexw, r0, - TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0); tgen_arithi(s, ARITH_AND + rexw, r1, + TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0); + tgen_arithi(s, ARITH_AND + rexw, r0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, 0); - tcg_out_modrm_sib_offset(s, OPC_LEA + P_REXW, r1, TCG_AREG0, r1, 0, + tcg_out_modrm_sib_offset(s, OPC_LEA + P_REXW, r0, TCG_AREG0, r0, 0, offsetof(CPUArchState, tlb_table[mem_index][0]) + which); - /* cmp 0(r1), r0 */ - tcg_out_modrm_offset(s, OPC_CMP_GvEv + rexw, r0, r1, 0); + /* cmp 0(r0), r1 */ + tcg_out_modrm_offset(s, OPC_CMP_GvEv + rexw, r1, r0, 0); - tcg_out_mov(s, type, r0, addrlo); + tcg_out_mov(s, type, r1, addrlo); /* jne label1 */ tcg_out8(s, OPC_JCC_short + JCC_JNE); @@ -1065,8 +1066,8 @@ static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx, s->code_ptr++; if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) { - /* cmp 4(r1), addrhi */ - tcg_out_modrm_offset(s, OPC_CMP_GvEv, args[addrlo_idx+1], r1, 4); + /* cmp 4(r0), addrhi */ + tcg_out_modrm_offset(s, OPC_CMP_GvEv, args[addrlo_idx+1], r0, 4); /* jne label1 */ tcg_out8(s, OPC_JCC_short + JCC_JNE); @@ -1076,14 +1077,31 @@ static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx, /* TLB Hit. */ - /* add addend(r1), r0 */ - tcg_out_modrm_offset(s, OPC_ADD_GvEv + P_REXW, r0, r1, + /* add addend(r0), r1 */ + tcg_out_modrm_offset(s, OPC_ADD_GvEv + P_REXW, r1, r0, offsetof(CPUTLBEntry, addend) - which); } -#endif +#elif defined(__x86_64__) && defined(__linux__) +# include <asm/prctl.h> +# include <sys/prctl.h> + +int arch_prctl(int code, unsigned long addr); + +static int guest_base_flags; +static inline void setup_guest_base_seg(void) +{ + if (arch_prctl(ARCH_SET_GS, GUEST_BASE) == 0) { + guest_base_flags = P_GS; + } +} +#else +# define guest_base_flags 0 +static inline void setup_guest_base_seg(void) { } +#endif /* SOFTMMU */ static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi, - int base, tcg_target_long ofs, int sizeop) + int base, tcg_target_long ofs, int seg, + int sizeop) { #ifdef TARGET_WORDS_BIGENDIAN const int bswap = 1; @@ -1092,28 +1110,29 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi, #endif switch (sizeop) { case 0: - tcg_out_modrm_offset(s, OPC_MOVZBL, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVZBL + seg, datalo, base, ofs); break; case 0 | 4: - tcg_out_modrm_offset(s, OPC_MOVSBL + P_REXW, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVSBL + P_REXW + seg, datalo, base, ofs); break; case 1: - tcg_out_modrm_offset(s, OPC_MOVZWL, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVZWL + seg, datalo, base, ofs); if (bswap) { tcg_out_rolw_8(s, datalo); } break; case 1 | 4: if (bswap) { - tcg_out_modrm_offset(s, OPC_MOVZWL, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVZWL + seg, datalo, base, ofs); tcg_out_rolw_8(s, datalo); tcg_out_modrm(s, OPC_MOVSWL + P_REXW, datalo, datalo); } else { - tcg_out_modrm_offset(s, OPC_MOVSWL + P_REXW, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVSWL + P_REXW + seg, + datalo, base, ofs); } break; case 2: - tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_GvEv + seg, datalo, base, ofs); if (bswap) { tcg_out_bswap32(s, datalo); } @@ -1121,17 +1140,18 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi, #if TCG_TARGET_REG_BITS == 64 case 2 | 4: if (bswap) { - tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_GvEv + seg, datalo, base, ofs); tcg_out_bswap32(s, datalo); tcg_out_ext32s(s, datalo, datalo); } else { - tcg_out_modrm_offset(s, OPC_MOVSLQ, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVSLQ + seg, datalo, base, ofs); } break; #endif case 3: if (TCG_TARGET_REG_BITS == 64) { - tcg_out_ld(s, TCG_TYPE_I64, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_GvEv + P_REXW + seg, + datalo, base, ofs); if (bswap) { tcg_out_bswap64(s, datalo); } @@ -1142,11 +1162,15 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi, datahi = t; } if (base != datalo) { - tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs); - tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4); + tcg_out_modrm_offset(s, OPC_MOVL_GvEv + seg, + datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_GvEv + seg, + datahi, base, ofs + 4); } else { - tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4); - tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_GvEv + seg, + datahi, base, ofs + 4); + tcg_out_modrm_offset(s, OPC_MOVL_GvEv + seg, + datalo, base, ofs); } if (bswap) { tcg_out_bswap32(s, datalo); @@ -1169,9 +1193,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int addrlo_idx; #if defined(CONFIG_SOFTMMU) int mem_index, s_bits; -#if TCG_TARGET_REG_BITS == 64 - int arg_idx; -#else +#if TCG_TARGET_REG_BITS == 32 int stack_adjust; #endif uint8_t *label_ptr[3]; @@ -1192,7 +1214,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, label_ptr, offsetof(CPUTLBEntry, addr_read)); /* TLB Hit. */ - tcg_out_qemu_ld_direct(s, data_reg, data_reg2, TCG_REG_L0, 0, opc); + tcg_out_qemu_ld_direct(s, data_reg, data_reg2, TCG_REG_L1, 0, 0, opc); /* jmp label2 */ tcg_out8(s, OPC_JMP_short); @@ -1220,15 +1242,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, tcg_out_push(s, TCG_AREG0); stack_adjust += 4; #else - /* The first argument is already loaded with addrlo. */ - arg_idx = 1; - tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx], - mem_index); - /* XXX/FIXME: suboptimal */ - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], TCG_REG_L2); - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], TCG_REG_L1); - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], TCG_REG_L0); tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); + /* The second argument is already loaded with addrlo. */ + tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], mem_index); #endif tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]); @@ -1285,29 +1301,31 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, { int32_t offset = GUEST_BASE; int base = args[addrlo_idx]; - - if (TCG_TARGET_REG_BITS == 64) { - /* ??? We assume all operations have left us with register - contents that are zero extended. So far this appears to - be true. If we want to enforce this, we can either do - an explicit zero-extension here, or (if GUEST_BASE == 0) - use the ADDR32 prefix. For now, do nothing. */ - - if (offset != GUEST_BASE) { - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L0, GUEST_BASE); - tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L0, base); - base = TCG_REG_L0; - offset = 0; - } + int seg = 0; + + /* ??? We assume all operations have left us with register contents + that are zero extended. So far this appears to be true. If we + want to enforce this, we can either do an explicit zero-extension + here, or (if GUEST_BASE == 0, or a segment register is in use) + use the ADDR32 prefix. For now, do nothing. */ + if (GUEST_BASE && guest_base_flags) { + seg = guest_base_flags; + offset = 0; + } else if (TCG_TARGET_REG_BITS == 64 && offset != GUEST_BASE) { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE); + tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base); + base = TCG_REG_L1; + offset = 0; } - tcg_out_qemu_ld_direct(s, data_reg, data_reg2, base, offset, opc); + tcg_out_qemu_ld_direct(s, data_reg, data_reg2, base, offset, seg, opc); } #endif } static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi, - int base, tcg_target_long ofs, int sizeop) + int base, tcg_target_long ofs, int seg, + int sizeop) { #ifdef TARGET_WORDS_BIGENDIAN const int bswap = 1; @@ -1317,12 +1335,13 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi, /* ??? Ideally we wouldn't need a scratch register. For user-only, we could perform the bswap twice to restore the original value instead of moving to the scratch. But as it is, the L constraint - means that TCG_REG_L1 is definitely free here. */ - const int scratch = TCG_REG_L1; + means that TCG_REG_L0 is definitely free here. */ + const int scratch = TCG_REG_L0; switch (sizeop) { case 0: - tcg_out_modrm_offset(s, OPC_MOVB_EvGv + P_REXB_R, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVB_EvGv + P_REXB_R + seg, + datalo, base, ofs); break; case 1: if (bswap) { @@ -1330,7 +1349,8 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi, tcg_out_rolw_8(s, scratch); datalo = scratch; } - tcg_out_modrm_offset(s, OPC_MOVL_EvGv + P_DATA16, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_EvGv + P_DATA16 + seg, + datalo, base, ofs); break; case 2: if (bswap) { @@ -1338,7 +1358,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi, tcg_out_bswap32(s, scratch); datalo = scratch; } - tcg_out_st(s, TCG_TYPE_I32, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_EvGv + seg, datalo, base, ofs); break; case 3: if (TCG_TARGET_REG_BITS == 64) { @@ -1347,17 +1367,18 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi, tcg_out_bswap64(s, scratch); datalo = scratch; } - tcg_out_st(s, TCG_TYPE_I64, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_EvGv + P_REXW + seg, + datalo, base, ofs); } else if (bswap) { tcg_out_mov(s, TCG_TYPE_I32, scratch, datahi); tcg_out_bswap32(s, scratch); - tcg_out_st(s, TCG_TYPE_I32, scratch, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_EvGv + seg, scratch, base, ofs); tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo); tcg_out_bswap32(s, scratch); - tcg_out_st(s, TCG_TYPE_I32, scratch, base, ofs + 4); + tcg_out_modrm_offset(s, OPC_MOVL_EvGv + seg, scratch, base, ofs+4); } else { - tcg_out_st(s, TCG_TYPE_I32, datalo, base, ofs); - tcg_out_st(s, TCG_TYPE_I32, datahi, base, ofs + 4); + tcg_out_modrm_offset(s, OPC_MOVL_EvGv + seg, datalo, base, ofs); + tcg_out_modrm_offset(s, OPC_MOVL_EvGv + seg, datahi, base, ofs+4); } break; default: @@ -1391,7 +1412,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, label_ptr, offsetof(CPUTLBEntry, addr_write)); /* TLB Hit. */ - tcg_out_qemu_st_direct(s, data_reg, data_reg2, TCG_REG_L0, 0, opc); + tcg_out_qemu_st_direct(s, data_reg, data_reg2, TCG_REG_L1, 0, 0, opc); /* jmp label2 */ tcg_out8(s, OPC_JMP_short); @@ -1425,15 +1446,12 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, tcg_out_push(s, TCG_AREG0); stack_adjust += 4; #else + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); + /* The second argument is already loaded with addrlo. */ tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32), - TCG_REG_L1, data_reg); - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_L2, mem_index); + tcg_target_call_iarg_regs[2], data_reg); + tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], mem_index); stack_adjust = 0; - /* XXX/FIXME: suboptimal */ - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], TCG_REG_L2); - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], TCG_REG_L1); - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], TCG_REG_L0); - tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); #endif tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]); @@ -1451,23 +1469,24 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, { int32_t offset = GUEST_BASE; int base = args[addrlo_idx]; - - if (TCG_TARGET_REG_BITS == 64) { - /* ??? We assume all operations have left us with register - contents that are zero extended. So far this appears to - be true. If we want to enforce this, we can either do - an explicit zero-extension here, or (if GUEST_BASE == 0) - use the ADDR32 prefix. For now, do nothing. */ - - if (offset != GUEST_BASE) { - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L0, GUEST_BASE); - tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L0, base); - base = TCG_REG_L0; - offset = 0; - } + int seg = 0; + + /* ??? We assume all operations have left us with register contents + that are zero extended. So far this appears to be true. If we + want to enforce this, we can either do an explicit zero-extension + here, or (if GUEST_BASE == 0, or a segment register is in use) + use the ADDR32 prefix. For now, do nothing. */ + if (GUEST_BASE && guest_base_flags) { + seg = guest_base_flags; + offset = 0; + } else if (TCG_TARGET_REG_BITS == 64 && offset != GUEST_BASE) { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE); + tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base); + base = TCG_REG_L1; + offset = 0; } - tcg_out_qemu_st_direct(s, data_reg, data_reg2, base, offset, opc); + tcg_out_qemu_st_direct(s, data_reg, data_reg2, base, offset, seg, opc); } #endif } @@ -2061,6 +2080,13 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out_pop(s, tcg_target_callee_save_regs[i]); } tcg_out_opc(s, OPC_RET, 0, 0, 0); + +#if !defined(CONFIG_SOFTMMU) + /* Try to set up a segment register to point to GUEST_BASE. */ + if (GUEST_BASE) { + setup_guest_base_seg(); + } +#endif } static void tcg_target_init(TCGContext *s) diff --git a/tcg/optimize.c b/tcg/optimize.c index a06c8eb..8e5d918 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -915,7 +915,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, 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))) { + if (!(args[nb_call_args + 1] & (TCG_CALL_NO_READ_GLOBALS | + TCG_CALL_NO_WRITE_GLOBALS))) { for (i = 0; i < nb_globals; i++) { reset_temp(i); } diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 8100a5a..8d1da2b 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -401,10 +401,10 @@ static inline void tcg_gen_helperN(void *func, int flags, int sizemask, } /* Note: Both tcg_gen_helper32() and tcg_gen_helper64() are currently - reserved for helpers in tcg-runtime.c. These helpers are all const - and pure, hence the call to tcg_gen_callN() with TCG_CALL_CONST | - TCG_CALL_PURE. This may need to be adjusted if these functions - start to be used with other helpers. */ + reserved for helpers in tcg-runtime.c. These helpers all do not read + globals and do not have side effects, hence the call to tcg_gen_callN() + with TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_SIDE_EFFECTS. This may need + to be adjusted if these functions start to be used with other helpers. */ static inline void tcg_gen_helper32(void *func, int sizemask, TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) { @@ -413,8 +413,9 @@ static inline void tcg_gen_helper32(void *func, int sizemask, TCGv_i32 ret, fn = tcg_const_ptr(func); args[0] = GET_TCGV_I32(a); args[1] = GET_TCGV_I32(b); - tcg_gen_callN(&tcg_ctx, fn, TCG_CALL_CONST | TCG_CALL_PURE, sizemask, - GET_TCGV_I32(ret), 2, args); + tcg_gen_callN(&tcg_ctx, fn, + TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_SIDE_EFFECTS, + sizemask, GET_TCGV_I32(ret), 2, args); tcg_temp_free_ptr(fn); } @@ -426,8 +427,9 @@ static inline void tcg_gen_helper64(void *func, int sizemask, TCGv_i64 ret, fn = tcg_const_ptr(func); args[0] = GET_TCGV_I64(a); args[1] = GET_TCGV_I64(b); - tcg_gen_callN(&tcg_ctx, fn, TCG_CALL_CONST | TCG_CALL_PURE, sizemask, - GET_TCGV_I64(ret), 2, args); + tcg_gen_callN(&tcg_ctx, fn, + TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_SIDE_EFFECTS, + sizemask, GET_TCGV_I64(ret), 2, args); tcg_temp_free_ptr(fn); } diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index 04cb7ca..9651063 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -37,8 +37,8 @@ DEF(nopn, 0, 0, 1, 0) /* variable number of parameters */ DEF(discard, 1, 0, 0, 0) DEF(set_label, 0, 0, 1, TCG_OPF_BB_END) -DEF(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ -DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF(call, 0, 1, 2, TCG_OPF_CALL_CLOBBER) /* variable number of parameters */ +DEF(br, 0, 0, 1, TCG_OPF_BB_END) #define IMPL(X) (X ? 0 : TCG_OPF_NOT_PRESENT) #if TCG_TARGET_REG_BITS == 32 @@ -57,9 +57,9 @@ DEF(ld8s_i32, 1, 1, 1, 0) DEF(ld16u_i32, 1, 1, 1, 0) DEF(ld16s_i32, 1, 1, 1, 0) DEF(ld_i32, 1, 1, 1, 0) -DEF(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) -DEF(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) -DEF(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS) +DEF(st8_i32, 0, 2, 1, 0) +DEF(st16_i32, 0, 2, 1, 0) +DEF(st_i32, 0, 2, 1, 0) /* arith */ DEF(add_i32, 1, 2, 0, 0) DEF(sub_i32, 1, 2, 0, 0) @@ -81,12 +81,11 @@ DEF(rotl_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rot_i32)) DEF(rotr_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rot_i32)) DEF(deposit_i32, 1, 2, 2, IMPL(TCG_TARGET_HAS_deposit_i32)) -DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END) DEF(add2_i32, 2, 4, 0, IMPL(TCG_TARGET_REG_BITS == 32)) DEF(sub2_i32, 2, 4, 0, IMPL(TCG_TARGET_REG_BITS == 32)) -DEF(brcond2_i32, 0, 4, 2, - TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS | IMPL(TCG_TARGET_REG_BITS == 32)) +DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | IMPL(TCG_TARGET_REG_BITS == 32)) DEF(mulu2_i32, 2, 2, 0, IMPL(TCG_TARGET_REG_BITS == 32)) DEF(setcond2_i32, 1, 4, 1, IMPL(TCG_TARGET_REG_BITS == 32)) @@ -116,10 +115,10 @@ DEF(ld16s_i64, 1, 1, 1, IMPL64) DEF(ld32u_i64, 1, 1, 1, IMPL64) DEF(ld32s_i64, 1, 1, 1, IMPL64) DEF(ld_i64, 1, 1, 1, IMPL64) -DEF(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS | IMPL64) -DEF(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS | IMPL64) -DEF(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS | IMPL64) -DEF(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS | IMPL64) +DEF(st8_i64, 0, 2, 1, IMPL64) +DEF(st16_i64, 0, 2, 1, IMPL64) +DEF(st32_i64, 0, 2, 1, IMPL64) +DEF(st_i64, 0, 2, 1, IMPL64) /* arith */ DEF(add_i64, 1, 2, 0, IMPL64) DEF(sub_i64, 1, 2, 0, IMPL64) @@ -141,7 +140,7 @@ DEF(rotl_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64)) DEF(rotr_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64)) DEF(deposit_i64, 1, 2, 2, IMPL64 | IMPL(TCG_TARGET_HAS_deposit_i64)) -DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS | IMPL64) +DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | IMPL64) DEF(ext8s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext8s_i64)) DEF(ext16s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext16s_i64)) DEF(ext32s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext32s_i64)) @@ -165,8 +164,8 @@ DEF(debug_insn_start, 0, 0, 2, 0) #else DEF(debug_insn_start, 0, 0, 1, 0) #endif -DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) -DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_END) +DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_END) /* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op constants must be defined */ #if TCG_TARGET_REG_BITS == 32 @@ -776,7 +776,11 @@ static void tcg_reg_alloc_start(TCGContext *s) } for(i = s->nb_globals; i < s->nb_temps; i++) { ts = &s->temps[i]; - ts->val_type = TEMP_VAL_DEAD; + if (ts->temp_local) { + ts->val_type = TEMP_VAL_MEM; + } else { + ts->val_type = TEMP_VAL_DEAD; + } ts->mem_allocated = 0; ts->fixed_reg = 0; } @@ -1180,31 +1184,27 @@ static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, } } -/* liveness analysis: end of function: globals are live, temps are - dead. */ -/* XXX: at this stage, not used as there would be little gains because - most TBs end with a conditional jump. */ -static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps) +/* liveness analysis: end of function: all temps are dead, and globals + should be in memory. */ +static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps, + uint8_t *mem_temps) { - memset(dead_temps, 0, s->nb_globals); - memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals); + memset(dead_temps, 1, s->nb_temps); + memset(mem_temps, 1, s->nb_globals); + memset(mem_temps + s->nb_globals, 0, s->nb_temps - s->nb_globals); } -/* liveness analysis: end of basic block: globals are live, temps are - dead, local temps are live. */ -static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps) +/* liveness analysis: end of basic block: all temps are dead, globals + and local temps should be in memory. */ +static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps, + uint8_t *mem_temps) { int i; - TCGTemp *ts; - memset(dead_temps, 0, s->nb_globals); - ts = &s->temps[s->nb_globals]; + memset(dead_temps, 1, s->nb_temps); + memset(mem_temps, 1, s->nb_globals); for(i = s->nb_globals; i < s->nb_temps; i++) { - if (ts->temp_local) - dead_temps[i] = 0; - else - dead_temps[i] = 1; - ts++; + mem_temps[i] = s->temps[i].temp_local; } } @@ -1217,17 +1217,20 @@ static void tcg_liveness_analysis(TCGContext *s) TCGOpcode op; TCGArg *args; const TCGOpDef *def; - uint8_t *dead_temps; - unsigned int dead_args; + uint8_t *dead_temps, *mem_temps; + uint16_t dead_args; + uint8_t sync_args; gen_opc_ptr++; /* skip end */ nb_ops = gen_opc_ptr - gen_opc_buf; s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t)); + s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t)); dead_temps = tcg_malloc(s->nb_temps); - memset(dead_temps, 1, s->nb_temps); + mem_temps = tcg_malloc(s->nb_temps); + tcg_la_func_end(s, dead_temps, mem_temps); args = gen_opparam_ptr; op_index = nb_ops - 1; @@ -1248,11 +1251,12 @@ static void tcg_liveness_analysis(TCGContext *s) /* pure functions can be removed if their result is not used */ - if (call_flags & TCG_CALL_PURE) { + if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { for(i = 0; i < nb_oargs; i++) { arg = args[i]; - if (!dead_temps[arg]) + if (!dead_temps[arg] || mem_temps[arg]) { goto do_not_remove_call; + } } tcg_set_nop(s, gen_opc_buf + op_index, args - 1, nb_args); @@ -1261,17 +1265,27 @@ static void tcg_liveness_analysis(TCGContext *s) /* output args are dead */ dead_args = 0; + sync_args = 0; for(i = 0; i < nb_oargs; i++) { arg = args[i]; if (dead_temps[arg]) { dead_args |= (1 << i); } + if (mem_temps[arg]) { + sync_args |= (1 << i); + } dead_temps[arg] = 1; + mem_temps[arg] = 0; + } + + if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) { + /* globals should be synced to memory */ + memset(mem_temps, 1, s->nb_globals); } - - if (!(call_flags & TCG_CALL_CONST)) { - /* globals are live (they may be used by the call) */ - memset(dead_temps, 0, s->nb_globals); + if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS | + TCG_CALL_NO_READ_GLOBALS))) { + /* globals should go back to memory */ + memset(dead_temps, 1, s->nb_globals); } /* input args are live */ @@ -1285,6 +1299,7 @@ static void tcg_liveness_analysis(TCGContext *s) } } s->op_dead_args[op_index] = dead_args; + s->op_sync_args[op_index] = sync_args; } args--; } @@ -1300,6 +1315,7 @@ static void tcg_liveness_analysis(TCGContext *s) args--; /* mark the temporary as dead */ dead_temps[args[0]] = 1; + mem_temps[args[0]] = 0; break; case INDEX_op_end: break; @@ -1365,8 +1381,9 @@ static void tcg_liveness_analysis(TCGContext *s) if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { for(i = 0; i < nb_oargs; i++) { arg = args[i]; - if (!dead_temps[arg]) + if (!dead_temps[arg] || mem_temps[arg]) { goto do_not_remove; + } } do_remove: tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); @@ -1378,20 +1395,25 @@ static void tcg_liveness_analysis(TCGContext *s) /* output args are dead */ dead_args = 0; + sync_args = 0; for(i = 0; i < nb_oargs; i++) { arg = args[i]; if (dead_temps[arg]) { dead_args |= (1 << i); } + if (mem_temps[arg]) { + sync_args |= (1 << i); + } dead_temps[arg] = 1; + mem_temps[arg] = 0; } /* if end of basic block, update */ if (def->flags & TCG_OPF_BB_END) { - tcg_la_bb_end(s, dead_temps); - } else if (def->flags & TCG_OPF_CALL_CLOBBER) { - /* globals are live */ - memset(dead_temps, 0, s->nb_globals); + tcg_la_bb_end(s, dead_temps, mem_temps); + } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { + /* globals should be synced to memory */ + memset(mem_temps, 1, s->nb_globals); } /* input args are live */ @@ -1403,6 +1425,7 @@ static void tcg_liveness_analysis(TCGContext *s) dead_temps[arg] = 0; } s->op_dead_args[op_index] = dead_args; + s->op_sync_args[op_index] = sync_args; } break; } @@ -1421,6 +1444,8 @@ static void tcg_liveness_analysis(TCGContext *s) s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t)); memset(s->op_dead_args, 0, nb_ops * sizeof(uint16_t)); + s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t)); + memset(s->op_sync_args, 0, nb_ops * sizeof(uint8_t)); } #endif @@ -1517,22 +1542,33 @@ static void temp_allocate_frame(TCGContext *s, int temp) s->current_frame_offset += (tcg_target_long)sizeof(tcg_target_long); } +/* sync register 'reg' by saving it to the corresponding temporary */ +static inline void tcg_reg_sync(TCGContext *s, int reg) +{ + TCGTemp *ts; + int temp; + + temp = s->reg_to_temp[reg]; + ts = &s->temps[temp]; + assert(ts->val_type == TEMP_VAL_REG); + if (!ts->mem_coherent && !ts->fixed_reg) { + if (!ts->mem_allocated) { + temp_allocate_frame(s, temp); + } + tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); + } + ts->mem_coherent = 1; +} + /* free register 'reg' by spilling the corresponding temporary if necessary */ static void tcg_reg_free(TCGContext *s, int reg) { - TCGTemp *ts; int temp; temp = s->reg_to_temp[reg]; if (temp != -1) { - ts = &s->temps[temp]; - assert(ts->val_type == TEMP_VAL_REG); - if (!ts->mem_coherent) { - if (!ts->mem_allocated) - temp_allocate_frame(s, temp); - tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); - } - ts->val_type = TEMP_VAL_MEM; + tcg_reg_sync(s, reg); + s->temps[temp].val_type = TEMP_VAL_MEM; s->reg_to_temp[reg] = -1; } } @@ -1564,31 +1600,45 @@ static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) tcg_abort(); } -/* save a temporary to memory. 'allocated_regs' is used in case a +/* mark a temporary as dead. */ +static inline void temp_dead(TCGContext *s, int temp) +{ + TCGTemp *ts; + + ts = &s->temps[temp]; + if (!ts->fixed_reg) { + if (ts->val_type == TEMP_VAL_REG) { + s->reg_to_temp[ts->reg] = -1; + } + if (temp < s->nb_globals || (ts->temp_local && ts->mem_allocated)) { + ts->val_type = TEMP_VAL_MEM; + } else { + ts->val_type = TEMP_VAL_DEAD; + } + } +} + +/* sync a temporary to memory. 'allocated_regs' is used in case a temporary registers needs to be allocated to store a constant. */ -static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) +static inline void temp_sync(TCGContext *s, int temp, TCGRegSet allocated_regs) { TCGTemp *ts; - int reg; ts = &s->temps[temp]; if (!ts->fixed_reg) { switch(ts->val_type) { + case TEMP_VAL_CONST: + ts->reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + allocated_regs); + ts->val_type = TEMP_VAL_REG; + s->reg_to_temp[ts->reg] = temp; + ts->mem_coherent = 0; + tcg_out_movi(s, ts->type, ts->reg, ts->val); + /* fallthrough*/ case TEMP_VAL_REG: - tcg_reg_free(s, ts->reg); + tcg_reg_sync(s, ts->reg); break; case TEMP_VAL_DEAD: - ts->val_type = TEMP_VAL_MEM; - break; - case TEMP_VAL_CONST: - reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], - allocated_regs); - if (!ts->mem_allocated) - temp_allocate_frame(s, temp); - tcg_out_movi(s, ts->type, reg, ts->val); - tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); - ts->val_type = TEMP_VAL_MEM; - break; case TEMP_VAL_MEM: break; default: @@ -1597,6 +1647,20 @@ static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) } } +/* save a temporary to memory. 'allocated_regs' is used in case a + temporary registers needs to be allocated to store a constant. */ +static inline void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) +{ +#ifdef USE_LIVENESS_ANALYSIS + /* The liveness analysis already ensures that globals are back + in memory. Keep an assert for safety. */ + assert(s->temps[temp].val_type == TEMP_VAL_MEM || s->temps[temp].fixed_reg); +#else + temp_sync(s, temp, allocated_regs); + temp_dead(s, temp); +#endif +} + /* save globals to their canonical location and assume they can be modified be the following code. 'allocated_regs' is used in case a temporary registers needs to be allocated to store a constant. */ @@ -1609,6 +1673,23 @@ static void save_globals(TCGContext *s, TCGRegSet allocated_regs) } } +/* sync globals to their canonical location and assume they can be + read by the following code. 'allocated_regs' is used in case a + temporary registers needs to be allocated to store a constant. */ +static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) +{ + int i; + + for (i = 0; i < s->nb_globals; i++) { +#ifdef USE_LIVENESS_ANALYSIS + assert(s->temps[i].val_type != TEMP_VAL_REG || s->temps[i].fixed_reg || + s->temps[i].mem_coherent); +#else + temp_sync(s, i, allocated_regs); +#endif + } +} + /* at the end of a basic block, we assume all temporaries are dead and all globals are stored at their canonical location. */ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) @@ -1621,10 +1702,13 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) if (ts->temp_local) { temp_save(s, i, allocated_regs); } else { - if (ts->val_type == TEMP_VAL_REG) { - s->reg_to_temp[ts->reg] = -1; - } - ts->val_type = TEMP_VAL_DEAD; +#ifdef USE_LIVENESS_ANALYSIS + /* The liveness analysis already ensures that temps are dead. + Keep an assert for safety. */ + assert(ts->val_type == TEMP_VAL_DEAD); +#else + temp_dead(s, i); +#endif } } @@ -1632,8 +1716,10 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) } #define IS_DEAD_ARG(n) ((dead_args >> (n)) & 1) +#define NEED_SYNC_ARG(n) ((sync_args >> (n)) & 1) -static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args) +static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args, + uint16_t dead_args, uint8_t sync_args) { TCGTemp *ots; tcg_target_ulong val; @@ -1652,71 +1738,99 @@ static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args) ots->val_type = TEMP_VAL_CONST; ots->val = val; } + if (NEED_SYNC_ARG(0)) { + temp_sync(s, args[0], s->reserved_regs); + } + if (IS_DEAD_ARG(0)) { + temp_dead(s, args[0]); + } } static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, - const TCGArg *args, - unsigned int dead_args) + const TCGArg *args, uint16_t dead_args, + uint8_t sync_args) { + TCGRegSet allocated_regs; TCGTemp *ts, *ots; - int reg; - const TCGArgConstraint *arg_ct; + const TCGArgConstraint *arg_ct, *oarg_ct; + tcg_regset_set(allocated_regs, s->reserved_regs); ots = &s->temps[args[0]]; ts = &s->temps[args[1]]; - arg_ct = &def->args_ct[0]; + oarg_ct = &def->args_ct[0]; + arg_ct = &def->args_ct[1]; + + /* If the source value is not in a register, and we're going to be + forced to have it in a register in order to perform the copy, + then copy the SOURCE value into its own register first. That way + we don't have to reload SOURCE the next time it is used. */ + if (((NEED_SYNC_ARG(0) || ots->fixed_reg) && ts->val_type != TEMP_VAL_REG) + || ts->val_type == TEMP_VAL_MEM) { + ts->reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + if (ts->val_type == TEMP_VAL_MEM) { + tcg_out_ld(s, ts->type, ts->reg, ts->mem_reg, ts->mem_offset); + ts->mem_coherent = 1; + } else if (ts->val_type == TEMP_VAL_CONST) { + tcg_out_movi(s, ts->type, ts->reg, ts->val); + } + s->reg_to_temp[ts->reg] = args[1]; + ts->val_type = TEMP_VAL_REG; + } - /* XXX: always mark arg dead if IS_DEAD_ARG(1) */ - if (ts->val_type == TEMP_VAL_REG) { + if (IS_DEAD_ARG(0) && !ots->fixed_reg) { + /* mov to a non-saved dead register makes no sense (even with + liveness analysis disabled). */ + assert(NEED_SYNC_ARG(0)); + /* The code above should have moved the temp to a register. */ + assert(ts->val_type == TEMP_VAL_REG); + if (!ots->mem_allocated) { + temp_allocate_frame(s, args[0]); + } + tcg_out_st(s, ots->type, ts->reg, ots->mem_reg, ots->mem_offset); + if (IS_DEAD_ARG(1)) { + temp_dead(s, args[1]); + } + temp_dead(s, args[0]); + } else if (ts->val_type == TEMP_VAL_CONST) { + /* propagate constant */ + if (ots->val_type == TEMP_VAL_REG) { + s->reg_to_temp[ots->reg] = -1; + } + ots->val_type = TEMP_VAL_CONST; + ots->val = ts->val; + } else { + /* The code in the first if block should have moved the + temp to a register. */ + assert(ts->val_type == TEMP_VAL_REG); if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) { /* the mov can be suppressed */ - if (ots->val_type == TEMP_VAL_REG) - s->reg_to_temp[ots->reg] = -1; - reg = ts->reg; - s->reg_to_temp[reg] = -1; - ts->val_type = TEMP_VAL_DEAD; - } else { if (ots->val_type == TEMP_VAL_REG) { - reg = ots->reg; - } else { - reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); - } - if (ts->reg != reg) { - tcg_out_mov(s, ots->type, reg, ts->reg); + s->reg_to_temp[ots->reg] = -1; } - } - } else if (ts->val_type == TEMP_VAL_MEM) { - if (ots->val_type == TEMP_VAL_REG) { - reg = ots->reg; + ots->reg = ts->reg; + temp_dead(s, args[1]); } else { - reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs); + if (ots->val_type != TEMP_VAL_REG) { + /* When allocating a new register, make sure to not spill the + input one. */ + tcg_regset_set_reg(allocated_regs, ts->reg); + ots->reg = tcg_reg_alloc(s, oarg_ct->u.regs, allocated_regs); + } + tcg_out_mov(s, ots->type, ots->reg, ts->reg); } - tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); - } else if (ts->val_type == TEMP_VAL_CONST) { - if (ots->fixed_reg) { - reg = ots->reg; - tcg_out_movi(s, ots->type, reg, ts->val); - } else { - /* propagate constant */ - if (ots->val_type == TEMP_VAL_REG) - s->reg_to_temp[ots->reg] = -1; - ots->val_type = TEMP_VAL_CONST; - ots->val = ts->val; - return; + ots->val_type = TEMP_VAL_REG; + ots->mem_coherent = 0; + s->reg_to_temp[ots->reg] = args[0]; + if (NEED_SYNC_ARG(0)) { + tcg_reg_sync(s, ots->reg); } - } else { - tcg_abort(); } - s->reg_to_temp[reg] = args[0]; - ots->reg = reg; - ots->val_type = TEMP_VAL_REG; - ots->mem_coherent = 0; } static void tcg_reg_alloc_op(TCGContext *s, const TCGOpDef *def, TCGOpcode opc, - const TCGArg *args, - unsigned int dead_args) + const TCGArg *args, uint16_t dead_args, + uint8_t sync_args) { TCGRegSet allocated_regs; int i, k, nb_iargs, nb_oargs, reg; @@ -1796,22 +1910,16 @@ static void tcg_reg_alloc_op(TCGContext *s, iarg_end: ; } + /* mark dead temporaries and free the associated registers */ + for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { + if (IS_DEAD_ARG(i)) { + temp_dead(s, args[i]); + } + } + if (def->flags & TCG_OPF_BB_END) { tcg_reg_alloc_bb_end(s, allocated_regs); } else { - /* mark dead temporaries and free the associated registers */ - for(i = nb_oargs; i < nb_oargs + nb_iargs; i++) { - arg = args[i]; - if (IS_DEAD_ARG(i)) { - ts = &s->temps[arg]; - if (!ts->fixed_reg) { - if (ts->val_type == TEMP_VAL_REG) - s->reg_to_temp[ts->reg] = -1; - ts->val_type = TEMP_VAL_DEAD; - } - } - } - if (def->flags & TCG_OPF_CALL_CLOBBER) { /* XXX: permit generic clobber register list ? */ for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { @@ -1819,12 +1927,11 @@ static void tcg_reg_alloc_op(TCGContext *s, tcg_reg_free(s, reg); } } - /* XXX: for load/store we could do that only for the slow path - (i.e. when a memory callback is called) */ - - /* store globals and free associated registers (we assume the insn - can modify any global. */ - save_globals(s, allocated_regs); + } + if (def->flags & TCG_OPF_SIDE_EFFECTS) { + /* sync globals if the op has side effects and might trigger + an exception. */ + sync_globals(s, allocated_regs); } /* satisfy the output constraints */ @@ -1848,18 +1955,15 @@ static void tcg_reg_alloc_op(TCGContext *s, tcg_regset_set_reg(allocated_regs, reg); /* if a fixed register is used, then a move will be done afterwards */ if (!ts->fixed_reg) { - if (ts->val_type == TEMP_VAL_REG) + if (ts->val_type == TEMP_VAL_REG) { s->reg_to_temp[ts->reg] = -1; - if (IS_DEAD_ARG(i)) { - ts->val_type = TEMP_VAL_DEAD; - } else { - ts->val_type = TEMP_VAL_REG; - ts->reg = reg; - /* temp value is modified, so the value kept in memory is - potentially not the same */ - ts->mem_coherent = 0; - s->reg_to_temp[reg] = arg; - } + } + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + /* temp value is modified, so the value kept in memory is + potentially not the same */ + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; } oarg_end: new_args[i] = reg; @@ -1876,6 +1980,12 @@ static void tcg_reg_alloc_op(TCGContext *s, if (ts->fixed_reg && ts->reg != reg) { tcg_out_mov(s, ts->type, ts->reg, reg); } + if (NEED_SYNC_ARG(i)) { + tcg_reg_sync(s, reg); + } + if (IS_DEAD_ARG(i)) { + temp_dead(s, args[i]); + } } } @@ -1887,7 +1997,7 @@ static void tcg_reg_alloc_op(TCGContext *s, static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, TCGOpcode opc, const TCGArg *args, - unsigned int dead_args) + uint16_t dead_args, uint8_t sync_args) { int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; TCGArg arg, func_arg; @@ -2011,14 +2121,8 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, /* mark dead temporaries and free the associated registers */ for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) { - arg = args[i]; if (IS_DEAD_ARG(i)) { - ts = &s->temps[arg]; - if (!ts->fixed_reg) { - if (ts->val_type == TEMP_VAL_REG) - s->reg_to_temp[ts->reg] = -1; - ts->val_type = TEMP_VAL_DEAD; - } + temp_dead(s, args[i]); } } @@ -2028,10 +2132,14 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, tcg_reg_free(s, reg); } } - - /* store globals and free associated registers (we assume the call - can modify any global. */ - if (!(flags & TCG_CALL_CONST)) { + + /* Save globals if they might be written by the helper, sync them if + they might be read. */ + if (flags & TCG_CALL_NO_READ_GLOBALS) { + /* Nothing to do */ + } else if (flags & TCG_CALL_NO_WRITE_GLOBALS) { + sync_globals(s, allocated_regs); + } else { save_globals(s, allocated_regs); } @@ -2048,15 +2156,18 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, tcg_out_mov(s, ts->type, ts->reg, reg); } } else { - if (ts->val_type == TEMP_VAL_REG) + if (ts->val_type == TEMP_VAL_REG) { s->reg_to_temp[ts->reg] = -1; + } + ts->val_type = TEMP_VAL_REG; + ts->reg = reg; + ts->mem_coherent = 0; + s->reg_to_temp[reg] = arg; + if (NEED_SYNC_ARG(i)) { + tcg_reg_sync(s, reg); + } if (IS_DEAD_ARG(i)) { - ts->val_type = TEMP_VAL_DEAD; - } else { - ts->val_type = TEMP_VAL_REG; - ts->reg = reg; - ts->mem_coherent = 0; - s->reg_to_temp[reg] = arg; + temp_dead(s, args[i]); } } } @@ -2087,7 +2198,6 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, TCGOpcode opc; int op_index; const TCGOpDef *def; - unsigned int dead_args; const TCGArg *args; #ifdef DEBUG_DISAS @@ -2148,12 +2258,13 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, switch(opc) { case INDEX_op_mov_i32: case INDEX_op_mov_i64: - dead_args = s->op_dead_args[op_index]; - tcg_reg_alloc_mov(s, def, args, dead_args); + tcg_reg_alloc_mov(s, def, args, s->op_dead_args[op_index], + s->op_sync_args[op_index]); break; case INDEX_op_movi_i32: case INDEX_op_movi_i64: - tcg_reg_alloc_movi(s, args); + tcg_reg_alloc_movi(s, args, s->op_dead_args[op_index], + s->op_sync_args[op_index]); break; case INDEX_op_debug_insn_start: /* debug instruction */ @@ -2167,24 +2278,16 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, args += args[0]; goto next; case INDEX_op_discard: - { - TCGTemp *ts; - ts = &s->temps[args[0]]; - /* mark the temporary as dead */ - if (!ts->fixed_reg) { - if (ts->val_type == TEMP_VAL_REG) - s->reg_to_temp[ts->reg] = -1; - ts->val_type = TEMP_VAL_DEAD; - } - } + temp_dead(s, args[0]); break; case INDEX_op_set_label: tcg_reg_alloc_bb_end(s, s->reserved_regs); tcg_out_label(s, args[0], s->code_ptr); break; case INDEX_op_call: - dead_args = s->op_dead_args[op_index]; - args += tcg_reg_alloc_call(s, def, opc, args, dead_args); + args += tcg_reg_alloc_call(s, def, opc, args, + s->op_dead_args[op_index], + s->op_sync_args[op_index]); goto next; case INDEX_op_end: goto the_end; @@ -2196,8 +2299,8 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, /* Note: in order to speed up the code, it would be much faster to have specialized register allocator functions for some common argument patterns */ - dead_args = s->op_dead_args[op_index]; - tcg_reg_alloc_op(s, def, opc, args, dead_args); + tcg_reg_alloc_op(s, def, opc, args, s->op_dead_args[op_index], + s->op_sync_args[op_index]); break; } args += def->nb_args; @@ -253,14 +253,20 @@ typedef int TCGv_i64; #define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1) /* call flags */ -/* A pure function only reads its arguments and TCG global variables - and cannot raise exceptions. Hence a call to a pure function can be - safely suppressed if the return value is not used. */ -#define TCG_CALL_PURE 0x0010 -/* A const function only reads its arguments and does not use TCG - global variables. Hence a call to such a function does not - save TCG global variables back to their canonical location. */ -#define TCG_CALL_CONST 0x0020 +/* Helper does not read globals (either directly or through an exception). It + implies TCG_CALL_NO_WRITE_GLOBALS. */ +#define TCG_CALL_NO_READ_GLOBALS 0x0010 +/* Helper does not write globals */ +#define TCG_CALL_NO_WRITE_GLOBALS 0x0020 +/* Helper can be safely suppressed if the return value is not used. */ +#define TCG_CALL_NO_SIDE_EFFECTS 0x0040 + +/* convenience version of most used call flags */ +#define TCG_CALL_NO_RWG TCG_CALL_NO_READ_GLOBALS +#define TCG_CALL_NO_WG TCG_CALL_NO_WRITE_GLOBALS +#define TCG_CALL_NO_SE TCG_CALL_NO_SIDE_EFFECTS +#define TCG_CALL_NO_RWG_SE (TCG_CALL_NO_RWG | TCG_CALL_NO_SE) +#define TCG_CALL_NO_WG_SE (TCG_CALL_NO_WG | TCG_CALL_NO_SE) /* used to align parameters */ #define TCG_CALL_DUMMY_TCGV MAKE_TCGV_I32(-1) @@ -381,6 +387,9 @@ struct TCGContext { /* liveness analysis */ uint16_t *op_dead_args; /* for each operation, each bit tells if the corresponding argument is dead */ + uint8_t *op_sync_args; /* for each operation, each bit tells if the + corresponding output argument needs to be + sync to memory. */ /* tells in which temporary a given register is. It does not take into account fixed registers */ @@ -527,8 +536,8 @@ enum { TCG_OPF_BB_END = 0x01, /* Instruction clobbers call registers and potentially update globals. */ TCG_OPF_CALL_CLOBBER = 0x02, - /* Instruction has side effects: it cannot be removed - if its outputs are not used. */ + /* Instruction has side effects: it cannot be removed if its outputs + are not used, and might trigger exceptions. */ TCG_OPF_SIDE_EFFECTS = 0x04, /* Instruction operands are 64-bits (otherwise 32-bits). */ TCG_OPF_64BIT = 0x08, diff --git a/tests/Makefile b/tests/Makefile index 26a67ce..86c9b79 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -42,11 +42,11 @@ test-qapi-obj-y += module.o $(test-obj-y): QEMU_INCLUDES += -Itests -tests/check-qint$(EXESUF): tests/check-qint.o qint.o $(tools-obj-y) -tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o $(tools-obj-y) -tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y) -tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o $(tools-obj-y) -tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o $(tools-obj-y) +tests/check-qint$(EXESUF): tests/check-qint.o qint.o +tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o +tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o +tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o +tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) $(tools-obj-y) tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) tests/test-iov$(EXESUF): tests/test-iov.o iov.o diff --git a/tests/tcg/hello-i386.c b/tests/tcg/hello-i386.c index 86afc34..fa00380 100644 --- a/tests/tcg/hello-i386.c +++ b/tests/tcg/hello-i386.c @@ -1,6 +1,6 @@ #include <asm/unistd.h> -static inline volatile void exit(int status) +static inline void exit(int status) { int __res; __asm__ volatile ("movl %%ecx,%%ebx\n"\ @@ -17,6 +17,7 @@ static inline int write(int fd, const char * buf, int len) "popl %%ebx\n"\ : "=a" (status) \ : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len))); + return status; } void _start(void) diff --git a/tests/tcg/test-i386.c b/tests/tcg/test-i386.c index 64d929e..40392ac 100644 --- a/tests/tcg/test-i386.c +++ b/tests/tcg/test-i386.c @@ -785,7 +785,7 @@ void fpu_clear_exceptions(void) long double fpregs[8]; } float_env32; - asm volatile ("fnstenv %0\n" : : "m" (float_env32)); + asm volatile ("fnstenv %0\n" : "=m" (float_env32)); float_env32.fpus &= ~0x7f; asm volatile ("fldenv %0\n" : : "m" (float_env32)); } @@ -2850,7 +2850,7 @@ char *vnc_display_local_addr(DisplayState *ds) return vnc_socket_local_addr("%s:%s", vs->lsock); } -int vnc_display_open(DisplayState *ds, const char *display) +void vnc_display_open(DisplayState *ds, const char *display, Error **errp) { VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; const char *options; @@ -2868,14 +2868,15 @@ int vnc_display_open(DisplayState *ds, const char *display) #endif int lock_key_sync = 1; - if (!vnc_display) - return -1; + if (!vnc_display) { + error_setg(errp, "VNC display not active"); + return; + } vnc_display_close(ds); if (strcmp(display, "none") == 0) - return 0; + return; - if (!(vs->display = strdup(display))) - return -1; + vs->display = g_strdup(display); vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; options = display; @@ -2883,13 +2884,11 @@ int vnc_display_open(DisplayState *ds, const char *display) options++; if (strncmp(options, "password", 8) == 0) { if (fips_get_state()) { - fprintf(stderr, - "VNC password auth disabled due to FIPS mode, " - "consider using the VeNCrypt or SASL authentication " - "methods as an alternative\n"); - g_free(vs->display); - vs->display = NULL; - return -1; + error_setg(errp, + "VNC password auth disabled due to FIPS mode, " + "consider using the VeNCrypt or SASL authentication " + "methods as an alternative"); + goto fail; } password = 1; /* Require password auth */ } else if (strncmp(options, "reverse", 7) == 0) { @@ -2919,18 +2918,14 @@ int vnc_display_open(DisplayState *ds, const char *display) VNC_DEBUG("Trying certificate path '%s'\n", path); if (vnc_tls_set_x509_creds_dir(vs, path) < 0) { - fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path); + error_setg(errp, "Failed to find x509 certificates/keys in %s", path); g_free(path); - g_free(vs->display); - vs->display = NULL; - return -1; + goto fail; } g_free(path); } else { - fprintf(stderr, "No certificate path provided\n"); - g_free(vs->display); - vs->display = NULL; - return -1; + error_setg(errp, "No certificate path provided"); + goto fail; } #endif #if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL) @@ -2949,10 +2944,8 @@ int vnc_display_open(DisplayState *ds, const char *display) } else if (strncmp(options+6, "force-shared", 12) == 0) { vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED; } else { - fprintf(stderr, "unknown vnc share= option\n"); - g_free(vs->display); - vs->display = NULL; - return -1; + error_setg(errp, "unknown vnc share= option"); + goto fail; } } } @@ -3053,52 +3046,50 @@ int vnc_display_open(DisplayState *ds, const char *display) #ifdef CONFIG_VNC_SASL if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) { - fprintf(stderr, "Failed to initialize SASL auth %s", - sasl_errstring(saslErr, NULL, NULL)); - g_free(vs->display); - vs->display = NULL; - return -1; + error_setg(errp, "Failed to initialize SASL auth: %s", + sasl_errstring(saslErr, NULL, NULL)); + goto fail; } #endif vs->lock_key_sync = lock_key_sync; if (reverse) { /* connect to viewer */ - if (strncmp(display, "unix:", 5) == 0) - vs->lsock = unix_connect(display+5); - else - vs->lsock = inet_connect(display, NULL); - if (-1 == vs->lsock) { - g_free(vs->display); - vs->display = NULL; - return -1; + int csock; + vs->lsock = -1; + if (strncmp(display, "unix:", 5) == 0) { + csock = unix_connect(display+5, errp); } else { - int csock = vs->lsock; - vs->lsock = -1; - vnc_connect(vs, csock, 0); + csock = inet_connect(display, errp); } - return 0; - + if (csock < 0) { + goto fail; + } + vnc_connect(vs, csock, 0); } else { /* listen for connects */ char *dpy; dpy = g_malloc(256); if (strncmp(display, "unix:", 5) == 0) { pstrcpy(dpy, 256, "unix:"); - vs->lsock = unix_listen(display+5, dpy+5, 256-5); + vs->lsock = unix_listen(display+5, dpy+5, 256-5, errp); } else { vs->lsock = inet_listen(display, dpy, 256, - SOCK_STREAM, 5900, NULL); + SOCK_STREAM, 5900, errp); } - if (-1 == vs->lsock) { + if (vs->lsock < 0) { g_free(dpy); - return -1; - } else { - g_free(vs->display); - vs->display = dpy; + goto fail; } + g_free(vs->display); + vs->display = dpy; + qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs); } - return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs); + return; + +fail: + g_free(vs->display); + vs->display = NULL; } void vnc_display_add_client(DisplayState *ds, int csock, int skipauth) @@ -203,7 +203,6 @@ CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES]; int win2k_install_hack = 0; -int usb_enabled = 0; int singlestep = 0; int smp_cpus = 1; int max_cpus = 0; @@ -341,7 +340,7 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_DEBUG, RUN_STATE_RUNNING }, { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING }, - { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH }, + { RUN_STATE_INMIGRATE, RUN_STATE_PAUSED }, { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED }, { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE }, @@ -790,6 +789,17 @@ static int parse_sandbox(QemuOpts *opts, void *opaque) return 0; } +/*********QEMU USB setting******/ +bool usb_enabled(bool default_usb) +{ + QemuOpts *mach_opts; + mach_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (mach_opts) { + return qemu_opt_get_bool(mach_opts, "usb", default_usb); + } + return default_usb; +} + #ifndef _WIN32 static int parse_add_fd(QemuOpts *opts, void *opaque) { @@ -1149,8 +1159,9 @@ static int usb_device_add(const char *devname) const char *p; USBDevice *dev = NULL; - if (!usb_enabled) + if (!usb_enabled(false)) { return -1; + } /* drivers with .usbdevice_name entry in USBDeviceInfo */ dev = usbdevice_create(devname); @@ -1186,8 +1197,9 @@ static int usb_device_del(const char *devname) if (strstart(devname, "host:", &p)) return usb_host_device_close(p); - if (!usb_enabled) + if (!usb_enabled(false)) { return -1; + } p = strchr(devname, '.'); if (!p) @@ -3155,10 +3167,16 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_usb: - usb_enabled = 1; + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + qemu_opt_set_bool(machine_opts, "usb", true); + } break; case QEMU_OPTION_usbdevice: - usb_enabled = 1; + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + qemu_opt_set_bool(machine_opts, "usb", true); + } add_device_config(DEV_USB, optarg); break; case QEMU_OPTION_device: @@ -3747,7 +3765,7 @@ int main(int argc, char **argv, char **envp) current_machine = machine; /* init USB devices */ - if (usb_enabled) { + if (usb_enabled(false)) { if (foreach_device_config(DEV_USB, usb_parse) < 0) exit(1); } @@ -3805,10 +3823,13 @@ int main(int argc, char **argv, char **envp) #ifdef CONFIG_VNC /* init remote displays */ if (vnc_display) { + Error *local_err = NULL; vnc_display_init(ds); - if (vnc_display_open(ds, vnc_display) < 0) { - fprintf(stderr, "Failed to start VNC server on `%s'\n", - vnc_display); + vnc_display_open(ds, vnc_display, &local_err); + if (local_err != NULL) { + fprintf(stderr, "Failed to start VNC server on `%s': %s\n", + vnc_display, error_get_pretty(local_err)); + error_free(local_err); exit(1); } @@ -3860,16 +3881,12 @@ int main(int argc, char **argv, char **envp) } if (incoming) { - Error *errp = NULL; - int ret = qemu_start_incoming_migration(incoming, &errp); - if (ret < 0) { - if (error_is_set(&errp)) { - fprintf(stderr, "Migrate: %s\n", error_get_pretty(errp)); - error_free(errp); - } - fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n", - incoming, ret); - exit(ret); + Error *local_err = NULL; + qemu_start_incoming_migration(incoming, &local_err); + if (local_err) { + fprintf(stderr, "-incoming %s: %s\n", incoming, error_get_pretty(local_err)); + error_free(local_err); + exit(1); } } else if (autostart) { vm_start(); |