diff options
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; @@ -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); @@ -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; } |