aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--arch_init.c33
-rw-r--r--audio/mixeng.c6
-rwxr-xr-xconfigure18
-rw-r--r--hw/acpi/core.c3
-rw-r--r--hw/audio/hda-codec-common.h456
-rw-r--r--hw/audio/hda-codec.c454
-rw-r--r--hw/char/Makefile.objs2
-rw-r--r--hw/char/sclpconsole-lm.c398
-rw-r--r--hw/char/sclpconsole.c88
-rw-r--r--hw/i386/pc_piix.c1
-rw-r--r--hw/s390x/event-facility.c17
-rw-r--r--hw/s390x/sclpquiesce.c29
-rw-r--r--include/exec/exec-all.h4
-rw-r--r--include/hw/s390x/ebcdic.h104
-rw-r--r--include/hw/s390x/event-facility.h88
-rw-r--r--include/migration/vmstate.h17
-rw-r--r--include/sysemu/sysemu.h4
-rw-r--r--linux-user/alpha/syscall_nr.h4
-rw-r--r--linux-user/ioctls.h1
-rw-r--r--linux-user/linuxload.c8
-rw-r--r--linux-user/main.c92
-rw-r--r--linux-user/qemu.h2
-rw-r--r--linux-user/strace.list9
-rw-r--r--linux-user/syscall.c210
-rw-r--r--linux-user/syscall_defs.h12
-rw-r--r--migration-rdma.c17
-rw-r--r--migration.c3
-rw-r--r--pc-bios/s390-ccw.imgbin9432 -> 9336 bytes
-rw-r--r--pc-bios/s390-ccw/virtio.c7
-rw-r--r--pc-bios/s390-ccw/virtio.h1
-rw-r--r--savevm.c9
-rw-r--r--target-s390x/arch_dump.c1
-rw-r--r--target-s390x/cpu.h11
-rw-r--r--target-s390x/ioinst.c110
-rw-r--r--target-s390x/ioinst.h26
-rw-r--r--target-s390x/kvm.c54
-rw-r--r--target-s390x/misc_helper.c107
-rw-r--r--tcg/ppc/tcg-target.c506
-rw-r--r--tcg/ppc64/tcg-target.c1109
-rw-r--r--vl.c15
-rw-r--r--xen-all.c17
42 files changed, 2489 insertions, 1565 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 0431d09..5c3c70c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -638,6 +638,7 @@ Subsystems
----------
Audio
M: Vassili Karpov (malc) <av1474@comtv.ru>
+M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: audio/
F: hw/audio/
diff --git a/arch_init.c b/arch_init.c
index e47e139..d14457d 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -150,10 +150,9 @@ int qemu_read_default_config_files(bool userconfig)
return 0;
}
-static inline bool is_zero_page(uint8_t *p)
+static inline bool is_zero_range(uint8_t *p, uint64_t size)
{
- return buffer_find_nonzero_offset(p, TARGET_PAGE_SIZE) ==
- TARGET_PAGE_SIZE;
+ return buffer_find_nonzero_offset(p, size) == size;
}
/* struct contains XBZRLE cache and a static page
@@ -497,7 +496,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
acct_info.dup_pages++;
}
}
- } else if (is_zero_page(p)) {
+ } else if (is_zero_range(p, TARGET_PAGE_SIZE)) {
acct_info.dup_pages++;
bytes_sent = save_block_hdr(f, block, offset, cont,
RAM_SAVE_FLAG_COMPRESS);
@@ -710,15 +709,20 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
*/
ram_control_after_iterate(f, RAM_CONTROL_ROUND);
+ bytes_transferred += total_sent;
+
+ /*
+ * Do not count these 8 bytes into total_sent, so that we can
+ * return 0 if no page had been dirtied.
+ */
+ qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
+ bytes_transferred += 8;
+
+ ret = qemu_file_get_error(f);
if (ret < 0) {
- bytes_transferred += total_sent;
return ret;
}
- qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
- total_sent += 8;
- bytes_transferred += total_sent;
-
return total_sent;
}
@@ -844,13 +848,14 @@ static inline void *host_from_stream_offset(QEMUFile *f,
*/
void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
{
- if (ch != 0 || !is_zero_page(host)) {
+ if (ch != 0 || !is_zero_range(host, size)) {
memset(host, ch, size);
#ifndef _WIN32
- if (ch == 0 &&
- (!kvm_enabled() || kvm_has_sync_mmu()) &&
- getpagesize() <= TARGET_PAGE_SIZE) {
- qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
+ if (ch == 0 && (!kvm_enabled() || kvm_has_sync_mmu())) {
+ size = size & ~(getpagesize() - 1);
+ if (size > 0) {
+ qemu_madvise(host, size, QEMU_MADV_DONTNEED);
+ }
}
#endif
}
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 02a9d9f..0e4976f 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -348,7 +348,6 @@ void mixeng_clear (struct st_sample *buf, int len)
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol)
{
-#ifdef CONFIG_MIXEMU
if (vol->mute) {
mixeng_clear (buf, len);
return;
@@ -364,9 +363,4 @@ void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol)
#endif
buf += 1;
}
-#else
- (void) buf;
- (void) len;
- (void) vol;
-#endif
}
diff --git a/configure b/configure
index 05e16da..23dbaaf 100755
--- a/configure
+++ b/configure
@@ -215,7 +215,6 @@ linux_user="no"
bsd_user="no"
guest_base="yes"
uname_release=""
-mixemu="no"
aix="no"
blobs="yes"
pkgversion=""
@@ -869,8 +868,6 @@ for opt do
;;
--enable-fdt) fdt="yes"
;;
- --enable-mixemu) mixemu="yes"
- ;;
--disable-linux-aio) linux_aio="no"
;;
--enable-linux-aio) linux_aio="yes"
@@ -981,6 +978,14 @@ for opt do
done
case "$cpu" in
+ ppc)
+ CPU_CFLAGS="-m32"
+ LDFLAGS="-m32 $LDFLAGS"
+ ;;
+ ppc64)
+ CPU_CFLAGS="-m64"
+ LDFLAGS="-m64 $LDFLAGS"
+ ;;
sparc)
LDFLAGS="-m32 $LDFLAGS"
CPU_CFLAGS="-m32 -mcpu=ultrasparc"
@@ -1103,7 +1108,6 @@ echo " (affects only QEMU, not qemu-img)"
echo " --block-drv-ro-whitelist=L"
echo " set block driver read-only whitelist"
echo " (affects only QEMU, not qemu-img)"
-echo " --enable-mixemu enable mixer emulation"
echo " --disable-xen disable xen backend driver support"
echo " --enable-xen enable xen backend driver support"
echo " --disable-xen-pci-passthrough"
@@ -3694,7 +3698,6 @@ echo "mingw32 support $mingw32"
echo "Audio drivers $audio_drv_list"
echo "Block whitelist (rw) $block_drv_rw_whitelist"
echo "Block whitelist (ro) $block_drv_ro_whitelist"
-echo "Mixer emulation $mixemu"
echo "VirtFS support $virtfs"
echo "VNC support $vnc"
if test "$vnc" = "yes" ; then
@@ -3792,7 +3795,7 @@ echo "libs_softmmu=$libs_softmmu" >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
case "$cpu" in
- arm|i386|x86_64|x32|ppc|aarch64)
+ aarch64 | arm | i386 | x86_64 | x32 | ppc*)
# The TCG interpreter currently does not support ld/st optimization.
if test "$tcg_interpreter" = "no" ; then
echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_host_mak
@@ -3881,9 +3884,6 @@ if test "$audio_win_int" = "yes" ; then
fi
echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak
echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak
-if test "$mixemu" = "yes" ; then
- echo "CONFIG_MIXEMU=y" >> $config_host_mak
-fi
if test "$vnc" = "yes" ; then
echo "CONFIG_VNC=y" >> $config_host_mak
fi
diff --git a/hw/acpi/core.c b/hw/acpi/core.c
index 7467b88..7138139 100644
--- a/hw/acpi/core.c
+++ b/hw/acpi/core.c
@@ -324,12 +324,13 @@ static void acpi_notify_wakeup(Notifier *notifier, void *data)
(ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS);
break;
case QEMU_WAKEUP_REASON_OTHER:
- default:
/* ACPI_BITMASK_WAKE_STATUS should be set on resume.
Pretend that resume was caused by power button */
ar->pm1.evt.sts |=
(ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
break;
+ default:
+ break;
}
}
diff --git a/hw/audio/hda-codec-common.h b/hw/audio/hda-codec-common.h
new file mode 100644
index 0000000..b4fdb51
--- /dev/null
+++ b/hw/audio/hda-codec-common.h
@@ -0,0 +1,456 @@
+/*
+ * Common code to disable/enable mixer emulation at run time
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Written by Bandan Das <bsd@redhat.com>
+ * with important bits picked up from hda-codec.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * HDA codec descriptions
+ */
+
+#ifdef HDA_MIXER
+#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x12)
+#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x22)
+#define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x32)
+#define QEMU_HDA_AMP_CAPS \
+ (AC_AMPCAP_MUTE | \
+ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \
+ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \
+ (3 << AC_AMPCAP_STEP_SIZE_SHIFT))
+#else
+#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x11)
+#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x21)
+#define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x31)
+#define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE
+#endif
+
+
+/* common: audio output widget */
+static const desc_param glue(common_params_audio_dac_, PARAM)[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_FORMAT_OVRD |
+ AC_WCAP_AMP_OVRD |
+ AC_WCAP_OUT_AMP |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_CAPS,
+ },
+};
+
+/* common: audio input widget */
+static const desc_param glue(common_params_audio_adc_, PARAM)[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_CONN_LIST |
+ AC_WCAP_FORMAT_OVRD |
+ AC_WCAP_AMP_OVRD |
+ AC_WCAP_IN_AMP |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_CONNLIST_LEN,
+ .val = 1,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_CAPS,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },
+};
+
+/* common: pin widget (line-out) */
+static const desc_param glue(common_params_audio_lineout_, PARAM)[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_CONN_LIST |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_PIN_CAP,
+ .val = AC_PINCAP_OUT,
+ },{
+ .id = AC_PAR_CONNLIST_LEN,
+ .val = 1,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },
+};
+
+/* common: pin widget (line-in) */
+static const desc_param glue(common_params_audio_linein_, PARAM)[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_PIN_CAP,
+ .val = AC_PINCAP_IN,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },
+};
+
+/* output: root node */
+static const desc_param glue(output_params_root_, PARAM)[] = {
+ {
+ .id = AC_PAR_VENDOR_ID,
+ .val = QEMU_HDA_ID_OUTPUT,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_OUTPUT,
+ },{
+ .id = AC_PAR_REV_ID,
+ .val = 0x00100101,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00010001,
+ },
+};
+
+/* output: audio function */
+static const desc_param glue(output_params_audio_func_, PARAM)[] = {
+ {
+ .id = AC_PAR_FUNCTION_TYPE,
+ .val = AC_GRP_AUDIO_FUNCTION,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_OUTPUT,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00020002,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_GPIO_CAP,
+ .val = 0,
+ },{
+ .id = AC_PAR_AUDIO_FG_CAP,
+ .val = 0x00000808,
+ },{
+ .id = AC_PAR_POWER_STATE,
+ .val = 0,
+ },
+};
+
+/* output: nodes */
+static const desc_node glue(output_nodes_, PARAM)[] = {
+ {
+ .nid = AC_NODE_ROOT,
+ .name = "root",
+ .params = glue(output_params_root_, PARAM),
+ .nparams = ARRAY_SIZE(glue(output_params_root_, PARAM)),
+ },{
+ .nid = 1,
+ .name = "func",
+ .params = glue(output_params_audio_func_, PARAM),
+ .nparams = ARRAY_SIZE(glue(output_params_audio_func_, PARAM)),
+ },{
+ .nid = 2,
+ .name = "dac",
+ .params = glue(common_params_audio_dac_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)),
+ .stindex = 0,
+ },{
+ .nid = 3,
+ .name = "out",
+ .params = glue(common_params_audio_lineout_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
+ 0x10),
+ .pinctl = AC_PINCTL_OUT_EN,
+ .conn = (uint32_t[]) { 2 },
+ }
+};
+
+/* output: codec */
+static const desc_codec glue(output_, PARAM) = {
+ .name = "output",
+ .iid = QEMU_HDA_ID_OUTPUT,
+ .nodes = glue(output_nodes_, PARAM),
+ .nnodes = ARRAY_SIZE(glue(output_nodes_, PARAM)),
+};
+
+/* duplex: root node */
+static const desc_param glue(duplex_params_root_, PARAM)[] = {
+ {
+ .id = AC_PAR_VENDOR_ID,
+ .val = QEMU_HDA_ID_DUPLEX,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_DUPLEX,
+ },{
+ .id = AC_PAR_REV_ID,
+ .val = 0x00100101,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00010001,
+ },
+};
+
+/* duplex: audio function */
+static const desc_param glue(duplex_params_audio_func_, PARAM)[] = {
+ {
+ .id = AC_PAR_FUNCTION_TYPE,
+ .val = AC_GRP_AUDIO_FUNCTION,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_DUPLEX,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00020004,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_GPIO_CAP,
+ .val = 0,
+ },{
+ .id = AC_PAR_AUDIO_FG_CAP,
+ .val = 0x00000808,
+ },{
+ .id = AC_PAR_POWER_STATE,
+ .val = 0,
+ },
+};
+
+/* duplex: nodes */
+static const desc_node glue(duplex_nodes_, PARAM)[] = {
+ {
+ .nid = AC_NODE_ROOT,
+ .name = "root",
+ .params = glue(duplex_params_root_, PARAM),
+ .nparams = ARRAY_SIZE(glue(duplex_params_root_, PARAM)),
+ },{
+ .nid = 1,
+ .name = "func",
+ .params = glue(duplex_params_audio_func_, PARAM),
+ .nparams = ARRAY_SIZE(glue(duplex_params_audio_func_, PARAM)),
+ },{
+ .nid = 2,
+ .name = "dac",
+ .params = glue(common_params_audio_dac_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)),
+ .stindex = 0,
+ },{
+ .nid = 3,
+ .name = "out",
+ .params = glue(common_params_audio_lineout_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
+ 0x10),
+ .pinctl = AC_PINCTL_OUT_EN,
+ .conn = (uint32_t[]) { 2 },
+ },{
+ .nid = 4,
+ .name = "adc",
+ .params = glue(common_params_audio_adc_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)),
+ .stindex = 1,
+ .conn = (uint32_t[]) { 5 },
+ },{
+ .nid = 5,
+ .name = "in",
+ .params = glue(common_params_audio_linein_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
+ 0x20),
+ .pinctl = AC_PINCTL_IN_EN,
+ }
+};
+
+/* duplex: codec */
+static const desc_codec glue(duplex_, PARAM) = {
+ .name = "duplex",
+ .iid = QEMU_HDA_ID_DUPLEX,
+ .nodes = glue(duplex_nodes_, PARAM),
+ .nnodes = ARRAY_SIZE(glue(duplex_nodes_, PARAM)),
+};
+
+/* micro: root node */
+static const desc_param glue(micro_params_root_, PARAM)[] = {
+ {
+ .id = AC_PAR_VENDOR_ID,
+ .val = QEMU_HDA_ID_MICRO,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_MICRO,
+ },{
+ .id = AC_PAR_REV_ID,
+ .val = 0x00100101,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00010001,
+ },
+};
+
+/* micro: audio function */
+static const desc_param glue(micro_params_audio_func_, PARAM)[] = {
+ {
+ .id = AC_PAR_FUNCTION_TYPE,
+ .val = AC_GRP_AUDIO_FUNCTION,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_MICRO,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00020004,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_GPIO_CAP,
+ .val = 0,
+ },{
+ .id = AC_PAR_AUDIO_FG_CAP,
+ .val = 0x00000808,
+ },{
+ .id = AC_PAR_POWER_STATE,
+ .val = 0,
+ },
+};
+
+/* micro: nodes */
+static const desc_node glue(micro_nodes_, PARAM)[] = {
+ {
+ .nid = AC_NODE_ROOT,
+ .name = "root",
+ .params = glue(micro_params_root_, PARAM),
+ .nparams = ARRAY_SIZE(glue(micro_params_root_, PARAM)),
+ },{
+ .nid = 1,
+ .name = "func",
+ .params = glue(micro_params_audio_func_, PARAM),
+ .nparams = ARRAY_SIZE(glue(micro_params_audio_func_, PARAM)),
+ },{
+ .nid = 2,
+ .name = "dac",
+ .params = glue(common_params_audio_dac_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)),
+ .stindex = 0,
+ },{
+ .nid = 3,
+ .name = "out",
+ .params = glue(common_params_audio_lineout_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_SPEAKER << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
+ 0x10),
+ .pinctl = AC_PINCTL_OUT_EN,
+ .conn = (uint32_t[]) { 2 },
+ },{
+ .nid = 4,
+ .name = "adc",
+ .params = glue(common_params_audio_adc_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)),
+ .stindex = 1,
+ .conn = (uint32_t[]) { 5 },
+ },{
+ .nid = 5,
+ .name = "in",
+ .params = glue(common_params_audio_linein_, PARAM),
+ .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
+ 0x20),
+ .pinctl = AC_PINCTL_IN_EN,
+ }
+};
+
+/* micro: codec */
+static const desc_codec glue(micro_, PARAM) = {
+ .name = "micro",
+ .iid = QEMU_HDA_ID_MICRO,
+ .nodes = glue(micro_nodes_, PARAM),
+ .nnodes = ARRAY_SIZE(glue(micro_nodes_, PARAM)),
+};
+
+#undef PARAM
+#undef HDA_MIXER
+#undef QEMU_HDA_ID_OUTPUT
+#undef QEMU_HDA_ID_DUPLEX
+#undef QEMU_HDA_ID_MICRO
+#undef QEMU_HDA_AMP_CAPS
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 9550c97..07a43bf 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -118,428 +118,12 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
#define QEMU_HDA_AMP_NONE (0)
#define QEMU_HDA_AMP_STEPS 0x4a
-#ifdef CONFIG_MIXEMU
-# define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x12)
-# define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x22)
-# define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x32)
-# define QEMU_HDA_AMP_CAPS \
- (AC_AMPCAP_MUTE | \
- (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \
- (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \
- (3 << AC_AMPCAP_STEP_SIZE_SHIFT))
-#else
-# define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x11)
-# define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x21)
-# define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x31)
-# define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE
-#endif
-
-/* common: audio output widget */
-static const desc_param common_params_audio_dac[] = {
- {
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_FORMAT_OVRD |
- AC_WCAP_AMP_OVRD |
- AC_WCAP_OUT_AMP |
- AC_WCAP_STEREO),
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_CAPS,
- },
-};
-
-/* common: audio input widget */
-static const desc_param common_params_audio_adc[] = {
- {
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_CONN_LIST |
- AC_WCAP_FORMAT_OVRD |
- AC_WCAP_AMP_OVRD |
- AC_WCAP_IN_AMP |
- AC_WCAP_STEREO),
- },{
- .id = AC_PAR_CONNLIST_LEN,
- .val = 1,
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_CAPS,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },
-};
-
-/* common: pin widget (line-out) */
-static const desc_param common_params_audio_lineout[] = {
- {
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_CONN_LIST |
- AC_WCAP_STEREO),
- },{
- .id = AC_PAR_PIN_CAP,
- .val = AC_PINCAP_OUT,
- },{
- .id = AC_PAR_CONNLIST_LEN,
- .val = 1,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },
-};
-
-/* common: pin widget (line-in) */
-static const desc_param common_params_audio_linein[] = {
- {
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_STEREO),
- },{
- .id = AC_PAR_PIN_CAP,
- .val = AC_PINCAP_IN,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },
-};
-
-/* output: root node */
-static const desc_param output_params_root[] = {
- {
- .id = AC_PAR_VENDOR_ID,
- .val = QEMU_HDA_ID_OUTPUT,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_OUTPUT,
- },{
- .id = AC_PAR_REV_ID,
- .val = 0x00100101,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00010001,
- },
-};
+#define PARAM mixemu
+#define HDA_MIXER
+#include "hda-codec-common.h"
-/* output: audio function */
-static const desc_param output_params_audio_func[] = {
- {
- .id = AC_PAR_FUNCTION_TYPE,
- .val = AC_GRP_AUDIO_FUNCTION,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_OUTPUT,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00020002,
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_GPIO_CAP,
- .val = 0,
- },{
- .id = AC_PAR_AUDIO_FG_CAP,
- .val = 0x00000808,
- },{
- .id = AC_PAR_POWER_STATE,
- .val = 0,
- },
-};
-
-/* output: nodes */
-static const desc_node output_nodes[] = {
- {
- .nid = AC_NODE_ROOT,
- .name = "root",
- .params = output_params_root,
- .nparams = ARRAY_SIZE(output_params_root),
- },{
- .nid = 1,
- .name = "func",
- .params = output_params_audio_func,
- .nparams = ARRAY_SIZE(output_params_audio_func),
- },{
- .nid = 2,
- .name = "dac",
- .params = common_params_audio_dac,
- .nparams = ARRAY_SIZE(common_params_audio_dac),
- .stindex = 0,
- },{
- .nid = 3,
- .name = "out",
- .params = common_params_audio_lineout,
- .nparams = ARRAY_SIZE(common_params_audio_lineout),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
- 0x10),
- .pinctl = AC_PINCTL_OUT_EN,
- .conn = (uint32_t[]) { 2 },
- }
-};
-
-/* output: codec */
-static const desc_codec output = {
- .name = "output",
- .iid = QEMU_HDA_ID_OUTPUT,
- .nodes = output_nodes,
- .nnodes = ARRAY_SIZE(output_nodes),
-};
-
-/* duplex: root node */
-static const desc_param duplex_params_root[] = {
- {
- .id = AC_PAR_VENDOR_ID,
- .val = QEMU_HDA_ID_DUPLEX,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_DUPLEX,
- },{
- .id = AC_PAR_REV_ID,
- .val = 0x00100101,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00010001,
- },
-};
-
-/* duplex: audio function */
-static const desc_param duplex_params_audio_func[] = {
- {
- .id = AC_PAR_FUNCTION_TYPE,
- .val = AC_GRP_AUDIO_FUNCTION,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_DUPLEX,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00020004,
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_GPIO_CAP,
- .val = 0,
- },{
- .id = AC_PAR_AUDIO_FG_CAP,
- .val = 0x00000808,
- },{
- .id = AC_PAR_POWER_STATE,
- .val = 0,
- },
-};
-
-/* duplex: nodes */
-static const desc_node duplex_nodes[] = {
- {
- .nid = AC_NODE_ROOT,
- .name = "root",
- .params = duplex_params_root,
- .nparams = ARRAY_SIZE(duplex_params_root),
- },{
- .nid = 1,
- .name = "func",
- .params = duplex_params_audio_func,
- .nparams = ARRAY_SIZE(duplex_params_audio_func),
- },{
- .nid = 2,
- .name = "dac",
- .params = common_params_audio_dac,
- .nparams = ARRAY_SIZE(common_params_audio_dac),
- .stindex = 0,
- },{
- .nid = 3,
- .name = "out",
- .params = common_params_audio_lineout,
- .nparams = ARRAY_SIZE(common_params_audio_lineout),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
- 0x10),
- .pinctl = AC_PINCTL_OUT_EN,
- .conn = (uint32_t[]) { 2 },
- },{
- .nid = 4,
- .name = "adc",
- .params = common_params_audio_adc,
- .nparams = ARRAY_SIZE(common_params_audio_adc),
- .stindex = 1,
- .conn = (uint32_t[]) { 5 },
- },{
- .nid = 5,
- .name = "in",
- .params = common_params_audio_linein,
- .nparams = ARRAY_SIZE(common_params_audio_linein),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
- 0x20),
- .pinctl = AC_PINCTL_IN_EN,
- }
-};
-
-/* duplex: codec */
-static const desc_codec duplex = {
- .name = "duplex",
- .iid = QEMU_HDA_ID_DUPLEX,
- .nodes = duplex_nodes,
- .nnodes = ARRAY_SIZE(duplex_nodes),
-};
-
-/* micro: root node */
-static const desc_param micro_params_root[] = {
- {
- .id = AC_PAR_VENDOR_ID,
- .val = QEMU_HDA_ID_MICRO,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_MICRO,
- },{
- .id = AC_PAR_REV_ID,
- .val = 0x00100101,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00010001,
- },
-};
-
-/* micro: audio function */
-static const desc_param micro_params_audio_func[] = {
- {
- .id = AC_PAR_FUNCTION_TYPE,
- .val = AC_GRP_AUDIO_FUNCTION,
- },{
- .id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_MICRO,
- },{
- .id = AC_PAR_NODE_COUNT,
- .val = 0x00020004,
- },{
- .id = AC_PAR_PCM,
- .val = QEMU_HDA_PCM_FORMATS,
- },{
- .id = AC_PAR_STREAM,
- .val = AC_SUPFMT_PCM,
- },{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
- },{
- .id = AC_PAR_GPIO_CAP,
- .val = 0,
- },{
- .id = AC_PAR_AUDIO_FG_CAP,
- .val = 0x00000808,
- },{
- .id = AC_PAR_POWER_STATE,
- .val = 0,
- },
-};
-
-/* micro: nodes */
-static const desc_node micro_nodes[] = {
- {
- .nid = AC_NODE_ROOT,
- .name = "root",
- .params = micro_params_root,
- .nparams = ARRAY_SIZE(micro_params_root),
- },{
- .nid = 1,
- .name = "func",
- .params = micro_params_audio_func,
- .nparams = ARRAY_SIZE(micro_params_audio_func),
- },{
- .nid = 2,
- .name = "dac",
- .params = common_params_audio_dac,
- .nparams = ARRAY_SIZE(common_params_audio_dac),
- .stindex = 0,
- },{
- .nid = 3,
- .name = "out",
- .params = common_params_audio_lineout,
- .nparams = ARRAY_SIZE(common_params_audio_lineout),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_SPEAKER << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
- 0x10),
- .pinctl = AC_PINCTL_OUT_EN,
- .conn = (uint32_t[]) { 2 },
- },{
- .nid = 4,
- .name = "adc",
- .params = common_params_audio_adc,
- .nparams = ARRAY_SIZE(common_params_audio_adc),
- .stindex = 1,
- .conn = (uint32_t[]) { 5 },
- },{
- .nid = 5,
- .name = "in",
- .params = common_params_audio_linein,
- .nparams = ARRAY_SIZE(common_params_audio_linein),
- .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT) |
- (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
- (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
- 0x20),
- .pinctl = AC_PINCTL_IN_EN,
- }
-};
-
-/* micro: codec */
-static const desc_codec micro = {
- .name = "micro",
- .iid = QEMU_HDA_ID_MICRO,
- .nodes = micro_nodes,
- .nnodes = ARRAY_SIZE(micro_nodes),
-};
+#define PARAM nomixemu
+#include "hda-codec-common.h"
/* -------------------------------------------------------------------------- */
@@ -585,6 +169,7 @@ struct HDAAudioState {
/* properties */
uint32_t debug;
+ bool mixer;
};
static void hda_audio_input_cb(void *opaque, int avail)
@@ -1006,23 +591,42 @@ static const VMStateDescription vmstate_hda_audio = {
};
static Property hda_audio_properties[] = {
- DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
+ DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
+ DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
DEFINE_PROP_END_OF_LIST(),
};
static int hda_audio_init_output(HDACodecDevice *hda)
{
- return hda_audio_init(hda, &output);
+ HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+
+ if (!a->mixer) {
+ return hda_audio_init(hda, &output_nomixemu);
+ } else {
+ return hda_audio_init(hda, &output_mixemu);
+ }
}
static int hda_audio_init_duplex(HDACodecDevice *hda)
{
- return hda_audio_init(hda, &duplex);
+ HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+
+ if (!a->mixer) {
+ return hda_audio_init(hda, &duplex_nomixemu);
+ } else {
+ return hda_audio_init(hda, &duplex_mixemu);
+ }
}
static int hda_audio_init_micro(HDACodecDevice *hda)
{
- return hda_audio_init(hda, &micro);
+ HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+
+ if (!a->mixer) {
+ return hda_audio_init(hda, &micro_nomixemu);
+ } else {
+ return hda_audio_init(hda, &micro_mixemu);
+ }
}
static void hda_audio_output_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index f8f3dbc..cbd6a00 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -22,6 +22,6 @@ common-obj-$(CONFIG_IMX) += imx_serial.o
common-obj-$(CONFIG_LM32) += lm32_juart.o
common-obj-$(CONFIG_LM32) += lm32_uart.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
-common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o
+common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o
obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
new file mode 100644
index 0000000..9339067
--- /dev/null
+++ b/hw/char/sclpconsole-lm.c
@@ -0,0 +1,398 @@
+/*
+ * SCLP event types
+ * Operations Command - Line Mode input
+ * Message - Line Mode output
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * Heinz Graalfs <graalfs@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/qdev.h"
+#include "qemu/thread.h"
+#include "qemu/error-report.h"
+#include "sysemu/char.h"
+
+#include "hw/s390x/sclp.h"
+#include "hw/s390x/event-facility.h"
+#include "hw/s390x/ebcdic.h"
+
+#define SIZE_BUFFER 4096
+#define NEWLINE "\n"
+
+typedef struct OprtnsCommand {
+ EventBufferHeader header;
+ MDMSU message_unit;
+ char data[0];
+} QEMU_PACKED OprtnsCommand;
+
+/* max size for line-mode data in 4K SCCB page */
+#define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand))
+
+typedef struct SCLPConsoleLM {
+ SCLPEvent event;
+ CharDriverState *chr;
+ bool echo; /* immediate echo of input if true */
+ uint32_t write_errors; /* errors writing to char layer */
+ uint32_t length; /* length of byte stream in buffer */
+ uint8_t buf[SIZE_CONSOLE_BUFFER];
+ qemu_irq irq_console_read;
+} SCLPConsoleLM;
+
+/*
+* Character layer call-back functions
+ *
+ * Allow 1 character at a time
+ *
+ * Accumulate bytes from character layer in console buffer,
+ * event_pending is set when a newline character is encountered
+ *
+ * The maximum command line length is limited by the maximum
+ * space available in an SCCB
+ */
+
+static int chr_can_read(void *opaque)
+{
+ SCLPConsoleLM *scon = opaque;
+
+ if (scon->event.event_pending) {
+ return 0;
+ } else if (SIZE_CONSOLE_BUFFER - scon->length) {
+ return 1;
+ }
+ return 0;
+}
+
+static void receive_from_chr_layer(SCLPConsoleLM *scon, const uint8_t *buf,
+ int size)
+{
+ assert(size == 1);
+
+ if (*buf == '\r' || *buf == '\n') {
+ scon->event.event_pending = true;
+ return;
+ }
+ scon->buf[scon->length] = *buf;
+ scon->length += 1;
+ if (scon->echo) {
+ qemu_chr_fe_write(scon->chr, buf, size);
+ }
+}
+
+/*
+ * Send data from a char device over to the guest
+ */
+static void chr_read(void *opaque, const uint8_t *buf, int size)
+{
+ SCLPConsoleLM *scon = opaque;
+
+ receive_from_chr_layer(scon, buf, size);
+ if (scon->event.event_pending) {
+ /* trigger SCLP read operation */
+ qemu_irq_raise(scon->irq_console_read);
+ }
+}
+
+/* functions to be called by event facility */
+
+static bool can_handle_event(uint8_t type)
+{
+ return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD;
+}
+
+static unsigned int send_mask(void)
+{
+ return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD;
+}
+
+static unsigned int receive_mask(void)
+{
+ return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD;
+}
+
+/*
+ * Triggered by SCLP's read_event_data
+ * - convert ASCII byte stream to EBCDIC and
+ * - copy converted data into provided (SCLP) buffer
+ */
+static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
+ int avail)
+{
+ int len;
+
+ SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ len = cons->length;
+ /* data need to fit into provided SCLP buffer */
+ if (len > avail) {
+ return 1;
+ }
+
+ ebcdic_put(buf, (char *)&cons->buf, len);
+ *size = len;
+ cons->length = 0;
+ /* data provided and no more data pending */
+ event->event_pending = false;
+ return 0;
+}
+
+static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+ int *slen)
+{
+ int avail, rc;
+ size_t src_len;
+ uint8_t *to;
+ OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr;
+
+ if (!event->event_pending) {
+ /* no data pending */
+ return 0;
+ }
+
+ to = (uint8_t *)&oc->data;
+ avail = *slen - sizeof(OprtnsCommand);
+ rc = get_console_data(event, to, &src_len, avail);
+ if (rc) {
+ /* data didn't fit, try next SCCB */
+ return 1;
+ }
+
+ oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU;
+ oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU));
+
+ oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU;
+ oc->message_unit.cpmsu.length =
+ cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector));
+
+ oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD;
+ oc->message_unit.text_command.length =
+ cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector)));
+
+ oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG;
+ oc->message_unit.self_def_text_message.length =
+ cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector)));
+
+ oc->message_unit.text_message.key = GDS_KEY_TEXTMSG;
+ oc->message_unit.text_message.length =
+ cpu_to_be16(sizeof(GdsSubvector) + src_len);
+
+ oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len);
+ oc->header.type = SCLP_EVENT_OPRTNS_COMMAND;
+ *slen = avail - src_len;
+
+ return 1;
+}
+
+/*
+ * Triggered by SCLP's write_event_data
+ * - write console data to character layer
+ * returns < 0 if an error occurred
+ */
+static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
+{
+ int ret = 0;
+ const uint8_t *buf_offset;
+
+ SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ if (!scon->chr) {
+ /* If there's no backend, we can just say we consumed all data. */
+ return len;
+ }
+
+ buf_offset = buf;
+ while (len > 0) {
+ ret = qemu_chr_fe_write(scon->chr, buf, len);
+ if (ret == 0) {
+ /* a pty doesn't seem to be connected - no error */
+ len = 0;
+ } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
+ len -= ret;
+ buf_offset += ret;
+ } else {
+ len = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int process_mdb(SCLPEvent *event, MDBO *mdbo)
+{
+ int rc;
+ int len;
+ uint8_t buffer[SIZE_BUFFER];
+
+ len = be16_to_cpu(mdbo->length);
+ len -= sizeof(mdbo->length) + sizeof(mdbo->type)
+ + sizeof(mdbo->mto.line_type_flags)
+ + sizeof(mdbo->mto.alarm_control)
+ + sizeof(mdbo->mto._reserved);
+
+ assert(len <= SIZE_BUFFER);
+
+ /* convert EBCDIC SCLP contents to ASCII console message */
+ ascii_put(buffer, mdbo->mto.message, len);
+ rc = write_console_data(event, (uint8_t *)NEWLINE, 1);
+ if (rc < 0) {
+ return rc;
+ }
+ return write_console_data(event, buffer, len);
+}
+
+static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
+{
+ int len;
+ int written;
+ int errors = 0;
+ MDBO *mdbo;
+ SclpMsg *data = (SclpMsg *) ebh;
+ SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ len = be16_to_cpu(data->mdb.header.length);
+ if (len < sizeof(data->mdb.header)) {
+ return SCLP_RC_INCONSISTENT_LENGTHS;
+ }
+ len -= sizeof(data->mdb.header);
+
+ /* first check message buffers */
+ mdbo = data->mdb.mdbo;
+ while (len > 0) {
+ if (be16_to_cpu(mdbo->length) > len
+ || be16_to_cpu(mdbo->length) == 0) {
+ return SCLP_RC_INCONSISTENT_LENGTHS;
+ }
+ len -= be16_to_cpu(mdbo->length);
+ mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
+ }
+
+ /* then execute */
+ len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header);
+ mdbo = data->mdb.mdbo;
+ while (len > 0) {
+ switch (be16_to_cpu(mdbo->type)) {
+ case MESSAGE_TEXT:
+ /* message text object */
+ written = process_mdb(event, mdbo);
+ if (written < 0) {
+ /* character layer error */
+ errors++;
+ }
+ break;
+ default: /* ignore */
+ break;
+ }
+ len -= be16_to_cpu(mdbo->length);
+ mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
+ }
+ if (errors) {
+ scon->write_errors += errors;
+ }
+ data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED;
+
+ return SCLP_RC_NORMAL_COMPLETION;
+}
+
+static void trigger_console_data(void *opaque, int n, int level)
+{
+ sclp_service_interrupt(0);
+}
+
+/* functions for live migration */
+
+static const VMStateDescription vmstate_sclplmconsole = {
+ .name = "sclplmconsole",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(event.event_pending, SCLPConsoleLM),
+ VMSTATE_UINT32(write_errors, SCLPConsoleLM),
+ VMSTATE_UINT32(length, SCLPConsoleLM),
+ VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+/* qemu object creation and initialization functions */
+
+/* tell character layer our call-back functions */
+
+static int console_init(SCLPEvent *event)
+{
+ static bool console_available;
+
+ SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ if (console_available) {
+ error_report("Multiple line-mode operator consoles are not supported");
+ return -1;
+ }
+ console_available = true;
+
+ if (scon->chr) {
+ qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon);
+ }
+ scon->irq_console_read = *qemu_allocate_irqs(trigger_console_data, NULL, 1);
+
+ return 0;
+}
+
+static int console_exit(SCLPEvent *event)
+{
+ return 0;
+}
+
+static void console_reset(DeviceState *dev)
+{
+ SCLPEvent *event = SCLP_EVENT(dev);
+ SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ event->event_pending = false;
+ scon->length = 0;
+ scon->write_errors = 0;
+}
+
+static Property console_properties[] = {
+ DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr),
+ DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0),
+ DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void console_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
+
+ dc->props = console_properties;
+ dc->reset = console_reset;
+ dc->vmsd = &vmstate_sclplmconsole;
+ ec->init = console_init;
+ ec->exit = console_exit;
+ ec->get_send_mask = send_mask;
+ ec->get_receive_mask = receive_mask;
+ ec->can_handle_event = can_handle_event;
+ ec->read_event_data = read_event_data;
+ ec->write_event_data = write_event_data;
+}
+
+static const TypeInfo sclp_console_info = {
+ .name = "sclplmconsole",
+ .parent = TYPE_SCLP_EVENT,
+ .instance_size = sizeof(SCLPConsoleLM),
+ .class_init = console_class_init,
+ .class_size = sizeof(SCLPEventClass),
+};
+
+static void register_types(void)
+{
+ type_register_static(&sclp_console_info);
+}
+
+type_init(register_types)
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index eb3988c..16d77c5 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -31,12 +31,11 @@ typedef struct ASCIIConsoleData {
typedef struct SCLPConsole {
SCLPEvent event;
CharDriverState *chr;
- /* io vector */
- uint8_t *iov; /* iov buffer pointer */
- uint8_t *iov_sclp; /* pointer to SCLP read offset */
- uint8_t *iov_bs; /* pointer byte stream read offset */
- uint32_t iov_data_len; /* length of byte stream in buffer */
- uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
+ uint8_t iov[SIZE_BUFFER_VT220];
+ uint32_t iov_sclp; /* offset in buf for SCLP read operation */
+ uint32_t iov_bs; /* offset in buf for char layer read operation */
+ uint32_t iov_data_len; /* length of byte stream in buffer */
+ uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
qemu_irq irq_read_vt220;
} SCLPConsole;
@@ -47,7 +46,7 @@ static int chr_can_read(void *opaque)
{
SCLPConsole *scon = opaque;
- return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0;
+ return SIZE_BUFFER_VT220 - scon->iov_data_len;
}
/* Receive n bytes from character layer, save in iov buffer,
@@ -55,13 +54,11 @@ static int chr_can_read(void *opaque)
static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
int size)
{
- assert(scon->iov);
-
/* read data must fit into current buffer */
assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
/* put byte-stream from character layer into buffer */
- memcpy(scon->iov_bs, buf, size);
+ memcpy(&scon->iov[scon->iov_bs], buf, size);
scon->iov_data_len += size;
scon->iov_sclp_rest += size;
scon->iov_bs += size;
@@ -80,34 +77,11 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
qemu_irq_raise(scon->irq_read_vt220);
}
-static void chr_event(void *opaque, int event)
-{
- SCLPConsole *scon = opaque;
-
- switch (event) {
- case CHR_EVENT_OPENED:
- if (!scon->iov) {
- scon->iov = g_malloc0(SIZE_BUFFER_VT220);
- scon->iov_sclp = scon->iov;
- scon->iov_bs = scon->iov;
- scon->iov_data_len = 0;
- scon->iov_sclp_rest = 0;
- }
- break;
- case CHR_EVENT_CLOSED:
- if (scon->iov) {
- g_free(scon->iov);
- scon->iov = NULL;
- }
- break;
- }
-}
-
/* functions to be called by event facility */
-static int event_type(void)
+static bool can_handle_event(uint8_t type)
{
- return SCLP_EVENT_ASCII_CONSOLE_DATA;
+ return type == SCLP_EVENT_ASCII_CONSOLE_DATA;
}
static unsigned int send_mask(void)
@@ -134,17 +108,17 @@ static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
/* if all data fit into provided SCLP buffer */
if (avail >= cons->iov_sclp_rest) {
/* copy character byte-stream to SCLP buffer */
- memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
+ memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest);
*size = cons->iov_sclp_rest + 1;
- cons->iov_sclp = cons->iov;
- cons->iov_bs = cons->iov;
+ cons->iov_sclp = 0;
+ cons->iov_bs = 0;
cons->iov_data_len = 0;
cons->iov_sclp_rest = 0;
event->event_pending = false;
/* data provided and no more data pending */
} else {
/* if provided buffer is too small, just copy part */
- memcpy(buf, cons->iov_sclp, avail);
+ memcpy(buf, &cons->iov[cons->iov_sclp], avail);
*size = avail + 1;
cons->iov_sclp_rest -= avail;
cons->iov_sclp += avail;
@@ -223,9 +197,26 @@ static void trigger_ascii_console_data(void *opaque, int n, int level)
sclp_service_interrupt(0);
}
+static const VMStateDescription vmstate_sclpconsole = {
+ .name = "sclpconsole",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(event.event_pending, SCLPConsole),
+ VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
+ VMSTATE_UINT32(iov_sclp, SCLPConsole),
+ VMSTATE_UINT32(iov_bs, SCLPConsole),
+ VMSTATE_UINT32(iov_data_len, SCLPConsole),
+ VMSTATE_UINT32(iov_sclp_rest, SCLPConsole),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
/* qemu object creation and initialization functions */
/* tell character layer our call-back functions */
+
static int console_init(SCLPEvent *event)
{
static bool console_available;
@@ -237,10 +228,9 @@ static int console_init(SCLPEvent *event)
return -1;
}
console_available = true;
- event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
if (scon->chr) {
qemu_chr_add_handlers(scon->chr, chr_can_read,
- chr_read, chr_event, scon);
+ chr_read, NULL, scon);
}
scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
NULL, 1);
@@ -248,6 +238,18 @@ static int console_init(SCLPEvent *event)
return 0;
}
+static void console_reset(DeviceState *dev)
+{
+ SCLPEvent *event = SCLP_EVENT(dev);
+ SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+ event->event_pending = false;
+ scon->iov_sclp = 0;
+ scon->iov_bs = 0;
+ scon->iov_data_len = 0;
+ scon->iov_sclp_rest = 0;
+}
+
static int console_exit(SCLPEvent *event)
{
return 0;
@@ -264,11 +266,13 @@ static void console_class_init(ObjectClass *klass, void *data)
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
dc->props = console_properties;
+ dc->reset = console_reset;
+ dc->vmsd = &vmstate_sclpconsole;
ec->init = console_init;
ec->exit = console_exit;
ec->get_send_mask = send_mask;
ec->get_receive_mask = receive_mask;
- ec->event_type = event_type;
+ ec->can_handle_event = can_handle_event;
ec->read_event_data = read_event_data;
ec->write_event_data = write_event_data;
}
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 907792b..c6042c7 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -741,6 +741,7 @@ static QEMUMachine xenfv_machine = {
.init = pc_xen_hvm_init,
.max_cpus = HVM_MAX_VCPUS,
.default_machine_opts = "accel=xen",
+ .hot_add_cpu = pc_hot_add_cpu,
};
#endif
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index a3aceef..25951a0 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -120,7 +120,7 @@ static uint16_t handle_write_event_buf(SCLPEventFacility *ef,
ec = SCLP_EVENT_GET_CLASS(event);
if (ec->write_event_data &&
- ec->event_type() == event_buf->type) {
+ ec->can_handle_event(event_buf->type)) {
rc = ec->write_event_data(event, event_buf);
break;
}
@@ -183,7 +183,7 @@ static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb,
{
uint16_t rc;
int slen;
- unsigned elen = 0;
+ unsigned elen;
BusChild *kid;
SCLPEvent *event;
SCLPEventClass *ec;
@@ -203,11 +203,11 @@ static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb,
if (mask & ec->get_send_mask()) {
if (ec->read_event_data(event, event_buf, &slen)) {
+ elen = be16_to_cpu(event_buf->length);
+ event_buf = (EventBufferHeader *) ((char *)event_buf + elen);
rc = SCLP_RC_NORMAL_COMPLETION;
}
}
- elen = be16_to_cpu(event_buf->length);
- event_buf = (void *) event_buf + elen;
}
if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
@@ -338,10 +338,19 @@ static int init_event_facility(S390SCLPDevice *sdev)
return 0;
}
+static void reset_event_facility(DeviceState *dev)
+{
+ S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev);
+
+ sdev->ef->receive_mask = 0;
+}
+
static void init_event_facility_class(ObjectClass *klass, void *data)
{
+ DeviceClass *dc = DEVICE_CLASS(klass);
S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
+ dc->reset = reset_event_facility;
k->init = init_event_facility;
}
diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c
index 5fadc86..a3c4bd6 100644
--- a/hw/s390x/sclpquiesce.c
+++ b/hw/s390x/sclpquiesce.c
@@ -22,9 +22,9 @@ typedef struct SignalQuiesce {
uint8_t unit;
} QEMU_PACKED SignalQuiesce;
-static int event_type(void)
+static bool can_handle_event(uint8_t type)
{
- return SCLP_EVENT_SIGNAL_QUIESCE;
+ return type == SCLP_EVENT_SIGNAL_QUIESCE;
}
static unsigned int send_mask(void)
@@ -65,6 +65,17 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
return 1;
}
+static const VMStateDescription vmstate_sclpquiesce = {
+ .name = "sclpquiesce",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(event_pending, SCLPEvent),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
typedef struct QuiesceNotifier QuiesceNotifier;
static struct QuiesceNotifier {
@@ -84,8 +95,6 @@ static void quiesce_powerdown_req(Notifier *n, void *opaque)
static int quiesce_init(SCLPEvent *event)
{
- event->event_type = SCLP_EVENT_SIGNAL_QUIESCE;
-
qn.notifier.notify = quiesce_powerdown_req;
qn.event = event;
@@ -94,15 +103,25 @@ static int quiesce_init(SCLPEvent *event)
return 0;
}
+static void quiesce_reset(DeviceState *dev)
+{
+ SCLPEvent *event = SCLP_EVENT(dev);
+
+ event->event_pending = false;
+}
+
static void quiesce_class_init(ObjectClass *klass, void *data)
{
+ DeviceClass *dc = DEVICE_CLASS(klass);
SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
+ dc->reset = quiesce_reset;
+ dc->vmsd = &vmstate_sclpquiesce;
k->init = quiesce_init;
k->get_send_mask = send_mask;
k->get_receive_mask = receive_mask;
- k->event_type = event_type;
+ k->can_handle_event = can_handle_event;
k->read_event_data = read_event_data;
k->write_event_data = NULL;
}
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 77242e2..dc27f33 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -324,9 +324,7 @@ extern uintptr_t tci_tb_ptr;
In some implementations, we pass the "logical" return address manually;
in others, we must infer the logical return from the true return. */
#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
-# if defined (_ARCH_PPC) && !defined (_ARCH_PPC64)
-# define GETRA_LDST(RA) (*(int32_t *)((RA) - 4))
-# elif defined(__arm__)
+# if defined(__arm__)
/* We define two insns between the return address and the branch back to
straight-line. Find and decode that branch insn. */
# define GETRA_LDST(RA) tcg_getra_ldst(RA)
diff --git a/include/hw/s390x/ebcdic.h b/include/hw/s390x/ebcdic.h
new file mode 100644
index 0000000..1d6fde9
--- /dev/null
+++ b/include/hw/s390x/ebcdic.h
@@ -0,0 +1,104 @@
+/*
+ * EBCDIC/ASCII conversion Support
+ *
+ * Copyright (c) 2011 Alexander Graf
+ * Copyright IBM, Corp. 2013
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef EBCDIC_H_
+#define EBCDIC_H_
+
+/* EBCDIC handling */
+static const uint8_t ebcdic2ascii[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
+};
+
+static const uint8_t ascii2ebcdic[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
+ }
+}
+
+static inline void ascii_put(uint8_t *p, const char *ebcdic, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ p[i] = ebcdic2ascii[(uint8_t)ebcdic[i]];
+ }
+}
+
+#endif /* EBCDIC_H_ */
diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h
index 791ab2a..7ce7079 100644
--- a/include/hw/s390x/event-facility.h
+++ b/include/hw/s390x/event-facility.h
@@ -19,12 +19,18 @@
#include "qemu/thread.h"
/* SCLP event types */
+#define SCLP_EVENT_OPRTNS_COMMAND 0x01
+#define SCLP_EVENT_MESSAGE 0x02
+#define SCLP_EVENT_PMSGCMD 0x09
#define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a
#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d
/* SCLP event masks */
#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008
#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040
+#define SCLP_EVENT_MASK_OP_CMD 0x80000000
+#define SCLP_EVENT_MASK_MSG 0x40000000
+#define SCLP_EVENT_MASK_PMSGCMD 0x00800000
#define SCLP_UNCONDITIONAL_READ 0x00
#define SCLP_SELECTIVE_READ 0x01
@@ -43,8 +49,8 @@ typedef struct WriteEventMask {
uint16_t mask_length;
uint32_t cp_receive_mask;
uint32_t cp_send_mask;
- uint32_t send_mask;
uint32_t receive_mask;
+ uint32_t send_mask;
} QEMU_PACKED WriteEventMask;
typedef struct EventBufferHeader {
@@ -54,6 +60,80 @@ typedef struct EventBufferHeader {
uint16_t _reserved;
} QEMU_PACKED EventBufferHeader;
+typedef struct MdbHeader {
+ uint16_t length;
+ uint16_t type;
+ uint32_t tag;
+ uint32_t revision_code;
+} QEMU_PACKED MdbHeader;
+
+typedef struct MTO {
+ uint16_t line_type_flags;
+ uint8_t alarm_control;
+ uint8_t _reserved[3];
+ char message[];
+} QEMU_PACKED MTO;
+
+typedef struct GO {
+ uint32_t domid;
+ uint8_t hhmmss_time[8];
+ uint8_t th_time[3];
+ uint8_t _reserved_0;
+ uint8_t dddyyyy_date[7];
+ uint8_t _reserved_1;
+ uint16_t general_msg_flags;
+ uint8_t _reserved_2[10];
+ uint8_t originating_system_name[8];
+ uint8_t job_guest_name[8];
+} QEMU_PACKED GO;
+
+#define MESSAGE_TEXT 0x0004
+
+typedef struct MDBO {
+ uint16_t length;
+ uint16_t type;
+ union {
+ GO go;
+ MTO mto;
+ };
+} QEMU_PACKED MDBO;
+
+typedef struct MDB {
+ MdbHeader header;
+ MDBO mdbo[0];
+} QEMU_PACKED MDB;
+
+typedef struct SclpMsg {
+ EventBufferHeader header;
+ MDB mdb;
+} QEMU_PACKED SclpMsg;
+
+#define GDS_ID_MDSMU 0x1310
+#define GDS_ID_CPMSU 0x1212
+#define GDS_ID_TEXTCMD 0x1320
+
+typedef struct GdsVector {
+ uint16_t length;
+ uint16_t gds_id;
+} QEMU_PACKED GdsVector;
+
+#define GDS_KEY_SELFDEFTEXTMSG 0x31
+#define GDS_KEY_TEXTMSG 0x30
+
+typedef struct GdsSubvector {
+ uint8_t length;
+ uint8_t key;
+} QEMU_PACKED GdsSubvector;
+
+/* MDS Message Unit */
+typedef struct MDMSU {
+ GdsVector mdmsu;
+ GdsVector cpmsu;
+ GdsVector text_command;
+ GdsSubvector self_def_text_message;
+ GdsSubvector text_message;
+} QEMU_PACKED MDMSU;
+
typedef struct WriteEventData {
SCCBHeader h;
EventBufferHeader ebh;
@@ -68,7 +148,6 @@ typedef struct ReadEventData {
typedef struct SCLPEvent {
DeviceState qdev;
bool event_pending;
- uint32_t event_type;
char *name;
} SCLPEvent;
@@ -88,9 +167,8 @@ typedef struct SCLPEventClass {
int (*write_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr);
- /* returns the supported event type */
- int (*event_type)(void);
-
+ /* can we handle this event type? */
+ bool (*can_handle_event)(uint8_t type);
} SCLPEventClass;
#endif
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1c31b5d..9d09e60 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -310,8 +310,18 @@ extern const VMStateInfo vmstate_info_bitmap;
.offset = vmstate_offset_value(_state, _field, _type), \
}
-#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) { \
+#define VMSTATE_STRUCT_POINTER_V(_field, _state, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_POINTER, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_POINTER_TEST_V(_field, _state, _test, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
.field_exists = (_test), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
@@ -497,7 +507,10 @@ extern const VMStateInfo vmstate_info_bitmap;
VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \
- VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type)
+ VMSTATE_STRUCT_POINTER_V(_field, _state, 0, _vmsd, _type)
+
+#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) \
+ VMSTATE_STRUCT_POINTER_TEST_V(_field, _state, _test, 0, _vmsd, _type)
#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, \
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index e2c6f58..ffc53aa 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -41,9 +41,11 @@ int vm_stop(RunState state);
int vm_stop_force_state(RunState state);
typedef enum WakeupReason {
- QEMU_WAKEUP_REASON_OTHER = 0,
+ /* Always keep QEMU_WAKEUP_REASON_NONE = 0 */
+ QEMU_WAKEUP_REASON_NONE = 0,
QEMU_WAKEUP_REASON_RTC,
QEMU_WAKEUP_REASON_PMTIMER,
+ QEMU_WAKEUP_REASON_OTHER,
} WakeupReason;
void qemu_system_reset_request(void);
diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h
index ac2b6e2..d52d76e 100644
--- a/linux-user/alpha/syscall_nr.h
+++ b/linux-user/alpha/syscall_nr.h
@@ -20,7 +20,7 @@
#define TARGET_NR_lseek 19
#define TARGET_NR_getxpid 20
#define TARGET_NR_osf_mount 21
-#define TARGET_NR_umount 22
+#define TARGET_NR_umount2 22
#define TARGET_NR_setuid 23
#define TARGET_NR_getxuid 24
#define TARGET_NR_exec_with_loader 25 /* not implemented */
@@ -255,7 +255,7 @@
#define TARGET_NR_sysinfo 318
#define TARGET_NR__sysctl 319
/* 320 was sys_idle. */
-#define TARGET_NR_oldumount 321
+#define TARGET_NR_umount 321
#define TARGET_NR_swapon 322
#define TARGET_NR_times 323
#define TARGET_NR_personality 324
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 439c2a9..7381012 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -20,6 +20,7 @@
IOCTL(TIOCSCTTY, 0, TYPE_INT)
IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+ IOCTL(TIOCGSID, IOC_W, MK_PTR(TYPE_INT))
IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_INT))
IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 5cd6d91..a1fe5ed 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -131,7 +131,7 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
return sp;
}
-int loader_exec(const char * filename, char ** argv, char ** envp,
+int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
struct target_pt_regs * regs, struct image_info *infop,
struct linux_binprm *bprm)
{
@@ -140,11 +140,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
memset(bprm->page, 0, sizeof(bprm->page));
- retval = open(filename, O_RDONLY);
- if (retval < 0) {
- return -errno;
- }
- bprm->fd = retval;
+ bprm->fd = fdexec;
bprm->filename = (char *)filename;
bprm->argc = count(argv);
bprm->argv = argv;
diff --git a/linux-user/main.c b/linux-user/main.c
index 01e3cd4..1561950 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1861,7 +1861,7 @@ static const uint8_t mips_syscall_args[] = {
MIPS_SYS(sys_lseek , 3)
MIPS_SYS(sys_getpid , 0) /* 4020 */
MIPS_SYS(sys_mount , 5)
- MIPS_SYS(sys_oldumount , 1)
+ MIPS_SYS(sys_umount , 1)
MIPS_SYS(sys_setuid , 1)
MIPS_SYS(sys_getuid , 0)
MIPS_SYS(sys_stime , 1) /* 4025 */
@@ -1891,7 +1891,7 @@ static const uint8_t mips_syscall_args[] = {
MIPS_SYS(sys_geteuid , 0)
MIPS_SYS(sys_getegid , 0) /* 4050 */
MIPS_SYS(sys_acct , 0)
- MIPS_SYS(sys_umount , 2)
+ MIPS_SYS(sys_umount2 , 2)
MIPS_SYS(sys_ni_syscall , 0)
MIPS_SYS(sys_ioctl , 3)
MIPS_SYS(sys_fcntl , 3) /* 4055 */
@@ -2400,12 +2400,31 @@ done_syscall:
if (env->hflags & MIPS_HFLAG_M16) {
if (env->insn_flags & ASE_MICROMIPS) {
/* microMIPS mode */
- abi_ulong instr[2];
-
- ret = get_user_u16(instr[0], env->active_tc.PC) ||
- get_user_u16(instr[1], env->active_tc.PC + 2);
+ ret = get_user_u16(trap_instr, env->active_tc.PC);
+ if (ret != 0) {
+ goto error;
+ }
- trap_instr = (instr[0] << 16) | instr[1];
+ if ((trap_instr >> 10) == 0x11) {
+ /* 16-bit instruction */
+ code = trap_instr & 0xf;
+ } else {
+ /* 32-bit instruction */
+ abi_ulong instr_lo;
+
+ ret = get_user_u16(instr_lo,
+ env->active_tc.PC + 2);
+ if (ret != 0) {
+ goto error;
+ }
+ trap_instr = (trap_instr << 16) | instr_lo;
+ code = ((trap_instr >> 6) & ((1 << 20) - 1));
+ /* Unfortunately, microMIPS also suffers from
+ the old assembler bug... */
+ if (code >= (1 << 10)) {
+ code >>= 10;
+ }
+ }
} else {
/* MIPS16e mode */
ret = get_user_u16(trap_instr, env->active_tc.PC);
@@ -2413,26 +2432,21 @@ done_syscall:
goto error;
}
code = (trap_instr >> 6) & 0x3f;
- if (do_break(env, &info, code) != 0) {
- goto error;
- }
- break;
}
} else {
ret = get_user_ual(trap_instr, env->active_tc.PC);
- }
-
- if (ret != 0) {
- goto error;
- }
+ if (ret != 0) {
+ goto error;
+ }
- /* As described in the original Linux kernel code, the
- * below checks on 'code' are to work around an old
- * assembly bug.
- */
- code = ((trap_instr >> 6) & ((1 << 20) - 1));
- if (code >= (1 << 10)) {
- code >>= 10;
+ /* As described in the original Linux kernel code, the
+ * below checks on 'code' are to work around an old
+ * assembly bug.
+ */
+ code = ((trap_instr >> 6) & ((1 << 20) - 1));
+ if (code >= (1 << 10)) {
+ code >>= 10;
+ }
}
if (do_break(env, &info, code) != 0) {
@@ -3618,6 +3632,26 @@ static int parse_args(int argc, char **argv)
return optind;
}
+static int get_execfd(char **envp)
+{
+ typedef struct {
+ long a_type;
+ long a_val;
+ } auxv_t;
+ auxv_t *auxv;
+
+ while (*envp++ != NULL) {
+ ;
+ }
+
+ for (auxv = (auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
+ if (auxv->a_type == AT_EXECFD) {
+ return auxv->a_val;
+ }
+ }
+ return -1;
+}
+
int main(int argc, char **argv, char **envp)
{
struct target_pt_regs regs1, *regs = &regs1;
@@ -3632,6 +3666,7 @@ int main(int argc, char **argv, char **envp)
int target_argc;
int i;
int ret;
+ int execfd;
module_call_init(MODULE_INIT_QOM);
@@ -3809,7 +3844,16 @@ int main(int argc, char **argv, char **envp)
env->opaque = ts;
task_settid(ts);
- ret = loader_exec(filename, target_argv, target_environ, regs,
+ execfd = get_execfd(envp);
+ if (execfd < 0) {
+ execfd = open(filename, O_RDONLY);
+ }
+ if (execfd < 0) {
+ printf("Error while loading %s: %s\n", filename, strerror(-execfd));
+ _exit(1);
+ }
+
+ ret = loader_exec(execfd, filename, target_argv, target_environ, regs,
info, &bprm);
if (ret != 0) {
printf("Error while loading %s: %s\n", filename, strerror(-ret));
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 617cac1..da64e87 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -174,7 +174,7 @@ struct linux_binprm {
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr);
-int loader_exec(const char * filename, char ** argv, char ** envp,
+int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
struct target_pt_regs * regs, struct image_info *infop,
struct linux_binprm *);
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 08f115d..cf5841a 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -612,9 +612,6 @@
#ifdef TARGET_NR_oldstat
{ TARGET_NR_oldstat, "oldstat" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_oldumount
-{ TARGET_NR_oldumount, "oldumount" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_olduname
{ TARGET_NR_olduname, "olduname" , NULL, NULL, NULL },
#endif
@@ -1524,3 +1521,9 @@
#ifdef TARGET_NR_pipe2
{ TARGET_NR_pipe2, "pipe2", NULL, NULL, NULL },
#endif
+#ifdef TARGET_NR_atomic_cmpxchg_32
+{ TARGET_NR_atomic_cmpxchg_32, "atomic_cmpxchg_32", NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_atomic_barrier
+{ TARGET_NR_atomic_barrier, "atomic_barrier", NULL, NULL, NULL },
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c62d875..4a14a43 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -106,6 +106,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <linux/dm-ioctl.h>
#include <linux/reboot.h>
#include <linux/route.h>
+#include <linux/filter.h>
#include "linux_loop.h"
#include "cpu-uname.h"
@@ -1149,11 +1150,15 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
break;
}
- cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+ if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
+ cmsg->cmsg_level = SOL_SOCKET;
+ } else {
+ cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+ }
cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
cmsg->cmsg_len = CMSG_LEN(len);
- if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(data, target_data, len);
} else {
@@ -1204,11 +1209,15 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
break;
}
- target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+ if (cmsg->cmsg_level == SOL_SOCKET) {
+ target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
+ } else {
+ target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+ }
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
- if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+ if ((cmsg->cmsg_level == SOL_SOCKET) &&
(cmsg->cmsg_type == SCM_RIGHTS)) {
int *fd = (int *)data;
int *target_fd = (int *)target_data;
@@ -1216,7 +1225,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
for (i = 0; i < numfds; i++)
target_fd[i] = tswap32(fd[i]);
- } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+ } else if ((cmsg->cmsg_level == SOL_SOCKET) &&
(cmsg->cmsg_type == SO_TIMESTAMP) &&
(len == sizeof(struct timeval))) {
/* copy struct timeval to target */
@@ -1314,6 +1323,26 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
goto unimplemented;
}
break;
+ case SOL_IPV6:
+ switch (optname) {
+ case IPV6_MTU_DISCOVER:
+ case IPV6_MTU:
+ case IPV6_V6ONLY:
+ case IPV6_RECVPKTINFO:
+ val = 0;
+ if (optlen < sizeof(uint32_t)) {
+ return -TARGET_EINVAL;
+ }
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, level, optname,
+ &val, sizeof(val)));
+ break;
+ default:
+ goto unimplemented;
+ }
+ break;
case SOL_RAW:
switch (optname) {
case ICMP_FILTER:
@@ -1357,6 +1386,49 @@ set_timeout:
case TARGET_SO_SNDTIMEO:
optname = SO_SNDTIMEO;
goto set_timeout;
+ case TARGET_SO_ATTACH_FILTER:
+ {
+ struct target_sock_fprog *tfprog;
+ struct target_sock_filter *tfilter;
+ struct sock_fprog fprog;
+ struct sock_filter *filter;
+ int i;
+
+ if (optlen != sizeof(*tfprog)) {
+ return -TARGET_EINVAL;
+ }
+ if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+ if (!lock_user_struct(VERIFY_READ, tfilter,
+ tswapal(tfprog->filter), 0)) {
+ unlock_user_struct(tfprog, optval_addr, 1);
+ return -TARGET_EFAULT;
+ }
+
+ fprog.len = tswap16(tfprog->len);
+ filter = malloc(fprog.len * sizeof(*filter));
+ if (filter == NULL) {
+ unlock_user_struct(tfilter, tfprog->filter, 1);
+ unlock_user_struct(tfprog, optval_addr, 1);
+ return -TARGET_ENOMEM;
+ }
+ for (i = 0; i < fprog.len; i++) {
+ filter[i].code = tswap16(tfilter[i].code);
+ filter[i].jt = tfilter[i].jt;
+ filter[i].jf = tfilter[i].jf;
+ filter[i].k = tswap32(tfilter[i].k);
+ }
+ fprog.filter = filter;
+
+ ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
+ SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
+ free(filter);
+
+ unlock_user_struct(tfilter, tfprog->filter, 1);
+ unlock_user_struct(tfprog, optval_addr, 1);
+ return ret;
+ }
/* Options with 'int' argument. */
case TARGET_SO_DEBUG:
optname = SO_DEBUG;
@@ -1701,7 +1773,7 @@ static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
free(vec);
}
-static inline void target_to_host_sock_type(int *type)
+static inline int target_to_host_sock_type(int *type)
{
int host_type = 0;
int target_type = *type;
@@ -1718,22 +1790,56 @@ static inline void target_to_host_sock_type(int *type)
break;
}
if (target_type & TARGET_SOCK_CLOEXEC) {
+#if defined(SOCK_CLOEXEC)
host_type |= SOCK_CLOEXEC;
+#else
+ return -TARGET_EINVAL;
+#endif
}
if (target_type & TARGET_SOCK_NONBLOCK) {
+#if defined(SOCK_NONBLOCK)
host_type |= SOCK_NONBLOCK;
+#elif !defined(O_NONBLOCK)
+ return -TARGET_EINVAL;
+#endif
}
*type = host_type;
+ return 0;
+}
+
+/* Try to emulate socket type flags after socket creation. */
+static int sock_flags_fixup(int fd, int target_type)
+{
+#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
+ if (target_type & TARGET_SOCK_NONBLOCK) {
+ int flags = fcntl(fd, F_GETFL);
+ if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
+ close(fd);
+ return -TARGET_EINVAL;
+ }
+ }
+#endif
+ return fd;
}
/* do_socket() Must return target values and target errnos. */
static abi_long do_socket(int domain, int type, int protocol)
{
- target_to_host_sock_type(&type);
+ int target_type = type;
+ int ret;
+
+ ret = target_to_host_sock_type(&type);
+ if (ret) {
+ return ret;
+ }
if (domain == PF_NETLINK)
return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
- return get_errno(socket(domain, type, protocol));
+ ret = get_errno(socket(domain, type, protocol));
+ if (ret >= 0) {
+ ret = sock_flags_fixup(ret, target_type);
+ }
+ return ret;
}
/* do_bind() Must return target values and target errnos. */
@@ -5071,22 +5177,70 @@ static int is_proc_myself(const char *filename, const char *entry)
return 0;
}
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+static int is_proc(const char *filename, const char *entry)
+{
+ return strcmp(filename, entry) == 0;
+}
+
+static int open_net_route(void *cpu_env, int fd)
+{
+ FILE *fp;
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read;
+
+ fp = fopen("/proc/net/route", "r");
+ if (fp == NULL) {
+ return -EACCES;
+ }
+
+ /* read header */
+
+ read = getline(&line, &len, fp);
+ dprintf(fd, "%s", line);
+
+ /* read routes */
+
+ while ((read = getline(&line, &len, fp)) != -1) {
+ char iface[16];
+ uint32_t dest, gw, mask;
+ unsigned int flags, refcnt, use, metric, mtu, window, irtt;
+ sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
+ iface, &dest, &gw, &flags, &refcnt, &use, &metric,
+ &mask, &mtu, &window, &irtt);
+ dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
+ iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
+ metric, tswap32(mask), mtu, window, irtt);
+ }
+
+ free(line);
+ fclose(fp);
+
+ return 0;
+}
+#endif
+
static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
{
struct fake_open {
const char *filename;
int (*fill)(void *cpu_env, int fd);
+ int (*cmp)(const char *s1, const char *s2);
};
const struct fake_open *fake_open;
static const struct fake_open fakes[] = {
- { "maps", open_self_maps },
- { "stat", open_self_stat },
- { "auxv", open_self_auxv },
- { NULL, NULL }
+ { "maps", open_self_maps, is_proc_myself },
+ { "stat", open_self_stat, is_proc_myself },
+ { "auxv", open_self_auxv, is_proc_myself },
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+ { "/proc/net/route", open_net_route, is_proc },
+#endif
+ { NULL, NULL, NULL }
};
for (fake_open = fakes; fake_open->filename; fake_open++) {
- if (is_proc_myself(pathname, fake_open->filename)) {
+ if (fake_open->cmp(pathname, fake_open->filename)) {
break;
}
}
@@ -5697,7 +5851,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
}
break;
-#ifdef TARGET_NR_umount2 /* not on alpha */
+#ifdef TARGET_NR_umount2
case TARGET_NR_umount2:
if (!(p = lock_user_string(arg1)))
goto efault;
@@ -9013,6 +9167,34 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
}
#endif
+#ifdef TARGET_NR_atomic_cmpxchg_32
+ case TARGET_NR_atomic_cmpxchg_32:
+ {
+ /* should use start_exclusive from main.c */
+ abi_ulong mem_value;
+ if (get_user_u32(mem_value, arg6)) {
+ target_siginfo_t info;
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = arg6;
+ queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
+ ret = 0xdeadbeef;
+
+ }
+ if (mem_value == arg2)
+ put_user_u32(arg1, arg6);
+ ret = mem_value;
+ break;
+ }
+#endif
+#ifdef TARGET_NR_atomic_barrier
+ case TARGET_NR_atomic_barrier:
+ {
+ /* Like the kernel implementation and the qemu arm barrier, no-op this? */
+ break;
+ }
+#endif
default:
unimplemented:
gemu_log("qemu: Unsupported syscall: %d\n", num);
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 2ebe356..5f53a28 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -119,6 +119,18 @@ struct target_sockaddr {
uint8_t sa_data[14];
};
+struct target_sock_filter {
+ abi_ushort code;
+ uint8_t jt;
+ uint8_t jf;
+ abi_uint k;
+};
+
+struct target_sock_fprog {
+ abi_ushort len;
+ abi_ulong filter;
+};
+
struct target_in_addr {
uint32_t s_addr; /* big endian */
};
diff --git a/migration-rdma.c b/migration-rdma.c
index 05a155b..f94f3b4 100644
--- a/migration-rdma.c
+++ b/migration-rdma.c
@@ -356,6 +356,7 @@ typedef struct RDMAContext {
*/
struct rdma_cm_id *cm_id; /* connection manager ID */
struct rdma_cm_id *listen_id;
+ bool connected;
struct ibv_context *verbs;
struct rdma_event_channel *channel;
@@ -510,19 +511,21 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head,
int *resp_idx,
int (*callback)(RDMAContext *rdma));
-static inline uint64_t ram_chunk_index(uint8_t *start, uint8_t *host)
+static inline uint64_t ram_chunk_index(const uint8_t *start,
+ const uint8_t *host)
{
return ((uintptr_t) host - (uintptr_t) start) >> RDMA_REG_CHUNK_SHIFT;
}
-static inline uint8_t *ram_chunk_start(RDMALocalBlock *rdma_ram_block,
+static inline uint8_t *ram_chunk_start(const RDMALocalBlock *rdma_ram_block,
uint64_t i)
{
return (uint8_t *) (((uintptr_t) rdma_ram_block->local_host_addr)
+ (i << RDMA_REG_CHUNK_SHIFT));
}
-static inline uint8_t *ram_chunk_end(RDMALocalBlock *rdma_ram_block, uint64_t i)
+static inline uint8_t *ram_chunk_end(const RDMALocalBlock *rdma_ram_block,
+ uint64_t i)
{
uint8_t *result = ram_chunk_start(rdma_ram_block, i) +
(1UL << RDMA_REG_CHUNK_SHIFT);
@@ -2194,7 +2197,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma)
struct rdma_cm_event *cm_event;
int ret, idx;
- if (rdma->cm_id) {
+ if (rdma->cm_id && rdma->connected) {
if (rdma->error_state) {
RDMAControlHeader head = { .len = 0,
.type = RDMA_CONTROL_ERROR,
@@ -2213,7 +2216,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma)
}
}
DDPRINTF("Disconnected.\n");
- rdma->cm_id = NULL;
+ rdma->connected = false;
}
g_free(rdma->block);
@@ -2235,7 +2238,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma)
}
if (rdma->qp) {
- ibv_destroy_qp(rdma->qp);
+ rdma_destroy_qp(rdma->cm_id);
rdma->qp = NULL;
}
if (rdma->cq) {
@@ -2372,6 +2375,7 @@ static int qemu_rdma_connect(RDMAContext *rdma, Error **errp)
rdma->cm_id = NULL;
goto err_rdma_source_connect;
}
+ rdma->connected = true;
memcpy(&cap, cm_event->param.conn.private_data, sizeof(cap));
network_to_caps(&cap);
@@ -2906,6 +2910,7 @@ static int qemu_rdma_accept(RDMAContext *rdma)
}
rdma_ack_cm_event(cm_event);
+ rdma->connected = true;
ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY);
if (ret) {
diff --git a/migration.c b/migration.c
index 200d404..b4f8462 100644
--- a/migration.c
+++ b/migration.c
@@ -567,7 +567,8 @@ static void *migration_thread(void *opaque)
if (!qemu_file_rate_limit(s->file)) {
DPRINTF("iterate\n");
pending_size = qemu_savevm_state_pending(s->file, max_size);
- DPRINTF("pending size %lu max %lu\n", pending_size, max_size);
+ DPRINTF("pending size %" PRIu64 " max %" PRIu64 "\n",
+ pending_size, max_size);
if (pending_size && pending_size >= max_size) {
qemu_savevm_state_iterate(s->file);
} else {
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 05fc7c2..6727f0c 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 49f2d29..4d6e48f 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -123,6 +123,7 @@ static void vring_init(struct vring *vr, unsigned int num, void *p,
/* We're running with interrupts off anyways, so don't bother */
vr->used->flags = VRING_USED_F_NO_NOTIFY;
vr->used->idx = 0;
+ vr->used_idx = 0;
debug_print_addr("init vr", vr);
}
@@ -150,8 +151,6 @@ static void vring_send_buf(struct vring *vr, void *p, int len, int flags)
if (!(flags & VRING_DESC_F_NEXT)) {
vr->avail->idx++;
}
-
- vr->used->idx = vr->next_idx;
}
static u64 get_clock(void)
@@ -180,7 +179,8 @@ static int vring_wait_reply(struct vring *vr, int timeout)
struct subchannel_id schid = vr->schid;
int r = 0;
- while (vr->used->idx == vr->next_idx) {
+ /* Wait until the used index has moved. */
+ while (vr->used->idx == vr->used_idx) {
vring_notify(schid);
if (timeout && (get_second() >= target_second)) {
r = 1;
@@ -189,6 +189,7 @@ static int vring_wait_reply(struct vring *vr, int timeout)
yield();
}
+ vr->used_idx = vr->used->idx;
vr->next_idx = 0;
vr->desc[0].len = 0;
vr->desc[0].flags = 0;
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 86fdd57..772a63f 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -115,6 +115,7 @@ struct vring_used {
struct vring {
unsigned int num;
int next_idx;
+ int used_idx;
struct vring_desc *desc;
struct vring_avail *avail;
struct vring_used *used;
diff --git a/savevm.c b/savevm.c
index 4a3c819..2f631d4 100644
--- a/savevm.c
+++ b/savevm.c
@@ -566,6 +566,13 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
return f;
}
+/*
+ * Get last error for stream f
+ *
+ * Return negative error value if there has been an error on previous
+ * operations, return 0 if no error happened.
+ *
+ */
int qemu_file_get_error(QEMUFile *f)
{
return f->last_error;
@@ -642,7 +649,7 @@ void ram_control_after_iterate(QEMUFile *f, uint64_t flags)
void ram_control_load_hook(QEMUFile *f, uint64_t flags)
{
- int ret = 0;
+ int ret = -EINVAL;
if (f->ops->hook_ram_load) {
ret = f->ops->hook_ram_load(f, f->opaque, flags);
diff --git a/target-s390x/arch_dump.c b/target-s390x/arch_dump.c
index 9d36116..5cbb53c 100644
--- a/target-s390x/arch_dump.c
+++ b/target-s390x/arch_dump.c
@@ -151,6 +151,7 @@ static int s390x_write_all_elf64_notes(const char *note_name,
int ret = -1;
for (nf = note_func; nf->note_contents_func; nf++) {
+ memset(&note, 0, sizeof(note));
note.hdr.n_namesz = cpu_to_be32(sizeof(note.name));
note.hdr.n_descsz = cpu_to_be32(nf->contents_size);
strncpy(note.name, note_name, sizeof(note.name));
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 8be5648..a2c077b 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -148,6 +148,7 @@ typedef struct CPUS390XState {
} CPUS390XState;
#include "cpu-qom.h"
+#include <sysemu/kvm.h>
/* distinguish between 24 bit and 31 bit addressing */
#define HIGH_ORDER_BIT 0x80000000
@@ -692,6 +693,14 @@ static inline const char *cc_name(int cc_op)
return cc_names[cc_op];
}
+static inline void setcc(S390CPU *cpu, uint64_t cc)
+{
+ CPUS390XState *env = &cpu->env;
+
+ env->psw.mask &= ~(3ull << 44);
+ env->psw.mask |= (cc & 3) << 44;
+}
+
typedef struct LowCore
{
/* prefix area: defined by architecture */
@@ -1058,8 +1067,6 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
uintptr_t retaddr);
-#include <sysemu/kvm.h>
-
#ifdef CONFIG_KVM
void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id,
uint16_t subchannel_nr, uint32_t io_int_parm,
diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c
index 85fd285..8d6363d 100644
--- a/target-s390x/ioinst.c
+++ b/target-s390x/ioinst.c
@@ -36,7 +36,7 @@ int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
return 0;
}
-int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -44,8 +44,8 @@ int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1)
int cc;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
+ return;
}
trace_ioinst_sch_id("xsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
@@ -66,11 +66,10 @@ int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1)
cc = 1;
break;
}
-
- return cc;
+ setcc(cpu, cc);
}
-int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -78,8 +77,8 @@ int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1)
int cc;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
+ return;
}
trace_ioinst_sch_id("csch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
@@ -91,10 +90,10 @@ int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1)
} else {
cc = 0;
}
- return cc;
+ setcc(cpu, cc);
}
-int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -102,8 +101,8 @@ int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1)
int cc;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
+ return;
}
trace_ioinst_sch_id("hsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
@@ -124,8 +123,7 @@ int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1)
cc = 1;
break;
}
-
- return cc;
+ setcc(cpu, cc);
}
static int ioinst_schib_valid(SCHIB *schib)
@@ -141,7 +139,7 @@ static int ioinst_schib_valid(SCHIB *schib)
return 1;
}
-int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
+void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -150,22 +148,21 @@ int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
int ret = -ENODEV;
int cc;
hwaddr len = sizeof(*schib);
+ CPUS390XState *env = &cpu->env;
addr = decode_basedisp_s(env, ipb);
if (addr & 3) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
schib = s390_cpu_physical_memory_map(env, addr, &len, 0);
if (!schib || len != sizeof(*schib)) {
program_interrupt(env, PGM_ADDRESSING, 2);
- cc = -EIO;
goto out;
}
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
!ioinst_schib_valid(schib)) {
program_interrupt(env, PGM_OPERAND, 2);
- cc = -EIO;
goto out;
}
trace_ioinst_sch_id("msch", cssid, ssid, schid);
@@ -187,9 +184,10 @@ int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
cc = 1;
break;
}
+ setcc(cpu, cc);
+
out:
s390_cpu_physical_memory_unmap(env, schib, len, 0);
- return cc;
}
static void copy_orb_from_guest(ORB *dest, const ORB *src)
@@ -213,7 +211,7 @@ static int ioinst_orb_valid(ORB *orb)
return 1;
}
-int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
+void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -222,23 +220,22 @@ int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
int ret = -ENODEV;
int cc;
hwaddr len = sizeof(*orig_orb);
+ CPUS390XState *env = &cpu->env;
addr = decode_basedisp_s(env, ipb);
if (addr & 3) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
orig_orb = s390_cpu_physical_memory_map(env, addr, &len, 0);
if (!orig_orb || len != sizeof(*orig_orb)) {
program_interrupt(env, PGM_ADDRESSING, 2);
- cc = -EIO;
goto out;
}
copy_orb_from_guest(&orb, orig_orb);
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
!ioinst_orb_valid(&orb)) {
program_interrupt(env, PGM_OPERAND, 2);
- cc = -EIO;
goto out;
}
trace_ioinst_sch_id("ssch", cssid, ssid, schid);
@@ -260,38 +257,39 @@ int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
cc = 1;
break;
}
+ setcc(cpu, cc);
out:
s390_cpu_physical_memory_unmap(env, orig_orb, len, 0);
- return cc;
}
-int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb)
+void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb)
{
CRW *crw;
uint64_t addr;
int cc;
hwaddr len = sizeof(*crw);
+ CPUS390XState *env = &cpu->env;
addr = decode_basedisp_s(env, ipb);
if (addr & 3) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
crw = s390_cpu_physical_memory_map(env, addr, &len, 1);
if (!crw || len != sizeof(*crw)) {
program_interrupt(env, PGM_ADDRESSING, 2);
- cc = -EIO;
goto out;
}
cc = css_do_stcrw(crw);
/* 0 - crw stored, 1 - zeroes stored */
+ setcc(cpu, cc);
+
out:
s390_cpu_physical_memory_unmap(env, crw, len, 1);
- return cc;
}
-int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
+void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -299,22 +297,21 @@ int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
int cc;
SCHIB *schib;
hwaddr len = sizeof(*schib);
+ CPUS390XState *env = &cpu->env;
addr = decode_basedisp_s(env, ipb);
if (addr & 3) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
schib = s390_cpu_physical_memory_map(env, addr, &len, 1);
if (!schib || len != sizeof(*schib)) {
program_interrupt(env, PGM_ADDRESSING, 2);
- cc = -EIO;
goto out;
}
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
program_interrupt(env, PGM_OPERAND, 2);
- cc = -EIO;
goto out;
}
trace_ioinst_sch_id("stsch", cssid, ssid, schid);
@@ -336,9 +333,10 @@ int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
cc = 0;
}
}
+ setcc(cpu, cc);
+
out:
s390_cpu_physical_memory_unmap(env, schib, len, 1);
- return cc;
}
int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
@@ -575,7 +573,7 @@ static void ioinst_handle_chsc_unimplemented(ChscResp *res)
res->param = 0;
}
-int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
+void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb)
{
ChscReq *req;
ChscResp *res;
@@ -584,7 +582,7 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
uint16_t len;
uint16_t command;
hwaddr map_size = TARGET_PAGE_SIZE;
- int ret = 0;
+ CPUS390XState *env = &cpu->env;
trace_ioinst("chsc");
reg = (ipb >> 20) & 0x00f;
@@ -592,19 +590,17 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
/* Page boundary? */
if (addr & 0xfff) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
req = s390_cpu_physical_memory_map(env, addr, &map_size, 1);
if (!req || map_size != TARGET_PAGE_SIZE) {
program_interrupt(env, PGM_ADDRESSING, 2);
- ret = -EIO;
goto out;
}
len = be16_to_cpu(req->len);
/* Length field valid? */
if ((len < 16) || (len > 4088) || (len & 7)) {
program_interrupt(env, PGM_OPERAND, 2);
- ret = -EIO;
goto out;
}
memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
@@ -628,7 +624,6 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
out:
s390_cpu_physical_memory_unmap(env, req, map_size, 1);
- return ret;
}
int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb)
@@ -666,18 +661,19 @@ out:
#define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
#define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
-int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2,
- uint32_t ipb)
+void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
+ uint32_t ipb)
{
uint8_t mbk;
int update;
int dct;
+ CPUS390XState *env = &cpu->env;
trace_ioinst("schm");
if (SCHM_REG1_RES(reg1)) {
program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ return;
}
mbk = SCHM_REG1_MBK(reg1);
@@ -686,15 +682,13 @@ int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2,
if (update && (reg2 & 0x000000000000001f)) {
program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ return;
}
css_do_schm(mbk, update, dct, update ? reg2 : 0);
-
- return 0;
}
-int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -702,8 +696,8 @@ int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1)
int cc;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
+ return;
}
trace_ioinst_sch_id("rsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
@@ -724,24 +718,23 @@ int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1)
cc = 1;
break;
}
-
- return cc;
-
+ setcc(cpu, cc);
}
#define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
#define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
#define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
-int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1)
{
int cc;
uint8_t cssid;
uint8_t chpid;
int ret;
+ CPUS390XState *env = &cpu->env;
if (RCHP_REG1_RES(reg1)) {
program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ return;
}
cssid = RCHP_REG1_CSSID(reg1);
@@ -764,19 +757,16 @@ int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1)
default:
/* Invalid channel subsystem. */
program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ return;
}
-
- return cc;
+ setcc(cpu, cc);
}
#define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
-int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1)
{
/* We do not provide address limit checking, so let's suppress it. */
if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
}
- return 0;
}
diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h
index 7bed291..613da49 100644
--- a/target-s390x/ioinst.h
+++ b/target-s390x/ioinst.h
@@ -214,20 +214,20 @@ typedef struct IOIntCode {
int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
int *schid);
-int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb);
-int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb);
-int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb);
-int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb);
+void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb);
+void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb);
+void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb);
+void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb);
int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb);
-int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb);
+void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb);
int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb);
-int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2,
- uint32_t ipb);
-int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1);
+void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
+ uint32_t ipb);
+void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1);
#endif
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 4923e0a..a444f69 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -418,18 +418,6 @@ static void enter_pgmcheck(S390CPU *cpu, uint16_t code)
kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code);
}
-static inline void setcc(S390CPU *cpu, uint64_t cc)
-{
- CPUS390XState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
-
- cs->kvm_run->psw_mask &= ~(3ull << 44);
- cs->kvm_run->psw_mask |= (cc & 3) << 44;
-
- env->psw.mask &= ~(3ul << 44);
- env->psw.mask |= (cc & 3) << 44;
-}
-
static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
uint16_t ipbh0)
{
@@ -439,6 +427,10 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
int r = 0;
cpu_synchronize_state(CPU(cpu));
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ enter_pgmcheck(cpu, PGM_PRIVILEGED);
+ return 0;
+ }
sccb = env->regs[ipbh0 & 0xf];
code = env->regs[(ipbh0 & 0xf0) >> 4];
@@ -454,8 +446,6 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run,
uint8_t ipa0, uint8_t ipa1, uint8_t ipb)
{
- int r = 0;
- int no_cc = 0;
CPUS390XState *env = &cpu->env;
CPUState *cs = CPU(cpu);
@@ -469,69 +459,61 @@ static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run,
switch (ipa1) {
case PRIV_XSCH:
- r = ioinst_handle_xsch(env, env->regs[1]);
+ ioinst_handle_xsch(cpu, env->regs[1]);
break;
case PRIV_CSCH:
- r = ioinst_handle_csch(env, env->regs[1]);
+ ioinst_handle_csch(cpu, env->regs[1]);
break;
case PRIV_HSCH:
- r = ioinst_handle_hsch(env, env->regs[1]);
+ ioinst_handle_hsch(cpu, env->regs[1]);
break;
case PRIV_MSCH:
- r = ioinst_handle_msch(env, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
case PRIV_SSCH:
- r = ioinst_handle_ssch(env, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
case PRIV_STCRW:
- r = ioinst_handle_stcrw(env, run->s390_sieic.ipb);
+ ioinst_handle_stcrw(cpu, run->s390_sieic.ipb);
break;
case PRIV_STSCH:
- r = ioinst_handle_stsch(env, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
case PRIV_TSCH:
/* We should only get tsch via KVM_EXIT_S390_TSCH. */
fprintf(stderr, "Spurious tsch intercept\n");
break;
case PRIV_CHSC:
- r = ioinst_handle_chsc(env, run->s390_sieic.ipb);
+ ioinst_handle_chsc(cpu, run->s390_sieic.ipb);
break;
case PRIV_TPI:
/* This should have been handled by kvm already. */
fprintf(stderr, "Spurious tpi intercept\n");
break;
case PRIV_SCHM:
- no_cc = 1;
- r = ioinst_handle_schm(env, env->regs[1], env->regs[2],
- run->s390_sieic.ipb);
+ ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
+ run->s390_sieic.ipb);
break;
case PRIV_RSCH:
- r = ioinst_handle_rsch(env, env->regs[1]);
+ ioinst_handle_rsch(cpu, env->regs[1]);
break;
case PRIV_RCHP:
- r = ioinst_handle_rchp(env, env->regs[1]);
+ ioinst_handle_rchp(cpu, env->regs[1]);
break;
case PRIV_STCPS:
/* We do not provide this instruction, it is suppressed. */
- no_cc = 1;
- r = 0;
break;
case PRIV_SAL:
- no_cc = 1;
- r = ioinst_handle_sal(env, env->regs[1]);
+ ioinst_handle_sal(cpu, env->regs[1]);
break;
case PRIV_SIGA:
/* Not provided, set CC = 3 for subchannel not operational */
- r = 3;
+ setcc(cpu, 3);
break;
default:
return -1;
}
- if (r >= 0 && !no_cc) {
- setcc(cpu, r);
- }
-
return 0;
}
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 1690907..10d0425 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -33,6 +33,7 @@
#include "exec/softmmu_exec.h"
#include "sysemu/cpus.h"
#include "sysemu/sysemu.h"
+#include "hw/s390x/ebcdic.h"
#endif
/* #define DEBUG_HELPER */
@@ -72,86 +73,6 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp)
#ifndef CONFIG_USER_ONLY
-/* EBCDIC handling */
-static const uint8_t ebcdic2ascii[] = {
- 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
- 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
- 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
- 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
- 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
- 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
- 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
- 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
- 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
- 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
- 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
- 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
- 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
- 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
- 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
- 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
- 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
- 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
- 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
- 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
- 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
- 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
- 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
-};
-
-static const uint8_t ascii2ebcdic[] = {
- 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
- 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
- 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
- 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
- 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
- 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
- 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
- 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
- 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
- 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
- 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
- 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
- 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
-};
-
-static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
- }
-}
-
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
{
qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
@@ -192,6 +113,29 @@ static void cpu_reset_all(void)
}
}
+static void cpu_full_reset_all(void)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ cpu_reset(cpu);
+ }
+}
+
+static int modified_clear_reset(S390CPU *cpu)
+{
+ S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
+
+ pause_all_vcpus();
+ cpu_synchronize_all_states();
+ cpu_full_reset_all();
+ io_subsystem_reset();
+ scc->load_normal(CPU(cpu));
+ cpu_synchronize_all_post_reset();
+ resume_all_vcpus();
+ return 0;
+}
+
static int load_normal_reset(S390CPU *cpu)
{
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
@@ -225,6 +169,9 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
}
switch (subcode) {
+ case 0:
+ modified_clear_reset(s390_env_get_cpu(env));
+ break;
case 1:
load_normal_reset(s390_env_get_cpu(env));
break;
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 2595556..97e33ed 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -450,7 +450,9 @@ static const uint32_t tcg_to_bc[] = {
static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
{
- tcg_out32 (s, OR | SAB (arg, ret, arg));
+ if (ret != arg) {
+ tcg_out32(s, OR | SAB(arg, ret, arg));
+ }
}
static void tcg_out_movi(TCGContext *s, TCGType type,
@@ -490,7 +492,8 @@ static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
}
}
-static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
+static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg,
+ int lk)
{
#ifdef _CALL_AIX
int reg;
@@ -504,14 +507,14 @@ static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
tcg_out32 (s, LWZ | RT (0) | RA (reg));
tcg_out32 (s, MTSPR | RA (0) | CTR);
tcg_out32 (s, LWZ | RT (2) | RA (reg) | 4);
- tcg_out32 (s, BCCTR | BO_ALWAYS | LK);
+ tcg_out32 (s, BCCTR | BO_ALWAYS | lk);
#else
if (const_arg) {
- tcg_out_b (s, LK, arg);
+ tcg_out_b (s, lk, arg);
}
else {
tcg_out32 (s, MTSPR | RS (arg) | LR);
- tcg_out32 (s, BCLR | BO_ALWAYS | LK);
+ tcg_out32 (s, BCLR | BO_ALWAYS | lk);
}
#endif
}
@@ -549,118 +552,128 @@ static void add_qemu_ldst_label (TCGContext *s,
label->label_ptr[0] = label_ptr;
}
-/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
- int mmu_idx) */
+/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
+ * int mmu_idx, uintptr_t ra)
+ */
static const void * const qemu_ld_helpers[4] = {
- helper_ldb_mmu,
- helper_ldw_mmu,
- helper_ldl_mmu,
- helper_ldq_mmu,
+ helper_ret_ldub_mmu,
+ helper_ret_lduw_mmu,
+ helper_ret_ldul_mmu,
+ helper_ret_ldq_mmu,
};
-/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
- uintxx_t val, int mmu_idx) */
+/* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr,
+ * uintxx_t val, int mmu_idx, uintptr_t ra)
+ */
static const void * const qemu_st_helpers[4] = {
- helper_stb_mmu,
- helper_stw_mmu,
- helper_stl_mmu,
- helper_stq_mmu,
+ helper_ret_stb_mmu,
+ helper_ret_stw_mmu,
+ helper_ret_stl_mmu,
+ helper_ret_stq_mmu,
};
static void *ld_trampolines[4];
static void *st_trampolines[4];
-static void tcg_out_tlb_check (TCGContext *s, int r0, int r1, int r2,
- int addr_reg, int addr_reg2, int s_bits,
- int offset1, int offset2, uint8_t **label_ptr)
+/* Perform the TLB load and compare. Branches to the slow path, placing the
+ address of the branch in *LABEL_PTR. Loads the addend of the TLB into R0.
+ Clobbers R1 and R2. */
+
+static void tcg_out_tlb_check(TCGContext *s, TCGReg r0, TCGReg r1, TCGReg r2,
+ TCGReg addrlo, TCGReg addrhi, int s_bits,
+ int mem_index, int is_load, uint8_t **label_ptr)
{
+ int cmp_off =
+ (is_load
+ ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read)
+ : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write));
+ int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend);
uint16_t retranst;
+ TCGReg base = TCG_AREG0;
+
+ /* Extract the page index, shifted into place for tlb index. */
+ tcg_out32(s, (RLWINM
+ | RA(r0)
+ | RS(addrlo)
+ | SH(32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS))
+ | MB(32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS))
+ | ME(31 - CPU_TLB_ENTRY_BITS)));
+
+ /* Compensate for very large offsets. */
+ if (add_off >= 0x8000) {
+ /* Most target env are smaller than 32k; none are larger than 64k.
+ Simplify the logic here merely to offset by 0x7ff0, giving us a
+ range just shy of 64k. Check this assumption. */
+ QEMU_BUILD_BUG_ON(offsetof(CPUArchState,
+ tlb_table[NB_MMU_MODES - 1][1])
+ > 0x7ff0 + 0x7fff);
+ tcg_out32(s, ADDI | RT(r1) | RA(base) | 0x7ff0);
+ base = r1;
+ cmp_off -= 0x7ff0;
+ add_off -= 0x7ff0;
+ }
- tcg_out32 (s, (RLWINM
- | RA (r0)
- | RS (addr_reg)
- | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS))
- | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS))
- | ME (31 - CPU_TLB_ENTRY_BITS)
- )
- );
- tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0));
- tcg_out32 (s, (LWZU
- | RT (r1)
- | RA (r0)
- | offset1
- )
- );
- tcg_out32 (s, (RLWINM
- | RA (r2)
- | RS (addr_reg)
- | SH (0)
- | MB ((32 - s_bits) & 31)
- | ME (31 - TARGET_PAGE_BITS)
- )
- );
+ /* Clear the non-page, non-alignment bits from the address. */
+ tcg_out32(s, (RLWINM
+ | RA(r2)
+ | RS(addrlo)
+ | SH(0)
+ | MB((32 - s_bits) & 31)
+ | ME(31 - TARGET_PAGE_BITS)));
- tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1));
-#if TARGET_LONG_BITS == 64
- tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4);
- tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1));
- tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ));
-#endif
- *label_ptr = s->code_ptr;
- retranst = ((uint16_t *) s->code_ptr)[1] & ~3;
- tcg_out32 (s, BC | BI (7, CR_EQ) | retranst | BO_COND_FALSE);
+ tcg_out32(s, ADD | RT(r0) | RA(r0) | RB(base));
+ base = r0;
- /* r0 now contains &env->tlb_table[mem_index][index].addr_x */
- tcg_out32 (s, (LWZ
- | RT (r0)
- | RA (r0)
- | offset2
- )
- );
- /* r0 = env->tlb_table[mem_index][index].addend */
- tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg));
- /* r0 = env->tlb_table[mem_index][index].addend + addr */
+ /* Load the tlb comparator. */
+ tcg_out32(s, LWZ | RT(r1) | RA(base) | (cmp_off & 0xffff));
+ tcg_out32(s, CMP | BF(7) | RA(r2) | RB(r1));
+
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out32(s, LWZ | RT(r1) | RA(base) | ((cmp_off + 4) & 0xffff));
+ }
+
+ /* Load the tlb addend for use on the fast path.
+ Do this asap to minimize load delay. */
+ tcg_out32(s, LWZ | RT(r0) | RA(base) | (add_off & 0xffff));
+
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out32(s, CMP | BF(6) | RA(addrhi) | RB(r1));
+ tcg_out32(s, CRAND | BT(7, CR_EQ) | BA(6, CR_EQ) | BB(7, CR_EQ));
+ }
+
+ /* Use a conditional branch-and-link so that we load a pointer to
+ somewhere within the current opcode, for passing on to the helper.
+ This address cannot be used for a tail call, but it's shorter
+ than forming an address from scratch. */
+ *label_ptr = s->code_ptr;
+ retranst = ((uint16_t *) s->code_ptr)[1] & ~3;
+ tcg_out32(s, BC | BI(7, CR_EQ) | retranst | BO_COND_FALSE | LK);
}
#endif
static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
{
- int addr_reg, data_reg, data_reg2, r0, r1, rbase, bswap;
+ TCGReg addrlo, datalo, datahi, rbase;
+ int bswap;
#ifdef CONFIG_SOFTMMU
- int mem_index, s_bits, r2, addr_reg2;
+ int mem_index;
+ TCGReg addrhi;
uint8_t *label_ptr;
#endif
- data_reg = *args++;
- if (opc == 3)
- data_reg2 = *args++;
- else
- data_reg2 = 0;
- addr_reg = *args++;
+ datalo = *args++;
+ datahi = (opc == 3 ? *args++ : 0);
+ addrlo = *args++;
#ifdef CONFIG_SOFTMMU
-#if TARGET_LONG_BITS == 64
- addr_reg2 = *args++;
-#else
- addr_reg2 = 0;
-#endif
+ addrhi = (TARGET_LONG_BITS == 64 ? *args++ : 0);
mem_index = *args;
- s_bits = opc & 3;
- r0 = 3;
- r1 = 4;
- r2 = 0;
- rbase = 0;
-
- tcg_out_tlb_check (
- s, r0, r1, r2, addr_reg, addr_reg2, s_bits,
- offsetof (CPUArchState, tlb_table[mem_index][0].addr_read),
- offsetof (CPUTLBEntry, addend) - offsetof (CPUTLBEntry, addr_read),
- &label_ptr
- );
+
+ tcg_out_tlb_check(s, TCG_REG_R3, TCG_REG_R4, TCG_REG_R0, addrlo,
+ addrhi, opc & 3, mem_index, 0, &label_ptr);
+ rbase = TCG_REG_R3;
#else /* !CONFIG_SOFTMMU */
- r0 = addr_reg;
- r1 = 3;
rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
#endif
@@ -673,106 +686,72 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
switch (opc) {
default:
case 0:
- tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
+ tcg_out32(s, LBZX | TAB(datalo, rbase, addrlo));
break;
case 0|4:
- tcg_out32 (s, LBZX | TAB (data_reg, rbase, r0));
- tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg));
+ tcg_out32(s, LBZX | TAB(datalo, rbase, addrlo));
+ tcg_out32(s, EXTSB | RA(datalo) | RS(datalo));
break;
case 1:
- if (bswap)
- tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
- else
- tcg_out32 (s, LHZX | TAB (data_reg, rbase, r0));
+ tcg_out32(s, (bswap ? LHBRX : LHZX) | TAB(datalo, rbase, addrlo));
break;
case 1|4:
if (bswap) {
- tcg_out32 (s, LHBRX | TAB (data_reg, rbase, r0));
- tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg));
+ tcg_out32(s, LHBRX | TAB(datalo, rbase, addrlo));
+ tcg_out32(s, EXTSH | RA(datalo) | RS(datalo));
+ } else {
+ tcg_out32(s, LHAX | TAB(datalo, rbase, addrlo));
}
- else tcg_out32 (s, LHAX | TAB (data_reg, rbase, r0));
break;
case 2:
- if (bswap)
- tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
- else
- tcg_out32 (s, LWZX | TAB (data_reg, rbase, r0));
+ tcg_out32(s, (bswap ? LWBRX : LWZX) | TAB(datalo, rbase, addrlo));
break;
case 3:
if (bswap) {
- tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
- tcg_out32 (s, LWBRX | TAB (data_reg, rbase, r0));
- tcg_out32 (s, LWBRX | TAB (data_reg2, rbase, r1));
- }
- else {
-#ifdef CONFIG_USE_GUEST_BASE
- tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
- tcg_out32 (s, LWZX | TAB (data_reg2, rbase, r0));
- tcg_out32 (s, LWZX | TAB (data_reg, rbase, r1));
-#else
- if (r0 == data_reg2) {
- tcg_out32 (s, LWZ | RT (0) | RA (r0));
- tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4);
- tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 0);
- }
- else {
- tcg_out32 (s, LWZ | RT (data_reg2) | RA (r0));
- tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4);
- }
-#endif
+ tcg_out32(s, ADDI | RT(TCG_REG_R0) | RA(addrlo) | 4);
+ tcg_out32(s, LWBRX | TAB(datalo, rbase, addrlo));
+ tcg_out32(s, LWBRX | TAB(datahi, rbase, TCG_REG_R0));
+ } else if (rbase != 0) {
+ tcg_out32(s, ADDI | RT(TCG_REG_R0) | RA(addrlo) | 4);
+ tcg_out32(s, LWZX | TAB(datahi, rbase, addrlo));
+ tcg_out32(s, LWZX | TAB(datalo, rbase, TCG_REG_R0));
+ } else if (addrlo == datahi) {
+ tcg_out32(s, LWZ | RT(datalo) | RA(addrlo) | 4);
+ tcg_out32(s, LWZ | RT(datahi) | RA(addrlo));
+ } else {
+ tcg_out32(s, LWZ | RT(datahi) | RA(addrlo));
+ tcg_out32(s, LWZ | RT(datalo) | RA(addrlo) | 4);
}
break;
}
#ifdef CONFIG_SOFTMMU
- add_qemu_ldst_label (s,
- 1,
- opc,
- data_reg,
- data_reg2,
- addr_reg,
- addr_reg2,
- mem_index,
- s->code_ptr,
- label_ptr);
+ add_qemu_ldst_label(s, 1, opc, datalo, datahi, addrlo,
+ addrhi, mem_index, s->code_ptr, label_ptr);
#endif
}
static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
{
- int addr_reg, r0, r1, data_reg, data_reg2, bswap, rbase;
+ TCGReg addrlo, datalo, datahi, rbase;
+ int bswap;
#ifdef CONFIG_SOFTMMU
- int mem_index, r2, addr_reg2;
+ int mem_index;
+ TCGReg addrhi;
uint8_t *label_ptr;
#endif
- data_reg = *args++;
- if (opc == 3)
- data_reg2 = *args++;
- else
- data_reg2 = 0;
- addr_reg = *args++;
+ datalo = *args++;
+ datahi = (opc == 3 ? *args++ : 0);
+ addrlo = *args++;
#ifdef CONFIG_SOFTMMU
-#if TARGET_LONG_BITS == 64
- addr_reg2 = *args++;
-#else
- addr_reg2 = 0;
-#endif
+ addrhi = (TARGET_LONG_BITS == 64 ? *args++ : 0);
mem_index = *args;
- r0 = 3;
- r1 = 4;
- r2 = 0;
- rbase = 0;
-
- tcg_out_tlb_check (
- s, r0, r1, r2, addr_reg, addr_reg2, opc & 3,
- offsetof (CPUArchState, tlb_table[mem_index][0].addr_write),
- offsetof (CPUTLBEntry, addend) - offsetof (CPUTLBEntry, addr_write),
- &label_ptr
- );
+
+ tcg_out_tlb_check(s, TCG_REG_R3, TCG_REG_R4, TCG_REG_R0, addrlo,
+ addrhi, opc & 3, mem_index, 0, &label_ptr);
+ rbase = TCG_REG_R3;
#else /* !CONFIG_SOFTMMU */
- r0 = addr_reg;
- r1 = 3;
rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
#endif
@@ -783,180 +762,132 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
#endif
switch (opc) {
case 0:
- tcg_out32 (s, STBX | SAB (data_reg, rbase, r0));
+ tcg_out32(s, STBX | SAB(datalo, rbase, addrlo));
break;
case 1:
- if (bswap)
- tcg_out32 (s, STHBRX | SAB (data_reg, rbase, r0));
- else
- tcg_out32 (s, STHX | SAB (data_reg, rbase, r0));
+ tcg_out32(s, (bswap ? STHBRX : STHX) | SAB(datalo, rbase, addrlo));
break;
case 2:
- if (bswap)
- tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
- else
- tcg_out32 (s, STWX | SAB (data_reg, rbase, r0));
+ tcg_out32(s, (bswap ? STWBRX : STWX) | SAB(datalo, rbase, addrlo));
break;
case 3:
if (bswap) {
- tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
- tcg_out32 (s, STWBRX | SAB (data_reg, rbase, r0));
- tcg_out32 (s, STWBRX | SAB (data_reg2, rbase, r1));
- }
- else {
-#ifdef CONFIG_USE_GUEST_BASE
- tcg_out32 (s, STWX | SAB (data_reg2, rbase, r0));
- tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
- tcg_out32 (s, STWX | SAB (data_reg, rbase, r1));
-#else
- tcg_out32 (s, STW | RS (data_reg2) | RA (r0));
- tcg_out32 (s, STW | RS (data_reg) | RA (r0) | 4);
-#endif
+ tcg_out32(s, ADDI | RT(TCG_REG_R0) | RA(addrlo) | 4);
+ tcg_out32(s, STWBRX | SAB(datalo, rbase, addrlo));
+ tcg_out32(s, STWBRX | SAB(datahi, rbase, TCG_REG_R0));
+ } else if (rbase != 0) {
+ tcg_out32(s, ADDI | RT(TCG_REG_R0) | RA(addrlo) | 4);
+ tcg_out32(s, STWX | SAB(datahi, rbase, addrlo));
+ tcg_out32(s, STWX | SAB(datalo, rbase, TCG_REG_R0));
+ } else {
+ tcg_out32(s, STW | RS(datahi) | RA(addrlo));
+ tcg_out32(s, STW | RS(datalo) | RA(addrlo) | 4);
}
break;
}
#ifdef CONFIG_SOFTMMU
- add_qemu_ldst_label (s,
- 0,
- opc,
- data_reg,
- data_reg2,
- addr_reg,
- addr_reg2,
- mem_index,
- s->code_ptr,
- label_ptr);
+ add_qemu_ldst_label(s, 0, opc, datalo, datahi, addrlo, addrhi,
+ mem_index, s->code_ptr, label_ptr);
#endif
}
#if defined(CONFIG_SOFTMMU)
-static void tcg_out_qemu_ld_slow_path (TCGContext *s, TCGLabelQemuLdst *label)
+static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
- int s_bits;
- int ir;
- int opc = label->opc;
- int mem_index = label->mem_index;
- int data_reg = label->datalo_reg;
- int data_reg2 = label->datahi_reg;
- int addr_reg = label->addrlo_reg;
- uint8_t *raddr = label->raddr;
- uint8_t **label_ptr = &label->label_ptr[0];
-
- s_bits = opc & 3;
-
- /* resolve label address */
- reloc_pc14 (label_ptr[0], (tcg_target_long) s->code_ptr);
-
- /* slow path */
- ir = 4;
-#if TARGET_LONG_BITS == 32
- tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg);
-#else
+ TCGReg ir, datalo, datahi;
+
+ reloc_pc14 (l->label_ptr[0], (uintptr_t)s->code_ptr);
+
+ ir = TCG_REG_R4;
+ if (TARGET_LONG_BITS == 32) {
+ tcg_out_mov(s, TCG_TYPE_I32, ir++, l->addrlo_reg);
+ } else {
#ifdef TCG_TARGET_CALL_ALIGN_ARGS
- ir |= 1;
-#endif
- tcg_out_mov (s, TCG_TYPE_I32, ir++, label->addrhi_reg);
- tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg);
+ ir |= 1;
#endif
- tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index);
- tcg_out_call (s, (tcg_target_long) ld_trampolines[s_bits], 1);
- tcg_out32 (s, (tcg_target_long) raddr);
- switch (opc) {
+ tcg_out_mov(s, TCG_TYPE_I32, ir++, l->addrhi_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, ir++, l->addrlo_reg);
+ }
+ tcg_out_movi(s, TCG_TYPE_I32, ir++, l->mem_index);
+ tcg_out32(s, MFSPR | RT(ir++) | LR);
+ tcg_out_b(s, LK, (uintptr_t)ld_trampolines[l->opc & 3]);
+
+ datalo = l->datalo_reg;
+ switch (l->opc) {
case 0|4:
- tcg_out32 (s, EXTSB | RA (data_reg) | RS (3));
+ tcg_out32(s, EXTSB | RA(datalo) | RS(TCG_REG_R3));
break;
case 1|4:
- tcg_out32 (s, EXTSH | RA (data_reg) | RS (3));
+ tcg_out32(s, EXTSH | RA(datalo) | RS(TCG_REG_R3));
break;
case 0:
case 1:
case 2:
- if (data_reg != 3)
- tcg_out_mov (s, TCG_TYPE_I32, data_reg, 3);
+ tcg_out_mov(s, TCG_TYPE_I32, datalo, TCG_REG_R3);
break;
case 3:
- if (data_reg == 3) {
- if (data_reg2 == 4) {
- tcg_out_mov (s, TCG_TYPE_I32, 0, 4);
- tcg_out_mov (s, TCG_TYPE_I32, 4, 3);
- tcg_out_mov (s, TCG_TYPE_I32, 3, 0);
- }
- else {
- tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 3);
- tcg_out_mov (s, TCG_TYPE_I32, 3, 4);
- }
- }
- else {
- if (data_reg != 4) tcg_out_mov (s, TCG_TYPE_I32, data_reg, 4);
- if (data_reg2 != 3) tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 3);
+ datahi = l->datahi_reg;
+ if (datalo != TCG_REG_R3) {
+ tcg_out_mov(s, TCG_TYPE_I32, datalo, TCG_REG_R4);
+ tcg_out_mov(s, TCG_TYPE_I32, datahi, TCG_REG_R3);
+ } else if (datahi != TCG_REG_R4) {
+ tcg_out_mov(s, TCG_TYPE_I32, datahi, TCG_REG_R3);
+ tcg_out_mov(s, TCG_TYPE_I32, datalo, TCG_REG_R4);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R0, TCG_REG_R4);
+ tcg_out_mov(s, TCG_TYPE_I32, datahi, TCG_REG_R3);
+ tcg_out_mov(s, TCG_TYPE_I32, datalo, TCG_REG_R0);
}
break;
}
- /* Jump to the code corresponding to next IR of qemu_st */
- tcg_out_b (s, 0, (tcg_target_long) raddr);
+ tcg_out_b (s, 0, (uintptr_t)l->raddr);
}
-static void tcg_out_qemu_st_slow_path (TCGContext *s, TCGLabelQemuLdst *label)
+static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
- int ir;
- int opc = label->opc;
- int mem_index = label->mem_index;
- int data_reg = label->datalo_reg;
- int data_reg2 = label->datahi_reg;
- int addr_reg = label->addrlo_reg;
- uint8_t *raddr = label->raddr;
- uint8_t **label_ptr = &label->label_ptr[0];
-
- /* resolve label address */
- reloc_pc14 (label_ptr[0], (tcg_target_long) s->code_ptr);
-
- /* slow path */
- ir = 4;
-#if TARGET_LONG_BITS == 32
- tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg);
-#else
+ TCGReg ir, datalo;
+
+ reloc_pc14 (l->label_ptr[0], (tcg_target_long) s->code_ptr);
+
+ ir = TCG_REG_R4;
+ if (TARGET_LONG_BITS == 32) {
+ tcg_out_mov (s, TCG_TYPE_I32, ir++, l->addrlo_reg);
+ } else {
#ifdef TCG_TARGET_CALL_ALIGN_ARGS
- ir |= 1;
-#endif
- tcg_out_mov (s, TCG_TYPE_I32, ir++, label->addrhi_reg);
- tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg);
+ ir |= 1;
#endif
+ tcg_out_mov (s, TCG_TYPE_I32, ir++, l->addrhi_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, ir++, l->addrlo_reg);
+ }
- switch (opc) {
+ datalo = l->datalo_reg;
+ switch (l->opc) {
case 0:
- tcg_out32 (s, (RLWINM
- | RA (ir)
- | RS (data_reg)
- | SH (0)
- | MB (24)
- | ME (31)));
+ tcg_out32(s, (RLWINM | RA (ir) | RS (datalo)
+ | SH (0) | MB (24) | ME (31)));
break;
case 1:
- tcg_out32 (s, (RLWINM
- | RA (ir)
- | RS (data_reg)
- | SH (0)
- | MB (16)
- | ME (31)));
+ tcg_out32(s, (RLWINM | RA (ir) | RS (datalo)
+ | SH (0) | MB (16) | ME (31)));
break;
case 2:
- tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, ir, datalo);
break;
case 3:
#ifdef TCG_TARGET_CALL_ALIGN_ARGS
ir |= 1;
#endif
- tcg_out_mov (s, TCG_TYPE_I32, ir++, data_reg2);
- tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, ir++, l->datahi_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, ir, datalo);
break;
}
ir++;
- tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index);
- tcg_out_call (s, (tcg_target_long) st_trampolines[opc], 1);
- tcg_out32 (s, (tcg_target_long) raddr);
- tcg_out_b (s, 0, (tcg_target_long) raddr);
+ tcg_out_movi(s, TCG_TYPE_I32, ir++, l->mem_index);
+ tcg_out32(s, MFSPR | RT(ir++) | LR);
+ tcg_out_b(s, LK, (uintptr_t)st_trampolines[l->opc]);
+ tcg_out_b(s, 0, (uintptr_t)l->raddr);
}
void tcg_out_tb_finalize(TCGContext *s)
@@ -980,11 +911,8 @@ void tcg_out_tb_finalize(TCGContext *s)
#ifdef CONFIG_SOFTMMU
static void emit_ldst_trampoline (TCGContext *s, const void *ptr)
{
- tcg_out32 (s, MFSPR | RT (3) | LR);
- tcg_out32 (s, ADDI | RT (3) | RA (3) | 4);
- tcg_out32 (s, MTSPR | RS (3) | LR);
tcg_out_mov (s, TCG_TYPE_I32, 3, TCG_AREG0);
- tcg_out_b (s, 0, (tcg_target_long) ptr);
+ tcg_out_call (s, (tcg_target_long) ptr, 1, 0);
}
#endif
@@ -1493,7 +1421,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
}
break;
case INDEX_op_call:
- tcg_out_call (s, args[0], const_args[0]);
+ tcg_out_call (s, args[0], const_args[0], LK);
break;
case INDEX_op_movi_i32:
tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
@@ -2018,7 +1946,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L" } },
{ INDEX_op_qemu_ld32, { "r", "L" } },
- { INDEX_op_qemu_ld64, { "r", "r", "L" } },
+ { INDEX_op_qemu_ld64, { "L", "L", "L" } },
{ INDEX_op_qemu_st8, { "K", "K" } },
{ INDEX_op_qemu_st16, { "K", "K" } },
@@ -2030,7 +1958,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld32, { "r", "L", "L" } },
- { INDEX_op_qemu_ld64, { "r", "L", "L", "L" } },
+ { INDEX_op_qemu_ld64, { "L", "L", "L", "L" } },
{ INDEX_op_qemu_st8, { "K", "K", "K" } },
{ INDEX_op_qemu_st16, { "K", "K", "K" } },
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index 0bd1e0c..332f4d8 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -31,13 +31,11 @@
static uint8_t *tb_ret_addr;
-#define FAST_PATH
-
#if TARGET_LONG_BITS == 32
-#define LD_ADDR LWZU
+#define LD_ADDR LWZ
#define CMP_L 0
#else
-#define LD_ADDR LDU
+#define LD_ADDR LD
#define CMP_L (1<<21)
#endif
@@ -99,7 +97,7 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
#endif
static const int tcg_target_reg_alloc_order[] = {
- TCG_REG_R14,
+ TCG_REG_R14, /* call saved registers */
TCG_REG_R15,
TCG_REG_R16,
TCG_REG_R17,
@@ -109,29 +107,24 @@ static const int tcg_target_reg_alloc_order[] = {
TCG_REG_R21,
TCG_REG_R22,
TCG_REG_R23,
+ TCG_REG_R24,
+ TCG_REG_R25,
+ TCG_REG_R26,
+ TCG_REG_R27,
TCG_REG_R28,
TCG_REG_R29,
TCG_REG_R30,
TCG_REG_R31,
-#ifdef __APPLE__
- TCG_REG_R2,
-#endif
- TCG_REG_R3,
- TCG_REG_R4,
- TCG_REG_R5,
- TCG_REG_R6,
- TCG_REG_R7,
- TCG_REG_R8,
- TCG_REG_R9,
- TCG_REG_R10,
-#ifndef __APPLE__
+ TCG_REG_R12, /* call clobbered, non-arguments */
TCG_REG_R11,
-#endif
- TCG_REG_R12,
- TCG_REG_R24,
- TCG_REG_R25,
- TCG_REG_R26,
- TCG_REG_R27
+ TCG_REG_R10, /* call clobbered, arguments */
+ TCG_REG_R9,
+ TCG_REG_R8,
+ TCG_REG_R7,
+ TCG_REG_R6,
+ TCG_REG_R5,
+ TCG_REG_R4,
+ TCG_REG_R3,
};
static const int tcg_target_call_iarg_regs[] = {
@@ -173,58 +166,74 @@ static const int tcg_target_callee_save_regs[] = {
TCG_REG_R31
};
-static uint32_t reloc_pc24_val (void *pc, tcg_target_long target)
+static inline bool in_range_b(tcg_target_long target)
+{
+ return target == sextract64(target, 0, 26);
+}
+
+static uint32_t reloc_pc24_val(void *pc, tcg_target_long target)
{
tcg_target_long disp;
- disp = target - (tcg_target_long) pc;
- if ((disp << 38) >> 38 != disp)
- tcg_abort ();
+ disp = target - (tcg_target_long)pc;
+ assert(in_range_b(disp));
return disp & 0x3fffffc;
}
-static void reloc_pc24 (void *pc, tcg_target_long target)
+static void reloc_pc24(void *pc, tcg_target_long target)
{
- *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc)
- | reloc_pc24_val (pc, target);
+ *(uint32_t *)pc = (*(uint32_t *)pc & ~0x3fffffc)
+ | reloc_pc24_val(pc, target);
}
-static uint16_t reloc_pc14_val (void *pc, tcg_target_long target)
+static uint16_t reloc_pc14_val(void *pc, tcg_target_long target)
{
tcg_target_long disp;
- disp = target - (tcg_target_long) pc;
- if (disp != (int16_t) disp)
- tcg_abort ();
+ disp = target - (tcg_target_long)pc;
+ if (disp != (int16_t) disp) {
+ tcg_abort();
+ }
return disp & 0xfffc;
}
-static void reloc_pc14 (void *pc, tcg_target_long target)
+static void reloc_pc14(void *pc, tcg_target_long target)
+{
+ *(uint32_t *)pc = (*(uint32_t *)pc & ~0xfffc) | reloc_pc14_val(pc, target);
+}
+
+static inline void tcg_out_b_noaddr(TCGContext *s, int insn)
+{
+ unsigned retrans = *(uint32_t *)s->code_ptr & 0x3fffffc;
+ tcg_out32(s, insn | retrans);
+}
+
+static inline void tcg_out_bc_noaddr(TCGContext *s, int insn)
{
- *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc)
- | reloc_pc14_val (pc, target);
+ unsigned retrans = *(uint32_t *)s->code_ptr & 0xfffc;
+ tcg_out32(s, insn | retrans);
}
-static void patch_reloc (uint8_t *code_ptr, int type,
- intptr_t value, intptr_t addend)
+static void patch_reloc(uint8_t *code_ptr, int type,
+ intptr_t value, intptr_t addend)
{
value += addend;
switch (type) {
case R_PPC_REL14:
- reloc_pc14 (code_ptr, value);
+ reloc_pc14(code_ptr, value);
break;
case R_PPC_REL24:
- reloc_pc24 (code_ptr, value);
+ reloc_pc24(code_ptr, value);
break;
default:
- tcg_abort ();
+ tcg_abort();
}
}
/* parse target specific constraints */
-static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str)
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
{
const char *ct_str;
@@ -232,29 +241,29 @@ static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str)
switch (ct_str[0]) {
case 'A': case 'B': case 'C': case 'D':
ct->ct |= TCG_CT_REG;
- tcg_regset_set_reg (ct->u.regs, 3 + ct_str[0] - 'A');
+ tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A');
break;
case 'r':
ct->ct |= TCG_CT_REG;
- tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
break;
case 'L': /* qemu_ld constraint */
ct->ct |= TCG_CT_REG;
- tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
- tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3);
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
#ifdef CONFIG_SOFTMMU
- tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4);
- tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5);
#endif
break;
case 'S': /* qemu_st constraint */
ct->ct |= TCG_CT_REG;
- tcg_regset_set32 (ct->u.regs, 0, 0xffffffff);
- tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3);
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
#ifdef CONFIG_SOFTMMU
- tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4);
- tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5);
- tcg_regset_reset_reg (ct->u.regs, TCG_REG_R6);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6);
#endif
break;
case 'I':
@@ -284,8 +293,8 @@ static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str)
}
/* test if a constant matches the constraint */
-static int tcg_target_const_match (tcg_target_long val,
- const TCGArgConstraint *arg_ct)
+static int tcg_target_const_match(tcg_target_long val,
+ const TCGArgConstraint *arg_ct)
{
int ct = arg_ct->ct;
if (ct & TCG_CT_CONST) {
@@ -425,7 +434,7 @@ static int tcg_target_const_match (tcg_target_long val,
#define STHX XO31(407)
#define STWX XO31(151)
-#define SPR(a,b) ((((a)<<5)|(b))<<11)
+#define SPR(a, b) ((((a)<<5)|(b))<<11)
#define LR SPR(8, 0)
#define CTR SPR(9, 0)
@@ -439,7 +448,7 @@ static int tcg_target_const_match (tcg_target_long val,
#define SRADI XO31(413<<1)
#define TW XO31( 4)
-#define TRAP (TW | TO (31))
+#define TRAP (TW | TO(31))
#define RT(r) ((r)<<21)
#define RS(r) ((r)<<21)
@@ -467,9 +476,9 @@ static int tcg_target_const_match (tcg_target_long val,
#define BB(n, c) (((c)+((n)*4))<<11)
#define BC_(n, c) (((c)+((n)*4))<<6)
-#define BO_COND_TRUE BO (12)
-#define BO_COND_FALSE BO ( 4)
-#define BO_ALWAYS BO (20)
+#define BO_COND_TRUE BO(12)
+#define BO_COND_FALSE BO( 4)
+#define BO_ALWAYS BO(20)
enum {
CR_LT,
@@ -479,16 +488,16 @@ enum {
};
static const uint32_t tcg_to_bc[] = {
- [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE,
- [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE,
- [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE,
- [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE,
- [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE,
- [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE,
- [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE,
- [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE,
- [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE,
- [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
+ [TCG_COND_EQ] = BC | BI(7, CR_EQ) | BO_COND_TRUE,
+ [TCG_COND_NE] = BC | BI(7, CR_EQ) | BO_COND_FALSE,
+ [TCG_COND_LT] = BC | BI(7, CR_LT) | BO_COND_TRUE,
+ [TCG_COND_GE] = BC | BI(7, CR_LT) | BO_COND_FALSE,
+ [TCG_COND_LE] = BC | BI(7, CR_GT) | BO_COND_FALSE,
+ [TCG_COND_GT] = BC | BI(7, CR_GT) | BO_COND_TRUE,
+ [TCG_COND_LTU] = BC | BI(7, CR_LT) | BO_COND_TRUE,
+ [TCG_COND_GEU] = BC | BI(7, CR_LT) | BO_COND_FALSE,
+ [TCG_COND_LEU] = BC | BI(7, CR_GT) | BO_COND_FALSE,
+ [TCG_COND_GTU] = BC | BI(7, CR_GT) | BO_COND_TRUE,
};
/* The low bit here is set if the RA and RB fields must be inverted. */
@@ -508,15 +517,17 @@ static const uint32_t tcg_to_isel[] = {
static inline void tcg_out_mov(TCGContext *s, TCGType type,
TCGReg ret, TCGReg arg)
{
- tcg_out32 (s, OR | SAB (arg, ret, arg));
+ if (ret != arg) {
+ tcg_out32(s, OR | SAB(arg, ret, arg));
+ }
}
static inline void tcg_out_rld(TCGContext *s, int op, TCGReg ra, TCGReg rs,
int sh, int mb)
{
- sh = SH (sh & 0x1f) | (((sh >> 5) & 1) << 1);
- mb = MB64 ((mb >> 5) | ((mb << 1) & 0x3f));
- tcg_out32 (s, op | RA (ra) | RS (rs) | sh | mb);
+ sh = SH(sh & 0x1f) | (((sh >> 5) & 1) << 1);
+ mb = MB64((mb >> 5) | ((mb << 1) & 0x3f));
+ tcg_out32(s, op | RA(ra) | RS(rs) | sh | mb);
}
static inline void tcg_out_rlw(TCGContext *s, int op, TCGReg ra, TCGReg rs,
@@ -636,8 +647,8 @@ static void tcg_out_andi32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
} else if (mask_operand(c, &mb, &me)) {
tcg_out_rlw(s, RLWINM, dst, src, 0, mb, me);
} else {
- tcg_out_movi(s, TCG_TYPE_I32, 0, c);
- tcg_out32(s, AND | SAB(src, dst, 0));
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R0, c);
+ tcg_out32(s, AND | SAB(src, dst, TCG_REG_R0));
}
}
@@ -658,8 +669,8 @@ static void tcg_out_andi64(TCGContext *s, TCGReg dst, TCGReg src, uint64_t c)
tcg_out_rld(s, RLDICL, dst, src, 0, mb);
}
} else {
- tcg_out_movi(s, TCG_TYPE_I64, 0, c);
- tcg_out32(s, AND | SAB(src, dst, 0));
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, c);
+ tcg_out32(s, AND | SAB(src, dst, TCG_REG_R0));
}
}
@@ -686,123 +697,115 @@ static void tcg_out_xori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
tcg_out_zori32(s, dst, src, c, XORI, XORIS);
}
-static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
+static void tcg_out_b(TCGContext *s, int mask, tcg_target_long target)
{
tcg_target_long disp;
- disp = target - (tcg_target_long) s->code_ptr;
- if ((disp << 38) >> 38 == disp)
- tcg_out32 (s, B | (disp & 0x3fffffc) | mask);
- else {
- tcg_out_movi (s, TCG_TYPE_I64, 0, (tcg_target_long) target);
- tcg_out32 (s, MTSPR | RS (0) | CTR);
- tcg_out32 (s, BCCTR | BO_ALWAYS | mask);
+ disp = target - (tcg_target_long)s->code_ptr;
+ if (in_range_b(disp)) {
+ tcg_out32(s, B | (disp & 0x3fffffc) | mask);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, (tcg_target_long)target);
+ tcg_out32(s, MTSPR | RS(TCG_REG_R0) | CTR);
+ tcg_out32(s, BCCTR | BO_ALWAYS | mask);
}
}
-static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
+static void tcg_out_call(TCGContext *s, tcg_target_long arg, int const_arg)
{
#ifdef __APPLE__
if (const_arg) {
- tcg_out_b (s, LK, arg);
- }
- else {
- tcg_out32 (s, MTSPR | RS (arg) | LR);
- tcg_out32 (s, BCLR | BO_ALWAYS | LK);
+ tcg_out_b(s, LK, arg);
+ } else {
+ tcg_out32(s, MTSPR | RS(arg) | LR);
+ tcg_out32(s, BCLR | BO_ALWAYS | LK);
}
#else
- int reg;
+ TCGReg reg = arg;
+ int ofs = 0;
if (const_arg) {
- reg = 2;
- tcg_out_movi (s, TCG_TYPE_I64, reg, arg);
+ /* Look through the descriptor. If the branch is in range, and we
+ don't have to spend too much effort on building the toc. */
+ intptr_t tgt = ((intptr_t *)arg)[0];
+ intptr_t toc = ((intptr_t *)arg)[1];
+ intptr_t diff = tgt - (intptr_t)s->code_ptr;
+
+ if (in_range_b(diff) && toc == (uint32_t)toc) {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R2, toc);
+ tcg_out_b(s, LK, tgt);
+ return;
+ }
+
+ /* Fold the low bits of the constant into the addresses below. */
+ ofs = (int16_t)arg;
+ if (ofs + 8 < 0x8000) {
+ arg -= ofs;
+ } else {
+ ofs = 0;
+ }
+ reg = TCG_REG_R2;
+ tcg_out_movi(s, TCG_TYPE_I64, reg, arg);
}
- else reg = arg;
- tcg_out32 (s, LD | RT (0) | RA (reg));
- tcg_out32 (s, MTSPR | RA (0) | CTR);
- tcg_out32 (s, LD | RT (11) | RA (reg) | 16);
- tcg_out32 (s, LD | RT (2) | RA (reg) | 8);
- tcg_out32 (s, BCCTR | BO_ALWAYS | LK);
+ tcg_out32(s, LD | TAI(TCG_REG_R0, reg, ofs));
+ tcg_out32(s, MTSPR | RA(TCG_REG_R0) | CTR);
+ tcg_out32(s, LD | TAI(TCG_REG_R2, reg, ofs + 8));
+ tcg_out32(s, BCCTR | BO_ALWAYS | LK);
#endif
}
-static void tcg_out_ldst(TCGContext *s, TCGReg ret, TCGReg addr,
- int offset, int op1, int op2)
+static void tcg_out_mem_long(TCGContext *s, int opi, int opx, TCGReg rt,
+ TCGReg base, tcg_target_long offset)
{
- if (offset == (int16_t) offset) {
- tcg_out32(s, op1 | TAI(ret, addr, offset));
- } else {
- tcg_out_movi(s, TCG_TYPE_I64, 0, offset);
- tcg_out32(s, op2 | TAB(ret, addr, 0));
- }
-}
+ tcg_target_long orig = offset, l0, l1, extra = 0, align = 0;
+ TCGReg rs = TCG_REG_R2;
-static void tcg_out_ldsta(TCGContext *s, TCGReg ret, TCGReg addr,
- int offset, int op1, int op2)
-{
- if (offset == (int16_t) (offset & ~3)) {
- tcg_out32(s, op1 | TAI(ret, addr, offset));
- } else {
- tcg_out_movi(s, TCG_TYPE_I64, 0, offset);
- tcg_out32(s, op2 | TAB(ret, addr, 0));
- }
-}
-
-#if defined (CONFIG_SOFTMMU)
-/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
- int mmu_idx) */
-static const void * const qemu_ld_helpers[4] = {
- helper_ldb_mmu,
- helper_ldw_mmu,
- helper_ldl_mmu,
- helper_ldq_mmu,
-};
+ assert(rt != TCG_REG_R2 && base != TCG_REG_R2);
-/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
- uintxx_t val, int mmu_idx) */
-static const void * const qemu_st_helpers[4] = {
- helper_stb_mmu,
- helper_stw_mmu,
- helper_stl_mmu,
- helper_stq_mmu,
-};
+ switch (opi) {
+ case LD: case LWA:
+ align = 3;
+ /* FALLTHRU */
+ default:
+ if (rt != TCG_REG_R0) {
+ rs = rt;
+ }
+ break;
+ case STD:
+ align = 3;
+ break;
+ case STB: case STH: case STW:
+ break;
+ }
-static void tcg_out_tlb_read(TCGContext *s, TCGReg r0, TCGReg r1, TCGReg r2,
- TCGReg addr_reg, int s_bits, int offset)
-{
-#if TARGET_LONG_BITS == 32
- tcg_out_ext32u(s, addr_reg, addr_reg);
-
- tcg_out_rlw(s, RLWINM, r0, addr_reg,
- 32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS),
- 32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS),
- 31 - CPU_TLB_ENTRY_BITS);
- tcg_out32(s, ADD | TAB(r0, r0, TCG_AREG0));
- tcg_out32(s, LWZU | TAI(r1, r0, offset));
- tcg_out_rlw(s, RLWINM, r2, addr_reg, 0,
- (32 - s_bits) & 31, 31 - TARGET_PAGE_BITS);
-#else
- tcg_out_rld (s, RLDICL, r0, addr_reg,
- 64 - TARGET_PAGE_BITS,
- 64 - CPU_TLB_BITS);
- tcg_out_shli64(s, r0, r0, CPU_TLB_ENTRY_BITS);
+ /* For unaligned, or very large offsets, use the indexed form. */
+ if (offset & align || offset != (int32_t)offset) {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R2, orig);
+ tcg_out32(s, opx | TAB(rt, base, TCG_REG_R2));
+ return;
+ }
- tcg_out32(s, ADD | TAB(r0, r0, TCG_AREG0));
- tcg_out32(s, LD_ADDR | TAI(r1, r0, offset));
+ l0 = (int16_t)offset;
+ offset = (offset - l0) >> 16;
+ l1 = (int16_t)offset;
- if (!s_bits) {
- tcg_out_rld (s, RLDICR, r2, addr_reg, 0, 63 - TARGET_PAGE_BITS);
+ if (l1 < 0 && orig >= 0) {
+ extra = 0x4000;
+ l1 = (int16_t)(offset - 0x4000);
}
- else {
- tcg_out_rld (s, RLDICL, r2, addr_reg,
- 64 - TARGET_PAGE_BITS,
- TARGET_PAGE_BITS - s_bits);
- tcg_out_rld (s, RLDICL, r2, r2, TARGET_PAGE_BITS, 0);
+ if (l1) {
+ tcg_out32(s, ADDIS | TAI(rs, base, l1));
+ base = rs;
+ }
+ if (extra) {
+ tcg_out32(s, ADDIS | TAI(rs, base, extra));
+ base = rs;
+ }
+ if (opi != ADDI || base != rt || l0 != 0) {
+ tcg_out32(s, opi | TAI(rt, base, l0));
}
-#endif
}
-#endif
static const uint32_t qemu_ldx_opc[8] = {
#ifdef TARGET_WORDS_BIGENDIAN
@@ -826,105 +829,251 @@ static const uint32_t qemu_exts_opc[4] = {
EXTSB, EXTSH, EXTSW, 0
};
-static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
+#if defined (CONFIG_SOFTMMU)
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+ * int mmu_idx, uintptr_t ra)
+ */
+static const void * const qemu_ld_helpers[4] = {
+ helper_ret_ldub_mmu,
+ helper_ret_lduw_mmu,
+ helper_ret_ldul_mmu,
+ helper_ret_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+ * uintxx_t val, int mmu_idx, uintptr_t ra)
+ */
+static const void * const qemu_st_helpers[4] = {
+ helper_ret_stb_mmu,
+ helper_ret_stw_mmu,
+ helper_ret_stl_mmu,
+ helper_ret_stq_mmu,
+};
+
+/* Perform the TLB load and compare. Places the result of the comparison
+ in CR7, loads the addend of the TLB into R3, and returns the register
+ containing the guest address (zero-extended into R4). Clobbers R0 and R2. */
+
+static TCGReg tcg_out_tlb_read(TCGContext *s, int s_bits, TCGReg addr_reg,
+ int mem_index, bool is_read)
{
- TCGReg addr_reg, data_reg, r0, r1, rbase;
- uint32_t insn, s_bits;
-#ifdef CONFIG_SOFTMMU
- TCGReg r2, ir;
- int mem_index;
- void *label1_ptr, *label2_ptr;
-#endif
+ int cmp_off
+ = (is_read
+ ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read)
+ : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write));
+ int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend);
+ TCGReg base = TCG_AREG0;
+
+ /* Extract the page index, shifted into place for tlb index. */
+ if (TARGET_LONG_BITS == 32) {
+ /* Zero-extend the address into a place helpful for further use. */
+ tcg_out_ext32u(s, TCG_REG_R4, addr_reg);
+ addr_reg = TCG_REG_R4;
+ } else {
+ tcg_out_rld(s, RLDICL, TCG_REG_R3, addr_reg,
+ 64 - TARGET_PAGE_BITS, 64 - CPU_TLB_BITS);
+ }
- data_reg = *args++;
- addr_reg = *args++;
- s_bits = opc & 3;
+ /* Compensate for very large offsets. */
+ if (add_off >= 0x8000) {
+ /* Most target env are smaller than 32k; none are larger than 64k.
+ Simplify the logic here merely to offset by 0x7ff0, giving us a
+ range just shy of 64k. Check this assumption. */
+ QEMU_BUILD_BUG_ON(offsetof(CPUArchState,
+ tlb_table[NB_MMU_MODES - 1][1])
+ > 0x7ff0 + 0x7fff);
+ tcg_out32(s, ADDI | TAI(TCG_REG_R2, base, 0x7ff0));
+ base = TCG_REG_R2;
+ cmp_off -= 0x7ff0;
+ add_off -= 0x7ff0;
+ }
-#ifdef CONFIG_SOFTMMU
- mem_index = *args;
+ /* Extraction and shifting, part 2. */
+ if (TARGET_LONG_BITS == 32) {
+ tcg_out_rlw(s, RLWINM, TCG_REG_R3, addr_reg,
+ 32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS),
+ 32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS),
+ 31 - CPU_TLB_ENTRY_BITS);
+ } else {
+ tcg_out_shli64(s, TCG_REG_R3, TCG_REG_R3, CPU_TLB_ENTRY_BITS);
+ }
- r0 = 3;
- r1 = 4;
- r2 = 0;
- rbase = 0;
+ tcg_out32(s, ADD | TAB(TCG_REG_R3, TCG_REG_R3, base));
- tcg_out_tlb_read (s, r0, r1, r2, addr_reg, s_bits,
- offsetof (CPUArchState, tlb_table[mem_index][0].addr_read));
+ /* Load the tlb comparator. */
+ tcg_out32(s, LD_ADDR | TAI(TCG_REG_R2, TCG_REG_R3, cmp_off));
- tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L);
+ /* Load the TLB addend for use on the fast path. Do this asap
+ to minimize any load use delay. */
+ tcg_out32(s, LD | TAI(TCG_REG_R3, TCG_REG_R3, add_off));
- label1_ptr = s->code_ptr;
-#ifdef FAST_PATH
- tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
-#endif
+ /* Clear the non-page, non-alignment bits from the address. */
+ if (TARGET_LONG_BITS == 32) {
+ tcg_out_rlw(s, RLWINM, TCG_REG_R0, addr_reg, 0,
+ (32 - s_bits) & 31, 31 - TARGET_PAGE_BITS);
+ } else if (!s_bits) {
+ tcg_out_rld(s, RLDICR, TCG_REG_R0, addr_reg, 0, 63 - TARGET_PAGE_BITS);
+ } else {
+ tcg_out_rld(s, RLDICL, TCG_REG_R0, addr_reg,
+ 64 - TARGET_PAGE_BITS, TARGET_PAGE_BITS - s_bits);
+ tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, TARGET_PAGE_BITS, 0);
+ }
+
+ tcg_out32(s, CMP | BF(7) | RA(TCG_REG_R0) | RB(TCG_REG_R2) | CMP_L);
+
+ return addr_reg;
+}
+
+/* Record the context of a call to the out of line helper code for the slow
+ path for a load or store, so that we can later generate the correct
+ helper code. */
+static void add_qemu_ldst_label(TCGContext *s, bool is_ld, int opc,
+ int data_reg, int addr_reg, int mem_index,
+ uint8_t *raddr, uint8_t *label_ptr)
+{
+ int idx;
+ TCGLabelQemuLdst *label;
- /* slow path */
- ir = 3;
- tcg_out_mov (s, TCG_TYPE_I64, ir++, TCG_AREG0);
- tcg_out_mov (s, TCG_TYPE_I64, ir++, addr_reg);
- tcg_out_movi (s, TCG_TYPE_I64, ir++, mem_index);
+ if (s->nb_qemu_ldst_labels >= TCG_MAX_QEMU_LDST) {
+ tcg_abort();
+ }
+
+ idx = s->nb_qemu_ldst_labels++;
+ label = (TCGLabelQemuLdst *)&s->qemu_ldst_labels[idx];
+ label->is_ld = is_ld;
+ label->opc = opc;
+ label->datalo_reg = data_reg;
+ label->addrlo_reg = addr_reg;
+ label->mem_index = mem_index;
+ label->raddr = raddr;
+ label->label_ptr[0] = label_ptr;
+}
+
+static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
+{
+ int opc = lb->opc;
+ int s_bits = opc & 3;
+
+ reloc_pc14(lb->label_ptr[0], (uintptr_t)s->code_ptr);
+
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R3, TCG_AREG0);
- tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
+ /* If the address needed to be zero-extended, we'll have already
+ placed it in R4. The only remaining case is 64-bit guest. */
+ tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R4, lb->addrlo_reg);
+
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R5, lb->mem_index);
+ tcg_out32(s, MFSPR | RT(TCG_REG_R6) | LR);
+
+ tcg_out_call(s, (tcg_target_long)qemu_ld_helpers[s_bits], 1);
if (opc & 4) {
- insn = qemu_exts_opc[s_bits];
- tcg_out32(s, insn | RA(data_reg) | RS(3));
- } else if (data_reg != 3) {
- tcg_out_mov(s, TCG_TYPE_I64, data_reg, 3);
+ uint32_t insn = qemu_exts_opc[s_bits];
+ tcg_out32(s, insn | RA(lb->datalo_reg) | RS(TCG_REG_R3));
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I64, lb->datalo_reg, TCG_REG_R3);
}
- label2_ptr = s->code_ptr;
- tcg_out32 (s, B);
- /* label1: fast path */
-#ifdef FAST_PATH
- reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
+ tcg_out_b(s, 0, (uintptr_t)lb->raddr);
+}
+
+static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
+{
+ int opc = lb->opc;
+
+ reloc_pc14(lb->label_ptr[0], (uintptr_t)s->code_ptr);
+
+ tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R3, TCG_AREG0);
+
+ /* If the address needed to be zero-extended, we'll have already
+ placed it in R4. The only remaining case is 64-bit guest. */
+ tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R4, lb->addrlo_reg);
+
+ tcg_out_rld(s, RLDICL, TCG_REG_R5, lb->datalo_reg,
+ 0, 64 - (1 << (3 + opc)));
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R6, lb->mem_index);
+ tcg_out32(s, MFSPR | RT(TCG_REG_R7) | LR);
+
+ tcg_out_call(s, (tcg_target_long)qemu_st_helpers[opc], 1);
+
+ tcg_out_b(s, 0, (uintptr_t)lb->raddr);
+}
+
+void tcg_out_tb_finalize(TCGContext *s)
+{
+ int i, n = s->nb_qemu_ldst_labels;
+
+ /* qemu_ld/st slow paths */
+ for (i = 0; i < n; i++) {
+ TCGLabelQemuLdst *label = &s->qemu_ldst_labels[i];
+ if (label->is_ld) {
+ tcg_out_qemu_ld_slow_path(s, label);
+ } else {
+ tcg_out_qemu_st_slow_path(s, label);
+ }
+ }
+}
+#endif /* SOFTMMU */
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+ TCGReg addr_reg, data_reg, rbase;
+ uint32_t insn, s_bits;
+#ifdef CONFIG_SOFTMMU
+ int mem_index;
+ void *label_ptr;
#endif
- /* r0 now contains &env->tlb_table[mem_index][index].addr_read */
- tcg_out32(s, LD | TAI(r0, r0,
- offsetof(CPUTLBEntry, addend)
- - offsetof(CPUTLBEntry, addr_read)));
- /* r0 = env->tlb_table[mem_index][index].addend */
- tcg_out32(s, ADD | TAB(r0, r0, addr_reg));
- /* r0 = env->tlb_table[mem_index][index].addend + addr */
+ data_reg = *args++;
+ addr_reg = *args++;
+ s_bits = opc & 3;
+
+#ifdef CONFIG_SOFTMMU
+ mem_index = *args;
+ addr_reg = tcg_out_tlb_read(s, s_bits, addr_reg, mem_index, true);
+
+ /* Load a pointer into the current opcode w/conditional branch-link. */
+ label_ptr = s->code_ptr;
+ tcg_out_bc_noaddr(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK);
+
+ rbase = TCG_REG_R3;
#else /* !CONFIG_SOFTMMU */
-#if TARGET_LONG_BITS == 32
- tcg_out_ext32u(s, addr_reg, addr_reg);
-#endif
- r0 = addr_reg;
- r1 = 3;
rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+ if (TARGET_LONG_BITS == 32) {
+ tcg_out_ext32u(s, TCG_REG_R2, addr_reg);
+ addr_reg = TCG_REG_R2;
+ }
#endif
insn = qemu_ldx_opc[opc];
if (!HAVE_ISA_2_06 && insn == LDBRX) {
- tcg_out32(s, ADDI | TAI(r1, r0, 4));
- tcg_out32(s, LWBRX | TAB(data_reg, rbase, r0));
- tcg_out32(s, LWBRX | TAB( r1, rbase, r1));
- tcg_out_rld(s, RLDIMI, data_reg, r1, 32, 0);
+ tcg_out32(s, ADDI | TAI(TCG_REG_R0, addr_reg, 4));
+ tcg_out32(s, LWBRX | TAB(data_reg, rbase, addr_reg));
+ tcg_out32(s, LWBRX | TAB(TCG_REG_R0, rbase, TCG_REG_R0));
+ tcg_out_rld(s, RLDIMI, data_reg, TCG_REG_R0, 32, 0);
} else if (insn) {
- tcg_out32(s, insn | TAB(data_reg, rbase, r0));
+ tcg_out32(s, insn | TAB(data_reg, rbase, addr_reg));
} else {
insn = qemu_ldx_opc[s_bits];
- tcg_out32(s, insn | TAB(data_reg, rbase, r0));
+ tcg_out32(s, insn | TAB(data_reg, rbase, addr_reg));
insn = qemu_exts_opc[s_bits];
- tcg_out32 (s, insn | RA(data_reg) | RS(data_reg));
+ tcg_out32(s, insn | RA(data_reg) | RS(data_reg));
}
#ifdef CONFIG_SOFTMMU
- reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+ add_qemu_ldst_label(s, true, opc, data_reg, addr_reg, mem_index,
+ s->code_ptr, label_ptr);
#endif
}
-static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
{
- TCGReg addr_reg, r0, r1, rbase, data_reg;
+ TCGReg addr_reg, rbase, data_reg;
uint32_t insn;
#ifdef CONFIG_SOFTMMU
- TCGReg r2, ir;
int mem_index;
- void *label1_ptr, *label2_ptr;
+ void *label_ptr;
#endif
data_reg = *args++;
@@ -933,158 +1082,122 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
#ifdef CONFIG_SOFTMMU
mem_index = *args;
- r0 = 3;
- r1 = 4;
- r2 = 0;
- rbase = 0;
-
- tcg_out_tlb_read (s, r0, r1, r2, addr_reg, opc,
- offsetof (CPUArchState, tlb_table[mem_index][0].addr_write));
-
- tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1) | CMP_L);
-
- label1_ptr = s->code_ptr;
-#ifdef FAST_PATH
- tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE);
-#endif
-
- /* slow path */
- ir = 3;
- tcg_out_mov (s, TCG_TYPE_I64, ir++, TCG_AREG0);
- tcg_out_mov (s, TCG_TYPE_I64, ir++, addr_reg);
- tcg_out_rld (s, RLDICL, ir++, data_reg, 0, 64 - (1 << (3 + opc)));
- tcg_out_movi (s, TCG_TYPE_I64, ir++, mem_index);
+ addr_reg = tcg_out_tlb_read(s, opc, addr_reg, mem_index, false);
- tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
-
- label2_ptr = s->code_ptr;
- tcg_out32 (s, B);
-
- /* label1: fast path */
-#ifdef FAST_PATH
- reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr);
-#endif
-
- tcg_out32 (s, (LD
- | RT (r0)
- | RA (r0)
- | (offsetof (CPUTLBEntry, addend)
- - offsetof (CPUTLBEntry, addr_write))
- ));
- /* r0 = env->tlb_table[mem_index][index].addend */
- tcg_out32(s, ADD | TAB(r0, r0, addr_reg));
- /* r0 = env->tlb_table[mem_index][index].addend + addr */
+ /* Load a pointer into the current opcode w/conditional branch-link. */
+ label_ptr = s->code_ptr;
+ tcg_out_bc_noaddr(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK);
+ rbase = TCG_REG_R3;
#else /* !CONFIG_SOFTMMU */
-#if TARGET_LONG_BITS == 32
- tcg_out_ext32u(s, addr_reg, addr_reg);
-#endif
- r1 = 3;
- r0 = addr_reg;
rbase = GUEST_BASE ? TCG_GUEST_BASE_REG : 0;
+ if (TARGET_LONG_BITS == 32) {
+ tcg_out_ext32u(s, TCG_REG_R2, addr_reg);
+ addr_reg = TCG_REG_R2;
+ }
#endif
insn = qemu_stx_opc[opc];
if (!HAVE_ISA_2_06 && insn == STDBRX) {
- tcg_out32(s, STWBRX | SAB(data_reg, rbase, r0));
- tcg_out32(s, ADDI | TAI(r1, r0, 4));
- tcg_out_shri64(s, 0, data_reg, 32);
- tcg_out32(s, STWBRX | SAB(0, rbase, r1));
+ tcg_out32(s, STWBRX | SAB(data_reg, rbase, addr_reg));
+ tcg_out32(s, ADDI | TAI(TCG_REG_R2, addr_reg, 4));
+ tcg_out_shri64(s, TCG_REG_R0, data_reg, 32);
+ tcg_out32(s, STWBRX | SAB(TCG_REG_R0, rbase, TCG_REG_R2));
} else {
- tcg_out32(s, insn | SAB(data_reg, rbase, r0));
+ tcg_out32(s, insn | SAB(data_reg, rbase, addr_reg));
}
#ifdef CONFIG_SOFTMMU
- reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr);
+ add_qemu_ldst_label(s, false, opc, data_reg, addr_reg, mem_index,
+ s->code_ptr, label_ptr);
#endif
}
-static void tcg_target_qemu_prologue (TCGContext *s)
+#define FRAME_SIZE ((int) \
+ ((8 /* back chain */ \
+ + 8 /* CR */ \
+ + 8 /* LR */ \
+ + 8 /* compiler doubleword */ \
+ + 8 /* link editor doubleword */ \
+ + 8 /* TOC save area */ \
+ + TCG_STATIC_CALL_ARGS_SIZE \
+ + CPU_TEMP_BUF_NLONGS * sizeof(long) \
+ + ARRAY_SIZE(tcg_target_callee_save_regs) * 8 \
+ + 15) & ~15))
+
+#define REG_SAVE_BOT (FRAME_SIZE - ARRAY_SIZE(tcg_target_callee_save_regs) * 8)
+
+static void tcg_target_qemu_prologue(TCGContext *s)
{
- int i, frame_size;
-#ifndef __APPLE__
- uint64_t addr;
-#endif
+ int i;
- frame_size = 0
- + 8 /* back chain */
- + 8 /* CR */
- + 8 /* LR */
- + 8 /* compiler doubleword */
- + 8 /* link editor doubleword */
- + 8 /* TOC save area */
- + TCG_STATIC_CALL_ARGS_SIZE
- + ARRAY_SIZE (tcg_target_callee_save_regs) * 8
- + CPU_TEMP_BUF_NLONGS * sizeof(long)
- ;
- frame_size = (frame_size + 15) & ~15;
-
- tcg_set_frame (s, TCG_REG_CALL_STACK, frame_size
- - CPU_TEMP_BUF_NLONGS * sizeof (long),
- CPU_TEMP_BUF_NLONGS * sizeof (long));
+ tcg_set_frame(s, TCG_REG_CALL_STACK,
+ REG_SAVE_BOT - CPU_TEMP_BUF_NLONGS * sizeof(long),
+ CPU_TEMP_BUF_NLONGS * sizeof(long));
#ifndef __APPLE__
/* First emit adhoc function descriptor */
- addr = (uint64_t) s->code_ptr + 24;
- tcg_out32 (s, addr >> 32); tcg_out32 (s, addr); /* entry point */
+ tcg_out64(s, (uint64_t)s->code_ptr + 24); /* entry point */
s->code_ptr += 16; /* skip TOC and environment pointer */
#endif
/* Prologue */
- tcg_out32 (s, MFSPR | RT (0) | LR);
- tcg_out32 (s, STDU | RS (1) | RA (1) | (-frame_size & 0xffff));
- for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
- tcg_out32 (s, (STD
- | RS (tcg_target_callee_save_regs[i])
- | RA (1)
- | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE)
- )
- );
- tcg_out32 (s, STD | RS (0) | RA (1) | (frame_size + 16));
+ tcg_out32(s, MFSPR | RT(TCG_REG_R0) | LR);
+ tcg_out32(s, STDU | SAI(TCG_REG_R1, TCG_REG_R1, -FRAME_SIZE));
+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); ++i) {
+ tcg_out32(s, STD | SAI(tcg_target_callee_save_regs[i], 1,
+ REG_SAVE_BOT + i * 8));
+ }
+ tcg_out32(s, STD | SAI(TCG_REG_R0, TCG_REG_R1, FRAME_SIZE + 16));
#ifdef CONFIG_USE_GUEST_BASE
if (GUEST_BASE) {
- tcg_out_movi (s, TCG_TYPE_I64, TCG_GUEST_BASE_REG, GUEST_BASE);
- tcg_regset_set_reg (s->reserved_regs, TCG_GUEST_BASE_REG);
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_GUEST_BASE_REG, GUEST_BASE);
+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
}
#endif
- tcg_out_mov (s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
- tcg_out32 (s, MTSPR | RS (tcg_target_call_iarg_regs[1]) | CTR);
- tcg_out32 (s, BCCTR | BO_ALWAYS);
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+ tcg_out32(s, MTSPR | RS(tcg_target_call_iarg_regs[1]) | CTR);
+ tcg_out32(s, BCCTR | BO_ALWAYS);
/* Epilogue */
tb_ret_addr = s->code_ptr;
- for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
- tcg_out32 (s, (LD
- | RT (tcg_target_callee_save_regs[i])
- | RA (1)
- | (i * 8 + 48 + TCG_STATIC_CALL_ARGS_SIZE)
- )
- );
- tcg_out32(s, LD | TAI(0, 1, frame_size + 16));
- tcg_out32(s, MTSPR | RS(0) | LR);
- tcg_out32(s, ADDI | TAI(1, 1, frame_size));
+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); ++i) {
+ tcg_out32(s, LD | TAI(tcg_target_callee_save_regs[i], TCG_REG_R1,
+ REG_SAVE_BOT + i * 8));
+ }
+ tcg_out32(s, LD | TAI(TCG_REG_R0, TCG_REG_R1, FRAME_SIZE + 16));
+ tcg_out32(s, MTSPR | RS(TCG_REG_R0) | LR);
+ tcg_out32(s, ADDI | TAI(TCG_REG_R1, TCG_REG_R1, FRAME_SIZE));
tcg_out32(s, BCLR | BO_ALWAYS);
}
-static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
- intptr_t arg2)
+static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
+ TCGReg arg1, intptr_t arg2)
{
- if (type == TCG_TYPE_I32)
- tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX);
- else
- tcg_out_ldsta (s, ret, arg1, arg2, LD, LDX);
+ int opi, opx;
+
+ if (type == TCG_TYPE_I32) {
+ opi = LWZ, opx = LWZX;
+ } else {
+ opi = LD, opx = LDX;
+ }
+ tcg_out_mem_long(s, opi, opx, ret, arg1, arg2);
}
-static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
- intptr_t arg2)
+static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
+ TCGReg arg1, intptr_t arg2)
{
- if (type == TCG_TYPE_I32)
- tcg_out_ldst (s, arg, arg1, arg2, STW, STWX);
- else
- tcg_out_ldsta (s, arg, arg1, arg2, STD, STDX);
+ int opi, opx;
+
+ if (type == TCG_TYPE_I32) {
+ opi = STW, opx = STWX;
+ } else {
+ opi = STD, opx = STDX;
+ }
+ tcg_out_mem_long(s, opi, opx, arg, arg1, arg2);
}
static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
@@ -1106,8 +1219,7 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
op = CMPI;
imm = 1;
break;
- }
- else if ((uint16_t) arg2 == arg2) {
+ } else if ((uint16_t) arg2 == arg2) {
op = CMPLI;
imm = 1;
break;
@@ -1148,7 +1260,7 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
break;
default:
- tcg_abort ();
+ tcg_abort();
}
op |= BF(cr) | ((type == TCG_TYPE_I64) << 21);
@@ -1156,8 +1268,8 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
tcg_out32(s, op | RA(arg1) | (arg2 & 0xffff));
} else {
if (const_arg2) {
- tcg_out_movi(s, type, 0, arg2);
- arg2 = 0;
+ tcg_out_movi(s, type, TCG_REG_R0, arg2);
+ arg2 = TCG_REG_R0;
}
tcg_out32(s, op | RA(arg1) | RB(arg2));
}
@@ -1178,8 +1290,8 @@ static void tcg_out_setcond_ne0(TCGContext *s, TCGReg dst, TCGReg src)
tcg_out32(s, ADDIC | TAI(dst, src, -1));
tcg_out32(s, SUBFE | TAB(dst, dst, src));
} else {
- tcg_out32(s, ADDIC | TAI(0, src, -1));
- tcg_out32(s, SUBFE | TAB(dst, 0, src));
+ tcg_out32(s, ADDIC | TAI(TCG_REG_R0, src, -1));
+ tcg_out32(s, SUBFE | TAB(dst, TCG_REG_R0, src));
}
}
@@ -1292,13 +1404,13 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond,
case TCG_COND_GE:
case TCG_COND_GEU:
sh = 31;
- crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_LT) | BB (7, CR_LT);
+ crop = CRNOR | BT(7, CR_EQ) | BA(7, CR_LT) | BB(7, CR_LT);
goto crtest;
case TCG_COND_LE:
case TCG_COND_LEU:
sh = 31;
- crop = CRNOR | BT (7, CR_EQ) | BA (7, CR_GT) | BB (7, CR_GT);
+ crop = CRNOR | BT(7, CR_EQ) | BA(7, CR_GT) | BB(7, CR_GT);
crtest:
tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 7, type);
if (crop) {
@@ -1309,22 +1421,19 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond,
break;
default:
- tcg_abort ();
+ tcg_abort();
}
}
-static void tcg_out_bc (TCGContext *s, int bc, int label_index)
+static void tcg_out_bc(TCGContext *s, int bc, int label_index)
{
TCGLabel *l = &s->labels[label_index];
- if (l->has_value)
- tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value));
- else {
- uint16_t val = *(uint16_t *) &s->code_ptr[2];
-
- /* Thanks to Andrzej Zaborowski */
- tcg_out32 (s, bc | (val & 0xfffc));
- tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0);
+ if (l->has_value) {
+ tcg_out32(s, bc | reloc_pc14_val(s->code_ptr, l->u.value));
+ } else {
+ tcg_out_reloc(s, s->code_ptr, R_PPC_REL14, label_index, 0);
+ tcg_out_bc_noaddr(s, bc);
}
}
@@ -1360,7 +1469,7 @@ static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond,
}
/* V1 == 0 is handled by isel; V2 == 0 must be handled by hand. */
if (v2 == 0) {
- tcg_out_movi(s, type, 0, 0);
+ tcg_out_movi(s, type, TCG_REG_R0, 0);
}
tcg_out32(s, isel | TAB(dest, v1, v2));
} else {
@@ -1384,37 +1493,36 @@ static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond,
}
}
-void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr)
+void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr)
{
TCGContext s;
unsigned long patch_size;
s.code_ptr = (uint8_t *) jmp_addr;
- tcg_out_b (&s, 0, addr);
+ tcg_out_b(&s, 0, addr);
patch_size = s.code_ptr - (uint8_t *) jmp_addr;
- flush_icache_range (jmp_addr, jmp_addr + patch_size);
+ flush_icache_range(jmp_addr, jmp_addr + patch_size);
}
-static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
- const int *const_args)
+static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+ const int *const_args)
{
TCGArg a0, a1, a2;
int c;
switch (opc) {
case INDEX_op_exit_tb:
- tcg_out_movi (s, TCG_TYPE_I64, TCG_REG_R3, args[0]);
- tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr);
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R3, args[0]);
+ tcg_out_b(s, 0, (tcg_target_long)tb_ret_addr);
break;
case INDEX_op_goto_tb:
if (s->tb_jmp_offset) {
- /* direct jump method */
-
+ /* Direct jump method. */
s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
s->code_ptr += 28;
- }
- else {
- tcg_abort ();
+ } else {
+ /* Indirect jump method. */
+ tcg_abort();
}
s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
break;
@@ -1423,83 +1531,70 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
TCGLabel *l = &s->labels[args[0]];
if (l->has_value) {
- tcg_out_b (s, 0, l->u.value);
- }
- else {
- uint32_t val = *(uint32_t *) s->code_ptr;
-
- /* Thanks to Andrzej Zaborowski */
- tcg_out32 (s, B | (val & 0x3fffffc));
- tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0);
+ tcg_out_b(s, 0, l->u.value);
+ } else {
+ tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, args[0], 0);
+ tcg_out_b_noaddr(s, B);
}
}
break;
case INDEX_op_call:
- tcg_out_call (s, args[0], const_args[0]);
+ tcg_out_call(s, args[0], const_args[0]);
break;
case INDEX_op_movi_i32:
- tcg_out_movi (s, TCG_TYPE_I32, args[0], args[1]);
+ tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
break;
case INDEX_op_movi_i64:
- tcg_out_movi (s, TCG_TYPE_I64, args[0], args[1]);
+ tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
break;
case INDEX_op_ld8u_i32:
case INDEX_op_ld8u_i64:
- tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
+ tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]);
break;
case INDEX_op_ld8s_i32:
case INDEX_op_ld8s_i64:
- tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX);
- tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0]));
+ tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]);
+ tcg_out32(s, EXTSB | RS(args[0]) | RA(args[0]));
break;
case INDEX_op_ld16u_i32:
case INDEX_op_ld16u_i64:
- tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX);
+ tcg_out_mem_long(s, LHZ, LHZX, args[0], args[1], args[2]);
break;
case INDEX_op_ld16s_i32:
case INDEX_op_ld16s_i64:
- tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX);
+ tcg_out_mem_long(s, LHA, LHAX, args[0], args[1], args[2]);
break;
case INDEX_op_ld_i32:
case INDEX_op_ld32u_i64:
- tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX);
+ tcg_out_mem_long(s, LWZ, LWZX, args[0], args[1], args[2]);
break;
case INDEX_op_ld32s_i64:
- tcg_out_ldsta (s, args[0], args[1], args[2], LWA, LWAX);
+ tcg_out_mem_long(s, LWA, LWAX, args[0], args[1], args[2]);
break;
case INDEX_op_ld_i64:
- tcg_out_ldsta (s, args[0], args[1], args[2], LD, LDX);
+ tcg_out_mem_long(s, LD, LDX, args[0], args[1], args[2]);
break;
case INDEX_op_st8_i32:
case INDEX_op_st8_i64:
- tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX);
+ tcg_out_mem_long(s, STB, STBX, args[0], args[1], args[2]);
break;
case INDEX_op_st16_i32:
case INDEX_op_st16_i64:
- tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX);
+ tcg_out_mem_long(s, STH, STHX, args[0], args[1], args[2]);
break;
case INDEX_op_st_i32:
case INDEX_op_st32_i64:
- tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX);
+ tcg_out_mem_long(s, STW, STWX, args[0], args[1], args[2]);
break;
case INDEX_op_st_i64:
- tcg_out_ldsta (s, args[0], args[1], args[2], STD, STDX);
+ tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]);
break;
case INDEX_op_add_i32:
a0 = args[0], a1 = args[1], a2 = args[2];
if (const_args[2]) {
- int32_t l, h;
do_addi_32:
- l = (int16_t)a2;
- h = a2 - l;
- if (h) {
- tcg_out32(s, ADDIS | TAI(a0, a1, h >> 16));
- a1 = a0;
- }
- if (l || a0 != a1) {
- tcg_out32(s, ADDI | TAI(a0, a1, l));
- }
+ tcg_out_mem_long(s, ADDI, ADD, a0, a1, (int32_t)a2);
} else {
tcg_out32(s, ADD | TAB(a0, a1, a2));
}
@@ -1607,32 +1702,33 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
break;
case INDEX_op_div_i32:
- tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2]));
+ tcg_out32(s, DIVW | TAB(args[0], args[1], args[2]));
break;
case INDEX_op_divu_i32:
- tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2]));
+ tcg_out32(s, DIVWU | TAB(args[0], args[1], args[2]));
break;
case INDEX_op_shl_i32:
if (const_args[2]) {
tcg_out_rlw(s, RLWINM, args[0], args[1], args[2], 0, 31 - args[2]);
} else {
- tcg_out32 (s, SLW | SAB (args[1], args[0], args[2]));
+ tcg_out32(s, SLW | SAB(args[1], args[0], args[2]));
}
break;
case INDEX_op_shr_i32:
if (const_args[2]) {
tcg_out_rlw(s, RLWINM, args[0], args[1], 32 - args[2], args[2], 31);
} else {
- tcg_out32 (s, SRW | SAB (args[1], args[0], args[2]));
+ tcg_out32(s, SRW | SAB(args[1], args[0], args[2]));
}
break;
case INDEX_op_sar_i32:
- if (const_args[2])
- tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2]));
- else
- tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2]));
+ if (const_args[2]) {
+ tcg_out32(s, SRAWI | RS(args[1]) | RA(args[0]) | SH(args[2]));
+ } else {
+ tcg_out32(s, SRAW | SAB(args[1], args[0], args[2]));
+ }
break;
case INDEX_op_rotl_i32:
if (const_args[2]) {
@@ -1646,8 +1742,8 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
if (const_args[2]) {
tcg_out_rlw(s, RLWINM, args[0], args[1], 32 - args[2], 0, 31);
} else {
- tcg_out32(s, SUBFIC | TAI(0, args[2], 32));
- tcg_out32(s, RLWNM | SAB(args[1], args[0], 0)
+ tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 32));
+ tcg_out32(s, RLWNM | SAB(args[1], args[0], TCG_REG_R0)
| MB(0) | ME(31));
}
break;
@@ -1664,43 +1760,19 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_neg_i32:
case INDEX_op_neg_i64:
- tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
+ tcg_out32(s, NEG | RT(args[0]) | RA(args[1]));
break;
case INDEX_op_not_i32:
case INDEX_op_not_i64:
- tcg_out32 (s, NOR | SAB (args[1], args[0], args[1]));
+ tcg_out32(s, NOR | SAB(args[1], args[0], args[1]));
break;
case INDEX_op_add_i64:
a0 = args[0], a1 = args[1], a2 = args[2];
if (const_args[2]) {
- int32_t l0, h1, h2;
do_addi_64:
- /* We can always split any 32-bit signed constant into 3 pieces.
- Note the positive 0x80000000 coming from the sub_i64 path,
- handled with the same code we need for eg 0x7fff8000. */
- assert(a2 == (int32_t)a2 || a2 == 0x80000000);
- l0 = (int16_t)a2;
- h1 = a2 - l0;
- h2 = 0;
- if (h1 < 0 && (int64_t)a2 > 0) {
- h2 = 0x40000000;
- h1 = a2 - h2 - l0;
- }
- assert((TCGArg)h2 + h1 + l0 == a2);
-
- if (h2) {
- tcg_out32(s, ADDIS | TAI(a0, a1, h2 >> 16));
- a1 = a0;
- }
- if (h1) {
- tcg_out32(s, ADDIS | TAI(a0, a1, h1 >> 16));
- a1 = a0;
- }
- if (l0 || a0 != a1) {
- tcg_out32(s, ADDI | TAI(a0, a1, l0));
- }
+ tcg_out_mem_long(s, ADDI, ADD, a0, a1, a2);
} else {
tcg_out32(s, ADD | TAB(a0, a1, a2));
}
@@ -1722,24 +1794,26 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
break;
case INDEX_op_shl_i64:
- if (const_args[2])
+ if (const_args[2]) {
tcg_out_shli64(s, args[0], args[1], args[2]);
- else
- tcg_out32 (s, SLD | SAB (args[1], args[0], args[2]));
+ } else {
+ tcg_out32(s, SLD | SAB(args[1], args[0], args[2]));
+ }
break;
case INDEX_op_shr_i64:
- if (const_args[2])
+ if (const_args[2]) {
tcg_out_shri64(s, args[0], args[1], args[2]);
- else
- tcg_out32 (s, SRD | SAB (args[1], args[0], args[2]));
+ } else {
+ tcg_out32(s, SRD | SAB(args[1], args[0], args[2]));
+ }
break;
case INDEX_op_sar_i64:
if (const_args[2]) {
- int sh = SH (args[2] & 0x1f) | (((args[2] >> 5) & 1) << 1);
- tcg_out32 (s, SRADI | RA (args[0]) | RS (args[1]) | sh);
+ int sh = SH(args[2] & 0x1f) | (((args[2] >> 5) & 1) << 1);
+ tcg_out32(s, SRADI | RA(args[0]) | RS(args[1]) | sh);
+ } else {
+ tcg_out32(s, SRAD | SAB(args[1], args[0], args[2]));
}
- else
- tcg_out32 (s, SRAD | SAB (args[1], args[0], args[2]));
break;
case INDEX_op_rotl_i64:
if (const_args[2]) {
@@ -1752,8 +1826,8 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
if (const_args[2]) {
tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 0);
} else {
- tcg_out32(s, SUBFIC | TAI(0, args[2], 64));
- tcg_out32(s, RLDCL | SAB(args[1], args[0], 0) | MB64(0));
+ tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 64));
+ tcg_out32(s, RLDCL | SAB(args[1], args[0], TCG_REG_R0) | MB64(0));
}
break;
@@ -1766,45 +1840,45 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
}
break;
case INDEX_op_div_i64:
- tcg_out32 (s, DIVD | TAB (args[0], args[1], args[2]));
+ tcg_out32(s, DIVD | TAB(args[0], args[1], args[2]));
break;
case INDEX_op_divu_i64:
- tcg_out32 (s, DIVDU | TAB (args[0], args[1], args[2]));
+ tcg_out32(s, DIVDU | TAB(args[0], args[1], args[2]));
break;
case INDEX_op_qemu_ld8u:
- tcg_out_qemu_ld (s, args, 0);
+ tcg_out_qemu_ld(s, args, 0);
break;
case INDEX_op_qemu_ld8s:
- tcg_out_qemu_ld (s, args, 0 | 4);
+ tcg_out_qemu_ld(s, args, 0 | 4);
break;
case INDEX_op_qemu_ld16u:
- tcg_out_qemu_ld (s, args, 1);
+ tcg_out_qemu_ld(s, args, 1);
break;
case INDEX_op_qemu_ld16s:
- tcg_out_qemu_ld (s, args, 1 | 4);
+ tcg_out_qemu_ld(s, args, 1 | 4);
break;
case INDEX_op_qemu_ld32:
case INDEX_op_qemu_ld32u:
- tcg_out_qemu_ld (s, args, 2);
+ tcg_out_qemu_ld(s, args, 2);
break;
case INDEX_op_qemu_ld32s:
- tcg_out_qemu_ld (s, args, 2 | 4);
+ tcg_out_qemu_ld(s, args, 2 | 4);
break;
case INDEX_op_qemu_ld64:
- tcg_out_qemu_ld (s, args, 3);
+ tcg_out_qemu_ld(s, args, 3);
break;
case INDEX_op_qemu_st8:
- tcg_out_qemu_st (s, args, 0);
+ tcg_out_qemu_st(s, args, 0);
break;
case INDEX_op_qemu_st16:
- tcg_out_qemu_st (s, args, 1);
+ tcg_out_qemu_st(s, args, 1);
break;
case INDEX_op_qemu_st32:
- tcg_out_qemu_st (s, args, 2);
+ tcg_out_qemu_st(s, args, 2);
break;
case INDEX_op_qemu_st64:
- tcg_out_qemu_st (s, args, 3);
+ tcg_out_qemu_st(s, args, 3);
break;
case INDEX_op_ext8s_i32:
@@ -1819,16 +1893,16 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
c = EXTSW;
goto gen_ext;
gen_ext:
- tcg_out32 (s, c | RS (args[1]) | RA (args[0]));
+ tcg_out32(s, c | RS(args[1]) | RA(args[0]));
break;
case INDEX_op_setcond_i32:
- tcg_out_setcond (s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
- const_args[2]);
+ tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
+ const_args[2]);
break;
case INDEX_op_setcond_i64:
- tcg_out_setcond (s, TCG_TYPE_I64, args[3], args[0], args[1], args[2],
- const_args[2]);
+ tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2],
+ const_args[2]);
break;
case INDEX_op_bswap16_i32:
@@ -1870,9 +1944,9 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
break;
case INDEX_op_bswap64_i64:
- a0 = args[0], a1 = args[1], a2 = 0;
+ a0 = args[0], a1 = args[1], a2 = TCG_REG_R0;
if (a0 == a1) {
- a0 = 0;
+ a0 = TCG_REG_R0;
a2 = a1;
}
@@ -1980,8 +2054,8 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
break;
default:
- tcg_dump_ops (s);
- tcg_abort ();
+ tcg_dump_ops(s);
+ tcg_abort();
}
}
@@ -2109,7 +2183,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ -1 },
};
-static void tcg_target_init (TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
#ifdef CONFIG_GETAUXVAL
unsigned long hwcap = getauxval(AT_HWCAP);
@@ -2118,13 +2192,11 @@ static void tcg_target_init (TCGContext *s)
}
#endif
- tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
- tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
- tcg_regset_set32 (tcg_target_call_clobber_regs, 0,
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
+ tcg_regset_set32(tcg_target_call_clobber_regs, 0,
(1 << TCG_REG_R0) |
-#ifdef __APPLE__
(1 << TCG_REG_R2) |
-#endif
(1 << TCG_REG_R3) |
(1 << TCG_REG_R4) |
(1 << TCG_REG_R5) |
@@ -2134,16 +2206,65 @@ static void tcg_target_init (TCGContext *s)
(1 << TCG_REG_R9) |
(1 << TCG_REG_R10) |
(1 << TCG_REG_R11) |
- (1 << TCG_REG_R12)
- );
+ (1 << TCG_REG_R12));
- tcg_regset_clear (s->reserved_regs);
- tcg_regset_set_reg (s->reserved_regs, TCG_REG_R0);
- tcg_regset_set_reg (s->reserved_regs, TCG_REG_R1);
-#ifndef __APPLE__
- tcg_regset_set_reg (s->reserved_regs, TCG_REG_R2);
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* tcg temp */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); /* stack pointer */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2); /* mem temp */
+#ifdef __APPLE__
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R11); /* ??? */
#endif
- tcg_regset_set_reg (s->reserved_regs, TCG_REG_R13);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); /* thread pointer */
+
+ tcg_add_target_add_op_defs(ppc_op_defs);
+}
+
+typedef struct {
+ DebugFrameCIE cie;
+ DebugFrameFDEHeader fde;
+ uint8_t fde_def_cfa[4];
+ uint8_t fde_reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2 + 3];
+} DebugFrame;
+
+/* We're expecting a 2 byte uleb128 encoded value. */
+QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14));
+
+#define ELF_HOST_MACHINE EM_PPC64
+
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = 0x78, /* sleb128 -8 */
+ .cie.return_column = 65,
+
+ /* Total FDE size does not include the "len" member. */
+ .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
+
+ .fde_def_cfa = {
+ 12, 1, /* DW_CFA_def_cfa r1, ... */
+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
+ (FRAME_SIZE >> 7)
+ },
+ .fde_reg_ofs = {
+ 0x11, 65, 0x7e, /* DW_CFA_offset_extended_sf, lr, 16 */
+ }
+};
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+ uint8_t *p = &debug_frame.fde_reg_ofs[3];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); ++i, p += 2) {
+ p[0] = 0x80 + tcg_target_callee_save_regs[i];
+ p[1] = (FRAME_SIZE - (REG_SAVE_BOT + i * 8)) / 8;
+ }
+
+ debug_frame.fde.func_start = (tcg_target_long) buf;
+ debug_frame.fde.func_len = buf_size;
- tcg_add_target_add_op_defs (ppc_op_defs);
+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
}
diff --git a/vl.c b/vl.c
index 4e709d5..e4113ef 100644
--- a/vl.c
+++ b/vl.c
@@ -1718,14 +1718,14 @@ static pid_t shutdown_pid;
static int powerdown_requested;
static int debug_requested;
static int suspend_requested;
-static int wakeup_requested;
+static WakeupReason wakeup_reason;
static NotifierList powerdown_notifiers =
NOTIFIER_LIST_INITIALIZER(powerdown_notifiers);
static NotifierList suspend_notifiers =
NOTIFIER_LIST_INITIALIZER(suspend_notifiers);
static NotifierList wakeup_notifiers =
NOTIFIER_LIST_INITIALIZER(wakeup_notifiers);
-static uint32_t wakeup_reason_mask = ~0;
+static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
static RunState vmstop_requested = RUN_STATE_MAX;
int qemu_shutdown_requested_get(void)
@@ -1775,11 +1775,9 @@ static int qemu_suspend_requested(void)
return r;
}
-static int qemu_wakeup_requested(void)
+static WakeupReason qemu_wakeup_requested(void)
{
- int r = wakeup_requested;
- wakeup_requested = 0;
- return r;
+ return wakeup_reason;
}
static int qemu_powerdown_requested(void)
@@ -1896,8 +1894,7 @@ void qemu_system_wakeup_request(WakeupReason reason)
return;
}
runstate_set(RUN_STATE_RUNNING);
- notifier_list_notify(&wakeup_notifiers, &reason);
- wakeup_requested = 1;
+ wakeup_reason = reason;
qemu_notify_event();
}
@@ -1989,6 +1986,8 @@ static bool main_loop_should_exit(void)
pause_all_vcpus();
cpu_synchronize_all_states();
qemu_system_reset(VMRESET_SILENT);
+ notifier_list_notify(&wakeup_notifiers, &wakeup_reason);
+ wakeup_reason = QEMU_WAKEUP_REASON_NONE;
resume_all_vcpus();
monitor_protocol_event(QEVENT_WAKEUP, NULL);
}
diff --git a/xen-all.c b/xen-all.c
index 839f14f..48e881b 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -98,6 +98,7 @@ typedef struct XenIOState {
Notifier exit;
Notifier suspend;
+ Notifier wakeup;
} XenIOState;
/* Xen specific function for piix pci */
@@ -613,13 +614,13 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state)
}
if (port != -1) {
- for (i = 0; i < smp_cpus; i++) {
+ for (i = 0; i < max_cpus; i++) {
if (state->ioreq_local_port[i] == port) {
break;
}
}
- if (i == smp_cpus) {
+ if (i == max_cpus) {
hw_error("Fatal error while trying to get io event!\n");
}
@@ -1060,6 +1061,11 @@ static void xen_read_physmap(XenIOState *state)
free(entries);
}
+static void xen_wakeup_notifier(Notifier *notifier, void *data)
+{
+ xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 0);
+}
+
int xen_hvm_init(MemoryRegion **ram_memory)
{
int i, rc;
@@ -1089,6 +1095,9 @@ int xen_hvm_init(MemoryRegion **ram_memory)
state->suspend.notify = xen_suspend_notifier;
qemu_register_suspend_notifier(&state->suspend);
+ state->wakeup.notify = xen_wakeup_notifier;
+ qemu_register_wakeup_notifier(&state->wakeup);
+
xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
DPRINTF("shared page at pfn %lx\n", ioreq_pfn);
state->shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
@@ -1106,10 +1115,10 @@ int xen_hvm_init(MemoryRegion **ram_memory)
hw_error("map buffered IO page returned error %d", errno);
}
- state->ioreq_local_port = g_malloc0(smp_cpus * sizeof (evtchn_port_t));
+ state->ioreq_local_port = g_malloc0(max_cpus * sizeof (evtchn_port_t));
/* FIXME: how about if we overflow the page here? */
- for (i = 0; i < smp_cpus; i++) {
+ for (i = 0; i < max_cpus; i++) {
rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid,
xen_vcpu_eport(state->shared_page, i));
if (rc == -1) {