aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2012-09-11 13:30:22 -0300
committerMarcelo Tosatti <mtosatti@redhat.com>2012-09-11 13:30:22 -0300
commit6b414d9fb86527118f3ddb81a1d1a684b3548a9d (patch)
tree21973df930ee1bff414b15a42088dd97e256543c
parent4c3e02beed9878a5f760eeceb6cd42c475cf0127 (diff)
parent8ca9e258af2921d41214b0b644bdaeedab0f7f64 (diff)
Merge branch 'upstream-merge'
* upstream-merge: (88 commits) Add ability to force enable/disable of tools build Add ability to disable build of all targets RTC: Remove the current_tm field RTC: Get and set time without going through s->current_tm RTC: Do not fire timer periodically to catch next alarm RTC: Add divider reset support RTC: Update the RTC clock only when reading it vmstate: add VMSTATE_TIMER_V RTC: Update interrupt state when interrupts are masked/unmasked RTC: introduce RTC_CLOCK_RATE RTC: Rename rtc_timer_update RTC: Remove the logic to update time format when DM bit changed socket: don't attempt to reconnect a TCP socket in server mode use --libexecdir instead of ignoring it first and reinventing it later hw/mcf5206: Fix buffer overflow for MBAR read / write target-arm: Fix potential buffer overflow hw/wm8750: Fix potential buffer overflow kvm: i386: Add classic PCI device assignment kvm: i386: Add services required for PCI device assignment kvm: Introduce kvm_has_intx_set_mask ... Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--.exrc7
-rw-r--r--MAINTAINERS6
-rwxr-xr-xQMP/qmp-shell46
-rw-r--r--VERSION2
-rwxr-xr-xconfigure59
-rw-r--r--console.c7
-rw-r--r--console.h10
-rw-r--r--error.h6
-rw-r--r--hmp-commands.hx13
-rw-r--r--hmp.c66
-rw-r--r--hmp.h2
-rw-r--r--hw/blizzard.c4
-rw-r--r--hw/elf_ops.h11
-rw-r--r--hw/g364fb.c55
-rw-r--r--hw/kvm/pci-assign.c294
-rw-r--r--hw/lan9118.c2
-rw-r--r--hw/mc146818rtc.c520
-rw-r--r--hw/mc146818rtc_regs.h1
-rw-r--r--hw/mcf5206.c12
-rw-r--r--hw/musicpal.c4
-rw-r--r--hw/omap_lcdc.c66
-rw-r--r--hw/pci.c2
-rw-r--r--hw/pcie.h1
-rw-r--r--hw/pcie_aer.c5
-rw-r--r--hw/pl110.c30
-rw-r--r--hw/pl110_template.h22
-rw-r--r--hw/qdev-monitor.c1
-rw-r--r--hw/qxl.c182
-rw-r--r--hw/qxl.h10
-rw-r--r--hw/tcx.c97
-rw-r--r--hw/vga.c38
-rw-r--r--hw/vga_int.h3
-rw-r--r--hw/vhost.c5
-rw-r--r--hw/vhost.h3
-rw-r--r--hw/vhost_net.c2
-rw-r--r--hw/virtio-pci.c4
-rw-r--r--hw/vmware_vga.c7
-rw-r--r--hw/wm8750.c4
-rw-r--r--input.c251
-rw-r--r--kvm-all.c25
-rw-r--r--kvm-stub.c14
-rw-r--r--kvm.h6
-rw-r--r--monitor.c270
-rw-r--r--monitor.h2
-rw-r--r--net.c18
-rw-r--r--net.h2
-rw-r--r--net/socket.c2
-rw-r--r--net/tap.c4
-rw-r--r--qapi-schema.json64
-rw-r--r--qemu-char.c4
-rw-r--r--qemu-config.c3
-rw-r--r--qemu-options.hx21
-rw-r--r--qmp-commands.hx33
-rw-r--r--qobject.h2
-rwxr-xr-xscripts/checkpatch.pl68
-rw-r--r--scripts/qapi-types.py16
-rw-r--r--scripts/qapi-visit.py16
-rw-r--r--target-arm/helper.c4
-rw-r--r--target-cris/translate.c2
-rw-r--r--target-mips/cpu.h49
-rw-r--r--target-mips/op_helper.c49
-rw-r--r--target-mips/translate.c16
-rw-r--r--target-s390x/Makefile.objs5
-rw-r--r--target-s390x/cc_helper.c550
-rw-r--r--target-s390x/cpu.h9
-rw-r--r--target-s390x/fpu_helper.c843
-rw-r--r--target-s390x/helper.c102
-rw-r--r--target-s390x/helper.h250
-rw-r--r--target-s390x/int_helper.c201
-rw-r--r--target-s390x/mem_helper.c1203
-rw-r--r--target-s390x/misc_helper.c430
-rw-r--r--target-s390x/op_helper.c3019
-rw-r--r--target-s390x/translate.c233
-rw-r--r--target-sparc/fop_helper.c67
-rw-r--r--target-xtensa/xtensa-semi.c112
-rw-r--r--tcg/s390/tcg-target.c14
-rw-r--r--trace-events1
-rw-r--r--ui/spice-core.c41
-rw-r--r--ui/spice-display.c37
-rw-r--r--ui/spice-display.h13
-rw-r--r--vmstate.h5
81 files changed, 5394 insertions, 4291 deletions
diff --git a/.exrc b/.exrc
new file mode 100644
index 000000000..37755ede8
--- /dev/null
+++ b/.exrc
@@ -0,0 +1,7 @@
+"VIM settings to match QEMU coding style. They are activated by adding the
+"following settings (without the " symbol) as last two lines in $HOME/.vimrc:
+"set secure
+"set exrc
+set expandtab
+set shiftwidth=4
+set smarttab
diff --git a/MAINTAINERS b/MAINTAINERS
index 6d864c1ce..61f8b45cb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -398,6 +398,12 @@ M: Blue Swirl <blauwirbel@gmail.com>
S: Maintained
F: hw/sun4u.c
+Leon3
+M: Fabien Chouteau <chouteau@adacore.com>
+S: Maintained
+F: hw/leon3.c
+F: hw/grlib*
+
S390 Machines
-------------
S390 Virtio
diff --git a/QMP/qmp-shell b/QMP/qmp-shell
index 42dabc8c6..24b665c8c 100755
--- a/QMP/qmp-shell
+++ b/QMP/qmp-shell
@@ -33,6 +33,7 @@
import qmp
import readline
import sys
+import pprint
class QMPCompleter(list):
def complete(self, text, state):
@@ -52,10 +53,11 @@ class QMPShellBadPort(QMPShellError):
# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
# _execute_cmd()). Let's design a better one.
class QMPShell(qmp.QEMUMonitorProtocol):
- def __init__(self, address):
+ def __init__(self, address, pp=None):
qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
self._greeting = None
self._completer = None
+ self._pp = pp
def __get_address(self, arg):
"""
@@ -114,7 +116,11 @@ class QMPShell(qmp.QEMUMonitorProtocol):
if resp is None:
print 'Disconnected'
return False
- print resp
+
+ if self._pp is not None:
+ self._pp.pprint(resp)
+ else:
+ print resp
return True
def connect(self):
@@ -222,22 +228,36 @@ def die(msg):
def fail_cmdline(option=None):
if option:
sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
- sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n')
+ sys.stderr.write('qemu-shell [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
sys.exit(1)
def main():
addr = ''
+ qemu = None
+ hmp = False
+ pp = None
+
try:
- if len(sys.argv) == 2:
- qemu = QMPShell(sys.argv[1])
- addr = sys.argv[1]
- elif len(sys.argv) == 3:
- if sys.argv[1] != '-H':
- fail_cmdline(sys.argv[1])
- qemu = HMPShell(sys.argv[2])
- addr = sys.argv[2]
- else:
- fail_cmdline()
+ for arg in sys.argv[1:]:
+ if arg == "-H":
+ if qemu is not None:
+ fail_cmdline(arg)
+ hmp = True
+ elif arg == "-p":
+ if pp is not None:
+ fail_cmdline(arg)
+ pp = pprint.PrettyPrinter(indent=4)
+ else:
+ if qemu is not None:
+ fail_cmdline(arg)
+ if hmp:
+ qemu = HMPShell(arg)
+ else:
+ qemu = QMPShell(arg, pp)
+ addr = arg
+
+ if qemu is None:
+ fail_cmdline()
except QMPShellBadPort:
die('bad port number in command-line')
diff --git a/VERSION b/VERSION
index 26aaba0e8..99188f0c6 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.2.0
+1.2.50
diff --git a/configure b/configure
index bf3acc8d0..b67be2ce7 100755
--- a/configure
+++ b/configure
@@ -128,7 +128,6 @@ libs_qga=""
debug_info="yes"
target_list="x86_64-softmmu"
-
kvm_version() {
local fname="$(dirname "$0")/KVM_VERSION"
@@ -193,6 +192,7 @@ datadir="\${prefix}/share"
qemu_docdir="\${prefix}/share/doc/qemu"
bindir="\${prefix}/bin"
libdir="\${prefix}/lib"
+libexecdir="\${prefix}/libexec"
includedir="\${prefix}/include"
sysconfdir="\${prefix}/etc"
confsuffix="/qemu"
@@ -226,6 +226,7 @@ usb_redir=""
opengl=""
zlib="yes"
guest_agent="yes"
+want_tools="yes"
libiscsi=""
coroutine=""
seccomp=""
@@ -643,6 +644,8 @@ for opt do
;;
--libdir=*) libdir="$optarg"
;;
+ --libexecdir=*) libexecdir="$optarg"
+ ;;
--includedir=*) includedir="$optarg"
;;
--datadir=*) datadir="$optarg"
@@ -653,7 +656,7 @@ for opt do
;;
--sysconfdir=*) sysconfdir="$optarg"
;;
- --sbindir=*|--libexecdir=*|--sharedstatedir=*|--localstatedir=*|\
+ --sbindir=*|--sharedstatedir=*|--localstatedir=*|\
--oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\
--htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
# These switches are silently ignored, for compatibility with
@@ -875,6 +878,10 @@ for opt do
;;
--disable-guest-agent) guest_agent="no"
;;
+ --enable-tools) want_tools="yes"
+ ;;
+ --disable-tools) want_tools="no"
+ ;;
--enable-seccomp) seccomp="yes"
;;
--disable-seccomp) seccomp="no"
@@ -1324,15 +1331,10 @@ if ! "$python" -c 'import sys; sys.exit(sys.version_info < (2,4) or sys.version_
exit 1
fi
-if test -z "$target_list" ; then
- target_list="$default_target_list"
-else
- target_list=`echo "$target_list" | sed -e 's/,/ /g'`
-fi
-if test -z "$target_list" ; then
- echo "No targets enabled"
- exit 1
+if test "$target_list" = "DEFAULT" ; then
+ target_list=`echo "$default_target_list" | sed -e 's/,/ /g'`
fi
+
# see if system emulation was really requested
case " $target_list " in
*"-softmmu "*) softmmu=yes
@@ -2711,6 +2713,11 @@ EOF
spice="yes"
libs_softmmu="$libs_softmmu $spice_libs"
QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
+ spice_protocol_version=$($pkg_config --modversion spice-protocol)
+ spice_server_version=$($pkg_config --modversion spice-server)
+ if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then
+ spice_qxl_io_monitors_config_async="yes"
+ fi
else
if test "$spice" = "yes" ; then
feature_not_found "spice"
@@ -2973,11 +2980,12 @@ if compile_prog "-Werror" "" ; then
fi
########################################
-# check if we have valgrind/valgrind.h
+# check if we have valgrind/valgrind.h and valgrind/memcheck.h
valgrind_h=no
cat > $TMPC << EOF
#include <valgrind/valgrind.h>
+#include <valgrind/memcheck.h>
int main(void) {
return 0;
}
@@ -3049,9 +3057,14 @@ fi
qemu_confdir=$sysconfdir$confsuffix
qemu_datadir=$datadir$confsuffix
-tools=
-if test "$softmmu" = yes ; then
+tools=""
+if test "$want_tools" = "yes" ; then
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
+ if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
+ tools="qemu-nbd\$(EXESUF) $tools"
+ fi
+fi
+if test "$softmmu" = yes ; then
if test "$virtfs" != no ; then
if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
virtfs=yes
@@ -3065,14 +3078,13 @@ if test "$softmmu" = yes ; then
fi
fi
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
- tools="qemu-nbd\$(EXESUF) $tools"
if [ "$guest_agent" = "yes" ]; then
tools="qemu-ga\$(EXESUF) $tools"
fi
fi
-fi
-if test "$smartcard_nss" = "yes" ; then
- tools="vscclient\$(EXESUF) $tools"
+ if test "$smartcard_nss" = "yes" ; then
+ tools="vscclient\$(EXESUF) $tools"
+ fi
fi
# Mac OS X ships with a broken assembler
@@ -3090,6 +3102,7 @@ echo "Install prefix $prefix"
echo "BIOS directory `eval echo $qemu_datadir`"
echo "binary directory `eval echo $bindir`"
echo "library directory `eval echo $libdir`"
+echo "libexec directory `eval echo $libexecdir`"
echo "include directory `eval echo $includedir`"
echo "config directory `eval echo $sysconfdir`"
if test "$mingw32" = "no" ; then
@@ -3166,7 +3179,7 @@ echo "libcap-ng support $cap_ng"
echo "vhost-net support $vhost_net"
echo "Trace backend $trace_backend"
echo "Trace output file $trace_file-<pid>"
-echo "spice support $spice"
+echo "spice support $spice ($spice_protocol_version/$spice_server_version)"
echo "rbd support $rbd"
echo "xfsctl support $xfs"
echo "nss used $smartcard_nss"
@@ -3193,14 +3206,14 @@ echo all: >> $config_host_mak
echo "prefix=$prefix" >> $config_host_mak
echo "bindir=$bindir" >> $config_host_mak
echo "libdir=$libdir" >> $config_host_mak
+echo "libexecdir=$libexecdir" >> $config_host_mak
echo "includedir=$includedir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
-echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
-echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
+echo "CONFIG_QEMU_HELPERDIR=\"$libexecdir\"" >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
if test "$debug_tcg" = "yes" ; then
@@ -3448,6 +3461,10 @@ if test "$spice" = "yes" ; then
echo "CONFIG_SPICE=y" >> $config_host_mak
fi
+if test "$spice_qxl_io_monitors_config_async" = "yes" ; then
+ echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak
+fi
+
if test "$smartcard" = "yes" ; then
echo "CONFIG_SMARTCARD=y" >> $config_host_mak
fi
@@ -3839,7 +3856,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile"
case "$target_arch2" in
- alpha | i386 | or32 | sparc* | x86_64 | xtensa* | ppc*)
+ alpha | i386 | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*)
echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak
;;
esac
diff --git a/console.c b/console.c
index 3b5cabba3..c1ed5e09e 100644
--- a/console.c
+++ b/console.c
@@ -24,6 +24,7 @@
#include "qemu-common.h"
#include "console.h"
#include "qemu-timer.h"
+#include "qmp-commands.h"
//#define DEBUG_CONSOLE
#define DEFAULT_BACKSCROLL 512
@@ -176,7 +177,7 @@ void vga_hw_invalidate(void)
active_console->hw_invalidate(active_console->hw);
}
-void vga_hw_screen_dump(const char *filename)
+void qmp_screendump(const char *filename, Error **errp)
{
TextConsole *previous_active_console;
bool cswitch;
@@ -190,9 +191,9 @@ void vga_hw_screen_dump(const char *filename)
console_select(0);
}
if (consoles[0] && consoles[0]->hw_screen_dump) {
- consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch);
+ consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
} else {
- error_report("screen dump not implemented");
+ error_setg(errp, "device doesn't support screendump\n");
}
if (cswitch) {
diff --git a/console.h b/console.h
index 4334db5ca..f990684ef 100644
--- a/console.h
+++ b/console.h
@@ -6,6 +6,8 @@
#include "notify.h"
#include "monitor.h"
#include "trace.h"
+#include "qapi-types.h"
+#include "error.h"
/* keyboard/mouse support */
@@ -343,7 +345,8 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
typedef void (*vga_hw_update_ptr)(void *);
typedef void (*vga_hw_invalidate_ptr)(void *);
-typedef void (*vga_hw_screen_dump_ptr)(void *, const char *, bool cswitch);
+typedef void (*vga_hw_screen_dump_ptr)(void *, const char *, bool cswitch,
+ Error **errp);
typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *);
DisplayState *graphic_console_init(vga_hw_update_ptr update,
@@ -354,7 +357,6 @@ DisplayState *graphic_console_init(vga_hw_update_ptr update,
void vga_hw_update(void);
void vga_hw_invalidate(void);
-void vga_hw_screen_dump(const char *filename);
void vga_hw_text_update(console_ch_t *chardata);
int is_graphic_console(void);
@@ -397,4 +399,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
/* curses.c */
void curses_display_init(DisplayState *ds, int full_screen);
+/* input.c */
+int index_from_key(const char *key);
+int index_from_keycode(int code);
+
#endif
diff --git a/error.h b/error.h
index 96fc20328..da7fed399 100644
--- a/error.h
+++ b/error.h
@@ -30,6 +30,12 @@ typedef struct Error Error;
void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
/**
+ * Same as error_set(), but sets a generic error
+ */
+#define error_setg(err, fmt, ...) \
+ error_set(err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__)
+
+/**
* Returns true if an indirect pointer to an error is pointing to a valid
* error object.
*/
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 13f28cfdd..20806b7d7 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -194,8 +194,7 @@ ETEXI
.args_type = "filename:F",
.params = "filename",
.help = "save screen into PPM image 'filename'",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_screen_dump,
+ .mhandler.cmd = hmp_screen_dump,
},
STEXI
@@ -502,19 +501,19 @@ ETEXI
{
.name = "sendkey",
- .args_type = "string:s,hold_time:i?",
+ .args_type = "keys:s,hold-time:i?",
.params = "keys [hold_ms]",
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
- .mhandler.cmd = do_sendkey,
+ .mhandler.cmd = hmp_send_key,
},
STEXI
@item sendkey @var{keys}
@findex sendkey
-Send @var{keys} to the emulator. @var{keys} could be the name of the
-key or @code{#} followed by the raw value in either decimal or hexadecimal
-format. Use @code{-} to press several keys simultaneously. Example:
+Send @var{keys} to the guest. @var{keys} could be the name of the
+key or the raw value in hexadecimal format. Use @code{-} to press
+several keys simultaneously. Example:
@example
sendkey ctrl-alt-f1
@end example
diff --git a/hmp.c b/hmp.c
index 81c8acb67..ba6fbd3dc 100644
--- a/hmp.c
+++ b/hmp.c
@@ -19,6 +19,7 @@
#include "qemu-timer.h"
#include "qmp-commands.h"
#include "monitor.h"
+#include "console.h"
static void hmp_handle_error(Monitor *mon, Error **errp)
{
@@ -413,6 +414,8 @@ void hmp_info_spice(Monitor *mon)
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
info->host, info->tls_port);
}
+ monitor_printf(mon, " migrated: %s\n",
+ info->migrated ? "true" : "false");
monitor_printf(mon, " auth: %s\n", info->auth);
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
monitor_printf(mon, " mouse-mode: %s\n",
@@ -1102,3 +1105,66 @@ void hmp_closefd(Monitor *mon, const QDict *qdict)
qmp_closefd(fdname, &errp);
hmp_handle_error(mon, &errp);
}
+
+void hmp_send_key(Monitor *mon, const QDict *qdict)
+{
+ const char *keys = qdict_get_str(qdict, "keys");
+ QKeyCodeList *keylist, *head = NULL, *tmp = NULL;
+ int has_hold_time = qdict_haskey(qdict, "hold-time");
+ int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
+ Error *err = NULL;
+ char keyname_buf[16];
+ char *separator;
+ int keyname_len, idx;
+
+ while (1) {
+ separator = strchr(keys, '-');
+ keyname_len = separator ? separator - keys : strlen(keys);
+ pstrcpy(keyname_buf, sizeof(keyname_buf), keys);
+
+ /* Be compatible with old interface, convert user inputted "<" */
+ if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) {
+ pstrcpy(keyname_buf, sizeof(keyname_buf), "less");
+ keyname_len = 4;
+ }
+ keyname_buf[keyname_len] = 0;
+
+ idx = index_from_key(keyname_buf);
+ if (idx == Q_KEY_CODE_MAX) {
+ monitor_printf(mon, "invalid parameter: %s\n", keyname_buf);
+ break;
+ }
+
+ keylist = g_malloc0(sizeof(*keylist));
+ keylist->value = idx;
+ keylist->next = NULL;
+
+ if (!head) {
+ head = keylist;
+ }
+ if (tmp) {
+ tmp->next = keylist;
+ }
+ tmp = keylist;
+
+ if (!separator) {
+ break;
+ }
+ keys = separator + 1;
+ }
+
+ if (idx != Q_KEY_CODE_MAX) {
+ qmp_send_key(head, has_hold_time, hold_time, &err);
+ }
+ hmp_handle_error(mon, &err);
+ qapi_free_QKeyCodeList(head);
+}
+
+void hmp_screen_dump(Monitor *mon, const QDict *qdict)
+{
+ const char *filename = qdict_get_str(qdict, "filename");
+ Error *err = NULL;
+
+ qmp_screendump(filename, &err);
+ hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 7dd93bf0f..48b9c59f8 100644
--- a/hmp.h
+++ b/hmp.h
@@ -71,5 +71,7 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict);
void hmp_netdev_del(Monitor *mon, const QDict *qdict);
void hmp_getfd(Monitor *mon, const QDict *qdict);
void hmp_closefd(Monitor *mon, const QDict *qdict);
+void hmp_send_key(Monitor *mon, const QDict *qdict);
+void hmp_screen_dump(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/blizzard.c b/hw/blizzard.c
index 29074c4fa..d1c9d8151 100644
--- a/hw/blizzard.c
+++ b/hw/blizzard.c
@@ -933,13 +933,13 @@ static void blizzard_update_display(void *opaque)
}
static void blizzard_screen_dump(void *opaque, const char *filename,
- bool cswitch)
+ bool cswitch, Error **errp)
{
BlizzardState *s = (BlizzardState *) opaque;
blizzard_update_display(opaque);
if (s && ds_get_data(s->state))
- ppm_save(filename, s->state->surface);
+ ppm_save(filename, s->state->surface, errp);
}
#define DEPTH 8
diff --git a/hw/elf_ops.h b/hw/elf_ops.h
index fa65ce2f9..731a98385 100644
--- a/hw/elf_ops.h
+++ b/hw/elf_ops.h
@@ -269,6 +269,17 @@ static int glue(load_elf, SZ)(const char *name, int fd,
addr = ph->p_paddr;
}
+ /* the entry pointer in the ELF header is a virtual
+ * address, if the text segments paddr and vaddr differ
+ * we need to adjust the entry */
+ if (pentry && !translate_fn &&
+ ph->p_vaddr != ph->p_paddr &&
+ ehdr.e_entry >= ph->p_vaddr &&
+ ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
+ ph->p_flags & PF_X) {
+ *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
+ }
+
snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
rom_add_blob_fixed(label, data, mem_size, addr);
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 3a0b68fba..059e6220e 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -289,10 +289,11 @@ static void g364fb_reset(G364State *s)
g364fb_invalidate_display(s);
}
-static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch)
+static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp)
{
G364State *s = opaque;
- int y, x;
+ int ret, y, x;
uint8_t index;
uint8_t *data_buffer;
FILE *f;
@@ -300,35 +301,63 @@ static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch)
qemu_flush_coalesced_mmio_buffer();
if (s->depth != 8) {
- error_report("g364: unknown guest depth %d", s->depth);
+ error_setg(errp, "g364: unknown guest depth %d", s->depth);
return;
}
f = fopen(filename, "wb");
- if (!f)
+ if (!f) {
+ error_setg(errp, "failed to open file '%s': %s", filename,
+ strerror(errno));
return;
+ }
if (s->ctla & CTLA_FORCE_BLANK) {
/* blank screen */
- fprintf(f, "P4\n%d %d\n",
- s->width, s->height);
+ ret = fprintf(f, "P4\n%d %d\n", s->width, s->height);
+ if (ret < 0) {
+ goto write_err;
+ }
for (y = 0; y < s->height; y++)
- for (x = 0; x < s->width; x++)
- fputc(0, f);
+ for (x = 0; x < s->width; x++) {
+ ret = fputc(0, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ }
} else {
data_buffer = s->vram + s->top_of_screen;
- fprintf(f, "P6\n%d %d\n%d\n",
- s->width, s->height, 255);
+ ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+ if (ret < 0) {
+ goto write_err;
+ }
for (y = 0; y < s->height; y++)
for (x = 0; x < s->width; x++, data_buffer++) {
index = *data_buffer;
- fputc(s->color_palette[index][0], f);
- fputc(s->color_palette[index][1], f);
- fputc(s->color_palette[index][2], f);
+ ret = fputc(s->color_palette[index][0], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc(s->color_palette[index][1], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc(s->color_palette[index][2], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
}
}
+out:
fclose(f);
+ return;
+
+write_err:
+ error_setg(errp, "failed to write to file '%s': %s", filename,
+ strerror(errno));
+ unlink(filename);
+ goto out;
}
/* called for accesses to io ports */
diff --git a/hw/kvm/pci-assign.c b/hw/kvm/pci-assign.c
index 9cce02cbf..05b93d9a5 100644
--- a/hw/kvm/pci-assign.c
+++ b/hw/kvm/pci-assign.c
@@ -1,23 +1,18 @@
/*
* Copyright (c) 2007, Neocleus Corporation.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
*
*
* Assign a PCI device from the host to a guest VM.
*
- * Adapted for KVM by Qumranet.
+ * This implementation uses the classic device assignment interface of KVM
+ * and is only available on x86 hosts. It is expected to be obsoleted by VFIO
+ * based device assignment.
+ *
+ * Adapted for KVM (qemu-kvm) by Qumranet. QEMU version was based on qemu-kvm
+ * revision 4144fe9d48. See its repository for the history.
*
* Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
* Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
@@ -52,7 +47,7 @@
#define IORESOURCE_DMA 0x00000800
#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */
-/* #define DEVICE_ASSIGNMENT_DEBUG 1 */
+//#define DEVICE_ASSIGNMENT_DEBUG
#ifdef DEVICE_ASSIGNMENT_DEBUG
#define DEBUG(fmt, ...) \
@@ -63,15 +58,15 @@
#define DEBUG(fmt, ...)
#endif
-typedef struct {
+typedef struct PCIRegion {
int type; /* Memory or port I/O */
int valid;
- uint32_t base_addr;
- uint32_t size; /* size of the region */
+ uint64_t base_addr;
+ uint64_t size; /* size of the region */
int resource_fd;
} PCIRegion;
-typedef struct {
+typedef struct PCIDevRegions {
uint8_t bus, dev, func; /* Bus inside domain, device and function */
int irq; /* IRQ number */
uint16_t region_number; /* number of active regions */
@@ -81,11 +76,11 @@ typedef struct {
int config_fd;
} PCIDevRegions;
-typedef struct {
+typedef struct AssignedDevRegion {
MemoryRegion container;
MemoryRegion real_iomem;
union {
- void *r_virtbase; /* mmapped access address for memory regions */
+ uint8_t *r_virtbase; /* mmapped access address for memory regions */
uint32_t r_baseport; /* the base guest port for I/O regions */
} u;
pcibus_t e_size; /* emulated size of region in bytes */
@@ -99,7 +94,7 @@ typedef struct {
#define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT)
#define ASSIGNED_DEVICE_SHARE_INTX_MASK (1 << ASSIGNED_DEVICE_SHARE_INTX_BIT)
-typedef struct {
+typedef struct MSIXTableEntry {
uint32_t addr_lo;
uint32_t addr_hi;
uint32_t data;
@@ -160,27 +155,27 @@ static uint64_t assigned_dev_ioport_rw(AssignedDevRegion *dev_region,
if (fd >= 0) {
if (data) {
- DEBUG("pwrite data=%lx, size=%d, e_phys=%lx, addr=%lx\n",
- *data, size, addr, addr);
+ DEBUG("pwrite data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
+ ", addr="TARGET_FMT_plx"\n", *data, size, addr, addr);
if (pwrite(fd, data, size, addr) != size) {
- fprintf(stderr, "%s - pwrite failed %s\n",
- __func__, strerror(errno));
+ error_report("%s - pwrite failed %s",
+ __func__, strerror(errno));
}
} else {
if (pread(fd, &val, size, addr) != size) {
- fprintf(stderr, "%s - pread failed %s\n",
- __func__, strerror(errno));
+ error_report("%s - pread failed %s",
+ __func__, strerror(errno));
val = (1UL << (size * 8)) - 1;
}
- DEBUG("pread val=%lx, size=%d, e_phys=%lx, addr=%lx\n",
- val, size, addr, addr);
+ DEBUG("pread val=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
+ ", addr=" TARGET_FMT_plx "\n", val, size, addr, addr);
}
} else {
uint32_t port = addr + dev_region->u.r_baseport;
if (data) {
- DEBUG("out data=%lx, size=%d, e_phys=%lx, host=%x\n",
- *data, size, addr, port);
+ DEBUG("out data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
+ ", host=%x\n", *data, size, addr, port);
switch (size) {
case 1:
outb(*data, port);
@@ -204,8 +199,8 @@ static uint64_t assigned_dev_ioport_rw(AssignedDevRegion *dev_region,
val = inl(port);
break;
}
- DEBUG("in data=%lx, size=%d, e_phys=%lx, host=%x\n",
- val, size, addr, port);
+ DEBUG("in data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
+ ", host=%x\n", val, size, addr, port);
}
}
return val;
@@ -238,7 +233,7 @@ static uint32_t slow_bar_readb(void *opaque, target_phys_addr_t addr)
static uint32_t slow_bar_readw(void *opaque, target_phys_addr_t addr)
{
AssignedDevRegion *d = opaque;
- uint16_t *in = d->u.r_virtbase + addr;
+ uint16_t *in = (uint16_t *)(d->u.r_virtbase + addr);
uint32_t r;
r = *in;
@@ -250,7 +245,7 @@ static uint32_t slow_bar_readw(void *opaque, target_phys_addr_t addr)
static uint32_t slow_bar_readl(void *opaque, target_phys_addr_t addr)
{
AssignedDevRegion *d = opaque;
- uint32_t *in = d->u.r_virtbase + addr;
+ uint32_t *in = (uint32_t *)(d->u.r_virtbase + addr);
uint32_t r;
r = *in;
@@ -271,7 +266,7 @@ static void slow_bar_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
static void slow_bar_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
AssignedDevRegion *d = opaque;
- uint16_t *out = d->u.r_virtbase + addr;
+ uint16_t *out = (uint16_t *)(d->u.r_virtbase + addr);
DEBUG("slow_bar_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, val);
*out = val;
@@ -280,7 +275,7 @@ static void slow_bar_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
static void slow_bar_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
AssignedDevRegion *d = opaque;
- uint32_t *out = d->u.r_virtbase + addr;
+ uint32_t *out = (uint32_t *)(d->u.r_virtbase + addr);
DEBUG("slow_bar_writel addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, val);
*out = val;
@@ -310,7 +305,7 @@ static void assigned_dev_iomem_setup(PCIDevice *pci_dev, int region_num,
if (real_region->base_addr <= r_dev->msix_table_addr &&
real_region->base_addr + real_region->size >
r_dev->msix_table_addr) {
- int offset = r_dev->msix_table_addr - real_region->base_addr;
+ uint64_t offset = r_dev->msix_table_addr - real_region->base_addr;
memory_region_add_subregion_overlap(&region->container,
offset,
@@ -460,9 +455,8 @@ static int assigned_dev_register_regions(PCIRegion *io_regions,
if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) {
pci_dev->v_addrs[i].u.r_virtbase = NULL;
- fprintf(stderr, "%s: Error: Couldn't mmap 0x%x!"
- "\n", __func__,
- (uint32_t) (cur_region->base_addr));
+ error_report("%s: Error: Couldn't mmap 0x%" PRIx64 "!",
+ __func__, cur_region->base_addr);
return -1;
}
@@ -474,12 +468,11 @@ static int assigned_dev_register_regions(PCIRegion *io_regions,
(cur_region->base_addr & 0xFFF);
if (cur_region->size & 0xFFF) {
- fprintf(stderr, "PCI region %d at address 0x%llx "
- "has size 0x%x, which is not a multiple of 4K. "
- "You might experience some performance hit "
- "due to that.\n",
- i, (unsigned long long)cur_region->base_addr,
- cur_region->size);
+ error_report("PCI region %d at address 0x%" PRIx64 " has "
+ "size 0x%" PRIx64 ", which is not a multiple of "
+ "4K. You might experience some performance hit "
+ "due to that.",
+ i, cur_region->base_addr, cur_region->size);
memory_region_init_io(&pci_dev->v_addrs[i].real_iomem,
&slow_bar_ops, &pci_dev->v_addrs[i],
"assigned-dev-slow-bar",
@@ -510,12 +503,11 @@ static int assigned_dev_register_regions(PCIRegion *io_regions,
* so should return EINVAL for a 3 byte read */
ret = pread(pci_dev->v_addrs[i].region->resource_fd, &val, 3, 0);
if (ret >= 0) {
- fprintf(stderr, "Unexpected return from I/O port read: %d\n",
- ret);
+ error_report("Unexpected return from I/O port read: %d", ret);
abort();
} else if (errno != EINVAL) {
- fprintf(stderr, "Kernel doesn't support ioport resource "
- "access, hiding this region.\n");
+ error_report("Kernel doesn't support ioport resource "
+ "access, hiding this region.");
close(pci_dev->v_addrs[i].region->resource_fd);
cur_region->valid = 0;
continue;
@@ -545,7 +537,7 @@ static int get_real_id(const char *devpath, const char *idname, uint16_t *val)
snprintf(name, sizeof(name), "%s%s", devpath, idname);
f = fopen(name, "r");
if (f == NULL) {
- fprintf(stderr, "%s: %s: %m\n", __func__, name);
+ error_report("%s: %s: %m", __func__, name);
return -1;
}
if (fscanf(f, "%li\n", &id) == 1) {
@@ -574,7 +566,7 @@ static int get_real_device(AssignedDevice *pci_dev, uint16_t r_seg,
char dir[128], name[128];
int fd, r = 0, v;
FILE *f;
- unsigned long long start, end, size, flags;
+ uint64_t start, end, size, flags;
uint16_t id;
PCIRegion *rp;
PCIDevRegions *dev = &pci_dev->real_device;
@@ -592,8 +584,8 @@ static int get_real_device(AssignedDevice *pci_dev, uint16_t r_seg,
} else {
dev->config_fd = monitor_get_fd(cur_mon, pci_dev->configfd_name);
if (dev->config_fd < 0) {
- fprintf(stderr, "%s: (%s) unkown\n", __func__,
- pci_dev->configfd_name);
+ error_report("%s: (%s) unkown", __func__,
+ pci_dev->configfd_name);
return 1;
}
}
@@ -601,7 +593,7 @@ static int get_real_device(AssignedDevice *pci_dev, uint16_t r_seg,
dev->config_fd = open(name, O_RDWR);
if (dev->config_fd == -1) {
- fprintf(stderr, "%s: %s: %m\n", __func__, name);
+ error_report("%s: %s: %m", __func__, name);
return 1;
}
}
@@ -612,7 +604,7 @@ again:
if (errno == EINTR || errno == EAGAIN) {
goto again;
}
- fprintf(stderr, "%s: read failed, errno = %d\n", __func__, errno);
+ error_report("%s: read failed, errno = %d", __func__, errno);
}
/* Restore or clear multifunction, this is always controlled by qemu */
@@ -632,12 +624,13 @@ again:
f = fopen(name, "r");
if (f == NULL) {
- fprintf(stderr, "%s: %s: %m\n", __func__, name);
+ error_report("%s: %s: %m", __func__, name);
return 1;
}
for (r = 0; r < PCI_ROM_SLOT; r++) {
- if (fscanf(f, "%lli %lli %lli\n", &start, &end, &flags) != 3) {
+ if (fscanf(f, "%" SCNi64 " %" SCNi64 " %" SCNi64 "\n",
+ &start, &end, &flags) != 3) {
break;
}
@@ -666,7 +659,8 @@ again:
rp->base_addr = start;
rp->size = size;
pci_dev->v_addrs[r].region = rp;
- DEBUG("region %d size %d start 0x%llx type %d resource_fd %d\n",
+ DEBUG("region %d size %" PRIu64 " start 0x%" PRIx64
+ " type %d resource_fd %d\n",
r, rp->size, start, rp->type, rp->resource_fd);
}
@@ -748,9 +742,8 @@ static void free_assigned_device(AssignedDevice *dev)
memory_region_destroy(&region->container);
if (munmap(region->u.r_virtbase,
(pci_region->size + 0xFFF) & 0xFFFFF000)) {
- fprintf(stderr,
- "Failed to unmap assigned device region: %s\n",
- strerror(errno));
+ error_report("Failed to unmap assigned device region: %s",
+ strerror(errno));
}
}
}
@@ -772,11 +765,11 @@ static void assign_failed_examine(AssignedDevice *dev)
uint16_t vendor_id, device_id;
int r;
- sprintf(dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
+ snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
dev->host.domain, dev->host.bus, dev->host.slot,
dev->host.function);
- sprintf(name, "%sdriver", dir);
+ snprintf(name, sizeof(name), "%sdriver", dir);
r = readlink(name, driver, sizeof(driver));
if ((r <= 0) || r >= sizeof(driver)) {
@@ -795,31 +788,31 @@ static void assign_failed_examine(AssignedDevice *dev)
goto fail;
}
- fprintf(stderr, "*** The driver '%s' is occupying your device "
- "%04x:%02x:%02x.%x.\n",
- ns, dev->host.domain, dev->host.bus, dev->host.slot,
- dev->host.function);
- fprintf(stderr, "***\n");
- fprintf(stderr, "*** You can try the following commands to free it:\n");
- fprintf(stderr, "***\n");
- fprintf(stderr, "*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/"
- "new_id\n", vendor_id, device_id);
- fprintf(stderr, "*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
- "%s/unbind\n",
- dev->host.domain, dev->host.bus, dev->host.slot,
- dev->host.function, ns);
- fprintf(stderr, "*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
- "pci-stub/bind\n",
- dev->host.domain, dev->host.bus, dev->host.slot,
- dev->host.function);
- fprintf(stderr, "*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub"
- "/remove_id\n", vendor_id, device_id);
- fprintf(stderr, "***\n");
+ error_report("*** The driver '%s' is occupying your device "
+ "%04x:%02x:%02x.%x.",
+ ns, dev->host.domain, dev->host.bus, dev->host.slot,
+ dev->host.function);
+ error_report("***");
+ error_report("*** You can try the following commands to free it:");
+ error_report("***");
+ error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/"
+ "new_id", vendor_id, device_id);
+ error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
+ "%s/unbind",
+ dev->host.domain, dev->host.bus, dev->host.slot,
+ dev->host.function, ns);
+ error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
+ "pci-stub/bind",
+ dev->host.domain, dev->host.bus, dev->host.slot,
+ dev->host.function);
+ error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub"
+ "/remove_id", vendor_id, device_id);
+ error_report("***");
return;
fail:
- fprintf(stderr, "Couldn't find out why.\n");
+ error_report("Couldn't find out why.");
}
static int assign_device(AssignedDevice *dev)
@@ -830,14 +823,14 @@ static int assign_device(AssignedDevice *dev)
/* Only pass non-zero PCI segment to capable module */
if (!kvm_check_extension(kvm_state, KVM_CAP_PCI_SEGMENT) &&
dev->host.domain) {
- fprintf(stderr, "Can't assign device inside non-zero PCI segment "
- "as this KVM module doesn't support it.\n");
+ error_report("Can't assign device inside non-zero PCI segment "
+ "as this KVM module doesn't support it.");
return -ENODEV;
}
if (!kvm_check_extension(kvm_state, KVM_CAP_IOMMU)) {
- fprintf(stderr, "No IOMMU found. Unable to assign device \"%s\"\n",
- dev->dev.qdev.id);
+ error_report("No IOMMU found. Unable to assign device \"%s\"",
+ dev->dev.qdev.id);
return -ENODEV;
}
@@ -848,8 +841,8 @@ static int assign_device(AssignedDevice *dev)
r = kvm_device_pci_assign(kvm_state, &dev->host, flags, &dev->dev_id);
if (r < 0) {
- fprintf(stderr, "Failed to assign device \"%s\" : %s\n",
- dev->dev.qdev.id, strerror(-r));
+ error_report("Failed to assign device \"%s\" : %s",
+ dev->dev.qdev.id, strerror(-r));
switch (r) {
case -EBUSY:
@@ -892,7 +885,7 @@ static int assign_intx(AssignedDevice *dev)
pci_device_set_intx_routing_notifier(&dev->dev,
assigned_dev_update_irq_routing);
- intx_route = pci_device_route_intx_to_irq(&dev->dev, 0);
+ intx_route = pci_device_route_intx_to_irq(&dev->dev, dev->intpin);
assert(intx_route.mode != PCI_INTX_INVERTED);
if (dev->intx_route.mode == intx_route.mode &&
@@ -917,7 +910,7 @@ static int assign_intx(AssignedDevice *dev)
break;
}
if (r) {
- perror("assign_intx: deassign");
+ perror("assign_intx: deassignment of previous interrupt failed");
}
dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
@@ -943,17 +936,16 @@ retry:
dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
/* Retry with host-side MSI. There might be an IRQ conflict and
* either the kernel or the device doesn't support sharing. */
- fprintf(stderr,
- "Host-side INTx sharing not supported, "
- "using MSI instead.\n"
- "Some devices do not to work properly in this mode.\n");
+ error_report("Host-side INTx sharing not supported, "
+ "using MSI instead.\n"
+ "Some devices do not to work properly in this mode.");
dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK;
goto retry;
}
- fprintf(stderr, "Failed to assign irq for \"%s\": %s\n",
- dev->dev.qdev.id, strerror(-r));
- fprintf(stderr, "Perhaps you are assigning a device "
- "that shares an IRQ with another device?\n");
+ error_report("Failed to assign irq for \"%s\": %s",
+ dev->dev.qdev.id, strerror(-r));
+ error_report("Perhaps you are assigning a device "
+ "that shares an IRQ with another device?");
return r;
}
@@ -967,10 +959,7 @@ static void deassign_device(AssignedDevice *dev)
int r;
r = kvm_device_pci_deassign(kvm_state, dev->dev_id);
- if (r < 0) {
- fprintf(stderr, "Failed to deassign device \"%s\" : %s\n",
- dev->dev.qdev.id, strerror(-r));
- }
+ assert(r == 0);
}
/* The pci config space got updated. Check if irq numbers have changed
@@ -1041,7 +1030,7 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev)
}
}
-static bool msix_masked(MSIXTableEntry *entry)
+static bool assigned_dev_msix_masked(MSIXTableEntry *entry)
{
return (entry->ctrl & cpu_to_le32(0x1)) != 0;
}
@@ -1056,7 +1045,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
/* Get the usable entry number for allocating */
for (i = 0; i < adev->msix_max; i++, entry++) {
- if (msix_masked(entry)) {
+ if (assigned_dev_msix_masked(entry)) {
continue;
}
entries_nr++;
@@ -1071,8 +1060,8 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
r = kvm_device_msix_init_vectors(kvm_state, adev->dev_id, entries_nr);
if (r != 0) {
- fprintf(stderr, "fail to set MSI-X entry number for MSIX! %s\n",
- strerror(-r));
+ error_report("fail to set MSI-X entry number for MSIX! %s",
+ strerror(-r));
return r;
}
@@ -1085,7 +1074,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
for (i = 0; i < adev->msix_max; i++, entry++) {
adev->msi_virq[i] = -1;
- if (msix_masked(entry)) {
+ if (assigned_dev_msix_masked(entry)) {
continue;
}
@@ -1103,7 +1092,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
r = kvm_device_msix_set_vector(kvm_state, adev->dev_id, i,
adev->msi_virq[i]);
if (r) {
- fprintf(stderr, "fail to set MSI-X entry! %s\n", strerror(-r));
+ error_report("fail to set MSI-X entry! %s", strerror(-r));
break;
}
}
@@ -1350,15 +1339,13 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev)
*/
size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos);
if (size < 0x34) {
- fprintf(stderr,
- "%s: Invalid size PCIe cap-id 0x%x\n",
- __func__, PCI_CAP_ID_EXP);
+ error_report("%s: Invalid size PCIe cap-id 0x%x",
+ __func__, PCI_CAP_ID_EXP);
return -EINVAL;
} else if (size != 0x3c) {
- fprintf(stderr,
- "WARNING, %s: PCIe cap-id 0x%x has "
- "non-standard size 0x%x; std size should be 0x3c\n",
- __func__, PCI_CAP_ID_EXP, size);
+ error_report("WARNING, %s: PCIe cap-id 0x%x has "
+ "non-standard size 0x%x; std size should be 0x3c",
+ __func__, PCI_CAP_ID_EXP, size);
}
} else if (version == 0) {
uint16_t vid, did;
@@ -1374,9 +1361,8 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev)
}
if (size == 0) {
- fprintf(stderr,
- "%s: Unsupported PCI express capability version %d\n",
- __func__, version);
+ error_report("%s: Unsupported PCI express capability version %d",
+ __func__, version);
return -EINVAL;
}
@@ -1391,9 +1377,8 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev)
type = (type & PCI_EXP_FLAGS_TYPE) >> 4;
if (type != PCI_EXP_TYPE_ENDPOINT &&
type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) {
- fprintf(stderr,
- "Device assignment only supports endpoint assignment, "
- "device type %d\n", type);
+ error_report("Device assignment only supports endpoint assignment,"
+ " device type %d", type);
return -EINVAL;
}
@@ -1519,8 +1504,9 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev)
return 0;
}
-static uint64_t msix_mmio_read(void *opaque, target_phys_addr_t addr,
- unsigned size)
+static uint64_t
+assigned_dev_msix_mmio_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
AssignedDevice *adev = opaque;
uint64_t val;
@@ -1530,8 +1516,8 @@ static uint64_t msix_mmio_read(void *opaque, target_phys_addr_t addr,
return val;
}
-static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
- uint64_t val, unsigned size)
+static void assigned_dev_msix_mmio_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
AssignedDevice *adev = opaque;
PCIDevice *pdev = &adev->dev;
@@ -1551,12 +1537,13 @@ static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
orig = adev->msix_table[i];
}
- memcpy((void *)((uint8_t *)adev->msix_table + addr), &val, size);
+ memcpy((uint8_t *)adev->msix_table + addr, &val, size);
if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
MSIXTableEntry *entry = &adev->msix_table[i];
- if (!msix_masked(&orig) && msix_masked(entry)) {
+ if (!assigned_dev_msix_masked(&orig) &&
+ assigned_dev_msix_masked(entry)) {
/*
* Vector masked, disable it
*
@@ -1568,7 +1555,8 @@ static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
* are lost. Can we get away with always injecting an
* interrupt on unmask?
*/
- } else if (msix_masked(&orig) && !msix_masked(entry)) {
+ } else if (assigned_dev_msix_masked(&orig) &&
+ !assigned_dev_msix_masked(entry)) {
/* Vector unmasked */
if (i >= adev->msi_virq_nr || adev->msi_virq[i] < 0) {
/* Previously unassigned vector, start from scratch */
@@ -1586,17 +1574,16 @@ static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
ret = kvm_irqchip_update_msi_route(kvm_state,
adev->msi_virq[i], msg);
if (ret) {
- fprintf(stderr,
- "Error updating irq routing entry (%d)\n", ret);
+ error_report("Error updating irq routing entry (%d)", ret);
}
}
}
}
}
-static const MemoryRegionOps msix_mmio_ops = {
- .read = msix_mmio_read,
- .write = msix_mmio_write,
+static const MemoryRegionOps assigned_dev_msix_mmio_ops = {
+ .read = assigned_dev_msix_mmio_read,
+ .write = assigned_dev_msix_mmio_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = {
.min_access_size = 4,
@@ -1608,7 +1595,7 @@ static const MemoryRegionOps msix_mmio_ops = {
},
};
-static void msix_reset(AssignedDevice *dev)
+static void assigned_dev_msix_reset(AssignedDevice *dev)
{
MSIXTableEntry *entry;
int i;
@@ -1629,13 +1616,13 @@ static int assigned_dev_register_msix_mmio(AssignedDevice *dev)
dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
if (dev->msix_table == MAP_FAILED) {
- fprintf(stderr, "fail allocate msix_table! %s\n", strerror(errno));
+ error_report("fail allocate msix_table! %s", strerror(errno));
return -EFAULT;
}
- msix_reset(dev);
+ assigned_dev_msix_reset(dev);
- memory_region_init_io(&dev->mmio, &msix_mmio_ops, dev,
+ memory_region_init_io(&dev->mmio, &assigned_dev_msix_mmio_ops, dev,
"assigned-dev-msix", MSIX_PAGE_SIZE);
return 0;
}
@@ -1649,8 +1636,7 @@ static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev)
memory_region_destroy(&dev->mmio);
if (munmap(dev->msix_table, MSIX_PAGE_SIZE) == -1) {
- fprintf(stderr, "error unmapping msix_table! %s\n",
- strerror(errno));
+ error_report("error unmapping msix_table! %s", strerror(errno));
}
dev->msix_table = NULL;
}
@@ -1779,7 +1765,7 @@ static int assigned_initfn(struct PCIDevice *pci_dev)
}
/* handle interrupt routing */
- e_intx = dev->dev.config[0x3d] - 1;
+ e_intx = dev->dev.config[PCI_INTERRUPT_PIN] - 1;
dev->intpin = e_intx;
dev->intx_route.mode = PCI_INTX_DISABLED;
dev->intx_route.irq = -1;
@@ -1817,7 +1803,7 @@ static void assigned_exitfn(struct PCIDevice *pci_dev)
free_assigned_device(dev);
}
-static Property da_properties[] = {
+static Property assigned_dev_properties[] = {
DEFINE_PROP_PCI_HOST_DEVADDR("host", AssignedDevice, host),
DEFINE_PROP_BIT("prefer_msi", AssignedDevice, features,
ASSIGNED_DEVICE_PREFER_MSI_BIT, false),
@@ -1837,13 +1823,14 @@ static void assign_class_init(ObjectClass *klass, void *data)
k->exit = assigned_exitfn;
k->config_read = assigned_dev_pci_read_config;
k->config_write = assigned_dev_pci_write_config;
- dc->props = da_properties;
+ dc->props = assigned_dev_properties;
dc->vmsd = &vmstate_assigned_device;
dc->reset = reset_assigned_device;
+ dc->desc = "KVM-based PCI passthrough";
}
-static TypeInfo assign_info = {
- .name = "pci-assign",
+static const TypeInfo assign_info = {
+ .name = "kvm-pci-assign",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(AssignedDevice),
.class_init = assign_class_init,
@@ -1884,8 +1871,7 @@ static void assigned_dev_load_option_rom(AssignedDevice *dev)
}
if (access(rom_file, F_OK)) {
- fprintf(stderr, "pci-assign: Insufficient privileges for %s\n",
- rom_file);
+ error_report("pci-assign: Insufficient privileges for %s", rom_file);
return;
}
@@ -1908,10 +1894,10 @@ static void assigned_dev_load_option_rom(AssignedDevice *dev)
memset(ptr, 0xff, st.st_size);
if (!fread(ptr, 1, st.st_size, fp)) {
- fprintf(stderr, "pci-assign: Cannot read from host %s\n"
- "\tDevice option ROM contents are probably invalid "
- "(check dmesg).\n\tSkip option ROM probe with rombar=0, "
- "or load from file with romfile=\n", rom_file);
+ error_report("pci-assign: Cannot read from host %s\n"
+ "\tDevice option ROM contents are probably invalid "
+ "(check dmesg).\n\tSkip option ROM probe with rombar=0, "
+ "or load from file with romfile=", rom_file);
memory_region_destroy(&dev->dev.rom);
goto close_rom;
}
diff --git a/hw/lan9118.c b/hw/lan9118.c
index ff0a50be1..ceaf96fc3 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -500,7 +500,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
}
} else {
/* Hash matching */
- hash = (crc32(~0, addr, 6) >> 26);
+ hash = compute_mcast_idx(addr);
if (hash & 0x20) {
return (s->mac_hashh >> (hash & 0x1f)) & 1;
} else {
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 3777f858a..d63554f89 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -45,36 +45,65 @@
# define DPRINTF_C(format, ...) do { } while (0)
#endif
+#define NSEC_PER_SEC 1000000000LL
+#define SEC_PER_MIN 60
+#define MIN_PER_HOUR 60
+#define SEC_PER_HOUR 3600
+#define HOUR_PER_DAY 24
+#define SEC_PER_DAY 86400
+
#define RTC_REINJECT_ON_ACK_COUNT 20
+#define RTC_CLOCK_RATE 32768
+#define UIP_HOLD_LENGTH (8 * NSEC_PER_SEC / 32768)
typedef struct RTCState {
ISADevice dev;
MemoryRegion io;
uint8_t cmos_data[128];
uint8_t cmos_index;
- struct tm current_tm;
int32_t base_year;
+ uint64_t base_rtc;
+ uint64_t last_update;
+ int64_t offset;
qemu_irq irq;
qemu_irq sqw_irq;
int it_shift;
/* periodic timer */
QEMUTimer *periodic_timer;
int64_t next_periodic_time;
- /* second update */
- int64_t next_second_time;
+ /* update-ended timer */
+ QEMUTimer *update_timer;
+ uint64_t next_alarm_time;
uint16_t irq_reinject_on_ack_count;
uint32_t irq_coalesced;
uint32_t period;
QEMUTimer *coalesced_timer;
- QEMUTimer *second_timer;
- QEMUTimer *second_timer2;
Notifier clock_reset_notifier;
LostTickPolicy lost_tick_policy;
Notifier suspend_notifier;
} RTCState;
static void rtc_set_time(RTCState *s);
-static void rtc_copy_date(RTCState *s);
+static void rtc_update_time(RTCState *s);
+static void rtc_set_cmos(RTCState *s, const struct tm *tm);
+static inline int rtc_from_bcd(RTCState *s, int a);
+static uint64_t get_next_alarm(RTCState *s);
+
+static inline bool rtc_running(RTCState *s)
+{
+ return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) &&
+ (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20);
+}
+
+static uint64_t get_guest_rtc_ns(RTCState *s)
+{
+ uint64_t guest_rtc;
+ uint64_t guest_clock = qemu_get_clock_ns(rtc_clock);
+
+ guest_rtc = s->base_rtc * NSEC_PER_SEC
+ + guest_clock - s->last_update + s->offset;
+ return guest_rtc;
+}
#ifdef TARGET_I386
static void rtc_coalesced_timer_update(RTCState *s)
@@ -85,7 +114,7 @@ static void rtc_coalesced_timer_update(RTCState *s)
/* divide each RTC interval to 2 - 8 smaller intervals */
int c = MIN(s->irq_coalesced, 7) + 1;
int64_t next_clock = qemu_get_clock_ns(rtc_clock) +
- muldiv64(s->period / c, get_ticks_per_sec(), 32768);
+ muldiv64(s->period / c, get_ticks_per_sec(), RTC_CLOCK_RATE);
qemu_mod_timer(s->coalesced_timer, next_clock);
}
}
@@ -110,7 +139,8 @@ static void rtc_coalesced_timer(void *opaque)
}
#endif
-static void rtc_timer_update(RTCState *s, int64_t current_time)
+/* handle periodic timer */
+static void periodic_timer_update(RTCState *s, int64_t current_time)
{
int period_code, period;
int64_t cur_clock, next_irq_clock;
@@ -131,10 +161,10 @@ static void rtc_timer_update(RTCState *s, int64_t current_time)
s->period = period;
#endif
/* compute 32 khz clock */
- cur_clock = muldiv64(current_time, 32768, get_ticks_per_sec());
+ cur_clock = muldiv64(current_time, RTC_CLOCK_RATE, get_ticks_per_sec());
next_irq_clock = (cur_clock & ~(period - 1)) + period;
s->next_periodic_time =
- muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1;
+ muldiv64(next_irq_clock, get_ticks_per_sec(), RTC_CLOCK_RATE) + 1;
qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
} else {
#ifdef TARGET_I386
@@ -148,7 +178,7 @@ static void rtc_periodic_timer(void *opaque)
{
RTCState *s = opaque;
- rtc_timer_update(s, s->next_periodic_time);
+ periodic_timer_update(s, s->next_periodic_time);
s->cmos_data[RTC_REG_C] |= REG_C_PF;
if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
@@ -175,6 +205,184 @@ static void rtc_periodic_timer(void *opaque)
}
}
+/* handle update-ended timer */
+static void check_update_timer(RTCState *s)
+{
+ uint64_t next_update_time;
+ uint64_t guest_nsec;
+ int next_alarm_sec;
+
+ /* From the data sheet: "Holding the dividers in reset prevents
+ * interrupts from operating, while setting the SET bit allows"
+ * them to occur. However, it will prevent an alarm interrupt
+ * from occurring, because the time of day is not updated.
+ */
+ if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) {
+ qemu_del_timer(s->update_timer);
+ return;
+ }
+ if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
+ (s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+ qemu_del_timer(s->update_timer);
+ return;
+ }
+ if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
+ (s->cmos_data[RTC_REG_C] & REG_C_AF)) {
+ qemu_del_timer(s->update_timer);
+ return;
+ }
+
+ guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC;
+ /* if UF is clear, reprogram to next second */
+ next_update_time = qemu_get_clock_ns(rtc_clock)
+ + NSEC_PER_SEC - guest_nsec;
+
+ /* Compute time of next alarm. One second is already accounted
+ * for in next_update_time.
+ */
+ next_alarm_sec = get_next_alarm(s);
+ s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NSEC_PER_SEC;
+
+ if (s->cmos_data[RTC_REG_C] & REG_C_UF) {
+ /* UF is set, but AF is clear. Program the timer to target
+ * the alarm time. */
+ next_update_time = s->next_alarm_time;
+ }
+ if (next_update_time != qemu_timer_expire_time_ns(s->update_timer)) {
+ qemu_mod_timer(s->update_timer, next_update_time);
+ }
+}
+
+static inline uint8_t convert_hour(RTCState *s, uint8_t hour)
+{
+ if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) {
+ hour %= 12;
+ if (s->cmos_data[RTC_HOURS] & 0x80) {
+ hour += 12;
+ }
+ }
+ return hour;
+}
+
+static uint64_t get_next_alarm(RTCState *s)
+{
+ int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec;
+ int32_t hour, min, sec;
+
+ rtc_update_time(s);
+
+ alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]);
+ alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]);
+ alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]);
+ alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour);
+
+ cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
+ cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
+ cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]);
+ cur_hour = convert_hour(s, cur_hour);
+
+ if (alarm_hour == -1) {
+ alarm_hour = cur_hour;
+ if (alarm_min == -1) {
+ alarm_min = cur_min;
+ if (alarm_sec == -1) {
+ alarm_sec = cur_sec + 1;
+ } else if (cur_sec > alarm_sec) {
+ alarm_min++;
+ }
+ } else if (cur_min == alarm_min) {
+ if (alarm_sec == -1) {
+ alarm_sec = cur_sec + 1;
+ } else {
+ if (cur_sec > alarm_sec) {
+ alarm_hour++;
+ }
+ }
+ if (alarm_sec == SEC_PER_MIN) {
+ /* wrap to next hour, minutes is not in don't care mode */
+ alarm_sec = 0;
+ alarm_hour++;
+ }
+ } else if (cur_min > alarm_min) {
+ alarm_hour++;
+ }
+ } else if (cur_hour == alarm_hour) {
+ if (alarm_min == -1) {
+ alarm_min = cur_min;
+ if (alarm_sec == -1) {
+ alarm_sec = cur_sec + 1;
+ } else if (cur_sec > alarm_sec) {
+ alarm_min++;
+ }
+
+ if (alarm_sec == SEC_PER_MIN) {
+ alarm_sec = 0;
+ alarm_min++;
+ }
+ /* wrap to next day, hour is not in don't care mode */
+ alarm_min %= MIN_PER_HOUR;
+ } else if (cur_min == alarm_min) {
+ if (alarm_sec == -1) {
+ alarm_sec = cur_sec + 1;
+ }
+ /* wrap to next day, hours+minutes not in don't care mode */
+ alarm_sec %= SEC_PER_MIN;
+ }
+ }
+
+ /* values that are still don't care fire at the next min/sec */
+ if (alarm_min == -1) {
+ alarm_min = 0;
+ }
+ if (alarm_sec == -1) {
+ alarm_sec = 0;
+ }
+
+ /* keep values in range */
+ if (alarm_sec == SEC_PER_MIN) {
+ alarm_sec = 0;
+ alarm_min++;
+ }
+ if (alarm_min == MIN_PER_HOUR) {
+ alarm_min = 0;
+ alarm_hour++;
+ }
+ alarm_hour %= HOUR_PER_DAY;
+
+ hour = alarm_hour - cur_hour;
+ min = hour * MIN_PER_HOUR + alarm_min - cur_min;
+ sec = min * SEC_PER_MIN + alarm_sec - cur_sec;
+ return sec <= 0 ? sec + SEC_PER_DAY : sec;
+}
+
+static void rtc_update_timer(void *opaque)
+{
+ RTCState *s = opaque;
+ int32_t irqs = REG_C_UF;
+ int32_t new_irqs;
+
+ assert((s->cmos_data[RTC_REG_A] & 0x60) != 0x60);
+
+ /* UIP might have been latched, update time and clear it. */
+ rtc_update_time(s);
+ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+
+ if (qemu_get_clock_ns(rtc_clock) >= s->next_alarm_time) {
+ irqs |= REG_C_AF;
+ if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC);
+ }
+ }
+
+ new_irqs = irqs & ~s->cmos_data[RTC_REG_C];
+ s->cmos_data[RTC_REG_C] |= irqs;
+ if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) {
+ s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+ qemu_irq_raise(s->irq);
+ }
+ check_update_timer(s);
+}
+
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
{
RTCState *s = opaque;
@@ -189,6 +397,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
case RTC_MINUTES_ALARM:
case RTC_HOURS_ALARM:
s->cmos_data[s->cmos_index] = data;
+ check_update_timer(s);
break;
case RTC_SECONDS:
case RTC_MINUTES:
@@ -199,37 +408,66 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
case RTC_YEAR:
s->cmos_data[s->cmos_index] = data;
/* if in set mode, do not update the time */
- if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+ if (rtc_running(s)) {
rtc_set_time(s);
+ check_update_timer(s);
}
break;
case RTC_REG_A:
+ if ((data & 0x60) == 0x60) {
+ if (rtc_running(s)) {
+ rtc_update_time(s);
+ }
+ /* What happens to UIP when divider reset is enabled is
+ * unclear from the datasheet. Shouldn't matter much
+ * though.
+ */
+ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+ } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) &&
+ (data & 0x70) <= 0x20) {
+ /* when the divider reset is removed, the first update cycle
+ * begins one-half second later*/
+ if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+ s->offset = 500000000;
+ rtc_set_time(s);
+ }
+ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+ }
/* UIP bit is read only */
s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
(s->cmos_data[RTC_REG_A] & REG_A_UIP);
- rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
+ periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
+ check_update_timer(s);
break;
case RTC_REG_B:
if (data & REG_B_SET) {
+ /* update cmos to when the rtc was stopping */
+ if (rtc_running(s)) {
+ rtc_update_time(s);
+ }
/* set mode: reset UIP mode */
s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
data &= ~REG_B_UIE;
} else {
/* if disabling set mode, update the time */
- if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
+ if ((s->cmos_data[RTC_REG_B] & REG_B_SET) &&
+ (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) {
+ s->offset = get_guest_rtc_ns(s) % NSEC_PER_SEC;
rtc_set_time(s);
}
}
- if (((s->cmos_data[RTC_REG_B] ^ data) & (REG_B_DM | REG_B_24H)) &&
- !(data & REG_B_SET)) {
- /* If the time format has changed and not in set mode,
- update the registers immediately. */
- s->cmos_data[RTC_REG_B] = data;
- rtc_copy_date(s);
+ /* if an interrupt flag is already set when the interrupt
+ * becomes enabled, raise an interrupt immediately. */
+ if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) {
+ s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+ qemu_irq_raise(s->irq);
} else {
- s->cmos_data[RTC_REG_B] = data;
+ s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF;
+ qemu_irq_lower(s->irq);
}
- rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
+ s->cmos_data[RTC_REG_B] = data;
+ periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
+ check_update_timer(s);
break;
case RTC_REG_C:
case RTC_REG_D:
@@ -253,6 +491,9 @@ static inline int rtc_to_bcd(RTCState *s, int a)
static inline int rtc_from_bcd(RTCState *s, int a)
{
+ if ((a & 0xc0) == 0xc0) {
+ return -1;
+ }
if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
return a;
} else {
@@ -260,10 +501,8 @@ static inline int rtc_from_bcd(RTCState *s, int a)
}
}
-static void rtc_set_time(RTCState *s)
+static void rtc_get_time(RTCState *s, struct tm *tm)
{
- struct tm *tm = &s->current_tm;
-
tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
@@ -277,13 +516,21 @@ static void rtc_set_time(RTCState *s)
tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
+}
+
+static void rtc_set_time(RTCState *s)
+{
+ struct tm tm;
- rtc_change_mon_event(tm);
+ rtc_get_time(s, &tm);
+ s->base_rtc = mktimegm(&tm);
+ s->last_update = qemu_get_clock_ns(rtc_clock);
+
+ rtc_change_mon_event(&tm);
}
-static void rtc_copy_date(RTCState *s)
+static void rtc_set_cmos(RTCState *s, const struct tm *tm)
{
- const struct tm *tm = &s->current_tm;
int year;
s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
@@ -307,122 +554,40 @@ static void rtc_copy_date(RTCState *s)
s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year);
}
-/* month is between 0 and 11. */
-static int get_days_in_month(int month, int year)
-{
- static const int days_tab[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- int d;
- if ((unsigned )month >= 12)
- return 31;
- d = days_tab[month];
- if (month == 1) {
- if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
- d++;
- }
- return d;
-}
-
-/* update 'tm' to the next second */
-static void rtc_next_second(struct tm *tm)
-{
- int days_in_month;
-
- tm->tm_sec++;
- if ((unsigned)tm->tm_sec >= 60) {
- tm->tm_sec = 0;
- tm->tm_min++;
- if ((unsigned)tm->tm_min >= 60) {
- tm->tm_min = 0;
- tm->tm_hour++;
- if ((unsigned)tm->tm_hour >= 24) {
- tm->tm_hour = 0;
- /* next day */
- tm->tm_wday++;
- if ((unsigned)tm->tm_wday >= 7)
- tm->tm_wday = 0;
- days_in_month = get_days_in_month(tm->tm_mon,
- tm->tm_year + 1900);
- tm->tm_mday++;
- if (tm->tm_mday < 1) {
- tm->tm_mday = 1;
- } else if (tm->tm_mday > days_in_month) {
- tm->tm_mday = 1;
- tm->tm_mon++;
- if (tm->tm_mon >= 12) {
- tm->tm_mon = 0;
- tm->tm_year++;
- }
- }
- }
- }
- }
-}
-
-
-static void rtc_update_second(void *opaque)
+static void rtc_update_time(RTCState *s)
{
- RTCState *s = opaque;
- int64_t delay;
-
- /* if the oscillator is not in normal operation, we do not update */
- if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
- s->next_second_time += get_ticks_per_sec();
- qemu_mod_timer(s->second_timer, s->next_second_time);
- } else {
- rtc_next_second(&s->current_tm);
-
- if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
- /* update in progress bit */
- s->cmos_data[RTC_REG_A] |= REG_A_UIP;
- }
- /* should be 244 us = 8 / 32768 seconds, but currently the
- timers do not have the necessary resolution. */
- delay = (get_ticks_per_sec() * 1) / 100;
- if (delay < 1)
- delay = 1;
- qemu_mod_timer(s->second_timer2,
- s->next_second_time + delay);
- }
+ struct tm ret;
+ time_t guest_sec;
+ int64_t guest_nsec;
+
+ guest_nsec = get_guest_rtc_ns(s);
+ guest_sec = guest_nsec / NSEC_PER_SEC;
+ gmtime_r(&guest_sec, &ret);
+ rtc_set_cmos(s, &ret);
}
-static void rtc_update_second2(void *opaque)
+static int update_in_progress(RTCState *s)
{
- RTCState *s = opaque;
+ int64_t guest_nsec;
- if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
- rtc_copy_date(s);
+ if (!rtc_running(s)) {
+ return 0;
}
-
- /* check alarm */
- if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
- rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) &&
- ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
- rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) &&
- ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
- rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) {
-
- s->cmos_data[RTC_REG_C] |= REG_C_AF;
- if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC);
- qemu_irq_raise(s->irq);
- s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+ if (qemu_timer_pending(s->update_timer)) {
+ int64_t next_update_time = qemu_timer_expire_time_ns(s->update_timer);
+ /* Latch UIP until the timer expires. */
+ if (qemu_get_clock_ns(rtc_clock) >= (next_update_time - UIP_HOLD_LENGTH)) {
+ s->cmos_data[RTC_REG_A] |= REG_A_UIP;
+ return 1;
}
}
- /* update ended interrupt */
- s->cmos_data[RTC_REG_C] |= REG_C_UF;
- if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
- s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
- qemu_irq_raise(s->irq);
+ guest_nsec = get_guest_rtc_ns(s);
+ /* UIP bit will be set at last 244us of every second. */
+ if ((guest_nsec % NSEC_PER_SEC) >= (NSEC_PER_SEC - UIP_HOLD_LENGTH)) {
+ return 1;
}
-
- /* clear update in progress bit */
- s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
-
- s->next_second_time += get_ticks_per_sec();
- qemu_mod_timer(s->second_timer, s->next_second_time);
+ return 0;
}
static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
@@ -440,15 +605,28 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
case RTC_DAY_OF_MONTH:
case RTC_MONTH:
case RTC_YEAR:
+ /* if not in set mode, calibrate cmos before
+ * reading*/
+ if (rtc_running(s)) {
+ rtc_update_time(s);
+ }
ret = s->cmos_data[s->cmos_index];
break;
case RTC_REG_A:
+ if (update_in_progress(s)) {
+ s->cmos_data[s->cmos_index] |= REG_A_UIP;
+ } else {
+ s->cmos_data[s->cmos_index] &= ~REG_A_UIP;
+ }
ret = s->cmos_data[s->cmos_index];
break;
case RTC_REG_C:
ret = s->cmos_data[s->cmos_index];
qemu_irq_lower(s->irq);
s->cmos_data[RTC_REG_C] = 0x00;
+ if (ret & (REG_C_UF | REG_C_AF)) {
+ check_update_timer(s);
+ }
#ifdef TARGET_I386
if(s->irq_coalesced &&
(s->cmos_data[RTC_REG_B] & REG_B_PIE) &&
@@ -483,13 +661,6 @@ void rtc_set_memory(ISADevice *dev, int addr, int val)
s->cmos_data[addr] = val;
}
-void rtc_set_date(ISADevice *dev, const struct tm *tm)
-{
- RTCState *s = DO_UPCAST(RTCState, dev, dev);
- s->current_tm = *tm;
- rtc_copy_date(s);
-}
-
/* PC cmos mappings */
#define REG_IBM_CENTURY_BYTE 0x32
#define REG_IBM_PS2_CENTURY_BYTE 0x37
@@ -500,9 +671,14 @@ static void rtc_set_date_from_host(ISADevice *dev)
struct tm tm;
int val;
- /* set the CMOS date */
qemu_get_timedate(&tm, 0);
- rtc_set_date(dev, &tm);
+
+ s->base_rtc = mktimegm(&tm);
+ s->last_update = qemu_get_clock_ns(rtc_clock);
+ s->offset = 0;
+
+ /* set the CMOS date */
+ rtc_set_cmos(s, &tm);
val = rtc_to_bcd(s, (tm.tm_year / 100) + 19);
rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val);
@@ -511,9 +687,15 @@ static void rtc_set_date_from_host(ISADevice *dev)
static int rtc_post_load(void *opaque, int version_id)
{
-#ifdef TARGET_I386
RTCState *s = opaque;
+ if (version_id <= 2) {
+ rtc_set_time(s);
+ s->offset = 0;
+ check_update_timer(s);
+ }
+
+#ifdef TARGET_I386
if (version_id >= 2) {
if (s->lost_tick_policy == LOST_TICK_SLEW) {
rtc_coalesced_timer_update(s);
@@ -525,27 +707,24 @@ static int rtc_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_rtc = {
.name = "mc146818rtc",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = rtc_post_load,
.fields = (VMStateField []) {
VMSTATE_BUFFER(cmos_data, RTCState),
VMSTATE_UINT8(cmos_index, RTCState),
- VMSTATE_INT32(current_tm.tm_sec, RTCState),
- VMSTATE_INT32(current_tm.tm_min, RTCState),
- VMSTATE_INT32(current_tm.tm_hour, RTCState),
- VMSTATE_INT32(current_tm.tm_wday, RTCState),
- VMSTATE_INT32(current_tm.tm_mday, RTCState),
- VMSTATE_INT32(current_tm.tm_mon, RTCState),
- VMSTATE_INT32(current_tm.tm_year, RTCState),
+ VMSTATE_UNUSED(7*4),
VMSTATE_TIMER(periodic_timer, RTCState),
VMSTATE_INT64(next_periodic_time, RTCState),
- VMSTATE_INT64(next_second_time, RTCState),
- VMSTATE_TIMER(second_timer, RTCState),
- VMSTATE_TIMER(second_timer2, RTCState),
+ VMSTATE_UNUSED(3*8),
VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
VMSTATE_UINT32_V(period, RTCState, 2),
+ VMSTATE_UINT64_V(base_rtc, RTCState, 3),
+ VMSTATE_UINT64_V(last_update, RTCState, 3),
+ VMSTATE_INT64_V(offset, RTCState, 3),
+ VMSTATE_TIMER_V(update_timer, RTCState, 3),
+ VMSTATE_UINT64_V(next_alarm_time, RTCState, 3),
VMSTATE_END_OF_LIST()
}
};
@@ -556,9 +735,8 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data)
int64_t now = *(int64_t *)data;
rtc_set_date_from_host(&s->dev);
- s->next_second_time = now + (get_ticks_per_sec() * 99) / 100;
- qemu_mod_timer(s->second_timer2, s->next_second_time);
- rtc_timer_update(s, now);
+ periodic_timer_update(s, now);
+ check_update_timer(s);
#ifdef TARGET_I386
if (s->lost_tick_policy == LOST_TICK_SLEW) {
rtc_coalesced_timer_update(s);
@@ -580,6 +758,7 @@ static void rtc_reset(void *opaque)
s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
+ check_update_timer(s);
qemu_irq_lower(s->irq);
@@ -604,14 +783,17 @@ static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
{
ISADevice *isa = ISA_DEVICE(obj);
RTCState *s = DO_UPCAST(RTCState, dev, isa);
+ struct tm current_tm;
+ rtc_update_time(s);
+ rtc_get_time(s, &current_tm);
visit_start_struct(v, NULL, "struct tm", name, 0, errp);
- visit_type_int32(v, &s->current_tm.tm_year, "tm_year", errp);
- visit_type_int32(v, &s->current_tm.tm_mon, "tm_mon", errp);
- visit_type_int32(v, &s->current_tm.tm_mday, "tm_mday", errp);
- visit_type_int32(v, &s->current_tm.tm_hour, "tm_hour", errp);
- visit_type_int32(v, &s->current_tm.tm_min, "tm_min", errp);
- visit_type_int32(v, &s->current_tm.tm_sec, "tm_sec", errp);
+ visit_type_int32(v, &current_tm.tm_year, "tm_year", errp);
+ visit_type_int32(v, &current_tm.tm_mon, "tm_mon", errp);
+ visit_type_int32(v, &current_tm.tm_mday, "tm_mday", errp);
+ visit_type_int32(v, &current_tm.tm_hour, "tm_hour", errp);
+ visit_type_int32(v, &current_tm.tm_min, "tm_min", errp);
+ visit_type_int32(v, &current_tm.tm_sec, "tm_sec", errp);
visit_end_struct(v, errp);
}
@@ -641,8 +823,8 @@ static int rtc_initfn(ISADevice *dev)
#endif
s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
- s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
- s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
+ s->update_timer = qemu_new_timer_ns(rtc_clock, rtc_update_timer, s);
+ check_update_timer(s);
s->clock_reset_notifier.notify = rtc_notify_clock_reset;
qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
@@ -650,14 +832,10 @@ static int rtc_initfn(ISADevice *dev)
s->suspend_notifier.notify = rtc_notify_suspend;
qemu_register_suspend_notifier(&s->suspend_notifier);
- s->next_second_time =
- qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
- qemu_mod_timer(s->second_timer2, s->next_second_time);
-
memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2);
isa_register_ioport(dev, &s->io, base);
- qdev_set_legacy_instance_id(&dev->qdev, base, 2);
+ qdev_set_legacy_instance_id(&dev->qdev, base, 3);
qemu_register_reset(rtc_reset, s);
object_property_add(OBJECT(s), "date", "struct tm",
diff --git a/hw/mc146818rtc_regs.h b/hw/mc146818rtc_regs.h
index 3ab37709f..fc10076ec 100644
--- a/hw/mc146818rtc_regs.h
+++ b/hw/mc146818rtc_regs.h
@@ -58,5 +58,6 @@
#define REG_C_IRQF 0x80
#define REG_C_PF 0x40
#define REG_C_AF 0x20
+#define REG_C_MASK 0x70
#endif
diff --git a/hw/mcf5206.c b/hw/mcf5206.c
index 539b39133..27753e271 100644
--- a/hw/mcf5206.c
+++ b/hw/mcf5206.c
@@ -378,7 +378,7 @@ static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
{
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
offset &= 0x3ff;
- if (offset > 0x200) {
+ if (offset >= 0x200) {
hw_error("Bad MBAR read offset 0x%x", (int)offset);
}
if (m5206_mbar_width[offset >> 2] > 1) {
@@ -397,7 +397,7 @@ static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
int width;
offset &= 0x3ff;
- if (offset > 0x200) {
+ if (offset >= 0x200) {
hw_error("Bad MBAR read offset 0x%x", (int)offset);
}
width = m5206_mbar_width[offset >> 2];
@@ -421,7 +421,7 @@ static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
int width;
offset &= 0x3ff;
- if (offset > 0x200) {
+ if (offset >= 0x200) {
hw_error("Bad MBAR read offset 0x%x", (int)offset);
}
width = m5206_mbar_width[offset >> 2];
@@ -445,7 +445,7 @@ static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
int width;
offset &= 0x3ff;
- if (offset > 0x200) {
+ if (offset >= 0x200) {
hw_error("Bad MBAR write offset 0x%x", (int)offset);
}
width = m5206_mbar_width[offset >> 2];
@@ -469,7 +469,7 @@ static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
int width;
offset &= 0x3ff;
- if (offset > 0x200) {
+ if (offset >= 0x200) {
hw_error("Bad MBAR write offset 0x%x", (int)offset);
}
width = m5206_mbar_width[offset >> 2];
@@ -497,7 +497,7 @@ static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
int width;
offset &= 0x3ff;
- if (offset > 0x200) {
+ if (offset >= 0x200) {
hw_error("Bad MBAR write offset 0x%x", (int)offset);
}
width = m5206_mbar_width[offset >> 2];
diff --git a/hw/musicpal.c b/hw/musicpal.c
index ad725b559..f305e2103 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -1583,7 +1583,7 @@ static void musicpal_init(ram_addr_t ram_size,
* image is smaller than 32 MB.
*/
#ifdef TARGET_WORDS_BIGENDIAN
- pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
+ pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
"musicpal.flash", flash_size,
dinfo->bdrv, 0x10000,
(flash_size + 0xffff) >> 16,
@@ -1591,7 +1591,7 @@ static void musicpal_init(ram_addr_t ram_size,
2, 0x00BF, 0x236D, 0x0000, 0x0000,
0x5555, 0x2AAA, 1);
#else
- pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
+ pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
"musicpal.flash", flash_size,
dinfo->bdrv, 0x10000,
(flash_size + 0xffff) >> 16,
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
index 4a08e9d00..e2ba10834 100644
--- a/hw/omap_lcdc.c
+++ b/hw/omap_lcdc.c
@@ -224,18 +224,24 @@ static void omap_update_display(void *opaque)
omap_lcd->invalidate = 0;
}
-static int ppm_save(const char *filename, uint8_t *data,
- int w, int h, int linesize)
+static void omap_ppm_save(const char *filename, uint8_t *data,
+ int w, int h, int linesize, Error **errp)
{
FILE *f;
uint8_t *d, *d1;
unsigned int v;
- int y, x, bpp;
+ int ret, y, x, bpp;
f = fopen(filename, "wb");
- if (!f)
- return -1;
- fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
+ if (!f) {
+ error_setg(errp, "failed to open file '%s': %s", filename,
+ strerror(errno));
+ return;
+ }
+ ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
+ if (ret < 0) {
+ goto write_err;
+ }
d1 = data;
bpp = linesize / w;
for (y = 0; y < h; y ++) {
@@ -244,35 +250,61 @@ static int ppm_save(const char *filename, uint8_t *data,
v = *(uint32_t *) d;
switch (bpp) {
case 2:
- fputc((v >> 8) & 0xf8, f);
- fputc((v >> 3) & 0xfc, f);
- fputc((v << 3) & 0xf8, f);
+ ret = fputc((v >> 8) & 0xf8, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc((v >> 3) & 0xfc, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc((v << 3) & 0xf8, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
break;
case 3:
case 4:
default:
- fputc((v >> 16) & 0xff, f);
- fputc((v >> 8) & 0xff, f);
- fputc((v) & 0xff, f);
+ ret = fputc((v >> 16) & 0xff, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc((v >> 8) & 0xff, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc((v) & 0xff, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
break;
}
d += bpp;
}
d1 += linesize;
}
+out:
fclose(f);
- return 0;
+ return;
+
+write_err:
+ error_setg(errp, "failed to write to file '%s': %s", filename,
+ strerror(errno));
+ unlink(filename);
+ goto out;
}
-static void omap_screen_dump(void *opaque, const char *filename, bool cswitch)
+static void omap_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp)
{
struct omap_lcd_panel_s *omap_lcd = opaque;
omap_update_display(opaque);
if (omap_lcd && ds_get_data(omap_lcd->state))
- ppm_save(filename, ds_get_data(omap_lcd->state),
- omap_lcd->width, omap_lcd->height,
- ds_get_linesize(omap_lcd->state));
+ omap_ppm_save(filename, ds_get_data(omap_lcd->state),
+ omap_lcd->width, omap_lcd->height,
+ ds_get_linesize(omap_lcd->state), errp);
}
static void omap_invalidate_display(void *opaque) {
diff --git a/hw/pci.c b/hw/pci.c
index 4d9598480..f855cf3f3 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -439,7 +439,7 @@ const VMStateDescription vmstate_pci_device = {
};
const VMStateDescription vmstate_pcie_device = {
- .name = "PCIDevice",
+ .name = "PCIEDevice",
.version_id = 2,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
diff --git a/hw/pcie.h b/hw/pcie.h
index b8ab0c7b4..4889194ae 100644
--- a/hw/pcie.h
+++ b/hw/pcie.h
@@ -133,7 +133,6 @@ extern const VMStateDescription vmstate_pcie_device;
#define VMSTATE_PCIE_DEVICE(_field, _state) { \
.name = (stringify(_field)), \
- .version_id = 2, \
.size = sizeof(PCIDevice), \
.vmsd = &vmstate_pcie_device, \
.flags = VMS_STRUCT, \
diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c
index 3b6981c7b..b04c164e2 100644
--- a/hw/pcie_aer.c
+++ b/hw/pcie_aer.c
@@ -738,6 +738,11 @@ void pcie_aer_root_init(PCIDevice *dev)
PCI_ERR_ROOT_CMD_EN_MASK);
pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
PCI_ERR_ROOT_STATUS_REPORT_MASK);
+ /* PCI_ERR_ROOT_IRQ is RO but devices change it using a
+ * device-specific method.
+ */
+ pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS,
+ ~PCI_ERR_ROOT_IRQ);
}
void pcie_aer_root_reset(PCIDevice *dev)
diff --git a/hw/pl110.c b/hw/pl110.c
index f94608cb6..a5826407a 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -55,8 +55,8 @@ typedef struct {
enum pl110_bppmode bpp;
int invalidate;
uint32_t mux_ctrl;
- uint32_t pallette[256];
- uint32_t raw_pallette[128];
+ uint32_t palette[256];
+ uint32_t raw_palette[128];
qemu_irq irq;
} pl110_state;
@@ -79,8 +79,8 @@ static const VMStateDescription vmstate_pl110 = {
VMSTATE_INT32(rows, pl110_state),
VMSTATE_UINT32(bpp, pl110_state),
VMSTATE_INT32(invalidate, pl110_state),
- VMSTATE_UINT32_ARRAY(pallette, pl110_state, 256),
- VMSTATE_UINT32_ARRAY(raw_pallette, pl110_state, 128),
+ VMSTATE_UINT32_ARRAY(palette, pl110_state, 256),
+ VMSTATE_UINT32_ARRAY(raw_palette, pl110_state, 128),
VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2),
VMSTATE_END_OF_LIST()
}
@@ -236,7 +236,7 @@ static void pl110_update_display(void *opaque)
s->upbase, s->cols, s->rows,
src_width, dest_width, 0,
s->invalidate,
- fn, s->pallette,
+ fn, s->palette,
&first, &last);
if (first >= 0) {
dpy_update(s->ds, 0, first, s->cols, last - first + 1);
@@ -253,13 +253,13 @@ static void pl110_invalidate_display(void * opaque)
}
}
-static void pl110_update_pallette(pl110_state *s, int n)
+static void pl110_update_palette(pl110_state *s, int n)
{
int i;
uint32_t raw;
unsigned int r, g, b;
- raw = s->raw_pallette[n];
+ raw = s->raw_palette[n];
n <<= 1;
for (i = 0; i < 2; i++) {
r = (raw & 0x1f) << 3;
@@ -271,17 +271,17 @@ static void pl110_update_pallette(pl110_state *s, int n)
raw >>= 6;
switch (ds_get_bits_per_pixel(s->ds)) {
case 8:
- s->pallette[n] = rgb_to_pixel8(r, g, b);
+ s->palette[n] = rgb_to_pixel8(r, g, b);
break;
case 15:
- s->pallette[n] = rgb_to_pixel15(r, g, b);
+ s->palette[n] = rgb_to_pixel15(r, g, b);
break;
case 16:
- s->pallette[n] = rgb_to_pixel16(r, g, b);
+ s->palette[n] = rgb_to_pixel16(r, g, b);
break;
case 24:
case 32:
- s->pallette[n] = rgb_to_pixel32(r, g, b);
+ s->palette[n] = rgb_to_pixel32(r, g, b);
break;
}
n++;
@@ -314,7 +314,7 @@ static uint64_t pl110_read(void *opaque, target_phys_addr_t offset,
return idregs[s->version][(offset - 0xfe0) >> 2];
}
if (offset >= 0x200 && offset < 0x400) {
- return s->raw_pallette[(offset - 0x200) >> 2];
+ return s->raw_palette[(offset - 0x200) >> 2];
}
switch (offset >> 2) {
case 0: /* LCDTiming0 */
@@ -364,10 +364,10 @@ static void pl110_write(void *opaque, target_phys_addr_t offset,
is written to. */
s->invalidate = 1;
if (offset >= 0x200 && offset < 0x400) {
- /* Pallette. */
+ /* Palette. */
n = (offset - 0x200) >> 2;
- s->raw_pallette[(offset - 0x200) >> 2] = val;
- pl110_update_pallette(s, n);
+ s->raw_palette[(offset - 0x200) >> 2] = val;
+ pl110_update_palette(s, n);
return;
}
switch (offset >> 2) {
diff --git a/hw/pl110_template.h b/hw/pl110_template.h
index 1dce32a0c..e738e4a24 100644
--- a/hw/pl110_template.h
+++ b/hw/pl110_template.h
@@ -129,14 +129,14 @@ static drawfn glue(pl110_draw_fn_,BITS)[48] =
static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
- uint32_t *pallette = opaque;
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]);
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 7 - (x))) & 1]);
#else
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]);
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) + y)) & 1]);
#endif
#ifdef SWAP_WORDS
FN_8(24)
@@ -157,14 +157,14 @@ static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t
static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
- uint32_t *pallette = opaque;
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]);
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 6 - (x)*2)) & 3]);
#else
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]);
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*2 + y)) & 3]);
#endif
#ifdef SWAP_WORDS
FN_4(0, 24)
@@ -185,14 +185,14 @@ static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t
static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
- uint32_t *pallette = opaque;
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]);
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 4 - (x)*4)) & 0xf]);
#else
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]);
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*4 + y)) & 0xf]);
#endif
#ifdef SWAP_WORDS
FN_2(0, 24)
@@ -213,11 +213,11 @@ static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t
static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
- uint32_t *pallette = opaque;
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
-#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]);
+#define FN(x) COPY_PIXEL(d, palette[(data >> (x)) & 0xff]);
#ifdef SWAP_WORDS
FN(24)
FN(16)
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 33b7f79a9..479eecda3 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -44,6 +44,7 @@ static const QDevAlias qdev_alias_table[] = {
{ "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X },
{ "lsi53c895a", "lsi" },
{ "ich9-ahci", "ahci" },
+ { "kvm-pci-assign", "pci-assign" },
{ }
};
diff --git a/hw/qxl.c b/hw/qxl.c
index c2dd3b471..5b3f48426 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -27,6 +27,11 @@
#include "qxl.h"
+#ifndef CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC
+/* spice-protocol is too old, add missing definitions */
+#define QXL_IO_MONITORS_CONFIG_ASYNC (QXL_IO_FLUSH_RELEASE + 1)
+#endif
+
/*
* NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
* such can be changed by the guest, so to avoid a guest trigerrable
@@ -231,7 +236,8 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
{
trace_qxl_spice_destroy_surfaces_complete(qxl->id);
qemu_mutex_lock(&qxl->track_lock);
- memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
+ memset(qxl->guest_surfaces.cmds, 0,
+ sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces);
qxl->guest_surfaces.count = 0;
qemu_mutex_unlock(&qxl->track_lock);
}
@@ -249,6 +255,39 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
}
}
+static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
+{
+ trace_qxl_spice_monitors_config(qxl->id);
+/* 0x000b01 == 0.11.1 */
+#if SPICE_SERVER_VERSION >= 0x000b01 && \
+ defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC)
+ if (replay) {
+ /*
+ * don't use QXL_COOKIE_TYPE_IO:
+ * - we are not running yet (post_load), we will assert
+ * in send_events
+ * - this is not a guest io, but a reply, so async_io isn't set.
+ */
+ spice_qxl_monitors_config_async(&qxl->ssd.qxl,
+ qxl->guest_monitors_config,
+ MEMSLOT_GROUP_GUEST,
+ (uintptr_t)qxl_cookie_new(
+ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
+ 0));
+ } else {
+ qxl->guest_monitors_config = qxl->ram->monitors_config;
+ spice_qxl_monitors_config_async(&qxl->ssd.qxl,
+ qxl->ram->monitors_config,
+ MEMSLOT_GROUP_GUEST,
+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+ QXL_IO_MONITORS_CONFIG_ASYNC));
+ }
+#else
+ fprintf(stderr, "qxl: too old spice-protocol/spice-server for "
+ "QXL_IO_MONITORS_CONFIG_ASYNC\n");
+#endif
+}
+
void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
{
trace_qxl_spice_reset_image_cache(qxl->id);
@@ -307,7 +346,7 @@ static void init_qxl_rom(PCIQXLDevice *d)
rom->slot_id_bits = MEMSLOT_SLOT_BITS;
rom->slots_start = 1;
rom->slots_end = NUM_MEMSLOTS - 1;
- rom->n_surfaces = cpu_to_le32(NUM_SURFACES);
+ rom->n_surfaces = cpu_to_le32(d->ssd.num_surfaces);
for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) {
fb = qxl_modes[i].y_res * qxl_modes[i].stride;
@@ -411,9 +450,9 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
}
uint32_t id = le32_to_cpu(cmd->surface_id);
- if (id >= NUM_SURFACES) {
+ if (id >= qxl->ssd.num_surfaces) {
qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id,
- NUM_SURFACES);
+ qxl->ssd.num_surfaces);
return 1;
}
qemu_mutex_lock(&qxl->track_lock);
@@ -489,7 +528,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
info->internal_groupslot_id = 0;
info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
- info->n_surfaces = NUM_SURFACES;
+ info->n_surfaces = qxl->ssd.num_surfaces;
}
static const char *qxl_mode_to_string(int mode)
@@ -538,6 +577,7 @@ static const char *io_port_to_string(uint32_t io_port)
= "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
[QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC",
[QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE",
+ [QXL_IO_MONITORS_CONFIG_ASYNC] = "QXL_IO_MONITORS_CONFIG_ASYNC",
};
return io_port_to_string[io_port];
}
@@ -819,6 +859,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
case QXL_IO_DESTROY_PRIMARY_ASYNC:
case QXL_IO_UPDATE_AREA_ASYNC:
case QXL_IO_FLUSH_SURFACES_ASYNC:
+ case QXL_IO_MONITORS_CONFIG_ASYNC:
break;
case QXL_IO_CREATE_PRIMARY_ASYNC:
qxl_create_guest_primary_complete(qxl);
@@ -894,6 +935,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
qxl_render_update_area_done(qxl, cookie);
break;
+ case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
+ break;
default:
fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
__func__, cookie->type);
@@ -901,6 +944,26 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
}
}
+#if SPICE_SERVER_VERSION >= 0x000b04
+
+/* called from spice server thread context only */
+static void interface_set_client_capabilities(QXLInstance *sin,
+ uint8_t client_present,
+ uint8_t caps[58])
+{
+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+ qxl->shadow_rom.client_present = client_present;
+ memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps));
+ qxl->rom->client_present = client_present;
+ memcpy(qxl->rom->client_capabilities, caps, sizeof(caps));
+ qxl_rom_set_dirty(qxl);
+
+ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
+}
+
+#endif
+
static const QXLInterface qxl_interface = {
.base.type = SPICE_INTERFACE_QXL,
.base.description = "qxl gpu",
@@ -922,6 +985,9 @@ static const QXLInterface qxl_interface = {
.flush_resources = interface_flush_resources,
.async_complete = interface_async_complete,
.update_area_complete = interface_update_area_complete,
+#if SPICE_SERVER_VERSION >= 0x000b04
+ .set_client_capabilities = interface_set_client_capabilities,
+#endif
};
static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -958,9 +1024,10 @@ static void qxl_update_irq(PCIQXLDevice *d)
static void qxl_check_state(PCIQXLDevice *d)
{
QXLRam *ram = d->ram;
+ int spice_display_running = qemu_spice_display_is_running(&d->ssd);
- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+ assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+ assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
}
static void qxl_reset_state(PCIQXLDevice *d)
@@ -1292,11 +1359,9 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
d->mode = QXL_MODE_COMPAT;
d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
-#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */
if (mode->bits == 16) {
d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
}
-#endif
d->shadow_rom.mode = cpu_to_le32(modenr);
d->rom->mode = cpu_to_le32(modenr);
qxl_rom_set_dirty(d);
@@ -1314,6 +1379,13 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
return;
}
+ if (d->revision <= QXL_REVISION_STABLE_V10 &&
+ io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) {
+ qxl_set_guest_bug(d, "unsupported io %d for revision %d\n",
+ io_port, d->revision);
+ return;
+ }
+
switch (io_port) {
case QXL_IO_RESET:
case QXL_IO_SET_MODE:
@@ -1333,7 +1405,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
io_port, io_port_to_string(io_port));
/* be nice to buggy guest drivers */
if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
- io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
+ io_port < QXL_IO_RANGE_SIZE) {
qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
}
return;
@@ -1361,6 +1433,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
io_port = QXL_IO_DESTROY_ALL_SURFACES;
goto async_common;
case QXL_IO_FLUSH_SURFACES_ASYNC:
+ case QXL_IO_MONITORS_CONFIG_ASYNC:
async_common:
async = QXL_ASYNC;
qemu_mutex_lock(&d->async_lock);
@@ -1385,6 +1458,18 @@ async_common:
QXLCookie *cookie = NULL;
QXLRect update = d->ram->update_area;
+ if (d->ram->update_surface > d->ssd.num_surfaces) {
+ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
+ d->ram->update_surface);
+ return;
+ }
+ if (update.left >= update.right || update.top >= update.bottom) {
+ qxl_set_guest_bug(d,
+ "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n",
+ update.left, update.top, update.right, update.bottom);
+ return;
+ }
+
if (async == QXL_ASYNC) {
cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
QXL_IO_UPDATE_AREA_ASYNC);
@@ -1466,7 +1551,7 @@ async_common:
}
break;
case QXL_IO_DESTROY_SURFACE_WAIT:
- if (val >= NUM_SURFACES) {
+ if (val >= d->ssd.num_surfaces) {
qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
"%" PRIu64 " >= NUM_SURFACES", async, val);
goto cancel_async;
@@ -1490,6 +1575,9 @@ async_common:
d->mode = QXL_MODE_UNDEFINED;
qxl_spice_destroy_surfaces(d, async);
break;
+ case QXL_IO_MONITORS_CONFIG_ASYNC:
+ qxl_spice_monitors_config_async(d, 0);
+ break;
default:
qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
}
@@ -1538,7 +1626,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
uint32_t old_pending;
uint32_t le_events = cpu_to_le32(events);
- assert(d->ssd.running);
+ assert(qemu_spice_display_is_running(&d->ssd));
old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
if ((old_pending & le_events) == le_events) {
return;
@@ -1595,7 +1683,8 @@ static void qxl_hw_invalidate(void *opaque)
vga->invalidate(vga);
}
-static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch)
+static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp)
{
PCIQXLDevice *qxl = opaque;
VGACommonState *vga = &qxl->vga;
@@ -1604,10 +1693,10 @@ static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch)
case QXL_MODE_COMPAT:
case QXL_MODE_NATIVE:
qxl_render_update(qxl);
- ppm_save(filename, qxl->ssd.ds->surface);
+ ppm_save(filename, qxl->ssd.ds->surface, errp);
break;
case QXL_MODE_VGA:
- vga->screen_dump(vga, filename, cswitch);
+ vga->screen_dump(vga, filename, cswitch, errp);
break;
default:
break;
@@ -1641,7 +1730,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
/* dirty the off-screen surfaces */
- for (i = 0; i < NUM_SURFACES; i++) {
+ for (i = 0; i < qxl->ssd.num_surfaces; i++) {
QXLSurfaceCmd *cmd;
intptr_t surface_offset;
int surface_size;
@@ -1769,7 +1858,6 @@ static int qxl_init_common(PCIQXLDevice *qxl)
qxl->mode = QXL_MODE_UNDEFINED;
qxl->generation = 1;
qxl->num_memslots = NUM_MEMSLOTS;
- qxl->num_surfaces = NUM_SURFACES;
qemu_mutex_init(&qxl->track_lock);
qemu_mutex_init(&qxl->async_lock);
qxl->current_async = QXL_UNDEFINED_IO;
@@ -1785,10 +1873,21 @@ static int qxl_init_common(PCIQXLDevice *qxl)
io_size = 16;
break;
case 3: /* qxl-3 */
- default:
- pci_device_rev = QXL_DEFAULT_REVISION;
+ pci_device_rev = QXL_REVISION_STABLE_V10;
+ io_size = 32; /* PCI region size must be pow2 */
+ break;
+/* 0x000b01 == 0.11.1 */
+#if SPICE_SERVER_VERSION >= 0x000b01 && \
+ defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC)
+ case 4: /* qxl-4 */
+ pci_device_rev = QXL_REVISION_STABLE_V12;
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
break;
+#endif
+ default:
+ error_report("Invalid revision %d for qxl device (max %d)",
+ qxl->revision, QXL_DEFAULT_REVISION);
+ return -1;
}
pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
@@ -1800,6 +1899,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
init_qxl_rom(qxl);
init_qxl_ram(qxl);
+ qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size);
vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar,
@@ -1965,8 +2065,8 @@ static int qxl_post_load(void *opaque, int version)
qxl_create_guest_primary(d, 1, QXL_SYNC);
/* replay surface-create and cursor-set commands */
- cmds = g_malloc0(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
- for (in = 0, out = 0; in < NUM_SURFACES; in++) {
+ cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1));
+ for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) {
if (d->guest_surfaces.cmds[in] == 0) {
continue;
}
@@ -1983,7 +2083,9 @@ static int qxl_post_load(void *opaque, int version)
}
qxl_spice_loadvm_commands(d, cmds, out);
g_free(cmds);
-
+ if (d->guest_monitors_config) {
+ qxl_spice_monitors_config_async(d, 1);
+ }
break;
case QXL_MODE_COMPAT:
/* note: no need to call qxl_create_memslots, qxl_set_mode
@@ -1996,6 +2098,14 @@ static int qxl_post_load(void *opaque, int version)
#define QXL_SAVE_VERSION 21
+static bool qxl_monitors_config_needed(void *opaque)
+{
+ PCIQXLDevice *qxl = opaque;
+
+ return qxl->guest_monitors_config != 0;
+}
+
+
static VMStateDescription qxl_memslot = {
.name = "qxl-memslot",
.version_id = QXL_SAVE_VERSION,
@@ -2026,6 +2136,16 @@ static VMStateDescription qxl_surface = {
}
};
+static VMStateDescription qxl_vmstate_monitors_config = {
+ .name = "qxl/monitors-config",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static VMStateDescription qxl_vmstate = {
.name = "qxl",
.version_id = QXL_SAVE_VERSION,
@@ -2033,7 +2153,7 @@ static VMStateDescription qxl_vmstate = {
.pre_save = qxl_pre_save,
.pre_load = qxl_pre_load,
.post_load = qxl_post_load,
- .fields = (VMStateField []) {
+ .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
@@ -2046,12 +2166,21 @@ static VMStateDescription qxl_vmstate = {
qxl_memslot, struct guest_slots),
VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
qxl_surface, QXLSurfaceCreate),
- VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice),
- VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0,
- vmstate_info_uint64, uint64_t),
+ VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice),
+ VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice,
+ ssd.num_surfaces, 0,
+ vmstate_info_uint64, uint64_t),
VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
VMSTATE_END_OF_LIST()
},
+ .subsections = (VMStateSubsection[]) {
+ {
+ .vmsd = &qxl_vmstate_monitors_config,
+ .needed = qxl_monitors_config_needed,
+ }, {
+ /* empty */
+ }
+ }
};
static Property qxl_properties[] = {
@@ -2068,6 +2197,7 @@ static Property qxl_properties[] = {
DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16),
+ DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/qxl.h b/hw/qxl.h
index 172baf6cc..5553824be 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -40,7 +40,6 @@ typedef struct PCIQXLDevice {
uint32_t revision;
int32_t num_memslots;
- int32_t num_surfaces;
uint32_t current_async;
QemuMutex async_lock;
@@ -65,12 +64,14 @@ typedef struct PCIQXLDevice {
} guest_primary;
struct surfaces {
- QXLPHYSICAL cmds[NUM_SURFACES];
+ QXLPHYSICAL *cmds;
uint32_t count;
uint32_t max;
} guest_surfaces;
QXLPHYSICAL guest_cursor;
+ QXLPHYSICAL guest_monitors_config;
+
QemuMutex track_lock;
/* thread signaling */
@@ -128,7 +129,12 @@ typedef struct PCIQXLDevice {
} \
} while (0)
+#if 0
+/* spice-server 0.12 is still in development */
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
+#else
#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
+#endif
/* qxl.c */
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
diff --git a/hw/tcx.c b/hw/tcx.c
index ac7dcb428..93994d644 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -56,8 +56,10 @@ typedef struct TCXState {
uint8_t dac_index, dac_state;
} TCXState;
-static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch);
-static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch);
+static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp);
+static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp);
static void tcx_set_dirty(TCXState *s)
{
@@ -574,45 +576,76 @@ static int tcx_init1(SysBusDevice *dev)
return 0;
}
-static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch)
+static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp)
{
TCXState *s = opaque;
FILE *f;
uint8_t *d, *d1, v;
- int y, x;
+ int ret, y, x;
f = fopen(filename, "wb");
- if (!f)
+ if (!f) {
+ error_setg(errp, "failed to open file '%s': %s", filename,
+ strerror(errno));
return;
- fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+ }
+ ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+ if (ret < 0) {
+ goto write_err;
+ }
d1 = s->vram;
for(y = 0; y < s->height; y++) {
d = d1;
for(x = 0; x < s->width; x++) {
v = *d;
- fputc(s->r[v], f);
- fputc(s->g[v], f);
- fputc(s->b[v], f);
+ ret = fputc(s->r[v], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc(s->g[v], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc(s->b[v], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
d++;
}
d1 += MAXX;
}
+
+out:
fclose(f);
return;
+
+write_err:
+ error_setg(errp, "failed to write to file '%s': %s", filename,
+ strerror(errno));
+ unlink(filename);
+ goto out;
}
-static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch)
+static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp)
{
TCXState *s = opaque;
FILE *f;
uint8_t *d, *d1, v;
uint32_t *s24, *cptr, dval;
- int y, x;
+ int ret, y, x;
f = fopen(filename, "wb");
- if (!f)
+ if (!f) {
+ error_setg(errp, "failed to open file '%s': %s", filename,
+ strerror(errno));
return;
- fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+ }
+ ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+ if (ret < 0) {
+ goto write_err;
+ }
d1 = s->vram;
s24 = s->vram24;
cptr = s->cplane;
@@ -621,20 +654,46 @@ static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch)
for(x = 0; x < s->width; x++, d++, s24++) {
if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
dval = *s24 & 0x00ffffff;
- fputc((dval >> 16) & 0xff, f);
- fputc((dval >> 8) & 0xff, f);
- fputc(dval & 0xff, f);
+ ret = fputc((dval >> 16) & 0xff, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc((dval >> 8) & 0xff, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc(dval & 0xff, f);
+ if (ret == EOF) {
+ goto write_err;
+ }
} else {
v = *d;
- fputc(s->r[v], f);
- fputc(s->g[v], f);
- fputc(s->b[v], f);
+ ret = fputc(s->r[v], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc(s->g[v], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
+ ret = fputc(s->b[v], f);
+ if (ret == EOF) {
+ goto write_err;
+ }
}
}
d1 += MAXX;
}
+
+out:
fclose(f);
return;
+
+write_err:
+ error_setg(errp, "failed to write to file '%s': %s", filename,
+ strerror(errno));
+ unlink(filename);
+ goto out;
}
static Property tcx_properties[] = {
diff --git a/hw/vga.c b/hw/vga.c
index f82ced8e6..80299ea1d 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -166,7 +166,8 @@ static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
-static void vga_screen_dump(void *opaque, const char *filename, bool cswitch);
+static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp);
static void vga_update_memory_access(VGACommonState *s)
{
@@ -2389,7 +2390,7 @@ void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
/********************************************************/
/* vga screen dump */
-int ppm_save(const char *filename, struct DisplaySurface *ds)
+void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp)
{
FILE *f;
uint8_t *d, *d1;
@@ -2401,10 +2402,16 @@ int ppm_save(const char *filename, struct DisplaySurface *ds)
trace_ppm_save(filename, ds);
f = fopen(filename, "wb");
- if (!f)
- return -1;
- fprintf(f, "P6\n%d %d\n%d\n",
- ds->width, ds->height, 255);
+ if (!f) {
+ error_setg(errp, "failed to open file '%s': %s", filename,
+ strerror(errno));
+ return;
+ }
+ ret = fprintf(f, "P6\n%d %d\n%d\n", ds->width, ds->height, 255);
+ if (ret < 0) {
+ linebuf = NULL;
+ goto write_err;
+ }
linebuf = g_malloc(ds->width * 3);
d1 = ds->data;
for(y = 0; y < ds->height; y++) {
@@ -2425,17 +2432,30 @@ int ppm_save(const char *filename, struct DisplaySurface *ds)
d += ds->pf.bytes_per_pixel;
}
d1 += ds->linesize;
+ clearerr(f);
ret = fwrite(linebuf, 1, pbuf - linebuf, f);
(void)ret;
+ if (ferror(f)) {
+ goto write_err;
+ }
}
+
+out:
g_free(linebuf);
fclose(f);
- return 0;
+ return;
+
+write_err:
+ error_setg(errp, "failed to write to file '%s': %s", filename,
+ strerror(errno));
+ unlink(filename);
+ goto out;
}
/* save the vga display in a PPM image even if no display is
available */
-static void vga_screen_dump(void *opaque, const char *filename, bool cswitch)
+static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp)
{
VGACommonState *s = opaque;
@@ -2443,5 +2463,5 @@ static void vga_screen_dump(void *opaque, const char *filename, bool cswitch)
vga_invalidate_display(s);
}
vga_hw_update();
- ppm_save(filename, s->ds->surface);
+ ppm_save(filename, s->ds->surface, errp);
}
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 893809368..330a32f77 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -23,6 +23,7 @@
*/
#include <hw/hw.h>
+#include "error.h"
#include "memory.h"
#define ST01_V_RETRACE 0x08
@@ -204,7 +205,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr);
void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val);
void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
-int ppm_save(const char *filename, struct DisplaySurface *ds);
+void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp);
int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
diff --git a/hw/vhost.c b/hw/vhost.c
index 0fd8da84e..d0ce5aad9 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -747,14 +747,15 @@ static void vhost_eventfd_del(MemoryListener *listener,
{
}
-int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force)
+int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,
+ bool force)
{
uint64_t features;
int r;
if (devfd >= 0) {
hdev->control = devfd;
} else {
- hdev->control = open("/dev/vhost-net", O_RDWR);
+ hdev->control = open(devpath, O_RDWR);
if (hdev->control < 0) {
return -errno;
}
diff --git a/hw/vhost.h b/hw/vhost.h
index 80e64df86..0c47229f9 100644
--- a/hw/vhost.h
+++ b/hw/vhost.h
@@ -44,7 +44,8 @@ struct vhost_dev {
bool force;
};
-int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force);
+int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,
+ bool force);
void vhost_dev_cleanup(struct vhost_dev *hdev);
bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
index ecaa22dfb..df2c4a30a 100644
--- a/hw/vhost_net.c
+++ b/hw/vhost_net.c
@@ -109,7 +109,7 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
(1 << VHOST_NET_F_VIRTIO_NET_HDR);
net->backend = r;
- r = vhost_dev_init(&net->dev, devfd, force);
+ r = vhost_dev_init(&net->dev, devfd, "/dev/vhost-net", force);
if (r < 0) {
goto fail;
}
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index b3f0710f3..400f3c26b 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -517,7 +517,7 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
}
irqfd->users++;
- ret = kvm_irqchip_add_irq_notifier(kvm_state, n, irqfd->virq);
+ ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
if (ret < 0) {
if (--irqfd->users == 0) {
kvm_irqchip_release_virq(kvm_state, irqfd->virq);
@@ -538,7 +538,7 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
int ret;
- ret = kvm_irqchip_remove_irq_notifier(kvm_state, n, irqfd->virq);
+ ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
assert(ret == 0);
if (--irqfd->users == 0) {
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index f5e4f440d..b68e88367 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1003,18 +1003,19 @@ static void vmsvga_invalidate_display(void *opaque)
/* save the vga display in a PPM image even if no display is
available */
-static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch)
+static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch,
+ Error **errp)
{
struct vmsvga_state_s *s = opaque;
if (!s->enable) {
- s->vga.screen_dump(&s->vga, filename, cswitch);
+ s->vga.screen_dump(&s->vga, filename, cswitch, errp);
return;
}
if (s->depth == 32) {
DisplaySurface *ds = qemu_create_displaysurface_from(s->width,
s->height, 32, ds_get_linesize(s->vga.ds), s->vga.vram_ptr);
- ppm_save(filename, ds);
+ ppm_save(filename, ds, errp);
g_free(ds);
}
}
diff --git a/hw/wm8750.c b/hw/wm8750.c
index 11bcec341..44f138fd5 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -361,10 +361,10 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data)
uint16_t value;
if (s->i2c_len >= 2) {
- printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
#ifdef VERBOSE
- return 1;
+ printf("%s: long message (%i bytes)\n", __func__, s->i2c_len);
#endif
+ return 1;
}
s->i2c_data[s->i2c_len ++] = data;
if (s->i2c_len != 2)
diff --git a/input.c b/input.c
index 6968b3178..c4b0619a7 100644
--- a/input.c
+++ b/input.c
@@ -28,6 +28,7 @@
#include "console.h"
#include "error.h"
#include "qmp-commands.h"
+#include "qapi-types.h"
static QEMUPutKBDEvent *qemu_put_kbd_event;
static void *qemu_put_kbd_event_opaque;
@@ -37,6 +38,256 @@ static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
static NotifierList mouse_mode_notifiers =
NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
+static const int key_defs[] = {
+ [Q_KEY_CODE_SHIFT] = 0x2a,
+ [Q_KEY_CODE_SHIFT_R] = 0x36,
+
+ [Q_KEY_CODE_ALT] = 0x38,
+ [Q_KEY_CODE_ALT_R] = 0xb8,
+ [Q_KEY_CODE_ALTGR] = 0x64,
+ [Q_KEY_CODE_ALTGR_R] = 0xe4,
+ [Q_KEY_CODE_CTRL] = 0x1d,
+ [Q_KEY_CODE_CTRL_R] = 0x9d,
+
+ [Q_KEY_CODE_MENU] = 0xdd,
+
+ [Q_KEY_CODE_ESC] = 0x01,
+
+ [Q_KEY_CODE_1] = 0x02,
+ [Q_KEY_CODE_2] = 0x03,
+ [Q_KEY_CODE_3] = 0x04,
+ [Q_KEY_CODE_4] = 0x05,
+ [Q_KEY_CODE_5] = 0x06,
+ [Q_KEY_CODE_6] = 0x07,
+ [Q_KEY_CODE_7] = 0x08,
+ [Q_KEY_CODE_8] = 0x09,
+ [Q_KEY_CODE_9] = 0x0a,
+ [Q_KEY_CODE_0] = 0x0b,
+ [Q_KEY_CODE_MINUS] = 0x0c,
+ [Q_KEY_CODE_EQUAL] = 0x0d,
+ [Q_KEY_CODE_BACKSPACE] = 0x0e,
+
+ [Q_KEY_CODE_TAB] = 0x0f,
+ [Q_KEY_CODE_Q] = 0x10,
+ [Q_KEY_CODE_W] = 0x11,
+ [Q_KEY_CODE_E] = 0x12,
+ [Q_KEY_CODE_R] = 0x13,
+ [Q_KEY_CODE_T] = 0x14,
+ [Q_KEY_CODE_Y] = 0x15,
+ [Q_KEY_CODE_U] = 0x16,
+ [Q_KEY_CODE_I] = 0x17,
+ [Q_KEY_CODE_O] = 0x18,
+ [Q_KEY_CODE_P] = 0x19,
+ [Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
+ [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
+ [Q_KEY_CODE_RET] = 0x1c,
+
+ [Q_KEY_CODE_A] = 0x1e,
+ [Q_KEY_CODE_S] = 0x1f,
+ [Q_KEY_CODE_D] = 0x20,
+ [Q_KEY_CODE_F] = 0x21,
+ [Q_KEY_CODE_G] = 0x22,
+ [Q_KEY_CODE_H] = 0x23,
+ [Q_KEY_CODE_J] = 0x24,
+ [Q_KEY_CODE_K] = 0x25,
+ [Q_KEY_CODE_L] = 0x26,
+ [Q_KEY_CODE_SEMICOLON] = 0x27,
+ [Q_KEY_CODE_APOSTROPHE] = 0x28,
+ [Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
+
+ [Q_KEY_CODE_BACKSLASH] = 0x2b,
+ [Q_KEY_CODE_Z] = 0x2c,
+ [Q_KEY_CODE_X] = 0x2d,
+ [Q_KEY_CODE_C] = 0x2e,
+ [Q_KEY_CODE_V] = 0x2f,
+ [Q_KEY_CODE_B] = 0x30,
+ [Q_KEY_CODE_N] = 0x31,
+ [Q_KEY_CODE_M] = 0x32,
+ [Q_KEY_CODE_COMMA] = 0x33,
+ [Q_KEY_CODE_DOT] = 0x34,
+ [Q_KEY_CODE_SLASH] = 0x35,
+
+ [Q_KEY_CODE_ASTERISK] = 0x37,
+
+ [Q_KEY_CODE_SPC] = 0x39,
+ [Q_KEY_CODE_CAPS_LOCK] = 0x3a,
+ [Q_KEY_CODE_F1] = 0x3b,
+ [Q_KEY_CODE_F2] = 0x3c,
+ [Q_KEY_CODE_F3] = 0x3d,
+ [Q_KEY_CODE_F4] = 0x3e,
+ [Q_KEY_CODE_F5] = 0x3f,
+ [Q_KEY_CODE_F6] = 0x40,
+ [Q_KEY_CODE_F7] = 0x41,
+ [Q_KEY_CODE_F8] = 0x42,
+ [Q_KEY_CODE_F9] = 0x43,
+ [Q_KEY_CODE_F10] = 0x44,
+ [Q_KEY_CODE_NUM_LOCK] = 0x45,
+ [Q_KEY_CODE_SCROLL_LOCK] = 0x46,
+
+ [Q_KEY_CODE_KP_DIVIDE] = 0xb5,
+ [Q_KEY_CODE_KP_MULTIPLY] = 0x37,
+ [Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
+ [Q_KEY_CODE_KP_ADD] = 0x4e,
+ [Q_KEY_CODE_KP_ENTER] = 0x9c,
+ [Q_KEY_CODE_KP_DECIMAL] = 0x53,
+ [Q_KEY_CODE_SYSRQ] = 0x54,
+
+ [Q_KEY_CODE_KP_0] = 0x52,
+ [Q_KEY_CODE_KP_1] = 0x4f,
+ [Q_KEY_CODE_KP_2] = 0x50,
+ [Q_KEY_CODE_KP_3] = 0x51,
+ [Q_KEY_CODE_KP_4] = 0x4b,
+ [Q_KEY_CODE_KP_5] = 0x4c,
+ [Q_KEY_CODE_KP_6] = 0x4d,
+ [Q_KEY_CODE_KP_7] = 0x47,
+ [Q_KEY_CODE_KP_8] = 0x48,
+ [Q_KEY_CODE_KP_9] = 0x49,
+
+ [Q_KEY_CODE_LESS] = 0x56,
+
+ [Q_KEY_CODE_F11] = 0x57,
+ [Q_KEY_CODE_F12] = 0x58,
+
+ [Q_KEY_CODE_PRINT] = 0xb7,
+
+ [Q_KEY_CODE_HOME] = 0xc7,
+ [Q_KEY_CODE_PGUP] = 0xc9,
+ [Q_KEY_CODE_PGDN] = 0xd1,
+ [Q_KEY_CODE_END] = 0xcf,
+
+ [Q_KEY_CODE_LEFT] = 0xcb,
+ [Q_KEY_CODE_UP] = 0xc8,
+ [Q_KEY_CODE_DOWN] = 0xd0,
+ [Q_KEY_CODE_RIGHT] = 0xcd,
+
+ [Q_KEY_CODE_INSERT] = 0xd2,
+ [Q_KEY_CODE_DELETE] = 0xd3,
+#ifdef NEED_CPU_H
+#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
+ [Q_KEY_CODE_STOP] = 0xf0,
+ [Q_KEY_CODE_AGAIN] = 0xf1,
+ [Q_KEY_CODE_PROPS] = 0xf2,
+ [Q_KEY_CODE_UNDO] = 0xf3,
+ [Q_KEY_CODE_FRONT] = 0xf4,
+ [Q_KEY_CODE_COPY] = 0xf5,
+ [Q_KEY_CODE_OPEN] = 0xf6,
+ [Q_KEY_CODE_PASTE] = 0xf7,
+ [Q_KEY_CODE_FIND] = 0xf8,
+ [Q_KEY_CODE_CUT] = 0xf9,
+ [Q_KEY_CODE_LF] = 0xfa,
+ [Q_KEY_CODE_HELP] = 0xfb,
+ [Q_KEY_CODE_META_L] = 0xfc,
+ [Q_KEY_CODE_META_R] = 0xfd,
+ [Q_KEY_CODE_COMPOSE] = 0xfe,
+#endif
+#endif
+ [Q_KEY_CODE_MAX] = 0,
+};
+
+int index_from_key(const char *key)
+{
+ int i, keycode;
+ char *endp;
+
+ for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
+ if (!strcmp(key, QKeyCode_lookup[i])) {
+ break;
+ }
+ }
+
+ if (strstart(key, "0x", NULL)) {
+ keycode = strtoul(key, &endp, 0);
+ if (*endp == '\0' && keycode >= 0x01 && keycode <= 0xff) {
+ for (i = 0; i < Q_KEY_CODE_MAX; i++) {
+ if (keycode == key_defs[i]) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Return Q_KEY_CODE_MAX if the key is invalid */
+ return i;
+}
+
+int index_from_keycode(int code)
+{
+ int i;
+
+ for (i = 0; i < Q_KEY_CODE_MAX; i++) {
+ if (key_defs[i] == code) {
+ break;
+ }
+ }
+
+ /* Return Q_KEY_CODE_MAX if the code is invalid */
+ return i;
+}
+
+static QKeyCodeList *keycodes;
+static QEMUTimer *key_timer;
+
+static void release_keys(void *opaque)
+{
+ int keycode;
+ QKeyCodeList *p;
+
+ for (p = keycodes; p != NULL; p = p->next) {
+ keycode = key_defs[p->value];
+ if (keycode & 0x80) {
+ kbd_put_keycode(0xe0);
+ }
+ kbd_put_keycode(keycode | 0x80);
+ }
+ qapi_free_QKeyCodeList(keycodes);
+ keycodes = NULL;
+}
+
+void qmp_send_key(QKeyCodeList *keys, bool has_hold_time, int64_t hold_time,
+ Error **errp)
+{
+ int keycode;
+ QKeyCodeList *p, *keylist, *head = NULL, *tmp = NULL;
+
+ if (!key_timer) {
+ key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
+ }
+
+ if (keycodes != NULL) {
+ qemu_del_timer(key_timer);
+ release_keys(NULL);
+ }
+ if (!has_hold_time) {
+ hold_time = 100;
+ }
+
+ for (p = keys; p != NULL; p = p->next) {
+ keylist = g_malloc0(sizeof(*keylist));
+ keylist->value = p->value;
+ keylist->next = NULL;
+
+ if (!head) {
+ head = keylist;
+ }
+ if (tmp) {
+ tmp->next = keylist;
+ }
+ tmp = keylist;
+
+ /* key down events */
+ keycode = key_defs[p->value];
+ if (keycode & 0x80) {
+ kbd_put_keycode(0xe0);
+ }
+ kbd_put_keycode(keycode & 0x7f);
+ }
+ keycodes = head;
+
+ /* delayed key up events */
+ qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) +
+ muldiv64(get_ticks_per_sec(), hold_time, 1000));
+}
+
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
{
qemu_put_kbd_event_opaque = opaque;
diff --git a/kvm-all.c b/kvm-all.c
index badf1d829..39cff55f5 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -39,6 +39,10 @@
#include <sys/eventfd.h>
#endif
+#ifdef CONFIG_VALGRIND_H
+#include <valgrind/memcheck.h>
+#endif
+
/* KVM uses PAGE_SIZE in its definition of COALESCED_MMIO_MAX */
#define PAGE_SIZE TARGET_PAGE_SIZE
@@ -1205,24 +1209,14 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
}
#endif /* !KVM_CAP_IRQ_ROUTING */
-int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq)
-{
- return kvm_irqchip_assign_irqfd(s, fd, virq, true);
-}
-
-int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq)
+int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
{
- return kvm_irqchip_add_irqfd(s, event_notifier_get_fd(n), virq);
+ return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), virq, true);
}
-int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq)
+int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
{
- return kvm_irqchip_assign_irqfd(s, fd, virq, false);
-}
-
-int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq)
-{
- return kvm_irqchip_remove_irqfd(s, event_notifier_get_fd(n), virq);
+ return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), virq, false);
}
static int kvm_irqchip_create(KVMState *s)
@@ -1769,6 +1763,9 @@ void *kvm_vmalloc(ram_addr_t size)
void kvm_setup_guest_memory(void *start, size_t size)
{
+#ifdef CONFIG_VALGRIND_H
+ VALGRIND_MAKE_MEM_DEFINED(start, size);
+#endif
if (!kvm_has_sync_mmu()) {
int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK);
diff --git a/kvm-stub.c b/kvm-stub.c
index 94c9ea15b..3c52eb5bc 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -141,22 +141,12 @@ void kvm_irqchip_release_virq(KVMState *s, int virq)
{
}
-int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq)
+int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
{
return -ENOSYS;
}
-int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq)
-{
- return -ENOSYS;
-}
-
-int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq)
-{
- return -ENOSYS;
-}
-
-int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq)
+int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
{
return -ENOSYS;
}
diff --git a/kvm.h b/kvm.h
index 2a68a5212..dea2998fd 100644
--- a/kvm.h
+++ b/kvm.h
@@ -274,8 +274,6 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
void kvm_irqchip_release_virq(KVMState *s, int virq);
-int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq);
-int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq);
-int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq);
-int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq);
+int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
+int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
#endif
diff --git a/monitor.c b/monitor.c
index 29e428791..4ca30e127 100644
--- a/monitor.c
+++ b/monitor.c
@@ -455,6 +455,7 @@ static const char *monitor_event_names[] = {
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
[QEVENT_WAKEUP] = "WAKEUP",
[QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
+ [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED",
};
QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
@@ -1037,12 +1038,6 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict,
return -1;
}
-static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- vga_hw_screen_dump(qdict_get_str(qdict, "filename"));
- return 0;
-}
-
static void do_logfile(Monitor *mon, const QDict *qdict)
{
cpu_set_log_filename(qdict_get_str(qdict, "filename"));
@@ -1311,245 +1306,6 @@ static void do_sum(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "%05d\n", sum);
}
-typedef struct {
- int keycode;
- const char *name;
-} KeyDef;
-
-static const KeyDef key_defs[] = {
- { 0x2a, "shift" },
- { 0x36, "shift_r" },
-
- { 0x38, "alt" },
- { 0xb8, "alt_r" },
- { 0x64, "altgr" },
- { 0xe4, "altgr_r" },
- { 0x1d, "ctrl" },
- { 0x9d, "ctrl_r" },
-
- { 0xdd, "menu" },
-
- { 0x01, "esc" },
-
- { 0x02, "1" },
- { 0x03, "2" },
- { 0x04, "3" },
- { 0x05, "4" },
- { 0x06, "5" },
- { 0x07, "6" },
- { 0x08, "7" },
- { 0x09, "8" },
- { 0x0a, "9" },
- { 0x0b, "0" },
- { 0x0c, "minus" },
- { 0x0d, "equal" },
- { 0x0e, "backspace" },
-
- { 0x0f, "tab" },
- { 0x10, "q" },
- { 0x11, "w" },
- { 0x12, "e" },
- { 0x13, "r" },
- { 0x14, "t" },
- { 0x15, "y" },
- { 0x16, "u" },
- { 0x17, "i" },
- { 0x18, "o" },
- { 0x19, "p" },
- { 0x1a, "bracket_left" },
- { 0x1b, "bracket_right" },
- { 0x1c, "ret" },
-
- { 0x1e, "a" },
- { 0x1f, "s" },
- { 0x20, "d" },
- { 0x21, "f" },
- { 0x22, "g" },
- { 0x23, "h" },
- { 0x24, "j" },
- { 0x25, "k" },
- { 0x26, "l" },
- { 0x27, "semicolon" },
- { 0x28, "apostrophe" },
- { 0x29, "grave_accent" },
-
- { 0x2b, "backslash" },
- { 0x2c, "z" },
- { 0x2d, "x" },
- { 0x2e, "c" },
- { 0x2f, "v" },
- { 0x30, "b" },
- { 0x31, "n" },
- { 0x32, "m" },
- { 0x33, "comma" },
- { 0x34, "dot" },
- { 0x35, "slash" },
-
- { 0x37, "asterisk" },
-
- { 0x39, "spc" },
- { 0x3a, "caps_lock" },
- { 0x3b, "f1" },
- { 0x3c, "f2" },
- { 0x3d, "f3" },
- { 0x3e, "f4" },
- { 0x3f, "f5" },
- { 0x40, "f6" },
- { 0x41, "f7" },
- { 0x42, "f8" },
- { 0x43, "f9" },
- { 0x44, "f10" },
- { 0x45, "num_lock" },
- { 0x46, "scroll_lock" },
-
- { 0xb5, "kp_divide" },
- { 0x37, "kp_multiply" },
- { 0x4a, "kp_subtract" },
- { 0x4e, "kp_add" },
- { 0x9c, "kp_enter" },
- { 0x53, "kp_decimal" },
- { 0x54, "sysrq" },
-
- { 0x52, "kp_0" },
- { 0x4f, "kp_1" },
- { 0x50, "kp_2" },
- { 0x51, "kp_3" },
- { 0x4b, "kp_4" },
- { 0x4c, "kp_5" },
- { 0x4d, "kp_6" },
- { 0x47, "kp_7" },
- { 0x48, "kp_8" },
- { 0x49, "kp_9" },
-
- { 0x56, "<" },
-
- { 0x57, "f11" },
- { 0x58, "f12" },
-
- { 0xb7, "print" },
-
- { 0xc7, "home" },
- { 0xc9, "pgup" },
- { 0xd1, "pgdn" },
- { 0xcf, "end" },
-
- { 0xcb, "left" },
- { 0xc8, "up" },
- { 0xd0, "down" },
- { 0xcd, "right" },
-
- { 0xd2, "insert" },
- { 0xd3, "delete" },
-#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
- { 0xf0, "stop" },
- { 0xf1, "again" },
- { 0xf2, "props" },
- { 0xf3, "undo" },
- { 0xf4, "front" },
- { 0xf5, "copy" },
- { 0xf6, "open" },
- { 0xf7, "paste" },
- { 0xf8, "find" },
- { 0xf9, "cut" },
- { 0xfa, "lf" },
- { 0xfb, "help" },
- { 0xfc, "meta_l" },
- { 0xfd, "meta_r" },
- { 0xfe, "compose" },
-#endif
- { 0, NULL },
-};
-
-static int get_keycode(const char *key)
-{
- const KeyDef *p;
- char *endp;
- int ret;
-
- for(p = key_defs; p->name != NULL; p++) {
- if (!strcmp(key, p->name))
- return p->keycode;
- }
- if (strstart(key, "0x", NULL)) {
- ret = strtoul(key, &endp, 0);
- if (*endp == '\0' && ret >= 0x01 && ret <= 0xff)
- return ret;
- }
- return -1;
-}
-
-#define MAX_KEYCODES 16
-static uint8_t keycodes[MAX_KEYCODES];
-static int nb_pending_keycodes;
-static QEMUTimer *key_timer;
-
-static void release_keys(void *opaque)
-{
- int keycode;
-
- while (nb_pending_keycodes > 0) {
- nb_pending_keycodes--;
- keycode = keycodes[nb_pending_keycodes];
- if (keycode & 0x80)
- kbd_put_keycode(0xe0);
- kbd_put_keycode(keycode | 0x80);
- }
-}
-
-static void do_sendkey(Monitor *mon, const QDict *qdict)
-{
- char keyname_buf[16];
- char *separator;
- int keyname_len, keycode, i;
- const char *string = qdict_get_str(qdict, "string");
- int has_hold_time = qdict_haskey(qdict, "hold_time");
- int hold_time = qdict_get_try_int(qdict, "hold_time", -1);
-
- if (nb_pending_keycodes > 0) {
- qemu_del_timer(key_timer);
- release_keys(NULL);
- }
- if (!has_hold_time)
- hold_time = 100;
- i = 0;
- while (1) {
- separator = strchr(string, '-');
- keyname_len = separator ? separator - string : strlen(string);
- if (keyname_len > 0) {
- pstrcpy(keyname_buf, sizeof(keyname_buf), string);
- if (keyname_len > sizeof(keyname_buf) - 1) {
- monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf);
- return;
- }
- if (i == MAX_KEYCODES) {
- monitor_printf(mon, "too many keys\n");
- return;
- }
- keyname_buf[keyname_len] = 0;
- keycode = get_keycode(keyname_buf);
- if (keycode < 0) {
- monitor_printf(mon, "unknown key: '%s'\n", keyname_buf);
- return;
- }
- keycodes[i++] = keycode;
- }
- if (!separator)
- break;
- string = separator + 1;
- }
- nb_pending_keycodes = i;
- /* key down events */
- for (i = 0; i < nb_pending_keycodes; i++) {
- keycode = keycodes[i];
- if (keycode & 0x80)
- kbd_put_keycode(0xe0);
- kbd_put_keycode(keycode & 0x7f);
- }
- /* delayed key up events */
- qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) +
- muldiv64(get_ticks_per_sec(), hold_time, 1000));
-}
-
static int mouse_button_state;
static void do_mouse_move(Monitor *mon, const QDict *qdict)
@@ -2672,6 +2428,24 @@ int monitor_fdset_dup_fd_remove(int dup_fd)
return monitor_fdset_dup_fd_find_remove(dup_fd, true);
}
+int monitor_handle_fd_param(Monitor *mon, const char *fdname)
+{
+ int fd;
+
+ if (!qemu_isdigit(fdname[0]) && mon) {
+
+ fd = monitor_get_fd(mon, fdname);
+ if (fd == -1) {
+ error_report("No file descriptor named %s found", fdname);
+ return -1;
+ }
+ } else {
+ fd = qemu_parse_fd(fdname);
+ }
+
+ return fd;
+}
+
/* mon_cmds and info_cmds would be sorted at runtime */
static mon_cmd_t mon_cmds[] = {
#include "hmp-commands.h"
@@ -4336,7 +4110,6 @@ static void monitor_find_completion(const char *cmdline)
int nb_args, i, len;
const char *ptype, *str;
const mon_cmd_t *cmd;
- const KeyDef *key;
parse_cmdline(cmdline, &nb_args, args);
#ifdef DEBUG_COMPLETION
@@ -4410,8 +4183,8 @@ static void monitor_find_completion(const char *cmdline)
if (sep)
str = sep + 1;
readline_set_completion_index(cur_mon->rs, strlen(str));
- for(key = key_defs; key->name != NULL; key++) {
- cmd_completion(str, key->name);
+ for (i = 0; i < Q_KEY_CODE_MAX; i++) {
+ cmd_completion(str, QKeyCode_lookup[i]);
}
} else if (!strcmp(cmd->name, "help|?")) {
readline_set_completion_index(cur_mon->rs, strlen(str));
@@ -4947,7 +4720,6 @@ void monitor_init(CharDriverState *chr, int flags)
Monitor *mon;
if (is_first_init) {
- key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
monitor_protocol_event_init();
is_first_init = 0;
}
diff --git a/monitor.h b/monitor.h
index 47d556b9d..64c156184 100644
--- a/monitor.h
+++ b/monitor.h
@@ -43,6 +43,7 @@ typedef enum MonitorEvent {
QEVENT_SUSPEND_DISK,
QEVENT_WAKEUP,
QEVENT_BALLOON_CHANGE,
+ QEVENT_SPICE_MIGRATE_COMPLETED,
/* Add to 'monitor_event_names' array in monitor.c when
* defining new events here */
@@ -66,6 +67,7 @@ int monitor_read_block_device_key(Monitor *mon, const char *device,
void *opaque);
int monitor_get_fd(Monitor *mon, const char *fdname);
+int monitor_handle_fd_param(Monitor *mon, const char *fdname);
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
GCC_FMT_ATTR(2, 0);
diff --git a/net.c b/net.c
index 60043ddec..e5d25d4b6 100644
--- a/net.c
+++ b/net.c
@@ -522,24 +522,6 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
return -1;
}
-int net_handle_fd_param(Monitor *mon, const char *param)
-{
- int fd;
-
- if (!qemu_isdigit(param[0]) && mon) {
-
- fd = monitor_get_fd(mon, param);
- if (fd == -1) {
- error_report("No file descriptor named %s found", param);
- return -1;
- }
- } else {
- fd = qemu_parse_fd(param);
- }
-
- return fd;
-}
-
static int net_init_nic(const NetClientOptions *opts, const char *name,
NetClientState *peer)
{
diff --git a/net.h b/net.h
index 29750567e..04fda1d6c 100644
--- a/net.h
+++ b/net.h
@@ -168,8 +168,6 @@ int qmp_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret);
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
-int net_handle_fd_param(Monitor *mon, const char *param);
-
#define POLYNOMIAL 0x04c11db6
unsigned compute_mcast_idx(const uint8_t *ep);
diff --git a/net/socket.c b/net/socket.c
index c172c249b..7c602e4c3 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -629,7 +629,7 @@ int net_init_socket(const NetClientOptions *opts, const char *name,
if (sock->has_fd) {
int fd;
- fd = net_handle_fd_param(cur_mon, sock->fd);
+ fd = monitor_handle_fd_param(cur_mon, sock->fd);
if (fd == -1 || !net_socket_fd_init(peer, "socket", name, fd, 1)) {
return -1;
}
diff --git a/net/tap.c b/net/tap.c
index 197152579..a88ae8f61 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -610,7 +610,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
return -1;
}
- fd = net_handle_fd_param(cur_mon, tap->fd);
+ fd = monitor_handle_fd_param(cur_mon, tap->fd);
if (fd == -1) {
return -1;
}
@@ -686,7 +686,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
int vhostfd;
if (tap->has_vhostfd) {
- vhostfd = net_handle_fd_param(cur_mon, tap->vhostfd);
+ vhostfd = monitor_handle_fd_param(cur_mon, tap->vhostfd);
if (vhostfd == -1) {
return -1;
}
diff --git a/qapi-schema.json b/qapi-schema.json
index bd8ad7449..a9f465a9f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -808,6 +808,9 @@
#
# @enabled: true if the SPICE server is enabled, false otherwise
#
+# @migrated: true if the last guest migration completed and spice
+# migration had completed as well. false otherwise.
+#
# @host: #optional The hostname the SPICE server is bound to. This depends on
# the name resolution on the host and may be an IP address.
#
@@ -833,7 +836,7 @@
# Since: 0.14.0
##
{ 'type': 'SpiceInfo',
- 'data': {'enabled': 'bool', '*host': 'str', '*port': 'int',
+ 'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
@@ -2493,3 +2496,62 @@
# Since: 1.2.0
##
{ 'command': 'query-target', 'returns': 'TargetInfo' }
+
+##
+# @QKeyCode:
+#
+# An enumeration of key name.
+#
+# This is used by the send-key command.
+#
+# Since: 1.3.0
+##
+{ 'enum': 'QKeyCode',
+ 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl',
+ 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e',
+ 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right',
+ 'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'semicolon',
+ 'apostrophe', 'grave_accent', 'backslash', 'z', 'x', 'c', 'v', 'b',
+ 'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', 'caps_lock',
+ 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10',
+ 'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply',
+ 'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', 'sysrq', 'kp_0',
+ 'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', 'kp_7', 'kp_8',
+ 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end',
+ 'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again',
+ 'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut',
+ 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] }
+
+##
+# @send-key:
+#
+# Send keys to guest.
+#
+# @keys: key sequence. 'keys' is the name of the key. Use a JSON array to
+# press several keys simultaneously.
+#
+# @hold-time: #optional time to delay key up events, milliseconds. Defaults
+# to 100
+#
+# Returns: Nothing on success
+# If key is unknown or redundant, InvalidParameter
+#
+# Since: 1.3.0
+#
+##
+{ 'command': 'send-key',
+ 'data': { 'keys': ['QKeyCode'], '*hold-time': 'int' } }
+
+##
+# @screendump:
+#
+# Write a PPM of the VGA screen to a file.
+#
+# @filename: the path of a new PPM file to store the image
+#
+# Returns: Nothing on success
+#
+# Since: 0.14.0
+##
+{ 'command': 'screendump', 'data': {'filename': 'str'} }
diff --git a/qemu-char.c b/qemu-char.c
index 398baf1e0..767da9386 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2148,10 +2148,12 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
TCPCharDriver *s = chr->opaque;
if (s->connected) {
return send_all(s->fd, buf, len);
- } else {
+ } else if (s->listen_fd == -1) {
/* (Re-)connect for unconnected writing */
tcp_chr_connect(chr);
return 0;
+ } else {
+ return len;
}
}
diff --git a/qemu-config.c b/qemu-config.c
index 238390e81..3eaee489f 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -541,6 +541,9 @@ QemuOptsList qemu_spice_opts = {
},{
.name = "playback-compression",
.type = QEMU_OPT_BOOL,
+ }, {
+ .name = "seamless-migration",
+ .type = QEMU_OPT_BOOL,
},
{ /* end of list */ }
},
diff --git a/qemu-options.hx b/qemu-options.hx
index ea06324e5..1af4fecf7 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -838,7 +838,23 @@ Enable SDL.
ETEXI
DEF("spice", HAS_ARG, QEMU_OPTION_spice,
- "-spice <args> enable spice\n", QEMU_ARCH_ALL)
+ "-spice [port=port][,tls-port=secured-port][,x509-dir=<dir>]\n"
+ " [,x509-key-file=<file>][,x509-key-password=<file>]\n"
+ " [,x509-cert-file=<file>][,x509-cacert-file=<file>]\n"
+ " [,x509-dh-key-file=<file>][,addr=addr][,ipv4|ipv6]\n"
+ " [,tls-ciphers=<list>]\n"
+ " [,tls-channel=[main|display|cursor|inputs|record|playback]]\n"
+ " [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n"
+ " [,sasl][,password=<secret>][,disable-ticketing]\n"
+ " [,image-compression=[auto_glz|auto_lz|quic|glz|lz|off]]\n"
+ " [,jpeg-wan-compression=[auto|never|always]]\n"
+ " [,zlib-glz-wan-compression=[auto|never|always]]\n"
+ " [,streaming-video=[off|all|filter]][,disable-copy-paste]\n"
+ " [,agent-mouse=[on|off]][,playback-compression=[on|off]]\n"
+ " [,seamless-migration=[on|off]]\n"
+ " enable spice\n"
+ " at least one of {port, tls-port} is mandatory\n",
+ QEMU_ARCH_ALL)
STEXI
@item -spice @var{option}[,@var{option}[,...]]
@findex -spice
@@ -920,6 +936,9 @@ Enable/disable passing mouse events via vdagent. Default is on.
@item playback-compression=[on|off]
Enable/disable audio stream compression (using celt 0.5.1). Default is on.
+@item seamless-migration=[on|off]
+Enable/disable spice seamless migration. Default is off.
+
@end table
ETEXI
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 3745a2119..6e21ddba6 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -146,10 +146,7 @@ EQMP
{
.name = "screendump",
.args_type = "filename:F",
- .params = "filename",
- .help = "save screen into PPM image 'filename'",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_screen_dump,
+ .mhandler.cmd_new = qmp_marshal_input_screendump,
},
SQMP
@@ -335,6 +332,34 @@ Example:
EQMP
{
+ .name = "send-key",
+ .args_type = "keys:O,hold-time:i?",
+ .mhandler.cmd_new = qmp_marshal_input_send_key,
+ },
+
+SQMP
+send-key
+----------
+
+Send keys to VM.
+
+Arguments:
+
+keys array:
+ - "key": key sequence (a json-array of key enum values)
+
+- hold-time: time to delay key up events, milliseconds. Defaults to 100
+ (json-int, optional)
+
+Example:
+
+-> { "execute": "send-key",
+ "arguments": { 'keys': [ 'ctrl', 'alt', 'delete' ] } }
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "cpu",
.args_type = "index:i",
.mhandler.cmd_new = qmp_marshal_input_cpu,
diff --git a/qobject.h b/qobject.h
index d42386dde..9124649ed 100644
--- a/qobject.h
+++ b/qobject.h
@@ -71,7 +71,7 @@ typedef struct QObject {
/* High-level interface for qobject_decref() */
#define QDECREF(obj) \
- qobject_decref(QOBJECT(obj))
+ qobject_decref(obj ? QOBJECT(obj) : NULL)
/* Initialize an object to default values */
#define QOBJECT_INIT(obj, qtype_type) \
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index b98dc6cad..ec0aa4cd9 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -97,6 +97,9 @@ my $dbg_values = 0;
my $dbg_possible = 0;
my $dbg_type = 0;
my $dbg_attr = 0;
+my $dbg_adv_dcs = 0;
+my $dbg_adv_checking = 0;
+my $dbg_adv_apw = 0;
for my $key (keys %debug) {
## no critic
eval "\${dbg_$key} = '$debug{$key}';";
@@ -2486,8 +2489,11 @@ sub process {
if ($line =~ /(^.*)\bif\b/ && $line !~ /\#\s*if/) {
my ($level, $endln, @chunks) =
ctx_statement_full($linenr, $realcnt, 1);
- #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
- #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+ if ($dbg_adv_apw) {
+ print "APW: chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
+ print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"
+ if $#chunks >= 1;
+ }
if ($#chunks >= 0 && $level == 0) {
my $allowed = 0;
my $seen = 0;
@@ -2512,18 +2518,22 @@ sub process {
$seen++ if ($block =~ /^\s*{/);
- #print "cond<$cond> block<$block> allowed<$allowed>\n";
+ print "APW: cond<$cond> block<$block> allowed<$allowed>\n"
+ if $dbg_adv_apw;
if (statement_lines($cond) > 1) {
- #print "APW: ALLOWED: cond<$cond>\n";
- $allowed = 1;
+ print "APW: ALLOWED: cond<$cond>\n"
+ if $dbg_adv_apw;
+ $allowed = 1;
}
if ($block =~/\b(?:if|for|while)\b/) {
- #print "APW: ALLOWED: block<$block>\n";
- $allowed = 1;
+ print "APW: ALLOWED: block<$block>\n"
+ if $dbg_adv_apw;
+ $allowed = 1;
}
if (statement_block_size($block) > 1) {
- #print "APW: ALLOWED: lines block<$block>\n";
- $allowed = 1;
+ print "APW: ALLOWED: lines block<$block>\n"
+ if $dbg_adv_apw;
+ $allowed = 1;
}
}
if ($seen != ($#chunks + 1)) {
@@ -2537,32 +2547,41 @@ sub process {
$line !~ /\#\s*else/) {
my $allowed = 0;
- # Check the pre-context.
- if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
- #print "APW: ALLOWED: pre<$1>\n";
- $allowed = 1;
- }
+ # Check the pre-context.
+ if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+ my $pre = $1;
+
+ if ($line !~ /else/) {
+ print "APW: ALLOWED: pre<$pre> line<$line>\n"
+ if $dbg_adv_apw;
+ $allowed = 1;
+ }
+ }
my ($level, $endln, @chunks) =
ctx_statement_full($linenr, $realcnt, $-[0]);
# Check the condition.
my ($cond, $block) = @{$chunks[0]};
- #print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+ print "CHECKING<$linenr> cond<$cond> block<$block>\n"
+ if $dbg_adv_checking;
if (defined $cond) {
substr($block, 0, length($cond), '');
}
if (statement_lines($cond) > 1) {
- #print "APW: ALLOWED: cond<$cond>\n";
- $allowed = 1;
+ print "APW: ALLOWED: cond<$cond>\n"
+ if $dbg_adv_apw;
+ $allowed = 1;
}
if ($block =~/\b(?:if|for|while)\b/) {
- #print "APW: ALLOWED: block<$block>\n";
- $allowed = 1;
+ print "APW: ALLOWED: block<$block>\n"
+ if $dbg_adv_apw;
+ $allowed = 1;
}
if (statement_block_size($block) > 1) {
- #print "APW: ALLOWED: lines block<$block>\n";
- $allowed = 1;
+ print "APW: ALLOWED: lines block<$block>\n"
+ if $dbg_adv_apw;
+ $allowed = 1;
}
# Check the post-context.
if (defined $chunks[1]) {
@@ -2571,10 +2590,13 @@ sub process {
substr($block, 0, length($cond), '');
}
if ($block =~ /^\s*\{/) {
- #print "APW: ALLOWED: chunk-1 block<$block>\n";
- $allowed = 1;
+ print "APW: ALLOWED: chunk-1 block<$block>\n"
+ if $dbg_adv_apw;
+ $allowed = 1;
}
}
+ print "DCS: level=$level block<$block> allowed=$allowed\n"
+ if $dbg_adv_dcs;
if ($level == 0 && $block !~ /^\s*\{/ && !$allowed) {
my $herectx = $here . "\n";;
my $cnt = statement_rawlines($block);
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index cf601ae2d..49ef569a2 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -28,6 +28,16 @@ typedef struct %(name)sList
''',
name=name)
+def generate_fwd_enum_struct(name, members):
+ return mcgen('''
+typedef struct %(name)sList
+{
+ %(name)s value;
+ struct %(name)sList *next;
+} %(name)sList;
+''',
+ name=name)
+
def generate_struct(structname, fieldname, members):
ret = mcgen('''
struct %(name)s
@@ -276,7 +286,8 @@ for expr in exprs:
if expr.has_key('type'):
ret += generate_fwd_struct(expr['type'], expr['data'])
elif expr.has_key('enum'):
- ret += generate_enum(expr['enum'], expr['data'])
+ ret += generate_enum(expr['enum'], expr['data']) + "\n"
+ ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
elif expr.has_key('union'):
ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
@@ -300,6 +311,9 @@ for expr in exprs:
fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
ret += generate_type_cleanup_decl(expr['union'])
fdef.write(generate_type_cleanup(expr['union']) + "\n")
+ elif expr.has_key('enum'):
+ ret += generate_type_cleanup_decl(expr['enum'] + "List")
+ fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
else:
continue
fdecl.write(ret)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 04ef7c41a..e2093e894 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -157,7 +157,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
if (!error_is_set(errp)) {
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
if (!err) {
- if (!obj || *obj) {
+ if (obj && *obj) {
visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
if (!err) {
switch ((*obj)->kind) {
@@ -217,6 +217,16 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name,
return ret
+def generate_enum_declaration(name, members, genlist=True):
+ ret = ""
+ if genlist:
+ ret += mcgen('''
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
+''',
+ name=name)
+
+ return ret
+
def generate_decl_enum(name, members, genlist=True):
return mcgen('''
@@ -335,10 +345,12 @@ for expr in exprs:
ret += generate_declaration(expr['union'], expr['data'])
fdecl.write(ret)
elif expr.has_key('enum'):
- ret = generate_visit_enum(expr['enum'], expr['data'])
+ ret = generate_visit_list(expr['enum'], expr['data'])
+ ret += generate_visit_enum(expr['enum'], expr['data'])
fdef.write(ret)
ret = generate_decl_enum(expr['enum'], expr['data'])
+ ret += generate_enum_declaration(expr['enum'], expr['data'])
fdecl.write(ret)
fdecl.write('''
diff --git a/target-arm/helper.c b/target-arm/helper.c
index dceaa95c8..e27df9627 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -645,7 +645,7 @@ static int pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri,
static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t *value)
{
- if (ri->crm > 8) {
+ if (ri->crm >= 8) {
return EXCP_UDEF;
}
*value = env->cp15.c6_region[ri->crm];
@@ -655,7 +655,7 @@ static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri,
static int arm946_prbs_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
- if (ri->crm > 8) {
+ if (ri->crm >= 8) {
return EXCP_UDEF;
}
env->cp15.c6_region[ri->crm] = value;
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 1ad9ec788..ad3187773 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3458,7 +3458,7 @@ void cpu_dump_state (CPUCRISState *env, FILE *f, fprintf_function cpu_fprintf,
}
srs = env->pregs[PR_SRS];
cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs);
- if (srs < 256) {
+ if (srs < ARRAY_SIZE(env->sregs)) {
for (i = 0; i < 16; i++) {
cpu_fprintf(f, "s%2.2d=%8.8x ",
i, env->sregs[srs][i]);
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index ce3467f14..88d92f118 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -742,4 +742,53 @@ static inline void cpu_pc_from_tb(CPUMIPSState *env, TranslationBlock *tb)
env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
}
+static inline void compute_hflags(CPUMIPSState *env)
+{
+ env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
+ MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
+ MIPS_HFLAG_UX);
+ if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+ !(env->CP0_Status & (1 << CP0St_ERL)) &&
+ !(env->hflags & MIPS_HFLAG_DM)) {
+ env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
+ }
+#if defined(TARGET_MIPS64)
+ if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
+ (env->CP0_Status & (1 << CP0St_PX)) ||
+ (env->CP0_Status & (1 << CP0St_UX))) {
+ env->hflags |= MIPS_HFLAG_64;
+ }
+ if (env->CP0_Status & (1 << CP0St_UX)) {
+ env->hflags |= MIPS_HFLAG_UX;
+ }
+#endif
+ if ((env->CP0_Status & (1 << CP0St_CU0)) ||
+ !(env->hflags & MIPS_HFLAG_KSU)) {
+ env->hflags |= MIPS_HFLAG_CP0;
+ }
+ if (env->CP0_Status & (1 << CP0St_CU1)) {
+ env->hflags |= MIPS_HFLAG_FPU;
+ }
+ if (env->CP0_Status & (1 << CP0St_FR)) {
+ env->hflags |= MIPS_HFLAG_F64;
+ }
+ if (env->insn_flags & ISA_MIPS32R2) {
+ if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
+ env->hflags |= MIPS_HFLAG_COP1X;
+ }
+ } else if (env->insn_flags & ISA_MIPS32) {
+ if (env->hflags & MIPS_HFLAG_64) {
+ env->hflags |= MIPS_HFLAG_COP1X;
+ }
+ } else if (env->insn_flags & ISA_MIPS4) {
+ /* All supported MIPS IV CPUs use the XX (CU3) to enable
+ and disable the MIPS IV extensions to the MIPS III ISA.
+ Some other MIPS IV CPUs ignore the bit, so the check here
+ would be too restrictive for them. */
+ if (env->CP0_Status & (1 << CP0St_CU3)) {
+ env->hflags |= MIPS_HFLAG_COP1X;
+ }
+ }
+}
+
#endif /* !defined (__MIPS_CPU_H__) */
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index e5bc93e22..3d242aafd 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -32,55 +32,6 @@
static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
#endif
-static inline void compute_hflags(CPUMIPSState *env)
-{
- env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
- MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
- MIPS_HFLAG_UX);
- if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
- !(env->CP0_Status & (1 << CP0St_ERL)) &&
- !(env->hflags & MIPS_HFLAG_DM)) {
- env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
- }
-#if defined(TARGET_MIPS64)
- if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
- (env->CP0_Status & (1 << CP0St_PX)) ||
- (env->CP0_Status & (1 << CP0St_UX))) {
- env->hflags |= MIPS_HFLAG_64;
- }
- if (env->CP0_Status & (1 << CP0St_UX)) {
- env->hflags |= MIPS_HFLAG_UX;
- }
-#endif
- if ((env->CP0_Status & (1 << CP0St_CU0)) ||
- !(env->hflags & MIPS_HFLAG_KSU)) {
- env->hflags |= MIPS_HFLAG_CP0;
- }
- if (env->CP0_Status & (1 << CP0St_CU1)) {
- env->hflags |= MIPS_HFLAG_FPU;
- }
- if (env->CP0_Status & (1 << CP0St_FR)) {
- env->hflags |= MIPS_HFLAG_F64;
- }
- if (env->insn_flags & ISA_MIPS32R2) {
- if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
- env->hflags |= MIPS_HFLAG_COP1X;
- }
- } else if (env->insn_flags & ISA_MIPS32) {
- if (env->hflags & MIPS_HFLAG_64) {
- env->hflags |= MIPS_HFLAG_COP1X;
- }
- } else if (env->insn_flags & ISA_MIPS4) {
- /* All supported MIPS IV CPUs use the XX (CU3) to enable
- and disable the MIPS IV extensions to the MIPS III ISA.
- Some other MIPS IV CPUs ignore the bit, so the check here
- would be too restrictive for them. */
- if (env->CP0_Status & (1 << CP0St_CU3)) {
- env->hflags |= MIPS_HFLAG_COP1X;
- }
- }
-}
-
/*****************************************************************************/
/* Exceptions processing helpers */
diff --git a/target-mips/translate.c b/target-mips/translate.c
index b29341953..a884f751b 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -12787,18 +12787,13 @@ void cpu_state_reset(CPUMIPSState *env)
env->insn_flags = env->cpu_model->insn_flags;
#if defined(CONFIG_USER_ONLY)
- env->hflags = MIPS_HFLAG_UM;
+ env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
/* Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
hardware registers. */
env->CP0_HWREna |= 0x0000000F;
if (env->CP0_Config1 & (1 << CP0C1_FP)) {
- env->hflags |= MIPS_HFLAG_FPU;
+ env->CP0_Status |= (1 << CP0St_CU1);
}
-#ifdef TARGET_MIPS64
- if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
- env->hflags |= MIPS_HFLAG_F64;
- }
-#endif
#else
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot,
@@ -12828,7 +12823,6 @@ void cpu_state_reset(CPUMIPSState *env)
}
/* Count register increments in debug mode, EJTAG version 1 */
env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
- env->hflags = MIPS_HFLAG_CP0;
if (env->CP0_Config3 & (1 << CP0C3_MT)) {
int i;
@@ -12856,11 +12850,7 @@ void cpu_state_reset(CPUMIPSState *env)
}
}
#endif
-#if defined(TARGET_MIPS64)
- if (env->cpu_model->insn_flags & ISA_MIPS3) {
- env->hflags |= MIPS_HFLAG_64;
- }
-#endif
+ compute_hflags(env);
env->exception_index = EXCP_NONE;
}
diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs
index 80be3bbdb..e728abf75 100644
--- a/target-s390x/Makefile.objs
+++ b/target-s390x/Makefile.objs
@@ -1,5 +1,4 @@
-obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o
+obj-y += translate.o helper.o cpu.o interrupt.o
+obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o
-
-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c
new file mode 100644
index 000000000..19ef145da
--- /dev/null
+++ b/target-s390x/cc_helper.c
@@ -0,0 +1,550 @@
+/*
+ * S/390 condition code helper routines
+ *
+ * Copyright (c) 2009 Ulrich Hecht
+ * Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src,
+ int32_t dst)
+{
+ if (src == dst) {
+ return 0;
+ } else if (src < dst) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst)
+{
+ return cc_calc_ltgt_32(env, dst, 0);
+}
+
+static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src,
+ int64_t dst)
+{
+ if (src == dst) {
+ return 0;
+ } else if (src < dst) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst)
+{
+ return cc_calc_ltgt_64(env, dst, 0);
+}
+
+static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src,
+ uint32_t dst)
+{
+ if (src == dst) {
+ return 0;
+ } else if (src < dst) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
+ uint64_t dst)
+{
+ if (src == dst) {
+ return 0;
+ } else if (src < dst) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val,
+ uint32_t mask)
+{
+ uint16_t r = val & mask;
+
+ HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask);
+ if (r == 0 || mask == 0) {
+ return 0;
+ } else if (r == mask) {
+ return 3;
+ } else {
+ return 1;
+ }
+}
+
+/* set condition code for test under mask */
+static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val,
+ uint32_t mask)
+{
+ uint16_t r = val & mask;
+
+ HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r);
+ if (r == 0 || mask == 0) {
+ return 0;
+ } else if (r == mask) {
+ return 3;
+ } else {
+ while (!(mask & 0x8000)) {
+ mask <<= 1;
+ val <<= 1;
+ }
+ if (val & 0x8000) {
+ return 2;
+ } else {
+ return 1;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst)
+{
+ return !!dst;
+}
+
+static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1,
+ int64_t a2, int64_t ar)
+{
+ if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
+ return 3; /* overflow */
+ } else {
+ if (ar < 0) {
+ return 1;
+ } else if (ar > 0) {
+ return 2;
+ } else {
+ return 0;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1,
+ uint64_t a2, uint64_t ar)
+{
+ if (ar == 0) {
+ if (a1) {
+ return 2;
+ } else {
+ return 0;
+ }
+ } else {
+ if (ar < a1 || ar < a2) {
+ return 3;
+ } else {
+ return 1;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1,
+ int64_t a2, int64_t ar)
+{
+ if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
+ return 3; /* overflow */
+ } else {
+ if (ar < 0) {
+ return 1;
+ } else if (ar > 0) {
+ return 2;
+ } else {
+ return 0;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1,
+ uint64_t a2, uint64_t ar)
+{
+ if (ar == 0) {
+ return 2;
+ } else {
+ if (a2 > a1) {
+ return 1;
+ } else {
+ return 3;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
+{
+ if ((uint64_t)dst == 0x8000000000000000ULL) {
+ return 3;
+ } else if (dst) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst)
+{
+ return !!dst;
+}
+
+static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst)
+{
+ if ((uint64_t)dst == 0x8000000000000000ULL) {
+ return 3;
+ } else if (dst < 0) {
+ return 1;
+ } else if (dst > 0) {
+ return 2;
+ } else {
+ return 0;
+ }
+}
+
+
+static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1,
+ int32_t a2, int32_t ar)
+{
+ if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
+ return 3; /* overflow */
+ } else {
+ if (ar < 0) {
+ return 1;
+ } else if (ar > 0) {
+ return 2;
+ } else {
+ return 0;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1,
+ uint32_t a2, uint32_t ar)
+{
+ if (ar == 0) {
+ if (a1) {
+ return 2;
+ } else {
+ return 0;
+ }
+ } else {
+ if (ar < a1 || ar < a2) {
+ return 3;
+ } else {
+ return 1;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1,
+ int32_t a2, int32_t ar)
+{
+ if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
+ return 3; /* overflow */
+ } else {
+ if (ar < 0) {
+ return 1;
+ } else if (ar > 0) {
+ return 2;
+ } else {
+ return 0;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1,
+ uint32_t a2, uint32_t ar)
+{
+ if (ar == 0) {
+ return 2;
+ } else {
+ if (a2 > a1) {
+ return 1;
+ } else {
+ return 3;
+ }
+ }
+}
+
+static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
+{
+ if ((uint32_t)dst == 0x80000000UL) {
+ return 3;
+ } else if (dst) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst)
+{
+ return !!dst;
+}
+
+static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst)
+{
+ if ((uint32_t)dst == 0x80000000UL) {
+ return 3;
+ } else if (dst < 0) {
+ return 1;
+ } else if (dst > 0) {
+ return 2;
+ } else {
+ return 0;
+ }
+}
+
+/* calculate condition code for insert character under mask insn */
+static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask,
+ uint32_t val)
+{
+ uint32_t cc;
+
+ HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val);
+ if (mask == 0xf) {
+ if (!val) {
+ return 0;
+ } else if (val & 0x80000000) {
+ return 1;
+ } else {
+ return 2;
+ }
+ }
+
+ if (!val || !mask) {
+ cc = 0;
+ } else {
+ while (mask != 1) {
+ mask >>= 1;
+ val >>= 8;
+ }
+ if (val & 0x80) {
+ cc = 1;
+ } else {
+ cc = 2;
+ }
+ }
+ return cc;
+}
+
+static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src,
+ uint64_t shift)
+{
+ uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
+ uint64_t match, r;
+
+ /* check if the sign bit stays the same */
+ if (src & (1ULL << 63)) {
+ match = mask;
+ } else {
+ match = 0;
+ }
+
+ if ((src & mask) != match) {
+ /* overflow */
+ return 3;
+ }
+
+ r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
+
+ if ((int64_t)r == 0) {
+ return 0;
+ } else if ((int64_t)r < 0) {
+ return 1;
+ }
+
+ return 2;
+}
+
+
+static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
+ uint64_t src, uint64_t dst, uint64_t vr)
+{
+ uint32_t r = 0;
+
+ switch (cc_op) {
+ case CC_OP_CONST0:
+ case CC_OP_CONST1:
+ case CC_OP_CONST2:
+ case CC_OP_CONST3:
+ /* cc_op value _is_ cc */
+ r = cc_op;
+ break;
+ case CC_OP_LTGT0_32:
+ r = cc_calc_ltgt0_32(env, dst);
+ break;
+ case CC_OP_LTGT0_64:
+ r = cc_calc_ltgt0_64(env, dst);
+ break;
+ case CC_OP_LTGT_32:
+ r = cc_calc_ltgt_32(env, src, dst);
+ break;
+ case CC_OP_LTGT_64:
+ r = cc_calc_ltgt_64(env, src, dst);
+ break;
+ case CC_OP_LTUGTU_32:
+ r = cc_calc_ltugtu_32(env, src, dst);
+ break;
+ case CC_OP_LTUGTU_64:
+ r = cc_calc_ltugtu_64(env, src, dst);
+ break;
+ case CC_OP_TM_32:
+ r = cc_calc_tm_32(env, src, dst);
+ break;
+ case CC_OP_TM_64:
+ r = cc_calc_tm_64(env, src, dst);
+ break;
+ case CC_OP_NZ:
+ r = cc_calc_nz(env, dst);
+ break;
+ case CC_OP_ADD_64:
+ r = cc_calc_add_64(env, src, dst, vr);
+ break;
+ case CC_OP_ADDU_64:
+ r = cc_calc_addu_64(env, src, dst, vr);
+ break;
+ case CC_OP_SUB_64:
+ r = cc_calc_sub_64(env, src, dst, vr);
+ break;
+ case CC_OP_SUBU_64:
+ r = cc_calc_subu_64(env, src, dst, vr);
+ break;
+ case CC_OP_ABS_64:
+ r = cc_calc_abs_64(env, dst);
+ break;
+ case CC_OP_NABS_64:
+ r = cc_calc_nabs_64(env, dst);
+ break;
+ case CC_OP_COMP_64:
+ r = cc_calc_comp_64(env, dst);
+ break;
+
+ case CC_OP_ADD_32:
+ r = cc_calc_add_32(env, src, dst, vr);
+ break;
+ case CC_OP_ADDU_32:
+ r = cc_calc_addu_32(env, src, dst, vr);
+ break;
+ case CC_OP_SUB_32:
+ r = cc_calc_sub_32(env, src, dst, vr);
+ break;
+ case CC_OP_SUBU_32:
+ r = cc_calc_subu_32(env, src, dst, vr);
+ break;
+ case CC_OP_ABS_32:
+ r = cc_calc_abs_64(env, dst);
+ break;
+ case CC_OP_NABS_32:
+ r = cc_calc_nabs_64(env, dst);
+ break;
+ case CC_OP_COMP_32:
+ r = cc_calc_comp_32(env, dst);
+ break;
+
+ case CC_OP_ICM:
+ r = cc_calc_icm_32(env, src, dst);
+ break;
+ case CC_OP_SLAG:
+ r = cc_calc_slag(env, src, dst);
+ break;
+
+ case CC_OP_LTGT_F32:
+ r = set_cc_f32(env, src, dst);
+ break;
+ case CC_OP_LTGT_F64:
+ r = set_cc_f64(env, src, dst);
+ break;
+ case CC_OP_NZ_F32:
+ r = set_cc_nz_f32(dst);
+ break;
+ case CC_OP_NZ_F64:
+ r = set_cc_nz_f64(dst);
+ break;
+
+ default:
+ cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
+ }
+
+ HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
+ cc_name(cc_op), src, dst, vr, r);
+ return r;
+}
+
+uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
+ uint64_t vr)
+{
+ return do_calc_cc(env, cc_op, src, dst, vr);
+}
+
+uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
+ uint64_t dst, uint64_t vr)
+{
+ return do_calc_cc(env, cc_op, src, dst, vr);
+}
+
+/* insert psw mask and condition code into r1 */
+void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1)
+{
+ uint64_t r = env->regs[r1];
+
+ r &= 0xffffffff00ffffffULL;
+ r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf);
+ env->regs[r1] = r;
+ HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__,
+ cc, env->psw.mask, r);
+}
+
+#ifndef CONFIG_USER_ONLY
+void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
+{
+ load_psw(env, mask, addr);
+ cpu_loop_exit(env);
+}
+
+void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
+{
+ HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
+
+ switch (a1 & 0xf00) {
+ case 0x000:
+ env->psw.mask &= ~PSW_MASK_ASC;
+ env->psw.mask |= PSW_ASC_PRIMARY;
+ break;
+ case 0x100:
+ env->psw.mask &= ~PSW_MASK_ASC;
+ env->psw.mask |= PSW_ASC_SECONDARY;
+ break;
+ case 0x300:
+ env->psw.mask &= ~PSW_MASK_ASC;
+ env->psw.mask |= PSW_ASC_HOME;
+ break;
+ default:
+ qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
+ program_interrupt(env, PGM_SPECIFICATION, 2);
+ break;
+ }
+}
+#endif
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 18ac6e393..ed81af33a 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -999,4 +999,13 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb)
env->psw.addr = tb->pc;
}
+/* fpu_helper.c */
+uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2);
+uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2);
+uint32_t set_cc_nz_f32(float32 v);
+uint32_t set_cc_nz_f64(float64 v);
+
+/* misc_helper.c */
+void program_interrupt(CPUS390XState *env, uint32_t code, int ilc);
+
#endif
diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c
new file mode 100644
index 000000000..ee9420d44
--- /dev/null
+++ b/target-s390x/fpu_helper.c
@@ -0,0 +1,843 @@
+/*
+ * S/390 FPU helper routines
+ *
+ * Copyright (c) 2009 Ulrich Hecht
+ * Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
+{
+ switch (float_compare) {
+ case float_relation_equal:
+ return 0;
+ case float_relation_less:
+ return 1;
+ case float_relation_greater:
+ return 2;
+ case float_relation_unordered:
+ return 3;
+ default:
+ cpu_abort(env, "unknown return value for float compare\n");
+ }
+}
+
+/* condition codes for binary FP ops */
+uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2)
+{
+ return float_comp_to_cc(env, float32_compare_quiet(v1, v2,
+ &env->fpu_status));
+}
+
+uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2)
+{
+ return float_comp_to_cc(env, float64_compare_quiet(v1, v2,
+ &env->fpu_status));
+}
+
+/* condition codes for unary FP ops */
+uint32_t set_cc_nz_f32(float32 v)
+{
+ if (float32_is_any_nan(v)) {
+ return 3;
+ } else if (float32_is_zero(v)) {
+ return 0;
+ } else if (float32_is_neg(v)) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+uint32_t set_cc_nz_f64(float64 v)
+{
+ if (float64_is_any_nan(v)) {
+ return 3;
+ } else if (float64_is_zero(v)) {
+ return 0;
+ } else if (float64_is_neg(v)) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+static uint32_t set_cc_nz_f128(float128 v)
+{
+ if (float128_is_any_nan(v)) {
+ return 3;
+ } else if (float128_is_zero(v)) {
+ return 0;
+ } else if (float128_is_neg(v)) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+/* convert 32-bit int to 64-bit float */
+void HELPER(cdfbr)(CPUS390XState *env, uint32_t f1, int32_t v2)
+{
+ HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1);
+ env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status);
+}
+
+/* convert 32-bit int to 128-bit float */
+void HELPER(cxfbr)(CPUS390XState *env, uint32_t f1, int32_t v2)
+{
+ CPU_QuadU v1;
+
+ v1.q = int32_to_float128(v2, &env->fpu_status);
+ env->fregs[f1].ll = v1.ll.upper;
+ env->fregs[f1 + 2].ll = v1.ll.lower;
+}
+
+/* convert 64-bit int to 32-bit float */
+void HELPER(cegbr)(CPUS390XState *env, uint32_t f1, int64_t v2)
+{
+ HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1);
+ env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status);
+}
+
+/* convert 64-bit int to 64-bit float */
+void HELPER(cdgbr)(CPUS390XState *env, uint32_t f1, int64_t v2)
+{
+ HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1);
+ env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status);
+}
+
+/* convert 64-bit int to 128-bit float */
+void HELPER(cxgbr)(CPUS390XState *env, uint32_t f1, int64_t v2)
+{
+ CPU_QuadU x1;
+
+ x1.q = int64_to_float128(v2, &env->fpu_status);
+ HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2,
+ x1.ll.upper, x1.ll.lower);
+ env->fregs[f1].ll = x1.ll.upper;
+ env->fregs[f1 + 2].ll = x1.ll.lower;
+}
+
+/* convert 32-bit int to 32-bit float */
+void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2)
+{
+ env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status);
+ HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2,
+ env->fregs[f1].l.upper, f1);
+}
+
+/* 32-bit FP addition RR */
+uint32_t HELPER(aebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
+ env->fregs[f2].l.upper,
+ &env->fpu_status);
+ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__,
+ env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
+
+ return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* 64-bit FP addition RR */
+uint32_t HELPER(adbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d,
+ &env->fpu_status);
+ HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__,
+ env->fregs[f2].d, env->fregs[f1].d, f1);
+
+ return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* 32-bit FP subtraction RR */
+uint32_t HELPER(sebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper,
+ env->fregs[f2].l.upper,
+ &env->fpu_status);
+ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__,
+ env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
+
+ return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* 64-bit FP subtraction RR */
+uint32_t HELPER(sdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d,
+ &env->fpu_status);
+ HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n",
+ __func__, env->fregs[f2].d, env->fregs[f1].d, f1);
+
+ return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* 32-bit FP division RR */
+void HELPER(debr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper,
+ env->fregs[f2].l.upper,
+ &env->fpu_status);
+}
+
+/* 128-bit FP division RR */
+void HELPER(dxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU v1;
+ CPU_QuadU v2;
+ CPU_QuadU res;
+
+ v1.ll.upper = env->fregs[f1].ll;
+ v1.ll.lower = env->fregs[f1 + 2].ll;
+ v2.ll.upper = env->fregs[f2].ll;
+ v2.ll.lower = env->fregs[f2 + 2].ll;
+ res.q = float128_div(v1.q, v2.q, &env->fpu_status);
+ env->fregs[f1].ll = res.ll.upper;
+ env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* 64-bit FP multiplication RR */
+void HELPER(mdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d,
+ &env->fpu_status);
+}
+
+/* 128-bit FP multiplication RR */
+void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU v1;
+ CPU_QuadU v2;
+ CPU_QuadU res;
+
+ v1.ll.upper = env->fregs[f1].ll;
+ v1.ll.lower = env->fregs[f1 + 2].ll;
+ v2.ll.upper = env->fregs[f2].ll;
+ v2.ll.lower = env->fregs[f2 + 2].ll;
+ res.q = float128_mul(v1.q, v2.q, &env->fpu_status);
+ env->fregs[f1].ll = res.ll.upper;
+ env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* convert 32-bit float to 64-bit float */
+void HELPER(ldebr)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+ env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper,
+ &env->fpu_status);
+}
+
+/* convert 128-bit float to 64-bit float */
+void HELPER(ldxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU x2;
+
+ x2.ll.upper = env->fregs[f2].ll;
+ x2.ll.lower = env->fregs[f2 + 2].ll;
+ env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status);
+ HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d);
+}
+
+/* convert 64-bit float to 128-bit float */
+void HELPER(lxdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU res;
+
+ res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status);
+ env->fregs[f1].ll = res.ll.upper;
+ env->fregs[f1 + 2].ll = res.ll.lower;
+}
+
+/* convert 64-bit float to 32-bit float */
+void HELPER(ledbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ float64 d2 = env->fregs[f2].d;
+
+ env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status);
+}
+
+/* convert 128-bit float to 32-bit float */
+void HELPER(lexbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU x2;
+
+ x2.ll.upper = env->fregs[f2].ll;
+ x2.ll.lower = env->fregs[f2 + 2].ll;
+ env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status);
+ HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper);
+}
+
+/* absolute value of 32-bit float */
+uint32_t HELPER(lpebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ float32 v1;
+ float32 v2 = env->fregs[f2].d;
+
+ v1 = float32_abs(v2);
+ env->fregs[f1].d = v1;
+ return set_cc_nz_f32(v1);
+}
+
+/* absolute value of 64-bit float */
+uint32_t HELPER(lpdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ float64 v1;
+ float64 v2 = env->fregs[f2].d;
+
+ v1 = float64_abs(v2);
+ env->fregs[f1].d = v1;
+ return set_cc_nz_f64(v1);
+}
+
+/* absolute value of 128-bit float */
+uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU v1;
+ CPU_QuadU v2;
+
+ v2.ll.upper = env->fregs[f2].ll;
+ v2.ll.lower = env->fregs[f2 + 2].ll;
+ v1.q = float128_abs(v2.q);
+ env->fregs[f1].ll = v1.ll.upper;
+ env->fregs[f1 + 2].ll = v1.ll.lower;
+ return set_cc_nz_f128(v1.q);
+}
+
+/* load and test 64-bit float */
+uint32_t HELPER(ltdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].d = env->fregs[f2].d;
+ return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* load and test 32-bit float */
+uint32_t HELPER(ltebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].l.upper = env->fregs[f2].l.upper;
+ return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* load and test 128-bit float */
+uint32_t HELPER(ltxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU x;
+
+ x.ll.upper = env->fregs[f2].ll;
+ x.ll.lower = env->fregs[f2 + 2].ll;
+ env->fregs[f1].ll = x.ll.upper;
+ env->fregs[f1 + 2].ll = x.ll.lower;
+ return set_cc_nz_f128(x.q);
+}
+
+/* load complement of 32-bit float */
+uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper);
+
+ return set_cc_nz_f32(env->fregs[f1].l.upper);
+}
+
+/* load complement of 64-bit float */
+uint32_t HELPER(lcdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].d = float64_chs(env->fregs[f2].d);
+
+ return set_cc_nz_f64(env->fregs[f1].d);
+}
+
+/* load complement of 128-bit float */
+uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU x1, x2;
+
+ x2.ll.upper = env->fregs[f2].ll;
+ x2.ll.lower = env->fregs[f2 + 2].ll;
+ x1.q = float128_chs(x2.q);
+ env->fregs[f1].ll = x1.ll.upper;
+ env->fregs[f1 + 2].ll = x1.ll.lower;
+ return set_cc_nz_f128(x1.q);
+}
+
+/* 32-bit FP addition RM */
+void HELPER(aeb)(CPUS390XState *env, uint32_t f1, uint32_t val)
+{
+ float32 v1 = env->fregs[f1].l.upper;
+ CPU_FloatU v2;
+
+ v2.l = val;
+ HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__,
+ v1, f1, v2.f);
+ env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP division RM */
+void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val)
+{
+ float32 v1 = env->fregs[f1].l.upper;
+ CPU_FloatU v2;
+
+ v2.l = val;
+ HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__,
+ v1, f1, v2.f);
+ env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP multiplication RM */
+void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val)
+{
+ float32 v1 = env->fregs[f1].l.upper;
+ CPU_FloatU v2;
+
+ v2.l = val;
+ HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__,
+ v1, f1, v2.f);
+ env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status);
+}
+
+/* 32-bit FP compare RR */
+uint32_t HELPER(cebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ float32 v1 = env->fregs[f1].l.upper;
+ float32 v2 = env->fregs[f2].l.upper;
+
+ HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__,
+ v1, f1, v2);
+ return set_cc_f32(env, v1, v2);
+}
+
+/* 64-bit FP compare RR */
+uint32_t HELPER(cdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ float64 v1 = env->fregs[f1].d;
+ float64 v2 = env->fregs[f2].d;
+
+ HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__,
+ v1, f1, v2);
+ return set_cc_f64(env, v1, v2);
+}
+
+/* 128-bit FP compare RR */
+uint32_t HELPER(cxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU v1;
+ CPU_QuadU v2;
+
+ v1.ll.upper = env->fregs[f1].ll;
+ v1.ll.lower = env->fregs[f1 + 2].ll;
+ v2.ll.upper = env->fregs[f2].ll;
+ v2.ll.lower = env->fregs[f2 + 2].ll;
+
+ return float_comp_to_cc(env, float128_compare_quiet(v1.q, v2.q,
+ &env->fpu_status));
+}
+
+/* 64-bit FP compare RM */
+uint32_t HELPER(cdb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+{
+ float64 v1 = env->fregs[f1].d;
+ CPU_DoubleU v2;
+
+ v2.ll = cpu_ldq_data(env, a2);
+ HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1,
+ f1, v2.d);
+ return set_cc_f64(env, v1, v2.d);
+}
+
+/* 64-bit FP addition RM */
+uint32_t HELPER(adb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+{
+ float64 v1 = env->fregs[f1].d;
+ CPU_DoubleU v2;
+
+ v2.ll = cpu_ldq_data(env, a2);
+ HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__,
+ v1, f1, v2.d);
+ env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status);
+ return set_cc_nz_f64(v1);
+}
+
+/* 32-bit FP subtraction RM */
+void HELPER(seb)(CPUS390XState *env, uint32_t f1, uint32_t val)
+{
+ float32 v1 = env->fregs[f1].l.upper;
+ CPU_FloatU v2;
+
+ v2.l = val;
+ env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status);
+}
+
+/* 64-bit FP subtraction RM */
+uint32_t HELPER(sdb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+{
+ float64 v1 = env->fregs[f1].d;
+ CPU_DoubleU v2;
+
+ v2.ll = cpu_ldq_data(env, a2);
+ env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status);
+ return set_cc_nz_f64(v1);
+}
+
+/* 64-bit FP multiplication RM */
+void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+{
+ float64 v1 = env->fregs[f1].d;
+ CPU_DoubleU v2;
+
+ v2.ll = cpu_ldq_data(env, a2);
+ HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__,
+ v1, f1, v2.d);
+ env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status);
+}
+
+/* 64-bit FP division RM */
+void HELPER(ddb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+{
+ float64 v1 = env->fregs[f1].d;
+ CPU_DoubleU v2;
+
+ v2.ll = cpu_ldq_data(env, a2);
+ HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__,
+ v1, f1, v2.d);
+ env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status);
+}
+
+static void set_round_mode(CPUS390XState *env, int m3)
+{
+ switch (m3) {
+ case 0:
+ /* current mode */
+ break;
+ case 1:
+ /* biased round no nearest */
+ case 4:
+ /* round to nearest */
+ set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
+ break;
+ case 5:
+ /* round to zero */
+ set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
+ break;
+ case 6:
+ /* round to +inf */
+ set_float_rounding_mode(float_round_up, &env->fpu_status);
+ break;
+ case 7:
+ /* round to -inf */
+ set_float_rounding_mode(float_round_down, &env->fpu_status);
+ break;
+ }
+}
+
+/* convert 32-bit float to 64-bit int */
+uint32_t HELPER(cgebr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
+ uint32_t m3)
+{
+ float32 v2 = env->fregs[f2].l.upper;
+
+ set_round_mode(env, m3);
+ env->regs[r1] = float32_to_int64(v2, &env->fpu_status);
+ return set_cc_nz_f32(v2);
+}
+
+/* convert 64-bit float to 64-bit int */
+uint32_t HELPER(cgdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
+ uint32_t m3)
+{
+ float64 v2 = env->fregs[f2].d;
+
+ set_round_mode(env, m3);
+ env->regs[r1] = float64_to_int64(v2, &env->fpu_status);
+ return set_cc_nz_f64(v2);
+}
+
+/* convert 128-bit float to 64-bit int */
+uint32_t HELPER(cgxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
+ uint32_t m3)
+{
+ CPU_QuadU v2;
+
+ v2.ll.upper = env->fregs[f2].ll;
+ v2.ll.lower = env->fregs[f2 + 2].ll;
+ set_round_mode(env, m3);
+ env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status);
+ if (float128_is_any_nan(v2.q)) {
+ return 3;
+ } else if (float128_is_zero(v2.q)) {
+ return 0;
+ } else if (float128_is_neg(v2.q)) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+/* convert 32-bit float to 32-bit int */
+uint32_t HELPER(cfebr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
+ uint32_t m3)
+{
+ float32 v2 = env->fregs[f2].l.upper;
+
+ set_round_mode(env, m3);
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+ float32_to_int32(v2, &env->fpu_status);
+ return set_cc_nz_f32(v2);
+}
+
+/* convert 64-bit float to 32-bit int */
+uint32_t HELPER(cfdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
+ uint32_t m3)
+{
+ float64 v2 = env->fregs[f2].d;
+
+ set_round_mode(env, m3);
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+ float64_to_int32(v2, &env->fpu_status);
+ return set_cc_nz_f64(v2);
+}
+
+/* convert 128-bit float to 32-bit int */
+uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
+ uint32_t m3)
+{
+ CPU_QuadU v2;
+
+ v2.ll.upper = env->fregs[f2].ll;
+ v2.ll.lower = env->fregs[f2 + 2].ll;
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+ float128_to_int32(v2.q, &env->fpu_status);
+ return set_cc_nz_f128(v2.q);
+}
+
+/* load 32-bit FP zero */
+void HELPER(lzer)(CPUS390XState *env, uint32_t f1)
+{
+ env->fregs[f1].l.upper = float32_zero;
+}
+
+/* load 64-bit FP zero */
+void HELPER(lzdr)(CPUS390XState *env, uint32_t f1)
+{
+ env->fregs[f1].d = float64_zero;
+}
+
+/* load 128-bit FP zero */
+void HELPER(lzxr)(CPUS390XState *env, uint32_t f1)
+{
+ CPU_QuadU x;
+
+ x.q = float64_to_float128(float64_zero, &env->fpu_status);
+ env->fregs[f1].ll = x.ll.upper;
+ env->fregs[f1 + 1].ll = x.ll.lower;
+}
+
+/* 128-bit FP subtraction RR */
+uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU v1;
+ CPU_QuadU v2;
+ CPU_QuadU res;
+
+ v1.ll.upper = env->fregs[f1].ll;
+ v1.ll.lower = env->fregs[f1 + 2].ll;
+ v2.ll.upper = env->fregs[f2].ll;
+ v2.ll.lower = env->fregs[f2 + 2].ll;
+ res.q = float128_sub(v1.q, v2.q, &env->fpu_status);
+ env->fregs[f1].ll = res.ll.upper;
+ env->fregs[f1 + 2].ll = res.ll.lower;
+ return set_cc_nz_f128(res.q);
+}
+
+/* 128-bit FP addition RR */
+uint32_t HELPER(axbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ CPU_QuadU v1;
+ CPU_QuadU v2;
+ CPU_QuadU res;
+
+ v1.ll.upper = env->fregs[f1].ll;
+ v1.ll.lower = env->fregs[f1 + 2].ll;
+ v2.ll.upper = env->fregs[f2].ll;
+ v2.ll.lower = env->fregs[f2 + 2].ll;
+ res.q = float128_add(v1.q, v2.q, &env->fpu_status);
+ env->fregs[f1].ll = res.ll.upper;
+ env->fregs[f1 + 2].ll = res.ll.lower;
+ return set_cc_nz_f128(res.q);
+}
+
+/* 32-bit FP multiplication RR */
+void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper,
+ env->fregs[f2].l.upper,
+ &env->fpu_status);
+}
+
+/* 64-bit FP division RR */
+void HELPER(ddbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d,
+ &env->fpu_status);
+}
+
+/* 64-bit FP multiply and add RM */
+void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3)
+{
+ CPU_DoubleU v2;
+
+ HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3);
+ v2.ll = cpu_ldq_data(env, a2);
+ env->fregs[f1].d = float64_add(env->fregs[f1].d,
+ float64_mul(v2.d, env->fregs[f3].d,
+ &env->fpu_status),
+ &env->fpu_status);
+}
+
+/* 64-bit FP multiply and add RR */
+void HELPER(madbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2)
+{
+ HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3);
+ env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d,
+ env->fregs[f3].d,
+ &env->fpu_status),
+ env->fregs[f1].d, &env->fpu_status);
+}
+
+/* 64-bit FP multiply and subtract RR */
+void HELPER(msdbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2)
+{
+ HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3);
+ env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d,
+ env->fregs[f3].d,
+ &env->fpu_status),
+ env->fregs[f1].d, &env->fpu_status);
+}
+
+/* 32-bit FP multiply and add RR */
+void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2)
+{
+ env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
+ float32_mul(env->fregs[f2].l.upper,
+ env->fregs[f3].l.upper,
+ &env->fpu_status),
+ &env->fpu_status);
+}
+
+/* convert 32-bit float to 64-bit float */
+void HELPER(ldeb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+{
+ uint32_t v2;
+
+ v2 = cpu_ldl_data(env, a2);
+ env->fregs[f1].d = float32_to_float64(v2,
+ &env->fpu_status);
+}
+
+/* convert 64-bit float to 128-bit float */
+void HELPER(lxdb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+{
+ CPU_DoubleU v2;
+ CPU_QuadU v1;
+
+ v2.ll = cpu_ldq_data(env, a2);
+ v1.q = float64_to_float128(v2.d, &env->fpu_status);
+ env->fregs[f1].ll = v1.ll.upper;
+ env->fregs[f1 + 2].ll = v1.ll.lower;
+}
+
+/* test data class 32-bit */
+uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2)
+{
+ float32 v1 = env->fregs[f1].l.upper;
+ int neg = float32_is_neg(v1);
+ uint32_t cc = 0;
+
+ HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg);
+ if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
+ (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
+ (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
+ (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
+ cc = 1;
+ } else if (m2 & (1 << (9-neg))) {
+ /* assume normalized number */
+ cc = 1;
+ }
+
+ /* FIXME: denormalized? */
+ return cc;
+}
+
+/* test data class 64-bit */
+uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2)
+{
+ float64 v1 = env->fregs[f1].d;
+ int neg = float64_is_neg(v1);
+ uint32_t cc = 0;
+
+ HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg);
+ if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
+ (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
+ (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
+ (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
+ cc = 1;
+ } else if (m2 & (1 << (9-neg))) {
+ /* assume normalized number */
+ cc = 1;
+ }
+ /* FIXME: denormalized? */
+ return cc;
+}
+
+/* test data class 128-bit */
+uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2)
+{
+ CPU_QuadU v1;
+ uint32_t cc = 0;
+ int neg;
+
+ v1.ll.upper = env->fregs[f1].ll;
+ v1.ll.lower = env->fregs[f1 + 2].ll;
+
+ neg = float128_is_neg(v1.q);
+ if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) ||
+ (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) ||
+ (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) ||
+ (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) {
+ cc = 1;
+ } else if (m2 & (1 << (9-neg))) {
+ /* assume normalized number */
+ cc = 1;
+ }
+ /* FIXME: denormalized? */
+ return cc;
+}
+
+/* square root 64-bit RR */
+void HELPER(sqdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+{
+ env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status);
+}
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index d0a1180a8..a5741ecde 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -74,7 +74,7 @@ S390CPU *cpu_s390x_init(const char *cpu_model)
{
S390CPU *cpu;
CPUS390XState *env;
- static int inited = 0;
+ static int inited;
cpu = S390_CPU(object_new(TYPE_S390_CPU));
env = &cpu->env;
@@ -91,25 +91,27 @@ S390CPU *cpu_s390x_init(const char *cpu_model)
#if defined(CONFIG_USER_ONLY)
-void do_interrupt (CPUS390XState *env)
+void do_interrupt(CPUS390XState *env)
{
env->exception_index = -1;
}
-int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
- int mmu_idx)
+int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address,
+ int rw, int mmu_idx)
{
- /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d\n",
- __FUNCTION__, address, rw, mmu_idx); */
+ /* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n",
+ __func__, address, rw, mmu_idx); */
env->exception_index = EXCP_ADDR;
- env->__excp_addr = address; /* FIXME: find out how this works on a real machine */
+ /* FIXME: find out how this works on a real machine */
+ env->__excp_addr = address;
return 1;
}
#else /* !CONFIG_USER_ONLY */
/* Ensure to exit the TB after this call! */
-static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilc)
+static void trigger_pgm_exception(CPUS390XState *env, uint32_t code,
+ uint32_t ilc)
{
env->exception_index = EXCP_PGM;
env->int_pgm_code = code;
@@ -138,19 +140,20 @@ static int trans_bits(CPUS390XState *env, uint64_t mode)
return bits;
}
-static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, uint64_t mode)
+static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr,
+ uint64_t mode)
{
int ilc = ILC_LATER_INC_2;
int bits = trans_bits(env, mode) | 4;
- DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits);
+ DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits);
stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits);
trigger_pgm_exception(env, PGM_PROTECTION, ilc);
}
-static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type,
- uint64_t asc, int rw)
+static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
+ uint32_t type, uint64_t asc, int rw)
{
int ilc = ILC_LATER;
int bits = trans_bits(env, asc);
@@ -160,26 +163,26 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t
ilc = 2;
}
- DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits);
+ DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits);
stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits);
trigger_pgm_exception(env, type, ilc);
}
-static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t asc,
- uint64_t asce, int level, target_ulong *raddr,
- int *flags, int rw)
+static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr,
+ uint64_t asc, uint64_t asce, int level,
+ target_ulong *raddr, int *flags, int rw)
{
uint64_t offs = 0;
uint64_t origin;
uint64_t new_asce;
- PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __FUNCTION__, asce);
+ PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __func__, asce);
if (((level != _ASCE_TYPE_SEGMENT) && (asce & _REGION_ENTRY_INV)) ||
((level == _ASCE_TYPE_SEGMENT) && (asce & _SEGMENT_ENTRY_INV))) {
/* XXX different regions have different faults */
- DPRINTF("%s: invalid region\n", __FUNCTION__);
+ DPRINTF("%s: invalid region\n", __func__);
trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw);
return -1;
}
@@ -222,7 +225,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a
new_asce = ldq_phys(origin + offs);
PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n",
- __FUNCTION__, origin, offs, new_asce);
+ __func__, origin, offs, new_asce);
if (level != _ASCE_TYPE_SEGMENT) {
/* yet another region */
@@ -232,7 +235,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a
/* PTE */
if (new_asce & _PAGE_INVALID) {
- DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __FUNCTION__, new_asce);
+ DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, new_asce);
trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw);
return -1;
}
@@ -243,13 +246,14 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a
*raddr = new_asce & _ASCE_ORIGIN;
- PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __FUNCTION__, new_asce);
+ PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, new_asce);
return 0;
}
-static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t asc,
- target_ulong *raddr, int *flags, int rw)
+static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr,
+ uint64_t asc, target_ulong *raddr, int *flags,
+ int rw)
{
uint64_t asce = 0;
int level, new_level;
@@ -257,15 +261,15 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as
switch (asc) {
case PSW_ASC_PRIMARY:
- PTE_DPRINTF("%s: asc=primary\n", __FUNCTION__);
+ PTE_DPRINTF("%s: asc=primary\n", __func__);
asce = env->cregs[1];
break;
case PSW_ASC_SECONDARY:
- PTE_DPRINTF("%s: asc=secondary\n", __FUNCTION__);
+ PTE_DPRINTF("%s: asc=secondary\n", __func__);
asce = env->cregs[7];
break;
case PSW_ASC_HOME:
- PTE_DPRINTF("%s: asc=home\n", __FUNCTION__);
+ PTE_DPRINTF("%s: asc=home\n", __func__);
asce = env->cregs[13];
break;
}
@@ -276,8 +280,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as
case _ASCE_TYPE_REGION2:
if (vaddr & 0xffe0000000000000ULL) {
DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
- " 0xffe0000000000000ULL\n", __FUNCTION__,
- vaddr);
+ " 0xffe0000000000000ULL\n", __func__, vaddr);
trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
return -1;
}
@@ -285,8 +288,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as
case _ASCE_TYPE_REGION3:
if (vaddr & 0xfffffc0000000000ULL) {
DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
- " 0xfffffc0000000000ULL\n", __FUNCTION__,
- vaddr);
+ " 0xfffffc0000000000ULL\n", __func__, vaddr);
trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
return -1;
}
@@ -294,8 +296,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as
case _ASCE_TYPE_SEGMENT:
if (vaddr & 0xffffffff80000000ULL) {
DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
- " 0xffffffff80000000ULL\n", __FUNCTION__,
- vaddr);
+ " 0xffffffff80000000ULL\n", __func__, vaddr);
trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
return -1;
}
@@ -358,7 +359,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
break;
}
-out:
+ out:
/* Convert real address -> absolute address */
if (*raddr < 0x2000) {
*raddr = *raddr + env->psa;
@@ -378,18 +379,18 @@ out:
return r;
}
-int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong _vaddr, int rw,
- int mmu_idx)
+int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr,
+ int rw, int mmu_idx)
{
uint64_t asc = env->psw.mask & PSW_MASK_ASC;
target_ulong vaddr, raddr;
int prot;
DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d\n",
- __FUNCTION__, _vaddr, rw, mmu_idx);
+ __func__, _vaddr, rw, mmu_idx);
- _vaddr &= TARGET_PAGE_MASK;
- vaddr = _vaddr;
+ orig_vaddr &= TARGET_PAGE_MASK;
+ vaddr = orig_vaddr;
/* 31-Bit mode */
if (!(env->psw.mask & PSW_MASK_64)) {
@@ -403,22 +404,23 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong _vaddr, int rw,
/* check out of RAM access */
if (raddr > (ram_size + virtio_size)) {
- DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __FUNCTION__,
+ DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
(uint64_t)aaddr, (uint64_t)ram_size);
trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER);
return 1;
}
- DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __FUNCTION__,
+ DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __func__,
(uint64_t)vaddr, (uint64_t)raddr, prot);
- tlb_set_page(env, _vaddr, raddr, prot,
+ tlb_set_page(env, orig_vaddr, raddr, prot,
mmu_idx, TARGET_PAGE_SIZE);
return 0;
}
-target_phys_addr_t cpu_get_phys_page_debug(CPUS390XState *env, target_ulong vaddr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUS390XState *env,
+ target_ulong vaddr)
{
target_ulong raddr;
int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
@@ -497,19 +499,19 @@ static void do_program_interrupt(CPUS390XState *env)
switch (ilc) {
case ILC_LATER:
- ilc = get_ilc(ldub_code(env->psw.addr));
+ ilc = get_ilc(cpu_ldub_code(env, env->psw.addr));
break;
case ILC_LATER_INC:
- ilc = get_ilc(ldub_code(env->psw.addr));
+ ilc = get_ilc(cpu_ldub_code(env, env->psw.addr));
env->psw.addr += ilc * 2;
break;
case ILC_LATER_INC_2:
- ilc = get_ilc(ldub_code(env->psw.addr)) * 2;
+ ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2;
env->psw.addr += ilc;
break;
}
- qemu_log("%s: code=0x%x ilc=%d\n", __FUNCTION__, env->int_pgm_code, ilc);
+ qemu_log("%s: code=0x%x ilc=%d\n", __func__, env->int_pgm_code, ilc);
lowcore = cpu_physical_memory_map(env->psa, &len, 1);
@@ -522,7 +524,7 @@ static void do_program_interrupt(CPUS390XState *env)
cpu_physical_memory_unmap(lowcore, len, 1, len);
- DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __FUNCTION__,
+ DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__,
env->int_pgm_code, ilc, env->psw.mask,
env->psw.addr);
@@ -565,15 +567,15 @@ static void do_ext_interrupt(CPUS390XState *env)
env->pending_int &= ~INTERRUPT_EXT;
}
- DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __FUNCTION__,
+ DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__,
env->psw.mask, env->psw.addr);
load_psw(env, mask, addr);
}
-void do_interrupt (CPUS390XState *env)
+void do_interrupt(CPUS390XState *env)
{
- qemu_log("%s: %d at pc=%" PRIx64 "\n", __FUNCTION__, env->exception_index,
+ qemu_log("%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index,
env->psw.addr);
s390_add_running_cpu(env);
diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index 01c8d0ea8..5419f37dc 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -1,19 +1,19 @@
#include "def-helper.h"
-DEF_HELPER_1(exception, void, i32)
-DEF_HELPER_3(nc, i32, i32, i64, i64)
-DEF_HELPER_3(oc, i32, i32, i64, i64)
-DEF_HELPER_3(xc, i32, i32, i64, i64)
-DEF_HELPER_3(mvc, void, i32, i64, i64)
-DEF_HELPER_3(clc, i32, i32, i64, i64)
-DEF_HELPER_2(mvcl, i32, i32, i32)
+DEF_HELPER_2(exception, void, env, i32)
+DEF_HELPER_4(nc, i32, env, i32, i64, i64)
+DEF_HELPER_4(oc, i32, env, i32, i64, i64)
+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_3(clm, i32, i32, i32, i64)
-DEF_HELPER_3(stcm, void, i32, i32, i64)
-DEF_HELPER_2(mlg, void, i32, i64)
-DEF_HELPER_2(dlg, void, i32, i64)
+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)
@@ -22,131 +22,131 @@ DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s6
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_3(srst, i32, i32, i32, i32)
-DEF_HELPER_3(clst, i32, i32, i32, i32)
-DEF_HELPER_3(mvpg, void, i64, i64, i64)
-DEF_HELPER_3(mvst, void, i32, i32, i32)
-DEF_HELPER_3(csg, i32, i32, i64, i32)
-DEF_HELPER_3(cdsg, i32, i32, i64, i32)
-DEF_HELPER_3(cs, i32, i32, i64, i32)
-DEF_HELPER_4(ex, i32, i32, i64, i64, i64)
+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)
+DEF_HELPER_4(mvst, void, env, i32, i32, i32)
+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_3(stcmh, void, i32, i64, i32)
-DEF_HELPER_3(icmh, i32, i32, i64, i32)
-DEF_HELPER_2(ipm, void, i32, i32)
+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_3(stam, void, i32, i64, i32)
-DEF_HELPER_3(lam, void, i32, i64, i32)
-DEF_HELPER_3(mvcle, i32, i32, i64, i32)
-DEF_HELPER_3(clcle, i32, i32, i64, i32)
-DEF_HELPER_3(slb, i32, i32, i32, i32)
-DEF_HELPER_4(slbg, i32, i32, i32, i64, i64)
-DEF_HELPER_2(cefbr, void, i32, s32)
-DEF_HELPER_2(cdfbr, void, i32, s32)
-DEF_HELPER_2(cxfbr, void, i32, s32)
-DEF_HELPER_2(cegbr, void, i32, s64)
-DEF_HELPER_2(cdgbr, void, i32, s64)
-DEF_HELPER_2(cxgbr, void, i32, s64)
-DEF_HELPER_2(adbr, i32, i32, i32)
-DEF_HELPER_2(aebr, i32, i32, i32)
-DEF_HELPER_2(sebr, i32, i32, i32)
-DEF_HELPER_2(sdbr, i32, i32, i32)
-DEF_HELPER_2(debr, void, i32, i32)
-DEF_HELPER_2(dxbr, void, i32, i32)
-DEF_HELPER_2(mdbr, void, i32, i32)
-DEF_HELPER_2(mxbr, void, i32, i32)
-DEF_HELPER_2(ldebr, void, i32, i32)
-DEF_HELPER_2(ldxbr, void, i32, i32)
-DEF_HELPER_2(lxdbr, void, i32, i32)
-DEF_HELPER_2(ledbr, void, i32, i32)
-DEF_HELPER_2(lexbr, void, i32, i32)
-DEF_HELPER_2(lpebr, i32, i32, i32)
-DEF_HELPER_2(lpdbr, i32, i32, i32)
-DEF_HELPER_2(lpxbr, i32, i32, i32)
-DEF_HELPER_2(ltebr, i32, i32, i32)
-DEF_HELPER_2(ltdbr, i32, i32, i32)
-DEF_HELPER_2(ltxbr, i32, i32, i32)
-DEF_HELPER_2(lcebr, i32, i32, i32)
-DEF_HELPER_2(lcdbr, i32, i32, i32)
-DEF_HELPER_2(lcxbr, i32, i32, i32)
-DEF_HELPER_2(aeb, void, i32, i32)
-DEF_HELPER_2(deb, void, i32, i32)
-DEF_HELPER_2(meeb, void, i32, i32)
-DEF_HELPER_2(cdb, i32, i32, i64)
-DEF_HELPER_2(adb, i32, i32, i64)
-DEF_HELPER_2(seb, void, i32, i32)
-DEF_HELPER_2(sdb, i32, i32, i64)
-DEF_HELPER_2(mdb, void, i32, i64)
-DEF_HELPER_2(ddb, void, i32, i64)
-DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32)
-DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32)
-DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32)
-DEF_HELPER_3(cgebr, i32, i32, i32, i32)
-DEF_HELPER_3(cgdbr, i32, i32, i32, i32)
-DEF_HELPER_3(cgxbr, i32, i32, i32, i32)
-DEF_HELPER_1(lzer, void, i32)
-DEF_HELPER_1(lzdr, void, i32)
-DEF_HELPER_1(lzxr, void, i32)
-DEF_HELPER_3(cfebr, i32, i32, i32, i32)
-DEF_HELPER_3(cfdbr, i32, i32, i32, i32)
-DEF_HELPER_3(cfxbr, i32, i32, i32, i32)
-DEF_HELPER_2(axbr, i32, i32, i32)
-DEF_HELPER_2(sxbr, i32, i32, i32)
-DEF_HELPER_2(meebr, void, i32, i32)
-DEF_HELPER_2(ddbr, void, i32, i32)
-DEF_HELPER_3(madb, void, i32, i64, i32)
-DEF_HELPER_3(maebr, void, i32, i32, i32)
-DEF_HELPER_3(madbr, void, i32, i32, i32)
-DEF_HELPER_3(msdbr, void, i32, i32, i32)
-DEF_HELPER_2(ldeb, void, i32, i64)
-DEF_HELPER_2(lxdb, void, i32, i64)
-DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64)
-DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64)
-DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64)
-DEF_HELPER_2(flogr, i32, i32, i64)
-DEF_HELPER_2(sqdbr, void, i32, i32)
+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)
+DEF_HELPER_4(clcle, i32, env, i32, i64, i32)
+DEF_HELPER_4(slb, i32, env, i32, i32, i32)
+DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64)
+DEF_HELPER_3(cefbr, void, env, i32, s32)
+DEF_HELPER_3(cdfbr, void, env, i32, s32)
+DEF_HELPER_3(cxfbr, void, env, i32, s32)
+DEF_HELPER_3(cegbr, void, env, i32, s64)
+DEF_HELPER_3(cdgbr, void, env, i32, s64)
+DEF_HELPER_3(cxgbr, void, env, i32, s64)
+DEF_HELPER_3(adbr, i32, env, i32, i32)
+DEF_HELPER_3(aebr, i32, env, i32, i32)
+DEF_HELPER_3(sebr, i32, env, i32, i32)
+DEF_HELPER_3(sdbr, i32, env, i32, i32)
+DEF_HELPER_3(debr, void, env, i32, i32)
+DEF_HELPER_3(dxbr, void, env, i32, i32)
+DEF_HELPER_3(mdbr, void, env, i32, i32)
+DEF_HELPER_3(mxbr, void, env, i32, i32)
+DEF_HELPER_3(ldebr, void, env, i32, i32)
+DEF_HELPER_3(ldxbr, void, env, i32, i32)
+DEF_HELPER_3(lxdbr, void, env, i32, i32)
+DEF_HELPER_3(ledbr, void, env, i32, i32)
+DEF_HELPER_3(lexbr, void, env, i32, i32)
+DEF_HELPER_3(lpebr, i32, env, i32, i32)
+DEF_HELPER_3(lpdbr, i32, env, i32, i32)
+DEF_HELPER_3(lpxbr, i32, env, i32, i32)
+DEF_HELPER_3(ltebr, i32, env, i32, i32)
+DEF_HELPER_3(ltdbr, i32, env, i32, i32)
+DEF_HELPER_3(ltxbr, i32, env, i32, i32)
+DEF_HELPER_3(lcebr, i32, env, i32, i32)
+DEF_HELPER_3(lcdbr, i32, env, i32, i32)
+DEF_HELPER_3(lcxbr, i32, env, i32, i32)
+DEF_HELPER_3(aeb, void, env, i32, i32)
+DEF_HELPER_3(deb, void, env, i32, i32)
+DEF_HELPER_3(meeb, void, env, i32, i32)
+DEF_HELPER_3(cdb, i32, env, i32, i64)
+DEF_HELPER_3(adb, i32, env, i32, i64)
+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_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)
+DEF_HELPER_2(lzer, void, env, i32)
+DEF_HELPER_2(lzdr, void, env, i32)
+DEF_HELPER_2(lzxr, void, env, i32)
+DEF_HELPER_4(cfebr, i32, env, i32, i32, i32)
+DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32)
+DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32)
+DEF_HELPER_3(axbr, i32, env, i32, i32)
+DEF_HELPER_3(sxbr, i32, env, i32, i32)
+DEF_HELPER_3(meebr, void, env, i32, i32)
+DEF_HELPER_3(ddbr, void, env, i32, i32)
+DEF_HELPER_4(madb, void, env, i32, i64, i32)
+DEF_HELPER_4(maebr, void, env, i32, i32, i32)
+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_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_3(unpk, void, i32, i64, i64)
-DEF_HELPER_3(tr, void, i32, i64, i64)
+DEF_HELPER_4(unpk, void, env, i32, i64, i64)
+DEF_HELPER_4(tr, void, env, i32, i64, i64)
-DEF_HELPER_2(servc, i32, i32, i64)
-DEF_HELPER_3(diag, i64, i32, i64, i64)
-DEF_HELPER_2(load_psw, void, i64, i64)
+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_1(stidp, TCG_CALL_CONST, void, i64)
-DEF_HELPER_FLAGS_1(spx, TCG_CALL_CONST, void, i64)
+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_1(stck, i32, i64)
-DEF_HELPER_1(stcke, i32, i64)
-DEF_HELPER_FLAGS_1(sckc, TCG_CALL_CONST, void, i64)
-DEF_HELPER_FLAGS_1(stckc, TCG_CALL_CONST, void, i64)
-DEF_HELPER_FLAGS_1(spt, TCG_CALL_CONST, void, i64)
-DEF_HELPER_FLAGS_1(stpt, TCG_CALL_CONST, void, i64)
-DEF_HELPER_3(stsi, i32, i64, i32, i32)
-DEF_HELPER_3(lctl, void, i32, i64, i32)
-DEF_HELPER_3(lctlg, void, i32, i64, i32)
-DEF_HELPER_3(stctl, void, i32, i64, i32)
-DEF_HELPER_3(stctg, void, i32, i64, i32)
+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_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_1(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_2(sske, TCG_CALL_CONST, void, i32, i64)
-DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_CONST, i32, i32, i64)
-DEF_HELPER_2(csp, i32, i32, i32)
-DEF_HELPER_3(mvcs, i32, i64, i64, i64)
-DEF_HELPER_3(mvcp, i32, i64, i64, i64)
-DEF_HELPER_3(sigp, i32, i64, i32, i64)
-DEF_HELPER_1(sacf, void, i64)
-DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64)
-DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void)
-DEF_HELPER_2(lra, i32, i64, i32)
-DEF_HELPER_2(stura, void, i64, i32)
-DEF_HELPER_2(cksm, void, i32, i32)
+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_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_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_4(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST,
- i32, i32, i64, i64, i64)
+DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST,
+ i32, env, i32, i64, i64, i64)
#include "def-helper.h"
diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c
new file mode 100644
index 000000000..f202a7e1d
--- /dev/null
+++ b/target-s390x/int_helper.c
@@ -0,0 +1,201 @@
+/*
+ * S/390 integer helper routines
+ *
+ * Copyright (c) 2009 Ulrich Hecht
+ * Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "host-utils.h"
+#include "helper.h"
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+/* 64/64 -> 128 unsigned multiplication */
+void HELPER(mlg)(CPUS390XState *env, uint32_t r1, uint64_t v2)
+{
+#if HOST_LONG_BITS == 64 && defined(__GNUC__)
+ /* assuming 64-bit hosts have __uint128_t */
+ __uint128_t res = (__uint128_t)env->regs[r1 + 1];
+
+ res *= (__uint128_t)v2;
+ env->regs[r1] = (uint64_t)(res >> 64);
+ env->regs[r1 + 1] = (uint64_t)res;
+#else
+ mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2);
+#endif
+}
+
+/* 128 -> 64/64 unsigned division */
+void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2)
+{
+ uint64_t divisor = v2;
+
+ if (!env->regs[r1]) {
+ /* 64 -> 64/64 case */
+ env->regs[r1] = env->regs[r1 + 1] % divisor;
+ env->regs[r1 + 1] = env->regs[r1 + 1] / divisor;
+ return;
+ } else {
+#if HOST_LONG_BITS == 64 && defined(__GNUC__)
+ /* assuming 64-bit hosts have __uint128_t */
+ __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) |
+ (env->regs[r1 + 1]);
+ __uint128_t quotient = dividend / divisor;
+ __uint128_t remainder = dividend % divisor;
+
+ env->regs[r1 + 1] = quotient;
+ env->regs[r1] = remainder;
+#else
+ /* 32-bit hosts would need special wrapper functionality - just abort if
+ we encounter such a case; it's very unlikely anyways. */
+ cpu_abort(env, "128 -> 64/64 division not implemented\n");
+#endif
+ }
+}
+
+/* absolute value 32-bit */
+uint32_t HELPER(abs_i32)(int32_t val)
+{
+ if (val < 0) {
+ return -val;
+ } else {
+ return val;
+ }
+}
+
+/* negative absolute value 32-bit */
+int32_t HELPER(nabs_i32)(int32_t val)
+{
+ if (val < 0) {
+ return val;
+ } else {
+ return -val;
+ }
+}
+
+/* absolute value 64-bit */
+uint64_t HELPER(abs_i64)(int64_t val)
+{
+ HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val);
+
+ if (val < 0) {
+ return -val;
+ } else {
+ return val;
+ }
+}
+
+/* negative absolute value 64-bit */
+int64_t HELPER(nabs_i64)(int64_t val)
+{
+ if (val < 0) {
+ return val;
+ } else {
+ return -val;
+ }
+}
+
+/* add with carry 32-bit unsigned */
+uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2)
+{
+ uint32_t res;
+
+ res = v1 + v2;
+ if (cc & 2) {
+ res++;
+ }
+
+ return res;
+}
+
+/* subtract unsigned v2 from v1 with borrow */
+uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2)
+{
+ uint32_t v1 = env->regs[r1];
+ uint32_t res = v1 + (~v2) + (cc >> 1);
+
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res;
+ if (cc & 2) {
+ /* borrow */
+ return v1 ? 1 : 0;
+ } else {
+ return v1 ? 3 : 2;
+ }
+}
+
+/* subtract unsigned v2 from v1 with borrow */
+uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1,
+ uint64_t v1, uint64_t v2)
+{
+ uint64_t res = v1 + (~v2) + (cc >> 1);
+
+ env->regs[r1] = res;
+ if (cc & 2) {
+ /* borrow */
+ return v1 ? 1 : 0;
+ } else {
+ return v1 ? 3 : 2;
+ }
+}
+
+/* find leftmost one */
+uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2)
+{
+ uint64_t res = 0;
+ uint64_t ov2 = v2;
+
+ while (!(v2 & 0x8000000000000000ULL) && v2) {
+ v2 <<= 1;
+ res++;
+ }
+
+ if (!v2) {
+ env->regs[r1] = 64;
+ env->regs[r1 + 1] = 0;
+ return 0;
+ } else {
+ env->regs[r1] = res;
+ env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res);
+ return 2;
+ }
+}
+
+uint64_t HELPER(cvd)(int32_t bin)
+{
+ /* positive 0 */
+ uint64_t dec = 0x0c;
+ int shift = 4;
+
+ if (bin < 0) {
+ bin = -bin;
+ dec = 0x0d;
+ }
+
+ for (shift = 4; (shift < 64) && bin; shift += 4) {
+ int current_number = bin % 10;
+
+ dec |= (current_number) << shift;
+ bin /= 10;
+ }
+
+ return dec;
+}
diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
new file mode 100644
index 000000000..b21b37c5e
--- /dev/null
+++ b/target-s390x/mem_helper.c
@@ -0,0 +1,1203 @@
+/*
+ * S/390 memory access helper routines
+ *
+ * Copyright (c) 2009 Ulrich Hecht
+ * Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+ NULL, it means that the function was called in C code (i.e. not
+ from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(CPUS390XState *env, target_ulong addr, int is_write, int mmu_idx,
+ uintptr_t retaddr)
+{
+ TranslationBlock *tb;
+ int ret;
+
+ ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ if (unlikely(ret != 0)) {
+ if (likely(retaddr)) {
+ /* now we have a real cpu fault */
+ tb = tb_find_pc(retaddr);
+ if (likely(tb)) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, retaddr);
+ }
+ }
+ cpu_loop_exit(env);
+ }
+}
+
+#endif
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+#ifndef CONFIG_USER_ONLY
+static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
+ uint8_t byte)
+{
+ target_phys_addr_t dest_phys;
+ target_phys_addr_t len = l;
+ void *dest_p;
+ uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+ int flags;
+
+ if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
+ cpu_stb_data(env, dest, byte);
+ cpu_abort(env, "should never reach here");
+ }
+ dest_phys |= dest & ~TARGET_PAGE_MASK;
+
+ dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
+
+ memset(dest_p, byte, len);
+
+ cpu_physical_memory_unmap(dest_p, 1, len, len);
+}
+
+static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
+ uint64_t src)
+{
+ target_phys_addr_t dest_phys;
+ target_phys_addr_t src_phys;
+ target_phys_addr_t len = l;
+ void *dest_p;
+ void *src_p;
+ uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+ int flags;
+
+ if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
+ cpu_stb_data(env, dest, 0);
+ cpu_abort(env, "should never reach here");
+ }
+ dest_phys |= dest & ~TARGET_PAGE_MASK;
+
+ if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
+ cpu_ldub_data(env, src);
+ cpu_abort(env, "should never reach here");
+ }
+ src_phys |= src & ~TARGET_PAGE_MASK;
+
+ dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
+ src_p = cpu_physical_memory_map(src_phys, &len, 0);
+
+ memmove(dest_p, src_p, len);
+
+ cpu_physical_memory_unmap(dest_p, 1, len, len);
+ cpu_physical_memory_unmap(src_p, 0, len, len);
+}
+#endif
+
+/* and on array */
+uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
+ uint64_t src)
+{
+ int i;
+ unsigned char x;
+ uint32_t cc = 0;
+
+ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+ __func__, l, dest, src);
+ for (i = 0; i <= l; i++) {
+ x = cpu_ldub_data(env, dest + i) & cpu_ldub_data(env, src + i);
+ if (x) {
+ cc = 1;
+ }
+ cpu_stb_data(env, dest + i, x);
+ }
+ return cc;
+}
+
+/* xor on array */
+uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
+ uint64_t src)
+{
+ int i;
+ unsigned char x;
+ uint32_t cc = 0;
+
+ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+ __func__, l, dest, src);
+
+#ifndef CONFIG_USER_ONLY
+ /* xor with itself is the same as memset(0) */
+ if ((l > 32) && (src == dest) &&
+ (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
+ mvc_fast_memset(env, l + 1, dest, 0);
+ return 0;
+ }
+#else
+ if (src == dest) {
+ memset(g2h(dest), 0, l + 1);
+ return 0;
+ }
+#endif
+
+ for (i = 0; i <= l; i++) {
+ x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i);
+ if (x) {
+ cc = 1;
+ }
+ cpu_stb_data(env, dest + i, x);
+ }
+ return cc;
+}
+
+/* or on array */
+uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
+ uint64_t src)
+{
+ int i;
+ unsigned char x;
+ uint32_t cc = 0;
+
+ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+ __func__, l, dest, src);
+ for (i = 0; i <= l; i++) {
+ x = cpu_ldub_data(env, dest + i) | cpu_ldub_data(env, src + i);
+ if (x) {
+ cc = 1;
+ }
+ cpu_stb_data(env, dest + i, x);
+ }
+ return cc;
+}
+
+/* memmove */
+void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
+{
+ int i = 0;
+ int x = 0;
+ uint32_t l_64 = (l + 1) / 8;
+
+ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+ __func__, l, dest, src);
+
+#ifndef CONFIG_USER_ONLY
+ if ((l > 32) &&
+ (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
+ (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
+ if (dest == (src + 1)) {
+ mvc_fast_memset(env, l + 1, dest, cpu_ldub_data(env, src));
+ return;
+ } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
+ mvc_fast_memmove(env, l + 1, dest, src);
+ return;
+ }
+ }
+#else
+ if (dest == (src + 1)) {
+ memset(g2h(dest), cpu_ldub_data(env, src), l + 1);
+ return;
+ } else {
+ memmove(g2h(dest), g2h(src), l + 1);
+ return;
+ }
+#endif
+
+ /* handle the parts that fit into 8-byte loads/stores */
+ if (dest != (src + 1)) {
+ for (i = 0; i < l_64; i++) {
+ cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x));
+ x += 8;
+ }
+ }
+
+ /* slow version crossing pages with byte accesses */
+ for (i = x; i <= l; i++) {
+ cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i));
+ }
+}
+
+/* compare unsigned byte arrays */
+uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
+{
+ int i;
+ unsigned char x, y;
+ uint32_t cc;
+
+ HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
+ __func__, l, s1, s2);
+ for (i = 0; i <= l; i++) {
+ x = cpu_ldub_data(env, s1 + i);
+ y = cpu_ldub_data(env, s2 + i);
+ HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
+ if (x < y) {
+ cc = 1;
+ goto done;
+ } else if (x > y) {
+ cc = 2;
+ goto done;
+ }
+ }
+ cc = 0;
+ done:
+ HELPER_LOG("\n");
+ return cc;
+}
+
+/* compare logical under mask */
+uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
+ uint64_t addr)
+{
+ uint8_t r, d;
+ uint32_t cc;
+
+ HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
+ mask, addr);
+ cc = 0;
+ while (mask) {
+ if (mask & 8) {
+ d = cpu_ldub_data(env, addr);
+ r = (r1 & 0xff000000UL) >> 24;
+ HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
+ addr);
+ if (r < d) {
+ cc = 1;
+ break;
+ } else if (r > d) {
+ cc = 2;
+ break;
+ }
+ addr++;
+ }
+ mask = (mask << 1) & 0xf;
+ r1 <<= 8;
+ }
+ HELPER_LOG("\n");
+ return cc;
+}
+
+/* store character under mask */
+void HELPER(stcm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
+ uint64_t addr)
+{
+ uint8_t r;
+
+ HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask,
+ addr);
+ while (mask) {
+ if (mask & 8) {
+ r = (r1 & 0xff000000UL) >> 24;
+ cpu_stb_data(env, addr, r);
+ HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
+ addr++;
+ }
+ mask = (mask << 1) & 0xf;
+ r1 <<= 8;
+ }
+ HELPER_LOG("\n");
+}
+
+static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2)
+{
+ uint64_t r = d2;
+
+ if (x2) {
+ r += env->regs[x2];
+ }
+
+ if (b2) {
+ r += env->regs[b2];
+ }
+
+ /* 31-Bit mode */
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ r &= 0x7fffffff;
+ }
+
+ return r;
+}
+
+static inline uint64_t get_address_31fix(CPUS390XState *env, int reg)
+{
+ uint64_t r = env->regs[reg];
+
+ /* 31-Bit mode */
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ r &= 0x7fffffff;
+ }
+
+ return r;
+}
+
+/* search string (c is byte to search, r2 is string, r1 end of string) */
+uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2)
+{
+ uint64_t i;
+ uint32_t cc = 2;
+ uint64_t str = get_address_31fix(env, r2);
+ uint64_t end = get_address_31fix(env, r1);
+
+ HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
+ c, env->regs[r1], env->regs[r2]);
+
+ for (i = str; i != end; i++) {
+ if (cpu_ldub_data(env, i) == c) {
+ env->regs[r1] = i;
+ cc = 1;
+ break;
+ }
+ }
+
+ return cc;
+}
+
+/* unsigned string compare (c is string terminator) */
+uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2)
+{
+ uint64_t s1 = get_address_31fix(env, r1);
+ uint64_t s2 = get_address_31fix(env, r2);
+ uint8_t v1, v2;
+ uint32_t cc;
+
+ c = c & 0xff;
+#ifdef CONFIG_USER_ONLY
+ if (!c) {
+ HELPER_LOG("%s: comparing '%s' and '%s'\n",
+ __func__, (char *)g2h(s1), (char *)g2h(s2));
+ }
+#endif
+ for (;;) {
+ v1 = cpu_ldub_data(env, s1);
+ v2 = cpu_ldub_data(env, s2);
+ if ((v1 == c || v2 == c) || (v1 != v2)) {
+ break;
+ }
+ s1++;
+ s2++;
+ }
+
+ if (v1 == v2) {
+ cc = 0;
+ } else {
+ cc = (v1 < v2) ? 1 : 2;
+ /* FIXME: 31-bit mode! */
+ env->regs[r1] = s1;
+ env->regs[r2] = s2;
+ }
+ return cc;
+}
+
+/* move page */
+void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
+{
+ /* XXX missing r0 handling */
+#ifdef CONFIG_USER_ONLY
+ int i;
+
+ for (i = 0; i < TARGET_PAGE_SIZE; i++) {
+ cpu_stb_data(env, r1 + i, cpu_ldub_data(env, r2 + i));
+ }
+#else
+ mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
+#endif
+}
+
+/* string copy (c is string terminator) */
+void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2)
+{
+ uint64_t dest = get_address_31fix(env, r1);
+ uint64_t src = get_address_31fix(env, r2);
+ uint8_t v;
+
+ c = c & 0xff;
+#ifdef CONFIG_USER_ONLY
+ if (!c) {
+ HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src),
+ dest);
+ }
+#endif
+ for (;;) {
+ v = cpu_ldub_data(env, src);
+ cpu_stb_data(env, dest, v);
+ if (v == c) {
+ break;
+ }
+ src++;
+ dest++;
+ }
+ env->regs[r1] = dest; /* FIXME: 31-bit mode! */
+}
+
+/* compare and swap 64-bit */
+uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ /* FIXME: locking? */
+ uint32_t cc;
+ uint64_t v2 = cpu_ldq_data(env, a2);
+
+ if (env->regs[r1] == v2) {
+ cc = 0;
+ cpu_stq_data(env, a2, env->regs[r3]);
+ } else {
+ cc = 1;
+ env->regs[r1] = v2;
+ }
+ return cc;
+}
+
+/* compare double and swap 64-bit */
+uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ /* FIXME: locking? */
+ uint32_t cc;
+ uint64_t v2_hi = cpu_ldq_data(env, a2);
+ uint64_t v2_lo = cpu_ldq_data(env, a2 + 8);
+ uint64_t v1_hi = env->regs[r1];
+ uint64_t v1_lo = env->regs[r1 + 1];
+
+ if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
+ cc = 0;
+ cpu_stq_data(env, a2, env->regs[r3]);
+ cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]);
+ } else {
+ cc = 1;
+ env->regs[r1] = v2_hi;
+ env->regs[r1 + 1] = v2_lo;
+ }
+
+ return cc;
+}
+
+/* compare and swap 32-bit */
+uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ /* FIXME: locking? */
+ uint32_t cc;
+ uint32_t v2 = cpu_ldl_data(env, a2);
+
+ HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3);
+ if (((uint32_t)env->regs[r1]) == v2) {
+ cc = 0;
+ cpu_stl_data(env, a2, (uint32_t)env->regs[r3]);
+ } else {
+ cc = 1;
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
+ }
+ return cc;
+}
+
+static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
+ uint32_t mask)
+{
+ int pos = 24; /* top of the lower half of r1 */
+ uint64_t rmask = 0xff000000ULL;
+ uint8_t val = 0;
+ int ccd = 0;
+ uint32_t cc = 0;
+
+ while (mask) {
+ if (mask & 8) {
+ env->regs[r1] &= ~rmask;
+ val = cpu_ldub_data(env, address);
+ if ((val & 0x80) && !ccd) {
+ cc = 1;
+ }
+ ccd = 1;
+ if (val && cc == 0) {
+ cc = 2;
+ }
+ env->regs[r1] |= (uint64_t)val << pos;
+ address++;
+ }
+ mask = (mask << 1) & 0xf;
+ pos -= 8;
+ rmask >>= 8;
+ }
+
+ return cc;
+}
+
+/* execute instruction
+ this instruction executes an insn modified with the contents of r1
+ it does not change the executed instruction in memory
+ it does not change the program counter
+ in other words: tricky...
+ currently implemented by interpreting the cases it is most commonly used in
+*/
+uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
+ uint64_t addr, uint64_t ret)
+{
+ uint16_t insn = cpu_lduw_code(env, addr);
+
+ HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
+ insn);
+ if ((insn & 0xf0ff) == 0xd000) {
+ uint32_t l, insn2, b1, b2, d1, d2;
+
+ l = v1 & 0xff;
+ insn2 = cpu_ldl_code(env, addr + 2);
+ b1 = (insn2 >> 28) & 0xf;
+ b2 = (insn2 >> 12) & 0xf;
+ d1 = (insn2 >> 16) & 0xfff;
+ d2 = insn2 & 0xfff;
+ switch (insn & 0xf00) {
+ case 0x200:
+ helper_mvc(env, l, get_address(env, 0, b1, d1),
+ get_address(env, 0, b2, d2));
+ break;
+ case 0x500:
+ cc = helper_clc(env, l, get_address(env, 0, b1, d1),
+ get_address(env, 0, b2, d2));
+ break;
+ case 0x700:
+ cc = helper_xc(env, l, get_address(env, 0, b1, d1),
+ get_address(env, 0, b2, d2));
+ break;
+ case 0xc00:
+ helper_tr(env, l, get_address(env, 0, b1, d1),
+ get_address(env, 0, b2, d2));
+ break;
+ default:
+ goto abort;
+ break;
+ }
+ } else if ((insn & 0xff00) == 0x0a00) {
+ /* supervisor call */
+ HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
+ env->psw.addr = ret - 4;
+ env->int_svc_code = (insn | v1) & 0xff;
+ env->int_svc_ilc = 4;
+ helper_exception(env, EXCP_SVC);
+ } else if ((insn & 0xff00) == 0xbf00) {
+ uint32_t insn2, r1, r3, b2, d2;
+
+ insn2 = cpu_ldl_code(env, addr + 2);
+ r1 = (insn2 >> 20) & 0xf;
+ r3 = (insn2 >> 16) & 0xf;
+ b2 = (insn2 >> 12) & 0xf;
+ d2 = insn2 & 0xfff;
+ cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
+ } else {
+ abort:
+ cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
+ insn);
+ }
+ return cc;
+}
+
+/* store character under mask high operates on the upper half of r1 */
+void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address,
+ uint32_t mask)
+{
+ int pos = 56; /* top of the upper half of r1 */
+
+ while (mask) {
+ if (mask & 8) {
+ cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff);
+ address++;
+ }
+ mask = (mask << 1) & 0xf;
+ pos -= 8;
+ }
+}
+
+/* insert character under mask high; same as icm, but operates on the
+ upper half of r1 */
+uint32_t HELPER(icmh)(CPUS390XState *env, uint32_t r1, uint64_t address,
+ uint32_t mask)
+{
+ int pos = 56; /* top of the upper half of r1 */
+ uint64_t rmask = 0xff00000000000000ULL;
+ uint8_t val = 0;
+ int ccd = 0;
+ uint32_t cc = 0;
+
+ while (mask) {
+ if (mask & 8) {
+ env->regs[r1] &= ~rmask;
+ val = cpu_ldub_data(env, address);
+ if ((val & 0x80) && !ccd) {
+ cc = 1;
+ }
+ ccd = 1;
+ if (val && cc == 0) {
+ cc = 2;
+ }
+ env->regs[r1] |= (uint64_t)val << pos;
+ address++;
+ }
+ mask = (mask << 1) & 0xf;
+ pos -= 8;
+ rmask >>= 8;
+ }
+
+ return cc;
+}
+
+/* load access registers r1 to r3 from memory at a2 */
+void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ int i;
+
+ for (i = r1;; i = (i + 1) % 16) {
+ env->aregs[i] = cpu_ldl_data(env, a2);
+ a2 += 4;
+
+ if (i == r3) {
+ break;
+ }
+ }
+}
+
+/* store access registers r1 to r3 in memory at a2 */
+void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ int i;
+
+ for (i = r1;; i = (i + 1) % 16) {
+ cpu_stl_data(env, a2, env->aregs[i]);
+ a2 += 4;
+
+ if (i == r3) {
+ break;
+ }
+ }
+}
+
+/* move long */
+uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+ uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
+ uint64_t dest = get_address_31fix(env, r1);
+ uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
+ uint64_t src = get_address_31fix(env, r2);
+ uint8_t pad = src >> 24;
+ uint8_t v;
+ uint32_t cc;
+
+ if (destlen == srclen) {
+ cc = 0;
+ } else if (destlen < srclen) {
+ cc = 1;
+ } else {
+ cc = 2;
+ }
+
+ if (srclen > destlen) {
+ srclen = destlen;
+ }
+
+ for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
+ v = cpu_ldub_data(env, src);
+ cpu_stb_data(env, dest, v);
+ }
+
+ for (; destlen; dest++, destlen--) {
+ cpu_stb_data(env, dest, pad);
+ }
+
+ env->regs[r1 + 1] = destlen;
+ /* can't use srclen here, we trunc'ed it */
+ env->regs[r2 + 1] -= src - env->regs[r2];
+ env->regs[r1] = dest;
+ env->regs[r2] = src;
+
+ return cc;
+}
+
+/* move long extended another memcopy insn with more bells and whistles */
+uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
+ uint32_t r3)
+{
+ uint64_t destlen = env->regs[r1 + 1];
+ uint64_t dest = env->regs[r1];
+ uint64_t srclen = env->regs[r3 + 1];
+ uint64_t src = env->regs[r3];
+ uint8_t pad = a2 & 0xff;
+ uint8_t v;
+ uint32_t cc;
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ destlen = (uint32_t)destlen;
+ srclen = (uint32_t)srclen;
+ dest &= 0x7fffffff;
+ src &= 0x7fffffff;
+ }
+
+ if (destlen == srclen) {
+ cc = 0;
+ } else if (destlen < srclen) {
+ cc = 1;
+ } else {
+ cc = 2;
+ }
+
+ if (srclen > destlen) {
+ srclen = destlen;
+ }
+
+ for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
+ v = cpu_ldub_data(env, src);
+ cpu_stb_data(env, dest, v);
+ }
+
+ for (; destlen; dest++, destlen--) {
+ cpu_stb_data(env, dest, pad);
+ }
+
+ env->regs[r1 + 1] = destlen;
+ /* can't use srclen here, we trunc'ed it */
+ /* FIXME: 31-bit mode! */
+ env->regs[r3 + 1] -= src - env->regs[r3];
+ env->regs[r1] = dest;
+ env->regs[r3] = src;
+
+ return cc;
+}
+
+/* compare logical long extended memcompare insn with padding */
+uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
+ uint32_t r3)
+{
+ uint64_t destlen = env->regs[r1 + 1];
+ uint64_t dest = get_address_31fix(env, r1);
+ uint64_t srclen = env->regs[r3 + 1];
+ uint64_t src = get_address_31fix(env, r3);
+ uint8_t pad = a2 & 0xff;
+ uint8_t v1 = 0, v2 = 0;
+ uint32_t cc = 0;
+
+ if (!(destlen || srclen)) {
+ return cc;
+ }
+
+ if (srclen > destlen) {
+ srclen = destlen;
+ }
+
+ for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
+ v1 = srclen ? cpu_ldub_data(env, src) : pad;
+ v2 = destlen ? cpu_ldub_data(env, dest) : pad;
+ if (v1 != v2) {
+ cc = (v1 < v2) ? 1 : 2;
+ break;
+ }
+ }
+
+ env->regs[r1 + 1] = destlen;
+ /* can't use srclen here, we trunc'ed it */
+ env->regs[r3 + 1] -= src - env->regs[r3];
+ env->regs[r1] = dest;
+ env->regs[r3] = src;
+
+ return cc;
+}
+
+/* checksum */
+void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+ uint64_t src = get_address_31fix(env, r2);
+ uint64_t src_len = env->regs[(r2 + 1) & 15];
+ uint64_t cksm = (uint32_t)env->regs[r1];
+
+ while (src_len >= 4) {
+ cksm += cpu_ldl_data(env, src);
+
+ /* move to next word */
+ src_len -= 4;
+ src += 4;
+ }
+
+ switch (src_len) {
+ case 0:
+ break;
+ case 1:
+ cksm += cpu_ldub_data(env, src) << 24;
+ break;
+ case 2:
+ cksm += cpu_lduw_data(env, src) << 16;
+ break;
+ case 3:
+ cksm += cpu_lduw_data(env, src) << 16;
+ cksm += cpu_ldub_data(env, src + 2) << 8;
+ break;
+ }
+
+ /* indicate we've processed everything */
+ env->regs[r2] = src + src_len;
+ env->regs[(r2 + 1) & 15] = 0;
+
+ /* store result */
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+ ((uint32_t)cksm + (cksm >> 32));
+}
+
+void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
+ uint64_t src)
+{
+ int len_dest = len >> 4;
+ int len_src = len & 0xf;
+ uint8_t b;
+ int second_nibble = 0;
+
+ dest += len_dest;
+ src += len_src;
+
+ /* last byte is special, it only flips the nibbles */
+ b = cpu_ldub_data(env, src);
+ cpu_stb_data(env, dest, (b << 4) | (b >> 4));
+ src--;
+ len_src--;
+
+ /* now pad every nibble with 0xf0 */
+
+ while (len_dest > 0) {
+ uint8_t cur_byte = 0;
+
+ if (len_src > 0) {
+ cur_byte = cpu_ldub_data(env, src);
+ }
+
+ len_dest--;
+ dest--;
+
+ /* only advance one nibble at a time */
+ if (second_nibble) {
+ cur_byte >>= 4;
+ len_src--;
+ src--;
+ }
+ second_nibble = !second_nibble;
+
+ /* digit */
+ cur_byte = (cur_byte & 0xf);
+ /* zone bits */
+ cur_byte |= 0xf0;
+
+ cpu_stb_data(env, dest, cur_byte);
+ }
+}
+
+void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
+ uint64_t trans)
+{
+ int i;
+
+ for (i = 0; i <= len; i++) {
+ uint8_t byte = cpu_ldub_data(env, array + i);
+ uint8_t new_byte = cpu_ldub_data(env, trans + byte);
+
+ cpu_stb_data(env, array + i, new_byte);
+ }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ int i;
+ uint64_t src = a2;
+
+ for (i = r1;; i = (i + 1) % 16) {
+ env->cregs[i] = cpu_ldq_data(env, src);
+ HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
+ i, src, env->cregs[i]);
+ src += sizeof(uint64_t);
+
+ if (i == r3) {
+ break;
+ }
+ }
+
+ tlb_flush(env, 1);
+}
+
+void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ int i;
+ uint64_t src = a2;
+
+ for (i = r1;; i = (i + 1) % 16) {
+ env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) |
+ cpu_ldl_data(env, src);
+ src += sizeof(uint32_t);
+
+ if (i == r3) {
+ break;
+ }
+ }
+
+ tlb_flush(env, 1);
+}
+
+void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ int i;
+ uint64_t dest = a2;
+
+ for (i = r1;; i = (i + 1) % 16) {
+ cpu_stq_data(env, dest, env->cregs[i]);
+ dest += sizeof(uint64_t);
+
+ if (i == r3) {
+ break;
+ }
+ }
+}
+
+void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+ int i;
+ uint64_t dest = a2;
+
+ for (i = r1;; i = (i + 1) % 16) {
+ cpu_stl_data(env, dest, env->cregs[i]);
+ dest += sizeof(uint32_t);
+
+ if (i == r3) {
+ break;
+ }
+ }
+}
+
+uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
+{
+ /* XXX implement */
+
+ return 0;
+}
+
+/* insert storage key extended */
+uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
+{
+ uint64_t addr = get_address(env, 0, 0, r2);
+
+ if (addr > ram_size) {
+ return 0;
+ }
+
+ return env->storage_keys[addr / TARGET_PAGE_SIZE];
+}
+
+/* set storage key extended */
+void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2)
+{
+ uint64_t addr = get_address(env, 0, 0, r2);
+
+ if (addr > ram_size) {
+ return;
+ }
+
+ env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
+}
+
+/* reset reference bit extended */
+uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2)
+{
+ uint8_t re;
+ uint8_t key;
+
+ if (r2 > ram_size) {
+ return 0;
+ }
+
+ key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
+ re = key & (SK_R | SK_C);
+ env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
+
+ /*
+ * cc
+ *
+ * 0 Reference bit zero; change bit zero
+ * 1 Reference bit zero; change bit one
+ * 2 Reference bit one; change bit zero
+ * 3 Reference bit one; change bit one
+ */
+
+ return re >> 1;
+}
+
+/* compare and swap and purge */
+uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+ uint32_t cc;
+ uint32_t o1 = env->regs[r1];
+ uint64_t a2 = get_address_31fix(env, r2) & ~3ULL;
+ uint32_t o2 = cpu_ldl_data(env, a2);
+
+ if (o1 == o2) {
+ cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
+ if (env->regs[r2] & 0x3) {
+ /* flush TLB / ALB */
+ tlb_flush(env, 1);
+ }
+ cc = 0;
+ } else {
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
+ cc = 1;
+ }
+
+ return cc;
+}
+
+static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
+ uint64_t mode1, uint64_t a2, uint64_t mode2)
+{
+ target_ulong src, dest;
+ int flags, cc = 0, i;
+
+ if (!l) {
+ return 0;
+ } else if (l > 256) {
+ /* max 256 */
+ l = 256;
+ cc = 3;
+ }
+
+ if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
+ cpu_loop_exit(env);
+ }
+ dest |= a1 & ~TARGET_PAGE_MASK;
+
+ if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
+ cpu_loop_exit(env);
+ }
+ src |= a2 & ~TARGET_PAGE_MASK;
+
+ /* XXX replace w/ memcpy */
+ for (i = 0; i < l; i++) {
+ /* XXX be more clever */
+ if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
+ (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
+ mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2);
+ break;
+ }
+ stb_phys(dest + i, ldub_phys(src + i));
+ }
+
+ return cc;
+}
+
+uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
+{
+ HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+ __func__, l, a1, a2);
+
+ return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
+}
+
+uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
+{
+ HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+ __func__, l, a1, a2);
+
+ return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
+}
+
+/* invalidate pte */
+void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
+{
+ uint64_t page = vaddr & TARGET_PAGE_MASK;
+ uint64_t pte = 0;
+
+ /* XXX broadcast to other CPUs */
+
+ /* XXX Linux is nice enough to give us the exact pte address.
+ According to spec we'd have to find it out ourselves */
+ /* XXX Linux is fine with overwriting the pte, the spec requires
+ us to only set the invalid bit */
+ stq_phys(pte_addr, pte | _PAGE_INVALID);
+
+ /* XXX we exploit the fact that Linux passes the exact virtual
+ address here - it's not obliged to! */
+ tlb_flush_page(env, page);
+
+ /* XXX 31-bit hack */
+ if (page & 0x80000000) {
+ tlb_flush_page(env, page & ~0x80000000);
+ } else {
+ tlb_flush_page(env, page | 0x80000000);
+ }
+}
+
+/* flush local tlb */
+void HELPER(ptlb)(CPUS390XState *env)
+{
+ tlb_flush(env, 1);
+}
+
+/* store using real address */
+void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1)
+{
+ stw_phys(get_address(env, 0, 0, addr), v1);
+}
+
+/* load real address */
+uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1)
+{
+ uint32_t cc = 0;
+ int old_exc = env->exception_index;
+ uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+ uint64_t ret;
+ int flags;
+
+ /* XXX incomplete - has more corner cases */
+ if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
+ program_interrupt(env, PGM_SPECIAL_OP, 2);
+ }
+
+ env->exception_index = old_exc;
+ if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
+ cc = 3;
+ }
+ if (env->exception_index == EXCP_PGM) {
+ ret = env->int_pgm_code | 0x80000000;
+ } else {
+ ret |= addr & ~TARGET_PAGE_MASK;
+ }
+ env->exception_index = old_exc;
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+ (ret & 0xffffffffULL);
+ } else {
+ env->regs[r1] = ret;
+ }
+
+ return cc;
+}
+
+#endif
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
new file mode 100644
index 000000000..2938ac9c7
--- /dev/null
+++ b/target-s390x/misc_helper.c
@@ -0,0 +1,430 @@
+/*
+ * S/390 misc helper routines
+ *
+ * Copyright (c) 2009 Ulrich Hecht
+ * Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "memory.h"
+#include "cputlb.h"
+#include "host-utils.h"
+#include "helper.h"
+#include <string.h>
+#include "kvm.h"
+#include "qemu-timer.h"
+#ifdef CONFIG_KVM
+#include <linux/kvm.h>
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#include "sysemu.h"
+#endif
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+/* raise an exception */
+void HELPER(exception)(CPUS390XState *env, uint32_t excp)
+{
+ HELPER_LOG("%s: exception %d\n", __func__, excp);
+ env->exception_index = excp;
+ cpu_loop_exit(env);
+}
+
+#ifndef CONFIG_USER_ONLY
+void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
+{
+ qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
+
+ if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+ kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
+#endif
+ } else {
+ env->int_pgm_code = code;
+ env->int_pgm_ilc = ilc;
+ env->exception_index = EXCP_PGM;
+ cpu_loop_exit(env);
+ }
+}
+
+/*
+ * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc
+ */
+int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
+{
+ int r = 0;
+ int shift = 0;
+
+#ifdef DEBUG_HELPER
+ printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
+#endif
+
+ /* basic checks */
+ if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) {
+ return -PGM_ADDRESSING;
+ }
+ if (sccb & ~0x7ffffff8ul) {
+ return -PGM_SPECIFICATION;
+ }
+
+ switch (code) {
+ case SCLP_CMDW_READ_SCP_INFO:
+ case SCLP_CMDW_READ_SCP_INFO_FORCED:
+ while ((ram_size >> (20 + shift)) > 65535) {
+ shift++;
+ }
+ stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
+ stb_phys(sccb + SCP_INCREMENT, 1 << shift);
+ stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
+
+ s390_sclp_extint(sccb & ~3);
+ break;
+ default:
+#ifdef DEBUG_HELPER
+ printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
+#endif
+ r = 3;
+ break;
+ }
+
+ return r;
+}
+
+/* SCLP service call */
+uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2)
+{
+ int r;
+
+ r = sclp_service_call(env, r1, r2);
+ if (r < 0) {
+ program_interrupt(env, -r, 4);
+ return 0;
+ }
+ return r;
+}
+
+/* DIAG */
+uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
+ uint64_t code)
+{
+ uint64_t r;
+
+ switch (num) {
+ case 0x500:
+ /* KVM hypercall */
+ r = s390_virtio_hypercall(env, mem, code);
+ break;
+ case 0x44:
+ /* yield */
+ r = 0;
+ break;
+ case 0x308:
+ /* ipl */
+ r = 0;
+ break;
+ default:
+ r = -1;
+ break;
+ }
+
+ if (r) {
+ program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
+ }
+
+ return r;
+}
+
+/* Store CPU ID */
+void HELPER(stidp)(CPUS390XState *env, uint64_t a1)
+{
+ cpu_stq_data(env, a1, env->cpu_num);
+}
+
+/* Set Prefix */
+void HELPER(spx)(CPUS390XState *env, uint64_t a1)
+{
+ uint32_t prefix;
+
+ prefix = cpu_ldl_data(env, a1);
+ env->psa = prefix & 0xfffff000;
+ qemu_log("prefix: %#x\n", prefix);
+ tlb_flush_page(env, 0);
+ tlb_flush_page(env, TARGET_PAGE_SIZE);
+}
+
+/* Set Clock */
+uint32_t HELPER(sck)(uint64_t a1)
+{
+ /* XXX not implemented - is it necessary? */
+
+ return 0;
+}
+
+static inline uint64_t clock_value(CPUS390XState *env)
+{
+ uint64_t time;
+
+ time = env->tod_offset +
+ time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
+
+ return time;
+}
+
+/* Store Clock */
+uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1)
+{
+ cpu_stq_data(env, a1, clock_value(env));
+
+ return 0;
+}
+
+/* Store Clock Extended */
+uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1)
+{
+ cpu_stb_data(env, a1, 0);
+ /* basically the same value as stck */
+ cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num);
+ /* more fine grained than stck */
+ cpu_stq_data(env, a1 + 9, 0);
+ /* XXX programmable fields */
+ cpu_stw_data(env, a1 + 17, 0);
+
+ return 0;
+}
+
+/* Set Clock Comparator */
+void HELPER(sckc)(CPUS390XState *env, uint64_t a1)
+{
+ uint64_t time = cpu_ldq_data(env, a1);
+
+ if (time == -1ULL) {
+ return;
+ }
+
+ /* difference between now and then */
+ time -= clock_value(env);
+ /* nanoseconds */
+ time = (time * 125) >> 9;
+
+ qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
+}
+
+/* Store Clock Comparator */
+void HELPER(stckc)(CPUS390XState *env, uint64_t a1)
+{
+ /* XXX implement */
+ cpu_stq_data(env, a1, 0);
+}
+
+/* Set CPU Timer */
+void HELPER(spt)(CPUS390XState *env, uint64_t a1)
+{
+ uint64_t time = cpu_ldq_data(env, a1);
+
+ if (time == -1ULL) {
+ return;
+ }
+
+ /* nanoseconds */
+ time = (time * 125) >> 9;
+
+ qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
+}
+
+/* Store CPU Timer */
+void HELPER(stpt)(CPUS390XState *env, uint64_t a1)
+{
+ /* XXX implement */
+ cpu_stq_data(env, a1, 0);
+}
+
+/* Store System Information */
+uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0,
+ uint32_t r1)
+{
+ int cc = 0;
+ int sel1, sel2;
+
+ if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
+ ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
+ /* valid function code, invalid reserved bits */
+ program_interrupt(env, PGM_SPECIFICATION, 2);
+ }
+
+ sel1 = r0 & STSI_R0_SEL1_MASK;
+ sel2 = r1 & STSI_R1_SEL2_MASK;
+
+ /* XXX: spec exception if sysib is not 4k-aligned */
+
+ switch (r0 & STSI_LEVEL_MASK) {
+ case STSI_LEVEL_1:
+ if ((sel1 == 1) && (sel2 == 1)) {
+ /* Basic Machine Configuration */
+ struct sysib_111 sysib;
+
+ memset(&sysib, 0, sizeof(sysib));
+ ebcdic_put(sysib.manuf, "QEMU ", 16);
+ /* same as machine type number in STORE CPU ID */
+ ebcdic_put(sysib.type, "QEMU", 4);
+ /* same as model number in STORE CPU ID */
+ ebcdic_put(sysib.model, "QEMU ", 16);
+ ebcdic_put(sysib.sequence, "QEMU ", 16);
+ ebcdic_put(sysib.plant, "QEMU", 4);
+ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
+ } else if ((sel1 == 2) && (sel2 == 1)) {
+ /* Basic Machine CPU */
+ struct sysib_121 sysib;
+
+ memset(&sysib, 0, sizeof(sysib));
+ /* XXX make different for different CPUs? */
+ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
+ ebcdic_put(sysib.plant, "QEMU", 4);
+ stw_p(&sysib.cpu_addr, env->cpu_num);
+ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
+ } else if ((sel1 == 2) && (sel2 == 2)) {
+ /* Basic Machine CPUs */
+ struct sysib_122 sysib;
+
+ memset(&sysib, 0, sizeof(sysib));
+ stl_p(&sysib.capability, 0x443afc29);
+ /* XXX change when SMP comes */
+ stw_p(&sysib.total_cpus, 1);
+ stw_p(&sysib.active_cpus, 1);
+ stw_p(&sysib.standby_cpus, 0);
+ stw_p(&sysib.reserved_cpus, 0);
+ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
+ } else {
+ cc = 3;
+ }
+ break;
+ case STSI_LEVEL_2:
+ {
+ if ((sel1 == 2) && (sel2 == 1)) {
+ /* LPAR CPU */
+ struct sysib_221 sysib;
+
+ memset(&sysib, 0, sizeof(sysib));
+ /* XXX make different for different CPUs? */
+ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
+ ebcdic_put(sysib.plant, "QEMU", 4);
+ stw_p(&sysib.cpu_addr, env->cpu_num);
+ stw_p(&sysib.cpu_id, 0);
+ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
+ } else if ((sel1 == 2) && (sel2 == 2)) {
+ /* LPAR CPUs */
+ struct sysib_222 sysib;
+
+ memset(&sysib, 0, sizeof(sysib));
+ stw_p(&sysib.lpar_num, 0);
+ sysib.lcpuc = 0;
+ /* XXX change when SMP comes */
+ stw_p(&sysib.total_cpus, 1);
+ stw_p(&sysib.conf_cpus, 1);
+ stw_p(&sysib.standby_cpus, 0);
+ stw_p(&sysib.reserved_cpus, 0);
+ ebcdic_put(sysib.name, "QEMU ", 8);
+ stl_p(&sysib.caf, 1000);
+ stw_p(&sysib.dedicated_cpus, 0);
+ stw_p(&sysib.shared_cpus, 0);
+ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
+ } else {
+ cc = 3;
+ }
+ break;
+ }
+ case STSI_LEVEL_3:
+ {
+ if ((sel1 == 2) && (sel2 == 2)) {
+ /* VM CPUs */
+ struct sysib_322 sysib;
+
+ memset(&sysib, 0, sizeof(sysib));
+ sysib.count = 1;
+ /* XXX change when SMP comes */
+ stw_p(&sysib.vm[0].total_cpus, 1);
+ stw_p(&sysib.vm[0].conf_cpus, 1);
+ stw_p(&sysib.vm[0].standby_cpus, 0);
+ stw_p(&sysib.vm[0].reserved_cpus, 0);
+ ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
+ stl_p(&sysib.vm[0].caf, 1000);
+ ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
+ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
+ } else {
+ cc = 3;
+ }
+ break;
+ }
+ case STSI_LEVEL_CURRENT:
+ env->regs[0] = STSI_LEVEL_3;
+ break;
+ default:
+ cc = 3;
+ break;
+ }
+
+ return cc;
+}
+
+uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
+ uint64_t cpu_addr)
+{
+ int cc = 0;
+
+ HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
+ __func__, order_code, r1, cpu_addr);
+
+ /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
+ as parameter (input). Status (output) is always R1. */
+
+ switch (order_code) {
+ case SIGP_SET_ARCH:
+ /* switch arch */
+ break;
+ case SIGP_SENSE:
+ /* enumerate CPU status */
+ if (cpu_addr) {
+ /* XXX implement when SMP comes */
+ return 3;
+ }
+ env->regs[r1] &= 0xffffffff00000000ULL;
+ cc = 1;
+ break;
+#if !defined(CONFIG_USER_ONLY)
+ case SIGP_RESTART:
+ qemu_system_reset_request();
+ cpu_loop_exit(env);
+ break;
+ case SIGP_STOP:
+ qemu_system_shutdown_request();
+ cpu_loop_exit(env);
+ break;
+#endif
+ default:
+ /* unknown sigp */
+ fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
+ cc = 3;
+ }
+
+ return cc;
+}
+#endif
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
deleted file mode 100644
index abc35ddd7..000000000
--- a/target-s390x/op_helper.c
+++ /dev/null
@@ -1,3019 +0,0 @@
-/*
- * S/390 helper routines
- *
- * Copyright (c) 2009 Ulrich Hecht
- * Copyright (c) 2009 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "cpu.h"
-#include "memory.h"
-#include "cputlb.h"
-#include "dyngen-exec.h"
-#include "host-utils.h"
-#include "helper.h"
-#include <string.h>
-#include "kvm.h"
-#include "qemu-timer.h"
-#ifdef CONFIG_KVM
-#include <linux/kvm.h>
-#endif
-
-#if !defined (CONFIG_USER_ONLY)
-#include "sysemu.h"
-#endif
-
-/*****************************************************************************/
-/* Softmmu support */
-#if !defined (CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-
-#define MMUSUFFIX _mmu
-
-#define SHIFT 0
-#include "softmmu_template.h"
-
-#define SHIFT 1
-#include "softmmu_template.h"
-
-#define SHIFT 2
-#include "softmmu_template.h"
-
-#define SHIFT 3
-#include "softmmu_template.h"
-
-/* try to fill the TLB and return an exception if error. If retaddr is
- NULL, it means that the function was called in C code (i.e. not
- from generated code or from helper.c) */
-/* XXX: fix it to restore all registers */
-void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
- uintptr_t retaddr)
-{
- TranslationBlock *tb;
- CPUS390XState *saved_env;
- int ret;
-
- saved_env = env;
- env = env1;
- ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
- if (unlikely(ret != 0)) {
- if (likely(retaddr)) {
- /* now we have a real cpu fault */
- tb = tb_find_pc(retaddr);
- if (likely(tb)) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, retaddr);
- }
- }
- cpu_loop_exit(env);
- }
- env = saved_env;
-}
-
-#endif
-
-/* #define DEBUG_HELPER */
-#ifdef DEBUG_HELPER
-#define HELPER_LOG(x...) qemu_log(x)
-#else
-#define HELPER_LOG(x...)
-#endif
-
-/* raise an exception */
-void HELPER(exception)(uint32_t excp)
-{
- HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp);
- env->exception_index = excp;
- cpu_loop_exit(env);
-}
-
-#ifndef CONFIG_USER_ONLY
-static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
- uint8_t byte)
-{
- target_phys_addr_t dest_phys;
- target_phys_addr_t len = l;
- void *dest_p;
- uint64_t asc = env->psw.mask & PSW_MASK_ASC;
- int flags;
-
- if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
- stb(dest, byte);
- cpu_abort(env, "should never reach here");
- }
- dest_phys |= dest & ~TARGET_PAGE_MASK;
-
- dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
-
- memset(dest_p, byte, len);
-
- cpu_physical_memory_unmap(dest_p, 1, len, len);
-}
-
-static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
- uint64_t src)
-{
- target_phys_addr_t dest_phys;
- target_phys_addr_t src_phys;
- target_phys_addr_t len = l;
- void *dest_p;
- void *src_p;
- uint64_t asc = env->psw.mask & PSW_MASK_ASC;
- int flags;
-
- if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
- stb(dest, 0);
- cpu_abort(env, "should never reach here");
- }
- dest_phys |= dest & ~TARGET_PAGE_MASK;
-
- if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
- ldub(src);
- cpu_abort(env, "should never reach here");
- }
- src_phys |= src & ~TARGET_PAGE_MASK;
-
- dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
- src_p = cpu_physical_memory_map(src_phys, &len, 0);
-
- memmove(dest_p, src_p, len);
-
- cpu_physical_memory_unmap(dest_p, 1, len, len);
- cpu_physical_memory_unmap(src_p, 0, len, len);
-}
-#endif
-
-/* and on array */
-uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
-{
- int i;
- unsigned char x;
- uint32_t cc = 0;
-
- HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
- __FUNCTION__, l, dest, src);
- for (i = 0; i <= l; i++) {
- x = ldub(dest + i) & ldub(src + i);
- if (x) {
- cc = 1;
- }
- stb(dest + i, x);
- }
- return cc;
-}
-
-/* xor on array */
-uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
-{
- int i;
- unsigned char x;
- uint32_t cc = 0;
-
- HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
- __FUNCTION__, l, dest, src);
-
-#ifndef CONFIG_USER_ONLY
- /* xor with itself is the same as memset(0) */
- if ((l > 32) && (src == dest) &&
- (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
- mvc_fast_memset(env, l + 1, dest, 0);
- return 0;
- }
-#else
- if (src == dest) {
- memset(g2h(dest), 0, l + 1);
- return 0;
- }
-#endif
-
- for (i = 0; i <= l; i++) {
- x = ldub(dest + i) ^ ldub(src + i);
- if (x) {
- cc = 1;
- }
- stb(dest + i, x);
- }
- return cc;
-}
-
-/* or on array */
-uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
-{
- int i;
- unsigned char x;
- uint32_t cc = 0;
-
- HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
- __FUNCTION__, l, dest, src);
- for (i = 0; i <= l; i++) {
- x = ldub(dest + i) | ldub(src + i);
- if (x) {
- cc = 1;
- }
- stb(dest + i, x);
- }
- return cc;
-}
-
-/* memmove */
-void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
-{
- int i = 0;
- int x = 0;
- uint32_t l_64 = (l + 1) / 8;
-
- HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
- __FUNCTION__, l, dest, src);
-
-#ifndef CONFIG_USER_ONLY
- if ((l > 32) &&
- (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
- (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
- if (dest == (src + 1)) {
- mvc_fast_memset(env, l + 1, dest, ldub(src));
- return;
- } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
- mvc_fast_memmove(env, l + 1, dest, src);
- return;
- }
- }
-#else
- if (dest == (src + 1)) {
- memset(g2h(dest), ldub(src), l + 1);
- return;
- } else {
- memmove(g2h(dest), g2h(src), l + 1);
- return;
- }
-#endif
-
- /* handle the parts that fit into 8-byte loads/stores */
- if (dest != (src + 1)) {
- for (i = 0; i < l_64; i++) {
- stq(dest + x, ldq(src + x));
- x += 8;
- }
- }
-
- /* slow version crossing pages with byte accesses */
- for (i = x; i <= l; i++) {
- stb(dest + i, ldub(src + i));
- }
-}
-
-/* compare unsigned byte arrays */
-uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
-{
- int i;
- unsigned char x,y;
- uint32_t cc;
- HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
- __FUNCTION__, l, s1, s2);
- for (i = 0; i <= l; i++) {
- x = ldub(s1 + i);
- y = ldub(s2 + i);
- HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
- if (x < y) {
- cc = 1;
- goto done;
- } else if (x > y) {
- cc = 2;
- goto done;
- }
- }
- cc = 0;
-done:
- HELPER_LOG("\n");
- return cc;
-}
-
-/* compare logical under mask */
-uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
-{
- uint8_t r,d;
- uint32_t cc;
- HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __FUNCTION__, r1,
- mask, addr);
- cc = 0;
- while (mask) {
- if (mask & 8) {
- d = ldub(addr);
- r = (r1 & 0xff000000UL) >> 24;
- HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
- addr);
- if (r < d) {
- cc = 1;
- break;
- } else if (r > d) {
- cc = 2;
- break;
- }
- addr++;
- }
- mask = (mask << 1) & 0xf;
- r1 <<= 8;
- }
- HELPER_LOG("\n");
- return cc;
-}
-
-/* store character under mask */
-void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
-{
- uint8_t r;
- HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __FUNCTION__, r1, mask,
- addr);
- while (mask) {
- if (mask & 8) {
- r = (r1 & 0xff000000UL) >> 24;
- stb(addr, r);
- HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
- addr++;
- }
- mask = (mask << 1) & 0xf;
- r1 <<= 8;
- }
- HELPER_LOG("\n");
-}
-
-/* 64/64 -> 128 unsigned multiplication */
-void HELPER(mlg)(uint32_t r1, uint64_t v2)
-{
-#if HOST_LONG_BITS == 64 && defined(__GNUC__)
- /* assuming 64-bit hosts have __uint128_t */
- __uint128_t res = (__uint128_t)env->regs[r1 + 1];
- res *= (__uint128_t)v2;
- env->regs[r1] = (uint64_t)(res >> 64);
- env->regs[r1 + 1] = (uint64_t)res;
-#else
- mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2);
-#endif
-}
-
-/* 128 -> 64/64 unsigned division */
-void HELPER(dlg)(uint32_t r1, uint64_t v2)
-{
- uint64_t divisor = v2;
-
- if (!env->regs[r1]) {
- /* 64 -> 64/64 case */
- env->regs[r1] = env->regs[r1+1] % divisor;
- env->regs[r1+1] = env->regs[r1+1] / divisor;
- return;
- } else {
-
-#if HOST_LONG_BITS == 64 && defined(__GNUC__)
- /* assuming 64-bit hosts have __uint128_t */
- __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) |
- (env->regs[r1+1]);
- __uint128_t quotient = dividend / divisor;
- env->regs[r1+1] = quotient;
- __uint128_t remainder = dividend % divisor;
- env->regs[r1] = remainder;
-#else
- /* 32-bit hosts would need special wrapper functionality - just abort if
- we encounter such a case; it's very unlikely anyways. */
- cpu_abort(env, "128 -> 64/64 division not implemented\n");
-#endif
- }
-}
-
-static inline uint64_t get_address(int x2, int b2, int d2)
-{
- uint64_t r = d2;
-
- if (x2) {
- r += env->regs[x2];
- }
-
- if (b2) {
- r += env->regs[b2];
- }
-
- /* 31-Bit mode */
- if (!(env->psw.mask & PSW_MASK_64)) {
- r &= 0x7fffffff;
- }
-
- return r;
-}
-
-static inline uint64_t get_address_31fix(int reg)
-{
- uint64_t r = env->regs[reg];
-
- /* 31-Bit mode */
- if (!(env->psw.mask & PSW_MASK_64)) {
- r &= 0x7fffffff;
- }
-
- return r;
-}
-
-/* search string (c is byte to search, r2 is string, r1 end of string) */
-uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
-{
- uint64_t i;
- uint32_t cc = 2;
- uint64_t str = get_address_31fix(r2);
- uint64_t end = get_address_31fix(r1);
-
- HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __FUNCTION__,
- c, env->regs[r1], env->regs[r2]);
-
- for (i = str; i != end; i++) {
- if (ldub(i) == c) {
- env->regs[r1] = i;
- cc = 1;
- break;
- }
- }
-
- return cc;
-}
-
-/* unsigned string compare (c is string terminator) */
-uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
-{
- uint64_t s1 = get_address_31fix(r1);
- uint64_t s2 = get_address_31fix(r2);
- uint8_t v1, v2;
- uint32_t cc;
- c = c & 0xff;
-#ifdef CONFIG_USER_ONLY
- if (!c) {
- HELPER_LOG("%s: comparing '%s' and '%s'\n",
- __FUNCTION__, (char*)g2h(s1), (char*)g2h(s2));
- }
-#endif
- for (;;) {
- v1 = ldub(s1);
- v2 = ldub(s2);
- if ((v1 == c || v2 == c) || (v1 != v2)) {
- break;
- }
- s1++;
- s2++;
- }
-
- if (v1 == v2) {
- cc = 0;
- } else {
- cc = (v1 < v2) ? 1 : 2;
- /* FIXME: 31-bit mode! */
- env->regs[r1] = s1;
- env->regs[r2] = s2;
- }
- return cc;
-}
-
-/* move page */
-void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
-{
- /* XXX missing r0 handling */
-#ifdef CONFIG_USER_ONLY
- int i;
-
- for (i = 0; i < TARGET_PAGE_SIZE; i++) {
- stb(r1 + i, ldub(r2 + i));
- }
-#else
- mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
-#endif
-}
-
-/* string copy (c is string terminator) */
-void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
-{
- uint64_t dest = get_address_31fix(r1);
- uint64_t src = get_address_31fix(r2);
- uint8_t v;
- c = c & 0xff;
-#ifdef CONFIG_USER_ONLY
- if (!c) {
- HELPER_LOG("%s: copy '%s' to 0x%lx\n", __FUNCTION__, (char*)g2h(src),
- dest);
- }
-#endif
- for (;;) {
- v = ldub(src);
- stb(dest, v);
- if (v == c) {
- break;
- }
- src++;
- dest++;
- }
- env->regs[r1] = dest; /* FIXME: 31-bit mode! */
-}
-
-/* compare and swap 64-bit */
-uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- /* FIXME: locking? */
- uint32_t cc;
- uint64_t v2 = ldq(a2);
- if (env->regs[r1] == v2) {
- cc = 0;
- stq(a2, env->regs[r3]);
- } else {
- cc = 1;
- env->regs[r1] = v2;
- }
- return cc;
-}
-
-/* compare double and swap 64-bit */
-uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- /* FIXME: locking? */
- uint32_t cc;
- uint64_t v2_hi = ldq(a2);
- uint64_t v2_lo = ldq(a2 + 8);
- uint64_t v1_hi = env->regs[r1];
- uint64_t v1_lo = env->regs[r1 + 1];
-
- if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
- cc = 0;
- stq(a2, env->regs[r3]);
- stq(a2 + 8, env->regs[r3 + 1]);
- } else {
- cc = 1;
- env->regs[r1] = v2_hi;
- env->regs[r1 + 1] = v2_lo;
- }
-
- return cc;
-}
-
-/* compare and swap 32-bit */
-uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- /* FIXME: locking? */
- uint32_t cc;
- HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3);
- uint32_t v2 = ldl(a2);
- if (((uint32_t)env->regs[r1]) == v2) {
- cc = 0;
- stl(a2, (uint32_t)env->regs[r3]);
- } else {
- cc = 1;
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
- }
- return cc;
-}
-
-static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
-{
- int pos = 24; /* top of the lower half of r1 */
- uint64_t rmask = 0xff000000ULL;
- uint8_t val = 0;
- int ccd = 0;
- uint32_t cc = 0;
-
- while (mask) {
- if (mask & 8) {
- env->regs[r1] &= ~rmask;
- val = ldub(address);
- if ((val & 0x80) && !ccd) {
- cc = 1;
- }
- ccd = 1;
- if (val && cc == 0) {
- cc = 2;
- }
- env->regs[r1] |= (uint64_t)val << pos;
- address++;
- }
- mask = (mask << 1) & 0xf;
- pos -= 8;
- rmask >>= 8;
- }
-
- return cc;
-}
-
-/* execute instruction
- this instruction executes an insn modified with the contents of r1
- it does not change the executed instruction in memory
- it does not change the program counter
- in other words: tricky...
- currently implemented by interpreting the cases it is most commonly used in
- */
-uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
-{
- uint16_t insn = lduw_code(addr);
- HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr,
- insn);
- if ((insn & 0xf0ff) == 0xd000) {
- uint32_t l, insn2, b1, b2, d1, d2;
- l = v1 & 0xff;
- insn2 = ldl_code(addr + 2);
- b1 = (insn2 >> 28) & 0xf;
- b2 = (insn2 >> 12) & 0xf;
- d1 = (insn2 >> 16) & 0xfff;
- d2 = insn2 & 0xfff;
- switch (insn & 0xf00) {
- case 0x200:
- helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
- break;
- case 0x500:
- cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
- break;
- case 0x700:
- cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
- break;
- case 0xc00:
- helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
- break;
- default:
- goto abort;
- break;
- }
- } else if ((insn & 0xff00) == 0x0a00) {
- /* supervisor call */
- HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff);
- env->psw.addr = ret - 4;
- env->int_svc_code = (insn|v1) & 0xff;
- env->int_svc_ilc = 4;
- helper_exception(EXCP_SVC);
- } else if ((insn & 0xff00) == 0xbf00) {
- uint32_t insn2, r1, r3, b2, d2;
- insn2 = ldl_code(addr + 2);
- r1 = (insn2 >> 20) & 0xf;
- r3 = (insn2 >> 16) & 0xf;
- b2 = (insn2 >> 12) & 0xf;
- d2 = insn2 & 0xfff;
- cc = helper_icm(r1, get_address(0, b2, d2), r3);
- } else {
-abort:
- cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
- insn);
- }
- return cc;
-}
-
-/* absolute value 32-bit */
-uint32_t HELPER(abs_i32)(int32_t val)
-{
- if (val < 0) {
- return -val;
- } else {
- return val;
- }
-}
-
-/* negative absolute value 32-bit */
-int32_t HELPER(nabs_i32)(int32_t val)
-{
- if (val < 0) {
- return val;
- } else {
- return -val;
- }
-}
-
-/* absolute value 64-bit */
-uint64_t HELPER(abs_i64)(int64_t val)
-{
- HELPER_LOG("%s: val 0x%" PRIx64 "\n", __FUNCTION__, val);
-
- if (val < 0) {
- return -val;
- } else {
- return val;
- }
-}
-
-/* negative absolute value 64-bit */
-int64_t HELPER(nabs_i64)(int64_t val)
-{
- if (val < 0) {
- return val;
- } else {
- return -val;
- }
-}
-
-/* add with carry 32-bit unsigned */
-uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2)
-{
- uint32_t res;
-
- res = v1 + v2;
- if (cc & 2) {
- res++;
- }
-
- return res;
-}
-
-/* store character under mask high operates on the upper half of r1 */
-void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
-{
- int pos = 56; /* top of the upper half of r1 */
-
- while (mask) {
- if (mask & 8) {
- stb(address, (env->regs[r1] >> pos) & 0xff);
- address++;
- }
- mask = (mask << 1) & 0xf;
- pos -= 8;
- }
-}
-
-/* insert character under mask high; same as icm, but operates on the
- upper half of r1 */
-uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
-{
- int pos = 56; /* top of the upper half of r1 */
- uint64_t rmask = 0xff00000000000000ULL;
- uint8_t val = 0;
- int ccd = 0;
- uint32_t cc = 0;
-
- while (mask) {
- if (mask & 8) {
- env->regs[r1] &= ~rmask;
- val = ldub(address);
- if ((val & 0x80) && !ccd) {
- cc = 1;
- }
- ccd = 1;
- if (val && cc == 0) {
- cc = 2;
- }
- env->regs[r1] |= (uint64_t)val << pos;
- address++;
- }
- mask = (mask << 1) & 0xf;
- pos -= 8;
- rmask >>= 8;
- }
-
- return cc;
-}
-
-/* insert psw mask and condition code into r1 */
-void HELPER(ipm)(uint32_t cc, uint32_t r1)
-{
- uint64_t r = env->regs[r1];
-
- r &= 0xffffffff00ffffffULL;
- r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf );
- env->regs[r1] = r;
- HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__,
- cc, env->psw.mask, r);
-}
-
-/* load access registers r1 to r3 from memory at a2 */
-void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- int i;
-
- for (i = r1;; i = (i + 1) % 16) {
- env->aregs[i] = ldl(a2);
- a2 += 4;
-
- if (i == r3) {
- break;
- }
- }
-}
-
-/* store access registers r1 to r3 in memory at a2 */
-void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- int i;
-
- for (i = r1;; i = (i + 1) % 16) {
- stl(a2, env->aregs[i]);
- a2 += 4;
-
- if (i == r3) {
- break;
- }
- }
-}
-
-/* move long */
-uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
-{
- uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
- uint64_t dest = get_address_31fix(r1);
- uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
- uint64_t src = get_address_31fix(r2);
- uint8_t pad = src >> 24;
- uint8_t v;
- uint32_t cc;
-
- if (destlen == srclen) {
- cc = 0;
- } else if (destlen < srclen) {
- cc = 1;
- } else {
- cc = 2;
- }
-
- if (srclen > destlen) {
- srclen = destlen;
- }
-
- for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
- v = ldub(src);
- stb(dest, v);
- }
-
- for (; destlen; dest++, destlen--) {
- stb(dest, pad);
- }
-
- env->regs[r1 + 1] = destlen;
- /* can't use srclen here, we trunc'ed it */
- env->regs[r2 + 1] -= src - env->regs[r2];
- env->regs[r1] = dest;
- env->regs[r2] = src;
-
- return cc;
-}
-
-/* move long extended another memcopy insn with more bells and whistles */
-uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- uint64_t destlen = env->regs[r1 + 1];
- uint64_t dest = env->regs[r1];
- uint64_t srclen = env->regs[r3 + 1];
- uint64_t src = env->regs[r3];
- uint8_t pad = a2 & 0xff;
- uint8_t v;
- uint32_t cc;
-
- if (!(env->psw.mask & PSW_MASK_64)) {
- destlen = (uint32_t)destlen;
- srclen = (uint32_t)srclen;
- dest &= 0x7fffffff;
- src &= 0x7fffffff;
- }
-
- if (destlen == srclen) {
- cc = 0;
- } else if (destlen < srclen) {
- cc = 1;
- } else {
- cc = 2;
- }
-
- if (srclen > destlen) {
- srclen = destlen;
- }
-
- for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
- v = ldub(src);
- stb(dest, v);
- }
-
- for (; destlen; dest++, destlen--) {
- stb(dest, pad);
- }
-
- env->regs[r1 + 1] = destlen;
- /* can't use srclen here, we trunc'ed it */
- /* FIXME: 31-bit mode! */
- env->regs[r3 + 1] -= src - env->regs[r3];
- env->regs[r1] = dest;
- env->regs[r3] = src;
-
- return cc;
-}
-
-/* compare logical long extended memcompare insn with padding */
-uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- uint64_t destlen = env->regs[r1 + 1];
- uint64_t dest = get_address_31fix(r1);
- uint64_t srclen = env->regs[r3 + 1];
- uint64_t src = get_address_31fix(r3);
- uint8_t pad = a2 & 0xff;
- uint8_t v1 = 0,v2 = 0;
- uint32_t cc = 0;
-
- if (!(destlen || srclen)) {
- return cc;
- }
-
- if (srclen > destlen) {
- srclen = destlen;
- }
-
- for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
- v1 = srclen ? ldub(src) : pad;
- v2 = destlen ? ldub(dest) : pad;
- if (v1 != v2) {
- cc = (v1 < v2) ? 1 : 2;
- break;
- }
- }
-
- env->regs[r1 + 1] = destlen;
- /* can't use srclen here, we trunc'ed it */
- env->regs[r3 + 1] -= src - env->regs[r3];
- env->regs[r1] = dest;
- env->regs[r3] = src;
-
- return cc;
-}
-
-/* subtract unsigned v2 from v1 with borrow */
-uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2)
-{
- uint32_t v1 = env->regs[r1];
- uint32_t res = v1 + (~v2) + (cc >> 1);
-
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res;
- if (cc & 2) {
- /* borrow */
- return v1 ? 1 : 0;
- } else {
- return v1 ? 3 : 2;
- }
-}
-
-/* subtract unsigned v2 from v1 with borrow */
-uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2)
-{
- uint64_t res = v1 + (~v2) + (cc >> 1);
-
- env->regs[r1] = res;
- if (cc & 2) {
- /* borrow */
- return v1 ? 1 : 0;
- } else {
- return v1 ? 3 : 2;
- }
-}
-
-static inline int float_comp_to_cc(int float_compare)
-{
- switch (float_compare) {
- case float_relation_equal:
- return 0;
- case float_relation_less:
- return 1;
- case float_relation_greater:
- return 2;
- case float_relation_unordered:
- return 3;
- default:
- cpu_abort(env, "unknown return value for float compare\n");
- }
-}
-
-/* condition codes for binary FP ops */
-static uint32_t set_cc_f32(float32 v1, float32 v2)
-{
- return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status));
-}
-
-static uint32_t set_cc_f64(float64 v1, float64 v2)
-{
- return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status));
-}
-
-/* condition codes for unary FP ops */
-static uint32_t set_cc_nz_f32(float32 v)
-{
- if (float32_is_any_nan(v)) {
- return 3;
- } else if (float32_is_zero(v)) {
- return 0;
- } else if (float32_is_neg(v)) {
- return 1;
- } else {
- return 2;
- }
-}
-
-static uint32_t set_cc_nz_f64(float64 v)
-{
- if (float64_is_any_nan(v)) {
- return 3;
- } else if (float64_is_zero(v)) {
- return 0;
- } else if (float64_is_neg(v)) {
- return 1;
- } else {
- return 2;
- }
-}
-
-static uint32_t set_cc_nz_f128(float128 v)
-{
- if (float128_is_any_nan(v)) {
- return 3;
- } else if (float128_is_zero(v)) {
- return 0;
- } else if (float128_is_neg(v)) {
- return 1;
- } else {
- return 2;
- }
-}
-
-/* convert 32-bit int to 64-bit float */
-void HELPER(cdfbr)(uint32_t f1, int32_t v2)
-{
- HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1);
- env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status);
-}
-
-/* convert 32-bit int to 128-bit float */
-void HELPER(cxfbr)(uint32_t f1, int32_t v2)
-{
- CPU_QuadU v1;
- v1.q = int32_to_float128(v2, &env->fpu_status);
- env->fregs[f1].ll = v1.ll.upper;
- env->fregs[f1 + 2].ll = v1.ll.lower;
-}
-
-/* convert 64-bit int to 32-bit float */
-void HELPER(cegbr)(uint32_t f1, int64_t v2)
-{
- HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
- env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status);
-}
-
-/* convert 64-bit int to 64-bit float */
-void HELPER(cdgbr)(uint32_t f1, int64_t v2)
-{
- HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
- env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status);
-}
-
-/* convert 64-bit int to 128-bit float */
-void HELPER(cxgbr)(uint32_t f1, int64_t v2)
-{
- CPU_QuadU x1;
- x1.q = int64_to_float128(v2, &env->fpu_status);
- HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2,
- x1.ll.upper, x1.ll.lower);
- env->fregs[f1].ll = x1.ll.upper;
- env->fregs[f1 + 2].ll = x1.ll.lower;
-}
-
-/* convert 32-bit int to 32-bit float */
-void HELPER(cefbr)(uint32_t f1, int32_t v2)
-{
- env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status);
- HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2,
- env->fregs[f1].l.upper, f1);
-}
-
-/* 32-bit FP addition RR */
-uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
- env->fregs[f2].l.upper,
- &env->fpu_status);
- HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
- env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
-
- return set_cc_nz_f32(env->fregs[f1].l.upper);
-}
-
-/* 64-bit FP addition RR */
-uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d,
- &env->fpu_status);
- HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__,
- env->fregs[f2].d, env->fregs[f1].d, f1);
-
- return set_cc_nz_f64(env->fregs[f1].d);
-}
-
-/* 32-bit FP subtraction RR */
-uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper,
- env->fregs[f2].l.upper,
- &env->fpu_status);
- HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
- env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
-
- return set_cc_nz_f32(env->fregs[f1].l.upper);
-}
-
-/* 64-bit FP subtraction RR */
-uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d,
- &env->fpu_status);
- HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n",
- __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1);
-
- return set_cc_nz_f64(env->fregs[f1].d);
-}
-
-/* 32-bit FP division RR */
-void HELPER(debr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper,
- env->fregs[f2].l.upper,
- &env->fpu_status);
-}
-
-/* 128-bit FP division RR */
-void HELPER(dxbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU v1;
- v1.ll.upper = env->fregs[f1].ll;
- v1.ll.lower = env->fregs[f1 + 2].ll;
- CPU_QuadU v2;
- v2.ll.upper = env->fregs[f2].ll;
- v2.ll.lower = env->fregs[f2 + 2].ll;
- CPU_QuadU res;
- res.q = float128_div(v1.q, v2.q, &env->fpu_status);
- env->fregs[f1].ll = res.ll.upper;
- env->fregs[f1 + 2].ll = res.ll.lower;
-}
-
-/* 64-bit FP multiplication RR */
-void HELPER(mdbr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d,
- &env->fpu_status);
-}
-
-/* 128-bit FP multiplication RR */
-void HELPER(mxbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU v1;
- v1.ll.upper = env->fregs[f1].ll;
- v1.ll.lower = env->fregs[f1 + 2].ll;
- CPU_QuadU v2;
- v2.ll.upper = env->fregs[f2].ll;
- v2.ll.lower = env->fregs[f2 + 2].ll;
- CPU_QuadU res;
- res.q = float128_mul(v1.q, v2.q, &env->fpu_status);
- env->fregs[f1].ll = res.ll.upper;
- env->fregs[f1 + 2].ll = res.ll.lower;
-}
-
-/* convert 32-bit float to 64-bit float */
-void HELPER(ldebr)(uint32_t r1, uint32_t r2)
-{
- env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper,
- &env->fpu_status);
-}
-
-/* convert 128-bit float to 64-bit float */
-void HELPER(ldxbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU x2;
- x2.ll.upper = env->fregs[f2].ll;
- x2.ll.lower = env->fregs[f2 + 2].ll;
- env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status);
- HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d);
-}
-
-/* convert 64-bit float to 128-bit float */
-void HELPER(lxdbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU res;
- res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status);
- env->fregs[f1].ll = res.ll.upper;
- env->fregs[f1 + 2].ll = res.ll.lower;
-}
-
-/* convert 64-bit float to 32-bit float */
-void HELPER(ledbr)(uint32_t f1, uint32_t f2)
-{
- float64 d2 = env->fregs[f2].d;
- env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status);
-}
-
-/* convert 128-bit float to 32-bit float */
-void HELPER(lexbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU x2;
- x2.ll.upper = env->fregs[f2].ll;
- x2.ll.lower = env->fregs[f2 + 2].ll;
- env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status);
- HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper);
-}
-
-/* absolute value of 32-bit float */
-uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2)
-{
- float32 v1;
- float32 v2 = env->fregs[f2].d;
- v1 = float32_abs(v2);
- env->fregs[f1].d = v1;
- return set_cc_nz_f32(v1);
-}
-
-/* absolute value of 64-bit float */
-uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2)
-{
- float64 v1;
- float64 v2 = env->fregs[f2].d;
- v1 = float64_abs(v2);
- env->fregs[f1].d = v1;
- return set_cc_nz_f64(v1);
-}
-
-/* absolute value of 128-bit float */
-uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU v1;
- CPU_QuadU v2;
- v2.ll.upper = env->fregs[f2].ll;
- v2.ll.lower = env->fregs[f2 + 2].ll;
- v1.q = float128_abs(v2.q);
- env->fregs[f1].ll = v1.ll.upper;
- env->fregs[f1 + 2].ll = v1.ll.lower;
- return set_cc_nz_f128(v1.q);
-}
-
-/* load and test 64-bit float */
-uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].d = env->fregs[f2].d;
- return set_cc_nz_f64(env->fregs[f1].d);
-}
-
-/* load and test 32-bit float */
-uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].l.upper = env->fregs[f2].l.upper;
- return set_cc_nz_f32(env->fregs[f1].l.upper);
-}
-
-/* load and test 128-bit float */
-uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU x;
- x.ll.upper = env->fregs[f2].ll;
- x.ll.lower = env->fregs[f2 + 2].ll;
- env->fregs[f1].ll = x.ll.upper;
- env->fregs[f1 + 2].ll = x.ll.lower;
- return set_cc_nz_f128(x.q);
-}
-
-/* load complement of 32-bit float */
-uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper);
-
- return set_cc_nz_f32(env->fregs[f1].l.upper);
-}
-
-/* load complement of 64-bit float */
-uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].d = float64_chs(env->fregs[f2].d);
-
- return set_cc_nz_f64(env->fregs[f1].d);
-}
-
-/* load complement of 128-bit float */
-uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU x1, x2;
- x2.ll.upper = env->fregs[f2].ll;
- x2.ll.lower = env->fregs[f2 + 2].ll;
- x1.q = float128_chs(x2.q);
- env->fregs[f1].ll = x1.ll.upper;
- env->fregs[f1 + 2].ll = x1.ll.lower;
- return set_cc_nz_f128(x1.q);
-}
-
-/* 32-bit FP addition RM */
-void HELPER(aeb)(uint32_t f1, uint32_t val)
-{
- float32 v1 = env->fregs[f1].l.upper;
- CPU_FloatU v2;
- v2.l = val;
- HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__,
- v1, f1, v2.f);
- env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status);
-}
-
-/* 32-bit FP division RM */
-void HELPER(deb)(uint32_t f1, uint32_t val)
-{
- float32 v1 = env->fregs[f1].l.upper;
- CPU_FloatU v2;
- v2.l = val;
- HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__,
- v1, f1, v2.f);
- env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status);
-}
-
-/* 32-bit FP multiplication RM */
-void HELPER(meeb)(uint32_t f1, uint32_t val)
-{
- float32 v1 = env->fregs[f1].l.upper;
- CPU_FloatU v2;
- v2.l = val;
- HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__,
- v1, f1, v2.f);
- env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status);
-}
-
-/* 32-bit FP compare RR */
-uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2)
-{
- float32 v1 = env->fregs[f1].l.upper;
- float32 v2 = env->fregs[f2].l.upper;
- HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__,
- v1, f1, v2);
- return set_cc_f32(v1, v2);
-}
-
-/* 64-bit FP compare RR */
-uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2)
-{
- float64 v1 = env->fregs[f1].d;
- float64 v2 = env->fregs[f2].d;
- HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__,
- v1, f1, v2);
- return set_cc_f64(v1, v2);
-}
-
-/* 128-bit FP compare RR */
-uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU v1;
- v1.ll.upper = env->fregs[f1].ll;
- v1.ll.lower = env->fregs[f1 + 2].ll;
- CPU_QuadU v2;
- v2.ll.upper = env->fregs[f2].ll;
- v2.ll.lower = env->fregs[f2 + 2].ll;
-
- return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q,
- &env->fpu_status));
-}
-
-/* 64-bit FP compare RM */
-uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2)
-{
- float64 v1 = env->fregs[f1].d;
- CPU_DoubleU v2;
- v2.ll = ldq(a2);
- HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1,
- f1, v2.d);
- return set_cc_f64(v1, v2.d);
-}
-
-/* 64-bit FP addition RM */
-uint32_t HELPER(adb)(uint32_t f1, uint64_t a2)
-{
- float64 v1 = env->fregs[f1].d;
- CPU_DoubleU v2;
- v2.ll = ldq(a2);
- HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__,
- v1, f1, v2.d);
- env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status);
- return set_cc_nz_f64(v1);
-}
-
-/* 32-bit FP subtraction RM */
-void HELPER(seb)(uint32_t f1, uint32_t val)
-{
- float32 v1 = env->fregs[f1].l.upper;
- CPU_FloatU v2;
- v2.l = val;
- env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status);
-}
-
-/* 64-bit FP subtraction RM */
-uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2)
-{
- float64 v1 = env->fregs[f1].d;
- CPU_DoubleU v2;
- v2.ll = ldq(a2);
- env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status);
- return set_cc_nz_f64(v1);
-}
-
-/* 64-bit FP multiplication RM */
-void HELPER(mdb)(uint32_t f1, uint64_t a2)
-{
- float64 v1 = env->fregs[f1].d;
- CPU_DoubleU v2;
- v2.ll = ldq(a2);
- HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__,
- v1, f1, v2.d);
- env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status);
-}
-
-/* 64-bit FP division RM */
-void HELPER(ddb)(uint32_t f1, uint64_t a2)
-{
- float64 v1 = env->fregs[f1].d;
- CPU_DoubleU v2;
- v2.ll = ldq(a2);
- HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__,
- v1, f1, v2.d);
- env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status);
-}
-
-static void set_round_mode(int m3)
-{
- switch (m3) {
- case 0:
- /* current mode */
- break;
- case 1:
- /* biased round no nearest */
- case 4:
- /* round to nearest */
- set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
- break;
- case 5:
- /* round to zero */
- set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
- break;
- case 6:
- /* round to +inf */
- set_float_rounding_mode(float_round_up, &env->fpu_status);
- break;
- case 7:
- /* round to -inf */
- set_float_rounding_mode(float_round_down, &env->fpu_status);
- break;
- }
-}
-
-/* convert 32-bit float to 64-bit int */
-uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3)
-{
- float32 v2 = env->fregs[f2].l.upper;
- set_round_mode(m3);
- env->regs[r1] = float32_to_int64(v2, &env->fpu_status);
- return set_cc_nz_f32(v2);
-}
-
-/* convert 64-bit float to 64-bit int */
-uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
-{
- float64 v2 = env->fregs[f2].d;
- set_round_mode(m3);
- env->regs[r1] = float64_to_int64(v2, &env->fpu_status);
- return set_cc_nz_f64(v2);
-}
-
-/* convert 128-bit float to 64-bit int */
-uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
-{
- CPU_QuadU v2;
- v2.ll.upper = env->fregs[f2].ll;
- v2.ll.lower = env->fregs[f2 + 2].ll;
- set_round_mode(m3);
- env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status);
- if (float128_is_any_nan(v2.q)) {
- return 3;
- } else if (float128_is_zero(v2.q)) {
- return 0;
- } else if (float128_is_neg(v2.q)) {
- return 1;
- } else {
- return 2;
- }
-}
-
-/* convert 32-bit float to 32-bit int */
-uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3)
-{
- float32 v2 = env->fregs[f2].l.upper;
- set_round_mode(m3);
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
- float32_to_int32(v2, &env->fpu_status);
- return set_cc_nz_f32(v2);
-}
-
-/* convert 64-bit float to 32-bit int */
-uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
-{
- float64 v2 = env->fregs[f2].d;
- set_round_mode(m3);
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
- float64_to_int32(v2, &env->fpu_status);
- return set_cc_nz_f64(v2);
-}
-
-/* convert 128-bit float to 32-bit int */
-uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
-{
- CPU_QuadU v2;
- v2.ll.upper = env->fregs[f2].ll;
- v2.ll.lower = env->fregs[f2 + 2].ll;
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
- float128_to_int32(v2.q, &env->fpu_status);
- return set_cc_nz_f128(v2.q);
-}
-
-/* load 32-bit FP zero */
-void HELPER(lzer)(uint32_t f1)
-{
- env->fregs[f1].l.upper = float32_zero;
-}
-
-/* load 64-bit FP zero */
-void HELPER(lzdr)(uint32_t f1)
-{
- env->fregs[f1].d = float64_zero;
-}
-
-/* load 128-bit FP zero */
-void HELPER(lzxr)(uint32_t f1)
-{
- CPU_QuadU x;
- x.q = float64_to_float128(float64_zero, &env->fpu_status);
- env->fregs[f1].ll = x.ll.upper;
- env->fregs[f1 + 1].ll = x.ll.lower;
-}
-
-/* 128-bit FP subtraction RR */
-uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU v1;
- v1.ll.upper = env->fregs[f1].ll;
- v1.ll.lower = env->fregs[f1 + 2].ll;
- CPU_QuadU v2;
- v2.ll.upper = env->fregs[f2].ll;
- v2.ll.lower = env->fregs[f2 + 2].ll;
- CPU_QuadU res;
- res.q = float128_sub(v1.q, v2.q, &env->fpu_status);
- env->fregs[f1].ll = res.ll.upper;
- env->fregs[f1 + 2].ll = res.ll.lower;
- return set_cc_nz_f128(res.q);
-}
-
-/* 128-bit FP addition RR */
-uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2)
-{
- CPU_QuadU v1;
- v1.ll.upper = env->fregs[f1].ll;
- v1.ll.lower = env->fregs[f1 + 2].ll;
- CPU_QuadU v2;
- v2.ll.upper = env->fregs[f2].ll;
- v2.ll.lower = env->fregs[f2 + 2].ll;
- CPU_QuadU res;
- res.q = float128_add(v1.q, v2.q, &env->fpu_status);
- env->fregs[f1].ll = res.ll.upper;
- env->fregs[f1 + 2].ll = res.ll.lower;
- return set_cc_nz_f128(res.q);
-}
-
-/* 32-bit FP multiplication RR */
-void HELPER(meebr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper,
- env->fregs[f2].l.upper,
- &env->fpu_status);
-}
-
-/* 64-bit FP division RR */
-void HELPER(ddbr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d,
- &env->fpu_status);
-}
-
-/* 64-bit FP multiply and add RM */
-void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3)
-{
- HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3);
- CPU_DoubleU v2;
- v2.ll = ldq(a2);
- env->fregs[f1].d = float64_add(env->fregs[f1].d,
- float64_mul(v2.d, env->fregs[f3].d,
- &env->fpu_status),
- &env->fpu_status);
-}
-
-/* 64-bit FP multiply and add RR */
-void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2)
-{
- HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
- env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d,
- env->fregs[f3].d,
- &env->fpu_status),
- env->fregs[f1].d, &env->fpu_status);
-}
-
-/* 64-bit FP multiply and subtract RR */
-void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2)
-{
- HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
- env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d,
- env->fregs[f3].d,
- &env->fpu_status),
- env->fregs[f1].d, &env->fpu_status);
-}
-
-/* 32-bit FP multiply and add RR */
-void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2)
-{
- env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
- float32_mul(env->fregs[f2].l.upper,
- env->fregs[f3].l.upper,
- &env->fpu_status),
- &env->fpu_status);
-}
-
-/* convert 32-bit float to 64-bit float */
-void HELPER(ldeb)(uint32_t f1, uint64_t a2)
-{
- uint32_t v2;
- v2 = ldl(a2);
- env->fregs[f1].d = float32_to_float64(v2,
- &env->fpu_status);
-}
-
-/* convert 64-bit float to 128-bit float */
-void HELPER(lxdb)(uint32_t f1, uint64_t a2)
-{
- CPU_DoubleU v2;
- v2.ll = ldq(a2);
- CPU_QuadU v1;
- v1.q = float64_to_float128(v2.d, &env->fpu_status);
- env->fregs[f1].ll = v1.ll.upper;
- env->fregs[f1 + 2].ll = v1.ll.lower;
-}
-
-/* test data class 32-bit */
-uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2)
-{
- float32 v1 = env->fregs[f1].l.upper;
- int neg = float32_is_neg(v1);
- uint32_t cc = 0;
-
- HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, (long)v1, m2, neg);
- if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
- (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
- (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
- (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
- cc = 1;
- } else if (m2 & (1 << (9-neg))) {
- /* assume normalized number */
- cc = 1;
- }
-
- /* FIXME: denormalized? */
- return cc;
-}
-
-/* test data class 64-bit */
-uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2)
-{
- float64 v1 = env->fregs[f1].d;
- int neg = float64_is_neg(v1);
- uint32_t cc = 0;
-
- HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg);
- if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
- (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
- (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
- (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
- cc = 1;
- } else if (m2 & (1 << (9-neg))) {
- /* assume normalized number */
- cc = 1;
- }
- /* FIXME: denormalized? */
- return cc;
-}
-
-/* test data class 128-bit */
-uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2)
-{
- CPU_QuadU v1;
- uint32_t cc = 0;
- v1.ll.upper = env->fregs[f1].ll;
- v1.ll.lower = env->fregs[f1 + 2].ll;
-
- int neg = float128_is_neg(v1.q);
- if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) ||
- (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) ||
- (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) ||
- (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) {
- cc = 1;
- } else if (m2 & (1 << (9-neg))) {
- /* assume normalized number */
- cc = 1;
- }
- /* FIXME: denormalized? */
- return cc;
-}
-
-/* find leftmost one */
-uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2)
-{
- uint64_t res = 0;
- uint64_t ov2 = v2;
-
- while (!(v2 & 0x8000000000000000ULL) && v2) {
- v2 <<= 1;
- res++;
- }
-
- if (!v2) {
- env->regs[r1] = 64;
- env->regs[r1 + 1] = 0;
- return 0;
- } else {
- env->regs[r1] = res;
- env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res);
- return 2;
- }
-}
-
-/* square root 64-bit RR */
-void HELPER(sqdbr)(uint32_t f1, uint32_t f2)
-{
- env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status);
-}
-
-/* checksum */
-void HELPER(cksm)(uint32_t r1, uint32_t r2)
-{
- uint64_t src = get_address_31fix(r2);
- uint64_t src_len = env->regs[(r2 + 1) & 15];
- uint64_t cksm = (uint32_t)env->regs[r1];
-
- while (src_len >= 4) {
- cksm += ldl(src);
-
- /* move to next word */
- src_len -= 4;
- src += 4;
- }
-
- switch (src_len) {
- case 0:
- break;
- case 1:
- cksm += ldub(src) << 24;
- break;
- case 2:
- cksm += lduw(src) << 16;
- break;
- case 3:
- cksm += lduw(src) << 16;
- cksm += ldub(src + 2) << 8;
- break;
- }
-
- /* indicate we've processed everything */
- env->regs[r2] = src + src_len;
- env->regs[(r2 + 1) & 15] = 0;
-
- /* store result */
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
- ((uint32_t)cksm + (cksm >> 32));
-}
-
-static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src,
- int32_t dst)
-{
- if (src == dst) {
- return 0;
- } else if (src < dst) {
- return 1;
- } else {
- return 2;
- }
-}
-
-static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst)
-{
- return cc_calc_ltgt_32(env, dst, 0);
-}
-
-static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src,
- int64_t dst)
-{
- if (src == dst) {
- return 0;
- } else if (src < dst) {
- return 1;
- } else {
- return 2;
- }
-}
-
-static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst)
-{
- return cc_calc_ltgt_64(env, dst, 0);
-}
-
-static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src,
- uint32_t dst)
-{
- if (src == dst) {
- return 0;
- } else if (src < dst) {
- return 1;
- } else {
- return 2;
- }
-}
-
-static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
- uint64_t dst)
-{
- if (src == dst) {
- return 0;
- } else if (src < dst) {
- return 1;
- } else {
- return 2;
- }
-}
-
-static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask)
-{
- HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask);
- uint16_t r = val & mask;
- if (r == 0 || mask == 0) {
- return 0;
- } else if (r == mask) {
- return 3;
- } else {
- return 1;
- }
-}
-
-/* set condition code for test under mask */
-static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint32_t mask)
-{
- uint16_t r = val & mask;
- HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r);
- if (r == 0 || mask == 0) {
- return 0;
- } else if (r == mask) {
- return 3;
- } else {
- while (!(mask & 0x8000)) {
- mask <<= 1;
- val <<= 1;
- }
- if (val & 0x8000) {
- return 2;
- } else {
- return 1;
- }
- }
-}
-
-static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst)
-{
- return !!dst;
-}
-
-static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, int64_t a2,
- int64_t ar)
-{
- if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
- return 3; /* overflow */
- } else {
- if (ar < 0) {
- return 1;
- } else if (ar > 0) {
- return 2;
- } else {
- return 0;
- }
- }
-}
-
-static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, uint64_t a2,
- uint64_t ar)
-{
- if (ar == 0) {
- if (a1) {
- return 2;
- } else {
- return 0;
- }
- } else {
- if (ar < a1 || ar < a2) {
- return 3;
- } else {
- return 1;
- }
- }
-}
-
-static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, int64_t a2,
- int64_t ar)
-{
- if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
- return 3; /* overflow */
- } else {
- if (ar < 0) {
- return 1;
- } else if (ar > 0) {
- return 2;
- } else {
- return 0;
- }
- }
-}
-
-static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, uint64_t a2,
- uint64_t ar)
-{
- if (ar == 0) {
- return 2;
- } else {
- if (a2 > a1) {
- return 1;
- } else {
- return 3;
- }
- }
-}
-
-static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
-{
- if ((uint64_t)dst == 0x8000000000000000ULL) {
- return 3;
- } else if (dst) {
- return 1;
- } else {
- return 0;
- }
-}
-
-static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst)
-{
- return !!dst;
-}
-
-static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst)
-{
- if ((uint64_t)dst == 0x8000000000000000ULL) {
- return 3;
- } else if (dst < 0) {
- return 1;
- } else if (dst > 0) {
- return 2;
- } else {
- return 0;
- }
-}
-
-
-static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, int32_t a2,
- int32_t ar)
-{
- if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
- return 3; /* overflow */
- } else {
- if (ar < 0) {
- return 1;
- } else if (ar > 0) {
- return 2;
- } else {
- return 0;
- }
- }
-}
-
-static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, uint32_t a2,
- uint32_t ar)
-{
- if (ar == 0) {
- if (a1) {
- return 2;
- } else {
- return 0;
- }
- } else {
- if (ar < a1 || ar < a2) {
- return 3;
- } else {
- return 1;
- }
- }
-}
-
-static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, int32_t a2,
- int32_t ar)
-{
- if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
- return 3; /* overflow */
- } else {
- if (ar < 0) {
- return 1;
- } else if (ar > 0) {
- return 2;
- } else {
- return 0;
- }
- }
-}
-
-static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, uint32_t a2,
- uint32_t ar)
-{
- if (ar == 0) {
- return 2;
- } else {
- if (a2 > a1) {
- return 1;
- } else {
- return 3;
- }
- }
-}
-
-static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
-{
- if ((uint32_t)dst == 0x80000000UL) {
- return 3;
- } else if (dst) {
- return 1;
- } else {
- return 0;
- }
-}
-
-static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst)
-{
- return !!dst;
-}
-
-static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst)
-{
- if ((uint32_t)dst == 0x80000000UL) {
- return 3;
- } else if (dst < 0) {
- return 1;
- } else if (dst > 0) {
- return 2;
- } else {
- return 0;
- }
-}
-
-/* calculate condition code for insert character under mask insn */
-static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, uint32_t val)
-{
- HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val);
- uint32_t cc;
-
- if (mask == 0xf) {
- if (!val) {
- return 0;
- } else if (val & 0x80000000) {
- return 1;
- } else {
- return 2;
- }
- }
-
- if (!val || !mask) {
- cc = 0;
- } else {
- while (mask != 1) {
- mask >>= 1;
- val >>= 8;
- }
- if (val & 0x80) {
- cc = 1;
- } else {
- cc = 2;
- }
- }
- return cc;
-}
-
-static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, uint64_t shift)
-{
- uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
- uint64_t match, r;
-
- /* check if the sign bit stays the same */
- if (src & (1ULL << 63)) {
- match = mask;
- } else {
- match = 0;
- }
-
- if ((src & mask) != match) {
- /* overflow */
- return 3;
- }
-
- r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
-
- if ((int64_t)r == 0) {
- return 0;
- } else if ((int64_t)r < 0) {
- return 1;
- }
-
- return 2;
-}
-
-
-static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src,
- uint64_t dst, uint64_t vr)
-{
- uint32_t r = 0;
-
- switch (cc_op) {
- case CC_OP_CONST0:
- case CC_OP_CONST1:
- case CC_OP_CONST2:
- case CC_OP_CONST3:
- /* cc_op value _is_ cc */
- r = cc_op;
- break;
- case CC_OP_LTGT0_32:
- r = cc_calc_ltgt0_32(env, dst);
- break;
- case CC_OP_LTGT0_64:
- r = cc_calc_ltgt0_64(env, dst);
- break;
- case CC_OP_LTGT_32:
- r = cc_calc_ltgt_32(env, src, dst);
- break;
- case CC_OP_LTGT_64:
- r = cc_calc_ltgt_64(env, src, dst);
- break;
- case CC_OP_LTUGTU_32:
- r = cc_calc_ltugtu_32(env, src, dst);
- break;
- case CC_OP_LTUGTU_64:
- r = cc_calc_ltugtu_64(env, src, dst);
- break;
- case CC_OP_TM_32:
- r = cc_calc_tm_32(env, src, dst);
- break;
- case CC_OP_TM_64:
- r = cc_calc_tm_64(env, src, dst);
- break;
- case CC_OP_NZ:
- r = cc_calc_nz(env, dst);
- break;
- case CC_OP_ADD_64:
- r = cc_calc_add_64(env, src, dst, vr);
- break;
- case CC_OP_ADDU_64:
- r = cc_calc_addu_64(env, src, dst, vr);
- break;
- case CC_OP_SUB_64:
- r = cc_calc_sub_64(env, src, dst, vr);
- break;
- case CC_OP_SUBU_64:
- r = cc_calc_subu_64(env, src, dst, vr);
- break;
- case CC_OP_ABS_64:
- r = cc_calc_abs_64(env, dst);
- break;
- case CC_OP_NABS_64:
- r = cc_calc_nabs_64(env, dst);
- break;
- case CC_OP_COMP_64:
- r = cc_calc_comp_64(env, dst);
- break;
-
- case CC_OP_ADD_32:
- r = cc_calc_add_32(env, src, dst, vr);
- break;
- case CC_OP_ADDU_32:
- r = cc_calc_addu_32(env, src, dst, vr);
- break;
- case CC_OP_SUB_32:
- r = cc_calc_sub_32(env, src, dst, vr);
- break;
- case CC_OP_SUBU_32:
- r = cc_calc_subu_32(env, src, dst, vr);
- break;
- case CC_OP_ABS_32:
- r = cc_calc_abs_64(env, dst);
- break;
- case CC_OP_NABS_32:
- r = cc_calc_nabs_64(env, dst);
- break;
- case CC_OP_COMP_32:
- r = cc_calc_comp_32(env, dst);
- break;
-
- case CC_OP_ICM:
- r = cc_calc_icm_32(env, src, dst);
- break;
- case CC_OP_SLAG:
- r = cc_calc_slag(env, src, dst);
- break;
-
- case CC_OP_LTGT_F32:
- r = set_cc_f32(src, dst);
- break;
- case CC_OP_LTGT_F64:
- r = set_cc_f64(src, dst);
- break;
- case CC_OP_NZ_F32:
- r = set_cc_nz_f32(dst);
- break;
- case CC_OP_NZ_F64:
- r = set_cc_nz_f64(dst);
- break;
-
- default:
- cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
- }
-
- HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __FUNCTION__,
- cc_name(cc_op), src, dst, vr, r);
- return r;
-}
-
-uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
- uint64_t vr)
-{
- return do_calc_cc(env, cc_op, src, dst, vr);
-}
-
-uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst,
- uint64_t vr)
-{
- return do_calc_cc(env, cc_op, src, dst, vr);
-}
-
-uint64_t HELPER(cvd)(int32_t bin)
-{
- /* positive 0 */
- uint64_t dec = 0x0c;
- int shift = 4;
-
- if (bin < 0) {
- bin = -bin;
- dec = 0x0d;
- }
-
- for (shift = 4; (shift < 64) && bin; shift += 4) {
- int current_number = bin % 10;
-
- dec |= (current_number) << shift;
- bin /= 10;
- }
-
- return dec;
-}
-
-void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
-{
- int len_dest = len >> 4;
- int len_src = len & 0xf;
- uint8_t b;
- int second_nibble = 0;
-
- dest += len_dest;
- src += len_src;
-
- /* last byte is special, it only flips the nibbles */
- b = ldub(src);
- stb(dest, (b << 4) | (b >> 4));
- src--;
- len_src--;
-
- /* now pad every nibble with 0xf0 */
-
- while (len_dest > 0) {
- uint8_t cur_byte = 0;
-
- if (len_src > 0) {
- cur_byte = ldub(src);
- }
-
- len_dest--;
- dest--;
-
- /* only advance one nibble at a time */
- if (second_nibble) {
- cur_byte >>= 4;
- len_src--;
- src--;
- }
- second_nibble = !second_nibble;
-
- /* digit */
- cur_byte = (cur_byte & 0xf);
- /* zone bits */
- cur_byte |= 0xf0;
-
- stb(dest, cur_byte);
- }
-}
-
-void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
-{
- int i;
-
- for (i = 0; i <= len; i++) {
- uint8_t byte = ldub(array + i);
- uint8_t new_byte = ldub(trans + byte);
- stb(array + i, new_byte);
- }
-}
-
-#ifndef CONFIG_USER_ONLY
-
-void HELPER(load_psw)(uint64_t mask, uint64_t addr)
-{
- load_psw(env, mask, addr);
- cpu_loop_exit(env);
-}
-
-static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
-{
- qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
-
- if (kvm_enabled()) {
-#ifdef CONFIG_KVM
- kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
-#endif
- } else {
- env->int_pgm_code = code;
- env->int_pgm_ilc = ilc;
- env->exception_index = EXCP_PGM;
- cpu_loop_exit(env);
- }
-}
-
-/*
- * ret < 0 indicates program check, ret = 0,1,2,3 -> cc
- */
-int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
-{
- int r = 0;
- int shift = 0;
-
-#ifdef DEBUG_HELPER
- printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
-#endif
-
- /* basic checks */
- if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) {
- return -PGM_ADDRESSING;
- }
- if (sccb & ~0x7ffffff8ul) {
- return -PGM_SPECIFICATION;
- }
-
- switch(code) {
- case SCLP_CMDW_READ_SCP_INFO:
- case SCLP_CMDW_READ_SCP_INFO_FORCED:
- while ((ram_size >> (20 + shift)) > 65535) {
- shift++;
- }
- stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
- stb_phys(sccb + SCP_INCREMENT, 1 << shift);
- stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
-
- s390_sclp_extint(sccb & ~3);
- break;
- default:
-#ifdef DEBUG_HELPER
- printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
-#endif
- r = 3;
- break;
- }
-
- return r;
-}
-
-/* SCLP service call */
-uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
-{
- int r;
-
- r = sclp_service_call(env, r1, r2);
- if (r < 0) {
- program_interrupt(env, -r, 4);
- return 0;
- }
- return r;
-}
-
-/* DIAG */
-uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
-{
- uint64_t r;
-
- switch (num) {
- case 0x500:
- /* KVM hypercall */
- r = s390_virtio_hypercall(env, mem, code);
- break;
- case 0x44:
- /* yield */
- r = 0;
- break;
- case 0x308:
- /* ipl */
- r = 0;
- break;
- default:
- r = -1;
- break;
- }
-
- if (r) {
- program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
- }
-
- return r;
-}
-
-/* Store CPU ID */
-void HELPER(stidp)(uint64_t a1)
-{
- stq(a1, env->cpu_num);
-}
-
-/* Set Prefix */
-void HELPER(spx)(uint64_t a1)
-{
- uint32_t prefix;
-
- prefix = ldl(a1);
- env->psa = prefix & 0xfffff000;
- qemu_log("prefix: %#x\n", prefix);
- tlb_flush_page(env, 0);
- tlb_flush_page(env, TARGET_PAGE_SIZE);
-}
-
-/* Set Clock */
-uint32_t HELPER(sck)(uint64_t a1)
-{
- /* XXX not implemented - is it necessary? */
-
- return 0;
-}
-
-static inline uint64_t clock_value(CPUS390XState *env)
-{
- uint64_t time;
-
- time = env->tod_offset +
- time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
-
- return time;
-}
-
-/* Store Clock */
-uint32_t HELPER(stck)(uint64_t a1)
-{
- stq(a1, clock_value(env));
-
- return 0;
-}
-
-/* Store Clock Extended */
-uint32_t HELPER(stcke)(uint64_t a1)
-{
- stb(a1, 0);
- /* basically the same value as stck */
- stq(a1 + 1, clock_value(env) | env->cpu_num);
- /* more fine grained than stck */
- stq(a1 + 9, 0);
- /* XXX programmable fields */
- stw(a1 + 17, 0);
-
-
- return 0;
-}
-
-/* Set Clock Comparator */
-void HELPER(sckc)(uint64_t a1)
-{
- uint64_t time = ldq(a1);
-
- if (time == -1ULL) {
- return;
- }
-
- /* difference between now and then */
- time -= clock_value(env);
- /* nanoseconds */
- time = (time * 125) >> 9;
-
- qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
-}
-
-/* Store Clock Comparator */
-void HELPER(stckc)(uint64_t a1)
-{
- /* XXX implement */
- stq(a1, 0);
-}
-
-/* Set CPU Timer */
-void HELPER(spt)(uint64_t a1)
-{
- uint64_t time = ldq(a1);
-
- if (time == -1ULL) {
- return;
- }
-
- /* nanoseconds */
- time = (time * 125) >> 9;
-
- qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
-}
-
-/* Store CPU Timer */
-void HELPER(stpt)(uint64_t a1)
-{
- /* XXX implement */
- stq(a1, 0);
-}
-
-/* Store System Information */
-uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
-{
- int cc = 0;
- int sel1, sel2;
-
- if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
- ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
- /* valid function code, invalid reserved bits */
- program_interrupt(env, PGM_SPECIFICATION, 2);
- }
-
- sel1 = r0 & STSI_R0_SEL1_MASK;
- sel2 = r1 & STSI_R1_SEL2_MASK;
-
- /* XXX: spec exception if sysib is not 4k-aligned */
-
- switch (r0 & STSI_LEVEL_MASK) {
- case STSI_LEVEL_1:
- if ((sel1 == 1) && (sel2 == 1)) {
- /* Basic Machine Configuration */
- struct sysib_111 sysib;
-
- memset(&sysib, 0, sizeof(sysib));
- ebcdic_put(sysib.manuf, "QEMU ", 16);
- /* same as machine type number in STORE CPU ID */
- ebcdic_put(sysib.type, "QEMU", 4);
- /* same as model number in STORE CPU ID */
- ebcdic_put(sysib.model, "QEMU ", 16);
- ebcdic_put(sysib.sequence, "QEMU ", 16);
- ebcdic_put(sysib.plant, "QEMU", 4);
- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
- } else if ((sel1 == 2) && (sel2 == 1)) {
- /* Basic Machine CPU */
- struct sysib_121 sysib;
-
- memset(&sysib, 0, sizeof(sysib));
- /* XXX make different for different CPUs? */
- ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
- ebcdic_put(sysib.plant, "QEMU", 4);
- stw_p(&sysib.cpu_addr, env->cpu_num);
- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
- } else if ((sel1 == 2) && (sel2 == 2)) {
- /* Basic Machine CPUs */
- struct sysib_122 sysib;
-
- memset(&sysib, 0, sizeof(sysib));
- stl_p(&sysib.capability, 0x443afc29);
- /* XXX change when SMP comes */
- stw_p(&sysib.total_cpus, 1);
- stw_p(&sysib.active_cpus, 1);
- stw_p(&sysib.standby_cpus, 0);
- stw_p(&sysib.reserved_cpus, 0);
- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
- } else {
- cc = 3;
- }
- break;
- case STSI_LEVEL_2:
- {
- if ((sel1 == 2) && (sel2 == 1)) {
- /* LPAR CPU */
- struct sysib_221 sysib;
-
- memset(&sysib, 0, sizeof(sysib));
- /* XXX make different for different CPUs? */
- ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
- ebcdic_put(sysib.plant, "QEMU", 4);
- stw_p(&sysib.cpu_addr, env->cpu_num);
- stw_p(&sysib.cpu_id, 0);
- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
- } else if ((sel1 == 2) && (sel2 == 2)) {
- /* LPAR CPUs */
- struct sysib_222 sysib;
-
- memset(&sysib, 0, sizeof(sysib));
- stw_p(&sysib.lpar_num, 0);
- sysib.lcpuc = 0;
- /* XXX change when SMP comes */
- stw_p(&sysib.total_cpus, 1);
- stw_p(&sysib.conf_cpus, 1);
- stw_p(&sysib.standby_cpus, 0);
- stw_p(&sysib.reserved_cpus, 0);
- ebcdic_put(sysib.name, "QEMU ", 8);
- stl_p(&sysib.caf, 1000);
- stw_p(&sysib.dedicated_cpus, 0);
- stw_p(&sysib.shared_cpus, 0);
- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
- } else {
- cc = 3;
- }
- break;
- }
- case STSI_LEVEL_3:
- {
- if ((sel1 == 2) && (sel2 == 2)) {
- /* VM CPUs */
- struct sysib_322 sysib;
-
- memset(&sysib, 0, sizeof(sysib));
- sysib.count = 1;
- /* XXX change when SMP comes */
- stw_p(&sysib.vm[0].total_cpus, 1);
- stw_p(&sysib.vm[0].conf_cpus, 1);
- stw_p(&sysib.vm[0].standby_cpus, 0);
- stw_p(&sysib.vm[0].reserved_cpus, 0);
- ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
- stl_p(&sysib.vm[0].caf, 1000);
- ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
- } else {
- cc = 3;
- }
- break;
- }
- case STSI_LEVEL_CURRENT:
- env->regs[0] = STSI_LEVEL_3;
- break;
- default:
- cc = 3;
- break;
- }
-
- return cc;
-}
-
-void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- int i;
- uint64_t src = a2;
-
- for (i = r1;; i = (i + 1) % 16) {
- env->cregs[i] = ldq(src);
- HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
- i, src, env->cregs[i]);
- src += sizeof(uint64_t);
-
- if (i == r3) {
- break;
- }
- }
-
- tlb_flush(env, 1);
-}
-
-void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- int i;
- uint64_t src = a2;
-
- for (i = r1;; i = (i + 1) % 16) {
- env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
- src += sizeof(uint32_t);
-
- if (i == r3) {
- break;
- }
- }
-
- tlb_flush(env, 1);
-}
-
-void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- int i;
- uint64_t dest = a2;
-
- for (i = r1;; i = (i + 1) % 16) {
- stq(dest, env->cregs[i]);
- dest += sizeof(uint64_t);
-
- if (i == r3) {
- break;
- }
- }
-}
-
-void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
-{
- int i;
- uint64_t dest = a2;
-
- for (i = r1;; i = (i + 1) % 16) {
- stl(dest, env->cregs[i]);
- dest += sizeof(uint32_t);
-
- if (i == r3) {
- break;
- }
- }
-}
-
-uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
-{
- /* XXX implement */
-
- return 0;
-}
-
-/* insert storage key extended */
-uint64_t HELPER(iske)(uint64_t r2)
-{
- uint64_t addr = get_address(0, 0, r2);
-
- if (addr > ram_size) {
- return 0;
- }
-
- return env->storage_keys[addr / TARGET_PAGE_SIZE];
-}
-
-/* set storage key extended */
-void HELPER(sske)(uint32_t r1, uint64_t r2)
-{
- uint64_t addr = get_address(0, 0, r2);
-
- if (addr > ram_size) {
- return;
- }
-
- env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
-}
-
-/* reset reference bit extended */
-uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
-{
- uint8_t re;
- uint8_t key;
- if (r2 > ram_size) {
- return 0;
- }
-
- key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
- re = key & (SK_R | SK_C);
- env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
-
- /*
- * cc
- *
- * 0 Reference bit zero; change bit zero
- * 1 Reference bit zero; change bit one
- * 2 Reference bit one; change bit zero
- * 3 Reference bit one; change bit one
- */
-
- return re >> 1;
-}
-
-/* compare and swap and purge */
-uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
-{
- uint32_t cc;
- uint32_t o1 = env->regs[r1];
- uint64_t a2 = get_address_31fix(r2) & ~3ULL;
- uint32_t o2 = ldl(a2);
-
- if (o1 == o2) {
- stl(a2, env->regs[(r1 + 1) & 15]);
- if (env->regs[r2] & 0x3) {
- /* flush TLB / ALB */
- tlb_flush(env, 1);
- }
- cc = 0;
- } else {
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
- cc = 1;
- }
-
- return cc;
-}
-
-static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
- uint64_t mode2)
-{
- target_ulong src, dest;
- int flags, cc = 0, i;
-
- if (!l) {
- return 0;
- } else if (l > 256) {
- /* max 256 */
- l = 256;
- cc = 3;
- }
-
- if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
- cpu_loop_exit(env);
- }
- dest |= a1 & ~TARGET_PAGE_MASK;
-
- if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
- cpu_loop_exit(env);
- }
- src |= a2 & ~TARGET_PAGE_MASK;
-
- /* XXX replace w/ memcpy */
- for (i = 0; i < l; i++) {
- /* XXX be more clever */
- if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
- (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
- mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
- break;
- }
- stb_phys(dest + i, ldub_phys(src + i));
- }
-
- return cc;
-}
-
-uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
-{
- HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
- __FUNCTION__, l, a1, a2);
-
- return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
-}
-
-uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
-{
- HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
- __FUNCTION__, l, a1, a2);
-
- return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
-}
-
-uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
-{
- int cc = 0;
-
- HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
- __FUNCTION__, order_code, r1, cpu_addr);
-
- /* Remember: Use "R1 or R1+1, whichever is the odd-numbered register"
- as parameter (input). Status (output) is always R1. */
-
- switch (order_code) {
- case SIGP_SET_ARCH:
- /* switch arch */
- break;
- case SIGP_SENSE:
- /* enumerate CPU status */
- if (cpu_addr) {
- /* XXX implement when SMP comes */
- return 3;
- }
- env->regs[r1] &= 0xffffffff00000000ULL;
- cc = 1;
- break;
-#if !defined (CONFIG_USER_ONLY)
- case SIGP_RESTART:
- qemu_system_reset_request();
- cpu_loop_exit(env);
- break;
- case SIGP_STOP:
- qemu_system_shutdown_request();
- cpu_loop_exit(env);
- break;
-#endif
- default:
- /* unknown sigp */
- fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
- cc = 3;
- }
-
- return cc;
-}
-
-void HELPER(sacf)(uint64_t a1)
-{
- HELPER_LOG("%s: %16" PRIx64 "\n", __FUNCTION__, a1);
-
- switch (a1 & 0xf00) {
- case 0x000:
- env->psw.mask &= ~PSW_MASK_ASC;
- env->psw.mask |= PSW_ASC_PRIMARY;
- break;
- case 0x100:
- env->psw.mask &= ~PSW_MASK_ASC;
- env->psw.mask |= PSW_ASC_SECONDARY;
- break;
- case 0x300:
- env->psw.mask &= ~PSW_MASK_ASC;
- env->psw.mask |= PSW_ASC_HOME;
- break;
- default:
- qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
- program_interrupt(env, PGM_SPECIFICATION, 2);
- break;
- }
-}
-
-/* invalidate pte */
-void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
-{
- uint64_t page = vaddr & TARGET_PAGE_MASK;
- uint64_t pte = 0;
-
- /* XXX broadcast to other CPUs */
-
- /* XXX Linux is nice enough to give us the exact pte address.
- According to spec we'd have to find it out ourselves */
- /* XXX Linux is fine with overwriting the pte, the spec requires
- us to only set the invalid bit */
- stq_phys(pte_addr, pte | _PAGE_INVALID);
-
- /* XXX we exploit the fact that Linux passes the exact virtual
- address here - it's not obliged to! */
- tlb_flush_page(env, page);
-
- /* XXX 31-bit hack */
- if (page & 0x80000000) {
- tlb_flush_page(env, page & ~0x80000000);
- } else {
- tlb_flush_page(env, page | 0x80000000);
- }
-}
-
-/* flush local tlb */
-void HELPER(ptlb)(void)
-{
- tlb_flush(env, 1);
-}
-
-/* store using real address */
-void HELPER(stura)(uint64_t addr, uint32_t v1)
-{
- stw_phys(get_address(0, 0, addr), v1);
-}
-
-/* load real address */
-uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
-{
- uint32_t cc = 0;
- int old_exc = env->exception_index;
- uint64_t asc = env->psw.mask & PSW_MASK_ASC;
- uint64_t ret;
- int flags;
-
- /* XXX incomplete - has more corner cases */
- if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
- program_interrupt(env, PGM_SPECIAL_OP, 2);
- }
-
- env->exception_index = old_exc;
- if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
- cc = 3;
- }
- if (env->exception_index == EXCP_PGM) {
- ret = env->int_pgm_code | 0x80000000;
- } else {
- ret |= addr & ~TARGET_PAGE_MASK;
- }
- env->exception_index = old_exc;
-
- if (!(env->psw.mask & PSW_MASK_64)) {
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (ret & 0xffffffffULL);
- } else {
- env->regs[r1] = ret;
- }
-
- return cc;
-}
-
-#endif
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 1c1baf534..66119cd12 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -276,19 +276,19 @@ static inline void potential_page_fault(DisasContext *s)
static inline uint64_t ld_code2(uint64_t pc)
{
- return (uint64_t)lduw_code(pc);
+ return (uint64_t)cpu_lduw_code(cpu_single_env, pc);
}
static inline uint64_t ld_code4(uint64_t pc)
{
- return (uint64_t)ldl_code(pc);
+ return (uint64_t)cpu_ldl_code(cpu_single_env, pc);
}
static inline uint64_t ld_code6(uint64_t pc)
{
uint64_t opc;
- opc = (uint64_t)lduw_code(pc) << 32;
- opc |= (uint64_t)(uint32_t)ldl_code(pc+2);
+ opc = (uint64_t)cpu_lduw_code(cpu_single_env, pc) << 32;
+ opc |= (uint64_t)(uint32_t)cpu_ldl_code(cpu_single_env, pc + 2);
return opc;
}
@@ -312,7 +312,7 @@ static inline void gen_debug(DisasContext *s)
TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
update_psw_addr(s);
gen_op_calc_cc(s);
- gen_helper_exception(tmp);
+ gen_helper_exception(cpu_env, tmp);
tcg_temp_free_i32(tmp);
s->is_jmp = DISAS_EXCP;
}
@@ -324,7 +324,7 @@ static void gen_illegal_opcode(DisasContext *s, int ilc)
TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC);
update_psw_addr(s);
gen_op_calc_cc(s);
- gen_helper_exception(tmp);
+ gen_helper_exception(cpu_env, tmp);
tcg_temp_free_i32(tmp);
s->is_jmp = DISAS_EXCP;
}
@@ -377,7 +377,7 @@ static void gen_program_exception(DisasContext *s, int ilc, int code)
/* trigger exception */
tmp = tcg_const_i32(EXCP_PGM);
- gen_helper_exception(tmp);
+ gen_helper_exception(cpu_env, tmp);
tcg_temp_free_i32(tmp);
/* end TB here */
@@ -667,16 +667,11 @@ static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2)
s->cc_op = CC_OP_LTGT_F32;
}
-static void set_cc_nz_f32(DisasContext *s, TCGv_i32 v1)
+static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1)
{
gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1);
}
-static inline void set_cc_nz_f64(DisasContext *s, TCGv_i64 v1)
-{
- gen_op_update1_cc_i64(s, CC_OP_NZ_F64, v1);
-}
-
/* CC value is in env->cc_op */
static inline void set_cc_static(DisasContext *s)
{
@@ -727,7 +722,7 @@ static void gen_op_calc_cc(DisasContext *s)
case CC_OP_NZ_F32:
case CC_OP_NZ_F64:
/* 1 argument */
- gen_helper_calc_cc(cc_op, local_cc_op, dummy, cc_dst, dummy);
+ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy);
break;
case CC_OP_ICM:
case CC_OP_LTGT_32:
@@ -740,7 +735,7 @@ static void gen_op_calc_cc(DisasContext *s)
case CC_OP_LTGT_F64:
case CC_OP_SLAG:
/* 2 arguments */
- gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, dummy);
+ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy);
break;
case CC_OP_ADD_64:
case CC_OP_ADDU_64:
@@ -751,11 +746,11 @@ static void gen_op_calc_cc(DisasContext *s)
case CC_OP_SUB_32:
case CC_OP_SUBU_32:
/* 3 arguments */
- gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, cc_vr);
+ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr);
break;
case CC_OP_DYNAMIC:
/* unknown operation - assume 3 arguments and cc_op in env */
- gen_helper_calc_cc(cc_op, cc_op, cc_src, cc_dst, cc_vr);
+ gen_helper_calc_cc(cc_op, cpu_env, cc_op, cc_src, cc_dst, cc_vr);
break;
default:
tcg_abort();
@@ -1268,7 +1263,7 @@ static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2)
/* Fall back to helper */
vl = tcg_const_i32(l);
potential_page_fault(s);
- gen_helper_mvc(vl, s1, s2);
+ gen_helper_mvc(cpu_env, vl, s1, s2);
tcg_temp_free_i32(vl);
return;
}
@@ -1460,7 +1455,7 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2)
potential_page_fault(s);
vl = tcg_const_i32(l);
- gen_helper_clc(cc_op, vl, s1, s2);
+ gen_helper_clc(cc_op, cpu_env, vl, s1, s2);
tcg_temp_free_i32(vl);
set_cc_static(s);
}
@@ -1808,7 +1803,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2)
tmp2 = tcg_temp_new_i64();
tmp32_1 = tcg_const_i32(r1);
tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
- gen_helper_mlg(tmp32_1, tmp2);
+ gen_helper_mlg(cpu_env, tmp32_1, tmp2);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1);
break;
@@ -1816,7 +1811,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2)
tmp2 = tcg_temp_new_i64();
tmp32_1 = tcg_const_i32(r1);
tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
- gen_helper_dlg(tmp32_1, tmp2);
+ gen_helper_dlg(cpu_env, tmp32_1, tmp2);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1);
break;
@@ -1842,7 +1837,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2)
tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
/* XXX possible optimization point */
gen_op_calc_cc(s);
- gen_helper_slbg(cc_op, cc_op, tmp32_1, regs[r1], tmp2);
+ gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, regs[r1], tmp2);
set_cc_static(s);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1);
@@ -1922,7 +1917,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2)
tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
/* XXX possible optimization point */
gen_op_calc_cc(s);
- gen_helper_slb(cc_op, cc_op, tmp32_1, tmp32_2);
+ gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_1, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1);
@@ -2099,7 +2094,7 @@ do_mh:
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_stcmh(tmp32_1, tmp, tmp32_2);
+ gen_helper_stcmh(cpu_env, tmp32_1, tmp, tmp32_2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -2112,7 +2107,7 @@ do_mh:
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_lctlg(tmp32_1, tmp, tmp32_2);
+ gen_helper_lctlg(cpu_env, tmp32_1, tmp, tmp32_2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -2124,7 +2119,7 @@ do_mh:
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_stctg(tmp32_1, tmp, tmp32_2);
+ gen_helper_stctg(cpu_env, tmp32_1, tmp, tmp32_2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -2136,7 +2131,7 @@ do_mh:
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
/* XXX rewrite in tcg */
- gen_helper_csg(cc_op, tmp32_1, tmp, tmp32_2);
+ gen_helper_csg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -2148,7 +2143,7 @@ do_mh:
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
/* XXX rewrite in tcg */
- gen_helper_cdsg(cc_op, tmp32_1, tmp, tmp32_2);
+ gen_helper_cdsg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -2188,7 +2183,7 @@ do_mh:
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
/* XXX split CC calculation out */
- gen_helper_icmh(cc_op, tmp32_1, tmp, tmp32_2);
+ gen_helper_icmh(cc_op, cpu_env, tmp32_1, tmp, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -2211,11 +2206,11 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2,
switch (op) {
case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_ldeb(tmp_r1, addr);
+ gen_helper_ldeb(cpu_env, tmp_r1, addr);
break;
case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_lxdb(tmp_r1, addr);
+ gen_helper_lxdb(cpu_env, tmp_r1, addr);
break;
case 0x9: /* CEB R1,D2(X2,B2) [RXE] */
tmp = tcg_temp_new_i64();
@@ -2230,12 +2225,12 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2,
tmp32 = tcg_temp_new_i32();
tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
tcg_gen_trunc_i64_i32(tmp32, tmp);
- gen_helper_aeb(tmp_r1, tmp32);
+ gen_helper_aeb(cpu_env, tmp_r1, tmp32);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32);
tmp32 = load_freg32(r1);
- set_cc_nz_f32(s, tmp32);
+ gen_set_cc_nz_f32(s, tmp32);
tcg_temp_free_i32(tmp32);
break;
case 0xb: /* SEB R1,D2(X2,B2) [RXE] */
@@ -2243,12 +2238,12 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2,
tmp32 = tcg_temp_new_i32();
tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
tcg_gen_trunc_i64_i32(tmp32, tmp);
- gen_helper_seb(tmp_r1, tmp32);
+ gen_helper_seb(cpu_env, tmp_r1, tmp32);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32);
tmp32 = load_freg32(r1);
- set_cc_nz_f32(s, tmp32);
+ gen_set_cc_nz_f32(s, tmp32);
tcg_temp_free_i32(tmp32);
break;
case 0xd: /* DEB R1,D2(X2,B2) [RXE] */
@@ -2256,23 +2251,23 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2,
tmp32 = tcg_temp_new_i32();
tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
tcg_gen_trunc_i64_i32(tmp32, tmp);
- gen_helper_deb(tmp_r1, tmp32);
+ gen_helper_deb(cpu_env, tmp_r1, tmp32);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32);
break;
case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_tceb(cc_op, tmp_r1, addr);
+ gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr);
set_cc_static(s);
break;
case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_tcdb(cc_op, tmp_r1, addr);
+ gen_helper_tcdb(cc_op, cpu_env, tmp_r1, addr);
set_cc_static(s);
break;
case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_tcxb(cc_op, tmp_r1, addr);
+ gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr);
set_cc_static(s);
break;
case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */
@@ -2280,38 +2275,38 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2,
tmp32 = tcg_temp_new_i32();
tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
tcg_gen_trunc_i64_i32(tmp32, tmp);
- gen_helper_meeb(tmp_r1, tmp32);
+ gen_helper_meeb(cpu_env, tmp_r1, tmp32);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32);
break;
case 0x19: /* CDB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_cdb(cc_op, tmp_r1, addr);
+ gen_helper_cdb(cc_op, cpu_env, tmp_r1, addr);
set_cc_static(s);
break;
case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_adb(cc_op, tmp_r1, addr);
+ gen_helper_adb(cc_op, cpu_env, tmp_r1, addr);
set_cc_static(s);
break;
case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_sdb(cc_op, tmp_r1, addr);
+ gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr);
set_cc_static(s);
break;
case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_mdb(tmp_r1, addr);
+ gen_helper_mdb(cpu_env, tmp_r1, addr);
break;
case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */
potential_page_fault(s);
- gen_helper_ddb(tmp_r1, addr);
+ gen_helper_ddb(cpu_env, tmp_r1, addr);
break;
case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */
/* for RXF insns, r1 is R3 and r1b is R1 */
tmp32 = tcg_const_i32(r1b);
potential_page_fault(s);
- gen_helper_madb(tmp32, addr, tmp_r1);
+ gen_helper_madb(cpu_env, tmp32, addr, tmp_r1);
tcg_temp_free_i32(tmp32);
break;
default:
@@ -2633,14 +2628,14 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
case 0x22: /* IPM R1 [RRE] */
tmp32_1 = tcg_const_i32(r1);
gen_op_calc_cc(s);
- gen_helper_ipm(cc_op, tmp32_1);
+ gen_helper_ipm(cpu_env, cc_op, tmp32_1);
tcg_temp_free_i32(tmp32_1);
break;
case 0x41: /* CKSM R1,R2 [RRE] */
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r2);
potential_page_fault(s);
- gen_helper_cksm(tmp32_1, tmp32_2);
+ gen_helper_cksm(cpu_env, tmp32_1, tmp32_2);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
gen_op_movi_cc(s, 0);
@@ -2669,7 +2664,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
tmp2 = load_reg(r1);
tmp3 = load_reg(r2);
potential_page_fault(s);
- gen_helper_mvpg(tmp, tmp2, tmp3);
+ gen_helper_mvpg(cpu_env, tmp, tmp2, tmp3);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i64(tmp3);
@@ -2681,7 +2676,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
tmp32_2 = tcg_const_i32(r1);
tmp32_3 = tcg_const_i32(r2);
potential_page_fault(s);
- gen_helper_mvst(tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_mvst(cpu_env, tmp32_1, tmp32_2, tmp32_3);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
tcg_temp_free_i32(tmp32_3);
@@ -2692,7 +2687,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
tmp32_2 = tcg_const_i32(r1);
tmp32_3 = tcg_const_i32(r2);
potential_page_fault(s);
- gen_helper_clst(cc_op, tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_clst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -2703,7 +2698,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
tmp32_2 = tcg_const_i32(r1);
tmp32_3 = tcg_const_i32(r2);
potential_page_fault(s);
- gen_helper_srst(cc_op, tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_srst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -2717,7 +2712,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_stidp(tmp);
+ gen_helper_stidp(cpu_env, tmp);
tcg_temp_free_i64(tmp);
break;
case 0x04: /* SCK D2(B2) [S] */
@@ -2735,7 +2730,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_stck(cc_op, tmp);
+ gen_helper_stck(cc_op, cpu_env, tmp);
set_cc_static(s);
tcg_temp_free_i64(tmp);
break;
@@ -2745,7 +2740,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_sckc(tmp);
+ gen_helper_sckc(cpu_env, tmp);
tcg_temp_free_i64(tmp);
break;
case 0x07: /* STCKC D2(B2) [S] */
@@ -2754,7 +2749,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_stckc(tmp);
+ gen_helper_stckc(cpu_env, tmp);
tcg_temp_free_i64(tmp);
break;
case 0x08: /* SPT D2(B2) [S] */
@@ -2763,7 +2758,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_spt(tmp);
+ gen_helper_spt(cpu_env, tmp);
tcg_temp_free_i64(tmp);
break;
case 0x09: /* STPT D2(B2) [S] */
@@ -2772,7 +2767,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_stpt(tmp);
+ gen_helper_stpt(cpu_env, tmp);
tcg_temp_free_i64(tmp);
break;
case 0x0a: /* SPKA D2(B2) [S] */
@@ -2790,7 +2785,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
case 0x0d: /* PTLB [S] */
/* Purge TLB */
check_privileged(s, ilc);
- gen_helper_ptlb();
+ gen_helper_ptlb(cpu_env);
break;
case 0x10: /* SPX D2(B2) [S] */
/* Set Prefix Register */
@@ -2798,7 +2793,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_spx(tmp);
+ gen_helper_spx(cpu_env, tmp);
tcg_temp_free_i64(tmp);
break;
case 0x11: /* STPX D2(B2) [S] */
@@ -2833,7 +2828,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
r2 = insn & 0xf;
tmp = load_reg(r1);
tmp2 = load_reg(r2);
- gen_helper_ipte(tmp, tmp2);
+ gen_helper_ipte(cpu_env, tmp, tmp2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
break;
@@ -2844,7 +2839,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
r2 = insn & 0xf;
tmp = load_reg(r2);
tmp2 = tcg_temp_new_i64();
- gen_helper_iske(tmp2, tmp);
+ gen_helper_iske(tmp2, cpu_env, tmp);
store_reg(r1, tmp2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
@@ -2856,7 +2851,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
r2 = insn & 0xf;
tmp32_1 = load_reg32(r1);
tmp = load_reg(r2);
- gen_helper_rrbe(cc_op, tmp32_1, tmp);
+ gen_helper_rrbe(cc_op, cpu_env, tmp32_1, tmp);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i64(tmp);
@@ -2868,7 +2863,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
r2 = insn & 0xf;
tmp32_1 = load_reg32(r1);
tmp = load_reg(r2);
- gen_helper_sske(tmp32_1, tmp);
+ gen_helper_sske(cpu_env, tmp32_1, tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i64(tmp);
break;
@@ -2885,7 +2880,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
tmp32_1 = load_reg32(r1);
tmp = load_reg(r2);
potential_page_fault(s);
- gen_helper_stura(tmp, tmp32_1);
+ gen_helper_stura(cpu_env, tmp, tmp32_1);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i64(tmp);
break;
@@ -2896,7 +2891,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
r2 = insn & 0xf;
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r2);
- gen_helper_csp(cc_op, tmp32_1, tmp32_2);
+ gen_helper_csp(cc_op, cpu_env, tmp32_1, tmp32_2);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -2911,7 +2906,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_stcke(cc_op, tmp);
+ gen_helper_stcke(cc_op, cpu_env, tmp);
set_cc_static(s);
tcg_temp_free_i64(tmp);
break;
@@ -2921,7 +2916,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2);
potential_page_fault(s);
- gen_helper_sacf(tmp);
+ gen_helper_sacf(cpu_env, tmp);
tcg_temp_free_i64(tmp);
/* addressing mode has changed, so end the block */
s->pc += ilc * 2;
@@ -2935,7 +2930,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
tmp32_1 = load_reg32(0);
tmp32_2 = load_reg32(1);
potential_page_fault(s);
- gen_helper_stsi(cc_op, tmp, tmp32_1, tmp32_2);
+ gen_helper_stsi(cc_op, cpu_env, tmp, tmp32_1, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -2972,7 +2967,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s));
tcg_gen_addi_i64(tmp, tmp, 8);
tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s));
- gen_helper_load_psw(tmp2, tmp3);
+ gen_helper_load_psw(cpu_env, tmp2, tmp3);
/* we need to keep cc_op intact */
s->is_jmp = DISAS_JUMP;
tcg_temp_free_i64(tmp);
@@ -2985,7 +2980,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
potential_page_fault(s);
tmp32_1 = load_reg32(r2);
tmp = load_reg(r1);
- gen_helper_servc(cc_op, tmp32_1, tmp);
+ gen_helper_servc(cc_op, cpu_env, tmp32_1, tmp);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i64(tmp);
@@ -3006,14 +3001,14 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
#define FP_HELPER(i) \
tmp32_1 = tcg_const_i32(r1); \
tmp32_2 = tcg_const_i32(r2); \
- gen_helper_ ## i (tmp32_1, tmp32_2); \
+ gen_helper_ ## i(cpu_env, tmp32_1, tmp32_2); \
tcg_temp_free_i32(tmp32_1); \
tcg_temp_free_i32(tmp32_2);
#define FP_HELPER_CC(i) \
tmp32_1 = tcg_const_i32(r1); \
tmp32_2 = tcg_const_i32(r2); \
- gen_helper_ ## i (cc_op, tmp32_1, tmp32_2); \
+ gen_helper_ ## i(cc_op, cpu_env, tmp32_1, tmp32_2); \
set_cc_static(s); \
tcg_temp_free_i32(tmp32_1); \
tcg_temp_free_i32(tmp32_2);
@@ -3085,13 +3080,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
tmp32_3 = tcg_const_i32(r1);
switch (op) {
case 0xe:
- gen_helper_maebr(tmp32_1, tmp32_3, tmp32_2);
+ gen_helper_maebr(cpu_env, tmp32_1, tmp32_3, tmp32_2);
break;
case 0x1e:
- gen_helper_madbr(tmp32_1, tmp32_3, tmp32_2);
+ gen_helper_madbr(cpu_env, tmp32_1, tmp32_3, tmp32_2);
break;
case 0x1f:
- gen_helper_msdbr(tmp32_1, tmp32_3, tmp32_2);
+ gen_helper_msdbr(cpu_env, tmp32_1, tmp32_3, tmp32_2);
break;
default:
tcg_abort();
@@ -3143,17 +3138,17 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
break;
case 0x74: /* LZER R1 [RRE] */
tmp32_1 = tcg_const_i32(r1);
- gen_helper_lzer(tmp32_1);
+ gen_helper_lzer(cpu_env, tmp32_1);
tcg_temp_free_i32(tmp32_1);
break;
case 0x75: /* LZDR R1 [RRE] */
tmp32_1 = tcg_const_i32(r1);
- gen_helper_lzdr(tmp32_1);
+ gen_helper_lzdr(cpu_env, tmp32_1);
tcg_temp_free_i32(tmp32_1);
break;
case 0x76: /* LZXR R1 [RRE] */
tmp32_1 = tcg_const_i32(r1);
- gen_helper_lzxr(tmp32_1);
+ gen_helper_lzxr(cpu_env, tmp32_1);
tcg_temp_free_i32(tmp32_1);
break;
case 0x84: /* SFPC R1 [RRE] */
@@ -3174,13 +3169,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
tmp32_2 = load_reg32(r2);
switch (op) {
case 0x94:
- gen_helper_cefbr(tmp32_1, tmp32_2);
+ gen_helper_cefbr(cpu_env, tmp32_1, tmp32_2);
break;
case 0x95:
- gen_helper_cdfbr(tmp32_1, tmp32_2);
+ gen_helper_cdfbr(cpu_env, tmp32_1, tmp32_2);
break;
case 0x96:
- gen_helper_cxfbr(tmp32_1, tmp32_2);
+ gen_helper_cxfbr(cpu_env, tmp32_1, tmp32_2);
break;
default:
tcg_abort();
@@ -3196,13 +3191,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
tmp32_3 = tcg_const_i32(m3);
switch (op) {
case 0x98:
- gen_helper_cfebr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_cfebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3);
break;
case 0x99:
- gen_helper_cfdbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_cfdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3);
break;
case 0x9a:
- gen_helper_cfxbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_cfxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3);
break;
default:
tcg_abort();
@@ -3218,10 +3213,10 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
tmp = load_reg(r2);
switch (op) {
case 0xa4:
- gen_helper_cegbr(tmp32_1, tmp);
+ gen_helper_cegbr(cpu_env, tmp32_1, tmp);
break;
case 0xa5:
- gen_helper_cdgbr(tmp32_1, tmp);
+ gen_helper_cdgbr(cpu_env, tmp32_1, tmp);
break;
default:
tcg_abort();
@@ -3232,7 +3227,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
case 0xa6: /* CXGBR R1,R2 [RRE] */
tmp32_1 = tcg_const_i32(r1);
tmp = load_reg(r2);
- gen_helper_cxgbr(tmp32_1, tmp);
+ gen_helper_cxgbr(cpu_env, tmp32_1, tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i64(tmp);
break;
@@ -3240,7 +3235,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r2);
tmp32_3 = tcg_const_i32(m3);
- gen_helper_cgebr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_cgebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -3250,7 +3245,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r2);
tmp32_3 = tcg_const_i32(m3);
- gen_helper_cgdbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_cgdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -3260,7 +3255,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r2);
tmp32_3 = tcg_const_i32(m3);
- gen_helper_cgxbr(cc_op, tmp32_1, tmp32_2, tmp32_3);
+ gen_helper_cgxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -3540,7 +3535,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2)
case 0x83: /* FLOGR R1,R2 [RRE] */
tmp = load_reg(r2);
tmp32_1 = tcg_const_i32(r1);
- gen_helper_flogr(cc_op, tmp32_1, tmp);
+ gen_helper_flogr(cc_op, cpu_env, tmp32_1, tmp);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -3560,7 +3555,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2)
case 0x87: /* DLGR R1,R2 [RRE] */
tmp32_1 = tcg_const_i32(r1);
tmp = load_reg(r2);
- gen_helper_dlg(tmp32_1, tmp);
+ gen_helper_dlg(cpu_env, tmp32_1, tmp);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
break;
@@ -3585,7 +3580,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2)
tmp2 = load_reg(r2);
tmp32_1 = tcg_const_i32(r1);
gen_op_calc_cc(s);
- gen_helper_slbg(cc_op, cc_op, tmp32_1, tmp, tmp2);
+ gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, tmp, tmp2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
@@ -3652,7 +3647,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2)
tmp32_1 = load_reg32(r2);
tmp32_2 = tcg_const_i32(r1);
gen_op_calc_cc(s);
- gen_helper_slb(cc_op, cc_op, tmp32_2, tmp32_1);
+ gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_2, tmp32_1);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -3870,7 +3865,7 @@ static void disas_s390_insn(DisasContext *s)
int ilc;
int l1;
- opc = ldub_code(s->pc);
+ opc = cpu_ldub_code(cpu_single_env, s->pc);
LOG_DISAS("opc 0x%x\n", opc);
ilc = get_ilc(opc);
@@ -3931,7 +3926,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_3 = tcg_const_i32(EXCP_SVC);
tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code));
tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilc));
- gen_helper_exception(tmp32_3);
+ gen_helper_exception(cpu_env, tmp32_3);
s->is_jmp = DISAS_EXCP;
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -3956,7 +3951,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r2);
potential_page_fault(s);
- gen_helper_mvcl(cc_op, tmp32_1, tmp32_2);
+ gen_helper_mvcl(cc_op, cpu_env, tmp32_1, tmp32_2);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -4170,7 +4165,7 @@ static void disas_s390_insn(DisasContext *s)
tmp3 = tcg_const_i64(s->pc + 4);
update_psw_addr(s);
gen_op_calc_cc(s);
- gen_helper_ex(cc_op, cc_op, tmp2, tmp, tmp3);
+ gen_helper_ex(cc_op, cpu_env, cc_op, tmp2, tmp, tmp3);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
@@ -4532,7 +4527,7 @@ static void disas_s390_insn(DisasContext *s)
tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
tcg_gen_addi_i64(tmp, tmp, 4);
tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s));
- gen_helper_load_psw(tmp2, tmp3);
+ gen_helper_load_psw(cpu_env, tmp2, tmp3);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i64(tmp3);
@@ -4548,7 +4543,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(insn & 0xfff);
tmp2 = load_reg(2);
tmp3 = load_reg(1);
- gen_helper_diag(tmp2, tmp32_1, tmp2, tmp3);
+ gen_helper_diag(tmp2, cpu_env, tmp32_1, tmp2, tmp3);
store_reg(2, tmp2);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i64(tmp2);
@@ -4699,7 +4694,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_lam(tmp32_1, tmp, tmp32_2);
+ gen_helper_lam(cpu_env, tmp32_1, tmp, tmp32_2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -4711,7 +4706,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_stam(tmp32_1, tmp, tmp32_2);
+ gen_helper_stam(cpu_env, tmp32_1, tmp, tmp32_2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -4737,7 +4732,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_mvcle(cc_op, tmp32_1, tmp, tmp32_2);
+ gen_helper_mvcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -4750,7 +4745,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_clcle(cc_op, tmp32_1, tmp, tmp32_2);
+ gen_helper_clcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -4782,7 +4777,7 @@ static void disas_s390_insn(DisasContext *s)
tmp2 = load_reg(r3);
tmp32_1 = tcg_const_i32(r1);
potential_page_fault(s);
- gen_helper_sigp(cc_op, tmp, tmp32_1, tmp2);
+ gen_helper_sigp(cc_op, cpu_env, tmp, tmp32_1, tmp2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
@@ -4794,7 +4789,7 @@ static void disas_s390_insn(DisasContext *s)
tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
tmp32_1 = tcg_const_i32(r1);
potential_page_fault(s);
- gen_helper_lra(cc_op, tmp, tmp32_1);
+ gen_helper_lra(cc_op, cpu_env, tmp, tmp32_1);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -4840,7 +4835,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_stctl(tmp32_1, tmp, tmp32_2);
+ gen_helper_stctl(cpu_env, tmp32_1, tmp, tmp32_2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -4854,7 +4849,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_lctl(tmp32_1, tmp, tmp32_2);
+ gen_helper_lctl(cpu_env, tmp32_1, tmp, tmp32_2);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -4874,7 +4869,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_cs(cc_op, tmp32_1, tmp, tmp32_2);
+ gen_helper_cs(cc_op, cpu_env, tmp32_1, tmp, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -4887,7 +4882,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = load_reg32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_clm(cc_op, tmp32_1, tmp32_2, tmp);
+ gen_helper_clm(cc_op, cpu_env, tmp32_1, tmp32_2, tmp);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
@@ -4900,7 +4895,7 @@ static void disas_s390_insn(DisasContext *s)
tmp32_1 = load_reg32(r1);
tmp32_2 = tcg_const_i32(r3);
potential_page_fault(s);
- gen_helper_stcm(tmp32_1, tmp32_2, tmp);
+ gen_helper_stcm(cpu_env, tmp32_1, tmp32_2, tmp);
tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
@@ -4997,7 +4992,7 @@ static void disas_s390_insn(DisasContext *s)
break;
case 0xd4:
potential_page_fault(s);
- gen_helper_nc(cc_op, vl, tmp, tmp2);
+ gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2);
set_cc_static(s);
break;
case 0xd5:
@@ -5005,22 +5000,22 @@ static void disas_s390_insn(DisasContext *s)
break;
case 0xd6:
potential_page_fault(s);
- gen_helper_oc(cc_op, vl, tmp, tmp2);
+ gen_helper_oc(cc_op, cpu_env, vl, tmp, tmp2);
set_cc_static(s);
break;
case 0xd7:
potential_page_fault(s);
- gen_helper_xc(cc_op, vl, tmp, tmp2);
+ gen_helper_xc(cc_op, cpu_env, vl, tmp, tmp2);
set_cc_static(s);
break;
case 0xdc:
potential_page_fault(s);
- gen_helper_tr(vl, tmp, tmp2);
+ gen_helper_tr(cpu_env, vl, tmp, tmp2);
set_cc_static(s);
break;
case 0xf3:
potential_page_fault(s);
- gen_helper_unpk(vl, tmp, tmp2);
+ gen_helper_unpk(cpu_env, vl, tmp, tmp2);
break;
default:
tcg_abort();
@@ -5045,9 +5040,9 @@ static void disas_s390_insn(DisasContext *s)
tmp2 = get_address(s, 0, b1, d1);
tmp3 = get_address(s, 0, b2, d2);
if (opc == 0xda) {
- gen_helper_mvcp(cc_op, tmp, tmp2, tmp3);
+ gen_helper_mvcp(cc_op, cpu_env, tmp, tmp2, tmp3);
} else {
- gen_helper_mvcs(cc_op, tmp, tmp2, tmp3);
+ gen_helper_mvcs(cc_op, cpu_env, tmp, tmp2, tmp3);
}
set_cc_static(s);
tcg_temp_free_i64(tmp);
diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
index 9c64ef89f..f4b62a5ba 100644
--- a/target-sparc/fop_helper.c
+++ b/target-sparc/fop_helper.c
@@ -334,34 +334,28 @@ void helper_fsqrtq(CPUSPARCState *env)
}
#define GEN_FCMP(name, size, reg1, reg2, FS, E) \
- void glue(helper_, name) (CPUSPARCState *env) \
+ void glue(helper_, name) (CPUSPARCState *env) \
{ \
- env->fsr &= FSR_FTT_NMASK; \
- if (E && (glue(size, _is_any_nan)(reg1) || \
- glue(size, _is_any_nan)(reg2)) && \
- (env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- helper_raise_exception(env, TT_FP_EXCP); \
+ int ret; \
+ clear_float_exceptions(env); \
+ if (E) { \
+ ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \
+ } else { \
+ ret = glue(size, _compare_quiet)(reg1, reg2, \
+ &env->fp_status); \
} \
- switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
+ check_ieee_exceptions(env); \
+ switch (ret) { \
case float_relation_unordered: \
- if ((env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- helper_raise_exception(env, TT_FP_EXCP); \
- } else { \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
- env->fsr |= FSR_NVA; \
- } \
+ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
+ env->fsr |= FSR_NVA; \
break; \
case float_relation_less: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr &= ~(FSR_FCC1) << FS; \
env->fsr |= FSR_FCC0 << FS; \
break; \
case float_relation_greater: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr &= ~(FSR_FCC0) << FS; \
env->fsr |= FSR_FCC1 << FS; \
break; \
default: \
@@ -370,34 +364,27 @@ void helper_fsqrtq(CPUSPARCState *env)
} \
}
#define GEN_FCMP_T(name, size, FS, E) \
- void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \
+ void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \
{ \
- env->fsr &= FSR_FTT_NMASK; \
- if (E && (glue(size, _is_any_nan)(src1) || \
- glue(size, _is_any_nan)(src2)) && \
- (env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- helper_raise_exception(env, TT_FP_EXCP); \
+ int ret; \
+ clear_float_exceptions(env); \
+ if (E) { \
+ ret = glue(size, _compare)(src1, src2, &env->fp_status); \
+ } else { \
+ ret = glue(size, _compare_quiet)(src1, src2, \
+ &env->fp_status); \
} \
- switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \
+ check_ieee_exceptions(env); \
+ switch (ret) { \
case float_relation_unordered: \
- if ((env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- helper_raise_exception(env, TT_FP_EXCP); \
- } else { \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
- env->fsr |= FSR_NVA; \
- } \
+ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
break; \
case float_relation_less: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr &= ~(FSR_FCC1 << FS); \
env->fsr |= FSR_FCC0 << FS; \
break; \
case float_relation_greater: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr &= ~(FSR_FCC0 << FS); \
env->fsr |= FSR_FCC1 << FS; \
break; \
default: \
diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c
index 6d001c2c1..52be07a36 100644
--- a/target-xtensa/xtensa-semi.c
+++ b/target-xtensa/xtensa-semi.c
@@ -54,6 +54,102 @@ enum {
SELECT_ONE_EXCEPT = 3,
};
+enum {
+ TARGET_EPERM = 1,
+ TARGET_ENOENT = 2,
+ TARGET_ESRCH = 3,
+ TARGET_EINTR = 4,
+ TARGET_EIO = 5,
+ TARGET_ENXIO = 6,
+ TARGET_E2BIG = 7,
+ TARGET_ENOEXEC = 8,
+ TARGET_EBADF = 9,
+ TARGET_ECHILD = 10,
+ TARGET_EAGAIN = 11,
+ TARGET_ENOMEM = 12,
+ TARGET_EACCES = 13,
+ TARGET_EFAULT = 14,
+ TARGET_ENOTBLK = 15,
+ TARGET_EBUSY = 16,
+ TARGET_EEXIST = 17,
+ TARGET_EXDEV = 18,
+ TARGET_ENODEV = 19,
+ TARGET_ENOTDIR = 20,
+ TARGET_EISDIR = 21,
+ TARGET_EINVAL = 22,
+ TARGET_ENFILE = 23,
+ TARGET_EMFILE = 24,
+ TARGET_ENOTTY = 25,
+ TARGET_ETXTBSY = 26,
+ TARGET_EFBIG = 27,
+ TARGET_ENOSPC = 28,
+ TARGET_ESPIPE = 29,
+ TARGET_EROFS = 30,
+ TARGET_EMLINK = 31,
+ TARGET_EPIPE = 32,
+ TARGET_EDOM = 33,
+ TARGET_ERANGE = 34,
+ TARGET_ENOSYS = 88,
+ TARGET_ELOOP = 92,
+};
+
+static uint32_t errno_h2g(int host_errno)
+{
+ static const uint32_t guest_errno[] = {
+ [EPERM] = TARGET_EPERM,
+ [ENOENT] = TARGET_ENOENT,
+ [ESRCH] = TARGET_ESRCH,
+ [EINTR] = TARGET_EINTR,
+ [EIO] = TARGET_EIO,
+ [ENXIO] = TARGET_ENXIO,
+ [E2BIG] = TARGET_E2BIG,
+ [ENOEXEC] = TARGET_ENOEXEC,
+ [EBADF] = TARGET_EBADF,
+ [ECHILD] = TARGET_ECHILD,
+ [EAGAIN] = TARGET_EAGAIN,
+ [ENOMEM] = TARGET_ENOMEM,
+ [EACCES] = TARGET_EACCES,
+ [EFAULT] = TARGET_EFAULT,
+#ifdef ENOTBLK
+ [ENOTBLK] = TARGET_ENOTBLK,
+#endif
+ [EBUSY] = TARGET_EBUSY,
+ [EEXIST] = TARGET_EEXIST,
+ [EXDEV] = TARGET_EXDEV,
+ [ENODEV] = TARGET_ENODEV,
+ [ENOTDIR] = TARGET_ENOTDIR,
+ [EISDIR] = TARGET_EISDIR,
+ [EINVAL] = TARGET_EINVAL,
+ [ENFILE] = TARGET_ENFILE,
+ [EMFILE] = TARGET_EMFILE,
+ [ENOTTY] = TARGET_ENOTTY,
+#ifdef ETXTBSY
+ [ETXTBSY] = TARGET_ETXTBSY,
+#endif
+ [EFBIG] = TARGET_EFBIG,
+ [ENOSPC] = TARGET_ENOSPC,
+ [ESPIPE] = TARGET_ESPIPE,
+ [EROFS] = TARGET_EROFS,
+ [EMLINK] = TARGET_EMLINK,
+ [EPIPE] = TARGET_EPIPE,
+ [EDOM] = TARGET_EDOM,
+ [ERANGE] = TARGET_ERANGE,
+ [ENOSYS] = TARGET_ENOSYS,
+#ifdef ELOOP
+ [ELOOP] = TARGET_ELOOP,
+#endif
+ };
+
+ if (host_errno == 0) {
+ return 0;
+ } else if (host_errno > 0 && host_errno < ARRAY_SIZE(guest_errno) &&
+ guest_errno[host_errno]) {
+ return guest_errno[host_errno];
+ } else {
+ return TARGET_EINVAL;
+ }
+}
+
void HELPER(simcall)(CPUXtensaState *env)
{
uint32_t *regs = env->regs;
@@ -87,14 +183,14 @@ void HELPER(simcall)(CPUXtensaState *env)
regs[2] = is_write ?
write(fd, buf, io_sz) :
read(fd, buf, io_sz);
- regs[3] = errno;
+ regs[3] = errno_h2g(errno);
cpu_physical_memory_unmap(buf, sz, is_write, sz);
if (regs[2] == -1) {
break;
}
} else {
regs[2] = -1;
- regs[3] = EINVAL;
+ regs[3] = TARGET_EINVAL;
break;
}
}
@@ -117,10 +213,10 @@ void HELPER(simcall)(CPUXtensaState *env)
if (rc == 0 && i < ARRAY_SIZE(name)) {
regs[2] = open(name, regs[4], regs[5]);
- regs[3] = errno;
+ regs[3] = errno_h2g(errno);
} else {
regs[2] = -1;
- regs[3] = EINVAL;
+ regs[3] = TARGET_EINVAL;
}
}
break;
@@ -130,13 +226,13 @@ void HELPER(simcall)(CPUXtensaState *env)
regs[2] = regs[3] = 0;
} else {
regs[2] = close(regs[3]);
- regs[3] = errno;
+ regs[3] = errno_h2g(errno);
}
break;
case TARGET_SYS_lseek:
regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]);
- regs[3] = errno;
+ regs[3] = errno_h2g(errno);
break;
case TARGET_SYS_select_one:
@@ -163,7 +259,7 @@ void HELPER(simcall)(CPUXtensaState *env)
rq == SELECT_ONE_WRITE ? &fdset : NULL,
rq == SELECT_ONE_EXCEPT ? &fdset : NULL,
target_tv ? &tv : NULL);
- regs[3] = errno;
+ regs[3] = errno_h2g(errno);
}
break;
@@ -219,7 +315,7 @@ void HELPER(simcall)(CPUXtensaState *env)
default:
qemu_log("%s(%d): not implemented\n", __func__, regs[2]);
regs[2] = -1;
- regs[3] = ENOSYS;
+ regs[3] = TARGET_ENOSYS;
break;
}
}
diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 04662c15f..99b53390c 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -1509,11 +1509,13 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg,
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index);
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
+ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3],
+ tcg_target_call_iarg_regs[2]);
+ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1],
tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0],
TCG_AREG0);
#endif
tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]);
@@ -1521,13 +1523,11 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg,
tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index);
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
- tcg_target_call_iarg_regs[2]);
tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1],
tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0],
TCG_AREG0);
#endif
tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]);
diff --git a/trace-events b/trace-events
index 04b072392..8fcbc50f9 100644
--- a/trace-events
+++ b/trace-events
@@ -956,6 +956,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d"
qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d"
qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d"
qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d"
+qxl_spice_monitors_config(int id) "%d"
qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d"
qxl_spice_oom(int qid) "%d"
qxl_spice_reset_cursor(int qid) "%d"
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 4fc48f890..ba0d0bdbc 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -37,6 +37,7 @@
#include "migration.h"
#include "monitor.h"
#include "hw/hw.h"
+#include "spice-display.h"
/* core bits */
@@ -45,6 +46,7 @@ static Notifier migration_state;
static const char *auth = "spice";
static char *auth_passwd;
static time_t auth_expires = TIME_MAX;
+static int spice_migration_completed;
int using_spice = 0;
static QemuThread me;
@@ -284,6 +286,7 @@ typedef struct SpiceMigration {
} SpiceMigration;
static void migrate_connect_complete_cb(SpiceMigrateInstance *sin);
+static void migrate_end_complete_cb(SpiceMigrateInstance *sin);
static const SpiceMigrateInterface migrate_interface = {
.base.type = SPICE_INTERFACE_MIGRATION,
@@ -291,7 +294,7 @@ static const SpiceMigrateInterface migrate_interface = {
.base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR,
.base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR,
.migrate_connect_complete = migrate_connect_complete_cb,
- .migrate_end_complete = NULL,
+ .migrate_end_complete = migrate_end_complete_cb,
};
static SpiceMigration spice_migrate;
@@ -304,6 +307,12 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin)
}
sm->connect_complete.cb = NULL;
}
+
+static void migrate_end_complete_cb(SpiceMigrateInstance *sin)
+{
+ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL);
+ spice_migration_completed = true;
+}
#endif
/* config string parsing */
@@ -344,7 +353,8 @@ static const char *stream_video_names[] = {
[ SPICE_STREAM_VIDEO_FILTER ] = "filter",
};
#define parse_stream_video(_name) \
- name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
+ parse_name(_name, "stream video control", \
+ stream_video_names, ARRAY_SIZE(stream_video_names))
static const char *compression_names[] = {
[ SPICE_IMAGE_COMPRESS_OFF ] = "off",
@@ -435,6 +445,7 @@ SpiceInfo *qmp_query_spice(Error **errp)
}
info->enabled = true;
+ info->migrated = spice_migration_completed;
addr = qemu_opt_get(opts, "addr");
port = qemu_opt_get_number(opts, "port", 0);
@@ -487,6 +498,8 @@ static void migration_state_notifier(Notifier *notifier, void *data)
} else if (migration_has_finished(s)) {
#ifndef SPICE_INTERFACE_MIGRATION
spice_server_migrate_switch(spice_server);
+ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL);
+ spice_migration_completed = true;
#else
spice_server_migrate_end(spice_server, true);
} else if (migration_has_failed(s)) {
@@ -545,6 +558,20 @@ static int add_channel(const char *name, const char *value, void *opaque)
return 0;
}
+static void vm_change_state_handler(void *opaque, int running,
+ RunState state)
+{
+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */
+ if (running) {
+ qemu_spice_display_start();
+ spice_server_vm_start(spice_server);
+ } else {
+ spice_server_vm_stop(spice_server);
+ qemu_spice_display_stop();
+ }
+#endif
+}
+
void qemu_spice_init(void)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
@@ -558,6 +585,9 @@ void qemu_spice_init(void)
int port, tls_port, len, addr_flags;
spice_image_compression_t compression;
spice_wan_compression_t wan_compr;
+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */
+ bool seamless_migration;
+#endif
qemu_thread_get_self(&me);
@@ -701,6 +731,10 @@ void qemu_spice_init(void)
spice_server_set_uuid(spice_server, qemu_uuid);
#endif
+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */
+ seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0);
+ spice_server_set_seamless_migration(spice_server, seamless_migration);
+#endif
if (0 != spice_server_init(spice_server, &core_interface)) {
error_report("failed to initialize spice server");
exit(1);
@@ -718,6 +752,8 @@ void qemu_spice_init(void)
qemu_spice_input_init();
qemu_spice_audio_init();
+ qemu_add_vm_change_state_handler(vm_change_state_handler, &spice_server);
+
g_free(x509_key_file);
g_free(x509_cert_file);
g_free(x509_cacert_file);
@@ -740,6 +776,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin)
spice_server = spice_server_new();
spice_server_init(spice_server, &core_interface);
}
+
return spice_server_add_interface(spice_server, sin);
}
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 3e8f0b3ad..99bc665bc 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -126,18 +126,44 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
ssd->worker->wakeup(ssd->worker);
}
-void qemu_spice_start(SimpleSpiceDisplay *ssd)
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
+static void qemu_spice_start(SimpleSpiceDisplay *ssd)
{
trace_qemu_spice_start(ssd->qxl.id);
ssd->worker->start(ssd->worker);
}
-void qemu_spice_stop(SimpleSpiceDisplay *ssd)
+static void qemu_spice_stop(SimpleSpiceDisplay *ssd)
{
trace_qemu_spice_stop(ssd->qxl.id);
ssd->worker->stop(ssd->worker);
}
+#else
+
+static int spice_display_is_running;
+
+void qemu_spice_display_start(void)
+{
+ spice_display_is_running = true;
+}
+
+void qemu_spice_display_stop(void)
+{
+ spice_display_is_running = false;
+}
+
+#endif
+
+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd)
+{
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
+ return ssd->running;
+#else
+ return spice_display_is_running;
+#endif
+}
+
static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
{
SimpleSpiceUpdate *update;
@@ -272,6 +298,7 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
void qemu_spice_vm_change_state_handler(void *opaque, int running,
RunState state)
{
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
SimpleSpiceDisplay *ssd = opaque;
if (running) {
@@ -281,6 +308,7 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running,
qemu_spice_stop(ssd);
ssd->running = false;
}
+#endif
}
void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
@@ -289,6 +317,9 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
qemu_mutex_init(&ssd->lock);
ssd->mouse_x = -1;
ssd->mouse_y = -1;
+ if (ssd->num_surfaces == 0) {
+ ssd->num_surfaces = 1024;
+ }
ssd->bufsize = (16 * 1024 * 1024);
ssd->buf = g_malloc(ssd->bufsize);
}
@@ -399,7 +430,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
info->internal_groupslot_id = 0;
info->qxl_ram_size = ssd->bufsize;
- info->n_surfaces = NUM_SURFACES;
+ info->n_surfaces = ssd->num_surfaces;
}
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 12e50b6ef..512ab7831 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -32,8 +32,6 @@
#define MEMSLOT_GROUP_GUEST 1
#define NUM_MEMSLOTS_GROUPS 2
-#define NUM_SURFACES 1024
-
/*
* Internal enum to differenciate between options for
* io calls that have a sync (old) version and an _async (new)
@@ -51,6 +49,7 @@ typedef enum qxl_async_io {
enum {
QXL_COOKIE_TYPE_IO,
QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
+ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
};
typedef struct QXLCookie {
@@ -79,10 +78,13 @@ struct SimpleSpiceDisplay {
QXLInstance qxl;
uint32_t unique;
QemuPfConv *conv;
+ int32_t num_surfaces;
QXLRect dirty;
int notify;
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
int running;
+#endif
/*
* All struct members below this comment can be accessed from
@@ -129,5 +131,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
uint32_t id, qxl_async_io async);
void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
-void qemu_spice_start(SimpleSpiceDisplay *ssd);
-void qemu_spice_stop(SimpleSpiceDisplay *ssd);
+#if SPICE_SERVER_VERSION >= 0x000b02 /* before 0.11.2 */
+void qemu_spice_display_start(void);
+void qemu_spice_display_stop(void);
+#endif
+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd);
diff --git a/vmstate.h b/vmstate.h
index 5bd2b762a..c9c320e62 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -503,8 +503,11 @@ extern const VMStateInfo vmstate_info_unused_buffer;
#define VMSTATE_TIMER_TEST(_f, _s, _test) \
VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
+#define VMSTATE_TIMER_V(_f, _s, _v) \
+ VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *)
+
#define VMSTATE_TIMER(_f, _s) \
- VMSTATE_TIMER_TEST(_f, _s, NULL)
+ VMSTATE_TIMER_V(_f, _s, 0)
#define VMSTATE_TIMER_ARRAY(_f, _s, _n) \
VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)