aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel/meson.build9
-rw-r--r--chardev/char.c33
-rwxr-xr-xconfigure74
-rw-r--r--docs/about/deprecated.rst34
-rw-r--r--docs/about/removed-features.rst41
-rw-r--r--docs/qdev-device-use.txt4
-rw-r--r--hw/core/machine.c1
-rw-r--r--hw/i386/amd_iommu.c2
-rw-r--r--hw/i386/intel_iommu.c4
-rw-r--r--hw/i386/sgx.c15
-rw-r--r--hw/ide/core.c43
-rw-r--r--hw/ide/qdev.c32
-rw-r--r--include/hw/boards.h1
-rw-r--r--include/hw/i386/apic_internal.h2
-rw-r--r--include/hw/ide/internal.h1
-rw-r--r--include/qemu/accel.h4
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--meson.build83
-rw-r--r--qapi/misc-target.json12
-rw-r--r--qemu-options.hx11
-rwxr-xr-xscripts/ci/org.centos/stream/8/x86_64/configure2
-rw-r--r--scripts/symlink-install-tree.py1
-rw-r--r--target/i386/cpu-sysemu.c15
-rw-r--r--target/i386/cpu.c4
-rw-r--r--tcg/s390x/tcg-target-con-set.h18
-rw-r--r--tcg/s390x/tcg-target-con-str.h11
-rw-r--r--tcg/s390x/tcg-target.c.inc1245
-rw-r--r--tcg/s390x/tcg-target.h54
-rw-r--r--tests/qapi-schema/meson.build6
-rw-r--r--tests/unit/test-cutils.c8
-rw-r--r--util/cutils.c14
-rw-r--r--util/log.c84
32 files changed, 937 insertions, 932 deletions
diff --git a/accel/meson.build b/accel/meson.build
index 259c35c..3a480cc 100644
--- a/accel/meson.build
+++ b/accel/meson.build
@@ -11,10 +11,5 @@ if have_system
subdir('stubs')
endif
-dummy_ss = ss.source_set()
-dummy_ss.add(files(
- 'dummy-cpus.c',
-))
-
-specific_ss.add_all(when: ['CONFIG_SOFTMMU'], if_true: dummy_ss)
-specific_ss.add_all(when: ['CONFIG_XEN'], if_true: dummy_ss)
+# qtest
+softmmu_ss.add(files('dummy-cpus.c'))
diff --git a/chardev/char.c b/chardev/char.c
index 4c5de16..87ab6ef 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -530,19 +530,6 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
return cc;
}
-static struct ChardevAlias {
- const char *typename;
- const char *alias;
- bool deprecation_warning_printed;
-} chardev_alias_table[] = {
-#ifdef HAVE_CHARDEV_PARPORT
- { "parallel", "parport" },
-#endif
-#ifdef HAVE_CHARDEV_SERIAL
- { "serial", "tty" },
-#endif
-};
-
typedef struct ChadevClassFE {
void (*fn)(const char *name, void *opaque);
void *opaque;
@@ -578,28 +565,12 @@ help_string_append(const char *name, void *opaque)
g_string_append_printf(str, "\n %s", name);
}
-static const char *chardev_alias_translate(const char *name)
-{
- int i;
- for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
- if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
- if (!chardev_alias_table[i].deprecation_warning_printed) {
- warn_report("The alias '%s' is deprecated, use '%s' instead",
- name, chardev_alias_table[i].typename);
- chardev_alias_table[i].deprecation_warning_printed = true;
- }
- return chardev_alias_table[i].typename;
- }
- }
- return name;
-}
-
ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
{
Error *local_err = NULL;
const ChardevClass *cc;
ChardevBackend *backend = NULL;
- const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
+ const char *name = qemu_opt_get(opts, "backend");
if (name == NULL) {
error_setg(errp, "chardev: \"%s\" missing backend",
@@ -637,7 +608,7 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
const ChardevClass *cc;
Chardev *chr = NULL;
ChardevBackend *backend = NULL;
- const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
+ const char *name = qemu_opt_get(opts, "backend");
const char *id = qemu_opts_id(opts);
char *bid = NULL;
diff --git a/configure b/configure
index 9f0bc57..2281892 100755
--- a/configure
+++ b/configure
@@ -211,10 +211,6 @@ version_ge () {
done
}
-glob() {
- eval test -z '"${1#'"$2"'}"'
-}
-
if printf %s\\n "$source_path" "$PWD" | grep -q "[[:space:]:]";
then
error_exit "main directory cannot contain spaces nor colons"
@@ -342,9 +338,6 @@ for opt do
;;
esac
done
-# OS specific
-# Using uname is really, really broken. Once we have the right set of checks
-# we can eliminate its usage altogether.
# Preferred compiler:
# ${CC} (if set)
@@ -387,8 +380,6 @@ sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
# 2s-complement style results. (Both clang and gcc agree that it
# provides these semantics.)
QEMU_CFLAGS="-fno-strict-aliasing -fno-common -fwrapv"
-QEMU_CFLAGS="-Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
-QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
QEMU_LDFLAGS=
@@ -495,13 +486,6 @@ sunos)
QEMU_CFLAGS="-D_XOPEN_SOURCE=600 $QEMU_CFLAGS"
# needed for TIOCWIN* defines in termios.h
QEMU_CFLAGS="-D__EXTENSIONS__ $QEMU_CFLAGS"
- # $(uname -m) returns i86pc even on an x86_64 box, so default based on isainfo
- # Note that this check is broken for cross-compilation: if you're
- # cross-compiling to one of these OSes then you'll need to specify
- # the correct CPU with the --cpu option.
- if test -z "$cpu" && test "$(isainfo -k)" = "amd64"; then
- cpu="x86_64"
- fi
;;
haiku)
pie="no"
@@ -556,16 +540,21 @@ elif check_define __aarch64__ ; then
elif check_define __loongarch64 ; then
cpu="loongarch64"
else
+ # Using uname is really broken, but it is just a fallback for architectures
+ # that are going to use TCI anyway
cpu=$(uname -m)
+ echo "WARNING: unrecognized host CPU, proceeding with 'uname -m' output '$cpu'"
fi
-# Normalise host CPU name, set multilib cflags
+# Normalise host CPU name and set multilib cflags. The canonicalization
+# isn't really necessary, because the architectures that we check for
+# should not hit the 'uname -m' case, but better safe than sorry.
# Note that this case should only have supported host CPUs, not guests.
case "$cpu" in
armv*b|armv*l|arm)
cpu="arm" ;;
- i386|i486|i586|i686|i86pc|BePC)
+ i386|i486|i586|i686)
cpu="i386"
CPU_CFLAGS="-m32" ;;
x32)
@@ -640,7 +629,6 @@ if test "$mingw32" = "yes" ; then
EXESUF=".exe"
# MinGW needs -mthreads for TLS and macro _MT.
CONFIGURE_CFLAGS="-mthreads $CONFIGURE_CFLAGS"
- write_c_skeleton;
prefix="/qemu"
bindir=""
qemu_suffix=""
@@ -855,17 +843,6 @@ for opt do
;;
--with-coroutine=*) coroutine="$optarg"
;;
- --disable-zlib-test)
- ;;
- --disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane)
- echo "$0: $opt is obsolete, virtio-blk data-plane is always on" >&2
- ;;
- --enable-vhdx|--disable-vhdx)
- echo "$0: $opt is obsolete, VHDX driver is always built" >&2
- ;;
- --enable-uuid|--disable-uuid)
- echo "$0: $opt is obsolete, UUID support is always built" >&2
- ;;
--with-git=*) git="$optarg"
;;
--with-git-submodules=*)
@@ -885,19 +862,10 @@ for opt do
;;
--gdb=*) gdb_bin="$optarg"
;;
- # backwards compatibility options
- --enable-trace-backend=*) meson_option_parse "--enable-trace-backends=$optarg" "$optarg"
- ;;
- --disable-blobs) meson_option_parse --disable-install-blobs ""
- ;;
--enable-vfio-user-server) vfio_user_server="enabled"
;;
--disable-vfio-user-server) vfio_user_server="disabled"
;;
- --enable-tcmalloc) meson_option_parse --enable-malloc=tcmalloc tcmalloc
- ;;
- --enable-jemalloc) meson_option_parse --enable-malloc=jemalloc jemalloc
- ;;
# everything else has the same name in configure and meson
--*) meson_option_parse "$opt" "$optarg"
;;
@@ -1198,6 +1166,11 @@ fi
# just silently disable some features, so it's too error prone.
warn_flags=
+add_to warn_flags -Wundef
+add_to warn_flags -Wwrite-strings
+add_to warn_flags -Wmissing-prototypes
+add_to warn_flags -Wstrict-prototypes
+add_to warn_flags -Wredundant-decls
add_to warn_flags -Wold-style-declaration
add_to warn_flags -Wold-style-definition
add_to warn_flags -Wtype-limits
@@ -2237,20 +2210,6 @@ if test "$have_ubsan" = "yes"; then
QEMU_LDFLAGS="-fsanitize=undefined $QEMU_LDFLAGS"
fi
-##########################################
-# Guest agent Windows MSI package
-
-if test "$QEMU_GA_MANUFACTURER" = ""; then
- QEMU_GA_MANUFACTURER=QEMU
-fi
-if test "$QEMU_GA_DISTRO" = ""; then
- QEMU_GA_DISTRO=Linux
-fi
-if test "$QEMU_GA_VERSION" = ""; then
- QEMU_GA_VERSION=$(cat "$source_path"/VERSION)
-fi
-
-
#######################################
# cross-compiled firmware targets
@@ -2346,9 +2305,9 @@ if test "$debug_tcg" = "yes" ; then
fi
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=y" >> $config_host_mak
- echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER}" >> $config_host_mak
- echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO}" >> $config_host_mak
- echo "QEMU_GA_VERSION=${QEMU_GA_VERSION}" >> $config_host_mak
+ echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER-QEMU}" >> $config_host_mak
+ echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO-Linux}" >> $config_host_mak
+ echo "QEMU_GA_VERSION=${QEMU_GA_VERSION-$(cat "$source_path"/VERSION)}" >> $config_host_mak
else
echo "CONFIG_POSIX=y" >> $config_host_mak
fi
@@ -2663,6 +2622,9 @@ preserve_env PKG_CONFIG
preserve_env PKG_CONFIG_LIBDIR
preserve_env PKG_CONFIG_PATH
preserve_env PYTHON
+preserve_env QEMU_GA_MANUFACTURER
+preserve_env QEMU_GA_DISTRO
+preserve_env QEMU_GA_VERSION
preserve_env SDL2_CONFIG
preserve_env SMBD
preserve_env STRIP
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 93affe3..c3a874d 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -39,12 +39,6 @@ should specify an ``audiodev=`` property. Additionally, when using
vnc, you should specify an ``audiodev=`` property if you plan to
transmit audio through the VNC protocol.
-``-chardev`` backend aliases ``tty`` and ``parport`` (since 6.0)
-''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-``tty`` and ``parport`` are aliases that will be removed. Instead, the
-actual backend names ``serial`` and ``parallel`` should be used.
-
Short-form boolean options (since 6.0)
''''''''''''''''''''''''''''''''''''''
@@ -58,21 +52,6 @@ and will cause a warning.
The replacement for the ``nodelay`` short-form boolean option is ``nodelay=on``
rather than ``delay=off``.
-Userspace local APIC with KVM (x86, since 6.0)
-''''''''''''''''''''''''''''''''''''''''''''''
-
-Using ``-M kernel-irqchip=off`` with x86 machine types that include a local
-APIC is deprecated. The ``split`` setting is supported, as is using
-``-M kernel-irqchip=off`` with the ISA PC machine type.
-
-hexadecimal sizes with scaling multipliers (since 6.0)
-''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-Input parameters that take a size value should only use a size suffix
-(such as 'k' or 'M') when the base is written in decimal, and not when
-the value is hexadecimal. That is, '0x20M' is deprecated, and should
-be written either as '32M' or as '0x2000000'.
-
``-spice password=string`` (since 6.0)
''''''''''''''''''''''''''''''''''''''
@@ -186,19 +165,6 @@ accepted incorrect commands will return an error. Users should make sure that
all arguments passed to ``device_add`` are consistent with the documented
property types.
-``query-sgx`` return value member ``section-size`` (since 7.0)
-''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-Member ``section-size`` in return value elements with meta-type ``uint64`` is
-deprecated. Use ``sections`` instead.
-
-
-``query-sgx-capabilities`` return value member ``section-size`` (since 7.0)
-'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-Member ``section-size`` in return value elements with meta-type ``uint64`` is
-deprecated. Use ``sections`` instead.
-
System accelerators
-------------------
diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst
index 63df984..c918cab 100644
--- a/docs/about/removed-features.rst
+++ b/docs/about/removed-features.rst
@@ -408,6 +408,19 @@ pcspk-audiodev=<name>``.
Use ``-device`` instead.
+Hexadecimal sizes with scaling multipliers (since 8.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Input parameters that take a size value should only use a size suffix
+(such as 'k' or 'M') when the base is written in decimal, and not when
+the value is hexadecimal. That is, '0x20M' should be written either as
+'32M' or as '0x2000000'.
+
+``-chardev`` backend aliases ``tty`` and ``parport`` (removed in 8.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+``tty`` and ``parport`` used to be aliases for ``serial`` and ``parallel``
+respectively. The actual backend names should be used instead.
QEMU Machine Protocol (QMP) commands
------------------------------------
@@ -494,6 +507,19 @@ type of array items in query-named-block-nodes.
Specify the properties for the object as top-level arguments instead.
+``query-sgx`` return value member ``section-size`` (removed in 8.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Member ``section-size`` in the return value of ``query-sgx``
+was superseded by ``sections``.
+
+
+``query-sgx-capabilities`` return value member ``section-size`` (removed in 8.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Member ``section-size`` in the return value of ``query-sgx-capabilities``
+was superseded by ``sections``.
+
Human Monitor Protocol (HMP) commands
-------------------------------------
@@ -565,9 +591,8 @@ KVM guest support on 32-bit Arm hosts (removed in 5.2)
''''''''''''''''''''''''''''''''''''''''''''''''''''''
The Linux kernel has dropped support for allowing 32-bit Arm systems
-to host KVM guests as of the 5.7 kernel. Accordingly, QEMU is deprecating
-its support for this configuration and will remove it in a future version.
-Running 32-bit guests on a 64-bit Arm host remains supported.
+to host KVM guests as of the 5.7 kernel, and was thus removed from QEMU
+as well. Running 32-bit guests on a 64-bit Arm host remains supported.
RISC-V ISA Specific CPUs (removed in 5.1)
'''''''''''''''''''''''''''''''''''''''''
@@ -617,6 +642,16 @@ x86 ``Icelake-Client`` CPU (removed in 7.1)
There isn't ever Icelake Client CPU, it is some wrong and imaginary one.
Use ``Icelake-Server`` instead.
+System accelerators
+-------------------
+
+Userspace local APIC with KVM (x86, removed 8.0)
+''''''''''''''''''''''''''''''''''''''''''''''''
+
+``-M kernel-irqchip=off`` cannot be used on KVM if the CPU model includes
+a local APIC. The ``split`` setting is supported, as is using ``-M
+kernel-irqchip=off`` when the CPU does not have a local APIC.
+
System emulator machines
------------------------
diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt
index 2408889..c98c86d 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -216,11 +216,11 @@ LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
* unix:FNAME becomes -chardev socket,path=FNAME
-* /dev/parportN becomes -chardev parport,file=/dev/parportN
+* /dev/parportN becomes -chardev parallel,file=/dev/parportN
* /dev/ppiN likewise
-* Any other /dev/FNAME becomes -chardev tty,path=/dev/FNAME
+* Any other /dev/FNAME becomes -chardev serial,path=/dev/FNAME
* mon:LEGACY-CHARDEV is special: it multiplexes the monitor onto the
character device defined by LEGACY-CHARDEV. -chardev provides more
diff --git a/hw/core/machine.c b/hw/core/machine.c
index f589b92..616f3a2 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "qemu/option.h"
+#include "qemu/accel.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/replay.h"
#include "qemu/units.h"
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 725f690..bcd016f 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -1368,7 +1368,7 @@ static MemTxResult amdvi_mem_ir_write(void *opaque, hwaddr addr,
return MEMTX_ERROR;
}
- apic_get_class()->send_msi(&to);
+ apic_get_class(NULL)->send_msi(&to);
trace_amdvi_mem_ir_write(to.address, to.data);
return MEMTX_OK;
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index a08ee85..98a5c30 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -396,7 +396,7 @@ static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg,
trace_vtd_irq_generate(msi.address, msi.data);
- apic_get_class()->send_msi(&msi);
+ apic_get_class(NULL)->send_msi(&msi);
}
/* Generate a fault event to software via MSI if conditions are met.
@@ -3529,7 +3529,7 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr,
return MEMTX_ERROR;
}
- apic_get_class()->send_msi(&to);
+ apic_get_class(NULL)->send_msi(&to);
return MEMTX_OK;
}
diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c
index 09d9c7c..db004d1 100644
--- a/hw/i386/sgx.c
+++ b/hw/i386/sgx.c
@@ -83,7 +83,7 @@ static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
((high & MAKE_64BIT_MASK(0, 20)) << 32);
}
-static SGXEPCSectionList *sgx_calc_host_epc_sections(uint64_t *size)
+static SGXEPCSectionList *sgx_calc_host_epc_sections(void)
{
SGXEPCSectionList *head = NULL, **tail = &head;
SGXEPCSection *section;
@@ -106,7 +106,6 @@ static SGXEPCSectionList *sgx_calc_host_epc_sections(uint64_t *size)
section = g_new0(SGXEPCSection, 1);
section->node = j++;
section->size = sgx_calc_section_metric(ecx, edx);
- *size += section->size;
QAPI_LIST_APPEND(tail, section);
}
@@ -157,7 +156,6 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp)
{
SGXInfo *info = NULL;
uint32_t eax, ebx, ecx, edx;
- uint64_t size = 0;
int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
if (fd < 0) {
@@ -175,8 +173,7 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp)
info->sgx1 = eax & (1U << 0) ? true : false;
info->sgx2 = eax & (1U << 1) ? true : false;
- info->sections = sgx_calc_host_epc_sections(&size);
- info->section_size = size;
+ info->sections = sgx_calc_host_epc_sections();
close(fd);
@@ -223,14 +220,12 @@ SGXInfo *qmp_query_sgx(Error **errp)
return NULL;
}
- SGXEPCState *sgx_epc = &pcms->sgx_epc;
info = g_new0(SGXInfo, 1);
info->sgx = true;
info->sgx1 = true;
info->sgx2 = true;
info->flc = true;
- info->section_size = sgx_epc->size;
info->sections = sgx_get_epc_sections_list();
return info;
@@ -241,6 +236,7 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict)
Error *err = NULL;
SGXEPCSectionList *section_list, *section;
g_autoptr(SGXInfo) info = qmp_query_sgx(&err);
+ uint64_t size = 0;
if (err) {
error_report_err(err);
@@ -254,8 +250,6 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict)
info->sgx2 ? "enabled" : "disabled");
monitor_printf(mon, "FLC support: %s\n",
info->flc ? "enabled" : "disabled");
- monitor_printf(mon, "size: %" PRIu64 "\n",
- info->section_size);
section_list = info->sections;
for (section = section_list; section; section = section->next) {
@@ -263,7 +257,10 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict)
section->value->node);
monitor_printf(mon, "size=%" PRIu64 "\n",
section->value->size);
+ size += section->value->size;
}
+ monitor_printf(mon, "total size=%" PRIu64 "\n",
+ size);
}
bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 39afdc0..5d10393 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1648,6 +1648,13 @@ static bool cmd_set_features(IDEState *s, uint8_t cmd)
/* XXX: valid for CDROM ? */
switch (s->feature) {
+ case 0x01: /* 8-bit I/O enable (CompactFlash) */
+ case 0x81: /* 8-bit I/O disable (CompactFlash) */
+ if (s->drive_kind != IDE_CFATA) {
+ goto abort_cmd;
+ }
+ s->io8 = !(s->feature & 0x80);
+ return true;
case 0x02: /* write cache enable */
blk_set_enable_write_cache(s->blk, true);
identify_data = (uint16_t *)s->identify_data;
@@ -2374,12 +2381,20 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
}
p = s->data_ptr;
- if (p + 2 > s->data_end) {
- return;
- }
+ if (s->io8) {
+ if (p + 1 > s->data_end) {
+ return;
+ }
+
+ *p++ = val;
+ } else {
+ if (p + 2 > s->data_end) {
+ return;
+ }
- *(uint16_t *)p = le16_to_cpu(val);
- p += 2;
+ *(uint16_t *)p = le16_to_cpu(val);
+ p += 2;
+ }
s->data_ptr = p;
if (p >= s->data_end) {
s->status &= ~DRQ_STAT;
@@ -2401,12 +2416,20 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
}
p = s->data_ptr;
- if (p + 2 > s->data_end) {
- return 0;
- }
+ if (s->io8) {
+ if (p + 1 > s->data_end) {
+ return 0;
+ }
- ret = cpu_to_le16(*(uint16_t *)p);
- p += 2;
+ ret = *p++;
+ } else {
+ if (p + 2 > s->data_end) {
+ return 0;
+ }
+
+ ret = cpu_to_le16(*(uint16_t *)p);
+ p += 2;
+ }
s->data_ptr = p;
if (p >= s->data_end) {
s->status &= ~DRQ_STAT;
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 618045b..6f6c746 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -283,6 +283,11 @@ static void ide_cd_realize(IDEDevice *dev, Error **errp)
ide_dev_initfn(dev, IDE_CD, errp);
}
+static void ide_cf_realize(IDEDevice *dev, Error **errp)
+{
+ ide_dev_initfn(dev, IDE_CFATA, errp);
+}
+
#define DEFINE_IDE_DEV_PROPERTIES() \
DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \
DEFINE_BLOCK_ERROR_PROPERTIES(IDEDrive, dev.conf), \
@@ -341,6 +346,32 @@ static const TypeInfo ide_cd_info = {
.class_init = ide_cd_class_init,
};
+static Property ide_cf_properties[] = {
+ DEFINE_IDE_DEV_PROPERTIES(),
+ DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
+ DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
+ IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_cf_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+
+ k->realize = ide_cf_realize;
+ dc->fw_name = "drive";
+ dc->desc = "virtual CompactFlash card";
+ device_class_set_props(dc, ide_cf_properties);
+}
+
+static const TypeInfo ide_cf_info = {
+ .name = "ide-cf",
+ .parent = TYPE_IDE_DEVICE,
+ .instance_size = sizeof(IDEDrive),
+ .class_init = ide_cf_class_init,
+};
+
static void ide_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
@@ -365,6 +396,7 @@ static void ide_register_types(void)
type_register_static(&ide_bus_info);
type_register_static(&ide_hd_info);
type_register_static(&ide_cd_info);
+ type_register_static(&ide_cf_info);
type_register_static(&ide_device_type_info);
}
diff --git a/include/hw/boards.h b/include/hw/boards.h
index b0abbdd..6fbbfd5 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -6,7 +6,6 @@
#include "exec/memory.h"
#include "sysemu/hostmem.h"
#include "sysemu/blockdev.h"
-#include "qemu/accel.h"
#include "qapi/qapi-types-machine.h"
#include "qemu/module.h"
#include "qom/object.h"
diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h
index c175e7e..968b664 100644
--- a/include/hw/i386/apic_internal.h
+++ b/include/hw/i386/apic_internal.h
@@ -226,6 +226,6 @@ static inline int apic_get_bit(uint32_t *tab, int index)
return !!(tab[i] & mask);
}
-APICCommonClass *apic_get_class(void);
+APICCommonClass *apic_get_class(Error **errp);
#endif /* QEMU_APIC_INTERNAL_H */
diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
index b17f36d..fc0aa81 100644
--- a/include/hw/ide/internal.h
+++ b/include/hw/ide/internal.h
@@ -402,6 +402,7 @@ struct IDEState {
uint8_t select;
uint8_t status;
+ bool io8;
bool reset_reverts;
/* set for lba48 access */
diff --git a/include/qemu/accel.h b/include/qemu/accel.h
index ce47476..e84db2e 100644
--- a/include/qemu/accel.h
+++ b/include/qemu/accel.h
@@ -26,10 +26,10 @@
#include "qom/object.h"
#include "exec/hwaddr.h"
-typedef struct AccelState {
+struct AccelState {
/*< private >*/
Object parent_obj;
-} AccelState;
+};
typedef struct AccelClass {
/*< private >*/
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 688408e..073abab 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -21,6 +21,7 @@
* Incomplete struct types
* Please keep this list in case-insensitive alphabetical order.
*/
+typedef struct AccelState AccelState;
typedef struct AdapterInfo AdapterInfo;
typedef struct AddressSpace AddressSpace;
typedef struct AioContext AioContext;
diff --git a/meson.build b/meson.build
index 827e726..175517e 100644
--- a/meson.build
+++ b/meson.build
@@ -14,8 +14,8 @@ keyval = import('keyval')
ss = import('sourceset')
fs = import('fs')
+targetos = host_machine.system()
sh = find_program('sh')
-cc = meson.get_compiler('c')
config_host = keyval.load(meson.current_build_dir() / 'config-host.mak')
enable_modules = 'CONFIG_MODULES' in config_host
enable_static = 'CONFIG_STATIC' in config_host
@@ -23,6 +23,18 @@ enable_static = 'CONFIG_STATIC' in config_host
# Allow both shared and static libraries unless --enable-static
static_kwargs = enable_static ? {'static': true} : {}
+cc = meson.get_compiler('c')
+all_languages = ['c']
+if add_languages('cpp', required: false, native: false)
+ all_languages += ['cpp']
+ cxx = meson.get_compiler('cpp')
+endif
+if targetos == 'darwin' and \
+ add_languages('objc', required: get_option('cocoa'), native: false)
+ all_languages += ['objc']
+ objc = meson.get_compiler('objc')
+endif
+
# Temporary directory used for files created while
# configure runs. Since it is in the build directory
# we can safely blow away any previous version of it
@@ -58,8 +70,6 @@ if cpu in ['riscv32', 'riscv64']
cpu = 'riscv'
endif
-targetos = host_machine.system()
-
target_dirs = config_host['TARGET_DIRS'].split()
have_linux_user = false
have_bsd_user = false
@@ -165,7 +175,7 @@ if 'dtrace' in get_option('trace_backends')
# semaphores are linked into the main binary and not the module's shared
# object.
add_global_arguments('-DSTAP_SDT_V2',
- native: false, language: ['c', 'cpp', 'objc'])
+ native: false, language: all_languages)
endif
endif
@@ -193,10 +203,7 @@ qemu_ldflags += cc.get_supported_link_arguments('-Wl,-z,relro', '-Wl,-z,now')
if targetos == 'windows'
qemu_ldflags += cc.get_supported_link_arguments('-Wl,--no-seh', '-Wl,--nxcompat')
- # Disable ASLR for debug builds to allow debugging with gdb
- if get_option('optimization') == '0'
- qemu_ldflags += cc.get_supported_link_arguments('-Wl,--dynamicbase')
- endif
+ qemu_ldflags += cc.get_supported_link_arguments('-Wl,--dynamicbase', '-Wl,--high-entropy-va')
endif
if get_option('gprof')
@@ -210,7 +217,7 @@ endif
if get_option('fuzzing')
add_project_link_arguments(['-Wl,-T,',
(meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')],
- native: false, language: ['c', 'cpp', 'objc'])
+ native: false, language: all_languages)
# Specify a filter to only instrument code that is directly related to
# virtual-devices.
@@ -223,7 +230,7 @@ if get_option('fuzzing')
args: ['-fsanitize-coverage-allowlist=/dev/null',
'-fsanitize-coverage=trace-pc'] )
add_global_arguments('-fsanitize-coverage-allowlist=instrumentation-filter',
- native: false, language: ['c', 'cpp', 'objc'])
+ native: false, language: all_languages)
endif
if get_option('fuzzing_engine') == ''
@@ -232,9 +239,9 @@ if get_option('fuzzing')
# everything with fsanitize=fuzzer-no-link. Otherwise, the linker will be
# unable to bind the fuzzer-related callbacks added by instrumentation.
add_global_arguments('-fsanitize=fuzzer-no-link',
- native: false, language: ['c', 'cpp', 'objc'])
+ native: false, language: all_languages)
add_global_link_arguments('-fsanitize=fuzzer-no-link',
- native: false, language: ['c', 'cpp', 'objc'])
+ native: false, language: all_languages)
# For the actual fuzzer binaries, we need to link against the libfuzzer
# library. They need to be configurable, to support OSS-Fuzz
fuzz_exe_ldflags = ['-fsanitize=fuzzer']
@@ -245,15 +252,11 @@ if get_option('fuzzing')
endif
endif
-add_global_arguments(qemu_cflags, native: false, language: ['c'])
-add_global_arguments(qemu_objcflags, native: false, language: ['objc'])
-
# Check that the C++ compiler exists and works with the C compiler.
link_language = 'c'
linker = cc
qemu_cxxflags = []
-if add_languages('cpp', required: false, native: false)
- cxx = meson.get_compiler('cpp')
+if 'cpp' in all_languages
add_global_arguments(['-D__STDC_LIMIT_MACROS', '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS'],
native: false, language: 'cpp')
foreach k: qemu_cflags
@@ -262,7 +265,6 @@ if add_languages('cpp', required: false, native: false)
qemu_cxxflags += [k]
endif
endforeach
- add_global_arguments(qemu_cxxflags, native: false, language: 'cpp')
if cxx.links(files('scripts/main.c'), args: qemu_cflags)
link_language = 'cpp'
@@ -278,22 +280,21 @@ if targetos != 'sunos' and not config_host.has_key('CONFIG_TSAN')
qemu_ldflags += linker.get_supported_link_arguments('-Wl,--warn-common')
endif
-add_global_link_arguments(qemu_ldflags, native: false, language: ['c', 'cpp', 'objc'])
+add_global_link_arguments(qemu_ldflags, native: false, language: all_languages)
+add_global_arguments(qemu_cflags, native: false, language: 'c')
+add_global_arguments(qemu_cxxflags, native: false, language: 'cpp')
+add_global_arguments(qemu_objcflags, native: false, language: 'objc')
if targetos == 'linux'
add_project_arguments('-isystem', meson.current_source_dir() / 'linux-headers',
'-isystem', 'linux-headers',
- language: ['c', 'cpp'])
+ language: all_languages)
endif
add_project_arguments('-iquote', '.',
'-iquote', meson.current_source_dir(),
'-iquote', meson.current_source_dir() / 'include',
- language: ['c', 'cpp', 'objc'])
-
-if host_machine.system() == 'darwin'
- add_languages('objc', required: false, native: false)
-endif
+ language: all_languages)
sparse = find_program('cgcc', required: get_option('sparse'))
if sparse.found()
@@ -476,7 +477,7 @@ if get_option('tcg').allowed()
tcg_arch = 'ppc'
endif
add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch,
- language: ['c', 'cpp', 'objc'])
+ language: all_languages)
accelerators += 'CONFIG_TCG'
config_host += { 'CONFIG_TCG': 'y' }
@@ -502,7 +503,7 @@ endif
# The path to glib.h is added to all compilation commands. This was
# grandfathered in from the QEMU Makefiles.
add_project_arguments(config_host['GLIB_CFLAGS'].split(),
- native: false, language: ['c', 'cpp', 'objc'])
+ native: false, language: all_languages)
glib = declare_dependency(compile_args: config_host['GLIB_CFLAGS'].split(),
link_args: config_host['GLIB_LIBS'].split(),
version: config_host['GLIB_VERSION'],
@@ -1727,8 +1728,8 @@ if get_option('cfi')
error('-fno-sanitize-trap=cfi-icall is not supported by the compiler')
endif
endif
- add_global_arguments(cfi_flags, native: false, language: ['c', 'cpp', 'objc'])
- add_global_link_arguments(cfi_flags, native: false, language: ['c', 'cpp', 'objc'])
+ add_global_arguments(cfi_flags, native: false, language: all_languages)
+ add_global_link_arguments(cfi_flags, native: false, language: all_languages)
endif
have_host_block_device = (targetos != 'darwin' or
@@ -3758,26 +3759,28 @@ endif
if targetos == 'darwin'
summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())}
endif
-summary_info += {'CFLAGS': ' '.join(get_option('c_args')
- + ['-O' + get_option('optimization')]
- + (get_option('debug') ? ['-g'] : []))}
+option_cflags = (get_option('debug') ? ['-g'] : [])
+if get_option('optimization') != 'plain'
+ option_cflags += ['-O' + get_option('optimization')]
+endif
+summary_info += {'CFLAGS': ' '.join(get_option('c_args') + option_cflags)}
if link_language == 'cpp'
- summary_info += {'CXXFLAGS': ' '.join(get_option('cpp_args')
- + ['-O' + get_option('optimization')]
- + (get_option('debug') ? ['-g'] : []))}
+ summary_info += {'CXXFLAGS': ' '.join(get_option('cpp_args') + option_cflags)}
endif
if targetos == 'darwin'
- summary_info += {'OBJCFLAGS': ' '.join(get_option('objc_args')
- + ['-O' + get_option('optimization')]
- + (get_option('debug') ? ['-g'] : []))}
+ summary_info += {'OBJCFLAGS': ' '.join(get_option('objc_args') + option_cflags)}
endif
link_args = get_option(link_language + '_link_args')
if link_args.length() > 0
summary_info += {'LDFLAGS': ' '.join(link_args)}
endif
summary_info += {'QEMU_CFLAGS': ' '.join(qemu_cflags)}
-summary_info += {'QEMU_CXXFLAGS': ' '.join(qemu_cxxflags)}
-summary_info += {'QEMU_OBJCFLAGS': ' '.join(qemu_objcflags)}
+if 'cpp' in all_languages
+ summary_info += {'QEMU_CXXFLAGS': ' '.join(qemu_cxxflags)}
+endif
+if 'objc' in all_languages
+ summary_info += {'QEMU_OBJCFLAGS': ' '.join(qemu_objcflags)}
+endif
summary_info += {'QEMU_LDFLAGS': ' '.join(qemu_ldflags)}
summary_info += {'profiler': get_option('profiler')}
summary_info += {'link-time optimization (LTO)': get_option('b_lto')}
diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 4944c05..5b6a8e9 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -329,14 +329,8 @@
#
# @flc: true if FLC is supported
#
-# @section-size: The EPC section size for guest
-# Redundant with @sections. Just for backward compatibility.
-#
# @sections: The EPC sections info for guest (Since: 7.0)
#
-# Features:
-# @deprecated: Member @section-size is deprecated. Use @sections instead.
-#
# Since: 6.2
##
{ 'struct': 'SGXInfo',
@@ -344,8 +338,6 @@
'sgx1': 'bool',
'sgx2': 'bool',
'flc': 'bool',
- 'section-size': { 'type': 'uint64',
- 'features': [ 'deprecated' ] },
'sections': ['SGXEPCSection']},
'if': 'TARGET_I386' }
@@ -362,7 +354,7 @@
#
# -> { "execute": "query-sgx" }
# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true,
-# "flc": true, "section-size" : 96468992,
+# "flc": true,
# "sections": [{"node": 0, "size": 67108864},
# {"node": 1, "size": 29360128}]} }
#
@@ -382,7 +374,7 @@
#
# -> { "execute": "query-sgx-capabilities" }
# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true,
-# "flc": true, "section-size" : 96468992,
+# "flc": true,
# "section" : [{"node": 0, "size": 67108864},
# {"node": 1, "size": 29360128}]} }
#
diff --git a/qemu-options.hx b/qemu-options.hx
index 8662568..fa0084c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3382,11 +3382,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
"-chardev serial,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
- "-chardev tty,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
"-chardev parallel,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
- "-chardev parport,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
#endif
#if defined(CONFIG_SPICE)
"-chardev spicevmc,id=id,name=name[,debug=debug][,logfile=PATH][,logappend=on|off]\n"
@@ -3401,7 +3399,7 @@ The general form of a character device option is:
``-chardev backend,id=id[,mux=on|off][,options]``
Backend is one of: ``null``, ``socket``, ``udp``, ``msmouse``,
``vc``, ``ringbuf``, ``file``, ``pipe``, ``console``, ``serial``,
- ``pty``, ``stdio``, ``braille``, ``tty``, ``parallel``, ``parport``,
+ ``pty``, ``stdio``, ``braille``, ``parallel``,
``spicevmc``, ``spiceport``. The specific backend will determine the
applicable options.
@@ -3625,15 +3623,8 @@ The available backends are:
Connect to a local BrlAPI server. ``braille`` does not take any
options.
-``-chardev tty,id=id,path=path``
- ``tty`` is only available on Linux, Sun, FreeBSD, NetBSD, OpenBSD
- and DragonFlyBSD hosts. It is an alias for ``serial``.
-
- ``path`` specifies the path to the tty. ``path`` is required.
-
``-chardev parallel,id=id,path=path``
\
-``-chardev parport,id=id,path=path``
``parallel`` is only available on Linux, FreeBSD and DragonFlyBSD
hosts.
diff --git a/scripts/ci/org.centos/stream/8/x86_64/configure b/scripts/ci/org.centos/stream/8/x86_64/configure
index a7f92af..75882fa 100755
--- a/scripts/ci/org.centos/stream/8/x86_64/configure
+++ b/scripts/ci/org.centos/stream/8/x86_64/configure
@@ -188,7 +188,7 @@
--enable-tcg \
--enable-tools \
--enable-tpm \
---enable-trace-backend=dtrace \
+--enable-trace-backends=dtrace \
--enable-usb-redir \
--enable-virtiofsd \
--enable-vhost-kernel \
diff --git a/scripts/symlink-install-tree.py b/scripts/symlink-install-tree.py
index a5bf0b0..67cb86d 100644
--- a/scripts/symlink-install-tree.py
+++ b/scripts/symlink-install-tree.py
@@ -17,7 +17,6 @@ introspect = os.environ.get('MESONINTROSPECT')
out = subprocess.run([*introspect.split(' '), '--installed'],
stdout=subprocess.PIPE, check=True).stdout
for source, dest in json.loads(out).items():
- assert os.path.isabs(source)
bundle_dest = destdir_join('qemu-bundle', dest)
path = os.path.dirname(bundle_dest)
try:
diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c
index fc97213..28115ed 100644
--- a/target/i386/cpu-sysemu.c
+++ b/target/i386/cpu-sysemu.c
@@ -247,12 +247,16 @@ void x86_cpu_machine_reset_cb(void *opaque)
cpu_reset(CPU(cpu));
}
-APICCommonClass *apic_get_class(void)
+APICCommonClass *apic_get_class(Error **errp)
{
const char *apic_type = "apic";
/* TODO: in-kernel irqchip for hvf */
- if (kvm_apic_in_kernel()) {
+ if (kvm_enabled()) {
+ if (!kvm_apic_in_kernel()) {
+ error_setg(errp, "KVM does not support userspace APIC");
+ return NULL;
+ }
apic_type = "kvm-apic";
} else if (xen_enabled()) {
apic_type = "xen-apic";
@@ -266,10 +270,13 @@ APICCommonClass *apic_get_class(void)
void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
{
APICCommonState *apic;
- ObjectClass *apic_class = OBJECT_CLASS(apic_get_class());
+ APICCommonClass *apic_class = apic_get_class(errp);
- cpu->apic_state = DEVICE(object_new_with_class(apic_class));
+ if (!apic_class) {
+ return;
+ }
+ cpu->apic_state = DEVICE(object_new_with_class(OBJECT_CLASS(apic_class)));
object_property_add_child(OBJECT(cpu), "lapic",
OBJECT(cpu->apic_state));
object_unref(OBJECT(cpu->apic_state));
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 3410e5e..4d2b8d0 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1233,7 +1233,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.feat_names = {
"sgx1", "sgx2", NULL, NULL,
NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "sgx-edeccssa",
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
@@ -1273,7 +1273,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.feat_names = {
NULL, "sgx-debug", "sgx-mode64", NULL,
"sgx-provisionkey", "sgx-tokenkey", NULL, "sgx-kss",
- NULL, NULL, NULL, NULL,
+ NULL, NULL, "sgx-aex-notify", NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h
index 426dd92..15f1c55 100644
--- a/tcg/s390x/tcg-target-con-set.h
+++ b/tcg/s390x/tcg-target-con-set.h
@@ -13,6 +13,7 @@ C_O0_I1(r)
C_O0_I2(L, L)
C_O0_I2(r, r)
C_O0_I2(r, ri)
+C_O0_I2(r, rA)
C_O0_I2(v, r)
C_O1_I1(r, L)
C_O1_I1(r, r)
@@ -22,15 +23,24 @@ C_O1_I1(v, vr)
C_O1_I2(r, 0, ri)
C_O1_I2(r, 0, rI)
C_O1_I2(r, 0, rJ)
+C_O1_I2(r, r, r)
C_O1_I2(r, r, ri)
+C_O1_I2(r, r, rA)
+C_O1_I2(r, r, rI)
+C_O1_I2(r, r, rJ)
+C_O1_I2(r, r, rK)
+C_O1_I2(r, r, rKR)
+C_O1_I2(r, r, rNK)
+C_O1_I2(r, r, rNKR)
C_O1_I2(r, rZ, r)
C_O1_I2(v, v, r)
C_O1_I2(v, v, v)
C_O1_I3(v, v, v, v)
-C_O1_I4(r, r, ri, r, 0)
-C_O1_I4(r, r, ri, rI, 0)
-C_O2_I2(b, a, 0, r)
-C_O2_I3(b, a, 0, 1, r)
+C_O1_I4(r, r, ri, rI, r)
+C_O1_I4(r, r, rA, rI, r)
+C_O2_I2(o, m, 0, r)
+C_O2_I2(o, m, r, r)
+C_O2_I3(o, m, 0, 1, r)
C_O2_I4(r, r, 0, 1, rA, r)
C_O2_I4(r, r, 0, 1, ri, r)
C_O2_I4(r, r, 0, 1, r, r)
diff --git a/tcg/s390x/tcg-target-con-str.h b/tcg/s390x/tcg-target-con-str.h
index 8bb0358..6fa64a1 100644
--- a/tcg/s390x/tcg-target-con-str.h
+++ b/tcg/s390x/tcg-target-con-str.h
@@ -11,13 +11,7 @@
REGS('r', ALL_GENERAL_REGS)
REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS)
REGS('v', ALL_VECTOR_REGS)
-/*
- * A (single) even/odd pair for division.
- * TODO: Add something to the register allocator to allow
- * this kind of regno+1 pairing to be done more generally.
- */
-REGS('a', 1u << TCG_REG_R2)
-REGS('b', 1u << TCG_REG_R3)
+REGS('o', 0xaaaa) /* odd numbered general regs */
/*
* Define constraint letters for constants:
@@ -26,4 +20,7 @@ REGS('b', 1u << TCG_REG_R3)
CONST('A', TCG_CT_CONST_S33)
CONST('I', TCG_CT_CONST_S16)
CONST('J', TCG_CT_CONST_S32)
+CONST('K', TCG_CT_CONST_P32)
+CONST('N', TCG_CT_CONST_INV)
+CONST('R', TCG_CT_CONST_INVRISBG)
CONST('Z', TCG_CT_CONST_ZERO)
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
index b9ba7b6..2b38fd9 100644
--- a/tcg/s390x/tcg-target.c.inc
+++ b/tcg/s390x/tcg-target.c.inc
@@ -33,15 +33,13 @@
#include "../tcg-pool.c.inc"
#include "elf.h"
-/* ??? The translation blocks produced by TCG are generally small enough to
- be entirely reachable with a 16-bit displacement. Leaving the option for
- a 32-bit displacement here Just In Case. */
-#define USE_LONG_BRANCHES 0
-
-#define TCG_CT_CONST_S16 0x100
-#define TCG_CT_CONST_S32 0x200
-#define TCG_CT_CONST_S33 0x400
-#define TCG_CT_CONST_ZERO 0x800
+#define TCG_CT_CONST_S16 (1 << 8)
+#define TCG_CT_CONST_S32 (1 << 9)
+#define TCG_CT_CONST_S33 (1 << 10)
+#define TCG_CT_CONST_ZERO (1 << 11)
+#define TCG_CT_CONST_P32 (1 << 12)
+#define TCG_CT_CONST_INV (1 << 13)
+#define TCG_CT_CONST_INVRISBG (1 << 14)
#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 16)
#define ALL_VECTOR_REGS MAKE_64BIT_MASK(32, 32)
@@ -65,12 +63,6 @@
/* A scratch register that may be be used throughout the backend. */
#define TCG_TMP0 TCG_REG_R1
-/* A scratch register that holds a pointer to the beginning of the TB.
- We don't need this when we have pc-relative loads with the general
- instructions extension facility. */
-#define TCG_REG_TB TCG_REG_R12
-#define USE_REG_TB (!HAVE_FACILITY(GEN_INST_EXT))
-
#ifndef CONFIG_SOFTMMU
#define TCG_GUEST_BASE_REG TCG_REG_R13
#endif
@@ -139,16 +131,19 @@ typedef enum S390Opcode {
RI_OILL = 0xa50b,
RI_TMLL = 0xa701,
- RIE_CGIJ = 0xec7c,
- RIE_CGRJ = 0xec64,
- RIE_CIJ = 0xec7e,
- RIE_CLGRJ = 0xec65,
- RIE_CLIJ = 0xec7f,
- RIE_CLGIJ = 0xec7d,
- RIE_CLRJ = 0xec77,
- RIE_CRJ = 0xec76,
- RIE_LOCGHI = 0xec46,
- RIE_RISBG = 0xec55,
+ RIEb_CGRJ = 0xec64,
+ RIEb_CLGRJ = 0xec65,
+ RIEb_CLRJ = 0xec77,
+ RIEb_CRJ = 0xec76,
+
+ RIEc_CGIJ = 0xec7c,
+ RIEc_CIJ = 0xec7e,
+ RIEc_CLGIJ = 0xec7d,
+ RIEc_CLIJ = 0xec7f,
+
+ RIEf_RISBG = 0xec55,
+
+ RIEg_LOCGHI = 0xec46,
RRE_AGR = 0xb908,
RRE_ALGR = 0xb90a,
@@ -183,18 +178,35 @@ typedef enum S390Opcode {
RRE_SLBGR = 0xb989,
RRE_XGR = 0xb982,
- RRF_LOCR = 0xb9f2,
- RRF_LOCGR = 0xb9e2,
- RRF_NRK = 0xb9f4,
- RRF_NGRK = 0xb9e4,
- RRF_ORK = 0xb9f6,
- RRF_OGRK = 0xb9e6,
- RRF_SRK = 0xb9f9,
- RRF_SGRK = 0xb9e9,
- RRF_SLRK = 0xb9fb,
- RRF_SLGRK = 0xb9eb,
- RRF_XRK = 0xb9f7,
- RRF_XGRK = 0xb9e7,
+ RRFa_MGRK = 0xb9ec,
+ RRFa_MSRKC = 0xb9fd,
+ RRFa_MSGRKC = 0xb9ed,
+ RRFa_NCRK = 0xb9f5,
+ RRFa_NCGRK = 0xb9e5,
+ RRFa_NNRK = 0xb974,
+ RRFa_NNGRK = 0xb964,
+ RRFa_NORK = 0xb976,
+ RRFa_NOGRK = 0xb966,
+ RRFa_NRK = 0xb9f4,
+ RRFa_NGRK = 0xb9e4,
+ RRFa_NXRK = 0xb977,
+ RRFa_NXGRK = 0xb967,
+ RRFa_OCRK = 0xb975,
+ RRFa_OCGRK = 0xb965,
+ RRFa_ORK = 0xb9f6,
+ RRFa_OGRK = 0xb9e6,
+ RRFa_SRK = 0xb9f9,
+ RRFa_SGRK = 0xb9e9,
+ RRFa_SLRK = 0xb9fb,
+ RRFa_SLGRK = 0xb9eb,
+ RRFa_XRK = 0xb9f7,
+ RRFa_XGRK = 0xb9e7,
+
+ RRFam_SELGR = 0xb9e3,
+
+ RRFc_LOCR = 0xb9f2,
+ RRFc_LOCGR = 0xb9e2,
+ RRFc_POPCNT = 0xb9e1,
RR_AR = 0x1a,
RR_ALR = 0x1e,
@@ -511,6 +523,60 @@ static bool patch_reloc(tcg_insn_unit *src_rw, int type,
return false;
}
+static int is_const_p16(uint64_t val)
+{
+ for (int i = 0; i < 4; ++i) {
+ uint64_t mask = 0xffffull << (i * 16);
+ if ((val & ~mask) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int is_const_p32(uint64_t val)
+{
+ if ((val & 0xffffffff00000000ull) == 0) {
+ return 0;
+ }
+ if ((val & 0x00000000ffffffffull) == 0) {
+ return 1;
+ }
+ return -1;
+}
+
+/*
+ * Accept bit patterns like these:
+ * 0....01....1
+ * 1....10....0
+ * 1..10..01..1
+ * 0..01..10..0
+ * Copied from gcc sources.
+ */
+static bool risbg_mask(uint64_t c)
+{
+ uint64_t lsb;
+ /* We don't change the number of transitions by inverting,
+ so make sure we start with the LSB zero. */
+ if (c & 1) {
+ c = ~c;
+ }
+ /* Reject all zeros or all ones. */
+ if (c == 0) {
+ return false;
+ }
+ /* Find the first transition. */
+ lsb = c & -c;
+ /* Invert to look for a second transition. */
+ c = ~c;
+ /* Erase the first transition. */
+ c &= -lsb;
+ /* Find the second transition, if any. */
+ lsb = c & -c;
+ /* Match if all the bits are 1's, or if c is zero. */
+ return c == -lsb;
+}
+
/* Test if a constant matches the constraint. */
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
{
@@ -533,6 +599,20 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
return val == 0;
}
+ if (ct & TCG_CT_CONST_INV) {
+ val = ~val;
+ }
+ /*
+ * Note that is_const_p16 is a subset of is_const_p32,
+ * so we don't need both constraints.
+ */
+ if ((ct & TCG_CT_CONST_P32) && is_const_p32(val) >= 0) {
+ return true;
+ }
+ if ((ct & TCG_CT_CONST_INVRISBG) && risbg_mask(~val)) {
+ return true;
+ }
+
return 0;
}
@@ -549,8 +629,22 @@ static void tcg_out_insn_RRE(TCGContext *s, S390Opcode op,
tcg_out32(s, (op << 16) | (r1 << 4) | r2);
}
-static void tcg_out_insn_RRF(TCGContext *s, S390Opcode op,
- TCGReg r1, TCGReg r2, int m3)
+/* RRF-a without the m4 field */
+static void tcg_out_insn_RRFa(TCGContext *s, S390Opcode op,
+ TCGReg r1, TCGReg r2, TCGReg r3)
+{
+ tcg_out32(s, (op << 16) | (r3 << 12) | (r1 << 4) | r2);
+}
+
+/* RRF-a with the m4 field */
+static void tcg_out_insn_RRFam(TCGContext *s, S390Opcode op,
+ TCGReg r1, TCGReg r2, TCGReg r3, int m4)
+{
+ tcg_out32(s, (op << 16) | (r3 << 12) | (m4 << 8) | (r1 << 4) | r2);
+}
+
+static void tcg_out_insn_RRFc(TCGContext *s, S390Opcode op,
+ TCGReg r1, TCGReg r2, int m3)
{
tcg_out32(s, (op << 16) | (m3 << 12) | (r1 << 4) | r2);
}
@@ -560,7 +654,7 @@ static void tcg_out_insn_RI(TCGContext *s, S390Opcode op, TCGReg r1, int i2)
tcg_out32(s, (op << 16) | (r1 << 20) | (i2 & 0xffff));
}
-static void tcg_out_insn_RIE(TCGContext *s, S390Opcode op, TCGReg r1,
+static void tcg_out_insn_RIEg(TCGContext *s, S390Opcode op, TCGReg r1,
int i2, int m3)
{
tcg_out16(s, (op & 0xff00) | (r1 << 4) | m3);
@@ -780,14 +874,22 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg dst, TCGReg src)
return true;
}
-static const S390Opcode lli_insns[4] = {
+static const S390Opcode li_insns[4] = {
RI_LLILL, RI_LLILH, RI_LLIHL, RI_LLIHH
};
+static const S390Opcode oi_insns[4] = {
+ RI_OILL, RI_OILH, RI_OIHL, RI_OIHH
+};
+static const S390Opcode lif_insns[2] = {
+ RIL_LLILF, RIL_LLIHF,
+};
-static bool maybe_out_small_movi(TCGContext *s, TCGType type,
- TCGReg ret, tcg_target_long sval)
+/* load a register with an immediate value */
+static void tcg_out_movi(TCGContext *s, TCGType type,
+ TCGReg ret, tcg_target_long sval)
{
tcg_target_ulong uval = sval;
+ ptrdiff_t pc_off;
int i;
if (type == TCG_TYPE_I32) {
@@ -798,100 +900,51 @@ static bool maybe_out_small_movi(TCGContext *s, TCGType type,
/* Try all 32-bit insns that can load it in one go. */
if (sval >= -0x8000 && sval < 0x8000) {
tcg_out_insn(s, RI, LGHI, ret, sval);
- return true;
- }
-
- for (i = 0; i < 4; i++) {
- tcg_target_long mask = 0xffffull << i * 16;
- if ((uval & mask) == uval) {
- tcg_out_insn_RI(s, lli_insns[i], ret, uval >> i * 16);
- return true;
- }
- }
-
- return false;
-}
-
-/* load a register with an immediate value */
-static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
- tcg_target_long sval, bool in_prologue)
-{
- tcg_target_ulong uval;
-
- /* Try all 32-bit insns that can load it in one go. */
- if (maybe_out_small_movi(s, type, ret, sval)) {
return;
}
- uval = sval;
- if (type == TCG_TYPE_I32) {
- uval = (uint32_t)sval;
- sval = (int32_t)sval;
+ i = is_const_p16(uval);
+ if (i >= 0) {
+ tcg_out_insn_RI(s, li_insns[i], ret, uval >> (i * 16));
+ return;
}
/* Try all 48-bit insns that can load it in one go. */
- if (HAVE_FACILITY(EXT_IMM)) {
- if (sval == (int32_t)sval) {
- tcg_out_insn(s, RIL, LGFI, ret, sval);
- return;
- }
- if (uval <= 0xffffffff) {
- tcg_out_insn(s, RIL, LLILF, ret, uval);
- return;
- }
- if ((uval & 0xffffffff) == 0) {
- tcg_out_insn(s, RIL, LLIHF, ret, uval >> 32);
- return;
- }
+ if (sval == (int32_t)sval) {
+ tcg_out_insn(s, RIL, LGFI, ret, sval);
+ return;
}
- /* Try for PC-relative address load. For odd addresses,
- attempt to use an offset from the start of the TB. */
- if ((sval & 1) == 0) {
- ptrdiff_t off = tcg_pcrel_diff(s, (void *)sval) >> 1;
- if (off == (int32_t)off) {
- tcg_out_insn(s, RIL, LARL, ret, off);
- return;
- }
- } else if (USE_REG_TB && !in_prologue) {
- ptrdiff_t off = tcg_tbrel_diff(s, (void *)sval);
- if (off == sextract64(off, 0, 20)) {
- /* This is certain to be an address within TB, and therefore
- OFF will be negative; don't try RX_LA. */
- tcg_out_insn(s, RXY, LAY, ret, TCG_REG_TB, TCG_REG_NONE, off);
- return;
- }
+ i = is_const_p32(uval);
+ if (i >= 0) {
+ tcg_out_insn_RIL(s, lif_insns[i], ret, uval >> (i * 32));
+ return;
}
- /* A 32-bit unsigned value can be loaded in 2 insns. And given
- that LLILL, LLIHL, LLILF above did not succeed, we know that
- both insns are required. */
- if (uval <= 0xffffffff) {
- tcg_out_insn(s, RI, LLILL, ret, uval);
- tcg_out_insn(s, RI, IILH, ret, uval >> 16);
+ /* Try for PC-relative address load. For odd addresses, add one. */
+ pc_off = tcg_pcrel_diff(s, (void *)sval) >> 1;
+ if (pc_off == (int32_t)pc_off) {
+ tcg_out_insn(s, RIL, LARL, ret, pc_off);
+ if (sval & 1) {
+ tcg_out_insn(s, RI, AGHI, ret, 1);
+ }
return;
}
- /* Otherwise, stuff it in the constant pool. */
- if (HAVE_FACILITY(GEN_INST_EXT)) {
- tcg_out_insn(s, RIL, LGRL, ret, 0);
- new_pool_label(s, sval, R_390_PC32DBL, s->code_ptr - 2, 2);
- } else if (USE_REG_TB && !in_prologue) {
- tcg_out_insn(s, RXY, LG, ret, TCG_REG_TB, TCG_REG_NONE, 0);
- new_pool_label(s, sval, R_390_20, s->code_ptr - 2,
- tcg_tbrel_diff(s, NULL));
+ /* Otherwise, load it by parts. */
+ i = is_const_p16((uint32_t)uval);
+ if (i >= 0) {
+ tcg_out_insn_RI(s, li_insns[i], ret, uval >> (i * 16));
} else {
- TCGReg base = ret ? ret : TCG_TMP0;
- tcg_out_insn(s, RIL, LARL, base, 0);
- new_pool_label(s, sval, R_390_PC32DBL, s->code_ptr - 2, 2);
- tcg_out_insn(s, RXY, LG, ret, base, TCG_REG_NONE, 0);
+ tcg_out_insn(s, RIL, LLILF, ret, uval);
+ }
+ uval >>= 32;
+ i = is_const_p16(uval);
+ if (i >= 0) {
+ tcg_out_insn_RI(s, oi_insns[i + 2], ret, uval >> (i * 16));
+ } else {
+ tcg_out_insn(s, RIL, OIHF, ret, uval);
}
-}
-
-static void tcg_out_movi(TCGContext *s, TCGType type,
- TCGReg ret, tcg_target_long sval)
-{
- tcg_out_movi_int(s, type, ret, sval, false);
}
/* Emit a load/store type instruction. Inputs are:
@@ -1020,122 +1073,33 @@ static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
return false;
}
-/* load data from an absolute host address */
-static void tcg_out_ld_abs(TCGContext *s, TCGType type,
- TCGReg dest, const void *abs)
-{
- intptr_t addr = (intptr_t)abs;
-
- if (HAVE_FACILITY(GEN_INST_EXT) && !(addr & 1)) {
- ptrdiff_t disp = tcg_pcrel_diff(s, abs) >> 1;
- if (disp == (int32_t)disp) {
- if (type == TCG_TYPE_I32) {
- tcg_out_insn(s, RIL, LRL, dest, disp);
- } else {
- tcg_out_insn(s, RIL, LGRL, dest, disp);
- }
- return;
- }
- }
- if (USE_REG_TB) {
- ptrdiff_t disp = tcg_tbrel_diff(s, abs);
- if (disp == sextract64(disp, 0, 20)) {
- tcg_out_ld(s, type, dest, TCG_REG_TB, disp);
- return;
- }
- }
-
- tcg_out_movi(s, TCG_TYPE_PTR, dest, addr & ~0xffff);
- tcg_out_ld(s, type, dest, dest, addr & 0xffff);
-}
-
static inline void tcg_out_risbg(TCGContext *s, TCGReg dest, TCGReg src,
int msb, int lsb, int ofs, int z)
{
/* Format RIE-f */
- tcg_out16(s, (RIE_RISBG & 0xff00) | (dest << 4) | src);
+ tcg_out16(s, (RIEf_RISBG & 0xff00) | (dest << 4) | src);
tcg_out16(s, (msb << 8) | (z << 7) | lsb);
- tcg_out16(s, (ofs << 8) | (RIE_RISBG & 0xff));
+ tcg_out16(s, (ofs << 8) | (RIEf_RISBG & 0xff));
}
static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
{
- if (HAVE_FACILITY(EXT_IMM)) {
- tcg_out_insn(s, RRE, LGBR, dest, src);
- return;
- }
-
- if (type == TCG_TYPE_I32) {
- if (dest == src) {
- tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 24);
- } else {
- tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 24);
- }
- tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 24);
- } else {
- tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 56);
- tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 56);
- }
+ tcg_out_insn(s, RRE, LGBR, dest, src);
}
static void tgen_ext8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
{
- if (HAVE_FACILITY(EXT_IMM)) {
- tcg_out_insn(s, RRE, LLGCR, dest, src);
- return;
- }
-
- if (dest == src) {
- tcg_out_movi(s, type, TCG_TMP0, 0xff);
- src = TCG_TMP0;
- } else {
- tcg_out_movi(s, type, dest, 0xff);
- }
- if (type == TCG_TYPE_I32) {
- tcg_out_insn(s, RR, NR, dest, src);
- } else {
- tcg_out_insn(s, RRE, NGR, dest, src);
- }
+ tcg_out_insn(s, RRE, LLGCR, dest, src);
}
static void tgen_ext16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
{
- if (HAVE_FACILITY(EXT_IMM)) {
- tcg_out_insn(s, RRE, LGHR, dest, src);
- return;
- }
-
- if (type == TCG_TYPE_I32) {
- if (dest == src) {
- tcg_out_sh32(s, RS_SLL, dest, TCG_REG_NONE, 16);
- } else {
- tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 16);
- }
- tcg_out_sh32(s, RS_SRA, dest, TCG_REG_NONE, 16);
- } else {
- tcg_out_sh64(s, RSY_SLLG, dest, src, TCG_REG_NONE, 48);
- tcg_out_sh64(s, RSY_SRAG, dest, dest, TCG_REG_NONE, 48);
- }
+ tcg_out_insn(s, RRE, LGHR, dest, src);
}
static void tgen_ext16u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
{
- if (HAVE_FACILITY(EXT_IMM)) {
- tcg_out_insn(s, RRE, LLGHR, dest, src);
- return;
- }
-
- if (dest == src) {
- tcg_out_movi(s, type, TCG_TMP0, 0xffff);
- src = TCG_TMP0;
- } else {
- tcg_out_movi(s, type, dest, 0xffff);
- }
- if (type == TCG_TYPE_I32) {
- tcg_out_insn(s, RR, NR, dest, src);
- } else {
- tcg_out_insn(s, RRE, NGR, dest, src);
- }
+ tcg_out_insn(s, RRE, LLGHR, dest, src);
}
static inline void tgen_ext32s(TCGContext *s, TCGReg dest, TCGReg src)
@@ -1148,36 +1112,6 @@ static inline void tgen_ext32u(TCGContext *s, TCGReg dest, TCGReg src)
tcg_out_insn(s, RRE, LLGFR, dest, src);
}
-/* Accept bit patterns like these:
- 0....01....1
- 1....10....0
- 1..10..01..1
- 0..01..10..0
- Copied from gcc sources. */
-static inline bool risbg_mask(uint64_t c)
-{
- uint64_t lsb;
- /* We don't change the number of transitions by inverting,
- so make sure we start with the LSB zero. */
- if (c & 1) {
- c = ~c;
- }
- /* Reject all zeros or all ones. */
- if (c == 0) {
- return false;
- }
- /* Find the first transition. */
- lsb = c & -c;
- /* Invert to look for a second transition. */
- c = ~c;
- /* Erase the first transition. */
- c &= -lsb;
- /* Find the second transition, if any. */
- lsb = c & -c;
- /* Match if all the bits are 1's, or if c is zero. */
- return c == -lsb;
-}
-
static void tgen_andi_risbg(TCGContext *s, TCGReg out, TCGReg in, uint64_t val)
{
int msb, lsb;
@@ -1208,157 +1142,78 @@ static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
tgen_ext32u(s, dest, dest);
return;
}
- if (HAVE_FACILITY(EXT_IMM)) {
- if ((val & valid) == 0xff) {
- tgen_ext8u(s, TCG_TYPE_I64, dest, dest);
- return;
- }
- if ((val & valid) == 0xffff) {
- tgen_ext16u(s, TCG_TYPE_I64, dest, dest);
- return;
- }
+ if ((val & valid) == 0xff) {
+ tgen_ext8u(s, TCG_TYPE_I64, dest, dest);
+ return;
+ }
+ if ((val & valid) == 0xffff) {
+ tgen_ext16u(s, TCG_TYPE_I64, dest, dest);
+ return;
}
- /* Try all 32-bit insns that can perform it in one go. */
- for (i = 0; i < 4; i++) {
- tcg_target_ulong mask = ~(0xffffull << i * 16);
- if (((val | ~valid) & mask) == mask) {
- tcg_out_insn_RI(s, ni_insns[i], dest, val >> i * 16);
- return;
- }
+ i = is_const_p16(~val & valid);
+ if (i >= 0) {
+ tcg_out_insn_RI(s, ni_insns[i], dest, val >> (i * 16));
+ return;
}
- /* Try all 48-bit insns that can perform it in one go. */
- if (HAVE_FACILITY(EXT_IMM)) {
- for (i = 0; i < 2; i++) {
- tcg_target_ulong mask = ~(0xffffffffull << i * 32);
- if (((val | ~valid) & mask) == mask) {
- tcg_out_insn_RIL(s, nif_insns[i], dest, val >> i * 32);
- return;
- }
- }
+ i = is_const_p32(~val & valid);
+ tcg_debug_assert(i == 0 || type != TCG_TYPE_I32);
+ if (i >= 0) {
+ tcg_out_insn_RIL(s, nif_insns[i], dest, val >> (i * 32));
+ return;
}
- if (HAVE_FACILITY(GEN_INST_EXT) && risbg_mask(val)) {
+
+ if (risbg_mask(val)) {
tgen_andi_risbg(s, dest, dest, val);
return;
}
- /* Use the constant pool if USE_REG_TB, but not for small constants. */
- if (USE_REG_TB) {
- if (!maybe_out_small_movi(s, type, TCG_TMP0, val)) {
- tcg_out_insn(s, RXY, NG, dest, TCG_REG_TB, TCG_REG_NONE, 0);
- new_pool_label(s, val & valid, R_390_20, s->code_ptr - 2,
- tcg_tbrel_diff(s, NULL));
- return;
- }
- } else {
- tcg_out_movi(s, type, TCG_TMP0, val);
- }
- if (type == TCG_TYPE_I32) {
- tcg_out_insn(s, RR, NR, dest, TCG_TMP0);
- } else {
- tcg_out_insn(s, RRE, NGR, dest, TCG_TMP0);
- }
+ g_assert_not_reached();
}
-static void tgen_ori(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
+static void tgen_ori(TCGContext *s, TCGReg dest, uint64_t val)
{
- static const S390Opcode oi_insns[4] = {
- RI_OILL, RI_OILH, RI_OIHL, RI_OIHH
- };
static const S390Opcode oif_insns[2] = {
RIL_OILF, RIL_OIHF
};
int i;
- /* Look for no-op. */
- if (unlikely(val == 0)) {
+ i = is_const_p16(val);
+ if (i >= 0) {
+ tcg_out_insn_RI(s, oi_insns[i], dest, val >> (i * 16));
return;
}
- /* Try all 32-bit insns that can perform it in one go. */
- for (i = 0; i < 4; i++) {
- tcg_target_ulong mask = (0xffffull << i * 16);
- if ((val & mask) != 0 && (val & ~mask) == 0) {
- tcg_out_insn_RI(s, oi_insns[i], dest, val >> i * 16);
- return;
- }
- }
-
- /* Try all 48-bit insns that can perform it in one go. */
- if (HAVE_FACILITY(EXT_IMM)) {
- for (i = 0; i < 2; i++) {
- tcg_target_ulong mask = (0xffffffffull << i * 32);
- if ((val & mask) != 0 && (val & ~mask) == 0) {
- tcg_out_insn_RIL(s, oif_insns[i], dest, val >> i * 32);
- return;
- }
- }
+ i = is_const_p32(val);
+ if (i >= 0) {
+ tcg_out_insn_RIL(s, oif_insns[i], dest, val >> (i * 32));
+ return;
}
- /* Use the constant pool if USE_REG_TB, but not for small constants. */
- if (maybe_out_small_movi(s, type, TCG_TMP0, val)) {
- if (type == TCG_TYPE_I32) {
- tcg_out_insn(s, RR, OR, dest, TCG_TMP0);
- } else {
- tcg_out_insn(s, RRE, OGR, dest, TCG_TMP0);
- }
- } else if (USE_REG_TB) {
- tcg_out_insn(s, RXY, OG, dest, TCG_REG_TB, TCG_REG_NONE, 0);
- new_pool_label(s, val, R_390_20, s->code_ptr - 2,
- tcg_tbrel_diff(s, NULL));
- } else {
- /* Perform the OR via sequential modifications to the high and
- low parts. Do this via recursion to handle 16-bit vs 32-bit
- masks in each half. */
- tcg_debug_assert(HAVE_FACILITY(EXT_IMM));
- tgen_ori(s, type, dest, val & 0x00000000ffffffffull);
- tgen_ori(s, type, dest, val & 0xffffffff00000000ull);
- }
+ g_assert_not_reached();
}
-static void tgen_xori(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
+static void tgen_xori(TCGContext *s, TCGReg dest, uint64_t val)
{
- /* Try all 48-bit insns that can perform it in one go. */
- if (HAVE_FACILITY(EXT_IMM)) {
- if ((val & 0xffffffff00000000ull) == 0) {
- tcg_out_insn(s, RIL, XILF, dest, val);
- return;
- }
- if ((val & 0x00000000ffffffffull) == 0) {
- tcg_out_insn(s, RIL, XIHF, dest, val >> 32);
- return;
- }
- }
-
- /* Use the constant pool if USE_REG_TB, but not for small constants. */
- if (maybe_out_small_movi(s, type, TCG_TMP0, val)) {
- if (type == TCG_TYPE_I32) {
- tcg_out_insn(s, RR, XR, dest, TCG_TMP0);
- } else {
- tcg_out_insn(s, RRE, XGR, dest, TCG_TMP0);
- }
- } else if (USE_REG_TB) {
- tcg_out_insn(s, RXY, XG, dest, TCG_REG_TB, TCG_REG_NONE, 0);
- new_pool_label(s, val, R_390_20, s->code_ptr - 2,
- tcg_tbrel_diff(s, NULL));
- } else {
- /* Perform the xor by parts. */
- tcg_debug_assert(HAVE_FACILITY(EXT_IMM));
- if (val & 0xffffffff) {
- tcg_out_insn(s, RIL, XILF, dest, val);
- }
- if (val > 0xffffffff) {
- tcg_out_insn(s, RIL, XIHF, dest, val >> 32);
- }
+ switch (is_const_p32(val)) {
+ case 0:
+ tcg_out_insn(s, RIL, XILF, dest, val);
+ break;
+ case 1:
+ tcg_out_insn(s, RIL, XIHF, dest, val >> 32);
+ break;
+ default:
+ g_assert_not_reached();
}
}
-static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
- TCGArg c2, bool c2const, bool need_carry)
+static int tgen_cmp2(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
+ TCGArg c2, bool c2const, bool need_carry, int *inv_cc)
{
bool is_unsigned = is_unsigned_cond(c);
+ TCGCond inv_c = tcg_invert_cond(c);
S390Opcode op;
if (c2const) {
@@ -1369,6 +1224,7 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
} else {
tcg_out_insn(s, RRE, LTGR, r1, r1);
}
+ *inv_cc = tcg_cond_to_ltr_cond[inv_c];
return tcg_cond_to_ltr_cond[c];
}
}
@@ -1379,48 +1235,25 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
goto exit;
}
- if (HAVE_FACILITY(EXT_IMM)) {
- if (type == TCG_TYPE_I32) {
- op = (is_unsigned ? RIL_CLFI : RIL_CFI);
- tcg_out_insn_RIL(s, op, r1, c2);
- goto exit;
- } else if (c2 == (is_unsigned ? (TCGArg)(uint32_t)c2 : (TCGArg)(int32_t)c2)) {
- op = (is_unsigned ? RIL_CLGFI : RIL_CGFI);
- tcg_out_insn_RIL(s, op, r1, c2);
- goto exit;
- }
+ if (type == TCG_TYPE_I32) {
+ op = (is_unsigned ? RIL_CLFI : RIL_CFI);
+ tcg_out_insn_RIL(s, op, r1, c2);
+ goto exit;
}
- /* Use the constant pool, but not for small constants. */
- if (maybe_out_small_movi(s, type, TCG_TMP0, c2)) {
- c2 = TCG_TMP0;
- /* fall through to reg-reg */
- } else if (USE_REG_TB) {
- if (type == TCG_TYPE_I32) {
- op = (is_unsigned ? RXY_CLY : RXY_CY);
- tcg_out_insn_RXY(s, op, r1, TCG_REG_TB, TCG_REG_NONE, 0);
- new_pool_label(s, (uint32_t)c2, R_390_20, s->code_ptr - 2,
- 4 - tcg_tbrel_diff(s, NULL));
- } else {
- op = (is_unsigned ? RXY_CLG : RXY_CG);
- tcg_out_insn_RXY(s, op, r1, TCG_REG_TB, TCG_REG_NONE, 0);
- new_pool_label(s, c2, R_390_20, s->code_ptr - 2,
- tcg_tbrel_diff(s, NULL));
- }
- goto exit;
- } else {
- if (type == TCG_TYPE_I32) {
- op = (is_unsigned ? RIL_CLRL : RIL_CRL);
- tcg_out_insn_RIL(s, op, r1, 0);
- new_pool_label(s, (uint32_t)c2, R_390_PC32DBL,
- s->code_ptr - 2, 2 + 4);
- } else {
- op = (is_unsigned ? RIL_CLGRL : RIL_CGRL);
- tcg_out_insn_RIL(s, op, r1, 0);
- new_pool_label(s, c2, R_390_PC32DBL, s->code_ptr - 2, 2);
- }
+ /*
+ * Constraints are for a signed 33-bit operand, which is a
+ * convenient superset of this signed/unsigned test.
+ */
+ if (c2 == (is_unsigned ? (TCGArg)(uint32_t)c2 : (TCGArg)(int32_t)c2)) {
+ op = (is_unsigned ? RIL_CLGFI : RIL_CGFI);
+ tcg_out_insn_RIL(s, op, r1, c2);
goto exit;
}
+
+ /* Load everything else into a register. */
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, c2);
+ c2 = TCG_TMP0;
}
if (type == TCG_TYPE_I32) {
@@ -1432,27 +1265,31 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
}
exit:
+ *inv_cc = tcg_cond_to_s390_cond[inv_c];
return tcg_cond_to_s390_cond[c];
}
+static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
+ TCGArg c2, bool c2const, bool need_carry)
+{
+ int inv_cc;
+ return tgen_cmp2(s, type, c, r1, c2, c2const, need_carry, &inv_cc);
+}
+
static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
TCGReg dest, TCGReg c1, TCGArg c2, int c2const)
{
int cc;
- bool have_loc;
/* With LOC2, we can always emit the minimum 3 insns. */
if (HAVE_FACILITY(LOAD_ON_COND2)) {
/* Emit: d = 0, d = (cc ? 1 : d). */
cc = tgen_cmp(s, type, cond, c1, c2, c2const, false);
tcg_out_movi(s, TCG_TYPE_I64, dest, 0);
- tcg_out_insn(s, RIE, LOCGHI, dest, 1, cc);
+ tcg_out_insn(s, RIEg, LOCGHI, dest, 1, cc);
return;
}
- have_loc = HAVE_FACILITY(LOAD_ON_COND);
-
- /* For HAVE_LOC, only the paths through GTU/GT/LEU/LE are smaller. */
restart:
switch (cond) {
case TCG_COND_NE:
@@ -1497,60 +1334,74 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
case TCG_COND_LT:
case TCG_COND_GE:
/* Swap operands so that we can use LEU/GTU/GT/LE. */
- if (c2const) {
- if (have_loc) {
- break;
- }
- tcg_out_movi(s, type, TCG_TMP0, c2);
- c2 = c1;
- c2const = 0;
- c1 = TCG_TMP0;
- } else {
+ if (!c2const) {
TCGReg t = c1;
c1 = c2;
c2 = t;
+ cond = tcg_swap_cond(cond);
+ goto restart;
}
- cond = tcg_swap_cond(cond);
- goto restart;
+ break;
default:
g_assert_not_reached();
}
cc = tgen_cmp(s, type, cond, c1, c2, c2const, false);
- if (have_loc) {
- /* Emit: d = 0, t = 1, d = (cc ? t : d). */
- tcg_out_movi(s, TCG_TYPE_I64, dest, 0);
- tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1);
- tcg_out_insn(s, RRF, LOCGR, dest, TCG_TMP0, cc);
+ /* Emit: d = 0, t = 1, d = (cc ? t : d). */
+ tcg_out_movi(s, TCG_TYPE_I64, dest, 0);
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1);
+ tcg_out_insn(s, RRFc, LOCGR, dest, TCG_TMP0, cc);
+}
+
+static void tgen_movcond_int(TCGContext *s, TCGType type, TCGReg dest,
+ TCGArg v3, int v3const, TCGReg v4,
+ int cc, int inv_cc)
+{
+ TCGReg src;
+
+ if (v3const) {
+ if (dest == v4) {
+ if (HAVE_FACILITY(LOAD_ON_COND2)) {
+ /* Emit: if (cc) dest = v3. */
+ tcg_out_insn(s, RIEg, LOCGHI, dest, v3, cc);
+ return;
+ }
+ tcg_out_insn(s, RI, LGHI, TCG_TMP0, v3);
+ src = TCG_TMP0;
+ } else {
+ /* LGR+LOCGHI is larger than LGHI+LOCGR. */
+ tcg_out_insn(s, RI, LGHI, dest, v3);
+ cc = inv_cc;
+ src = v4;
+ }
} else {
- /* Emit: d = 1; if (cc) goto over; d = 0; over: */
- tcg_out_movi(s, type, dest, 1);
- tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
- tcg_out_movi(s, type, dest, 0);
+ if (HAVE_FACILITY(MISC_INSN_EXT3)) {
+ /* Emit: dest = cc ? v3 : v4. */
+ tcg_out_insn(s, RRFam, SELGR, dest, v3, v4, cc);
+ return;
+ }
+ if (dest == v4) {
+ src = v3;
+ } else {
+ tcg_out_mov(s, type, dest, v3);
+ cc = inv_cc;
+ src = v4;
+ }
}
+
+ /* Emit: if (cc) dest = src. */
+ tcg_out_insn(s, RRFc, LOCGR, dest, src, cc);
}
static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest,
TCGReg c1, TCGArg c2, int c2const,
- TCGArg v3, int v3const)
+ TCGArg v3, int v3const, TCGReg v4)
{
- int cc;
- if (HAVE_FACILITY(LOAD_ON_COND)) {
- cc = tgen_cmp(s, type, c, c1, c2, c2const, false);
- if (v3const) {
- tcg_out_insn(s, RIE, LOCGHI, dest, v3, cc);
- } else {
- tcg_out_insn(s, RRF, LOCGR, dest, v3, cc);
- }
- } else {
- c = tcg_invert_cond(c);
- cc = tgen_cmp(s, type, c, c1, c2, c2const, false);
+ int cc, inv_cc;
- /* Emit: if (cc) goto over; dest = r3; over: */
- tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
- tcg_out_insn(s, RRE, LGR, dest, v3);
- }
+ cc = tgen_cmp2(s, type, c, c1, c2, c2const, false, &inv_cc);
+ tgen_movcond_int(s, type, dest, v3, v3const, v4, cc, inv_cc);
}
static void tgen_clz(TCGContext *s, TCGReg dest, TCGReg a1,
@@ -1563,20 +1414,40 @@ static void tgen_clz(TCGContext *s, TCGReg dest, TCGReg a1,
if (a2const && a2 == 64) {
tcg_out_mov(s, TCG_TYPE_I64, dest, TCG_REG_R0);
- } else {
- if (a2const) {
- tcg_out_movi(s, TCG_TYPE_I64, dest, a2);
- } else {
- tcg_out_mov(s, TCG_TYPE_I64, dest, a2);
- }
- if (HAVE_FACILITY(LOAD_ON_COND)) {
- /* Emit: if (one bit found) dest = r0. */
- tcg_out_insn(s, RRF, LOCGR, dest, TCG_REG_R0, 2);
- } else {
- /* Emit: if (no one bit found) goto over; dest = r0; over: */
- tcg_out_insn(s, RI, BRC, 8, (4 + 4) >> 1);
- tcg_out_insn(s, RRE, LGR, dest, TCG_REG_R0);
+ return;
+ }
+
+ /*
+ * Conditions from FLOGR are:
+ * 2 -> one bit found
+ * 8 -> no one bit found
+ */
+ tgen_movcond_int(s, TCG_TYPE_I64, dest, a2, a2const, TCG_REG_R0, 8, 2);
+}
+
+static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
+{
+ /* With MIE3, and bit 0 of m4 set, we get the complete result. */
+ if (HAVE_FACILITY(MISC_INSN_EXT3)) {
+ if (type == TCG_TYPE_I32) {
+ tgen_ext32u(s, dest, src);
+ src = dest;
}
+ tcg_out_insn(s, RRFc, POPCNT, dest, src, 8);
+ return;
+ }
+
+ /* Without MIE3, each byte gets the count of bits for the byte. */
+ tcg_out_insn(s, RRFc, POPCNT, dest, src, 0);
+
+ /* Multiply to sum each byte at the top of the word. */
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RIL, MSFI, dest, 0x01010101);
+ tcg_out_sh32(s, RS_SRL, dest, TCG_REG_NONE, 24);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 0x0101010101010101ull);
+ tcg_out_insn(s, RRE, MSGR, dest, TCG_TMP0);
+ tcg_out_sh64(s, RSY_SRLG, dest, dest, TCG_REG_NONE, 56);
}
}
@@ -1611,10 +1482,6 @@ static void tgen_branch(TCGContext *s, int cc, TCGLabel *l)
{
if (l->has_value) {
tgen_gotoi(s, cc, l->u.value_ptr);
- } else if (USE_LONG_BRANCHES) {
- tcg_out16(s, RIL_BRCL | (cc << 4));
- tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, l, 2);
- s->code_ptr += 2;
} else {
tcg_out16(s, RI_BRC | (cc << 4));
tcg_out_reloc(s, s->code_ptr, R_390_PC16DBL, l, 2);
@@ -1626,6 +1493,7 @@ static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc,
TCGReg r1, TCGReg r2, TCGLabel *l)
{
tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
+ /* Format RIE-b */
tcg_out16(s, (opc & 0xff00) | (r1 << 4) | r2);
tcg_out16(s, 0);
tcg_out16(s, cc << 12 | (opc & 0xff));
@@ -1635,6 +1503,7 @@ static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc,
TCGReg r1, int i2, TCGLabel *l)
{
tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
+ /* Format RIE-c */
tcg_out16(s, (opc & 0xff00) | (r1 << 4) | cc);
tcg_out16(s, 0);
tcg_out16(s, (i2 << 8) | (opc & 0xff));
@@ -1644,48 +1513,47 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
TCGReg r1, TCGArg c2, int c2const, TCGLabel *l)
{
int cc;
+ bool is_unsigned = is_unsigned_cond(c);
+ bool in_range;
+ S390Opcode opc;
- if (HAVE_FACILITY(GEN_INST_EXT)) {
- bool is_unsigned = is_unsigned_cond(c);
- bool in_range;
- S390Opcode opc;
-
- cc = tcg_cond_to_s390_cond[c];
+ cc = tcg_cond_to_s390_cond[c];
- if (!c2const) {
- opc = (type == TCG_TYPE_I32
- ? (is_unsigned ? RIE_CLRJ : RIE_CRJ)
- : (is_unsigned ? RIE_CLGRJ : RIE_CGRJ));
- tgen_compare_branch(s, opc, cc, r1, c2, l);
- return;
- }
+ if (!c2const) {
+ opc = (type == TCG_TYPE_I32
+ ? (is_unsigned ? RIEb_CLRJ : RIEb_CRJ)
+ : (is_unsigned ? RIEb_CLGRJ : RIEb_CGRJ));
+ tgen_compare_branch(s, opc, cc, r1, c2, l);
+ return;
+ }
- /* COMPARE IMMEDIATE AND BRANCH RELATIVE has an 8-bit immediate field.
- If the immediate we've been given does not fit that range, we'll
- fall back to separate compare and branch instructions using the
- larger comparison range afforded by COMPARE IMMEDIATE. */
- if (type == TCG_TYPE_I32) {
- if (is_unsigned) {
- opc = RIE_CLIJ;
- in_range = (uint32_t)c2 == (uint8_t)c2;
- } else {
- opc = RIE_CIJ;
- in_range = (int32_t)c2 == (int8_t)c2;
- }
+ /*
+ * COMPARE IMMEDIATE AND BRANCH RELATIVE has an 8-bit immediate field.
+ * If the immediate we've been given does not fit that range, we'll
+ * fall back to separate compare and branch instructions using the
+ * larger comparison range afforded by COMPARE IMMEDIATE.
+ */
+ if (type == TCG_TYPE_I32) {
+ if (is_unsigned) {
+ opc = RIEc_CLIJ;
+ in_range = (uint32_t)c2 == (uint8_t)c2;
} else {
- if (is_unsigned) {
- opc = RIE_CLGIJ;
- in_range = (uint64_t)c2 == (uint8_t)c2;
- } else {
- opc = RIE_CGIJ;
- in_range = (int64_t)c2 == (int8_t)c2;
- }
+ opc = RIEc_CIJ;
+ in_range = (int32_t)c2 == (int8_t)c2;
}
- if (in_range) {
- tgen_compare_imm_branch(s, opc, cc, r1, c2, l);
- return;
+ } else {
+ if (is_unsigned) {
+ opc = RIEc_CLGIJ;
+ in_range = (uint64_t)c2 == (uint8_t)c2;
+ } else {
+ opc = RIEc_CGIJ;
+ in_range = (int64_t)c2 == (int8_t)c2;
}
}
+ if (in_range) {
+ tgen_compare_imm_branch(s, opc, cc, r1, c2, l);
+ return;
+ }
cc = tgen_cmp(s, type, c, r1, c2, c2const, false);
tgen_branch(s, cc, l);
@@ -1843,7 +1711,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
cross pages using the address of the last byte of the access. */
a_off = (a_bits >= s_bits ? 0 : s_mask - a_mask);
tlb_mask = (uint64_t)TARGET_PAGE_MASK | a_mask;
- if (HAVE_FACILITY(GEN_INST_EXT) && a_off == 0) {
+ if (a_off == 0) {
tgen_andi_risbg(s, TCG_REG_R3, addr_reg, tlb_mask);
} else {
tcg_out_insn(s, RX, LA, TCG_REG_R3, addr_reg, TCG_REG_NONE, a_off);
@@ -2101,43 +1969,21 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
case INDEX_op_goto_tb:
a0 = args[0];
- if (s->tb_jmp_insn_offset) {
- /*
- * branch displacement must be aligned for atomic patching;
- * see if we need to add extra nop before branch
- */
- if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) {
- tcg_out16(s, NOP);
- }
- tcg_debug_assert(!USE_REG_TB);
- tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4));
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
- s->code_ptr += 2;
- } else {
- /* load address stored at s->tb_jmp_target_addr + a0 */
- tcg_out_ld_abs(s, TCG_TYPE_PTR, TCG_REG_TB,
- tcg_splitwx_to_rx(s->tb_jmp_target_addr + a0));
- /* and go there */
- tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_TB);
- }
+ /*
+ * branch displacement must be aligned for atomic patching;
+ * see if we need to add extra nop before branch
+ */
+ if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) {
+ tcg_out16(s, NOP);
+ }
+ tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4));
+ s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
+ s->code_ptr += 2;
set_jmp_reset_offset(s, a0);
-
- /* For the unlinked path of goto_tb, we need to reset
- TCG_REG_TB to the beginning of this TB. */
- if (USE_REG_TB) {
- int ofs = -tcg_current_code_size(s);
- /* All TB are restricted to 64KiB by unwind info. */
- tcg_debug_assert(ofs == sextract64(ofs, 0, 20));
- tcg_out_insn(s, RXY, LAY, TCG_REG_TB,
- TCG_REG_TB, TCG_REG_NONE, ofs);
- }
break;
case INDEX_op_goto_ptr:
a0 = args[0];
- if (USE_REG_TB) {
- tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, a0);
- }
tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, a0);
break;
@@ -2189,10 +2035,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_insn(s, RI, AHI, a0, a2);
break;
}
- if (HAVE_FACILITY(EXT_IMM)) {
- tcg_out_insn(s, RIL, AFI, a0, a2);
- break;
- }
+ tcg_out_insn(s, RIL, AFI, a0, a2);
+ break;
}
tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2);
} else if (a0 == a1) {
@@ -2209,7 +2053,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
} else if (a0 == a1) {
tcg_out_insn(s, RR, SR, a0, a2);
} else {
- tcg_out_insn(s, RRF, SRK, a0, a1, a2);
+ tcg_out_insn(s, RRFa, SRK, a0, a1, a2);
}
break;
@@ -2221,53 +2065,102 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
} else if (a0 == a1) {
tcg_out_insn(s, RR, NR, a0, a2);
} else {
- tcg_out_insn(s, RRF, NRK, a0, a1, a2);
+ tcg_out_insn(s, RRFa, NRK, a0, a1, a2);
}
break;
case INDEX_op_or_i32:
a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2];
if (const_args[2]) {
tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
- tgen_ori(s, TCG_TYPE_I32, a0, a2);
+ tgen_ori(s, a0, a2);
} else if (a0 == a1) {
tcg_out_insn(s, RR, OR, a0, a2);
} else {
- tcg_out_insn(s, RRF, ORK, a0, a1, a2);
+ tcg_out_insn(s, RRFa, ORK, a0, a1, a2);
}
break;
case INDEX_op_xor_i32:
a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2];
if (const_args[2]) {
tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
- tgen_xori(s, TCG_TYPE_I32, a0, a2);
+ tcg_out_insn(s, RIL, XILF, a0, a2);
} else if (a0 == a1) {
tcg_out_insn(s, RR, XR, args[0], args[2]);
} else {
- tcg_out_insn(s, RRF, XRK, a0, a1, a2);
+ tcg_out_insn(s, RRFa, XRK, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_andc_i32:
+ a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2];
+ if (const_args[2]) {
+ tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
+ tgen_andi(s, TCG_TYPE_I32, a0, (uint32_t)~a2);
+ } else {
+ tcg_out_insn(s, RRFa, NCRK, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_orc_i32:
+ a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2];
+ if (const_args[2]) {
+ tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
+ tgen_ori(s, a0, (uint32_t)~a2);
+ } else {
+ tcg_out_insn(s, RRFa, OCRK, a0, a1, a2);
}
break;
+ case INDEX_op_eqv_i32:
+ a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2];
+ if (const_args[2]) {
+ tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
+ tcg_out_insn(s, RIL, XILF, a0, ~a2);
+ } else {
+ tcg_out_insn(s, RRFa, NXRK, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_nand_i32:
+ tcg_out_insn(s, RRFa, NNRK, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_nor_i32:
+ tcg_out_insn(s, RRFa, NORK, args[0], args[1], args[2]);
+ break;
case INDEX_op_neg_i32:
tcg_out_insn(s, RR, LCR, args[0], args[1]);
break;
+ case INDEX_op_not_i32:
+ tcg_out_insn(s, RRFa, NORK, args[0], args[1], args[1]);
+ break;
case INDEX_op_mul_i32:
+ a0 = args[0], a1 = args[1], a2 = (int32_t)args[2];
if (const_args[2]) {
- if ((int32_t)args[2] == (int16_t)args[2]) {
- tcg_out_insn(s, RI, MHI, args[0], args[2]);
+ tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
+ if (a2 == (int16_t)a2) {
+ tcg_out_insn(s, RI, MHI, a0, a2);
} else {
- tcg_out_insn(s, RIL, MSFI, args[0], args[2]);
+ tcg_out_insn(s, RIL, MSFI, a0, a2);
}
+ } else if (a0 == a1) {
+ tcg_out_insn(s, RRE, MSR, a0, a2);
} else {
- tcg_out_insn(s, RRE, MSR, args[0], args[2]);
+ tcg_out_insn(s, RRFa, MSRKC, a0, a1, a2);
}
break;
case INDEX_op_div2_i32:
- tcg_out_insn(s, RR, DR, TCG_REG_R2, args[4]);
+ tcg_debug_assert(args[0] == args[2]);
+ tcg_debug_assert(args[1] == args[3]);
+ tcg_debug_assert((args[1] & 1) == 0);
+ tcg_debug_assert(args[0] == args[1] + 1);
+ tcg_out_insn(s, RR, DR, args[1], args[4]);
break;
case INDEX_op_divu2_i32:
- tcg_out_insn(s, RRE, DLR, TCG_REG_R2, args[4]);
+ tcg_debug_assert(args[0] == args[2]);
+ tcg_debug_assert(args[1] == args[3]);
+ tcg_debug_assert((args[1] & 1) == 0);
+ tcg_debug_assert(args[0] == args[1] + 1);
+ tcg_out_insn(s, RRE, DLR, args[1], args[4]);
break;
case INDEX_op_shl_i32:
@@ -2393,7 +2286,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_movcond_i32:
tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1],
- args[2], const_args[2], args[3], const_args[3]);
+ args[2], const_args[2], args[3], const_args[3], args[4]);
break;
case INDEX_op_qemu_ld_i32:
@@ -2435,17 +2328,17 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_insn(s, RI, AGHI, a0, a2);
break;
}
- if (HAVE_FACILITY(EXT_IMM)) {
- if (a2 == (int32_t)a2) {
- tcg_out_insn(s, RIL, AGFI, a0, a2);
- break;
- } else if (a2 == (uint32_t)a2) {
- tcg_out_insn(s, RIL, ALGFI, a0, a2);
- break;
- } else if (-a2 == (uint32_t)-a2) {
- tcg_out_insn(s, RIL, SLGFI, a0, -a2);
- break;
- }
+ if (a2 == (int32_t)a2) {
+ tcg_out_insn(s, RIL, AGFI, a0, a2);
+ break;
+ }
+ if (a2 == (uint32_t)a2) {
+ tcg_out_insn(s, RIL, ALGFI, a0, a2);
+ break;
+ }
+ if (-a2 == (uint32_t)-a2) {
+ tcg_out_insn(s, RIL, SLGFI, a0, -a2);
+ break;
}
}
tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2);
@@ -2460,10 +2353,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
if (const_args[2]) {
a2 = -a2;
goto do_addi_64;
- } else if (a0 == a1) {
- tcg_out_insn(s, RRE, SGR, a0, a2);
} else {
- tcg_out_insn(s, RRF, SGRK, a0, a1, a2);
+ tcg_out_insn(s, RRFa, SGRK, a0, a1, a2);
}
break;
@@ -2472,66 +2363,119 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
if (const_args[2]) {
tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
tgen_andi(s, TCG_TYPE_I64, args[0], args[2]);
- } else if (a0 == a1) {
- tcg_out_insn(s, RRE, NGR, args[0], args[2]);
} else {
- tcg_out_insn(s, RRF, NGRK, a0, a1, a2);
+ tcg_out_insn(s, RRFa, NGRK, a0, a1, a2);
}
break;
case INDEX_op_or_i64:
a0 = args[0], a1 = args[1], a2 = args[2];
if (const_args[2]) {
tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
- tgen_ori(s, TCG_TYPE_I64, a0, a2);
- } else if (a0 == a1) {
- tcg_out_insn(s, RRE, OGR, a0, a2);
+ tgen_ori(s, a0, a2);
} else {
- tcg_out_insn(s, RRF, OGRK, a0, a1, a2);
+ tcg_out_insn(s, RRFa, OGRK, a0, a1, a2);
}
break;
case INDEX_op_xor_i64:
a0 = args[0], a1 = args[1], a2 = args[2];
if (const_args[2]) {
tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
- tgen_xori(s, TCG_TYPE_I64, a0, a2);
- } else if (a0 == a1) {
- tcg_out_insn(s, RRE, XGR, a0, a2);
+ tgen_xori(s, a0, a2);
+ } else {
+ tcg_out_insn(s, RRFa, XGRK, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_andc_i64:
+ a0 = args[0], a1 = args[1], a2 = args[2];
+ if (const_args[2]) {
+ tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
+ tgen_andi(s, TCG_TYPE_I64, a0, ~a2);
+ } else {
+ tcg_out_insn(s, RRFa, NCGRK, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_orc_i64:
+ a0 = args[0], a1 = args[1], a2 = args[2];
+ if (const_args[2]) {
+ tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
+ tgen_ori(s, a0, ~a2);
+ } else {
+ tcg_out_insn(s, RRFa, OCGRK, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_eqv_i64:
+ a0 = args[0], a1 = args[1], a2 = args[2];
+ if (const_args[2]) {
+ tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
+ tgen_xori(s, a0, ~a2);
} else {
- tcg_out_insn(s, RRF, XGRK, a0, a1, a2);
+ tcg_out_insn(s, RRFa, NXGRK, a0, a1, a2);
}
break;
+ case INDEX_op_nand_i64:
+ tcg_out_insn(s, RRFa, NNGRK, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_nor_i64:
+ tcg_out_insn(s, RRFa, NOGRK, args[0], args[1], args[2]);
+ break;
case INDEX_op_neg_i64:
tcg_out_insn(s, RRE, LCGR, args[0], args[1]);
break;
+ case INDEX_op_not_i64:
+ tcg_out_insn(s, RRFa, NOGRK, args[0], args[1], args[1]);
+ break;
case INDEX_op_bswap64_i64:
tcg_out_insn(s, RRE, LRVGR, args[0], args[1]);
break;
case INDEX_op_mul_i64:
+ a0 = args[0], a1 = args[1], a2 = args[2];
if (const_args[2]) {
- if (args[2] == (int16_t)args[2]) {
- tcg_out_insn(s, RI, MGHI, args[0], args[2]);
+ tcg_out_mov(s, TCG_TYPE_I64, a0, a1);
+ if (a2 == (int16_t)a2) {
+ tcg_out_insn(s, RI, MGHI, a0, a2);
} else {
- tcg_out_insn(s, RIL, MSGFI, args[0], args[2]);
+ tcg_out_insn(s, RIL, MSGFI, a0, a2);
}
+ } else if (a0 == a1) {
+ tcg_out_insn(s, RRE, MSGR, a0, a2);
} else {
- tcg_out_insn(s, RRE, MSGR, args[0], args[2]);
+ tcg_out_insn(s, RRFa, MSGRKC, a0, a1, a2);
}
break;
case INDEX_op_div2_i64:
- /* ??? We get an unnecessary sign-extension of the dividend
- into R3 with this definition, but as we do in fact always
- produce both quotient and remainder using INDEX_op_div_i64
- instead requires jumping through even more hoops. */
- tcg_out_insn(s, RRE, DSGR, TCG_REG_R2, args[4]);
+ /*
+ * ??? We get an unnecessary sign-extension of the dividend
+ * into op0 with this definition, but as we do in fact always
+ * produce both quotient and remainder using INDEX_op_div_i64
+ * instead requires jumping through even more hoops.
+ */
+ tcg_debug_assert(args[0] == args[2]);
+ tcg_debug_assert(args[1] == args[3]);
+ tcg_debug_assert((args[1] & 1) == 0);
+ tcg_debug_assert(args[0] == args[1] + 1);
+ tcg_out_insn(s, RRE, DSGR, args[1], args[4]);
break;
case INDEX_op_divu2_i64:
- tcg_out_insn(s, RRE, DLGR, TCG_REG_R2, args[4]);
+ tcg_debug_assert(args[0] == args[2]);
+ tcg_debug_assert(args[1] == args[3]);
+ tcg_debug_assert((args[1] & 1) == 0);
+ tcg_debug_assert(args[0] == args[1] + 1);
+ tcg_out_insn(s, RRE, DLGR, args[1], args[4]);
break;
case INDEX_op_mulu2_i64:
- tcg_out_insn(s, RRE, MLGR, TCG_REG_R2, args[3]);
+ tcg_debug_assert(args[0] == args[2]);
+ tcg_debug_assert((args[1] & 1) == 0);
+ tcg_debug_assert(args[0] == args[1] + 1);
+ tcg_out_insn(s, RRE, MLGR, args[1], args[3]);
+ break;
+ case INDEX_op_muls2_i64:
+ tcg_debug_assert((args[1] & 1) == 0);
+ tcg_debug_assert(args[0] == args[1] + 1);
+ tcg_out_insn(s, RRFa, MGRK, args[1], args[2], args[3]);
break;
case INDEX_op_shl_i64:
@@ -2626,7 +2570,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_movcond_i64:
tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1],
- args[2], const_args[2], args[3], const_args[3]);
+ args[2], const_args[2], args[3], const_args[3], args[4]);
break;
OP_32_64(deposit):
@@ -2656,11 +2600,19 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tgen_clz(s, args[0], args[1], args[2], const_args[2]);
break;
+ case INDEX_op_ctpop_i32:
+ tgen_ctpop(s, TCG_TYPE_I32, args[0], args[1]);
+ break;
+ case INDEX_op_ctpop_i64:
+ tgen_ctpop(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+
case INDEX_op_mb:
/* The host memory model is quite strong, we simply need to
serialize the instruction stream. */
if (args[0] & TCG_MO_ST_LD) {
- tcg_out_insn(s, RR, BCR, HAVE_FACILITY(FAST_BCR_SER) ? 14 : 15, 0);
+ /* fast-bcr-serialization facility (45) is present */
+ tcg_out_insn(s, RR, BCR, 14, 0);
}
break;
@@ -3141,46 +3093,60 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_rotl_i64:
case INDEX_op_rotr_i32:
case INDEX_op_rotr_i64:
- case INDEX_op_clz_i64:
case INDEX_op_setcond_i32:
- case INDEX_op_setcond_i64:
return C_O1_I2(r, r, ri);
+ case INDEX_op_setcond_i64:
+ return C_O1_I2(r, r, rA);
+
+ case INDEX_op_clz_i64:
+ return C_O1_I2(r, r, rI);
case INDEX_op_sub_i32:
case INDEX_op_sub_i64:
case INDEX_op_and_i32:
- case INDEX_op_and_i64:
case INDEX_op_or_i32:
- case INDEX_op_or_i64:
case INDEX_op_xor_i32:
+ return C_O1_I2(r, r, ri);
+ case INDEX_op_and_i64:
+ return C_O1_I2(r, r, rNKR);
+ case INDEX_op_or_i64:
case INDEX_op_xor_i64:
- return (HAVE_FACILITY(DISTINCT_OPS)
- ? C_O1_I2(r, r, ri)
- : C_O1_I2(r, 0, ri));
+ return C_O1_I2(r, r, rK);
- case INDEX_op_mul_i32:
- /* If we have the general-instruction-extensions, then we have
- MULTIPLY SINGLE IMMEDIATE with a signed 32-bit, otherwise we
- have only MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit. */
- return (HAVE_FACILITY(GEN_INST_EXT)
- ? C_O1_I2(r, 0, ri)
- : C_O1_I2(r, 0, rI));
+ case INDEX_op_andc_i32:
+ case INDEX_op_orc_i32:
+ case INDEX_op_eqv_i32:
+ return C_O1_I2(r, r, ri);
+ case INDEX_op_andc_i64:
+ return C_O1_I2(r, r, rKR);
+ case INDEX_op_orc_i64:
+ case INDEX_op_eqv_i64:
+ return C_O1_I2(r, r, rNK);
+
+ case INDEX_op_nand_i32:
+ case INDEX_op_nand_i64:
+ case INDEX_op_nor_i32:
+ case INDEX_op_nor_i64:
+ return C_O1_I2(r, r, r);
+ case INDEX_op_mul_i32:
+ return (HAVE_FACILITY(MISC_INSN_EXT2)
+ ? C_O1_I2(r, r, ri)
+ : C_O1_I2(r, 0, ri));
case INDEX_op_mul_i64:
- return (HAVE_FACILITY(GEN_INST_EXT)
- ? C_O1_I2(r, 0, rJ)
- : C_O1_I2(r, 0, rI));
+ return (HAVE_FACILITY(MISC_INSN_EXT2)
+ ? C_O1_I2(r, r, rJ)
+ : C_O1_I2(r, 0, rJ));
case INDEX_op_shl_i32:
case INDEX_op_shr_i32:
case INDEX_op_sar_i32:
- return (HAVE_FACILITY(DISTINCT_OPS)
- ? C_O1_I2(r, r, ri)
- : C_O1_I2(r, 0, ri));
+ return C_O1_I2(r, r, ri);
case INDEX_op_brcond_i32:
- case INDEX_op_brcond_i64:
return C_O0_I2(r, ri);
+ case INDEX_op_brcond_i64:
+ return C_O0_I2(r, rA);
case INDEX_op_bswap16_i32:
case INDEX_op_bswap16_i64:
@@ -3189,6 +3155,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_bswap64_i64:
case INDEX_op_neg_i32:
case INDEX_op_neg_i64:
+ case INDEX_op_not_i32:
+ case INDEX_op_not_i64:
case INDEX_op_ext8s_i32:
case INDEX_op_ext8s_i64:
case INDEX_op_ext8u_i32:
@@ -3203,6 +3171,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_extu_i32_i64:
case INDEX_op_extract_i32:
case INDEX_op_extract_i64:
+ case INDEX_op_ctpop_i32:
+ case INDEX_op_ctpop_i64:
return C_O1_I1(r, r);
case INDEX_op_qemu_ld_i32:
@@ -3217,31 +3187,28 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
return C_O1_I2(r, rZ, r);
case INDEX_op_movcond_i32:
+ return C_O1_I4(r, r, ri, rI, r);
case INDEX_op_movcond_i64:
- return (HAVE_FACILITY(LOAD_ON_COND2)
- ? C_O1_I4(r, r, ri, rI, 0)
- : C_O1_I4(r, r, ri, r, 0));
+ return C_O1_I4(r, r, rA, rI, r);
case INDEX_op_div2_i32:
case INDEX_op_div2_i64:
case INDEX_op_divu2_i32:
case INDEX_op_divu2_i64:
- return C_O2_I3(b, a, 0, 1, r);
+ return C_O2_I3(o, m, 0, 1, r);
case INDEX_op_mulu2_i64:
- return C_O2_I2(b, a, 0, r);
+ return C_O2_I2(o, m, 0, r);
+ case INDEX_op_muls2_i64:
+ return C_O2_I2(o, m, r, r);
case INDEX_op_add2_i32:
case INDEX_op_sub2_i32:
- return (HAVE_FACILITY(EXT_IMM)
- ? C_O2_I4(r, r, 0, 1, ri, r)
- : C_O2_I4(r, r, 0, 1, r, r));
+ return C_O2_I4(r, r, 0, 1, ri, r);
case INDEX_op_add2_i64:
case INDEX_op_sub2_i64:
- return (HAVE_FACILITY(EXT_IMM)
- ? C_O2_I4(r, r, 0, 1, rA, r)
- : C_O2_I4(r, r, 0, 1, r, r));
+ return C_O2_I4(r, r, 0, 1, rA, r);
case INDEX_op_st_vec:
return C_O0_I2(v, r);
@@ -3307,6 +3274,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
static void query_s390_facilities(void)
{
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
+ const char *which;
/* Is STORE FACILITY LIST EXTENDED available? Honestly, I believe this
is present on all 64-bit systems, but let's check for it anyway. */
@@ -3328,6 +3296,38 @@ static void query_s390_facilities(void)
if (!(hwcap & HWCAP_S390_VXRS)) {
s390_facilities[2] = 0;
}
+
+ /*
+ * Minimum supported cpu revision is z196.
+ * Check for all required facilities.
+ * ZARCH_ACTIVE is done via preprocessor check for 64-bit.
+ */
+ if (!HAVE_FACILITY(LONG_DISP)) {
+ which = "long-displacement";
+ goto fail;
+ }
+ if (!HAVE_FACILITY(EXT_IMM)) {
+ which = "extended-immediate";
+ goto fail;
+ }
+ if (!HAVE_FACILITY(GEN_INST_EXT)) {
+ which = "general-instructions-extension";
+ goto fail;
+ }
+ /*
+ * Facility 45 is a big bin that contains: distinct-operands,
+ * fast-BCR-serialization, high-word, population-count,
+ * interlocked-access-1, and load/store-on-condition-1
+ */
+ if (!HAVE_FACILITY(45)) {
+ which = "45";
+ goto fail;
+ }
+ return;
+
+ fail:
+ error_report("%s: missing required facility %s", __func__, which);
+ exit(EXIT_FAILURE);
}
static void tcg_target_init(TCGContext *s)
@@ -3384,9 +3384,6 @@ static void tcg_target_init(TCGContext *s)
/* XXX many insns can't be used with R0, so we better avoid it for now */
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
- if (USE_REG_TB) {
- tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB);
- }
}
#define FRAME_SIZE ((int)(TCG_TARGET_CALL_STACK_OFFSET \
@@ -3407,16 +3404,12 @@ static void tcg_target_qemu_prologue(TCGContext *s)
#ifndef CONFIG_SOFTMMU
if (guest_base >= 0x80000) {
- tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base, true);
+ tcg_out_movi(s, TCG_TYPE_PTR, 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]);
- if (USE_REG_TB) {
- tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB,
- tcg_target_call_iarg_regs[1]);
- }
/* br %r3 (go to TB) */
tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, tcg_target_call_iarg_regs[1]);
diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h
index 22d70d4..68dcbc6 100644
--- a/tcg/s390x/tcg-target.h
+++ b/tcg/s390x/tcg-target.h
@@ -52,17 +52,19 @@ typedef enum TCGReg {
#define TCG_TARGET_NB_REGS 64
-/* A list of relevant facilities used by this translator. Some of these
- are required for proper operation, and these are checked at startup. */
+/* Facilities required for proper operation; checked at startup. */
#define FACILITY_ZARCH_ACTIVE 2
#define FACILITY_LONG_DISP 18
#define FACILITY_EXT_IMM 21
#define FACILITY_GEN_INST_EXT 34
-#define FACILITY_LOAD_ON_COND 45
-#define FACILITY_FAST_BCR_SER FACILITY_LOAD_ON_COND
-#define FACILITY_DISTINCT_OPS FACILITY_LOAD_ON_COND
+#define FACILITY_45 45
+
+/* Facilities that are checked at runtime. */
+
#define FACILITY_LOAD_ON_COND2 53
+#define FACILITY_MISC_INSN_EXT2 58
+#define FACILITY_MISC_INSN_EXT3 61
#define FACILITY_VECTOR 129
#define FACILITY_VECTOR_ENH1 135
@@ -80,18 +82,18 @@ extern uint64_t s390_facilities[3];
#define TCG_TARGET_HAS_ext16u_i32 1
#define TCG_TARGET_HAS_bswap16_i32 1
#define TCG_TARGET_HAS_bswap32_i32 1
-#define TCG_TARGET_HAS_not_i32 0
+#define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3)
#define TCG_TARGET_HAS_neg_i32 1
-#define TCG_TARGET_HAS_andc_i32 0
-#define TCG_TARGET_HAS_orc_i32 0
-#define TCG_TARGET_HAS_eqv_i32 0
-#define TCG_TARGET_HAS_nand_i32 0
-#define TCG_TARGET_HAS_nor_i32 0
+#define TCG_TARGET_HAS_andc_i32 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_orc_i32 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_eqv_i32 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_nand_i32 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_nor_i32 HAVE_FACILITY(MISC_INSN_EXT3)
#define TCG_TARGET_HAS_clz_i32 0
#define TCG_TARGET_HAS_ctz_i32 0
-#define TCG_TARGET_HAS_ctpop_i32 0
-#define TCG_TARGET_HAS_deposit_i32 HAVE_FACILITY(GEN_INST_EXT)
-#define TCG_TARGET_HAS_extract_i32 HAVE_FACILITY(GEN_INST_EXT)
+#define TCG_TARGET_HAS_ctpop_i32 1
+#define TCG_TARGET_HAS_deposit_i32 1
+#define TCG_TARGET_HAS_extract_i32 1
#define TCG_TARGET_HAS_sextract_i32 0
#define TCG_TARGET_HAS_extract2_i32 0
#define TCG_TARGET_HAS_movcond_i32 1
@@ -103,7 +105,7 @@ extern uint64_t s390_facilities[3];
#define TCG_TARGET_HAS_mulsh_i32 0
#define TCG_TARGET_HAS_extrl_i64_i32 0
#define TCG_TARGET_HAS_extrh_i64_i32 0
-#define TCG_TARGET_HAS_direct_jump HAVE_FACILITY(GEN_INST_EXT)
+#define TCG_TARGET_HAS_direct_jump 1
#define TCG_TARGET_HAS_qemu_st8_i32 0
#define TCG_TARGET_HAS_div2_i64 1
@@ -117,25 +119,25 @@ extern uint64_t s390_facilities[3];
#define TCG_TARGET_HAS_bswap16_i64 1
#define TCG_TARGET_HAS_bswap32_i64 1
#define TCG_TARGET_HAS_bswap64_i64 1
-#define TCG_TARGET_HAS_not_i64 0
+#define TCG_TARGET_HAS_not_i64 HAVE_FACILITY(MISC_INSN_EXT3)
#define TCG_TARGET_HAS_neg_i64 1
-#define TCG_TARGET_HAS_andc_i64 0
-#define TCG_TARGET_HAS_orc_i64 0
-#define TCG_TARGET_HAS_eqv_i64 0
-#define TCG_TARGET_HAS_nand_i64 0
-#define TCG_TARGET_HAS_nor_i64 0
-#define TCG_TARGET_HAS_clz_i64 HAVE_FACILITY(EXT_IMM)
+#define TCG_TARGET_HAS_andc_i64 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_orc_i64 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_eqv_i64 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_nand_i64 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_nor_i64 HAVE_FACILITY(MISC_INSN_EXT3)
+#define TCG_TARGET_HAS_clz_i64 1
#define TCG_TARGET_HAS_ctz_i64 0
-#define TCG_TARGET_HAS_ctpop_i64 0
-#define TCG_TARGET_HAS_deposit_i64 HAVE_FACILITY(GEN_INST_EXT)
-#define TCG_TARGET_HAS_extract_i64 HAVE_FACILITY(GEN_INST_EXT)
+#define TCG_TARGET_HAS_ctpop_i64 1
+#define TCG_TARGET_HAS_deposit_i64 1
+#define TCG_TARGET_HAS_extract_i64 1
#define TCG_TARGET_HAS_sextract_i64 0
#define TCG_TARGET_HAS_extract2_i64 0
#define TCG_TARGET_HAS_movcond_i64 1
#define TCG_TARGET_HAS_add2_i64 1
#define TCG_TARGET_HAS_sub2_i64 1
#define TCG_TARGET_HAS_mulu2_i64 1
-#define TCG_TARGET_HAS_muls2_i64 0
+#define TCG_TARGET_HAS_muls2_i64 HAVE_FACILITY(MISC_INSN_EXT2)
#define TCG_TARGET_HAS_muluh_i64 0
#define TCG_TARGET_HAS_mulsh_i64 0
diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build
index 406bc72..9dfe98b 100644
--- a/tests/qapi-schema/meson.build
+++ b/tests/qapi-schema/meson.build
@@ -277,10 +277,6 @@ if build_docs
command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'],
capture: true)
- # "full_path()" needed here to work around
- # https://github.com/mesonbuild/meson/issues/7585
- test('QAPI rST doc', diff, args: ['-u', qapi_doc_ref_nocr[0].full_path(),
- qapi_doc_out_nocr[0].full_path()],
- depends: [qapi_doc_ref_nocr, qapi_doc_out_nocr],
+ test('QAPI rST doc', diff, args: ['-u', qapi_doc_ref_nocr[0], qapi_doc_out_nocr[0]],
suite: ['qapi-schema', 'qapi-doc'])
endif
diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c
index 86caddc..2126b46 100644
--- a/tests/unit/test-cutils.c
+++ b/tests/unit/test-cutils.c
@@ -2315,6 +2315,14 @@ static void test_qemu_strtosz_invalid(void)
g_assert_cmpint(res, ==, 0xbaadf00d);
g_assert(endptr == str);
+ /* No suffixes */
+ str = "0x18M";
+ endptr = NULL;
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert_cmpint(res, ==, 0xbaadf00d);
+ g_assert(endptr == str);
+
/* No negative values */
str = "-0";
endptr = NULL;
diff --git a/util/cutils.c b/util/cutils.c
index def9c74..5887e74 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -197,10 +197,8 @@ static int64_t suffix_mul(char suffix, int64_t unit)
* fractional portion is truncated to byte
* - 0x7fEE - hexadecimal, unit determined by @default_suffix
*
- * The following cause a deprecation warning, and may be removed in the future
- * - 0xabc{kKmMgGtTpP} - hex with scaling suffix
- *
* The following are intentionally not supported
+ * - hex with scaling suffix, such as 0x20M
* - octal, such as 08
* - fractional hex, such as 0x1.8
* - floating point exponents, such as 1e3
@@ -222,7 +220,6 @@ static int do_strtosz(const char *nptr, const char **end,
int retval;
const char *endptr, *f;
unsigned char c;
- bool hex = false;
uint64_t val, valf = 0;
int64_t mul;
@@ -237,17 +234,16 @@ static int do_strtosz(const char *nptr, const char **end,
goto out;
}
if (val == 0 && (*endptr == 'x' || *endptr == 'X')) {
- /* Input looks like hex, reparse, and insist on no fraction. */
+ /* Input looks like hex; reparse, and insist on no fraction or suffix. */
retval = qemu_strtou64(nptr, &endptr, 16, &val);
if (retval) {
goto out;
}
- if (*endptr == '.') {
+ if (*endptr == '.' || suffix_mul(*endptr, unit) > 0) {
endptr = nptr;
retval = -EINVAL;
goto out;
}
- hex = true;
} else if (*endptr == '.') {
/*
* Input looks like a fraction. Make sure even 1.k works
@@ -272,10 +268,6 @@ static int do_strtosz(const char *nptr, const char **end,
c = *endptr;
mul = suffix_mul(c, unit);
if (mul > 0) {
- if (hex) {
- warn_report("Using a multiplier suffix on hex numbers "
- "is deprecated: %s", nptr);
- }
endptr++;
} else {
mul = suffix_mul(default_suffix, unit);
diff --git a/util/log.c b/util/log.c
index c2198ba..7837ff9 100644
--- a/util/log.c
+++ b/util/log.c
@@ -45,7 +45,6 @@ static __thread FILE *thread_file;
static __thread Notifier qemu_log_thread_cleanup_notifier;
int qemu_loglevel;
-static bool log_append;
static bool log_per_thread;
static GArray *debug_regions;
@@ -80,13 +79,15 @@ static int log_thread_id(void)
static void qemu_log_thread_cleanup(Notifier *n, void *unused)
{
- fclose(thread_file);
- thread_file = NULL;
+ if (thread_file != stderr) {
+ fclose(thread_file);
+ thread_file = NULL;
+ }
}
/* Lock/unlock output. */
-FILE *qemu_log_trylock(void)
+static FILE *qemu_log_trylock_with_err(Error **errp)
{
FILE *logfile;
@@ -97,6 +98,9 @@ FILE *qemu_log_trylock(void)
= g_strdup_printf(global_filename, log_thread_id());
logfile = fopen(filename, "w");
if (!logfile) {
+ error_setg_errno(errp, errno,
+ "Error opening logfile %s for thread %d",
+ filename, log_thread_id());
return NULL;
}
thread_file = logfile;
@@ -123,6 +127,11 @@ FILE *qemu_log_trylock(void)
return logfile;
}
+FILE *qemu_log_trylock(void)
+{
+ return qemu_log_trylock_with_err(NULL);
+}
+
void qemu_log_unlock(FILE *logfile)
{
if (logfile) {
@@ -266,40 +275,61 @@ static bool qemu_set_log_internal(const char *filename, bool changed_name,
#endif
qemu_loglevel = log_flags;
- /*
- * In all cases we only log if qemu_loglevel is set.
- * Also:
- * If per-thread, open the file for each thread in qemu_log_lock.
- * If not daemonized we will always log either to stderr
- * or to a file (if there is a filename).
- * If we are daemonized, we will only log if there is a filename.
- */
daemonized = is_daemonized();
- need_to_open_file = log_flags && !per_thread && (!daemonized || filename);
+ need_to_open_file = false;
+ if (!daemonized) {
+ /*
+ * If not daemonized we only log if qemu_loglevel is set, either to
+ * stderr or to a file (if there is a filename).
+ * If per-thread, open the file for each thread in qemu_log_trylock().
+ */
+ need_to_open_file = qemu_loglevel && !log_per_thread;
+ } else {
+ /*
+ * If we are daemonized, we will only log if there is a filename.
+ */
+ need_to_open_file = filename != NULL;
+ }
- if (logfile && (!need_to_open_file || changed_name)) {
- qatomic_rcu_set(&global_file, NULL);
- if (logfile != stderr) {
+ if (logfile) {
+ fflush(logfile);
+ if (changed_name && logfile != stderr) {
RCUCloseFILE *r = g_new0(RCUCloseFILE, 1);
r->fd = logfile;
+ qatomic_rcu_set(&global_file, NULL);
call_rcu(r, rcu_close_file, rcu);
+ logfile = NULL;
}
- logfile = NULL;
+ }
+
+ if (log_per_thread && daemonized) {
+ logfile = thread_file;
}
if (!logfile && need_to_open_file) {
if (filename) {
- logfile = fopen(filename, log_append ? "a" : "w");
- if (!logfile) {
- error_setg_errno(errp, errno, "Error opening logfile %s",
- filename);
- return false;
+ if (log_per_thread) {
+ logfile = qemu_log_trylock_with_err(errp);
+ if (!logfile) {
+ return false;
+ }
+ qemu_log_unlock(logfile);
+ } else {
+ logfile = fopen(filename, "w");
+ if (!logfile) {
+ error_setg_errno(errp, errno, "Error opening logfile %s",
+ filename);
+ return false;
+ }
}
/* In case we are a daemon redirect stderr to logfile */
if (daemonized) {
dup2(fileno(logfile), STDERR_FILENO);
fclose(logfile);
- /* This will skip closing logfile in rcu_close_file. */
+ /*
+ * This will skip closing logfile in rcu_close_file()
+ * or qemu_log_thread_cleanup().
+ */
logfile = stderr;
}
} else {
@@ -308,9 +338,11 @@ static bool qemu_set_log_internal(const char *filename, bool changed_name,
logfile = stderr;
}
- log_append = 1;
-
- qatomic_rcu_set(&global_file, logfile);
+ if (log_per_thread && daemonized) {
+ thread_file = logfile;
+ } else {
+ qatomic_rcu_set(&global_file, logfile);
+ }
}
return true;
}