aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--Makefile.objs9
-rw-r--r--block.c19
-rw-r--r--block.h1
-rw-r--r--block_int.h2
-rw-r--r--blockdev-nbd.c119
-rwxr-xr-xconfigure26
-rw-r--r--console.h2
-rw-r--r--default-configs/sparc64-softmmu.mak1
-rw-r--r--error.c28
-rw-r--r--error.h9
-rw-r--r--hmp.c11
-rw-r--r--hw/ac97.c109
-rw-r--r--hw/es1370.c46
-rw-r--r--hw/i8254.c20
-rw-r--r--hw/m48t59.c24
-rw-r--r--hw/mc146818rtc.c19
-rw-r--r--hw/nseries.c3
-rw-r--r--hw/pc.c19
-rw-r--r--hw/pc_piix.c2
-rw-r--r--hw/pckbd.c48
-rw-r--r--hw/ppc/Makefile.objs1
-rw-r--r--hw/ppc/e500.c5
-rw-r--r--hw/ppc440_bamboo.c2
-rw-r--r--hw/ppc_newworld.c19
-rw-r--r--hw/ppc_oldworld.c2
-rw-r--r--hw/ppc_prep.c2
-rw-r--r--hw/ppce500_pci.c9
-rw-r--r--hw/pxa2xx.c4
-rw-r--r--hw/realview.c2
-rw-r--r--hw/rtl8139.c78
-rw-r--r--hw/serial.c30
-rw-r--r--hw/spapr.c16
-rw-r--r--hw/spapr.h8
-rw-r--r--hw/spapr_events.c321
-rw-r--r--hw/spapr_hcall.c29
-rw-r--r--hw/spapr_pci.c44
-rw-r--r--hw/spapr_pci.h2
-rw-r--r--hw/spapr_rtas.c9
-rw-r--r--hw/versatilepb.c2
-rw-r--r--hw/virtio-pci.c126
-rw-r--r--hw/vmport.c21
-rw-r--r--hw/xen_platform.c48
-rw-r--r--hw/xtensa_lx60.c30
-rw-r--r--hw/xtensa_sim.c27
-rw-r--r--migration-exec.c26
-rw-r--r--migration-fd.c27
-rw-r--r--migration-tcp.c19
-rw-r--r--migration-unix.c95
-rw-r--r--migration.c36
-rw-r--r--migration.h19
-rw-r--r--nbd.c39
-rw-r--r--osdep.h2
-rw-r--r--qapi-schema.json119
-rw-r--r--qemu-char.c24
-rw-r--r--qemu-config.c4
-rw-r--r--qemu-sockets.c424
-rw-r--r--qemu-timer.c4
-rw-r--r--qemu-tool.c6
-rw-r--r--qemu_socket.h19
-rw-r--r--qerror.h6
-rw-r--r--qga/channel-posix.c8
-rw-r--r--qmp-commands.hx16
-rw-r--r--qmp.c23
-rw-r--r--sysemu.h4
-rw-r--r--target-alpha/helper.h176
-rw-r--r--target-arm/arm-semi.c167
-rw-r--r--target-arm/helper.c5
-rw-r--r--target-arm/helper.h18
-rw-r--r--target-arm/neon_helper.c6
-rw-r--r--target-arm/op_helper.c2
-rw-r--r--target-arm/translate.c15
-rw-r--r--target-cris/helper.h18
-rw-r--r--target-i386/cpu.c1
-rw-r--r--target-i386/helper.h4
-rw-r--r--target-microblaze/helper.h6
-rw-r--r--target-mips/helper.h106
-rw-r--r--target-mips/translate.c96
-rw-r--r--target-ppc/cpu.h7
-rw-r--r--target-ppc/helper.h38
-rw-r--r--target-ppc/mmu_helper.c2
-rw-r--r--target-ppc/translate_init.c9
-rw-r--r--target-s390x/helper.h76
-rw-r--r--target-sh4/helper.h6
-rw-r--r--target-sparc/helper.h50
-rw-r--r--target-xtensa/helper.h16
-rw-r--r--tcg/README22
-rw-r--r--tcg/i386/tcg-target.c218
-rw-r--r--tcg/optimize.c3
-rw-r--r--tcg/tcg-op.h18
-rw-r--r--tcg/tcg-opc.h29
-rw-r--r--tcg/tcg.c449
-rw-r--r--tcg/tcg.h29
-rw-r--r--tests/Makefile10
-rw-r--r--tests/tcg/hello-i386.c3
-rw-r--r--tests/tcg/test-i386.c2
-rw-r--r--ui/vnc.c93
-rw-r--r--vl.c57
98 files changed, 2526 insertions, 1521 deletions
diff --git a/Makefile b/Makefile
index 88285a4..b522b10 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/block.c b/block.c
index 1564137..da1fdca 100644
--- a/block.c
+++ b/block.c
@@ -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;
}
diff --git a/block.h b/block.h
index 27b8f80..722c620 100644
--- a/block.h
+++ b/block.h
@@ -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;
+}
diff --git a/configure b/configure
index fa5657f..3685020 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/console.h b/console.h
index f990684..6099d8d 100644
--- a/console.h
+++ b/console.h
@@ -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
diff --git a/error.c b/error.c
index 1f05fc4..128d88c 100644
--- a/error.c
+++ b/error.c
@@ -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;
diff --git a/error.h b/error.h
index da7fed3..4d52e73 100644
--- a/error.h
+++ b/error.h
@@ -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
diff --git a/hmp.c b/hmp.c
index 4a458ac..895a343 100644
--- a/hmp.c
+++ b/hmp.c
@@ -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) {
diff --git a/hw/ac97.c b/hw/ac97.c
index 0f561fa..ce6a1dc 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -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,
};
diff --git a/hw/i8254.c b/hw/i8254.c
index 77bd5e8..bea5f92 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -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. */
diff --git a/hw/pc.c b/hw/pc.c
index 16de04c..a02b397 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -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");
}
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 000c7f0..5bb3e0a 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -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] = {
diff --git a/hw/spapr.c b/hw/spapr.c
index 73d75e8..8d0ad3c 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -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);
}
diff --git a/hw/spapr.h b/hw/spapr.h
index 8ee69bd..51c709e 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -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 &current_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(&params);
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);
diff --git a/nbd.c b/nbd.c
index 6f0db62..cec5a94 100644
--- a/nbd.c
+++ b/nbd.c
@@ -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
diff --git a/osdep.h b/osdep.h
index c5fd3d9..585e2c1 100644
--- a/osdep.h
+++ b/osdep.h
@@ -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);
diff --git a/qerror.h b/qerror.h
index dacac52..8db4309 100644
--- a/qerror.h
+++ b/qerror.h
@@ -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,
diff --git a/qmp.c b/qmp.c
index 36c54c5..d8a3c00 100644
--- a/qmp.c
+++ b/qmp.c
@@ -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,
diff --git a/sysemu.h b/sysemu.h
index 0c39a3a..f72b4ce 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -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)
diff --git a/tcg/README b/tcg/README
index aa86992..ec1ac79 100644
--- a/tcg/README
+++ b/tcg/README
@@ -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
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 5faaca5..c3a7f19 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -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;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 45e94f5..a6c9256 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -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));
}
diff --git a/ui/vnc.c b/ui/vnc.c
index 66ae930..d0ffcc5 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -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)
diff --git a/vl.c b/vl.c
index b870caf..5a3d316 100644
--- a/vl.c
+++ b/vl.c
@@ -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();