diff options
430 files changed, 22687 insertions, 5541 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..79d02cf740 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,73 @@ +before_script: + - apt-get update -qq + - apt-get install -y -qq flex bison libglib2.0-dev libpixman-1-dev genisoimage + +build-system1: + script: + - apt-get install -y -qq libgtk-3-dev libvte-dev nettle-dev libcacard-dev + libusb-dev libvde-dev libspice-protocol-dev libgl1-mesa-dev + - ./configure --enable-werror --target-list="aarch64-softmmu alpha-softmmu + cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu + mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu" + - make -j2 + - make -j2 check + +build-system2: + script: + - apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev + libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev + - ./configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu + microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu + sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu" + - make -j2 + - make -j2 check + +build-disabled: + script: + - ./configure --enable-werror --disable-rdma --disable-slirp --disable-curl + --disable-capstone --disable-live-block-migration --disable-glusterfs + --disable-replication --disable-coroutine-pool --disable-smartcard + --disable-guest-agent --disable-curses --disable-libxml2 --disable-tpm + --disable-qom-cast-debug --disable-spice --disable-vhost-vsock + --disable-vhost-net --disable-vhost-crypto --disable-vhost-user + --target-list="i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user" + - make -j2 + - make -j2 check-qtest SPEED=slow + +build-tcg-disabled: + script: + - apt-get install -y -qq clang libgtk-3-dev libbluetooth-dev libusb-dev + - ./configure --cc=clang --enable-werror --disable-tcg --audio-drv-list="" + - make -j2 + - make check-unit + - make check-qapi-schema + - cd tests/qemu-iotests/ + - ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048 + 052 063 077 086 101 104 106 113 147 148 150 151 152 157 159 160 + 163 170 171 183 184 192 194 197 205 208 215 221 222 226 227 236 + - ./check -qcow2 001 002 003 004 005 007 008 009 010 011 012 013 017 018 019 + 020 021 022 024 025 027 028 029 031 032 033 034 035 036 037 038 + 039 040 042 043 046 047 048 049 050 051 052 053 054 056 057 058 + 060 061 062 063 065 066 067 068 069 071 072 073 074 079 080 082 + 085 086 089 090 091 095 096 097 098 099 102 103 104 105 107 108 + 110 111 114 117 120 122 124 126 127 129 130 132 133 134 137 138 + 139 140 141 142 143 144 145 147 150 151 152 154 155 156 157 158 + 161 165 170 172 174 176 177 179 184 186 187 190 192 194 195 196 + 197 200 202 203 205 208 209 214 215 216 217 218 222 226 227 229 234 + +build-user: + script: + - ./configure --enable-werror --disable-system --disable-guest-agent + --disable-capstone --disable-slirp --disable-fdt + - make -j2 + - make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user + +build-clang: + script: + - apt-get install -y -qq clang libsdl2-dev + xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev + - ./configure --cc=clang --cxx=clang++ --enable-werror + --target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu + ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user" + - make -j2 + - make -j2 check diff --git a/.gitmodules b/.gitmodules index 6b91176098..ceafb0ee29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,3 +49,6 @@ [submodule "tests/fp/berkeley-softfloat-3"] path = tests/fp/berkeley-softfloat-3 url = https://github.com/cota/berkeley-softfloat-3 +[submodule "roms/edk2"] + path = roms/edk2 + url = https://github.com/tianocore/edk2.git diff --git a/.travis.yml b/.travis.yml index baa06b976a..cca57f4314 100644 --- a/.travis.yml +++ b/.travis.yml @@ -86,11 +86,16 @@ matrix: - env: - - CONFIG="--enable-debug --enable-debug-tcg" + - CONFIG="--enable-debug --enable-debug-tcg --disable-user" + # TCG debug can be run just on it's own and is mostly agnostic to user/softmmu distinctions - env: - - CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-uuid --disable-libusb --disable-user" + - CONFIG="--enable-debug-tcg --disable-system" + + + - env: + - CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-libusb --disable-user --disable-replication" - env: @@ -174,13 +179,6 @@ matrix: compiler: clang - - env: - - CONFIG="--target-list=i386-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,x86_64-softmmu" - os: osx - osx_image: xcode10 - compiler: clang - - # Python builds - env: - CONFIG="--target-list=x86_64-softmmu" diff --git a/MAINTAINERS b/MAINTAINERS index 6ae55ff732..5040d9dfb1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -425,15 +425,20 @@ Hosts: ------ LINUX -L: qemu-devel@nongnu.org +M: Michael S. Tsirkin <mst@redhat.com> +M: Cornelia Huck <cohuck@redhat.com> +M: Paolo Bonzini <pbonzini@redhat.com> S: Maintained -F: linux-* F: linux-headers/ +F: scripts/update-linux-headers.sh POSIX -L: qemu-devel@nongnu.org +M: Paolo Bonzini <pbonzini@redhat.com> S: Maintained -F: *posix* +F: os-posix.c +F: include/sysemu/os-posix.h +F: util/*posix*.c +F: include/qemu/*posix*.h NETBSD L: qemu-devel@nongnu.org @@ -633,6 +638,8 @@ F: hw/misc/iotkit-sysinfo.c F: include/hw/misc/iotkit-sysinfo.h F: hw/misc/armsse-cpuid.c F: include/hw/misc/armsse-cpuid.h +F: hw/misc/armsse-mhu.c +F: include/hw/misc/armsse-mhu.h Musca M: Peter Maydell <peter.maydell@linaro.org> @@ -851,6 +858,15 @@ S: Maintained F: hw/cris/axis_dev88.c F: hw/*/etraxfs_*.c +HP-PARISC Machines +------------------ +Dino +M: Richard Henderson <rth@twiddle.net> +R: Helge Deller <deller@gmx.de> +S: Odd Fixes +F: hw/hppa/ +F: pc-bios/hppa-firmware.img + LM32 Machines ------------- EVR32 and uclinux BSP @@ -1089,20 +1105,27 @@ M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> S: Maintained F: hw/sparc/sun4m.c F: hw/sparc/sun4m_iommu.c +F: hw/display/cg3.c +F: hw/display/tcx.c F: hw/dma/sparc32_dma.c F: hw/misc/eccmemctl.c -F: hw/misc/slavio_misc.c +F: hw/*/slavio_*.c +F: include/hw/nvram/sun_nvram.h F: include/hw/sparc/sparc32_dma.h -F: pc-bios/openbios-sparc32 F: include/hw/sparc/sun4m_iommu.h +F: pc-bios/openbios-sparc32 Sun4u M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> S: Maintained F: hw/sparc64/sun4u.c -F: pc-bios/openbios-sparc64 +F: hw/sparc64/sun4u_iommu.c +F: include/hw/sparc/sun4u_iommu.h F: hw/pci-host/sabre.c F: include/hw/pci-host/sabre.h +F: hw/pci-bridge/simba.c +F: include/hw/pci-bridge/simba.h +F: pc-bios/openbios-sparc64 Sun4v M: Artyom Tarasenko <atar4qemu@gmail.com> @@ -1181,6 +1204,10 @@ F: hw/acpi/ich9.c F: include/hw/acpi/ich9.h F: include/hw/acpi/piix4.h F: hw/misc/sga.c +F: hw/isa/apm.c +F: include/hw/isa/apm.h +F: tests/test-x86-cpuid.c +F: tests/test-x86-cpuid-compat.c PC Chipset M: Michael S. Tsirkin <mst@redhat.com> @@ -1698,7 +1725,7 @@ F: include/scsi/* F: scsi/* Block Jobs -M: Jeff Cody <jcody@redhat.com> +M: John Snow <jsnow@redhat.com> L: qemu-block@nongnu.org S: Supported F: blockjob.c @@ -1711,7 +1738,7 @@ F: block/commit.c F: block/stream.c F: block/mirror.c F: qapi/job.json -T: git https://github.com/codyprime/qemu-kvm-jtc.git block +T: git https://github.com/jnsnow/qemu.git jobs Block QAPI, monitor, command line M: Markus Armbruster <armbru@redhat.com> @@ -1795,8 +1822,7 @@ F: util/error.c F: util/qemu-error.c GDB stub -L: qemu-devel@nongnu.org -S: Odd Fixes +S: Orphan F: gdbstub* F: gdb-xml/ @@ -1932,10 +1958,14 @@ F: include/qapi/qmp/ X: include/qapi/qmp/dispatch.h F: scripts/coccinelle/qobject.cocci F: tests/check-qdict.c -F: tests/check-qnum.c F: tests/check-qjson.c F: tests/check-qlist.c +F: tests/check-qlit.c +F: tests/check-qnull.c +F: tests/check-qnum.c +F: tests/check-qobject.c F: tests/check-qstring.c +F: qdict-test-data.txt T: git https://repo.or.cz/qemu/armbru.git qapi-next QEMU Guest Agent @@ -2057,6 +2087,8 @@ F: crypto/ F: include/crypto/ F: tests/test-crypto-* F: tests/benchmark-crypto-* +F: tests/crypto-tls-* +F: tests/pkix_asn1_tab.c F: qemu.sasl Coroutines @@ -2079,6 +2111,14 @@ F: io/ F: include/io/ F: tests/test-io-* +User authorization +M: Daniel P. Berrange <berrange@redhat.com> +S: Maintained +F: authz/ +F: qapi/authz.json +F: include/authz/ +F: tests/test-authz-* + Sockets M: Daniel P. Berrange <berrange@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com> @@ -2087,6 +2127,13 @@ F: include/qemu/sockets.h F: util/qemu-sockets.c F: qapi/sockets.json +File monitor +M: Daniel P. Berrange <berrange@redhat.com> +S: Odd fixes +F: util/filemonitor*.c +F: include/qemu/filemonitor.h +F: tests/test-util-filemonitor.c + Throttling infrastructure M: Alberto Garcia <berto@igalia.com> S: Supported @@ -2145,6 +2192,18 @@ M: Viktor Prutyanov <viktor.prutyanov@phystech.edu> S: Maintained F: contrib/elf2dmp/ +I2C and SMBus +M: Corey Minyard <cminyard@mvista.com> +S: Maintained +F: hw/i2c/core.c +F: hw/i2c/smbus_slave.c +F: hw/i2c/smbus_master.c +F: hw/i2c/smbus_eeprom.c +F: include/hw/i2c/i2c.h +F: include/hw/i2c/smbus_master.h +F: include/hw/i2c/smbus_slave.h +F: include/hw/i2c/smbus_eeprom.h + Usermode Emulation ------------------ Overall @@ -2190,7 +2249,7 @@ F: tcg/arm/ F: disas/arm.c i386 target -L: qemu-devel@nongnu.org +M: Richard Henderson <rth@twiddle.net> S: Maintained F: tcg/i386/ F: disas/i386.c @@ -2209,7 +2268,6 @@ F: tcg/ppc/ F: disas/ppc.c RISC-V -M: Michael Clark <mjc@sifive.com> M: Palmer Dabbelt <palmer@sifive.com> M: Alistair Francis <Alistair.Francis@wdc.com> L: qemu-riscv@nongnu.org @@ -2246,26 +2304,22 @@ F: block/vmdk.c RBD M: Josh Durgin <jdurgin@redhat.com> -M: Jeff Cody <jcody@redhat.com> L: qemu-block@nongnu.org S: Supported F: block/rbd.c -T: git https://github.com/codyprime/qemu-kvm-jtc.git block Sheepdog M: Liu Yuan <namei.unix@gmail.com> -M: Jeff Cody <jcody@redhat.com> L: qemu-block@nongnu.org -S: Supported +L: sheepdog@lists.wpkg.org +S: Odd Fixes F: block/sheepdog.c -T: git https://github.com/codyprime/qemu-kvm-jtc.git block VHDX -M: Jeff Cody <jcody@redhat.com> +M: Jeff Cody <codyprime@gmail.com> L: qemu-block@nongnu.org S: Supported F: block/vhdx* -T: git https://github.com/codyprime/qemu-kvm-jtc.git block VDI M: Stefan Weil <sw@weilnetz.de> @@ -2295,34 +2349,26 @@ F: docs/interop/nbd.txt T: git https://repo.or.cz/qemu/ericb.git nbd NFS -M: Jeff Cody <jcody@redhat.com> M: Peter Lieven <pl@kamp.de> L: qemu-block@nongnu.org S: Maintained F: block/nfs.c -T: git https://github.com/codyprime/qemu-kvm-jtc.git block SSH M: Richard W.M. Jones <rjones@redhat.com> -M: Jeff Cody <jcody@redhat.com> L: qemu-block@nongnu.org S: Supported F: block/ssh.c -T: git https://github.com/codyprime/qemu-kvm-jtc.git block CURL -M: Jeff Cody <jcody@redhat.com> L: qemu-block@nongnu.org S: Supported F: block/curl.c -T: git https://github.com/codyprime/qemu-kvm-jtc.git block GLUSTER -M: Jeff Cody <jcody@redhat.com> L: qemu-block@nongnu.org S: Supported F: block/gluster.c -T: git https://github.com/codyprime/qemu-kvm-jtc.git block Null Block Driver M: Fam Zheng <fam@euphon.net> @@ -2486,6 +2532,11 @@ S: Maintained F: .cirrus.yml W: https://cirrus-ci.com/github/qemu/qemu +GitLab Continuous Integration +M: Thomas Huth <thuth@redhat.com> +S: Maintained +F: .gitlab-ci.yml + Guest Test Compilation Support M: Alex Bennée <alex.bennee@linaro.org> R: Philippe Mathieu-Daudé <f4bug@amsat.org> @@ -359,6 +359,7 @@ endif dummy := $(call unnest-vars,, \ stub-obj-y \ + authz-obj-y \ chardev-obj-y \ util-obj-y \ qga-obj-y \ @@ -423,6 +424,7 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES)) +$(SOFTMMU_SUBDIR_RULES): $(authz-obj-y) $(SOFTMMU_SUBDIR_RULES): $(block-obj-y) $(SOFTMMU_SUBDIR_RULES): $(crypto-obj-y) $(SOFTMMU_SUBDIR_RULES): $(io-obj-y) @@ -485,9 +487,9 @@ COMMON_LDADDS = libqemuutil.a qemu-img.o: qemu-img-cmds.h -qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) -qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) -qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) +qemu-img$(EXESUF): qemu-img.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) +qemu-nbd$(EXESUF): qemu-nbd.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) +qemu-io$(EXESUF): qemu-io.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS) @@ -498,7 +500,7 @@ qemu-edid$(EXESUF): qemu-edid.o hw/display/edid-generate.o $(COMMON_LDADDS) fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS) fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap -scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) +scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(authz-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) ifdef CONFIG_MPATH scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist endif @@ -607,7 +609,11 @@ clean: rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f qemu-options.def rm -f *.msi - find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} + + find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f \ + ! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-aarch64.a \ + ! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-arm.a \ + ! -path ./roms/edk2/BaseTools/Source/Python/UPT/Dll/sqlite3.dll \ + -exec rm {} + rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -f fsdev/*.pod scsi/*.pod rm -f qemu-img-cmds.h diff --git a/Makefile.objs b/Makefile.objs index 5fb022d7ad..6e91ee5674 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -1,12 +1,17 @@ ####################################################################### # Common libraries for tools and emulators -stub-obj-y = stubs/ crypto/ +stub-obj-y = stubs/ util/ crypto/ util-obj-y = util/ qobject/ qapi/ chardev-obj-y = chardev/ slirp-obj-$(CONFIG_SLIRP) = slirp/ ####################################################################### +# authz-obj-y is code used by both qemu system emulation and qemu-img + +authz-obj-y = authz/ + +####################################################################### # block-obj-y is code used by both qemu system emulation and qemu-img block-obj-y += nbd/ @@ -125,6 +130,7 @@ trace-events-subdirs = trace-events-subdirs += accel/kvm trace-events-subdirs += accel/tcg trace-events-subdirs += audio +trace-events-subdirs += authz trace-events-subdirs += block trace-events-subdirs += chardev trace-events-subdirs += crypto diff --git a/Makefile.target b/Makefile.target index d6ce549388..3b79e7074c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -179,6 +179,7 @@ include $(SRC_PATH)/Makefile.objs dummy := $(call unnest-vars,,target-obj-y) target-obj-y-save := $(target-obj-y) dummy := $(call unnest-vars,.., \ + authz-obj-y \ block-obj-y \ block-obj-m \ chardev-obj-y \ @@ -193,6 +194,7 @@ target-obj-y := $(target-obj-y-save) all-obj-y += $(common-obj-y) all-obj-y += $(target-obj-y) all-obj-y += $(qom-obj-y) +all-obj-$(CONFIG_SOFTMMU) += $(authz-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y) all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y) diff --git a/audio/audio.c b/audio/audio.c index d163ffbc88..909c817103 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -454,9 +454,7 @@ static void audio_print_options (const char *prefix, static void audio_process_options (const char *prefix, struct audio_option *opt) { - char *optname; - const char qemu_prefix[] = "QEMU_"; - size_t preflen, optlen; + gchar *prefix_upper; if (audio_bug(__func__, !prefix)) { dolog ("prefix = NULL\n"); @@ -468,10 +466,10 @@ static void audio_process_options (const char *prefix, return; } - preflen = strlen (prefix); + prefix_upper = g_utf8_strup(prefix, -1); for (; opt->name; opt++) { - size_t len, i; + char *optname; int def; if (!opt->valp) { @@ -480,21 +478,7 @@ static void audio_process_options (const char *prefix, continue; } - len = strlen (opt->name); - /* len of opt->name + len of prefix + size of qemu_prefix - * (includes trailing zero) + zero + underscore (on behalf of - * sizeof) */ - optlen = len + preflen + sizeof (qemu_prefix) + 1; - optname = g_malloc (optlen); - - pstrcpy (optname, optlen, qemu_prefix); - - /* copy while upper-casing, including trailing zero */ - for (i = 0; i <= preflen; ++i) { - optname[i + sizeof (qemu_prefix) - 1] = qemu_toupper(prefix[i]); - } - pstrcat (optname, optlen, "_"); - pstrcat (optname, optlen, opt->name); + optname = g_strdup_printf("QEMU_%s_%s", prefix_upper, opt->name); def = 1; switch (opt->tag) { @@ -532,6 +516,7 @@ static void audio_process_options (const char *prefix, *opt->overriddenp = !def; g_free (optname); } + g_free(prefix_upper); } static void audio_print_settings (struct audsettings *as) @@ -826,12 +811,7 @@ static int audio_attach_capture (HWVoiceOut *hw) SWVoiceOut *sw; HWVoiceOut *hw_cap = &cap->hw; - sc = audio_calloc(__func__, 1, sizeof(*sc)); - if (!sc) { - dolog ("Could not allocate soft capture voice (%zu bytes)\n", - sizeof (*sc)); - return -1; - } + sc = g_malloc0(sizeof(*sc)); sc->cap = cap; sw = &sc->sw; @@ -1975,15 +1955,10 @@ CaptureVoiceOut *AUD_add_capture ( if (audio_validate_settings (as)) { dolog ("Invalid settings were passed when trying to add capture\n"); audio_print_settings (as); - goto err0; + return NULL; } - cb = audio_calloc(__func__, 1, sizeof(*cb)); - if (!cb) { - dolog ("Could not allocate capture callback information, size %zu\n", - sizeof (*cb)); - goto err0; - } + cb = g_malloc0(sizeof(*cb)); cb->ops = *ops; cb->opaque = cb_opaque; @@ -1996,12 +1971,7 @@ CaptureVoiceOut *AUD_add_capture ( HWVoiceOut *hw; CaptureVoiceOut *cap; - cap = audio_calloc(__func__, 1, sizeof(*cap)); - if (!cap) { - dolog ("Could not allocate capture voice, size %zu\n", - sizeof (*cap)); - goto err1; - } + cap = g_malloc0(sizeof(*cap)); hw = &cap->hw; QLIST_INIT (&hw->sw_head); @@ -2009,23 +1979,11 @@ CaptureVoiceOut *AUD_add_capture ( /* XXX find a more elegant way */ hw->samples = 4096 * 4; - hw->mix_buf = audio_calloc(__func__, hw->samples, - sizeof(struct st_sample)); - if (!hw->mix_buf) { - dolog ("Could not allocate capture mix buffer (%d samples)\n", - hw->samples); - goto err2; - } + hw->mix_buf = g_new0(struct st_sample, hw->samples); audio_pcm_init_info (&hw->info, as); - cap->buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); - if (!cap->buf) { - dolog ("Could not allocate capture buffer " - "(%d samples, each %d bytes)\n", - hw->samples, 1 << hw->info.shift); - goto err3; - } + cap->buf = g_malloc0_n(hw->samples, 1 << hw->info.shift); hw->clip = mixeng_clip [hw->info.nchannels == 2] @@ -2040,15 +1998,6 @@ CaptureVoiceOut *AUD_add_capture ( audio_attach_capture (hw); } return cap; - - err3: - g_free (cap->hw.mix_buf); - err2: - g_free (cap); - err1: - g_free (cb); - err0: - return NULL; } } diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 9db5ac92bc..f7ee70b153 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -38,14 +38,9 @@ #define AUDIO_CAP "sdl" #include "audio_int.h" -#define USE_SEMAPHORE (SDL_MAJOR_VERSION < 2) - typedef struct SDLVoiceOut { HWVoiceOut hw; int live; -#if USE_SEMAPHORE - int rpos; -#endif int decr; } SDLVoiceOut; @@ -57,10 +52,6 @@ static struct { static struct SDLAudioState { int exit; -#if USE_SEMAPHORE - SDL_mutex *mutex; - SDL_sem *sem; -#endif int initialized; bool driver_created; } glob_sdl; @@ -77,66 +68,6 @@ static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...) AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ()); } -static int sdl_lock (SDLAudioState *s, const char *forfn) -{ -#if USE_SEMAPHORE - if (SDL_LockMutex (s->mutex)) { - sdl_logerr ("SDL_LockMutex for %s failed\n", forfn); - return -1; - } -#else - SDL_LockAudio(); -#endif - - return 0; -} - -static int sdl_unlock (SDLAudioState *s, const char *forfn) -{ -#if USE_SEMAPHORE - if (SDL_UnlockMutex (s->mutex)) { - sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn); - return -1; - } -#else - SDL_UnlockAudio(); -#endif - - return 0; -} - -static int sdl_post (SDLAudioState *s, const char *forfn) -{ -#if USE_SEMAPHORE - if (SDL_SemPost (s->sem)) { - sdl_logerr ("SDL_SemPost for %s failed\n", forfn); - return -1; - } -#endif - - return 0; -} - -#if USE_SEMAPHORE -static int sdl_wait (SDLAudioState *s, const char *forfn) -{ - if (SDL_SemWait (s->sem)) { - sdl_logerr ("SDL_SemWait for %s failed\n", forfn); - return -1; - } - return 0; -} -#endif - -static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn) -{ - if (sdl_unlock (s, forfn)) { - return -1; - } - - return sdl_post (s, forfn); -} - static int aud_to_sdlfmt (audfmt_e fmt) { switch (fmt) { @@ -243,9 +174,9 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) static void sdl_close (SDLAudioState *s) { if (s->initialized) { - sdl_lock (s, "sdl_close"); + SDL_LockAudio(); s->exit = 1; - sdl_unlock_and_post (s, "sdl_close"); + SDL_UnlockAudio(); SDL_PauseAudio (1); SDL_CloseAudio (); s->initialized = 0; @@ -258,76 +189,36 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len) SDLAudioState *s = &glob_sdl; HWVoiceOut *hw = &sdl->hw; int samples = len >> hw->info.shift; + int to_mix, decr; - if (s->exit) { + if (s->exit || !sdl->live) { return; } - while (samples) { - int to_mix, decr; - - /* dolog ("in callback samples=%d\n", samples); */ -#if USE_SEMAPHORE - sdl_wait (s, "sdl_callback"); - if (s->exit) { - return; - } - - if (sdl_lock (s, "sdl_callback")) { - return; - } - - if (audio_bug(__func__, sdl->live < 0 || sdl->live > hw->samples)) { - dolog ("sdl->live=%d hw->samples=%d\n", - sdl->live, hw->samples); - return; - } - - if (!sdl->live) { - goto again; - } -#else - if (s->exit || !sdl->live) { - break; - } -#endif + /* dolog ("in callback samples=%d live=%d\n", samples, sdl->live); */ - /* dolog ("in callback live=%d\n", live); */ - to_mix = audio_MIN (samples, sdl->live); - decr = to_mix; - while (to_mix) { - int chunk = audio_MIN (to_mix, hw->samples - hw->rpos); - struct st_sample *src = hw->mix_buf + hw->rpos; - - /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ - hw->clip (buf, src, chunk); -#if USE_SEMAPHORE - sdl->rpos = (sdl->rpos + chunk) % hw->samples; -#else - hw->rpos = (hw->rpos + chunk) % hw->samples; -#endif - to_mix -= chunk; - buf += chunk << hw->info.shift; - } - samples -= decr; - sdl->live -= decr; - sdl->decr += decr; - -#if USE_SEMAPHORE - again: - if (sdl_unlock (s, "sdl_callback")) { - return; - } -#endif + to_mix = audio_MIN(samples, sdl->live); + decr = to_mix; + while (to_mix) { + int chunk = audio_MIN(to_mix, hw->samples - hw->rpos); + struct st_sample *src = hw->mix_buf + hw->rpos; + + /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ + hw->clip(buf, src, chunk); + hw->rpos = (hw->rpos + chunk) % hw->samples; + to_mix -= chunk; + buf += chunk << hw->info.shift; } + samples -= decr; + sdl->live -= decr; + sdl->decr += decr; + /* dolog ("done len=%d\n", len); */ -#if (SDL_MAJOR_VERSION >= 2) /* SDL2 does not clear the remaining buffer for us, so do it on our own */ if (samples) { memset(buf, 0, samples << hw->info.shift); } -#endif } static int sdl_write_out (SWVoiceOut *sw, void *buf, int len) @@ -339,11 +230,8 @@ static int sdl_run_out (HWVoiceOut *hw, int live) { int decr; SDLVoiceOut *sdl = (SDLVoiceOut *) hw; - SDLAudioState *s = &glob_sdl; - if (sdl_lock (s, "sdl_run_out")) { - return 0; - } + SDL_LockAudio(); if (sdl->decr > live) { ldebug ("sdl->decr %d live %d sdl->live %d\n", @@ -355,19 +243,10 @@ static int sdl_run_out (HWVoiceOut *hw, int live) decr = audio_MIN (sdl->decr, live); sdl->decr -= decr; -#if USE_SEMAPHORE - sdl->live = live - decr; - hw->rpos = sdl->rpos; -#else sdl->live = live; -#endif - if (sdl->live > 0) { - sdl_unlock_and_post (s, "sdl_run_out"); - } - else { - sdl_unlock (s, "sdl_run_out"); - } + SDL_UnlockAudio(); + return decr; } @@ -449,23 +328,6 @@ static void *sdl_audio_init (void) return NULL; } -#if USE_SEMAPHORE - s->mutex = SDL_CreateMutex (); - if (!s->mutex) { - sdl_logerr ("Failed to create SDL mutex\n"); - SDL_QuitSubSystem (SDL_INIT_AUDIO); - return NULL; - } - - s->sem = SDL_CreateSemaphore (0); - if (!s->sem) { - sdl_logerr ("Failed to create SDL semaphore\n"); - SDL_DestroyMutex (s->mutex); - SDL_QuitSubSystem (SDL_INIT_AUDIO); - return NULL; - } -#endif - s->driver_created = true; return s; } @@ -474,10 +336,6 @@ static void sdl_audio_fini (void *opaque) { SDLAudioState *s = opaque; sdl_close (s); -#if USE_SEMAPHORE - SDL_DestroySemaphore (s->sem); - SDL_DestroyMutex (s->mutex); -#endif SDL_QuitSubSystem (SDL_INIT_AUDIO); s->driver_created = false; } diff --git a/authz/Makefile.objs b/authz/Makefile.objs new file mode 100644 index 0000000000..ed7b273596 --- /dev/null +++ b/authz/Makefile.objs @@ -0,0 +1,7 @@ +authz-obj-y += base.o +authz-obj-y += simple.o +authz-obj-y += list.o +authz-obj-y += listfile.o +authz-obj-$(CONFIG_AUTH_PAM) += pamacct.o + +pamacct.o-libs = -lpam diff --git a/authz/base.c b/authz/base.c new file mode 100644 index 0000000000..110dfa4195 --- /dev/null +++ b/authz/base.c @@ -0,0 +1,82 @@ +/* + * QEMU authorization framework base class + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "authz/base.h" +#include "authz/trace.h" + +bool qauthz_is_allowed(QAuthZ *authz, + const char *identity, + Error **errp) +{ + QAuthZClass *cls = QAUTHZ_GET_CLASS(authz); + bool allowed; + + allowed = cls->is_allowed(authz, identity, errp); + trace_qauthz_is_allowed(authz, identity, allowed); + + return allowed; +} + + +bool qauthz_is_allowed_by_id(const char *authzid, + const char *identity, + Error **errp) +{ + QAuthZ *authz; + Object *obj; + Object *container; + + container = object_get_objects_root(); + obj = object_resolve_path_component(container, + authzid); + if (!obj) { + error_setg(errp, "Cannot find QAuthZ object ID %s", + authzid); + return false; + } + + if (!object_dynamic_cast(obj, TYPE_QAUTHZ)) { + error_setg(errp, "Object '%s' is not a QAuthZ subclass", + authzid); + return false; + } + + authz = QAUTHZ(obj); + + return qauthz_is_allowed(authz, identity, errp); +} + + +static const TypeInfo authz_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QAUTHZ, + .instance_size = sizeof(QAuthZ), + .class_size = sizeof(QAuthZClass), + .abstract = true, +}; + +static void qauthz_register_types(void) +{ + type_register_static(&authz_info); +} + +type_init(qauthz_register_types) + diff --git a/authz/list.c b/authz/list.c new file mode 100644 index 0000000000..dc6b0fec13 --- /dev/null +++ b/authz/list.c @@ -0,0 +1,271 @@ +/* + * QEMU access control list authorization driver + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "authz/list.h" +#include "authz/trace.h" +#include "qom/object_interfaces.h" +#include "qapi/qapi-visit-authz.h" + +static bool qauthz_list_is_allowed(QAuthZ *authz, + const char *identity, + Error **errp) +{ + QAuthZList *lauthz = QAUTHZ_LIST(authz); + QAuthZListRuleList *rules = lauthz->rules; + + while (rules) { + QAuthZListRule *rule = rules->value; + QAuthZListFormat format = rule->has_format ? rule->format : + QAUTHZ_LIST_FORMAT_EXACT; + + trace_qauthz_list_check_rule(authz, rule->match, identity, + format, rule->policy); + switch (format) { + case QAUTHZ_LIST_FORMAT_EXACT: + if (g_str_equal(rule->match, identity)) { + return rule->policy == QAUTHZ_LIST_POLICY_ALLOW; + } + break; + case QAUTHZ_LIST_FORMAT_GLOB: + if (g_pattern_match_simple(rule->match, identity)) { + return rule->policy == QAUTHZ_LIST_POLICY_ALLOW; + } + break; + default: + g_warn_if_reached(); + return false; + } + rules = rules->next; + } + + trace_qauthz_list_default_policy(authz, identity, lauthz->policy); + return lauthz->policy == QAUTHZ_LIST_POLICY_ALLOW; +} + + +static void +qauthz_list_prop_set_policy(Object *obj, + int value, + Error **errp G_GNUC_UNUSED) +{ + QAuthZList *lauthz = QAUTHZ_LIST(obj); + + lauthz->policy = value; +} + + +static int +qauthz_list_prop_get_policy(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QAuthZList *lauthz = QAUTHZ_LIST(obj); + + return lauthz->policy; +} + + +static void +qauthz_list_prop_get_rules(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QAuthZList *lauthz = QAUTHZ_LIST(obj); + + visit_type_QAuthZListRuleList(v, name, &lauthz->rules, errp); +} + +static void +qauthz_list_prop_set_rules(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QAuthZList *lauthz = QAUTHZ_LIST(obj); + QAuthZListRuleList *oldrules; + + oldrules = lauthz->rules; + visit_type_QAuthZListRuleList(v, name, &lauthz->rules, errp); + + qapi_free_QAuthZListRuleList(oldrules); +} + + +static void +qauthz_list_finalize(Object *obj) +{ + QAuthZList *lauthz = QAUTHZ_LIST(obj); + + qapi_free_QAuthZListRuleList(lauthz->rules); +} + + +static void +qauthz_list_class_init(ObjectClass *oc, void *data) +{ + QAuthZClass *authz = QAUTHZ_CLASS(oc); + + object_class_property_add_enum(oc, "policy", + "QAuthZListPolicy", + &QAuthZListPolicy_lookup, + qauthz_list_prop_get_policy, + qauthz_list_prop_set_policy, + NULL); + + object_class_property_add(oc, "rules", "QAuthZListRule", + qauthz_list_prop_get_rules, + qauthz_list_prop_set_rules, + NULL, NULL, NULL); + + authz->is_allowed = qauthz_list_is_allowed; +} + + +QAuthZList *qauthz_list_new(const char *id, + QAuthZListPolicy policy, + Error **errp) +{ + return QAUTHZ_LIST( + object_new_with_props(TYPE_QAUTHZ_LIST, + object_get_objects_root(), + id, errp, + "policy", QAuthZListPolicy_str(policy), + NULL)); +} + +ssize_t qauthz_list_append_rule(QAuthZList *auth, + const char *match, + QAuthZListPolicy policy, + QAuthZListFormat format, + Error **errp) +{ + QAuthZListRule *rule; + QAuthZListRuleList *rules, *tmp; + size_t i = 0; + + rule = g_new0(QAuthZListRule, 1); + rule->policy = policy; + rule->match = g_strdup(match); + rule->format = format; + rule->has_format = true; + + tmp = g_new0(QAuthZListRuleList, 1); + tmp->value = rule; + + rules = auth->rules; + if (rules) { + while (rules->next) { + i++; + rules = rules->next; + } + rules->next = tmp; + return i + 1; + } else { + auth->rules = tmp; + return 0; + } +} + + +ssize_t qauthz_list_insert_rule(QAuthZList *auth, + const char *match, + QAuthZListPolicy policy, + QAuthZListFormat format, + size_t index, + Error **errp) +{ + QAuthZListRule *rule; + QAuthZListRuleList *rules, *tmp; + size_t i = 0; + + rule = g_new0(QAuthZListRule, 1); + rule->policy = policy; + rule->match = g_strdup(match); + rule->format = format; + rule->has_format = true; + + tmp = g_new0(QAuthZListRuleList, 1); + tmp->value = rule; + + rules = auth->rules; + if (rules && index > 0) { + while (rules->next && i < (index - 1)) { + i++; + rules = rules->next; + } + tmp->next = rules->next; + rules->next = tmp; + return i + 1; + } else { + tmp->next = auth->rules; + auth->rules = tmp; + return 0; + } +} + + +ssize_t qauthz_list_delete_rule(QAuthZList *auth, const char *match) +{ + QAuthZListRule *rule; + QAuthZListRuleList *rules, *prev; + size_t i = 0; + + prev = NULL; + rules = auth->rules; + while (rules) { + rule = rules->value; + if (g_str_equal(rule->match, match)) { + if (prev) { + prev->next = rules->next; + } else { + auth->rules = rules->next; + } + rules->next = NULL; + qapi_free_QAuthZListRuleList(rules); + return i; + } + prev = rules; + rules = rules->next; + i++; + } + + return -1; +} + + +static const TypeInfo qauthz_list_info = { + .parent = TYPE_QAUTHZ, + .name = TYPE_QAUTHZ_LIST, + .instance_size = sizeof(QAuthZList), + .instance_finalize = qauthz_list_finalize, + .class_size = sizeof(QAuthZListClass), + .class_init = qauthz_list_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + + +static void +qauthz_list_register_types(void) +{ + type_register_static(&qauthz_list_info); +} + + +type_init(qauthz_list_register_types); diff --git a/authz/listfile.c b/authz/listfile.c new file mode 100644 index 0000000000..d4579767e7 --- /dev/null +++ b/authz/listfile.c @@ -0,0 +1,283 @@ +/* + * QEMU access control list file authorization driver + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "authz/listfile.h" +#include "authz/trace.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" +#include "qemu/sockets.h" +#include "qemu/filemonitor.h" +#include "qom/object_interfaces.h" +#include "qapi/qapi-visit-authz.h" +#include "qapi/qmp/qjson.h" +#include "qapi/qmp/qobject.h" +#include "qapi/qmp/qerror.h" +#include "qapi/qobject-input-visitor.h" + + +static bool +qauthz_list_file_is_allowed(QAuthZ *authz, + const char *identity, + Error **errp) +{ + QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(authz); + if (fauthz->list) { + return qauthz_is_allowed(fauthz->list, identity, errp); + } + + return false; +} + + +static QAuthZ * +qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp) +{ + GError *err = NULL; + gchar *content = NULL; + gsize len; + QObject *obj = NULL; + QDict *pdict; + Visitor *v = NULL; + QAuthZ *ret = NULL; + + trace_qauthz_list_file_load(fauthz, fauthz->filename); + if (!g_file_get_contents(fauthz->filename, &content, &len, &err)) { + error_setg(errp, "Unable to read '%s': %s", + fauthz->filename, err->message); + goto cleanup; + } + + obj = qobject_from_json(content, errp); + if (!obj) { + goto cleanup; + } + + pdict = qobject_to(QDict, obj); + if (!pdict) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "obj", "dict"); + goto cleanup; + } + + v = qobject_input_visitor_new(obj); + + ret = (QAuthZ *)user_creatable_add_type(TYPE_QAUTHZ_LIST, + NULL, pdict, v, errp); + + cleanup: + visit_free(v); + qobject_unref(obj); + if (err) { + g_error_free(err); + } + g_free(content); + return ret; +} + + +static void +qauthz_list_file_event(int wd G_GNUC_UNUSED, + QFileMonitorEvent ev G_GNUC_UNUSED, + const char *name G_GNUC_UNUSED, + void *opaque) +{ + QAuthZListFile *fauthz = opaque; + Error *err = NULL; + + if (ev != QFILE_MONITOR_EVENT_MODIFIED && + ev != QFILE_MONITOR_EVENT_CREATED) { + return; + } + + object_unref(OBJECT(fauthz->list)); + fauthz->list = qauthz_list_file_load(fauthz, &err); + trace_qauthz_list_file_refresh(fauthz, + fauthz->filename, fauthz->list ? 1 : 0); + if (!fauthz->list) { + error_report_err(err); + } +} + +static void +qauthz_list_file_complete(UserCreatable *uc, Error **errp) +{ + QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(uc); + gchar *dir = NULL, *file = NULL; + + fauthz->list = qauthz_list_file_load(fauthz, errp); + + if (!fauthz->refresh) { + return; + } + + fauthz->file_monitor = qemu_file_monitor_new(errp); + if (!fauthz->file_monitor) { + return; + } + + dir = g_path_get_dirname(fauthz->filename); + if (g_str_equal(dir, ".")) { + error_setg(errp, "Filename must be an absolute path"); + goto cleanup; + } + file = g_path_get_basename(fauthz->filename); + if (g_str_equal(file, ".")) { + error_setg(errp, "Path has no trailing filename component"); + goto cleanup; + } + + fauthz->file_watch = qemu_file_monitor_add_watch( + fauthz->file_monitor, dir, file, + qauthz_list_file_event, fauthz, errp); + if (fauthz->file_watch < 0) { + goto cleanup; + } + + cleanup: + g_free(file); + g_free(dir); +} + + +static void +qauthz_list_file_prop_set_filename(Object *obj, + const char *value, + Error **errp G_GNUC_UNUSED) +{ + QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); + + g_free(fauthz->filename); + fauthz->filename = g_strdup(value); +} + + +static char * +qauthz_list_file_prop_get_filename(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); + + return g_strdup(fauthz->filename); +} + + +static void +qauthz_list_file_prop_set_refresh(Object *obj, + bool value, + Error **errp G_GNUC_UNUSED) +{ + QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); + + fauthz->refresh = value; +} + + +static bool +qauthz_list_file_prop_get_refresh(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); + + return fauthz->refresh; +} + + +static void +qauthz_list_file_finalize(Object *obj) +{ + QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); + + object_unref(OBJECT(fauthz->list)); + g_free(fauthz->filename); + qemu_file_monitor_free(fauthz->file_monitor); +} + + +static void +qauthz_list_file_class_init(ObjectClass *oc, void *data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + QAuthZClass *authz = QAUTHZ_CLASS(oc); + + ucc->complete = qauthz_list_file_complete; + + object_class_property_add_str(oc, "filename", + qauthz_list_file_prop_get_filename, + qauthz_list_file_prop_set_filename, + NULL); + object_class_property_add_bool(oc, "refresh", + qauthz_list_file_prop_get_refresh, + qauthz_list_file_prop_set_refresh, + NULL); + + authz->is_allowed = qauthz_list_file_is_allowed; +} + + +static void +qauthz_list_file_init(Object *obj) +{ + QAuthZListFile *authz = QAUTHZ_LIST_FILE(obj); + + authz->file_watch = -1; +#ifdef CONFIG_INOTIFY1 + authz->refresh = TRUE; +#endif +} + + +QAuthZListFile *qauthz_list_file_new(const char *id, + const char *filename, + bool refresh, + Error **errp) +{ + return QAUTHZ_LIST_FILE( + object_new_with_props(TYPE_QAUTHZ_LIST_FILE, + object_get_objects_root(), + id, errp, + "filename", filename, + "refresh", refresh ? "yes" : "no", + NULL)); +} + + +static const TypeInfo qauthz_list_file_info = { + .parent = TYPE_QAUTHZ, + .name = TYPE_QAUTHZ_LIST_FILE, + .instance_init = qauthz_list_file_init, + .instance_size = sizeof(QAuthZListFile), + .instance_finalize = qauthz_list_file_finalize, + .class_size = sizeof(QAuthZListFileClass), + .class_init = qauthz_list_file_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + + +static void +qauthz_list_file_register_types(void) +{ + type_register_static(&qauthz_list_file_info); +} + + +type_init(qauthz_list_file_register_types); diff --git a/authz/pamacct.c b/authz/pamacct.c new file mode 100644 index 0000000000..5038358cdc --- /dev/null +++ b/authz/pamacct.c @@ -0,0 +1,148 @@ +/* + * QEMU PAM authorization driver + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "authz/pamacct.h" +#include "authz/trace.h" +#include "qom/object_interfaces.h" + +#include <security/pam_appl.h> + + +static bool qauthz_pam_is_allowed(QAuthZ *authz, + const char *identity, + Error **errp) +{ + QAuthZPAM *pauthz = QAUTHZ_PAM(authz); + const struct pam_conv pam_conversation = { 0 }; + pam_handle_t *pamh = NULL; + int ret; + + trace_qauthz_pam_check(authz, identity, pauthz->service); + ret = pam_start(pauthz->service, + identity, + &pam_conversation, + &pamh); + if (ret != PAM_SUCCESS) { + error_setg(errp, "Unable to start PAM transaction: %s", + pam_strerror(NULL, ret)); + return false; + } + + ret = pam_acct_mgmt(pamh, PAM_SILENT); + pam_end(pamh, ret); + if (ret != PAM_SUCCESS) { + error_setg(errp, "Unable to authorize user '%s': %s", + identity, pam_strerror(pamh, ret)); + return false; + } + + return true; +} + + +static void +qauthz_pam_prop_set_service(Object *obj, + const char *service, + Error **errp G_GNUC_UNUSED) +{ + QAuthZPAM *pauthz = QAUTHZ_PAM(obj); + + g_free(pauthz->service); + pauthz->service = g_strdup(service); +} + + +static char * +qauthz_pam_prop_get_service(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QAuthZPAM *pauthz = QAUTHZ_PAM(obj); + + return g_strdup(pauthz->service); +} + + +static void +qauthz_pam_complete(UserCreatable *uc, Error **errp) +{ +} + + +static void +qauthz_pam_finalize(Object *obj) +{ + QAuthZPAM *pauthz = QAUTHZ_PAM(obj); + + g_free(pauthz->service); +} + + +static void +qauthz_pam_class_init(ObjectClass *oc, void *data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + QAuthZClass *authz = QAUTHZ_CLASS(oc); + + ucc->complete = qauthz_pam_complete; + authz->is_allowed = qauthz_pam_is_allowed; + + object_class_property_add_str(oc, "service", + qauthz_pam_prop_get_service, + qauthz_pam_prop_set_service, + NULL); +} + + +QAuthZPAM *qauthz_pam_new(const char *id, + const char *service, + Error **errp) +{ + return QAUTHZ_PAM( + object_new_with_props(TYPE_QAUTHZ_PAM, + object_get_objects_root(), + id, errp, + "service", service, + NULL)); +} + + +static const TypeInfo qauthz_pam_info = { + .parent = TYPE_QAUTHZ, + .name = TYPE_QAUTHZ_PAM, + .instance_size = sizeof(QAuthZPAM), + .instance_finalize = qauthz_pam_finalize, + .class_size = sizeof(QAuthZPAMClass), + .class_init = qauthz_pam_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + + +static void +qauthz_pam_register_types(void) +{ + type_register_static(&qauthz_pam_info); +} + + +type_init(qauthz_pam_register_types); diff --git a/authz/simple.c b/authz/simple.c new file mode 100644 index 0000000000..8ab718803e --- /dev/null +++ b/authz/simple.c @@ -0,0 +1,115 @@ +/* + * QEMU simple authorization driver + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "authz/simple.h" +#include "authz/trace.h" +#include "qom/object_interfaces.h" + +static bool qauthz_simple_is_allowed(QAuthZ *authz, + const char *identity, + Error **errp) +{ + QAuthZSimple *sauthz = QAUTHZ_SIMPLE(authz); + + trace_qauthz_simple_is_allowed(authz, sauthz->identity, identity); + return g_str_equal(identity, sauthz->identity); +} + +static void +qauthz_simple_prop_set_identity(Object *obj, + const char *value, + Error **errp G_GNUC_UNUSED) +{ + QAuthZSimple *sauthz = QAUTHZ_SIMPLE(obj); + + g_free(sauthz->identity); + sauthz->identity = g_strdup(value); +} + + +static char * +qauthz_simple_prop_get_identity(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QAuthZSimple *sauthz = QAUTHZ_SIMPLE(obj); + + return g_strdup(sauthz->identity); +} + + +static void +qauthz_simple_finalize(Object *obj) +{ + QAuthZSimple *sauthz = QAUTHZ_SIMPLE(obj); + + g_free(sauthz->identity); +} + + +static void +qauthz_simple_class_init(ObjectClass *oc, void *data) +{ + QAuthZClass *authz = QAUTHZ_CLASS(oc); + + authz->is_allowed = qauthz_simple_is_allowed; + + object_class_property_add_str(oc, "identity", + qauthz_simple_prop_get_identity, + qauthz_simple_prop_set_identity, + NULL); +} + + +QAuthZSimple *qauthz_simple_new(const char *id, + const char *identity, + Error **errp) +{ + return QAUTHZ_SIMPLE( + object_new_with_props(TYPE_QAUTHZ_SIMPLE, + object_get_objects_root(), + id, errp, + "identity", identity, + NULL)); +} + + +static const TypeInfo qauthz_simple_info = { + .parent = TYPE_QAUTHZ, + .name = TYPE_QAUTHZ_SIMPLE, + .instance_size = sizeof(QAuthZSimple), + .instance_finalize = qauthz_simple_finalize, + .class_size = sizeof(QAuthZSimpleClass), + .class_init = qauthz_simple_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + + +static void +qauthz_simple_register_types(void) +{ + type_register_static(&qauthz_simple_info); +} + + +type_init(qauthz_simple_register_types); diff --git a/authz/trace-events b/authz/trace-events new file mode 100644 index 0000000000..72c411927d --- /dev/null +++ b/authz/trace-events @@ -0,0 +1,18 @@ +# See docs/devel/tracing.txt for syntax documentation. + +# authz/base.c +qauthz_is_allowed(void *authz, const char *identity, bool allowed) "AuthZ %p check identity=%s allowed=%d" + +# auth/simple.c +qauthz_simple_is_allowed(void *authz, const char *wantidentity, const char *gotidentity) "AuthZ simple %p check want identity=%s got identity=%s" + +# auth/list.c +qauthz_list_check_rule(void *authz, const char *identity, const char *rule, int format, int policy) "AuthZ list %p check rule=%s identity=%s format=%d policy=%d" +qauthz_list_default_policy(void *authz, const char *identity, int policy) "AuthZ list %p default identity=%s policy=%d" + +# auth/listfile.c +qauthz_list_file_load(void *authz, const char *filename) "AuthZ file %p load filename=%s" +qauthz_list_file_refresh(void *authz, const char *filename, int success) "AuthZ file %p load filename=%s success=%d" + +# auth/pam.c +qauthz_pam_check(void *authz, const char *identity, const char *service) "AuthZ PAM %p identity=%s service=%s" diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 717fcbdae4..ff619d31b4 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -9,10 +9,9 @@ common-obj-$(CONFIG_POSIX) += hostmem-file.o common-obj-y += cryptodev.o common-obj-y += cryptodev-builtin.o -ifeq ($(CONFIG_VIRTIO),y) +ifeq ($(CONFIG_VIRTIO_CRYPTO),y) common-obj-y += cryptodev-vhost.o -common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) += \ - cryptodev-vhost-user.o +common-obj-$(CONFIG_VHOST_CRYPTO) += cryptodev-vhost-user.o endif common-obj-$(CONFIG_LINUX) += hostmem-memfd.o @@ -152,53 +152,53 @@ int path_is_absolute(const char *path) #endif } -/* if filename is absolute, just copy it to dest. Otherwise, build a +/* if filename is absolute, just return its duplicate. Otherwise, build a path to it by considering it is relative to base_path. URL are supported. */ -void path_combine(char *dest, int dest_size, - const char *base_path, - const char *filename) +char *path_combine(const char *base_path, const char *filename) { + const char *protocol_stripped = NULL; const char *p, *p1; + char *result; int len; - if (dest_size <= 0) - return; if (path_is_absolute(filename)) { - pstrcpy(dest, dest_size, filename); - } else { - const char *protocol_stripped = NULL; + return g_strdup(filename); + } - if (path_has_protocol(base_path)) { - protocol_stripped = strchr(base_path, ':'); - if (protocol_stripped) { - protocol_stripped++; - } + if (path_has_protocol(base_path)) { + protocol_stripped = strchr(base_path, ':'); + if (protocol_stripped) { + protocol_stripped++; } - p = protocol_stripped ?: base_path; + } + p = protocol_stripped ?: base_path; - p1 = strrchr(base_path, '/'); + p1 = strrchr(base_path, '/'); #ifdef _WIN32 - { - const char *p2; - p2 = strrchr(base_path, '\\'); - if (!p1 || p2 > p1) - p1 = p2; + { + const char *p2; + p2 = strrchr(base_path, '\\'); + if (!p1 || p2 > p1) { + p1 = p2; } + } #endif - if (p1) - p1++; - else - p1 = base_path; - if (p1 > p) - p = p1; - len = p - base_path; - if (len > dest_size - 1) - len = dest_size - 1; - memcpy(dest, base_path, len); - dest[len] = '\0'; - pstrcat(dest, dest_size, filename); + if (p1) { + p1++; + } else { + p1 = base_path; } + if (p1 > p) { + p = p1; + } + len = p - base_path; + + result = g_malloc(len + strlen(filename) + 1); + memcpy(result, base_path, len); + strcpy(result + len, filename); + + return result; } /* @@ -303,30 +303,61 @@ fail: return -EACCES; } -void bdrv_get_full_backing_filename_from_filename(const char *backed, - const char *backing, - char *dest, size_t sz, - Error **errp) +/* + * If @backing is empty, this function returns NULL without setting + * @errp. In all other cases, NULL will only be returned with @errp + * set. + * + * Therefore, a return value of NULL without @errp set means that + * there is no backing file; if @errp is set, there is one but its + * absolute filename cannot be generated. + */ +char *bdrv_get_full_backing_filename_from_filename(const char *backed, + const char *backing, + Error **errp) { - if (backing[0] == '\0' || path_has_protocol(backing) || - path_is_absolute(backing)) - { - pstrcpy(dest, sz, backing); + if (backing[0] == '\0') { + return NULL; + } else if (path_has_protocol(backing) || path_is_absolute(backing)) { + return g_strdup(backing); } else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) { error_setg(errp, "Cannot use relative backing file names for '%s'", backed); + return NULL; } else { - path_combine(dest, sz, backed, backing); + return path_combine(backed, backing); } } -void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz, - Error **errp) +/* + * If @filename is empty or NULL, this function returns NULL without + * setting @errp. In all other cases, NULL will only be returned with + * @errp set. + */ +static char *bdrv_make_absolute_filename(BlockDriverState *relative_to, + const char *filename, Error **errp) { - char *backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename; + char *dir, *full_name; - bdrv_get_full_backing_filename_from_filename(backed, bs->backing_file, - dest, sz, errp); + if (!filename || filename[0] == '\0') { + return NULL; + } else if (path_has_protocol(filename) || path_is_absolute(filename)) { + return g_strdup(filename); + } + + dir = bdrv_dirname(relative_to, errp); + if (!dir) { + return NULL; + } + + full_name = g_strconcat(dir, filename, NULL); + g_free(dir); + return full_name; +} + +char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp) +{ + return bdrv_make_absolute_filename(bs, bs->backing_file, errp); } void bdrv_register(BlockDriver *bdrv) @@ -1004,6 +1035,8 @@ static void bdrv_backing_attach(BdrvChild *c) "node is used as backing hd of '%s'", bdrv_get_device_or_node_name(parent)); + bdrv_refresh_filename(backing_hd); + parent->open_flags &= ~BDRV_O_NO_BACKING; pstrcpy(parent->backing_file, sizeof(parent->backing_file), backing_hd->filename); @@ -1413,6 +1446,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, } if (file != NULL) { + bdrv_refresh_filename(blk_bs(file)); filename = blk_bs(file)->filename; } else { /* @@ -1954,13 +1988,32 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, errp); g_slist_free(ignore_children); - return ret; + if (ret < 0) { + return ret; + } + + if (!c->has_backup_perm) { + c->has_backup_perm = true; + c->backup_perm = c->perm; + c->backup_shared_perm = c->shared_perm; + } + /* + * Note: it's OK if c->has_backup_perm was already set, as we can find the + * same child twice during check_perm procedure + */ + + c->perm = perm; + c->shared_perm = shared; + + return 0; } static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared) { uint64_t cumulative_perms, cumulative_shared_perms; + c->has_backup_perm = false; + c->perm = perm; c->shared_perm = shared; @@ -1971,6 +2024,12 @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared) static void bdrv_child_abort_perm_update(BdrvChild *c) { + if (c->has_backup_perm) { + c->perm = c->backup_perm; + c->shared_perm = c->backup_shared_perm; + c->has_backup_perm = false; + } + bdrv_abort_perm_update(c->bs); } @@ -2309,8 +2368,6 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, bdrv_unref(backing_hd); } - bdrv_refresh_filename(bs); - out: bdrv_refresh_limits(bs, NULL); } @@ -2328,10 +2385,11 @@ out: int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, const char *bdref_key, Error **errp) { - char *backing_filename = g_malloc0(PATH_MAX); + char *backing_filename = NULL; char *bdref_key_dot; const char *reference = NULL; int ret = 0; + bool implicit_backing = false; BlockDriverState *backing_hd; QDict *options; QDict *tmp_parent_options = NULL; @@ -2362,13 +2420,22 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, */ reference = qdict_get_try_str(parent_options, bdref_key); if (reference || qdict_haskey(options, "file.filename")) { - backing_filename[0] = '\0'; + /* keep backing_filename NULL */ } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) { qobject_unref(options); goto free_exit; } else { - bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX, - &local_err); + if (qdict_size(options) == 0) { + /* If the user specifies options that do not modify the + * backing file's behavior, we might still consider it the + * implicit backing file. But it's easier this way, and + * just specifying some of the backing BDS's options is + * only possible with -drive anyway (otherwise the QAPI + * schema forces the user to specify everything). */ + implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file); + } + + backing_filename = bdrv_get_full_backing_filename(bs, &local_err); if (local_err) { ret = -EINVAL; error_propagate(errp, local_err); @@ -2389,9 +2456,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, qdict_put_str(options, "driver", bs->backing_format); } - backing_hd = bdrv_open_inherit(*backing_filename ? backing_filename : NULL, - reference, options, 0, bs, &child_backing, - errp); + backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs, + &child_backing, errp); if (!backing_hd) { bs->open_flags |= BDRV_O_NO_BACKING; error_prepend(errp, "Could not open backing file: "); @@ -2400,6 +2466,12 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, } bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs)); + if (implicit_backing) { + bdrv_refresh_filename(backing_hd); + pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file), + backing_hd->filename); + } + /* Hook up the backing file link; drop our reference, bs owns the * backing_hd reference now */ bdrv_set_backing_hd(bs, backing_hd, &local_err); @@ -2839,8 +2911,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, g_free(child_key_dot); } - bdrv_refresh_filename(bs); - /* Check if any unknown options were used */ if (qdict_size(options) != 0) { const QDictEntry *entry = qdict_first(options); @@ -3285,6 +3355,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, if (local_err != NULL) { error_propagate(errp, local_err); } else { + bdrv_refresh_filename(reopen_state->bs); error_setg(errp, "failed while preparing to reopen image '%s'", reopen_state->bs->filename); } @@ -3542,7 +3613,9 @@ void bdrv_close_all(void) static bool should_update_child(BdrvChild *c, BlockDriverState *to) { - BdrvChild *to_c; + GQueue *queue; + GHashTable *found; + bool ret; if (c->role->stay_at_node) { return false; @@ -3578,14 +3651,43 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) * if A is a child of B, that means we cannot replace A by B there * because that would create a loop. Silently detaching A from B * is also not really an option. So overall just leaving A in - * place there is the most sensible choice. */ - QLIST_FOREACH(to_c, &to->children, next) { - if (to_c == c) { - return false; + * place there is the most sensible choice. + * + * We would also create a loop in any cases where @c is only + * indirectly referenced by @to. Prevent this by returning false + * if @c is found (by breadth-first search) anywhere in the whole + * subtree of @to. + */ + + ret = true; + found = g_hash_table_new(NULL, NULL); + g_hash_table_add(found, to); + queue = g_queue_new(); + g_queue_push_tail(queue, to); + + while (!g_queue_is_empty(queue)) { + BlockDriverState *v = g_queue_pop_head(queue); + BdrvChild *c2; + + QLIST_FOREACH(c2, &v->children, next) { + if (c2 == c) { + ret = false; + break; + } + + if (g_hash_table_contains(found, c2->bs)) { + continue; + } + + g_queue_push_tail(queue, c2->bs); + g_hash_table_add(found, c2->bs); } } - return true; + g_queue_free(queue); + g_hash_table_destroy(found); + + return ret; } void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, @@ -3789,6 +3891,8 @@ int bdrv_change_backing_file(BlockDriverState *bs, if (ret == 0) { pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: ""); pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: ""); + pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file), + backing_file ?: ""); } return ret; } @@ -3881,7 +3985,10 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, /* success - we can delete the intermediate states, and link top->base */ /* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once * we've figured out how they should work. */ - backing_file_str = backing_file_str ? backing_file_str : base->filename; + if (!backing_file_str) { + bdrv_refresh_filename(base); + backing_file_str = base->filename; + } QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) { /* Check whether we are allowed to switch c from top to base */ @@ -4429,16 +4536,6 @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs) return bs->supported_zero_flags & BDRV_REQ_MAY_UNMAP; } -const char *bdrv_get_encrypted_filename(BlockDriverState *bs) -{ - if (bs->backing && bs->backing->bs->encrypted) - return bs->backing_file; - else if (bs->encrypted) - return bs->filename; - else - return NULL; -} - void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size) { @@ -4547,7 +4644,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, int is_protocol = 0; BlockDriverState *curr_bs = NULL; BlockDriverState *retval = NULL; - Error *local_error = NULL; if (!bs || !bs->drv || !backing_file) { return NULL; @@ -4555,7 +4651,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, filename_full = g_malloc(PATH_MAX); backing_file_full = g_malloc(PATH_MAX); - filename_tmp = g_malloc(PATH_MAX); is_protocol = path_has_protocol(backing_file); @@ -4564,41 +4659,43 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, /* If either of the filename paths is actually a protocol, then * compare unmodified paths; otherwise make paths relative */ if (is_protocol || path_has_protocol(curr_bs->backing_file)) { + char *backing_file_full_ret; + if (strcmp(backing_file, curr_bs->backing_file) == 0) { retval = curr_bs->backing->bs; break; } /* Also check against the full backing filename for the image */ - bdrv_get_full_backing_filename(curr_bs, backing_file_full, PATH_MAX, - &local_error); - if (local_error == NULL) { - if (strcmp(backing_file, backing_file_full) == 0) { + backing_file_full_ret = bdrv_get_full_backing_filename(curr_bs, + NULL); + if (backing_file_full_ret) { + bool equal = strcmp(backing_file, backing_file_full_ret) == 0; + g_free(backing_file_full_ret); + if (equal) { retval = curr_bs->backing->bs; break; } - } else { - error_free(local_error); - local_error = NULL; } } else { /* If not an absolute filename path, make it relative to the current * image's filename path */ - path_combine(filename_tmp, PATH_MAX, curr_bs->filename, - backing_file); - - /* We are going to compare absolute pathnames */ - if (!realpath(filename_tmp, filename_full)) { + filename_tmp = bdrv_make_absolute_filename(curr_bs, backing_file, + NULL); + /* We are going to compare canonicalized absolute pathnames */ + if (!filename_tmp || !realpath(filename_tmp, filename_full)) { + g_free(filename_tmp); continue; } + g_free(filename_tmp); /* We need to make sure the backing filename we are comparing against * is relative to the current image filename (or absolute) */ - path_combine(filename_tmp, PATH_MAX, curr_bs->filename, - curr_bs->backing_file); - - if (!realpath(filename_tmp, backing_file_full)) { + filename_tmp = bdrv_get_full_backing_filename(curr_bs, NULL); + if (!filename_tmp || !realpath(filename_tmp, backing_file_full)) { + g_free(filename_tmp); continue; } + g_free(filename_tmp); if (strcmp(backing_file_full, filename_full) == 0) { retval = curr_bs->backing->bs; @@ -4609,7 +4706,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, g_free(filename_full); g_free(backing_file_full); - g_free(filename_tmp); return retval; } @@ -5096,17 +5192,17 @@ void bdrv_img_create(const char *filename, const char *fmt, size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, img_size); if (backing_file && !(flags & BDRV_O_NO_BACKING)) { BlockDriverState *bs; - char *full_backing = g_new0(char, PATH_MAX); + char *full_backing; int back_flags; QDict *backing_options = NULL; - bdrv_get_full_backing_filename_from_filename(filename, backing_file, - full_backing, PATH_MAX, - &local_err); + full_backing = + bdrv_get_full_backing_filename_from_filename(filename, backing_file, + &local_err); if (local_err) { - g_free(full_backing); goto out; } + assert(full_backing); /* backing files always opened read-only */ back_flags = flags; @@ -5227,6 +5323,9 @@ void bdrv_detach_aio_context(BlockDriverState *bs) bdrv_detach_aio_context(child->bs); } + if (bs->quiesce_counter) { + aio_enable_external(bs->aio_context); + } bs->aio_context = NULL; } @@ -5240,6 +5339,10 @@ void bdrv_attach_aio_context(BlockDriverState *bs, return; } + if (bs->quiesce_counter) { + aio_disable_external(new_context); + } + bs->aio_context = new_context; QLIST_FOREACH(child, &bs->children, next) { @@ -5261,18 +5364,16 @@ void bdrv_attach_aio_context(BlockDriverState *bs, bs->walking_aio_notifiers = false; } +/* The caller must own the AioContext lock for the old AioContext of bs, but it + * must not own the AioContext lock for new_context (unless new_context is + * the same as the current context of bs). */ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) { - AioContext *ctx = bdrv_get_aio_context(bs); - - aio_disable_external(ctx); - bdrv_parent_drained_begin(bs, NULL, false); - bdrv_drain(bs); /* ensure there are no in-flight requests */ - - while (aio_poll(ctx, false)) { - /* wait for all bottom halves to execute */ + if (bdrv_get_aio_context(bs) == new_context) { + return; } + bdrv_drained_begin(bs); bdrv_detach_aio_context(bs); /* This function executes in the old AioContext so acquire the new one in @@ -5280,8 +5381,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) */ aio_context_acquire(new_context); bdrv_attach_aio_context(bs, new_context); - bdrv_parent_drained_end(bs, NULL, false); - aio_enable_external(ctx); + bdrv_drained_end(bs); aio_context_release(new_context); } @@ -5435,33 +5535,113 @@ out: return to_replace_bs; } -static bool append_open_options(QDict *d, BlockDriverState *bs) +/** + * Iterates through the list of runtime option keys that are said to + * be "strong" for a BDS. An option is called "strong" if it changes + * a BDS's data. For example, the null block driver's "size" and + * "read-zeroes" options are strong, but its "latency-ns" option is + * not. + * + * If a key returned by this function ends with a dot, all options + * starting with that prefix are strong. + */ +static const char *const *strong_options(BlockDriverState *bs, + const char *const *curopt) +{ + static const char *const global_options[] = { + "driver", "filename", NULL + }; + + if (!curopt) { + return &global_options[0]; + } + + curopt++; + if (curopt == &global_options[ARRAY_SIZE(global_options) - 1] && bs->drv) { + curopt = bs->drv->strong_runtime_opts; + } + + return (curopt && *curopt) ? curopt : NULL; +} + +/** + * Copies all strong runtime options from bs->options to the given + * QDict. The set of strong option keys is determined by invoking + * strong_options(). + * + * Returns true iff any strong option was present in bs->options (and + * thus copied to the target QDict) with the exception of "filename" + * and "driver". The caller is expected to use this value to decide + * whether the existence of strong options prevents the generation of + * a plain filename. + */ +static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs) { - const QDictEntry *entry; - QemuOptDesc *desc; bool found_any = false; + const char *const *option_name = NULL; - for (entry = qdict_first(bs->options); entry; - entry = qdict_next(bs->options, entry)) - { - /* Exclude all non-driver-specific options */ - for (desc = bdrv_runtime_opts.desc; desc->name; desc++) { - if (!strcmp(qdict_entry_key(entry), desc->name)) { - break; + if (!bs->drv) { + return false; + } + + while ((option_name = strong_options(bs, option_name))) { + bool option_given = false; + + assert(strlen(*option_name) > 0); + if ((*option_name)[strlen(*option_name) - 1] != '.') { + QObject *entry = qdict_get(bs->options, *option_name); + if (!entry) { + continue; + } + + qdict_put_obj(d, *option_name, qobject_ref(entry)); + option_given = true; + } else { + const QDictEntry *entry; + for (entry = qdict_first(bs->options); entry; + entry = qdict_next(bs->options, entry)) + { + if (strstart(qdict_entry_key(entry), *option_name, NULL)) { + qdict_put_obj(d, qdict_entry_key(entry), + qobject_ref(qdict_entry_value(entry))); + option_given = true; + } } } - if (desc->name) { - continue; + + /* While "driver" and "filename" need to be included in a JSON filename, + * their existence does not prohibit generation of a plain filename. */ + if (!found_any && option_given && + strcmp(*option_name, "driver") && strcmp(*option_name, "filename")) + { + found_any = true; } + } - qdict_put_obj(d, qdict_entry_key(entry), - qobject_ref(qdict_entry_value(entry))); - found_any = true; + if (!qdict_haskey(d, "driver")) { + /* Drivers created with bdrv_new_open_driver() may not have a + * @driver option. Add it here. */ + qdict_put_str(d, "driver", bs->drv->format_name); } return found_any; } +/* Note: This function may return false positives; it may return true + * even if opening the backing file specified by bs's image header + * would result in exactly bs->backing. */ +static bool bdrv_backing_overridden(BlockDriverState *bs) +{ + if (bs->backing) { + return strcmp(bs->auto_backing_file, + bs->backing->bs->filename); + } else { + /* No backing BDS, so if the image header reports any backing + * file, it must have been suppressed */ + return bs->auto_backing_file[0] != '\0'; + } +} + /* Updates the following BDS fields: * - exact_filename: A filename which may be used for opening a block device * which (mostly) equals the given BDS (even without any @@ -5477,92 +5657,108 @@ static bool append_open_options(QDict *d, BlockDriverState *bs) void bdrv_refresh_filename(BlockDriverState *bs) { BlockDriver *drv = bs->drv; + BdrvChild *child; QDict *opts; + bool backing_overridden; + bool generate_json_filename; /* Whether our default implementation should + fill exact_filename (false) or not (true) */ if (!drv) { return; } - /* This BDS's file name will most probably depend on its file's name, so - * refresh that first */ - if (bs->file) { - bdrv_refresh_filename(bs->file->bs); + /* This BDS's file name may depend on any of its children's file names, so + * refresh those first */ + QLIST_FOREACH(child, &bs->children, next) { + bdrv_refresh_filename(child->bs); + } + + if (bs->implicit) { + /* For implicit nodes, just copy everything from the single child */ + child = QLIST_FIRST(&bs->children); + assert(QLIST_NEXT(child, next) == NULL); + + pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), + child->bs->exact_filename); + pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename); + + bs->full_open_options = qobject_ref(child->bs->full_open_options); + + return; + } + + backing_overridden = bdrv_backing_overridden(bs); + + if (bs->open_flags & BDRV_O_NO_IO) { + /* Without I/O, the backing file does not change anything. + * Therefore, in such a case (primarily qemu-img), we can + * pretend the backing file has not been overridden even if + * it technically has been. */ + backing_overridden = false; } + /* Gather the options QDict */ + opts = qdict_new(); + generate_json_filename = append_strong_runtime_options(opts, bs); + generate_json_filename |= backing_overridden; + + if (drv->bdrv_gather_child_options) { + /* Some block drivers may not want to present all of their children's + * options, or name them differently from BdrvChild.name */ + drv->bdrv_gather_child_options(bs, opts, backing_overridden); + } else { + QLIST_FOREACH(child, &bs->children, next) { + if (child->role == &child_backing && !backing_overridden) { + /* We can skip the backing BDS if it has not been overridden */ + continue; + } + + qdict_put(opts, child->name, + qobject_ref(child->bs->full_open_options)); + } + + if (backing_overridden && !bs->backing) { + /* Force no backing file */ + qdict_put_null(opts, "backing"); + } + } + + qobject_unref(bs->full_open_options); + bs->full_open_options = opts; + if (drv->bdrv_refresh_filename) { /* Obsolete information is of no use here, so drop the old file name * information before refreshing it */ bs->exact_filename[0] = '\0'; - if (bs->full_open_options) { - qobject_unref(bs->full_open_options); - bs->full_open_options = NULL; - } - opts = qdict_new(); - append_open_options(opts, bs); - drv->bdrv_refresh_filename(bs, opts); - qobject_unref(opts); + drv->bdrv_refresh_filename(bs); } else if (bs->file) { /* Try to reconstruct valid information from the underlying file */ - bool has_open_options; bs->exact_filename[0] = '\0'; - if (bs->full_open_options) { - qobject_unref(bs->full_open_options); - bs->full_open_options = NULL; - } - - opts = qdict_new(); - has_open_options = append_open_options(opts, bs); - /* If no specific options have been given for this BDS, the filename of - * the underlying file should suffice for this one as well */ - if (bs->file->bs->exact_filename[0] && !has_open_options) { + /* + * We can use the underlying file's filename if: + * - it has a filename, + * - the file is a protocol BDS, and + * - opening that file (as this BDS's format) will automatically create + * the BDS tree we have right now, that is: + * - the user did not significantly change this BDS's behavior with + * some explicit (strong) options + * - no non-file child of this BDS has been overridden by the user + * Both of these conditions are represented by generate_json_filename. + */ + if (bs->file->bs->exact_filename[0] && + bs->file->bs->drv->bdrv_file_open && + !generate_json_filename) + { strcpy(bs->exact_filename, bs->file->bs->exact_filename); } - /* Reconstructing the full options QDict is simple for most format block - * drivers, as long as the full options are known for the underlying - * file BDS. The full options QDict of that file BDS should somehow - * contain a representation of the filename, therefore the following - * suffices without querying the (exact_)filename of this BDS. */ - if (bs->file->bs->full_open_options) { - qdict_put_str(opts, "driver", drv->format_name); - qdict_put(opts, "file", - qobject_ref(bs->file->bs->full_open_options)); - - bs->full_open_options = opts; - } else { - qobject_unref(opts); - } - } else if (!bs->full_open_options && qdict_size(bs->options)) { - /* There is no underlying file BDS (at least referenced by BDS.file), - * so the full options QDict should be equal to the options given - * specifically for this block device when it was opened (plus the - * driver specification). - * Because those options don't change, there is no need to update - * full_open_options when it's already set. */ - - opts = qdict_new(); - append_open_options(opts, bs); - qdict_put_str(opts, "driver", drv->format_name); - - if (bs->exact_filename[0]) { - /* This may not work for all block protocol drivers (some may - * require this filename to be parsed), but we have to find some - * default solution here, so just include it. If some block driver - * does not support pure options without any filename at all or - * needs some special format of the options QDict, it needs to - * implement the driver-specific bdrv_refresh_filename() function. - */ - qdict_put_str(opts, "filename", bs->exact_filename); - } - - bs->full_open_options = opts; } if (bs->exact_filename[0]) { pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename); - } else if (bs->full_open_options) { + } else { QString *json = qobject_to_json(QOBJECT(bs->full_open_options)); snprintf(bs->filename, sizeof(bs->filename), "json:%s", qstring_get_str(json)); @@ -5570,6 +5766,33 @@ void bdrv_refresh_filename(BlockDriverState *bs) } } +char *bdrv_dirname(BlockDriverState *bs, Error **errp) +{ + BlockDriver *drv = bs->drv; + + if (!drv) { + error_setg(errp, "Node '%s' is ejected", bs->node_name); + return NULL; + } + + if (drv->bdrv_dirname) { + return drv->bdrv_dirname(bs, errp); + } + + if (bs->file) { + return bdrv_dirname(bs->file->bs, errp); + } + + bdrv_refresh_filename(bs); + if (bs->exact_filename[0] != '\0') { + return path_combine(bs->exact_filename, ""); + } + + error_setg(errp, "Cannot generate a base directory for %s nodes", + drv->format_name); + return NULL; +} + /* * Hot add/remove a BDS's child. So the user can take a child offline when * it is broken and take a new child online diff --git a/block/backup.c b/block/backup.c index 435414e964..9988753249 100644 --- a/block/backup.c +++ b/block/backup.c @@ -107,7 +107,6 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job, void **bounce_buffer) { int ret; - struct iovec iov; QEMUIOVector qiov; BlockBackend *blk = job->common.blk; int nbytes; @@ -119,9 +118,7 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job, if (!*bounce_buffer) { *bounce_buffer = blk_blockalign(blk, job->cluster_size); } - iov.iov_base = *bounce_buffer; - iov.iov_len = nbytes; - qemu_iovec_init_external(&qiov, &iov, 1); + qemu_iovec_init_buf(&qiov, *bounce_buffer, nbytes); ret = blk_co_preadv(blk, start, qiov.size, &qiov, read_flags); if (ret < 0) { diff --git a/block/blkdebug.c b/block/blkdebug.c index 0759452925..1ea835c2b9 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -811,51 +811,37 @@ static int64_t blkdebug_getlength(BlockDriverState *bs) return bdrv_getlength(bs->file->bs); } -static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) +static void blkdebug_refresh_filename(BlockDriverState *bs) { BDRVBlkdebugState *s = bs->opaque; - QDict *opts; const QDictEntry *e; - bool force_json = false; - - for (e = qdict_first(options); e; e = qdict_next(options, e)) { - if (strcmp(qdict_entry_key(e), "config") && - strcmp(qdict_entry_key(e), "x-image")) - { - force_json = true; - break; - } - } + int ret; - if (force_json && !bs->file->bs->full_open_options) { - /* The config file cannot be recreated, so creating a plain filename - * is impossible */ + if (!bs->file->bs->exact_filename[0]) { return; } - if (!force_json && bs->file->bs->exact_filename[0]) { - int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "blkdebug:%s:%s", s->config_file ?: "", - bs->file->bs->exact_filename); - if (ret >= sizeof(bs->exact_filename)) { - /* An overflow makes the filename unusable, so do not report any */ - bs->exact_filename[0] = 0; + for (e = qdict_first(bs->full_open_options); e; + e = qdict_next(bs->full_open_options, e)) + { + /* Real child options are under "image", but "x-image" may + * contain a filename */ + if (strcmp(qdict_entry_key(e), "config") && + strcmp(qdict_entry_key(e), "image") && + strcmp(qdict_entry_key(e), "x-image") && + strcmp(qdict_entry_key(e), "driver")) + { + return; } } - opts = qdict_new(); - qdict_put_str(opts, "driver", "blkdebug"); - - qdict_put(opts, "image", qobject_ref(bs->file->bs->full_open_options)); - - for (e = qdict_first(options); e; e = qdict_next(options, e)) { - if (strcmp(qdict_entry_key(e), "x-image")) { - qdict_put_obj(opts, qdict_entry_key(e), - qobject_ref(qdict_entry_value(e))); - } + ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "blkdebug:%s:%s", + s->config_file ?: "", bs->file->bs->exact_filename); + if (ret >= sizeof(bs->exact_filename)) { + /* An overflow makes the filename unusable, so do not report any */ + bs->exact_filename[0] = 0; } - - bs->full_open_options = opts; } static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) @@ -888,6 +874,20 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, return 0; } +static const char *const blkdebug_strong_runtime_opts[] = { + "config", + "inject-error.", + "set-state.", + "align", + "max-transfer", + "opt-write-zero", + "max-write-zero", + "opt-discard", + "max-discard", + + NULL +}; + static BlockDriver bdrv_blkdebug = { .format_name = "blkdebug", .protocol_name = "blkdebug", @@ -917,6 +917,8 @@ static BlockDriver bdrv_blkdebug = { = blkdebug_debug_remove_breakpoint, .bdrv_debug_resume = blkdebug_debug_resume, .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, + + .strong_runtime_opts = blkdebug_strong_runtime_opts, }; static void bdrv_blkdebug_init(void) diff --git a/block/blklogwrites.c b/block/blklogwrites.c index d2e01bdb1d..eb2b4901a5 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -280,30 +280,6 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs) return bdrv_getlength(bs->file->bs); } -static void blk_log_writes_refresh_filename(BlockDriverState *bs, - QDict *options) -{ - BDRVBlkLogWritesState *s = bs->opaque; - - /* bs->file->bs has already been refreshed */ - bdrv_refresh_filename(s->log_file->bs); - - if (bs->file->bs->full_open_options - && s->log_file->bs->full_open_options) - { - QDict *opts = qdict_new(); - qdict_put_str(opts, "driver", "blklogwrites"); - - qobject_ref(bs->file->bs->full_open_options); - qdict_put(opts, "file", bs->file->bs->full_open_options); - qobject_ref(s->log_file->bs->full_open_options); - qdict_put(opts, "log", s->log_file->bs->full_open_options); - qdict_put_int(opts, "log-sector-size", s->sectorsize); - - bs->full_open_options = opts; - } -} - static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildRole *role, BlockReopenQueue *ro_q, @@ -520,6 +496,13 @@ blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) LOG_DISCARD_FLAG, false); } +static const char *const blk_log_writes_strong_runtime_opts[] = { + "log-append", + "log-sector-size", + + NULL +}; + static BlockDriver bdrv_blk_log_writes = { .format_name = "blklogwrites", .instance_size = sizeof(BDRVBlkLogWritesState), @@ -527,7 +510,6 @@ static BlockDriver bdrv_blk_log_writes = { .bdrv_open = blk_log_writes_open, .bdrv_close = blk_log_writes_close, .bdrv_getlength = blk_log_writes_getlength, - .bdrv_refresh_filename = blk_log_writes_refresh_filename, .bdrv_child_perm = blk_log_writes_child_perm, .bdrv_refresh_limits = blk_log_writes_refresh_limits, @@ -539,6 +521,7 @@ static BlockDriver bdrv_blk_log_writes = { .bdrv_co_block_status = bdrv_co_block_status_from_file, .is_filter = true, + .strong_runtime_opts = blk_log_writes_strong_runtime_opts, }; static void bdrv_blk_log_writes_init(void) diff --git a/block/blkverify.c b/block/blkverify.c index 89bf4386e3..3ff77ff49a 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -281,27 +281,10 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate); } -static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options) +static void blkverify_refresh_filename(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - /* bs->file->bs has already been refreshed */ - bdrv_refresh_filename(s->test_file->bs); - - if (bs->file->bs->full_open_options - && s->test_file->bs->full_open_options) - { - QDict *opts = qdict_new(); - qdict_put_str(opts, "driver", "blkverify"); - - qdict_put(opts, "raw", - qobject_ref(bs->file->bs->full_open_options)); - qdict_put(opts, "test", - qobject_ref(s->test_file->bs->full_open_options)); - - bs->full_open_options = opts; - } - if (bs->file->bs->exact_filename[0] && s->test_file->bs->exact_filename[0]) { @@ -316,6 +299,15 @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options) } } +static char *blkverify_dirname(BlockDriverState *bs, Error **errp) +{ + /* In general, there are two BDSs with different dirnames below this one; + * so there is no unique dirname we could return (unless both are equal by + * chance). Therefore, to be consistent, just always return NULL. */ + error_setg(errp, "Cannot generate a base directory for blkverify nodes"); + return NULL; +} + static BlockDriver bdrv_blkverify = { .format_name = "blkverify", .protocol_name = "blkverify", @@ -327,6 +319,7 @@ static BlockDriver bdrv_blkverify = { .bdrv_child_perm = bdrv_filter_default_perms, .bdrv_getlength = blkverify_getlength, .bdrv_refresh_filename = blkverify_refresh_filename, + .bdrv_dirname = blkverify_dirname, .bdrv_co_preadv = blkverify_co_preadv, .bdrv_co_pwritev = blkverify_co_pwritev, diff --git a/block/block-backend.c b/block/block-backend.c index f6ea824308..edad02a0f2 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1204,17 +1204,8 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, int64_t bytes, CoroutineEntry co_entry, BdrvRequestFlags flags) { - QEMUIOVector qiov; - struct iovec iov; - BlkRwCo rwco; - - iov = (struct iovec) { - .iov_base = buf, - .iov_len = bytes, - }; - qemu_iovec_init_external(&qiov, &iov, 1); - - rwco = (BlkRwCo) { + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); + BlkRwCo rwco = { .blk = blk, .offset = offset, .iobuf = &qiov, @@ -1262,12 +1253,12 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) return bdrv_make_zero(blk->root, flags); } -static void blk_inc_in_flight(BlockBackend *blk) +void blk_inc_in_flight(BlockBackend *blk) { atomic_inc(&blk->in_flight); } -static void blk_dec_in_flight(BlockBackend *blk) +void blk_dec_in_flight(BlockBackend *blk) { atomic_dec(&blk->in_flight); aio_wait_kick(); diff --git a/block/commit.c b/block/commit.c index 53148e610b..3b46ca7f97 100644 --- a/block/commit.c +++ b/block/commit.c @@ -47,14 +47,9 @@ static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base, void *buf) { int ret = 0; - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = buf, - .iov_len = bytes, - }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); assert(bytes < SIZE_MAX); - qemu_iovec_init_external(&qiov, &iov, 1); ret = blk_co_preadv(bs, offset, qiov.size, &qiov, 0); if (ret < 0) { @@ -230,9 +225,8 @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs, return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); } -static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *opts) +static void bdrv_commit_top_refresh_filename(BlockDriverState *bs) { - bdrv_refresh_filename(bs->backing->bs); pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), bs->backing->bs->filename); } @@ -374,10 +368,12 @@ fail: if (s->top) { blk_unref(s->top); } + job_early_fail(&s->common.job); + /* commit_top_bs has to be replaced after deleting the block job, + * otherwise this would fail because of lack of permissions. */ if (commit_top_bs) { bdrv_replace_node(commit_top_bs, top, &error_abort); } - job_early_fail(&s->common.job); } diff --git a/block/crypto.c b/block/crypto.c index d5b1da66a1..fd8c7cfac6 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -619,6 +619,12 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) return spec_info; } +static const char *const block_crypto_strong_runtime_opts[] = { + BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, + + NULL +}; + BlockDriver bdrv_crypto_luks = { .format_name = "luks", .instance_size = sizeof(BlockCrypto), @@ -640,6 +646,8 @@ BlockDriver bdrv_crypto_luks = { .bdrv_getlength = block_crypto_getlength, .bdrv_get_info = block_crypto_get_info_luks, .bdrv_get_specific_info = block_crypto_get_specific_info_luks, + + .strong_runtime_opts = block_crypto_strong_runtime_opts, }; static void block_crypto_init(void) diff --git a/block/curl.c b/block/curl.c index b7ac265d3a..606709fea4 100644 --- a/block/curl.c +++ b/block/curl.c @@ -61,8 +61,6 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle, #define CURL_NUM_STATES 8 #define CURL_NUM_ACB 8 -#define READ_AHEAD_DEFAULT (256 * 1024) -#define CURL_TIMEOUT_DEFAULT 5 #define CURL_TIMEOUT_MAX 10000 #define CURL_BLOCK_OPT_URL "url" @@ -76,6 +74,10 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle, #define CURL_BLOCK_OPT_PROXY_USERNAME "proxy-username" #define CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET "proxy-password-secret" +#define CURL_BLOCK_OPT_READAHEAD_DEFAULT (256 * 1024) +#define CURL_BLOCK_OPT_SSLVERIFY_DEFAULT true +#define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5 + struct BDRVCURLState; static bool libcurl_initialized; @@ -696,7 +698,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, } s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD, - READ_AHEAD_DEFAULT); + CURL_BLOCK_OPT_READAHEAD_DEFAULT); if ((s->readahead_size & 0x1ff) != 0) { error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512", s->readahead_size); @@ -704,13 +706,14 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, } s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT, - CURL_TIMEOUT_DEFAULT); + CURL_BLOCK_OPT_TIMEOUT_DEFAULT); if (s->timeout > CURL_TIMEOUT_MAX) { error_setg(errp, "timeout parameter is too large or negative"); goto out_noclean; } - s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true); + s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, + CURL_BLOCK_OPT_SSLVERIFY_DEFAULT); cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE); cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET); @@ -947,6 +950,36 @@ static int64_t curl_getlength(BlockDriverState *bs) return s->len; } +static void curl_refresh_filename(BlockDriverState *bs) +{ + BDRVCURLState *s = bs->opaque; + + /* "readahead" and "timeout" do not change the guest-visible data, + * so ignore them */ + if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT || + s->cookie || s->username || s->password || s->proxyusername || + s->proxypassword) + { + return; + } + + pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url); +} + + +static const char *const curl_strong_runtime_opts[] = { + CURL_BLOCK_OPT_URL, + CURL_BLOCK_OPT_SSLVERIFY, + CURL_BLOCK_OPT_COOKIE, + CURL_BLOCK_OPT_COOKIE_SECRET, + CURL_BLOCK_OPT_USERNAME, + CURL_BLOCK_OPT_PASSWORD_SECRET, + CURL_BLOCK_OPT_PROXY_USERNAME, + CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET, + + NULL +}; + static BlockDriver bdrv_http = { .format_name = "http", .protocol_name = "http", @@ -961,6 +994,9 @@ static BlockDriver bdrv_http = { .bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_attach_aio_context = curl_attach_aio_context, + + .bdrv_refresh_filename = curl_refresh_filename, + .strong_runtime_opts = curl_strong_runtime_opts, }; static BlockDriver bdrv_https = { @@ -977,6 +1013,9 @@ static BlockDriver bdrv_https = { .bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_attach_aio_context = curl_attach_aio_context, + + .bdrv_refresh_filename = curl_refresh_filename, + .strong_runtime_opts = curl_strong_runtime_opts, }; static BlockDriver bdrv_ftp = { @@ -993,6 +1032,9 @@ static BlockDriver bdrv_ftp = { .bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_attach_aio_context = curl_attach_aio_context, + + .bdrv_refresh_filename = curl_refresh_filename, + .strong_runtime_opts = curl_strong_runtime_opts, }; static BlockDriver bdrv_ftps = { @@ -1009,6 +1051,9 @@ static BlockDriver bdrv_ftps = { .bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_attach_aio_context = curl_attach_aio_context, + + .bdrv_refresh_filename = curl_refresh_filename, + .strong_runtime_opts = curl_strong_runtime_opts, }; static void curl_block_init(void) diff --git a/block/gluster.c b/block/gluster.c index 72891060e3..af64330211 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1495,6 +1495,21 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs, } +static const char *const gluster_strong_open_opts[] = { + GLUSTER_OPT_VOLUME, + GLUSTER_OPT_PATH, + GLUSTER_OPT_TYPE, + GLUSTER_OPT_SERVER_PATTERN, + GLUSTER_OPT_HOST, + GLUSTER_OPT_PORT, + GLUSTER_OPT_TO, + GLUSTER_OPT_IPV4, + GLUSTER_OPT_IPV6, + GLUSTER_OPT_SOCKET, + + NULL +}; + static BlockDriver bdrv_gluster = { .format_name = "gluster", .protocol_name = "gluster", @@ -1522,6 +1537,7 @@ static BlockDriver bdrv_gluster = { #endif .bdrv_co_block_status = qemu_gluster_co_block_status, .create_opts = &qemu_gluster_create_opts, + .strong_runtime_opts = gluster_strong_open_opts, }; static BlockDriver bdrv_gluster_tcp = { @@ -1551,6 +1567,7 @@ static BlockDriver bdrv_gluster_tcp = { #endif .bdrv_co_block_status = qemu_gluster_co_block_status, .create_opts = &qemu_gluster_create_opts, + .strong_runtime_opts = gluster_strong_open_opts, }; static BlockDriver bdrv_gluster_unix = { @@ -1580,6 +1597,7 @@ static BlockDriver bdrv_gluster_unix = { #endif .bdrv_co_block_status = qemu_gluster_co_block_status, .create_opts = &qemu_gluster_create_opts, + .strong_runtime_opts = gluster_strong_open_opts, }; /* rdma is deprecated (actually never supported for volfile fetch). @@ -1615,6 +1633,7 @@ static BlockDriver bdrv_gluster_rdma = { #endif .bdrv_co_block_status = qemu_gluster_co_block_status, .create_opts = &qemu_gluster_create_opts, + .strong_runtime_opts = gluster_strong_open_opts, }; static void bdrv_gluster_init(void) diff --git a/block/io.c b/block/io.c index 213ca03d8d..2ba603c7bc 100644 --- a/block/io.c +++ b/block/io.c @@ -843,17 +843,13 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset, static int bdrv_rw_co(BdrvChild *child, int64_t sector_num, uint8_t *buf, int nb_sectors, bool is_write, BdrvRequestFlags flags) { - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = (void *)buf, - .iov_len = nb_sectors * BDRV_SECTOR_SIZE, - }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, + nb_sectors * BDRV_SECTOR_SIZE); if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { return -EINVAL; } - qemu_iovec_init_external(&qiov, &iov, 1); return bdrv_prwv_co(child, sector_num << BDRV_SECTOR_BITS, &qiov, is_write, flags); } @@ -880,13 +876,8 @@ int bdrv_write(BdrvChild *child, int64_t sector_num, int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int bytes, BdrvRequestFlags flags) { - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = NULL, - .iov_len = bytes, - }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes); - qemu_iovec_init_external(&qiov, &iov, 1); return bdrv_prwv_co(child, offset, &qiov, true, BDRV_REQ_ZERO_WRITE | flags); } @@ -950,17 +941,12 @@ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov) int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes) { - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = (void *)buf, - .iov_len = bytes, - }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); if (bytes < 0) { return -EINVAL; } - qemu_iovec_init_external(&qiov, &iov, 1); return bdrv_preadv(child, offset, &qiov); } @@ -978,17 +964,12 @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov) int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes) { - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = (void *) buf, - .iov_len = bytes, - }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); if (bytes < 0) { return -EINVAL; } - qemu_iovec_init_external(&qiov, &iov, 1); return bdrv_pwritev(child, offset, &qiov); } @@ -1165,7 +1146,6 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, void *bounce_buffer; BlockDriver *drv = bs->drv; - struct iovec iov; QEMUIOVector local_qiov; int64_t cluster_offset; int64_t cluster_bytes; @@ -1230,9 +1210,8 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, if (ret <= 0) { /* Must copy-on-read; use the bounce buffer */ - iov.iov_base = bounce_buffer; - iov.iov_len = pnum = MIN(pnum, MAX_BOUNCE_BUFFER); - qemu_iovec_init_external(&local_qiov, &iov, 1); + pnum = MIN(pnum, MAX_BOUNCE_BUFFER); + qemu_iovec_init_buf(&local_qiov, bounce_buffer, pnum); ret = bdrv_driver_preadv(bs, cluster_offset, pnum, &local_qiov, 0); @@ -1477,7 +1456,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, { BlockDriver *drv = bs->drv; QEMUIOVector qiov; - struct iovec iov = {0}; + void *buf = NULL; int ret = 0; bool need_flush = false; int head = 0; @@ -1547,16 +1526,14 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, need_flush = true; } num = MIN(num, max_transfer); - iov.iov_len = num; - if (iov.iov_base == NULL) { - iov.iov_base = qemu_try_blockalign(bs, num); - if (iov.iov_base == NULL) { + if (buf == NULL) { + buf = qemu_try_blockalign0(bs, num); + if (buf == NULL) { ret = -ENOMEM; goto fail; } - memset(iov.iov_base, 0, num); } - qemu_iovec_init_external(&qiov, &iov, 1); + qemu_iovec_init_buf(&qiov, buf, num); ret = bdrv_driver_pwritev(bs, offset, num, &qiov, write_flags); @@ -1564,8 +1541,8 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, * all future requests. */ if (num < max_transfer) { - qemu_vfree(iov.iov_base); - iov.iov_base = NULL; + qemu_vfree(buf); + buf = NULL; } } @@ -1577,7 +1554,7 @@ fail: if (ret == 0 && need_flush) { ret = bdrv_co_flush(bs); } - qemu_vfree(iov.iov_base); + qemu_vfree(buf); return ret; } @@ -1763,7 +1740,6 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, BlockDriverState *bs = child->bs; uint8_t *buf = NULL; QEMUIOVector local_qiov; - struct iovec iov; uint64_t align = bs->bl.request_alignment; unsigned int head_padding_bytes, tail_padding_bytes; int ret = 0; @@ -1775,11 +1751,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, assert(flags & BDRV_REQ_ZERO_WRITE); if (head_padding_bytes || tail_padding_bytes) { buf = qemu_blockalign(bs, align); - iov = (struct iovec) { - .iov_base = buf, - .iov_len = align, - }; - qemu_iovec_init_external(&local_qiov, &iov, 1); + qemu_iovec_init_buf(&local_qiov, buf, align); } if (head_padding_bytes) { uint64_t zero_bytes = MIN(bytes, align - head_padding_bytes); @@ -1885,17 +1857,12 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, if (offset & (align - 1)) { QEMUIOVector head_qiov; - struct iovec head_iov; mark_request_serialising(&req, align); wait_serialising_requests(&req); head_buf = qemu_blockalign(bs, align); - head_iov = (struct iovec) { - .iov_base = head_buf, - .iov_len = align, - }; - qemu_iovec_init_external(&head_qiov, &head_iov, 1); + qemu_iovec_init_buf(&head_qiov, head_buf, align); bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); ret = bdrv_aligned_preadv(child, &req, offset & ~(align - 1), align, @@ -1924,7 +1891,6 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, if ((offset + bytes) & (align - 1)) { QEMUIOVector tail_qiov; - struct iovec tail_iov; size_t tail_bytes; bool waited; @@ -1933,11 +1899,7 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, assert(!waited || !use_local_qiov); tail_buf = qemu_blockalign(bs, align); - tail_iov = (struct iovec) { - .iov_base = tail_buf, - .iov_len = align, - }; - qemu_iovec_init_external(&tail_qiov, &tail_iov, 1); + qemu_iovec_init_buf(&tail_qiov, tail_buf, align); bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); ret = bdrv_aligned_preadv(child, &req, (offset + bytes) & ~(align - 1), @@ -2468,15 +2430,9 @@ bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos, int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, int64_t pos, int size) { - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = (void *) buf, - .iov_len = size, - }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size); int ret; - qemu_iovec_init_external(&qiov, &iov, 1); - ret = bdrv_writev_vmstate(bs, &qiov, pos); if (ret < 0) { return ret; @@ -2493,14 +2449,9 @@ int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size) { - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = buf, - .iov_len = size, - }; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size); int ret; - qemu_iovec_init_external(&qiov, &iov, 1); ret = bdrv_readv_vmstate(bs, &qiov, pos); if (ret < 0) { return ret; diff --git a/block/iscsi.c b/block/iscsi.c index ff473206e6..a0c0084837 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2448,6 +2448,20 @@ static QemuOptsList iscsi_create_opts = { } }; +static const char *const iscsi_strong_runtime_opts[] = { + "transport", + "portal", + "target", + "user", + "password", + "password-secret", + "lun", + "initiator-name", + "header-digest", + + NULL +}; + static BlockDriver bdrv_iscsi = { .format_name = "iscsi", .protocol_name = "iscsi", @@ -2482,6 +2496,8 @@ static BlockDriver bdrv_iscsi = { .bdrv_detach_aio_context = iscsi_detach_aio_context, .bdrv_attach_aio_context = iscsi_attach_aio_context, + + .strong_runtime_opts = iscsi_strong_runtime_opts, }; #if LIBISCSI_API_VERSION >= (20160603) @@ -2519,6 +2535,8 @@ static BlockDriver bdrv_iser = { .bdrv_detach_aio_context = iscsi_detach_aio_context, .bdrv_attach_aio_context = iscsi_attach_aio_context, + + .strong_runtime_opts = iscsi_strong_runtime_opts, }; #endif diff --git a/block/mirror.c b/block/mirror.c index b67b0120f8..726d3c27fb 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1431,14 +1431,13 @@ static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs, NULL, 0); } -static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts) +static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) { if (bs->backing == NULL) { /* we can be here after failed bdrv_attach_child in * bdrv_set_backing_hd */ return; } - bdrv_refresh_filename(bs->backing->bs); pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), bs->backing->bs->filename); } diff --git a/block/nbd-client.c b/block/nbd-client.c index f0ad54ce21..bfbaf7ebe9 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -76,8 +76,18 @@ static coroutine_fn void nbd_connection_entry(void *opaque) Error *local_err = NULL; while (!s->quit) { + /* + * The NBD client can only really be considered idle when it has + * yielded from qio_channel_readv_all_eof(), waiting for data. This is + * the point where the additional scheduled coroutine entry happens + * after nbd_client_attach_aio_context(). + * + * Therefore we keep an additional in_flight reference all the time and + * only drop it temporarily here. + */ assert(s->reply.handle == 0); - ret = nbd_receive_reply(s->ioc, &s->reply, &local_err); + ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, &local_err); + if (local_err) { trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err)); error_free(local_err); @@ -116,6 +126,8 @@ static coroutine_fn void nbd_connection_entry(void *opaque) s->quit = true; nbd_recv_coroutines_wake_all(s); + bdrv_dec_in_flight(s->bs); + s->connection_co = NULL; aio_wait_kick(); } @@ -965,12 +977,30 @@ void nbd_client_detach_aio_context(BlockDriverState *bs) qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc)); } +static void nbd_client_attach_aio_context_bh(void *opaque) +{ + BlockDriverState *bs = opaque; + NBDClientSession *client = nbd_get_client_session(bs); + + /* The node is still drained, so we know the coroutine has yielded in + * nbd_read_eof(), the only place where bs->in_flight can reach 0, or it is + * entered for the first time. Both places are safe for entering the + * coroutine.*/ + qemu_aio_coroutine_enter(bs->aio_context, client->connection_co); + bdrv_dec_in_flight(bs); +} + void nbd_client_attach_aio_context(BlockDriverState *bs, AioContext *new_context) { NBDClientSession *client = nbd_get_client_session(bs); qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc), new_context); - aio_co_schedule(new_context, client->connection_co); + + bdrv_inc_in_flight(bs); + + /* Need to wait here for the BH to run because the BH must run while the + * node is still drained. */ + aio_wait_bh_oneshot(new_context, nbd_client_attach_aio_context_bh, bs); } void nbd_client_close(BlockDriverState *bs) @@ -1076,6 +1106,7 @@ static int nbd_client_connect(BlockDriverState *bs, * kick the reply mechanism. */ qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL); client->connection_co = qemu_coroutine_create(nbd_connection_entry, client); + bdrv_inc_in_flight(bs); nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs)); logout("Established connection with NBD server\n"); @@ -1108,6 +1139,7 @@ int nbd_client_init(BlockDriverState *bs, { NBDClientSession *client = nbd_get_client_session(bs); + client->bs = bs; qemu_co_mutex_init(&client->send_mutex); qemu_co_queue_init(&client->free_sema); diff --git a/block/nbd-client.h b/block/nbd-client.h index d990207a5c..09e03013d2 100644 --- a/block/nbd-client.h +++ b/block/nbd-client.h @@ -35,6 +35,7 @@ typedef struct NBDClientSession { NBDClientRequest requests[MAX_NBD_REQUESTS]; NBDReply reply; + BlockDriverState *bs; bool quit; } NBDClientSession; diff --git a/block/nbd.c b/block/nbd.c index 9db5eded89..2e72df528a 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -477,12 +477,9 @@ static void nbd_attach_aio_context(BlockDriverState *bs, nbd_client_attach_aio_context(bs, new_context); } -static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) +static void nbd_refresh_filename(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; - QDict *opts = qdict_new(); - QObject *saddr_qdict; - Visitor *ov; const char *host = NULL, *port = NULL, *path = NULL; if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) { @@ -495,8 +492,6 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) path = s->saddr->u.q_unix.path; } /* else can't represent as pseudo-filename */ - qdict_put_str(opts, "driver", "nbd"); - if (path && s->export) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nbd+unix:///%s?socket=%s", s->export, path); @@ -510,23 +505,28 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nbd://%s:%s", host, port); } +} - ov = qobject_output_visitor_new(&saddr_qdict); - visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort); - visit_complete(ov, &saddr_qdict); - visit_free(ov); - qdict_put_obj(opts, "server", saddr_qdict); +static char *nbd_dirname(BlockDriverState *bs, Error **errp) +{ + /* The generic bdrv_dirname() implementation is able to work out some + * directory name for NBD nodes, but that would be wrong. So far there is no + * specification for how "export paths" would work, so NBD does not have + * directory names. */ + error_setg(errp, "Cannot generate a base directory for NBD nodes"); + return NULL; +} - if (s->export) { - qdict_put_str(opts, "export", s->export); - } - if (s->tlscredsid) { - qdict_put_str(opts, "tls-creds", s->tlscredsid); - } +static const char *const nbd_strong_runtime_opts[] = { + "path", + "host", + "port", + "export", + "tls-creds", + "server.", - qdict_flatten(opts); - bs->full_open_options = opts; -} + NULL +}; static BlockDriver bdrv_nbd = { .format_name = "nbd", @@ -546,6 +546,8 @@ static BlockDriver bdrv_nbd = { .bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, }; static BlockDriver bdrv_nbd_tcp = { @@ -566,6 +568,8 @@ static BlockDriver bdrv_nbd_tcp = { .bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, }; static BlockDriver bdrv_nbd_unix = { @@ -586,6 +590,8 @@ static BlockDriver bdrv_nbd_unix = { .bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, }; static void bdrv_nbd_init(void) diff --git a/block/nfs.c b/block/nfs.c index eab1a2c408..531903610b 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -799,14 +799,9 @@ static int nfs_reopen_prepare(BDRVReopenState *state, return 0; } -static void nfs_refresh_filename(BlockDriverState *bs, QDict *options) +static void nfs_refresh_filename(BlockDriverState *bs) { NFSClient *client = bs->opaque; - QDict *opts = qdict_new(); - QObject *server_qdict; - Visitor *ov; - - qdict_put_str(opts, "driver", "nfs"); if (client->uid && !client->gid) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), @@ -824,35 +819,20 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options) snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nfs://%s%s", client->server->host, client->path); } +} - ov = qobject_output_visitor_new(&server_qdict); - visit_type_NFSServer(ov, NULL, &client->server, &error_abort); - visit_complete(ov, &server_qdict); - qdict_put_obj(opts, "server", server_qdict); - qdict_put_str(opts, "path", client->path); +static char *nfs_dirname(BlockDriverState *bs, Error **errp) +{ + NFSClient *client = bs->opaque; - if (client->uid) { - qdict_put_int(opts, "user", client->uid); - } - if (client->gid) { - qdict_put_int(opts, "group", client->gid); - } - if (client->tcp_syncnt) { - qdict_put_int(opts, "tcp-syn-cnt", client->tcp_syncnt); - } - if (client->readahead) { - qdict_put_int(opts, "readahead-size", client->readahead); - } - if (client->pagecache) { - qdict_put_int(opts, "page-cache-size", client->pagecache); - } - if (client->debug) { - qdict_put_int(opts, "debug", client->debug); + if (client->uid || client->gid) { + bdrv_refresh_filename(bs); + error_setg(errp, "Cannot generate a base directory for NFS node '%s'", + bs->filename); + return NULL; } - visit_free(ov); - qdict_flatten(opts); - bs->full_open_options = opts; + return g_strdup_printf("nfs://%s%s/", client->server->host, client->path); } #ifdef LIBNFS_FEATURE_PAGECACHE @@ -864,6 +844,15 @@ static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs, } #endif +static const char *nfs_strong_runtime_opts[] = { + "path", + "user", + "group", + "server.", + + NULL +}; + static BlockDriver bdrv_nfs = { .format_name = "nfs", .protocol_name = "nfs", @@ -889,6 +878,9 @@ static BlockDriver bdrv_nfs = { .bdrv_detach_aio_context = nfs_detach_aio_context, .bdrv_attach_aio_context = nfs_attach_aio_context, .bdrv_refresh_filename = nfs_refresh_filename, + .bdrv_dirname = nfs_dirname, + + .strong_runtime_opts = nfs_strong_runtime_opts, #ifdef LIBNFS_FEATURE_PAGECACHE .bdrv_co_invalidate_cache = nfs_co_invalidate_cache, diff --git a/block/null.c b/block/null.c index d442d3e901..a322929478 100644 --- a/block/null.c +++ b/block/null.c @@ -239,19 +239,33 @@ static int coroutine_fn null_co_block_status(BlockDriverState *bs, return ret; } -static void null_refresh_filename(BlockDriverState *bs, QDict *opts) +static void null_refresh_filename(BlockDriverState *bs) { - qdict_del(opts, "filename"); - - if (!qdict_size(opts)) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", - bs->drv->format_name); + const QDictEntry *e; + + for (e = qdict_first(bs->full_open_options); e; + e = qdict_next(bs->full_open_options, e)) + { + /* These options can be ignored */ + if (strcmp(qdict_entry_key(e), "filename") && + strcmp(qdict_entry_key(e), "driver") && + strcmp(qdict_entry_key(e), NULL_OPT_LATENCY)) + { + return; + } } - qdict_put_str(opts, "driver", bs->drv->format_name); - bs->full_open_options = qobject_ref(opts); + snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", + bs->drv->format_name); } +static const char *const null_strong_runtime_opts[] = { + BLOCK_OPT_SIZE, + NULL_OPT_ZEROES, + + NULL +}; + static BlockDriver bdrv_null_co = { .format_name = "null-co", .protocol_name = "null-co", @@ -269,6 +283,7 @@ static BlockDriver bdrv_null_co = { .bdrv_co_block_status = null_co_block_status, .bdrv_refresh_filename = null_refresh_filename, + .strong_runtime_opts = null_strong_runtime_opts, }; static BlockDriver bdrv_null_aio = { @@ -288,6 +303,7 @@ static BlockDriver bdrv_null_aio = { .bdrv_co_block_status = null_co_block_status, .bdrv_refresh_filename = null_refresh_filename, + .strong_runtime_opts = null_strong_runtime_opts, }; static void bdrv_null_init(void) diff --git a/block/nvme.c b/block/nvme.c index b5952c9b08..0684bbd077 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -82,7 +82,7 @@ typedef volatile struct { uint8_t reserved1[0xec0]; uint8_t cmd_set_specfic[0x100]; uint32_t doorbells[]; -} QEMU_PACKED NVMeRegs; +} NVMeRegs; QEMU_BUILD_BUG_ON(offsetof(NVMeRegs, doorbells) != 0x1000); @@ -111,6 +111,9 @@ typedef struct { /* Total size of mapped qiov, accessed under dma_map_lock */ int dma_map_count; + + /* PCI address (required for nvme_refresh_filename()) */ + char *device; } BDRVNVMeState; #define NVME_BLOCK_OPT_DEVICE "device" @@ -557,6 +560,7 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, qemu_co_mutex_init(&s->dma_map_lock); qemu_co_queue_init(&s->dma_flush_queue); + s->device = g_strdup(device); s->nsid = namespace; s->aio_context = bdrv_get_aio_context(bs); ret = event_notifier_init(&s->irq_notifier, 0); @@ -729,6 +733,8 @@ static void nvme_close(BlockDriverState *bs) event_notifier_cleanup(&s->irq_notifier); qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE); qemu_vfio_close(s->vfio); + + g_free(s->device); } static int nvme_file_open(BlockDriverState *bs, QDict *options, int flags, @@ -1053,17 +1059,12 @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state, return 0; } -static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts) +static void nvme_refresh_filename(BlockDriverState *bs) { - qdict_del(opts, "filename"); - - if (!qdict_size(opts)) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", - bs->drv->format_name); - } + BDRVNVMeState *s = bs->opaque; - qdict_put_str(opts, "driver", bs->drv->format_name); - bs->full_open_options = qobject_ref(opts); + snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nvme://%s/%i", + s->device, s->nsid); } static void nvme_refresh_limits(BlockDriverState *bs, Error **errp) @@ -1136,6 +1137,13 @@ static void nvme_unregister_buf(BlockDriverState *bs, void *host) qemu_vfio_dma_unmap(s->vfio, host); } +static const char *const nvme_strong_runtime_opts[] = { + NVME_BLOCK_OPT_DEVICE, + NVME_BLOCK_OPT_NAMESPACE, + + NULL +}; + static BlockDriver bdrv_nvme = { .format_name = "nvme", .protocol_name = "nvme", @@ -1153,6 +1161,7 @@ static BlockDriver bdrv_nvme = { .bdrv_refresh_filename = nvme_refresh_filename, .bdrv_refresh_limits = nvme_refresh_limits, + .strong_runtime_opts = nvme_strong_runtime_opts, .bdrv_detach_aio_context = nvme_detach_aio_context, .bdrv_attach_aio_context = nvme_attach_aio_context, diff --git a/block/parallels.c b/block/parallels.c index cc9445879d..15bc97b759 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -220,23 +220,20 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, if (bs->backing) { int64_t nb_cow_sectors = to_allocate * s->tracks; int64_t nb_cow_bytes = nb_cow_sectors << BDRV_SECTOR_BITS; - QEMUIOVector qiov; - struct iovec iov = { - .iov_len = nb_cow_bytes, - .iov_base = qemu_blockalign(bs, nb_cow_bytes) - }; - qemu_iovec_init_external(&qiov, &iov, 1); + QEMUIOVector qiov = + QEMU_IOVEC_INIT_BUF(qiov, qemu_blockalign(bs, nb_cow_bytes), + nb_cow_bytes); ret = bdrv_co_preadv(bs->backing, idx * s->tracks * BDRV_SECTOR_SIZE, nb_cow_bytes, &qiov, 0); if (ret < 0) { - qemu_vfree(iov.iov_base); + qemu_vfree(qemu_iovec_buf(&qiov)); return ret; } ret = bdrv_co_pwritev(bs->file, s->data_end * BDRV_SECTOR_SIZE, nb_cow_bytes, &qiov, 0); - qemu_vfree(iov.iov_base); + qemu_vfree(qemu_iovec_buf(&qiov)); if (ret < 0) { return ret; } diff --git a/block/qapi.c b/block/qapi.c index 00291f9105..6002a768f8 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -51,6 +51,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, return NULL; } + bdrv_refresh_filename(bs); + info = g_malloc0(sizeof(*info)); info->file = g_strdup(bs->filename); info->ro = bs->read_only; @@ -264,6 +266,8 @@ void bdrv_query_image_info(BlockDriverState *bs, goto out; } + bdrv_refresh_filename(bs); + info = g_new0(ImageInfo, 1); info->filename = g_strdup(bs->filename); info->format = g_strdup(bdrv_get_format_name(bs)); @@ -292,18 +296,10 @@ void bdrv_query_image_info(BlockDriverState *bs, backing_filename = bs->backing_file; if (backing_filename[0] != '\0') { - char *backing_filename2 = g_malloc0(PATH_MAX); + char *backing_filename2; info->backing_filename = g_strdup(backing_filename); info->has_backing_filename = true; - bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err); - if (err) { - /* Can't reconstruct the full backing filename, so we must omit - * this field and apply a Best Effort to this query. */ - g_free(backing_filename2); - backing_filename2 = NULL; - error_free(err); - err = NULL; - } + backing_filename2 = bdrv_get_full_backing_filename(bs, NULL); /* Always report the full_backing_filename if present, even if it's the * same as backing_filename. That they are same is useful info. */ diff --git a/block/qcow.c b/block/qcow.c index 0a235bf393..10d2cf14b3 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -31,6 +31,7 @@ #include "qemu/module.h" #include "qemu/option.h" #include "qemu/bswap.h" +#include "qemu/cutils.h" #include <zlib.h> #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" @@ -295,11 +296,13 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } ret = bdrv_pread(bs->file, header.backing_file_offset, - bs->backing_file, len); + bs->auto_backing_file, len); if (ret < 0) { goto fail; } - bs->backing_file[len] = '\0'; + bs->auto_backing_file[len] = '\0'; + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->auto_backing_file); } /* Disable migration when qcow images are used */ @@ -628,7 +631,6 @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset, int offset_in_cluster; int ret = 0, n; uint64_t cluster_offset; - struct iovec hd_iov; QEMUIOVector hd_qiov; uint8_t *buf; void *orig_buf; @@ -661,9 +663,7 @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset, if (!cluster_offset) { if (bs->backing) { /* read from the base image */ - hd_iov.iov_base = (void *)buf; - hd_iov.iov_len = n; - qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); + qemu_iovec_init_buf(&hd_qiov, buf, n); qemu_co_mutex_unlock(&s->lock); /* qcow2 emits this on bs->file instead of bs->backing */ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); @@ -688,9 +688,7 @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset, ret = -EIO; break; } - hd_iov.iov_base = (void *)buf; - hd_iov.iov_len = n; - qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); + qemu_iovec_init_buf(&hd_qiov, buf, n); qemu_co_mutex_unlock(&s->lock); BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); ret = bdrv_co_preadv(bs->file, cluster_offset + offset_in_cluster, @@ -733,7 +731,6 @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, uint64_t offset, int offset_in_cluster; uint64_t cluster_offset; int ret = 0, n; - struct iovec hd_iov; QEMUIOVector hd_qiov; uint8_t *buf; void *orig_buf; @@ -779,9 +776,7 @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, uint64_t offset, } } - hd_iov.iov_base = (void *)buf; - hd_iov.iov_len = n; - qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); + qemu_iovec_init_buf(&hd_qiov, buf, n); qemu_co_mutex_unlock(&s->lock); BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster, @@ -1062,7 +1057,6 @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, { BDRVQcowState *s = bs->opaque; QEMUIOVector hd_qiov; - struct iovec iov; z_stream strm; int ret, out_len; uint8_t *buf, *out_buf; @@ -1128,11 +1122,7 @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, } cluster_offset &= s->cluster_offset_mask; - iov = (struct iovec) { - .iov_base = out_buf, - .iov_len = out_len, - }; - qemu_iovec_init_external(&hd_qiov, &iov, 1); + qemu_iovec_init_buf(&hd_qiov, out_buf, out_len); BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0); if (ret < 0) { @@ -1183,6 +1173,12 @@ static QemuOptsList qcow_create_opts = { } }; +static const char *const qcow_strong_runtime_opts[] = { + "encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET, + + NULL +}; + static BlockDriver bdrv_qcow = { .format_name = "qcow", .instance_size = sizeof(BDRVQcowState), @@ -1206,6 +1202,7 @@ static BlockDriver bdrv_qcow = { .bdrv_get_info = qcow_get_info, .create_opts = &qcow_create_opts, + .strong_runtime_opts = qcow_strong_runtime_opts, }; static void bdrv_qcow_init(void) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 30eca26c47..179aa2c728 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -285,6 +285,9 @@ static int l2_allocate(BlockDriverState *bs, int l1_index) goto fail; } + /* The offset must fit in the offset field of the L1 table entry */ + assert((l2_offset & L1E_OFFSET_MASK) == l2_offset); + /* If we're allocating the table at offset 0 then something is wrong */ if (l2_offset == 0) { qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid " diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index bb6a5b7516..20e8472191 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -358,11 +358,6 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) /* Generate an ID */ find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str)); - /* Check that the ID is unique */ - if (find_snapshot_by_id_and_name(bs, sn_info->id_str, NULL) >= 0) { - return -EEXIST; - } - /* Populate sn with passed data */ sn->id_str = g_strdup(sn_info->id_str); sn->name = g_strdup(sn_info->name); diff --git a/block/qcow2.c b/block/qcow2.c index 65a54c9ac6..7fb2730f09 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1474,13 +1474,15 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, goto fail; } ret = bdrv_pread(bs->file, header.backing_file_offset, - bs->backing_file, len); + bs->auto_backing_file, len); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read backing file name"); goto fail; } - bs->backing_file[len] = '\0'; - s->image_backing_file = g_strdup(bs->backing_file); + bs->auto_backing_file[len] = '\0'; + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->auto_backing_file); + s->image_backing_file = g_strdup(bs->auto_backing_file); } /* Internal snapshots */ @@ -2518,6 +2520,8 @@ static int qcow2_change_backing_file(BlockDriverState *bs, return -EINVAL; } + pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file), + backing_file ?: ""); pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: ""); pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: ""); @@ -3894,7 +3898,6 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, { BDRVQcow2State *s = bs->opaque; QEMUIOVector hd_qiov; - struct iovec iov; int ret; size_t out_len; uint8_t *buf, *out_buf; @@ -3960,11 +3963,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, goto fail; } - iov = (struct iovec) { - .iov_base = out_buf, - .iov_len = out_len, - }; - qemu_iovec_init_external(&hd_qiov, &iov, 1); + qemu_iovec_init_buf(&hd_qiov, out_buf, out_len); BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0); @@ -3990,7 +3989,6 @@ qcow2_co_preadv_compressed(BlockDriverState *bs, int ret = 0, csize, nb_csectors; uint64_t coffset; uint8_t *buf, *out_buf; - struct iovec iov; QEMUIOVector local_qiov; int offset_in_cluster = offset_into_cluster(s, offset); @@ -4002,9 +4000,7 @@ qcow2_co_preadv_compressed(BlockDriverState *bs, if (!buf) { return -ENOMEM; } - iov.iov_base = buf; - iov.iov_len = csize; - qemu_iovec_init_external(&local_qiov, &iov, 1); + qemu_iovec_init_buf(&local_qiov, buf, csize); out_buf = qemu_blockalign(bs, s->cluster_size); @@ -4232,6 +4228,60 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs) return ret; } +static ssize_t qcow2_measure_crypto_hdr_init_func(QCryptoBlock *block, + size_t headerlen, void *opaque, Error **errp) +{ + size_t *headerlenp = opaque; + + /* Stash away the payload size */ + *headerlenp = headerlen; + return 0; +} + +static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block, + size_t offset, const uint8_t *buf, size_t buflen, + void *opaque, Error **errp) +{ + /* Discard the bytes, we're not actually writing to an image */ + return buflen; +} + +/* Determine the number of bytes for the LUKS payload */ +static bool qcow2_measure_luks_headerlen(QemuOpts *opts, size_t *len, + Error **errp) +{ + QDict *opts_qdict; + QDict *cryptoopts_qdict; + QCryptoBlockCreateOptions *cryptoopts; + QCryptoBlock *crypto; + + /* Extract "encrypt." options into a qdict */ + opts_qdict = qemu_opts_to_qdict(opts, NULL); + qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt."); + qobject_unref(opts_qdict); + + /* Build QCryptoBlockCreateOptions object from qdict */ + qdict_put_str(cryptoopts_qdict, "format", "luks"); + cryptoopts = block_crypto_create_opts_init(cryptoopts_qdict, errp); + qobject_unref(cryptoopts_qdict); + if (!cryptoopts) { + return false; + } + + /* Fake LUKS creation in order to determine the payload size */ + crypto = qcrypto_block_create(cryptoopts, "encrypt.", + qcow2_measure_crypto_hdr_init_func, + qcow2_measure_crypto_hdr_write_func, + len, errp); + qapi_free_QCryptoBlockCreateOptions(cryptoopts); + if (!crypto) { + return false; + } + + qcrypto_block_free(crypto); + return true; +} + static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, Error **errp) { @@ -4241,11 +4291,13 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, uint64_t virtual_size; /* disk size as seen by guest */ uint64_t refcount_bits; uint64_t l2_tables; + uint64_t luks_payload_size = 0; size_t cluster_size; int version; char *optstr; PreallocMode prealloc; bool has_backing_file; + bool has_luks; /* Parse image creation options */ cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err); @@ -4275,6 +4327,20 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, has_backing_file = !!optstr; g_free(optstr); + optstr = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT); + has_luks = optstr && strcmp(optstr, "luks") == 0; + g_free(optstr); + + if (has_luks) { + size_t headerlen; + + if (!qcow2_measure_luks_headerlen(opts, &headerlen, &local_err)) { + goto err; + } + + luks_payload_size = ROUND_UP(headerlen, cluster_size); + } + virtual_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); virtual_size = ROUND_UP(virtual_size, cluster_size); @@ -4345,7 +4411,7 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, info = g_new(BlockMeasureInfo, 1); info->fully_allocated = qcow2_calc_prealloc_size(virtual_size, cluster_size, - ctz32(refcount_bits)); + ctz32(refcount_bits)) + luks_payload_size; /* Remove data clusters that are not required. This overestimates the * required size because metadata needed for the fully allocated file is @@ -4932,6 +4998,12 @@ static QemuOptsList qcow2_create_opts = { } }; +static const char *const qcow2_strong_runtime_opts[] = { + "encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET, + + NULL +}; + BlockDriver bdrv_qcow2 = { .format_name = "qcow2", .instance_size = sizeof(BDRVQcow2State), @@ -4980,6 +5052,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_inactivate = qcow2_inactivate, .create_opts = &qcow2_create_opts, + .strong_runtime_opts = qcow2_strong_runtime_opts, .bdrv_co_check = qcow2_co_check, .bdrv_amend_options = qcow2_amend_options, diff --git a/block/qed-table.c b/block/qed-table.c index 7df5680adb..c497bd4aec 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -21,16 +21,11 @@ /* Called with table_lock held. */ static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table) { - QEMUIOVector qiov; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF( + qiov, table->offsets, s->header.cluster_size * s->header.table_size); int noffsets; int i, ret; - struct iovec iov = { - .iov_base = table->offsets, - .iov_len = s->header.cluster_size * s->header.table_size, - }; - qemu_iovec_init_external(&qiov, &iov, 1); - trace_qed_read_table(s, offset, table); qemu_co_mutex_unlock(&s->table_lock); @@ -71,7 +66,6 @@ static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table, unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1; unsigned int start, end, i; QEDTable *new_table; - struct iovec iov; QEMUIOVector qiov; size_t len_bytes; int ret; @@ -85,11 +79,7 @@ static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table, len_bytes = (end - start) * sizeof(uint64_t); new_table = qemu_blockalign(s->bs, len_bytes); - iov = (struct iovec) { - .iov_base = new_table->offsets, - .iov_len = len_bytes, - }; - qemu_iovec_init_external(&qiov, &iov, 1); + qemu_iovec_init_buf(&qiov, new_table->offsets, len_bytes); /* Byteswap table */ for (i = start; i < end; i++) { diff --git a/block/qed.c b/block/qed.c index 1280870024..89af05d524 100644 --- a/block/qed.c +++ b/block/qed.c @@ -113,18 +113,13 @@ static int coroutine_fn qed_write_header(BDRVQEDState *s) int nsectors = DIV_ROUND_UP(sizeof(QEDHeader), BDRV_SECTOR_SIZE); size_t len = nsectors * BDRV_SECTOR_SIZE; uint8_t *buf; - struct iovec iov; QEMUIOVector qiov; int ret; assert(s->allocating_acb || s->allocating_write_reqs_plugged); buf = qemu_blockalign(s->bs, len); - iov = (struct iovec) { - .iov_base = buf, - .iov_len = len, - }; - qemu_iovec_init_external(&qiov, &iov, 1); + qemu_iovec_init_buf(&qiov, buf, len); ret = bdrv_co_preadv(s->bs->file, 0, qiov.size, &qiov, 0); if (ret < 0) { @@ -454,11 +449,14 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, } ret = qed_read_string(bs->file, s->header.backing_filename_offset, - s->header.backing_filename_size, bs->backing_file, - sizeof(bs->backing_file)); + s->header.backing_filename_size, + bs->auto_backing_file, + sizeof(bs->auto_backing_file)); if (ret < 0) { return ret; } + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->auto_backing_file); if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) { pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw"); @@ -913,7 +911,6 @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s, { QEMUIOVector qiov; QEMUIOVector *backing_qiov = NULL; - struct iovec iov; int ret; /* Skip copy entirely if there is no work to do */ @@ -921,11 +918,7 @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s, return 0; } - iov = (struct iovec) { - .iov_base = qemu_blockalign(s->bs, len), - .iov_len = len, - }; - qemu_iovec_init_external(&qiov, &iov, 1); + qemu_iovec_init_buf(&qiov, qemu_blockalign(s->bs, len), len); ret = qed_read_backing_file(s, pos, &qiov, &backing_qiov); @@ -946,7 +939,7 @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s, } ret = 0; out: - qemu_vfree(iov.iov_base); + qemu_vfree(qemu_iovec_buf(&qiov)); return ret; } @@ -1447,8 +1440,12 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, BdrvRequestFlags flags) { BDRVQEDState *s = bs->opaque; - QEMUIOVector qiov; - struct iovec iov; + + /* + * Zero writes start without an I/O buffer. If a buffer becomes necessary + * then it will be allocated during request processing. + */ + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes); /* Fall back if the request is not aligned */ if (qed_offset_into_cluster(s, offset) || @@ -1456,13 +1453,6 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, return -ENOTSUP; } - /* Zero writes start without an I/O buffer. If a buffer becomes necessary - * then it will be allocated during request processing. - */ - iov.iov_base = NULL; - iov.iov_len = bytes; - - qemu_iovec_init_external(&qiov, &iov, 1); return qed_co_request(bs, offset >> BDRV_SECTOR_BITS, &qiov, bytes >> BDRV_SECTOR_BITS, QED_AIOCB_WRITE | QED_AIOCB_ZERO); diff --git a/block/quorum.c b/block/quorum.c index 16b3c8067c..352f729136 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -1065,36 +1065,64 @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child, bdrv_drained_end(bs); } -static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) +static void quorum_gather_child_options(BlockDriverState *bs, QDict *target, + bool backing_overridden) { BDRVQuorumState *s = bs->opaque; - QDict *opts; - QList *children; + QList *children_list; int i; - for (i = 0; i < s->num_children; i++) { - bdrv_refresh_filename(s->children[i]->bs); - if (!s->children[i]->bs->full_open_options) { - return; - } - } + /* + * The generic implementation for gathering child options in + * bdrv_refresh_filename() would use the names of the children + * as specified for bdrv_open_child() or bdrv_attach_child(), + * which is "children.%u" with %u being a value + * (s->next_child_index) that is incremented each time a new child + * is added (and never decremented). Since children can be + * deleted at runtime, there may be gaps in that enumeration. + * When creating a new quorum BDS and specifying the children for + * it through runtime options, the enumeration used there may not + * have any gaps, though. + * + * Therefore, we have to create a new gap-less enumeration here + * (which we can achieve by simply putting all of the children's + * full_open_options into a QList). + * + * XXX: Note that there are issues with the current child option + * structure quorum uses (such as the fact that children do + * not really have unique permanent names). Therefore, this + * is going to have to change in the future and ideally we + * want quorum to be covered by the generic implementation. + */ + + children_list = qlist_new(); + qdict_put(target, "children", children_list); - children = qlist_new(); for (i = 0; i < s->num_children; i++) { - qlist_append(children, + qlist_append(children_list, qobject_ref(s->children[i]->bs->full_open_options)); } +} - opts = qdict_new(); - qdict_put_str(opts, "driver", "quorum"); - qdict_put_int(opts, QUORUM_OPT_VOTE_THRESHOLD, s->threshold); - qdict_put_bool(opts, QUORUM_OPT_BLKVERIFY, s->is_blkverify); - qdict_put_bool(opts, QUORUM_OPT_REWRITE, s->rewrite_corrupted); - qdict_put(opts, "children", children); - - bs->full_open_options = opts; +static char *quorum_dirname(BlockDriverState *bs, Error **errp) +{ + /* In general, there are multiple BDSs with different dirnames below this + * one; so there is no unique dirname we could return (unless all are equal + * by chance, or there is only one). Therefore, to be consistent, just + * always return NULL. */ + error_setg(errp, "Cannot generate a base directory for quorum nodes"); + return NULL; } +static const char *const quorum_strong_runtime_opts[] = { + QUORUM_OPT_VOTE_THRESHOLD, + QUORUM_OPT_BLKVERIFY, + QUORUM_OPT_REWRITE, + QUORUM_OPT_READ_PATTERN, + + NULL +}; + static BlockDriver bdrv_quorum = { .format_name = "quorum", @@ -1102,7 +1130,8 @@ static BlockDriver bdrv_quorum = { .bdrv_open = quorum_open, .bdrv_close = quorum_close, - .bdrv_refresh_filename = quorum_refresh_filename, + .bdrv_gather_child_options = quorum_gather_child_options, + .bdrv_dirname = quorum_dirname, .bdrv_co_flush_to_disk = quorum_co_flush, @@ -1118,6 +1147,8 @@ static BlockDriver bdrv_quorum = { .is_filter = true, .bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter, + + .strong_runtime_opts = quorum_strong_runtime_opts, }; static void bdrv_quorum_init(void) diff --git a/block/raw-format.c b/block/raw-format.c index 6f6dc99b2c..e3e5ba2c8a 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -436,6 +436,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, bs->file->bs->supported_zero_flags); if (bs->probed && !bdrv_is_read_only(bs)) { + bdrv_refresh_filename(bs->file->bs); fprintf(stderr, "WARNING: Image format was not specified for '%s' and probing " "guessed raw.\n" @@ -531,6 +532,13 @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, read_flags, write_flags); } +static const char *const raw_strong_runtime_opts[] = { + "offset", + "size", + + NULL +}; + BlockDriver bdrv_raw = { .format_name = "raw", .instance_size = sizeof(BDRVRawState), @@ -560,7 +568,8 @@ BlockDriver bdrv_raw = { .bdrv_lock_medium = &raw_lock_medium, .bdrv_co_ioctl = &raw_co_ioctl, .create_opts = &raw_create_opts, - .bdrv_has_zero_init = &raw_has_zero_init + .bdrv_has_zero_init = &raw_has_zero_init, + .strong_runtime_opts = raw_strong_runtime_opts, }; static void bdrv_raw_init(void) diff --git a/block/rbd.c b/block/rbd.c index 8a1a9f4b6e..0c549c9935 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1228,6 +1228,18 @@ static QemuOptsList qemu_rbd_create_opts = { } }; +static const char *const qemu_rbd_strong_runtime_opts[] = { + "pool", + "image", + "conf", + "snapshot", + "user", + "server.", + "password-secret", + + NULL +}; + static BlockDriver bdrv_rbd = { .format_name = "rbd", .instance_size = sizeof(BDRVRBDState), @@ -1265,6 +1277,8 @@ static BlockDriver bdrv_rbd = { #ifdef LIBRBD_SUPPORTS_INVALIDATE .bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache, #endif + + .strong_runtime_opts = qemu_rbd_strong_runtime_opts, }; static void bdrv_rbd_init(void) diff --git a/block/replication.c b/block/replication.c index e70dd95001..4c80b54daf 100644 --- a/block/replication.c +++ b/block/replication.c @@ -616,8 +616,6 @@ static void replication_done(void *opaque, int ret) if (ret == 0) { s->stage = BLOCK_REPLICATION_DONE; - /* refresh top bs's filename */ - bdrv_refresh_filename(bs); s->active_disk = NULL; s->secondary_disk = NULL; s->hidden_disk = NULL; @@ -678,6 +676,13 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) aio_context_release(aio_context); } +static const char *const replication_strong_runtime_opts[] = { + REPLICATION_MODE, + REPLICATION_TOP_ID, + + NULL +}; + BlockDriver bdrv_replication = { .format_name = "replication", .instance_size = sizeof(BDRVReplicationState), @@ -694,6 +699,7 @@ BlockDriver bdrv_replication = { .bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter, .has_variable_length = true, + .strong_runtime_opts = replication_strong_runtime_opts, }; static void bdrv_replication_init(void) diff --git a/block/sheepdog.c b/block/sheepdog.c index b916ba07bf..cbdfe9ab6e 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -3203,6 +3203,15 @@ static QemuOptsList sd_create_opts = { } }; +static const char *const sd_strong_runtime_opts[] = { + "vdi", + "snap-id", + "tag", + "server.", + + NULL +}; + static BlockDriver bdrv_sheepdog = { .format_name = "sheepdog", .protocol_name = "sheepdog", @@ -3238,6 +3247,7 @@ static BlockDriver bdrv_sheepdog = { .bdrv_attach_aio_context = sd_attach_aio_context, .create_opts = &sd_create_opts, + .strong_runtime_opts = sd_strong_runtime_opts, }; static BlockDriver bdrv_sheepdog_tcp = { @@ -3275,6 +3285,7 @@ static BlockDriver bdrv_sheepdog_tcp = { .bdrv_attach_aio_context = sd_attach_aio_context, .create_opts = &sd_create_opts, + .strong_runtime_opts = sd_strong_runtime_opts, }; static BlockDriver bdrv_sheepdog_unix = { @@ -3312,6 +3323,7 @@ static BlockDriver bdrv_sheepdog_unix = { .bdrv_attach_aio_context = sd_attach_aio_context, .create_opts = &sd_create_opts, + .strong_runtime_opts = sd_strong_runtime_opts, }; static void bdrv_sheepdog_init(void) diff --git a/block/snapshot.c b/block/snapshot.c index 3218a542df..f2f48f926a 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -63,7 +63,7 @@ int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, } for (i = 0; i < nb_sns; i++) { sn = &sn_tab[i]; - if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { + if (!strcmp(sn->name, name)) { *sn_info = *sn; ret = 0; break; @@ -301,26 +301,6 @@ int bdrv_snapshot_delete(BlockDriverState *bs, return ret; } -int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs, - const char *id_or_name, - Error **errp) -{ - int ret; - Error *local_err = NULL; - - ret = bdrv_snapshot_delete(bs, id_or_name, NULL, &local_err); - if (ret == -ENOENT || ret == -EINVAL) { - error_free(local_err); - local_err = NULL; - ret = bdrv_snapshot_delete(bs, NULL, id_or_name, &local_err); - } - - if (ret < 0) { - error_propagate(errp, local_err); - } - return ret; -} - int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info) { @@ -448,7 +428,8 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs, aio_context_acquire(ctx); if (bdrv_can_snapshot(bs) && bdrv_snapshot_find(bs, snapshot, name) >= 0) { - ret = bdrv_snapshot_delete_by_id_or_name(bs, name, err); + ret = bdrv_snapshot_delete(bs, snapshot->id_str, + snapshot->name, err); } aio_context_release(ctx); if (ret < 0) { diff --git a/block/ssh.c b/block/ssh.c index bbc513e095..190ef95300 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -1254,6 +1254,17 @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset, return ssh_grow_file(s, offset, errp); } +static const char *const ssh_strong_runtime_opts[] = { + "host", + "port", + "path", + "user", + "host_key_check", + "server.", + + NULL +}; + static BlockDriver bdrv_ssh = { .format_name = "ssh", .protocol_name = "ssh", @@ -1270,6 +1281,7 @@ static BlockDriver bdrv_ssh = { .bdrv_co_truncate = ssh_co_truncate, .bdrv_co_flush_to_disk = ssh_co_flush, .create_opts = &ssh_create_opts, + .strong_runtime_opts = ssh_strong_runtime_opts, }; static void bdrv_ssh_init(void) diff --git a/block/stream.c b/block/stream.c index 7a49ac0992..e14579ff80 100644 --- a/block/stream.c +++ b/block/stream.c @@ -41,14 +41,9 @@ static int coroutine_fn stream_populate(BlockBackend *blk, int64_t offset, uint64_t bytes, void *buf) { - struct iovec iov = { - .iov_base = buf, - .iov_len = bytes, - }; - QEMUIOVector qiov; + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); assert(bytes < SIZE_MAX); - qemu_iovec_init_external(&qiov, &iov, 1); /* Copy-on-read the unallocated clusters */ return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ); diff --git a/block/throttle.c b/block/throttle.c index 636c9764aa..f64dcc27b9 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -227,6 +227,12 @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs) atomic_dec(&tgm->io_limits_disabled); } +static const char *const throttle_strong_runtime_opts[] = { + QEMU_OPT_THROTTLE_GROUP_NAME, + + NULL +}; + static BlockDriver bdrv_throttle = { .format_name = "throttle", .instance_size = sizeof(ThrottleGroupMember), @@ -259,6 +265,7 @@ static BlockDriver bdrv_throttle = { .bdrv_co_drain_end = throttle_co_drain_end, .is_filter = true, + .strong_runtime_opts = throttle_strong_runtime_opts, }; static void bdrv_throttle_init(void) diff --git a/block/vhdx-log.c b/block/vhdx-log.c index ecd64266c5..3149ff08d8 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -803,6 +803,7 @@ int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed, if (logs.valid) { if (bs->read_only) { + bdrv_refresh_filename(bs); ret = -EPERM; error_setg(errp, "VHDX image file '%s' opened read-only, but " diff --git a/block/vmdk.c b/block/vmdk.c index 096e8eb662..d8c0c50390 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -27,6 +27,7 @@ #include "qapi/error.h" #include "block/block_int.h" #include "sysemu/block-backend.h" +#include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qemu/error-report.h" #include "qemu/module.h" @@ -386,12 +387,14 @@ static int vmdk_parent_open(BlockDriverState *bs) ret = -EINVAL; goto out; } - if ((end_name - p_name) > sizeof(bs->backing_file) - 1) { + if ((end_name - p_name) > sizeof(bs->auto_backing_file) - 1) { ret = -EINVAL; goto out; } - pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); + pstrcpy(bs->auto_backing_file, end_name - p_name + 1, p_name); + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->auto_backing_file); } out: @@ -479,6 +482,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, extent->l1_table, l1_size); if (ret < 0) { + bdrv_refresh_filename(extent->file->bs); error_setg_errno(errp, -ret, "Could not read l1 table from extent '%s'", extent->file->bs->filename); @@ -499,6 +503,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, extent->l1_backup_table, l1_size); if (ret < 0) { + bdrv_refresh_filename(extent->file->bs); error_setg_errno(errp, -ret, "Could not read l1 backup table from extent '%s'", extent->file->bs->filename); @@ -530,6 +535,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs, ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); if (ret < 0) { + bdrv_refresh_filename(file->bs); error_setg_errno(errp, -ret, "Could not read header from file '%s'", file->bs->filename); @@ -607,6 +613,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); if (ret < 0) { + bdrv_refresh_filename(file->bs); error_setg_errno(errp, -ret, "Could not read header from file '%s'", file->bs->filename); @@ -861,13 +868,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, if (!path_is_absolute(fname) && !path_has_protocol(fname) && !desc_file_path[0]) { + bdrv_refresh_filename(bs->file->bs); error_setg(errp, "Cannot use relative extent paths with VMDK " "descriptor file '%s'", bs->file->bs->filename); return -EINVAL; } - extent_path = g_malloc0(PATH_MAX); - path_combine(extent_path, PATH_MAX, desc_file_path, fname); + extent_path = path_combine(desc_file_path, fname); ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); assert(ret < 32); @@ -1371,7 +1378,6 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, VmdkGrainMarker *data = NULL; uLongf buf_len; QEMUIOVector local_qiov; - struct iovec iov; int64_t write_offset; int64_t write_end_sector; @@ -1399,11 +1405,7 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, data->size = cpu_to_le32(buf_len); n_bytes = buf_len + sizeof(VmdkGrainMarker); - iov = (struct iovec) { - .iov_base = data, - .iov_len = n_bytes, - }; - qemu_iovec_init_external(&local_qiov, &iov, 1); + qemu_iovec_init_buf(&local_qiov, data, n_bytes); BLKDBG_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED); } else { @@ -2072,16 +2074,16 @@ static int coroutine_fn vmdk_co_do_create(int64_t size, if (backing_file) { BlockBackend *backing; - char *full_backing = g_new0(char, PATH_MAX); - bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, backing_file, - full_backing, PATH_MAX, - &local_err); + char *full_backing = + bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, + backing_file, + &local_err); if (local_err) { - g_free(full_backing); error_propagate(errp, local_err); ret = -ENOENT; goto exit; } + assert(full_backing); backing = blk_new_open(full_backing, NULL, NULL, BDRV_O_NO_BACKING, errp); @@ -2260,7 +2262,7 @@ static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false); if (strcmp(hw_version, "undefined") == 0) { g_free(hw_version); - hw_version = g_strdup("4"); + hw_version = NULL; } fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); zeroed_grain = qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false); @@ -2470,6 +2472,7 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) { ImageInfo *info = g_new0(ImageInfo, 1); + bdrv_refresh_filename(extent->file->bs); *info = (ImageInfo){ .filename = g_strdup(extent->file->bs->filename), .format = g_strdup(extent->type), @@ -2601,6 +2604,23 @@ static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return 0; } +static void vmdk_gather_child_options(BlockDriverState *bs, QDict *target, + bool backing_overridden) +{ + /* No children but file and backing can be explicitly specified (TODO) */ + qdict_put(target, "file", + qobject_ref(bs->file->bs->full_open_options)); + + if (backing_overridden) { + if (bs->backing) { + qdict_put(target, "backing", + qobject_ref(bs->backing->bs->full_open_options)); + } else { + qdict_put_null(target, "backing"); + } + } +} + static QemuOptsList vmdk_create_opts = { .name = "vmdk-create-opts", .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head), @@ -2672,6 +2692,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_get_specific_info = vmdk_get_specific_info, .bdrv_refresh_limits = vmdk_refresh_limits, .bdrv_get_info = vmdk_get_info, + .bdrv_gather_child_options = vmdk_gather_child_options, .supports_backing = true, .create_opts = &vmdk_create_opts, diff --git a/block/vpc.c b/block/vpc.c index 52ab717642..a902a4c54d 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1218,6 +1218,12 @@ static QemuOptsList vpc_create_opts = { } }; +static const char *const vpc_strong_runtime_opts[] = { + VPC_OPT_SIZE_CALC, + + NULL +}; + static BlockDriver bdrv_vpc = { .format_name = "vpc", .instance_size = sizeof(BDRVVPCState), @@ -1238,6 +1244,7 @@ static BlockDriver bdrv_vpc = { .create_opts = &vpc_create_opts, .bdrv_has_zero_init = vpc_has_zero_init, + .strong_runtime_opts = vpc_strong_runtime_opts, }; static void bdrv_vpc_init(void) diff --git a/block/vvfat.c b/block/vvfat.c index b7b61ea8b7..5f66787890 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3253,6 +3253,16 @@ static void vvfat_close(BlockDriverState *bs) } } +static const char *const vvfat_strong_runtime_opts[] = { + "dir", + "fat-type", + "floppy", + "label", + "rw", + + NULL +}; + static BlockDriver bdrv_vvfat = { .format_name = "vvfat", .protocol_name = "fat", @@ -3267,6 +3277,8 @@ static BlockDriver bdrv_vvfat = { .bdrv_co_preadv = vvfat_co_preadv, .bdrv_co_pwritev = vvfat_co_pwritev, .bdrv_co_block_status = vvfat_co_block_status, + + .strong_runtime_opts = vvfat_strong_runtime_opts, }; static void bdrv_vvfat_init(void) diff --git a/block/vxhs.c b/block/vxhs.c index 0cb0a007e9..2e18229ba4 100644 --- a/block/vxhs.c +++ b/block/vxhs.c @@ -556,6 +556,16 @@ static int64_t vxhs_getlength(BlockDriverState *bs) return vdisk_size; } +static const char *const vxhs_strong_runtime_opts[] = { + VXHS_OPT_VDISK_ID, + "tls-creds", + VXHS_OPT_HOST, + VXHS_OPT_PORT, + VXHS_OPT_SERVER".", + + NULL +}; + static BlockDriver bdrv_vxhs = { .format_name = "vxhs", .protocol_name = "vxhs", @@ -567,6 +577,7 @@ static BlockDriver bdrv_vxhs = { .bdrv_getlength = vxhs_getlength, .bdrv_aio_preadv = vxhs_aio_preadv, .bdrv_aio_pwritev = vxhs_aio_pwritev, + .strong_runtime_opts = vxhs_strong_runtime_opts, }; static void bdrv_vxhs_init(void) diff --git a/blockdev.c b/blockdev.c index 8714ad2702..7e6bf9955c 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1627,6 +1627,7 @@ static void external_snapshot_prepare(BlkActionState *common, error_setg_errno(errp, -size, "bdrv_getlength failed"); goto out; } + bdrv_refresh_filename(state->old_bs); bdrv_img_create(new_image_file, format, state->old_bs->filename, state->old_bs->drv->format_name, @@ -3230,6 +3231,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, goto out; } assert(bdrv_get_aio_context(base_bs) == aio_context); + bdrv_refresh_filename(base_bs); base_name = base_bs->filename; } @@ -3349,6 +3351,10 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, goto out; } } else if (has_top && top) { + /* This strcmp() is just a shortcut, there is no need to + * refresh @bs's filename. If it mismatches, + * bdrv_find_backing_image() will do the refresh and may still + * return @bs. */ if (strcmp(bs->filename, top) != 0) { top_bs = bdrv_find_backing_image(bs, top); } @@ -3509,6 +3515,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, if (backup->mode != NEW_IMAGE_MODE_EXISTING) { assert(backup->format); if (source) { + bdrv_refresh_filename(source); bdrv_img_create(backup->target, backup->format, source->filename, source->drv->format_name, NULL, size, flags, false, &local_err); @@ -3889,6 +3896,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) break; case NEW_IMAGE_MODE_ABSOLUTE_PATHS: /* create new image with backing file */ + bdrv_refresh_filename(source); bdrv_img_create(arg->target, format, source->filename, source->drv->format_name, diff --git a/chardev/spice.c b/chardev/spice.c index 173c257949..22c30ae833 100644 --- a/chardev/spice.c +++ b/chardev/spice.c @@ -2,30 +2,12 @@ #include "trace.h" #include "ui/qemu-spice.h" #include "chardev/char.h" +#include "chardev/spice.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/option.h" -#include <spice.h> #include <spice/protocol.h> - -typedef struct SpiceChardev { - Chardev parent; - - SpiceCharDeviceInstance sin; - bool active; - bool blocked; - const uint8_t *datapos; - int datalen; - QLIST_ENTRY(SpiceChardev) next; -} SpiceChardev; - -#define TYPE_CHARDEV_SPICE "chardev-spice" -#define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc" -#define TYPE_CHARDEV_SPICEPORT "chardev-spiceport" - -#define SPICE_CHARDEV(obj) OBJECT_CHECK(SpiceChardev, (obj), TYPE_CHARDEV_SPICE) - typedef struct SpiceCharSource { GSource source; SpiceChardev *scd; @@ -148,15 +130,25 @@ static void vmc_unregister_interface(SpiceChardev *scd) static gboolean spice_char_source_prepare(GSource *source, gint *timeout) { SpiceCharSource *src = (SpiceCharSource *)source; + Chardev *chr = CHARDEV(src->scd); *timeout = -1; + if (!chr->be_open) { + return true; + } + return !src->scd->blocked; } static gboolean spice_char_source_check(GSource *source) { SpiceCharSource *src = (SpiceCharSource *)source; + Chardev *chr = CHARDEV(src->scd); + + if (!chr->be_open) { + return true; + } return !src->scd->blocked; } @@ -164,9 +156,12 @@ static gboolean spice_char_source_check(GSource *source) static gboolean spice_char_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { + SpiceCharSource *src = (SpiceCharSource *)source; + Chardev *chr = CHARDEV(src->scd); GIOFunc func = (GIOFunc)callback; + GIOCondition cond = chr->be_open ? G_IO_OUT : G_IO_HUP; - return func(NULL, G_IO_OUT, user_data); + return func(NULL, cond, user_data); } static GSourceFuncs SpiceCharSourceFuncs = { @@ -195,6 +190,12 @@ static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len) int read_bytes; assert(s->datalen == 0); + + if (!chr->be_open) { + trace_spice_chr_discard_write(len); + return len; + } + s->datapos = buf; s->datalen = len; spice_server_char_device_wakeup(&s->sin); @@ -287,13 +288,19 @@ static void qemu_chr_open_spice_vmc(Chardev *chr, } *be_opened = false; +#if SPICE_SERVER_VERSION < 0x000e02 + /* Spice < 0.14.2 doesn't explicitly open smartcard chardev */ + if (strcmp(type, "smartcard") == 0) { + *be_opened = true; + } +#endif chr_open(chr, type); } -static void qemu_chr_open_spice_port(Chardev *chr, - ChardevBackend *backend, - bool *be_opened, - Error **errp) +void qemu_chr_open_spice_port(Chardev *chr, + ChardevBackend *backend, + bool *be_opened, + Error **errp) { ChardevSpicePort *spiceport = backend->u.spiceport.data; const char *name = spiceport->fqdn; @@ -309,6 +316,11 @@ static void qemu_chr_open_spice_port(Chardev *chr, *be_opened = false; s = SPICE_CHARDEV(chr); s->sin.portname = g_strdup(name); + + if (using_spice) { + /* spice server already created */ + vmc_register_interface(s); + } } void qemu_spice_register_ports(void) diff --git a/chardev/trace-events b/chardev/trace-events index d0e5f3bbc1..b8a7596344 100644 --- a/chardev/trace-events +++ b/chardev/trace-events @@ -10,6 +10,7 @@ wct_cmd_other(const char *cmd) "%s" wct_speed(int speed) "%d" # chardev/spice.c +spice_chr_discard_write(int len) "spice chr write discarded %d" spice_vmc_write(ssize_t out, int len) "spice wrote %zd of requested %d" spice_vmc_read(int bytes, int len) "spice read %d of requested %d" spice_vmc_register_interface(void *scd) "spice vmc registered interface %p" @@ -368,10 +368,10 @@ libattr="" xfs="" tcg="yes" membarrier="" -vhost_net="no" -vhost_crypto="no" -vhost_scsi="no" -vhost_vsock="no" +vhost_net="" +vhost_crypto="" +vhost_scsi="" +vhost_vsock="" vhost_user="" kvm="no" hax="no" @@ -463,6 +463,7 @@ gnutls="" nettle="" gcrypt="" gcrypt_hmac="no" +auth_pam="" vte="" virglrenderer="" tpm="yes" @@ -782,6 +783,7 @@ case $targetos in MINGW32*) mingw32="yes" hax="yes" + vhost_user="no" audio_possible_drivers="dsound sdl" if check_include dsound.h; then audio_drv_list="dsound" @@ -878,15 +880,11 @@ Haiku) LIBS="-lposix_error_mapper -lnetwork $LIBS" ;; Linux) - audio_drv_list="try-pa try-alsa try-sdl oss" + audio_drv_list="try-pa oss" audio_possible_drivers="oss alsa sdl pa" linux="yes" linux_user="yes" kvm="yes" - vhost_net="yes" - vhost_crypto="yes" - vhost_scsi="yes" - vhost_vsock="yes" QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$PWD/linux-headers $QEMU_INCLUDES" supported_os="yes" libudev="yes" @@ -1262,11 +1260,7 @@ for opt do ;; --disable-vhost-crypto) vhost_crypto="no" ;; - --enable-vhost-crypto) - vhost_crypto="yes" - if test "$mingw32" = "yes"; then - error_exit "vhost-crypto isn't available on win32" - fi + --enable-vhost-crypto) vhost_crypto="yes" ;; --disable-vhost-scsi) vhost_scsi="no" ;; @@ -1381,6 +1375,10 @@ for opt do ;; --enable-gcrypt) gcrypt="yes" ;; + --disable-auth-pam) auth_pam="no" + ;; + --enable-auth-pam) auth_pam="yes" + ;; --enable-rdma) rdma="yes" ;; --disable-rdma) rdma="no" @@ -1471,11 +1469,11 @@ for opt do ;; --disable-vhost-user) vhost_user="no" ;; - --enable-vhost-user) - vhost_user="yes" - if test "$mingw32" = "yes"; then - error_exit "vhost-user isn't available on win32" - fi + --enable-vhost-user) vhost_user="yes" + ;; + --disable-vhost-kernel) vhost_kernel="no" + ;; + --enable-vhost-kernel) vhost_kernel="yes" ;; --disable-capstone) capstone="no" ;; @@ -1507,14 +1505,6 @@ for opt do esac done -if test "$vhost_user" = ""; then - if test "$mingw32" = "yes"; then - vhost_user="no" - else - vhost_user="yes" - fi -fi - case "$cpu" in ppc) CPU_CFLAGS="-m32" @@ -1707,6 +1697,7 @@ disabled with --disable-FEATURE, default is enabled if available: gnutls GNUTLS cryptography support nettle nettle cryptography support gcrypt libgcrypt cryptography support + auth-pam PAM access control sdl SDL UI sdl_image SDL Image support for icons gtk gtk UI @@ -1737,8 +1728,12 @@ disabled with --disable-FEATURE, default is enabled if available: linux-aio Linux AIO support cap-ng libcap-ng support attr attr and xattr support - vhost-net vhost-net acceleration support - vhost-crypto vhost-crypto acceleration support + vhost-net vhost-net kernel acceleration support + vhost-vsock virtio sockets device support + vhost-scsi vhost-scsi kernel target support + vhost-crypto vhost-user-crypto backend support + vhost-kernel vhost kernel backend support + vhost-user vhost-user backend support spice spice rbd rados block device (rbd) libiscsi iscsi support @@ -1764,7 +1759,6 @@ disabled with --disable-FEATURE, default is enabled if available: jemalloc jemalloc support avx2 AVX2 optimization support replication replication support - vhost-vsock virtio sockets device support opengl opengl support virglrenderer virgl rendering support xfsctl xfsctl support @@ -1781,7 +1775,6 @@ disabled with --disable-FEATURE, default is enabled if available: parallels parallels image format support sheepdog sheepdog block driver support crypto-afalg Linux AF_ALG crypto backend driver - vhost-user vhost-user support capstone capstone disassembler support debug-mutex mutex debugging support libpmem libpmem support @@ -2171,6 +2164,45 @@ else l2tpv3=no fi +######################################### +# vhost interdependencies and host support + +# vhost backends +test "$vhost_user" = "" && vhost_user=yes +if test "$vhost_user" = "yes" && test "$mingw32" = "yes"; then + error_exit "vhost-user isn't available on win32" +fi +test "$vhost_kernel" = "" && vhost_kernel=$linux +if test "$vhost_kernel" = "yes" && test "$linux" != "yes"; then + error_exit "vhost-kernel is only available on Linux" +fi + +# vhost-kernel devices +test "$vhost_scsi" = "" && vhost_scsi=$vhost_kernel +if test "$vhost_scsi" = "yes" && test "$vhost_kernel" != "yes"; then + error_exit "--enable-vhost-scsi requires --enable-vhost-kernel" +fi +test "$vhost_vsock" = "" && vhost_vsock=$vhost_kernel +if test "$vhost_vsock" = "yes" && test "$vhost_kernel" != "yes"; then + error_exit "--enable-vhost-vsock requires --enable-vhost-kernel" +fi + +# vhost-user backends +test "$vhost_net_user" = "" && vhost_net_user=$vhost_user +if test "$vhost_net_user" = "yes" && test "$vhost_user" = "no"; then + error_exit "--enable-vhost-net-user requires --enable-vhost-user" +fi +test "$vhost_crypto" = "" && vhost_crypto=$vhost_user +if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then + error_exit "--enable-vhost-crypto requires --enable-vhost-user" +fi + +# OR the vhost-kernel and vhost-user values for simplicity +if test "$vhost_net" = ""; then + test "$vhost_net_user" = "yes" && vhost_net=yes + test "$vhost_kernel" = "yes" && vhost_net=yes +fi + ########################################## # MinGW / Mingw-w64 localtime_r/gmtime_r check @@ -2865,6 +2897,33 @@ fi ########################################## +# PAM probe + +if test "$auth_pam" != "no"; then + cat > $TMPC <<EOF +#include <security/pam_appl.h> +#include <stdio.h> +int main(void) { + const char *service_name = "qemu"; + const char *user = "frank"; + const struct pam_conv *pam_conv = NULL; + pam_handle_t *pamh = NULL; + pam_start(service_name, user, pam_conv, &pamh); + return 0; +} +EOF + if compile_prog "" "-lpam" ; then + auth_pam=yes + else + if test "$auth_pam" = "yes"; then + feature_not_found "PAM" "Install PAM development package" + else + auth_pam=no + fi + fi +fi + +########################################## # getifaddrs (for tests/test-io-channel-socket ) have_ifaddrs_h=yes @@ -3172,20 +3231,6 @@ if test "$xkbcommon" != "no" ; then fi fi -########################################## -# fnmatch() probe, used for ACL routines -fnmatch="no" -cat > $TMPC << EOF -#include <fnmatch.h> -int main(void) -{ - fnmatch("foo", "foo", 0); - return 0; -} -EOF -if compile_prog "" "" ; then - fnmatch="yes" -fi ########################################## # xfsctl() probe, used for file-posix.c @@ -3503,6 +3548,14 @@ for i in $glib_modules; do fi done +if $pkg_config --atleast-version=$glib_req_ver gio-2.0; then + gio=yes + gio_cflags=$($pkg_config --cflags gio-2.0) + gio_libs=$($pkg_config --libs gio-2.0) +else + gio=no +fi + # Sanity check that the current size_t matches the # size that glib thinks it should be. This catches # problems on multi-arch where people try to build @@ -6083,6 +6136,7 @@ echo "GNUTLS support $gnutls" echo "libgcrypt $gcrypt" echo "nettle $nettle $(echo_version $nettle $nettle_version)" echo "libtasn1 $tasn1" +echo "PAM $auth_pam" echo "curses support $curses" echo "virgl support $virglrenderer $(echo_version $virglrenderer $virgl_version)" echo "curl support $curl" @@ -6374,9 +6428,6 @@ if test "$xkbcommon" = "yes" ; then echo "XKBCOMMON_CFLAGS=$xkbcommon_cflags" >> $config_host_mak echo "XKBCOMMON_LIBS=$xkbcommon_libs" >> $config_host_mak fi -if test "$fnmatch" = "yes" ; then - echo "CONFIG_FNMATCH=y" >> $config_host_mak -fi if test "$xfs" = "yes" ; then echo "CONFIG_XFS=y" >> $config_host_mak fi @@ -6520,6 +6571,11 @@ if test "$gtk" = "yes" ; then echo "CONFIG_GTK_GL=y" >> $config_host_mak fi fi +if test "$gio" = "yes" ; then + echo "CONFIG_GIO=y" >> $config_host_mak + echo "GIO_CFLAGS=$gio_cflags" >> $config_host_mak + echo "GIO_LIBS=$gio_libs" >> $config_host_mak +fi echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak if test "$gnutls" = "yes" ; then echo "CONFIG_GNUTLS=y" >> $config_host_mak @@ -6537,6 +6593,9 @@ fi if test "$tasn1" = "yes" ; then echo "CONFIG_TASN1=y" >> $config_host_mak fi +if test "$auth_pam" = "yes" ; then + echo "CONFIG_AUTH_PAM=y" >> $config_host_mak +fi if test "$have_ifaddrs_h" = "yes" ; then echo "HAVE_IFADDRS_H=y" >> $config_host_mak fi @@ -6589,8 +6648,11 @@ fi if test "$vhost_scsi" = "yes" ; then echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak fi -if test "$vhost_net" = "yes" && test "$vhost_user" = "yes"; then - echo "CONFIG_VHOST_NET_USED=y" >> $config_host_mak +if test "$vhost_net" = "yes" ; then + echo "CONFIG_VHOST_NET=y" >> $config_host_mak +fi +if test "$vhost_net_user" = "yes" ; then + echo "CONFIG_VHOST_NET_USER=y" >> $config_host_mak fi if test "$vhost_crypto" = "yes" ; then echo "CONFIG_VHOST_CRYPTO=y" >> $config_host_mak @@ -6598,6 +6660,9 @@ fi if test "$vhost_vsock" = "yes" ; then echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak fi +if test "$vhost_kernel" = "yes" ; then + echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak +fi if test "$vhost_user" = "yes" ; then echo "CONFIG_VHOST_USER=y" >> $config_host_mak fi @@ -7368,12 +7433,6 @@ if supported_xen_target $target; then fi if supported_kvm_target $target; then echo "CONFIG_KVM=y" >> $config_target_mak - if test "$vhost_net" = "yes" ; then - echo "CONFIG_VHOST_NET=y" >> $config_target_mak - if test "$vhost_user" = "yes" ; then - echo "CONFIG_VHOST_USER_NET_TEST_$target_name=y" >> $config_host_mak - fi - fi fi if supported_hax_target $target; then echo "CONFIG_HAX=y" >> $config_target_mak @@ -1333,6 +1333,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg) qemu_wait_io_event(cpu); } while (!cpu->unplug); + qemu_mutex_unlock_iothread(); rcu_unregister_thread(); return NULL; #endif diff --git a/crypto/tlssession.c b/crypto/tlssession.c index 0dedd4af52..c3a920dfe8 100644 --- a/crypto/tlssession.c +++ b/crypto/tlssession.c @@ -24,7 +24,7 @@ #include "crypto/tlscredspsk.h" #include "crypto/tlscredsx509.h" #include "qapi/error.h" -#include "qemu/acl.h" +#include "authz/base.h" #include "trace.h" #ifdef CONFIG_GNUTLS @@ -37,7 +37,7 @@ struct QCryptoTLSSession { QCryptoTLSCreds *creds; gnutls_session_t handle; char *hostname; - char *aclname; + char *authzid; bool handshakeComplete; QCryptoTLSSessionWriteFunc writeFunc; QCryptoTLSSessionReadFunc readFunc; @@ -56,7 +56,7 @@ qcrypto_tls_session_free(QCryptoTLSSession *session) gnutls_deinit(session->handle); g_free(session->hostname); g_free(session->peername); - g_free(session->aclname); + g_free(session->authzid); object_unref(OBJECT(session->creds)); g_free(session); } @@ -95,7 +95,7 @@ qcrypto_tls_session_pull(void *opaque, void *buf, size_t len) QCryptoTLSSession * qcrypto_tls_session_new(QCryptoTLSCreds *creds, const char *hostname, - const char *aclname, + const char *authzid, QCryptoTLSCredsEndpoint endpoint, Error **errp) { @@ -105,13 +105,13 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds, session = g_new0(QCryptoTLSSession, 1); trace_qcrypto_tls_session_new( session, creds, hostname ? hostname : "<none>", - aclname ? aclname : "<none>", endpoint); + authzid ? authzid : "<none>", endpoint); if (hostname) { session->hostname = g_strdup(hostname); } - if (aclname) { - session->aclname = g_strdup(aclname); + if (authzid) { + session->authzid = g_strdup(authzid); } session->creds = creds; object_ref(OBJECT(creds)); @@ -262,6 +262,7 @@ qcrypto_tls_session_check_certificate(QCryptoTLSSession *session, unsigned int nCerts, i; time_t now; gnutls_x509_crt_t cert = NULL; + Error *err = NULL; now = time(NULL); if (now == ((time_t)-1)) { @@ -349,19 +350,17 @@ qcrypto_tls_session_check_certificate(QCryptoTLSSession *session, gnutls_strerror(ret)); goto error; } - if (session->aclname) { - qemu_acl *acl = qemu_acl_find(session->aclname); - int allow; - if (!acl) { - error_setg(errp, "Cannot find ACL %s", - session->aclname); + if (session->authzid) { + bool allow; + + allow = qauthz_is_allowed_by_id(session->authzid, + session->peername, &err); + if (err) { + error_propagate(errp, err); goto error; } - - allow = qemu_acl_party_is_allowed(acl, session->peername); - if (!allow) { - error_setg(errp, "TLS x509 ACL check for %s is denied", + error_setg(errp, "TLS x509 authz check for %s is denied", session->peername); goto error; } @@ -555,7 +554,7 @@ qcrypto_tls_session_get_peer_name(QCryptoTLSSession *session) QCryptoTLSSession * qcrypto_tls_session_new(QCryptoTLSCreds *creds G_GNUC_UNUSED, const char *hostname G_GNUC_UNUSED, - const char *aclname G_GNUC_UNUSED, + const char *authzid G_GNUC_UNUSED, QCryptoTLSCredsEndpoint endpoint G_GNUC_UNUSED, Error **errp) { diff --git a/crypto/trace-events b/crypto/trace-events index 597389b73c..a38ad7b787 100644 --- a/crypto/trace-events +++ b/crypto/trace-events @@ -19,5 +19,5 @@ qcrypto_tls_creds_x509_load_cert(void *creds, int isServer, const char *file) "T qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds x509 load cert list creds=%p file=%s" # crypto/tlssession.c -qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *aclname, int endpoint) "TLS session new session=%p creds=%p hostname=%s aclname=%s endpoint=%d" +qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d" qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s" diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 87ad267494..bd6943b691 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -119,6 +119,7 @@ CONFIG_IOTKIT_SECCTL=y CONFIG_IOTKIT_SYSCTL=y CONFIG_IOTKIT_SYSINFO=y CONFIG_ARMSSE_CPUID=y +CONFIG_ARMSSE_MHU=y CONFIG_VERSATILE=y CONFIG_VERSATILE_PCI=y diff --git a/default-configs/virtio.mak b/default-configs/virtio.mak index ecb4420e74..b653aa06b1 100644 --- a/default-configs/virtio.mak +++ b/default-configs/virtio.mak @@ -1,5 +1,5 @@ -CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +CONFIG_VHOST_USER_SCSI=$(CONFIG_VHOST_USER) +CONFIG_VHOST_USER_BLK=$(CONFIG_VHOST_USER) CONFIG_VIRTIO=y CONFIG_VIRTIO_9P=$(CONFIG_VIRTFS) CONFIG_VIRTIO_BALLOON=y diff --git a/disas/nanomips.cpp b/disas/nanomips.cpp index f90f1a958b..f090f61c76 100644 --- a/disas/nanomips.cpp +++ b/disas/nanomips.cpp @@ -1058,7 +1058,7 @@ uint64 NMD::extract_stripe_6(uint64 instruction) } -uint64 NMD::extract_ac_13_12(uint64 instruction) +uint64 NMD::extract_ac_15_14(uint64 instruction) { uint64 value = 0; value |= extract_bits(instruction, 14, 2); @@ -6375,7 +6375,7 @@ std::string NMD::DPA_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6399,7 +6399,7 @@ std::string NMD::DPAQ_SA_L_W(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6423,7 +6423,7 @@ std::string NMD::DPAQ_S_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6447,7 +6447,7 @@ std::string NMD::DPAQX_SA_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6471,7 +6471,7 @@ std::string NMD::DPAQX_S_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6495,7 +6495,7 @@ std::string NMD::DPAU_H_QBL(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6519,7 +6519,7 @@ std::string NMD::DPAU_H_QBR(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6543,7 +6543,7 @@ std::string NMD::DPAX_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6567,7 +6567,7 @@ std::string NMD::DPS_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6591,7 +6591,7 @@ std::string NMD::DPSQ_SA_L_W(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6615,7 +6615,7 @@ std::string NMD::DPSQ_S_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6639,7 +6639,7 @@ std::string NMD::DPSQX_SA_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6663,7 +6663,7 @@ std::string NMD::DPSQX_S_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6687,7 +6687,7 @@ std::string NMD::DPSU_H_QBL(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6711,7 +6711,7 @@ std::string NMD::DPSU_H_QBR(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -6735,7 +6735,7 @@ std::string NMD::DPSX_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -7373,7 +7373,7 @@ std::string NMD::EXTPDP(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 size_value = extract_size_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7397,7 +7397,7 @@ std::string NMD::EXTPDPV(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7421,7 +7421,7 @@ std::string NMD::EXTP(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 size_value = extract_size_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7445,7 +7445,7 @@ std::string NMD::EXTPV(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7469,7 +7469,7 @@ std::string NMD::EXTR_RS_W(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 shift_value = extract_shift_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7493,7 +7493,7 @@ std::string NMD::EXTR_R_W(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 shift_value = extract_shift_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7517,7 +7517,7 @@ std::string NMD::EXTR_S_H(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 shift_value = extract_shift_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7541,7 +7541,7 @@ std::string NMD::EXTR_W(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 shift_value = extract_shift_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7565,7 +7565,7 @@ std::string NMD::EXTRV_RS_W(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7589,7 +7589,7 @@ std::string NMD::EXTRV_R_W(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7613,7 +7613,7 @@ std::string NMD::EXTRV_S_H(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -7637,7 +7637,7 @@ std::string NMD::EXTRV_W(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -9719,7 +9719,7 @@ std::string NMD::MADD_DSP_(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -9792,7 +9792,7 @@ std::string NMD::MADDU_DSP_(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -9817,7 +9817,7 @@ std::string NMD::MAQ_S_W_PHL(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -9842,7 +9842,7 @@ std::string NMD::MAQ_S_W_PHR(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -9867,7 +9867,7 @@ std::string NMD::MAQ_SA_W_PHL(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -9892,7 +9892,7 @@ std::string NMD::MAQ_SA_W_PHR(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -10195,7 +10195,7 @@ std::string NMD::MFHGC0(uint64 instruction) std::string NMD::MFHI_DSP_(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -10243,7 +10243,7 @@ std::string NMD::MFHTR(uint64 instruction) std::string NMD::MFLO_DSP_(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rt = GPR(copy(rt_value)); std::string ac = AC(copy(ac_value)); @@ -10652,7 +10652,7 @@ std::string NMD::MSUB_DSP_(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -10724,7 +10724,7 @@ std::string NMD::MSUBU_DSP_(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -10931,7 +10931,7 @@ std::string NMD::MTHGC0(uint64 instruction) std::string NMD::MTHI_DSP_(uint64 instruction) { uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rs = GPR(copy(rs_value)); std::string ac = AC(copy(ac_value)); @@ -10953,7 +10953,7 @@ std::string NMD::MTHI_DSP_(uint64 instruction) std::string NMD::MTHLIP(uint64 instruction) { uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rs = GPR(copy(rs_value)); std::string ac = AC(copy(ac_value)); @@ -11001,7 +11001,7 @@ std::string NMD::MTHTR(uint64 instruction) std::string NMD::MTLO_DSP_(uint64 instruction) { uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rs = GPR(copy(rs_value)); std::string ac = AC(copy(ac_value)); @@ -11432,7 +11432,7 @@ std::string NMD::MULSA_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -11456,7 +11456,7 @@ std::string NMD::MULSAQ_S_W_PH(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -11480,7 +11480,7 @@ std::string NMD::MULT_DSP_(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -11504,7 +11504,7 @@ std::string NMD::MULTU_DSP_(uint64 instruction) { uint64 rt_value = extract_rt_25_24_23_22_21(instruction); uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string ac = AC(copy(ac_value)); std::string rs = GPR(copy(rs_value)); @@ -13932,7 +13932,7 @@ std::string NMD::SHE(uint64 instruction) std::string NMD::SHILO(uint64 instruction) { int64 shift_value = extract_shift__se5_21_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string shift = IMMEDIATE(copy(shift_value)); std::string ac = AC(copy(ac_value)); @@ -13954,7 +13954,7 @@ std::string NMD::SHILO(uint64 instruction) std::string NMD::SHILOV(uint64 instruction) { uint64 rs_value = extract_rs_20_19_18_17_16(instruction); - uint64 ac_value = extract_ac_13_12(instruction); + uint64 ac_value = extract_ac_15_14(instruction); std::string rs = GPR(copy(rs_value)); std::string ac = AC(copy(ac_value)); diff --git a/disas/nanomips.h b/disas/nanomips.h index 6482edafe3..243c3e38d2 100644 --- a/disas/nanomips.h +++ b/disas/nanomips.h @@ -159,7 +159,7 @@ private: int64 extract_s__se31_0_11_to_2_20_to_12_s12(uint64 instruction); int64 extract_shift__se5_21_20_19_18_17_16(uint64 instruction); - uint64 extract_ac_13_12(uint64 instruction); + uint64 extract_ac_15_14(uint64 instruction); uint64 extract_bit_16_15_14_13_12_11(uint64 instruction); uint64 extract_bit_23_22_21(uint64 instruction); uint64 extract_c0s_20_19_18_17_16(uint64 instruction); diff --git a/docs/vfio-ap.txt b/docs/vfio-ap.txt index 12339684cd..8cd060a01e 100644 --- a/docs/vfio-ap.txt +++ b/docs/vfio-ap.txt @@ -440,8 +440,7 @@ unassign_control_domain 'unassign_domain' file. This may be done multiple times to unassign more than one control domain. -Notes: Hot plug/unplug is not currently supported for mediated AP matrix -devices, so no changes to the AP matrix will be allowed while a guest using +Notes: No changes to the AP matrix will be allowed while a guest using the mediated matrix device is running. Attempts to assign an adapter, domain or control domain will be rejected and an error (EBUSY) returned. @@ -562,6 +561,54 @@ facilities: for guest usage, no AP devices can be made accessible to a guest started without APFT installed. +Hot plug a vfio-ap device into a running guest: +============================================== +Only one vfio-ap device can be attached to the virtual machine's ap-bus, so a +vfio-ap device can be hot plugged if and only if no vfio-ap device is attached +to the bus already, whether via the QEMU command line or a prior hot plug +action. + +To hot plug a vfio-ap device, use the QEMU device_add command: + + (qemu) device_add vfio-ap,sysfsdev="$path-to-mdev" + + Where the '$path-to-mdev' value specifies the absolute path to a mediated + device to which AP resources to be used by the guest have been assigned. + +Note that on Linux guests, the AP devices will be created in the +/sys/bus/ap/devices directory when the AP bus subsequently performs its periodic +scan, so there may be a short delay before the AP devices are accessible on the +guest. + +The command will fail if: + +* A vfio-ap device has already been attached to the virtual machine's ap-bus. + +* The CPU model features for controlling guest access to AP facilities are not + enabled (see 'CPU model features' subsection in the previous section). + +Hot unplug a vfio-ap device from a running guest: +================================================ +A vfio-ap device can be unplugged from a running KVM guest if a vfio-ap device +has been attached to the virtual machine's ap-bus via the QEMU command line +or a prior hot plug action. + +To hot unplug a vfio-ap device, use the QEMU device_del command: + + (qemu) device_del vfio-ap,sysfsdev="$path-to-mdev" + + Where $path-to-mdev is the same as the path specified when the vfio-ap + device was attached to the virtual machine's ap-bus. + +On a Linux guest, the AP devices will be removed from the /sys/bus/ap/devices +directory on the guest when the AP bus subsequently performs its periodic scan, +so there may be a short delay before the AP devices are no longer accessible by +the guest. + +The command will fail if the $path-to-mdev specified on the device_del command +does not match the value specified when the vfio-ap device was attached to +the virtual machine's ap-bus. + Example: Configure AP Matrixes for Three Linux Guests: ===================================================== Let's now provide an example to illustrate how KVM guests may be given @@ -819,7 +866,11 @@ Limitations assigned lest the host be given access to the private data of the AP queue device, such as a private key configured specifically for the guest. -* Dynamically modifying the AP matrix for a running guest (which would amount to - hot(un)plug of AP devices for the guest) is currently not supported +* Dynamically assigning AP resources to or unassigning AP resources from a + mediated matrix device - see 'Configuring an AP matrix for a linux guest' + section above - while a running guest is using it is currently not supported. -* Live guest migration is not supported for guests using AP devices. +* Live guest migration is not supported for guests using AP devices. If a guest + is using AP devices, the vfio-ap device configured for the guest must be + unplugged before migrating the guest (see 'Hot unplug a vfio-ap device from a + running guest' section above. diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 9132d7a0b0..4610738ab1 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -696,6 +696,7 @@ static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm, static FloatParts round_canonical(FloatParts p, float_status *s, const FloatFmt *parm) { + const uint64_t frac_lsb = parm->frac_lsb; const uint64_t frac_lsbm1 = parm->frac_lsbm1; const uint64_t round_mask = parm->round_mask; const uint64_t roundeven_mask = parm->roundeven_mask; @@ -731,6 +732,10 @@ static FloatParts round_canonical(FloatParts p, float_status *s, inc = p.sign ? round_mask : 0; overflow_norm = !p.sign; break; + case float_round_to_odd: + overflow_norm = true; + inc = frac & frac_lsb ? 0 : round_mask; + break; default: g_assert_not_reached(); } @@ -778,9 +783,14 @@ static FloatParts round_canonical(FloatParts p, float_status *s, shift64RightJamming(frac, 1 - exp, &frac); if (frac & round_mask) { /* Need to recompute round-to-even. */ - if (s->float_rounding_mode == float_round_nearest_even) { + switch (s->float_rounding_mode) { + case float_round_nearest_even: inc = ((frac & roundeven_mask) != frac_lsbm1 ? frac_lsbm1 : 0); + break; + case float_round_to_odd: + inc = frac & frac_lsb ? 0 : round_mask; + break; } flags |= float_flag_inexact; frac += inc; @@ -1988,6 +1998,9 @@ static FloatParts round_to_int(FloatParts a, int rmode, case float_round_down: one = a.sign; break; + case float_round_to_odd: + one = true; + break; default: g_assert_not_reached(); } @@ -2021,6 +2034,9 @@ static FloatParts round_to_int(FloatParts a, int rmode, case float_round_down: inc = a.sign ? rnd_mask : 0; break; + case float_round_to_odd: + inc = a.frac & frac_lsb ? 0 : rnd_mask; + break; default: g_assert_not_reached(); } @@ -3314,6 +3330,9 @@ static int32_t roundAndPackInt32(flag zSign, uint64_t absZ, float_status *status case float_round_down: roundIncrement = zSign ? 0x7f : 0; break; + case float_round_to_odd: + roundIncrement = absZ & 0x80 ? 0 : 0x7f; + break; default: abort(); } @@ -3368,6 +3387,9 @@ static int64_t roundAndPackInt64(flag zSign, uint64_t absZ0, uint64_t absZ1, case float_round_down: increment = zSign && absZ1; break; + case float_round_to_odd: + increment = !(absZ0 & 1) && absZ1; + break; default: abort(); } @@ -3424,6 +3446,9 @@ static int64_t roundAndPackUint64(flag zSign, uint64_t absZ0, case float_round_down: increment = zSign && absZ1; break; + case float_round_to_odd: + increment = !(absZ0 & 1) && absZ1; + break; default: abort(); } @@ -3526,6 +3551,9 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig, case float_round_down: roundIncrement = zSign ? 0x7f : 0; break; + case float_round_to_odd: + roundIncrement = zSig & 0x80 ? 0 : 0x7f; + break; default: abort(); break; @@ -3536,8 +3564,10 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig, || ( ( zExp == 0xFD ) && ( (int32_t) ( zSig + roundIncrement ) < 0 ) ) ) { + bool overflow_to_inf = roundingMode != float_round_to_odd && + roundIncrement != 0; float_raise(float_flag_overflow | float_flag_inexact, status); - return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); + return packFloat32(zSign, 0xFF, -!overflow_to_inf); } if ( zExp < 0 ) { if (status->flush_to_zero) { @@ -3555,6 +3585,13 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig, if (isTiny && roundBits) { float_raise(float_flag_underflow, status); } + if (roundingMode == float_round_to_odd) { + /* + * For round-to-odd case, the roundIncrement depends on + * zSig which just changed. + */ + roundIncrement = zSig & 0x80 ? 0 : 0x7f; + } } } if (roundBits) { @@ -6793,6 +6830,35 @@ uint32_t float128_to_uint32_round_to_zero(float128 a, float_status *status) } /*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point value +| `a' to the 32-bit unsigned integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. If the conversion overflows, the +| largest unsigned integer is returned. If 'a' is negative, the value is +| rounded and zero is returned; negative values that do not round to zero +| will raise the inexact exception. +*----------------------------------------------------------------------------*/ + +uint32_t float128_to_uint32(float128 a, float_status *status) +{ + uint64_t v; + uint32_t res; + int old_exc_flags = get_float_exception_flags(status); + + v = float128_to_uint64(a, status); + if (v > 0xffffffff) { + res = 0xffffffff; + } else { + return v; + } + set_float_exception_flags(old_exc_flags, status); + float_raise(float_flag_invalid, status); + return res; +} + +/*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the single-precision floating-point format. The conversion | is performed according to the IEC/IEEE Standard for Binary Floating-Point @@ -6958,6 +7024,15 @@ float128 float128_round_to_int(float128 a, float_status *status) add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low); } break; + case float_round_to_odd: + /* + * Note that if lastBitMask == 0, the last bit is the lsb + * of high, and roundBitsMask == -1. + */ + if ((lastBitMask ? z.low & lastBitMask : z.high & 1) == 0) { + add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low); + } + break; default: abort(); } @@ -6969,7 +7044,7 @@ float128 float128_round_to_int(float128 a, float_status *status) status->float_exception_flags |= float_flag_inexact; aSign = extractFloat128Sign( a ); switch (status->float_rounding_mode) { - case float_round_nearest_even: + case float_round_nearest_even: if ( ( aExp == 0x3FFE ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) @@ -6982,14 +7057,17 @@ float128 float128_round_to_int(float128 a, float_status *status) return packFloat128(aSign, 0x3FFF, 0, 0); } break; - case float_round_down: + case float_round_down: return aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) : packFloat128( 0, 0, 0, 0 ); - case float_round_up: + case float_round_up: return aSign ? packFloat128( 1, 0, 0, 0 ) : packFloat128( 0, 0x3FFF, 0, 0 ); + + case float_round_to_odd: + return packFloat128(aSign, 0x3FFF, 0, 0); } return packFloat128( aSign, 0, 0, 0 ); } @@ -7022,6 +7100,12 @@ float128 float128_round_to_int(float128 a, float_status *status) z.high += roundBitsMask; } break; + case float_round_to_odd: + if ((z.high & lastBitMask) == 0) { + z.high |= (a.low != 0); + z.high += roundBitsMask; + } + break; default: abort(); } diff --git a/hmp-commands.hx b/hmp-commands.hx index ba71558c25..e5fbc2ca59 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -350,49 +350,57 @@ ETEXI { .name = "savevm", .args_type = "name:s?", - .params = "[tag|id]", - .help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created", + .params = "tag", + .help = "save a VM snapshot. If no tag is provided, a new snapshot is created", .cmd = hmp_savevm, }, STEXI -@item savevm [@var{tag}|@var{id}] +@item savevm @var{tag} @findex savevm Create a snapshot of the whole virtual machine. If @var{tag} is provided, it is used as human readable identifier. If there is already -a snapshot with the same tag or ID, it is replaced. More info at +a snapshot with the same tag, it is replaced. More info at @ref{vm_snapshots}. + +Since 4.0, savevm stopped allowing the snapshot id to be set, accepting +only @var{tag} as parameter. ETEXI { .name = "loadvm", .args_type = "name:s", - .params = "tag|id", - .help = "restore a VM snapshot from its tag or id", + .params = "tag", + .help = "restore a VM snapshot from its tag", .cmd = hmp_loadvm, .command_completion = loadvm_completion, }, STEXI -@item loadvm @var{tag}|@var{id} +@item loadvm @var{tag} @findex loadvm Set the whole virtual machine to the snapshot identified by the tag -@var{tag} or the unique snapshot ID @var{id}. +@var{tag}. + +Since 4.0, loadvm stopped accepting snapshot id as parameter. ETEXI { .name = "delvm", .args_type = "name:s", - .params = "tag|id", - .help = "delete a VM snapshot from its tag or id", + .params = "tag", + .help = "delete a VM snapshot from its tag", .cmd = hmp_delvm, .command_completion = delvm_completion, }, STEXI -@item delvm @var{tag}|@var{id} +@item delvm @var{tag} @findex delvm -Delete the snapshot identified by @var{tag} or @var{id}. +Delete the snapshot identified by @var{tag}. + +Since 4.0, delvm stopped deleting snapshots by snapshot id, accepting +only @var{tag} as parameter. ETEXI { diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index df8c0db909..8fd25a5926 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -302,6 +302,11 @@ static const VMStateDescription vmstate_cpuhp_state = { } }; +static bool piix4_vmstate_need_smbus(void *opaque, int version_id) +{ + return pm_smbus_vmstate_needed(); +} + /* qemu-kvm 1.2 uses version 3 but advertised as 2 * To support incoming qemu-kvm 1.2 migration, change version_id * and minimum_version_id to 2 below (which breaks migration from @@ -321,6 +326,8 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState), VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState), VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), + VMSTATE_STRUCT_TEST(smb, PIIX4PMState, piix4_vmstate_need_smbus, 3, + pmsmb_vmstate, PMSMBus), VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState), VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState), VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 129e7ea7fe..76cc690579 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/bitops.h" #include "qapi/error.h" #include "trace.h" #include "hw/sysbus.h" @@ -29,6 +30,7 @@ struct ARMSSEInfo { int sram_banks; int num_cpus; uint32_t sys_version; + uint32_t cpuwait_rst; SysConfigFormat sys_config_format; bool has_mhus; bool has_ppus; @@ -43,6 +45,7 @@ static const ARMSSEInfo armsse_variants[] = { .sram_banks = 1, .num_cpus = 1, .sys_version = 0x41743, + .cpuwait_rst = 0, .sys_config_format = IoTKitFormat, .has_mhus = false, .has_ppus = false, @@ -55,6 +58,7 @@ static const ARMSSEInfo armsse_variants[] = { .sram_banks = 4, .num_cpus = 2, .sys_version = 0x22041743, + .cpuwait_rst = 2, .sys_config_format = SSE200Format, .has_mhus = true, .has_ppus = true, @@ -282,9 +286,9 @@ static void armsse_init(Object *obj) sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO); if (info->has_mhus) { sysbus_init_child_obj(obj, "mhu0", &s->mhu[0], sizeof(s->mhu[0]), - TYPE_UNIMPLEMENTED_DEVICE); + TYPE_ARMSSE_MHU); sysbus_init_child_obj(obj, "mhu1", &s->mhu[1], sizeof(s->mhu[1]), - TYPE_UNIMPLEMENTED_DEVICE); + TYPE_ARMSSE_MHU); } if (info->has_ppus) { for (i = 0; i < info->num_cpus; i++) { @@ -495,30 +499,33 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(cpudev, "num-irq", s->exp_numirq + 32); /* - * In real hardware the initial Secure VTOR is set from the INITSVTOR0 - * register in the IoT Kit System Control Register block, and the - * initial value of that is in turn specifiable by the FPGA that - * instantiates the IoT Kit. In QEMU we don't implement this wrinkle, - * and simply set the CPU's init-svtor to the IoT Kit default value. - * In SSE-200 the situation is similar, except that the default value - * is a reset-time signal input. Typically a board using the SSE-200 - * will have a system control processor whose boot firmware initializes - * the INITSVTOR* registers before powering up the CPUs in any case, - * so the hardware's default value doesn't matter. QEMU doesn't emulate + * In real hardware the initial Secure VTOR is set from the INITSVTOR* + * registers in the IoT Kit System Control Register block. In QEMU + * we set the initial value here, and also the reset value of the + * sysctl register, from this object's QOM init-svtor property. + * If the guest changes the INITSVTOR* registers at runtime then the + * code in iotkit-sysctl.c will update the CPU init-svtor property + * (which will then take effect on the next CPU warm-reset). + * + * Note that typically a board using the SSE-200 will have a system + * control processor whose boot firmware initializes the INITSVTOR* + * registers before powering up the CPUs. QEMU doesn't emulate * the control processor, so instead we behave in the way that the - * firmware does. The initial value is configurable by the board code - * to match whatever its firmware does. + * firmware does: the initial value should be set by the board code + * (using the init-svtor property on the ARMSSE object) to match + * whatever its firmware does. */ qdev_prop_set_uint32(cpudev, "init-svtor", s->init_svtor); /* - * Start all CPUs except CPU0 powered down. In real hardware it is - * a configurable property of the SSE-200 which CPUs start powered up - * (via the CPUWAIT0_RST and CPUWAIT1_RST parameters), but since all - * the boards we care about start CPU0 and leave CPU1 powered off, - * we hard-code that for now. We can add QOM properties for this + * CPUs start powered down if the corresponding bit in the CPUWAIT + * register is 1. In real hardware the CPUWAIT register reset value is + * a configurable property of the SSE-200 (via the CPUWAIT0_RST and + * CPUWAIT1_RST parameters), but since all the boards we care about + * start CPU0 and leave CPU1 powered off, we hard-code that in + * info->cpuwait_rst for now. We can add QOM properties for this * later if necessary. */ - if (i > 0) { + if (extract32(info->cpuwait_rst, i, 1)) { object_property_set_bool(cpuobj, true, "start-powered-off", &err); if (err) { error_propagate(errp, err); @@ -766,22 +773,28 @@ static void armsse_realize(DeviceState *dev, Error **errp) } if (info->has_mhus) { + /* + * An SSE-200 with only one CPU should have only one MHU created, + * with the region where the second MHU usually is being RAZ/WI. + * We don't implement that SSE-200 config; if we want to support + * it then this code needs to be enhanced to handle creating the + * RAZ/WI region instead of the second MHU. + */ + assert(info->num_cpus == ARRAY_SIZE(s->mhu)); + for (i = 0; i < ARRAY_SIZE(s->mhu); i++) { - char *name; char *port; + int cpunum; + SysBusDevice *mhu_sbd = SYS_BUS_DEVICE(&s->mhu[i]); - name = g_strdup_printf("MHU%d", i); - qdev_prop_set_string(DEVICE(&s->mhu[i]), "name", name); - qdev_prop_set_uint64(DEVICE(&s->mhu[i]), "size", 0x1000); object_property_set_bool(OBJECT(&s->mhu[i]), true, "realized", &err); - g_free(name); if (err) { error_propagate(errp, err); return; } port = g_strdup_printf("port[%d]", i + 3); - mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mhu[i]), 0); + mr = sysbus_mmio_get_region(mhu_sbd, 0); object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), port, &err); g_free(port); @@ -789,6 +802,20 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } + + /* + * Each MHU has an irq line for each CPU: + * MHU 0 irq line 0 -> CPU 0 IRQ 6 + * MHU 0 irq line 1 -> CPU 1 IRQ 6 + * MHU 1 irq line 0 -> CPU 0 IRQ 7 + * MHU 1 irq line 1 -> CPU 1 IRQ 7 + */ + for (cpunum = 0; cpunum < info->num_cpus; cpunum++) { + DeviceState *cpudev = DEVICE(&s->armv7m[cpunum]); + + sysbus_connect_irq(mhu_sbd, cpunum, + qdev_get_gpio_in(cpudev, 6 + i)); + } } } @@ -977,6 +1004,14 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* System information registers */ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000); /* System control registers */ + object_property_set_int(OBJECT(&s->sysctl), info->sys_version, + "SYS_VERSION", &err); + object_property_set_int(OBJECT(&s->sysctl), info->cpuwait_rst, + "CPUWAIT_RST", &err); + object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, + "INITSVTOR0_RST", &err); + object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, + "INITSVTOR1_RST", &err); object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 5158985482..996812498d 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -18,7 +18,7 @@ #include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" #include "hw/boards.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_eeprom.h" #include "qemu/log.h" #include "sysemu/block-backend.h" #include "hw/loader.h" diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index f598a1c053..3d7c88910e 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1286,7 +1286,7 @@ static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int pxa2xx_i2c_rx(I2CSlave *i2c) +static uint8_t pxa2xx_i2c_rx(I2CSlave *i2c) { PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c); PXA2xxI2CState *s = slave->host; diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 442529cc65..7b45fe3ccf 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -811,7 +811,7 @@ static void stellaris_i2c_write(void *opaque, hwaddr offset, /* TODO: Handle errors. */ if (s->msa & 1) { /* Recv */ - s->mdr = i2c_recv(s->bus) & 0xff; + s->mdr = i2c_recv(s->bus); } else { /* Send */ i2c_send(s->bus, s->mdr); diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 7a925fa5e6..eef9d427e7 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -197,10 +197,10 @@ static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int tosa_dac_recv(I2CSlave *s) +static uint8_t tosa_dac_recv(I2CSlave *s) { printf("%s: recv not supported!!!\n", __func__); - return -1; + return 0xff; } static void tosa_tg_init(PXA2xxState *cpu) diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 697a822f1e..6f18d924df 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -243,7 +243,7 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int aer915_recv(I2CSlave *slave) +static uint8_t aer915_recv(I2CSlave *slave) { AER915State *s = AER915(slave); int retval = 0x00; diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c index f4aa838f62..169b006ade 100644 --- a/hw/audio/wm8750.c +++ b/hw/audio/wm8750.c @@ -561,7 +561,7 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data) return 0; } -static int wm8750_rx(I2CSlave *i2c) +static uint8_t wm8750_rx(I2CSlave *i2c) { return 0x00; } diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index c6a15da024..f1523c5b45 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -281,10 +281,6 @@ static void xen_block_complete_aio(void *opaque, int ret) break; case BLKIF_OP_WRITE: case BLKIF_OP_FLUSH_DISKCACHE: - if (!request->req.nr_segments) { - break; - } - break; default: break; } @@ -298,6 +294,7 @@ static void xen_block_complete_aio(void *opaque, int ret) if (!request->req.nr_segments) { break; } + /* fall through */ case BLKIF_OP_READ: if (request->status == BLKIF_RSP_OKAY) { block_acct_done(blk_get_stats(dataplane->blk), &request->acct); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index cf7f47eaba..0cc3c590b9 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -28,9 +28,28 @@ #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" -/* We don't support discard yet, hide associated config fields. */ +/* Config size before the discard support (hide associated config fields) */ #define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \ max_discard_sectors) +/* + * Starting from the discard feature, we can use this array to properly + * set the config size depending on the features enabled. + */ +static VirtIOFeature feature_sizes[] = { + {.flags = 1ULL << VIRTIO_BLK_F_DISCARD, + .end = virtio_endof(struct virtio_blk_config, discard_sector_alignment)}, + {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES, + .end = virtio_endof(struct virtio_blk_config, write_zeroes_may_unmap)}, + {} +}; + +static void virtio_blk_set_config_size(VirtIOBlock *s, uint64_t host_features) +{ + s->config_size = MAX(VIRTIO_BLK_CFG_SIZE, + virtio_feature_get_config_size(feature_sizes, host_features)); + + assert(s->config_size <= sizeof(struct virtio_blk_config)); +} static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, VirtIOBlockReq *req) @@ -65,7 +84,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) } static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, - bool is_read) + bool is_read, bool acct_failed) { VirtIOBlock *s = req->dev; BlockErrorAction action = blk_get_error_action(s->blk, is_read, error); @@ -78,7 +97,9 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, s->rq = req; } else if (action == BLOCK_ERROR_ACTION_REPORT) { virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); - block_acct_failed(blk_get_stats(s->blk), &req->acct); + if (acct_failed) { + block_acct_failed(blk_get_stats(s->blk), &req->acct); + } virtio_blk_free_request(req); } @@ -116,7 +137,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret) * the memory until the request is completed (which will * happen on the other side of the migration). */ - if (virtio_blk_handle_rw_error(req, -ret, is_read)) { + if (virtio_blk_handle_rw_error(req, -ret, is_read, true)) { continue; } } @@ -135,7 +156,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret) aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); if (ret) { - if (virtio_blk_handle_rw_error(req, -ret, 0)) { + if (virtio_blk_handle_rw_error(req, -ret, 0, true)) { goto out; } } @@ -148,6 +169,30 @@ out: aio_context_release(blk_get_aio_context(s->conf.conf.blk)); } +static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret) +{ + VirtIOBlockReq *req = opaque; + VirtIOBlock *s = req->dev; + bool is_write_zeroes = (virtio_ldl_p(VIRTIO_DEVICE(s), &req->out.type) & + ~VIRTIO_BLK_T_BARRIER) == VIRTIO_BLK_T_WRITE_ZEROES; + + aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); + if (ret) { + if (virtio_blk_handle_rw_error(req, -ret, false, is_write_zeroes)) { + goto out; + } + } + + virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); + if (is_write_zeroes) { + block_acct_done(blk_get_stats(s->blk), &req->acct); + } + virtio_blk_free_request(req); + +out: + aio_context_release(blk_get_aio_context(s->conf.conf.blk)); +} + #ifdef __linux__ typedef struct { @@ -243,7 +288,7 @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req) */ scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base; - if (!blk->conf.scsi) { + if (!virtio_has_feature(blk->host_features, VIRTIO_BLK_F_SCSI)) { status = VIRTIO_BLK_S_UNSUPP; goto fail; } @@ -481,6 +526,84 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev, return true; } +static uint8_t virtio_blk_handle_discard_write_zeroes(VirtIOBlockReq *req, + struct virtio_blk_discard_write_zeroes *dwz_hdr, bool is_write_zeroes) +{ + VirtIOBlock *s = req->dev; + VirtIODevice *vdev = VIRTIO_DEVICE(s); + uint64_t sector; + uint32_t num_sectors, flags, max_sectors; + uint8_t err_status; + int bytes; + + sector = virtio_ldq_p(vdev, &dwz_hdr->sector); + num_sectors = virtio_ldl_p(vdev, &dwz_hdr->num_sectors); + flags = virtio_ldl_p(vdev, &dwz_hdr->flags); + max_sectors = is_write_zeroes ? s->conf.max_write_zeroes_sectors : + s->conf.max_discard_sectors; + + /* + * max_sectors is at most BDRV_REQUEST_MAX_SECTORS, this check + * make us sure that "num_sectors << BDRV_SECTOR_BITS" can fit in + * the integer variable. + */ + if (unlikely(num_sectors > max_sectors)) { + err_status = VIRTIO_BLK_S_IOERR; + goto err; + } + + bytes = num_sectors << BDRV_SECTOR_BITS; + + if (unlikely(!virtio_blk_sect_range_ok(s, sector, bytes))) { + err_status = VIRTIO_BLK_S_IOERR; + goto err; + } + + /* + * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard + * and write zeroes commands if any unknown flag is set. + */ + if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { + err_status = VIRTIO_BLK_S_UNSUPP; + goto err; + } + + if (is_write_zeroes) { /* VIRTIO_BLK_T_WRITE_ZEROES */ + int blk_aio_flags = 0; + + if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) { + blk_aio_flags |= BDRV_REQ_MAY_UNMAP; + } + + block_acct_start(blk_get_stats(s->blk), &req->acct, bytes, + BLOCK_ACCT_WRITE); + + blk_aio_pwrite_zeroes(s->blk, sector << BDRV_SECTOR_BITS, + bytes, blk_aio_flags, + virtio_blk_discard_write_zeroes_complete, req); + } else { /* VIRTIO_BLK_T_DISCARD */ + /* + * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for + * discard commands if the unmap flag is set. + */ + if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { + err_status = VIRTIO_BLK_S_UNSUPP; + goto err; + } + + blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes, + virtio_blk_discard_write_zeroes_complete, req); + } + + return VIRTIO_BLK_S_OK; + +err: + if (is_write_zeroes) { + block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE); + } + return err_status; +} + static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) { uint32_t type; @@ -582,6 +705,47 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) virtio_blk_free_request(req); break; } + /* + * VIRTIO_BLK_T_DISCARD and VIRTIO_BLK_T_WRITE_ZEROES are defined with + * VIRTIO_BLK_T_OUT flag set. We masked this flag in the switch statement, + * so we must mask it for these requests, then we will check if it is set. + */ + case VIRTIO_BLK_T_DISCARD & ~VIRTIO_BLK_T_OUT: + case VIRTIO_BLK_T_WRITE_ZEROES & ~VIRTIO_BLK_T_OUT: + { + struct virtio_blk_discard_write_zeroes dwz_hdr; + size_t out_len = iov_size(out_iov, out_num); + bool is_write_zeroes = (type & ~VIRTIO_BLK_T_BARRIER) == + VIRTIO_BLK_T_WRITE_ZEROES; + uint8_t err_status; + + /* + * Unsupported if VIRTIO_BLK_T_OUT is not set or the request contains + * more than one segment. + */ + if (unlikely(!(type & VIRTIO_BLK_T_OUT) || + out_len > sizeof(dwz_hdr))) { + virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); + virtio_blk_free_request(req); + return 0; + } + + if (unlikely(iov_to_buf(out_iov, out_num, 0, &dwz_hdr, + sizeof(dwz_hdr)) != sizeof(dwz_hdr))) { + virtio_error(vdev, "virtio-blk discard/write_zeroes header" + " too short"); + return -1; + } + + err_status = virtio_blk_handle_discard_write_zeroes(req, &dwz_hdr, + is_write_zeroes); + if (err_status != VIRTIO_BLK_S_OK) { + virtio_blk_req_complete(req, err_status); + virtio_blk_free_request(req); + } + + break; + } default: virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); virtio_blk_free_request(req); @@ -675,6 +839,7 @@ static void virtio_blk_dma_restart_bh(void *opaque) if (mrb.num_reqs) { virtio_blk_submit_multireq(s->blk, &mrb); } + blk_dec_in_flight(s->conf.conf.blk); aio_context_release(blk_get_aio_context(s->conf.conf.blk)); } @@ -688,8 +853,11 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, } if (!s->bh) { + /* FIXME The data plane is not started yet, so these requests are + * processed in the main thread. */ s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk), virtio_blk_dma_restart_bh, s); + blk_inc_in_flight(s->conf.conf.blk); qemu_bh_schedule(s->bh); } } @@ -761,8 +929,25 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) blkcfg.alignment_offset = 0; blkcfg.wce = blk_enable_write_cache(s->blk); virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues); - memcpy(config, &blkcfg, VIRTIO_BLK_CFG_SIZE); - QEMU_BUILD_BUG_ON(VIRTIO_BLK_CFG_SIZE > sizeof(blkcfg)); + if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD)) { + virtio_stl_p(vdev, &blkcfg.max_discard_sectors, + s->conf.max_discard_sectors); + virtio_stl_p(vdev, &blkcfg.discard_sector_alignment, + blk_size >> BDRV_SECTOR_BITS); + /* + * We support only one segment per request since multiple segments + * are not widely used and there are no userspace APIs that allow + * applications to submit multiple segments in a single call. + */ + virtio_stl_p(vdev, &blkcfg.max_discard_seg, 1); + } + if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES)) { + virtio_stl_p(vdev, &blkcfg.max_write_zeroes_sectors, + s->conf.max_write_zeroes_sectors); + blkcfg.write_zeroes_may_unmap = 1; + virtio_stl_p(vdev, &blkcfg.max_write_zeroes_seg, 1); + } + memcpy(config, &blkcfg, s->config_size); } static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) @@ -770,8 +955,7 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) VirtIOBlock *s = VIRTIO_BLK(vdev); struct virtio_blk_config blkcfg; - memcpy(&blkcfg, config, VIRTIO_BLK_CFG_SIZE); - QEMU_BUILD_BUG_ON(VIRTIO_BLK_CFG_SIZE > sizeof(blkcfg)); + memcpy(&blkcfg, config, s->config_size); aio_context_acquire(blk_get_aio_context(s->blk)); blk_set_enable_write_cache(s->blk, blkcfg.wce != 0); @@ -783,12 +967,15 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, { VirtIOBlock *s = VIRTIO_BLK(vdev); + /* Firstly sync all virtio-blk possible supported features */ + features |= s->host_features; + virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX); virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) { - if (s->conf.scsi) { + if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_SCSI)) { error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0"); return 0; } @@ -797,9 +984,6 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, virtio_add_feature(&features, VIRTIO_BLK_F_SCSI); } - if (s->conf.config_wce) { - virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE); - } if (blk_enable_write_cache(s->blk)) { virtio_add_feature(&features, VIRTIO_BLK_F_WCE); } @@ -954,7 +1138,28 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, VIRTIO_BLK_CFG_SIZE); + if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD) && + (!conf->max_discard_sectors || + conf->max_discard_sectors > BDRV_REQUEST_MAX_SECTORS)) { + error_setg(errp, "invalid max-discard-sectors property (%" PRIu32 ")" + ", must be between 1 and %d", + conf->max_discard_sectors, (int)BDRV_REQUEST_MAX_SECTORS); + return; + } + + if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES) && + (!conf->max_write_zeroes_sectors || + conf->max_write_zeroes_sectors > BDRV_REQUEST_MAX_SECTORS)) { + error_setg(errp, "invalid max-write-zeroes-sectors property (%" PRIu32 + "), must be between 1 and %d", + conf->max_write_zeroes_sectors, + (int)BDRV_REQUEST_MAX_SECTORS); + return; + } + + virtio_blk_set_config_size(s, s->host_features); + + virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, s->config_size); s->blk = conf->conf.blk; s->rq = NULL; @@ -1013,9 +1218,11 @@ static Property virtio_blk_properties[] = { DEFINE_BLOCK_ERROR_PROPERTIES(VirtIOBlock, conf.conf), DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf), DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial), - DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true), + DEFINE_PROP_BIT64("config-wce", VirtIOBlock, host_features, + VIRTIO_BLK_F_CONFIG_WCE, true), #ifdef __linux__ - DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false), + DEFINE_PROP_BIT64("scsi", VirtIOBlock, host_features, + VIRTIO_BLK_F_SCSI, false), #endif DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0, true), @@ -1023,6 +1230,14 @@ static Property virtio_blk_properties[] = { DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128), DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD, IOThread *), + DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features, + VIRTIO_BLK_F_DISCARD, true), + DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features, + VIRTIO_BLK_F_WRITE_ZEROES, true), + DEFINE_PROP_UINT32("max-discard-sectors", VirtIOBlock, + conf.max_discard_sectors, BDRV_REQUEST_MAX_SECTORS), + DEFINE_PROP_UINT32("max-write-zeroes-sectors", VirtIOBlock, + conf.max_write_zeroes_sectors, BDRV_REQUEST_MAX_SECTORS), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 5012af9cb6..70fc2455e8 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -351,21 +351,28 @@ static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name, g_free(str); } -static unsigned int vbd_name_to_disk(const char *name, const char **endp) +static int vbd_name_to_disk(const char *name, const char **endp, + unsigned long *disk) { - unsigned int disk = 0; + unsigned int n = 0; while (*name != '\0') { if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) { break; } - disk *= 26; - disk += *name++ - 'a' + 1; + n *= 26; + n += *name++ - 'a' + 1; } *endp = name; - return disk - 1; + if (!n) { + return -1; + } + + *disk = n - 1; + + return 0; } static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, @@ -413,13 +420,14 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, } if (*end == 'p') { - p = (char *) ++end; - if (*end == '\0') { + if (*(++end) == '\0') { goto invalid; } } } else { - vdev->disk = vbd_name_to_disk(p, &end); + if (vbd_name_to_disk(p, &end, &vdev->disk)) { + goto invalid; + } } if (*end != '\0') { @@ -735,12 +743,12 @@ static XenBlockDrive *xen_block_drive_create(const char *id, } g_strfreev(v); - } - - if (!filename) { - error_setg(errp, "no filename"); + } else { + error_setg(errp, "no params"); goto done; } + + assert(filename); assert(driver); drive = g_new0(XenBlockDrive, 1); @@ -750,6 +758,7 @@ static XenBlockDrive *xen_block_drive_create(const char *id, qdict_put_str(file_layer, "driver", "file"); qdict_put_str(file_layer, "filename", filename); + g_free(filename); if (mode && *mode != 'w') { qdict_put_bool(file_layer, "read-only", true); @@ -785,16 +794,17 @@ static XenBlockDrive *xen_block_drive_create(const char *id, driver_layer = qdict_new(); qdict_put_str(driver_layer, "driver", driver); + g_free(driver); + qdict_put_obj(driver_layer, "file", QOBJECT(file_layer)); g_assert(!drive->node_name); drive->node_name = xen_block_blockdev_add(drive->id, driver_layer, &local_err); -done: - g_free(driver); - g_free(filename); + qobject_unref(driver_layer); +done: if (local_err) { error_propagate(errp, local_err); xen_block_drive_destroy(drive, NULL); diff --git a/hw/core/machine.c b/hw/core/machine.c index 077fbd182a..766ca5899d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -33,6 +33,8 @@ GlobalProperty hw_compat_3_1[] = { { "usb-kbd", "serial", "42" }, { "usb-mouse", "serial", "42" }, { "usb-kbd", "serial", "42" }, + { "virtio-blk-device", "discard", "false" }, + { "virtio-blk-device", "write-zeroes", "false" }, }; const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1); diff --git a/hw/display/qxl.c b/hw/display/qxl.c index da8fd5a40a..c8ce5781e0 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -276,7 +276,8 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, 0)); } else { -#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ +/* >= release 0.12.6, < release 0.14.2 */ +#if SPICE_SERVER_VERSION >= 0x000c06 && SPICE_SERVER_VERSION < 0x000e02 if (qxl->max_outputs) { spice_qxl_set_max_monitors(&qxl->ssd.qxl, qxl->max_outputs); } @@ -2188,6 +2189,17 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp) SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR); return; } + +#if SPICE_SERVER_VERSION >= 0x000e02 /* release 0.14.2 */ + char device_address[256] = ""; + if (qemu_spice_fill_device_address(qxl->vga.con, device_address, 256)) { + spice_qxl_set_device_info(&qxl->ssd.qxl, + device_address, + 0, + qxl->max_outputs); + } +#endif + qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl); qxl->update_irq = qemu_bh_new(qxl_update_irq_bh, qxl); diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c index eaf11a6e7b..9994385c35 100644 --- a/hw/display/sii9022.c +++ b/hw/display/sii9022.c @@ -79,7 +79,7 @@ static int sii9022_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int sii9022_rx(I2CSlave *i2c) +static uint8_t sii9022_rx(I2CSlave *i2c) { sii9022_state *s = SII9022(i2c); uint8_t res = 0x00; diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c index eb90ba26be..8edf34986c 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -62,10 +62,10 @@ typedef struct { uint8_t framebuffer[132*8]; } ssd0303_state; -static int ssd0303_recv(I2CSlave *i2c) +static uint8_t ssd0303_recv(I2CSlave *i2c) { BADF("Reads not implemented\n"); - return -1; + return 0xff; } static int ssd0303_send(I2CSlave *i2c, uint8_t data) diff --git a/hw/display/trace-events b/hw/display/trace-events index 387c6b8931..37d3264bb2 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -35,6 +35,7 @@ vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp" # hw/display/virtio-gpu.c virtio_gpu_features(bool virgl) "virgl %d" virtio_gpu_cmd_get_display_info(void) "" +virtio_gpu_cmd_get_edid(uint32_t scanout) "scanout %d" virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d" virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d" virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d" diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c index bc6e99c943..2d302526ab 100644 --- a/hw/display/virtio-gpu-3d.c +++ b/hw/display/virtio-gpu-3d.c @@ -404,11 +404,6 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, { VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); - cmd->waiting = g->renderer_blocked; - if (cmd->waiting) { - return; - } - virgl_renderer_force_ctx_0(); switch (cmd->cmd_hdr.type) { case VIRTIO_GPU_CMD_CTX_CREATE: @@ -468,6 +463,9 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: virtio_gpu_get_display_info(g, cmd); break; + case VIRTIO_GPU_CMD_GET_EDID: + virtio_gpu_get_edid(g, cmd); + break; default: cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; break; @@ -604,22 +602,6 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g) } } -void virtio_gpu_gl_block(void *opaque, bool block) -{ - VirtIOGPU *g = opaque; - - if (block) { - g->renderer_blocked++; - } else { - g->renderer_blocked--; - } - assert(g->renderer_blocked >= 0); - - if (g->renderer_blocked == 0) { - virtio_gpu_process_cmdq(g); - } -} - int virtio_gpu_virgl_init(VirtIOGPU *g) { int ret; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index c6fab56f9b..a3627f58a9 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -21,6 +21,7 @@ #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-bus.h" +#include "hw/display/edid.h" #include "migration/blocker.h" #include "qemu/log.h" #include "qapi/error.h" @@ -207,6 +208,9 @@ static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features, if (virtio_gpu_virgl_enabled(g->conf)) { features |= (1 << VIRTIO_GPU_F_VIRGL); } + if (virtio_gpu_edid_enabled(g->conf)) { + features |= (1 << VIRTIO_GPU_F_EDID); + } return features; } @@ -301,6 +305,40 @@ void virtio_gpu_get_display_info(VirtIOGPU *g, sizeof(display_info)); } +static void +virtio_gpu_generate_edid(VirtIOGPU *g, int scanout, + struct virtio_gpu_resp_edid *edid) +{ + qemu_edid_info info = { + .prefx = g->req_state[scanout].width, + .prefy = g->req_state[scanout].height, + }; + + edid->size = cpu_to_le32(sizeof(edid->edid)); + qemu_edid_generate(edid->edid, sizeof(edid->edid), &info); +} + +void virtio_gpu_get_edid(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resp_edid edid; + struct virtio_gpu_cmd_get_edid get_edid; + + VIRTIO_GPU_FILL_CMD(get_edid); + virtio_gpu_bswap_32(&get_edid, sizeof(get_edid)); + + if (get_edid.scanout >= g->conf.max_outputs) { + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + trace_virtio_gpu_cmd_get_edid(get_edid.scanout); + memset(&edid, 0, sizeof(edid)); + edid.hdr.type = VIRTIO_GPU_RESP_OK_EDID; + virtio_gpu_generate_edid(g, get_edid.scanout, &edid); + virtio_gpu_ctrl_response(g, cmd, &edid.hdr, sizeof(edid)); +} + static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format) { switch (virtio_gpu_format) { @@ -839,6 +877,9 @@ static void virtio_gpu_simple_process_cmd(VirtIOGPU *g, case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: virtio_gpu_get_display_info(g, cmd); break; + case VIRTIO_GPU_CMD_GET_EDID: + virtio_gpu_get_edid(g, cmd); + break; case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: virtio_gpu_resource_create_2d(g, cmd); break; @@ -889,12 +930,14 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) while (!QTAILQ_EMPTY(&g->cmdq)) { cmd = QTAILQ_FIRST(&g->cmdq); + if (g->renderer_blocked) { + break; + } + /* process command */ VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd, g, cmd); - if (cmd->waiting) { - break; - } + QTAILQ_REMOVE(&g->cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->conf)) { g->stats.requests++; @@ -936,7 +979,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) cmd->vq = vq; cmd->error = 0; cmd->finished = false; - cmd->waiting = false; QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); } @@ -1030,14 +1072,28 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) return 0; } +static void virtio_gpu_gl_block(void *opaque, bool block) +{ + VirtIOGPU *g = opaque; + + if (block) { + g->renderer_blocked++; + } else { + g->renderer_blocked--; + } + assert(g->renderer_blocked >= 0); + + if (g->renderer_blocked == 0) { + virtio_gpu_process_cmdq(g); + } +} + const GraphicHwOps virtio_gpu_ops = { .invalidate = virtio_gpu_invalidate_display, .gfx_update = virtio_gpu_update_display, .text_update = virtio_gpu_text_update, .ui_info = virtio_gpu_ui_info, -#ifdef CONFIG_VIRGL .gl_block = virtio_gpu_gl_block, -#endif }; static const VMStateDescription vmstate_virtio_gpu_scanout = { @@ -1238,10 +1294,9 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) } } - g->config_size = sizeof(struct virtio_gpu_config); g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, - g->config_size); + sizeof(struct virtio_gpu_config)); g->req_state[0].width = g->conf.xres; g->req_state[0].height = g->conf.yres; @@ -1268,7 +1323,6 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) QTAILQ_INIT(&g->fenceq); g->enabled_output_bitmask = 1; - g->qdev = qdev; for (i = 0; i < g->conf.max_outputs; i++) { g->scanout[i].con = @@ -1356,6 +1410,8 @@ static Property virtio_gpu_properties[] = { DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags, VIRTIO_GPU_FLAG_STATS_ENABLED, false), #endif + DEFINE_PROP_BIT("edid", VirtIOGPU, conf.flags, + VIRTIO_GPU_FLAG_EDID_ENABLED, false), DEFINE_PROP_UINT32("xres", VirtIOGPU, conf.xres, 1024), DEFINE_PROP_UINT32("yres", VirtIOGPU, conf.yres, 768), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c index 1a2478b5a9..c6f686c3eb 100644 --- a/hw/gpio/max7310.c +++ b/hw/gpio/max7310.c @@ -39,7 +39,7 @@ static void max7310_reset(DeviceState *dev) s->command = 0x00; } -static int max7310_rx(I2CSlave *i2c) +static uint8_t max7310_rx(I2CSlave *i2c) { MAX7310State *s = MAX7310(i2c); diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs index cecee486f7..9205cbee16 100644 --- a/hw/i2c/Makefile.objs +++ b/hw/i2c/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-$(CONFIG_I2C) += core.o smbus.o +common-obj-$(CONFIG_I2C) += core.o smbus_slave.o smbus_master.o common-obj-$(CONFIG_SMBUS_EEPROM) += smbus_eeprom.o common-obj-$(CONFIG_DDC) += i2c-ddc.o common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index a2dfa82760..a085510cfd 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -189,16 +189,11 @@ static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus) static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) { - int ret; + uint8_t ret; aspeed_i2c_set_state(bus, I2CD_MRXD); ret = i2c_recv(bus->bus); - if (ret < 0) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__); - ret = 0xff; - } else { - bus->intr_status |= I2CD_INTR_RX_DONE; - } + bus->intr_status |= I2CD_INTR_RX_DONE; bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT; if (bus->cmd & I2CD_M_S_RX_CMD_LAST) { i2c_nack(bus->bus); diff --git a/hw/i2c/core.c b/hw/i2c/core.c index b54725985a..15237ad073 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -191,23 +191,17 @@ int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send) } return ret ? -1 : 0; } else { - if ((QLIST_EMPTY(&bus->current_devs)) || (bus->broadcast)) { - return -1; - } - - sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt); - if (sc->recv) { - s = QLIST_FIRST(&bus->current_devs)->elt; - ret = sc->recv(s); - trace_i2c_recv(s->address, ret); - if (ret < 0) { - return ret; - } else { - *data = ret; - return 0; + ret = 0xff; + if (!QLIST_EMPTY(&bus->current_devs) && !bus->broadcast) { + sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt); + if (sc->recv) { + s = QLIST_FIRST(&bus->current_devs)->elt; + ret = sc->recv(s); + trace_i2c_recv(s->address, ret); } } - return -1; + *data = ret; + return 0; } } @@ -216,12 +210,12 @@ int i2c_send(I2CBus *bus, uint8_t data) return i2c_send_recv(bus, &data, true); } -int i2c_recv(I2CBus *bus) +uint8_t i2c_recv(I2CBus *bus) { - uint8_t data; - int ret = i2c_send_recv(bus, &data, false); + uint8_t data = 0xff; - return ret < 0 ? ret : data; + i2c_send_recv(bus, &data, false); + return data; } void i2c_nack(I2CBus *bus) diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c index c96fa7d7be..d154b05739 100644 --- a/hw/i2c/exynos4210_i2c.c +++ b/hw/i2c/exynos4210_i2c.c @@ -106,16 +106,10 @@ static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s) static void exynos4210_i2c_data_receive(void *opaque) { Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; - int ret; s->i2cstat &= ~I2CSTAT_LAST_BIT; s->scl_free = false; - ret = i2c_recv(s->bus); - if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) { - s->i2cstat |= I2CSTAT_LAST_BIT; /* Data is not acknowledged */ - } else { - s->i2cds = ret; - } + s->i2cds = i2c_recv(s->bus); exynos4210_i2c_raise_interrupt(s); } diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c index 0a0367ff38..7aa8727771 100644 --- a/hw/i2c/i2c-ddc.c +++ b/hw/i2c/i2c-ddc.c @@ -51,7 +51,7 @@ static int i2c_ddc_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int i2c_ddc_rx(I2CSlave *i2c) +static uint8_t i2c_ddc_rx(I2CSlave *i2c) { I2CDDCState *s = I2CDDC(i2c); diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c index 6c81b98ebd..6da5224e2e 100644 --- a/hw/i2c/imx_i2c.c +++ b/hw/i2c/imx_i2c.c @@ -120,7 +120,7 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset, value = s->i2dr_read; if (imx_i2c_is_master(s)) { - int ret = 0xff; + uint8_t ret = 0xff; if (s->address == ADDR_RESET) { /* something is wrong as the address is not set */ @@ -133,15 +133,7 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset, } else { /* get the next byte */ ret = i2c_recv(s->bus); - - if (ret >= 0) { - imx_i2c_raise_interrupt(s); - } else { - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed " - "for device 0x%02x\n", TYPE_IMX_I2C, - __func__, s->address); - ret = 0xff; - } + imx_i2c_raise_interrupt(s); } s->i2dr_read = ret; diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index 03062740cc..e48544f909 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -19,8 +19,9 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" +#include "hw/boards.h" #include "hw/i2c/pm_smbus.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_master.h" #define SMBHSTSTS 0x00 #define SMBHSTCNT 0x02 @@ -118,19 +119,30 @@ static void smb_transaction(PMSMBus *s) } break; case PROT_I2C_BLOCK_READ: - if (read) { - int xfersize = s->smb_data0; - if (xfersize > sizeof(s->smb_data)) { - xfersize = sizeof(s->smb_data); - } - ret = smbus_read_block(bus, addr, s->smb_data1, s->smb_data, - xfersize, false, true); - goto data8; - } else { - /* The manual says the behavior is undefined, just set DEV_ERR. */ + /* According to the Linux i2c-i801 driver: + * NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading. + * However if SPD Write Disable is set (Lynx Point and later), + * the read will fail if we don't set the R/#W bit. + * So at least Linux may or may not set the read bit here. + * So just ignore the read bit for this command. + */ + if (i2c_start_transfer(bus, addr, 0)) { goto error; } - break; + ret = i2c_send(bus, s->smb_data1); + if (ret) { + goto error; + } + if (i2c_start_transfer(bus, addr, 1)) { + goto error; + } + s->in_i2c_block_read = true; + s->smb_blkdata = i2c_recv(s->smbus); + s->op_done = false; + s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE; + goto out; + case PROT_BLOCK_DATA: if (read) { ret = smbus_read_block(bus, addr, cmd, s->smb_data, @@ -208,6 +220,7 @@ static void smb_transaction_start(PMSMBus *s) { if (s->smb_ctl & CTL_INTREN) { smb_transaction(s); + s->start_transaction_on_status_read = false; } else { /* Do not execute immediately the command; it will be * executed when guest will read SMB_STAT register. This @@ -217,6 +230,7 @@ static void smb_transaction_start(PMSMBus *s) * checking for status. If STS_HOST_BUSY doesn't get * set, it gets stuck. */ s->smb_stat |= STS_HOST_BUSY; + s->start_transaction_on_status_read = true; } } @@ -226,19 +240,38 @@ smb_irq_value(PMSMBus *s) return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN); } +static bool +smb_byte_by_byte(PMSMBus *s) +{ + if (s->op_done) { + return false; + } + if (s->in_i2c_block_read) { + return true; + } + return !(s->smb_auxctl & AUX_BLK); +} + static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, unsigned width) { PMSMBus *s = opaque; + uint8_t clear_byte_done; SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx " val=0x%02" PRIx64 "\n", addr, val); switch(addr) { case SMBHSTSTS: + clear_byte_done = s->smb_stat & val & STS_BYTE_DONE; s->smb_stat &= ~(val & ~STS_HOST_BUSY); - if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) { + if (clear_byte_done && smb_byte_by_byte(s)) { uint8_t read = s->smb_addr & 0x01; + if (s->in_i2c_block_read) { + /* See comment below PROT_I2C_BLOCK_READ above. */ + read = 1; + } + s->smb_index++; if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { s->smb_index = 0; @@ -268,12 +301,23 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, s->smb_stat |= STS_BYTE_DONE; } else if (s->smb_ctl & CTL_LAST_BYTE) { s->op_done = true; - s->smb_blkdata = s->smb_data[s->smb_index]; + if (s->in_i2c_block_read) { + s->in_i2c_block_read = false; + s->smb_blkdata = i2c_recv(s->smbus); + i2c_nack(s->smbus); + i2c_end_transfer(s->smbus); + } else { + s->smb_blkdata = s->smb_data[s->smb_index]; + } s->smb_index = 0; s->smb_stat |= STS_INTR; s->smb_stat &= ~STS_HOST_BUSY; } else { - s->smb_blkdata = s->smb_data[s->smb_index]; + if (s->in_i2c_block_read) { + s->smb_blkdata = i2c_recv(s->smbus); + } else { + s->smb_blkdata = s->smb_data[s->smb_index]; + } s->smb_stat |= STS_BYTE_DONE; } } @@ -284,6 +328,10 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, if (!s->op_done) { s->smb_index = 0; s->op_done = true; + if (s->in_i2c_block_read) { + s->in_i2c_block_read = false; + i2c_end_transfer(s->smbus); + } } smb_transaction_start(s); } @@ -337,8 +385,9 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) switch(addr) { case SMBHSTSTS: val = s->smb_stat; - if (s->smb_stat & STS_HOST_BUSY) { + if (s->start_transaction_on_status_read) { /* execute command now */ + s->start_transaction_on_status_read = false; s->smb_stat &= ~STS_HOST_BUSY; smb_transaction(s); } @@ -359,10 +408,10 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) val = s->smb_data1; break; case SMBBLKDAT: - if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { - s->smb_index = 0; - } - if (s->smb_auxctl & AUX_BLK) { + if (s->smb_auxctl & AUX_BLK && !s->in_i2c_block_read) { + if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { + s->smb_index = 0; + } val = s->smb_data[s->smb_index++]; if (!s->op_done && s->smb_index == s->smb_data0) { s->op_done = true; @@ -405,6 +454,36 @@ static const MemoryRegionOps pm_smbus_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +bool pm_smbus_vmstate_needed(void) +{ + MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); + + return !mc->smbus_no_migration_support; +} + +const VMStateDescription pmsmb_vmstate = { + .name = "pmsmb", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(smb_stat, PMSMBus), + VMSTATE_UINT8(smb_ctl, PMSMBus), + VMSTATE_UINT8(smb_cmd, PMSMBus), + VMSTATE_UINT8(smb_addr, PMSMBus), + VMSTATE_UINT8(smb_data0, PMSMBus), + VMSTATE_UINT8(smb_data1, PMSMBus), + VMSTATE_UINT32(smb_index, PMSMBus), + VMSTATE_UINT8_ARRAY(smb_data, PMSMBus, PM_SMBUS_MAX_MSG_SIZE), + VMSTATE_UINT8(smb_auxctl, PMSMBus), + VMSTATE_UINT8(smb_blkdata, PMSMBus), + VMSTATE_BOOL(i2c_enable, PMSMBus), + VMSTATE_BOOL(op_done, PMSMBus), + VMSTATE_BOOL(in_i2c_block_read, PMSMBus), + VMSTATE_BOOL(start_transaction_on_status_read, PMSMBus), + VMSTATE_END_OF_LIST() + } +}; + void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk) { smb->op_done = true; diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c deleted file mode 100644 index 30028bfcc2..0000000000 --- a/hw/i2c/smbus.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * QEMU SMBus device emulation. - * - * Copyright (c) 2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the LGPL. - */ - -/* TODO: Implement PEC. */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i2c/i2c.h" -#include "hw/i2c/smbus.h" - -//#define DEBUG_SMBUS 1 - -#ifdef DEBUG_SMBUS -#define DPRINTF(fmt, ...) \ -do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0) -#endif - -enum { - SMBUS_IDLE, - SMBUS_WRITE_DATA, - SMBUS_RECV_BYTE, - SMBUS_READ_DATA, - SMBUS_DONE, - SMBUS_CONFUSED = -1 -}; - -static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) -{ - SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); - - DPRINTF("Quick Command %d\n", recv); - if (sc->quick_cmd) { - sc->quick_cmd(dev, recv); - } -} - -static void smbus_do_write(SMBusDevice *dev) -{ - SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); - - if (dev->data_len == 0) { - smbus_do_quick_cmd(dev, 0); - } else if (dev->data_len == 1) { - DPRINTF("Send Byte\n"); - if (sc->send_byte) { - sc->send_byte(dev, dev->data_buf[0]); - } - } else { - dev->command = dev->data_buf[0]; - DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1); - if (sc->write_data) { - sc->write_data(dev, dev->command, dev->data_buf + 1, - dev->data_len - 1); - } - } -} - -static int smbus_i2c_event(I2CSlave *s, enum i2c_event event) -{ - SMBusDevice *dev = SMBUS_DEVICE(s); - - switch (event) { - case I2C_START_SEND: - switch (dev->mode) { - case SMBUS_IDLE: - DPRINTF("Incoming data\n"); - dev->mode = SMBUS_WRITE_DATA; - break; - default: - BADF("Unexpected send start condition in state %d\n", dev->mode); - dev->mode = SMBUS_CONFUSED; - break; - } - break; - - case I2C_START_RECV: - switch (dev->mode) { - case SMBUS_IDLE: - DPRINTF("Read mode\n"); - dev->mode = SMBUS_RECV_BYTE; - break; - case SMBUS_WRITE_DATA: - if (dev->data_len == 0) { - BADF("Read after write with no data\n"); - dev->mode = SMBUS_CONFUSED; - } else { - if (dev->data_len > 1) { - smbus_do_write(dev); - } else { - dev->command = dev->data_buf[0]; - DPRINTF("%02x: Command %d\n", dev->i2c.address, - dev->command); - } - DPRINTF("Read mode\n"); - dev->data_len = 0; - dev->mode = SMBUS_READ_DATA; - } - break; - default: - BADF("Unexpected recv start condition in state %d\n", dev->mode); - dev->mode = SMBUS_CONFUSED; - break; - } - break; - - case I2C_FINISH: - switch (dev->mode) { - case SMBUS_WRITE_DATA: - smbus_do_write(dev); - break; - case SMBUS_RECV_BYTE: - smbus_do_quick_cmd(dev, 1); - break; - case SMBUS_READ_DATA: - BADF("Unexpected stop during receive\n"); - break; - default: - /* Nothing to do. */ - break; - } - dev->mode = SMBUS_IDLE; - dev->data_len = 0; - break; - - case I2C_NACK: - switch (dev->mode) { - case SMBUS_DONE: - /* Nothing to do. */ - break; - case SMBUS_READ_DATA: - dev->mode = SMBUS_DONE; - break; - default: - BADF("Unexpected NACK in state %d\n", dev->mode); - dev->mode = SMBUS_CONFUSED; - break; - } - } - - return 0; -} - -static int smbus_i2c_recv(I2CSlave *s) -{ - SMBusDevice *dev = SMBUS_DEVICE(s); - SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); - int ret; - - switch (dev->mode) { - case SMBUS_RECV_BYTE: - if (sc->receive_byte) { - ret = sc->receive_byte(dev); - } else { - ret = 0; - } - DPRINTF("Receive Byte %02x\n", ret); - dev->mode = SMBUS_DONE; - break; - case SMBUS_READ_DATA: - if (sc->read_data) { - ret = sc->read_data(dev, dev->command, dev->data_len); - dev->data_len++; - } else { - ret = 0; - } - DPRINTF("Read data %02x\n", ret); - break; - default: - BADF("Unexpected read in state %d\n", dev->mode); - dev->mode = SMBUS_CONFUSED; - ret = 0; - break; - } - return ret; -} - -static int smbus_i2c_send(I2CSlave *s, uint8_t data) -{ - SMBusDevice *dev = SMBUS_DEVICE(s); - - switch (dev->mode) { - case SMBUS_WRITE_DATA: - DPRINTF("Write data %02x\n", data); - if (dev->data_len >= sizeof(dev->data_buf)) { - BADF("Too many bytes sent\n"); - } else { - dev->data_buf[dev->data_len++] = data; - } - break; - default: - BADF("Unexpected write in state %d\n", dev->mode); - break; - } - return 0; -} - -/* Master device commands. */ -int smbus_quick_command(I2CBus *bus, uint8_t addr, int read) -{ - if (i2c_start_transfer(bus, addr, read)) { - return -1; - } - i2c_end_transfer(bus); - return 0; -} - -int smbus_receive_byte(I2CBus *bus, uint8_t addr) -{ - uint8_t data; - - if (i2c_start_transfer(bus, addr, 1)) { - return -1; - } - data = i2c_recv(bus); - i2c_nack(bus); - i2c_end_transfer(bus); - return data; -} - -int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data) -{ - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, data); - i2c_end_transfer(bus); - return 0; -} - -int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) -{ - uint8_t data; - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - if (i2c_start_transfer(bus, addr, 1)) { - i2c_end_transfer(bus); - return -1; - } - data = i2c_recv(bus); - i2c_nack(bus); - i2c_end_transfer(bus); - return data; -} - -int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data) -{ - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - i2c_send(bus, data); - i2c_end_transfer(bus); - return 0; -} - -int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) -{ - uint16_t data; - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - if (i2c_start_transfer(bus, addr, 1)) { - i2c_end_transfer(bus); - return -1; - } - data = i2c_recv(bus); - data |= i2c_recv(bus) << 8; - i2c_nack(bus); - i2c_end_transfer(bus); - return data; -} - -int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) -{ - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - i2c_send(bus, data & 0xff); - i2c_send(bus, data >> 8); - i2c_end_transfer(bus); - return 0; -} - -int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, - int len, bool recv_len, bool send_cmd) -{ - int rlen; - int i; - - if (send_cmd) { - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - } - if (i2c_start_transfer(bus, addr, 1)) { - if (send_cmd) { - i2c_end_transfer(bus); - } - return -1; - } - if (recv_len) { - rlen = i2c_recv(bus); - } else { - rlen = len; - } - if (rlen > len) { - rlen = 0; - } - for (i = 0; i < rlen; i++) { - data[i] = i2c_recv(bus); - } - i2c_nack(bus); - i2c_end_transfer(bus); - return rlen; -} - -int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, - int len, bool send_len) -{ - int i; - - if (len > 32) - len = 32; - - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - if (send_len) { - i2c_send(bus, len); - } - for (i = 0; i < len; i++) { - i2c_send(bus, data[i]); - } - i2c_end_transfer(bus); - return 0; -} - -static void smbus_device_class_init(ObjectClass *klass, void *data) -{ - I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); - - sc->event = smbus_i2c_event; - sc->recv = smbus_i2c_recv; - sc->send = smbus_i2c_send; -} - -static const TypeInfo smbus_device_type_info = { - .name = TYPE_SMBUS_DEVICE, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(SMBusDevice), - .abstract = true, - .class_size = sizeof(SMBusDeviceClass), - .class_init = smbus_device_class_init, -}; - -static void smbus_device_register_types(void) -{ - type_register_static(&smbus_device_type_info); -} - -type_init(smbus_device_register_types) diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c index 01b9439014..37167e7244 100644 --- a/hw/i2c/smbus_eeprom.c +++ b/hw/i2c/smbus_eeprom.c @@ -26,39 +26,35 @@ #include "qemu/units.h" #include "qapi/error.h" #include "hw/hw.h" +#include "hw/boards.h" #include "hw/i2c/i2c.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_slave.h" +#include "hw/i2c/smbus_eeprom.h" //#define DEBUG +#define TYPE_SMBUS_EEPROM "smbus-eeprom" + +#define SMBUS_EEPROM(obj) \ + OBJECT_CHECK(SMBusEEPROMDevice, (obj), TYPE_SMBUS_EEPROM) + +#define SMBUS_EEPROM_SIZE 256 + typedef struct SMBusEEPROMDevice { SMBusDevice smbusdev; - void *data; + uint8_t data[SMBUS_EEPROM_SIZE]; + void *init_data; uint8_t offset; + bool accessed; } SMBusEEPROMDevice; -static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read) -{ -#ifdef DEBUG - printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read); -#endif -} - -static void eeprom_send_byte(SMBusDevice *dev, uint8_t val) -{ - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; -#ifdef DEBUG - printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n", - dev->i2c.address, val); -#endif - eeprom->offset = val; -} - static uint8_t eeprom_receive_byte(SMBusDevice *dev) { - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; + SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev); uint8_t *data = eeprom->data; uint8_t val = data[eeprom->offset++]; + + eeprom->accessed = true; #ifdef DEBUG printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n", dev->i2c.address, val); @@ -66,48 +62,77 @@ static uint8_t eeprom_receive_byte(SMBusDevice *dev) return val; } -static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len) +static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len) { - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; - int n; + SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev); + uint8_t *data = eeprom->data; + + eeprom->accessed = true; #ifdef DEBUG printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", - dev->i2c.address, cmd, buf[0]); + dev->i2c.address, buf[0], buf[1]); #endif - /* A page write operation is not a valid SMBus command. - It is a block write without a length byte. Fortunately we - get the full block anyway. */ - /* TODO: Should this set the current location? */ - if (cmd + len > 256) - n = 256 - cmd; - else - n = len; - memcpy(eeprom->data + cmd, buf, n); - len -= n; - if (len) - memcpy(eeprom->data, buf + n, len); + /* len is guaranteed to be > 0 */ + eeprom->offset = buf[0]; + buf++; + len--; + + for (; len > 0; len--) { + data[eeprom->offset] = *buf++; + eeprom->offset = (eeprom->offset + 1) % SMBUS_EEPROM_SIZE; + } + + return 0; } -static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) +static bool smbus_eeprom_vmstate_needed(void *opaque) { - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; - /* If this is the first byte then set the current position. */ - if (n == 0) - eeprom->offset = cmd; - /* As with writes, we implement block reads without the - SMBus length byte. */ - return eeprom_receive_byte(dev); + MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); + SMBusEEPROMDevice *eeprom = opaque; + + return (eeprom->accessed || smbus_vmstate_needed(&eeprom->smbusdev)) && + !mc->smbus_no_migration_support; } -static void smbus_eeprom_realize(DeviceState *dev, Error **errp) +static const VMStateDescription vmstate_smbus_eeprom = { + .name = "smbus-eeprom", + .version_id = 1, + .minimum_version_id = 1, + .needed = smbus_eeprom_vmstate_needed, + .fields = (VMStateField[]) { + VMSTATE_SMBUS_DEVICE(smbusdev, SMBusEEPROMDevice), + VMSTATE_UINT8_ARRAY(data, SMBusEEPROMDevice, SMBUS_EEPROM_SIZE), + VMSTATE_UINT8(offset, SMBusEEPROMDevice), + VMSTATE_BOOL(accessed, SMBusEEPROMDevice), + VMSTATE_END_OF_LIST() + } +}; + +/* + * Reset the EEPROM contents to the initial state on a reset. This + * isn't really how an EEPROM works, of course, but the general + * principle of QEMU is to restore function on reset to what it would + * be if QEMU was stopped and started. + * + * The proper thing to do would be to have a backing blockdev to hold + * the contents and restore that on startup, and not do this on reset. + * But until that time, act as if we had been stopped and restarted. + */ +static void smbus_eeprom_reset(DeviceState *dev) { - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev; + SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev); + memcpy(eeprom->data, eeprom->init_data, SMBUS_EEPROM_SIZE); eeprom->offset = 0; } +static void smbus_eeprom_realize(DeviceState *dev, Error **errp) +{ + smbus_eeprom_reset(dev); +} + static Property smbus_eeprom_properties[] = { - DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data), + DEFINE_PROP_PTR("data", SMBusEEPROMDevice, init_data), DEFINE_PROP_END_OF_LIST(), }; @@ -117,18 +142,17 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data) SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); dc->realize = smbus_eeprom_realize; - sc->quick_cmd = eeprom_quick_cmd; - sc->send_byte = eeprom_send_byte; + dc->reset = smbus_eeprom_reset; sc->receive_byte = eeprom_receive_byte; sc->write_data = eeprom_write_data; - sc->read_data = eeprom_read_data; dc->props = smbus_eeprom_properties; + dc->vmsd = &vmstate_smbus_eeprom; /* Reason: pointer property "data" */ dc->user_creatable = false; } static const TypeInfo smbus_eeprom_info = { - .name = "smbus-eeprom", + .name = TYPE_SMBUS_EEPROM, .parent = TYPE_SMBUS_DEVICE, .instance_size = sizeof(SMBusEEPROMDevice), .class_init = smbus_eeprom_class_initfn, @@ -145,7 +169,7 @@ void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf) { DeviceState *dev; - dev = qdev_create((BusState *) smbus, "smbus-eeprom"); + dev = qdev_create((BusState *) smbus, TYPE_SMBUS_EEPROM); qdev_prop_set_uint8(dev, "address", address); qdev_prop_set_ptr(dev, "data", eeprom_buf); qdev_init_nofail(dev); @@ -155,13 +179,17 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, const uint8_t *eeprom_spd, int eeprom_spd_size) { int i; - uint8_t *eeprom_buf = g_malloc0(8 * 256); /* XXX: make this persistent */ + /* XXX: make this persistent */ + + assert(nb_eeprom <= 8); + uint8_t *eeprom_buf = g_malloc0(8 * SMBUS_EEPROM_SIZE); if (eeprom_spd_size > 0) { memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size); } for (i = 0; i < nb_eeprom; i++) { - smbus_eeprom_init_one(smbus, 0x50 + i, eeprom_buf + (i * 256)); + smbus_eeprom_init_one(smbus, 0x50 + i, + eeprom_buf + (i * SMBUS_EEPROM_SIZE)); } } diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index 2a8b49e02f..7b24be8256 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -29,8 +29,6 @@ #include "hw/i2c/pm_smbus.h" #include "hw/pci/pci.h" #include "sysemu/sysemu.h" -#include "hw/i2c/i2c.h" -#include "hw/i2c/smbus.h" #include "hw/i386/ich9.h" @@ -45,12 +43,20 @@ typedef struct ICH9SMBState { PMSMBus smb; } ICH9SMBState; +static bool ich9_vmstate_need_smbus(void *opaque, int version_id) +{ + return pm_smbus_vmstate_needed(); +} + static const VMStateDescription vmstate_ich9_smbus = { .name = "ich9_smb", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState), + VMSTATE_PCI_DEVICE(dev, ICH9SMBState), + VMSTATE_BOOL_TEST(irq_enabled, ICH9SMBState, ich9_vmstate_need_smbus), + VMSTATE_STRUCT_TEST(smb, ICH9SMBState, ich9_vmstate_need_smbus, 1, + pmsmb_vmstate, PMSMBus), VMSTATE_END_OF_LIST() } }; diff --git a/hw/i2c/smbus_master.c b/hw/i2c/smbus_master.c new file mode 100644 index 0000000000..0a6223744c --- /dev/null +++ b/hw/i2c/smbus_master.c @@ -0,0 +1,165 @@ +/* + * QEMU SMBus host (master) emulation. + * + * This code emulates SMBus transactions from the master point of view, + * it runs the individual I2C transaction to do the SMBus protocol + * over I2C. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the LGPL. + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/smbus_master.h" + +/* Master device commands. */ +int smbus_quick_command(I2CBus *bus, uint8_t addr, int read) +{ + if (i2c_start_transfer(bus, addr, read)) { + return -1; + } + i2c_end_transfer(bus); + return 0; +} + +int smbus_receive_byte(I2CBus *bus, uint8_t addr) +{ + uint8_t data; + + if (i2c_start_transfer(bus, addr, 1)) { + return -1; + } + data = i2c_recv(bus); + i2c_nack(bus); + i2c_end_transfer(bus); + return data; +} + +int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data) +{ + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } + i2c_send(bus, data); + i2c_end_transfer(bus); + return 0; +} + +int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) +{ + uint8_t data; + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } + i2c_send(bus, command); + if (i2c_start_transfer(bus, addr, 1)) { + i2c_end_transfer(bus); + return -1; + } + data = i2c_recv(bus); + i2c_nack(bus); + i2c_end_transfer(bus); + return data; +} + +int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data) +{ + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } + i2c_send(bus, command); + i2c_send(bus, data); + i2c_end_transfer(bus); + return 0; +} + +int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) +{ + uint16_t data; + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } + i2c_send(bus, command); + if (i2c_start_transfer(bus, addr, 1)) { + i2c_end_transfer(bus); + return -1; + } + data = i2c_recv(bus); + data |= i2c_recv(bus) << 8; + i2c_nack(bus); + i2c_end_transfer(bus); + return data; +} + +int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) +{ + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } + i2c_send(bus, command); + i2c_send(bus, data & 0xff); + i2c_send(bus, data >> 8); + i2c_end_transfer(bus); + return 0; +} + +int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, + int len, bool recv_len, bool send_cmd) +{ + int rlen; + int i; + + if (send_cmd) { + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } + i2c_send(bus, command); + } + if (i2c_start_transfer(bus, addr, 1)) { + if (send_cmd) { + i2c_end_transfer(bus); + } + return -1; + } + if (recv_len) { + rlen = i2c_recv(bus); + } else { + rlen = len; + } + if (rlen > len) { + rlen = 0; + } + for (i = 0; i < rlen; i++) { + data[i] = i2c_recv(bus); + } + i2c_nack(bus); + i2c_end_transfer(bus); + return rlen; +} + +int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, + int len, bool send_len) +{ + int i; + + if (len > 32) { + len = 32; + } + + if (i2c_start_transfer(bus, addr, 0)) { + return -1; + } + i2c_send(bus, command); + if (send_len) { + i2c_send(bus, len); + } + for (i = 0; i < len; i++) { + i2c_send(bus, data[i]); + } + i2c_end_transfer(bus); + return 0; +} diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c new file mode 100644 index 0000000000..9a2d314d1a --- /dev/null +++ b/hw/i2c/smbus_slave.c @@ -0,0 +1,236 @@ +/* + * QEMU SMBus device emulation. + * + * This code is a helper for SMBus device emulation. It implements an + * I2C device inteface and runs the SMBus protocol from the device + * point of view and maps those to simple calls to emulate. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the LGPL. + */ + +/* TODO: Implement PEC. */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/smbus_slave.h" + +//#define DEBUG_SMBUS 1 + +#ifdef DEBUG_SMBUS +#define DPRINTF(fmt, ...) \ +do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0) +#define BADF(fmt, ...) \ +do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) +#else +#define DPRINTF(fmt, ...) do {} while(0) +#define BADF(fmt, ...) \ +do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0) +#endif + +enum { + SMBUS_IDLE, + SMBUS_WRITE_DATA, + SMBUS_READ_DATA, + SMBUS_DONE, + SMBUS_CONFUSED = -1 +}; + +static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) +{ + SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); + + DPRINTF("Quick Command %d\n", recv); + if (sc->quick_cmd) { + sc->quick_cmd(dev, recv); + } +} + +static void smbus_do_write(SMBusDevice *dev) +{ + SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); + + DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len); + if (sc->write_data) { + sc->write_data(dev, dev->data_buf, dev->data_len); + } +} + +static int smbus_i2c_event(I2CSlave *s, enum i2c_event event) +{ + SMBusDevice *dev = SMBUS_DEVICE(s); + + switch (event) { + case I2C_START_SEND: + switch (dev->mode) { + case SMBUS_IDLE: + DPRINTF("Incoming data\n"); + dev->mode = SMBUS_WRITE_DATA; + break; + + default: + BADF("Unexpected send start condition in state %d\n", dev->mode); + dev->mode = SMBUS_CONFUSED; + break; + } + break; + + case I2C_START_RECV: + switch (dev->mode) { + case SMBUS_IDLE: + DPRINTF("Read mode\n"); + dev->mode = SMBUS_READ_DATA; + break; + + case SMBUS_WRITE_DATA: + if (dev->data_len == 0) { + BADF("Read after write with no data\n"); + dev->mode = SMBUS_CONFUSED; + } else { + smbus_do_write(dev); + DPRINTF("Read mode\n"); + dev->mode = SMBUS_READ_DATA; + } + break; + + default: + BADF("Unexpected recv start condition in state %d\n", dev->mode); + dev->mode = SMBUS_CONFUSED; + break; + } + break; + + case I2C_FINISH: + if (dev->data_len == 0) { + if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) { + smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA); + } + } else { + switch (dev->mode) { + case SMBUS_WRITE_DATA: + smbus_do_write(dev); + break; + + case SMBUS_READ_DATA: + BADF("Unexpected stop during receive\n"); + break; + + default: + /* Nothing to do. */ + break; + } + } + dev->mode = SMBUS_IDLE; + dev->data_len = 0; + break; + + case I2C_NACK: + switch (dev->mode) { + case SMBUS_DONE: + /* Nothing to do. */ + break; + + case SMBUS_READ_DATA: + dev->mode = SMBUS_DONE; + break; + + default: + BADF("Unexpected NACK in state %d\n", dev->mode); + dev->mode = SMBUS_CONFUSED; + break; + } + } + + return 0; +} + +static uint8_t smbus_i2c_recv(I2CSlave *s) +{ + SMBusDevice *dev = SMBUS_DEVICE(s); + SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); + uint8_t ret = 0xff; + + switch (dev->mode) { + case SMBUS_READ_DATA: + if (sc->receive_byte) { + ret = sc->receive_byte(dev); + } + DPRINTF("Read data %02x\n", ret); + break; + + default: + BADF("Unexpected read in state %d\n", dev->mode); + dev->mode = SMBUS_CONFUSED; + break; + } + + return ret; +} + +static int smbus_i2c_send(I2CSlave *s, uint8_t data) +{ + SMBusDevice *dev = SMBUS_DEVICE(s); + + switch (dev->mode) { + case SMBUS_WRITE_DATA: + DPRINTF("Write data %02x\n", data); + if (dev->data_len >= sizeof(dev->data_buf)) { + BADF("Too many bytes sent\n"); + } else { + dev->data_buf[dev->data_len++] = data; + } + break; + + default: + BADF("Unexpected write in state %d\n", dev->mode); + break; + } + + return 0; +} + +static void smbus_device_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); + + sc->event = smbus_i2c_event; + sc->recv = smbus_i2c_recv; + sc->send = smbus_i2c_send; +} + +bool smbus_vmstate_needed(SMBusDevice *dev) +{ + return dev->mode != SMBUS_IDLE; +} + +const VMStateDescription vmstate_smbus_device = { + .name = TYPE_SMBUS_DEVICE, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_I2C_SLAVE(i2c, SMBusDevice), + VMSTATE_INT32(mode, SMBusDevice), + VMSTATE_INT32(data_len, SMBusDevice), + VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN), + VMSTATE_END_OF_LIST() + } +}; + +static const TypeInfo smbus_device_type_info = { + .name = TYPE_SMBUS_DEVICE, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(SMBusDevice), + .abstract = true, + .class_size = sizeof(SMBusDeviceClass), + .class_init = smbus_device_class_init, +}; + +static void smbus_device_register_types(void) +{ + type_register_static(&smbus_device_type_info); +} + +type_init(smbus_device_register_types) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index fd0f2c268f..8770ecada9 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -42,7 +42,7 @@ #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/arch_init.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_eeprom.h" #include "hw/xen/xen.h" #include "exec/memory.h" #include "exec/address-spaces.h" @@ -444,6 +444,7 @@ static void pc_i440fx_3_1_machine_options(MachineClass *m) pc_i440fx_4_0_machine_options(m); m->is_default = 0; + m->smbus_no_migration_support = true; m->alias = NULL; pcmc->pvh_enabled = false; compat_props_add(m->compat_props, hw_compat_3_1, hw_compat_3_1_len); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 4a175ea50e..cfb9043e12 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -33,7 +33,7 @@ #include "hw/hw.h" #include "hw/loader.h" #include "sysemu/arch_init.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_eeprom.h" #include "hw/boards.h" #include "hw/timer/mc146818rtc.h" #include "hw/xen/xen.h" @@ -380,6 +380,7 @@ static void pc_q35_3_1_machine_options(MachineClass *m) pc_q35_4_0_machine_options(m); m->default_kernel_irqchip_split = false; + m->smbus_no_migration_support = true; m->alias = NULL; pcmc->pvh_enabled = false; compat_props_add(m->compat_props, hw_compat_3_1, hw_compat_3_1_len); diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 39e473f9c2..1b0f66cc08 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -174,16 +174,15 @@ static void cd_read_sector_cb(void *opaque, int ret) static int cd_read_sector(IDEState *s) { + void *buf; + if (s->cd_sector_size != 2048 && s->cd_sector_size != 2352) { block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ); return -EINVAL; } - s->iov.iov_base = (s->cd_sector_size == 2352) ? - s->io_buffer + 16 : s->io_buffer; - - s->iov.iov_len = ATAPI_SECTOR_SIZE; - qemu_iovec_init_external(&s->qiov, &s->iov, 1); + buf = (s->cd_sector_size == 2352) ? s->io_buffer + 16 : s->io_buffer; + qemu_iovec_init_buf(&s->qiov, buf, ATAPI_SECTOR_SIZE); trace_cd_read_sector(s->lba); @@ -421,9 +420,8 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) data_offset = 0; } trace_ide_atapi_cmd_read_dma_cb_aio(s, s->lba, n); - s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset); - s->bus->dma->iov.iov_len = n * ATAPI_SECTOR_SIZE; - qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1); + qemu_iovec_init_buf(&s->bus->dma->qiov, s->io_buffer + data_offset, + n * ATAPI_SECTOR_SIZE); s->bus->dma->aiocb = ide_buffered_readv(s, (int64_t)s->lba << 2, &s->bus->dma->qiov, n * 4, diff --git a/hw/ide/core.c b/hw/ide/core.c index 84832008b8..6afadf894f 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -629,13 +629,15 @@ static void ide_buffered_readv_cb(void *opaque, int ret) IDEBufferedRequest *req = opaque; if (!req->orphaned) { if (!ret) { - qemu_iovec_from_buf(req->original_qiov, 0, req->iov.iov_base, + assert(req->qiov.size == req->original_qiov->size); + qemu_iovec_from_buf(req->original_qiov, 0, + req->qiov.local_iov.iov_base, req->original_qiov->size); } req->original_cb(req->original_opaque, ret); } QLIST_REMOVE(req, list); - qemu_vfree(req->iov.iov_base); + qemu_vfree(qemu_iovec_buf(&req->qiov)); g_free(req); } @@ -660,9 +662,8 @@ BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num, req->original_qiov = iov; req->original_cb = cb; req->original_opaque = opaque; - req->iov.iov_base = qemu_blockalign(blk_bs(s->blk), iov->size); - req->iov.iov_len = iov->size; - qemu_iovec_init_external(&req->qiov, &req->iov, 1); + qemu_iovec_init_buf(&req->qiov, blk_blockalign(s->blk, iov->size), + iov->size); aioreq = blk_aio_preadv(s->blk, sector_num << BDRV_SECTOR_BITS, &req->qiov, 0, ide_buffered_readv_cb, req); @@ -774,9 +775,7 @@ static void ide_sector_read(IDEState *s) return; } - s->iov.iov_base = s->io_buffer; - s->iov.iov_len = n * BDRV_SECTOR_SIZE; - qemu_iovec_init_external(&s->qiov, &s->iov, 1); + qemu_iovec_init_buf(&s->qiov, s->io_buffer, n * BDRV_SECTOR_SIZE); block_acct_start(blk_get_stats(s->blk), &s->acct, n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ); @@ -1045,9 +1044,7 @@ static void ide_sector_write(IDEState *s) return; } - s->iov.iov_base = s->io_buffer; - s->iov.iov_len = n * BDRV_SECTOR_SIZE; - qemu_iovec_init_external(&s->qiov, &s->iov, 1); + qemu_iovec_init_buf(&s->qiov, s->io_buffer, n * BDRV_SECTOR_SIZE); block_acct_start(blk_get_stats(s->blk), &s->acct, n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE); diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c index cffbf586d4..1fc7b86f19 100644 --- a/hw/input/lm832x.c +++ b/hw/input/lm832x.c @@ -401,7 +401,7 @@ static int lm_i2c_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int lm_i2c_rx(I2CSlave *i2c) +static uint8_t lm_i2c_rx(I2CSlave *i2c) { LM823KbdState *s = LM8323(i2c); diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 290a290e43..e0e5cb5d8e 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -244,13 +244,12 @@ static void spapr_xive_instance_init(Object *obj) { sPAPRXive *xive = SPAPR_XIVE(obj); - object_initialize(&xive->source, sizeof(xive->source), TYPE_XIVE_SOURCE); - object_property_add_child(obj, "source", OBJECT(&xive->source), NULL); + object_initialize_child(obj, "source", &xive->source, sizeof(xive->source), + TYPE_XIVE_SOURCE, &error_abort, NULL); - object_initialize(&xive->end_source, sizeof(xive->end_source), - TYPE_XIVE_END_SOURCE); - object_property_add_child(obj, "end_source", OBJECT(&xive->end_source), - NULL); + object_initialize_child(obj, "end_source", &xive->end_source, + sizeof(xive->end_source), TYPE_XIVE_END_SOURCE, + &error_abort, NULL); } static void spapr_xive_realize(DeviceState *dev, Error **errp) @@ -317,6 +316,9 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp) /* Map all regions */ spapr_xive_map_mmio(xive); + xive->nodename = g_strdup_printf("interrupt-controller@%" PRIx64, + xive->tm_base + XIVE_TM_USER_PAGE * (1 << TM_SHIFT)); + qemu_register_reset(spapr_xive_reset, dev); } @@ -1448,7 +1450,6 @@ void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, cpu_to_be32(7), /* start */ cpu_to_be32(0xf8), /* count */ }; - gchar *nodename; /* Thread Interrupt Management Area : User (ring 3) and OS (ring 2) */ timas[0] = cpu_to_be64(xive->tm_base + @@ -1458,10 +1459,7 @@ void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, XIVE_TM_OS_PAGE * (1ull << TM_SHIFT)); timas[3] = cpu_to_be64(1ull << TM_SHIFT); - nodename = g_strdup_printf("interrupt-controller@%" PRIx64, - xive->tm_base + XIVE_TM_USER_PAGE * (1 << TM_SHIFT)); - _FDT(node = fdt_add_subnode(fdt, 0, nodename)); - g_free(nodename); + _FDT(node = fdt_add_subnode(fdt, 0, xive->nodename)); _FDT(fdt_setprop_string(fdt, node, "device_type", "power-ivpe")); _FDT(fdt_setprop(fdt, node, "reg", timas, sizeof(timas))); diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 3009fa7472..af7dc709ab 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -338,6 +338,9 @@ static void icp_realize(DeviceState *dev, Error **errp) case PPC_FLAGS_INPUT_POWER7: icp->output = env->irq_inputs[POWER7_INPUT_INT]; break; + case PPC_FLAGS_INPUT_POWER9: /* For SPAPR xics emulation */ + icp->output = env->irq_inputs[POWER9_INPUT_INT]; + break; case PPC_FLAGS_INPUT_970: icp->output = env->irq_inputs[PPC970_INPUT_INT]; @@ -755,6 +758,10 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) ics->irqs[srcno].flags |= lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI; + + if (kvm_irqchip_in_kernel()) { + ics_set_kvm_state_one(ics, srcno); + } } static void xics_register_types(void) diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index a00d0a7962..c6e1b630a4 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -213,45 +213,57 @@ void ics_synchronize_state(ICSState *ics) ics_get_kvm_state(ics); } -int ics_set_kvm_state(ICSState *ics) +int ics_set_kvm_state_one(ICSState *ics, int srcno) { uint64_t state; - int i; Error *local_err = NULL; + ICSIRQState *irq = &ics->irqs[srcno]; + int ret; - for (i = 0; i < ics->nr_irqs; i++) { - ICSIRQState *irq = &ics->irqs[i]; - int ret; - - state = irq->server; - state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK) - << KVM_XICS_PRIORITY_SHIFT; - if (irq->priority != irq->saved_priority) { - assert(irq->priority == 0xff); - state |= KVM_XICS_MASKED; - } + state = irq->server; + state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK) + << KVM_XICS_PRIORITY_SHIFT; + if (irq->priority != irq->saved_priority) { + assert(irq->priority == 0xff); + state |= KVM_XICS_MASKED; + } - if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) { - state |= KVM_XICS_LEVEL_SENSITIVE; - if (irq->status & XICS_STATUS_ASSERTED) { - state |= KVM_XICS_PENDING; - } - } else { - if (irq->status & XICS_STATUS_MASKED_PENDING) { - state |= KVM_XICS_PENDING; - } + if (irq->flags & XICS_FLAGS_IRQ_LSI) { + state |= KVM_XICS_LEVEL_SENSITIVE; + if (irq->status & XICS_STATUS_ASSERTED) { + state |= KVM_XICS_PENDING; } - if (irq->status & XICS_STATUS_PRESENTED) { - state |= KVM_XICS_PRESENTED; - } - if (irq->status & XICS_STATUS_QUEUED) { - state |= KVM_XICS_QUEUED; + } else { + if (irq->status & XICS_STATUS_MASKED_PENDING) { + state |= KVM_XICS_PENDING; } + } + if (irq->status & XICS_STATUS_PRESENTED) { + state |= KVM_XICS_PRESENTED; + } + if (irq->status & XICS_STATUS_QUEUED) { + state |= KVM_XICS_QUEUED; + } + + ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, + srcno + ics->offset, &state, true, &local_err); + if (local_err) { + error_report_err(local_err); + return ret; + } + + return 0; +} + +int ics_set_kvm_state(ICSState *ics) +{ + int i; + + for (i = 0; i < ics->nr_irqs; i++) { + int ret; - ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, - i + ics->offset, &state, true, &local_err); - if (local_err) { - error_report_err(local_err); + ret = ics_set_kvm_state_one(ics, i); + if (ret) { return ret; } } diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index e2d8b38183..53bda6661b 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -254,7 +254,7 @@ void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, }; int node; - _FDT(node = fdt_add_subnode(fdt, 0, "interrupt-controller")); + _FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME)); _FDT(fdt_setprop_string(fdt, node, "device_type", "PowerPC-External-Interrupt-Presentation")); diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 2e9b8efd43..daa7badc84 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -481,8 +481,8 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp) env = &cpu->env; switch (PPC_INPUT(env)) { - case PPC_FLAGS_INPUT_POWER7: - tctx->output = env->irq_inputs[POWER7_INPUT_INT]; + case PPC_FLAGS_INPUT_POWER9: + tctx->output = env->irq_inputs[POWER9_INPUT_INT]; break; default: diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 7302f6d74b..85d0532dd5 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -14,7 +14,6 @@ #include "hw/hw.h" #include "hw/isa/vt82c686.h" #include "hw/i2c/i2c.h" -#include "hw/i2c/smbus.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "hw/isa/superio.h" diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 8531e07e5b..6f6efae9fc 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -27,6 +27,8 @@ #define SYS_FREQ 166666666 +#define ROM_SIZE 0x200000 + #define PCSR_EN 0x0001 #define PCSR_RLD 0x0002 #define PCSR_PIF 0x0004 @@ -227,6 +229,7 @@ static void mcf5208evb_init(MachineState *machine) hwaddr entry; qemu_irq *pic; MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *rom = g_new(MemoryRegion, 1); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); @@ -237,6 +240,10 @@ static void mcf5208evb_init(MachineState *machine) env->vbr = 0; /* TODO: Configure BARs. */ + /* ROM at 0x00000000 */ + memory_region_init_rom(rom, NULL, "mcf5208.rom", ROM_SIZE, &error_fatal); + memory_region_add_subregion(address_space_mem, 0x00000000, rom); + /* DRAM at 0x40000000 */ memory_region_allocate_system_memory(ram, NULL, "mcf5208.ram", ram_size); memory_region_add_subregion(address_space_mem, 0x40000000, ram); @@ -285,9 +292,30 @@ static void mcf5208evb_init(MachineState *machine) /* 0xfc0a4000 GPIO. */ /* 0xfc0a8000 SDRAM controller. */ + /* Load firmware */ + if (bios_name) { + char *fn; + uint8_t *ptr; + + fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (!fn) { + error_report("Could not find ROM image '%s'", bios_name); + exit(1); + } + if (load_image_targphys(fn, 0x0, ROM_SIZE) < 8) { + error_report("Could not load ROM image '%s'", bios_name); + exit(1); + } + g_free(fn); + /* Initial PC is always at offset 4 in firmware binaries */ + ptr = rom_ptr(0x4, 4); + assert(ptr != NULL); + env->pc = ldl_p(ptr); + } + /* Load kernel. */ if (!kernel_filename) { - if (qtest_enabled()) { + if (qtest_enabled() || bios_name) { return; } error_report("Kernel image must be specified"); diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 0c9b9e8292..152400b1fc 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -204,9 +204,7 @@ static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md) { - const PCDIMMDevice *dimm = PC_DIMM(md); - - return dimm->addr; + return object_property_get_uint(OBJECT(md), PC_DIMM_ADDR_PROP, &error_abort); } static void pc_dimm_md_set_addr(MemoryDeviceState *md, uint64_t addr, diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index eec6fd02c8..fbbc543eed 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -28,7 +28,7 @@ #include "hw/isa/superio.h" #include "net/net.h" #include "hw/boards.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_eeprom.h" #include "hw/block/flash.h" #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 7a403ef1ce..39aef4b6db 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -33,7 +33,7 @@ #include "hw/char/serial.h" #include "net/net.h" #include "hw/boards.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_eeprom.h" #include "hw/block/flash.h" #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 74c91d250c..c71e07ae35 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -70,6 +70,7 @@ obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o obj-$(CONFIG_ARMSSE_CPUID) += armsse-cpuid.o +obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_AUX) += auxbus.o diff --git a/hw/misc/armsse-mhu.c b/hw/misc/armsse-mhu.c new file mode 100644 index 0000000000..9ebca32e9a --- /dev/null +++ b/hw/misc/armsse-mhu.c @@ -0,0 +1,198 @@ +/* + * ARM SSE-200 Message Handling Unit (MHU) + * + * Copyright (c) 2019 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* + * This is a model of the Message Handling Unit (MHU) which is part of the + * Arm SSE-200 and documented in + * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "trace.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/armsse-mhu.h" + +REG32(CPU0INTR_STAT, 0x0) +REG32(CPU0INTR_SET, 0x4) +REG32(CPU0INTR_CLR, 0x8) +REG32(CPU1INTR_STAT, 0x10) +REG32(CPU1INTR_SET, 0x14) +REG32(CPU1INTR_CLR, 0x18) +REG32(PID4, 0xfd0) +REG32(PID5, 0xfd4) +REG32(PID6, 0xfd8) +REG32(PID7, 0xfdc) +REG32(PID0, 0xfe0) +REG32(PID1, 0xfe4) +REG32(PID2, 0xfe8) +REG32(PID3, 0xfec) +REG32(CID0, 0xff0) +REG32(CID1, 0xff4) +REG32(CID2, 0xff8) +REG32(CID3, 0xffc) + +/* Valid bits in the interrupt registers. If any are set the IRQ is raised */ +#define INTR_MASK 0xf + +/* PID/CID values */ +static const int armsse_mhu_id[] = { + 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ + 0x56, 0xb8, 0x0b, 0x00, /* PID0..PID3 */ + 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ +}; + +static void armsse_mhu_update(ARMSSEMHU *s) +{ + qemu_set_irq(s->cpu0irq, s->cpu0intr != 0); + qemu_set_irq(s->cpu1irq, s->cpu1intr != 0); +} + +static uint64_t armsse_mhu_read(void *opaque, hwaddr offset, unsigned size) +{ + ARMSSEMHU *s = ARMSSE_MHU(opaque); + uint64_t r; + + switch (offset) { + case A_CPU0INTR_STAT: + r = s->cpu0intr; + break; + + case A_CPU1INTR_STAT: + r = s->cpu1intr; + break; + + case A_PID4 ... A_CID3: + r = armsse_mhu_id[(offset - A_PID4) / 4]; + break; + + case A_CPU0INTR_SET: + case A_CPU0INTR_CLR: + case A_CPU1INTR_SET: + case A_CPU1INTR_CLR: + qemu_log_mask(LOG_GUEST_ERROR, + "SSE MHU: read of write-only register at offset 0x%x\n", + (int)offset); + r = 0; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "SSE MHU read: bad offset 0x%x\n", (int)offset); + r = 0; + break; + } + trace_armsse_mhu_read(offset, r, size); + return r; +} + +static void armsse_mhu_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + ARMSSEMHU *s = ARMSSE_MHU(opaque); + + trace_armsse_mhu_write(offset, value, size); + + switch (offset) { + case A_CPU0INTR_SET: + s->cpu0intr |= (value & INTR_MASK); + break; + case A_CPU0INTR_CLR: + s->cpu0intr &= ~(value & INTR_MASK); + break; + case A_CPU1INTR_SET: + s->cpu1intr |= (value & INTR_MASK); + break; + case A_CPU1INTR_CLR: + s->cpu1intr &= ~(value & INTR_MASK); + break; + + case A_CPU0INTR_STAT: + case A_CPU1INTR_STAT: + case A_PID4 ... A_CID3: + qemu_log_mask(LOG_GUEST_ERROR, + "SSE MHU: write to read-only register at offset 0x%x\n", + (int)offset); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "SSE MHU write: bad offset 0x%x\n", (int)offset); + break; + } + + armsse_mhu_update(s); +} + +static const MemoryRegionOps armsse_mhu_ops = { + .read = armsse_mhu_read, + .write = armsse_mhu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, +}; + +static void armsse_mhu_reset(DeviceState *dev) +{ + ARMSSEMHU *s = ARMSSE_MHU(dev); + + s->cpu0intr = 0; + s->cpu1intr = 0; +} + +static const VMStateDescription armsse_mhu_vmstate = { + .name = "armsse-mhu", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cpu0intr, ARMSSEMHU), + VMSTATE_UINT32(cpu1intr, ARMSSEMHU), + VMSTATE_END_OF_LIST() + }, +}; + +static void armsse_mhu_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + ARMSSEMHU *s = ARMSSE_MHU(obj); + + memory_region_init_io(&s->iomem, obj, &armsse_mhu_ops, + s, "armsse-mhu", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->cpu0irq); + sysbus_init_irq(sbd, &s->cpu1irq); +} + +static void armsse_mhu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = armsse_mhu_reset; + dc->vmsd = &armsse_mhu_vmstate; +} + +static const TypeInfo armsse_mhu_info = { + .name = TYPE_ARMSSE_MHU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ARMSSEMHU), + .instance_init = armsse_mhu_init, + .class_init = armsse_mhu_class_init, +}; + +static void armsse_mhu_register_types(void) +{ + type_register_static(&armsse_mhu_info); +} + +type_init(armsse_mhu_register_types); diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c index a21d8bd678..54064a31ef 100644 --- a/hw/misc/iotkit-sysctl.c +++ b/hw/misc/iotkit-sysctl.c @@ -17,6 +17,7 @@ */ #include "qemu/osdep.h" +#include "qemu/bitops.h" #include "qemu/log.h" #include "trace.h" #include "qapi/error.h" @@ -24,19 +25,32 @@ #include "hw/sysbus.h" #include "hw/registerfields.h" #include "hw/misc/iotkit-sysctl.h" +#include "target/arm/arm-powerctl.h" +#include "target/arm/cpu.h" REG32(SECDBGSTAT, 0x0) REG32(SECDBGSET, 0x4) REG32(SECDBGCLR, 0x8) +REG32(SCSECCTRL, 0xc) +REG32(FCLK_DIV, 0x10) +REG32(SYSCLK_DIV, 0x14) +REG32(CLOCK_FORCE, 0x18) REG32(RESET_SYNDROME, 0x100) REG32(RESET_MASK, 0x104) REG32(SWRESET, 0x108) FIELD(SWRESET, SWRESETREQ, 9, 1) REG32(GRETREG, 0x10c) -REG32(INITSVRTOR0, 0x110) +REG32(INITSVTOR0, 0x110) +REG32(INITSVTOR1, 0x114) REG32(CPUWAIT, 0x118) -REG32(BUSWAIT, 0x11c) +REG32(NMI_ENABLE, 0x11c) /* BUSWAIT in IoTKit */ REG32(WICCTRL, 0x120) +REG32(EWCTRL, 0x124) +REG32(PDCM_PD_SYS_SENSE, 0x200) +REG32(PDCM_PD_SRAM0_SENSE, 0x20c) +REG32(PDCM_PD_SRAM1_SENSE, 0x210) +REG32(PDCM_PD_SRAM2_SENSE, 0x214) +REG32(PDCM_PD_SRAM3_SENSE, 0x218) REG32(PID4, 0xfd0) REG32(PID5, 0xfd4) REG32(PID6, 0xfd8) @@ -57,6 +71,21 @@ static const int sysctl_id[] = { 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ }; +/* + * Set the initial secure vector table offset address for the core. + * This will take effect when the CPU next resets. + */ +static void set_init_vtor(uint64_t cpuid, uint32_t vtor) +{ + Object *cpuobj = OBJECT(arm_get_cpu_by_id(cpuid)); + + if (cpuobj) { + if (object_property_find(cpuobj, "init-svtor", NULL)) { + object_property_set_uint(cpuobj, vtor, "init-svtor", &error_abort); + } + } +} + static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset, unsigned size) { @@ -67,6 +96,30 @@ static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset, case A_SECDBGSTAT: r = s->secure_debug; break; + case A_SCSECCTRL: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->scsecctrl; + break; + case A_FCLK_DIV: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->fclk_div; + break; + case A_SYSCLK_DIV: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->sysclk_div; + break; + case A_CLOCK_FORCE: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->clock_force; + break; case A_RESET_SYNDROME: r = s->reset_syndrome; break; @@ -76,19 +129,65 @@ static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset, case A_GRETREG: r = s->gretreg; break; - case A_INITSVRTOR0: - r = s->initsvrtor0; + case A_INITSVTOR0: + r = s->initsvtor0; + break; + case A_INITSVTOR1: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->initsvtor1; break; case A_CPUWAIT: r = s->cpuwait; break; - case A_BUSWAIT: - /* In IoTKit BUSWAIT is reserved, R/O, zero */ - r = 0; + case A_NMI_ENABLE: + /* In IoTKit this is named BUSWAIT but is marked reserved, R/O, zero */ + if (!s->is_sse200) { + r = 0; + break; + } + r = s->nmi_enable; break; case A_WICCTRL: r = s->wicctrl; break; + case A_EWCTRL: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->ewctrl; + break; + case A_PDCM_PD_SYS_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->pdcm_pd_sys_sense; + break; + case A_PDCM_PD_SRAM0_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->pdcm_pd_sram0_sense; + break; + case A_PDCM_PD_SRAM1_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->pdcm_pd_sram1_sense; + break; + case A_PDCM_PD_SRAM2_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->pdcm_pd_sram2_sense; + break; + case A_PDCM_PD_SRAM3_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + r = s->pdcm_pd_sram3_sense; + break; case A_PID4 ... A_CID3: r = sysctl_id[(offset - A_PID4) / 4]; break; @@ -101,6 +200,7 @@ static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset, r = 0; break; default: + bad_offset: qemu_log_mask(LOG_GUEST_ERROR, "IoTKit SysCtl read: bad offset %x\n", (int)offset); r = 0; @@ -145,12 +245,19 @@ static void iotkit_sysctl_write(void *opaque, hwaddr offset, */ s->gretreg = value; break; - case A_INITSVRTOR0: - qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl INITSVRTOR0 unimplemented\n"); - s->initsvrtor0 = value; + case A_INITSVTOR0: + s->initsvtor0 = value; + set_init_vtor(0, s->initsvtor0); break; case A_CPUWAIT: - qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CPUWAIT unimplemented\n"); + if ((s->cpuwait & 1) && !(value & 1)) { + /* Powering up CPU 0 */ + arm_set_cpu_on_and_reset(0); + } + if ((s->cpuwait & 2) && !(value & 2)) { + /* Powering up CPU 1 */ + arm_set_cpu_on_and_reset(1); + } s->cpuwait = value; break; case A_WICCTRL: @@ -172,14 +279,105 @@ static void iotkit_sysctl_write(void *opaque, hwaddr offset, qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); } break; - case A_BUSWAIT: /* In IoTKit BUSWAIT is reserved, R/O, zero */ + case A_SCSECCTRL: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SCSECCTRL unimplemented\n"); + s->scsecctrl = value; + break; + case A_FCLK_DIV: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl FCLK_DIV unimplemented\n"); + s->fclk_div = value; + break; + case A_SYSCLK_DIV: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SYSCLK_DIV unimplemented\n"); + s->sysclk_div = value; + break; + case A_CLOCK_FORCE: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CLOCK_FORCE unimplemented\n"); + s->clock_force = value; + break; + case A_INITSVTOR1: + if (!s->is_sse200) { + goto bad_offset; + } + s->initsvtor1 = value; + set_init_vtor(1, s->initsvtor1); + break; + case A_EWCTRL: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl EWCTRL unimplemented\n"); + s->ewctrl = value; + break; + case A_PDCM_PD_SYS_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, + "IoTKit SysCtl PDCM_PD_SYS_SENSE unimplemented\n"); + s->pdcm_pd_sys_sense = value; + break; + case A_PDCM_PD_SRAM0_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, + "IoTKit SysCtl PDCM_PD_SRAM0_SENSE unimplemented\n"); + s->pdcm_pd_sram0_sense = value; + break; + case A_PDCM_PD_SRAM1_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, + "IoTKit SysCtl PDCM_PD_SRAM1_SENSE unimplemented\n"); + s->pdcm_pd_sram1_sense = value; + break; + case A_PDCM_PD_SRAM2_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, + "IoTKit SysCtl PDCM_PD_SRAM2_SENSE unimplemented\n"); + s->pdcm_pd_sram2_sense = value; + break; + case A_PDCM_PD_SRAM3_SENSE: + if (!s->is_sse200) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, + "IoTKit SysCtl PDCM_PD_SRAM3_SENSE unimplemented\n"); + s->pdcm_pd_sram3_sense = value; + break; + case A_NMI_ENABLE: + /* In IoTKit this is BUSWAIT: reserved, R/O, zero */ + if (!s->is_sse200) { + goto ro_offset; + } + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl NMI_ENABLE unimplemented\n"); + s->nmi_enable = value; + break; case A_SECDBGSTAT: case A_PID4 ... A_CID3: + ro_offset: qemu_log_mask(LOG_GUEST_ERROR, "IoTKit SysCtl write: write of RO offset %x\n", (int)offset); break; default: + bad_offset: qemu_log_mask(LOG_GUEST_ERROR, "IoTKit SysCtl write: bad offset %x\n", (int)offset); break; @@ -206,9 +404,21 @@ static void iotkit_sysctl_reset(DeviceState *dev) s->reset_syndrome = 1; s->reset_mask = 0; s->gretreg = 0; - s->initsvrtor0 = 0x10000000; - s->cpuwait = 0; + s->initsvtor0 = s->initsvtor0_rst; + s->initsvtor1 = s->initsvtor1_rst; + s->cpuwait = s->cpuwait_rst; s->wicctrl = 0; + s->scsecctrl = 0; + s->fclk_div = 0; + s->sysclk_div = 0; + s->clock_force = 0; + s->nmi_enable = 0; + s->ewctrl = 0; + s->pdcm_pd_sys_sense = 0x7f; + s->pdcm_pd_sram0_sense = 0; + s->pdcm_pd_sram1_sense = 0; + s->pdcm_pd_sram2_sense = 0; + s->pdcm_pd_sram3_sense = 0; } static void iotkit_sysctl_init(Object *obj) @@ -221,6 +431,44 @@ static void iotkit_sysctl_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } +static void iotkit_sysctl_realize(DeviceState *dev, Error **errp) +{ + IoTKitSysCtl *s = IOTKIT_SYSCTL(dev); + + /* The top 4 bits of the SYS_VERSION register tell us if we're an SSE-200 */ + if (extract32(s->sys_version, 28, 4) == 2) { + s->is_sse200 = true; + } +} + +static bool sse200_needed(void *opaque) +{ + IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); + + return s->is_sse200; +} + +static const VMStateDescription iotkit_sysctl_sse200_vmstate = { + .name = "iotkit-sysctl/sse-200", + .version_id = 1, + .minimum_version_id = 1, + .needed = sse200_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(scsecctrl, IoTKitSysCtl), + VMSTATE_UINT32(fclk_div, IoTKitSysCtl), + VMSTATE_UINT32(sysclk_div, IoTKitSysCtl), + VMSTATE_UINT32(clock_force, IoTKitSysCtl), + VMSTATE_UINT32(initsvtor1, IoTKitSysCtl), + VMSTATE_UINT32(nmi_enable, IoTKitSysCtl), + VMSTATE_UINT32(pdcm_pd_sys_sense, IoTKitSysCtl), + VMSTATE_UINT32(pdcm_pd_sram0_sense, IoTKitSysCtl), + VMSTATE_UINT32(pdcm_pd_sram1_sense, IoTKitSysCtl), + VMSTATE_UINT32(pdcm_pd_sram2_sense, IoTKitSysCtl), + VMSTATE_UINT32(pdcm_pd_sram3_sense, IoTKitSysCtl), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription iotkit_sysctl_vmstate = { .name = "iotkit-sysctl", .version_id = 1, @@ -230,19 +478,35 @@ static const VMStateDescription iotkit_sysctl_vmstate = { VMSTATE_UINT32(reset_syndrome, IoTKitSysCtl), VMSTATE_UINT32(reset_mask, IoTKitSysCtl), VMSTATE_UINT32(gretreg, IoTKitSysCtl), - VMSTATE_UINT32(initsvrtor0, IoTKitSysCtl), + VMSTATE_UINT32(initsvtor0, IoTKitSysCtl), VMSTATE_UINT32(cpuwait, IoTKitSysCtl), VMSTATE_UINT32(wicctrl, IoTKitSysCtl), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &iotkit_sysctl_sse200_vmstate, + NULL } }; +static Property iotkit_sysctl_props[] = { + DEFINE_PROP_UINT32("SYS_VERSION", IoTKitSysCtl, sys_version, 0), + DEFINE_PROP_UINT32("CPUWAIT_RST", IoTKitSysCtl, cpuwait_rst, 0), + DEFINE_PROP_UINT32("INITSVTOR0_RST", IoTKitSysCtl, initsvtor0_rst, + 0x10000000), + DEFINE_PROP_UINT32("INITSVTOR1_RST", IoTKitSysCtl, initsvtor1_rst, + 0x10000000), + DEFINE_PROP_END_OF_LIST() +}; + static void iotkit_sysctl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &iotkit_sysctl_vmstate; dc->reset = iotkit_sysctl_reset; + dc->props = iotkit_sysctl_props; + dc->realize = iotkit_sysctl_realize; } static const TypeInfo iotkit_sysctl_info = { diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c index 9775d5274a..7325d3f287 100644 --- a/hw/misc/pca9552.c +++ b/hw/misc/pca9552.c @@ -115,7 +115,7 @@ static void pca9552_autoinc(PCA9552State *s) } } -static int pca9552_recv(I2CSlave *i2c) +static uint8_t pca9552_recv(I2CSlave *i2c) { PCA9552State *s = PCA9552(i2c); uint8_t ret; diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index f6d7163273..0c32f6f8b6 100644 --- a/hw/misc/tmp105.c +++ b/hw/misc/tmp105.c @@ -147,7 +147,7 @@ static void tmp105_write(TMP105State *s) } } -static int tmp105_rx(I2CSlave *i2c) +static uint8_t tmp105_rx(I2CSlave *i2c) { TMP105State *s = TMP105(i2c); diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c index eeb11000f0..ce6d40ac9c 100644 --- a/hw/misc/tmp421.c +++ b/hw/misc/tmp421.c @@ -249,7 +249,7 @@ static void tmp421_write(TMP421State *s) } } -static int tmp421_rx(I2CSlave *i2c) +static uint8_t tmp421_rx(I2CSlave *i2c) { TMP421State *s = TMP421(i2c); diff --git a/hw/misc/trace-events b/hw/misc/trace-events index b0701bddd3..c1795bb54b 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -136,3 +136,7 @@ iotkit_sysctl_reset(void) "IoTKit SysCtl: reset" # hw/misc/armsse-cpuid.c armsse_cpuid_read(uint64_t offset, uint64_t data, unsigned size) "SSE-200 CPU_IDENTITY read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" armsse_cpuid_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 CPU_IDENTITY write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" + +# hw/misc/armsse-mhu.c +armsse_mhu_read(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +armsse_mhu_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs index a43351aa04..ea63715780 100644 --- a/hw/net/Makefile.objs +++ b/hw/net/Makefile.objs @@ -37,7 +37,9 @@ obj-$(CONFIG_PSERIES) += spapr_llan.o obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o obj-$(CONFIG_VIRTIO_NET) += virtio-net.o -obj-y += vhost_net.o +common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET)) += vhost_net.o +common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET))) += vhost_net-stub.o +common-obj-$(CONFIG_ALL) += vhost_net-stub.o obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \ fsl_etsec/rings.o fsl_etsec/miim.o diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c new file mode 100644 index 0000000000..aac0e98228 --- /dev/null +++ b/hw/net/vhost_net-stub.c @@ -0,0 +1,92 @@ +/* + * vhost-net support + * + * Copyright Red Hat, Inc. 2010 + * + * Authors: + * Michael S. Tsirkin <mst@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "net/net.h" +#include "net/tap.h" +#include "net/vhost-user.h" + +#include "hw/virtio/virtio-net.h" +#include "net/vhost_net.h" +#include "qemu/error-report.h" + + +uint64_t vhost_net_get_max_queues(VHostNetState *net) +{ + return 1; +} + +struct vhost_net *vhost_net_init(VhostNetOptions *options) +{ + error_report("vhost-net support is not compiled in"); + return NULL; +} + +int vhost_net_start(VirtIODevice *dev, + NetClientState *ncs, + int total_queues) +{ + return -ENOSYS; +} +void vhost_net_stop(VirtIODevice *dev, + NetClientState *ncs, + int total_queues) +{ +} + +void vhost_net_cleanup(struct vhost_net *net) +{ +} + +uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) +{ + return features; +} + +void vhost_net_ack_features(struct vhost_net *net, uint64_t features) +{ +} + +uint64_t vhost_net_get_acked_features(VHostNetState *net) +{ + return 0; +} + +bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) +{ + return false; +} + +void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask) +{ +} + +int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) +{ + return -1; +} + +VHostNetState *get_vhost_net(NetClientState *nc) +{ + return 0; +} + +int vhost_set_vring_enable(NetClientState *nc, int enable) +{ + return 0; +} + +int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) +{ + return 0; +} diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index e037db63a3..be3cc88370 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -18,17 +18,13 @@ #include "net/tap.h" #include "net/vhost-user.h" +#include "standard-headers/linux/vhost_types.h" #include "hw/virtio/virtio-net.h" #include "net/vhost_net.h" #include "qemu/error-report.h" -#ifdef CONFIG_VHOST_NET -#include <linux/vhost.h> #include <sys/socket.h> -#include <linux/kvm.h> -#include <netpacket/packet.h> -#include <net/ethernet.h> #include <net/if.h> #include <netinet/in.h> @@ -136,7 +132,7 @@ static int vhost_net_get_fd(NetClientState *backend) return tap_get_fd(backend); default: fprintf(stderr, "vhost-net requires tap backend\n"); - return -EBADFD; + return -ENOSYS; } } @@ -194,6 +190,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) } /* Set sane init value. Override when guest acks. */ +#ifdef CONFIG_VHOST_NET_USER if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { features = vhost_user_get_acked_features(net->nc); if (~net->dev.features & features) { @@ -203,6 +200,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) goto fail; } } +#endif vhost_net_ack_features(net, features); @@ -414,10 +412,12 @@ VHostNetState *get_vhost_net(NetClientState *nc) case NET_CLIENT_DRIVER_TAP: vhost_net = tap_get_vhost_net(nc); break; +#ifdef CONFIG_VHOST_NET_USER case NET_CLIENT_DRIVER_VHOST_USER: vhost_net = vhost_user_get_vhost_net(nc); assert(vhost_net); break; +#endif default: break; } @@ -449,76 +449,3 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) return vhost_ops->vhost_net_set_mtu(&net->dev, mtu); } - -#else -uint64_t vhost_net_get_max_queues(VHostNetState *net) -{ - return 1; -} - -struct vhost_net *vhost_net_init(VhostNetOptions *options) -{ - error_report("vhost-net support is not compiled in"); - return NULL; -} - -int vhost_net_start(VirtIODevice *dev, - NetClientState *ncs, - int total_queues) -{ - return -ENOSYS; -} -void vhost_net_stop(VirtIODevice *dev, - NetClientState *ncs, - int total_queues) -{ -} - -void vhost_net_cleanup(struct vhost_net *net) -{ -} - -uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) -{ - return features; -} - -void vhost_net_ack_features(struct vhost_net *net, uint64_t features) -{ -} - -uint64_t vhost_net_get_acked_features(VHostNetState *net) -{ - return 0; -} - -bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) -{ - return false; -} - -void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, - int idx, bool mask) -{ -} - -int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) -{ - return -1; -} - -VHostNetState *get_vhost_net(NetClientState *nc) -{ - return 0; -} - -int vhost_set_vring_enable(NetClientState *nc, int enable) -{ - return 0; -} - -int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) -{ - return 0; -} -#endif diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 3f319ef723..6e6b146022 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -82,29 +82,17 @@ static inline __virtio16 *virtio_net_rsc_ext_num_dupacks( #endif -/* - * Calculate the number of bytes up to and including the given 'field' of - * 'container'. - */ -#define endof(container, field) \ - (offsetof(container, field) + sizeof_field(container, field)) - -typedef struct VirtIOFeature { - uint64_t flags; - size_t end; -} VirtIOFeature; - static VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_NET_F_MAC, - .end = endof(struct virtio_net_config, mac)}, + .end = virtio_endof(struct virtio_net_config, mac)}, {.flags = 1ULL << VIRTIO_NET_F_STATUS, - .end = endof(struct virtio_net_config, status)}, + .end = virtio_endof(struct virtio_net_config, status)}, {.flags = 1ULL << VIRTIO_NET_F_MQ, - .end = endof(struct virtio_net_config, max_virtqueue_pairs)}, + .end = virtio_endof(struct virtio_net_config, max_virtqueue_pairs)}, {.flags = 1ULL << VIRTIO_NET_F_MTU, - .end = endof(struct virtio_net_config, mtu)}, + .end = virtio_endof(struct virtio_net_config, mtu)}, {.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX, - .end = endof(struct virtio_net_config, duplex)}, + .end = virtio_endof(struct virtio_net_config, duplex)}, {} }; @@ -2580,15 +2568,10 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) { - int i, config_size = 0; virtio_add_feature(&host_features, VIRTIO_NET_F_MAC); - for (i = 0; feature_sizes[i].flags != 0; i++) { - if (host_features & feature_sizes[i].flags) { - config_size = MAX(feature_sizes[i].end, config_size); - } - } - n->config_size = config_size; + n->config_size = virtio_feature_get_config_size(feature_sizes, + host_features); } void virtio_net_set_netclient_name(VirtIONet *n, const char *name, diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c index 27cd01e615..d1456dafbd 100644 --- a/hw/nvram/eeprom_at24c.c +++ b/hw/nvram/eeprom_at24c.c @@ -74,10 +74,10 @@ int at24c_eeprom_event(I2CSlave *s, enum i2c_event event) } static -int at24c_eeprom_recv(I2CSlave *s) +uint8_t at24c_eeprom_recv(I2CSlave *s) { EEPROMState *ee = AT24C_EE(s); - int ret; + uint8_t ret; ret = ee->mem[ee->cur]; diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 3f7c366093..3618d6ab2e 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -834,9 +834,12 @@ void pcie_add_capability(PCIDevice *dev, /* * Sync the PCIe Link Status negotiated speed and width of a bridge with the * downstream device. If downstream device is not present, re-write with the - * Link Capability fields. Limit width and speed to bridge capabilities for - * compatibility. Use config_read to access the downstream device since it - * could be an assigned device with volatile link information. + * Link Capability fields. If downstream device reports invalid width or + * speed, replace with minimum values (LnkSta fields are RsvdZ on VFs but such + * values interfere with PCIe native hotplug detecting new devices). Limit + * width and speed to bridge capabilities for compatibility. Use config_read + * to access the downstream device since it could be an assigned device with + * volatile link information. */ void pcie_sync_bridge_lnk(PCIDevice *bridge_dev) { @@ -856,11 +859,15 @@ void pcie_sync_bridge_lnk(PCIDevice *bridge_dev) if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) { lnksta &= ~PCI_EXP_LNKSTA_NLW; lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW; + } else if (!(lnksta & PCI_EXP_LNKSTA_NLW)) { + lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1); } if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) { lnksta &= ~PCI_EXP_LNKSTA_CLS; lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS; + } else if (!(lnksta & PCI_EXP_LNKSTA_CLS)) { + lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT); } } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index da540860a2..3d5dfef220 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -47,14 +47,16 @@ #include <libfdt.h> -#define FDT_MAX_SIZE 0x00100000 +#define FDT_MAX_SIZE (1 * MiB) #define FW_FILE_NAME "skiboot.lid" #define FW_LOAD_ADDR 0x0 -#define FW_MAX_SIZE 0x00400000 +#define FW_MAX_SIZE (4 * MiB) #define KERNEL_LOAD_ADDR 0x20000000 +#define KERNEL_MAX_SIZE (256 * MiB) #define INITRD_LOAD_ADDR 0x60000000 +#define INITRD_MAX_SIZE (256 * MiB) static const char *pnv_chip_core_typename(const PnvChip *o) { @@ -588,7 +590,7 @@ static void pnv_init(MachineState *machine) long kernel_size; kernel_size = load_image_targphys(machine->kernel_filename, - KERNEL_LOAD_ADDR, 0x2000000); + KERNEL_LOAD_ADDR, KERNEL_MAX_SIZE); if (kernel_size < 0) { error_report("Could not load kernel '%s'", machine->kernel_filename); @@ -600,7 +602,7 @@ static void pnv_init(MachineState *machine) if (machine->initrd_filename) { pnv->initrd_base = INITRD_LOAD_ADDR; pnv->initrd_size = load_image_targphys(machine->initrd_filename, - pnv->initrd_base, 0x10000000); /* 128MB max */ + pnv->initrd_base, INITRD_MAX_SIZE); if (pnv->initrd_size < 0) { error_report("Could not load initial ram disk '%s'", machine->initrd_filename); @@ -736,18 +738,18 @@ static void pnv_chip_power8_instance_init(Object *obj) { Pnv8Chip *chip8 = PNV8_CHIP(obj); - object_initialize(&chip8->psi, sizeof(chip8->psi), TYPE_PNV_PSI); - object_property_add_child(obj, "psi", OBJECT(&chip8->psi), NULL); + object_initialize_child(obj, "psi", &chip8->psi, sizeof(chip8->psi), + TYPE_PNV_PSI, &error_abort, NULL); object_property_add_const_link(OBJECT(&chip8->psi), "xics", OBJECT(qdev_get_machine()), &error_abort); - object_initialize(&chip8->lpc, sizeof(chip8->lpc), TYPE_PNV_LPC); - object_property_add_child(obj, "lpc", OBJECT(&chip8->lpc), NULL); + object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc), + TYPE_PNV_LPC, &error_abort, NULL); object_property_add_const_link(OBJECT(&chip8->lpc), "psi", OBJECT(&chip8->psi), &error_abort); - object_initialize(&chip8->occ, sizeof(chip8->occ), TYPE_PNV_OCC); - object_property_add_child(obj, "occ", OBJECT(&chip8->occ), NULL); + object_initialize_child(obj, "occ", &chip8->occ, sizeof(chip8->occ), + TYPE_PNV_OCC, &error_abort, NULL); object_property_add_const_link(OBJECT(&chip8->occ), "psi", OBJECT(&chip8->psi), &error_abort); } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 8ced095063..44bc0cbf58 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -444,8 +444,8 @@ static void pnv_psi_init(Object *obj) { PnvPsi *psi = PNV_PSI(obj); - object_initialize(&psi->ics, sizeof(psi->ics), TYPE_ICS_SIMPLE); - object_property_add_child(obj, "ics-psi", OBJECT(&psi->ics), NULL); + object_initialize_child(obj, "ics-psi", &psi->ics, sizeof(psi->ics), + TYPE_ICS_SIMPLE, &error_abort, NULL); } static const uint8_t irq_to_xivr[] = { diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index cffdc3914a..d1e3d4cd20 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -306,6 +306,48 @@ void ppcPOWER7_irq_init(PowerPCCPU *cpu) env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, POWER7_INPUT_NB); } + +/* POWER9 internal IRQ controller */ +static void power9_set_irq(void *opaque, int pin, int level) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + LOG_IRQ("%s: env %p pin %d level %d\n", __func__, + env, pin, level); + + switch (pin) { + case POWER9_INPUT_INT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the external IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); + break; + case POWER9_INPUT_HINT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the external IRQ state to %d\n", + __func__, level); + ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); + break; + default: + /* Unknown pin - do nothing */ + LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); + return; + } + if (level) { + env->irq_input_state |= 1 << pin; + } else { + env->irq_input_state &= ~(1 << pin); + } +} + +void ppcPOWER9_irq_init(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + + env->irq_inputs = (void **)qemu_allocate_irqs(&power9_set_irq, cpu, + POWER9_INPUT_NB); +} #endif /* defined(TARGET_PPC64) */ void ppc40x_core_reset(PowerPCCPU *cpu) @@ -776,7 +818,7 @@ static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) * interrupts in a PM state. Not only they don't cause a * wakeup but they also get effectively discarded. */ - if (!env->in_pm_state) { + if (!env->resume_as_sreset) { ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); } } diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 75250d49e4..d455c4bd07 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -34,7 +34,7 @@ #include "hw/sysbus.h" #include "hw/char/serial.h" #include "hw/i2c/ppc4xx_i2c.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_eeprom.h" #include "hw/usb/hcd-ehci.h" #include "hw/ppc/fdt.h" diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index abf9ebce59..b6a571b6f1 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1247,13 +1247,30 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr) * Add info to guest to indentify which host is it being run on * and what is the uuid of the guest */ - if (kvmppc_get_host_model(&buf)) { - _FDT(fdt_setprop_string(fdt, 0, "host-model", buf)); - g_free(buf); + if (spapr->host_model && !g_str_equal(spapr->host_model, "none")) { + if (g_str_equal(spapr->host_model, "passthrough")) { + /* -M host-model=passthrough */ + if (kvmppc_get_host_model(&buf)) { + _FDT(fdt_setprop_string(fdt, 0, "host-model", buf)); + g_free(buf); + } + } else { + /* -M host-model=<user-string> */ + _FDT(fdt_setprop_string(fdt, 0, "host-model", spapr->host_model)); + } } - if (kvmppc_get_host_serial(&buf)) { - _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf)); - g_free(buf); + + if (spapr->host_serial && !g_str_equal(spapr->host_serial, "none")) { + if (g_str_equal(spapr->host_serial, "passthrough")) { + /* -M host-serial=passthrough */ + if (kvmppc_get_host_serial(&buf)) { + _FDT(fdt_setprop_string(fdt, 0, "host-serial", buf)); + g_free(buf); + } + } else { + /* -M host-serial=<user-string> */ + _FDT(fdt_setprop_string(fdt, 0, "host-serial", spapr->host_serial)); + } } buf = qemu_uuid_unparse_strdup(&qemu_uuid); @@ -1295,7 +1312,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr) QLIST_FOREACH(phb, &spapr->phbs, list) { ret = spapr_populate_pci_dt(phb, PHANDLE_INTC, fdt, - spapr->irq->nr_msis); + spapr->irq->nr_msis, NULL); if (ret < 0) { error_report("couldn't setup PCI devices in fdt"); exit(1); @@ -1348,6 +1365,14 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr) exit(1); } + if (smc->dr_phb_enabled) { + ret = spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB); + if (ret < 0) { + error_report("Couldn't set up PHB DR device tree properties"); + exit(1); + } + } + return fdt; } @@ -1372,11 +1397,44 @@ static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, } } -static uint64_t spapr_get_patbe(PPCVirtualHypervisor *vhyp) +struct LPCRSyncState { + target_ulong value; + target_ulong mask; +}; + +static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg) +{ + struct LPCRSyncState *s = arg.host_ptr; + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + target_ulong lpcr; + + cpu_synchronize_state(cs); + lpcr = env->spr[SPR_LPCR]; + lpcr &= ~s->mask; + lpcr |= s->value; + ppc_store_lpcr(cpu, lpcr); +} + +void spapr_set_all_lpcrs(target_ulong value, target_ulong mask) +{ + CPUState *cs; + struct LPCRSyncState s = { + .value = value, + .mask = mask + }; + CPU_FOREACH(cs) { + run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s)); + } +} + +static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry) { sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp); - return spapr->patb_entry; + /* Copy PATE1:GR into PATE0:HR */ + entry->dw0 = spapr->patb_entry & PATE0_HR; + entry->dw1 = spapr->patb_entry; } #define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2)) @@ -1476,8 +1534,25 @@ static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex, if (!spapr->htab) { kvmppc_write_hpte(ptex, pte0, pte1); } else { - stq_p(spapr->htab + offset, pte0); - stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1); + if (pte0 & HPTE64_V_VALID) { + stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1); + /* + * When setting valid, we write PTE1 first. This ensures + * proper synchronization with the reading code in + * ppc_hash64_pteg_search() + */ + smp_wmb(); + stq_p(spapr->htab + offset, pte0); + } else { + stq_p(spapr->htab + offset, pte0); + /* + * When clearing it we set PTE0 first. This ensures proper + * synchronization with the reading code in + * ppc_hash64_pteg_search() + */ + smp_wmb(); + stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1); + } } } @@ -1548,7 +1623,7 @@ void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, } } /* We're setting up a hash table, so that means we're not radix */ - spapr->patb_entry = 0; + spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT); } void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr) @@ -1602,16 +1677,21 @@ static void spapr_machine_reset(void) if (kvm_enabled() && kvmppc_has_cap_mmu_radix() && ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0, spapr->max_compat_pvr)) { - /* If using KVM with radix mode available, VCPUs can be started + /* + * If using KVM with radix mode available, VCPUs can be started * without a HPT because KVM will start them in radix mode. - * Set the GR bit in PATB so that we know there is no HPT. */ - spapr->patb_entry = PATBE1_GR; + * Set the GR bit in PATE so that we know there is no HPT. + */ + spapr->patb_entry = PATE1_GR; + spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT); } else { spapr_setup_hpt_and_vrma(spapr); } - /* if this reset wasn't generated by CAS, we should reset our - * negotiated options and start from scratch */ + /* + * If this reset wasn't generated by CAS, we should reset our + * negotiated options and start from scratch + */ if (!spapr->cas_reboot) { spapr_ovec_cleanup(spapr->ov5_cas); spapr->ov5_cas = spapr_ovec_new(); @@ -1696,9 +1776,9 @@ static void spapr_create_nvram(sPAPRMachineState *spapr) static void spapr_rtc_create(sPAPRMachineState *spapr) { - object_initialize(&spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC); - object_property_add_child(OBJECT(spapr), "rtc", OBJECT(&spapr->rtc), - &error_fatal); + object_initialize_child(OBJECT(spapr), "rtc", + &spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC, + &error_fatal, NULL); object_property_set_bool(OBJECT(&spapr->rtc), true, "realized", &error_fatal); object_property_add_alias(OBJECT(spapr), "rtc-time", OBJECT(&spapr->rtc), @@ -1761,9 +1841,16 @@ static int spapr_post_load(void *opaque, int version_id) if (kvm_enabled() && spapr->patb_entry) { PowerPCCPU *cpu = POWERPC_CPU(first_cpu); - bool radix = !!(spapr->patb_entry & PATBE1_GR); + bool radix = !!(spapr->patb_entry & PATE1_GR); bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE); + /* + * Update LPCR:HR and UPRT as they may not be set properly in + * the stream + */ + spapr_set_all_lpcrs(radix ? (LPCR_HR | LPCR_UPRT) : 0, + LPCR_HR | LPCR_UPRT); + err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry); if (err) { error_report("Process table config unsupported by the host"); @@ -2796,6 +2883,19 @@ static void spapr_machine_init(MachineState *machine) /* We always have at least the nvram device on VIO */ spapr_create_nvram(spapr); + /* + * Setup hotplug / dynamic-reconfiguration connectors. top-level + * connectors (described in root DT node's "ibm,drc-types" property) + * are pre-initialized here. additional child connectors (such as + * connectors for a PHBs PCI slots) are added as needed during their + * parent's realization. + */ + if (smc->dr_phb_enabled) { + for (i = 0; i < SPAPR_MAX_PHBS; i++) { + spapr_dr_connector_new(OBJECT(machine), TYPE_SPAPR_DRC_PHB, i); + } + } + /* Set up PCI */ spapr_pci_rtas_init(); @@ -2909,6 +3009,9 @@ static void spapr_machine_init(MachineState *machine) register_savevm_live(NULL, "spapr/htab", -1, 1, &savevm_htab_handlers, spapr); + qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine), + &error_fatal); + qemu_register_boot_set(spapr_boot_set, spapr); if (kvm_enabled()) { @@ -3144,6 +3247,36 @@ static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp) } } +static char *spapr_get_host_model(Object *obj, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + return g_strdup(spapr->host_model); +} + +static void spapr_set_host_model(Object *obj, const char *value, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + g_free(spapr->host_model); + spapr->host_model = g_strdup(value); +} + +static char *spapr_get_host_serial(Object *obj, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + return g_strdup(spapr->host_serial); +} + +static void spapr_set_host_serial(Object *obj, const char *value, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + g_free(spapr->host_serial); + spapr->host_serial = g_strdup(value); +} + static void spapr_instance_init(Object *obj) { sPAPRMachineState *spapr = SPAPR_MACHINE(obj); @@ -3189,6 +3322,17 @@ static void spapr_instance_init(Object *obj) object_property_set_description(obj, "ic-mode", "Specifies the interrupt controller mode (xics, xive, dual)", NULL); + + object_property_add_str(obj, "host-model", + spapr_get_host_model, spapr_set_host_model, + &error_abort); + object_property_set_description(obj, "host-model", + "Set host's model-id to use - none|passthrough|string", &error_abort); + object_property_add_str(obj, "host-serial", + spapr_get_host_serial, spapr_set_host_serial, + &error_abort); + object_property_set_description(obj, "host-serial", + "Set host's system-id to use - none|passthrough|string", &error_abort); } static void spapr_machine_finalizefn(Object *obj) @@ -3213,14 +3357,26 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp) } } +int spapr_lmb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp) +{ + uint64_t addr; + uint32_t node; + + addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE; + node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP, + &error_abort); + *fdt_start_offset = spapr_populate_memory_node(fdt, node, addr, + SPAPR_MEMORY_BLOCK_SIZE); + return 0; +} + static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size, - uint32_t node, bool dedicated_hp_event_source, - Error **errp) + bool dedicated_hp_event_source, Error **errp) { sPAPRDRConnector *drc; uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE; - int i, fdt_offset, fdt_size; - void *fdt; + int i; uint64_t addr = addr_start; bool hotplugged = spapr_drc_hotplugged(dev); Error *local_err = NULL; @@ -3230,11 +3386,7 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size, addr / SPAPR_MEMORY_BLOCK_SIZE); g_assert(drc); - fdt = create_device_tree(&fdt_size); - fdt_offset = spapr_populate_memory_node(fdt, node, addr, - SPAPR_MEMORY_BLOCK_SIZE); - - spapr_drc_attach(drc, dev, fdt, fdt_offset, &local_err); + spapr_drc_attach(drc, dev, &local_err); if (local_err) { while (addr > addr_start) { addr -= SPAPR_MEMORY_BLOCK_SIZE; @@ -3242,7 +3394,6 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size, addr / SPAPR_MEMORY_BLOCK_SIZE); spapr_drc_detach(drc); } - g_free(fdt); error_propagate(errp, local_err); return; } @@ -3275,7 +3426,6 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev); PCDIMMDevice *dimm = PC_DIMM(dev); uint64_t size, addr; - uint32_t node; size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort); @@ -3290,10 +3440,7 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, goto out_unplug; } - node = object_property_get_uint(OBJECT(dev), PC_DIMM_NODE_PROP, - &error_abort); - spapr_add_lmbs(dev, addr, size, node, - spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT), + spapr_add_lmbs(dev, addr, size, spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT), &local_err); if (local_err) { goto out_unplug; @@ -3513,27 +3660,6 @@ out: error_propagate(errp, local_err); } -static void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset, - sPAPRMachineState *spapr) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - DeviceClass *dc = DEVICE_GET_CLASS(cs); - int id = spapr_get_vcpu_id(cpu); - void *fdt; - int offset, fdt_size; - char *nodename; - - fdt = create_device_tree(&fdt_size); - nodename = g_strdup_printf("%s@%x", dc->fw_name, id); - offset = fdt_add_subnode(fdt, 0, nodename); - - spapr_populate_cpu_dt(cs, fdt, offset, spapr); - g_free(nodename); - - *fdt_offset = offset; - return fdt; -} - /* Callback to be called during DRC release. */ void spapr_core_release(DeviceState *dev) { @@ -3594,6 +3720,27 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, spapr_hotplug_req_remove_by_index(drc); } +int spapr_core_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp) +{ + sPAPRCPUCore *core = SPAPR_CPU_CORE(drc->dev); + CPUState *cs = CPU(core->threads[0]); + PowerPCCPU *cpu = POWERPC_CPU(cs); + DeviceClass *dc = DEVICE_GET_CLASS(cs); + int id = spapr_get_vcpu_id(cpu); + char *nodename; + int offset; + + nodename = g_strdup_printf("%s@%x", dc->fw_name, id); + offset = fdt_add_subnode(fdt, 0, nodename); + g_free(nodename); + + spapr_populate_cpu_dt(cs, fdt, offset, spapr); + + *fdt_start_offset = offset; + return 0; +} + static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -3602,7 +3749,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); - CPUState *cs = CPU(core->threads[0]); + CPUState *cs; sPAPRDRConnector *drc; Error *local_err = NULL; CPUArchId *core_slot; @@ -3621,14 +3768,8 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, g_assert(drc || !mc->has_hotpluggable_cpus); if (drc) { - void *fdt; - int fdt_offset; - - fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr); - - spapr_drc_attach(drc, dev, fdt, fdt_offset, &local_err); + spapr_drc_attach(drc, dev, &local_err); if (local_err) { - g_free(fdt); error_propagate(errp, local_err); return; } @@ -3712,6 +3853,115 @@ out: error_propagate(errp, local_err); } +int spapr_phb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp) +{ + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev); + int intc_phandle; + + intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp); + if (intc_phandle <= 0) { + return -1; + } + + if (spapr_populate_pci_dt(sphb, intc_phandle, fdt, spapr->irq->nr_msis, + fdt_start_offset)) { + error_setg(errp, "unable to create FDT node for PHB %d", sphb->index); + return -1; + } + + /* generally SLOF creates these, for hotplug it's up to QEMU */ + _FDT(fdt_setprop_string(fdt, *fdt_start_offset, "name", "pci")); + + return 0; +} + +static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev); + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + const unsigned windows_supported = spapr_phb_windows_supported(sphb); + + if (dev->hotplugged && !smc->dr_phb_enabled) { + error_setg(errp, "PHB hotplug not supported for this machine"); + return; + } + + if (sphb->index == (uint32_t)-1) { + error_setg(errp, "\"index\" for PAPR PHB is mandatory"); + return; + } + + /* + * This will check that sphb->index doesn't exceed the maximum number of + * PHBs for the current machine type. + */ + smc->phb_placement(spapr, sphb->index, + &sphb->buid, &sphb->io_win_addr, + &sphb->mem_win_addr, &sphb->mem64_win_addr, + windows_supported, sphb->dma_liobn, errp); +} + +static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev); + sPAPRDRConnector *drc; + bool hotplugged = spapr_drc_hotplugged(dev); + Error *local_err = NULL; + + if (!smc->dr_phb_enabled) { + return; + } + + drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index); + /* hotplug hooks should check it's enabled before getting this far */ + assert(drc); + + spapr_drc_attach(drc, DEVICE(dev), &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + if (hotplugged) { + spapr_hotplug_req_add_by_index(drc); + } else { + spapr_drc_reset(drc); + } +} + +void spapr_phb_release(DeviceState *dev) +{ + HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev); + + hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); +} + +static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) +{ + object_unparent(OBJECT(dev)); +} + +static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev); + sPAPRDRConnector *drc; + + drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index); + assert(drc); + + if (!spapr_drc_unplug_requested(drc)) { + spapr_drc_detach(drc); + spapr_hotplug_req_remove_by_index(drc); + } +} + static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -3719,6 +3969,8 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, spapr_memory_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { spapr_core_plug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { + spapr_phb_plug(hotplug_dev, dev, errp); } } @@ -3729,6 +3981,8 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, spapr_memory_unplug(hotplug_dev, dev); } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { spapr_core_unplug(hotplug_dev, dev); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { + spapr_phb_unplug(hotplug_dev, dev); } } @@ -3737,6 +3991,7 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev, { sPAPRMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev)); MachineClass *mc = MACHINE_GET_CLASS(sms); + sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) { @@ -3756,6 +4011,12 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev, return; } spapr_core_unplug_request(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { + if (!smc->dr_phb_enabled) { + error_setg(errp, "PHB hot unplug not supported on this machine"); + return; + } + spapr_phb_unplug_request(hotplug_dev, dev, errp); } } @@ -3766,6 +4027,8 @@ static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev, spapr_memory_pre_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { spapr_core_pre_plug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { + spapr_phb_pre_plug(hotplug_dev, dev, errp); } } @@ -3773,7 +4036,8 @@ static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine, DeviceState *dev) { if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || - object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { + object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) || + object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { return HOTPLUG_HANDLER(machine); } return NULL; @@ -4004,7 +4268,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) vhc->map_hptes = spapr_map_hptes; vhc->unmap_hptes = spapr_unmap_hptes; vhc->store_hpte = spapr_store_hpte; - vhc->get_patbe = spapr_get_patbe; + vhc->get_pate = spapr_get_pate; vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr; xic->ics_get = spapr_ics_get; xic->ics_resend = spapr_ics_resend; @@ -4026,6 +4290,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF; spapr_caps_add_properties(smc, &error_abort); smc->irq = &spapr_irq_xics; + smc->dr_phb_enabled = true; } static const TypeInfo spapr_machine_info = { @@ -4086,11 +4351,18 @@ DEFINE_SPAPR_MACHINE(4_0, "4.0", true); static void spapr_machine_3_1_class_options(MachineClass *mc) { sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + static GlobalProperty compat[] = { + { TYPE_SPAPR_MACHINE, "host-model", "passthrough" }, + { TYPE_SPAPR_MACHINE, "host-serial", "passthrough" }, + }; spapr_machine_4_0_class_options(mc); compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); smc->update_dt_enabled = false; + smc->dr_phb_enabled = false; } DEFINE_SPAPR_MACHINE(3_1, "3.1", false); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 2edb7d1e9c..2943cf47d4 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -22,6 +22,7 @@ #include "qemu/error-report.h" #include "hw/ppc/spapr.h" /* for RTAS return codes */ #include "hw/pci-host/spapr.h" /* spapr_phb_remove_pci_device_cb callback */ +#include "sysemu/device_tree.h" #include "trace.h" #define DRC_CONTAINER_PATH "/dr-connector" @@ -373,8 +374,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, } while (fdt_depth != 0); } -void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, - int fdt_start_offset, Error **errp) +void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, Error **errp) { trace_spapr_drc_attach(spapr_drc_index(drc)); @@ -384,11 +384,8 @@ void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, } g_assert((drc->state == SPAPR_DRC_STATE_LOGICAL_UNUSABLE) || (drc->state == SPAPR_DRC_STATE_PHYSICAL_POWERON)); - g_assert(fdt); drc->dev = d; - drc->fdt = fdt; - drc->fdt_start_offset = fdt_start_offset; object_property_add_link(OBJECT(drc), "device", object_get_typename(OBJECT(drc->dev)), @@ -674,6 +671,7 @@ static void spapr_drc_cpu_class_init(ObjectClass *k, void *data) drck->typename = "CPU"; drck->drc_name_prefix = "CPU "; drck->release = spapr_core_release; + drck->dt_populate = spapr_core_dt_populate; } static void spapr_drc_pci_class_init(ObjectClass *k, void *data) @@ -684,6 +682,7 @@ static void spapr_drc_pci_class_init(ObjectClass *k, void *data) drck->typename = "28"; drck->drc_name_prefix = "C"; drck->release = spapr_phb_remove_pci_device_cb; + drck->dt_populate = spapr_pci_dt_populate; } static void spapr_drc_lmb_class_init(ObjectClass *k, void *data) @@ -694,6 +693,18 @@ static void spapr_drc_lmb_class_init(ObjectClass *k, void *data) drck->typename = "MEM"; drck->drc_name_prefix = "LMB "; drck->release = spapr_lmb_release; + drck->dt_populate = spapr_lmb_dt_populate; +} + +static void spapr_drc_phb_class_init(ObjectClass *k, void *data) +{ + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); + + drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB; + drck->typename = "PHB"; + drck->drc_name_prefix = "PHB "; + drck->release = spapr_phb_release; + drck->dt_populate = spapr_phb_dt_populate; } static const TypeInfo spapr_dr_connector_info = { @@ -739,6 +750,13 @@ static const TypeInfo spapr_drc_lmb_info = { .class_init = spapr_drc_lmb_class_init, }; +static const TypeInfo spapr_drc_phb_info = { + .name = TYPE_SPAPR_DRC_PHB, + .parent = TYPE_SPAPR_DRC_LOGICAL, + .instance_size = sizeof(sPAPRDRConnector), + .class_init = spapr_drc_phb_class_init, +}; + /* helper functions for external users */ sPAPRDRConnector *spapr_drc_by_index(uint32_t index) @@ -1102,10 +1120,28 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, goto out; } - g_assert(drc->fdt); - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + if (!drc->fdt) { + Error *local_err = NULL; + void *fdt; + int fdt_size; + + fdt = create_device_tree(&fdt_size); + + if (drck->dt_populate(drc, spapr, fdt, &drc->fdt_start_offset, + &local_err)) { + g_free(fdt); + error_free(local_err); + rc = SPAPR_DR_CC_RESPONSE_ERROR; + goto out; + } + + drc->fdt = fdt; + drc->ccs_offset = drc->fdt_start_offset; + drc->ccs_depth = 0; + } + do { uint32_t tag; const char *name; @@ -1189,6 +1225,7 @@ static void spapr_drc_register_types(void) type_register_static(&spapr_drc_cpu_info); type_register_static(&spapr_drc_pci_info); type_register_static(&spapr_drc_lmb_info); + type_register_static(&spapr_drc_phb_info); spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator", rtas_set_indicator); diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index b9c7ecb9e9..ab9a1f0063 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -526,6 +526,9 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, case SPAPR_DR_CONNECTOR_TYPE_CPU: hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_CPU; break; + case SPAPR_DR_CONNECTOR_TYPE_PHB: + hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_PHB; + break; default: /* we shouldn't be signaling hotplug events for resources * that don't support them diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 17bcaa3822..476bad6271 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -17,37 +17,6 @@ #include "mmu-book3s-v3.h" #include "hw/mem/memory-device.h" -struct LPCRSyncState { - target_ulong value; - target_ulong mask; -}; - -static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg) -{ - struct LPCRSyncState *s = arg.host_ptr; - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - target_ulong lpcr; - - cpu_synchronize_state(cs); - lpcr = env->spr[SPR_LPCR]; - lpcr &= ~s->mask; - lpcr |= s->value; - ppc_store_lpcr(cpu, lpcr); -} - -static void set_all_lpcrs(target_ulong value, target_ulong mask) -{ - CPUState *cs; - struct LPCRSyncState s = { - .value = value, - .mask = mask - }; - CPU_FOREACH(cs) { - run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s)); - } -} - static bool has_spr(PowerPCCPU *cpu, int spr) { /* We can test whether the SPR is defined by checking for a valid name */ @@ -1255,12 +1224,12 @@ static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu, switch (mflags) { case H_SET_MODE_ENDIAN_BIG: - set_all_lpcrs(0, LPCR_ILE); + spapr_set_all_lpcrs(0, LPCR_ILE); spapr_pci_switch_vga(true); return H_SUCCESS; case H_SET_MODE_ENDIAN_LITTLE: - set_all_lpcrs(LPCR_ILE, LPCR_ILE); + spapr_set_all_lpcrs(LPCR_ILE, LPCR_ILE); spapr_pci_switch_vga(false); return H_SUCCESS; } @@ -1289,7 +1258,7 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu, return H_UNSUPPORTED_FLAG; } - set_all_lpcrs(mflags << LPCR_AIL_SHIFT, LPCR_AIL); + spapr_set_all_lpcrs(mflags << LPCR_AIL_SHIFT, LPCR_AIL); return H_SUCCESS; } @@ -1342,12 +1311,12 @@ static void spapr_check_setup_free_hpt(sPAPRMachineState *spapr, * later and so assumed radix and now it's called H_REG_PROC_TBL */ - if ((patbe_old & PATBE1_GR) == (patbe_new & PATBE1_GR)) { + if ((patbe_old & PATE1_GR) == (patbe_new & PATE1_GR)) { /* We assume RADIX, so this catches all the "Do Nothing" cases */ - } else if (!(patbe_old & PATBE1_GR)) { + } else if (!(patbe_old & PATE1_GR)) { /* HASH->RADIX : Free HPT */ spapr_free_hpt(spapr); - } else if (!(patbe_new & PATBE1_GR)) { + } else if (!(patbe_new & PATE1_GR)) { /* RADIX->HASH || NOTHING->HASH : Allocate HPT */ spapr_setup_hpt_and_vrma(spapr); } @@ -1385,7 +1354,7 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, } else if (table_size > 24) { return H_P4; } - cproc = PATBE1_GR | proc_tbl | table_size; + cproc = PATE1_GR | proc_tbl | table_size; } else { /* Register new HPT process table */ if (flags & FLAG_HASH_PROC_TBL) { /* Hash with Segment Tables */ /* TODO - Not Supported */ @@ -1404,13 +1373,15 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, } } else { /* Deregister current process table */ - /* Set to benign value: (current GR) | 0. This allows - * deregistration in KVM to succeed even if the radix bit in flags - * doesn't match the radix bit in the old PATB. */ - cproc = spapr->patb_entry & PATBE1_GR; + /* + * Set to benign value: (current GR) | 0. This allows + * deregistration in KVM to succeed even if the radix bit + * in flags doesn't match the radix bit in the old PATE. + */ + cproc = spapr->patb_entry & PATE1_GR; } } else { /* Maintain current registration */ - if (!(flags & FLAG_RADIX) != !(spapr->patb_entry & PATBE1_GR)) { + if (!(flags & FLAG_RADIX) != !(spapr->patb_entry & PATE1_GR)) { /* Technically caused by flag bits => H_PARAMETER */ return H_PARAMETER; /* Existing Process Table Mismatch */ } @@ -1422,10 +1393,11 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, spapr->patb_entry = cproc; /* Save new process table */ - /* Update the UPRT and GTSE bits in the LPCR for all cpus */ - set_all_lpcrs(((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? LPCR_UPRT : 0) | - ((flags & FLAG_GTSE) ? LPCR_GTSE : 0), - LPCR_UPRT | LPCR_GTSE); + /* Update the UPRT, HR and GTSE bits in the LPCR for all cpus */ + spapr_set_all_lpcrs(((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? + (LPCR_UPRT | LPCR_HR) : 0) | + ((flags & FLAG_GTSE) ? LPCR_GTSE : 0), + LPCR_UPRT | LPCR_HR | LPCR_GTSE); if (kvm_enabled()) { return kvmppc_configure_v3_mmu(cpu, flags & FLAG_RADIX, @@ -1646,7 +1618,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, if (!spapr->cas_reboot) { /* If spapr_machine_reset() did not set up a HPT but one is necessary * (because the guest isn't going to use radix) then set it up here. */ - if ((spapr->patb_entry & PATBE1_GR) && !guest_radix) { + if ((spapr->patb_entry & PATE1_GR) && !guest_radix) { /* legacy hash or new hash: */ spapr_setup_hpt_and_vrma(spapr); } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 4297eed600..4145079d7f 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -230,6 +230,11 @@ static void spapr_irq_reset_xics(sPAPRMachineState *spapr, Error **errp) /* TODO: create the KVM XICS device */ } +static const char *spapr_irq_get_nodename_xics(sPAPRMachineState *spapr) +{ + return XICS_NODENAME; +} + #define SPAPR_IRQ_XICS_NR_IRQS 0x1000 #define SPAPR_IRQ_XICS_NR_MSIS \ (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI) @@ -249,6 +254,7 @@ sPAPRIrq spapr_irq_xics = { .post_load = spapr_irq_post_load_xics, .reset = spapr_irq_reset_xics, .set_irq = spapr_irq_set_irq_xics, + .get_nodename = spapr_irq_get_nodename_xics, }; /* @@ -384,6 +390,11 @@ static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) xive_source_set_irq(&spapr->xive->source, srcno, val); } +static const char *spapr_irq_get_nodename_xive(sPAPRMachineState *spapr) +{ + return spapr->xive->nodename; +} + /* * XIVE uses the full IRQ number space. Set it to 8K to be compatible * with XICS. @@ -407,6 +418,7 @@ sPAPRIrq spapr_irq_xive = { .post_load = spapr_irq_post_load_xive, .reset = spapr_irq_reset_xive, .set_irq = spapr_irq_set_irq_xive, + .get_nodename = spapr_irq_get_nodename_xive, }; /* @@ -541,6 +553,11 @@ static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) spapr_irq_current(spapr)->set_irq(spapr, srcno, val); } +static const char *spapr_irq_get_nodename_dual(sPAPRMachineState *spapr) +{ + return spapr_irq_current(spapr)->get_nodename(spapr); +} + /* * Define values in sync with the XIVE and XICS backend */ @@ -561,7 +578,8 @@ sPAPRIrq spapr_irq_dual = { .cpu_intc_create = spapr_irq_cpu_intc_create_dual, .post_load = spapr_irq_post_load_dual, .reset = spapr_irq_reset_dual, - .set_irq = spapr_irq_set_irq_dual + .set_irq = spapr_irq_set_irq_dual, + .get_nodename = spapr_irq_get_nodename_dual, }; /* @@ -620,6 +638,27 @@ void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp) } } +int spapr_irq_get_phandle(sPAPRMachineState *spapr, void *fdt, Error **errp) +{ + const char *nodename = spapr->irq->get_nodename(spapr); + int offset, phandle; + + offset = fdt_subnode_offset(fdt, 0, nodename); + if (offset < 0) { + error_setg(errp, "Can't find node \"%s\": %s", nodename, + fdt_strerror(offset)); + return -1; + } + + phandle = fdt_get_phandle(fdt, offset); + if (!phandle) { + error_setg(errp, "Can't get phandle of node \"%s\"", nodename); + return -1; + } + + return phandle; +} + /* * XICS legacy routines - to deprecate one day */ @@ -691,4 +730,5 @@ sPAPRIrq spapr_irq_xics_legacy = { .cpu_intc_create = spapr_irq_cpu_intc_create_xics, .post_load = spapr_irq_post_load_xics, .set_irq = spapr_irq_set_irq_xics, + .get_nodename = spapr_irq_get_nodename_xics, }; diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c index 318bf33de4..12510b236a 100644 --- a/hw/ppc/spapr_ovec.c +++ b/hw/ppc/spapr_ovec.c @@ -16,6 +16,7 @@ #include "qemu/bitmap.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" +#include "sysemu/qtest.h" #include "trace.h" #include <libfdt.h> @@ -131,6 +132,11 @@ bool spapr_ovec_test(sPAPROptionVector *ov, long bitnr) g_assert(ov); g_assert(bitnr < OV_MAXBITS); + /* support memory unplug for qtest */ + if (qtest_enabled() && bitnr == OV5_HP_EVT) { + return true; + } + return test_bit(bitnr, ov->bitmap) ? true : false; } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 60777b2355..06a5ffd281 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1408,6 +1408,17 @@ static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb, return spapr_drc_index(drc); } +int spapr_pci_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp) +{ + HotplugHandler *plug_handler = qdev_get_hotplug_handler(drc->dev); + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(plug_handler); + PCIDevice *pdev = PCI_DEVICE(drc->dev); + + *fdt_start_offset = spapr_create_pci_child_dt(sphb, pdev, fdt, 0); + return 0; +} + static void spapr_pci_plug(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp) { @@ -1417,8 +1428,6 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, Error *local_err = NULL; PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev))); uint32_t slotnr = PCI_SLOT(pdev->devfn); - void *fdt = NULL; - int fdt_start_offset, fdt_size; /* if DR is disabled we don't need to do anything in the case of * hotplug or coldplug callbacks @@ -1448,10 +1457,7 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, goto out; } - fdt = create_device_tree(&fdt_size); - fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0); - - spapr_drc_attach(drc, DEVICE(pdev), fdt, fdt_start_offset, &local_err); + spapr_drc_attach(drc, DEVICE(pdev), &local_err); if (local_err) { goto out; } @@ -1483,7 +1489,6 @@ static void spapr_pci_plug(HotplugHandler *plug_handler, out: if (local_err) { error_propagate(errp, local_err); - g_free(fdt); } } @@ -1565,6 +1570,75 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, } } +static void spapr_phb_finalizefn(Object *obj) +{ + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(obj); + + g_free(sphb->dtbusname); + sphb->dtbusname = NULL; +} + +static void spapr_phb_unrealize(DeviceState *dev, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + SysBusDevice *s = SYS_BUS_DEVICE(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(s); + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(phb); + sPAPRTCETable *tcet; + int i; + const unsigned windows_supported = spapr_phb_windows_supported(sphb); + + if (sphb->msi) { + g_hash_table_unref(sphb->msi); + sphb->msi = NULL; + } + + /* + * Remove IO/MMIO subregions and aliases, rest should get cleaned + * via PHB's unrealize->object_finalize + */ + for (i = windows_supported - 1; i >= 0; i--) { + tcet = spapr_tce_find_by_liobn(sphb->dma_liobn[i]); + if (tcet) { + memory_region_del_subregion(&sphb->iommu_root, + spapr_tce_get_iommu(tcet)); + } + } + + if (sphb->dr_enabled) { + for (i = PCI_SLOT_MAX * 8 - 1; i >= 0; i--) { + sPAPRDRConnector *drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PCI, + (sphb->index << 16) | i); + + if (drc) { + object_unparent(OBJECT(drc)); + } + } + } + + for (i = PCI_NUM_PINS - 1; i >= 0; i--) { + if (sphb->lsi_table[i].irq) { + spapr_irq_free(spapr, sphb->lsi_table[i].irq, 1); + sphb->lsi_table[i].irq = 0; + } + } + + QLIST_REMOVE(sphb, list); + + memory_region_del_subregion(&sphb->iommu_root, &sphb->msiwindow); + + address_space_destroy(&sphb->iommu_as); + + qbus_set_hotplug_handler(BUS(phb->bus), NULL, &error_abort); + pci_unregister_root_bus(phb->bus); + + memory_region_del_subregion(get_system_memory(), &sphb->iowindow); + if (sphb->mem64_win_pciaddr != (hwaddr)-1) { + memory_region_del_subregion(get_system_memory(), &sphb->mem64window); + } + memory_region_del_subregion(get_system_memory(), &sphb->mem32window); +} + static void spapr_phb_realize(DeviceState *dev, Error **errp) { /* We don't use SPAPR_MACHINE() in order to exit gracefully if the user @@ -1582,29 +1656,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) PCIBus *bus; uint64_t msi_window_size = 4096; sPAPRTCETable *tcet; - const unsigned windows_supported = - sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1; + const unsigned windows_supported = spapr_phb_windows_supported(sphb); if (!spapr) { error_setg(errp, TYPE_SPAPR_PCI_HOST_BRIDGE " needs a pseries machine"); return; } - if (sphb->index != (uint32_t)-1) { - Error *local_err = NULL; - - smc->phb_placement(spapr, sphb->index, - &sphb->buid, &sphb->io_win_addr, - &sphb->mem_win_addr, &sphb->mem64_win_addr, - windows_supported, sphb->dma_liobn, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } else { - error_setg(errp, "\"index\" for PAPR PHB is mandatory"); - return; - } + assert(sphb->index != (uint32_t)-1); /* checked in spapr_phb_pre_plug() */ if (sphb->mem64_win_size != 0) { if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) { @@ -1740,6 +1799,10 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) if (local_err) { error_propagate_prepend(errp, local_err, "can't allocate LSIs: "); + /* + * Older machines will never support PHB hotplug, ie, this is an + * init only path and QEMU will terminate. No need to rollback. + */ return; } } @@ -1747,7 +1810,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) spapr_irq_claim(spapr, irq, true, &local_err); if (local_err) { error_propagate_prepend(errp, local_err, "can't allocate LSIs: "); - return; + goto unrealize; } sphb->lsi_table[i].irq = irq; @@ -1767,13 +1830,17 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) if (!tcet) { error_setg(errp, "Creating window#%d failed for %s", i, sphb->dtbusname); - return; + goto unrealize; } memory_region_add_subregion(&sphb->iommu_root, 0, spapr_tce_get_iommu(tcet)); } sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); + return; + +unrealize: + spapr_phb_unrealize(dev, NULL); } static int spapr_phb_children_reset(Object *child, void *opaque) @@ -1972,6 +2039,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) hc->root_bus_path = spapr_phb_root_bus_path; dc->realize = spapr_phb_realize; + dc->unrealize = spapr_phb_unrealize; dc->props = spapr_phb_properties; dc->reset = spapr_phb_reset; dc->vmsd = &vmstate_spapr_pci; @@ -1987,6 +2055,7 @@ static const TypeInfo spapr_phb_info = { .name = TYPE_SPAPR_PCI_HOST_BRIDGE, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(sPAPRPHBState), + .instance_finalize = spapr_phb_finalizefn, .class_init = spapr_phb_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, @@ -2070,7 +2139,7 @@ static void spapr_phb_pci_enumerate(sPAPRPHBState *phb) } int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t intc_phandle, void *fdt, - uint32_t nr_msis) + uint32_t nr_msis, int *node_offset) { int bus_off, i, j, ret; gchar *nodename; @@ -2120,11 +2189,15 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t intc_phandle, void *fdt, sPAPRTCETable *tcet; PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus; sPAPRFDT s_fdt; + sPAPRDRConnector *drc; /* Start populating the FDT */ nodename = g_strdup_printf("pci@%" PRIx64, phb->buid); _FDT(bus_off = fdt_add_subnode(fdt, 0, nodename)); g_free(nodename); + if (node_offset) { + *node_offset = bus_off; + } /* Write PHB properties */ _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci")); @@ -2183,6 +2256,14 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t intc_phandle, void *fdt, tcet->liobn, tcet->bus_offset, tcet->nb_table << tcet->page_shift); + drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, phb->index); + if (drc) { + uint32_t drc_index = cpu_to_be32(spapr_drc_index(drc)); + + _FDT(fdt_setprop(fdt, bus_off, "ibm,my-drc-index", &drc_index, + sizeof(drc_index))); + } + /* Walk the bridges and program the bus numbers*/ spapr_phb_pci_enumerate(phb); _FDT(fdt_setprop_cell(fdt, bus_off, "qemu,phb-enumerated", 0x1)); diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index d6a0952154..7a2cb786a3 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -172,10 +172,10 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, sPAPRMachineState *spapr, * New cpus are expected to start in the same radix/hash mode * as the existing CPUs */ - if (ppc64_radix_guest(callcpu)) { - lpcr |= LPCR_UPRT | LPCR_GTSE; + if (ppc64_v3_radix(callcpu)) { + lpcr |= LPCR_UPRT | LPCR_GTSE | LPCR_HR; } else { - lpcr &= ~(LPCR_UPRT | LPCR_GTSE); + lpcr &= ~(LPCR_UPRT | LPCR_GTSE | LPCR_HR); } } ppc_store_lpcr(newcpu, lpcr); diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c index 3795d30dd7..75ad0a66b9 100644 --- a/hw/s390x/ap-bridge.c +++ b/hw/s390x/ap-bridge.c @@ -39,6 +39,7 @@ static const TypeInfo ap_bus_info = { void s390_init_ap(void) { DeviceState *dev; + BusState *bus; /* If no AP instructions then no need for AP bridge */ if (!s390_has_feat(S390_FEAT_AP)) { @@ -52,13 +53,18 @@ void s390_init_ap(void) qdev_init_nofail(dev); /* Create bus on bridge device */ - qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS); + bus = qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS); + + /* Enable hotplugging */ + qbus_set_hotplug_handler(bus, OBJECT(dev), &error_abort); } static void ap_bridge_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + hc->unplug = qdev_simple_device_unplug_cb; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } @@ -67,6 +73,10 @@ static const TypeInfo ap_bridge_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = 0, .class_init = ap_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + } }; static void ap_register(void) diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 818be8a838..47be9071fa 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -563,6 +563,7 @@ static void smbios_build_type_3_table(void) t->height = 0; t->number_of_power_cords = 0; t->contained_element_count = 0; + t->contained_element_record_length = 0; SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku); SMBIOS_BUILD_TABLE_POST; diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c index 3849b74a68..03da75486b 100644 --- a/hw/timer/ds1338.c +++ b/hw/timer/ds1338.c @@ -117,7 +117,7 @@ static int ds1338_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int ds1338_recv(I2CSlave *i2c) +static uint8_t ds1338_recv(I2CSlave *i2c) { DS1338State *s = DS1338(i2c); uint8_t res; diff --git a/hw/timer/m41t80.c b/hw/timer/m41t80.c index 734d7d95fc..c45b9297d8 100644 --- a/hw/timer/m41t80.c +++ b/hw/timer/m41t80.c @@ -40,7 +40,7 @@ static int m41t80_send(I2CSlave *i2c, uint8_t data) return 0; } -static int m41t80_recv(I2CSlave *i2c) +static uint8_t m41t80_recv(I2CSlave *i2c) { M41t80State *s = M41T80(i2c); struct tm now; diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c index 51ec355f3f..c83d803dd8 100644 --- a/hw/timer/twl92230.c +++ b/hw/timer/twl92230.c @@ -737,7 +737,7 @@ static int menelaus_tx(I2CSlave *i2c, uint8_t data) return 0; } -static int menelaus_rx(I2CSlave *i2c) +static uint8_t menelaus_rx(I2CSlave *i2c) { MenelausState *s = TWL92230(i2c); diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index f1d20fa1b9..4ee4fc5a89 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -11,17 +11,16 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include <wchar.h> #include <dirent.h> #include <sys/statvfs.h> -#ifdef CONFIG_INOTIFY1 -#include <sys/inotify.h> -#include "qemu/main-loop.h" -#endif + #include "qemu-common.h" #include "qemu/iov.h" +#include "qemu/filemonitor.h" #include "trace.h" #include "hw/usb.h" #include "desc.h" @@ -132,7 +131,6 @@ enum { EP_EVENT, }; -#ifdef CONFIG_INOTIFY1 typedef struct MTPMonEntry MTPMonEntry; struct MTPMonEntry { @@ -141,7 +139,6 @@ struct MTPMonEntry { QTAILQ_ENTRY(MTPMonEntry) next; }; -#endif struct MTPControl { uint16_t code; @@ -172,10 +169,8 @@ struct MTPObject { char *name; char *path; struct stat stat; -#ifdef CONFIG_INOTIFY1 - /* inotify watch cookie */ - int watchfd; -#endif + /* file monitor watch id */ + int watchid; MTPObject *parent; uint32_t nchildren; QLIST_HEAD(, MTPObject) children; @@ -198,11 +193,8 @@ struct MTPState { bool readonly; QTAILQ_HEAD(, MTPObject) objects; -#ifdef CONFIG_INOTIFY1 - /* inotify descriptor */ - int inotifyfd; + QFileMonitor *file_monitor; QTAILQ_HEAD(, MTPMonEntry) events; -#endif /* Responder is expecting a write operation */ bool write_pending; struct { @@ -383,7 +375,7 @@ static const USBDesc desc = { /* ----------------------------------------------------------------------- */ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle, - MTPObject *parent, char *name) + MTPObject *parent, const char *name) { MTPObject *o = g_new0(MTPObject, 1); @@ -391,6 +383,7 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle, goto ignore; } + o->watchid = -1; o->handle = handle; o->parent = parent; o->name = g_strdup(name); @@ -437,6 +430,10 @@ static void usb_mtp_object_free(MTPState *s, MTPObject *o) trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path); + if (o->watchid != -1 && s->file_monitor) { + qemu_file_monitor_remove_watch(s->file_monitor, o->path, o->watchid); + } + QTAILQ_REMOVE(&s->objects, o, next); if (o->parent) { QLIST_REMOVE(o, list); @@ -465,7 +462,7 @@ static MTPObject *usb_mtp_object_lookup(MTPState *s, uint32_t handle) } static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o, - char *name) + const char *name) { MTPObject *child = usb_mtp_object_alloc(s, s->next_handle++, o, name); @@ -484,10 +481,14 @@ static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o, } static MTPObject *usb_mtp_object_lookup_name(MTPObject *parent, - char *name, int len) + const char *name, int len) { MTPObject *iter; + if (len == -1) { + len = strlen(name); + } + QLIST_FOREACH(iter, &parent->children, list) { if (strncmp(iter->name, name, len) == 0) { return iter; @@ -497,13 +498,12 @@ static MTPObject *usb_mtp_object_lookup_name(MTPObject *parent, return NULL; } -#ifdef CONFIG_INOTIFY1 -static MTPObject *usb_mtp_object_lookup_wd(MTPState *s, int wd) +static MTPObject *usb_mtp_object_lookup_id(MTPState *s, int id) { MTPObject *iter; QTAILQ_FOREACH(iter, &s->objects, next) { - if (iter->watchfd == wd) { + if (iter->watchid == id) { return iter; } } @@ -511,160 +511,103 @@ static MTPObject *usb_mtp_object_lookup_wd(MTPState *s, int wd) return NULL; } -static void inotify_watchfn(void *arg) +static void file_monitor_event(int id, + QFileMonitorEvent ev, + const char *name, + void *opaque) { - MTPState *s = arg; - ssize_t bytes; - /* From the man page: atleast one event can be read */ - int pos; - char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; - - for (;;) { - bytes = read(s->inotifyfd, buf, sizeof(buf)); - pos = 0; - - if (bytes <= 0) { - /* Better luck next time */ + MTPState *s = opaque; + MTPObject *parent = usb_mtp_object_lookup_id(s, id); + MTPMonEntry *entry = NULL; + MTPObject *o; + + if (!parent) { + return; + } + + switch (ev) { + case QFILE_MONITOR_EVENT_CREATED: + if (usb_mtp_object_lookup_name(parent, name, -1)) { + /* Duplicate create event */ return; } + entry = g_new0(MTPMonEntry, 1); + entry->handle = s->next_handle; + entry->event = EVT_OBJ_ADDED; + o = usb_mtp_add_child(s, parent, name); + if (!o) { + g_free(entry); + return; + } + trace_usb_mtp_file_monitor_event(s->dev.addr, name, "Obj Added"); + break; + case QFILE_MONITOR_EVENT_DELETED: /* - * TODO: Ignore initiator initiated events. - * For now we are good because the store is RO + * The kernel issues a IN_IGNORED event + * when a dir containing a watchpoint is + * deleted, so we don't have to delete the + * watchpoint */ - while (bytes > 0) { - char *p = buf + pos; - struct inotify_event *event = (struct inotify_event *)p; - int watchfd = 0; - uint32_t mask = event->mask & (IN_CREATE | IN_DELETE | - IN_MODIFY | IN_IGNORED); - MTPObject *parent = usb_mtp_object_lookup_wd(s, event->wd); - MTPMonEntry *entry = NULL; - MTPObject *o; - - pos = pos + sizeof(struct inotify_event) + event->len; - bytes = bytes - pos; - - if (!parent) { - continue; - } - - switch (mask) { - case IN_CREATE: - if (usb_mtp_object_lookup_name - (parent, event->name, event->len)) { - /* Duplicate create event */ - continue; - } - entry = g_new0(MTPMonEntry, 1); - entry->handle = s->next_handle; - entry->event = EVT_OBJ_ADDED; - o = usb_mtp_add_child(s, parent, event->name); - if (!o) { - g_free(entry); - continue; - } - o->watchfd = watchfd; - trace_usb_mtp_inotify_event(s->dev.addr, event->name, - event->mask, "Obj Added"); - break; - - case IN_DELETE: - /* - * The kernel issues a IN_IGNORED event - * when a dir containing a watchpoint is - * deleted, so we don't have to delete the - * watchpoint - */ - o = usb_mtp_object_lookup_name(parent, event->name, event->len); - if (!o) { - continue; - } - entry = g_new0(MTPMonEntry, 1); - entry->handle = o->handle; - entry->event = EVT_OBJ_REMOVED; - trace_usb_mtp_inotify_event(s->dev.addr, o->path, - event->mask, "Obj Deleted"); - usb_mtp_object_free(s, o); - break; - - case IN_MODIFY: - o = usb_mtp_object_lookup_name(parent, event->name, event->len); - if (!o) { - continue; - } - entry = g_new0(MTPMonEntry, 1); - entry->handle = o->handle; - entry->event = EVT_OBJ_INFO_CHANGED; - trace_usb_mtp_inotify_event(s->dev.addr, o->path, - event->mask, "Obj Modified"); - break; - - case IN_IGNORED: - trace_usb_mtp_inotify_event(s->dev.addr, parent->path, - event->mask, "Obj parent dir ignored"); - break; - - default: - fprintf(stderr, "usb-mtp: failed to parse inotify event\n"); - continue; - } - - if (entry) { - QTAILQ_INSERT_HEAD(&s->events, entry, next); - } + o = usb_mtp_object_lookup_name(parent, name, -1); + if (!o) { + return; } - } -} + entry = g_new0(MTPMonEntry, 1); + entry->handle = o->handle; + entry->event = EVT_OBJ_REMOVED; + trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, "Obj Deleted"); + usb_mtp_object_free(s, o); + break; -static int usb_mtp_inotify_init(MTPState *s) -{ - int fd; + case QFILE_MONITOR_EVENT_MODIFIED: + o = usb_mtp_object_lookup_name(parent, name, -1); + if (!o) { + return; + } + entry = g_new0(MTPMonEntry, 1); + entry->handle = o->handle; + entry->event = EVT_OBJ_INFO_CHANGED; + trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, "Obj Modified"); + break; - fd = inotify_init1(IN_NONBLOCK); - if (fd == -1) { - return 1; - } + case QFILE_MONITOR_EVENT_IGNORED: + trace_usb_mtp_file_monitor_event(s->dev.addr, parent->path, + "Obj parent dir ignored"); + break; - QTAILQ_INIT(&s->events); - s->inotifyfd = fd; + case QFILE_MONITOR_EVENT_ATTRIBUTES: + break; - qemu_set_fd_handler(fd, inotify_watchfn, NULL, s); + default: + g_assert_not_reached(); + } - return 0; + if (entry) { + QTAILQ_INSERT_HEAD(&s->events, entry, next); + } } -static void usb_mtp_inotify_cleanup(MTPState *s) +static void usb_mtp_file_monitor_cleanup(MTPState *s) { MTPMonEntry *e, *p; - if (!s->inotifyfd) { - return; - } - - qemu_set_fd_handler(s->inotifyfd, NULL, NULL, s); - close(s->inotifyfd); - QTAILQ_FOREACH_SAFE(e, &s->events, next, p) { QTAILQ_REMOVE(&s->events, e, next); g_free(e); } -} -static int usb_mtp_add_watch(int inotifyfd, char *path) -{ - uint32_t mask = IN_CREATE | IN_DELETE | IN_MODIFY | - IN_ISDIR; - - return inotify_add_watch(inotifyfd, path, mask); + qemu_file_monitor_free(s->file_monitor); + s->file_monitor = NULL; } -#endif + static void usb_mtp_object_readdir(MTPState *s, MTPObject *o) { struct dirent *entry; DIR *dir; int fd; + Error *err = NULL; if (o->have_children) { return; @@ -680,16 +623,21 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o) close(fd); return; } -#ifdef CONFIG_INOTIFY1 - int watchfd = usb_mtp_add_watch(s->inotifyfd, o->path); - if (watchfd == -1) { - fprintf(stderr, "usb-mtp: failed to add watch for %s\n", o->path); - } else { - trace_usb_mtp_inotify_event(s->dev.addr, o->path, - 0, "Watch Added"); - o->watchfd = watchfd; + + if (s->file_monitor) { + int id = qemu_file_monitor_add_watch(s->file_monitor, o->path, NULL, + file_monitor_event, s, &err); + if (id == -1) { + error_report("usb-mtp: failed to add watch for %s: %s", o->path, + error_get_pretty(err)); + error_free(err); + } else { + trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, + "Watch Added"); + o->watchid = id; + } } -#endif + while ((entry = readdir(dir)) != NULL) { usb_mtp_add_child(s, o, entry->d_name); } @@ -1197,13 +1145,11 @@ enum { /* Assumes that children, if any, have been already freed */ static void usb_mtp_object_free_one(MTPState *s, MTPObject *o) { -#ifndef CONFIG_INOTIFY1 assert(o->nchildren == 0); QTAILQ_REMOVE(&s->objects, o, next); g_free(o->name); g_free(o->path); g_free(o); -#endif } static int usb_mtp_deletefn(MTPState *s, MTPObject *o, uint32_t trans) @@ -1302,6 +1248,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) MTPData *data_in = NULL; MTPObject *o = NULL; uint32_t nres = 0, res0 = 0; + Error *err = NULL; /* sanity checks */ if (c->code >= CMD_CLOSE_SESSION && s->session == 0) { @@ -1329,19 +1276,21 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) trace_usb_mtp_op_open_session(s->dev.addr); s->session = c->argv[0]; usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root); -#ifdef CONFIG_INOTIFY1 - if (usb_mtp_inotify_init(s)) { - fprintf(stderr, "usb-mtp: file monitoring init failed\n"); + + s->file_monitor = qemu_file_monitor_new(&err); + if (err) { + error_report("usb-mtp: file monitoring init failed: %s", + error_get_pretty(err)); + error_free(err); + } else { + QTAILQ_INIT(&s->events); } -#endif break; case CMD_CLOSE_SESSION: trace_usb_mtp_op_close_session(s->dev.addr); s->session = 0; s->next_handle = 0; -#ifdef CONFIG_INOTIFY1 - usb_mtp_inotify_cleanup(s); -#endif + usb_mtp_file_monitor_cleanup(s); usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects)); assert(QTAILQ_EMPTY(&s->objects)); break; @@ -1554,9 +1503,7 @@ static void usb_mtp_handle_reset(USBDevice *dev) trace_usb_mtp_reset(s->dev.addr); -#ifdef CONFIG_INOTIFY1 - usb_mtp_inotify_cleanup(s); -#endif + usb_mtp_file_monitor_cleanup(s); usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects)); s->session = 0; usb_mtp_data_free(s->data_in); @@ -2027,7 +1974,6 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) } break; case EP_EVENT: -#ifdef CONFIG_INOTIFY1 if (!QTAILQ_EMPTY(&s->events)) { struct MTPMonEntry *e = QTAILQ_LAST(&s->events); uint32_t handle; @@ -2051,7 +1997,6 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) g_free(e); return; } -#endif p->status = USB_RET_NAK; return; default: diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 2c18770ca5..99b1e8b8ce 100644 --- a/hw/usb/trace-events +++ b/hw/usb/trace-events @@ -237,7 +237,7 @@ usb_mtp_op_unknown(int dev, uint32_t code) "dev %d, command code 0x%x" usb_mtp_object_alloc(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" usb_mtp_object_free(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" usb_mtp_add_child(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" -usb_mtp_inotify_event(int dev, const char *path, uint32_t mask, const char *s) "dev %d, path %s mask 0x%x event %s" +usb_mtp_file_monitor_event(int dev, const char *path, const char *s) "dev %d, path %s event %s" # hw/usb/host-libusb.c usb_host_open_started(int bus, int addr) "dev %d:%d" diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index 6166ccd47a..d8b79ebe53 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -169,7 +169,7 @@ static void vfio_ap_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->realize = vfio_ap_realize; dc->unrealize = vfio_ap_unrealize; - dc->hotpluggable = false; + dc->hotpluggable = true; dc->reset = vfio_ap_reset; dc->bus_type = TYPE_AP_BUS; } diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index eae31c74d6..40a12001f5 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -526,8 +526,6 @@ static void vfio_probe_ati_bar2_quirk(VFIOPCIDevice *vdev, int nr) * note it for future reference. */ -#define PCI_VENDOR_ID_NVIDIA 0x10de - /* * Nvidia has several different methods to get to config space, the * nouveu project has several of these documented here: diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index d335dd0a6a..a3eb8ed866 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -2,15 +2,18 @@ ifeq ($(CONFIG_VIRTIO),y) common-obj-y += virtio-bus.o obj-y += virtio.o +obj-$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_VHOST_KERNEL)) += vhost.o vhost-backend.o +common-obj-$(call lnot,$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_VHOST_KERNEL))) += vhost-stub.o +obj-$(CONFIG_VHOST_USER) += vhost-user.o + common-obj-$(CONFIG_VIRTIO_RNG) += virtio-rng.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o common-obj-$(CONFIG_VIRTIO_MMIO) += virtio-mmio.o obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon.o obj-$(CONFIG_VIRTIO_CRYPTO) += virtio-crypto.o obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-pci.o - -obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o + ifeq ($(CONFIG_VIRTIO_PCI),y) obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk-pci.o @@ -28,5 +31,4 @@ obj-$(CONFIG_VIRTIO_SERIAL) += virtio-serial-pci.o endif endif -common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o common-obj-$(CONFIG_ALL) += vhost-stub.o diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 7f09efab8b..96b8d3c95d 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -9,11 +9,14 @@ */ #include "qemu/osdep.h" -#include <linux/vhost.h> -#include <sys/ioctl.h> #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-backend.h" #include "qemu/error-report.h" +#include "standard-headers/linux/vhost_types.h" + +#ifdef CONFIG_VHOST_KERNEL +#include <linux/vhost.h> +#include <sys/ioctl.h> static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request, void *arg) @@ -265,18 +268,23 @@ static const VhostOps kernel_ops = { .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback, .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg, }; +#endif int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type) { int r = 0; switch (backend_type) { +#ifdef CONFIG_VHOST_KERNEL case VHOST_BACKEND_TYPE_KERNEL: dev->vhost_ops = &kernel_ops; break; +#endif +#ifdef CONFIG_VHOST_USER case VHOST_BACKEND_TYPE_USER: dev->vhost_ops = &user_ops; break; +#endif default: error_report("Unknown vhost backend type"); r = -1; diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 564a31d12c..0d6c64e5ca 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -27,8 +27,12 @@ #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/un.h> -#include <linux/vhost.h> + +#include "standard-headers/linux/vhost_types.h" + +#ifdef CONFIG_LINUX #include <linux/userfaultfd.h> +#endif #define VHOST_MEMORY_MAX_NREGIONS 8 #define VHOST_USER_F_PROTOCOL_FEATURES 30 @@ -1110,6 +1114,7 @@ out: return ret; } +#ifdef CONFIG_LINUX /* * Called back from the postcopy fault thread when a fault is received on our * ufd. @@ -1177,6 +1182,7 @@ static int vhost_user_postcopy_waker(struct PostCopyFD *pcfd, RAMBlock *rb, trace_vhost_user_postcopy_waker_nomatch(qemu_ram_get_idstr(rb), offset); return 0; } +#endif /* * Called at the start of an inbound postcopy on reception of the @@ -1184,6 +1190,7 @@ static int vhost_user_postcopy_waker(struct PostCopyFD *pcfd, RAMBlock *rb, */ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) { +#ifdef CONFIG_LINUX struct vhost_user *u = dev->opaque; CharBackend *chr = u->user->chr; int ufd; @@ -1227,6 +1234,10 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) u->postcopy_fd.idstr = "vhost-user"; /* Need to find unique name */ postcopy_register_shared_ufd(&u->postcopy_fd); return 0; +#else + error_setg(errp, "Postcopy not supported on non-Linux systems"); + return -1; +#endif } /* diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 569c4053ea..311432f190 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -21,7 +21,7 @@ #include "qemu/range.h" #include "qemu/error-report.h" #include "qemu/memfd.h" -#include <linux/vhost.h> +#include "standard-headers/linux/vhost_types.h" #include "exec/address-spaces.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index a12677d4d5..d3f2913a85 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -33,11 +33,81 @@ #define BALLOON_PAGE_SIZE (1 << VIRTIO_BALLOON_PFN_SHIFT) -static void balloon_page(void *addr, int deflate) +struct PartiallyBalloonedPage { + RAMBlock *rb; + ram_addr_t base; + unsigned long bitmap[]; +}; + +static void balloon_inflate_page(VirtIOBalloon *balloon, + MemoryRegion *mr, hwaddr offset) { - if (!qemu_balloon_is_inhibited()) { - qemu_madvise(addr, BALLOON_PAGE_SIZE, - deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED); + void *addr = memory_region_get_ram_ptr(mr) + offset; + RAMBlock *rb; + size_t rb_page_size; + int subpages; + ram_addr_t ram_offset, host_page_base; + + /* XXX is there a better way to get to the RAMBlock than via a + * host address? */ + rb = qemu_ram_block_from_host(addr, false, &ram_offset); + rb_page_size = qemu_ram_pagesize(rb); + host_page_base = ram_offset & ~(rb_page_size - 1); + + if (rb_page_size == BALLOON_PAGE_SIZE) { + /* Easy case */ + + ram_block_discard_range(rb, ram_offset, rb_page_size); + /* We ignore errors from ram_block_discard_range(), because it + * has already reported them, and failing to discard a balloon + * page is not fatal */ + return; + } + + /* Hard case + * + * We've put a piece of a larger host page into the balloon - we + * need to keep track until we have a whole host page to + * discard + */ + warn_report_once( +"Balloon used with backing page size > 4kiB, this may not be reliable"); + + subpages = rb_page_size / BALLOON_PAGE_SIZE; + + if (balloon->pbp + && (rb != balloon->pbp->rb + || host_page_base != balloon->pbp->base)) { + /* We've partially ballooned part of a host page, but now + * we're trying to balloon part of a different one. Too hard, + * give up on the old partial page */ + free(balloon->pbp); + balloon->pbp = NULL; + } + + if (!balloon->pbp) { + /* Starting on a new host page */ + size_t bitlen = BITS_TO_LONGS(subpages) * sizeof(unsigned long); + balloon->pbp = g_malloc0(sizeof(PartiallyBalloonedPage) + bitlen); + balloon->pbp->rb = rb; + balloon->pbp->base = host_page_base; + } + + bitmap_set(balloon->pbp->bitmap, + (ram_offset - balloon->pbp->base) / BALLOON_PAGE_SIZE, + subpages); + + if (bitmap_full(balloon->pbp->bitmap, subpages)) { + /* We've accumulated a full host page, we can actually discard + * it now */ + + ram_block_discard_range(rb, balloon->pbp->base, rb_page_size); + /* We ignore errors from ram_block_discard_range(), because it + * has already reported them, and failing to discard a balloon + * page is not fatal */ + + free(balloon->pbp); + balloon->pbp = NULL; } } @@ -222,17 +292,19 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) } while (iov_to_buf(elem->out_sg, elem->out_num, offset, &pfn, 4) == 4) { - ram_addr_t pa; - ram_addr_t addr; + hwaddr pa; int p = virtio_ldl_p(vdev, &pfn); - pa = (ram_addr_t) p << VIRTIO_BALLOON_PFN_SHIFT; + pa = (hwaddr) p << VIRTIO_BALLOON_PFN_SHIFT; offset += 4; - /* FIXME: remove get_system_memory(), but how? */ - section = memory_region_find(get_system_memory(), pa, 1); - if (!int128_nz(section.size) || - !memory_region_is_ram(section.mr) || + section = memory_region_find(get_system_memory(), pa, + BALLOON_PAGE_SIZE); + if (!section.mr) { + trace_virtio_balloon_bad_addr(pa); + continue; + } + if (!memory_region_is_ram(section.mr) || memory_region_is_rom(section.mr) || memory_region_is_romd(section.mr)) { trace_virtio_balloon_bad_addr(pa); @@ -242,11 +314,9 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) trace_virtio_balloon_handle_output(memory_region_name(section.mr), pa); - /* Using memory_region_get_ram_ptr is bending the rules a bit, but - should be OK because we only want a single page. */ - addr = section.offset_within_region; - balloon_page(memory_region_get_ram_ptr(section.mr) + addr, - !!(vq == s->dvq)); + if (!qemu_balloon_is_inhibited() && vq != s->dvq) { + balloon_inflate_page(s, section.mr, section.offset_within_region); + } memory_region_unref(section.mr); } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index a1ff647a66..2626a895cb 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2036,6 +2036,21 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) return ret; } +size_t virtio_feature_get_config_size(VirtIOFeature *feature_sizes, + uint64_t host_features) +{ + size_t config_size = 0; + int i; + + for (i = 0; feature_sizes[i].flags != 0; i++) { + if (host_features & feature_sizes[i].flags) { + config_size = MAX(feature_sizes[i].end, config_size); + } + } + + return config_size; +} + int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) { int i, ret; diff --git a/include/authz/base.h b/include/authz/base.h new file mode 100644 index 0000000000..77dcd54c4c --- /dev/null +++ b/include/authz/base.h @@ -0,0 +1,112 @@ +/* + * QEMU authorization framework base class + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QAUTHZ_BASE_H__ +#define QAUTHZ_BASE_H__ + +#include "qemu-common.h" +#include "qapi/error.h" +#include "qom/object.h" + + +#define TYPE_QAUTHZ "authz" + +#define QAUTHZ_CLASS(klass) \ + OBJECT_CLASS_CHECK(QAuthZClass, (klass), \ + TYPE_QAUTHZ) +#define QAUTHZ_GET_CLASS(obj) \ + OBJECT_GET_CLASS(QAuthZClass, (obj), \ + TYPE_QAUTHZ) +#define QAUTHZ(obj) \ + INTERFACE_CHECK(QAuthZ, (obj), \ + TYPE_QAUTHZ) + +typedef struct QAuthZ QAuthZ; +typedef struct QAuthZClass QAuthZClass; + +/** + * QAuthZ: + * + * The QAuthZ class defines an API contract to be used + * for providing an authorization driver for services + * with user identities. + */ + +struct QAuthZ { + Object parent_obj; +}; + + +struct QAuthZClass { + ObjectClass parent_class; + + bool (*is_allowed)(QAuthZ *authz, + const char *identity, + Error **errp); +}; + + +/** + * qauthz_is_allowed: + * @authz: the authorization object + * @identity: the user identity to authorize + * @errp: pointer to a NULL initialized error object + * + * Check if a user @identity is authorized. If an error + * occurs this method will return false to indicate + * denial, as well as setting @errp to contain the details. + * Callers are recommended to treat the denial and error + * scenarios identically. Specifically the error info in + * @errp should never be fed back to the user being + * authorized, it is merely for benefit of administrator + * debugging. + * + * Returns: true if @identity is authorized, false if denied or if + * an error occurred. + */ +bool qauthz_is_allowed(QAuthZ *authz, + const char *identity, + Error **errp); + + +/** + * qauthz_is_allowed_by_id: + * @authzid: ID of the authorization object + * @identity: the user identity to authorize + * @errp: pointer to a NULL initialized error object + * + * Check if a user @identity is authorized. If an error + * occurs this method will return false to indicate + * denial, as well as setting @errp to contain the details. + * Callers are recommended to treat the denial and error + * scenarios identically. Specifically the error info in + * @errp should never be fed back to the user being + * authorized, it is merely for benefit of administrator + * debugging. + * + * Returns: true if @identity is authorized, false if denied or if + * an error occurred. + */ +bool qauthz_is_allowed_by_id(const char *authzid, + const char *identity, + Error **errp); + +#endif /* QAUTHZ_BASE_H__ */ + diff --git a/include/authz/list.h b/include/authz/list.h new file mode 100644 index 0000000000..a7225a747c --- /dev/null +++ b/include/authz/list.h @@ -0,0 +1,106 @@ +/* + * QEMU list authorization driver + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QAUTHZ_LIST_H__ +#define QAUTHZ_LIST_H__ + +#include "authz/base.h" +#include "qapi/qapi-types-authz.h" + +#define TYPE_QAUTHZ_LIST "authz-list" + +#define QAUTHZ_LIST_CLASS(klass) \ + OBJECT_CLASS_CHECK(QAuthZListClass, (klass), \ + TYPE_QAUTHZ_LIST) +#define QAUTHZ_LIST_GET_CLASS(obj) \ + OBJECT_GET_CLASS(QAuthZListClass, (obj), \ + TYPE_QAUTHZ_LIST) +#define QAUTHZ_LIST(obj) \ + INTERFACE_CHECK(QAuthZList, (obj), \ + TYPE_QAUTHZ_LIST) + +typedef struct QAuthZList QAuthZList; +typedef struct QAuthZListClass QAuthZListClass; + + +/** + * QAuthZList: + * + * This authorization driver provides a list mechanism + * for granting access by matching user names against a + * list of globs. Each match rule has an associated policy + * and a catch all policy applies if no rule matches + * + * To create an instance of this class via QMP: + * + * { + * "execute": "object-add", + * "arguments": { + * "qom-type": "authz-list", + * "id": "authz0", + * "props": { + * "rules": [ + * { "match": "fred", "policy": "allow", "format": "exact" }, + * { "match": "bob", "policy": "allow", "format": "exact" }, + * { "match": "danb", "policy": "deny", "format": "exact" }, + * { "match": "dan*", "policy": "allow", "format": "glob" } + * ], + * "policy": "deny" + * } + * } + * } + * + */ +struct QAuthZList { + QAuthZ parent_obj; + + QAuthZListPolicy policy; + QAuthZListRuleList *rules; +}; + + +struct QAuthZListClass { + QAuthZClass parent_class; +}; + + +QAuthZList *qauthz_list_new(const char *id, + QAuthZListPolicy policy, + Error **errp); + +ssize_t qauthz_list_append_rule(QAuthZList *auth, + const char *match, + QAuthZListPolicy policy, + QAuthZListFormat format, + Error **errp); + +ssize_t qauthz_list_insert_rule(QAuthZList *auth, + const char *match, + QAuthZListPolicy policy, + QAuthZListFormat format, + size_t index, + Error **errp); + +ssize_t qauthz_list_delete_rule(QAuthZList *auth, + const char *match); + + +#endif /* QAUTHZ_LIST_H__ */ + diff --git a/include/authz/listfile.h b/include/authz/listfile.h new file mode 100644 index 0000000000..bcc8d80743 --- /dev/null +++ b/include/authz/listfile.h @@ -0,0 +1,111 @@ +/* + * QEMU list file authorization driver + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QAUTHZ_LIST_FILE_H__ +#define QAUTHZ_LIST_FILE_H__ + +#include "authz/list.h" +#include "qapi/qapi-types-authz.h" +#include "qemu/filemonitor.h" + +#define TYPE_QAUTHZ_LIST_FILE "authz-list-file" + +#define QAUTHZ_LIST_FILE_CLASS(klass) \ + OBJECT_CLASS_CHECK(QAuthZListFileClass, (klass), \ + TYPE_QAUTHZ_LIST_FILE) +#define QAUTHZ_LIST_FILE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(QAuthZListFileClass, (obj), \ + TYPE_QAUTHZ_LIST_FILE) +#define QAUTHZ_LIST_FILE(obj) \ + INTERFACE_CHECK(QAuthZListFile, (obj), \ + TYPE_QAUTHZ_LIST_FILE) + +typedef struct QAuthZListFile QAuthZListFile; +typedef struct QAuthZListFileClass QAuthZListFileClass; + + +/** + * QAuthZListFile: + * + * This authorization driver provides a file mechanism + * for granting access by matching user names against a + * file of globs. Each match rule has an associated policy + * and a catch all policy applies if no rule matches + * + * To create an instance of this class via QMP: + * + * { + * "execute": "object-add", + * "arguments": { + * "qom-type": "authz-list-file", + * "id": "authz0", + * "props": { + * "filename": "/etc/qemu/myvm-vnc.acl", + * "refresh": true + * } + * } + * } + * + * If 'refresh' is 'yes', inotify is used to monitor for changes + * to the file and auto-reload the rules. + * + * The myvm-vnc.acl file should contain the parameters for + * the QAuthZList object in JSON format: + * + * { + * "rules": [ + * { "match": "fred", "policy": "allow", "format": "exact" }, + * { "match": "bob", "policy": "allow", "format": "exact" }, + * { "match": "danb", "policy": "deny", "format": "exact" }, + * { "match": "dan*", "policy": "allow", "format": "glob" } + * ], + * "policy": "deny" + * } + * + * The object can be created on the command line using + * + * -object authz-list-file,id=authz0,\ + * filename=/etc/qemu/myvm-vnc.acl,refresh=yes + * + */ +struct QAuthZListFile { + QAuthZ parent_obj; + + QAuthZ *list; + char *filename; + bool refresh; + QFileMonitor *file_monitor; + int file_watch; +}; + + +struct QAuthZListFileClass { + QAuthZClass parent_class; +}; + + +QAuthZListFile *qauthz_list_file_new(const char *id, + const char *filename, + bool refresh, + Error **errp); + + +#endif /* QAUTHZ_LIST_FILE_H__ */ + diff --git a/include/authz/pamacct.h b/include/authz/pamacct.h new file mode 100644 index 0000000000..6e3046e528 --- /dev/null +++ b/include/authz/pamacct.h @@ -0,0 +1,100 @@ +/* + * QEMU PAM authorization driver + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QAUTHZ_PAM_H__ +#define QAUTHZ_PAM_H__ + +#include "authz/base.h" + + +#define TYPE_QAUTHZ_PAM "authz-pam" + +#define QAUTHZ_PAM_CLASS(klass) \ + OBJECT_CLASS_CHECK(QAuthZPAMClass, (klass), \ + TYPE_QAUTHZ_PAM) +#define QAUTHZ_PAM_GET_CLASS(obj) \ + OBJECT_GET_CLASS(QAuthZPAMClass, (obj), \ + TYPE_QAUTHZ_PAM) +#define QAUTHZ_PAM(obj) \ + INTERFACE_CHECK(QAuthZPAM, (obj), \ + TYPE_QAUTHZ_PAM) + +typedef struct QAuthZPAM QAuthZPAM; +typedef struct QAuthZPAMClass QAuthZPAMClass; + + +/** + * QAuthZPAM: + * + * This authorization driver provides a PAM mechanism + * for granting access by matching user names against a + * list of globs. Each match rule has an associated policy + * and a catch all policy applies if no rule matches + * + * To create an instance of this class via QMP: + * + * { + * "execute": "object-add", + * "arguments": { + * "qom-type": "authz-pam", + * "id": "authz0", + * "parameters": { + * "service": "qemu-vnc-tls" + * } + * } + * } + * + * The driver only uses the PAM "account" verification + * subsystem. The above config would require a config + * file /etc/pam.d/qemu-vnc-tls. For a simple file + * lookup it would contain + * + * account requisite pam_listfile.so item=user sense=allow \ + * file=/etc/qemu/vnc.allow + * + * The external file would then contain a list of usernames. + * If x509 cert was being used as the username, a suitable + * entry would match the distinguish name: + * + * CN=laptop.berrange.com,O=Berrange Home,L=London,ST=London,C=GB + * + * On the command line it can be created using + * + * -object authz-pam,id=authz0,service=qemu-vnc-tls + * + */ +struct QAuthZPAM { + QAuthZ parent_obj; + + char *service; +}; + + +struct QAuthZPAMClass { + QAuthZClass parent_class; +}; + + +QAuthZPAM *qauthz_pam_new(const char *id, + const char *service, + Error **errp); + + +#endif /* QAUTHZ_PAM_H__ */ diff --git a/include/authz/simple.h b/include/authz/simple.h new file mode 100644 index 0000000000..ef13958269 --- /dev/null +++ b/include/authz/simple.h @@ -0,0 +1,84 @@ +/* + * QEMU simple authorization driver + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QAUTHZ_SIMPLE_H__ +#define QAUTHZ_SIMPLE_H__ + +#include "authz/base.h" + +#define TYPE_QAUTHZ_SIMPLE "authz-simple" + +#define QAUTHZ_SIMPLE_CLASS(klass) \ + OBJECT_CLASS_CHECK(QAuthZSimpleClass, (klass), \ + TYPE_QAUTHZ_SIMPLE) +#define QAUTHZ_SIMPLE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(QAuthZSimpleClass, (obj), \ + TYPE_QAUTHZ_SIMPLE) +#define QAUTHZ_SIMPLE(obj) \ + INTERFACE_CHECK(QAuthZSimple, (obj), \ + TYPE_QAUTHZ_SIMPLE) + +typedef struct QAuthZSimple QAuthZSimple; +typedef struct QAuthZSimpleClass QAuthZSimpleClass; + + +/** + * QAuthZSimple: + * + * This authorization driver provides a simple mechanism + * for granting access based on an exact matched username. + * + * To create an instance of this class via QMP: + * + * { + * "execute": "object-add", + * "arguments": { + * "qom-type": "authz-simple", + * "id": "authz0", + * "props": { + * "identity": "fred" + * } + * } + * } + * + * Or via the command line + * + * -object authz-simple,id=authz0,identity=fred + * + */ +struct QAuthZSimple { + QAuthZ parent_obj; + + char *identity; +}; + + +struct QAuthZSimpleClass { + QAuthZClass parent_class; +}; + + +QAuthZSimple *qauthz_simple_new(const char *id, + const char *identity, + Error **errp); + + +#endif /* QAUTHZ_SIMPLE_H__ */ + diff --git a/include/block/block.h b/include/block/block.h index 73357c6c25..5b5cf868df 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -485,21 +485,17 @@ void bdrv_round_to_clusters(BlockDriverState *bs, int64_t *cluster_offset, int64_t *cluster_bytes); -const char *bdrv_get_encrypted_filename(BlockDriverState *bs); void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size); -void bdrv_get_full_backing_filename(BlockDriverState *bs, - char *dest, size_t sz, Error **errp); -void bdrv_get_full_backing_filename_from_filename(const char *backed, - const char *backing, - char *dest, size_t sz, - Error **errp); +char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp); +char *bdrv_get_full_backing_filename_from_filename(const char *backed, + const char *backing, + Error **errp); +char *bdrv_dirname(BlockDriverState *bs, Error **errp); int path_has_protocol(const char *path); int path_is_absolute(const char *path); -void path_combine(char *dest, int dest_size, - const char *base_path, - const char *filename); +char *path_combine(const char *base_path, const char *filename); int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); diff --git a/include/block/block_int.h b/include/block/block_int.h index 0075bafd10..836d67c1ae 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -139,7 +139,42 @@ struct BlockDriver { Error **errp); int (*bdrv_make_empty)(BlockDriverState *bs); - void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options); + /* + * Refreshes the bs->exact_filename field. If that is impossible, + * bs->exact_filename has to be left empty. + */ + void (*bdrv_refresh_filename)(BlockDriverState *bs); + + /* + * Gathers the open options for all children into @target. + * A simple format driver (without backing file support) might + * implement this function like this: + * + * QINCREF(bs->file->bs->full_open_options); + * qdict_put(target, "file", bs->file->bs->full_open_options); + * + * If not specified, the generic implementation will simply put + * all children's options under their respective name. + * + * @backing_overridden is true when bs->backing seems not to be + * the child that would result from opening bs->backing_file. + * Therefore, if it is true, the backing child's options should be + * gathered; otherwise, there is no need since the backing child + * is the one implied by the image header. + * + * Note that ideally this function would not be needed. Every + * block driver which implements it is probably doing something + * shady regarding its runtime option structure. + */ + void (*bdrv_gather_child_options)(BlockDriverState *bs, QDict *target, + bool backing_overridden); + + /* + * Returns an allocated string which is the directory name of this BDS: It + * will be used to make relative filenames absolute by prepending this + * function's return value to them. + */ + char *(*bdrv_dirname)(BlockDriverState *bs, Error **errp); /* aio */ BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs, @@ -510,6 +545,13 @@ struct BlockDriver { void (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size); void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host); QLIST_ENTRY(BlockDriver) list; + + /* Pointer to a NULL-terminated array of names of strong options + * that can be specified for bdrv_open(). A strong option is one + * that changes the data of a BDS. + * If this pointer is NULL, the array is considered empty. + * "filename" and "driver" are always considered strong. */ + const char *const *strong_runtime_opts; }; typedef struct BlockLimits { @@ -662,6 +704,11 @@ struct BdrvChild { */ uint64_t shared_perm; + /* backup of permissions during permission update procedure */ + bool has_backup_perm; + uint64_t backup_perm; + uint64_t backup_shared_perm; + QLIST_ENTRY(BdrvChild) next; QLIST_ENTRY(BdrvChild) next_parent; }; @@ -697,6 +744,10 @@ struct BlockDriverState { char filename[PATH_MAX]; char backing_file[PATH_MAX]; /* if non zero, the image is a diff of this file image */ + /* The backing filename indicated by the image header; if we ever + * open this file, then this is replaced by the resulting BDS's + * filename (i.e. after a bdrv_refresh_filename() run). */ + char auto_backing_file[PATH_MAX]; char backing_format[16]; /* if non-zero and backing_file exists */ QDict *full_open_options; diff --git a/include/block/nbd.h b/include/block/nbd.h index 96cfb1d7d5..c6ef1ef42e 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -300,7 +300,8 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, Error **errp); int nbd_send_request(QIOChannel *ioc, NBDRequest *request); -int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp); +int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc, + NBDReply *reply, Error **errp); int nbd_client(int fd); int nbd_disconnect(int fd); int nbd_errno_to_system_errno(int err); diff --git a/include/block/snapshot.h b/include/block/snapshot.h index f73d1094af..b5d5084a12 100644 --- a/include/block/snapshot.h +++ b/include/block/snapshot.h @@ -61,9 +61,6 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id, const char *name, Error **errp); -int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs, - const char *id_or_name, - Error **errp); int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); int bdrv_snapshot_load_tmp(BlockDriverState *bs, diff --git a/include/chardev/spice.h b/include/chardev/spice.h new file mode 100644 index 0000000000..6431da3205 --- /dev/null +++ b/include/chardev/spice.h @@ -0,0 +1,27 @@ +#ifndef CHARDEV_SPICE_H_ +#define CHARDEV_SPICE_H_ + +#include <spice.h> +#include "chardev/char-fe.h" + +typedef struct SpiceChardev { + Chardev parent; + + SpiceCharDeviceInstance sin; + bool active; + bool blocked; + const uint8_t *datapos; + int datalen; + QLIST_ENTRY(SpiceChardev) next; +} SpiceChardev; + +#define TYPE_CHARDEV_SPICE "chardev-spice" +#define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc" +#define TYPE_CHARDEV_SPICEPORT "chardev-spiceport" + +#define SPICE_CHARDEV(obj) OBJECT_CHECK(SpiceChardev, (obj), TYPE_CHARDEV_SPICE) + +void qemu_chr_open_spice_port(Chardev *chr, ChardevBackend *backend, + bool *be_opened, Error **errp); + +#endif diff --git a/include/exec/poison.h b/include/exec/poison.h index ecdc83c147..1a7a57baae 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -86,7 +86,6 @@ #pragma GCC poison CONFIG_XTENSA_DIS #pragma GCC poison CONFIG_LINUX_USER -#pragma GCC poison CONFIG_VHOST_NET #pragma GCC poison CONFIG_KVM #pragma GCC poison CONFIG_SOFTMMU diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 38a5e99cf3..3ff3fa5224 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -466,7 +466,7 @@ static inline int float32_is_zero_or_denormal(float32 a) static inline bool float32_is_normal(float32 a) { - return ((float32_val(a) + 0x00800000) & 0x7fffffff) >= 0x01000000; + return (((float32_val(a) >> 23) + 1) & 0xff) >= 2; } static inline bool float32_is_denormal(float32 a) @@ -622,7 +622,7 @@ static inline int float64_is_zero_or_denormal(float64 a) static inline bool float64_is_normal(float64 a) { - return ((float64_val(a) + (1ULL << 52)) & -1ULL >> 1) >= 1ULL << 53; + return (((float64_val(a) >> 52) + 1) & 0x7ff) >= 2; } static inline bool float64_is_denormal(float64 a) @@ -878,6 +878,7 @@ int64_t float128_to_int64(float128, float_status *status); int64_t float128_to_int64_round_to_zero(float128, float_status *status); uint64_t float128_to_uint64(float128, float_status *status); uint64_t float128_to_uint64_round_to_zero(float128, float_status *status); +uint32_t float128_to_uint32(float128, float_status *status); uint32_t float128_to_uint32_round_to_zero(float128, float_status *status); float32 float128_to_float32(float128, float_status *status); float64 float128_to_float64(float128, float_status *status); @@ -940,6 +941,16 @@ static inline int float128_is_zero_or_denormal(float128 a) return (a.high & 0x7fff000000000000LL) == 0; } +static inline bool float128_is_normal(float128 a) +{ + return (((a.high >> 48) + 1) & 0x7fff) >= 2; +} + +static inline bool float128_is_denormal(float128 a) +{ + return float128_is_zero_or_denormal(a) && !float128_is_zero(a); +} + static inline int float128_is_any_nan(float128 a) { return ((a.high >> 48) & 0x7fff) == 0x7fff && diff --git a/include/hw/arm/armsse.h b/include/hw/arm/armsse.h index 7ef871c7df..81e082cccf 100644 --- a/include/hw/arm/armsse.h +++ b/include/hw/arm/armsse.h @@ -95,6 +95,7 @@ #include "hw/misc/iotkit-sysctl.h" #include "hw/misc/iotkit-sysinfo.h" #include "hw/misc/armsse-cpuid.h" +#include "hw/misc/armsse-mhu.h" #include "hw/misc/unimp.h" #include "hw/or-irq.h" #include "hw/core/split-irq.h" @@ -166,7 +167,7 @@ typedef struct ARMSSE { IoTKitSysCtl sysctl; IoTKitSysCtl sysinfo; - UnimplementedDeviceState mhu[2]; + ARMSSEMHU mhu[2]; UnimplementedDeviceState ppu[NUM_PPUS]; UnimplementedDeviceState cachectrl[SSE_MAX_CPUS]; UnimplementedDeviceState cpusecctrl[SSE_MAX_CPUS]; diff --git a/include/hw/boards.h b/include/hw/boards.h index 05f9f45c3d..21212f0859 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -206,6 +206,7 @@ struct MachineClass { void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes, int nb_nodes, ram_addr_t size); bool ignore_boot_device_suffixes; + bool smbus_no_migration_support; HotplugHandler *(*get_hotplug_handler)(MachineState *machine, DeviceState *dev); diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h index eeb5a4d7b6..6fef32a3c9 100644 --- a/include/hw/firmware/smbios.h +++ b/include/hw/firmware/smbios.h @@ -162,6 +162,7 @@ struct smbios_type_3 { uint8_t height; uint8_t number_of_power_cords; uint8_t contained_element_count; + uint8_t contained_element_record_length; uint8_t sku_number_str; /* contained elements follow */ } QEMU_PACKED; diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index cf4c45a98f..8e236f7bb4 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -33,10 +33,9 @@ typedef struct I2CSlaveClass { /* * Slave to master. This cannot fail, the device should always - * return something here. Negative values probably result in 0xff - * and a possible log from the driver, and shouldn't be used. + * return something here. */ - int (*recv)(I2CSlave *s); + uint8_t (*recv)(I2CSlave *s); /* * Notify the slave of a bus state change. For start event, @@ -78,7 +77,7 @@ void i2c_end_transfer(I2CBus *bus); void i2c_nack(I2CBus *bus); int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send); int i2c_send(I2CBus *bus, uint8_t data); -int i2c_recv(I2CBus *bus); +uint8_t i2c_recv(I2CBus *bus); DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr); diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h index 060d3c6ac0..fb55c44444 100644 --- a/include/hw/i2c/pm_smbus.h +++ b/include/hw/i2c/pm_smbus.h @@ -1,6 +1,8 @@ #ifndef PM_SMBUS_H #define PM_SMBUS_H +#include "hw/i2c/smbus_master.h" + #define PM_SMBUS_MAX_MSG_SIZE 32 typedef struct PMSMBus { @@ -31,8 +33,23 @@ typedef struct PMSMBus { /* Set on block transfers after the last byte has been read, so the INTR bit can be set at the right time. */ bool op_done; + + /* Set during an I2C block read, so we know how to handle data. */ + bool in_i2c_block_read; + + /* Used to work around a bug in AMIBIOS, see smb_transaction_start() */ + bool start_transaction_on_status_read; } PMSMBus; void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk); +/* + * For backwards compatibility on migration, older versions don't have + * working migration for pm_smbus, this lets us ignore the migrations + * for older machine versions. + */ +bool pm_smbus_vmstate_needed(void); + +extern const VMStateDescription pmsmb_vmstate; + #endif /* PM_SMBUS_H */ diff --git a/include/qemu/acl.h b/include/hw/i2c/smbus_eeprom.h index 73d2a71c8d..0f96836bab 100644 --- a/include/qemu/acl.h +++ b/include/hw/i2c/smbus_eeprom.h @@ -1,7 +1,5 @@ /* - * QEMU access control list management - * - * Copyright (C) 2009 Red Hat, Inc + * QEMU SMBus EEPROM API * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,45 +20,16 @@ * THE SOFTWARE. */ -#ifndef QEMU_ACL_H -#define QEMU_ACL_H - -#include "qemu/queue.h" - -typedef struct qemu_acl_entry qemu_acl_entry; -typedef struct qemu_acl qemu_acl; - -struct qemu_acl_entry { - char *match; - int deny; - - QTAILQ_ENTRY(qemu_acl_entry) next; -}; - -struct qemu_acl { - char *aclname; - unsigned int nentries; - QTAILQ_HEAD(,qemu_acl_entry) entries; - int defaultDeny; -}; - -qemu_acl *qemu_acl_init(const char *aclname); - -qemu_acl *qemu_acl_find(const char *aclname); +#ifndef HW_SMBUS_EEPROM_H +#define HW_SMBUS_EEPROM_H -int qemu_acl_party_is_allowed(qemu_acl *acl, - const char *party); +#include "hw/i2c/i2c.h" -void qemu_acl_reset(qemu_acl *acl); +void smbus_eeprom_init_one(I2CBus *bus, uint8_t address, uint8_t *eeprom_buf); +void smbus_eeprom_init(I2CBus *bus, int nb_eeprom, + const uint8_t *eeprom_spd, int size); -int qemu_acl_append(qemu_acl *acl, - int deny, - const char *match); -int qemu_acl_insert(qemu_acl *acl, - int deny, - const char *match, - int index); -int qemu_acl_remove(qemu_acl *acl, - const char *match); +enum sdram_type { SDR = 0x4, DDR = 0x7, DDR2 = 0x8 }; +uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t size, Error **errp); -#endif /* QEMU_ACL_H */ +#endif diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus_master.h index 89dfea1a08..bb13bc423c 100644 --- a/include/hw/i2c/smbus.h +++ b/include/hw/i2c/smbus_master.h @@ -1,8 +1,5 @@ -#ifndef QEMU_SMBUS_H -#define QEMU_SMBUS_H - /* - * QEMU SMBus API + * QEMU SMBus host (master) API * * Copyright (c) 2007 Arastra, Inc. * @@ -25,46 +22,10 @@ * THE SOFTWARE. */ -#include "hw/i2c/i2c.h" - -#define TYPE_SMBUS_DEVICE "smbus-device" -#define SMBUS_DEVICE(obj) \ - OBJECT_CHECK(SMBusDevice, (obj), TYPE_SMBUS_DEVICE) -#define SMBUS_DEVICE_CLASS(klass) \ - OBJECT_CLASS_CHECK(SMBusDeviceClass, (klass), TYPE_SMBUS_DEVICE) -#define SMBUS_DEVICE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(SMBusDeviceClass, (obj), TYPE_SMBUS_DEVICE) - -typedef struct SMBusDevice SMBusDevice; - -typedef struct SMBusDeviceClass -{ - I2CSlaveClass parent_class; - void (*quick_cmd)(SMBusDevice *dev, uint8_t read); - void (*send_byte)(SMBusDevice *dev, uint8_t val); - uint8_t (*receive_byte)(SMBusDevice *dev); - /* We can't distinguish between a word write and a block write with - length 1, so pass the whole data block including the length byte - (if present). The device is responsible figuring out what type of - command this is. */ - void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len); - /* Likewise we can't distinguish between different reads, or even know - the length of the read until the read is complete, so read data a - byte at a time. The device is responsible for adding the length - byte on block reads. */ - uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n); -} SMBusDeviceClass; +#ifndef HW_SMBUS_MASTER_H +#define HW_SMBUS_MASTER_H -struct SMBusDevice { - /* The SMBus protocol is implemented on top of I2C. */ - I2CSlave i2c; - - /* Remaining fields for internal use only. */ - int mode; - int data_len; - uint8_t data_buf[34]; /* command + len + 32 bytes of data. */ - uint8_t command; -}; +#include "hw/i2c/i2c.h" /* Master device commands. */ int smbus_quick_command(I2CBus *bus, uint8_t addr, int read); @@ -91,11 +52,4 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, int len, bool send_len); -void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf); -void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, - const uint8_t *eeprom_spd, int size); - -enum sdram_type { SDR = 0x4, DDR = 0x7, DDR2 = 0x8 }; -uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t size, Error **errp); - #endif diff --git a/include/hw/i2c/smbus_slave.h b/include/hw/i2c/smbus_slave.h new file mode 100644 index 0000000000..ebe068304e --- /dev/null +++ b/include/hw/i2c/smbus_slave.h @@ -0,0 +1,100 @@ +/* + * QEMU SMBus device (slave) API + * + * Copyright (c) 2007 Arastra, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_SMBUS_SLAVE_H +#define HW_SMBUS_SLAVE_H + +#include "hw/i2c/i2c.h" + +#define TYPE_SMBUS_DEVICE "smbus-device" +#define SMBUS_DEVICE(obj) \ + OBJECT_CHECK(SMBusDevice, (obj), TYPE_SMBUS_DEVICE) +#define SMBUS_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SMBusDeviceClass, (klass), TYPE_SMBUS_DEVICE) +#define SMBUS_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SMBusDeviceClass, (obj), TYPE_SMBUS_DEVICE) + +typedef struct SMBusDevice SMBusDevice; + +typedef struct SMBusDeviceClass +{ + I2CSlaveClass parent_class; + + /* + * An operation with no data, special in SMBus. + * This may be NULL, quick commands are ignore in that case. + */ + void (*quick_cmd)(SMBusDevice *dev, uint8_t read); + + /* + * We can't distinguish between a word write and a block write with + * length 1, so pass the whole data block including the length byte + * (if present). The device is responsible figuring out what type of + * command this is. + * This may be NULL if no data is written to the device. Writes + * will be ignore in that case. + */ + int (*write_data)(SMBusDevice *dev, uint8_t *buf, uint8_t len); + + /* + * Likewise we can't distinguish between different reads, or even know + * the length of the read until the read is complete, so read data a + * byte at a time. The device is responsible for adding the length + * byte on block reads. This call cannot fail, it should return + * something, preferably 0xff if nothing is available. + * This may be NULL if no data is read from the device. Reads will + * return 0xff in that case. + */ + uint8_t (*receive_byte)(SMBusDevice *dev); +} SMBusDeviceClass; + +#define SMBUS_DATA_MAX_LEN 34 /* command + len + 32 bytes of data. */ + +struct SMBusDevice { + /* The SMBus protocol is implemented on top of I2C. */ + I2CSlave i2c; + + /* Remaining fields for internal use only. */ + int32_t mode; + int32_t data_len; + uint8_t data_buf[SMBUS_DATA_MAX_LEN]; +}; + +extern const VMStateDescription vmstate_smbus_device; + +#define VMSTATE_SMBUS_DEVICE(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(SMBusDevice), \ + .vmsd = &vmstate_smbus_device, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, SMBusDevice), \ +} + +/* + * Users should call this in their .needed functions to know if the + * SMBus slave data needs to be transferred. + */ +bool smbus_vmstate_needed(SMBusDevice *dev); + +#endif diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h index 880413ddc7..8efd03132b 100644 --- a/include/hw/ide/internal.h +++ b/include/hw/ide/internal.h @@ -346,7 +346,6 @@ extern const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT]; typedef struct IDEBufferedRequest { QLIST_ENTRY(IDEBufferedRequest) list; - struct iovec iov; QEMUIOVector qiov; QEMUIOVector *original_qiov; BlockCompletionFunc *original_cb; @@ -405,7 +404,6 @@ struct IDEState { int atapi_dma; /* true if dma is requested for the packet cmd */ BlockAcctCookie acct; BlockAIOCB *pio_aiocb; - struct iovec iov; QEMUIOVector qiov; QLIST_HEAD(, IDEBufferedRequest) buffered_requests; /* ATA DMA state */ @@ -457,7 +455,6 @@ struct IDEDMAOps { struct IDEDMA { const struct IDEDMAOps *ops; - struct iovec iov; QEMUIOVector qiov; BlockAIOCB *aiocb; }; diff --git a/include/hw/misc/armsse-mhu.h b/include/hw/misc/armsse-mhu.h new file mode 100644 index 0000000000..e57eafc252 --- /dev/null +++ b/include/hw/misc/armsse-mhu.h @@ -0,0 +1,44 @@ +/* + * ARM SSE-200 Message Handling Unit (MHU) + * + * Copyright (c) 2019 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* + * This is a model of the Message Handling Unit (MHU) which is part of the + * Arm SSE-200 and documented in + * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf + * + * QEMU interface: + * + sysbus MMIO region 0: the system information register bank + * + sysbus IRQ 0: interrupt for CPU 0 + * + sysbus IRQ 1: interrupt for CPU 1 + */ + +#ifndef HW_MISC_SSE_MHU_H +#define HW_MISC_SSE_MHU_H + +#include "hw/sysbus.h" + +#define TYPE_ARMSSE_MHU "armsse-mhu" +#define ARMSSE_MHU(obj) OBJECT_CHECK(ARMSSEMHU, (obj), TYPE_ARMSSE_MHU) + +typedef struct ARMSSEMHU { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + qemu_irq cpu0irq; + qemu_irq cpu1irq; + + uint32_t cpu0intr; + uint32_t cpu1intr; +} ARMSSEMHU; + +#endif diff --git a/include/hw/misc/iotkit-sysctl.h b/include/hw/misc/iotkit-sysctl.h index e36613cb5e..601c8ecc0d 100644 --- a/include/hw/misc/iotkit-sysctl.h +++ b/include/hw/misc/iotkit-sysctl.h @@ -17,6 +17,9 @@ * "system control register" blocks. * * QEMU interface: + * + QOM property "SYS_VERSION": value of the SYS_VERSION register of the + * system information block of the SSE + * (used to identify whether to provide SSE-200-only registers) * + sysbus MMIO region 0: the system information register bank * + sysbus MMIO region 1: the system control register bank */ @@ -41,9 +44,29 @@ typedef struct IoTKitSysCtl { uint32_t reset_syndrome; uint32_t reset_mask; uint32_t gretreg; - uint32_t initsvrtor0; + uint32_t initsvtor0; uint32_t cpuwait; uint32_t wicctrl; + uint32_t scsecctrl; + uint32_t fclk_div; + uint32_t sysclk_div; + uint32_t clock_force; + uint32_t initsvtor1; + uint32_t nmi_enable; + uint32_t ewctrl; + uint32_t pdcm_pd_sys_sense; + uint32_t pdcm_pd_sram0_sense; + uint32_t pdcm_pd_sram1_sense; + uint32_t pdcm_pd_sram2_sense; + uint32_t pdcm_pd_sram3_sense; + + /* Properties */ + uint32_t sys_version; + uint32_t cpuwait_rst; + uint32_t initsvtor0_rst; + uint32_t initsvtor1_rst; + + bool is_sse200; } IoTKitSysCtl; #endif diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 51d81c4b7c..ab0e3a0a6f 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -113,7 +113,7 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin) } int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t intc_phandle, void *fdt, - uint32_t nr_msis); + uint32_t nr_msis, int *node_offset); void spapr_pci_rtas_init(void); @@ -121,8 +121,10 @@ sPAPRPHBState *spapr_pci_find_phb(sPAPRMachineState *spapr, uint64_t buid); PCIDevice *spapr_pci_find_dev(sPAPRMachineState *spapr, uint64_t buid, uint32_t config_addr); -/* PCI release callback. */ +/* DRC callbacks */ void spapr_phb_remove_pci_device_cb(DeviceState *dev); +int spapr_pci_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); /* VFIO EEH hooks */ #ifdef CONFIG_LINUX @@ -163,4 +165,9 @@ static inline void spapr_phb_vfio_reset(DeviceState *qdev) void spapr_phb_dma_reset(sPAPRPHBState *sphb); +static inline unsigned spapr_phb_windows_supported(sPAPRPHBState *sphb) +{ + return sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1; +} + #endif /* PCI_HOST_SPAPR_H */ diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index eeb33018ad..0abe27a53a 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -271,4 +271,6 @@ #define PCI_VENDOR_ID_SYNOPSYS 0x16C3 +#define PCI_VENDOR_ID_NVIDIA 0x10de + #endif diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h index 298ec354a8..746170f635 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -73,6 +73,7 @@ static inline void ppc40x_irq_init(PowerPCCPU *cpu) {} static inline void ppc6xx_irq_init(PowerPCCPU *cpu) {} static inline void ppc970_irq_init(PowerPCCPU *cpu) {} static inline void ppcPOWER7_irq_init(PowerPCCPU *cpu) {} +static inline void ppcPOWER9_irq_init(PowerPCCPU *cpu) {} static inline void ppce500_irq_init(PowerPCCPU *cpu) {} #else void ppc40x_irq_init(PowerPCCPU *cpu); @@ -80,6 +81,7 @@ void ppce500_irq_init(PowerPCCPU *cpu); void ppc6xx_irq_init(PowerPCCPU *cpu); void ppc970_irq_init(PowerPCCPU *cpu); void ppcPOWER7_irq_init(PowerPCCPU *cpu); +void ppcPOWER9_irq_init(PowerPCCPU *cpu); #endif /* PPC machines for OpenBIOS */ diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 631fc5103b..59073a7579 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -104,6 +104,7 @@ struct sPAPRMachineClass { /*< public >*/ bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ + bool dr_phb_enabled; /* enable dynamic-reconfig/hotplug of PHBs */ bool update_dt_enabled; /* enable KVMPPC_H_UPDATE_DT */ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ bool pre_2_10_has_unused_icps; @@ -177,6 +178,8 @@ struct sPAPRMachineState { /*< public >*/ char *kvm_type; + char *host_model; + char *host_serial; int32_t irq_map_nr; unsigned long *irq_map; @@ -762,9 +765,16 @@ void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, void spapr_clear_pending_events(sPAPRMachineState *spapr); int spapr_max_server_number(sPAPRMachineState *spapr); -/* CPU and LMB DRC release callbacks. */ +/* DRC callbacks. */ void spapr_core_release(DeviceState *dev); +int spapr_core_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); void spapr_lmb_release(DeviceState *dev); +int spapr_lmb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); +void spapr_phb_release(DeviceState *dev); +int spapr_phb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); void spapr_rtc_read(sPAPRRTCState *rtc, struct tm *tm, uint32_t *ns); int spapr_rtc_import_offset(sPAPRRTCState *rtc, int64_t legacy_offset); @@ -839,4 +849,5 @@ void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize, #define SPAPR_OV5_XIVE_EXPLOIT 0x40 #define SPAPR_OV5_XIVE_BOTH 0x80 /* Only to advertise on the platform */ +void spapr_set_all_lpcrs(target_ulong value, target_ulong mask); #endif /* HW_SPAPR_H */ diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h index f6ff32e7e2..46b0f6216d 100644 --- a/include/hw/ppc/spapr_drc.h +++ b/include/hw/ppc/spapr_drc.h @@ -18,6 +18,7 @@ #include "qom/object.h" #include "sysemu/sysemu.h" #include "hw/qdev.h" +#include "qapi/error.h" #define TYPE_SPAPR_DR_CONNECTOR "spapr-dr-connector" #define SPAPR_DR_CONNECTOR_GET_CLASS(obj) \ @@ -70,6 +71,14 @@ #define SPAPR_DRC_LMB(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \ TYPE_SPAPR_DRC_LMB) +#define TYPE_SPAPR_DRC_PHB "spapr-drc-phb" +#define SPAPR_DRC_PHB_GET_CLASS(obj) \ + OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DRC_PHB) +#define SPAPR_DRC_PHB_CLASS(klass) \ + OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, TYPE_SPAPR_DRC_PHB) +#define SPAPR_DRC_PHB(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \ + TYPE_SPAPR_DRC_PHB) + /* * Various hotplug types managed by sPAPRDRConnector * @@ -213,6 +222,8 @@ typedef struct sPAPRDRConnector { int fdt_start_offset; } sPAPRDRConnector; +struct sPAPRMachineState; + typedef struct sPAPRDRConnectorClass { /*< private >*/ DeviceClass parent; @@ -228,6 +239,9 @@ typedef struct sPAPRDRConnectorClass { uint32_t (*isolate)(sPAPRDRConnector *drc); uint32_t (*unisolate)(sPAPRDRConnector *drc); void (*release)(DeviceState *dev); + + int (*dt_populate)(sPAPRDRConnector *drc, struct sPAPRMachineState *spapr, + void *fdt, int *fdt_start_offset, Error **errp); } sPAPRDRConnectorClass; typedef struct sPAPRDRCPhysical { @@ -255,8 +269,7 @@ sPAPRDRConnector *spapr_drc_by_id(const char *type, uint32_t id); int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, uint32_t drc_type_mask); -void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, - int fdt_start_offset, Error **errp); +void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, Error **errp); void spapr_drc_detach(sPAPRDRConnector *drc); bool spapr_drc_needed(void *opaque); diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 488511c3d8..ec1ee64fa6 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -47,6 +47,7 @@ typedef struct sPAPRIrq { int (*post_load)(sPAPRMachineState *spapr, int version_id); void (*reset)(sPAPRMachineState *spapr, Error **errp); void (*set_irq)(void *opaque, int srcno, int val); + const char *(*get_nodename)(sPAPRMachineState *spapr); } sPAPRIrq; extern sPAPRIrq spapr_irq_xics; @@ -60,6 +61,7 @@ void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num); qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq); int spapr_irq_post_load(sPAPRMachineState *spapr, int version_id); void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp); +int spapr_irq_get_phandle(sPAPRMachineState *spapr, void *fdt, Error **errp); /* * XICS legacy routines diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 9bec9192e4..2d31f24e3b 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -26,6 +26,9 @@ typedef struct sPAPRXive { XiveENDSource end_source; hwaddr end_base; + /* DT */ + gchar *nodename; + /* Routing table */ XiveEAS *eat; uint32_t nr_irqs; diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index d36bbe11ee..eb65ad7e43 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -195,6 +195,7 @@ void icp_synchronize_state(ICPState *icp); void icp_kvm_realize(DeviceState *dev, Error **errp); void ics_get_kvm_state(ICSState *ics); +int ics_set_kvm_state_one(ICSState *ics, int srcno); int ics_set_kvm_state(ICSState *ics); void ics_synchronize_state(ICSState *ics); void ics_kvm_set_irq(ICSState *ics, int srcno, int val); diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h index b1ab27d022..b8d924baf4 100644 --- a/include/hw/ppc/xics_spapr.h +++ b/include/hw/ppc/xics_spapr.h @@ -29,6 +29,8 @@ #include "hw/ppc/spapr.h" +#define XICS_NODENAME "interrupt-controller" + void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); int xics_kvm_init(sPAPRMachineState *spapr, Error **errp); diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h index e0df3528c8..99dcd6d105 100644 --- a/include/hw/virtio/virtio-balloon.h +++ b/include/hw/virtio/virtio-balloon.h @@ -30,6 +30,8 @@ typedef struct virtio_balloon_stat_modern { uint64_t val; } VirtIOBalloonStatModern; +typedef struct PartiallyBalloonedPage PartiallyBalloonedPage; + typedef struct VirtIOBalloon { VirtIODevice parent_obj; VirtQueue *ivq, *dvq, *svq; @@ -42,6 +44,7 @@ typedef struct VirtIOBalloon { int64_t stats_last_update; int64_t stats_poll_interval; uint32_t host_features; + PartiallyBalloonedPage *pbp; } VirtIOBalloon; #endif diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 5117431d96..cddcfbebe9 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -35,11 +35,11 @@ struct VirtIOBlkConf BlockConf conf; IOThread *iothread; char *serial; - uint32_t scsi; - uint32_t config_wce; uint32_t request_merging; uint16_t num_queues; uint16_t queue_size; + uint32_t max_discard_sectors; + uint32_t max_write_zeroes_sectors; }; struct VirtIOBlockDataPlane; @@ -57,6 +57,8 @@ typedef struct VirtIOBlock { bool dataplane_disabled; bool dataplane_started; struct VirtIOBlockDataPlane *dataplane; + uint64_t host_features; + size_t config_size; } VirtIOBlock; typedef struct VirtIOBlockReq { diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index c8c599f1b9..98504f9075 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -61,12 +61,15 @@ struct virtio_gpu_requested_state { enum virtio_gpu_conf_flags { VIRTIO_GPU_FLAG_VIRGL_ENABLED = 1, VIRTIO_GPU_FLAG_STATS_ENABLED, + VIRTIO_GPU_FLAG_EDID_ENABLED, }; #define virtio_gpu_virgl_enabled(_cfg) \ (_cfg.flags & (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED)) #define virtio_gpu_stats_enabled(_cfg) \ (_cfg.flags & (1 << VIRTIO_GPU_FLAG_STATS_ENABLED)) +#define virtio_gpu_edid_enabled(_cfg) \ + (_cfg.flags & (1 << VIRTIO_GPU_FLAG_EDID_ENABLED)) struct virtio_gpu_conf { uint64_t max_hostmem; @@ -81,7 +84,6 @@ struct virtio_gpu_ctrl_command { VirtQueue *vq; struct virtio_gpu_ctrl_hdr cmd_hdr; uint32_t error; - bool waiting; bool finished; QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; }; @@ -96,9 +98,6 @@ typedef struct VirtIOGPU { int enable; - int config_size; - DeviceState *qdev; - QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq; QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq; @@ -159,6 +158,8 @@ void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g, enum virtio_gpu_ctrl_type type); void virtio_gpu_get_display_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); +void virtio_gpu_get_edid(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd); int virtio_gpu_create_mapping_iov(VirtIOGPU *g, struct virtio_gpu_resource_attach_backing *ab, struct virtio_gpu_ctrl_command *cmd, @@ -172,7 +173,6 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); -void virtio_gpu_gl_block(void *opaque, bool block); int virtio_gpu_virgl_init(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); #endif diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 9c1fa07d6d..ce9516236a 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -37,6 +37,21 @@ static inline hwaddr vring_align(hwaddr addr, return QEMU_ALIGN_UP(addr, align); } +/* + * Calculate the number of bytes up to and including the given 'field' of + * 'container'. + */ +#define virtio_endof(container, field) \ + (offsetof(container, field) + sizeof_field(container, field)) + +typedef struct VirtIOFeature { + uint64_t flags; + size_t end; +} VirtIOFeature; + +size_t virtio_feature_get_config_size(VirtIOFeature *features, + uint64_t host_features); + typedef struct VirtQueue VirtQueue; #define VIRTQUEUE_MAX_SIZE 1024 diff --git a/include/io/channel.h b/include/io/channel.h index da2f138200..59460cb1ec 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -739,10 +739,13 @@ void qio_channel_detach_aio_context(QIOChannel *ioc); * addition, no two coroutine can be waiting on the same condition * and channel at the same time. * - * This must only be called from coroutine context + * This must only be called from coroutine context. It is safe to + * reenter the coroutine externally while it is waiting; in this + * case the function will return even if @condition is not yet + * available. */ -void qio_channel_yield(QIOChannel *ioc, - GIOCondition condition); +void coroutine_fn qio_channel_yield(QIOChannel *ioc, + GIOCondition condition); /** * qio_channel_wait: diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 067b126cf1..a668ec75b8 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -851,6 +851,9 @@ extern const VMStateInfo vmstate_info_qtailq; #define VMSTATE_INT32_POSITIVE_LE(_f, _s) \ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t) +#define VMSTATE_BOOL_TEST(_f, _s, _t) \ + VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_bool, bool) + #define VMSTATE_INT8_TEST(_f, _s, _t) \ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int8, int8_t) diff --git a/include/qemu/filemonitor.h b/include/qemu/filemonitor.h new file mode 100644 index 0000000000..cd031832ed --- /dev/null +++ b/include/qemu/filemonitor.h @@ -0,0 +1,128 @@ +/* + * QEMU file monitor helper + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef QEMU_FILE_MONITOR_H +#define QEMU_FILE_MONITOR_H + +#include "qemu-common.h" + + +typedef struct QFileMonitor QFileMonitor; + +typedef enum { + /* File has been created in a dir */ + QFILE_MONITOR_EVENT_CREATED, + /* File has been modified in a dir */ + QFILE_MONITOR_EVENT_MODIFIED, + /* File has been deleted in a dir */ + QFILE_MONITOR_EVENT_DELETED, + /* File has attributes changed */ + QFILE_MONITOR_EVENT_ATTRIBUTES, + /* Dir is no longer being monitored (due to deletion) */ + QFILE_MONITOR_EVENT_IGNORED, +} QFileMonitorEvent; + + +/** + * QFileMonitorHandler: + * @id: id from qemu_file_monitor_add_watch() + * @event: the file change that occurred + * @filename: the name of the file affected + * @opaque: opaque data provided to qemu_file_monitor_add_watch() + * + * Invoked whenever a file changes. If @event is + * QFILE_MONITOR_EVENT_IGNORED, @filename will be + * empty. + * + */ +typedef void (*QFileMonitorHandler)(int id, + QFileMonitorEvent event, + const char *filename, + void *opaque); + +/** + * qemu_file_monitor_new: + * @errp: pointer to a NULL-initialized error object + * + * Create a handle for a file monitoring object. + * + * This object does locking internally to enable it to be + * safe to use from multiple threads + * + * If the platform does not support file monitoring, an + * error will be reported. Likewise if file monitoring + * is supported, but cannot be initialized + * + * Currently this is implemented on Linux platforms with + * the inotify subsystem. + * + * Returns: the new monitoring object, or NULL on error + */ +QFileMonitor *qemu_file_monitor_new(Error **errp); + +/** + * qemu_file_monitor_free: + * @mon: the file monitor context + * + * Free resources associated with the file monitor, + * including any currently registered watches. + */ +void qemu_file_monitor_free(QFileMonitor *mon); + +/** + * qemu_file_monitor_add_watch: + * @mon: the file monitor context + * @dirpath: the directory whose contents to watch + * @filename: optional filename to filter on + * @cb: the function to invoke when @dirpath has changes + * @opaque: data to pass to @cb + * @errp: pointer to a NULL-initialized error object + * + * Register to receive notifications of changes + * in the directory @dirpath. All files in the + * directory will be monitored. If the caller is + * only interested in one specific file, @filename + * can be used to filter events. + * + * Returns: a positive integer watch ID, or -1 on error + */ +int qemu_file_monitor_add_watch(QFileMonitor *mon, + const char *dirpath, + const char *filename, + QFileMonitorHandler cb, + void *opaque, + Error **errp); + +/** + * qemu_file_monitor_remove_watch: + * @mon: the file monitor context + * @dirpath: the directory whose contents to unwatch + * @id: id of the watch to remove + * + * Removes the file monitoring watch @id, associated + * with the directory @dirpath. This must never be + * called from a QFileMonitorHandler callback, or a + * deadlock will result. + */ +void qemu_file_monitor_remove_watch(QFileMonitor *mon, + const char *dirpath, + int id); + +#endif /* QEMU_FILE_MONITOR_H */ diff --git a/include/qemu/iov.h b/include/qemu/iov.h index 5f433c7768..48b45987b7 100644 --- a/include/qemu/iov.h +++ b/include/qemu/iov.h @@ -133,10 +133,70 @@ size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, typedef struct QEMUIOVector { struct iovec *iov; int niov; - int nalloc; - size_t size; + + /* + * For external @iov (qemu_iovec_init_external()) or allocated @iov + * (qemu_iovec_init()), @size is the cumulative size of iovecs and + * @local_iov is invalid and unused. + * + * For embedded @iov (QEMU_IOVEC_INIT_BUF() or qemu_iovec_init_buf()), + * @iov is equal to &@local_iov, and @size is valid, as it has same + * offset and type as @local_iov.iov_len, which is guaranteed by + * static assertion below. + * + * @nalloc is always valid and is -1 both for embedded and external + * cases. It is included in the union only to ensure the padding prior + * to the @size field will not result in a 0-length array. + */ + union { + struct { + int nalloc; + struct iovec local_iov; + }; + struct { + char __pad[sizeof(int) + offsetof(struct iovec, iov_len)]; + size_t size; + }; + }; } QEMUIOVector; +QEMU_BUILD_BUG_ON(offsetof(QEMUIOVector, size) != + offsetof(QEMUIOVector, local_iov.iov_len)); + +#define QEMU_IOVEC_INIT_BUF(self, buf, len) \ +{ \ + .iov = &(self).local_iov, \ + .niov = 1, \ + .nalloc = -1, \ + .local_iov = { \ + .iov_base = (void *)(buf), /* cast away const */ \ + .iov_len = (len), \ + }, \ +} + +/* + * qemu_iovec_init_buf + * + * Initialize embedded QEMUIOVector. + * + * Note: "const" is used over @buf pointer to make it simple to pass + * const pointers, appearing in read functions. Then this "const" is + * cast away by QEMU_IOVEC_INIT_BUF(). + */ +static inline void qemu_iovec_init_buf(QEMUIOVector *qiov, + const void *buf, size_t len) +{ + *qiov = (QEMUIOVector) QEMU_IOVEC_INIT_BUF(*qiov, buf, len); +} + +static inline void *qemu_iovec_buf(QEMUIOVector *qiov) +{ + /* Only supports embedded iov */ + assert(qiov->nalloc == -1 && qiov->iov == &qiov->local_iov); + + return qiov->local_iov.iov_base; +} + void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint); void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len); diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 832a4bf168..e2066eb06b 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -156,6 +156,8 @@ int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes); int blk_co_flush(BlockBackend *blk); int blk_flush(BlockBackend *blk); int blk_commit_all(void); +void blk_inc_in_flight(BlockBackend *blk); +void blk_dec_in_flight(BlockBackend *blk); void blk_drain(BlockBackend *blk); void blk_drain_all(void); void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 87a84a59d4..53c3612c32 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -179,3 +179,7 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); void qemu_spice_display_start(void); void qemu_spice_display_stop(void); int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd); + +bool qemu_spice_fill_device_address(QemuConsole *con, + char *device_address, + size_t size); diff --git a/io/channel.c b/io/channel.c index 8dd0684f5d..2a26c2a2c0 100644 --- a/io/channel.c +++ b/io/channel.c @@ -400,15 +400,14 @@ off_t qio_channel_io_seek(QIOChannel *ioc, } -static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc); - static void qio_channel_restart_read(void *opaque) { QIOChannel *ioc = opaque; Coroutine *co = ioc->read_coroutine; - ioc->read_coroutine = NULL; - qio_channel_set_aio_fd_handlers(ioc); + /* Assert that aio_co_wake() reenters the coroutine directly */ + assert(qemu_get_current_aio_context() == + qemu_coroutine_get_aio_context(co)); aio_co_wake(co); } @@ -417,8 +416,9 @@ static void qio_channel_restart_write(void *opaque) QIOChannel *ioc = opaque; Coroutine *co = ioc->write_coroutine; - ioc->write_coroutine = NULL; - qio_channel_set_aio_fd_handlers(ioc); + /* Assert that aio_co_wake() reenters the coroutine directly */ + assert(qemu_get_current_aio_context() == + qemu_coroutine_get_aio_context(co)); aio_co_wake(co); } @@ -469,6 +469,16 @@ void coroutine_fn qio_channel_yield(QIOChannel *ioc, } qio_channel_set_aio_fd_handlers(ioc); qemu_coroutine_yield(); + + /* Allow interrupting the operation by reentering the coroutine other than + * through the aio_fd_handlers. */ + if (condition == G_IO_IN && ioc->read_coroutine) { + ioc->read_coroutine = NULL; + qio_channel_set_aio_fd_handlers(ioc); + } else if (condition == G_IO_OUT && ioc->write_coroutine) { + ioc->write_coroutine = NULL; + qio_channel_set_aio_fd_handlers(ioc); + } } diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 3a50d587ff..b9f7cbbdc1 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -602,6 +602,8 @@ static uint32_t get_elf_hwcap(void) GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA); GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE); GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG); + GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM); + GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT); #undef GET_FEATURE_ID diff --git a/migration/block.c b/migration/block.c index 0e24e18d13..83c633fb3f 100644 --- a/migration/block.c +++ b/migration/block.c @@ -83,7 +83,6 @@ typedef struct BlkMigBlock { BlkMigDevState *bmds; int64_t sector; int nr_sectors; - struct iovec iov; QEMUIOVector qiov; BlockAIOCB *aiocb; @@ -314,9 +313,7 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) blk->sector = cur_sector; blk->nr_sectors = nr_sectors; - blk->iov.iov_base = blk->buf; - blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; - qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); + qemu_iovec_init_buf(&blk->qiov, blk->buf, nr_sectors * BDRV_SECTOR_SIZE); blk_mig_lock(); block_mig_state.submitted++; @@ -556,9 +553,8 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, blk->nr_sectors = nr_sectors; if (is_async) { - blk->iov.iov_base = blk->buf; - blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; - qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); + qemu_iovec_init_buf(&blk->qiov, blk->buf, + nr_sectors * BDRV_SECTOR_SIZE); blk->aiocb = blk_aio_preadv(bmds->blk, sector * BDRV_SECTOR_SIZE, @@ -51,7 +51,8 @@ #include "sysemu/balloon.h" #include "qemu/timer.h" #include "sysemu/hw_accel.h" -#include "qemu/acl.h" +#include "authz/list.h" +#include "qapi/util.h" #include "sysemu/tpm.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" @@ -2016,93 +2017,148 @@ static void hmp_wavcapture(Monitor *mon, const QDict *qdict) QLIST_INSERT_HEAD (&capture_head, s, entries); } -static qemu_acl *find_acl(Monitor *mon, const char *name) +static QAuthZList *find_auth(Monitor *mon, const char *name) { - qemu_acl *acl = qemu_acl_find(name); + Object *obj; + Object *container; - if (!acl) { + container = object_get_objects_root(); + obj = object_resolve_path_component(container, name); + if (!obj) { monitor_printf(mon, "acl: unknown list '%s'\n", name); + return NULL; } - return acl; + + return QAUTHZ_LIST(obj); } static void hmp_acl_show(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); - qemu_acl *acl = find_acl(mon, aclname); - qemu_acl_entry *entry; - int i = 0; - - if (acl) { - monitor_printf(mon, "policy: %s\n", - acl->defaultDeny ? "deny" : "allow"); - QTAILQ_FOREACH(entry, &acl->entries, next) { - i++; - monitor_printf(mon, "%d: %s %s\n", i, - entry->deny ? "deny" : "allow", entry->match); - } + QAuthZList *auth = find_auth(mon, aclname); + QAuthZListRuleList *rules; + size_t i = 0; + + if (!auth) { + return; + } + + monitor_printf(mon, "policy: %s\n", + QAuthZListPolicy_str(auth->policy)); + + rules = auth->rules; + while (rules) { + QAuthZListRule *rule = rules->value; + i++; + monitor_printf(mon, "%zu: %s %s\n", i, + QAuthZListPolicy_str(rule->policy), + rule->match); + rules = rules->next; } } static void hmp_acl_reset(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); - qemu_acl *acl = find_acl(mon, aclname); + QAuthZList *auth = find_auth(mon, aclname); - if (acl) { - qemu_acl_reset(acl); - monitor_printf(mon, "acl: removed all rules\n"); + if (!auth) { + return; } + + auth->policy = QAUTHZ_LIST_POLICY_DENY; + qapi_free_QAuthZListRuleList(auth->rules); + auth->rules = NULL; + monitor_printf(mon, "acl: removed all rules\n"); } static void hmp_acl_policy(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); const char *policy = qdict_get_str(qdict, "policy"); - qemu_acl *acl = find_acl(mon, aclname); + QAuthZList *auth = find_auth(mon, aclname); + int val; + Error *err = NULL; - if (acl) { - if (strcmp(policy, "allow") == 0) { - acl->defaultDeny = 0; + if (!auth) { + return; + } + + val = qapi_enum_parse(&QAuthZListPolicy_lookup, + policy, + QAUTHZ_LIST_POLICY_DENY, + &err); + if (err) { + error_free(err); + monitor_printf(mon, "acl: unknown policy '%s', " + "expected 'deny' or 'allow'\n", policy); + } else { + auth->policy = val; + if (auth->policy == QAUTHZ_LIST_POLICY_ALLOW) { monitor_printf(mon, "acl: policy set to 'allow'\n"); - } else if (strcmp(policy, "deny") == 0) { - acl->defaultDeny = 1; - monitor_printf(mon, "acl: policy set to 'deny'\n"); } else { - monitor_printf(mon, "acl: unknown policy '%s', " - "expected 'deny' or 'allow'\n", policy); + monitor_printf(mon, "acl: policy set to 'deny'\n"); } } } +static QAuthZListFormat hmp_acl_get_format(const char *match) +{ + if (strchr(match, '*')) { + return QAUTHZ_LIST_FORMAT_GLOB; + } else { + return QAUTHZ_LIST_FORMAT_EXACT; + } +} + static void hmp_acl_add(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); const char *match = qdict_get_str(qdict, "match"); - const char *policy = qdict_get_str(qdict, "policy"); + const char *policystr = qdict_get_str(qdict, "policy"); int has_index = qdict_haskey(qdict, "index"); int index = qdict_get_try_int(qdict, "index", -1); - qemu_acl *acl = find_acl(mon, aclname); - int deny, ret; - - if (acl) { - if (strcmp(policy, "allow") == 0) { - deny = 0; - } else if (strcmp(policy, "deny") == 0) { - deny = 1; - } else { - monitor_printf(mon, "acl: unknown policy '%s', " - "expected 'deny' or 'allow'\n", policy); - return; - } - if (has_index) - ret = qemu_acl_insert(acl, deny, match, index); - else - ret = qemu_acl_append(acl, deny, match); - if (ret < 0) - monitor_printf(mon, "acl: unable to add acl entry\n"); - else - monitor_printf(mon, "acl: added rule at position %d\n", ret); + QAuthZList *auth = find_auth(mon, aclname); + Error *err = NULL; + QAuthZListPolicy policy; + QAuthZListFormat format; + size_t i = 0; + + if (!auth) { + return; + } + + policy = qapi_enum_parse(&QAuthZListPolicy_lookup, + policystr, + QAUTHZ_LIST_POLICY_DENY, + &err); + if (err) { + error_free(err); + monitor_printf(mon, "acl: unknown policy '%s', " + "expected 'deny' or 'allow'\n", policystr); + return; + } + + format = hmp_acl_get_format(match); + + if (has_index && index == 0) { + monitor_printf(mon, "acl: unable to add acl entry\n"); + return; + } + + if (has_index) { + i = qauthz_list_insert_rule(auth, match, policy, + format, index - 1, &err); + } else { + i = qauthz_list_append_rule(auth, match, policy, + format, &err); + } + if (err) { + monitor_printf(mon, "acl: unable to add rule: %s", + error_get_pretty(err)); + error_free(err); + } else { + monitor_printf(mon, "acl: added rule at position %zu\n", i + 1); } } @@ -2110,15 +2166,18 @@ static void hmp_acl_remove(Monitor *mon, const QDict *qdict) { const char *aclname = qdict_get_str(qdict, "aclname"); const char *match = qdict_get_str(qdict, "match"); - qemu_acl *acl = find_acl(mon, aclname); - int ret; + QAuthZList *auth = find_auth(mon, aclname); + ssize_t i = 0; - if (acl) { - ret = qemu_acl_remove(acl, match); - if (ret < 0) - monitor_printf(mon, "acl: no matching acl entry\n"); - else - monitor_printf(mon, "acl: removed rule at position %d\n", ret); + if (!auth) { + return; + } + + i = qauthz_list_delete_rule(auth, match); + if (i >= 0) { + monitor_printf(mon, "acl: removed rule at position %zu\n", i + 1); + } else { + monitor_printf(mon, "acl: no matching acl entry\n"); } } diff --git a/nbd/client.c b/nbd/client.c index 10a52ad7d0..de7da48246 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -1387,17 +1387,65 @@ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, return 0; } +/* nbd_read_eof + * Tries to read @size bytes from @ioc. + * Returns 1 on success + * 0 on eof, when no data was read (errp is not set) + * negative errno on failure (errp is set) + */ +static inline int coroutine_fn +nbd_read_eof(BlockDriverState *bs, QIOChannel *ioc, void *buffer, size_t size, + Error **errp) +{ + bool partial = false; + + assert(size); + while (size > 0) { + struct iovec iov = { .iov_base = buffer, .iov_len = size }; + ssize_t len; + + len = qio_channel_readv(ioc, &iov, 1, errp); + if (len == QIO_CHANNEL_ERR_BLOCK) { + bdrv_dec_in_flight(bs); + qio_channel_yield(ioc, G_IO_IN); + bdrv_inc_in_flight(bs); + continue; + } else if (len < 0) { + return -EIO; + } else if (len == 0) { + if (partial) { + error_setg(errp, + "Unexpected end-of-file before all bytes were read"); + return -EIO; + } else { + return 0; + } + } + + partial = true; + size -= len; + buffer = (uint8_t*) buffer + len; + } + return 1; +} + /* nbd_receive_reply + * + * Decreases bs->in_flight while waiting for a new reply. This yield is where + * we wait indefinitely and the coroutine must be able to be safely reentered + * for nbd_client_attach_aio_context(). + * * Returns 1 on success * 0 on eof, when no data was read (errp is not set) * negative errno on failure (errp is set) */ -int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) +int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc, + NBDReply *reply, Error **errp) { int ret; const char *type; - ret = nbd_read_eof(ioc, &reply->magic, sizeof(reply->magic), errp); + ret = nbd_read_eof(bs, ioc, &reply->magic, sizeof(reply->magic), errp); if (ret <= 0) { return ret; } diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 82aa221227..049f83df77 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -64,25 +64,6 @@ #define NBD_SET_TIMEOUT _IO(0xab, 9) #define NBD_SET_FLAGS _IO(0xab, 10) -/* nbd_read_eof - * Tries to read @size bytes from @ioc. - * Returns 1 on success - * 0 on eof, when no data was read (errp is not set) - * negative errno on failure (errp is set) - */ -static inline int nbd_read_eof(QIOChannel *ioc, void *buffer, size_t size, - Error **errp) -{ - int ret; - - assert(size); - ret = qio_channel_read_all_eof(ioc, buffer, size, errp); - if (ret < 0) { - ret = -EIO; - } - return ret; -} - /* nbd_write * Writes @size bytes to @ioc. Returns 0 on success. */ diff --git a/net/Makefile.objs b/net/Makefile.objs index b2bf88a0ef..df2b409066 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -3,7 +3,9 @@ common-obj-y += socket.o common-obj-y += dump.o common-obj-y += eth.o common-obj-$(CONFIG_L2TPV3) += l2tpv3.o -common-obj-$(CONFIG_POSIX) += vhost-user.o +common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET_USER)) += vhost-user.o +common-obj-$(call land,$(call lnot,$(CONFIG_VIRTIO_NET)),$(CONFIG_VHOST_NET_USER)) += vhost-user-stub.o +common-obj-$(CONFIG_ALL) += vhost-user-stub.o common-obj-$(CONFIG_SLIRP) += slirp.o common-obj-$(CONFIG_VDE) += vde.o common-obj-$(CONFIG_NETMAP) += netmap.o @@ -961,7 +961,7 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( [NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge, #endif [NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport, -#ifdef CONFIG_VHOST_NET_USED +#ifdef CONFIG_VHOST_NET_USER [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, #endif #ifdef CONFIG_L2TPV3 diff --git a/net/vhost-user-stub.c b/net/vhost-user-stub.c new file mode 100644 index 0000000000..52ab4e13f1 --- /dev/null +++ b/net/vhost-user-stub.c @@ -0,0 +1,23 @@ +/* + * vhost-user-stub.c + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "clients.h" +#include "net/vhost_net.h" +#include "net/vhost-user.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + +int net_init_vhost_user(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + error_setg(errp, "vhost-user requires frontend driver virtio-net-*"); + return -1; +} diff --git a/net/vhost-user.c b/net/vhost-user.c index a39f9c9974..cd9659df87 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -172,6 +172,17 @@ static void net_vhost_user_cleanup(NetClientState *nc) qemu_purge_queued_packets(nc); } +static int vhost_user_set_vnet_endianness(NetClientState *nc, + bool enable) +{ + /* Nothing to do. If the server supports + * VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, it will get the + * vnet header endianness from there. If it doesn't, negotiation + * fails. + */ + return 0; +} + static bool vhost_user_has_vnet_hdr(NetClientState *nc) { assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); @@ -193,6 +204,8 @@ static NetClientInfo net_vhost_user_info = { .cleanup = net_vhost_user_cleanup, .has_vnet_hdr = vhost_user_has_vnet_hdr, .has_ufo = vhost_user_has_ufo, + .set_vnet_be = vhost_user_set_vnet_endianness, + .set_vnet_le = vhost_user_set_vnet_endianness, }; static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond, diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs index 87e4df1660..77acca0209 100644 --- a/qapi/Makefile.objs +++ b/qapi/Makefile.objs @@ -5,7 +5,7 @@ util-obj-y += opts-visitor.o qapi-clone-visitor.o util-obj-y += qmp-event.o util-obj-y += qapi-util.o -QAPI_COMMON_MODULES = block-core block char common crypto introspect +QAPI_COMMON_MODULES = authz block-core block char common crypto introspect QAPI_COMMON_MODULES += job migration misc net rdma rocker run-state QAPI_COMMON_MODULES += sockets tpm trace transaction ui QAPI_TARGET_MODULES = target diff --git a/qapi/authz.json b/qapi/authz.json new file mode 100644 index 0000000000..1c836a3abd --- /dev/null +++ b/qapi/authz.json @@ -0,0 +1,58 @@ +# -*- Mode: Python -*- +# +# QAPI authz definitions + +## +# @QAuthZListPolicy: +# +# The authorization policy result +# +# @deny: deny access +# @allow: allow access +# +# Since: 4.0 +## +{ 'enum': 'QAuthZListPolicy', + 'prefix': 'QAUTHZ_LIST_POLICY', + 'data': ['deny', 'allow']} + +## +# @QAuthZListFormat: +# +# The authorization policy match format +# +# @exact: an exact string match +# @glob: string with ? and * shell wildcard support +# +# Since: 4.0 +## +{ 'enum': 'QAuthZListFormat', + 'prefix': 'QAUTHZ_LIST_FORMAT', + 'data': ['exact', 'glob']} + +## +# @QAuthZListRule: +# +# A single authorization rule. +# +# @match: a string or glob to match against a user identity +# @policy: the result to return if @match evaluates to true +# @format: the format of the @match rule (default 'exact') +# +# Since: 4.0 +## +{ 'struct': 'QAuthZListRule', + 'data': {'match': 'str', + 'policy': 'QAuthZListPolicy', + '*format': 'QAuthZListFormat'}} + +## +# @QAuthZListRuleListHack: +# +# Not exposed via QMP; hack to generate QAuthZListRuleList +# for use internally by the code. +# +# Since: 4.0 +## +{ 'struct': 'QAuthZListRuleListHack', + 'data': { 'unused': ['QAuthZListRule'] } } diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index db61bfd688..a34899c626 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -92,6 +92,7 @@ { 'include': 'rocker.json' } { 'include': 'tpm.json' } { 'include': 'ui.json' } +{ 'include': 'authz.json' } { 'include': 'migration.json' } { 'include': 'transaction.json' } { 'include': 'trace.json' } diff --git a/qapi/ui.json b/qapi/ui.json index 7d9c4bddaf..c5d1d7f099 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1085,12 +1085,42 @@ # # Display (user interface) type. # +# @default: The default user interface, selecting from the first available +# of gtk, sdl, cocoa, and vnc. +# +# @none: No user interface or video output display. The guest will +# still see an emulated graphics card, but its output will not +# be displayed to the QEMU user. +# +# @gtk: The GTK user interface. +# +# @sdl: The SDL user interface. +# +# @egl-headless: No user interface, offload GL operations to a local +# DRI device. Graphical display need to be paired with +# VNC or Spice. (Since 3.1) +# +# @curses: Display video output via curses. For graphics device +# models which support a text mode, QEMU can display this +# output using a curses/ncurses interface. Nothing is +# displayed when the graphics device is in graphical mode or +# if the graphics device does not support a text +# mode. Generally only the VGA device models support text +# mode. +# +# @cocoa: The Cocoa user interface. +# +# @spice-app: Set up a Spice server and run the default associated +# application to connect to it. The server will redirect +# the serial console and QEMU monitors. (Since 4.0) +# # Since: 2.12 # ## { 'enum' : 'DisplayType', 'data' : [ 'default', 'none', 'gtk', 'sdl', - 'egl-headless', 'curses', 'cocoa' ] } + 'egl-headless', 'curses', 'cocoa', + 'spice-app'] } ## # @DisplayOptions: diff --git a/qemu-doc.texi b/qemu-doc.texi index 83be010a0a..ae3c3f9632 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2049,6 +2049,15 @@ Malta FPGA serial device Cirrus (default) or any other PCI VGA graphics card @end itemize +The Boston board emulation supports the following devices: + +@itemize @minus +@item +Xilinx FPGA, which includes a PCIe root port and an UART +@item +Intel EG20T PCH connects the I/O peripherals, but only the SATA bus is emulated +@end itemize + The ACER Pica emulation supports: @itemize @minus @@ -2062,32 +2071,45 @@ PC Keyboard IDE controller @end itemize -The mipssim pseudo board emulation provides an environment similar -to what the proprietary MIPS emulator uses for running Linux. -It supports: +The MIPS Magnum R4000 emulation supports: @itemize @minus @item -A range of MIPS CPUs, default is the 24Kf +MIPS R4000 CPU @item -PC style serial port +PC-style IRQ controller @item -MIPSnet network emulation +PC Keyboard +@item +SCSI controller +@item +G364 framebuffer @end itemize -The MIPS Magnum R4000 emulation supports: +The Fulong 2E emulation supports: @itemize @minus @item -MIPS R4000 CPU +Loongson 2E CPU @item -PC-style IRQ controller +Bonito64 system controller as North Bridge @item -PC Keyboard +VT82C686 chipset as South Bridge @item -SCSI controller +RTL8139D as a network card chipset +@end itemize + +The mipssim pseudo board emulation provides an environment similar +to what the proprietary MIPS emulator uses for running Linux. +It supports: + +@itemize @minus @item -G364 framebuffer +A range of MIPS CPUs, default is the 24Kf +@item +PC style serial port +@item +MIPSnet network emulation @end itemize @node nanoMIPS System emulator diff --git a/qemu-img.c b/qemu-img.c index 25288c4d18..660c01898e 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -503,7 +503,7 @@ static int img_create(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { goto fail; } @@ -753,7 +753,7 @@ static int img_check(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -966,7 +966,7 @@ static int img_commit(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -1349,7 +1349,7 @@ static int img_compare(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { ret = 2; goto out4; } @@ -1670,7 +1670,6 @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num, { int n, ret; QEMUIOVector qiov; - struct iovec iov; assert(nb_sectors <= s->buf_sectors); while (nb_sectors > 0) { @@ -1686,9 +1685,7 @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num, bs_sectors = s->src_sectors[src_cur]; n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset)); - iov.iov_base = buf; - iov.iov_len = n << BDRV_SECTOR_BITS; - qemu_iovec_init_external(&qiov, &iov, 1); + qemu_iovec_init_buf(&qiov, buf, n << BDRV_SECTOR_BITS); ret = blk_co_preadv( blk, (sector_num - src_cur_offset) << BDRV_SECTOR_BITS, @@ -1712,7 +1709,6 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, { int ret; QEMUIOVector qiov; - struct iovec iov; while (nb_sectors > 0) { int n = nb_sectors; @@ -1740,9 +1736,7 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, (s->compressed && !buffer_is_zero(buf, n * BDRV_SECTOR_SIZE))) { - iov.iov_base = buf; - iov.iov_len = n << BDRV_SECTOR_BITS; - qemu_iovec_init_external(&qiov, &iov, 1); + qemu_iovec_init_buf(&qiov, buf, n << BDRV_SECTOR_BITS); ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS, n << BDRV_SECTOR_BITS, &qiov, flags); @@ -2159,7 +2153,7 @@ static int img_convert(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { goto fail_getopt; } @@ -2713,7 +2707,7 @@ static int img_info(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -2790,6 +2784,7 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, BlockDriverState *file; bool has_offset; int64_t map; + char *filename = NULL; /* As an optimization, we could cache the current range of unallocated * clusters in each file of the chain, and avoid querying the same @@ -2817,6 +2812,11 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID); + if (file && has_offset) { + bdrv_refresh_filename(file); + filename = file->filename; + } + *e = (MapEntry) { .start = offset, .length = bytes, @@ -2825,8 +2825,8 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, .offset = map, .has_offset = has_offset, .depth = depth, - .has_filename = file && has_offset, - .filename = file && has_offset ? file->filename : NULL, + .has_filename = filename, + .filename = filename, }; return 0; @@ -2932,7 +2932,7 @@ static int img_map(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -3081,7 +3081,7 @@ static int img_snapshot(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -3123,11 +3123,18 @@ static int img_snapshot(int argc, char **argv) break; case SNAPSHOT_DELETE: - bdrv_snapshot_delete_by_id_or_name(bs, snapshot_name, &err); - if (err) { - error_reportf_err(err, "Could not delete snapshot '%s': ", - snapshot_name); + ret = bdrv_snapshot_find(bs, &sn, snapshot_name); + if (ret < 0) { + error_report("Could not delete snapshot '%s': snapshot not " + "found", snapshot_name); ret = 1; + } else { + ret = bdrv_snapshot_delete(bs, sn.id_str, sn.name, &err); + if (ret < 0) { + error_reportf_err(err, "Could not delete snapshot '%s': ", + snapshot_name); + ret = 1; + } } break; } @@ -3241,7 +3248,7 @@ static int img_rebase(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -3327,20 +3334,17 @@ static int img_rebase(int argc, char **argv) qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); } + bdrv_refresh_filename(bs); overlay_filename = bs->exact_filename[0] ? bs->exact_filename : bs->filename; - out_real_path = g_malloc(PATH_MAX); - - bdrv_get_full_backing_filename_from_filename(overlay_filename, - out_baseimg, - out_real_path, - PATH_MAX, - &local_err); + out_real_path = + bdrv_get_full_backing_filename_from_filename(overlay_filename, + out_baseimg, + &local_err); if (local_err) { error_reportf_err(local_err, "Could not resolve backing filename: "); ret = -1; - g_free(out_real_path); goto out; } @@ -3621,7 +3625,7 @@ static int img_resize(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -3865,7 +3869,7 @@ static int img_amend(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { ret = -1; goto out_no_progress; } @@ -4509,7 +4513,7 @@ static int img_dd(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { ret = -1; goto out; } @@ -4786,7 +4790,7 @@ static int img_measure(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { goto out; } diff --git a/qemu-options.hx b/qemu-options.hx index 77bd98e20b..1cf9aac1fe 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1211,6 +1211,7 @@ STEXI ETEXI DEF("display", HAS_ARG, QEMU_OPTION_display, + "-display spice-app[,gl=on|off]\n" "-display sdl[,frame=on|off][,alt_grab=on|off][,ctrl_grab=on|off]\n" " [,window_close=on|off][,gl=on|core|es|off]\n" "-display gtk[,grab_on_hover=on|off][,gl=on|off]|\n" @@ -1262,6 +1263,10 @@ Start a VNC server on display <arg> @item egl-headless Offload all OpenGL operations to a local DRI device. For any graphical display, this display needs to be paired with either VNC or SPICE displays. +@item spice-app +Start QEMU as a Spice server and launch the default Spice client +application. The Spice server will redirect the serial consoles and +QEMU monitors. (Since 4.0) @end table ETEXI @@ -4360,6 +4365,111 @@ e.g to launch a SEV guest ..... @end example + + +@item -object authz-simple,id=@var{id},identity=@var{string} + +Create an authorization object that will control access to network services. + +The @option{identity} parameter is identifies the user and its format +depends on the network service that authorization object is associated +with. For authorizing based on TLS x509 certificates, the identity must +be the x509 distinguished name. Note that care must be taken to escape +any commas in the distinguished name. + +An example authorization object to validate a x509 distinguished name +would look like: +@example + # $QEMU \ + ... + -object 'authz-simple,id=auth0,identity=CN=laptop.example.com,,O=Example Org,,L=London,,ST=London,,C=GB' \ + ... +@end example + +Note the use of quotes due to the x509 distinguished name containing +whitespace, and escaping of ','. + +@item -object authz-listfile,id=@var{id},filename=@var{path},refresh=@var{yes|no} + +Create an authorization object that will control access to network services. + +The @option{filename} parameter is the fully qualified path to a file +containing the access control list rules in JSON format. + +An example set of rules that match against SASL usernames might look +like: + +@example + @{ + "rules": [ + @{ "match": "fred", "policy": "allow", "format": "exact" @}, + @{ "match": "bob", "policy": "allow", "format": "exact" @}, + @{ "match": "danb", "policy": "deny", "format": "glob" @}, + @{ "match": "dan*", "policy": "allow", "format": "exact" @}, + ], + "policy": "deny" + @} +@end example + +When checking access the object will iterate over all the rules and +the first rule to match will have its @option{policy} value returned +as the result. If no rules match, then the default @option{policy} +value is returned. + +The rules can either be an exact string match, or they can use the +simple UNIX glob pattern matching to allow wildcards to be used. + +If @option{refresh} is set to true the file will be monitored +and automatically reloaded whenever its content changes. + +As with the @code{authz-simple} object, the format of the identity +strings being matched depends on the network service, but is usually +a TLS x509 distinguished name, or a SASL username. + +An example authorization object to validate a SASL username +would look like: +@example + # $QEMU \ + ... + -object authz-simple,id=auth0,filename=/etc/qemu/vnc-sasl.acl,refresh=yes + ... +@end example + +@item -object authz-pam,id=@var{id},service=@var{string} + +Create an authorization object that will control access to network services. + +The @option{service} parameter provides the name of a PAM service to use +for authorization. It requires that a file @code{/etc/pam.d/@var{service}} +exist to provide the configuration for the @code{account} subsystem. + +An example authorization object to validate a TLS x509 distinguished +name would look like: + +@example + # $QEMU \ + ... + -object authz-pam,id=auth0,service=qemu-vnc + ... +@end example + +There would then be a corresponding config file for PAM at +@code{/etc/pam.d/qemu-vnc} that contains: + +@example +account requisite pam_listfile.so item=user sense=allow \ + file=/etc/qemu/vnc.allow +@end example + +Finally the @code{/etc/qemu/vnc.allow} file would contain +the list of x509 distingished names that are permitted +access + +@example +CN=laptop.example.com,O=Example Home,L=London,ST=London,C=GB +@end example + + @end table ETEXI diff --git a/qom/object.c b/qom/object.c index b8c732063b..05a8567041 100644 --- a/qom/object.c +++ b/qom/object.c @@ -646,16 +646,20 @@ Object *object_new_with_propv(const char *typename, goto error; } - object_property_add_child(parent, id, obj, &local_err); - if (local_err) { - goto error; + if (id != NULL) { + object_property_add_child(parent, id, obj, &local_err); + if (local_err) { + goto error; + } } uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); if (uc) { user_creatable_complete(uc, &local_err); if (local_err) { - object_unparent(obj); + if (id != NULL) { + object_unparent(obj); + } goto error; } } diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index db85d1eb75..cb5809934a 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -75,16 +75,20 @@ Object *user_creatable_add_type(const char *type, const char *id, goto out; } - object_property_add_child(object_get_objects_root(), - id, obj, &local_err); - if (local_err) { - goto out; + if (id != NULL) { + object_property_add_child(object_get_objects_root(), + id, obj, &local_err); + if (local_err) { + goto out; + } } user_creatable_complete(USER_CREATABLE(obj), &local_err); if (local_err) { - object_property_del(object_get_objects_root(), - id, &error_abort); + if (id != NULL) { + object_property_del(object_get_objects_root(), + id, &error_abort); + } goto out; } out: diff --git a/roms/Makefile b/roms/Makefile index a6043eff37..78d5dd18c3 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -47,10 +47,7 @@ SEABIOS_EXTRAVERSION="-prebuilt.qemu.org" # We need that to combine multiple images (legacy bios, # efi ia32, efi x64) into a single rom binary. # -# We try to find it in the path. You can also pass the location on -# the command line, i.e. "make EFIROM=/path/to/EfiRom efirom" -# -EFIROM ?= $(shell which EfiRom 2>/dev/null) +EFIROM = edk2/BaseTools/Source/C/bin/EfiRom default: @echo "nothing is build by default" @@ -59,8 +56,7 @@ default: @echo " vgabios -- update vgabios binaries (seabios)" @echo " sgabios -- update sgabios binaries" @echo " pxerom -- update nic roms (bios only)" - @echo " efirom -- update nic roms (bios+efi, this needs" - @echo " the EfiRom utility from edk2 / tianocore)" + @echo " efirom -- update nic roms (bios+efi)" @echo " slof -- update slof.bin" @echo " skiboot -- update skiboot.lid" @echo " u-boot.e500 -- update u-boot.e500" @@ -106,7 +102,7 @@ pxe-rom-%: build-pxe-roms efirom: $(patsubst %,efi-rom-%,$(pxerom_variants)) -efi-rom-%: build-pxe-roms build-efi-roms +efi-rom-%: build-pxe-roms build-efi-roms $(EFIROM) $(EFIROM) -f "0x$(VID)" -i "0x$(DID)" -l 0x02 \ -b ipxe/src/bin/$(VID)$(DID).rom \ -ec ipxe/src/bin-i386-efi/$(VID)$(DID).efidrv \ @@ -124,6 +120,8 @@ build-efi-roms: build-pxe-roms $(patsubst %,bin-i386-efi/%.efidrv,$(pxerom_targets)) \ $(patsubst %,bin-x86_64-efi/%.efidrv,$(pxerom_targets)) +$(EFIROM): + $(MAKE) -C edk2/BaseTools slof: $(MAKE) -C SLOF CROSS=$(powerpc64_cross_prefix) qemu @@ -150,6 +148,7 @@ clean: $(MAKE) -C sgabios clean rm -f sgabios/.depend $(MAKE) -C ipxe/src veryclean + $(MAKE) -C edk2/BaseTools clean $(MAKE) -C SLOF clean rm -rf u-boot/build.e500 $(MAKE) -C u-boot-sam460ex distclean diff --git a/roms/edk2 b/roms/edk2 new file mode 160000 +Subproject 85588389222a3636baf0f9ed8227f2434af4c3f diff --git a/scripts/qemu.py b/scripts/qemu.py index 32b00af5cc..f7269eefbb 100644 --- a/scripts/qemu.py +++ b/scripts/qemu.py @@ -144,10 +144,9 @@ class QEMUMachine(object): return False # This can be used to add an unused monitor instance. - def add_monitor_telnet(self, ip, port): - args = 'tcp:%s:%d,server,nowait,telnet' % (ip, port) + def add_monitor_null(self): self._args.append('-monitor') - self._args.append(args) + self._args.append('null') def add_fd(self, fd, fdset, opaque, opts=''): """ diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c index f9de5164e5..f77a950db6 100644 --- a/target/arm/arm-powerctl.c +++ b/target/arm/arm-powerctl.c @@ -228,6 +228,62 @@ int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id, return QEMU_ARM_POWERCTL_RET_SUCCESS; } +static void arm_set_cpu_on_and_reset_async_work(CPUState *target_cpu_state, + run_on_cpu_data data) +{ + ARMCPU *target_cpu = ARM_CPU(target_cpu_state); + + /* Initialize the cpu we are turning on */ + cpu_reset(target_cpu_state); + target_cpu_state->halted = 0; + + /* Finally set the power status */ + assert(qemu_mutex_iothread_locked()); + target_cpu->power_state = PSCI_ON; +} + +int arm_set_cpu_on_and_reset(uint64_t cpuid) +{ + CPUState *target_cpu_state; + ARMCPU *target_cpu; + + assert(qemu_mutex_iothread_locked()); + + /* Retrieve the cpu we are powering up */ + target_cpu_state = arm_get_cpu_by_id(cpuid); + if (!target_cpu_state) { + /* The cpu was not found */ + return QEMU_ARM_POWERCTL_INVALID_PARAM; + } + + target_cpu = ARM_CPU(target_cpu_state); + if (target_cpu->power_state == PSCI_ON) { + qemu_log_mask(LOG_GUEST_ERROR, + "[ARM]%s: CPU %" PRId64 " is already on\n", + __func__, cpuid); + return QEMU_ARM_POWERCTL_ALREADY_ON; + } + + /* + * If another CPU has powered the target on we are in the state + * ON_PENDING and additional attempts to power on the CPU should + * fail (see 6.6 Implementation CPU_ON/CPU_OFF races in the PSCI + * spec) + */ + if (target_cpu->power_state == PSCI_ON_PENDING) { + qemu_log_mask(LOG_GUEST_ERROR, + "[ARM]%s: CPU %" PRId64 " is already powering on\n", + __func__, cpuid); + return QEMU_ARM_POWERCTL_ON_PENDING; + } + + async_run_on_cpu(target_cpu_state, arm_set_cpu_on_and_reset_async_work, + RUN_ON_CPU_NULL); + + /* We are good to go */ + return QEMU_ARM_POWERCTL_RET_SUCCESS; +} + static void arm_set_cpu_off_async_work(CPUState *target_cpu_state, run_on_cpu_data data) { diff --git a/target/arm/arm-powerctl.h b/target/arm/arm-powerctl.h index 04353923c0..37c8a04f0a 100644 --- a/target/arm/arm-powerctl.h +++ b/target/arm/arm-powerctl.h @@ -74,4 +74,20 @@ int arm_set_cpu_off(uint64_t cpuid); */ int arm_reset_cpu(uint64_t cpuid); +/* + * arm_set_cpu_on_and_reset: + * @cpuid: the id of the CPU we want to star + * + * Start the cpu designated by @cpuid and put it through its normal + * CPU reset process. The CPU will start in the way it is architected + * to start after a power-on reset. + * + * Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success. + * QEMU_ARM_POWERCTL_INVALID_PARAM if there is no CPU with that ID. + * QEMU_ARM_POWERCTL_ALREADY_ON if the CPU is already on. + * QEMU_ARM_POWERCTL_ON_PENDING if the CPU is already partway through + * powering on. + */ +int arm_set_cpu_on_and_reset(uint64_t cpuid); + #endif diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 8ea6569088..54b61f917b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -22,6 +22,7 @@ #include "target/arm/idau.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "cpu.h" #include "internals.h" #include "qemu-common.h" @@ -771,9 +772,21 @@ static Property arm_cpu_pmsav7_dregion_property = pmsav7_dregion, qdev_prop_uint32, uint32_t); -/* M profile: initial value of the Secure VTOR */ -static Property arm_cpu_initsvtor_property = - DEFINE_PROP_UINT32("init-svtor", ARMCPU, init_svtor, 0); +static void arm_get_init_svtor(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + + visit_type_uint32(v, name, &cpu->init_svtor, errp); +} + +static void arm_set_init_svtor(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + + visit_type_uint32(v, name, &cpu->init_svtor, errp); +} void arm_cpu_post_init(Object *obj) { @@ -845,8 +858,14 @@ void arm_cpu_post_init(Object *obj) qdev_prop_allow_set_link_before_realize, OBJ_PROP_LINK_STRONG, &error_abort); - qdev_property_add_static(DEVICE(obj), &arm_cpu_initsvtor_property, - &error_abort); + /* + * M profile: initial value of the Secure VTOR. We can't just use + * a simple DEFINE_PROP_UINT32 for this because we want to permit + * the property to be set after realize. + */ + object_property_add(obj, "init-svtor", "uint32", + arm_get_init_svtor, arm_set_init_svtor, + NULL, NULL, &error_abort); } qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property, @@ -995,7 +1014,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } if (arm_feature(env, ARM_FEATURE_VFP4)) { set_feature(env, ARM_FEATURE_VFP3); - set_feature(env, ARM_FEATURE_VFP_FP16); } if (arm_feature(env, ARM_FEATURE_VFP3)) { set_feature(env, ARM_FEATURE_VFP); @@ -1656,7 +1674,6 @@ static void cortex_a9_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a9"; set_feature(&cpu->env, ARM_FEATURE_V7); set_feature(&cpu->env, ARM_FEATURE_VFP3); - set_feature(&cpu->env, ARM_FEATURE_VFP_FP16); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_EL3); @@ -2003,6 +2020,7 @@ static void arm_max_initfn(Object *obj) t = cpu->isar.id_isar6; t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); t = FIELD_DP32(t, ID_ISAR6, DP, 1); + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); cpu->isar.id_isar6 = t; t = cpu->id_mmfr4; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 1eea1a408b..36cd365efa 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1730,6 +1730,27 @@ FIELD(ID_DFR0, MPROFDBG, 20, 4) FIELD(ID_DFR0, PERFMON, 24, 4) FIELD(ID_DFR0, TRACEFILT, 28, 4) +FIELD(MVFR0, SIMDREG, 0, 4) +FIELD(MVFR0, FPSP, 4, 4) +FIELD(MVFR0, FPDP, 8, 4) +FIELD(MVFR0, FPTRAP, 12, 4) +FIELD(MVFR0, FPDIVIDE, 16, 4) +FIELD(MVFR0, FPSQRT, 20, 4) +FIELD(MVFR0, FPSHVEC, 24, 4) +FIELD(MVFR0, FPROUND, 28, 4) + +FIELD(MVFR1, FPFTZ, 0, 4) +FIELD(MVFR1, FPDNAN, 4, 4) +FIELD(MVFR1, SIMDLS, 8, 4) +FIELD(MVFR1, SIMDINT, 12, 4) +FIELD(MVFR1, SIMDSP, 16, 4) +FIELD(MVFR1, SIMDHP, 20, 4) +FIELD(MVFR1, FPHP, 24, 4) +FIELD(MVFR1, SIMDFMAC, 28, 4) + +FIELD(MVFR2, SIMDMISC, 0, 4) +FIELD(MVFR2, FPMISC, 4, 4) + QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK); /* If adding a feature bit which corresponds to a Linux ELF @@ -1747,7 +1768,6 @@ enum arm_features { ARM_FEATURE_THUMB2, ARM_FEATURE_PMSA, /* no MMU; may have Memory Protection Unit */ ARM_FEATURE_VFP3, - ARM_FEATURE_VFP_FP16, ARM_FEATURE_NEON, ARM_FEATURE_M, /* Microcontroller profile. */ ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */ @@ -2538,25 +2558,18 @@ bool write_list_to_cpustate(ARMCPU *cpu); /** * write_cpustate_to_list: * @cpu: ARMCPU - * @kvm_sync: true if this is for syncing back to KVM * * For each register listed in the ARMCPU cpreg_indexes list, write * its value from the ARMCPUState structure into the cpreg_values list. * This is used to copy info from TCG's working data structures into * KVM or for outbound migration. * - * @kvm_sync is true if we are doing this in order to sync the - * register state back to KVM. In this case we will only update - * values in the list if the previous list->cpustate sync actually - * successfully wrote the CPU state. Otherwise we will keep the value - * that is in the list. - * * Returns: true if all register values were read correctly, * false if some register was unknown or could not be read. * Note that we do not stop early on failure -- we will attempt * reading all registers in the list. */ -bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); +bool write_cpustate_to_list(ARMCPU *cpu); #define ARM_CPUID_TI915T 0x54029152 #define ARM_CPUID_TI925T 0x54029252 @@ -3283,6 +3296,11 @@ static inline bool isar_feature_aa32_dp(const ARMISARegisters *id) return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0; } +static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0; +} + static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) { /* @@ -3294,6 +3312,41 @@ static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) } /* + * We always set the FP and SIMD FP16 fields to indicate identical + * levels of support (assuming SIMD is implemented at all), so + * we only need one set of accessors. + */ +static inline bool isar_feature_aa32_fp16_spconv(const ARMISARegisters *id) +{ + return FIELD_EX64(id->mvfr1, MVFR1, FPHP) > 0; +} + +static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id) +{ + return FIELD_EX64(id->mvfr1, MVFR1, FPHP) > 1; +} + +static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id) +{ + return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 1; +} + +static inline bool isar_feature_aa32_vcvt_dr(const ARMISARegisters *id) +{ + return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 2; +} + +static inline bool isar_feature_aa32_vrint(const ARMISARegisters *id) +{ + return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 3; +} + +static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) +{ + return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 4; +} + +/* * 64-bit feature tests via id registers. */ static inline bool isar_feature_aa64_aes(const ARMISARegisters *id) @@ -3356,6 +3409,11 @@ static inline bool isar_feature_aa64_dp(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0; } +static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0; +} + static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 69e4134f79..1b0c427277 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -308,6 +308,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); cpu->isar.id_aa64isar0 = t; t = cpu->isar.id_aa64isar1; @@ -347,6 +348,7 @@ static void aarch64_max_initfn(Object *obj) u = cpu->isar.id_isar6; u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); u = FIELD_DP32(u, ID_ISAR6, DP, 1); + u = FIELD_DP32(u, ID_ISAR6, FHM, 1); cpu->isar.id_isar6 = u; /* diff --git a/target/arm/helper.c b/target/arm/helper.c index fbaa801cea..1fa282a7fc 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -265,7 +265,7 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri) return true; } -bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) +bool write_cpustate_to_list(ARMCPU *cpu) { /* Write the coprocessor state from cpu->env to the (index,value) list. */ int i; @@ -274,7 +274,6 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) for (i = 0; i < cpu->cpreg_array_len; i++) { uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]); const ARMCPRegInfo *ri; - uint64_t newval; ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); if (!ri) { @@ -284,29 +283,7 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) if (ri->type & ARM_CP_NO_RAW) { continue; } - - newval = read_raw_cp_reg(&cpu->env, ri); - if (kvm_sync) { - /* - * Only sync if the previous list->cpustate sync succeeded. - * Rather than tracking the success/failure state for every - * item in the list, we just recheck "does the raw write we must - * have made in write_list_to_cpustate() read back OK" here. - */ - uint64_t oldval = cpu->cpreg_values[i]; - - if (oldval == newval) { - continue; - } - - write_raw_cp_reg(&cpu->env, ri, oldval); - if (read_raw_cp_reg(&cpu->env, ri) != oldval) { - continue; - } - - write_raw_cp_reg(&cpu->env, ri, newval); - } - cpu->cpreg_values[i] = newval; + cpu->cpreg_values[i] = read_raw_cp_reg(&cpu->env, ri); } return ok; } diff --git a/target/arm/helper.h b/target/arm/helper.h index 747cb64d29..d363904278 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -677,6 +677,15 @@ DEF_HELPER_FLAGS_5(gvec_sqsub_s, TCG_CALL_NO_RWG, DEF_HELPER_FLAGS_5(gvec_sqsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_a32, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_a64, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a32, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a64, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "helper-a64.h" #include "helper-sve.h" diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c index a75e04cc8f..50327989dc 100644 --- a/target/arm/kvm32.c +++ b/target/arm/kvm32.c @@ -125,9 +125,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) if (extract32(id_pfr0, 12, 4) == 1) { set_feature(&features, ARM_FEATURE_THUMB2EE); } - if (extract32(ahcf->isar.mvfr1, 20, 4) == 1) { - set_feature(&features, ARM_FEATURE_VFP_FP16); - } if (extract32(ahcf->isar.mvfr1, 12, 4) == 1) { set_feature(&features, ARM_FEATURE_NEON); } @@ -387,8 +384,24 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } - write_cpustate_to_list(cpu, true); - + /* Note that we do not call write_cpustate_to_list() + * here, so we are only writing the tuple list back to + * KVM. This is safe because nothing can change the + * CPUARMState cp15 fields (in particular gdb accesses cannot) + * and so there are no changes to sync. In fact syncing would + * be wrong at this point: for a constant register where TCG and + * KVM disagree about its value, the preceding write_list_to_cpustate() + * would not have had any effect on the CPUARMState value (since the + * register is read-only), and a write_cpustate_to_list() here would + * then try to write the TCG value back into KVM -- this would either + * fail or incorrectly change the value the guest sees. + * + * If we ever want to allow the user to modify cp15 registers via + * the gdb stub, we would need to be more clever here (for instance + * tracking the set of registers kvm_arch_get_registers() successfully + * managed to update the CPUARMState with, and only allowing those + * to be written back up into the kernel). + */ if (!write_list_to_kvmstate(cpu, level)) { return EINVAL; } diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index e3ba149248..089af9c5f0 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -838,8 +838,6 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } - write_cpustate_to_list(cpu, true); - if (!write_list_to_kvmstate(cpu, level)) { return EINVAL; } diff --git a/target/arm/machine.c b/target/arm/machine.c index 124192bfc2..b292549614 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -630,7 +630,7 @@ static int cpu_pre_save(void *opaque) abort(); } } else { - if (!write_cpustate_to_list(cpu, false)) { + if (!write_cpustate_to_list(cpu)) { /* This should never fail. */ abort(); } diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index c56e878787..d3c8eaf089 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -10917,9 +10917,29 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn) if (!fp_access_check(s)) { return; } - handle_3same_float(s, size, elements, fpopcode, rd, rn, rm); return; + + case 0x1d: /* FMLAL */ + case 0x3d: /* FMLSL */ + case 0x59: /* FMLAL2 */ + case 0x79: /* FMLSL2 */ + if (size & 1 || !dc_isar_feature(aa64_fhm, s)) { + unallocated_encoding(s); + return; + } + if (fp_access_check(s)) { + int is_s = extract32(insn, 23, 1); + int is_2 = extract32(insn, 29, 1); + int data = (is_2 << 1) | is_s; + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), cpu_env, + is_q ? 16 : 8, vec_full_reg_size(s), + data, gen_helper_gvec_fmlal_a64); + } + return; + default: unallocated_encoding(s); return; @@ -12739,6 +12759,17 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) } is_fp = 2; break; + case 0x00: /* FMLAL */ + case 0x04: /* FMLSL */ + case 0x18: /* FMLAL2 */ + case 0x1c: /* FMLSL2 */ + if (is_scalar || size != MO_32 || !dc_isar_feature(aa64_fhm, s)) { + unallocated_encoding(s); + return; + } + size = MO_16; + /* is_fp, but we pass cpu_env not fp_status. */ + break; default: unallocated_encoding(s); return; @@ -12849,6 +12880,22 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpst); } return; + + case 0x00: /* FMLAL */ + case 0x04: /* FMLSL */ + case 0x18: /* FMLAL2 */ + case 0x1c: /* FMLSL2 */ + { + int is_s = extract32(opcode, 2, 1); + int is_2 = u; + int data = (index << 2) | (is_2 << 1) | is_s; + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), cpu_env, + is_q ? 16 : 8, vec_full_reg_size(s), + data, gen_helper_gvec_fmlal_idx_a64); + } + return; } if (size == 3) { diff --git a/target/arm/translate.c b/target/arm/translate.c index c1175798ac..8f7f5b95aa 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3357,14 +3357,10 @@ static const uint8_t fp_decode_rm[] = { FPROUNDING_NEGINF, }; -static int disas_vfp_v8_insn(DisasContext *s, uint32_t insn) +static int disas_vfp_misc_insn(DisasContext *s, uint32_t insn) { uint32_t rd, rn, rm, dp = extract32(insn, 8, 1); - if (!arm_dc_feature(s, ARM_FEATURE_V8)) { - return 1; - } - if (dp) { VFP_DREG_D(rd, insn); VFP_DREG_N(rn, insn); @@ -3375,15 +3371,18 @@ static int disas_vfp_v8_insn(DisasContext *s, uint32_t insn) rm = VFP_SREG_M(insn); } - if ((insn & 0x0f800e50) == 0x0e000a00) { + if ((insn & 0x0f800e50) == 0x0e000a00 && dc_isar_feature(aa32_vsel, s)) { return handle_vsel(insn, rd, rn, rm, dp); - } else if ((insn & 0x0fb00e10) == 0x0e800a00) { + } else if ((insn & 0x0fb00e10) == 0x0e800a00 && + dc_isar_feature(aa32_vminmaxnm, s)) { return handle_vminmaxnm(insn, rd, rn, rm, dp); - } else if ((insn & 0x0fbc0ed0) == 0x0eb80a40) { + } else if ((insn & 0x0fbc0ed0) == 0x0eb80a40 && + dc_isar_feature(aa32_vrint, s)) { /* VRINTA, VRINTN, VRINTP, VRINTM */ int rounding = fp_decode_rm[extract32(insn, 16, 2)]; return handle_vrint(insn, rd, rm, dp, rounding); - } else if ((insn & 0x0fbc0e50) == 0x0ebc0a40) { + } else if ((insn & 0x0fbc0e50) == 0x0ebc0a40 && + dc_isar_feature(aa32_vcvt_dr, s)) { /* VCVTA, VCVTN, VCVTP, VCVTM */ int rounding = fp_decode_rm[extract32(insn, 16, 2)]; return handle_vcvt(insn, rd, rm, dp, rounding); @@ -3427,10 +3426,12 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) } if (extract32(insn, 28, 4) == 0xf) { - /* Encodings with T=1 (Thumb) or unconditional (ARM): - * only used in v8 and above. + /* + * Encodings with T=1 (Thumb) or unconditional (ARM): + * only used for the "miscellaneous VFP features" added in v8A + * and v7M (and gated on the MVFR2.FPMisc field). */ - return disas_vfp_v8_insn(s, insn); + return disas_vfp_misc_insn(s, insn); } dp = ((insn & 0xf00) == 0xb00); @@ -3663,17 +3664,27 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) * UNPREDICTABLE if bit 8 is set prior to ARMv8 * (we choose to UNDEF) */ - if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) || - !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) { - return 1; + if (dp) { + if (!dc_isar_feature(aa32_fp16_dpconv, s)) { + return 1; + } + } else { + if (!dc_isar_feature(aa32_fp16_spconv, s)) { + return 1; + } } rm_is_dp = false; break; case 0x06: /* vcvtb.f16.f32, vcvtb.f16.f64 */ case 0x07: /* vcvtt.f16.f32, vcvtt.f16.f64 */ - if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) || - !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) { - return 1; + if (dp) { + if (!dc_isar_feature(aa32_fp16_dpconv, s)) { + return 1; + } + } else { + if (!dc_isar_feature(aa32_fp16_spconv, s)) { + return 1; + } } rd_is_dp = false; break; @@ -7876,7 +7887,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) TCGv_ptr fpst; TCGv_i32 ahp; - if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) || + if (!dc_isar_feature(aa32_fp16_spconv, s) || q || (rm & 1)) { return 1; } @@ -7908,7 +7919,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) { TCGv_ptr fpst; TCGv_i32 ahp; - if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) || + if (!dc_isar_feature(aa32_fp16_spconv, s) || q || (rd & 1)) { return 1; } @@ -8372,15 +8383,9 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL; int rd, rn, rm, opr_sz; int data = 0; - bool q; - - q = extract32(insn, 6, 1); - VFP_DREG_D(rd, insn); - VFP_DREG_N(rn, insn); - VFP_DREG_M(rm, insn); - if ((rd | rn | rm) & q) { - return 1; - } + int off_rn, off_rm; + bool is_long = false, q = extract32(insn, 6, 1); + bool ptr_is_env = false; if ((insn & 0xfe200f10) == 0xfc200800) { /* VCMLA -- 1111 110R R.1S .... .... 1000 ...0 .... */ @@ -8407,10 +8412,39 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) return 1; } fn_gvec = u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b; + } else if ((insn & 0xff300f10) == 0xfc200810) { + /* VFM[AS]L -- 1111 1100 S.10 .... .... 1000 .Q.1 .... */ + int is_s = extract32(insn, 23, 1); + if (!dc_isar_feature(aa32_fhm, s)) { + return 1; + } + is_long = true; + data = is_s; /* is_2 == 0 */ + fn_gvec_ptr = gen_helper_gvec_fmlal_a32; + ptr_is_env = true; } else { return 1; } + VFP_DREG_D(rd, insn); + if (rd & q) { + return 1; + } + if (q || !is_long) { + VFP_DREG_N(rn, insn); + VFP_DREG_M(rm, insn); + if ((rn | rm) & q & !is_long) { + return 1; + } + off_rn = vfp_reg_offset(1, rn); + off_rm = vfp_reg_offset(1, rm); + } else { + rn = VFP_SREG_N(insn); + rm = VFP_SREG_M(insn); + off_rn = vfp_reg_offset(0, rn); + off_rm = vfp_reg_offset(0, rm); + } + if (s->fp_excp_el) { gen_exception_insn(s, 4, EXCP_UDEF, syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); @@ -8422,16 +8456,19 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) opr_sz = (1 + q) * 8; if (fn_gvec_ptr) { - TCGv_ptr fpst = get_fpstatus_ptr(1); - tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), fpst, + TCGv_ptr ptr; + if (ptr_is_env) { + ptr = cpu_env; + } else { + ptr = get_fpstatus_ptr(1); + } + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr, opr_sz, opr_sz, data, fn_gvec_ptr); - tcg_temp_free_ptr(fpst); + if (!ptr_is_env) { + tcg_temp_free_ptr(ptr); + } } else { - tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), + tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm, opr_sz, opr_sz, data, fn_gvec); } return 0; @@ -8450,14 +8487,9 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) gen_helper_gvec_3 *fn_gvec = NULL; gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL; int rd, rn, rm, opr_sz, data; - bool q; - - q = extract32(insn, 6, 1); - VFP_DREG_D(rd, insn); - VFP_DREG_N(rn, insn); - if ((rd | rn) & q) { - return 1; - } + int off_rn, off_rm; + bool is_long = false, q = extract32(insn, 6, 1); + bool ptr_is_env = false; if ((insn & 0xff000f10) == 0xfe000800) { /* VCMLA (indexed) -- 1111 1110 S.RR .... .... 1000 ...0 .... */ @@ -8486,6 +8518,7 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) } else if ((insn & 0xffb00f00) == 0xfe200d00) { /* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */ int u = extract32(insn, 4, 1); + if (!dc_isar_feature(aa32_dp, s)) { return 1; } @@ -8493,10 +8526,48 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) /* rm is just Vm, and index is M. */ data = extract32(insn, 5, 1); /* index */ rm = extract32(insn, 0, 4); + } else if ((insn & 0xffa00f10) == 0xfe000810) { + /* VFM[AS]L -- 1111 1110 0.0S .... .... 1000 .Q.1 .... */ + int is_s = extract32(insn, 20, 1); + int vm20 = extract32(insn, 0, 3); + int vm3 = extract32(insn, 3, 1); + int m = extract32(insn, 5, 1); + int index; + + if (!dc_isar_feature(aa32_fhm, s)) { + return 1; + } + if (q) { + rm = vm20; + index = m * 2 + vm3; + } else { + rm = vm20 * 2 + m; + index = vm3; + } + is_long = true; + data = (index << 2) | is_s; /* is_2 == 0 */ + fn_gvec_ptr = gen_helper_gvec_fmlal_idx_a32; + ptr_is_env = true; } else { return 1; } + VFP_DREG_D(rd, insn); + if (rd & q) { + return 1; + } + if (q || !is_long) { + VFP_DREG_N(rn, insn); + if (rn & q & !is_long) { + return 1; + } + off_rn = vfp_reg_offset(1, rn); + off_rm = vfp_reg_offset(1, rm); + } else { + rn = VFP_SREG_N(insn); + off_rn = vfp_reg_offset(0, rn); + off_rm = vfp_reg_offset(0, rm); + } if (s->fp_excp_el) { gen_exception_insn(s, 4, EXCP_UDEF, syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); @@ -8508,16 +8579,19 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) opr_sz = (1 + q) * 8; if (fn_gvec_ptr) { - TCGv_ptr fpst = get_fpstatus_ptr(1); - tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), fpst, + TCGv_ptr ptr; + if (ptr_is_env) { + ptr = cpu_env; + } else { + ptr = get_fpstatus_ptr(1); + } + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr, opr_sz, opr_sz, data, fn_gvec_ptr); - tcg_temp_free_ptr(fpst); + if (!ptr_is_env) { + tcg_temp_free_ptr(ptr); + } } else { - tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), + tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm, opr_sz, opr_sz, data, fn_gvec); } return 0; diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index dfc635cf9a..dedef62403 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -898,3 +898,151 @@ void HELPER(gvec_sqsub_d)(void *vd, void *vq, void *vn, } clear_tail(d, oprsz, simd_maxsz(desc)); } + +/* + * Convert float16 to float32, raising no exceptions and + * preserving exceptional values, including SNaN. + * This is effectively an unpack+repack operation. + */ +static float32 float16_to_float32_by_bits(uint32_t f16, bool fz16) +{ + const int f16_bias = 15; + const int f32_bias = 127; + uint32_t sign = extract32(f16, 15, 1); + uint32_t exp = extract32(f16, 10, 5); + uint32_t frac = extract32(f16, 0, 10); + + if (exp == 0x1f) { + /* Inf or NaN */ + exp = 0xff; + } else if (exp == 0) { + /* Zero or denormal. */ + if (frac != 0) { + if (fz16) { + frac = 0; + } else { + /* + * Denormal; these are all normal float32. + * Shift the fraction so that the msb is at bit 11, + * then remove bit 11 as the implicit bit of the + * normalized float32. Note that we still go through + * the shift for normal numbers below, to put the + * float32 fraction at the right place. + */ + int shift = clz32(frac) - 21; + frac = (frac << shift) & 0x3ff; + exp = f32_bias - f16_bias - shift + 1; + } + } + } else { + /* Normal number; adjust the bias. */ + exp += f32_bias - f16_bias; + } + sign <<= 31; + exp <<= 23; + frac <<= 23 - 10; + + return sign | exp | frac; +} + +static uint64_t load4_f16(uint64_t *ptr, int is_q, int is_2) +{ + /* + * Branchless load of u32[0], u64[0], u32[1], or u64[1]. + * Load the 2nd qword iff is_q & is_2. + * Shift to the 2nd dword iff !is_q & is_2. + * For !is_q & !is_2, the upper bits of the result are garbage. + */ + return ptr[is_q & is_2] >> ((is_2 & ~is_q) << 5); +} + +/* + * Note that FMLAL requires oprsz == 8 or oprsz == 16, + * as there is not yet SVE versions that might use blocking. + */ + +static void do_fmlal(float32 *d, void *vn, void *vm, float_status *fpst, + uint32_t desc, bool fz16) +{ + intptr_t i, oprsz = simd_oprsz(desc); + int is_s = extract32(desc, SIMD_DATA_SHIFT, 1); + int is_2 = extract32(desc, SIMD_DATA_SHIFT + 1, 1); + int is_q = oprsz == 16; + uint64_t n_4, m_4; + + /* Pre-load all of the f16 data, avoiding overlap issues. */ + n_4 = load4_f16(vn, is_q, is_2); + m_4 = load4_f16(vm, is_q, is_2); + + /* Negate all inputs for FMLSL at once. */ + if (is_s) { + n_4 ^= 0x8000800080008000ull; + } + + for (i = 0; i < oprsz / 4; i++) { + float32 n_1 = float16_to_float32_by_bits(n_4 >> (i * 16), fz16); + float32 m_1 = float16_to_float32_by_bits(m_4 >> (i * 16), fz16); + d[H4(i)] = float32_muladd(n_1, m_1, d[H4(i)], 0, fpst); + } + clear_tail(d, oprsz, simd_maxsz(desc)); +} + +void HELPER(gvec_fmlal_a32)(void *vd, void *vn, void *vm, + void *venv, uint32_t desc) +{ + CPUARMState *env = venv; + do_fmlal(vd, vn, vm, &env->vfp.standard_fp_status, desc, + get_flush_inputs_to_zero(&env->vfp.fp_status_f16)); +} + +void HELPER(gvec_fmlal_a64)(void *vd, void *vn, void *vm, + void *venv, uint32_t desc) +{ + CPUARMState *env = venv; + do_fmlal(vd, vn, vm, &env->vfp.fp_status, desc, + get_flush_inputs_to_zero(&env->vfp.fp_status_f16)); +} + +static void do_fmlal_idx(float32 *d, void *vn, void *vm, float_status *fpst, + uint32_t desc, bool fz16) +{ + intptr_t i, oprsz = simd_oprsz(desc); + int is_s = extract32(desc, SIMD_DATA_SHIFT, 1); + int is_2 = extract32(desc, SIMD_DATA_SHIFT + 1, 1); + int index = extract32(desc, SIMD_DATA_SHIFT + 2, 3); + int is_q = oprsz == 16; + uint64_t n_4; + float32 m_1; + + /* Pre-load all of the f16 data, avoiding overlap issues. */ + n_4 = load4_f16(vn, is_q, is_2); + + /* Negate all inputs for FMLSL at once. */ + if (is_s) { + n_4 ^= 0x8000800080008000ull; + } + + m_1 = float16_to_float32_by_bits(((float16 *)vm)[H2(index)], fz16); + + for (i = 0; i < oprsz / 4; i++) { + float32 n_1 = float16_to_float32_by_bits(n_4 >> (i * 16), fz16); + d[H4(i)] = float32_muladd(n_1, m_1, d[H4(i)], 0, fpst); + } + clear_tail(d, oprsz, simd_maxsz(desc)); +} + +void HELPER(gvec_fmlal_idx_a32)(void *vd, void *vn, void *vm, + void *venv, uint32_t desc) +{ + CPUARMState *env = venv; + do_fmlal_idx(vd, vn, vm, &env->vfp.standard_fp_status, desc, + get_flush_inputs_to_zero(&env->vfp.fp_status_f16)); +} + +void HELPER(gvec_fmlal_idx_a64)(void *vd, void *vn, void *vm, + void *venv, uint32_t desc) +{ + CPUARMState *env = venv; + do_fmlal_idx(vd, vn, vm, &env->vfp.fp_status, desc, + get_flush_inputs_to_zero(&env->vfp.fp_status_f16)); +} diff --git a/target/mips/translate.c b/target/mips/translate.c index 3b170208c3..364bd6dc4f 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -4362,6 +4362,7 @@ static void gen_shift(DisasContext *ctx, uint32_t opc, tcg_temp_free(t1); } +#if defined(TARGET_MIPS64) /* Copy GPR to and from TX79 HI1/LO1 register. */ static void gen_HILO1_tx79(DisasContext *ctx, uint32_t opc, int reg) { @@ -4397,6 +4398,7 @@ static void gen_HILO1_tx79(DisasContext *ctx, uint32_t opc, int reg) break; } } +#endif /* Arithmetic on HI/LO registers */ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg) @@ -4746,6 +4748,7 @@ static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt) tcg_temp_free(t1); } +#if defined(TARGET_MIPS64) static void gen_div1_tx79(DisasContext *ctx, uint32_t opc, int rs, int rt) { TCGv t0, t1; @@ -4802,6 +4805,7 @@ static void gen_div1_tx79(DisasContext *ctx, uint32_t opc, int rs, int rt) tcg_temp_free(t0); tcg_temp_free(t1); } +#endif static void gen_muldiv(DisasContext *ctx, uint32_t opc, int acc, int rs, int rt) @@ -24324,6 +24328,29 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) } +#if defined(TARGET_MIPS64) + +/* + * + * MMI (MultiMedia Interface) ASE instructions + * =========================================== + */ + +/* + * MMI instructions category: data communication + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * PCPYH PEXCH PEXTLB PINTH PPACB PEXT5 PREVH + * PCPYLD PEXCW PEXTLH PINTEH PPACH PPAC5 PROT3W + * PCPYUD PEXEH PEXTLW PPACW + * PEXEW PEXTUB + * PEXTUH + * PEXTUW + */ + +#endif + + #if !defined(TARGET_MIPS64) /* MXU accumulate add/subtract 1-bit pattern 'aptn1' */ @@ -27247,6 +27274,9 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx) } } + +#if defined(TARGET_MIPS64) + static void decode_mmi0(CPUMIPSState *env, DisasContext *ctx) { uint32_t opc = MASK_MMI0(ctx->opcode); @@ -27491,6 +27521,8 @@ static void decode_mmi_sq(CPUMIPSState *env, DisasContext *ctx) gen_mmi_sq(ctx, base, rt, offset); } +#endif + static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd, sa; @@ -28796,10 +28828,11 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) decode_opc_special(env, ctx); break; case OPC_SPECIAL2: +#if defined(TARGET_MIPS64) if ((ctx->insn_flags & INSN_R5900) && (ctx->insn_flags & ASE_MMI)) { decode_mmi(env, ctx); -#if !defined(TARGET_MIPS64) - } else if (ctx->insn_flags & ASE_MXU) { +#else + if (ctx->insn_flags & ASE_MXU) { decode_opc_mxu(env, ctx); #endif } else { @@ -28807,11 +28840,15 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_SPECIAL3: +#if defined(TARGET_MIPS64) if (ctx->insn_flags & INSN_R5900) { decode_mmi_sq(env, ctx); /* MMI_OPC_SQ */ } else { decode_opc_special3(env, ctx); } +#else + decode_opc_special3(env, ctx); +#endif break; case OPC_REGIMM: op1 = MASK_REGIMM(ctx->opcode); @@ -29483,7 +29520,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) break; case OPC_MSA: /* OPC_MDMX */ if (ctx->insn_flags & INSN_R5900) { +#if defined(TARGET_MIPS64) gen_mmi_lq(env, ctx); /* MMI_OPC_LQ */ +#endif } else { /* MDMX: Not implemented. */ gen_msa(env, ctx); diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index 3130802304..ae51fe754e 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -113,6 +113,8 @@ enum powerpc_excp_t { POWERPC_EXCP_POWER7, /* POWER8 exception model */ POWERPC_EXCP_POWER8, + /* POWER9 exception model */ + POWERPC_EXCP_POWER9, }; /*****************************************************************************/ @@ -122,6 +124,7 @@ typedef enum { PPC_PM_NAP, PPC_PM_SLEEP, PPC_PM_RVWINKLE, + PPC_PM_STOP, } powerpc_pm_insn_t; /*****************************************************************************/ @@ -139,6 +142,8 @@ enum powerpc_input_t { PPC_FLAGS_INPUT_970, /* PowerPC POWER7 bus */ PPC_FLAGS_INPUT_POWER7, + /* PowerPC POWER9 bus */ + PPC_FLAGS_INPUT_POWER9, /* PowerPC 401 bus */ PPC_FLAGS_INPUT_401, /* Freescale RCPU bus */ diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 325ebbeb98..26604ddf98 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -160,8 +160,10 @@ enum { /* Server doorbell variants */ POWERPC_EXCP_SDOOR = 99, POWERPC_EXCP_SDOOR_HV = 100, + /* ISA 3.00 additions */ + POWERPC_EXCP_HVIRT = 101, /* EOL */ - POWERPC_EXCP_NB = 101, + POWERPC_EXCP_NB = 102, /* QEMU exceptions: used internally during code translation */ POWERPC_EXCP_STOP = 0x200, /* stop translation */ POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */ @@ -318,6 +320,10 @@ struct ppc_slb_t { #define SEGMENT_SHIFT_1T 40 #define SEGMENT_MASK_1T (~((1ULL << SEGMENT_SHIFT_1T) - 1)) +typedef struct ppc_v3_pate_t { + uint64_t dw0; + uint64_t dw1; +} ppc_v3_pate_t; /*****************************************************************************/ /* Machine state register bits definition */ @@ -386,6 +392,7 @@ struct ppc_slb_t { #define LPCR_AIL (3ull << LPCR_AIL_SHIFT) #define LPCR_UPRT PPC_BIT(41) /* Use Process Table */ #define LPCR_EVIRT PPC_BIT(42) /* Enhanced Virtualisation */ +#define LPCR_HR PPC_BIT(43) /* Host Radix */ #define LPCR_ONL PPC_BIT(45) #define LPCR_LD PPC_BIT(46) /* Large Decrementer */ #define LPCR_P7_PECE0 PPC_BIT(49) @@ -414,6 +421,10 @@ struct ppc_slb_t { #define LPCR_HVICE PPC_BIT(62) /* HV Virtualisation Int Enable */ #define LPCR_HDICE PPC_BIT(63) +/* PSSCR bits */ +#define PSSCR_ESL PPC_BIT(42) /* Enable State Loss */ +#define PSSCR_EC PPC_BIT(43) /* Exit Criterion */ + #define msr_sf ((env->msr >> MSR_SF) & 1) #define msr_isf ((env->msr >> MSR_ISF) & 1) #define msr_shv ((env->msr >> MSR_SHV) & 1) @@ -1110,11 +1121,13 @@ struct CPUPPCState { * instructions and SPRs are diallowed if MSR:HV is 0 */ bool has_hv_mode; - /* On P7/P8, set when in PM state, we need to handle resume - * in a special way (such as routing some resume causes to - * 0x100), so flag this here. + + /* + * On P7/P8/P9, set when in PM state, we need to handle resume in + * a special way (such as routing some resume causes to 0x100, ie, + * sreset), so flag this here. */ - bool in_pm_state; + bool resume_as_sreset; #endif /* Those resources are used only during code translation */ @@ -1239,7 +1252,7 @@ struct PPCVirtualHypervisorClass { hwaddr ptex, int n); void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte0, uint64_t pte1); - uint64_t (*get_patbe)(PPCVirtualHypervisor *vhyp); + void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry); target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp); }; @@ -2319,6 +2332,13 @@ enum { * them */ POWER7_INPUT_NB, }; + +enum { + /* POWER9 input pins */ + POWER9_INPUT_INT = 0, + POWER9_INPUT_HINT = 1, + POWER9_INPUT_NB, +}; #endif /* Hardware exceptions definitions */ @@ -2343,6 +2363,7 @@ enum { PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */ PPC_INTERRUPT_HMI, /* Hypervisor Maintainance interrupt */ PPC_INTERRUPT_HDOORBELL, /* Hypervisor Doorbell interrupt */ + PPC_INTERRUPT_HVIRT, /* Hypervisor virtualization interrupt */ }; /* Processor Compatibility mask (PCR) */ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 751d759fcc..39bedbb11d 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -65,6 +65,49 @@ static inline void dump_syscall(CPUPPCState *env) ppc_dump_gpr(env, 6), env->nip); } +static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, + target_ulong *msr) +{ + /* We no longer are in a PM state */ + env->resume_as_sreset = false; + + /* Pretend to be returning from doze always as we don't lose state */ + *msr |= (0x1ull << (63 - 47)); + + /* Machine checks are sent normally */ + if (excp == POWERPC_EXCP_MCHECK) { + return excp; + } + switch (excp) { + case POWERPC_EXCP_RESET: + *msr |= 0x4ull << (63 - 45); + break; + case POWERPC_EXCP_EXTERNAL: + *msr |= 0x8ull << (63 - 45); + break; + case POWERPC_EXCP_DECR: + *msr |= 0x6ull << (63 - 45); + break; + case POWERPC_EXCP_SDOOR: + *msr |= 0x5ull << (63 - 45); + break; + case POWERPC_EXCP_SDOOR_HV: + *msr |= 0x3ull << (63 - 45); + break; + case POWERPC_EXCP_HV_MAINT: + *msr |= 0xaull << (63 - 45); + break; + case POWERPC_EXCP_HVIRT: + *msr |= 0x9ull << (63 - 45); + break; + default: + cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", + excp); + } + return POWERPC_EXCP_RESET; +} + + /* Note that this function should be greatly optimized * when called with a constant excp, from ppc_hw_interrupt */ @@ -97,47 +140,17 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) asrr0 = -1; asrr1 = -1; - /* check for special resume at 0x100 from doze/nap/sleep/winkle on P7/P8 */ - if (env->in_pm_state) { - env->in_pm_state = false; - - /* Pretend to be returning from doze always as we don't lose state */ - msr |= (0x1ull << (63 - 47)); - - /* Non-machine check are routed to 0x100 with a wakeup cause - * encoded in SRR1 - */ - if (excp != POWERPC_EXCP_MCHECK) { - switch (excp) { - case POWERPC_EXCP_RESET: - msr |= 0x4ull << (63 - 45); - break; - case POWERPC_EXCP_EXTERNAL: - msr |= 0x8ull << (63 - 45); - break; - case POWERPC_EXCP_DECR: - msr |= 0x6ull << (63 - 45); - break; - case POWERPC_EXCP_SDOOR: - msr |= 0x5ull << (63 - 45); - break; - case POWERPC_EXCP_SDOOR_HV: - msr |= 0x3ull << (63 - 45); - break; - case POWERPC_EXCP_HV_MAINT: - msr |= 0xaull << (63 - 45); - break; - default: - cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", - excp); - } - excp = POWERPC_EXCP_RESET; - } + /* + * check for special resume at 0x100 from doze/nap/sleep/winkle on + * P7/P8/P9 + */ + if (env->resume_as_sreset) { + excp = powerpc_reset_wakeup(cs, env, excp, &msr); } /* Exception targetting modifiers * - * LPES0 is supported on POWER7/8 + * LPES0 is supported on POWER7/8/9 * LPES1 is not supported (old iSeries mode) * * On anything else, we behave as if LPES0 is 1 @@ -148,9 +161,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) */ #if defined(TARGET_PPC64) if (excp_model == POWERPC_EXCP_POWER7 || - excp_model == POWERPC_EXCP_POWER8) { + excp_model == POWERPC_EXCP_POWER8 || + excp_model == POWERPC_EXCP_POWER9) { lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); - if (excp_model == POWERPC_EXCP_POWER8) { + if (excp_model != POWERPC_EXCP_POWER7) { ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; } else { ail = 0; @@ -416,6 +430,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ case POWERPC_EXCP_HV_EMU: + case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; new_msr |= (target_ulong)MSR_HVB; @@ -652,7 +667,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } } else if (excp_model == POWERPC_EXCP_POWER8) { if (new_msr & MSR_HVB) { - if (env->spr[SPR_HID0] & (HID0_HILE | HID0_POWER9_HILE)) { + if (env->spr[SPR_HID0] & HID0_HILE) { + new_msr |= (target_ulong)1 << MSR_LE; + } + } else if (env->spr[SPR_LPCR] & LPCR_ILE) { + new_msr |= (target_ulong)1 << MSR_LE; + } + } else if (excp_model == POWERPC_EXCP_POWER9) { + if (new_msr & MSR_HVB) { + if (env->spr[SPR_HID0] & HID0_POWER9_HILE) { new_msr |= (target_ulong)1 << MSR_LE; } } else if (env->spr[SPR_LPCR] & LPCR_ILE) { @@ -748,6 +771,7 @@ void ppc_cpu_do_interrupt(CPUState *cs) static void ppc_hw_interrupt(CPUPPCState *env) { PowerPCCPU *cpu = ppc_env_get_cpu(env); + bool async_deliver; /* External reset */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { @@ -769,21 +793,44 @@ static void ppc_hw_interrupt(CPUPPCState *env) return; } #endif + + /* + * For interrupts that gate on MSR:EE, we need to do something a + * bit more subtle, as we need to let them through even when EE is + * clear when coming out of some power management states (in order + * for them to become a 0x100). + */ + async_deliver = (msr_ee != 0) || env->resume_as_sreset; + /* Hypervisor decrementer exception */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { /* LPCR will be clear when not supported so this will work */ bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); - if ((msr_ee != 0 || msr_hv == 0) && hdice) { + if ((async_deliver || msr_hv == 0) && hdice) { /* HDEC clears on delivery */ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); return; } } - /* Extermal interrupt can ignore MSR:EE under some circumstances */ + + /* Hypervisor virtualization interrupt */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) { + /* LPCR will be clear when not supported so this will work */ + bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); + if ((async_deliver || msr_hv == 0) && hvice) { + powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT); + return; + } + } + + /* External interrupt can ignore MSR:EE under some circumstances */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); - if (msr_ee != 0 || (env->has_hv_mode && msr_hv == 0 && !lpes0)) { + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + /* HEIC blocks delivery to the hypervisor */ + if ((async_deliver && !(heic && msr_hv && !msr_pr)) || + (env->has_hv_mode && msr_hv == 0 && !lpes0)) { powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); return; } @@ -795,7 +842,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) return; } } - if (msr_ee != 0) { + if (async_deliver != 0) { /* Watchdog timer on embedded PowerPC */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); @@ -849,6 +896,22 @@ static void ppc_hw_interrupt(CPUPPCState *env) return; } } + + if (env->resume_as_sreset) { + /* + * This is a bug ! It means that has_work took us out of halt without + * anything to deliver while in a PM state that requires getting + * out via a 0x100 + * + * This means we will incorrectly execute past the power management + * instruction instead of triggering a reset. + * + * It generally means a discrepancy between the wakup conditions in the + * processor has_work implementation and the logic in this function. + */ + cpu_abort(CPU(ppc_env_get_cpu(env)), + "Wakeup from PM state but interrupt Undelivered"); + } } void ppc_cpu_do_system_reset(CPUState *cs) @@ -943,22 +1006,15 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) cs = CPU(ppc_env_get_cpu(env)); cs->halted = 1; - env->in_pm_state = true; /* The architecture specifies that HDEC interrupts are * discarded in PM states */ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); - /* Technically, nap doesn't set EE, but if we don't set it - * then ppc_hw_interrupt() won't deliver. We could add some - * other tests there based on LPCR but it's simpler to just - * whack EE in. It will be cleared by the 0x100 at wakeup - * anyway. It will still be observable by the guest in SRR1 - * but this doesn't seem to be a problem. - */ - env->msr |= (1ull << MSR_EE); - raise_exception(env, EXCP_HLT); + /* Condition for waking up at 0x100 */ + env->resume_as_sreset = (insn != PPC_PM_STOP) || + (env->spr[SPR_PSSCR] & PSSCR_EC); } #endif /* defined(TARGET_PPC64) */ diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 18910d18a4..638a6e99c4 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -689,6 +689,7 @@ DEF_HELPER_2(store_ptcr, void, env, tl) #endif DEF_HELPER_2(store_sdr1, void, env, tl) DEF_HELPER_2(store_pidr, void, env, tl) +DEF_HELPER_2(store_lpidr, void, env, tl) DEF_HELPER_FLAGS_2(store_tbl, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_tbu, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_atbl, TCG_CALL_NO_RWG, void, env, tl) diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h index 5efd18049e..a2205e1044 100644 --- a/target/ppc/helper_regs.h +++ b/target/ppc/helper_regs.h @@ -174,26 +174,19 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, static inline void check_tlb_flush(CPUPPCState *env, bool global) { CPUState *cs = CPU(ppc_env_get_cpu(env)); - if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { - tlb_flush(cs); - env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; - } - /* Propagate TLB invalidations to other CPUs when the guest uses broadcast - * TLB invalidation instructions. - */ + /* Handle global flushes first */ if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { - CPUState *other_cs; - CPU_FOREACH(other_cs) { - if (other_cs != cs) { - PowerPCCPU *cpu = POWERPC_CPU(other_cs); - CPUPPCState *other_env = &cpu->env; - - other_env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; - tlb_flush(other_cs); - } - } env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; + env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; + tlb_flush_all_cpus_synced(cs); + return; + } + + /* Then handle local ones */ + if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { + env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; + tlb_flush(cs); } } #else diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index b884930096..c65d1ade15 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -117,6 +117,21 @@ void helper_store_pidr(CPUPPCState *env, target_ulong val) tlb_flush(CPU(cpu)); } +void helper_store_lpidr(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->spr[SPR_LPIDR] = val; + + /* + * We need to flush the TLB on LPID changes as we only tag HV vs + * guest in TCG TLB. Also the quadrants means the HV will + * potentially access and cache entries for the current LPID as + * well. + */ + tlb_flush(CPU(cpu)); +} + void helper_store_hid0_601(CPUPPCState *env, target_ulong val) { target_ulong hid0; diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c index b60df4408f..32b8c166b5 100644 --- a/target/ppc/mmu-book3s-v3.c +++ b/target/ppc/mmu-book3s-v3.c @@ -26,9 +26,36 @@ int ppc64_v3_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx) { - if (ppc64_radix_guest(cpu)) { /* Guest uses radix */ + if (ppc64_v3_radix(cpu)) { /* Guest uses radix */ return ppc_radix64_handle_mmu_fault(cpu, eaddr, rwx, mmu_idx); } else { /* Guest uses hash */ return ppc_hash64_handle_mmu_fault(cpu, eaddr, rwx, mmu_idx); } } + +hwaddr ppc64_v3_get_phys_page_debug(PowerPCCPU *cpu, vaddr eaddr) +{ + if (ppc64_v3_radix(cpu)) { + return ppc_radix64_get_phys_page_debug(cpu, eaddr); + } else { + return ppc_hash64_get_phys_page_debug(cpu, eaddr); + } +} + +bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry) +{ + uint64_t patb = cpu->env.spr[SPR_PTCR] & PTCR_PATB; + uint64_t pats = cpu->env.spr[SPR_PTCR] & PTCR_PATS; + + /* Calculate number of entries */ + pats = 1ull << (pats + 12 - 4); + if (pats <= lpid) { + return false; + } + + /* Grab entry */ + patb += 16 * lpid; + entry->dw0 = ldq_phys(CPU(cpu)->as, patb); + entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8); + return true; +} diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h index fdf80987d7..ee8288e32d 100644 --- a/target/ppc/mmu-book3s-v3.h +++ b/target/ppc/mmu-book3s-v3.h @@ -17,8 +17,10 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifndef MMU_H -#define MMU_H +#ifndef MMU_BOOOK3S_V3_H +#define MMU_BOOOK3S_V3_H + +#include "mmu-hash64.h" #ifndef CONFIG_USER_ONLY @@ -29,7 +31,16 @@ #define PTCR_PATS 0x000000000000001FULL /* Partition Table Size */ /* Partition Table Entry Fields */ -#define PATBE1_GR 0x8000000000000000 +#define PATE0_HR 0x8000000000000000 + +/* + * WARNING: This field doesn't actually exist in the final version of + * the architecture and is unused by hardware. However, qemu uses it + * as an indication of a radix guest in the pseudo-PATB entry that it + * maintains for SPAPR guests and in the migration stream, so we need + * to keep it around + */ +#define PATE1_GR 0x8000000000000000 /* Process Table Entry */ struct prtb_entry { @@ -43,19 +54,68 @@ static inline bool ppc64_use_proc_tbl(PowerPCCPU *cpu) return !!(cpu->env.spr[SPR_LPCR] & LPCR_UPRT); } -static inline bool ppc64_radix_guest(PowerPCCPU *cpu) -{ - PPCVirtualHypervisorClass *vhc = - PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); +bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, + ppc_v3_pate_t *entry); - return !!(vhc->get_patbe(cpu->vhyp) & PATBE1_GR); +/* + * The LPCR:HR bit is a shortcut that avoids having to + * dig out the partition table in the fast path. This is + * also how the HW uses it. + */ +static inline bool ppc64_v3_radix(PowerPCCPU *cpu) +{ + return !!(cpu->env.spr[SPR_LPCR] & LPCR_HR); } +hwaddr ppc64_v3_get_phys_page_debug(PowerPCCPU *cpu, vaddr eaddr); + int ppc64_v3_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx); +static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu) +{ + uint64_t base; + + if (cpu->vhyp) { + return 0; + } + if (cpu->env.mmu_model == POWERPC_MMU_3_00) { + ppc_v3_pate_t pate; + + if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) { + return 0; + } + base = pate.dw0; + } else { + base = cpu->env.spr[SPR_SDR1]; + } + return base & SDR_64_HTABORG; +} + +static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu) +{ + uint64_t base; + + if (cpu->vhyp) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + return vhc->hpt_mask(cpu->vhyp); + } + if (cpu->env.mmu_model == POWERPC_MMU_3_00) { + ppc_v3_pate_t pate; + + if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) { + return 0; + } + base = pate.dw0; + } else { + base = cpu->env.spr[SPR_SDR1]; + } + return (1ULL << ((base & SDR_64_HTABSIZE) + 18 - 7)) - 1; +} + #endif /* TARGET_PPC64 */ #endif /* CONFIG_USER_ONLY */ -#endif /* MMU_H */ +#endif /* MMU_BOOOK3S_V3_H */ diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c index 03ae3c1279..e8562a7c87 100644 --- a/target/ppc/mmu-hash32.c +++ b/target/ppc/mmu-hash32.c @@ -319,6 +319,12 @@ static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off, for (i = 0; i < HPTES_PER_GROUP; i++) { pte0 = ppc_hash32_load_hpte0(cpu, pte_offset); + /* + * pte0 contains the valid bit and must be read before pte1, + * otherwise we might see an old pte1 with a new valid bit and + * thus an inconsistent hpte value + */ + smp_rmb(); pte1 = ppc_hash32_load_hpte1(cpu, pte_offset); if ((pte0 & HPTE32_V_VALID) diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 276d9015e7..c431303eff 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -417,7 +417,7 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu, hwaddr ptex, int n) { hwaddr pte_offset = ptex * HASH_PTE_SIZE_64; - hwaddr base = ppc_hash64_hpt_base(cpu); + hwaddr base; hwaddr plen = n * HASH_PTE_SIZE_64; const ppc_hash_pte64_t *hptes; @@ -426,6 +426,7 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu, PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); return vhc->map_hptes(cpu->vhyp, ptex, n); } + base = ppc_hash64_hpt_base(cpu); if (!base) { return NULL; @@ -490,6 +491,18 @@ static unsigned hpte_page_shift(const PPCHash64SegmentPageSizes *sps, return 0; /* Bad page size encoding */ } +static void ppc64_v3_new_to_old_hpte(target_ulong *pte0, target_ulong *pte1) +{ + /* Insert B into pte0 */ + *pte0 = (*pte0 & HPTE64_V_COMMON_BITS) | + ((*pte1 & HPTE64_R_3_0_SSIZE_MASK) << + (HPTE64_V_SSIZE_SHIFT - HPTE64_R_3_0_SSIZE_SHIFT)); + + /* Remove B from pte1 */ + *pte1 = *pte1 & ~HPTE64_R_3_0_SSIZE_MASK; +} + + static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash, const PPCHash64SegmentPageSizes *sps, target_ulong ptem, @@ -507,8 +520,19 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash, } for (i = 0; i < HPTES_PER_GROUP; i++) { pte0 = ppc_hash64_hpte0(cpu, pteg, i); + /* + * pte0 contains the valid bit and must be read before pte1, + * otherwise we might see an old pte1 with a new valid bit and + * thus an inconsistent hpte value + */ + smp_rmb(); pte1 = ppc_hash64_hpte1(cpu, pteg, i); + /* Convert format if necessary */ + if (cpu->env.mmu_model == POWERPC_MMU_3_00 && !cpu->vhyp) { + ppc64_v3_new_to_old_hpte(&pte0, &pte1); + } + /* This compares V, B, H (secondary) and the AVPN */ if (HPTE64_V_COMPARE(pte0, ptem)) { *pshift = hpte_page_shift(sps, pte0, pte1); @@ -918,7 +942,7 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr) void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte0, uint64_t pte1) { - hwaddr base = ppc_hash64_hpt_base(cpu); + hwaddr base; hwaddr offset = ptex * HASH_PTE_SIZE_64; if (cpu->vhyp) { @@ -927,6 +951,7 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex, vhc->store_hpte(cpu->vhyp, ptex, pte0, pte1); return; } + base = ppc_hash64_hpt_base(cpu); stq_phys(CPU(cpu)->as, base + offset, pte0); stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1); @@ -1084,10 +1109,18 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) case POWERPC_MMU_3_00: /* P9 */ lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD | (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL | - LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | + LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE)) | LPCR_MER | LPCR_GTSE | LPCR_TC | LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE); + /* + * If we have a virtual hypervisor, we need to bring back RMLS. It + * doesn't exist on an actual P9 but that's all we know how to + * configure with softmmu at the moment + */ + if (cpu->vhyp) { + lpcr |= (val & LPCR_RMLS); + } break; default: ; diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index f11efc9cbc..6b555b7220 100644 --- a/target/ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h @@ -63,6 +63,7 @@ void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu, #define SDR_64_HTABORG 0x0FFFFFFFFFFC0000ULL #define SDR_64_HTABSIZE 0x000000000000001FULL +#define PATE0_HTABORG 0x0FFFFFFFFFFC0000ULL #define HPTES_PER_GROUP 8 #define HASH_PTE_SIZE_64 16 #define HASH_PTEG_SIZE_64 (HASH_PTE_SIZE_64 * HPTES_PER_GROUP) @@ -102,23 +103,10 @@ void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu, #define HPTE64_V_1TB_SEG 0x4000000000000000ULL #define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL -static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu) -{ - if (cpu->vhyp) { - return 0; - } - return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG; -} - -static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu) -{ - if (cpu->vhyp) { - PPCVirtualHypervisorClass *vhc = - PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); - return vhc->hpt_mask(cpu->vhyp); - } - return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18 - 7)) - 1; -} +/* Format changes for ARCH v3 */ +#define HPTE64_V_COMMON_BITS 0x000fffffffffffffULL +#define HPTE64_R_3_0_SSIZE_SHIFT 58 +#define HPTE64_R_3_0_SSIZE_MASK (3ULL << HPTE64_R_3_0_SSIZE_SHIFT) struct ppc_hash_pte64 { uint64_t pte0, pte1; diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index ab76cbc835..ca1fb2673f 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -31,10 +31,26 @@ static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr, uint64_t *lpid, uint64_t *pid) { - /* We don't have HV support yet and shouldn't get here with it set anyway */ - assert(!msr_hv); - - if (!msr_hv) { /* !MSR[HV] -> Guest */ + if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */ + switch (eaddr & R_EADDR_QUADRANT) { + case R_EADDR_QUADRANT0: + *lpid = 0; + *pid = env->spr[SPR_BOOKS_PID]; + break; + case R_EADDR_QUADRANT1: + *lpid = env->spr[SPR_LPIDR]; + *pid = env->spr[SPR_BOOKS_PID]; + break; + case R_EADDR_QUADRANT2: + *lpid = env->spr[SPR_LPIDR]; + *pid = 0; + break; + case R_EADDR_QUADRANT3: + *lpid = 0; + *pid = 0; + break; + } + } else { /* !MSR[HV] -> Guest */ switch (eaddr & R_EADDR_QUADRANT) { case R_EADDR_QUADRANT0: /* Guest application */ *lpid = env->spr[SPR_LPIDR]; @@ -186,20 +202,32 @@ static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, vaddr eaddr, raddr, psize, fault_cause, pte_addr); } +static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) +{ + CPUPPCState *env = &cpu->env; + + if (!(pate->dw0 & PATE0_HR)) { + return false; + } + if (lpid == 0 && !msr_hv) { + return false; + } + /* More checks ... */ + return true; +} + int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - PPCVirtualHypervisorClass *vhc = - PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + PPCVirtualHypervisorClass *vhc; hwaddr raddr, pte_addr; - uint64_t lpid = 0, pid = 0, offset, size, patbe, prtbe0, pte; + uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte; int page_size, prot, fault_cause = 0; + ppc_v3_pate_t pate; assert((rwx == 0) || (rwx == 1) || (rwx == 2)); - assert(!msr_hv); /* For now there is no Radix PowerNV Support */ - assert(cpu->vhyp); assert(ppc64_use_proc_tbl(cpu)); /* Real Mode Access */ @@ -220,17 +248,33 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, } /* Get Process Table */ - patbe = vhc->get_patbe(cpu->vhyp); + if (cpu->vhyp) { + vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->get_pate(cpu->vhyp, &pate); + } else { + if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); + return 1; + } + if (!validate_pate(cpu, lpid, &pate)) { + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG); + } + /* We don't support guest mode yet */ + if (lpid != 0) { + error_report("PowerNV guest support Unimplemented"); + exit(1); + } + } /* Index Process Table by PID to Find Corresponding Process Table Entry */ offset = pid * sizeof(struct prtb_entry); - size = 1ULL << ((patbe & PATBE1_R_PRTS) + 12); + size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); if (offset >= size) { /* offset exceeds size of the process table */ ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); return 1; } - prtbe0 = ldq_phys(cs->as, (patbe & PATBE1_R_PRTB) + offset); + prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset); /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ page_size = PRTBE_R_GET_RTS(prtbe0); @@ -255,11 +299,11 @@ hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - PPCVirtualHypervisorClass *vhc = - PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + PPCVirtualHypervisorClass *vhc; hwaddr raddr, pte_addr; - uint64_t lpid = 0, pid = 0, offset, size, patbe, prtbe0, pte; + uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte; int page_size, fault_cause = 0; + ppc_v3_pate_t pate; /* Handle Real Mode */ if (msr_dr == 0) { @@ -273,16 +317,31 @@ hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr) } /* Get Process Table */ - patbe = vhc->get_patbe(cpu->vhyp); + if (cpu->vhyp) { + vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->get_pate(cpu->vhyp, &pate); + } else { + if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { + return -1; + } + if (!validate_pate(cpu, lpid, &pate)) { + return -1; + } + /* We don't support guest mode yet */ + if (lpid != 0) { + error_report("PowerNV guest support Unimplemented"); + exit(1); + } + } /* Index Process Table by PID to Find Corresponding Process Table Entry */ offset = pid * sizeof(struct prtb_entry); - size = 1ULL << ((patbe & PATBE1_R_PRTS) + 12); + size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12); if (offset >= size) { /* offset exceeds size of the process table */ return -1; } - prtbe0 = ldq_phys(cs->as, (patbe & PATBE1_R_PRTB) + offset); + prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset); /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ page_size = PRTBE_R_GET_RTS(prtbe0); diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h index 0ecf063a17..96228546aa 100644 --- a/target/ppc/mmu-radix64.h +++ b/target/ppc/mmu-radix64.h @@ -12,8 +12,8 @@ #define R_EADDR_QUADRANT3 0xC000000000000000 /* Radix Partition Table Entry Fields */ -#define PATBE1_R_PRTB 0x0FFFFFFFFFFFF000 -#define PATBE1_R_PRTS 0x000000000000001F +#define PATE1_R_PRTB 0x0FFFFFFFFFFFF000 +#define PATE1_R_PRTS 0x000000000000001F /* Radix Process Table Entry Fields */ #define PRTBE_R_GET_RTS(rts) \ diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index bcf19da61d..4a6be4d63b 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -1342,7 +1342,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env)); break; case POWERPC_MMU_3_00: - if (ppc64_radix_guest(ppc_env_get_cpu(env))) { + if (ppc64_v3_radix(ppc_env_get_cpu(env))) { /* TODO - Unsupported */ } else { dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env)); @@ -1489,12 +1489,7 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) case POWERPC_MMU_2_07: return ppc_hash64_get_phys_page_debug(cpu, addr); case POWERPC_MMU_3_00: - if (ppc64_radix_guest(ppc_env_get_cpu(env))) { - return ppc_radix64_get_phys_page_debug(cpu, addr); - } else { - return ppc_hash64_get_phys_page_debug(cpu, addr); - } - break; + return ppc64_v3_get_phys_page_debug(cpu, addr); #endif case POWERPC_MMU_32B: diff --git a/target/ppc/translate.c b/target/ppc/translate.c index f4d70e725a..819221f246 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -3566,7 +3566,8 @@ static void gen_doze(DisasContext *ctx) t = tcg_const_i32(PPC_PM_DOZE); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); - gen_stop_exception(ctx); + /* Stop translation, as the CPU is supposed to sleep from now */ + gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -3581,13 +3582,25 @@ static void gen_nap(DisasContext *ctx) t = tcg_const_i32(PPC_PM_NAP); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); - gen_stop_exception(ctx); + /* Stop translation, as the CPU is supposed to sleep from now */ + gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ } static void gen_stop(DisasContext *ctx) { - gen_nap(ctx); +#if defined(CONFIG_USER_ONLY) + GEN_PRIV; +#else + TCGv_i32 t; + + CHK_HV; + t = tcg_const_i32(PPC_PM_STOP); + gen_helper_pminsn(cpu_env, t); + tcg_temp_free_i32(t); + /* Stop translation, as the CPU is supposed to sleep from now */ + gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_sleep(DisasContext *ctx) @@ -3601,7 +3614,8 @@ static void gen_sleep(DisasContext *ctx) t = tcg_const_i32(PPC_PM_SLEEP); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); - gen_stop_exception(ctx); + /* Stop translation, as the CPU is supposed to sleep from now */ + gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -3616,7 +3630,8 @@ static void gen_rvwinkle(DisasContext *ctx) t = tcg_const_i32(PPC_PM_RVWINKLE); gen_helper_pminsn(cpu_env, t); tcg_temp_free_i32(t); - gen_stop_exception(ctx); + /* Stop translation, as the CPU is supposed to sleep from now */ + gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); #endif /* defined(CONFIG_USER_ONLY) */ } #endif /* #if defined(TARGET_PPC64) */ @@ -7466,7 +7481,8 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, #if defined(TARGET_PPC64) if (env->excp_model == POWERPC_EXCP_POWER7 || - env->excp_model == POWERPC_EXCP_POWER8) { + env->excp_model == POWERPC_EXCP_POWER8 || + env->excp_model == POWERPC_EXCP_POWER9) { cpu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n", env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); } diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index d884906004..58542c0fe0 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -408,6 +408,11 @@ static void spr_write_pidr(DisasContext *ctx, int sprn, int gprn) gen_helper_store_pidr(cpu_env, cpu_gpr[gprn]); } +static void spr_write_lpidr(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_lpidr(cpu_env, cpu_gpr[gprn]); +} + static void spr_read_hior(DisasContext *ctx, int gprn, int sprn) { tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, excp_prefix)); @@ -3313,6 +3318,15 @@ static void init_excp_POWER8(CPUPPCState *env) #endif } +static void init_excp_POWER9(CPUPPCState *env) +{ + init_excp_POWER8(env); + +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_HVIRT] = 0x00000EA0; +#endif +} + #endif /*****************************************************************************/ @@ -7876,7 +7890,7 @@ static void gen_spr_book3s_ids(CPUPPCState *env) spr_register_hv(env, SPR_LPIDR, "LPIDR", SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_lpidr, 0x00000000); spr_register_hv(env, SPR_HFSCR, "HFSCR", SPR_NOACCESS, SPR_NOACCESS, @@ -8783,8 +8797,8 @@ static void init_proc_POWER9(CPUPPCState *env) env->icache_line_size = 128; /* Allocate hardware IRQ controller */ - init_excp_POWER8(env); - ppcPOWER7_irq_init(ppc_env_get_cpu(env)); + init_excp_POWER9(env); + ppcPOWER9_irq_init(ppc_env_get_cpu(env)); } static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr) @@ -8801,13 +8815,23 @@ static bool cpu_has_work_POWER9(CPUState *cs) CPUPPCState *env = &cpu->env; if (cs->halted) { + uint64_t psscr = env->spr[SPR_PSSCR]; + if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { return false; } + + /* If EC is clear, just return true on any pending interrupt */ + if (!(psscr & PSSCR_EC)) { + return true; + } /* External Exception */ if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && (env->spr[SPR_LPCR] & LPCR_EEE)) { - return true; + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + if (heic == 0 || !msr_hv || msr_pr) { + return true; + } } /* Decrementer Exception */ if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && @@ -8829,6 +8853,11 @@ static bool cpu_has_work_POWER9(CPUState *cs) (env->spr[SPR_LPCR] & LPCR_HDEE)) { return true; } + /* Hypervisor virtualization exception */ + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HVIRT)) && + (env->spr[SPR_LPCR] & LPCR_HVEE)) { + return true; + } if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { return true; } @@ -8898,8 +8927,8 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) pcc->hash64_opts = &ppc_hash64_opts_POWER7; pcc->radix_page_info = &POWER9_radix_page_info; #endif - pcc->excp_model = POWERPC_EXCP_POWER8; - pcc->bus_model = PPC_FLAGS_INPUT_POWER7; + pcc->excp_model = POWERPC_EXCP_POWER9; + pcc->bus_model = PPC_FLAGS_INPUT_POWER9; pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | diff --git a/target/s390x/cc_helper.c b/target/s390x/cc_helper.c index 307ad61aee..0e467bf2b6 100644 --- a/target/s390x/cc_helper.c +++ b/target/s390x/cc_helper.c @@ -397,6 +397,11 @@ static uint32_t cc_calc_flogr(uint64_t dst) return dst ? 2 : 0; } +static uint32_t cc_calc_lcbb(uint64_t dst) +{ + return dst == 16 ? 0 : 3; +} + static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) { @@ -506,6 +511,9 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_FLOGR: r = cc_calc_flogr(dst); break; + case CC_OP_LCBB: + r = cc_calc_lcbb(dst); + break; case CC_OP_NZ_F32: r = set_cc_nz_f32(dst); diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index a758649f47..f84bfb1284 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -347,10 +347,41 @@ static void do_io_interrupt(CPUS390XState *env) load_psw(env, mask, addr); } +typedef struct MchkExtSaveArea { + uint64_t vregs[32][2]; /* 0x0000 */ + uint8_t pad_0x0200[0x0400 - 0x0200]; /* 0x0200 */ +} MchkExtSaveArea; +QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea) != 1024); + +static int mchk_store_vregs(CPUS390XState *env, uint64_t mcesao) +{ + hwaddr len = sizeof(MchkExtSaveArea); + MchkExtSaveArea *sa; + int i; + + sa = cpu_physical_memory_map(mcesao, &len, 1); + if (!sa) { + return -EFAULT; + } + if (len != sizeof(MchkExtSaveArea)) { + cpu_physical_memory_unmap(sa, len, 1, 0); + return -EFAULT; + } + + for (i = 0; i < 32; i++) { + sa->vregs[i][0] = cpu_to_be64(env->vregs[i][0].ll); + sa->vregs[i][1] = cpu_to_be64(env->vregs[i][1].ll); + } + + cpu_physical_memory_unmap(sa, len, 1, len); + return 0; +} + static void do_mchk_interrupt(CPUS390XState *env) { QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic()); - uint64_t mask, addr; + uint64_t mcic = s390_build_validity_mcic() | MCIC_SC_CP; + uint64_t mask, addr, mcesao = 0; LowCore *lowcore; int i; @@ -362,6 +393,17 @@ static void do_mchk_interrupt(CPUS390XState *env) lowcore = cpu_map_lowcore(env); + /* extended save area */ + if (mcic & MCIC_VB_VR) { + /* length and alignment is 1024 bytes */ + mcesao = be64_to_cpu(lowcore->mcesad) & ~0x3ffull; + } + + /* try to store vector registers */ + if (!mcesao || mchk_store_vregs(env, mcesao)) { + mcic &= ~MCIC_VB_VR; + } + /* we are always in z/Architecture mode */ lowcore->ar_access_id = 1; @@ -377,7 +419,7 @@ static void do_mchk_interrupt(CPUS390XState *env) lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm); lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8); - lowcore->mcic = cpu_to_be64(s390_build_validity_mcic() | MCIC_SC_CP); + lowcore->mcic = cpu_to_be64(mcic); lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->mcck_new_psw.mask); diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c index e921172bc4..1be68bafea 100644 --- a/target/s390x/fpu_helper.c +++ b/target/s390x/fpu_helper.c @@ -36,13 +36,21 @@ #define RET128(F) (env->retxl = F.low, F.high) -#define convert_bit(mask, from, to) \ - (to < from \ - ? (mask / (from / to)) & to \ - : (mask & from) * (to / from)) +uint8_t s390_softfloat_exc_to_ieee(unsigned int exc) +{ + uint8_t s390_exc = 0; + + s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0; + s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0; + s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0; + s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0; + s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0; + + return s390_exc; +} /* Should be called after any operation that may raise IEEE exceptions. */ -static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr) +static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr) { unsigned s390_exc, qemu_exc; @@ -53,22 +61,54 @@ static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr) return; } env->fpu_status.float_exception_flags = 0; + s390_exc = s390_softfloat_exc_to_ieee(qemu_exc); + + /* + * IEEE-Underflow exception recognition exists if a tininess condition + * (underflow) exists and + * - The mask bit in the FPC is zero and the result is inexact + * - The mask bit in the FPC is one + * So tininess conditions that are not inexact don't trigger any + * underflow action in case the mask bit is not one. + */ + if (!(s390_exc & S390_IEEE_MASK_INEXACT) && + !((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) { + s390_exc &= ~S390_IEEE_MASK_UNDERFLOW; + } - /* Convert softfloat exception bits to s390 exception bits. */ - s390_exc = 0; - s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80); - s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40); - s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20); - s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10); - s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08); - - /* Install the exceptions that we raised. */ - env->fpc |= s390_exc << 16; + /* + * FIXME: + * 1. Right now, all inexact conditions are inidicated as + * "truncated" (0) and never as "incremented" (1) in the DXC. + * 2. Only traps due to invalid/divbyzero are suppressing. Other traps + * are completing, meaning the target register has to be written! + * This, however will mean that we have to write the register before + * triggering the trap - impossible right now. + */ + + /* + * invalid/divbyzero cannot coexist with other conditions. + * overflow/underflow however can coexist with inexact, we have to + * handle it separatly. + */ + if (s390_exc & ~S390_IEEE_MASK_INEXACT) { + if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) { + /* trap condition - inexact reported along */ + tcg_s390_data_exception(env, s390_exc, retaddr); + } + /* nontrap condition - inexact handled differently */ + env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16; + } - /* Send signals for enabled exceptions. */ - s390_exc &= env->fpc >> 24; - if (s390_exc) { - tcg_s390_data_exception(env, s390_exc, retaddr); + /* inexact handling */ + if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) { + /* trap condition - overflow/underflow _not_ reported along */ + if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) { + tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT, + retaddr); + } + /* nontrap condition */ + env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16; } } @@ -130,11 +170,22 @@ uint32_t set_cc_nz_f128(float128 v) } } +static inline uint8_t round_from_m34(uint32_t m34) +{ + return extract32(m34, 0, 4); +} + +static inline bool xxc_from_m34(uint32_t m34) +{ + /* XxC is bit 1 of m4 */ + return extract32(m34, 4 + 3 - 1, 1); +} + /* 32-bit FP addition */ uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float32 ret = float32_add(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -142,7 +193,7 @@ uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float64 ret = float64_add(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -153,7 +204,7 @@ uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, float128 ret = float128_add(make_float128(ah, al), make_float128(bh, bl), &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -161,7 +212,7 @@ uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float32 ret = float32_sub(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -169,7 +220,7 @@ uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2) uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float64 ret = float64_sub(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -180,7 +231,7 @@ uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, float128 ret = float128_sub(make_float128(ah, al), make_float128(bh, bl), &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -188,7 +239,7 @@ uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float32 ret = float32_div(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -196,7 +247,7 @@ uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2) uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float64 ret = float64_div(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -207,7 +258,7 @@ uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, float128 ret = float128_div(make_float128(ah, al), make_float128(bh, bl), &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -215,7 +266,7 @@ uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float32 ret = float32_mul(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -223,7 +274,7 @@ uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float64 ret = float64_mul(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -232,7 +283,7 @@ uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { float64 ret = float32_to_float64(f2, &env->fpu_status); ret = float64_mul(f1, ret, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -243,7 +294,7 @@ uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, float128 ret = float128_mul(make_float128(ah, al), make_float128(bh, bl), &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -253,7 +304,7 @@ uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, { float128 ret = float64_to_float128(f2, &env->fpu_status); ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -261,15 +312,19 @@ uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) { float64 ret = float32_to_float64(f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } /* convert 128-bit float to 64-bit float */ -uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al) +uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint32_t m34) { + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } @@ -277,7 +332,7 @@ uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al) uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) { float128 ret = float64_to_float128(f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -285,23 +340,30 @@ uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2) { float128 ret = float32_to_float128(f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return RET128(ret); } /* convert 64-bit float to 32-bit float */ -uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2) +uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34) { + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float32 ret = float64_to_float32(f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 128-bit float to 32-bit float */ -uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al) +uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint32_t m34) { + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } @@ -309,7 +371,7 @@ uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al) uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { int cmp = float32_compare_quiet(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -317,7 +379,7 @@ uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { int cmp = float64_compare_quiet(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -328,21 +390,28 @@ uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, int cmp = float128_compare_quiet(make_float128(ah, al), make_float128(bh, bl), &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } -static int swap_round_mode(CPUS390XState *env, int m3) +int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3) { int ret = env->fpu_status.float_rounding_mode; + switch (m3) { case 0: /* current mode */ break; case 1: - /* biased round no nearest */ + /* round to nearest with ties away from 0 */ + set_float_rounding_mode(float_round_ties_away, &env->fpu_status); + break; + case 3: + /* round to prepare for shorter precision */ + set_float_rounding_mode(float_round_to_odd, &env->fpu_status); + break; case 4: - /* round to nearest */ + /* round to nearest with ties to even */ set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); break; case 5: @@ -357,226 +426,251 @@ static int swap_round_mode(CPUS390XState *env, int m3) /* round to -inf */ set_float_rounding_mode(float_round_down, &env->fpu_status); break; + default: + g_assert_not_reached(); } return ret; } +void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode) +{ + set_float_rounding_mode(old_mode, &env->fpu_status); +} + /* convert 64-bit int to 32-bit float */ -uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m3) +uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float32 ret = int64_to_float32(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 64-bit int to 64-bit float */ -uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m3) +uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float64 ret = int64_to_float64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 64-bit int to 128-bit float */ -uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m3) +uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float128 ret = int64_to_float128(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return RET128(ret); } /* convert 64-bit uint to 32-bit float */ -uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float32 ret = uint64_to_float32(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 64-bit uint to 64-bit float */ -uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float64 ret = uint64_to_float64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 64-bit uint to 128-bit float */ -uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float128 ret = uint64_to_float128(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return RET128(ret); } /* convert 32-bit float to 64-bit int */ -uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); int64_t ret = float32_to_int64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 64-bit float to 64-bit int */ -uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); int64_t ret = float64_to_int64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 128-bit float to 64-bit int */ -uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float128 v2 = make_float128(h, l); int64_t ret = float128_to_int64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 32-bit float to 32-bit int */ -uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); int32_t ret = float32_to_int32(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 64-bit float to 32-bit int */ -uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); int32_t ret = float64_to_int32(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 128-bit float to 32-bit int */ -uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float128 v2 = make_float128(h, l); int32_t ret = float128_to_int32(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 32-bit float to 64-bit uint */ -uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); uint64_t ret; + v2 = float32_to_float64(v2, &env->fpu_status); ret = float64_to_uint64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 64-bit float to 64-bit uint */ -uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); uint64_t ret = float64_to_uint64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 128-bit float to 64-bit uint */ -uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) { - int hold = swap_round_mode(env, m3); - float128 v2 = make_float128(h, l); - /* ??? Not 100% correct. */ - uint64_t ret = float128_to_int64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); + uint64_t ret = float128_to_uint64(make_float128(h, l), &env->fpu_status); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 32-bit float to 32-bit uint */ -uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); uint32_t ret = float32_to_uint32(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 64-bit float to 32-bit uint */ -uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); uint32_t ret = float64_to_uint32(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* convert 128-bit float to 32-bit uint */ -uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) { - int hold = swap_round_mode(env, m3); - float128 v2 = make_float128(h, l); - /* Not 100% correct. */ - uint32_t ret = float128_to_int64(v2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); + uint32_t ret = float128_to_uint32(make_float128(h, l), &env->fpu_status); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* round to integer 32-bit */ -uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m3) +uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float32 ret = float32_round_to_int(f2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* round to integer 64-bit */ -uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m3) +uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float64 ret = float64_round_to_int(f2, &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return ret; } /* round to integer 128-bit */ -uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m3) +uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint32_t m34) { - int hold = swap_round_mode(env, m3); + int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float128 ret = float128_round_to_int(make_float128(ah, al), &env->fpu_status); - set_float_rounding_mode(hold, &env->fpu_status); - handle_exceptions(env, GETPC()); + + s390_restore_bfp_rounding_mode(env, old_mode); + handle_exceptions(env, xxc_from_m34(m34), GETPC()); return RET128(ret); } @@ -584,7 +678,7 @@ uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m3) uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { int cmp = float32_compare(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -592,7 +686,7 @@ uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { int cmp = float64_compare(f1, f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -603,7 +697,7 @@ uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al, int cmp = float128_compare(make_float128(ah, al), make_float128(bh, bl), &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); } @@ -612,7 +706,7 @@ uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) { float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -621,7 +715,7 @@ uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) { float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -631,7 +725,7 @@ uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, { float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -641,78 +735,63 @@ uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, { float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } +/* The rightmost bit has the number 11. */ +static inline uint16_t dcmask(int bit, bool neg) +{ + return 1 << (11 - bit - neg); +} + +#define DEF_FLOAT_DCMASK(_TYPE) \ +static uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1) \ +{ \ + const bool neg = _TYPE##_is_neg(f1); \ + \ + /* Sorted by most common cases - only one class is possible */ \ + if (_TYPE##_is_normal(f1)) { \ + return dcmask(2, neg); \ + } else if (_TYPE##_is_zero(f1)) { \ + return dcmask(0, neg); \ + } else if (_TYPE##_is_denormal(f1)) { \ + return dcmask(4, neg); \ + } else if (_TYPE##_is_infinity(f1)) { \ + return dcmask(6, neg); \ + } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) { \ + return dcmask(8, neg); \ + } \ + /* signaling nan, as last remaining case */ \ + return dcmask(10, neg); \ +} +DEF_FLOAT_DCMASK(float32) +DEF_FLOAT_DCMASK(float64) +DEF_FLOAT_DCMASK(float128) + /* test data class 32-bit */ uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2) { - float32 v1 = f1; - int neg = float32_is_neg(v1); - uint32_t cc = 0; - - if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || - (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || - (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || - (float32_is_signaling_nan(v1, &env->fpu_status) && - (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - /* FIXME: denormalized? */ - return cc; + return (m2 & float32_dcmask(env, f1)) != 0; } /* test data class 64-bit */ uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2) { - int neg = float64_is_neg(v1); - uint32_t cc = 0; - - if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || - (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || - (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || - (float64_is_signaling_nan(v1, &env->fpu_status) && - (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - /* FIXME: denormalized? */ - return cc; + return (m2 & float64_dcmask(env, v1)) != 0; } /* test data class 128-bit */ -uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, - uint64_t al, uint64_t m2) -{ - float128 v1 = make_float128(ah, al); - int neg = float128_is_neg(v1); - uint32_t cc = 0; - - if ((float128_is_zero(v1) && (m2 & (1 << (11-neg)))) || - (float128_is_infinity(v1) && (m2 & (1 << (5-neg)))) || - (float128_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || - (float128_is_signaling_nan(v1, &env->fpu_status) && - (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - /* FIXME: denormalized? */ - return cc; +uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2) +{ + return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0; } /* square root 32-bit */ uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) { float32 ret = float32_sqrt(f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -720,7 +799,7 @@ uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) { float64 ret = float64_sqrt(f2, &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return ret; } @@ -728,44 +807,84 @@ uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) { float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status); - handle_exceptions(env, GETPC()); + handle_exceptions(env, false, GETPC()); return RET128(ret); } -static const int fpc_to_rnd[4] = { +static const int fpc_to_rnd[8] = { float_round_nearest_even, float_round_to_zero, float_round_up, - float_round_down + float_round_down, + -1, + -1, + -1, + float_round_to_odd, }; /* set fpc */ void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) { + if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || + (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { + s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC()); + } + /* Install everything in the main FPC. */ env->fpc = fpc; /* Install the rounding mode in the shadow fpu_status. */ - set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status); + set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); } /* set fpc and signal */ -void HELPER(sfas)(CPUS390XState *env, uint64_t val) +void HELPER(sfas)(CPUS390XState *env, uint64_t fpc) { uint32_t signalling = env->fpc; - uint32_t source = val; uint32_t s390_exc; - /* The contents of the source operand are placed in the FPC register; - then the flags in the FPC register are set to the logical OR of the - signalling flags and the source flags. */ - env->fpc = source | (signalling & 0x00ff0000); - set_float_rounding_mode(fpc_to_rnd[source & 3], &env->fpu_status); + if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || + (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { + s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC()); + } - /* If any signalling flag is 1 and the corresponding source mask - is also 1, a simulated-iee-exception trap occurs. */ - s390_exc = (signalling >> 16) & (source >> 24); + /* + * FPC is set to the FPC operand with a bitwise OR of the signalling + * flags. + */ + env->fpc = fpc | (signalling & 0x00ff0000); + set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); + + /* + * If any signaling flag is enabled in the new FPC mask, a + * simulated-iee-exception exception occurs. + */ + s390_exc = (signalling >> 16) & (fpc >> 24); if (s390_exc) { + if (s390_exc & S390_IEEE_MASK_INVALID) { + s390_exc = S390_IEEE_MASK_INVALID; + } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) { + s390_exc = S390_IEEE_MASK_DIVBYZERO; + } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) { + s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT); + } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) { + s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT); + } else if (s390_exc & S390_IEEE_MASK_INEXACT) { + s390_exc = S390_IEEE_MASK_INEXACT; + } else if (s390_exc & S390_IEEE_MASK_QUANTUM) { + s390_exc = S390_IEEE_MASK_QUANTUM; + } tcg_s390_data_exception(env, s390_exc | 3, GETPC()); } } + +/* set bfp rounding mode */ +void HELPER(srnm)(CPUS390XState *env, uint64_t rnd) +{ + if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) { + s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC()); + } + + env->fpc = deposit32(env->fpc, 0, 3, rnd); + set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status); +} diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 44eca45474..e4739a6b9f 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -601,6 +601,11 @@ static uint16_t qemu_V3_1[] = { }; static uint16_t qemu_LATEST[] = { + /* + * Only BFP bits are implemented (HFP, DFP, PFPO and DIVIDE TO INTEGER not + * implemented yet). + */ + S390_FEAT_FLOATING_POINT_EXT, S390_FEAT_ZPCI, }; diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 3d74836a83..8e9573221c 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -211,7 +211,7 @@ void s390_cpu_recompute_watchpoints(CPUState *cs) } } -struct sigp_save_area { +typedef struct SigpSaveArea { uint64_t fprs[16]; /* 0x0000 */ uint64_t grs[16]; /* 0x0080 */ PSW psw; /* 0x0100 */ @@ -225,13 +225,13 @@ struct sigp_save_area { uint8_t pad_0x0138[0x0140 - 0x0138]; /* 0x0138 */ uint32_t ars[16]; /* 0x0140 */ uint64_t crs[16]; /* 0x0384 */ -}; -QEMU_BUILD_BUG_ON(sizeof(struct sigp_save_area) != 512); +} SigpSaveArea; +QEMU_BUILD_BUG_ON(sizeof(SigpSaveArea) != 512); int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch) { static const uint8_t ar_id = 1; - struct sigp_save_area *sa; + SigpSaveArea *sa; hwaddr len = sizeof(*sa); int i; @@ -272,32 +272,43 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch) return 0; } -#define ADTL_GS_OFFSET 1024 /* offset of GS data in adtl save area */ +typedef struct SigpAdtlSaveArea { + uint64_t vregs[32][2]; /* 0x0000 */ + uint8_t pad_0x0200[0x0400 - 0x0200]; /* 0x0200 */ + uint64_t gscb[4]; /* 0x0400 */ + uint8_t pad_0x0420[0x1000 - 0x0420]; /* 0x0420 */ +} SigpAdtlSaveArea; +QEMU_BUILD_BUG_ON(sizeof(SigpAdtlSaveArea) != 4096); + #define ADTL_GS_MIN_SIZE 2048 /* minimal size of adtl save area for GS */ int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len) { + SigpAdtlSaveArea *sa; hwaddr save = len; - void *mem; + int i; - mem = cpu_physical_memory_map(addr, &save, 1); - if (!mem) { + sa = cpu_physical_memory_map(addr, &save, 1); + if (!sa) { return -EFAULT; } if (save != len) { - cpu_physical_memory_unmap(mem, len, 1, 0); + cpu_physical_memory_unmap(sa, len, 1, 0); return -EFAULT; } - /* FIXME: as soon as TCG supports these features, convert cpu->be */ if (s390_has_feat(S390_FEAT_VECTOR)) { - memcpy(mem, &cpu->env.vregs, 512); + for (i = 0; i < 32; i++) { + sa->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i][0].ll); + sa->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i][1].ll); + } } if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) && len >= ADTL_GS_MIN_SIZE) { - memcpy(mem + ADTL_GS_OFFSET, &cpu->env.gscb, 32); + for (i = 0; i < 4; i++) { + sa->gscb[i] = cpu_to_be64(cpu->env.gscb[i]); + } } - cpu_physical_memory_unmap(mem, len, 1, len); - + cpu_physical_memory_unmap(sa, len, 1, len); return 0; } #endif /* CONFIG_USER_ONLY */ @@ -406,6 +417,7 @@ const char *cc_name(enum cc_op cc_op) [CC_OP_SLA_32] = "CC_OP_SLA_32", [CC_OP_SLA_64] = "CC_OP_SLA_64", [CC_OP_FLOGR] = "CC_OP_FLOGR", + [CC_OP_LCBB] = "CC_OP_LCBB", }; return cc_names[cc_op]; diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 6260b50496..bb659257f6 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -53,11 +53,11 @@ DEF_HELPER_FLAGS_3(mdb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_5(mxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_4(mxdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_2(ldeb, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_3(ldxb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_4(ldxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) DEF_HELPER_FLAGS_2(lxdb, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(lxeb, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_2(ledb, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_3(lexb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(ledb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(lexb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) @@ -104,8 +104,9 @@ DEF_HELPER_4(trtr, i32, env, i32, i64, i64) DEF_HELPER_5(trXX, i32, env, i32, i32, i32, i32) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) -DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) +DEF_HELPER_FLAGS_2(srnm, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_2(stfle, i32, env, i64) DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 61582372ab..61b750a855 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -479,6 +479,8 @@ F(0xb313, LCDBR, RRE, Z, 0, f2, new, f1, negf64, f64, IF_BFP) F(0xb343, LCXBR, RRE, Z, x2h, x2l, new_P, x1, negf128, f128, IF_BFP) F(0xb373, LCDFR, RRE, FPSSH, 0, f2, new, f1, negf64, 0, IF_AFP1 | IF_AFP2) +/* LOAD COUNT TO BLOCK BOUNDARY */ + C(0xe727, LCBB, RXE, V, la2, 0, r1, 0, lcbb, 0) /* LOAD HALFWORD */ C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) @@ -598,10 +600,12 @@ F(0xed04, LDEB, RXE, Z, 0, m2_32u, new, f1, ldeb, 0, IF_BFP) F(0xed05, LXDB, RXE, Z, 0, m2_64, new_P, x1, lxdb, 0, IF_BFP) F(0xed06, LXEB, RXE, Z, 0, m2_32u, new_P, x1, lxeb, 0, IF_BFP) + F(0xb324, LDER, RXE, Z, 0, e2, new, f1, lde, 0, IF_AFP1) + F(0xed24, LDE, RXE, Z, 0, m2_32u, new, f1, lde, 0, IF_AFP1) /* LOAD ROUNDED */ - F(0xb344, LEDBR, RRE, Z, 0, f2, new, e1, ledb, 0, IF_BFP) - F(0xb345, LDXBR, RRE, Z, x2h, x2l, new, f1, ldxb, 0, IF_BFP) - F(0xb346, LEXBR, RRE, Z, x2h, x2l, new, e1, lexb, 0, IF_BFP) + F(0xb344, LEDBR, RRF_e, Z, 0, f2, new, e1, ledb, 0, IF_BFP) + F(0xb345, LDXBR, RRF_e, Z, x2h, x2l, new, f1, ldxb, 0, IF_BFP) + F(0xb346, LEXBR, RRF_e, Z, x2h, x2l, new, e1, lexb, 0, IF_BFP) /* LOAD MULTIPLE */ C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) @@ -759,10 +763,10 @@ /* SET FPC AND SIGNAL */ F(0xb385, SFASR, RRE, IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0, IF_DFP) /* SET BFP ROUNDING MODE */ - F(0xb299, SRNM, S, Z, 0, 0, 0, 0, srnm, 0, IF_BFP) - F(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0, IF_BFP) + F(0xb299, SRNM, S, Z, la2, 0, 0, 0, srnm, 0, IF_BFP) + F(0xb2b8, SRNMB, S, FPE, la2, 0, 0, 0, srnmb, 0, IF_BFP) /* SET DFP ROUNDING MODE */ - F(0xb2b9, SRNMT, S, DFPR, 0, 0, 0, 0, srnm, 0, IF_DFP) + F(0xb2b9, SRNMT, S, DFPR, la2, 0, 0, 0, srnmt, 0, IF_DFP) /* SET PROGRAM MASK */ C(0x0400, SPM, RR_a, Z, r1, 0, 0, 0, spm, 0) diff --git a/target/s390x/insn-format.def b/target/s390x/insn-format.def index a412d90fb7..4297ff4165 100644 --- a/target/s390x/insn-format.def +++ b/target/s390x/insn-format.def @@ -36,7 +36,7 @@ F3(RSY_a, R(1, 8), BDL(2), R(3,12)) F3(RSY_b, R(1, 8), BDL(2), M(3,12)) F2(RX_a, R(1, 8), BXD(2)) F2(RX_b, M(1, 8), BXD(2)) -F2(RXE, R(1, 8), BXD(2)) +F3(RXE, R(1, 8), BXD(2), M(3,32)) F3(RXF, R(1,32), BXD(2), R(3, 8)) F2(RXY_a, R(1, 8), BXDL(2)) F2(RXY_b, M(1, 8), BXDL(2)) diff --git a/target/s390x/internal.h b/target/s390x/internal.h index f2a771e2b4..7baf0e2404 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -101,7 +101,9 @@ typedef struct LowCore { /* whether the kernel died with panic() or not */ uint32_t panic_magic; /* 0xe00 */ - uint8_t pad13[0x11b8 - 0xe04]; /* 0xe04 */ + uint8_t pad13[0x11b0 - 0xe04]; /* 0xe04 */ + + uint64_t mcesad; /* 0x11B0 */ /* 64 bit extparam used for pfault, diag 250 etc */ uint64_t ext_params2; /* 0x11B8 */ @@ -234,6 +236,7 @@ enum cc_op { CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ CC_OP_FLOGR, /* find leftmost one */ + CC_OP_LCBB, /* load count to block boundary */ CC_OP_MAX }; @@ -308,6 +311,15 @@ void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); uint32_t set_cc_nz_f128(float128 v); +#define S390_IEEE_MASK_INVALID 0x80 +#define S390_IEEE_MASK_DIVBYZERO 0x40 +#define S390_IEEE_MASK_OVERFLOW 0x20 +#define S390_IEEE_MASK_UNDERFLOW 0x10 +#define S390_IEEE_MASK_INEXACT 0x08 +#define S390_IEEE_MASK_QUANTUM 0x04 +uint8_t s390_softfloat_exc_to_ieee(unsigned int exc); +int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3); +void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode); /* gdbstub.c */ diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 19072efec6..41fb466bb4 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -145,12 +145,18 @@ void s390x_translate_init(void) } } -static inline int vec_reg_offset(uint8_t reg, uint8_t enr, TCGMemOp size) +static inline int vec_full_reg_offset(uint8_t reg) { - const uint8_t es = 1 << size; - int offs = enr * es; - g_assert(reg < 32); + return offsetof(CPUS390XState, vregs[reg][0].d); +} + +static inline int vec_reg_offset(uint8_t reg, uint8_t enr, TCGMemOp es) +{ + /* Convert element size (es) - e.g. MO_8 - to bytes */ + const uint8_t bytes = 1 << es; + int offs = enr * bytes; + /* * vregs[n][0] is the lowest 8 byte and vregs[n][1] the highest 8 byte * of the 16 byte vector, on both, little and big endian systems. @@ -173,11 +179,11 @@ static inline int vec_reg_offset(uint8_t reg, uint8_t enr, TCGMemOp size) * the two 8 byte elements have to be loaded separately. Let's force all * 16 byte operations to handle it in a special way. */ - g_assert(size <= MO_64); + g_assert(es <= MO_64); #ifndef HOST_WORDS_BIGENDIAN - offs ^= (8 - es); + offs ^= (8 - bytes); #endif - return offs + offsetof(CPUS390XState, vregs[reg][0].d); + return offs + vec_full_reg_offset(reg); } static inline int freg64_offset(uint8_t reg) @@ -376,32 +382,43 @@ static inline void gen_trap(DisasContext *s) gen_data_exception(0xff); } +static void gen_addi_and_wrap_i64(DisasContext *s, TCGv_i64 dst, TCGv_i64 src, + int64_t imm) +{ + tcg_gen_addi_i64(dst, src, imm); + if (!(s->base.tb->flags & FLAG_MASK_64)) { + if (s->base.tb->flags & FLAG_MASK_32) { + tcg_gen_andi_i64(dst, dst, 0x7fffffff); + } else { + tcg_gen_andi_i64(dst, dst, 0x00ffffff); + } + } +} + static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) { TCGv_i64 tmp = tcg_temp_new_i64(); - bool need_31 = !(s->base.tb->flags & FLAG_MASK_64); - - /* Note that d2 is limited to 20 bits, signed. If we crop negative - displacements early we create larger immedate addends. */ - /* Note that addi optimizes the imm==0 case. */ + /* + * Note that d2 is limited to 20 bits, signed. If we crop negative + * displacements early we create larger immedate addends. + */ if (b2 && x2) { tcg_gen_add_i64(tmp, regs[b2], regs[x2]); - tcg_gen_addi_i64(tmp, tmp, d2); + gen_addi_and_wrap_i64(s, tmp, tmp, d2); } else if (b2) { - tcg_gen_addi_i64(tmp, regs[b2], d2); + gen_addi_and_wrap_i64(s, tmp, regs[b2], d2); } else if (x2) { - tcg_gen_addi_i64(tmp, regs[x2], d2); - } else { - if (need_31) { - d2 &= 0x7fffffff; - need_31 = false; + gen_addi_and_wrap_i64(s, tmp, regs[x2], d2); + } else if (!(s->base.tb->flags & FLAG_MASK_64)) { + if (s->base.tb->flags & FLAG_MASK_32) { + tcg_gen_movi_i64(tmp, d2 & 0x7fffffff); + } else { + tcg_gen_movi_i64(tmp, d2 & 0x00ffffff); } + } else { tcg_gen_movi_i64(tmp, d2); } - if (need_31) { - tcg_gen_andi_i64(tmp, tmp, 0x7fffffff); - } return tmp; } @@ -540,6 +557,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_NZ_F32: case CC_OP_NZ_F64: case CC_OP_FLOGR: + case CC_OP_LCBB: /* 1 argument */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); break; @@ -1758,160 +1776,257 @@ static DisasJumpType op_cxb(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static TCGv_i32 fpinst_extract_m34(DisasContext *s, bool m3_with_fpe, + bool m4_with_fpe) +{ + const bool fpe = s390_has_feat(S390_FEAT_FLOATING_POINT_EXT); + uint8_t m3 = get_field(s->fields, m3); + uint8_t m4 = get_field(s->fields, m4); + + /* m3 field was introduced with FPE */ + if (!fpe && m3_with_fpe) { + m3 = 0; + } + /* m4 field was introduced with FPE */ + if (!fpe && m4_with_fpe) { + m4 = 0; + } + + /* Check for valid rounding modes. Mode 3 was introduced later. */ + if (m3 == 2 || m3 > 7 || (!fpe && m3 == 3)) { + gen_program_exception(s, PGM_SPECIFICATION); + return NULL; + } + + return tcg_const_i32(deposit32(m3, 4, 4, m4)); +} + static DisasJumpType op_cfeb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cfeb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cfeb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f32(s, o->in2); return DISAS_NEXT; } static DisasJumpType op_cfdb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cfdb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cfdb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f64(s, o->in2); return DISAS_NEXT; } static DisasJumpType op_cfxb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f128(s, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_cgeb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cgeb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cgeb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f32(s, o->in2); return DISAS_NEXT; } static DisasJumpType op_cgdb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cgdb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cgdb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f64(s, o->in2); return DISAS_NEXT; } static DisasJumpType op_cgxb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f128(s, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_clfeb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_clfeb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_clfeb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f32(s, o->in2); return DISAS_NEXT; } static DisasJumpType op_clfdb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_clfdb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_clfdb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f64(s, o->in2); return DISAS_NEXT; } static DisasJumpType op_clfxb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f128(s, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_clgeb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_clgeb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_clgeb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f32(s, o->in2); return DISAS_NEXT; } static DisasJumpType op_clgdb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_clgdb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_clgdb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f64(s, o->in2); return DISAS_NEXT; } static DisasJumpType op_clgxb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m34); + tcg_temp_free_i32(m34); gen_set_cc_nz_f128(s, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_cegb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cegb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, true, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cegb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } static DisasJumpType op_cdgb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cdgb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, true, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cdgb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } static DisasJumpType op_cxgb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cxgb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, true, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cxgb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return_low128(o->out2); return DISAS_NEXT; } static DisasJumpType op_celgb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_celgb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_celgb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } static DisasJumpType op_cdlgb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cdlgb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cdlgb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } static DisasJumpType op_cxlgb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_cxlgb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, false); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_cxlgb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return_low128(o->out2); return DISAS_NEXT; } @@ -2390,26 +2505,38 @@ static DisasJumpType op_ex(DisasContext *s, DisasOps *o) static DisasJumpType op_fieb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_fieb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_fieb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } static DisasJumpType op_fidb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_fidb(o->out, cpu_env, o->in2, m3); - tcg_temp_free_i32(m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_fidb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } static DisasJumpType op_fixb(DisasContext *s, DisasOps *o) { - TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); - gen_helper_fixb(o->out, cpu_env, o->in1, o->in2, m3); + TCGv_i32 m34 = fpinst_extract_m34(s, false, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_fixb(o->out, cpu_env, o->in1, o->in2, m34); return_low128(o->out2); - tcg_temp_free_i32(m3); + tcg_temp_free_i32(m34); return DISAS_NEXT; } @@ -2678,19 +2805,37 @@ static DisasJumpType op_ldeb(DisasContext *s, DisasOps *o) static DisasJumpType op_ledb(DisasContext *s, DisasOps *o) { - gen_helper_ledb(o->out, cpu_env, o->in2); + TCGv_i32 m34 = fpinst_extract_m34(s, true, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_ledb(o->out, cpu_env, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } static DisasJumpType op_ldxb(DisasContext *s, DisasOps *o) { - gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2); + TCGv_i32 m34 = fpinst_extract_m34(s, true, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } static DisasJumpType op_lexb(DisasContext *s, DisasOps *o) { - gen_helper_lexb(o->out, cpu_env, o->in1, o->in2); + TCGv_i32 m34 = fpinst_extract_m34(s, true, true); + + if (!m34) { + return DISAS_NORETURN; + } + gen_helper_lexb(o->out, cpu_env, o->in1, o->in2, m34); + tcg_temp_free_i32(m34); return DISAS_NEXT; } @@ -2708,6 +2853,12 @@ static DisasJumpType op_lxeb(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_lde(DisasContext *s, DisasOps *o) +{ + tcg_gen_shli_i64(o->out, o->in2, 32); + return DISAS_NEXT; +} + static DisasJumpType op_llgt(DisasContext *s, DisasOps *o) { tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff); @@ -3119,6 +3270,23 @@ static DisasJumpType op_lzrb(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_lcbb(DisasContext *s, DisasOps *o) +{ + const int64_t block_size = (1ull << (get_field(s->fields, m3) + 6)); + + if (get_field(s->fields, m3) > 6) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + + tcg_gen_ori_i64(o->addr1, o->addr1, -block_size); + tcg_gen_neg_i64(o->addr1, o->addr1); + tcg_gen_movi_i64(o->out, 16); + tcg_gen_umin_i64(o->out, o->out, o->addr1); + gen_op_update1_cc_i64(s, CC_OP_LCBB, o->out); + return DISAS_NEXT; +} + static DisasJumpType op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; @@ -3955,41 +4123,33 @@ static DisasJumpType op_sfas(DisasContext *s, DisasOps *o) static DisasJumpType op_srnm(DisasContext *s, DisasOps *o) { - int b2 = get_field(s->fields, b2); - int d2 = get_field(s->fields, d2); - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); - int mask, pos, len; + /* Bits other than 62 and 63 are ignored. Bit 29 is set to zero. */ + tcg_gen_andi_i64(o->addr1, o->addr1, 0x3ull); + gen_helper_srnm(cpu_env, o->addr1); + return DISAS_NEXT; +} - switch (s->fields->op2) { - case 0x99: /* SRNM */ - pos = 0, len = 2; - break; - case 0xb8: /* SRNMB */ - pos = 0, len = 3; - break; - case 0xb9: /* SRNMT */ - pos = 4, len = 3; - break; - default: - tcg_abort(); - } - mask = (1 << len) - 1; +static DisasJumpType op_srnmb(DisasContext *s, DisasOps *o) +{ + /* Bits 0-55 are are ignored. */ + tcg_gen_andi_i64(o->addr1, o->addr1, 0xffull); + gen_helper_srnm(cpu_env, o->addr1); + return DISAS_NEXT; +} - /* Insert the value into the appropriate field of the FPC. */ - if (b2 == 0) { - tcg_gen_movi_i64(t1, d2 & mask); - } else { - tcg_gen_addi_i64(t1, regs[b2], d2); - tcg_gen_andi_i64(t1, t1, mask); - } - tcg_gen_ld32u_i64(t2, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_gen_deposit_i64(t2, t2, t1, pos, len); - tcg_temp_free_i64(t1); +static DisasJumpType op_srnmt(DisasContext *s, DisasOps *o) +{ + TCGv_i64 tmp = tcg_temp_new_i64(); - /* Then install the new FPC to set the rounding mode in fpu_status. */ - gen_helper_sfpc(cpu_env, t2); - tcg_temp_free_i64(t2); + /* Bits other than 61-63 are ignored. */ + tcg_gen_andi_i64(o->addr1, o->addr1, 0x7ull); + + /* No need to call a helper, we don't implement dfp */ + tcg_gen_ld32u_i64(tmp, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_deposit_i64(tmp, tmp, o->addr1, 4, 3); + tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUS390XState, fpc)); + + tcg_temp_free_i64(tmp); return DISAS_NEXT; } @@ -5908,6 +6068,7 @@ enum DisasInsnEnum { #define FAC_ECT S390_FEAT_EXTRACT_CPU_TIME #define FAC_PCI S390_FEAT_ZPCI /* z/PCI facility */ #define FAC_AIS S390_FEAT_ADAPTER_INT_SUPPRESSION +#define FAC_V S390_FEAT_VECTOR /* vector facility */ static const DisasInsn insn_info[] = { #include "insn-data.def" @@ -6091,7 +6252,7 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) const DisasInsn *insn; DisasJumpType ret = DISAS_NEXT; DisasFields f; - DisasOps o; + DisasOps o = {}; /* Search for the insn in the table. */ insn = extract_insn(env, s, &f); @@ -6161,12 +6322,6 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) /* Set up the strutures we use to communicate with the helpers. */ s->insn = insn; s->fields = &f; - o.g_out = o.g_out2 = o.g_in1 = o.g_in2 = false; - o.out = NULL; - o.out2 = NULL; - o.in1 = NULL; - o.in2 = NULL; - o.addr1 = NULL; /* Implement the instruction. */ if (insn->help_in1) { diff --git a/target/xtensa/core-test_mmuhifi_c3/xtensa-modules.inc.c b/target/xtensa/core-test_mmuhifi_c3/xtensa-modules.inc.c index ef70f80f1d..687631b8fb 100644 --- a/target/xtensa/core-test_mmuhifi_c3/xtensa-modules.inc.c +++ b/target/xtensa/core-test_mmuhifi_c3/xtensa-modules.inc.c @@ -24159,2627 +24159,2627 @@ Opcode_ae_sbf_Slot_inst_encode (xtensa_insnbuf slotbuf) slotbuf[0] = 0xe7d014; } -xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { Opcode_excw_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { Opcode_rfe_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { Opcode_rfde_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { Opcode_syscall_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { Opcode_simcall_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_call12_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_call12_encode_fns[] = { Opcode_call12_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_call8_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_call8_encode_fns[] = { Opcode_call8_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_call4_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_call4_encode_fns[] = { Opcode_call4_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_callx12_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_callx12_encode_fns[] = { Opcode_callx12_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_callx8_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_callx8_encode_fns[] = { Opcode_callx8_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_callx4_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_callx4_encode_fns[] = { Opcode_callx4_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_entry_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_entry_encode_fns[] = { Opcode_entry_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_movsp_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_movsp_encode_fns[] = { Opcode_movsp_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rotw_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rotw_encode_fns[] = { Opcode_rotw_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_retw_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_retw_encode_fns[] = { Opcode_retw_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_retw_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_retw_n_encode_fns[] = { 0, 0, Opcode_retw_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rfwo_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rfwo_encode_fns[] = { Opcode_rfwo_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rfwu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rfwu_encode_fns[] = { Opcode_rfwu_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_l32e_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_l32e_encode_fns[] = { Opcode_l32e_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_s32e_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_s32e_encode_fns[] = { Opcode_s32e_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_windowbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_windowbase_encode_fns[] = { Opcode_rsr_windowbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_windowbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_windowbase_encode_fns[] = { Opcode_wsr_windowbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_windowbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_windowbase_encode_fns[] = { Opcode_xsr_windowbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_windowstart_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_windowstart_encode_fns[] = { Opcode_rsr_windowstart_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_windowstart_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_windowstart_encode_fns[] = { Opcode_wsr_windowstart_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_windowstart_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_windowstart_encode_fns[] = { Opcode_xsr_windowstart_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { 0, Opcode_add_n_Slot_inst16a_encode, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { 0, Opcode_addi_n_Slot_inst16a_encode, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { 0, 0, Opcode_beqz_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { 0, 0, Opcode_bnez_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { 0, 0, Opcode_ill_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { 0, Opcode_l32i_n_Slot_inst16a_encode, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { 0, 0, Opcode_mov_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { 0, 0, Opcode_movi_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { 0, 0, Opcode_nop_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { 0, 0, Opcode_ret_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { 0, Opcode_s32i_n_Slot_inst16a_encode, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_threadptr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_threadptr_encode_fns[] = { Opcode_rur_threadptr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_threadptr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_threadptr_encode_fns[] = { Opcode_wur_threadptr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { Opcode_addi_Slot_inst_encode, 0, 0, 0, Opcode_addi_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { Opcode_addmi_Slot_inst_encode, 0, 0, 0, Opcode_addmi_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { Opcode_add_Slot_inst_encode, 0, 0, 0, Opcode_add_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { Opcode_sub_Slot_inst_encode, 0, 0, 0, Opcode_sub_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { Opcode_addx2_Slot_inst_encode, 0, 0, 0, Opcode_addx2_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { Opcode_addx4_Slot_inst_encode, 0, 0, 0, Opcode_addx4_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { Opcode_addx8_Slot_inst_encode, 0, 0, 0, Opcode_addx8_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { Opcode_subx2_Slot_inst_encode, 0, 0, 0, Opcode_subx2_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { Opcode_subx4_Slot_inst_encode, 0, 0, 0, Opcode_subx4_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { Opcode_subx8_Slot_inst_encode, 0, 0, 0, Opcode_subx8_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { Opcode_and_Slot_inst_encode, 0, 0, 0, Opcode_and_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { Opcode_or_Slot_inst_encode, 0, 0, 0, Opcode_or_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { Opcode_xor_Slot_inst_encode, 0, 0, 0, Opcode_xor_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { Opcode_beqi_Slot_inst_encode, 0, 0, 0, Opcode_beqi_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { Opcode_bnei_Slot_inst_encode, 0, 0, 0, Opcode_bnei_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { Opcode_bgei_Slot_inst_encode, 0, 0, 0, Opcode_bgei_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { Opcode_blti_Slot_inst_encode, 0, 0, 0, Opcode_blti_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { Opcode_bbci_Slot_inst_encode, 0, 0, 0, Opcode_bbci_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { Opcode_bbsi_Slot_inst_encode, 0, 0, 0, Opcode_bbsi_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { Opcode_bgeui_Slot_inst_encode, 0, 0, 0, Opcode_bgeui_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { Opcode_bltui_Slot_inst_encode, 0, 0, 0, Opcode_bltui_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { Opcode_beq_Slot_inst_encode, 0, 0, 0, Opcode_beq_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { Opcode_bne_Slot_inst_encode, 0, 0, 0, Opcode_bne_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { Opcode_bge_Slot_inst_encode, 0, 0, 0, Opcode_bge_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { Opcode_blt_Slot_inst_encode, 0, 0, 0, Opcode_blt_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { Opcode_bgeu_Slot_inst_encode, 0, 0, 0, Opcode_bgeu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { Opcode_bltu_Slot_inst_encode, 0, 0, 0, Opcode_bltu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { Opcode_bany_Slot_inst_encode, 0, 0, 0, Opcode_bany_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { Opcode_bnone_Slot_inst_encode, 0, 0, 0, Opcode_bnone_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { Opcode_ball_Slot_inst_encode, 0, 0, 0, Opcode_ball_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { Opcode_bnall_Slot_inst_encode, 0, 0, 0, Opcode_bnall_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { Opcode_bbc_Slot_inst_encode, 0, 0, 0, Opcode_bbc_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { Opcode_bbs_Slot_inst_encode, 0, 0, 0, Opcode_bbs_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { Opcode_beqz_Slot_inst_encode, 0, 0, 0, Opcode_beqz_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { Opcode_bnez_Slot_inst_encode, 0, 0, 0, Opcode_bnez_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { Opcode_bgez_Slot_inst_encode, 0, 0, 0, Opcode_bgez_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { Opcode_bltz_Slot_inst_encode, 0, 0, 0, Opcode_bltz_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { Opcode_call0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { Opcode_callx0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { Opcode_extui_Slot_inst_encode, 0, 0, 0, Opcode_extui_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { Opcode_ill_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { Opcode_j_Slot_inst_encode, 0, 0, 0, Opcode_j_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { Opcode_jx_Slot_inst_encode, 0, 0, 0, Opcode_jx_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { Opcode_l16ui_Slot_inst_encode, 0, 0, 0, Opcode_l16ui_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { Opcode_l16si_Slot_inst_encode, 0, 0, 0, Opcode_l16si_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { Opcode_l32i_Slot_inst_encode, 0, 0, 0, Opcode_l32i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { Opcode_l32r_Slot_inst_encode, 0, 0, 0, Opcode_l32r_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { Opcode_l8ui_Slot_inst_encode, 0, 0, 0, Opcode_l8ui_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_loop_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_loop_encode_fns[] = { Opcode_loop_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_loopnez_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_loopnez_encode_fns[] = { Opcode_loopnez_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_loopgtz_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_loopgtz_encode_fns[] = { Opcode_loopgtz_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { Opcode_movi_Slot_inst_encode, 0, 0, 0, Opcode_movi_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { Opcode_moveqz_Slot_inst_encode, 0, 0, 0, Opcode_moveqz_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { Opcode_movnez_Slot_inst_encode, 0, 0, 0, Opcode_movnez_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { Opcode_movltz_Slot_inst_encode, 0, 0, 0, Opcode_movltz_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { Opcode_movgez_Slot_inst_encode, 0, 0, 0, Opcode_movgez_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { Opcode_neg_Slot_inst_encode, 0, 0, 0, Opcode_neg_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { Opcode_abs_Slot_inst_encode, 0, 0, 0, Opcode_abs_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { Opcode_nop_Slot_inst_encode, 0, 0, Opcode_nop_Slot_ae_slot1_encode, Opcode_nop_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { Opcode_ret_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { Opcode_s16i_Slot_inst_encode, 0, 0, 0, Opcode_s16i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { Opcode_s32i_Slot_inst_encode, 0, 0, 0, Opcode_s32i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { Opcode_s8i_Slot_inst_encode, 0, 0, 0, Opcode_s8i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { Opcode_ssr_Slot_inst_encode, 0, 0, 0, Opcode_ssr_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { Opcode_ssl_Slot_inst_encode, 0, 0, 0, Opcode_ssl_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { Opcode_ssa8l_Slot_inst_encode, 0, 0, 0, Opcode_ssa8l_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { Opcode_ssa8b_Slot_inst_encode, 0, 0, 0, Opcode_ssa8b_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { Opcode_ssai_Slot_inst_encode, 0, 0, 0, Opcode_ssai_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { Opcode_sll_Slot_inst_encode, 0, 0, 0, Opcode_sll_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { Opcode_src_Slot_inst_encode, 0, 0, 0, Opcode_src_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { Opcode_srl_Slot_inst_encode, 0, 0, 0, Opcode_srl_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { Opcode_sra_Slot_inst_encode, 0, 0, 0, Opcode_sra_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { Opcode_slli_Slot_inst_encode, 0, 0, 0, Opcode_slli_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { Opcode_srai_Slot_inst_encode, 0, 0, 0, Opcode_srai_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { Opcode_srli_Slot_inst_encode, 0, 0, 0, Opcode_srli_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { Opcode_memw_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { Opcode_extw_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { Opcode_isync_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { Opcode_rsync_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { Opcode_esync_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { Opcode_dsync_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { Opcode_rsil_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_lend_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_lend_encode_fns[] = { Opcode_rsr_lend_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_lend_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_lend_encode_fns[] = { Opcode_wsr_lend_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_lend_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_lend_encode_fns[] = { Opcode_xsr_lend_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_lcount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_lcount_encode_fns[] = { Opcode_rsr_lcount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_lcount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_lcount_encode_fns[] = { Opcode_wsr_lcount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_lcount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_lcount_encode_fns[] = { Opcode_xsr_lcount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_lbeg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_lbeg_encode_fns[] = { Opcode_rsr_lbeg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_lbeg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_lbeg_encode_fns[] = { Opcode_wsr_lbeg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_lbeg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_lbeg_encode_fns[] = { Opcode_xsr_lbeg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { Opcode_rsr_sar_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { Opcode_wsr_sar_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { Opcode_xsr_sar_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { Opcode_rsr_litbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { Opcode_wsr_litbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { Opcode_xsr_litbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_176_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_176_encode_fns[] = { Opcode_rsr_176_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_176_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_176_encode_fns[] = { Opcode_wsr_176_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_208_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_208_encode_fns[] = { Opcode_rsr_208_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { Opcode_rsr_ps_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { Opcode_wsr_ps_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { Opcode_xsr_ps_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { Opcode_rsr_epc1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { Opcode_wsr_epc1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { Opcode_xsr_epc1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { Opcode_rsr_excsave1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { Opcode_wsr_excsave1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { Opcode_xsr_excsave1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { Opcode_rsr_epc2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { Opcode_wsr_epc2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { Opcode_xsr_epc2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { Opcode_rsr_excsave2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { Opcode_wsr_excsave2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { Opcode_xsr_excsave2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { Opcode_rsr_eps2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { Opcode_wsr_eps2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { Opcode_xsr_eps2_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { Opcode_rsr_excvaddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { Opcode_wsr_excvaddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { Opcode_xsr_excvaddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { Opcode_rsr_depc_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { Opcode_wsr_depc_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { Opcode_xsr_depc_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { Opcode_rsr_exccause_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { Opcode_wsr_exccause_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { Opcode_xsr_exccause_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_misc0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_misc0_encode_fns[] = { Opcode_rsr_misc0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_misc0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_misc0_encode_fns[] = { Opcode_wsr_misc0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_misc0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_misc0_encode_fns[] = { Opcode_xsr_misc0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_misc1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_misc1_encode_fns[] = { Opcode_rsr_misc1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_misc1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_misc1_encode_fns[] = { Opcode_wsr_misc1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_misc1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_misc1_encode_fns[] = { Opcode_xsr_misc1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { Opcode_rsr_prid_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_vecbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_vecbase_encode_fns[] = { Opcode_rsr_vecbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_vecbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_vecbase_encode_fns[] = { Opcode_wsr_vecbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_vecbase_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_vecbase_encode_fns[] = { Opcode_xsr_vecbase_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_mul16u_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_mul16u_encode_fns[] = { Opcode_mul16u_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_mul16s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_mul16s_encode_fns[] = { Opcode_mul16s_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_mull_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_mull_encode_fns[] = { Opcode_mull_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { Opcode_rfi_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { Opcode_waiti_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { Opcode_rsr_interrupt_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { Opcode_wsr_intset_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { Opcode_wsr_intclear_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { Opcode_rsr_intenable_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { Opcode_wsr_intenable_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { Opcode_xsr_intenable_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { Opcode_break_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { 0, 0, Opcode_break_n_Slot_inst16b_encode, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { Opcode_rsr_debugcause_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { Opcode_wsr_debugcause_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { Opcode_xsr_debugcause_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { Opcode_rsr_icount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { Opcode_wsr_icount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { Opcode_xsr_icount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { Opcode_rsr_icountlevel_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { Opcode_wsr_icountlevel_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { Opcode_xsr_icountlevel_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { Opcode_rsr_ddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { Opcode_wsr_ddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { Opcode_xsr_ddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { Opcode_rfdo_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { Opcode_rfdd_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_andb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_andb_encode_fns[] = { Opcode_andb_Slot_inst_encode, 0, 0, 0, Opcode_andb_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_andbc_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_andbc_encode_fns[] = { Opcode_andbc_Slot_inst_encode, 0, 0, 0, Opcode_andbc_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_orb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_orb_encode_fns[] = { Opcode_orb_Slot_inst_encode, 0, 0, 0, Opcode_orb_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_orbc_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_orbc_encode_fns[] = { Opcode_orbc_Slot_inst_encode, 0, 0, 0, Opcode_orbc_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_xorb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xorb_encode_fns[] = { Opcode_xorb_Slot_inst_encode, 0, 0, 0, Opcode_xorb_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_any4_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_any4_encode_fns[] = { Opcode_any4_Slot_inst_encode, 0, 0, 0, Opcode_any4_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_all4_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_all4_encode_fns[] = { Opcode_all4_Slot_inst_encode, 0, 0, 0, Opcode_all4_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_any8_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_any8_encode_fns[] = { Opcode_any8_Slot_inst_encode, 0, 0, 0, Opcode_any8_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_all8_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_all8_encode_fns[] = { Opcode_all8_Slot_inst_encode, 0, 0, 0, Opcode_all8_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bf_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bf_encode_fns[] = { Opcode_bf_Slot_inst_encode, 0, 0, 0, Opcode_bf_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_bt_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_bt_encode_fns[] = { Opcode_bt_Slot_inst_encode, 0, 0, 0, Opcode_bt_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_movf_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_movf_encode_fns[] = { Opcode_movf_Slot_inst_encode, 0, 0, 0, Opcode_movf_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_movt_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_movt_encode_fns[] = { Opcode_movt_Slot_inst_encode, 0, 0, 0, Opcode_movt_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_rsr_br_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_br_encode_fns[] = { Opcode_rsr_br_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_br_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_br_encode_fns[] = { Opcode_wsr_br_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_br_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_br_encode_fns[] = { Opcode_xsr_br_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { Opcode_rsr_ccount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { Opcode_wsr_ccount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { Opcode_xsr_ccount_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { Opcode_rsr_ccompare0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { Opcode_wsr_ccompare0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { Opcode_xsr_ccompare0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_ccompare1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_ccompare1_encode_fns[] = { Opcode_rsr_ccompare1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_ccompare1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_ccompare1_encode_fns[] = { Opcode_wsr_ccompare1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_ccompare1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_ccompare1_encode_fns[] = { Opcode_xsr_ccompare1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ipf_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ipf_encode_fns[] = { Opcode_ipf_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ihi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ihi_encode_fns[] = { Opcode_ihi_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_iii_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_iii_encode_fns[] = { Opcode_iii_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_lict_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_lict_encode_fns[] = { Opcode_lict_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_licw_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_licw_encode_fns[] = { Opcode_licw_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_sict_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_sict_encode_fns[] = { Opcode_sict_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_sicw_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_sicw_encode_fns[] = { Opcode_sicw_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dhwb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dhwb_encode_fns[] = { Opcode_dhwb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dhwbi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dhwbi_encode_fns[] = { Opcode_dhwbi_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_diwb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_diwb_encode_fns[] = { Opcode_diwb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_diwbi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_diwbi_encode_fns[] = { Opcode_diwbi_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dhi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dhi_encode_fns[] = { Opcode_dhi_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dii_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dii_encode_fns[] = { Opcode_dii_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dpfr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dpfr_encode_fns[] = { Opcode_dpfr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dpfw_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dpfw_encode_fns[] = { Opcode_dpfw_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dpfro_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dpfro_encode_fns[] = { Opcode_dpfro_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_dpfwo_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_dpfwo_encode_fns[] = { Opcode_dpfwo_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_sdct_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_sdct_encode_fns[] = { Opcode_sdct_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ldct_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ldct_encode_fns[] = { Opcode_ldct_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_ptevaddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_ptevaddr_encode_fns[] = { Opcode_wsr_ptevaddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_ptevaddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_ptevaddr_encode_fns[] = { Opcode_rsr_ptevaddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_ptevaddr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_ptevaddr_encode_fns[] = { Opcode_xsr_ptevaddr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_rasid_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_rasid_encode_fns[] = { Opcode_rsr_rasid_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_rasid_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_rasid_encode_fns[] = { Opcode_wsr_rasid_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_rasid_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_rasid_encode_fns[] = { Opcode_xsr_rasid_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_itlbcfg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_itlbcfg_encode_fns[] = { Opcode_rsr_itlbcfg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_itlbcfg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_itlbcfg_encode_fns[] = { Opcode_wsr_itlbcfg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_itlbcfg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_itlbcfg_encode_fns[] = { Opcode_xsr_itlbcfg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_dtlbcfg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_dtlbcfg_encode_fns[] = { Opcode_rsr_dtlbcfg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_dtlbcfg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_dtlbcfg_encode_fns[] = { Opcode_wsr_dtlbcfg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_dtlbcfg_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_dtlbcfg_encode_fns[] = { Opcode_xsr_dtlbcfg_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { Opcode_idtlb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { Opcode_pdtlb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { Opcode_rdtlb0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { Opcode_rdtlb1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { Opcode_wdtlb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { Opcode_iitlb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { Opcode_pitlb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { Opcode_ritlb0_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { Opcode_ritlb1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { Opcode_witlb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ldpte_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ldpte_encode_fns[] = { Opcode_ldpte_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_hwwitlba_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_hwwitlba_encode_fns[] = { Opcode_hwwitlba_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_hwwdtlba_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_hwwdtlba_encode_fns[] = { Opcode_hwwdtlba_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_cpenable_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_cpenable_encode_fns[] = { Opcode_rsr_cpenable_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_cpenable_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_cpenable_encode_fns[] = { Opcode_wsr_cpenable_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_cpenable_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_cpenable_encode_fns[] = { Opcode_xsr_cpenable_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_clamps_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_clamps_encode_fns[] = { Opcode_clamps_Slot_inst_encode, 0, 0, 0, Opcode_clamps_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_min_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_min_encode_fns[] = { Opcode_min_Slot_inst_encode, 0, 0, 0, Opcode_min_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_max_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_max_encode_fns[] = { Opcode_max_Slot_inst_encode, 0, 0, 0, Opcode_max_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_minu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_minu_encode_fns[] = { Opcode_minu_Slot_inst_encode, 0, 0, 0, Opcode_minu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_maxu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_maxu_encode_fns[] = { Opcode_maxu_Slot_inst_encode, 0, 0, 0, Opcode_maxu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { Opcode_nsa_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { Opcode_nsau_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_sext_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_sext_encode_fns[] = { Opcode_sext_Slot_inst_encode, 0, 0, 0, Opcode_sext_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_l32ai_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_l32ai_encode_fns[] = { Opcode_l32ai_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_s32ri_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_s32ri_encode_fns[] = { Opcode_s32ri_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_s32c1i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_s32c1i_encode_fns[] = { Opcode_s32c1i_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_scompare1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_scompare1_encode_fns[] = { Opcode_rsr_scompare1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_scompare1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_scompare1_encode_fns[] = { Opcode_wsr_scompare1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_scompare1_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_scompare1_encode_fns[] = { Opcode_xsr_scompare1_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rsr_atomctl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rsr_atomctl_encode_fns[] = { Opcode_rsr_atomctl_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wsr_atomctl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wsr_atomctl_encode_fns[] = { Opcode_wsr_atomctl_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_xsr_atomctl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_xsr_atomctl_encode_fns[] = { Opcode_xsr_atomctl_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rer_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rer_encode_fns[] = { Opcode_rer_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wer_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wer_encode_fns[] = { Opcode_wer_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_ovf_sar_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_ovf_sar_encode_fns[] = { Opcode_rur_ae_ovf_sar_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_ovf_sar_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_ovf_sar_encode_fns[] = { Opcode_wur_ae_ovf_sar_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_bithead_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_bithead_encode_fns[] = { Opcode_rur_ae_bithead_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_bithead_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_bithead_encode_fns[] = { Opcode_wur_ae_bithead_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_ts_fts_bu_bp_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_ts_fts_bu_bp_encode_fns[] = { Opcode_rur_ae_ts_fts_bu_bp_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_ts_fts_bu_bp_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_ts_fts_bu_bp_encode_fns[] = { Opcode_wur_ae_ts_fts_bu_bp_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_sd_no_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_sd_no_encode_fns[] = { Opcode_rur_ae_sd_no_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_sd_no_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_sd_no_encode_fns[] = { Opcode_wur_ae_sd_no_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_overflow_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_overflow_encode_fns[] = { Opcode_rur_ae_overflow_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_overflow_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_overflow_encode_fns[] = { Opcode_wur_ae_overflow_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_sar_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_sar_encode_fns[] = { Opcode_rur_ae_sar_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_sar_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_sar_encode_fns[] = { Opcode_wur_ae_sar_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_bitptr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_bitptr_encode_fns[] = { Opcode_rur_ae_bitptr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_bitptr_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_bitptr_encode_fns[] = { Opcode_wur_ae_bitptr_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_bitsused_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_bitsused_encode_fns[] = { Opcode_rur_ae_bitsused_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_bitsused_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_bitsused_encode_fns[] = { Opcode_wur_ae_bitsused_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_tablesize_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_tablesize_encode_fns[] = { Opcode_rur_ae_tablesize_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_tablesize_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_tablesize_encode_fns[] = { Opcode_wur_ae_tablesize_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_first_ts_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_first_ts_encode_fns[] = { Opcode_rur_ae_first_ts_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_first_ts_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_first_ts_encode_fns[] = { Opcode_wur_ae_first_ts_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_nextoffset_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_nextoffset_encode_fns[] = { Opcode_rur_ae_nextoffset_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_nextoffset_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_nextoffset_encode_fns[] = { Opcode_wur_ae_nextoffset_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_rur_ae_searchdone_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_rur_ae_searchdone_encode_fns[] = { Opcode_rur_ae_searchdone_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_wur_ae_searchdone_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_wur_ae_searchdone_encode_fns[] = { Opcode_wur_ae_searchdone_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_lp16f_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp16f_i_encode_fns[] = { Opcode_ae_lp16f_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp16f_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp16f_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp16f_iu_encode_fns[] = { Opcode_ae_lp16f_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp16f_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp16f_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp16f_x_encode_fns[] = { Opcode_ae_lp16f_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp16f_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp16f_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp16f_xu_encode_fns[] = { Opcode_ae_lp16f_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp16f_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24_i_encode_fns[] = { Opcode_ae_lp24_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24_iu_encode_fns[] = { Opcode_ae_lp24_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24_x_encode_fns[] = { Opcode_ae_lp24_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24_xu_encode_fns[] = { Opcode_ae_lp24_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24f_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24f_i_encode_fns[] = { Opcode_ae_lp24f_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24f_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24f_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24f_iu_encode_fns[] = { Opcode_ae_lp24f_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24f_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24f_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24f_x_encode_fns[] = { Opcode_ae_lp24f_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24f_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24f_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24f_xu_encode_fns[] = { Opcode_ae_lp24f_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24f_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp16x2f_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp16x2f_i_encode_fns[] = { Opcode_ae_lp16x2f_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp16x2f_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp16x2f_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp16x2f_iu_encode_fns[] = { Opcode_ae_lp16x2f_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp16x2f_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp16x2f_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp16x2f_x_encode_fns[] = { Opcode_ae_lp16x2f_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp16x2f_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp16x2f_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp16x2f_xu_encode_fns[] = { Opcode_ae_lp16x2f_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp16x2f_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24x2f_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24x2f_i_encode_fns[] = { Opcode_ae_lp24x2f_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24x2f_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24x2f_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24x2f_iu_encode_fns[] = { Opcode_ae_lp24x2f_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24x2f_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24x2f_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24x2f_x_encode_fns[] = { Opcode_ae_lp24x2f_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24x2f_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24x2f_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24x2f_xu_encode_fns[] = { Opcode_ae_lp24x2f_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24x2f_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24x2_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24x2_i_encode_fns[] = { Opcode_ae_lp24x2_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24x2_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24x2_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24x2_iu_encode_fns[] = { Opcode_ae_lp24x2_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24x2_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24x2_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24x2_x_encode_fns[] = { Opcode_ae_lp24x2_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24x2_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lp24x2_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lp24x2_xu_encode_fns[] = { Opcode_ae_lp24x2_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lp24x2_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp16x2f_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp16x2f_i_encode_fns[] = { Opcode_ae_sp16x2f_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp16x2f_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp16x2f_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp16x2f_iu_encode_fns[] = { Opcode_ae_sp16x2f_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp16x2f_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp16x2f_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp16x2f_x_encode_fns[] = { Opcode_ae_sp16x2f_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp16x2f_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp16x2f_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp16x2f_xu_encode_fns[] = { Opcode_ae_sp16x2f_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp16x2f_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24x2s_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24x2s_i_encode_fns[] = { Opcode_ae_sp24x2s_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24x2s_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24x2s_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24x2s_iu_encode_fns[] = { Opcode_ae_sp24x2s_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24x2s_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24x2s_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24x2s_x_encode_fns[] = { Opcode_ae_sp24x2s_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24x2s_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24x2s_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24x2s_xu_encode_fns[] = { Opcode_ae_sp24x2s_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24x2s_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24x2f_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24x2f_i_encode_fns[] = { Opcode_ae_sp24x2f_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24x2f_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24x2f_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24x2f_iu_encode_fns[] = { Opcode_ae_sp24x2f_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24x2f_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24x2f_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24x2f_x_encode_fns[] = { Opcode_ae_sp24x2f_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24x2f_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24x2f_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24x2f_xu_encode_fns[] = { Opcode_ae_sp24x2f_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24x2f_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp16f_l_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp16f_l_i_encode_fns[] = { Opcode_ae_sp16f_l_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp16f_l_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp16f_l_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp16f_l_iu_encode_fns[] = { Opcode_ae_sp16f_l_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp16f_l_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp16f_l_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp16f_l_x_encode_fns[] = { Opcode_ae_sp16f_l_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp16f_l_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp16f_l_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp16f_l_xu_encode_fns[] = { Opcode_ae_sp16f_l_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp16f_l_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24s_l_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24s_l_i_encode_fns[] = { Opcode_ae_sp24s_l_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24s_l_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24s_l_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24s_l_iu_encode_fns[] = { Opcode_ae_sp24s_l_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24s_l_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24s_l_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24s_l_x_encode_fns[] = { Opcode_ae_sp24s_l_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24s_l_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24s_l_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24s_l_xu_encode_fns[] = { Opcode_ae_sp24s_l_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24s_l_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24f_l_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24f_l_i_encode_fns[] = { Opcode_ae_sp24f_l_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24f_l_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24f_l_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24f_l_iu_encode_fns[] = { Opcode_ae_sp24f_l_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24f_l_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24f_l_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24f_l_x_encode_fns[] = { Opcode_ae_sp24f_l_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24f_l_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sp24f_l_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sp24f_l_xu_encode_fns[] = { Opcode_ae_sp24f_l_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sp24f_l_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lq56_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lq56_i_encode_fns[] = { Opcode_ae_lq56_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_lq56_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lq56_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lq56_iu_encode_fns[] = { Opcode_ae_lq56_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lq56_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lq56_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lq56_x_encode_fns[] = { Opcode_ae_lq56_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_lq56_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lq56_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lq56_xu_encode_fns[] = { Opcode_ae_lq56_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lq56_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lq32f_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lq32f_i_encode_fns[] = { Opcode_ae_lq32f_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_lq32f_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lq32f_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lq32f_iu_encode_fns[] = { Opcode_ae_lq32f_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lq32f_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lq32f_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lq32f_x_encode_fns[] = { Opcode_ae_lq32f_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_lq32f_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_lq32f_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lq32f_xu_encode_fns[] = { Opcode_ae_lq32f_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_lq32f_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sq56s_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sq56s_i_encode_fns[] = { Opcode_ae_sq56s_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_sq56s_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sq56s_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sq56s_iu_encode_fns[] = { Opcode_ae_sq56s_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sq56s_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sq56s_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sq56s_x_encode_fns[] = { Opcode_ae_sq56s_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_sq56s_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sq56s_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sq56s_xu_encode_fns[] = { Opcode_ae_sq56s_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sq56s_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sq32f_i_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sq32f_i_encode_fns[] = { Opcode_ae_sq32f_i_Slot_inst_encode, 0, 0, 0, Opcode_ae_sq32f_i_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sq32f_iu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sq32f_iu_encode_fns[] = { Opcode_ae_sq32f_iu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sq32f_iu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sq32f_x_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sq32f_x_encode_fns[] = { Opcode_ae_sq32f_x_Slot_inst_encode, 0, 0, 0, Opcode_ae_sq32f_x_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sq32f_xu_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sq32f_xu_encode_fns[] = { Opcode_ae_sq32f_xu_Slot_inst_encode, 0, 0, 0, Opcode_ae_sq32f_xu_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_zerop48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_zerop48_encode_fns[] = { 0, 0, 0, Opcode_ae_zerop48_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_movp48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movp48_encode_fns[] = { Opcode_ae_movp48_Slot_inst_encode, 0, 0, Opcode_ae_movp48_Slot_ae_slot1_encode, Opcode_ae_movp48_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_selp24_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_selp24_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_selp24_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_selp24_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_selp24_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_selp24_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_selp24_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_selp24_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_selp24_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_selp24_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_selp24_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_selp24_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_movtp24x2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movtp24x2_encode_fns[] = { 0, 0, 0, Opcode_ae_movtp24x2_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_movfp24x2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movfp24x2_encode_fns[] = { 0, 0, 0, Opcode_ae_movfp24x2_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_movtp48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movtp48_encode_fns[] = { 0, 0, 0, Opcode_ae_movtp48_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_movfp48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movfp48_encode_fns[] = { 0, 0, 0, Opcode_ae_movfp48_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_movpa24x2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movpa24x2_encode_fns[] = { Opcode_ae_movpa24x2_Slot_inst_encode, 0, 0, 0, Opcode_ae_movpa24x2_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_truncp24a32x2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_truncp24a32x2_encode_fns[] = { Opcode_ae_truncp24a32x2_Slot_inst_encode, 0, 0, 0, Opcode_ae_truncp24a32x2_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_cvta32p24_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvta32p24_l_encode_fns[] = { Opcode_ae_cvta32p24_l_Slot_inst_encode, 0, 0, 0, Opcode_ae_cvta32p24_l_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_cvta32p24_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvta32p24_h_encode_fns[] = { Opcode_ae_cvta32p24_h_Slot_inst_encode, 0, 0, 0, Opcode_ae_cvta32p24_h_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_cvtp24a16x2_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvtp24a16x2_ll_encode_fns[] = { Opcode_ae_cvtp24a16x2_ll_Slot_inst_encode, 0, 0, 0, Opcode_ae_cvtp24a16x2_ll_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_cvtp24a16x2_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvtp24a16x2_lh_encode_fns[] = { Opcode_ae_cvtp24a16x2_lh_Slot_inst_encode, 0, 0, 0, Opcode_ae_cvtp24a16x2_lh_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_cvtp24a16x2_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvtp24a16x2_hl_encode_fns[] = { Opcode_ae_cvtp24a16x2_hl_Slot_inst_encode, 0, 0, 0, Opcode_ae_cvtp24a16x2_hl_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_cvtp24a16x2_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvtp24a16x2_hh_encode_fns[] = { Opcode_ae_cvtp24a16x2_hh_Slot_inst_encode, 0, 0, 0, Opcode_ae_cvtp24a16x2_hh_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_truncp24q48x2_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_truncp24q48x2_encode_fns[] = { 0, 0, 0, Opcode_ae_truncp24q48x2_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_truncp16_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_truncp16_encode_fns[] = { 0, 0, 0, Opcode_ae_truncp16_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_roundsp24q48sym_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_roundsp24q48sym_encode_fns[] = { 0, 0, 0, Opcode_ae_roundsp24q48sym_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_roundsp24q48asym_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_roundsp24q48asym_encode_fns[] = { 0, 0, 0, Opcode_ae_roundsp24q48asym_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_roundsp16q48sym_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_roundsp16q48sym_encode_fns[] = { 0, 0, 0, Opcode_ae_roundsp16q48sym_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_roundsp16q48asym_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_roundsp16q48asym_encode_fns[] = { 0, 0, 0, Opcode_ae_roundsp16q48asym_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_roundsp16sym_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_roundsp16sym_encode_fns[] = { 0, 0, 0, Opcode_ae_roundsp16sym_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_roundsp16asym_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_roundsp16asym_encode_fns[] = { 0, 0, 0, Opcode_ae_roundsp16asym_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_zeroq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_zeroq56_encode_fns[] = { 0, 0, 0, Opcode_ae_zeroq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_movq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movq56_encode_fns[] = { Opcode_ae_movq56_Slot_inst_encode, 0, 0, Opcode_ae_movq56_Slot_ae_slot1_encode, Opcode_ae_movq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_movtq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movtq56_encode_fns[] = { Opcode_ae_movtq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_movtq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_movfq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movfq56_encode_fns[] = { Opcode_ae_movfq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_movfq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_cvtq48a32s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvtq48a32s_encode_fns[] = { Opcode_ae_cvtq48a32s_Slot_inst_encode, 0, 0, 0, Opcode_ae_cvtq48a32s_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_cvtq48p24s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvtq48p24s_l_encode_fns[] = { 0, 0, 0, Opcode_ae_cvtq48p24s_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_cvtq48p24s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_cvtq48p24s_h_encode_fns[] = { 0, 0, 0, Opcode_ae_cvtq48p24s_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_satq48s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_satq48s_encode_fns[] = { 0, 0, 0, Opcode_ae_satq48s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_truncq32_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_truncq32_encode_fns[] = { 0, 0, 0, Opcode_ae_truncq32_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_roundsq32sym_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_roundsq32sym_encode_fns[] = { 0, 0, 0, Opcode_ae_roundsq32sym_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_roundsq32asym_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_roundsq32asym_encode_fns[] = { 0, 0, 0, Opcode_ae_roundsq32asym_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_trunca32q48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_trunca32q48_encode_fns[] = { Opcode_ae_trunca32q48_Slot_inst_encode, 0, 0, 0, Opcode_ae_trunca32q48_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_movap24s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movap24s_l_encode_fns[] = { Opcode_ae_movap24s_l_Slot_inst_encode, 0, 0, 0, Opcode_ae_movap24s_l_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_movap24s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_movap24s_h_encode_fns[] = { Opcode_ae_movap24s_h_Slot_inst_encode, 0, 0, 0, Opcode_ae_movap24s_h_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_trunca16p24s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_trunca16p24s_l_encode_fns[] = { Opcode_ae_trunca16p24s_l_Slot_inst_encode, 0, 0, 0, Opcode_ae_trunca16p24s_l_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_trunca16p24s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_trunca16p24s_h_encode_fns[] = { Opcode_ae_trunca16p24s_h_Slot_inst_encode, 0, 0, 0, Opcode_ae_trunca16p24s_h_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_addp24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_addp24_encode_fns[] = { 0, 0, 0, Opcode_ae_addp24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_subp24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_subp24_encode_fns[] = { 0, 0, 0, Opcode_ae_subp24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_negp24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_negp24_encode_fns[] = { 0, 0, 0, Opcode_ae_negp24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_absp24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_absp24_encode_fns[] = { 0, 0, 0, Opcode_ae_absp24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_maxp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_maxp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_maxp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_minp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_minp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_minp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_maxbp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_maxbp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_maxbp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_minbp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_minbp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_minbp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_addsp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_addsp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_addsp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_subsp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_subsp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_subsp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_negsp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_negsp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_negsp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_abssp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_abssp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_abssp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_andp48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_andp48_encode_fns[] = { 0, 0, 0, Opcode_ae_andp48_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_nandp48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_nandp48_encode_fns[] = { 0, 0, 0, Opcode_ae_nandp48_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_orp48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_orp48_encode_fns[] = { 0, 0, 0, Opcode_ae_orp48_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_xorp48_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_xorp48_encode_fns[] = { 0, 0, 0, Opcode_ae_xorp48_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_ltp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_ltp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_ltp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_lep24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lep24s_encode_fns[] = { 0, 0, 0, Opcode_ae_lep24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_eqp24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_eqp24_encode_fns[] = { 0, 0, 0, Opcode_ae_eqp24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_addq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_addq56_encode_fns[] = { 0, 0, 0, Opcode_ae_addq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_subq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_subq56_encode_fns[] = { 0, 0, 0, Opcode_ae_subq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_negq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_negq56_encode_fns[] = { 0, 0, 0, Opcode_ae_negq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_absq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_absq56_encode_fns[] = { 0, 0, 0, Opcode_ae_absq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_maxq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_maxq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_maxq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_minq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_minq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_minq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_maxbq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_maxbq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_maxbq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_minbq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_minbq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_minbq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_addsq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_addsq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_addsq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_subsq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_subsq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_subsq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_negsq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_negsq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_negsq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_abssq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_abssq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_abssq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_andq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_andq56_encode_fns[] = { 0, 0, 0, Opcode_ae_andq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_nandq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_nandq56_encode_fns[] = { 0, 0, 0, Opcode_ae_nandq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_orq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_orq56_encode_fns[] = { 0, 0, 0, Opcode_ae_orq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_xorq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_xorq56_encode_fns[] = { 0, 0, 0, Opcode_ae_xorq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sllip24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllip24_encode_fns[] = { 0, 0, 0, Opcode_ae_sllip24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_srlip24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_srlip24_encode_fns[] = { 0, 0, 0, Opcode_ae_srlip24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sraip24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sraip24_encode_fns[] = { 0, 0, 0, Opcode_ae_sraip24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sllsp24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllsp24_encode_fns[] = { 0, 0, 0, Opcode_ae_sllsp24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_srlsp24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_srlsp24_encode_fns[] = { 0, 0, 0, Opcode_ae_srlsp24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_srasp24_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_srasp24_encode_fns[] = { 0, 0, 0, Opcode_ae_srasp24_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sllisp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllisp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_sllisp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sllssp24s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllssp24s_encode_fns[] = { 0, 0, 0, Opcode_ae_sllssp24s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_slliq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_slliq56_encode_fns[] = { Opcode_ae_slliq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_slliq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_srliq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_srliq56_encode_fns[] = { Opcode_ae_srliq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_srliq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sraiq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sraiq56_encode_fns[] = { Opcode_ae_sraiq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_sraiq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sllsq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllsq56_encode_fns[] = { Opcode_ae_sllsq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_sllsq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_srlsq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_srlsq56_encode_fns[] = { Opcode_ae_srlsq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_srlsq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_srasq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_srasq56_encode_fns[] = { Opcode_ae_srasq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_srasq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sllaq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllaq56_encode_fns[] = { Opcode_ae_sllaq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_sllaq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_srlaq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_srlaq56_encode_fns[] = { Opcode_ae_srlaq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_srlaq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sraaq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sraaq56_encode_fns[] = { Opcode_ae_sraaq56_Slot_inst_encode, 0, 0, 0, Opcode_ae_sraaq56_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sllisq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllisq56s_encode_fns[] = { Opcode_ae_sllisq56s_Slot_inst_encode, 0, 0, 0, Opcode_ae_sllisq56s_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sllssq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllssq56s_encode_fns[] = { Opcode_ae_sllssq56s_Slot_inst_encode, 0, 0, 0, Opcode_ae_sllssq56s_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_sllasq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sllasq56s_encode_fns[] = { Opcode_ae_sllasq56s_Slot_inst_encode, 0, 0, 0, Opcode_ae_sllasq56s_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_ltq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_ltq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_ltq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_leq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_leq56s_encode_fns[] = { 0, 0, 0, Opcode_ae_leq56s_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_eqq56_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_eqq56_encode_fns[] = { 0, 0, 0, Opcode_ae_eqq56_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_nsaq56s_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_nsaq56s_encode_fns[] = { Opcode_ae_nsaq56s_Slot_inst_encode, 0, 0, 0, Opcode_ae_nsaq56s_Slot_ae_slot0_encode }; -xtensa_opcode_encode_fn Opcode_ae_mulfs32p16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfs32p16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfs32p16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfp24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfp24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfp24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulp24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulp24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulp24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfs32p16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfs32p16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfs32p16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfp24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfp24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfp24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulp24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulp24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulp24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfs32p16s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfs32p16s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfs32p16s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfp24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfp24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfp24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulp24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulp24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulp24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfs32p16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfs32p16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfs32p16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfp24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfp24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfp24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulp24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulp24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulp24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafs32p16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafs32p16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafs32p16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafp24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafp24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafp24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulap24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulap24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulap24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafs32p16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafs32p16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafs32p16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafp24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafp24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafp24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulap24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulap24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulap24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafs32p16s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafs32p16s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafs32p16s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafp24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafp24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafp24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulap24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulap24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulap24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafs32p16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafs32p16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafs32p16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafp24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafp24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafp24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulap24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulap24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulap24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfs32p16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfs32p16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfs32p16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfp24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfp24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfp24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsp24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsp24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsp24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfs32p16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfs32p16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfs32p16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfp24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfp24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfp24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsp24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsp24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsp24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfs32p16s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfs32p16s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfs32p16s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfp24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfp24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfp24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsp24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsp24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsp24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfs32p16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfs32p16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfs32p16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfp24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfp24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfp24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsp24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsp24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsp24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafs56p24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafs56p24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafs56p24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulas56p24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulas56p24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulas56p24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafs56p24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafs56p24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafs56p24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulas56p24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulas56p24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulas56p24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafs56p24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafs56p24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafs56p24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulas56p24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulas56p24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulas56p24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafs56p24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafs56p24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafs56p24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulas56p24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulas56p24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulas56p24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfs56p24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfs56p24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfs56p24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulss56p24s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulss56p24s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulss56p24s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfs56p24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfs56p24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfs56p24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulss56p24s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulss56p24s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulss56p24s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfs56p24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfs56p24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfs56p24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulss56p24s_hl_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulss56p24s_hl_encode_fns[] = { 0, 0, 0, Opcode_ae_mulss56p24s_hl_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfs56p24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfs56p24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfs56p24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulss56p24s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulss56p24s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulss56p24s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfq32sp16s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfq32sp16s_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfq32sp16s_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfq32sp16s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfq32sp16s_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfq32sp16s_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfq32sp16u_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfq32sp16u_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfq32sp16u_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulfq32sp16u_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulfq32sp16u_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulfq32sp16u_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulq32sp16s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulq32sp16s_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulq32sp16s_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulq32sp16s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulq32sp16s_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulq32sp16s_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulq32sp16u_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulq32sp16u_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulq32sp16u_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulq32sp16u_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulq32sp16u_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulq32sp16u_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafq32sp16s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafq32sp16s_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafq32sp16s_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafq32sp16s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafq32sp16s_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafq32sp16s_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafq32sp16u_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafq32sp16u_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafq32sp16u_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulafq32sp16u_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulafq32sp16u_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulafq32sp16u_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulaq32sp16s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulaq32sp16s_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulaq32sp16s_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulaq32sp16s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulaq32sp16s_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulaq32sp16s_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulaq32sp16u_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulaq32sp16u_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulaq32sp16u_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulaq32sp16u_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulaq32sp16u_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulaq32sp16u_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfq32sp16s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfq32sp16s_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfq32sp16s_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfq32sp16s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfq32sp16s_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfq32sp16s_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfq32sp16u_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfq32sp16u_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfq32sp16u_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsfq32sp16u_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsfq32sp16u_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsfq32sp16u_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsq32sp16s_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsq32sp16s_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsq32sp16s_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsq32sp16s_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsq32sp16s_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsq32sp16s_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsq32sp16u_l_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsq32sp16u_l_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsq32sp16u_l_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsq32sp16u_h_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsq32sp16u_h_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsq32sp16u_h_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaaq32sp16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaafq32sp16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16u_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16u_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaaq32sp16u_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16u_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16u_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaafq32sp16u_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaaq32sp16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaafq32sp16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16u_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16u_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaaq32sp16u_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16u_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16u_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaafq32sp16u_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaaq32sp16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaafq32sp16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16u_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaaq32sp16u_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaaq32sp16u_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16u_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaafq32sp16u_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaafq32sp16u_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasq32sp16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasfq32sp16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16u_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16u_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasq32sp16u_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16u_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16u_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasfq32sp16u_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasq32sp16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasfq32sp16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16u_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16u_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasq32sp16u_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16u_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16u_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasfq32sp16u_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasq32sp16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasfq32sp16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16u_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasq32sp16u_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasq32sp16u_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16u_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasfq32sp16u_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasfq32sp16u_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsaq32sp16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsafq32sp16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16u_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16u_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsaq32sp16u_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16u_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16u_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsafq32sp16u_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsaq32sp16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsafq32sp16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16u_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16u_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsaq32sp16u_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16u_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16u_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsafq32sp16u_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsaq32sp16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsafq32sp16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16u_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsaq32sp16u_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsaq32sp16u_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16u_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsafq32sp16u_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsafq32sp16u_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssq32sp16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16s_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16s_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssfq32sp16s_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16u_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16u_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssq32sp16u_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16u_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16u_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssfq32sp16u_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssq32sp16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16s_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16s_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssfq32sp16s_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16u_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16u_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssq32sp16u_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16u_hh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16u_hh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssfq32sp16u_hh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssq32sp16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16s_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16s_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssfq32sp16s_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16u_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssq32sp16u_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssq32sp16u_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16u_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssfq32sp16u_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssfq32sp16u_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaafp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaafp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaafp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaap24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaap24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaap24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaafp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaafp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaafp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzaap24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzaap24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzaap24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasfp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasfp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasfp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasfp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasfp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasfp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzasp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzasp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzasp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsafp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsafp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsafp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsap24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsap24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsap24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsafp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsafp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsafp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzsap24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzsap24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzsap24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssfp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssfp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssfp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssfp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssfp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssfp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulzssp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulzssp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulzssp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulaafp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulaafp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulaafp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulaap24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulaap24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulaap24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulaafp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulaafp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulaafp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulaap24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulaap24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulaap24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulasfp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulasfp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulasfp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulasp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulasp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulasp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulasfp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulasfp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulasfp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulasp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulasp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulasp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsafp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsafp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsafp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsap24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsap24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsap24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsafp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsafp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsafp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulsap24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulsap24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulsap24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulssfp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulssfp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulssfp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulssp24s_hh_ll_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulssp24s_hh_ll_encode_fns[] = { 0, 0, 0, Opcode_ae_mulssp24s_hh_ll_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulssfp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulssfp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulssfp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_mulssp24s_hl_lh_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_mulssp24s_hl_lh_encode_fns[] = { 0, 0, 0, Opcode_ae_mulssp24s_hl_lh_Slot_ae_slot1_encode, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sha32_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sha32_encode_fns[] = { Opcode_ae_sha32_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_vldl32t_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_vldl32t_encode_fns[] = { Opcode_ae_vldl32t_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_vldl16t_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_vldl16t_encode_fns[] = { Opcode_ae_vldl16t_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_vldl16c_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_vldl16c_encode_fns[] = { Opcode_ae_vldl16c_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_vldsht_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_vldsht_encode_fns[] = { Opcode_ae_vldsht_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_lb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lb_encode_fns[] = { Opcode_ae_lb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_lbi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lbi_encode_fns[] = { Opcode_ae_lbi_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_lbk_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lbk_encode_fns[] = { Opcode_ae_lbk_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_lbki_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_lbki_encode_fns[] = { Opcode_ae_lbki_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_db_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_db_encode_fns[] = { Opcode_ae_db_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_dbi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_dbi_encode_fns[] = { Opcode_ae_dbi_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_vlel32t_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_vlel32t_encode_fns[] = { Opcode_ae_vlel32t_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_vlel16t_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_vlel16t_encode_fns[] = { Opcode_ae_vlel16t_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sb_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sb_encode_fns[] = { Opcode_ae_sb_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sbi_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sbi_encode_fns[] = { Opcode_ae_sbi_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_vles16c_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_vles16c_encode_fns[] = { Opcode_ae_vles16c_Slot_inst_encode, 0, 0, 0, 0 }; -xtensa_opcode_encode_fn Opcode_ae_sbf_encode_fns[] = { +static xtensa_opcode_encode_fn Opcode_ae_sbf_encode_fns[] = { Opcode_ae_sbf_Slot_inst_encode, 0, 0, 0, 0 }; @@ -30818,7 +30818,7 @@ Slot_inst_decode (const xtensa_insnbuf insn) } break; } - return 0; + return XTENSA_UNDEFINED; } static int @@ -30869,7 +30869,7 @@ Slot_inst16b_decode (const xtensa_insnbuf insn) } break; } - return 0; + return XTENSA_UNDEFINED; } static int @@ -30886,7 +30886,7 @@ Slot_inst16a_decode (const xtensa_insnbuf insn) case 11: return OPCODE_ADDI_N; } - return 0; + return XTENSA_UNDEFINED; } static int @@ -31561,7 +31561,7 @@ Slot_ae_slot0_decode (const xtensa_insnbuf insn) return OPCODE_BF; break; } - return 0; + return XTENSA_UNDEFINED; } static int @@ -32279,7 +32279,7 @@ Slot_ae_slot1_decode (const xtensa_insnbuf insn) return OPCODE_AE_MULZSSQ32SP16U_LL; break; } - return 0; + return XTENSA_UNDEFINED; } diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index b665bfc006..4d8152682f 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -131,6 +131,7 @@ enum { ACCLO = 16, ACCHI = 17, MR = 32, + PREFCTL = 40, WINDOW_BASE = 72, WINDOW_START = 73, PTEVADDR = 83, @@ -345,14 +346,21 @@ typedef struct XtensaMemory { } location[MAX_NMEMORY]; } XtensaMemory; +typedef struct opcode_arg { + uint32_t imm; + uint32_t raw_imm; + void *in; + void *out; +} OpcodeArg; + typedef struct DisasContext DisasContext; -typedef void (*XtensaOpcodeOp)(DisasContext *dc, const uint32_t arg[], +typedef void (*XtensaOpcodeOp)(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]); typedef bool (*XtensaOpcodeBoolTest)(DisasContext *dc, - const uint32_t arg[], + const OpcodeArg arg[], const uint32_t par[]); typedef uint32_t (*XtensaOpcodeUintTest)(DisasContext *dc, - const uint32_t arg[], + const OpcodeArg arg[], const uint32_t par[]); enum { @@ -368,19 +376,34 @@ enum { XTENSA_OP_DIVIDE_BY_ZERO = 0x100, + /* Postprocessing flags */ XTENSA_OP_CHECK_INTERRUPTS = 0x200, XTENSA_OP_EXIT_TB_M1 = 0x400, XTENSA_OP_EXIT_TB_0 = 0x800, + XTENSA_OP_SYNC_REGISTER_WINDOW = 0x1000, + + XTENSA_OP_POSTPROCESS = + XTENSA_OP_CHECK_INTERRUPTS | + XTENSA_OP_EXIT_TB_M1 | + XTENSA_OP_EXIT_TB_0 | + XTENSA_OP_SYNC_REGISTER_WINDOW, + + XTENSA_OP_NAME_ARRAY = 0x8000, + + XTENSA_OP_CONTROL_FLOW = 0x10000, + XTENSA_OP_STORE = 0x20000, + XTENSA_OP_LOAD = 0x40000, + XTENSA_OP_LOAD_STORE = + XTENSA_OP_LOAD | XTENSA_OP_STORE, }; typedef struct XtensaOpcodeOps { - const char *name; + const void *name; XtensaOpcodeOp translate; XtensaOpcodeBoolTest test_ill; XtensaOpcodeUintTest test_overflow; const uint32_t *par; uint32_t op_flags; - uint32_t windowed_register_op; uint32_t coprocessor; } XtensaOpcodeOps; @@ -438,6 +461,8 @@ struct XtensaConfig { xtensa_isa isa; XtensaOpcodeOps **opcode_ops; const XtensaOpcodeTranslators **opcode_translators; + xtensa_regfile a_regfile; + void ***regfile; uint32_t clock_freq_khz; @@ -474,6 +499,7 @@ typedef struct CPUXtensaState { float64 f64; } fregs[16]; float_status fp_status; + uint32_t windowbase_next; #ifndef CONFIG_USER_ONLY xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE]; @@ -565,8 +591,8 @@ void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, XTENSA_CPU_TYPE_NAME(XTENSA_DEFAULT_CPU_NOMMU_MODEL) void xtensa_translate_init(void); +void **xtensa_get_regfile_by_name(const char *name); void xtensa_breakpoint_handler(CPUState *cs); -void xtensa_finalize_config(XtensaConfig *config); void xtensa_register_core(XtensaConfigList *node); void xtensa_sim_open_console(Chardev *chr); void check_interrupts(CPUXtensaState *s); @@ -588,8 +614,6 @@ static inline void xtensa_select_static_vectors(CPUXtensaState *env, env->static_vectors = n; } void xtensa_runstall(CPUXtensaState *env, bool runstall); -XtensaOpcodeOps *xtensa_find_opcode_ops(const XtensaOpcodeTranslators *t, - const char *opcode); #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) #define XTENSA_OPTION_ALL (~(uint64_t)0) diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index bcf2f20d48..f4867a9b56 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -30,24 +30,60 @@ #include "exec/exec-all.h" #include "exec/gdbstub.h" #include "exec/helper-proto.h" +#include "qemu/error-report.h" #include "qemu/host-utils.h" static struct XtensaConfigList *xtensa_cores; -static void xtensa_core_class_init(ObjectClass *oc, void *data) +static void add_translator_to_hash(GHashTable *translator, + const char *name, + const XtensaOpcodeOps *opcode) { - CPUClass *cc = CPU_CLASS(oc); - XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc); - const XtensaConfig *config = data; + if (!g_hash_table_insert(translator, (void *)name, (void *)opcode)) { + error_report("Multiple definitions of '%s' opcode in a single table", + name); + } +} - xcc->config = config; +static GHashTable *hash_opcode_translators(const XtensaOpcodeTranslators *t) +{ + unsigned i, j; + GHashTable *translator = g_hash_table_new(g_str_hash, g_str_equal); - /* Use num_core_regs to see only non-privileged registers in an unmodified - * gdb. Use num_regs to see all registers. gdb modification is required - * for that: reset bit 0 in the 'flags' field of the registers definitions - * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay. - */ - cc->gdb_num_core_regs = config->gdb_regmap.num_regs; + for (i = 0; i < t->num_opcodes; ++i) { + if (t->opcode[i].op_flags & XTENSA_OP_NAME_ARRAY) { + const char * const *name = t->opcode[i].name; + + for (j = 0; name[j]; ++j) { + add_translator_to_hash(translator, + (void *)name[j], + (void *)(t->opcode + i)); + } + } else { + add_translator_to_hash(translator, + (void *)t->opcode[i].name, + (void *)(t->opcode + i)); + } + } + return translator; +} + +static XtensaOpcodeOps * +xtensa_find_opcode_ops(const XtensaOpcodeTranslators *t, + const char *name) +{ + static GHashTable *translators; + GHashTable *translator; + + if (translators == NULL) { + translators = g_hash_table_new(g_direct_hash, g_direct_equal); + } + translator = g_hash_table_lookup(translators, t); + if (translator == NULL) { + translator = hash_opcode_translators(t); + g_hash_table_insert(translators, (void *)t, translator); + } + return g_hash_table_lookup(translator, name); } static void init_libisa(XtensaConfig *config) @@ -55,11 +91,13 @@ static void init_libisa(XtensaConfig *config) unsigned i, j; unsigned opcodes; unsigned formats; + unsigned regfiles; config->isa = xtensa_isa_init(config->isa_internal, NULL, NULL); assert(xtensa_isa_maxlength(config->isa) <= MAX_INSN_LENGTH); opcodes = xtensa_isa_num_opcodes(config->isa); formats = xtensa_isa_num_formats(config->isa); + regfiles = xtensa_isa_num_regfiles(config->isa); config->opcode_ops = g_new(XtensaOpcodeOps *, opcodes); for (i = 0; i < formats; ++i) { @@ -88,9 +126,23 @@ static void init_libisa(XtensaConfig *config) #endif config->opcode_ops[i] = ops; } + config->a_regfile = xtensa_regfile_lookup(config->isa, "AR"); + + config->regfile = g_new(void **, regfiles); + for (i = 0; i < regfiles; ++i) { + const char *name = xtensa_regfile_name(config->isa, i); + + config->regfile[i] = xtensa_get_regfile_by_name(name); +#ifdef DEBUG + if (config->regfile[i] == NULL) { + fprintf(stderr, "regfile '%s' not found for %s\n", + name, config->name); + } +#endif + } } -void xtensa_finalize_config(XtensaConfig *config) +static void xtensa_finalize_config(XtensaConfig *config) { if (config->isa_internal) { init_libisa(config); @@ -111,6 +163,24 @@ void xtensa_finalize_config(XtensaConfig *config) } } +static void xtensa_core_class_init(ObjectClass *oc, void *data) +{ + CPUClass *cc = CPU_CLASS(oc); + XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc); + XtensaConfig *config = data; + + xtensa_finalize_config(config); + xcc->config = config; + + /* + * Use num_core_regs to see only non-privileged registers in an unmodified + * gdb. Use num_regs to see all registers. gdb modification is required + * for that: reset bit 0 in the 'flags' field of the registers definitions + * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay. + */ + cc->gdb_num_core_regs = config->gdb_regmap.num_regs; +} + void xtensa_register_core(XtensaConfigList *node) { TypeInfo type = { diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h index 2a7db35874..0b9ec670c8 100644 --- a/target/xtensa/helper.h +++ b/target/xtensa/helper.h @@ -3,12 +3,11 @@ DEF_HELPER_3(exception_cause, noreturn, env, i32, i32) DEF_HELPER_4(exception_cause_vaddr, noreturn, env, i32, i32, i32) DEF_HELPER_3(debug_exception, noreturn, env, i32, i32) -DEF_HELPER_2(wsr_windowbase, void, env, i32) +DEF_HELPER_1(sync_windowbase, void, env) DEF_HELPER_4(entry, void, env, i32, i32, i32) DEF_HELPER_2(test_ill_retw, void, env, i32) DEF_HELPER_2(test_underflow_retw, void, env, i32) -DEF_HELPER_2(retw, i32, env, i32) -DEF_HELPER_2(rotw, void, env, i32) +DEF_HELPER_2(retw, void, env, i32) DEF_HELPER_3(window_check, noreturn, env, i32, i32) DEF_HELPER_1(restore_owb, void, env) DEF_HELPER_2(movsp, void, env, i32) diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh index 039406bf28..e4a2e39f63 100755 --- a/target/xtensa/import_core.sh +++ b/target/xtensa/import_core.sh @@ -27,7 +27,7 @@ tar -xf "$OVERLAY" -O gdb/xtensa-config.c | \ # Fix up known issues in the xtensa-modules.c # tar -xf "$OVERLAY" -O binutils/xtensa-modules.c | \ - sed -e 's/\(xtensa_opcode_encode_fn.*\[\] =\)/static \1/' \ + sed -e 's/^\(xtensa_opcode_encode_fn.*\[\] =\)/static \1/' \ -e '/^int num_bypass_groups()/,/}/d' \ -e '/^int num_bypass_group_chunks()/,/}/d' \ -e '/^uint32 \*bypass_entry(int i)/,/}/d' \ diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h index 12609a0d0c..ea07576bc9 100644 --- a/target/xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h @@ -377,7 +377,6 @@ static XtensaConfigList node = { \ .config = &core, \ }; \ - xtensa_finalize_config(&core); \ xtensa_register_core(&node); \ } #else diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index d1e9f59b31..77bc04d6b0 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -71,7 +71,7 @@ struct DisasContext { unsigned cpenable; - uint32_t *raw_arg; + uint32_t op_flags; xtensa_insnbuf insnbuf; xtensa_insnbuf slotbuf; }; @@ -79,8 +79,15 @@ struct DisasContext { static TCGv_i32 cpu_pc; static TCGv_i32 cpu_R[16]; static TCGv_i32 cpu_FR[16]; +static TCGv_i32 cpu_MR[4]; +static TCGv_i32 cpu_BR[16]; +static TCGv_i32 cpu_BR4[4]; +static TCGv_i32 cpu_BR8[2]; static TCGv_i32 cpu_SR[256]; static TCGv_i32 cpu_UR[256]; +static TCGv_i32 cpu_windowbase_next; + +static GHashTable *xtensa_regfile_table; #include "exec/gen-icount.h" @@ -127,6 +134,7 @@ static const XtensaReg sregnames[256] = { [MR + 1] = XTENSA_REG("MR1", XTENSA_OPTION_MAC16), [MR + 2] = XTENSA_REG("MR2", XTENSA_OPTION_MAC16), [MR + 3] = XTENSA_REG("MR3", XTENSA_OPTION_MAC16), + [PREFCTL] = XTENSA_REG_BITS("PREFCTL", XTENSA_OPTION_ALL), [WINDOW_BASE] = XTENSA_REG("WINDOW_BASE", XTENSA_OPTION_WINDOWED_REGISTER), [WINDOW_START] = XTENSA_REG("WINDOW_START", XTENSA_OPTION_WINDOWED_REGISTER), @@ -220,6 +228,15 @@ void xtensa_translate_init(void) "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", }; + static const char * const mregnames[] = { + "m0", "m1", "m2", "m3", + }; + static const char * const bregnames[] = { + "b0", "b1", "b2", "b3", + "b4", "b5", "b6", "b7", + "b8", "b9", "b10", "b11", + "b12", "b13", "b14", "b15", + }; int i; cpu_pc = tcg_global_mem_new_i32(cpu_env, @@ -227,14 +244,41 @@ void xtensa_translate_init(void) for (i = 0; i < 16; i++) { cpu_R[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUXtensaState, regs[i]), - regnames[i]); + offsetof(CPUXtensaState, regs[i]), + regnames[i]); } for (i = 0; i < 16; i++) { cpu_FR[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUXtensaState, fregs[i].f32[FP_F32_LOW]), - fregnames[i]); + offsetof(CPUXtensaState, + fregs[i].f32[FP_F32_LOW]), + fregnames[i]); + } + + for (i = 0; i < 4; i++) { + cpu_MR[i] = tcg_global_mem_new_i32(cpu_env, + offsetof(CPUXtensaState, + sregs[MR + i]), + mregnames[i]); + } + + for (i = 0; i < 16; i++) { + cpu_BR[i] = tcg_global_mem_new_i32(cpu_env, + offsetof(CPUXtensaState, + sregs[BR]), + bregnames[i]); + if (i % 4 == 0) { + cpu_BR4[i / 4] = tcg_global_mem_new_i32(cpu_env, + offsetof(CPUXtensaState, + sregs[BR]), + bregnames[i]); + } + if (i % 8 == 0) { + cpu_BR8[i / 8] = tcg_global_mem_new_i32(cpu_env, + offsetof(CPUXtensaState, + sregs[BR]), + bregnames[i]); + } } for (i = 0; i < 256; ++i) { @@ -252,6 +296,31 @@ void xtensa_translate_init(void) uregnames[i].name); } } + + cpu_windowbase_next = + tcg_global_mem_new_i32(cpu_env, + offsetof(CPUXtensaState, windowbase_next), + "windowbase_next"); +} + +void **xtensa_get_regfile_by_name(const char *name) +{ + if (xtensa_regfile_table == NULL) { + xtensa_regfile_table = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(xtensa_regfile_table, + (void *)"AR", (void *)cpu_R); + g_hash_table_insert(xtensa_regfile_table, + (void *)"MR", (void *)cpu_MR); + g_hash_table_insert(xtensa_regfile_table, + (void *)"FR", (void *)cpu_FR); + g_hash_table_insert(xtensa_regfile_table, + (void *)"BR", (void *)cpu_BR); + g_hash_table_insert(xtensa_regfile_table, + (void *)"BR4", (void *)cpu_BR4); + g_hash_table_insert(xtensa_regfile_table, + (void *)"BR8", (void *)cpu_BR8); + } + return (void **)g_hash_table_lookup(xtensa_regfile_table, (void *)name); } static inline bool option_enabled(DisasContext *dc, int opt) @@ -363,6 +432,8 @@ static bool gen_check_cpenable(DisasContext *dc, uint32_t cp_mask) return true; } +static int gen_postprocess(DisasContext *dc, int slot); + static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot) { tcg_gen_mov_i32(cpu_pc, dest); @@ -372,6 +443,9 @@ static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot) if (dc->base.singlestep_enabled) { gen_exception(dc, EXCP_DEBUG); } else { + if (dc->op_flags & XTENSA_OP_POSTPROCESS) { + slot = gen_postprocess(dc, slot); + } if (slot >= 0) { tcg_gen_goto_tb(slot); tcg_gen_exit_tb(dc->base.tb, slot); @@ -387,13 +461,19 @@ static void gen_jump(DisasContext *dc, TCGv dest) gen_jump_slot(dc, dest, -1); } -static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot) +static int adjust_jump_slot(DisasContext *dc, uint32_t dest, int slot) { - TCGv_i32 tmp = tcg_const_i32(dest); if (((dc->base.pc_first ^ dest) & TARGET_PAGE_MASK) != 0) { - slot = -1; + return -1; + } else { + return slot; } - gen_jump_slot(dc, tmp, slot); +} + +static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot) +{ + TCGv_i32 tmp = tcg_const_i32(dest); + gen_jump_slot(dc, tmp, adjust_jump_slot(dc, dest, slot)); tcg_temp_free(tmp); } @@ -410,21 +490,6 @@ static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest, gen_jump_slot(dc, dest, slot); } -static void gen_callw(DisasContext *dc, int callinc, TCGv_i32 dest) -{ - gen_callw_slot(dc, callinc, dest, -1); -} - -static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot) -{ - TCGv_i32 tmp = tcg_const_i32(dest); - if (((dc->base.pc_first ^ dest) & TARGET_PAGE_MASK) != 0) { - slot = -1; - } - gen_callw_slot(dc, callinc, tmp, slot); - tcg_temp_free(tmp); -} - static bool gen_check_loop_end(DisasContext *dc, int slot) { if (dc->base.pc_next == dc->lend) { @@ -560,7 +625,7 @@ static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s) #ifndef CONFIG_USER_ONLY static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v) { - gen_helper_wsr_windowbase(cpu_env, v); + tcg_gen_mov_i32(cpu_windowbase_next, v); } static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v) @@ -841,11 +906,11 @@ static TCGv_i32 gen_mac16_m(TCGv_i32 v, bool hi, bool is_unsigned) return m; } -static void gen_zero_check(DisasContext *dc, const uint32_t arg[]) +static void gen_zero_check(DisasContext *dc, const OpcodeArg arg[]) { TCGLabel *label = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[arg[2]], 0, label); + tcg_gen_brcondi_i32(TCG_COND_NE, arg[2].in, 0, label); gen_exception_cause(dc, INTEGER_DIVIDE_BY_ZERO_CAUSE); gen_set_label(label); } @@ -855,6 +920,270 @@ static inline unsigned xtensa_op0_insn_len(DisasContext *dc, uint8_t op0) return xtensa_isa_length_from_chars(dc->config->isa, &op0); } +static int gen_postprocess(DisasContext *dc, int slot) +{ + uint32_t op_flags = dc->op_flags; + + if (op_flags & XTENSA_OP_CHECK_INTERRUPTS) { + gen_check_interrupts(dc); + } + if (op_flags & XTENSA_OP_SYNC_REGISTER_WINDOW) { + gen_helper_sync_windowbase(cpu_env); + } + if (op_flags & XTENSA_OP_EXIT_TB_M1) { + slot = -1; + } + return slot; +} + +struct opcode_arg_copy { + uint32_t resource; + void *temp; + OpcodeArg *arg; +}; + +struct opcode_arg_info { + uint32_t resource; + int index; +}; + +struct slot_prop { + XtensaOpcodeOps *ops; + OpcodeArg arg[MAX_OPCODE_ARGS]; + struct opcode_arg_info in[MAX_OPCODE_ARGS]; + struct opcode_arg_info out[MAX_OPCODE_ARGS]; + unsigned n_in; + unsigned n_out; + uint32_t op_flags; +}; + +enum resource_type { + RES_REGFILE, + RES_STATE, + RES_MAX, +}; + +static uint32_t encode_resource(enum resource_type r, unsigned g, unsigned n) +{ + assert(r < RES_MAX && g < 256 && n < 65536); + return (r << 24) | (g << 16) | n; +} + +static enum resource_type get_resource_type(uint32_t resource) +{ + return resource >> 24; +} + +/* + * a depends on b if b must be executed before a, + * because a's side effects will destroy b's inputs. + */ +static bool op_depends_on(const struct slot_prop *a, + const struct slot_prop *b) +{ + unsigned i = 0; + unsigned j = 0; + + if (a->op_flags & XTENSA_OP_CONTROL_FLOW) { + return true; + } + if ((a->op_flags & XTENSA_OP_LOAD_STORE) < + (b->op_flags & XTENSA_OP_LOAD_STORE)) { + return true; + } + while (i < a->n_out && j < b->n_in) { + if (a->out[i].resource < b->in[j].resource) { + ++i; + } else if (a->out[i].resource > b->in[j].resource) { + ++j; + } else { + return true; + } + } + return false; +} + +/* + * Try to break a dependency on b, append temporary register copy records + * to the end of copy and update n_copy in case of success. + * This is not always possible: e.g. control flow must always be the last, + * load/store must be first and state dependencies are not supported yet. + */ +static bool break_dependency(struct slot_prop *a, + struct slot_prop *b, + struct opcode_arg_copy *copy, + unsigned *n_copy) +{ + unsigned i = 0; + unsigned j = 0; + unsigned n = *n_copy; + bool rv = false; + + if (a->op_flags & XTENSA_OP_CONTROL_FLOW) { + return false; + } + if ((a->op_flags & XTENSA_OP_LOAD_STORE) < + (b->op_flags & XTENSA_OP_LOAD_STORE)) { + return false; + } + while (i < a->n_out && j < b->n_in) { + if (a->out[i].resource < b->in[j].resource) { + ++i; + } else if (a->out[i].resource > b->in[j].resource) { + ++j; + } else { + int index = b->in[j].index; + + if (get_resource_type(a->out[i].resource) != RES_REGFILE || + index < 0) { + return false; + } + copy[n].resource = b->in[j].resource; + copy[n].arg = b->arg + index; + ++n; + ++i; + ++j; + rv = true; + } + } + *n_copy = n; + return rv; +} + +/* + * Calculate evaluation order for slot opcodes. + * Build opcode order graph and output its nodes in topological sort order. + * An edge a -> b in the graph means that opcode a must be followed by + * opcode b. + */ +static bool tsort(struct slot_prop *slot, + struct slot_prop *sorted[], + unsigned n, + struct opcode_arg_copy *copy, + unsigned *n_copy) +{ + struct tsnode { + unsigned n_in_edge; + unsigned n_out_edge; + unsigned out_edge[MAX_INSN_SLOTS]; + } node[MAX_INSN_SLOTS]; + + unsigned in[MAX_INSN_SLOTS]; + unsigned i, j; + unsigned n_in = 0; + unsigned n_out = 0; + unsigned n_edge = 0; + unsigned in_idx = 0; + unsigned node_idx = 0; + + for (i = 0; i < n; ++i) { + node[i].n_in_edge = 0; + node[i].n_out_edge = 0; + } + + for (i = 0; i < n; ++i) { + unsigned n_out_edge = 0; + + for (j = 0; j < n; ++j) { + if (i != j && op_depends_on(slot + j, slot + i)) { + node[i].out_edge[n_out_edge] = j; + ++node[j].n_in_edge; + ++n_out_edge; + ++n_edge; + } + } + node[i].n_out_edge = n_out_edge; + } + + for (i = 0; i < n; ++i) { + if (!node[i].n_in_edge) { + in[n_in] = i; + ++n_in; + } + } + +again: + for (; in_idx < n_in; ++in_idx) { + i = in[in_idx]; + sorted[n_out] = slot + i; + ++n_out; + for (j = 0; j < node[i].n_out_edge; ++j) { + --n_edge; + if (--node[node[i].out_edge[j]].n_in_edge == 0) { + in[n_in] = node[i].out_edge[j]; + ++n_in; + } + } + } + if (n_edge) { + for (; node_idx < n; ++node_idx) { + struct tsnode *cnode = node + node_idx; + + if (cnode->n_in_edge) { + for (j = 0; j < cnode->n_out_edge; ++j) { + unsigned k = cnode->out_edge[j]; + + if (break_dependency(slot + k, slot + node_idx, + copy, n_copy) && + --node[k].n_in_edge == 0) { + in[n_in] = k; + ++n_in; + --n_edge; + cnode->out_edge[j] = + cnode->out_edge[cnode->n_out_edge - 1]; + --cnode->n_out_edge; + goto again; + } + } + } + } + } + return n_edge == 0; +} + +static void opcode_add_resource(struct slot_prop *op, + uint32_t resource, char direction, + int index) +{ + switch (direction) { + case 'm': + case 'i': + assert(op->n_in < ARRAY_SIZE(op->in)); + op->in[op->n_in].resource = resource; + op->in[op->n_in].index = index; + ++op->n_in; + /* fall through */ + case 'o': + if (direction == 'm' || direction == 'o') { + assert(op->n_out < ARRAY_SIZE(op->out)); + op->out[op->n_out].resource = resource; + op->out[op->n_out].index = index; + ++op->n_out; + } + break; + default: + g_assert_not_reached(); + } +} + +static int resource_compare(const void *a, const void *b) +{ + const struct opcode_arg_info *pa = a; + const struct opcode_arg_info *pb = b; + + return pa->resource < pb->resource ? + -1 : (pa->resource > pb->resource ? 1 : 0); +} + +static int arg_copy_compare(const void *a, const void *b) +{ + const struct opcode_arg_copy *pa = a; + const struct opcode_arg_copy *pb = b; + + return pa->resource < pb->resource ? + -1 : (pa->resource > pb->resource ? 1 : 0); +} + static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) { xtensa_isa isa = dc->config->isa; @@ -864,11 +1193,10 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) int slot, slots; unsigned i; uint32_t op_flags = 0; - struct { - XtensaOpcodeOps *ops; - uint32_t arg[MAX_OPCODE_ARGS]; - uint32_t raw_arg[MAX_OPCODE_ARGS]; - } slot_prop[MAX_INSN_SLOTS]; + struct slot_prop slot_prop[MAX_INSN_SLOTS]; + struct slot_prop *ordered[MAX_INSN_SLOTS]; + struct opcode_arg_copy arg_copy[MAX_INSN_SLOTS * MAX_OPCODE_ARGS]; + unsigned n_arg_copy = 0; uint32_t debug_cause = 0; uint32_t windowed_register = 0; uint32_t coprocessor = 0; @@ -898,12 +1226,9 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) for (slot = 0; slot < slots; ++slot) { xtensa_opcode opc; int opnd, vopnd, opnds; - uint32_t *raw_arg = slot_prop[slot].raw_arg; - uint32_t *arg = slot_prop[slot].arg; + OpcodeArg *arg = slot_prop[slot].arg; XtensaOpcodeOps *ops; - dc->raw_arg = raw_arg; - xtensa_format_get_slot(isa, fmt, slot, dc->insnbuf, dc->slotbuf); opc = xtensa_opcode_decode(isa, fmt, slot, dc->slotbuf); if (opc == XTENSA_UNDEFINED) { @@ -916,17 +1241,37 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) opnds = xtensa_opcode_num_operands(isa, opc); for (opnd = vopnd = 0; opnd < opnds; ++opnd) { + void **register_file = NULL; + + if (xtensa_operand_is_register(isa, opc, opnd)) { + xtensa_regfile rf = xtensa_operand_regfile(isa, opc, opnd); + + register_file = dc->config->regfile[rf]; + + if (rf == dc->config->a_regfile) { + uint32_t v; + + xtensa_operand_get_field(isa, opc, opnd, fmt, slot, + dc->slotbuf, &v); + xtensa_operand_decode(isa, opc, opnd, &v); + windowed_register |= 1u << v; + } + } if (xtensa_operand_is_visible(isa, opc, opnd)) { uint32_t v; xtensa_operand_get_field(isa, opc, opnd, fmt, slot, dc->slotbuf, &v); xtensa_operand_decode(isa, opc, opnd, &v); - raw_arg[vopnd] = v; + arg[vopnd].raw_imm = v; if (xtensa_operand_is_PCrelative(isa, opc, opnd)) { xtensa_operand_undo_reloc(isa, opc, opnd, &v, dc->pc); } - arg[vopnd] = v; + arg[vopnd].imm = v; + if (register_file) { + arg[vopnd].in = register_file[v]; + arg[vopnd].out = register_file[v]; + } ++vopnd; } } @@ -952,17 +1297,69 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) if (ops->test_overflow) { windowed_register |= ops->test_overflow(dc, arg, ops->par); } - if (ops->windowed_register_op) { - uint32_t reg_opnd = ops->windowed_register_op; + coprocessor |= ops->coprocessor; + + if (slots > 1) { + slot_prop[slot].n_in = 0; + slot_prop[slot].n_out = 0; + slot_prop[slot].op_flags = ops->op_flags & XTENSA_OP_LOAD_STORE; - while (reg_opnd) { - unsigned i = ctz32(reg_opnd); + opnds = xtensa_opcode_num_operands(isa, opc); - windowed_register |= 1 << arg[i]; - reg_opnd ^= 1 << i; + for (opnd = vopnd = 0; opnd < opnds; ++opnd) { + bool visible = xtensa_operand_is_visible(isa, opc, opnd); + + if (xtensa_operand_is_register(isa, opc, opnd)) { + xtensa_regfile rf = xtensa_operand_regfile(isa, opc, opnd); + uint32_t v = 0; + + xtensa_operand_get_field(isa, opc, opnd, fmt, slot, + dc->slotbuf, &v); + xtensa_operand_decode(isa, opc, opnd, &v); + opcode_add_resource(slot_prop + slot, + encode_resource(RES_REGFILE, rf, v), + xtensa_operand_inout(isa, opc, opnd), + visible ? vopnd : -1); + } + if (visible) { + ++vopnd; + } + } + + opnds = xtensa_opcode_num_stateOperands(isa, opc); + + for (opnd = 0; opnd < opnds; ++opnd) { + xtensa_state state = xtensa_stateOperand_state(isa, opc, opnd); + + opcode_add_resource(slot_prop + slot, + encode_resource(RES_STATE, 0, state), + xtensa_stateOperand_inout(isa, opc, opnd), + -1); + } + if (xtensa_opcode_is_branch(isa, opc) || + xtensa_opcode_is_jump(isa, opc) || + xtensa_opcode_is_loop(isa, opc) || + xtensa_opcode_is_call(isa, opc)) { + slot_prop[slot].op_flags |= XTENSA_OP_CONTROL_FLOW; } + + qsort(slot_prop[slot].in, slot_prop[slot].n_in, + sizeof(slot_prop[slot].in[0]), resource_compare); + qsort(slot_prop[slot].out, slot_prop[slot].n_out, + sizeof(slot_prop[slot].out[0]), resource_compare); } - coprocessor |= ops->coprocessor; + } + + if (slots > 1) { + if (!tsort(slot_prop, ordered, slots, arg_copy, &n_arg_copy)) { + qemu_log_mask(LOG_UNIMP, + "Circular resource dependencies (pc = %08x)\n", + dc->pc); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + return; + } + } else { + ordered[0] = slot_prop + 0; } if ((op_flags & XTENSA_OP_PRIVILEGED) && @@ -1002,6 +1399,29 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) return; } + if (n_arg_copy) { + uint32_t resource; + void *temp; + unsigned j; + + qsort(arg_copy, n_arg_copy, sizeof(*arg_copy), arg_copy_compare); + for (i = j = 0; i < n_arg_copy; ++i) { + if (i == 0 || arg_copy[i].resource != resource) { + resource = arg_copy[i].resource; + temp = tcg_temp_local_new(); + tcg_gen_mov_i32(temp, arg_copy[i].arg->in); + arg_copy[i].temp = temp; + + if (i != j) { + arg_copy[j] = arg_copy[i]; + } + ++j; + } + arg_copy[i].arg->in = temp; + } + n_arg_copy = j; + } + if (op_flags & XTENSA_OP_DIVIDE_BY_ZERO) { for (slot = 0; slot < slots; ++slot) { if (slot_prop[slot].ops->op_flags & XTENSA_OP_DIVIDE_BY_ZERO) { @@ -1010,29 +1430,31 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) } } + dc->op_flags = op_flags; + for (slot = 0; slot < slots; ++slot) { - XtensaOpcodeOps *ops = slot_prop[slot].ops; + struct slot_prop *pslot = ordered[slot]; + XtensaOpcodeOps *ops = pslot->ops; - dc->raw_arg = slot_prop[slot].raw_arg; - ops->translate(dc, slot_prop[slot].arg, ops->par); + ops->translate(dc, pslot->arg, ops->par); } - if (dc->base.is_jmp == DISAS_NEXT) { - if (op_flags & XTENSA_OP_CHECK_INTERRUPTS) { - gen_check_interrupts(dc); - } + for (i = 0; i < n_arg_copy; ++i) { + tcg_temp_free(arg_copy[i].temp); + } + if (dc->base.is_jmp == DISAS_NEXT) { + gen_postprocess(dc, 0); + dc->op_flags = 0; if (op_flags & XTENSA_OP_EXIT_TB_M1) { /* Change in mmu index, memory mapping or tb->flags; exit tb */ gen_jumpi_check_loop_end(dc, -1); } else if (op_flags & XTENSA_OP_EXIT_TB_0) { gen_jumpi_check_loop_end(dc, 0); + } else { + gen_check_loop_end(dc, 0); } } - - if (dc->base.is_jmp == DISAS_NEXT) { - gen_check_loop_end(dc, 0); - } dc->pc = dc->base.pc_next; } @@ -1283,105 +1705,91 @@ void restore_state_to_opc(CPUXtensaState *env, TranslationBlock *tb, env->pc = data[0]; } -static int compare_opcode_ops(const void *a, const void *b) -{ - return strcmp((const char *)a, - ((const XtensaOpcodeOps *)b)->name); -} - -XtensaOpcodeOps * -xtensa_find_opcode_ops(const XtensaOpcodeTranslators *t, - const char *name) -{ - return bsearch(name, t->opcode, t->num_opcodes, - sizeof(XtensaOpcodeOps), compare_opcode_ops); -} - -static void translate_abs(DisasContext *dc, const uint32_t arg[], +static void translate_abs(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 zero = tcg_const_i32(0); TCGv_i32 neg = tcg_temp_new_i32(); - tcg_gen_neg_i32(neg, cpu_R[arg[1]]); - tcg_gen_movcond_i32(TCG_COND_GE, cpu_R[arg[0]], - cpu_R[arg[1]], zero, cpu_R[arg[1]], neg); + tcg_gen_neg_i32(neg, arg[1].in); + tcg_gen_movcond_i32(TCG_COND_GE, arg[0].out, + arg[1].in, zero, arg[1].in, neg); tcg_temp_free(neg); tcg_temp_free(zero); } -static void translate_add(DisasContext *dc, const uint32_t arg[], +static void translate_add(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_add_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_add_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_addi(DisasContext *dc, const uint32_t arg[], +static void translate_addi(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_addi_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2]); + tcg_gen_addi_i32(arg[0].out, arg[1].in, arg[2].imm); } -static void translate_addx(DisasContext *dc, const uint32_t arg[], +static void translate_addx(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[arg[1]], par[0]); - tcg_gen_add_i32(cpu_R[arg[0]], tmp, cpu_R[arg[2]]); + tcg_gen_shli_i32(tmp, arg[1].in, par[0]); + tcg_gen_add_i32(arg[0].out, tmp, arg[2].in); tcg_temp_free(tmp); } -static void translate_all(DisasContext *dc, const uint32_t arg[], +static void translate_all(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { uint32_t shift = par[1]; - TCGv_i32 mask = tcg_const_i32(((1 << shift) - 1) << arg[1]); + TCGv_i32 mask = tcg_const_i32(((1 << shift) - 1) << arg[1].imm); TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_and_i32(tmp, cpu_SR[BR], mask); + tcg_gen_and_i32(tmp, arg[1].in, mask); if (par[0]) { - tcg_gen_addi_i32(tmp, tmp, 1 << arg[1]); + tcg_gen_addi_i32(tmp, tmp, 1 << arg[1].imm); } else { tcg_gen_add_i32(tmp, tmp, mask); } - tcg_gen_shri_i32(tmp, tmp, arg[1] + shift); - tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], - tmp, arg[0], 1); + tcg_gen_shri_i32(tmp, tmp, arg[1].imm + shift); + tcg_gen_deposit_i32(arg[0].out, arg[0].out, + tmp, arg[0].imm, 1); tcg_temp_free(mask); tcg_temp_free(tmp); } -static void translate_and(DisasContext *dc, const uint32_t arg[], +static void translate_and(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_and_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_and_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_ball(DisasContext *dc, const uint32_t arg[], +static void translate_ball(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_and_i32(tmp, cpu_R[arg[0]], cpu_R[arg[1]]); - gen_brcond(dc, par[0], tmp, cpu_R[arg[1]], arg[2]); + tcg_gen_and_i32(tmp, arg[0].in, arg[1].in); + gen_brcond(dc, par[0], tmp, arg[1].in, arg[2].imm); tcg_temp_free(tmp); } -static void translate_bany(DisasContext *dc, const uint32_t arg[], +static void translate_bany(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_and_i32(tmp, cpu_R[arg[0]], cpu_R[arg[1]]); - gen_brcondi(dc, par[0], tmp, 0, arg[2]); + tcg_gen_and_i32(tmp, arg[0].in, arg[1].in); + gen_brcondi(dc, par[0], tmp, 0, arg[2].imm); tcg_temp_free(tmp); } -static void translate_b(DisasContext *dc, const uint32_t arg[], +static void translate_b(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_brcond(dc, par[0], cpu_R[arg[0]], cpu_R[arg[1]], arg[2]); + gen_brcond(dc, par[0], arg[0].in, arg[1].in, arg[2].imm); } -static void translate_bb(DisasContext *dc, const uint32_t arg[], +static void translate_bb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifdef TARGET_WORDS_BIGENDIAN @@ -1390,41 +1798,41 @@ static void translate_bb(DisasContext *dc, const uint32_t arg[], TCGv_i32 bit = tcg_const_i32(0x00000001u); #endif TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cpu_R[arg[1]], 0x1f); + tcg_gen_andi_i32(tmp, arg[1].in, 0x1f); #ifdef TARGET_WORDS_BIGENDIAN tcg_gen_shr_i32(bit, bit, tmp); #else tcg_gen_shl_i32(bit, bit, tmp); #endif - tcg_gen_and_i32(tmp, cpu_R[arg[0]], bit); - gen_brcondi(dc, par[0], tmp, 0, arg[2]); + tcg_gen_and_i32(tmp, arg[0].in, bit); + gen_brcondi(dc, par[0], tmp, 0, arg[2].imm); tcg_temp_free(tmp); tcg_temp_free(bit); } -static void translate_bbi(DisasContext *dc, const uint32_t arg[], +static void translate_bbi(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); #ifdef TARGET_WORDS_BIGENDIAN - tcg_gen_andi_i32(tmp, cpu_R[arg[0]], 0x80000000u >> arg[1]); + tcg_gen_andi_i32(tmp, arg[0].in, 0x80000000u >> arg[1].imm); #else - tcg_gen_andi_i32(tmp, cpu_R[arg[0]], 0x00000001u << arg[1]); + tcg_gen_andi_i32(tmp, arg[0].in, 0x00000001u << arg[1].imm); #endif - gen_brcondi(dc, par[0], tmp, 0, arg[2]); + gen_brcondi(dc, par[0], tmp, 0, arg[2].imm); tcg_temp_free(tmp); } -static void translate_bi(DisasContext *dc, const uint32_t arg[], +static void translate_bi(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_brcondi(dc, par[0], cpu_R[arg[0]], arg[1], arg[2]); + gen_brcondi(dc, par[0], arg[0].in, arg[1].imm, arg[2].imm); } -static void translate_bz(DisasContext *dc, const uint32_t arg[], +static void translate_bz(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_brcondi(dc, par[0], cpu_R[arg[0]], 0, arg[1]); + gen_brcondi(dc, par[0], arg[0].in, 0, arg[1].imm); } enum { @@ -1435,7 +1843,7 @@ enum { BOOLEAN_XOR, }; -static void translate_boolean(DisasContext *dc, const uint32_t arg[], +static void translate_boolean(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { static void (* const op[])(TCGv_i32, TCGv_i32, TCGv_i32) = { @@ -1449,114 +1857,110 @@ static void translate_boolean(DisasContext *dc, const uint32_t arg[], TCGv_i32 tmp1 = tcg_temp_new_i32(); TCGv_i32 tmp2 = tcg_temp_new_i32(); - tcg_gen_shri_i32(tmp1, cpu_SR[BR], arg[1]); - tcg_gen_shri_i32(tmp2, cpu_SR[BR], arg[2]); + tcg_gen_shri_i32(tmp1, arg[1].in, arg[1].imm); + tcg_gen_shri_i32(tmp2, arg[2].in, arg[2].imm); op[par[0]](tmp1, tmp1, tmp2); - tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], tmp1, arg[0], 1); + tcg_gen_deposit_i32(arg[0].out, arg[0].out, tmp1, arg[0].imm, 1); tcg_temp_free(tmp1); tcg_temp_free(tmp2); } -static void translate_bp(DisasContext *dc, const uint32_t arg[], +static void translate_bp(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << arg[0]); - gen_brcondi(dc, par[0], tmp, 0, arg[1]); + tcg_gen_andi_i32(tmp, arg[0].in, 1 << arg[0].imm); + gen_brcondi(dc, par[0], tmp, 0, arg[1].imm); tcg_temp_free(tmp); } -static void translate_call0(DisasContext *dc, const uint32_t arg[], +static void translate_call0(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { tcg_gen_movi_i32(cpu_R[0], dc->base.pc_next); - gen_jumpi(dc, arg[0], 0); -} - -static uint32_t test_overflow_callw(DisasContext *dc, const uint32_t arg[], - const uint32_t par[]) -{ - return 1 << (par[0] * 4); + gen_jumpi(dc, arg[0].imm, 0); } -static void translate_callw(DisasContext *dc, const uint32_t arg[], +static void translate_callw(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_callwi(dc, par[0], arg[0], 0); + TCGv_i32 tmp = tcg_const_i32(arg[0].imm); + gen_callw_slot(dc, par[0], tmp, adjust_jump_slot(dc, arg[0].imm, 0)); + tcg_temp_free(tmp); } -static void translate_callx0(DisasContext *dc, const uint32_t arg[], +static void translate_callx0(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp, cpu_R[arg[0]]); + tcg_gen_mov_i32(tmp, arg[0].in); tcg_gen_movi_i32(cpu_R[0], dc->base.pc_next); gen_jump(dc, tmp); tcg_temp_free(tmp); } -static void translate_callxw(DisasContext *dc, const uint32_t arg[], +static void translate_callxw(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp, cpu_R[arg[0]]); - gen_callw(dc, par[0], tmp); + tcg_gen_mov_i32(tmp, arg[0].in); + gen_callw_slot(dc, par[0], tmp, -1); tcg_temp_free(tmp); } -static void translate_clamps(DisasContext *dc, const uint32_t arg[], +static void translate_clamps(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 tmp1 = tcg_const_i32(-1u << arg[2]); - TCGv_i32 tmp2 = tcg_const_i32((1 << arg[2]) - 1); + TCGv_i32 tmp1 = tcg_const_i32(-1u << arg[2].imm); + TCGv_i32 tmp2 = tcg_const_i32((1 << arg[2].imm) - 1); - tcg_gen_smax_i32(tmp1, tmp1, cpu_R[arg[1]]); - tcg_gen_smin_i32(cpu_R[arg[0]], tmp1, tmp2); + tcg_gen_smax_i32(tmp1, tmp1, arg[1].in); + tcg_gen_smin_i32(arg[0].out, tmp1, tmp2); tcg_temp_free(tmp1); tcg_temp_free(tmp2); } -static void translate_clrb_expstate(DisasContext *dc, const uint32_t arg[], +static void translate_clrb_expstate(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { /* TODO: GPIO32 may be a part of coprocessor */ - tcg_gen_andi_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], ~(1u << arg[0])); + tcg_gen_andi_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], ~(1u << arg[0].imm)); } -static void translate_const16(DisasContext *dc, const uint32_t arg[], +static void translate_const16(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 c = tcg_const_i32(arg[1]); + TCGv_i32 c = tcg_const_i32(arg[1].imm); - tcg_gen_deposit_i32(cpu_R[arg[0]], c, cpu_R[arg[0]], 16, 16); + tcg_gen_deposit_i32(arg[0].out, c, arg[0].in, 16, 16); tcg_temp_free(c); } -static void translate_dcache(DisasContext *dc, const uint32_t arg[], +static void translate_dcache(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 addr = tcg_temp_new_i32(); TCGv_i32 res = tcg_temp_new_i32(); - tcg_gen_addi_i32(addr, cpu_R[arg[0]], arg[1]); + tcg_gen_addi_i32(addr, arg[0].in, arg[1].imm); tcg_gen_qemu_ld8u(res, addr, dc->cring); tcg_temp_free(addr); tcg_temp_free(res); } -static void translate_depbits(DisasContext *dc, const uint32_t arg[], +static void translate_depbits(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_deposit_i32(cpu_R[arg[1]], cpu_R[arg[1]], cpu_R[arg[0]], - arg[2], arg[3]); + tcg_gen_deposit_i32(arg[1].out, arg[1].in, arg[0].in, + arg[2].imm, arg[3].imm); } -static bool test_ill_entry(DisasContext *dc, const uint32_t arg[], +static bool test_ill_entry(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - if (arg[0] > 3 || !dc->cwoe) { + if (arg[0].imm > 3 || !dc->cwoe) { qemu_log_mask(LOG_GUEST_ERROR, "Illegal entry instruction(pc = %08x)\n", dc->pc); return true; @@ -1565,88 +1969,88 @@ static bool test_ill_entry(DisasContext *dc, const uint32_t arg[], } } -static uint32_t test_overflow_entry(DisasContext *dc, const uint32_t arg[], +static uint32_t test_overflow_entry(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { return 1 << (dc->callinc * 4); } -static void translate_entry(DisasContext *dc, const uint32_t arg[], +static void translate_entry(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 pc = tcg_const_i32(dc->pc); - TCGv_i32 s = tcg_const_i32(arg[0]); - TCGv_i32 imm = tcg_const_i32(arg[1]); + TCGv_i32 s = tcg_const_i32(arg[0].imm); + TCGv_i32 imm = tcg_const_i32(arg[1].imm); gen_helper_entry(cpu_env, pc, s, imm); tcg_temp_free(imm); tcg_temp_free(s); tcg_temp_free(pc); } -static void translate_extui(DisasContext *dc, const uint32_t arg[], +static void translate_extui(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - int maskimm = (1 << arg[3]) - 1; + int maskimm = (1 << arg[3].imm) - 1; TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shri_i32(tmp, cpu_R[arg[1]], arg[2]); - tcg_gen_andi_i32(cpu_R[arg[0]], tmp, maskimm); + tcg_gen_shri_i32(tmp, arg[1].in, arg[2].imm); + tcg_gen_andi_i32(arg[0].out, tmp, maskimm); tcg_temp_free(tmp); } -static void translate_icache(DisasContext *dc, const uint32_t arg[], +static void translate_icache(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY TCGv_i32 addr = tcg_temp_new_i32(); tcg_gen_movi_i32(cpu_pc, dc->pc); - tcg_gen_addi_i32(addr, cpu_R[arg[0]], arg[1]); + tcg_gen_addi_i32(addr, arg[0].in, arg[1].imm); gen_helper_itlb_hit_test(cpu_env, addr); tcg_temp_free(addr); #endif } -static void translate_itlb(DisasContext *dc, const uint32_t arg[], +static void translate_itlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY TCGv_i32 dtlb = tcg_const_i32(par[0]); - gen_helper_itlb(cpu_env, cpu_R[arg[0]], dtlb); + gen_helper_itlb(cpu_env, arg[0].in, dtlb); tcg_temp_free(dtlb); #endif } -static void translate_j(DisasContext *dc, const uint32_t arg[], +static void translate_j(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_jumpi(dc, arg[0], 0); + gen_jumpi(dc, arg[0].imm, 0); } -static void translate_jx(DisasContext *dc, const uint32_t arg[], +static void translate_jx(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_jump(dc, cpu_R[arg[0]]); + gen_jump(dc, arg[0].in); } -static void translate_l32e(DisasContext *dc, const uint32_t arg[], +static void translate_l32e(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + tcg_gen_addi_i32(addr, arg[1].in, arg[2].imm); gen_load_store_alignment(dc, 2, addr, false); - tcg_gen_qemu_ld_tl(cpu_R[arg[0]], addr, dc->ring, MO_TEUL); + tcg_gen_qemu_ld_tl(arg[0].out, addr, dc->ring, MO_TEUL); tcg_temp_free(addr); } -static void translate_ldst(DisasContext *dc, const uint32_t arg[], +static void translate_ldst(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + tcg_gen_addi_i32(addr, arg[1].in, arg[2].imm); if (par[0] & MO_SIZE) { gen_load_store_alignment(dc, par[0] & MO_SIZE, addr, par[1]); } @@ -1654,9 +2058,9 @@ static void translate_ldst(DisasContext *dc, const uint32_t arg[], if (par[1]) { tcg_gen_mb(TCG_BAR_STRL | TCG_MO_ALL); } - tcg_gen_qemu_st_tl(cpu_R[arg[0]], addr, dc->cring, par[0]); + tcg_gen_qemu_st_tl(arg[0].in, addr, dc->cring, par[0]); } else { - tcg_gen_qemu_ld_tl(cpu_R[arg[0]], addr, dc->cring, par[0]); + tcg_gen_qemu_ld_tl(arg[0].out, addr, dc->cring, par[0]); if (par[1]) { tcg_gen_mb(TCG_BAR_LDAQ | TCG_MO_ALL); } @@ -1664,33 +2068,33 @@ static void translate_ldst(DisasContext *dc, const uint32_t arg[], tcg_temp_free(addr); } -static void translate_l32r(DisasContext *dc, const uint32_t arg[], +static void translate_l32r(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp; if (dc->base.tb->flags & XTENSA_TBFLAG_LITBASE) { - tmp = tcg_const_i32(dc->raw_arg[1] - 1); + tmp = tcg_const_i32(arg[1].raw_imm - 1); tcg_gen_add_i32(tmp, cpu_SR[LITBASE], tmp); } else { - tmp = tcg_const_i32(arg[1]); + tmp = tcg_const_i32(arg[1].imm); } - tcg_gen_qemu_ld32u(cpu_R[arg[0]], tmp, dc->cring); + tcg_gen_qemu_ld32u(arg[0].out, tmp, dc->cring); tcg_temp_free(tmp); } -static void translate_loop(DisasContext *dc, const uint32_t arg[], +static void translate_loop(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - uint32_t lend = arg[1]; + uint32_t lend = arg[1].imm; - tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[arg[0]], 1); + tcg_gen_subi_i32(cpu_SR[LCOUNT], arg[0].in, 1); tcg_gen_movi_i32(cpu_SR[LBEG], dc->base.pc_next); tcg_gen_movi_i32(cpu_SR[LEND], lend); if (par[0] != TCG_COND_NEVER) { TCGLabel *label = gen_new_label(); - tcg_gen_brcondi_i32(par[0], cpu_R[arg[0]], 0, label); + tcg_gen_brcondi_i32(par[0], arg[0].in, 0, label); gen_jumpi(dc, lend, 1); gen_set_label(label); } @@ -1716,41 +2120,25 @@ enum { MAC16_XH = 0x2, }; -enum { - MAC16_AA, - MAC16_AD, - MAC16_DA, - MAC16_DD, - - MAC16_XD = 0x1, - MAC16_DX = 0x2, -}; - -static void translate_mac16(DisasContext *dc, const uint32_t arg[], +static void translate_mac16(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { int op = par[0]; - bool is_m1_sr = par[1] & MAC16_DX; - bool is_m2_sr = par[1] & MAC16_XD; - unsigned half = par[2]; - uint32_t ld_offset = par[3]; + unsigned half = par[1]; + uint32_t ld_offset = par[2]; unsigned off = ld_offset ? 2 : 0; TCGv_i32 vaddr = tcg_temp_new_i32(); TCGv_i32 mem32 = tcg_temp_new_i32(); if (ld_offset) { - tcg_gen_addi_i32(vaddr, cpu_R[arg[1]], ld_offset); + tcg_gen_addi_i32(vaddr, arg[1].in, ld_offset); gen_load_store_alignment(dc, 2, vaddr, false); tcg_gen_qemu_ld32u(mem32, vaddr, dc->cring); } if (op != MAC16_NONE) { - TCGv_i32 m1 = gen_mac16_m(is_m1_sr ? - cpu_SR[MR + arg[off]] : - cpu_R[arg[off]], + TCGv_i32 m1 = gen_mac16_m(arg[off].in, half & MAC16_HX, op == MAC16_UMUL); - TCGv_i32 m2 = gen_mac16_m(is_m2_sr ? - cpu_SR[MR + arg[off + 1]] : - cpu_R[arg[off + 1]], + TCGv_i32 m2 = gen_mac16_m(arg[off + 1].in, half & MAC16_XH, op == MAC16_UMUL); if (op == MAC16_MUL || op == MAC16_UMUL) { @@ -1784,221 +2172,221 @@ static void translate_mac16(DisasContext *dc, const uint32_t arg[], tcg_temp_free(m2); } if (ld_offset) { - tcg_gen_mov_i32(cpu_R[arg[1]], vaddr); - tcg_gen_mov_i32(cpu_SR[MR + arg[0]], mem32); + tcg_gen_mov_i32(arg[1].out, vaddr); + tcg_gen_mov_i32(cpu_SR[MR + arg[0].imm], mem32); } tcg_temp_free(vaddr); tcg_temp_free(mem32); } -static void translate_memw(DisasContext *dc, const uint32_t arg[], +static void translate_memw(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); } -static void translate_smin(DisasContext *dc, const uint32_t arg[], +static void translate_smin(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_smin_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_smin_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_umin(DisasContext *dc, const uint32_t arg[], +static void translate_umin(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_umin_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_umin_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_smax(DisasContext *dc, const uint32_t arg[], +static void translate_smax(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_smax_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_smax_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_umax(DisasContext *dc, const uint32_t arg[], +static void translate_umax(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_umax_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_umax_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_mov(DisasContext *dc, const uint32_t arg[], +static void translate_mov(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + tcg_gen_mov_i32(arg[0].out, arg[1].in); } -static void translate_movcond(DisasContext *dc, const uint32_t arg[], +static void translate_movcond(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 zero = tcg_const_i32(0); - tcg_gen_movcond_i32(par[0], cpu_R[arg[0]], - cpu_R[arg[2]], zero, cpu_R[arg[1]], cpu_R[arg[0]]); + tcg_gen_movcond_i32(par[0], arg[0].out, + arg[2].in, zero, arg[1].in, arg[0].in); tcg_temp_free(zero); } -static void translate_movi(DisasContext *dc, const uint32_t arg[], +static void translate_movi(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_movi_i32(cpu_R[arg[0]], arg[1]); + tcg_gen_movi_i32(arg[0].out, arg[1].imm); } -static void translate_movp(DisasContext *dc, const uint32_t arg[], +static void translate_movp(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 zero = tcg_const_i32(0); TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << arg[2]); + tcg_gen_andi_i32(tmp, arg[2].in, 1 << arg[2].imm); tcg_gen_movcond_i32(par[0], - cpu_R[arg[0]], tmp, zero, - cpu_R[arg[1]], cpu_R[arg[0]]); + arg[0].out, tmp, zero, + arg[1].in, arg[0].in); tcg_temp_free(tmp); tcg_temp_free(zero); } -static void translate_movsp(DisasContext *dc, const uint32_t arg[], +static void translate_movsp(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + tcg_gen_mov_i32(arg[0].out, arg[1].in); } -static void translate_mul16(DisasContext *dc, const uint32_t arg[], +static void translate_mul16(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 v1 = tcg_temp_new_i32(); TCGv_i32 v2 = tcg_temp_new_i32(); if (par[0]) { - tcg_gen_ext16s_i32(v1, cpu_R[arg[1]]); - tcg_gen_ext16s_i32(v2, cpu_R[arg[2]]); + tcg_gen_ext16s_i32(v1, arg[1].in); + tcg_gen_ext16s_i32(v2, arg[2].in); } else { - tcg_gen_ext16u_i32(v1, cpu_R[arg[1]]); - tcg_gen_ext16u_i32(v2, cpu_R[arg[2]]); + tcg_gen_ext16u_i32(v1, arg[1].in); + tcg_gen_ext16u_i32(v2, arg[2].in); } - tcg_gen_mul_i32(cpu_R[arg[0]], v1, v2); + tcg_gen_mul_i32(arg[0].out, v1, v2); tcg_temp_free(v2); tcg_temp_free(v1); } -static void translate_mull(DisasContext *dc, const uint32_t arg[], +static void translate_mull(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mul_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_mul_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_mulh(DisasContext *dc, const uint32_t arg[], +static void translate_mulh(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 lo = tcg_temp_new(); if (par[0]) { - tcg_gen_muls2_i32(lo, cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_muls2_i32(lo, arg[0].out, arg[1].in, arg[2].in); } else { - tcg_gen_mulu2_i32(lo, cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_mulu2_i32(lo, arg[0].out, arg[1].in, arg[2].in); } tcg_temp_free(lo); } -static void translate_neg(DisasContext *dc, const uint32_t arg[], +static void translate_neg(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_neg_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + tcg_gen_neg_i32(arg[0].out, arg[1].in); } -static void translate_nop(DisasContext *dc, const uint32_t arg[], +static void translate_nop(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { } -static void translate_nsa(DisasContext *dc, const uint32_t arg[], +static void translate_nsa(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_clrsb_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + tcg_gen_clrsb_i32(arg[0].out, arg[1].in); } -static void translate_nsau(DisasContext *dc, const uint32_t arg[], +static void translate_nsau(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_clzi_i32(cpu_R[arg[0]], cpu_R[arg[1]], 32); + tcg_gen_clzi_i32(arg[0].out, arg[1].in, 32); } -static void translate_or(DisasContext *dc, const uint32_t arg[], +static void translate_or(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_or_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_or_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_ptlb(DisasContext *dc, const uint32_t arg[], +static void translate_ptlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY TCGv_i32 dtlb = tcg_const_i32(par[0]); tcg_gen_movi_i32(cpu_pc, dc->pc); - gen_helper_ptlb(cpu_R[arg[0]], cpu_env, cpu_R[arg[1]], dtlb); + gen_helper_ptlb(arg[0].out, cpu_env, arg[1].in, dtlb); tcg_temp_free(dtlb); #endif } -static void translate_quos(DisasContext *dc, const uint32_t arg[], +static void translate_quos(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGLabel *label1 = gen_new_label(); TCGLabel *label2 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[arg[1]], 0x80000000, + tcg_gen_brcondi_i32(TCG_COND_NE, arg[1].in, 0x80000000, label1); - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[arg[2]], 0xffffffff, + tcg_gen_brcondi_i32(TCG_COND_NE, arg[2].in, 0xffffffff, label1); - tcg_gen_movi_i32(cpu_R[arg[0]], + tcg_gen_movi_i32(arg[0].out, par[0] ? 0x80000000 : 0); tcg_gen_br(label2); gen_set_label(label1); if (par[0]) { - tcg_gen_div_i32(cpu_R[arg[0]], - cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_div_i32(arg[0].out, + arg[1].in, arg[2].in); } else { - tcg_gen_rem_i32(cpu_R[arg[0]], - cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_rem_i32(arg[0].out, + arg[1].in, arg[2].in); } gen_set_label(label2); } -static void translate_quou(DisasContext *dc, const uint32_t arg[], +static void translate_quou(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_divu_i32(cpu_R[arg[0]], - cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_divu_i32(arg[0].out, + arg[1].in, arg[2].in); } -static void translate_read_impwire(DisasContext *dc, const uint32_t arg[], +static void translate_read_impwire(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { /* TODO: GPIO32 may be a part of coprocessor */ - tcg_gen_movi_i32(cpu_R[arg[0]], 0); + tcg_gen_movi_i32(arg[0].out, 0); } -static void translate_remu(DisasContext *dc, const uint32_t arg[], +static void translate_remu(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_remu_i32(cpu_R[arg[0]], - cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_remu_i32(arg[0].out, + arg[1].in, arg[2].in); } -static void translate_rer(DisasContext *dc, const uint32_t arg[], +static void translate_rer(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_rer(cpu_R[arg[0]], cpu_env, cpu_R[arg[1]]); + gen_helper_rer(arg[0].out, cpu_env, arg[1].in); } -static void translate_ret(DisasContext *dc, const uint32_t arg[], +static void translate_ret(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { gen_jump(dc, cpu_R[0]); } -static bool test_ill_retw(DisasContext *dc, const uint32_t arg[], +static bool test_ill_retw(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (!dc->cwoe) { @@ -2014,36 +2402,41 @@ static bool test_ill_retw(DisasContext *dc, const uint32_t arg[], } } -static void translate_retw(DisasContext *dc, const uint32_t arg[], +static void translate_retw(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 tmp = tcg_const_i32(dc->pc); - gen_helper_retw(tmp, cpu_env, tmp); + TCGv_i32 tmp = tcg_const_i32(1); + tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]); + tcg_gen_andc_i32(cpu_SR[WINDOW_START], + cpu_SR[WINDOW_START], tmp); + tcg_gen_movi_i32(tmp, dc->pc); + tcg_gen_deposit_i32(tmp, tmp, cpu_R[0], 0, 30); + gen_helper_retw(cpu_env, cpu_R[0]); gen_jump(dc, tmp); tcg_temp_free(tmp); } -static void translate_rfde(DisasContext *dc, const uint32_t arg[], +static void translate_rfde(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { gen_jump(dc, cpu_SR[dc->config->ndepc ? DEPC : EPC1]); } -static void translate_rfe(DisasContext *dc, const uint32_t arg[], +static void translate_rfe(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); gen_jump(dc, cpu_SR[EPC1]); } -static void translate_rfi(DisasContext *dc, const uint32_t arg[], +static void translate_rfi(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(cpu_SR[PS], cpu_SR[EPS2 + arg[0] - 2]); - gen_jump(dc, cpu_SR[EPC1 + arg[0] - 1]); + tcg_gen_mov_i32(cpu_SR[PS], cpu_SR[EPS2 + arg[0].imm - 2]); + gen_jump(dc, cpu_SR[EPC1 + arg[0].imm - 1]); } -static void translate_rfw(DisasContext *dc, const uint32_t arg[], +static void translate_rfw(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_const_i32(1); @@ -2064,35 +2457,33 @@ static void translate_rfw(DisasContext *dc, const uint32_t arg[], gen_jump(dc, cpu_SR[EPC1]); } -static void translate_rotw(DisasContext *dc, const uint32_t arg[], +static void translate_rotw(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 tmp = tcg_const_i32(arg[0]); - gen_helper_rotw(cpu_env, tmp); - tcg_temp_free(tmp); + tcg_gen_addi_i32(cpu_windowbase_next, cpu_SR[WINDOW_BASE], arg[0].imm); } -static void translate_rsil(DisasContext *dc, const uint32_t arg[], +static void translate_rsil(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(cpu_R[arg[0]], cpu_SR[PS]); + tcg_gen_mov_i32(arg[0].out, cpu_SR[PS]); tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL); - tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], arg[1]); + tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], arg[1].imm); } -static bool test_ill_rsr(DisasContext *dc, const uint32_t arg[], +static bool test_ill_rsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { return !check_sr(dc, par[0], SR_R); } -static void translate_rsr(DisasContext *dc, const uint32_t arg[], +static void translate_rsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_rsr(dc, cpu_R[arg[0]], par[0]); + gen_rsr(dc, arg[0].out, par[0]); } -static void translate_rtlb(DisasContext *dc, const uint32_t arg[], +static void translate_rtlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY @@ -2103,26 +2494,26 @@ static void translate_rtlb(DisasContext *dc, const uint32_t arg[], }; TCGv_i32 dtlb = tcg_const_i32(par[0]); - helper[par[1]](cpu_R[arg[0]], cpu_env, cpu_R[arg[1]], dtlb); + helper[par[1]](arg[0].out, cpu_env, arg[1].in, dtlb); tcg_temp_free(dtlb); #endif } -static void translate_rur(DisasContext *dc, const uint32_t arg[], +static void translate_rur(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (uregnames[par[0]].name) { - tcg_gen_mov_i32(cpu_R[arg[0]], cpu_UR[par[0]]); + tcg_gen_mov_i32(arg[0].out, cpu_UR[par[0]]); } else { qemu_log_mask(LOG_UNIMP, "RUR %d not implemented\n", par[0]); } } -static void translate_setb_expstate(DisasContext *dc, const uint32_t arg[], +static void translate_setb_expstate(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { /* TODO: GPIO32 may be a part of coprocessor */ - tcg_gen_ori_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], 1u << arg[0]); + tcg_gen_ori_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], 1u << arg[0].imm); } #ifdef CONFIG_USER_ONLY @@ -2139,59 +2530,59 @@ static void gen_check_atomctl(DisasContext *dc, TCGv_i32 addr) } #endif -static void translate_s32c1i(DisasContext *dc, const uint32_t arg[], +static void translate_s32c1i(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_local_new_i32(); TCGv_i32 addr = tcg_temp_local_new_i32(); - tcg_gen_mov_i32(tmp, cpu_R[arg[0]]); - tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + tcg_gen_mov_i32(tmp, arg[0].in); + tcg_gen_addi_i32(addr, arg[1].in, arg[2].imm); gen_load_store_alignment(dc, 2, addr, true); gen_check_atomctl(dc, addr); - tcg_gen_atomic_cmpxchg_i32(cpu_R[arg[0]], addr, cpu_SR[SCOMPARE1], + tcg_gen_atomic_cmpxchg_i32(arg[0].out, addr, cpu_SR[SCOMPARE1], tmp, dc->cring, MO_TEUL); tcg_temp_free(addr); tcg_temp_free(tmp); } -static void translate_s32e(DisasContext *dc, const uint32_t arg[], +static void translate_s32e(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + tcg_gen_addi_i32(addr, arg[1].in, arg[2].imm); gen_load_store_alignment(dc, 2, addr, false); - tcg_gen_qemu_st_tl(cpu_R[arg[0]], addr, dc->ring, MO_TEUL); + tcg_gen_qemu_st_tl(arg[0].in, addr, dc->ring, MO_TEUL); tcg_temp_free(addr); } -static void translate_salt(DisasContext *dc, const uint32_t arg[], +static void translate_salt(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { tcg_gen_setcond_i32(par[0], - cpu_R[arg[0]], - cpu_R[arg[1]], cpu_R[arg[2]]); + arg[0].out, + arg[1].in, arg[2].in); } -static void translate_sext(DisasContext *dc, const uint32_t arg[], +static void translate_sext(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - int shift = 31 - arg[2]; + int shift = 31 - arg[2].imm; if (shift == 24) { - tcg_gen_ext8s_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + tcg_gen_ext8s_i32(arg[0].out, arg[1].in); } else if (shift == 16) { - tcg_gen_ext16s_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + tcg_gen_ext16s_i32(arg[0].out, arg[1].in); } else { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[arg[1]], shift); - tcg_gen_sari_i32(cpu_R[arg[0]], tmp, shift); + tcg_gen_shli_i32(tmp, arg[1].in, shift); + tcg_gen_sari_i32(arg[0].out, tmp, shift); tcg_temp_free(tmp); } } -static bool test_ill_simcall(DisasContext *dc, const uint32_t arg[], +static bool test_ill_simcall(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifdef CONFIG_USER_ONLY @@ -2205,7 +2596,7 @@ static bool test_ill_simcall(DisasContext *dc, const uint32_t arg[], return ill; } -static void translate_simcall(DisasContext *dc, const uint32_t arg[], +static void translate_simcall(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY @@ -2221,73 +2612,73 @@ static void translate_simcall(DisasContext *dc, const uint32_t arg[], TCGv_i64 tmp = tcg_temp_new_i64(); \ tcg_gen_extu_i32_i64(tmp, reg); \ tcg_gen_##cmd##_i64(v, v, tmp); \ - tcg_gen_extrl_i64_i32(cpu_R[arg[0]], v); \ + tcg_gen_extrl_i64_i32(arg[0].out, v); \ tcg_temp_free_i64(v); \ tcg_temp_free_i64(tmp); \ } while (0) #define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR]) -static void translate_sll(DisasContext *dc, const uint32_t arg[], +static void translate_sll(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (dc->sar_m32_5bit) { - tcg_gen_shl_i32(cpu_R[arg[0]], cpu_R[arg[1]], dc->sar_m32); + tcg_gen_shl_i32(arg[0].out, arg[1].in, dc->sar_m32); } else { TCGv_i64 v = tcg_temp_new_i64(); TCGv_i32 s = tcg_const_i32(32); tcg_gen_sub_i32(s, s, cpu_SR[SAR]); tcg_gen_andi_i32(s, s, 0x3f); - tcg_gen_extu_i32_i64(v, cpu_R[arg[1]]); + tcg_gen_extu_i32_i64(v, arg[1].in); gen_shift_reg(shl, s); tcg_temp_free(s); } } -static void translate_slli(DisasContext *dc, const uint32_t arg[], +static void translate_slli(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - if (arg[2] == 32) { + if (arg[2].imm == 32) { qemu_log_mask(LOG_GUEST_ERROR, "slli a%d, a%d, 32 is undefined\n", - arg[0], arg[1]); + arg[0].imm, arg[1].imm); } - tcg_gen_shli_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2] & 0x1f); + tcg_gen_shli_i32(arg[0].out, arg[1].in, arg[2].imm & 0x1f); } -static void translate_sra(DisasContext *dc, const uint32_t arg[], +static void translate_sra(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (dc->sar_m32_5bit) { - tcg_gen_sar_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_SR[SAR]); + tcg_gen_sar_i32(arg[0].out, arg[1].in, cpu_SR[SAR]); } else { TCGv_i64 v = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(v, cpu_R[arg[1]]); + tcg_gen_ext_i32_i64(v, arg[1].in); gen_shift(sar); } } -static void translate_srai(DisasContext *dc, const uint32_t arg[], +static void translate_srai(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_sari_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2]); + tcg_gen_sari_i32(arg[0].out, arg[1].in, arg[2].imm); } -static void translate_src(DisasContext *dc, const uint32_t arg[], +static void translate_src(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i64 v = tcg_temp_new_i64(); - tcg_gen_concat_i32_i64(v, cpu_R[arg[2]], cpu_R[arg[1]]); + tcg_gen_concat_i32_i64(v, arg[2].in, arg[1].in); gen_shift(shr); } -static void translate_srl(DisasContext *dc, const uint32_t arg[], +static void translate_srl(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (dc->sar_m32_5bit) { - tcg_gen_shr_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_SR[SAR]); + tcg_gen_shr_i32(arg[0].out, arg[1].in, cpu_SR[SAR]); } else { TCGv_i64 v = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(v, cpu_R[arg[1]]); + tcg_gen_extu_i32_i64(v, arg[1].in); gen_shift(shr); } } @@ -2295,138 +2686,138 @@ static void translate_srl(DisasContext *dc, const uint32_t arg[], #undef gen_shift #undef gen_shift_reg -static void translate_srli(DisasContext *dc, const uint32_t arg[], +static void translate_srli(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_shri_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2]); + tcg_gen_shri_i32(arg[0].out, arg[1].in, arg[2].imm); } -static void translate_ssa8b(DisasContext *dc, const uint32_t arg[], +static void translate_ssa8b(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[arg[0]], 3); + tcg_gen_shli_i32(tmp, arg[0].in, 3); gen_left_shift_sar(dc, tmp); tcg_temp_free(tmp); } -static void translate_ssa8l(DisasContext *dc, const uint32_t arg[], +static void translate_ssa8l(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[arg[0]], 3); + tcg_gen_shli_i32(tmp, arg[0].in, 3); gen_right_shift_sar(dc, tmp); tcg_temp_free(tmp); } -static void translate_ssai(DisasContext *dc, const uint32_t arg[], +static void translate_ssai(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 tmp = tcg_const_i32(arg[0]); + TCGv_i32 tmp = tcg_const_i32(arg[0].imm); gen_right_shift_sar(dc, tmp); tcg_temp_free(tmp); } -static void translate_ssl(DisasContext *dc, const uint32_t arg[], +static void translate_ssl(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_left_shift_sar(dc, cpu_R[arg[0]]); + gen_left_shift_sar(dc, arg[0].in); } -static void translate_ssr(DisasContext *dc, const uint32_t arg[], +static void translate_ssr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_right_shift_sar(dc, cpu_R[arg[0]]); + gen_right_shift_sar(dc, arg[0].in); } -static void translate_sub(DisasContext *dc, const uint32_t arg[], +static void translate_sub(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_sub_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_sub_i32(arg[0].out, arg[1].in, arg[2].in); } -static void translate_subx(DisasContext *dc, const uint32_t arg[], +static void translate_subx(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[arg[1]], par[0]); - tcg_gen_sub_i32(cpu_R[arg[0]], tmp, cpu_R[arg[2]]); + tcg_gen_shli_i32(tmp, arg[1].in, par[0]); + tcg_gen_sub_i32(arg[0].out, tmp, arg[2].in); tcg_temp_free(tmp); } -static void translate_waiti(DisasContext *dc, const uint32_t arg[], +static void translate_waiti(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - gen_waiti(dc, arg[0]); + gen_waiti(dc, arg[0].imm); #endif } -static void translate_wtlb(DisasContext *dc, const uint32_t arg[], +static void translate_wtlb(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY TCGv_i32 dtlb = tcg_const_i32(par[0]); - gen_helper_wtlb(cpu_env, cpu_R[arg[0]], cpu_R[arg[1]], dtlb); + gen_helper_wtlb(cpu_env, arg[0].in, arg[1].in, dtlb); tcg_temp_free(dtlb); #endif } -static void translate_wer(DisasContext *dc, const uint32_t arg[], +static void translate_wer(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_wer(cpu_env, cpu_R[arg[0]], cpu_R[arg[1]]); + gen_helper_wer(cpu_env, arg[0].in, arg[1].in); } -static void translate_wrmsk_expstate(DisasContext *dc, const uint32_t arg[], +static void translate_wrmsk_expstate(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { /* TODO: GPIO32 may be a part of coprocessor */ - tcg_gen_and_i32(cpu_UR[EXPSTATE], cpu_R[arg[0]], cpu_R[arg[1]]); + tcg_gen_and_i32(cpu_UR[EXPSTATE], arg[0].in, arg[1].in); } -static bool test_ill_wsr(DisasContext *dc, const uint32_t arg[], +static bool test_ill_wsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { return !check_sr(dc, par[0], SR_W); } -static void translate_wsr(DisasContext *dc, const uint32_t arg[], +static void translate_wsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_wsr(dc, par[0], cpu_R[arg[0]]); + gen_wsr(dc, par[0], arg[0].in); } -static void translate_wur(DisasContext *dc, const uint32_t arg[], +static void translate_wur(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { if (uregnames[par[0]].name) { - gen_wur(par[0], cpu_R[arg[0]]); + gen_wur(par[0], arg[0].in); } else { qemu_log_mask(LOG_UNIMP, "WUR %d not implemented\n", par[0]); } } -static void translate_xor(DisasContext *dc, const uint32_t arg[], +static void translate_xor(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_xor_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_xor_i32(arg[0].out, arg[1].in, arg[2].in); } -static bool test_ill_xsr(DisasContext *dc, const uint32_t arg[], +static bool test_ill_xsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { return !check_sr(dc, par[0], SR_X); } -static void translate_xsr(DisasContext *dc, const uint32_t arg[], +static void translate_xsr(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp, cpu_R[arg[0]]); - gen_rsr(dc, cpu_R[arg[0]], par[0]); + tcg_gen_mov_i32(tmp, arg[0].in); + gen_rsr(dc, arg[0].out, par[0]); gen_wsr(dc, par[0], tmp); tcg_temp_free(tmp); } @@ -2435,42 +2826,33 @@ static const XtensaOpcodeOps core_ops[] = { { .name = "abs", .translate = translate_abs, - .windowed_register_op = 0x3, }, { - .name = "add", + .name = (const char * const[]) { + "add", "add.n", NULL, + }, .translate = translate_add, - .windowed_register_op = 0x7, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "add.n", - .translate = translate_add, - .windowed_register_op = 0x7, - }, { - .name = "addi", - .translate = translate_addi, - .windowed_register_op = 0x3, - }, { - .name = "addi.n", + .name = (const char * const[]) { + "addi", "addi.n", NULL, + }, .translate = translate_addi, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { .name = "addmi", .translate = translate_addi, - .windowed_register_op = 0x3, }, { .name = "addx2", .translate = translate_addx, .par = (const uint32_t[]){1}, - .windowed_register_op = 0x7, }, { .name = "addx4", .translate = translate_addx, .par = (const uint32_t[]){2}, - .windowed_register_op = 0x7, }, { .name = "addx8", .translate = translate_addx, .par = (const uint32_t[]){3}, - .windowed_register_op = 0x7, }, { .name = "all4", .translate = translate_all, @@ -2482,7 +2864,6 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "and", .translate = translate_and, - .windowed_register_op = 0x7, }, { .name = "andb", .translate = translate_boolean, @@ -2500,139 +2881,177 @@ static const XtensaOpcodeOps core_ops[] = { .translate = translate_all, .par = (const uint32_t[]){false, 8}, }, { - .name = "ball", + .name = (const char * const[]) { + "ball", "ball.w15", "ball.w18", NULL, + }, .translate = translate_ball, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bany", + .name = (const char * const[]) { + "bany", "bany.w15", "bany.w18", NULL, + }, .translate = translate_bany, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bbc", + .name = (const char * const[]) { + "bbc", "bbc.w15", "bbc.w18", NULL, + }, .translate = translate_bb, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bbci", + .name = (const char * const[]) { + "bbci", "bbci.w15", "bbci.w18", NULL, + }, .translate = translate_bbi, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bbs", + .name = (const char * const[]) { + "bbs", "bbs.w15", "bbs.w18", NULL, + }, .translate = translate_bb, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bbsi", + .name = (const char * const[]) { + "bbsi", "bbsi.w15", "bbsi.w18", NULL, + }, .translate = translate_bbi, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "beq", + .name = (const char * const[]) { + "beq", "beq.w15", "beq.w18", NULL, + }, .translate = translate_b, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "beqi", + .name = (const char * const[]) { + "beqi", "beqi.w15", "beqi.w18", NULL, + }, .translate = translate_bi, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x1, - }, { - .name = "beqz", - .translate = translate_bz, - .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "beqz.n", + .name = (const char * const[]) { + "beqz", "beqz.n", "beqz.w15", "beqz.w18", NULL, + }, .translate = translate_bz, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { .name = "bf", .translate = translate_bp, .par = (const uint32_t[]){TCG_COND_EQ}, }, { - .name = "bge", + .name = (const char * const[]) { + "bge", "bge.w15", "bge.w18", NULL, + }, .translate = translate_b, .par = (const uint32_t[]){TCG_COND_GE}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bgei", + .name = (const char * const[]) { + "bgei", "bgei.w15", "bgei.w18", NULL, + }, .translate = translate_bi, .par = (const uint32_t[]){TCG_COND_GE}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bgeu", + .name = (const char * const[]) { + "bgeu", "bgeu.w15", "bgeu.w18", NULL, + }, .translate = translate_b, .par = (const uint32_t[]){TCG_COND_GEU}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bgeui", + .name = (const char * const[]) { + "bgeui", "bgeui.w15", "bgeui.w18", NULL, + }, .translate = translate_bi, .par = (const uint32_t[]){TCG_COND_GEU}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bgez", + .name = (const char * const[]) { + "bgez", "bgez.w15", "bgez.w18", NULL, + }, .translate = translate_bz, .par = (const uint32_t[]){TCG_COND_GE}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "blt", + .name = (const char * const[]) { + "blt", "blt.w15", "blt.w18", NULL, + }, .translate = translate_b, .par = (const uint32_t[]){TCG_COND_LT}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "blti", + .name = (const char * const[]) { + "blti", "blti.w15", "blti.w18", NULL, + }, .translate = translate_bi, .par = (const uint32_t[]){TCG_COND_LT}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bltu", + .name = (const char * const[]) { + "bltu", "bltu.w15", "bltu.w18", NULL, + }, .translate = translate_b, .par = (const uint32_t[]){TCG_COND_LTU}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bltui", + .name = (const char * const[]) { + "bltui", "bltui.w15", "bltui.w18", NULL, + }, .translate = translate_bi, .par = (const uint32_t[]){TCG_COND_LTU}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bltz", + .name = (const char * const[]) { + "bltz", "bltz.w15", "bltz.w18", NULL, + }, .translate = translate_bz, .par = (const uint32_t[]){TCG_COND_LT}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bnall", + .name = (const char * const[]) { + "bnall", "bnall.w15", "bnall.w18", NULL, + }, .translate = translate_ball, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bne", + .name = (const char * const[]) { + "bne", "bne.w15", "bne.w18", NULL, + }, .translate = translate_b, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bnei", + .name = (const char * const[]) { + "bnei", "bnei.w15", "bnei.w18", NULL, + }, .translate = translate_bi, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bnez", + .name = (const char * const[]) { + "bnez", "bnez.n", "bnez.w15", "bnez.w18", NULL, + }, .translate = translate_bz, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "bnez.n", - .translate = translate_bz, - .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x1, - }, { - .name = "bnone", + .name = (const char * const[]) { + "bnone", "bnone.w15", "bnone.w18", NULL, + }, .translate = translate_bany, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { .name = "break", .translate = translate_nop, @@ -2653,114 +3072,88 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "call12", .translate = translate_callw, - .test_overflow = test_overflow_callw, .par = (const uint32_t[]){3}, }, { .name = "call4", .translate = translate_callw, - .test_overflow = test_overflow_callw, .par = (const uint32_t[]){1}, }, { .name = "call8", .translate = translate_callw, - .test_overflow = test_overflow_callw, .par = (const uint32_t[]){2}, }, { .name = "callx0", .translate = translate_callx0, - .windowed_register_op = 0x1, }, { .name = "callx12", .translate = translate_callxw, - .test_overflow = test_overflow_callw, .par = (const uint32_t[]){3}, - .windowed_register_op = 0x1, }, { .name = "callx4", .translate = translate_callxw, - .test_overflow = test_overflow_callw, .par = (const uint32_t[]){1}, - .windowed_register_op = 0x1, }, { .name = "callx8", .translate = translate_callxw, - .test_overflow = test_overflow_callw, .par = (const uint32_t[]){2}, - .windowed_register_op = 0x1, }, { .name = "clamps", .translate = translate_clamps, - .windowed_register_op = 0x3, }, { .name = "clrb_expstate", .translate = translate_clrb_expstate, }, { .name = "const16", .translate = translate_const16, - .windowed_register_op = 0x1, }, { .name = "depbits", .translate = translate_depbits, - .windowed_register_op = 0x3, }, { .name = "dhi", .translate = translate_dcache, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "dhu", .translate = translate_dcache, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "dhwb", .translate = translate_dcache, - .windowed_register_op = 0x1, }, { .name = "dhwbi", .translate = translate_dcache, - .windowed_register_op = 0x1, }, { .name = "dii", .translate = translate_nop, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "diu", .translate = translate_nop, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "diwb", .translate = translate_nop, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "diwbi", .translate = translate_nop, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "dpfl", .translate = translate_dcache, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "dpfr", .translate = translate_nop, - .windowed_register_op = 0x1, }, { .name = "dpfro", .translate = translate_nop, - .windowed_register_op = 0x1, }, { .name = "dpfw", .translate = translate_nop, - .windowed_register_op = 0x1, }, { .name = "dpfwo", .translate = translate_nop, - .windowed_register_op = 0x1, }, { .name = "dsync", .translate = translate_nop, @@ -2769,7 +3162,8 @@ static const XtensaOpcodeOps core_ops[] = { .translate = translate_entry, .test_ill = test_ill_entry, .test_overflow = test_overflow_entry, - .op_flags = XTENSA_OP_EXIT_TB_M1, + .op_flags = XTENSA_OP_EXIT_TB_M1 | + XTENSA_OP_SYNC_REGISTER_WINDOW, }, { .name = "esync", .translate = translate_nop, @@ -2779,7 +3173,6 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "extui", .translate = translate_extui, - .windowed_register_op = 0x3, }, { .name = "extw", .translate = translate_memw, @@ -2794,47 +3187,38 @@ static const XtensaOpcodeOps core_ops[] = { .translate = translate_itlb, .par = (const uint32_t[]){true}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "ihi", .translate = translate_icache, - .windowed_register_op = 0x1, }, { .name = "ihu", .translate = translate_icache, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "iii", .translate = translate_nop, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "iitlb", .translate = translate_itlb, .par = (const uint32_t[]){false}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "iiu", .translate = translate_nop, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { - .name = "ill", - .op_flags = XTENSA_OP_ILL, - }, { - .name = "ill.n", - .op_flags = XTENSA_OP_ILL, + .name = (const char * const[]) { + "ill", "ill.n", NULL, + }, + .op_flags = XTENSA_OP_ILL | XTENSA_OP_NAME_ARRAY, }, { .name = "ipf", .translate = translate_nop, - .windowed_register_op = 0x1, }, { .name = "ipfl", .translate = translate_icache, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "isync", .translate = translate_nop, @@ -2844,498 +3228,423 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "jx", .translate = translate_jx, - .windowed_register_op = 0x1, }, { .name = "l16si", .translate = translate_ldst, .par = (const uint32_t[]){MO_TESW, false, false}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_LOAD, }, { .name = "l16ui", .translate = translate_ldst, .par = (const uint32_t[]){MO_TEUW, false, false}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_LOAD, }, { .name = "l32ai", .translate = translate_ldst, .par = (const uint32_t[]){MO_TEUL, true, false}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_LOAD, }, { .name = "l32e", .translate = translate_l32e, - .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, - }, { - .name = "l32i", - .translate = translate_ldst, - .par = (const uint32_t[]){MO_TEUL, false, false}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_LOAD, }, { - .name = "l32i.n", + .name = (const char * const[]) { + "l32i", "l32i.n", NULL, + }, .translate = translate_ldst, .par = (const uint32_t[]){MO_TEUL, false, false}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY | XTENSA_OP_LOAD, }, { .name = "l32r", .translate = translate_l32r, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_LOAD, }, { .name = "l8ui", .translate = translate_ldst, .par = (const uint32_t[]){MO_UB, false, false}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_LOAD, }, { .name = "lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_NONE, 0, 0, -4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_NONE, 0, -4}, + .op_flags = XTENSA_OP_LOAD, }, { .name = "ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_NONE, 0, 0, 4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_NONE, 0, 4}, + .op_flags = XTENSA_OP_LOAD, }, { .name = "ldpte", .op_flags = XTENSA_OP_ILL, }, { - .name = "loop", + .name = (const char * const[]) { + "loop", "loop.w15", NULL, + }, .translate = translate_loop, .par = (const uint32_t[]){TCG_COND_NEVER}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "loopgtz", + .name = (const char * const[]) { + "loopgtz", "loopgtz.w15", NULL, + }, .translate = translate_loop, .par = (const uint32_t[]){TCG_COND_GT}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "loopnez", + .name = (const char * const[]) { + "loopnez", "loopnez.w15", NULL, + }, .translate = translate_loop, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { .name = "max", .translate = translate_smax, - .windowed_register_op = 0x7, }, { .name = "maxu", .translate = translate_umax, - .windowed_register_op = 0x7, }, { .name = "memw", .translate = translate_memw, }, { .name = "min", .translate = translate_smin, - .windowed_register_op = 0x7, }, { .name = "minu", .translate = translate_umin, - .windowed_register_op = 0x7, }, { - .name = "mov", + .name = (const char * const[]) { + "mov", "mov.n", NULL, + }, .translate = translate_mov, - .windowed_register_op = 0x3, - }, { - .name = "mov.n", - .translate = translate_mov, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { .name = "moveqz", .translate = translate_movcond, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x7, }, { .name = "movf", .translate = translate_movp, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x3, }, { .name = "movgez", .translate = translate_movcond, .par = (const uint32_t[]){TCG_COND_GE}, - .windowed_register_op = 0x7, }, { .name = "movi", .translate = translate_movi, - .windowed_register_op = 0x1, }, { .name = "movi.n", .translate = translate_movi, - .windowed_register_op = 0x1, }, { .name = "movltz", .translate = translate_movcond, .par = (const uint32_t[]){TCG_COND_LT}, - .windowed_register_op = 0x7, }, { .name = "movnez", .translate = translate_movcond, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x7, }, { .name = "movsp", .translate = translate_movsp, - .windowed_register_op = 0x3, .op_flags = XTENSA_OP_ALLOCA, }, { .name = "movt", .translate = translate_movp, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x3, }, { .name = "mul.aa.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_AA, MAC16_HH, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MUL, MAC16_HH, 0}, }, { .name = "mul.aa.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_AA, MAC16_HL, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MUL, MAC16_HL, 0}, }, { .name = "mul.aa.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_AA, MAC16_LH, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MUL, MAC16_LH, 0}, }, { .name = "mul.aa.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_AA, MAC16_LL, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MUL, MAC16_LL, 0}, }, { .name = "mul.ad.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_AD, MAC16_HH, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MUL, MAC16_HH, 0}, }, { .name = "mul.ad.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_AD, MAC16_HL, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MUL, MAC16_HL, 0}, }, { .name = "mul.ad.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_AD, MAC16_LH, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MUL, MAC16_LH, 0}, }, { .name = "mul.ad.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_AD, MAC16_LL, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MUL, MAC16_LL, 0}, }, { .name = "mul.da.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_DA, MAC16_HH, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MUL, MAC16_HH, 0}, }, { .name = "mul.da.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_DA, MAC16_HL, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MUL, MAC16_HL, 0}, }, { .name = "mul.da.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_DA, MAC16_LH, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MUL, MAC16_LH, 0}, }, { .name = "mul.da.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_DA, MAC16_LL, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MUL, MAC16_LL, 0}, }, { .name = "mul.dd.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_DD, MAC16_HH, 0}, + .par = (const uint32_t[]){MAC16_MUL, MAC16_HH, 0}, }, { .name = "mul.dd.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_DD, MAC16_HL, 0}, + .par = (const uint32_t[]){MAC16_MUL, MAC16_HL, 0}, }, { .name = "mul.dd.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_DD, MAC16_LH, 0}, + .par = (const uint32_t[]){MAC16_MUL, MAC16_LH, 0}, }, { .name = "mul.dd.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MUL, MAC16_DD, MAC16_LL, 0}, + .par = (const uint32_t[]){MAC16_MUL, MAC16_LL, 0}, }, { .name = "mul16s", .translate = translate_mul16, .par = (const uint32_t[]){true}, - .windowed_register_op = 0x7, }, { .name = "mul16u", .translate = translate_mul16, .par = (const uint32_t[]){false}, - .windowed_register_op = 0x7, }, { .name = "mula.aa.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_AA, MAC16_HH, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HH, 0}, }, { .name = "mula.aa.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_AA, MAC16_HL, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HL, 0}, }, { .name = "mula.aa.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_AA, MAC16_LH, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LH, 0}, }, { .name = "mula.aa.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_AA, MAC16_LL, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LL, 0}, }, { .name = "mula.ad.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_AD, MAC16_HH, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HH, 0}, }, { .name = "mula.ad.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_AD, MAC16_HL, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HL, 0}, }, { .name = "mula.ad.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_AD, MAC16_LH, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LH, 0}, }, { .name = "mula.ad.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_AD, MAC16_LL, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LL, 0}, }, { .name = "mula.da.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HH, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HH, 0}, }, { .name = "mula.da.hh.lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HH, -4}, - .windowed_register_op = 0xa, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HH, -4}, }, { .name = "mula.da.hh.ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HH, 4}, - .windowed_register_op = 0xa, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HH, 4}, }, { .name = "mula.da.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HL, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HL, 0}, }, { .name = "mula.da.hl.lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HL, -4}, - .windowed_register_op = 0xa, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HL, -4}, }, { .name = "mula.da.hl.ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HL, 4}, - .windowed_register_op = 0xa, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HL, 4}, }, { .name = "mula.da.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LH, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LH, 0}, }, { .name = "mula.da.lh.lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LH, -4}, - .windowed_register_op = 0xa, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LH, -4}, }, { .name = "mula.da.lh.ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LH, 4}, - .windowed_register_op = 0xa, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LH, 4}, }, { .name = "mula.da.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LL, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LL, 0}, }, { .name = "mula.da.ll.lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LL, -4}, - .windowed_register_op = 0xa, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LL, -4}, }, { .name = "mula.da.ll.ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LL, 4}, - .windowed_register_op = 0xa, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LL, 4}, }, { .name = "mula.dd.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HH, 0}, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HH, 0}, }, { .name = "mula.dd.hh.lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HH, -4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HH, -4}, }, { .name = "mula.dd.hh.ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HH, 4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HH, 4}, }, { .name = "mula.dd.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HL, 0}, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HL, 0}, }, { .name = "mula.dd.hl.lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HL, -4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HL, -4}, }, { .name = "mula.dd.hl.ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HL, 4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_HL, 4}, }, { .name = "mula.dd.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LH, 0}, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LH, 0}, }, { .name = "mula.dd.lh.lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LH, -4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LH, -4}, }, { .name = "mula.dd.lh.ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LH, 4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LH, 4}, }, { .name = "mula.dd.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LL, 0}, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LL, 0}, }, { .name = "mula.dd.ll.lddec", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LL, -4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LL, -4}, }, { .name = "mula.dd.ll.ldinc", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LL, 4}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULA, MAC16_LL, 4}, }, { .name = "mull", .translate = translate_mull, - .windowed_register_op = 0x7, }, { .name = "muls.aa.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_AA, MAC16_HH, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MULS, MAC16_HH, 0}, }, { .name = "muls.aa.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_AA, MAC16_HL, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MULS, MAC16_HL, 0}, }, { .name = "muls.aa.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_AA, MAC16_LH, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MULS, MAC16_LH, 0}, }, { .name = "muls.aa.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_AA, MAC16_LL, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_MULS, MAC16_LL, 0}, }, { .name = "muls.ad.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_AD, MAC16_HH, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MULS, MAC16_HH, 0}, }, { .name = "muls.ad.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_AD, MAC16_HL, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MULS, MAC16_HL, 0}, }, { .name = "muls.ad.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_AD, MAC16_LH, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MULS, MAC16_LH, 0}, }, { .name = "muls.ad.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_AD, MAC16_LL, 0}, - .windowed_register_op = 0x1, + .par = (const uint32_t[]){MAC16_MULS, MAC16_LL, 0}, }, { .name = "muls.da.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_DA, MAC16_HH, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULS, MAC16_HH, 0}, }, { .name = "muls.da.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_DA, MAC16_HL, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULS, MAC16_HL, 0}, }, { .name = "muls.da.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_DA, MAC16_LH, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULS, MAC16_LH, 0}, }, { .name = "muls.da.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_DA, MAC16_LL, 0}, - .windowed_register_op = 0x2, + .par = (const uint32_t[]){MAC16_MULS, MAC16_LL, 0}, }, { .name = "muls.dd.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_DD, MAC16_HH, 0}, + .par = (const uint32_t[]){MAC16_MULS, MAC16_HH, 0}, }, { .name = "muls.dd.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_DD, MAC16_HL, 0}, + .par = (const uint32_t[]){MAC16_MULS, MAC16_HL, 0}, }, { .name = "muls.dd.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_DD, MAC16_LH, 0}, + .par = (const uint32_t[]){MAC16_MULS, MAC16_LH, 0}, }, { .name = "muls.dd.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_MULS, MAC16_DD, MAC16_LL, 0}, + .par = (const uint32_t[]){MAC16_MULS, MAC16_LL, 0}, }, { .name = "mulsh", .translate = translate_mulh, .par = (const uint32_t[]){true}, - .windowed_register_op = 0x7, }, { .name = "muluh", .translate = translate_mulh, .par = (const uint32_t[]){false}, - .windowed_register_op = 0x7, }, { .name = "neg", .translate = translate_neg, - .windowed_register_op = 0x3, }, { - .name = "nop", - .translate = translate_nop, - }, { - .name = "nop.n", + .name = (const char * const[]) { + "nop", "nop.n", NULL, + }, .translate = translate_nop, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { .name = "nsa", .translate = translate_nsa, - .windowed_register_op = 0x3, }, { .name = "nsau", .translate = translate_nsau, - .windowed_register_op = 0x3, }, { .name = "or", .translate = translate_or, - .windowed_register_op = 0x7, }, { .name = "orb", .translate = translate_boolean, @@ -3349,72 +3658,59 @@ static const XtensaOpcodeOps core_ops[] = { .translate = translate_ptlb, .par = (const uint32_t[]){true}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, }, { .name = "pitlb", .translate = translate_ptlb, .par = (const uint32_t[]){false}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, }, { .name = "quos", .translate = translate_quos, .par = (const uint32_t[]){true}, .op_flags = XTENSA_OP_DIVIDE_BY_ZERO, - .windowed_register_op = 0x7, }, { .name = "quou", .translate = translate_quou, .op_flags = XTENSA_OP_DIVIDE_BY_ZERO, - .windowed_register_op = 0x7, }, { .name = "rdtlb0", .translate = translate_rtlb, .par = (const uint32_t[]){true, 0}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, }, { .name = "rdtlb1", .translate = translate_rtlb, .par = (const uint32_t[]){true, 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, }, { .name = "read_impwire", .translate = translate_read_impwire, - .windowed_register_op = 0x1, }, { .name = "rems", .translate = translate_quos, .par = (const uint32_t[]){false}, .op_flags = XTENSA_OP_DIVIDE_BY_ZERO, - .windowed_register_op = 0x7, }, { .name = "remu", .translate = translate_remu, .op_flags = XTENSA_OP_DIVIDE_BY_ZERO, - .windowed_register_op = 0x7, }, { .name = "rer", .translate = translate_rer, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, - }, { - .name = "ret", - .translate = translate_ret, }, { - .name = "ret.n", + .name = (const char * const[]) { + "ret", "ret.n", NULL, + }, .translate = translate_ret, + .op_flags = XTENSA_OP_NAME_ARRAY, }, { - .name = "retw", + .name = (const char * const[]) { + "retw", "retw.n", NULL, + }, .translate = translate_retw, .test_ill = test_ill_retw, - .op_flags = XTENSA_OP_UNDERFLOW, - }, { - .name = "retw.n", - .translate = translate_retw, - .test_ill = test_ill_retw, - .op_flags = XTENSA_OP_UNDERFLOW, + .op_flags = XTENSA_OP_UNDERFLOW | XTENSA_OP_NAME_ARRAY, }, { .name = "rfdd", .op_flags = XTENSA_OP_ILL, @@ -3448,17 +3744,17 @@ static const XtensaOpcodeOps core_ops[] = { .translate = translate_rtlb, .par = (const uint32_t[]){false, 0}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, }, { .name = "ritlb1", .translate = translate_rtlb, .par = (const uint32_t[]){false, 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, }, { .name = "rotw", .translate = translate_rotw, - .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, + .op_flags = XTENSA_OP_PRIVILEGED | + XTENSA_OP_EXIT_TB_M1 | + XTENSA_OP_SYNC_REGISTER_WINDOW, }, { .name = "rsil", .translate = translate_rsil, @@ -3466,526 +3762,454 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "rsr.176", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){176}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.208", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){208}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.acchi", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){ACCHI}, - .windowed_register_op = 0x1, }, { .name = "rsr.acclo", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){ACCLO}, - .windowed_register_op = 0x1, }, { .name = "rsr.atomctl", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){ATOMCTL}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.br", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){BR}, - .windowed_register_op = 0x1, }, { .name = "rsr.cacheattr", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){CACHEATTR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ccompare0", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){CCOMPARE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ccompare1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){CCOMPARE + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ccompare2", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){CCOMPARE + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ccount", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){CCOUNT}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "rsr.configid0", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){CONFIGID0}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.configid1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){CONFIGID1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.cpenable", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){CPENABLE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.dbreaka0", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){DBREAKA}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.dbreaka1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){DBREAKA + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.dbreakc0", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){DBREAKC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.dbreakc1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){DBREAKC + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ddr", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){DDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.debugcause", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){DEBUGCAUSE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.depc", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){DEPC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.dtlbcfg", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){DTLBCFG}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.epc1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPC1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.epc2", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPC1 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.epc3", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPC1 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.epc4", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPC1 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.epc5", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPC1 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.epc6", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPC1 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.epc7", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPC1 + 6}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.eps2", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPS2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.eps3", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPS2 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.eps4", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPS2 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.eps5", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPS2 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.eps6", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPS2 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.eps7", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EPS2 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.exccause", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCCAUSE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.excsave1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCSAVE1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.excsave2", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCSAVE1 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.excsave3", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCSAVE1 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.excsave4", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCSAVE1 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.excsave5", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCSAVE1 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.excsave6", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCSAVE1 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.excsave7", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCSAVE1 + 6}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.excvaddr", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){EXCVADDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ibreaka0", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){IBREAKA}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ibreaka1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){IBREAKA + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ibreakenable", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){IBREAKENABLE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.icount", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){ICOUNT}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.icountlevel", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){ICOUNTLEVEL}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.intclear", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){INTCLEAR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.intenable", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){INTENABLE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.interrupt", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){INTSET}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "rsr.intset", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){INTSET}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "rsr.itlbcfg", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){ITLBCFG}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.lbeg", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){LBEG}, - .windowed_register_op = 0x1, }, { .name = "rsr.lcount", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){LCOUNT}, - .windowed_register_op = 0x1, }, { .name = "rsr.lend", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){LEND}, - .windowed_register_op = 0x1, }, { .name = "rsr.litbase", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){LITBASE}, - .windowed_register_op = 0x1, }, { .name = "rsr.m0", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MR}, - .windowed_register_op = 0x1, }, { .name = "rsr.m1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MR + 1}, - .windowed_register_op = 0x1, }, { .name = "rsr.m2", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MR + 2}, - .windowed_register_op = 0x1, }, { .name = "rsr.m3", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MR + 3}, - .windowed_register_op = 0x1, }, { .name = "rsr.memctl", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MEMCTL}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.misc0", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MISC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.misc1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MISC + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.misc2", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MISC + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.misc3", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){MISC + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, + }, { + .name = "rsr.prefctl", + .translate = translate_rsr, + .test_ill = test_ill_rsr, + .par = (const uint32_t[]){PREFCTL}, }, { .name = "rsr.prid", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){PRID}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ps", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){PS}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.ptevaddr", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){PTEVADDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.rasid", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){RASID}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.sar", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){SAR}, - .windowed_register_op = 0x1, }, { .name = "rsr.scompare1", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){SCOMPARE1}, - .windowed_register_op = 0x1, }, { .name = "rsr.vecbase", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){VECBASE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.windowbase", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){WINDOW_BASE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsr.windowstart", .translate = translate_rsr, .test_ill = test_ill_rsr, .par = (const uint32_t[]){WINDOW_START}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "rsync", .translate = translate_nop, @@ -3993,80 +4217,64 @@ static const XtensaOpcodeOps core_ops[] = { .name = "rur.expstate", .translate = translate_rur, .par = (const uint32_t[]){EXPSTATE}, - .windowed_register_op = 0x1, }, { .name = "rur.fcr", .translate = translate_rur, .par = (const uint32_t[]){FCR}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "rur.fsr", .translate = translate_rur, .par = (const uint32_t[]){FSR}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "rur.threadptr", .translate = translate_rur, .par = (const uint32_t[]){THREADPTR}, - .windowed_register_op = 0x1, }, { .name = "s16i", .translate = translate_ldst, .par = (const uint32_t[]){MO_TEUW, false, true}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_STORE, }, { .name = "s32c1i", .translate = translate_s32c1i, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_LOAD | XTENSA_OP_STORE, }, { .name = "s32e", .translate = translate_s32e, - .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, - }, { - .name = "s32i", - .translate = translate_ldst, - .par = (const uint32_t[]){MO_TEUL, false, true}, - .windowed_register_op = 0x3, - }, { - .name = "s32i.n", - .translate = translate_ldst, - .par = (const uint32_t[]){MO_TEUL, false, true}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_STORE, }, { - .name = "s32nb", + .name = (const char * const[]) { + "s32i", "s32i.n", "s32nb", NULL, + }, .translate = translate_ldst, .par = (const uint32_t[]){MO_TEUL, false, true}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_NAME_ARRAY | XTENSA_OP_STORE, }, { .name = "s32ri", .translate = translate_ldst, .par = (const uint32_t[]){MO_TEUL, true, true}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_STORE, }, { .name = "s8i", .translate = translate_ldst, .par = (const uint32_t[]){MO_UB, false, true}, - .windowed_register_op = 0x3, + .op_flags = XTENSA_OP_STORE, }, { .name = "salt", .translate = translate_salt, .par = (const uint32_t[]){TCG_COND_LT}, - .windowed_register_op = 0x7, }, { .name = "saltu", .translate = translate_salt, .par = (const uint32_t[]){TCG_COND_LTU}, - .windowed_register_op = 0x7, }, { .name = "setb_expstate", .translate = translate_setb_expstate, }, { .name = "sext", .translate = translate_sext, - .windowed_register_op = 0x3, }, { .name = "simcall", .translate = translate_simcall, @@ -4075,92 +4283,73 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "sll", .translate = translate_sll, - .windowed_register_op = 0x3, }, { .name = "slli", .translate = translate_slli, - .windowed_register_op = 0x3, }, { .name = "sra", .translate = translate_sra, - .windowed_register_op = 0x3, }, { .name = "srai", .translate = translate_srai, - .windowed_register_op = 0x3, }, { .name = "src", .translate = translate_src, - .windowed_register_op = 0x7, }, { .name = "srl", .translate = translate_srl, - .windowed_register_op = 0x3, }, { .name = "srli", .translate = translate_srli, - .windowed_register_op = 0x3, }, { .name = "ssa8b", .translate = translate_ssa8b, - .windowed_register_op = 0x1, }, { .name = "ssa8l", .translate = translate_ssa8l, - .windowed_register_op = 0x1, }, { .name = "ssai", .translate = translate_ssai, }, { .name = "ssl", .translate = translate_ssl, - .windowed_register_op = 0x1, }, { .name = "ssr", .translate = translate_ssr, - .windowed_register_op = 0x1, }, { .name = "sub", .translate = translate_sub, - .windowed_register_op = 0x7, }, { .name = "subx2", .translate = translate_subx, .par = (const uint32_t[]){1}, - .windowed_register_op = 0x7, }, { .name = "subx4", .translate = translate_subx, .par = (const uint32_t[]){2}, - .windowed_register_op = 0x7, }, { .name = "subx8", .translate = translate_subx, .par = (const uint32_t[]){3}, - .windowed_register_op = 0x7, }, { .name = "syscall", .op_flags = XTENSA_OP_SYSCALL, }, { .name = "umul.aa.hh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_UMUL, MAC16_AA, MAC16_HH, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_UMUL, MAC16_HH, 0}, }, { .name = "umul.aa.hl", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_UMUL, MAC16_AA, MAC16_HL, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_UMUL, MAC16_HL, 0}, }, { .name = "umul.aa.lh", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_UMUL, MAC16_AA, MAC16_LH, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_UMUL, MAC16_LH, 0}, }, { .name = "umul.aa.ll", .translate = translate_mac16, - .par = (const uint32_t[]){MAC16_UMUL, MAC16_AA, MAC16_LL, 0}, - .windowed_register_op = 0x3, + .par = (const uint32_t[]){MAC16_UMUL, MAC16_LL, 0}, }, { .name = "waiti", .translate = translate_waiti, @@ -4170,362 +4359,309 @@ static const XtensaOpcodeOps core_ops[] = { .translate = translate_wtlb, .par = (const uint32_t[]){true}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x3, }, { .name = "wer", .translate = translate_wer, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x3, }, { .name = "witlb", .translate = translate_wtlb, .par = (const uint32_t[]){false}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x3, }, { .name = "wrmsk_expstate", .translate = translate_wrmsk_expstate, - .windowed_register_op = 0x3, }, { .name = "wsr.176", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){176}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.208", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){208}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.acchi", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){ACCHI}, - .windowed_register_op = 0x1, }, { .name = "wsr.acclo", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){ACCLO}, - .windowed_register_op = 0x1, }, { .name = "wsr.atomctl", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){ATOMCTL}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.br", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){BR}, - .windowed_register_op = 0x1, }, { .name = "wsr.cacheattr", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){CACHEATTR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.ccompare0", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){CCOMPARE}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "wsr.ccompare1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){CCOMPARE + 1}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "wsr.ccompare2", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){CCOMPARE + 2}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "wsr.ccount", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){CCOUNT}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "wsr.configid0", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){CONFIGID0}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.configid1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){CONFIGID1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.cpenable", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){CPENABLE}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "wsr.dbreaka0", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){DBREAKA}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.dbreaka1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){DBREAKA + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.dbreakc0", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){DBREAKC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.dbreakc1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){DBREAKC + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.ddr", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){DDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.debugcause", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){DEBUGCAUSE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.depc", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){DEPC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.dtlbcfg", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){DTLBCFG}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.epc1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPC1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.epc2", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPC1 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.epc3", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPC1 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.epc4", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPC1 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.epc5", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPC1 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.epc6", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPC1 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.epc7", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPC1 + 6}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.eps2", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPS2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.eps3", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPS2 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.eps4", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPS2 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.eps5", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPS2 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.eps6", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPS2 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.eps7", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EPS2 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.exccause", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCCAUSE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.excsave1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCSAVE1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.excsave2", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCSAVE1 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.excsave3", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCSAVE1 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.excsave4", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCSAVE1 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.excsave5", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCSAVE1 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.excsave6", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCSAVE1 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.excsave7", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCSAVE1 + 6}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.excvaddr", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){EXCVADDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.ibreaka0", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){IBREAKA}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "wsr.ibreaka1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){IBREAKA + 1}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "wsr.ibreakenable", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){IBREAKENABLE}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "wsr.icount", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){ICOUNT}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.icountlevel", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){ICOUNTLEVEL}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "wsr.intclear", .translate = translate_wsr, @@ -4535,7 +4671,6 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "wsr.intenable", .translate = translate_wsr, @@ -4545,7 +4680,6 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "wsr.interrupt", .translate = translate_wsr, @@ -4555,7 +4689,6 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "wsr.intset", .translate = translate_wsr, @@ -4565,114 +4698,102 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "wsr.itlbcfg", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){ITLBCFG}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.lbeg", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){LBEG}, .op_flags = XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "wsr.lcount", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){LCOUNT}, - .windowed_register_op = 0x1, }, { .name = "wsr.lend", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){LEND}, .op_flags = XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "wsr.litbase", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){LITBASE}, .op_flags = XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "wsr.m0", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MR}, - .windowed_register_op = 0x1, }, { .name = "wsr.m1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MR + 1}, - .windowed_register_op = 0x1, }, { .name = "wsr.m2", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MR + 2}, - .windowed_register_op = 0x1, }, { .name = "wsr.m3", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MR + 3}, - .windowed_register_op = 0x1, }, { .name = "wsr.memctl", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MEMCTL}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.misc0", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MISC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.misc1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MISC + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.misc2", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MISC + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.misc3", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MISC + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.mmid", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){MMID}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, + }, { + .name = "wsr.prefctl", + .translate = translate_wsr, + .test_ill = test_ill_wsr, + .par = (const uint32_t[]){PREFCTL}, }, { .name = "wsr.prid", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){PRID}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.ps", .translate = translate_wsr, @@ -4682,80 +4803,69 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "wsr.ptevaddr", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){PTEVADDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.rasid", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){RASID}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "wsr.sar", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){SAR}, - .windowed_register_op = 0x1, }, { .name = "wsr.scompare1", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){SCOMPARE1}, - .windowed_register_op = 0x1, }, { .name = "wsr.vecbase", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){VECBASE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "wsr.windowbase", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){WINDOW_BASE}, - .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_PRIVILEGED | + XTENSA_OP_EXIT_TB_M1 | + XTENSA_OP_SYNC_REGISTER_WINDOW, }, { .name = "wsr.windowstart", .translate = translate_wsr, .test_ill = test_ill_wsr, .par = (const uint32_t[]){WINDOW_START}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "wur.expstate", .translate = translate_wur, .par = (const uint32_t[]){EXPSTATE}, - .windowed_register_op = 0x1, }, { .name = "wur.fcr", .translate = translate_wur, .par = (const uint32_t[]){FCR}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "wur.fsr", .translate = translate_wur, .par = (const uint32_t[]){FSR}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "wur.threadptr", .translate = translate_wur, .par = (const uint32_t[]){THREADPTR}, - .windowed_register_op = 0x1, }, { .name = "xor", .translate = translate_xor, - .windowed_register_op = 0x7, }, { .name = "xorb", .translate = translate_boolean, @@ -4766,340 +4876,291 @@ static const XtensaOpcodeOps core_ops[] = { .test_ill = test_ill_xsr, .par = (const uint32_t[]){176}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.208", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){208}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.acchi", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){ACCHI}, - .windowed_register_op = 0x1, }, { .name = "xsr.acclo", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){ACCLO}, - .windowed_register_op = 0x1, }, { .name = "xsr.atomctl", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){ATOMCTL}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.br", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){BR}, - .windowed_register_op = 0x1, }, { .name = "xsr.cacheattr", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){CACHEATTR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.ccompare0", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){CCOMPARE}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "xsr.ccompare1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){CCOMPARE + 1}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "xsr.ccompare2", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){CCOMPARE + 2}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "xsr.ccount", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){CCOUNT}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "xsr.configid0", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){CONFIGID0}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.configid1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){CONFIGID1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.cpenable", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){CPENABLE}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "xsr.dbreaka0", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){DBREAKA}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.dbreaka1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){DBREAKA + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.dbreakc0", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){DBREAKC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.dbreakc1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){DBREAKC + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.ddr", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){DDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.debugcause", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){DEBUGCAUSE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.depc", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){DEPC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.dtlbcfg", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){DTLBCFG}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.epc1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPC1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.epc2", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPC1 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.epc3", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPC1 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.epc4", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPC1 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.epc5", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPC1 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.epc6", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPC1 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.epc7", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPC1 + 6}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.eps2", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPS2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.eps3", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPS2 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.eps4", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPS2 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.eps5", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPS2 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.eps6", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPS2 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.eps7", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EPS2 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.exccause", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCCAUSE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.excsave1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCSAVE1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.excsave2", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCSAVE1 + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.excsave3", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCSAVE1 + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.excsave4", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCSAVE1 + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.excsave5", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCSAVE1 + 4}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.excsave6", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCSAVE1 + 5}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.excsave7", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCSAVE1 + 6}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.excvaddr", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){EXCVADDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.ibreaka0", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){IBREAKA}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "xsr.ibreaka1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){IBREAKA + 1}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "xsr.ibreakenable", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){IBREAKENABLE}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0, - .windowed_register_op = 0x1, }, { .name = "xsr.icount", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){ICOUNT}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.icountlevel", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){ICOUNTLEVEL}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "xsr.intclear", .translate = translate_xsr, @@ -5109,7 +5170,6 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "xsr.intenable", .translate = translate_xsr, @@ -5119,7 +5179,6 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "xsr.interrupt", .translate = translate_xsr, @@ -5129,7 +5188,6 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "xsr.intset", .translate = translate_xsr, @@ -5139,107 +5197,96 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "xsr.itlbcfg", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){ITLBCFG}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.lbeg", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){LBEG}, .op_flags = XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "xsr.lcount", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){LCOUNT}, - .windowed_register_op = 0x1, }, { .name = "xsr.lend", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){LEND}, .op_flags = XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "xsr.litbase", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){LITBASE}, .op_flags = XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "xsr.m0", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MR}, - .windowed_register_op = 0x1, }, { .name = "xsr.m1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MR + 1}, - .windowed_register_op = 0x1, }, { .name = "xsr.m2", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MR + 2}, - .windowed_register_op = 0x1, }, { .name = "xsr.m3", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MR + 3}, - .windowed_register_op = 0x1, }, { .name = "xsr.memctl", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MEMCTL}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.misc0", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MISC}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.misc1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MISC + 1}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.misc2", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MISC + 2}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.misc3", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){MISC + 3}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, + }, { + .name = "xsr.prefctl", + .translate = translate_xsr, + .test_ill = test_ill_xsr, + .par = (const uint32_t[]){PREFCTL}, }, { .name = "xsr.prid", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){PRID}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.ps", .translate = translate_xsr, @@ -5249,54 +5296,48 @@ static const XtensaOpcodeOps core_ops[] = { XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1 | XTENSA_OP_CHECK_INTERRUPTS, - .windowed_register_op = 0x1, }, { .name = "xsr.ptevaddr", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){PTEVADDR}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.rasid", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){RASID}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, { .name = "xsr.sar", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){SAR}, - .windowed_register_op = 0x1, }, { .name = "xsr.scompare1", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){SCOMPARE1}, - .windowed_register_op = 0x1, }, { .name = "xsr.vecbase", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){VECBASE}, .op_flags = XTENSA_OP_PRIVILEGED, - .windowed_register_op = 0x1, }, { .name = "xsr.windowbase", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){WINDOW_BASE}, - .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, + .op_flags = XTENSA_OP_PRIVILEGED | + XTENSA_OP_EXIT_TB_M1 | + XTENSA_OP_SYNC_REGISTER_WINDOW, }, { .name = "xsr.windowstart", .translate = translate_xsr, .test_ill = test_ill_xsr, .par = (const uint32_t[]){WINDOW_START}, .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1, - .windowed_register_op = 0x1, }, }; @@ -5306,17 +5347,17 @@ const XtensaOpcodeTranslators xtensa_core_opcodes = { }; -static void translate_abs_s(DisasContext *dc, const uint32_t arg[], +static void translate_abs_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_abs_s(cpu_FR[arg[0]], cpu_FR[arg[1]]); + gen_helper_abs_s(arg[0].out, arg[1].in); } -static void translate_add_s(DisasContext *dc, const uint32_t arg[], +static void translate_add_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_add_s(cpu_FR[arg[0]], cpu_env, - cpu_FR[arg[1]], cpu_FR[arg[2]]); + gen_helper_add_s(arg[0].out, cpu_env, + arg[1].in, arg[2].in); } enum { @@ -5329,7 +5370,7 @@ enum { COMPARE_ULE, }; -static void translate_compare_s(DisasContext *dc, const uint32_t arg[], +static void translate_compare_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { static void (* const helper[])(TCGv_env env, TCGv_i32 bit, @@ -5342,153 +5383,153 @@ static void translate_compare_s(DisasContext *dc, const uint32_t arg[], [COMPARE_OLE] = gen_helper_ole_s, [COMPARE_ULE] = gen_helper_ule_s, }; - TCGv_i32 bit = tcg_const_i32(1 << arg[0]); + TCGv_i32 bit = tcg_const_i32(1 << arg[0].imm); - helper[par[0]](cpu_env, bit, cpu_FR[arg[1]], cpu_FR[arg[2]]); + helper[par[0]](cpu_env, bit, arg[1].in, arg[2].in); tcg_temp_free(bit); } -static void translate_float_s(DisasContext *dc, const uint32_t arg[], +static void translate_float_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - TCGv_i32 scale = tcg_const_i32(-arg[2]); + TCGv_i32 scale = tcg_const_i32(-arg[2].imm); if (par[0]) { - gen_helper_uitof(cpu_FR[arg[0]], cpu_env, cpu_R[arg[1]], scale); + gen_helper_uitof(arg[0].out, cpu_env, arg[1].in, scale); } else { - gen_helper_itof(cpu_FR[arg[0]], cpu_env, cpu_R[arg[1]], scale); + gen_helper_itof(arg[0].out, cpu_env, arg[1].in, scale); } tcg_temp_free(scale); } -static void translate_ftoi_s(DisasContext *dc, const uint32_t arg[], +static void translate_ftoi_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 rounding_mode = tcg_const_i32(par[0]); - TCGv_i32 scale = tcg_const_i32(arg[2]); + TCGv_i32 scale = tcg_const_i32(arg[2].imm); if (par[1]) { - gen_helper_ftoui(cpu_R[arg[0]], cpu_FR[arg[1]], + gen_helper_ftoui(arg[0].out, arg[1].in, rounding_mode, scale); } else { - gen_helper_ftoi(cpu_R[arg[0]], cpu_FR[arg[1]], + gen_helper_ftoi(arg[0].out, arg[1].in, rounding_mode, scale); } tcg_temp_free(rounding_mode); tcg_temp_free(scale); } -static void translate_ldsti(DisasContext *dc, const uint32_t arg[], +static void translate_ldsti(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + tcg_gen_addi_i32(addr, arg[1].in, arg[2].imm); gen_load_store_alignment(dc, 2, addr, false); if (par[0]) { - tcg_gen_qemu_st32(cpu_FR[arg[0]], addr, dc->cring); + tcg_gen_qemu_st32(arg[0].in, addr, dc->cring); } else { - tcg_gen_qemu_ld32u(cpu_FR[arg[0]], addr, dc->cring); + tcg_gen_qemu_ld32u(arg[0].out, addr, dc->cring); } if (par[1]) { - tcg_gen_mov_i32(cpu_R[arg[1]], addr); + tcg_gen_mov_i32(arg[1].out, addr); } tcg_temp_free(addr); } -static void translate_ldstx(DisasContext *dc, const uint32_t arg[], +static void translate_ldstx(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_add_i32(addr, cpu_R[arg[1]], cpu_R[arg[2]]); + tcg_gen_add_i32(addr, arg[1].in, arg[2].in); gen_load_store_alignment(dc, 2, addr, false); if (par[0]) { - tcg_gen_qemu_st32(cpu_FR[arg[0]], addr, dc->cring); + tcg_gen_qemu_st32(arg[0].in, addr, dc->cring); } else { - tcg_gen_qemu_ld32u(cpu_FR[arg[0]], addr, dc->cring); + tcg_gen_qemu_ld32u(arg[0].out, addr, dc->cring); } if (par[1]) { - tcg_gen_mov_i32(cpu_R[arg[1]], addr); + tcg_gen_mov_i32(arg[1].out, addr); } tcg_temp_free(addr); } -static void translate_madd_s(DisasContext *dc, const uint32_t arg[], +static void translate_madd_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_madd_s(cpu_FR[arg[0]], cpu_env, - cpu_FR[arg[0]], cpu_FR[arg[1]], cpu_FR[arg[2]]); + gen_helper_madd_s(arg[0].out, cpu_env, + arg[0].in, arg[1].in, arg[2].in); } -static void translate_mov_s(DisasContext *dc, const uint32_t arg[], +static void translate_mov_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_FR[arg[1]]); + tcg_gen_mov_i32(arg[0].out, arg[1].in); } -static void translate_movcond_s(DisasContext *dc, const uint32_t arg[], +static void translate_movcond_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 zero = tcg_const_i32(0); - tcg_gen_movcond_i32(par[0], cpu_FR[arg[0]], - cpu_R[arg[2]], zero, - cpu_FR[arg[1]], cpu_FR[arg[0]]); + tcg_gen_movcond_i32(par[0], arg[0].out, + arg[2].in, zero, + arg[1].in, arg[0].in); tcg_temp_free(zero); } -static void translate_movp_s(DisasContext *dc, const uint32_t arg[], +static void translate_movp_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 zero = tcg_const_i32(0); TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << arg[2]); + tcg_gen_andi_i32(tmp, arg[2].in, 1 << arg[2].imm); tcg_gen_movcond_i32(par[0], - cpu_FR[arg[0]], tmp, zero, - cpu_FR[arg[1]], cpu_FR[arg[0]]); + arg[0].out, tmp, zero, + arg[1].in, arg[0].in); tcg_temp_free(tmp); tcg_temp_free(zero); } -static void translate_mul_s(DisasContext *dc, const uint32_t arg[], +static void translate_mul_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_mul_s(cpu_FR[arg[0]], cpu_env, - cpu_FR[arg[1]], cpu_FR[arg[2]]); + gen_helper_mul_s(arg[0].out, cpu_env, + arg[1].in, arg[2].in); } -static void translate_msub_s(DisasContext *dc, const uint32_t arg[], +static void translate_msub_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_msub_s(cpu_FR[arg[0]], cpu_env, - cpu_FR[arg[0]], cpu_FR[arg[1]], cpu_FR[arg[2]]); + gen_helper_msub_s(arg[0].out, cpu_env, + arg[0].in, arg[1].in, arg[2].in); } -static void translate_neg_s(DisasContext *dc, const uint32_t arg[], +static void translate_neg_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_neg_s(cpu_FR[arg[0]], cpu_FR[arg[1]]); + gen_helper_neg_s(arg[0].out, arg[1].in); } -static void translate_rfr_s(DisasContext *dc, const uint32_t arg[], +static void translate_rfr_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(cpu_R[arg[0]], cpu_FR[arg[1]]); + tcg_gen_mov_i32(arg[0].out, arg[1].in); } -static void translate_sub_s(DisasContext *dc, const uint32_t arg[], +static void translate_sub_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - gen_helper_sub_s(cpu_FR[arg[0]], cpu_env, - cpu_FR[arg[1]], cpu_FR[arg[2]]); + gen_helper_sub_s(arg[0].out, cpu_env, + arg[1].in, arg[2].in); } -static void translate_wfr_s(DisasContext *dc, const uint32_t arg[], +static void translate_wfr_s(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_R[arg[1]]); + tcg_gen_mov_i32(arg[0].out, arg[1].in); } static const XtensaOpcodeOps fpu2000_ops[] = { @@ -5504,43 +5545,40 @@ static const XtensaOpcodeOps fpu2000_ops[] = { .name = "ceil.s", .translate = translate_ftoi_s, .par = (const uint32_t[]){float_round_up, false}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "float.s", .translate = translate_float_s, .par = (const uint32_t[]){false}, - .windowed_register_op = 0x2, .coprocessor = 0x1, }, { .name = "floor.s", .translate = translate_ftoi_s, .par = (const uint32_t[]){float_round_down, false}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "lsi", .translate = translate_ldsti, .par = (const uint32_t[]){false, false}, - .windowed_register_op = 0x2, + .op_flags = XTENSA_OP_LOAD, .coprocessor = 0x1, }, { .name = "lsiu", .translate = translate_ldsti, .par = (const uint32_t[]){false, true}, - .windowed_register_op = 0x2, + .op_flags = XTENSA_OP_LOAD, .coprocessor = 0x1, }, { .name = "lsx", .translate = translate_ldstx, .par = (const uint32_t[]){false, false}, - .windowed_register_op = 0x6, + .op_flags = XTENSA_OP_LOAD, .coprocessor = 0x1, }, { .name = "lsxu", .translate = translate_ldstx, .par = (const uint32_t[]){false, true}, - .windowed_register_op = 0x6, + .op_flags = XTENSA_OP_LOAD, .coprocessor = 0x1, }, { .name = "madd.s", @@ -5554,7 +5592,6 @@ static const XtensaOpcodeOps fpu2000_ops[] = { .name = "moveqz.s", .translate = translate_movcond_s, .par = (const uint32_t[]){TCG_COND_EQ}, - .windowed_register_op = 0x4, .coprocessor = 0x1, }, { .name = "movf.s", @@ -5565,19 +5602,16 @@ static const XtensaOpcodeOps fpu2000_ops[] = { .name = "movgez.s", .translate = translate_movcond_s, .par = (const uint32_t[]){TCG_COND_GE}, - .windowed_register_op = 0x4, .coprocessor = 0x1, }, { .name = "movltz.s", .translate = translate_movcond_s, .par = (const uint32_t[]){TCG_COND_LT}, - .windowed_register_op = 0x4, .coprocessor = 0x1, }, { .name = "movnez.s", .translate = translate_movcond_s, .par = (const uint32_t[]){TCG_COND_NE}, - .windowed_register_op = 0x4, .coprocessor = 0x1, }, { .name = "movt.s", @@ -5614,37 +5648,35 @@ static const XtensaOpcodeOps fpu2000_ops[] = { }, { .name = "rfr", .translate = translate_rfr_s, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "round.s", .translate = translate_ftoi_s, .par = (const uint32_t[]){float_round_nearest_even, false}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "ssi", .translate = translate_ldsti, .par = (const uint32_t[]){true, false}, - .windowed_register_op = 0x2, + .op_flags = XTENSA_OP_STORE, .coprocessor = 0x1, }, { .name = "ssiu", .translate = translate_ldsti, .par = (const uint32_t[]){true, true}, - .windowed_register_op = 0x2, + .op_flags = XTENSA_OP_STORE, .coprocessor = 0x1, }, { .name = "ssx", .translate = translate_ldstx, .par = (const uint32_t[]){true, false}, - .windowed_register_op = 0x6, + .op_flags = XTENSA_OP_STORE, .coprocessor = 0x1, }, { .name = "ssxu", .translate = translate_ldstx, .par = (const uint32_t[]){true, true}, - .windowed_register_op = 0x6, + .op_flags = XTENSA_OP_STORE, .coprocessor = 0x1, }, { .name = "sub.s", @@ -5654,7 +5686,6 @@ static const XtensaOpcodeOps fpu2000_ops[] = { .name = "trunc.s", .translate = translate_ftoi_s, .par = (const uint32_t[]){float_round_to_zero, false}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "ueq.s", @@ -5665,7 +5696,6 @@ static const XtensaOpcodeOps fpu2000_ops[] = { .name = "ufloat.s", .translate = translate_float_s, .par = (const uint32_t[]){true}, - .windowed_register_op = 0x2, .coprocessor = 0x1, }, { .name = "ule.s", @@ -5686,12 +5716,10 @@ static const XtensaOpcodeOps fpu2000_ops[] = { .name = "utrunc.s", .translate = translate_ftoi_s, .par = (const uint32_t[]){float_round_to_zero, true}, - .windowed_register_op = 0x1, .coprocessor = 0x1, }, { .name = "wfr", .translate = translate_wfr_s, - .windowed_register_op = 0x2, .coprocessor = 0x1, }, }; diff --git a/target/xtensa/win_helper.c b/target/xtensa/win_helper.c index 7d793d4f9c..f6f96a64c3 100644 --- a/target/xtensa/win_helper.c +++ b/target/xtensa/win_helper.c @@ -96,9 +96,9 @@ void xtensa_rotate_window(CPUXtensaState *env, uint32_t delta) xtensa_rotate_window_abs(env, env->sregs[WINDOW_BASE] + delta); } -void HELPER(wsr_windowbase)(CPUXtensaState *env, uint32_t v) +void HELPER(sync_windowbase)(CPUXtensaState *env) { - xtensa_rotate_window_abs(env, v); + xtensa_rotate_window_abs(env, env->windowbase_next); } void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm) @@ -106,9 +106,8 @@ void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm) int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT; env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - imm; - xtensa_rotate_window(env, callinc); - env->sregs[WINDOW_START] |= - windowstart_bit(env->sregs[WINDOW_BASE], env); + env->windowbase_next = env->sregs[WINDOW_BASE] + callinc; + env->sregs[WINDOW_START] |= windowstart_bit(env->windowbase_next, env); } void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w) @@ -185,20 +184,11 @@ void HELPER(test_underflow_retw)(CPUXtensaState *env, uint32_t pc) } } -uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc) +void HELPER(retw)(CPUXtensaState *env, uint32_t a0) { - int n = (env->regs[0] >> 30) & 0x3; - uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env); - uint32_t ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff); + int n = (a0 >> 30) & 0x3; xtensa_rotate_window(env, -n); - env->sregs[WINDOW_START] &= ~windowstart_bit(windowbase, env); - return ret_pc; -} - -void HELPER(rotw)(CPUXtensaState *env, uint32_t imm4) -{ - xtensa_rotate_window(env, imm4); } void xtensa_restore_owb(CPUXtensaState *env) diff --git a/tests/.gitignore b/tests/.gitignore index 72c18aaab0..f2bf85c8c4 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,6 +5,7 @@ benchmark-crypto-hmac check-* !check-*.c !check-*.sh +fp/*.out qht-bench rcutorture test-* diff --git a/tests/Makefile.include b/tests/Makefile.include index b39e989f72..c2ac4b8d4c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -70,6 +70,7 @@ check-unit-y += tests/test-throttle$(EXESUF) check-unit-y += tests/test-thread-pool$(EXESUF) check-unit-y += tests/test-hbitmap$(EXESUF) check-unit-y += tests/test-bdrv-drain$(EXESUF) +check-unit-y += tests/test-bdrv-graph-mod$(EXESUF) check-unit-y += tests/test-blockjob$(EXESUF) check-unit-y += tests/test-blockjob-txn$(EXESUF) check-unit-y += tests/test-block-backend$(EXESUF) @@ -111,10 +112,15 @@ check-unit-y += tests/test-crypto-secret$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF) ifneq (,$(findstring qemu-ga,$(TOOLS))) -check-unit-$(land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) +check-unit-$(call land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) endif check-unit-y += tests/test-timed-average$(EXESUF) +check-unit-$(CONFIG_INOTIFY1) += tests/test-util-filemonitor$(EXESUF) check-unit-y += tests/test-util-sockets$(EXESUF) +check-unit-y += tests/test-authz-simple$(EXESUF) +check-unit-y += tests/test-authz-list$(EXESUF) +check-unit-y += tests/test-authz-listfile$(EXESUF) +check-unit-$(CONFIG_AUTH_PAM) += tests/test-authz-pam$(EXESUF) check-unit-y += tests/test-io-task$(EXESUF) check-unit-y += tests/test-io-channel-socket$(EXESUF) check-unit-y += tests/test-io-channel-file$(EXESUF) @@ -192,6 +198,7 @@ check-qtest-i386-$(CONFIG_ISA_IPMI_KCS) += tests/ipmi-kcs-test$(EXESUF) # check-qtest-i386-$(CONFIG_ISA_IPMI_BT) += tests/ipmi-bt-test$(EXESUF) check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) +check-qtest-i386-y += tests/device-plug-test$(EXESUF) check-qtest-i386-y += tests/drive_del-test$(EXESUF) check-qtest-i386-$(CONFIG_WDT_IB700) += tests/wdt_ib700-test$(EXESUF) check-qtest-i386-y += tests/tco-test$(EXESUF) @@ -209,10 +216,7 @@ check-qtest-i386-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF) check-qtest-i386-y += tests/cpu-plug-test$(EXESUF) check-qtest-i386-y += tests/q35-test$(EXESUF) check-qtest-i386-y += tests/vmgenid-test$(EXESUF) -check-qtest-i386-$(CONFIG_VHOST_USER_NET_TEST_i386) += tests/vhost-user-test$(EXESUF) -ifeq ($(CONFIG_VHOST_USER_NET_TEST_i386),) -check-qtest-x86_64-$(CONFIG_VHOST_USER_NET_TEST_x86_64) += tests/vhost-user-test$(EXESUF) -endif +check-qtest-i386-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test$(EXESUF) check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF) check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF) check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF) @@ -256,6 +260,7 @@ check-qtest-ppc-$(CONFIG_M48T59) += tests/m48t59-test$(EXESUF) check-qtest-ppc64-y += $(check-qtest-ppc-y) check-qtest-ppc64-$(CONFIG_PSERIES) += tests/spapr-phb-test$(EXESUF) +check-qtest-ppc64-$(CONFIG_PSERIES) += tests/device-plug-test$(EXESUF) check-qtest-ppc64-$(CONFIG_POWERNV) += tests/pnv-xscom-test$(EXESUF) check-qtest-ppc64-y += tests/migration-test$(EXESUF) check-qtest-ppc64-$(CONFIG_PSERIES) += tests/rtas-test$(EXESUF) @@ -310,6 +315,7 @@ check-qtest-s390x-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF) check-qtest-s390x-y += tests/drive_del-test$(EXESUF) +check-qtest-s390x-y += tests/device-plug-test$(EXESUF) check-qtest-s390x-y += tests/virtio-ccw-test$(EXESUF) check-qtest-s390x-y += tests/cpu-plug-test$(EXESUF) check-qtest-s390x-y += tests/migration-test$(EXESUF) @@ -532,9 +538,10 @@ test-qom-obj-y = $(qom-obj-y) $(test-util-obj-y) test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \ tests/test-qapi-introspect.o \ $(test-qom-obj-y) -benchmark-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y) -test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y) +benchmark-crypto-obj-y = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y) +test-crypto-obj-y = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y) test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y) +test-authz-obj-y = $(test-qom-obj-y) $(authz-obj-y) test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y) @@ -555,6 +562,7 @@ tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y) tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y) tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y) tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y) +tests/test-bdrv-graph-mod$(EXESUF): tests/test-bdrv-graph-mod.o $(test-block-obj-y) $(test-util-obj-y) tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y) tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y) @@ -657,8 +665,14 @@ tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \ tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \ tests/crypto-tls-psk-helpers.o \ $(test-crypto-obj-y) +tests/test-util-filemonitor$(EXESUF): tests/test-util-filemonitor.o \ + $(test-util-obj-y) tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \ tests/socket-helpers.o $(test-util-obj-y) +tests/test-authz-simple$(EXESUF): tests/test-authz-simple.o $(test-authz-obj-y) +tests/test-authz-list$(EXESUF): tests/test-authz-list.o $(test-authz-obj-y) +tests/test-authz-listfile$(EXESUF): tests/test-authz-listfile.o $(test-authz-obj-y) +tests/test-authz-pam$(EXESUF): tests/test-authz-pam.o $(test-authz-obj-y) tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y) tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \ tests/io-channel-helpers.o tests/socket-helpers.o $(test-io-obj-y) @@ -750,6 +764,7 @@ tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o tests/qom-test$(EXESUF): tests/qom-test.o tests/test-hmp$(EXESUF): tests/test-hmp.o tests/machine-none-test$(EXESUF): tests/machine-none-test.o +tests/device-plug-test$(EXESUF): tests/device-plug-test.o tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y) tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y) tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o @@ -896,23 +911,20 @@ $(FP_TEST_BIN): "BUILD", "$(notdir $@)") # The full test suite can take a bit of time, default to a quick run -ifeq ($(SPEED), quick) -FP_TL=-l 1 -else -FP_TL=-l 2 -r all -endif +# "-l 2 -r all" can take more than a day for some operations and is best +# run manually +FP_TL=-l 1 -r all -# $1 = tests, $2 = description +# $1 = tests, $2 = description, $3 = test flags test-softfloat = $(call quiet-command, \ cd $(BUILD_DIR)/tests/fp && \ - ./fp-test -s $(FP_TL) $1 > $2.out 2>&1 || \ + ./fp-test -s $(if $3,$3,$(FP_TL)) $1 > $2.out 2>&1 || \ (cat $2.out && exit 1;), \ "FLOAT TEST", $2) # Conversion Routines: # FIXME: i32_to_extF80 (broken), i64_to_extF80 (broken) -# ui32_to_f128 (not implemented), f128_to_ui32 (not implemented) -# extF80_roundToInt (broken) +# ui32_to_f128 (not implemented), extF80_roundToInt (broken) # check-softfloat-conv: $(FP_TEST_BIN) $(call test-softfloat, \ @@ -941,9 +953,11 @@ check-softfloat-conv: $(FP_TEST_BIN) f16_to_ui32 f16_to_ui32_r_minMag \ f32_to_ui32 f32_to_ui32_r_minMag \ f64_to_ui32 f64_to_ui32_r_minMag \ + f128_to_ui32 f128_to_ui32_r_minMag \ f16_to_ui64 f16_to_ui64_r_minMag \ f32_to_ui64 f32_to_ui64_r_minMag \ - f64_to_ui64 f64_to_ui64_r_minMag, \ + f64_to_ui64 f64_to_ui64_r_minMag \ + f128_to_ui64 f128_to_ui64_r_minMag, \ float-to-uint) $(call test-softfloat, \ f16_roundToInt f32_roundToInt \ @@ -985,7 +999,7 @@ check-softfloat-compare: $(SF_COMPARE_RULES) check-softfloat-mulAdd: $(FP_TEST_BIN) $(call test-softfloat, \ f16_mulAdd f32_mulAdd f64_mulAdd f128_mulAdd, \ - mulAdd) + mulAdd,-l 1) # FIXME: extF80_rem (broken) check-softfloat-rem: $(FP_TEST_BIN) diff --git a/tests/cdrom-test.c b/tests/cdrom-test.c index 14bd981336..05611da648 100644 --- a/tests/cdrom-test.c +++ b/tests/cdrom-test.c @@ -132,8 +132,14 @@ static void add_x86_tests(void) qtest_add_data_func("cdrom/boot/virtio-scsi", "-device virtio-scsi -device scsi-cd,drive=cdr " "-blockdev file,node-name=cdr,filename=", test_cdboot); - qtest_add_data_func("cdrom/boot/isapc", "-M isapc " - "-drive if=ide,media=cdrom,file=", test_cdboot); + /* + * Unstable CI test under load + * See https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg05509.html + */ + if (g_test_slow()) { + qtest_add_data_func("cdrom/boot/isapc", "-M isapc " + "-drive if=ide,media=cdrom,file=", test_cdboot); + } qtest_add_data_func("cdrom/boot/am53c974", "-device am53c974 -device scsi-cd,drive=cd1 " "-drive if=none,id=cd1,format=raw,file=", test_cdboot); diff --git a/tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2 Binary files differnew file mode 100644 index 0000000000..ac0b7b1b8f --- /dev/null +++ b/tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2 diff --git a/tests/data/uefi-boot-images/bios-tables-test.arm.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.arm.iso.qcow2 Binary files differnew file mode 100644 index 0000000000..d20fa7c819 --- /dev/null +++ b/tests/data/uefi-boot-images/bios-tables-test.arm.iso.qcow2 diff --git a/tests/data/uefi-boot-images/bios-tables-test.i386.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.i386.iso.qcow2 Binary files differnew file mode 100644 index 0000000000..26c882baea --- /dev/null +++ b/tests/data/uefi-boot-images/bios-tables-test.i386.iso.qcow2 diff --git a/tests/data/uefi-boot-images/bios-tables-test.x86_64.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.x86_64.iso.qcow2 Binary files differnew file mode 100644 index 0000000000..9ec3c1f20b --- /dev/null +++ b/tests/data/uefi-boot-images/bios-tables-test.x86_64.iso.qcow2 diff --git a/tests/device-plug-test.c b/tests/device-plug-test.c new file mode 100644 index 0000000000..318e422d51 --- /dev/null +++ b/tests/device-plug-test.c @@ -0,0 +1,178 @@ +/* + * QEMU device plug/unplug handling + * + * Copyright (C) 2019 Red Hat Inc. + * + * Authors: + * David Hildenbrand <david@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qstring.h" + +static void device_del_start(QTestState *qtest, const char *id) +{ + qtest_qmp_send(qtest, + "{'execute': 'device_del', 'arguments': { 'id': %s } }", id); +} + +static void device_del_finish(QTestState *qtest) +{ + QDict *resp = qtest_qmp_receive(qtest); + + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); +} + +static void device_del_request(QTestState *qtest, const char *id) +{ + device_del_start(qtest, id); + device_del_finish(qtest); +} + +static void system_reset(QTestState *qtest) +{ + QDict *resp; + + resp = qtest_qmp(qtest, "{'execute': 'system_reset'}"); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); +} + +static void wait_device_deleted_event(QTestState *qtest, const char *id) +{ + QDict *resp, *data; + QString *qstr; + + /* + * Other devices might get removed along with the removed device. Skip + * these. The device of interest will be the last one. + */ + for (;;) { + resp = qtest_qmp_eventwait_ref(qtest, "DEVICE_DELETED"); + data = qdict_get_qdict(resp, "data"); + if (!data || !qdict_get(data, "device")) { + qobject_unref(resp); + continue; + } + qstr = qobject_to(QString, qdict_get(data, "device")); + g_assert(qstr); + if (!strcmp(qstring_get_str(qstr), id)) { + qobject_unref(resp); + break; + } + qobject_unref(resp); + } +} + +static void test_pci_unplug_request(void) +{ + QTestState *qtest = qtest_initf("-device virtio-mouse-pci,id=dev0"); + + /* + * Request device removal. As the guest is not running, the request won't + * be processed. However during system reset, the removal will be + * handled, removing the device. + */ + device_del_request(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + +static void test_ccw_unplug(void) +{ + QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0"); + + /* + * The DEVICE_DELETED events will be sent before the command + * completes. + */ + device_del_start(qtest, "dev0"); + wait_device_deleted_event(qtest, "dev0"); + device_del_finish(qtest); + + qtest_quit(qtest); +} + +static void test_spapr_cpu_unplug_request(void) +{ + QTestState *qtest; + + qtest = qtest_initf("-cpu power9_v2.0 -smp 1,maxcpus=2 " + "-device power9_v2.0-spapr-cpu-core,core-id=1,id=dev0"); + + /* similar to test_pci_unplug_request */ + device_del_request(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + +static void test_spapr_memory_unplug_request(void) +{ + QTestState *qtest; + + qtest = qtest_initf("-m 256M,slots=1,maxmem=768M " + "-object memory-backend-ram,id=mem0,size=512M " + "-device pc-dimm,id=dev0,memdev=mem0"); + + /* similar to test_pci_unplug_request */ + device_del_request(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + +static void test_spapr_phb_unplug_request(void) +{ + QTestState *qtest; + + qtest = qtest_initf("-device spapr-pci-host-bridge,index=1,id=dev0"); + + /* similar to test_pci_unplug_request */ + device_del_request(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + + g_test_init(&argc, &argv, NULL); + + /* + * We need a system that will process unplug requests during system resets + * and does not do PCI surprise removal. This holds for x86 ACPI, + * s390x and spapr. + */ + qtest_add_func("/device-plug/pci-unplug-request", + test_pci_unplug_request); + + if (!strcmp(arch, "s390x")) { + qtest_add_func("/device-plug/ccw-unplug", + test_ccw_unplug); + } + + if (!strcmp(arch, "ppc64")) { + qtest_add_func("/device-plug/spapr-cpu-unplug-request", + test_spapr_cpu_unplug_request); + qtest_add_func("/device-plug/spapr-memory-unplug-request", + test_spapr_memory_unplug_request); + qtest_add_func("/device-plug/spapr-phb-unplug-request", + test_spapr_phb_unplug_request); + } + + return g_test_run(); +} diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index 954fcf9606..d770a11a52 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -33,6 +33,7 @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \ apt-get install -y --no-install-recommends \ linux-headers-amd64 RUN git clone https://github.com/luigirizzo/netmap.git /usr/src/netmap +RUN cd /usr/src/netmap && git checkout v11.3 RUN cd /usr/src/netmap/LINUX && ./configure --no-drivers --no-apps --kernel-dir=$(ls -d /usr/src/linux-headers-*-amd64) && make install ENV QEMU_CONFIGURE_OPTS --enable-netmap diff --git a/tests/docker/dockerfiles/debian9.docker b/tests/docker/dockerfiles/debian9.docker index 154ae2a455..5f23a35404 100644 --- a/tests/docker/dockerfiles/debian9.docker +++ b/tests/docker/dockerfiles/debian9.docker @@ -13,8 +13,8 @@ FROM debian:stretch-slim RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list # Install common build utilities -RUN apt update -RUN DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata RUN DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ bison \ diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index 2a35ef601d..7d0faf2b47 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -125,17 +125,42 @@ static void not_implemented(void) static bool blacklisted(unsigned op, int rmode) { - /* odd has only been implemented for a few 128-bit ops */ + /* odd has not been implemented for any 80-bit ops */ if (rmode == softfloat_round_odd) { switch (op) { - case F128_ADD: - case F128_SUB: - case F128_MUL: - case F128_DIV: - case F128_TO_F64: - case F128_SQRT: - return false; - default: + case EXTF80_TO_UI32: + case EXTF80_TO_UI64: + case EXTF80_TO_I32: + case EXTF80_TO_I64: + case EXTF80_TO_UI32_R_MINMAG: + case EXTF80_TO_UI64_R_MINMAG: + case EXTF80_TO_I32_R_MINMAG: + case EXTF80_TO_I64_R_MINMAG: + case EXTF80_TO_F16: + case EXTF80_TO_F32: + case EXTF80_TO_F64: + case EXTF80_TO_F128: + case EXTF80_ROUNDTOINT: + case EXTF80_ADD: + case EXTF80_SUB: + case EXTF80_MUL: + case EXTF80_DIV: + case EXTF80_REM: + case EXTF80_SQRT: + case EXTF80_EQ: + case EXTF80_LE: + case EXTF80_LT: + case EXTF80_EQ_SIGNALING: + case EXTF80_LE_QUIET: + case EXTF80_LT_QUIET: + case UI32_TO_EXTF80: + case UI64_TO_EXTF80: + case I32_TO_EXTF80: + case I64_TO_EXTF80: + case F16_TO_EXTF80: + case F32_TO_EXTF80: + case F64_TO_EXTF80: + case F128_TO_EXTF80: return true; } } @@ -622,7 +647,8 @@ static void do_testfloat(int op, int rmode, bool exact) test_ab_extF80_z_bool(true_ab_extF80M_z_bool, subj_ab_extF80M_z_bool); break; case F128_TO_UI32: - not_implemented(); + test_a_f128_z_ui32_rx(slow_f128M_to_ui32, qemu_f128M_to_ui32, rmode, + exact); break; case F128_TO_UI64: test_a_f128_z_ui64_rx(slow_f128M_to_ui64, qemu_f128M_to_ui64, rmode, diff --git a/tests/fp/wrap.inc.c b/tests/fp/wrap.inc.c index d3bf600cd0..0cbd20013e 100644 --- a/tests/fp/wrap.inc.c +++ b/tests/fp/wrap.inc.c @@ -367,6 +367,7 @@ WRAP_80_TO_INT_MINMAG(qemu_extF80M_to_i64_r_minMag, WRAP_128_TO_INT(qemu_f128M_to_i32, float128_to_int32, int_fast32_t) WRAP_128_TO_INT(qemu_f128M_to_i64, float128_to_int64, int_fast64_t) +WRAP_128_TO_INT(qemu_f128M_to_ui32, float128_to_uint32, uint_fast32_t) WRAP_128_TO_INT(qemu_f128M_to_ui64, float128_to_uint64, uint_fast64_t) #undef WRAP_128_TO_INT diff --git a/tests/qemu-iotests/045 b/tests/qemu-iotests/045 index 55a5d31ca8..d5484a0ee1 100755 --- a/tests/qemu-iotests/045 +++ b/tests/qemu-iotests/045 @@ -132,7 +132,7 @@ class TestSCMFd(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, image0, '128K') # Add an unused monitor, to verify it works fine when two monitor # instances present - self.vm.add_monitor_telnet("0",4445) + self.vm.add_monitor_null() self.vm.launch() def tearDown(self): diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 793af2ab96..b900935fbc 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -82,7 +82,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.orig"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) @@ -172,7 +172,7 @@ QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) @@ -192,7 +192,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only) Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writethrough Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) @@ -212,7 +212,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only) Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback, ignore flushes Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index ca64edae6a..8c5c735dfd 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -82,7 +82,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.orig"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) @@ -244,7 +244,7 @@ QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) @@ -264,7 +264,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only) Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writethrough Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) @@ -284,7 +284,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only) Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback, ignore flushes Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110 index b64b3b215a..185ad5437e 100755 --- a/tests/qemu-iotests/110 +++ b/tests/qemu-iotests/110 @@ -29,6 +29,7 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img + rm -f "$TEST_IMG.copy" } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -60,7 +61,8 @@ echo '=== Non-reconstructable filename ===' echo # Across blkdebug without a config file, you cannot reconstruct filenames, so -# qemu is incapable of knowing the directory of the top image +# qemu is incapable of knowing the directory of the top image from the filename +# alone. However, using bdrv_dirname(), it should still work. TEST_IMG="json:{ 'driver': '$IMGFMT', 'file': { @@ -85,6 +87,31 @@ echo # omit the image size; it should work anyway _make_test_img -b "$TEST_IMG_REL.base" +echo +echo '=== Nodes without a common directory ===' +echo + +cp "$TEST_IMG" "$TEST_IMG.copy" + +# Should inform us that the actual path of the backing file cannot be determined +TEST_IMG="json:{ + 'driver': '$IMGFMT', + 'file': { + 'driver': 'quorum', + 'vote-threshold': 1, + 'children': [ + { + 'driver': 'file', + 'filename': '$TEST_IMG' + }, + { + 'driver': 'file', + 'filename': '$TEST_IMG.copy' + } + ] + } +}" _img_info | _filter_img_info + # success, all done echo '*** done' diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out index b3584ff87f..46e6a60510 100644 --- a/tests/qemu-iotests/110.out +++ b/tests/qemu-iotests/110.out @@ -14,9 +14,16 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base) image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}} file format: IMGFMT virtual size: 64M (67108864 bytes) -backing file: t.IMGFMT.base (cannot determine actual path) +backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base) === Backing name is always relative to the backed image === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base + +=== Nodes without a common directory === + +image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "vote-threshold": 1}} +file format: IMGFMT +virtual size: 64M (67108864 bytes) +backing file: t.IMGFMT.base (cannot determine actual path) *** done diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178 index 3f4b4a4564..927bf06e4d 100755 --- a/tests/qemu-iotests/178 +++ b/tests/qemu-iotests/178 @@ -142,6 +142,14 @@ for ofmt in human json; do # The backing file doesn't need to exist :) $QEMU_IMG measure --output=$ofmt -o backing_file=x \ -f "$fmt" -O "$IMGFMT" "$TEST_IMG" + + echo + echo "== $fmt input image and LUKS encryption ==" + echo + $QEMU_IMG measure --output=$ofmt \ + --object secret,id=sec0,data=base \ + -o encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10 \ + -f "$fmt" -O "$IMGFMT" "$TEST_IMG" fi echo diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2 index d42d4a4597..55a8dc926f 100644 --- a/tests/qemu-iotests/178.out.qcow2 +++ b/tests/qemu-iotests/178.out.qcow2 @@ -68,6 +68,11 @@ converted image file size in bytes: 458752 required size: 1074135040 fully allocated size: 1074135040 +== qcow2 input image and LUKS encryption == + +required size: 2686976 +fully allocated size: 1076232192 + == qcow2 input image and preallocation (human) == required size: 1074135040 @@ -114,6 +119,11 @@ converted image file size in bytes: 524288 required size: 1074135040 fully allocated size: 1074135040 +== raw input image and LUKS encryption == + +required size: 2686976 +fully allocated size: 1076232192 + == raw input image and preallocation (human) == required size: 1074135040 @@ -205,6 +215,13 @@ converted image file size in bytes: 458752 "fully-allocated": 1074135040 } +== qcow2 input image and LUKS encryption == + +{ + "required": 2686976, + "fully-allocated": 1076232192 +} + == qcow2 input image and preallocation (json) == { @@ -263,6 +280,13 @@ converted image file size in bytes: 524288 "fully-allocated": 1074135040 } +== raw input image and LUKS encryption == + +{ + "required": 2686976, + "fully-allocated": 1076232192 +} + == raw input image and preallocation (json) == { diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out index 91f4db55d3..0f1c23babb 100644 --- a/tests/qemu-iotests/206.out +++ b/tests/qemu-iotests/206.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -24,12 +24,12 @@ Format specific information: === Successful image creation (inline blockdev-add, explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -46,12 +46,12 @@ Format specific information: === Successful image creation (v3 non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -68,12 +68,12 @@ Format specific information: === Successful image creation (v2 non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -90,7 +90,7 @@ Format specific information: === Successful image creation (encrypted) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -144,111 +144,111 @@ Format specific information: === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}} {"return": {}} Job failed: Image size must be a multiple of 512 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}} {"return": {}} Job failed: Could not resize image: Image size cannot be negative {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}} {"return": {}} Job failed: Could not resize image: Image size cannot be negative {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}} {"return": {}} Job failed: Could not resize image: Failed to grow the L1 table: File too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid version === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}} {"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}} {"return": {}} Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}} {"return": {}} Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid backing file options === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}} {"return": {}} Job failed: Backing file and preallocation cannot be used at the same time {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Backing format cannot be used without backing file {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid cluster size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a power of two between 512 and 2048k {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a power of two between 512 and 2048k {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a power of two between 512 and 2048k {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a power of two between 512 and 2048k {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}} {"return": {}} Job failed: Could not resize image: Failed to grow the L1 table: File too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid refcount width === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}} {"return": {}} Job failed: Refcount width must be a power of two and may not exceed 64 bits {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}} {"return": {}} Job failed: Refcount width must be a power of two and may not exceed 64 bits {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}} {"return": {}} Job failed: Refcount width must be a power of two and may not exceed 64 bits {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 index c617ee7453..dfd3c51bd1 100755 --- a/tests/qemu-iotests/207 +++ b/tests/qemu-iotests/207 @@ -27,12 +27,16 @@ import re iotests.verify_image_format(supported_fmts=['raw']) iotests.verify_protocol(supported=['ssh']) -def filter_hash(msg): - return re.sub('"hash": "[0-9a-f]+"', '"hash": HASH', msg) +def filter_hash(qmsg): + def _filter(key, value): + if key == 'hash' and re.match('[0-9a-f]+', value): + return 'HASH' + return value + return iotests.filter_qmp(qmsg, _filter) def blockdev_create(vm, options): result = vm.qmp_log('blockdev-create', job_id='job0', options=options, - filters=[iotests.filter_testfiles, filter_hash]) + filters=[iotests.filter_qmp_testfiles, filter_hash]) if 'return' in result: assert result['return'] == {} diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out index 45ac7c2a8f..568e8619d0 100644 --- a/tests/qemu-iotests/207.out +++ b/tests/qemu-iotests/207.out @@ -1,6 +1,6 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -16,7 +16,7 @@ virtual size: 4.0M (4194304 bytes) === Test host-key-check options === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -25,7 +25,7 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po file format: IMGFMT virtual size: 8.0M (8388608 bytes) -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -34,13 +34,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po file format: IMGFMT virtual size: 4.0M (4194304 bytes) -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} {"return": {}} Job failed: remote host key does not match host_key_check 'wrong' {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -49,13 +49,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po file format: IMGFMT virtual size: 8.0M (8388608 bytes) -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} {"return": {}} Job failed: remote host key does not match host_key_check 'wrong' {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -66,13 +66,13 @@ virtual size: 4.0M (4194304 bytes) === Invalid path and user === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}} {"return": {}} Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210 index d142841e2b..565e3b7b9b 100755 --- a/tests/qemu-iotests/210 +++ b/tests/qemu-iotests/210 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['luks']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -53,7 +54,7 @@ with iotests.FilePath('t.luks') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out index 923cb05117..a3692ce00d 100644 --- a/tests/qemu-iotests/210.out +++ b/tests/qemu-iotests/210.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -54,12 +54,12 @@ Format specific information: === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -106,7 +106,7 @@ Format specific information: === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -114,7 +114,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi === Zero size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -161,19 +161,19 @@ Format specific information: === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}} {"return": {}} Job failed: The requested file size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}} {"return": {}} Job failed: The requested file size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}} {"return": {}} Job failed: The requested file size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -181,13 +181,13 @@ Job failed: The requested file size is too large === Resize image with invalid sizes === -{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775296}} +{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775296}} {"error": {"class": "GenericError", "desc": "The requested file size is too large"}} -{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775808}} +{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775808}} {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}} -{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 18446744073709551104}} +{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 18446744073709551104}} {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}} -{"execute": "block_resize", "arguments": {"node_name": "node1", "size": -9223372036854775808}} +{"execute": "block_resize", "arguments": {"node-name": "node1", "size": -9223372036854775808}} {"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}} image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"} file format: IMGFMT diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211 index 7b7985db6c..6afc894f76 100755 --- a/tests/qemu-iotests/211 +++ b/tests/qemu-iotests/211 @@ -27,11 +27,14 @@ iotests.verify_image_format(supported_fmts=['vdi']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} - vm.run_job('job0') + error = vm.run_job('job0') + if error and 'Could not allocate bmap' in error: + iotests.notrun('Insufficient memory') iotests.log("") with iotests.FilePath('t.vdi') as disk_path, \ @@ -51,7 +54,7 @@ with iotests.FilePath('t.vdi') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out index eebb0ea086..682adc2a10 100644 --- a/tests/qemu-iotests/211.out +++ b/tests/qemu-iotests/211.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -21,12 +21,12 @@ cluster_size: 1048576 === Successful image creation (explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -40,12 +40,12 @@ cluster_size: 1048576 === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -60,7 +60,7 @@ cluster_size: 1048576 === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -68,7 +68,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi === Zero size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -80,7 +80,7 @@ cluster_size: 1048576 === Maximum size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -92,19 +92,19 @@ cluster_size: 1048576 === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}} {"return": {}} Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}} {"return": {}} Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}} {"return": {}} Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000) {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212 index 95c8810d83..42b74f208b 100755 --- a/tests/qemu-iotests/212 +++ b/tests/qemu-iotests/212 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['parallels']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -51,7 +52,7 @@ with iotests.FilePath('t.parallels') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out index 01da467282..22810720cf 100644 --- a/tests/qemu-iotests/212.out +++ b/tests/qemu-iotests/212.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -18,12 +18,12 @@ virtual size: 128M (134217728 bytes) === Successful image creation (explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -34,12 +34,12 @@ virtual size: 64M (67108864 bytes) === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -50,7 +50,7 @@ virtual size: 32M (33554432 bytes) === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -58,7 +58,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi === Zero size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -69,7 +69,7 @@ virtual size: 0 (0 bytes) === Maximum size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -80,31 +80,31 @@ virtual size: 4096T (4503599627369984 bytes) === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}} {"return": {}} Job failed: Image size must be a multiple of 512 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -112,43 +112,43 @@ Job failed: Image size is too large for this cluster size === Invalid cluster size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a multiple of 512 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a multiple of 512 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213 index 4054439e3c..5604f3cebb 100755 --- a/tests/qemu-iotests/213 +++ b/tests/qemu-iotests/213 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['vhdx']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -51,7 +52,7 @@ with iotests.FilePath('t.vhdx') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out index 0c9d65b2fe..169083e08e 100644 --- a/tests/qemu-iotests/213.out +++ b/tests/qemu-iotests/213.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -19,12 +19,12 @@ cluster_size: 8388608 === Successful image creation (explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -36,12 +36,12 @@ cluster_size: 8388608 === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -53,7 +53,7 @@ cluster_size: 268435456 === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -61,7 +61,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi === Zero size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -73,7 +73,7 @@ cluster_size: 8388608 === Maximum size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -85,25 +85,25 @@ cluster_size: 67108864 === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}} {"return": {}} Job failed: Image size too large; max of 64TB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}} {"return": {}} Job failed: Image size too large; max of 64TB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}} {"return": {}} Job failed: Image size too large; max of 64TB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}} {"return": {}} Job failed: Image size too large; max of 64TB {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -111,31 +111,31 @@ Job failed: Image size too large; max of 64TB === Invalid block size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must be a power of two {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must not exceed 268435456 {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -143,25 +143,25 @@ Job failed: Block size must be a multiple of 1 MB === Invalid log size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}} {"return": {}} Job failed: Log size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}} {"return": {}} Job failed: Log size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}} {"return": {}} Job failed: Log size must be smaller than 4 GB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}} {"return": {}} Job failed: Log size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/224 b/tests/qemu-iotests/224 new file mode 100755 index 0000000000..b4dfaa639f --- /dev/null +++ b/tests/qemu-iotests/224 @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# +# Test json:{} filenames with qemu-internal BDSs +# (the one of commit, to be precise) +# +# Copyright (C) 2018 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Creator/Owner: Max Reitz <mreitz@redhat.com> + +import iotests +from iotests import log, qemu_img, qemu_io_silent, filter_qmp_testfiles, \ + filter_qmp_imgfmt +import json + +# Need backing file support (for arbitrary backing formats) +iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed']) +iotests.verify_platform(['linux']) + + +# There are two variations of this test: +# (1) We do not set filter_node_name. In that case, the commit_top +# driver should not appear anywhere. +# (2) We do set filter_node_name. In that case, it should appear. +# +# This for loop executes both. +for filter_node_name in False, True: + log('') + log('--- filter_node_name: %s ---' % filter_node_name) + log('') + + with iotests.FilePath('base.img') as base_img_path, \ + iotests.FilePath('mid.img') as mid_img_path, \ + iotests.FilePath('top.img') as top_img_path, \ + iotests.VM() as vm: + + assert qemu_img('create', '-f', iotests.imgfmt, + base_img_path, '64M') == 0 + assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, + mid_img_path) == 0 + assert qemu_img('create', '-f', iotests.imgfmt, '-b', mid_img_path, + top_img_path) == 0 + + # Something to commit + assert qemu_io_silent(mid_img_path, '-c', 'write -P 1 0 1M') == 0 + + vm.launch() + + # Change the bottom-most image's backing file (to null-co://) + # to enforce json:{} filenames + vm.qmp_log('blockdev-add', + node_name='top', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + backing={ + 'node-name': 'mid', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': mid_img_path + }, + 'backing': { + 'node-name': 'base', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': base_img_path + }, + 'backing': { + 'driver': 'null-co' + } + } + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # As long as block-commit does not accept node names, we have to + # get our mid/base filenames here + mid_name = vm.node_info('mid')['image']['filename'] + base_name = vm.node_info('base')['image']['filename'] + + assert mid_name[:5] == 'json:' + assert base_name[:5] == 'json:' + + # Start the block job + if filter_node_name: + vm.qmp_log('block-commit', + job_id='commit', + device='top', + filter_node_name='filter_node', + top=mid_name, + base=base_name, + speed=1, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + else: + vm.qmp_log('block-commit', + job_id='commit', + device='top', + top=mid_name, + base=base_name, + speed=1, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + vm.qmp_log('job-pause', id='commit') + + # Get and parse top's json:{} filename + top_name = vm.node_info('top')['image']['filename'] + + vm.shutdown() + + assert top_name[:5] == 'json:' + top_options = json.loads(top_name[5:]) + + if filter_node_name: + # This should be present and set + assert top_options['backing']['driver'] == 'commit_top' + # And the mid image is commit_top's backing image + mid_options = top_options['backing']['backing'] + else: + # The mid image should appear as the immediate backing BDS + # of top + mid_options = top_options['backing'] + + assert mid_options['driver'] == iotests.imgfmt + assert mid_options['file']['filename'] == mid_img_path diff --git a/tests/qemu-iotests/224.out b/tests/qemu-iotests/224.out new file mode 100644 index 0000000000..23374a1d29 --- /dev/null +++ b/tests/qemu-iotests/224.out @@ -0,0 +1,18 @@ + +--- filter_node_name: False --- + +{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "base"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-mid.img"}, "node-name": "mid"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "top"}} +{"return": {}} +{"execute": "block-commit", "arguments": {"base": "json:{\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}", "device": "top", "job-id": "commit", "speed": 1, "top": "json:{\"backing\": {\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-mid.img\"}}"}} +{"return": {}} +{"execute": "job-pause", "arguments": {"id": "commit"}} +{"return": {}} + +--- filter_node_name: True --- + +{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "base"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-mid.img"}, "node-name": "mid"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "top"}} +{"return": {}} +{"execute": "block-commit", "arguments": {"base": "json:{\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}", "device": "top", "filter-node-name": "filter_node", "job-id": "commit", "speed": 1, "top": "json:{\"backing\": {\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-mid.img\"}}"}} +{"return": {}} +{"execute": "job-pause", "arguments": {"id": "commit"}} +{"return": {}} diff --git a/tests/qemu-iotests/228 b/tests/qemu-iotests/228 new file mode 100755 index 0000000000..9a50afd205 --- /dev/null +++ b/tests/qemu-iotests/228 @@ -0,0 +1,239 @@ +#!/usr/bin/env python +# +# Test for when a backing file is considered overridden (thus, a +# json:{} filename is generated for the overlay) and when it is not +# +# Copyright (C) 2018 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Creator/Owner: Max Reitz <mreitz@redhat.com> + +import iotests +from iotests import log, qemu_img, filter_testfiles, filter_imgfmt, \ + filter_qmp_testfiles, filter_qmp_imgfmt + +# Need backing file and change-backing-file support +iotests.verify_image_format(supported_fmts=['qcow2', 'qed']) +iotests.verify_platform(['linux']) + + +def log_node_info(node): + log('') + + log('bs->filename: ' + node['image']['filename'], + filters=[filter_testfiles, filter_imgfmt]) + log('bs->backing_file: ' + node['backing_file'], + filters=[filter_testfiles, filter_imgfmt]) + + if 'backing-image' in node['image']: + log('bs->backing->bs->filename: ' + + node['image']['backing-image']['filename'], + filters=[filter_testfiles, filter_imgfmt]) + else: + log('bs->backing: (none)') + + log('') + + +with iotests.FilePath('base.img') as base_img_path, \ + iotests.FilePath('top.img') as top_img_path, \ + iotests.VM() as vm: + + assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0 + # Choose a funny way to describe the backing filename + assert qemu_img('create', '-f', iotests.imgfmt, '-b', + 'file:' + base_img_path, top_img_path) == 0 + + vm.launch() + + log('--- Implicit backing file ---') + log('') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Filename should be plain, and the backing filename should not + # contain the "file:" prefix + log_node_info(vm.node_info('node0')) + + vm.qmp_log('blockdev-del', node_name='node0') + + log('') + log('--- change-backing-file ---') + log('') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Changing the backing file to a qemu-reported filename should + # result in qemu accepting the corresponding BDS as the implicit + # backing BDS (and thus not generate a json:{} filename). + # So, first, query the backing filename. + + backing_filename = \ + vm.node_info('node0')['image']['backing-image']['filename'] + + # Next, change the backing file to something different + + vm.qmp_log('change-backing-file', + image_node_name='node0', + device='node0', + backing_file='null-co://', + filters=[filter_qmp_testfiles]) + + # Now, verify that we get a json:{} filename + # (Image header says "null-co://", actual backing file still is + # base_img_path) + + log_node_info(vm.node_info('node0')) + + # Change it back + # (To get header and backing file in sync) + + vm.qmp_log('change-backing-file', + image_node_name='node0', + device='node0', + backing_file=backing_filename, + filters=[filter_qmp_testfiles]) + + # And verify that we get our original results + + log_node_info(vm.node_info('node0')) + + # Finally, try a "file:" prefix. While this is actually what we + # originally had in the image header, qemu will not reopen the + # backing file here, so it cannot verify that this filename + # "resolves" to the actual backing BDS's filename and will thus + # consider both to be different. + # (This may be fixed in the future.) + + vm.qmp_log('change-backing-file', + image_node_name='node0', + device='node0', + backing_file=('file:' + backing_filename), + filters=[filter_qmp_testfiles]) + + # So now we should get a json:{} filename + + log_node_info(vm.node_info('node0')) + + # Remove and re-attach so we can see that (as in our first try), + # opening the image anew helps qemu resolve the header backing + # filename. + + vm.qmp_log('blockdev-del', node_name='node0') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + log_node_info(vm.node_info('node0')) + + vm.qmp_log('blockdev-del', node_name='node0') + + log('') + log('--- Override backing file ---') + log('') + + # For this test, we need the plain filename in the image header + # (because qemu cannot "canonicalize"/"resolve" the backing + # filename unless the backing file is opened implicitly with the + # overlay) + assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, + top_img_path) == 0 + + # You can only reliably override backing options by using a node + # reference (or by specifying file.filename, but, well...) + vm.qmp_log('blockdev-add', node_name='null', driver='null-co') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + backing='null', + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Should get a json:{} filename (and bs->backing_file is + # null-co://, because that field actually has not much to do + # with the header backing filename (except that it is changed by + # change-backing-file)) + + log_node_info(vm.node_info('node0')) + + # Detach the backing file by reopening the whole thing + + vm.qmp_log('blockdev-del', node_name='node0') + vm.qmp_log('blockdev-del', node_name='null') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + backing=None, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Should get a json:{} filename (because we overrode the backing + # file to not be there) + + log_node_info(vm.node_info('node0')) + + # Open the original backing file + + vm.qmp_log('blockdev-add', + node_name='original-backing', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': base_img_path + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Attach the original backing file to its overlay + + vm.qmp_log('blockdev-snapshot', + node='original-backing', + overlay='node0') + + # This should give us the original plain result + + log_node_info(vm.node_info('node0')) + + vm.qmp_log('blockdev-del', node_name='node0') + vm.qmp_log('blockdev-del', node_name='original-backing') + + vm.shutdown() diff --git a/tests/qemu-iotests/228.out b/tests/qemu-iotests/228.out new file mode 100644 index 0000000000..4217df24fe --- /dev/null +++ b/tests/qemu-iotests/228.out @@ -0,0 +1,84 @@ +--- Implicit backing file --- + +{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} + +bs->filename: TEST_DIR/PID-top.img +bs->backing_file: TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} + +--- change-backing-file --- + +{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} +{"execute": "change-backing-file", "arguments": {"backing-file": "null-co://", "device": "node0", "image-node-name": "node0"}} +{"return": {}} + +bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}} +bs->backing_file: null-co:// +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "change-backing-file", "arguments": {"backing-file": "TEST_DIR/PID-base.img", "device": "node0", "image-node-name": "node0"}} +{"return": {}} + +bs->filename: TEST_DIR/PID-top.img +bs->backing_file: TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "change-backing-file", "arguments": {"backing-file": "file:TEST_DIR/PID-base.img", "device": "node0", "image-node-name": "node0"}} +{"return": {}} + +bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}} +bs->backing_file: file:TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} + +bs->filename: TEST_DIR/PID-top.img +bs->backing_file: TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} + +--- Override backing file --- + +{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "null"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": {"backing": "null", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} + +bs->filename: json:{"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}} +bs->backing_file: null-co:// +bs->backing->bs->filename: null-co:// + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": {"node-name": "null"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": {"backing": null, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} + +bs->filename: json:{"backing": null, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}} +bs->backing_file: TEST_DIR/PID-base.img +bs->backing: (none) + +{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "original-backing"}} +{"return": {}} +{"execute": "blockdev-snapshot", "arguments": {"node": "original-backing", "overlay": "node0"}} +{"return": {}} + +bs->filename: TEST_DIR/PID-top.img +bs->backing_file: TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": {"node-name": "original-backing"}} +{"return": {}} diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 index 0708b8b155..e48bc8f5db 100755 --- a/tests/qemu-iotests/232 +++ b/tests/qemu-iotests/232 @@ -29,7 +29,6 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img - rm -f $TEST_IMG.snap } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -70,6 +69,10 @@ size=128M _make_test_img $size +if [ -n "$TEST_IMG_FILE" ]; then + TEST_IMG=$TEST_IMG_FILE +fi + echo echo "=== -drive with read-write image: read-only/auto-read-only combinations ===" echo diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 index fc345a1a46..adb742fafb 100755 --- a/tests/qemu-iotests/233 +++ b/tests/qemu-iotests/233 @@ -30,6 +30,8 @@ _cleanup() { nbd_server_stop _cleanup_test_img + # If we aborted early we want to see this log for diagnosis + test -f "$TEST_DIR/server.log" && cat "$TEST_DIR/server.log" rm -f "$TEST_DIR/server.log" tls_x509_cleanup } @@ -120,6 +122,7 @@ $QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io echo echo "== final server log ==" cat "$TEST_DIR/server.log" +rm -f "$TEST_DIR/server.log" # success, all done echo "*** done" diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 index 251771d7fb..06897f8c87 100755 --- a/tests/qemu-iotests/237 +++ b/tests/qemu-iotests/237 @@ -27,7 +27,8 @@ from iotests import imgfmt iotests.verify_image_format(supported_fmts=['vmdk']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -54,7 +55,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', @@ -223,7 +224,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \ iotests.log("= %s %d =" % (subfmt, size)) iotests.log("") - num_extents = math.ceil(size / 2.0**31) + num_extents = int(math.ceil(size / 2.0**31)) extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ] vm.launch() diff --git a/tests/qemu-iotests/237.out b/tests/qemu-iotests/237.out index 241c864369..2aaa68f672 100644 --- a/tests/qemu-iotests/237.out +++ b/tests/qemu-iotests/237.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -29,12 +29,12 @@ Format specific information: === Successful image creation (inline blockdev-add, explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -56,12 +56,12 @@ Format specific information: === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -83,7 +83,7 @@ Format specific information: === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -93,38 +93,38 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi == Valid adapter types == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} == Invalid adapter types == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"error": {"class": "GenericError", "desc": "Invalid parameter 'foo'"}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"error": {"class": "GenericError", "desc": "Invalid parameter 'IDE'"}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"error": {"class": "GenericError", "desc": "Invalid parameter 'legacyesx'"}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}} {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'options.adapter-type', expected: string"}} === Other subformats === @@ -137,7 +137,7 @@ Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefi == Missing extent == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} {"return": {}} Job failed: Extent [0] not specified {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -145,14 +145,14 @@ Job failed: Extent [0] not specified == Correct extent == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} == Extra extent == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}} {"return": {}} Job failed: List of extents contains unused extents {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -162,7 +162,7 @@ Job failed: List of extents contains unused extents = twoGbMaxExtentFlat 512 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -182,7 +182,7 @@ Format specific information: = twoGbMaxExtentSparse 512 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -204,7 +204,7 @@ Format specific information: = twoGbMaxExtentFlat 1073741824 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -224,7 +224,7 @@ Format specific information: = twoGbMaxExtentSparse 1073741824 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -246,7 +246,7 @@ Format specific information: = twoGbMaxExtentFlat 2147483648 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -266,7 +266,7 @@ Format specific information: = twoGbMaxExtentSparse 2147483648 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -288,7 +288,7 @@ Format specific information: = twoGbMaxExtentFlat 5368709120 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -316,7 +316,7 @@ Format specific information: = twoGbMaxExtentSparse 5368709120 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} diff --git a/tests/qemu-iotests/242 b/tests/qemu-iotests/242 index 16c65edcd7..c176e92da6 100755 --- a/tests/qemu-iotests/242 +++ b/tests/qemu-iotests/242 @@ -20,6 +20,7 @@ import iotests import json +import struct from iotests import qemu_img_create, qemu_io, qemu_img_pipe, \ file_path, img_info_log, log, filter_qemu_io @@ -64,10 +65,11 @@ def write_to_disk(offset, size): def toggle_flag(offset): with open(disk, "r+b") as f: f.seek(offset, 0) - c = f.read(1) - toggled = chr(ord(c) ^ bitmap_flag_unknown) + # Read one byte in a way compatible with Python 2 + flags = struct.unpack("B", f.read(1)) + toggled = flags[0] ^ bitmap_flag_unknown f.seek(-1, 1) - f.write(toggled) + f.write(struct.pack("B", toggled)) qemu_img_create('-f', iotests.imgfmt, disk, '1M') diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index e15e7a7c8e..09a27f02d0 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -145,6 +145,7 @@ else TEST_IMG="nbd:127.0.0.1:10810" elif [ "$IMGPROTO" = "ssh" ]; then TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT + REMOTE_TEST_DIR="ssh://127.0.0.1$TEST_DIR" TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE" elif [ "$IMGPROTO" = "nfs" ]; then TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls index eae81789bb..3caf989d28 100644 --- a/tests/qemu-iotests/common.tls +++ b/tests/qemu-iotests/common.tls @@ -29,6 +29,17 @@ tls_x509_cleanup() } +tls_certtool() +{ + certtool "$@" 1>"${tls_dir}"/certtool.log 2>&1 + if test "$?" = 0; then + head -1 "${tls_dir}"/certtool.log + else + cat "${tls_dir}"/certtool.log + fi + rm -f "${tls_dir}"/certtool.log +} + tls_x509_init() { (certtool --help) >/dev/null 2>&1 || \ @@ -71,10 +82,11 @@ ca cert_signing_key EOF - certtool --generate-self-signed \ - --load-privkey "${tls_dir}/key.pem" \ - --template "${tls_dir}/ca.info" \ - --outfile "${tls_dir}/$name-cert.pem" 2>&1 | head -1 + tls_certtool \ + --generate-self-signed \ + --load-privkey "${tls_dir}/key.pem" \ + --template "${tls_dir}/ca.info" \ + --outfile "${tls_dir}/$name-cert.pem" rm -f "${tls_dir}/ca.info" } @@ -98,12 +110,14 @@ encryption_key signing_key EOF - certtool --generate-certificate \ - --load-ca-privkey "${tls_dir}/key.pem" \ - --load-ca-certificate "${tls_dir}/$caname-cert.pem" \ - --load-privkey "${tls_dir}/key.pem" \ - --template "${tls_dir}/cert.info" \ - --outfile "${tls_dir}/$name/server-cert.pem" 2>&1 | head -1 + tls_certtool \ + --generate-certificate \ + --load-ca-privkey "${tls_dir}/key.pem" \ + --load-ca-certificate "${tls_dir}/$caname-cert.pem" \ + --load-privkey "${tls_dir}/key.pem" \ + --template "${tls_dir}/cert.info" \ + --outfile "${tls_dir}/$name/server-cert.pem" + ln -s "${tls_dir}/$caname-cert.pem" "${tls_dir}/$name/ca-cert.pem" ln -s "${tls_dir}/key.pem" "${tls_dir}/$name/server-key.pem" @@ -127,12 +141,14 @@ encryption_key signing_key EOF - certtool --generate-certificate \ - --load-ca-privkey "${tls_dir}/key.pem" \ - --load-ca-certificate "${tls_dir}/$caname-cert.pem" \ - --load-privkey "${tls_dir}/key.pem" \ - --template "${tls_dir}/cert.info" \ - --outfile "${tls_dir}/$name/client-cert.pem" 2>&1 | head -1 + tls_certtool \ + --generate-certificate \ + --load-ca-privkey "${tls_dir}/key.pem" \ + --load-ca-certificate "${tls_dir}/$caname-cert.pem" \ + --load-privkey "${tls_dir}/key.pem" \ + --template "${tls_dir}/cert.info" \ + --outfile "${tls_dir}/$name/client-cert.pem" + ln -s "${tls_dir}/$caname-cert.pem" "${tls_dir}/$name/ca-cert.pem" ln -s "${tls_dir}/key.pem" "${tls_dir}/$name/client-key.pem" diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index fc4c416fa3..b5ca63cf72 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -224,9 +224,11 @@ 221 rw auto quick 222 rw auto quick 223 rw auto quick +224 rw auto quick 225 rw auto quick 226 auto quick 227 auto quick +228 rw auto quick 229 auto quick 231 auto quick 232 auto quick diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index b461f53abf..4910fb2005 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -76,14 +76,16 @@ def qemu_img(*args): sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) return exitcode -def ordered_qmp(qmsg): +def ordered_qmp(qmsg, conv_keys=True): # Dictionaries are not ordered prior to 3.6, therefore: if isinstance(qmsg, list): return [ordered_qmp(atom) for atom in qmsg] if isinstance(qmsg, dict): od = OrderedDict() for k, v in sorted(qmsg.items()): - od[k] = ordered_qmp(v) + if conv_keys: + k = k.replace('_', '-') + od[k] = ordered_qmp(v, conv_keys=False) return od return qmsg @@ -236,6 +238,12 @@ def image_size(img): r = qemu_img_pipe('info', '--output=json', '-f', imgfmt, img) return json.loads(r)['virtual-size'] +def is_str(val): + if sys.version_info.major >= 3: + return isinstance(val, str) + else: + return isinstance(val, str) or isinstance(val, unicode) + test_dir_re = re.compile(r"%s" % test_dir) def filter_test_dir(msg): return test_dir_re.sub("TEST_DIR", msg) @@ -283,7 +291,7 @@ def filter_testfiles(msg): def filter_qmp_testfiles(qmsg): def _filter(key, value): - if key == 'filename' or key == 'backing-file': + if is_str(value): return filter_testfiles(value) return value return filter_qmp(qmsg, _filter) @@ -304,6 +312,16 @@ def filter_img_info(output, filename): lines.append(line) return '\n'.join(lines) +def filter_imgfmt(msg): + return msg.replace(imgfmt, 'IMGFMT') + +def filter_qmp_imgfmt(qmsg): + def _filter(key, value): + if is_str(value): + return filter_imgfmt(value) + return value + return filter_qmp(qmsg, _filter) + def log(msg, filters=[], indent=None): '''Logs either a string message or a JSON serializable message (like QMP). If indent is provided, JSON serializable messages are pretty-printed.''' @@ -514,7 +532,9 @@ class VM(qtest.QEMUQtestMachine): log(result, filters, indent=indent) return result + # Returns None on success, and an error string on failure def run_job(self, job, auto_finalize=True, auto_dismiss=False): + error = None while True: for ev in self.get_qmp_events_filtered(wait=True): if ev['event'] == 'JOB_STATUS_CHANGE': @@ -523,16 +543,24 @@ class VM(qtest.QEMUQtestMachine): result = self.qmp('query-jobs') for j in result['return']: if j['id'] == job: + error = j['error'] log('Job failed: %s' % (j['error'])) elif status == 'pending' and not auto_finalize: self.qmp_log('job-finalize', id=job) elif status == 'concluded' and not auto_dismiss: self.qmp_log('job-dismiss', id=job) elif status == 'null': - return + return error else: iotests.log(ev) + def node_info(self, node_name): + nodes = self.qmp('query-named-block-nodes') + for x in nodes['return']: + if x['node-name'] == node_name: + return x + return None + index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') diff --git a/tests/tcg/mips/include/wrappers_msa.h b/tests/tcg/mips/include/wrappers_msa.h index 3280f9b084..302f0ab54c 100644 --- a/tests/tcg/mips/include/wrappers_msa.h +++ b/tests/tcg/mips/include/wrappers_msa.h @@ -122,5 +122,35 @@ DO_MSA__WD__WS_WT(CLT_U_H, clt_u.h) DO_MSA__WD__WS_WT(CLT_U_W, clt_u.w) DO_MSA__WD__WS_WT(CLT_U_D, clt_u.d) +DO_MSA__WD__WS_WT(MAX_A_B, max_a.b) +DO_MSA__WD__WS_WT(MAX_A_H, max_a.h) +DO_MSA__WD__WS_WT(MAX_A_W, max_a.w) +DO_MSA__WD__WS_WT(MAX_A_D, max_a.d) + +DO_MSA__WD__WS_WT(MIN_A_B, min_a.b) +DO_MSA__WD__WS_WT(MIN_A_H, min_a.h) +DO_MSA__WD__WS_WT(MIN_A_W, min_a.w) +DO_MSA__WD__WS_WT(MIN_A_D, min_a.d) + +DO_MSA__WD__WS_WT(MAX_S_B, max_s.b) +DO_MSA__WD__WS_WT(MAX_S_H, max_s.h) +DO_MSA__WD__WS_WT(MAX_S_W, max_s.w) +DO_MSA__WD__WS_WT(MAX_S_D, max_s.d) + +DO_MSA__WD__WS_WT(MIN_S_B, min_s.b) +DO_MSA__WD__WS_WT(MIN_S_H, min_s.h) +DO_MSA__WD__WS_WT(MIN_S_W, min_s.w) +DO_MSA__WD__WS_WT(MIN_S_D, min_s.d) + +DO_MSA__WD__WS_WT(MAX_U_B, max_u.b) +DO_MSA__WD__WS_WT(MAX_U_H, max_u.h) +DO_MSA__WD__WS_WT(MAX_U_W, max_u.w) +DO_MSA__WD__WS_WT(MAX_U_D, max_u.d) + +DO_MSA__WD__WS_WT(MIN_U_B, min_u.b) +DO_MSA__WD__WS_WT(MIN_U_H, min_u.h) +DO_MSA__WD__WS_WT(MIN_U_W, min_u.w) +DO_MSA__WD__WS_WT(MIN_U_D, min_u.d) + #endif diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_b.c new file mode 100644 index 0000000000..b47b42e76e --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CEQ.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CEQ.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CEQ_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CEQ_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_d.c new file mode 100644 index 0000000000..e169bdc320 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CEQ.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CEQ.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CEQ_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CEQ_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_h.c new file mode 100644 index 0000000000..9f03cb0b2b --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CEQ.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CEQ.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CEQ_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CEQ_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_w.c new file mode 100644 index 0000000000..a927d96a89 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_ceq_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CEQ.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CEQ.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 72 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CEQ_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CEQ_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_b.c new file mode 100644 index 0000000000..1c1cb3bc4a --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLE_S.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLE_S.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, /* 48 */ + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, /* 56 */ + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0xff00ffffff000000ULL, 0x00000000ff00ff00ULL, }, + { 0xff00000000000000ULL, 0x000000000000ffffULL, }, + { 0xff00ffffff0000ffULL, 0x000000000000ff00ULL, }, + { 0x00ff000000ffffffULL, 0xffffffff00ff00ffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00ff000000ff0000ULL, 0xff00ff00000000ffULL, }, + { 0xffffff00ffffffffULL, 0x0000000000ff0000ULL, }, + { 0x00ffffffffffffffULL, 0xffffffffffff0000ULL, }, /* 72 */ + { 0xff00ffffff00ffffULL, 0x00ff00ffffffff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xff00ffffffffffffULL, 0x00ff000000ff0000ULL, }, + { 0x00ff000000ffff00ULL, 0xffffffffffff00ffULL, }, + { 0x000000ff00000000ULL, 0xffffffffff00ffffULL, }, + { 0x00ff000000000000ULL, 0xff00ffffff00ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_S_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_S_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_d.c new file mode 100644 index 0000000000..b51907cbc0 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLE_S.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLE_S.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 48 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_S_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_S_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_h.c new file mode 100644 index 0000000000..20ebbfbafb --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLE_S.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLE_S.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, /* 48 */ + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, /* 56 */ + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0xffffffffffff0000ULL, 0x00000000ffffffffULL, }, + { 0xffff000000000000ULL, 0x000000000000ffffULL, }, + { 0xffffffffffff0000ULL, 0x000000000000ffffULL, }, + { 0x000000000000ffffULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000ffffffffffffULL, 0xffffffffffff0000ULL, }, /* 72 */ + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x000000000000ffffULL, 0xffffffffffff0000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_S_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_S_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_w.c new file mode 100644 index 0000000000..4a78cce460 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_s_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLE_S.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLE_S.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, /* 48 */ + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, /* 56 */ + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, /* 72 */ + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_S_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_S_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_b.c new file mode 100644 index 0000000000..9990a5b08a --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLE_U.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLE_U.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0xffff0000ffffff00ULL, 0x00ffff00000000ffULL, }, + { 0xff000000ffffffffULL, 0x00ffffff000000ffULL, }, + { 0x00000000ff00ffffULL, 0xffffffff0000ffffULL, }, + { 0x0000ffff000000ffULL, 0xff0000ffffffff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffffffff00ffULL, 0xff00ffffff000000ULL, }, + { 0x0000ff00ff00ffffULL, 0xff0000ffffffff00ULL, }, + { 0x00ffffff00000000ULL, 0xff000000ffffff00ULL, }, /* 72 */ + { 0xffff00000000ff00ULL, 0x00ff000000ffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x000000000000ff00ULL, 0xffff000000ffffffULL, }, + { 0xffffffff00ff0000ULL, 0x00000000ffff0000ULL, }, + { 0xffff00ff00ff0000ULL, 0x00ffff00000000ffULL, }, + { 0xffffffffffff00ffULL, 0x0000ffffff000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_U_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_U_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_d.c new file mode 100644 index 0000000000..cde86d824a --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLE_U.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLE_U.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_U_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_U_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_h.c new file mode 100644 index 0000000000..70e4b48de5 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLE_U.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLE_U.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0xffff0000ffffffffULL, 0x0000ffff00000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffff00000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffff0000ffffULL, }, + { 0x0000ffff00000000ULL, 0xffff0000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffffffff0000ULL, 0xffffffffffff0000ULL, }, + { 0x0000ffffffffffffULL, 0xffff0000ffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff0000ffffffffULL, }, /* 72 */ + { 0xffff00000000ffffULL, 0x000000000000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x000000000000ffffULL, 0xffff00000000ffffULL, }, + { 0xffffffff00000000ULL, 0x00000000ffff0000ULL, }, + { 0xffff000000000000ULL, 0x0000ffff00000000ULL, }, + { 0xffffffffffff0000ULL, 0x0000ffffffff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_U_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_U_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_w.c new file mode 100644 index 0000000000..f38feacef2 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_cle_u_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLE_U.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLE_U.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 64 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ + { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_U_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLE_U_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_b.c new file mode 100644 index 0000000000..b81b569498 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLT_S.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLT_S.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, /* 48 */ + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00ff0000ff0000ffULL, 0x0000ff0000ff0000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, /* 56 */ + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xff00ffff00ffff00ULL, 0xffff00ffff00ffffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ + { 0xff00ffffff000000ULL, 0x00000000ff00ff00ULL, }, + { 0xff00000000000000ULL, 0x000000000000ffffULL, }, + { 0xff00ffffff0000ffULL, 0x000000000000ff00ULL, }, + { 0x00ff000000ffffffULL, 0xffffffff00ff00ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00ff000000ff0000ULL, 0xff00ff00000000ffULL, }, + { 0xffffff00ffffffffULL, 0x0000000000ff0000ULL, }, + { 0x00ffffffffffffffULL, 0xffffffffffff0000ULL, }, /* 72 */ + { 0xff00ffffff00ffffULL, 0x00ff00ffffffff00ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xff00ffffffffffffULL, 0x00ff000000ff0000ULL, }, + { 0x00ff000000ffff00ULL, 0xffffffffffff00ffULL, }, + { 0x000000ff00000000ULL, 0xffffffffff00ffffULL, }, + { 0x00ff000000000000ULL, 0xff00ffffff00ffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_S_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_S_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_d.c new file mode 100644 index 0000000000..393457a3c1 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLT_S.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLT_S.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, /* 48 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_S_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_S_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_h.c new file mode 100644 index 0000000000..56860d7bcc --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLT_S.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLT_S.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, /* 48 */ + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, /* 56 */ + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ + { 0xffffffffffff0000ULL, 0x00000000ffffffffULL, }, + { 0xffff000000000000ULL, 0x000000000000ffffULL, }, + { 0xffffffffffff0000ULL, 0x000000000000ffffULL, }, + { 0x000000000000ffffULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000ffffffffffffULL, 0xffffffffffff0000ULL, }, /* 72 */ + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x000000000000ffffULL, 0xffffffffffff0000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_S_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_S_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_w.c new file mode 100644 index 0000000000..346b2939bb --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_s_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLT_S.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLT_S.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, /* 48 */ + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, /* 56 */ + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffff00000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, /* 72 */ + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_S_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_S_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_b.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_b.c new file mode 100644 index 0000000000..be79646b45 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLT_U.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLT_U.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0x00ffff00ffff00ffULL, 0xff00ffff00ffff00ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000ff0000ff0000ULL, 0xff0000ff0000ff00ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xff0000ff0000ff00ULL, 0x00ff0000ff0000ffULL, }, + { 0xffff00ffff00ffffULL, 0x00ffff00ffff00ffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ + { 0xffff0000ffffff00ULL, 0x00ffff00000000ffULL, }, + { 0xff000000ffffffffULL, 0x00ffffff000000ffULL, }, + { 0x00000000ff00ffffULL, 0xffffffff0000ffffULL, }, + { 0x0000ffff000000ffULL, 0xff0000ffffffff00ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000ffffffff00ffULL, 0xff00ffffff000000ULL, }, + { 0x0000ff00ff00ffffULL, 0xff0000ffffffff00ULL, }, + { 0x00ffffff00000000ULL, 0xff000000ffffff00ULL, }, /* 72 */ + { 0xffff00000000ff00ULL, 0x00ff000000ffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x000000000000ff00ULL, 0xffff000000ffffffULL, }, + { 0xffffffff00ff0000ULL, 0x00000000ffff0000ULL, }, + { 0xffff00ff00ff0000ULL, 0x00ffff00000000ffULL, }, + { 0xffffffffffff00ffULL, 0x0000ffffff000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_U_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_U_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_d.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_d.c new file mode 100644 index 0000000000..afbe4904f8 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLT_U.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLT_U.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_U_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_U_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_h.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_h.c new file mode 100644 index 0000000000..126597af9d --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLT_U.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLT_U.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0x0000ffffffff0000ULL, 0xffffffff0000ffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ + { 0xffff0000ffffffffULL, 0x0000ffff00000000ULL, }, + { 0xffff0000ffffffffULL, 0x0000ffff00000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffff0000ffffULL, }, + { 0x0000ffff00000000ULL, 0xffff0000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000ffffffff0000ULL, 0xffffffffffff0000ULL, }, + { 0x0000ffffffffffffULL, 0xffff0000ffffffffULL, }, + { 0x0000ffff00000000ULL, 0xffff0000ffffffffULL, }, /* 72 */ + { 0xffff00000000ffffULL, 0x000000000000ffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x000000000000ffffULL, 0xffff00000000ffffULL, }, + { 0xffffffff00000000ULL, 0x00000000ffff0000ULL, }, + { 0xffff000000000000ULL, 0x0000ffff00000000ULL, }, + { 0xffffffffffff0000ULL, 0x0000ffffffff0000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_U_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_U_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_w.c b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_w.c new file mode 100644 index 0000000000..b4059292cd --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-compare/test_msa_clt_u_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction CLT_U.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "CLT_U.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 64 */ + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffff00000000ULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, + { 0x00000000ffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0xffffffffffffffffULL, }, /* 72 */ + { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xffffffff00000000ULL, }, + { 0xffffffff00000000ULL, 0x00000000ffffffffULL, }, + { 0xffffffff00000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0x00000000ffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_U_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_CLT_U_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_b.c new file mode 100644 index 0000000000..b7a9a61548 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_A.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_A.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaa8eaaaa8eaaaa8eULL, 0xaaaa8eaaaa8eaaaaULL, }, + { 0xaa71aaaa71aaaa71ULL, 0xaaaa71aaaa71aaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x558e55558e55558eULL, 0x55558e55558e5555ULL, }, + { 0x5571555571555571ULL, 0x5555715555715555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xcc8e38cc8e38cc8eULL, 0x38cc8e38cc8e38ccULL, }, + { 0xcc71c7cc71c7cc71ULL, 0xc7cc71c7cc71c7ccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x338e38338e38338eULL, 0x38338e38338e3833ULL, }, + { 0x3371c73371c73371ULL, 0xc73371c73371c733ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xaa8eaaaa8eaaaa8eULL, 0xaaaa8eaaaa8eaaaaULL, }, + { 0x558e55558e55558eULL, 0x55558e55558e5555ULL, }, + { 0xcc8e38cc8e38cc8eULL, 0x38cc8e38cc8e38ccULL, }, + { 0x338e38338e38338eULL, 0x38338e38338e3833ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaa71aaaa71aaaa71ULL, 0xaaaa71aaaa71aaaaULL, }, + { 0x5571555571555571ULL, 0x5555715555715555ULL, }, + { 0xcc71c7cc71c7cc71ULL, 0xc7cc71c7cc71c7ccULL, }, + { 0x3371c73371c73371ULL, 0xc73371c73371c733ULL, }, + { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6634d935540ULL, 0x4b67bb5e157b520cULL, }, + { 0x886aaeaab9628b80ULL, 0x4b67c65eab7bb014ULL, }, + { 0x886ae64d5e62554eULL, 0x8d67885ea97bb0a0ULL, }, + { 0x886ae6634d935540ULL, 0x4b67bb5e157b520cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aae634d938b80ULL, 0x27d8bb1aab3f5214ULL, }, + { 0x704f16635e93c74eULL, 0x8df188d8a94252a0ULL, }, + { 0x886aaeaab9628b80ULL, 0x4b67c65eab7bb014ULL, }, /* 72 */ + { 0xac5aae634d938b80ULL, 0x27d8bb1aab3f5214ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x705aaeaa5e318b80ULL, 0x8dd888d8a94225a0ULL, }, + { 0x886ae64d5e62554eULL, 0x8d67885ea97bb0a0ULL, }, + { 0x704f16635e93c74eULL, 0x8df188d8a94252a0ULL, }, + { 0x705aaeaa5ecf8b80ULL, 0x8dd888d8a94225a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_A_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_A_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_d.c new file mode 100644 index 0000000000..dfffaf5b5e --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_A.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_A.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, + { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, + { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, + { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_A_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_A_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_h.c new file mode 100644 index 0000000000..e0c1bd4c4b --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_A.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_A.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaa8e38aaaaULL, 0xaaaa8e38aaaaaaaaULL, }, + { 0xaaaaaaaa71c7aaaaULL, 0xaaaa71c7aaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x555555558e385555ULL, 0x55558e3855555555ULL, }, + { 0x5555555571c75555ULL, 0x555571c755555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xcccc38e38e38ccccULL, 0x38e38e38cccc38e3ULL, }, + { 0xccccc71c71c7ccccULL, 0xc71c71c7ccccc71cULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x333338e38e383333ULL, 0x38e38e38333338e3ULL, }, + { 0x3333c71c71c73333ULL, 0xc71c71c73333c71cULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xaaaaaaaa8e38aaaaULL, 0xaaaa8e38aaaaaaaaULL, }, + { 0x555555558e385555ULL, 0x55558e3855555555ULL, }, + { 0xcccc38e38e38ccccULL, 0x38e38e38cccc38e3ULL, }, + { 0x333338e38e383333ULL, 0x38e38e38333338e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaa71c7aaaaULL, 0xaaaa71c7aaaaaaaaULL, }, + { 0x5555555571c75555ULL, 0x555571c755555555ULL, }, + { 0xccccc71c71c7ccccULL, 0xc71c71c7ccccc71cULL, }, + { 0x3333c71c71c73333ULL, 0xc71c71c73333c71cULL, }, + { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6cc4d935540ULL, 0x4b67bb1a153f52fcULL, }, + { 0x886aaeaab9cf8b80ULL, 0x4b67c6ffab2bb00cULL, }, + { 0x886ae6cc5e315540ULL, 0x8df188d8a942b00cULL, }, + { 0x886ae6cc4d935540ULL, 0x4b67bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaa4d938b80ULL, 0x27d8bb1aab2b52fcULL, }, + { 0x704f164d5e31c708ULL, 0x8df188d8a94252fcULL, }, + { 0x886aaeaab9cf8b80ULL, 0x4b67c6ffab2bb00cULL, }, /* 72 */ + { 0xac5aaeaa4d938b80ULL, 0x27d8bb1aab2b52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704faeaa5e318b80ULL, 0x8df188d8a9422514ULL, }, + { 0x886ae6cc5e315540ULL, 0x8df188d8a942b00cULL, }, + { 0x704f164d5e31c708ULL, 0x8df188d8a94252fcULL, }, + { 0x704faeaa5e318b80ULL, 0x8df188d8a9422514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_A_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_A_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_w.c new file mode 100644 index 0000000000..40c30c5569 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_a_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_A.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_A.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaa71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x555555558e38e38eULL, 0x5555555555555555ULL, }, + { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, + { 0xcccccccc71c71c71ULL, 0xc71c71c7ccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x333333338e38e38eULL, 0x38e38e3833333333ULL, }, + { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x555555558e38e38eULL, 0x5555555555555555ULL, }, + { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, + { 0x333333338e38e38eULL, 0x38e38e3833333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaa71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, + { 0xcccccccc71c71c71ULL, 0xc71c71c7ccccccccULL, }, + { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6cc4d93c708ULL, 0x4b670b5e153f52fcULL, }, + { 0x886ae6ccb9cf8b80ULL, 0x4b670b5eab2b2514ULL, }, + { 0x886ae6cc5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc4d93c708ULL, 0x4b670b5e153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaa4d93c708ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6ccb9cf8b80ULL, 0x4b670b5eab2b2514ULL, }, /* 72 */ + { 0xac5aaeaa4d93c708ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_A_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_A_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_b.c new file mode 100644 index 0000000000..ab50eee187 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_S.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_S.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xffff38ffff38ffffULL, 0x38ffff38ffff38ffULL, }, + { 0x1c71ff1c71ff1c71ULL, 0xff1c71ff1c71ff1cULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x0000380000380000ULL, 0x3800003800003800ULL, }, + { 0x1c71001c71001c71ULL, 0x001c71001c71001cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe3aa38e3aa38e3aaULL, 0x38e3aa38e3aa38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5571555571555571ULL, 0x5555715555715555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe3cc38e3cc38e3ccULL, 0x38e3cc38e3cc38e3ULL, }, + { 0x1c71cc1c71cc1c71ULL, 0xcc1c71cc1c71cc1cULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333383333383333ULL, 0x3833333833333833ULL, }, + { 0x3371333371333371ULL, 0x3333713333713333ULL, }, + { 0xffff38ffff38ffffULL, 0x38ffff38ffff38ffULL, }, /* 48 */ + { 0x0000380000380000ULL, 0x3800003800003800ULL, }, + { 0xe3aa38e3aa38e3aaULL, 0x38e3aa38e3aa38e3ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xe3cc38e3cc38e3ccULL, 0x38e3cc38e3cc38e3ULL, }, + { 0x3333383333383333ULL, 0x3833333833333833ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, + { 0x1c71ff1c71ff1c71ULL, 0xff1c71ff1c71ff1cULL, }, /* 56 */ + { 0x1c71001c71001c71ULL, 0x001c71001c71001cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x5571555571555571ULL, 0x5555715555715555ULL, }, + { 0x1c71cc1c71cc1c71ULL, 0xcc1c71cc1c71cc1cULL, }, + { 0x3371333371333371ULL, 0x3333713333713333ULL, }, + { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfb6a00634d625540ULL, 0x4b670b5e157b520cULL, }, + { 0xac6ae6cc28625540ULL, 0x4b670b5efe7b2514ULL, }, + { 0x706a164d5e62554eULL, 0x4b670b5efe7be20cULL, }, + { 0xfb6a00634d625540ULL, 0x4b670b5e157b520cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfb5a00634dcfc708ULL, 0x27f7c61a153f5214ULL, }, + { 0x704f16635e31e24eULL, 0x12f7bb1a154252fcULL, }, + { 0xac6ae6cc28625540ULL, 0x4b670b5efe7b2514ULL, }, /* 72 */ + { 0xfb5a00634dcfc708ULL, 0x27f7c61a153f5214ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x705a164d5e31e24eULL, 0x27f1c6ffab422514ULL, }, + { 0x706a164d5e62554eULL, 0x4b670b5efe7be20cULL, }, + { 0x704f16635e31e24eULL, 0x12f7bb1a154252fcULL, }, + { 0x705a164d5e31e24eULL, 0x27f1c6ffab422514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_S_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_S_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_d.c new file mode 100644 index 0000000000..2957db4abc --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_S.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_S.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xffffffffffffffffULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333333333333333ULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0x0000000000000000ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, + { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ + { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, + { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_S_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_S_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_h.c new file mode 100644 index 0000000000..e101764d73 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_S.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_S.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xffff38e3ffffffffULL, 0x38e3ffffffff38e3ULL, }, + { 0x1c71ffff71c71c71ULL, 0xffff71c71c71ffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x000038e300000000ULL, 0x38e30000000038e3ULL, }, + { 0x1c71000071c71c71ULL, 0x000071c71c710000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e3aaaae38eULL, 0x38e3aaaae38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555571c75555ULL, 0x555571c755555555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e3cccce38eULL, 0x38e3cccce38e38e3ULL, }, + { 0x1c71cccc71c71c71ULL, 0xcccc71c71c71ccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x333338e333333333ULL, 0x38e33333333338e3ULL, }, + { 0x3333333371c73333ULL, 0x333371c733333333ULL, }, + { 0xffff38e3ffffffffULL, 0x38e3ffffffff38e3ULL, }, /* 48 */ + { 0x000038e300000000ULL, 0x38e30000000038e3ULL, }, + { 0xe38e38e3aaaae38eULL, 0x38e3aaaae38e38e3ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xe38e38e3cccce38eULL, 0x38e3cccce38e38e3ULL, }, + { 0x333338e333333333ULL, 0x38e33333333338e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, + { 0x1c71ffff71c71c71ULL, 0xffff71c71c71ffffULL, }, /* 56 */ + { 0x1c71000071c71c71ULL, 0x000071c71c710000ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x5555555571c75555ULL, 0x555571c755555555ULL, }, + { 0x1c71cccc71c71c71ULL, 0xcccc71c71c71ccccULL, }, + { 0x3333333371c73333ULL, 0x333371c733333333ULL, }, + { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe00634d935540ULL, 0x4b670b5e153f52fcULL, }, + { 0xac5ae6cc28625540ULL, 0x4b670b5efe7b2514ULL, }, + { 0x704f164d5e315540ULL, 0x4b670b5efe7be2a0ULL, }, + { 0xfbbe00634d935540ULL, 0x4b670b5e153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x27d8c6ff153f52fcULL, }, + { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5ae6cc28625540ULL, 0x4b670b5efe7b2514ULL, }, /* 72 */ + { 0xfbbe00634d93c708ULL, 0x27d8c6ff153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e315540ULL, 0x4b670b5efe7be2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_S_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_S_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_w.c new file mode 100644 index 0000000000..119f03ffba --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_s_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_S.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_S.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xffffffffffffffffULL, 0x38e38e38ffffffffULL, }, + { 0x1c71c71c71c71c71ULL, 0xffffffff1c71c71cULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x0000000000000000ULL, 0x38e38e3800000000ULL, }, + { 0x1c71c71c71c71c71ULL, 0x000000001c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e3ccccccccULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xcccccccc1c71c71cULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x38e38e3833333333ULL, }, + { 0x3333333371c71c71ULL, 0x3333333333333333ULL, }, + { 0xffffffffffffffffULL, 0x38e38e38ffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x38e38e3800000000ULL, }, + { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xe38e38e3ccccccccULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333333333333333ULL, 0x38e38e3833333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xffffffff1c71c71cULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0x000000001c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x5555555571c71c71ULL, 0x5555555555555555ULL, }, + { 0x1c71c71c71c71c71ULL, 0xcccccccc1c71c71cULL, }, + { 0x3333333371c71c71ULL, 0x3333333333333333ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe00634d93c708ULL, 0x4b670b5e153f52fcULL, }, + { 0xac5aaeaa28625540ULL, 0x4b670b5efe7bb00cULL, }, + { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x4b670b5e153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x27d8c6ff153f52fcULL, }, + { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaa28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ + { 0xfbbe00634d93c708ULL, 0x27d8c6ff153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, + { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_S_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_S_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_b.c new file mode 100644 index 0000000000..d18b6bf0cc --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_U.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_U.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xe3aaaae3aaaae3aaULL, 0xaae3aaaae3aaaae3ULL, }, + { 0xaaaac7aaaac7aaaaULL, 0xc7aaaac7aaaac7aaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xe38e55e38e55e38eULL, 0x55e38e55e38e55e3ULL, }, + { 0x5571c75571c75571ULL, 0xc75571c75571c755ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xe3cccce3cccce3ccULL, 0xcce3cccce3cccce3ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x3371c73371c73371ULL, 0xc73371c73371c733ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe3aaaae3aaaae3aaULL, 0xaae3aaaae3aaaae3ULL, }, + { 0xe38e55e38e55e38eULL, 0x55e38e55e38e55e3ULL, }, + { 0xe3cccce3cccce3ccULL, 0xcce3cccce3cccce3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaac7aaaac7aaaaULL, 0xc7aaaac7aaaac7aaULL, }, + { 0x5571c75571c75571ULL, 0xc75571c75571c755ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3371c73371c73371ULL, 0xc73371c73371c733ULL, }, + { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbee6cc4d93c740ULL, 0x4bf7bb5efe7bb0fcULL, }, + { 0xac6ae6ccb9cf8b80ULL, 0x4bd8c6fffe7bb014ULL, }, + { 0x886ae6cc5e62e24eULL, 0x8df188d8fe7be2a0ULL, }, + { 0xfbbee6cc4d93c740ULL, 0x4bf7bb5efe7bb0fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbeaeaab9cfc780ULL, 0x27f7c6ffab3f52fcULL, }, + { 0xfbbe16635e93e24eULL, 0x8df7bbd8a942e2fcULL, }, + { 0xac6ae6ccb9cf8b80ULL, 0x4bd8c6fffe7bb014ULL, }, /* 72 */ + { 0xfbbeaeaab9cfc780ULL, 0x27f7c6ffab3f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cfe280ULL, 0x8df1c6ffab42e2a0ULL, }, + { 0x886ae6cc5e62e24eULL, 0x8df188d8fe7be2a0ULL, }, + { 0xfbbe16635e93e24eULL, 0x8df7bbd8a942e2fcULL, }, + { 0xac5aaeaab9cfe280ULL, 0x8df1c6ffab42e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_U_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_U_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_d.c new file mode 100644 index 0000000000..1396e740ff --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_U.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_U.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xe38e38e38e38e38eULL, 0x5555555555555555ULL, }, + { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c71c71c71cULL, }, + { 0x5555555555555555ULL, 0xc71c71c71c71c71cULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0xc71c71c71c71c71cULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, + { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, + { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ + { 0xfbbe00634d93c708ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, + { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_U_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_U_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_h.c new file mode 100644 index 0000000000..c7dff10709 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_U.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_U.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xe38eaaaaaaaae38eULL, 0xaaaaaaaae38eaaaaULL, }, + { 0xaaaac71caaaaaaaaULL, 0xc71caaaaaaaac71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xe38e55558e38e38eULL, 0x55558e38e38e5555ULL, }, + { 0x5555c71c71c75555ULL, 0xc71c71c75555c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xe38ecccccccce38eULL, 0xcccccccce38eccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333c71c71c73333ULL, 0xc71c71c73333c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38eaaaaaaaae38eULL, 0xaaaaaaaae38eaaaaULL, }, + { 0xe38e55558e38e38eULL, 0x55558e38e38e5555ULL, }, + { 0xe38ecccccccce38eULL, 0xcccccccce38eccccULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaac71caaaaaaaaULL, 0xc71caaaaaaaac71cULL, }, + { 0x5555c71c71c75555ULL, 0xc71c71c75555c71cULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333c71c71c73333ULL, 0xc71c71c73333c71cULL, }, + { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbee6cc4d93c708ULL, 0x4b67bb1afe7bb00cULL, }, + { 0xac5ae6ccb9cf8b80ULL, 0x4b67c6fffe7bb00cULL, }, + { 0x886ae6cc5e31e24eULL, 0x8df188d8fe7be2a0ULL, }, + { 0xfbbee6cc4d93c708ULL, 0x4b67bb1afe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbeaeaab9cfc708ULL, 0x27d8c6ffab2b52fcULL, }, + { 0xfbbe164d5e31e24eULL, 0x8df1bb1aa942e2a0ULL, }, + { 0xac5ae6ccb9cf8b80ULL, 0x4b67c6fffe7bb00cULL, }, /* 72 */ + { 0xfbbeaeaab9cfc708ULL, 0x27d8c6ffab2b52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cfe24eULL, 0x8df1c6ffab2be2a0ULL, }, + { 0x886ae6cc5e31e24eULL, 0x8df188d8fe7be2a0ULL, }, + { 0xfbbe164d5e31e24eULL, 0x8df1bb1aa942e2a0ULL, }, + { 0xac5aaeaab9cfe24eULL, 0x8df1c6ffab2be2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_U_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_U_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_w.c new file mode 100644 index 0000000000..910dbfc0ca --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_max_u_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MAX_U.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MAX_U.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xe38e38e3aaaaaaaaULL, 0xaaaaaaaae38e38e3ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c7aaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xe38e38e38e38e38eULL, 0x55555555e38e38e3ULL, }, + { 0x5555555571c71c71ULL, 0xc71c71c755555555ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e3aaaaaaaaULL, 0xaaaaaaaae38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x55555555e38e38e3ULL, }, + { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xc71c71c7aaaaaaaaULL, }, + { 0x5555555571c71c71ULL, 0xc71c71c755555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333371c71c71ULL, 0xc71c71c733333333ULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, + { 0x886ae6cc5e31e24eULL, 0x8df188d8fe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe0063b9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xfbbe00635e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x4b670b5efe7bb00cULL, }, /* 72 */ + { 0xfbbe0063b9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8ab2b2514ULL, }, + { 0x886ae6cc5e31e24eULL, 0x8df188d8fe7bb00cULL, }, + { 0xfbbe00635e31e24eULL, 0x8df188d8a942e2a0ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8ab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_U_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MAX_U_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_b.c new file mode 100644 index 0000000000..c632fe974f --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_A.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_A.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe3aa38e3aa38e3aaULL, 0x38e3aa38e3aa38e3ULL, }, + { 0x1caac71caac71caaULL, 0xc71caac71caac71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe35538e35538e355ULL, 0x38e35538e35538e3ULL, }, + { 0x1c55c71c55c71c55ULL, 0xc71c55c71c55c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe3cccce3cccce3ccULL, 0xcce3cccce3cccce3ULL, }, + { 0x1ccccc1ccccc1cccULL, 0xcc1ccccc1ccccc1cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe33333e33333e333ULL, 0x33e33333e33333e3ULL, }, + { 0x1c33331c33331c33ULL, 0x331c33331c33331cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xe3aa38e3aa38e3aaULL, 0x38e3aa38e3aa38e3ULL, }, + { 0xe35538e35538e355ULL, 0x38e35538e35538e3ULL, }, + { 0xe3cccce3cccce3ccULL, 0xcce3cccce3cccce3ULL, }, + { 0xe33333e33333e333ULL, 0x33e33333e33333e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x1caac71caac71caaULL, 0xc71caac71caac71cULL, }, + { 0x1c55c71c55c71c55ULL, 0xc71c55c71c55c71cULL, }, + { 0x1ccccc1ccccc1cccULL, 0xcc1ccccc1ccccc1cULL, }, + { 0x1c33331c33331c33ULL, 0x331c33331c33331cULL, }, + { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe00cc2862c708ULL, 0x12f70b1afe3fb0fcULL, }, + { 0xac5ae6cc28cf5540ULL, 0x27d80bfffe2b250cULL, }, + { 0x704f16cc2831e240ULL, 0x4bf10bd8fe42e20cULL, }, + { 0xfbbe00cc2862c708ULL, 0x12f70b1afe3fb0fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00aab9cfc708ULL, 0x12f7c6ff152b25fcULL, }, + { 0xfbbe004d4d31e208ULL, 0x12f7bb1a153fe2fcULL, }, + { 0xac5ae6cc28cf5540ULL, 0x27d80bfffe2b250cULL, }, /* 72 */ + { 0xfbbe00aab9cfc708ULL, 0x12f7c6ff152b25fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac4f164db931e24eULL, 0x27f1c6ffab2be214ULL, }, + { 0x704f16cc2831e240ULL, 0x4bf10bd8fe42e20cULL, }, + { 0xfbbe004d4d31e208ULL, 0x12f7bb1a153fe2fcULL, }, + { 0xac4f164db9cfe24eULL, 0x27f1c6ffab2be214ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_A_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_A_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_d.c new file mode 100644 index 0000000000..5f9a9d4706 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_A.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_A.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, + { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, + { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0xccccccccccccccccULL, }, + { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xccccccccccccccccULL, }, + { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_A_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_A_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_h.c new file mode 100644 index 0000000000..dc73927bb7 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_A.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_A.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e3aaaae38eULL, 0x38e3aaaae38e38e3ULL, }, + { 0x1c71c71caaaa1c71ULL, 0xc71caaaa1c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e35555e38eULL, 0x38e35555e38e38e3ULL, }, + { 0x1c71c71c55551c71ULL, 0xc71c55551c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38ecccccccce38eULL, 0xcccccccce38eccccULL, }, + { 0x1c71cccccccc1c71ULL, 0xcccccccc1c71ccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e33333333e38eULL, 0x33333333e38e3333ULL, }, + { 0x1c71333333331c71ULL, 0x333333331c713333ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xe38e38e3aaaae38eULL, 0x38e3aaaae38e38e3ULL, }, + { 0xe38e38e35555e38eULL, 0x38e35555e38e38e3ULL, }, + { 0xe38ecccccccce38eULL, 0xcccccccce38eccccULL, }, + { 0xe38e33333333e38eULL, 0x33333333e38e3333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x1c71c71caaaa1c71ULL, 0xc71caaaa1c71c71cULL, }, + { 0x1c71c71c55551c71ULL, 0xc71c55551c71c71cULL, }, + { 0x1c71cccccccc1c71ULL, 0xcccccccc1c71ccccULL, }, + { 0x1c71333333331c71ULL, 0x333333331c713333ULL, }, + { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe00632862c708ULL, 0x12f70b5efe7bb00cULL, }, + { 0xac5ae6cc28625540ULL, 0x27d80b5efe7b2514ULL, }, + { 0x704f164d2862e24eULL, 0x4b670b5efe7be2a0ULL, }, + { 0xfbbe00632862c708ULL, 0x12f70b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe0063b9cfc708ULL, 0x12f7c6ff153f2514ULL, }, + { 0xfbbe00634d93e24eULL, 0x12f7bb1a153fe2a0ULL, }, + { 0xac5ae6cc28625540ULL, 0x27d80b5efe7b2514ULL, }, /* 72 */ + { 0xfbbe0063b9cfc708ULL, 0x12f7c6ff153f2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5a164db9cfe24eULL, 0x27d8c6ffab2be2a0ULL, }, + { 0x704f164d2862e24eULL, 0x4b670b5efe7be2a0ULL, }, + { 0xfbbe00634d93e24eULL, 0x12f7bb1a153fe2a0ULL, }, + { 0xac5a164db9cfe24eULL, 0x27d8c6ffab2be2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_A_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_A_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_w.c new file mode 100644 index 0000000000..67b33f3751 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_a_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_A.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_A.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71caaaaaaaaULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e355555555ULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, + { 0x1c71c71cccccccccULL, 0xcccccccc1c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e333333333ULL, 0x33333333e38e38e3ULL, }, + { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xe38e38e3aaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e355555555ULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e3ccccccccULL, 0xcccccccce38e38e3ULL, }, + { 0xe38e38e333333333ULL, 0x33333333e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x1c71c71caaaaaaaaULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71cccccccccULL, 0xcccccccc1c71c71cULL, }, + { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0xfbbe006328625540ULL, 0x12f7bb1afe7bb00cULL, }, + { 0xac5aaeaa28625540ULL, 0x27d8c6fffe7bb00cULL, }, + { 0x704f164d28625540ULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe006328625540ULL, 0x12f7bb1afe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe0063b9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaa28625540ULL, 0x27d8c6fffe7bb00cULL, }, /* 72 */ + { 0xfbbe0063b9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d28625540ULL, 0x4b670b5efe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_A_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_A_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_b.c new file mode 100644 index 0000000000..76bb133da7 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_S.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_S.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xe38effe38effe38eULL, 0xffe38effe38effe3ULL, }, + { 0xffffc7ffffc7ffffULL, 0xc7ffffc7ffffc7ffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xe38e00e38e00e38eULL, 0x00e38e00e38e00e3ULL, }, + { 0x0000c70000c70000ULL, 0xc70000c70000c700ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaa8eaaaa8eaaaa8eULL, 0xaaaa8eaaaa8eaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c55c71c55c71c55ULL, 0xc71c55c71c55c71cULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xcc8ecccc8ecccc8eULL, 0xcccc8ecccc8eccccULL, }, + { 0xccccc7ccccc7ccccULL, 0xc7ccccc7ccccc7ccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e33e38e33e38eULL, 0x33e38e33e38e33e3ULL, }, + { 0x1c33c71c33c71c33ULL, 0xc71c33c71c33c71cULL, }, + { 0xe38effe38effe38eULL, 0xffe38effe38effe3ULL, }, /* 48 */ + { 0xe38e00e38e00e38eULL, 0x00e38e00e38e00e3ULL, }, + { 0xaa8eaaaa8eaaaa8eULL, 0xaaaa8eaaaa8eaaaaULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xcc8ecccc8ecccc8eULL, 0xcccc8ecccc8eccccULL, }, + { 0xe38e33e38e33e38eULL, 0x33e38e33e38e33e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, + { 0xffffc7ffffc7ffffULL, 0xc7ffffc7ffffc7ffULL, }, /* 56 */ + { 0x0000c70000c70000ULL, 0xc70000c70000c700ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x1c55c71c55c71c55ULL, 0xc71c55c71c55c71cULL, }, + { 0xccccc7ccccc7ccccULL, 0xc7ccccc7ccccc7ccULL, }, + { 0x1c33c71c33c71c33ULL, 0xc71c33c71c33c71cULL, }, + { 0xe38ec7e38ec7e38eULL, 0xc7e38ec7e38ec7e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x88bee6cc2893c708ULL, 0x12f7bb1afe3fb0fcULL, }, + { 0x885aaeaab9cf8b80ULL, 0x27d8c6ffab2bb00cULL, }, + { 0x884fe6cc2831e240ULL, 0x8df188d8a942b0a0ULL, }, + { 0x88bee6cc2893c708ULL, 0x12f7bb1afe3fb0fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xacbeaeaab9938b80ULL, 0x12d8bbffab2b25fcULL, }, + { 0xfbbe004d4d93c708ULL, 0x8df188d8a93fe2a0ULL, }, + { 0x885aaeaab9cf8b80ULL, 0x27d8c6ffab2bb00cULL, }, /* 72 */ + { 0xacbeaeaab9938b80ULL, 0x12d8bbffab2b25fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac4faeaab9cf8b80ULL, 0x8dd888d8a92be2a0ULL, }, + { 0x884fe6cc2831e240ULL, 0x8df188d8a942b0a0ULL, }, + { 0xfbbe004d4d93c708ULL, 0x8df188d8a93fe2a0ULL, }, + { 0xac4faeaab9cf8b80ULL, 0x8dd888d8a92be2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_S_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_S_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_d.c new file mode 100644 index 0000000000..8ef57a9533 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_S.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_S.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, + { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xe38e38e38e38e38eULL, 0xffffffffffffffffULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xe38e38e38e38e38eULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, + { 0xffffffffffffffffULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x0000000000000000ULL, 0xc71c71c71c71c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xccccccccccccccccULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, + { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ + { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, + { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_S_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_S_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_h.c new file mode 100644 index 0000000000..e206040f98 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_S.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_S.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xe38effff8e38e38eULL, 0xffff8e38e38effffULL, }, + { 0xffffc71cffffffffULL, 0xc71cffffffffc71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xe38e00008e38e38eULL, 0x00008e38e38e0000ULL, }, + { 0x0000c71c00000000ULL, 0xc71c00000000c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaa8e38aaaaULL, 0xaaaa8e38aaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c55551c71ULL, 0xc71c55551c71c71cULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xcccccccc8e38ccccULL, 0xcccc8e38ccccccccULL, }, + { 0xccccc71cccccccccULL, 0xc71cccccccccc71cULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e33338e38e38eULL, 0x33338e38e38e3333ULL, }, + { 0x1c71c71c33331c71ULL, 0xc71c33331c71c71cULL, }, + { 0xe38effff8e38e38eULL, 0xffff8e38e38effffULL, }, /* 48 */ + { 0xe38e00008e38e38eULL, 0x00008e38e38e0000ULL, }, + { 0xaaaaaaaa8e38aaaaULL, 0xaaaa8e38aaaaaaaaULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xcccccccc8e38ccccULL, 0xcccc8e38ccccccccULL, }, + { 0xe38e33338e38e38eULL, 0x33338e38e38e3333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, + { 0xffffc71cffffffffULL, 0xc71cffffffffc71cULL, }, /* 56 */ + { 0x0000c71c00000000ULL, 0xc71c00000000c71cULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x1c71c71c55551c71ULL, 0xc71c55551c71c71cULL, }, + { 0xccccc71cccccccccULL, 0xc71cccccccccc71cULL, }, + { 0x1c71c71c33331c71ULL, 0xc71c33331c71c71cULL, }, + { 0xe38ec71c8e38e38eULL, 0xc71c8e38e38ec71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6cc2862c708ULL, 0x12f7bb1afe7bb00cULL, }, + { 0x886aaeaab9cf8b80ULL, 0x27d8c6ffab2bb00cULL, }, + { 0x886ae6cc2862e24eULL, 0x8df188d8a942b00cULL, }, + { 0x886ae6cc2862c708ULL, 0x12f7bb1afe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, + { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886aaeaab9cf8b80ULL, 0x27d8c6ffab2bb00cULL, }, /* 72 */ + { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc2862e24eULL, 0x8df188d8a942b00cULL, }, + { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_S_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_S_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_w.c new file mode 100644 index 0000000000..7532bce550 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_s_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_S.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_S.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, + { 0xe38e38e38e38e38eULL, 0xffffffffe38e38e3ULL, }, + { 0xffffffffffffffffULL, 0xc71c71c7ffffffffULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xe38e38e38e38e38eULL, 0x00000000e38e38e3ULL, }, + { 0x0000000000000000ULL, 0xc71c71c700000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0xcccccccc8e38e38eULL, 0xccccccccccccccccULL, }, + { 0xccccccccccccccccULL, 0xc71c71c7ccccccccULL, }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x33333333e38e38e3ULL, }, + { 0x1c71c71c33333333ULL, 0xc71c71c71c71c71cULL, }, + { 0xe38e38e38e38e38eULL, 0xffffffffe38e38e3ULL, }, /* 48 */ + { 0xe38e38e38e38e38eULL, 0x00000000e38e38e3ULL, }, + { 0xaaaaaaaa8e38e38eULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xcccccccc8e38e38eULL, 0xccccccccccccccccULL, }, + { 0xe38e38e38e38e38eULL, 0x33333333e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, + { 0xffffffffffffffffULL, 0xc71c71c7ffffffffULL, }, /* 56 */ + { 0x0000000000000000ULL, 0xc71c71c700000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x1c71c71c55555555ULL, 0xc71c71c71c71c71cULL, }, + { 0xccccccccccccccccULL, 0xc71c71c7ccccccccULL, }, + { 0x1c71c71c33333333ULL, 0xc71c71c71c71c71cULL, }, + { 0xe38e38e38e38e38eULL, 0xc71c71c7e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6cc28625540ULL, 0x12f7bb1afe7bb00cULL, }, + { 0x886ae6ccb9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x12f7bb1afe7bb00cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, + { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6ccb9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ + { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1aab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x8df188d8a942e2a0ULL, }, + { 0xfbbe00634d93c708ULL, 0x8df188d8a942e2a0ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x8df188d8a942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_S_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_S_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_b.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_b.c new file mode 100644 index 0000000000..1f611453a2 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_b.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_U.B + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_U.B"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaa8e38aa8e38aa8eULL, 0x38aa8e38aa8e38aaULL, }, + { 0x1c71aa1c71aa1c71ULL, 0xaa1c71aa1c71aa1cULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x5555385555385555ULL, 0x3855553855553855ULL, }, + { 0x1c55551c55551c55ULL, 0x551c55551c55551cULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xcc8e38cc8e38cc8eULL, 0x38cc8e38cc8e38ccULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x1c33331c33331c33ULL, 0x331c33331c33331cULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaa8e38aa8e38aa8eULL, 0x38aa8e38aa8e38aaULL, }, + { 0x5555385555385555ULL, 0x3855553855553855ULL, }, + { 0xcc8e38cc8e38cc8eULL, 0x38cc8e38cc8e38ccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x1c71aa1c71aa1c71ULL, 0xaa1c71aa1c71aa1cULL, }, + { 0x1c55551c55551c55ULL, 0x551c55551c55551cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x1c33331c33331c33ULL, 0x331c33331c33331cULL, }, + { 0x1c71381c71381c71ULL, 0x381c71381c71381cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886a006328625508ULL, 0x12670b1a153f520cULL, }, + { 0x885aaeaa28625540ULL, 0x27670b5eab2b250cULL, }, + { 0x704f164d28315540ULL, 0x4b670b5ea942b00cULL, }, + { 0x886a006328625508ULL, 0x12670b1a153f520cULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5a00634d938b08ULL, 0x12d8bb1a152b2514ULL, }, + { 0x704f004d4d31c708ULL, 0x12f1881a153f52a0ULL, }, + { 0x885aaeaa28625540ULL, 0x27670b5eab2b250cULL, }, /* 72 */ + { 0xac5a00634d938b08ULL, 0x12d8bb1a152b2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e318b4eULL, 0x27d888d8a92b2514ULL, }, + { 0x704f164d28315540ULL, 0x4b670b5ea942b00cULL, }, + { 0x704f004d4d31c708ULL, 0x12f1881a153f52a0ULL, }, + { 0x704f164d5e318b4eULL, 0x27d888d8a92b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_U_B(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_U_B(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_d.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_d.c new file mode 100644 index 0000000000..4626c62354 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_d.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_U.D + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_U.D"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0x38e38e38e38e38e3ULL, }, + { 0x5555555555555555ULL, 0x38e38e38e38e38e3ULL, }, + { 0xccccccccccccccccULL, 0x38e38e38e38e38e3ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x1c71c71c71c71c71ULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x1c71c71c71c71c71ULL, 0x5555555555555555ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0x3333333333333333ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, + { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, + { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, + { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, + { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ + { 0xac5aaeaab9cf8b80ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x4b670b5efe7bb00cULL, }, + { 0x704f164d5e31e24eULL, 0x12f7bb1a153f52fcULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_U_D(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_U_D(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_h.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_h.c new file mode 100644 index 0000000000..5eeb8d034b --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_h.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_U.H + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_U.H"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaa38e38e38aaaaULL, 0x38e38e38aaaa38e3ULL, }, + { 0x1c71aaaa71c71c71ULL, 0xaaaa71c71c71aaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x555538e355555555ULL, 0x38e35555555538e3ULL, }, + { 0x1c71555555551c71ULL, 0x555555551c715555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xcccc38e38e38ccccULL, 0x38e38e38cccc38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x1c71333333331c71ULL, 0x333333331c713333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaa38e38e38aaaaULL, 0x38e38e38aaaa38e3ULL, }, + { 0x555538e355555555ULL, 0x38e35555555538e3ULL, }, + { 0xcccc38e38e38ccccULL, 0x38e38e38cccc38e3ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x1c71aaaa71c71c71ULL, 0xaaaa71c71c71aaaaULL, }, + { 0x1c71555555551c71ULL, 0x555555551c715555ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71333333331c71ULL, 0x333333331c713333ULL, }, + { 0x1c7138e371c71c71ULL, 0x38e371c71c7138e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886a006328625540ULL, 0x12f70b5e153f52fcULL, }, + { 0x886aaeaa28625540ULL, 0x27d80b5eab2b2514ULL, }, + { 0x704f164d28625540ULL, 0x4b670b5ea942b00cULL, }, + { 0x886a006328625540ULL, 0x12f70b5e153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5a00634d938b80ULL, 0x12f7bb1a153f2514ULL, }, + { 0x704f00634d93c708ULL, 0x12f788d8153f52fcULL, }, + { 0x886aaeaa28625540ULL, 0x27d80b5eab2b2514ULL, }, /* 72 */ + { 0xac5a00634d938b80ULL, 0x12f7bb1a153f2514ULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e318b80ULL, 0x27d888d8a9422514ULL, }, + { 0x704f164d28625540ULL, 0x4b670b5ea942b00cULL, }, + { 0x704f00634d93c708ULL, 0x12f788d8153f52fcULL, }, + { 0x704f164d5e318b80ULL, 0x27d888d8a9422514ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_U_H(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_U_H(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_w.c b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_w.c new file mode 100644 index 0000000000..e70964afa8 --- /dev/null +++ b/tests/tcg/mips/user/ase/msa/int-max-min/test_msa_min_u_w.c @@ -0,0 +1,153 @@ +/* + * Test program for MSA instruction MIN_U.W + * + * Copyright (C) 2018 Wave Computing, Inc. + * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include <sys/time.h> +#include <stdint.h> + +#include "../../../../include/wrappers_msa.h" +#include "../../../../include/test_inputs.h" +#include "../../../../include/test_utils.h" + +#define TEST_COUNT_TOTAL ( \ + (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \ + (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT)) + + +int32_t main(void) +{ + char *instruction_name = "MIN_U.W"; + int32_t ret; + uint32_t i, j; + struct timeval start, end; + double elapsed_time; + + uint64_t b128_result[TEST_COUNT_TOTAL][2]; + uint64_t b128_expect[TEST_COUNT_TOTAL][2] = { + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, /* 16 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xaaaaaaaa8e38e38eULL, 0x38e38e38aaaaaaaaULL, }, + { 0x1c71c71c71c71c71ULL, 0xaaaaaaaa1c71c71cULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, /* 24 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x5555555555555555ULL, 0x38e38e3855555555ULL, }, + { 0x1c71c71c55555555ULL, 0x555555551c71c71cULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, /* 32 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x5555555555555555ULL, }, + { 0xccccccccccccccccULL, 0xccccccccccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, /* 40 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, /* 48 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0xaaaaaaaa8e38e38eULL, 0x38e38e38aaaaaaaaULL, }, + { 0x5555555555555555ULL, 0x38e38e3855555555ULL, }, + { 0xcccccccc8e38e38eULL, 0x38e38e38ccccccccULL, }, + { 0x3333333333333333ULL, 0x3333333333333333ULL, }, + { 0xe38e38e38e38e38eULL, 0x38e38e38e38e38e3ULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, /* 56 */ + { 0x0000000000000000ULL, 0x0000000000000000ULL, }, + { 0x1c71c71c71c71c71ULL, 0xaaaaaaaa1c71c71cULL, }, + { 0x1c71c71c55555555ULL, 0x555555551c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x1c71c71c33333333ULL, 0x333333331c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0x38e38e381c71c71cULL, }, + { 0x1c71c71c71c71c71ULL, 0xc71c71c71c71c71cULL, }, + { 0x886ae6cc28625540ULL, 0x4b670b5efe7bb00cULL, }, /* 64 */ + { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, + { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d28625540ULL, 0x4b670b5ea942e2a0ULL, }, + { 0x886ae6cc28625540ULL, 0x12f7bb1a153f52fcULL, }, + { 0xfbbe00634d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaa4d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0x704f164d4d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0x886ae6cc28625540ULL, 0x27d8c6ffab2b2514ULL, }, /* 72 */ + { 0xac5aaeaa4d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0xac5aaeaab9cf8b80ULL, 0x27d8c6ffab2b2514ULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffa942e2a0ULL, }, + { 0x704f164d28625540ULL, 0x4b670b5ea942e2a0ULL, }, + { 0x704f164d4d93c708ULL, 0x12f7bb1a153f52fcULL, }, + { 0x704f164d5e31e24eULL, 0x27d8c6ffa942e2a0ULL, }, + { 0x704f164d5e31e24eULL, 0x8df188d8a942e2a0ULL, }, + }; + + gettimeofday(&start, NULL); + + for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_U_W(b128_pattern[i], b128_pattern[j], + b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]); + } + } + + for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) { + for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) { + do_msa_MIN_U_W(b128_random[i], b128_random[j], + b128_result[((PATTERN_INPUTS_SHORT_COUNT) * + (PATTERN_INPUTS_SHORT_COUNT)) + + RANDOM_INPUTS_SHORT_COUNT * i + j]); + } + } + + gettimeofday(&end, NULL); + + elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0; + elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0; + + ret = check_results(instruction_name, TEST_COUNT_TOTAL, elapsed_time, + &b128_result[0][0], &b128_expect[0][0]); + + return ret; +} diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile index 2f5691f75b..2bd4491769 100644 --- a/tests/tcg/xtensa/Makefile +++ b/tests/tcg/xtensa/Makefile @@ -18,6 +18,9 @@ CC = $(CROSS)gcc AS = $(CROSS)gcc -x assembler-with-cpp LD = $(CROSS)ld +ASFLAGS = -Wa,--no-absolute-literals +vectors_ASFLAGS = -mtext-section-literals + XTENSA_SRC_PATH = $(SRC_PATH)/tests/tcg/xtensa INCLUDE_DIRS = $(XTENSA_SRC_PATH) $(SRC_PATH)/target/xtensa/core-$(CORE) XTENSA_INC = $(addprefix -I,$(INCLUDE_DIRS)) @@ -28,15 +31,21 @@ CRT = crt.o vectors.o TESTCASES += test_b.tst TESTCASES += test_bi.tst -#TESTCASES += test_boolean.tst +TESTCASES += test_boolean.tst TESTCASES += test_break.tst TESTCASES += test_bz.tst TESTCASES += test_cache.tst TESTCASES += test_clamps.tst TESTCASES += test_extui.tst TESTCASES += test_fail.tst +TESTCASES += test_flix.tst +TESTCASES += test_fp0_arith.tst +TESTCASES += test_fp0_conv.tst +TESTCASES += test_fp1.tst +TESTCASES += test_fp_cpenable.tst TESTCASES += test_interrupt.tst TESTCASES += test_loop.tst +TESTCASES += test_lsc.tst TESTCASES += test_mac16.tst TESTCASES += test_max.tst TESTCASES += test_min.tst @@ -68,7 +77,7 @@ linker.ld: $(XTENSA_SRC_PATH)/linker.ld.S $(CC) $(XTENSA_INC) $(CFLAGS) -c $< -o $@ %.o: $(XTENSA_SRC_PATH)/%.S - $(CC) $(XTENSA_INC) $(ASFLAGS) -c $< -o $@ + $(CC) $(XTENSA_INC) $($*_ASFLAGS) $(ASFLAGS) -c $< -o $@ %.tst: %.o linker.ld $(XTENSA_SRC_PATH)/macros.inc $(CRT) Makefile $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@ diff --git a/tests/tcg/xtensa/linker.ld.S b/tests/tcg/xtensa/linker.ld.S index d0f33157ca..ac89b0054e 100644 --- a/tests/tcg/xtensa/linker.ld.S +++ b/tests/tcg/xtensa/linker.ld.S @@ -1,17 +1,29 @@ #include "core-isa.h" -#if XTENSA_HAVE_BE +#ifndef XCHAL_VECBASE_RESET_VADDR +#define XCHAL_VECBASE_RESET_VADDR XCHAL_WINDOW_VECTORS_VADDR +#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS 0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS 0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS 0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS 0x00000140 +#endif + +#define RAM_SIZE 0x08000000 /* 128M */ +#define ROM_SIZE 0x00001000 /* 4k */ +#define VECTORS_RESERVED_SIZE 0x1000 + +#if XCHAL_HAVE_BE OUTPUT_FORMAT("elf32-xtensa-be") #else OUTPUT_FORMAT("elf32-xtensa-le") #endif ENTRY(_start) -__DYNAMIC = 0; - MEMORY { - ram : ORIGIN = XCHAL_VECBASE_RESET_VADDR, LENGTH = 0x08000000 /* 128M */ - rom : ORIGIN = XCHAL_RESET_VECTOR_VADDR, LENGTH = 0x00001000 /* 4k */ + ram : ORIGIN = XCHAL_VECBASE_RESET_VADDR, LENGTH = RAM_SIZE + rom : ORIGIN = XCHAL_RESET_VECTOR_VADDR, LENGTH = ROM_SIZE } SECTIONS @@ -22,9 +34,9 @@ SECTIONS *(.init.*) } > rom - .vector : - { #if XCHAL_HAVE_WINDOWED + .vector.window XCHAL_WINDOW_VECTORS_VADDR : + { . = XCHAL_WINDOW_OF4_VECOFS; *(.vector.window_overflow_4) . = XCHAL_WINDOW_UF4_VECOFS; @@ -37,41 +49,58 @@ SECTIONS *(.vector.window_overflow_12) . = XCHAL_WINDOW_UF12_VECOFS; *(.vector.window_underflow_12) + } #endif #if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 2 - . = XCHAL_INTLEVEL2_VECOFS; + .vector.level2 XCHAL_INTLEVEL2_VECTOR_VADDR : + { *(.vector.level2) + } #endif #if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 3 - . = XCHAL_INTLEVEL3_VECOFS; + .vector.level3 XCHAL_INTLEVEL3_VECTOR_VADDR : + { *(.vector.level3) + } #endif #if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 4 - . = XCHAL_INTLEVEL4_VECOFS; + .vector.level4 XCHAL_INTLEVEL4_VECTOR_VADDR : + { *(.vector.level4) + } #endif #if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 5 - . = XCHAL_INTLEVEL5_VECOFS; + .vector.level5 XCHAL_INTLEVEL5_VECTOR_VADDR : + { *(.vector.level5) + } #endif #if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 6 - . = XCHAL_INTLEVEL6_VECOFS; + .vector.level6 XCHAL_INTLEVEL6_VECTOR_VADDR : + { *(.vector.level6) + } #endif #if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI >= 7 - . = XCHAL_INTLEVEL7_VECOFS; + .vector.level7 XCHAL_INTLEVEL7_VECTOR_VADDR : + { *(.vector.level7) + } #endif - - . = XCHAL_KERNEL_VECOFS; + .vector.kernel XCHAL_KERNEL_VECTOR_VADDR : + { *(.vector.kernel) - . = XCHAL_USER_VECOFS; + } + .vector.user XCHAL_USER_VECTOR_VADDR : + { *(.vector.user) - . = XCHAL_DOUBLEEXC_VECOFS; + } + .vector.double XCHAL_DOUBLEEXC_VECTOR_VADDR : + { *(.vector.double) - } > ram + } - .vector.text : + .vector.text XCHAL_VECBASE_RESET_VADDR + VECTORS_RESERVED_SIZE : { *(.vector.window_overflow_4.*) *(.vector.window_underflow_4.*) diff --git a/tests/tcg/xtensa/macros.inc b/tests/tcg/xtensa/macros.inc index 4ebd30ab86..aa8f95bce8 100644 --- a/tests/tcg/xtensa/macros.inc +++ b/tests/tcg/xtensa/macros.inc @@ -23,11 +23,14 @@ main: movi a0, result sub a2, a2, a0 movi a3, 0 - loopnez a2, 1f - l8ui a2, a0, 0 - or a3, a3, a2 - addi a0, a0, 1 + beqz a2, 2f 1: + l8ui a1, a0, 0 + or a3, a3, a1 + addi a0, a0, 1 + addi a2, a2, -1 + bnez a2, 1b +2: exit .endm @@ -49,7 +52,9 @@ main: .endm .macro test name - //print test_\name +#ifdef DEBUG + print test_\name +#endif test_init test_\name: .global test_\name @@ -74,6 +79,9 @@ test_\name: l32i a2, a2, 0 movi a3, 1 s8i a3, a2, 0 +#ifdef DEBUG + print failed +#endif j 99f .endm @@ -89,3 +97,26 @@ test_\name: movi a3, \addr s32i a3, a2, 0 .endm + +.macro dump r +#ifdef DEBUG +.data +.align 4 +1: .word 0 +.text + movi a4, 1b + s32i a2, a4, 0 + movi a2, 4 + movi a3, 1 + movi a5, 4 + simcall + movi a4, 1b + l32i a2, a4, 0 +#endif +.endm + +#define glue(a, b) _glue(a, b) +#define _glue(a, b) a ## b + +#define glue3(a, b, c) _glue3(a, b, c) +#define _glue3(a, b, c) a ## b ## c diff --git a/tests/tcg/xtensa/test_b.S b/tests/tcg/xtensa/test_b.S index 8e81f956df..713a454c53 100644 --- a/tests/tcg/xtensa/test_b.S +++ b/tests/tcg/xtensa/test_b.S @@ -84,12 +84,24 @@ test_end test bbc movi a2, 0xfffffffd - movi a3, 0xffffff01 +#undef BIT +#if XCHAL_HAVE_BE +#define BIT 0xfffffffe +#else +#define BIT 0xffffff01 +#endif + movi a3, BIT bbc a2, a3, 1f test_fail 1: movi a2, 8 - movi a3, 0xffffff03 +#undef BIT +#if XCHAL_HAVE_BE +#define BIT 0xfffffffc +#else +#define BIT 0xffffff03 +#endif + movi a3, BIT bbc a2, a3, 1f j 2f 1: @@ -99,11 +111,11 @@ test_end test bbci movi a2, 0xfffdffff - bbci a2, 17, 1f + bbci.l a2, 17, 1f test_fail 1: movi a2, 0x00020000 - bbci a2, 17, 1f + bbci.l a2, 17, 1f j 2f 1: test_fail @@ -192,12 +204,24 @@ test_end test bbs movi a2, 8 - movi a3, 0xffffff03 +#undef BIT +#if XCHAL_HAVE_BE +#define BIT 0xfffffffc +#else +#define BIT 0xffffff03 +#endif + movi a3, BIT bbs a2, a3, 1f test_fail 1: movi a2, 0xfffffffd - movi a3, 0xffffff01 +#undef BIT +#if XCHAL_HAVE_BE +#define BIT 0xfffffffe +#else +#define BIT 0xffffff01 +#endif + movi a3, BIT bbs a2, a3, 1f j 2f 1: @@ -207,11 +231,11 @@ test_end test bbsi movi a2, 0x00020000 - bbsi a2, 17, 1f + bbsi.l a2, 17, 1f test_fail 1: movi a2, 0xfffdffff - bbsi a2, 17, 1f + bbsi.l a2, 17, 1f j 2f 1: test_fail diff --git a/tests/tcg/xtensa/test_boolean.S b/tests/tcg/xtensa/test_boolean.S index eac40e0973..5a850bfe7e 100644 --- a/tests/tcg/xtensa/test_boolean.S +++ b/tests/tcg/xtensa/test_boolean.S @@ -2,6 +2,8 @@ test_suite boolean +#if XCHAL_HAVE_BOOLEANS + test all4 movi a2, 0xfec0 wsr a2, br @@ -20,4 +22,6 @@ test all4 assert eq, a2, a3 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_break.S b/tests/tcg/xtensa/test_break.S index 775cd7c260..3379a3f9f0 100644 --- a/tests/tcg/xtensa/test_break.S +++ b/tests/tcg/xtensa/test_break.S @@ -1,10 +1,13 @@ #include "macros.inc" -#define debug_level 6 -#define debug_vector level6 - test_suite break +#if XCHAL_HAVE_DEBUG + +#define debug_level XCHAL_DEBUGLEVEL +#define debug_vector glue(level, XCHAL_DEBUGLEVEL) +#define EPC_DEBUG glue(epc, XCHAL_DEBUGLEVEL) + test break set_vector debug_vector, 0 rsil a2, debug_level @@ -21,7 +24,7 @@ test break and a2, a2, a3 movi a3, 0x10 | debug_level assert eq, a2, a3 - rsr a2, epc6 + rsr a2, EPC_DEBUG movi a3, 1b assert eq, a2, a3 rsr a2, debugcause @@ -45,7 +48,7 @@ test breakn and a2, a2, a3 movi a3, 0x10 | debug_level assert eq, a2, a3 - rsr a2, epc6 + rsr a2, EPC_DEBUG movi a3, 1b assert eq, a2, a3 rsr a2, debugcause @@ -53,6 +56,7 @@ test breakn assert eq, a2, a3 test_end +#if XCHAL_NUM_IBREAK test ibreak set_vector debug_vector, 0 rsil a2, debug_level @@ -83,7 +87,7 @@ test ibreak and a2, a2, a3 movi a3, 0x10 | debug_level assert eq, a2, a3 - rsr a2, epc6 + rsr a2, EPC_DEBUG movi a3, 1b assert eq, a2, a3 rsr a2, debugcause @@ -110,7 +114,7 @@ test ibreak_remove and a2, a2, a3 movi a3, 0x10 | debug_level assert eq, a2, a3 - rsr a2, epc6 + rsr a2, EPC_DEBUG movi a3, 2b assert eq, a2, a3 rsr a2, debugcause @@ -141,6 +145,7 @@ test ibreak_priority movi a3, 0x2 assert eq, a2, a3 test_end +#endif test icount set_vector debug_vector, 2f @@ -158,7 +163,7 @@ test icount 2: movi a2, 0 wsr a2, icountlevel - rsr a2, epc6 + rsr a2, EPC_DEBUG movi a3, 1b assert eq, a2, a3 rsr a2, debugcause @@ -167,7 +172,7 @@ test icount test_end .macro check_dbreak dr - rsr a2, epc6 + rsr a2, EPC_DEBUG movi a3, 1b assert eq, a2, a3 rsr a2, debugcause @@ -194,6 +199,7 @@ test_end reset_ps .endm +#if XCHAL_NUM_DBREAK test dbreak_exact dbreak_test 0, 0x4000003f, 0xd000007f, 0xd000007f, l8ui dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007e, l16ui @@ -253,5 +259,8 @@ test dbreak_invalid dbreak_test 0, 0x40000030, 0xd0000071, 0xd0000070, l16ui dbreak_test 1, 0x40000035, 0xd0000072, 0xd0000070, l32i test_end +#endif + +#endif test_suite_end diff --git a/tests/tcg/xtensa/test_cache.S b/tests/tcg/xtensa/test_cache.S index 6b2df9734b..7e6ba4c18a 100644 --- a/tests/tcg/xtensa/test_cache.S +++ b/tests/tcg/xtensa/test_cache.S @@ -7,6 +7,8 @@ test_suite cache +#if XCHAL_HAVE_PTP_MMU + .macro pf_op op \op a2, 0 \op a3, 0 @@ -18,14 +20,23 @@ test prefetch movi a3, 0xd8000000 /* non-cacheable */ movi a4, 0x00001235 /* unmapped */ +#if XCHAL_DCACHE_SIZE pf_op dpfr pf_op dpfro pf_op dpfw pf_op dpfwo +#endif +#ifdef XCHAL_ICACHE_SIZE pf_op ipf - +#endif +#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY +#if XCHAL_DCACHE_LINE_LOCKABLE dpfl a2, 0 +#endif +#if XCHAL_ICACHE_LINE_LOCKABLE ipfl a2, 0 +#endif +#endif test_end .macro cache_fault op, addr, exc_code @@ -46,10 +57,16 @@ test_end assert eq, a2, a3 .endm +#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY + +#if XCHAL_DCACHE_LINE_LOCKABLE test dpfl_tlb_miss cache_fault dpfl, 0x00002345, 24 test_end +#endif +#if XCHAL_DCACHE_SIZE +#if XCHAL_DCACHE_IS_WRITEBACK test dhwb_tlb_miss cache_fault dhwb, 0x00002345, 24 test_end @@ -57,16 +74,21 @@ test_end test dhwbi_tlb_miss cache_fault dhwbi, 0x00002345, 24 test_end +#endif test dhi_tlb_miss cache_fault dhi, 0x00002345, 24 test_end +#if XCHAL_DCACHE_LINE_LOCKABLE test dhu_tlb_miss cache_fault dhu, 0x00002345, 24 test_end +#endif +#endif - +#if XCHAL_ICACHE_SIZE +#if XCHAL_ICACHE_LINE_LOCKABLE test ipfl_tlb_miss cache_fault ipfl, 0x00002345, 16 test_end @@ -74,24 +96,40 @@ test_end test ihu_tlb_miss cache_fault ihu, 0x00002345, 16 test_end +#endif test ihi_tlb_miss cache_fault ihi, 0x00002345, 16 test_end +#endif + +#endif + +#endif test_suite_end -.macro cache_all op1, op2, size, linesize +cache_unlock_invalidate: +#if XCHAL_DCACHE_SIZE movi a2, 0 - movi a3, \size + movi a3, XCHAL_DCACHE_SIZE 1: - \op1 a2, 0 - \op2 a2, 0 - addi a2, a2, \linesize +#if XCHAL_DCACHE_LINE_LOCKABLE + diu a2, 0 +#endif + dii a2, 0 + addi a2, a2, XCHAL_DCACHE_LINESIZE bltu a2, a3, 1b -.endm - -cache_unlock_invalidate: - cache_all diu, dii, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE - cache_all iiu, iii, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE +#endif +#if XCHAL_ICACHE_SIZE + movi a2, 0 + movi a3, XCHAL_ICACHE_SIZE +1: +#if XCHAL_ICACHE_LINE_LOCKABLE + iiu a2, 0 +#endif + iii a2, 0 + addi a2, a2, XCHAL_ICACHE_LINESIZE + bltu a2, a3, 1b +#endif ret diff --git a/tests/tcg/xtensa/test_clamps.S b/tests/tcg/xtensa/test_clamps.S index 3efabfd9d3..d9b2c38ac1 100644 --- a/tests/tcg/xtensa/test_clamps.S +++ b/tests/tcg/xtensa/test_clamps.S @@ -2,6 +2,8 @@ test_suite clamps +#if XCHAL_HAVE_CLAMPS + test clamps movi a2, 0 movi a3, 0 @@ -39,4 +41,6 @@ test clamps assert eq, a3, a2 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_flix.S b/tests/tcg/xtensa/test_flix.S new file mode 100644 index 0000000000..7c259e7018 --- /dev/null +++ b/tests/tcg/xtensa/test_flix.S @@ -0,0 +1,60 @@ +#include "macros.inc" + +test_suite flix + +#if XCHAL_HAVE_FLIX3 + +test misc + { + mov a3, a4 + mov a2, a3 + nop + } + { + nop + bne.w18 a2, a3, 1f + } + movi a2, 1f + { + mov a2, a3 + mov a3, a2 + nop + } + { + l32i a2, a3, 0 + add a4, a4, a2 + nop + } + { + mov a3, a4 + jx a3 + nop + } +1: +test_end + +test sum + + movi a2, 0 + movi a3, 2f + movi a4, 0 + movi a5, 4 + + loop a5, 1f + { + l32i a2, a3, 0 + addi a3, a3, 4 + add a4, a4, a2 + } +1: + add a4, a4, a2 + assert eqi, a4, 10 + .data +2: + .word 1, 2, 3, 4 + .previous +test_end + +#endif + +test_suite_end diff --git a/tests/tcg/xtensa/test_fp0_arith.S b/tests/tcg/xtensa/test_fp0_arith.S new file mode 100644 index 0000000000..253d033a33 --- /dev/null +++ b/tests/tcg/xtensa/test_fp0_arith.S @@ -0,0 +1,173 @@ +#include "macros.inc" + +test_suite fp0_arith + +#if XCHAL_HAVE_FP + +.macro movfp fr, v + movi a2, \v + wfr \fr, a2 +.endm + +.macro check_res fr, r + rfr a2, \fr + dump a2 + movi a3, \r + assert eq, a2, a3 + rur a2, fsr + assert eqi, a2, 0 +.endm + +.macro test_op2_rm op, fr0, fr1, fr2, v0, v1, r + movi a2, 0 + wur a2, fsr + movfp \fr0, \v0 + movfp \fr1, \v1 + \op \fr2, \fr0, \fr1 + check_res \fr2, \r +.endm + +.macro test_op3_rm op, fr0, fr1, fr2, fr3, v0, v1, v2, r + movi a2, 0 + wur a2, fsr + movfp \fr0, \v0 + movfp \fr1, \v1 + movfp \fr2, \v2 + \op \fr0, \fr1, \fr2 + check_res \fr3, \r +.endm + +.macro test_op2_ex op, fr0, fr1, fr2, v0, v1, rm, r + movi a2, \rm + wur a2, fcr + test_op2_rm \op, \fr0, \fr1, \fr2, \v0, \v1, \r + movi a2, (\rm) | 0x7c + wur a2, fcr + test_op2_rm \op, \fr0, \fr1, \fr2, \v0, \v1, \r +.endm + +.macro test_op3_ex op, fr0, fr1, fr2, fr3, v0, v1, v2, rm, r + movi a2, \rm + wur a2, fcr + test_op3_rm \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, \r + movi a2, (\rm) | 0x7c + wur a2, fcr + test_op3_rm \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, \r +.endm + +.macro test_op2 op, fr0, fr1, fr2, v0, v1, r0, r1, r2, r3 + test_op2_ex \op, \fr0, \fr1, \fr2, \v0, \v1, 0, \r0 + test_op2_ex \op, \fr0, \fr1, \fr2, \v0, \v1, 1, \r1 + test_op2_ex \op, \fr0, \fr1, \fr2, \v0, \v1, 2, \r2 + test_op2_ex \op, \fr0, \fr1, \fr2, \v0, \v1, 3, \r3 +.endm + +.macro test_op3 op, fr0, fr1, fr2, fr3, v0, v1, v2, r0, r1, r2, r3 + test_op3_ex \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, 0, \r0 + test_op3_ex \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, 1, \r1 + test_op3_ex \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, 2, \r2 + test_op3_ex \op, \fr0, \fr1, \fr2, \fr3, \v0, \v1, \v2, 3, \r3 +.endm + +.macro test_op2_cpe op + set_vector kernel, 2f + movi a2, 0 + wsr a2, cpenable +1: + \op f2, f0, f1 + test_fail +2: + rsr a2, excvaddr + movi a3, 1b + assert eq, a2, a3 + rsr a2, exccause + movi a3, 32 + assert eq, a2, a3 + + set_vector kernel, 0 + movi a2, 1 + wsr a2, cpenable +.endm + +test add_s + movi a2, 1 + wsr a2, cpenable + + test_op2 add.s, f0, f1, f2, 0x3fc00000, 0x34400000, \ + 0x3fc00002, 0x3fc00001, 0x3fc00002, 0x3fc00001 + test_op2 add.s, f3, f4, f5, 0x3fc00000, 0x34a00000, \ + 0x3fc00002, 0x3fc00002, 0x3fc00003, 0x3fc00002 + + /* MAX_FLOAT + MAX_FLOAT = +inf/MAX_FLOAT */ + test_op2 add.s, f6, f7, f8, 0x7f7fffff, 0x7f7fffff, \ + 0x7f800000, 0x7f7fffff, 0x7f800000, 0x7f7fffff +test_end + +test add_s_inf + /* 1 + +inf = +inf */ + test_op2 add.s, f6, f7, f8, 0x3fc00000, 0x7f800000, \ + 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 + + /* +inf + -inf = default NaN */ + test_op2 add.s, f0, f1, f2, 0x7f800000, 0xff800000, \ + 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000 +test_end + +test add_s_nan + /* 1 + NaN = NaN */ + test_op2 add.s, f9, f10, f11, 0x3fc00000, 0x7fc00001, \ + 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001 + test_op2 add.s, f12, f13, f14, 0x3fc00000, 0x7f800001, \ + 0x7f800001, 0x7f800001, 0x7f800001, 0x7f800001 + + /* NaN1 + NaN2 = NaN1 */ + test_op2 add.s, f15, f0, f1, 0x7f800001, 0x7fbfffff, \ + 0x7f800001, 0x7f800001, 0x7f800001, 0x7f800001 + test_op2 add.s, f2, f3, f4, 0x7fbfffff, 0x7f800001, \ + 0x7fbfffff, 0x7fbfffff, 0x7fbfffff, 0x7fbfffff + test_op2 add.s, f5, f6, f7, 0x7fc00001, 0x7fbfffff, \ + 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001 + test_op2 add.s, f8, f9, f10, 0x7fbfffff, 0x7fc00001, \ + 0x7fbfffff, 0x7fbfffff, 0x7fbfffff, 0x7fbfffff +test_end + +test sub_s + test_op2 sub.s, f0, f1, f0, 0x3f800001, 0x33800000, \ + 0x3f800000, 0x3f800000, 0x3f800001, 0x3f800000 + test_op2 sub.s, f0, f1, f1, 0x3f800002, 0x33800000, \ + 0x3f800002, 0x3f800001, 0x3f800002, 0x3f800001 + + /* norm - norm = denorm */ + test_op2 sub.s, f6, f7, f8, 0x00800001, 0x00800000, \ + 0x00000001, 0x00000001, 0x00000001, 0x00000001 +test_end + +test mul_s + test_op2 mul.s, f0, f1, f2, 0x3f800001, 0x3f800001, \ + 0x3f800002, 0x3f800002, 0x3f800003, 0x3f800002 + + /* MAX_FLOAT/2 * MAX_FLOAT/2 = +inf/MAX_FLOAT */ + test_op2 mul.s, f6, f7, f8, 0x7f000000, 0x7f000000, \ + 0x7f800000, 0x7f7fffff, 0x7f800000, 0x7f7fffff + /* min norm * min norm = 0/denorm */ + test_op2 mul.s, f6, f7, f8, 0x00800001, 0x00800000, \ + 0x00000000, 0x00000000, 0x00000001, 0x00000000 + + /* inf * 0 = default NaN */ + test_op2 mul.s, f6, f7, f8, 0x7f800000, 0x00000000, \ + 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000 +test_end + +test madd_s + test_op3 madd.s, f0, f1, f2, f0, 0, 0x3f800001, 0x3f800001, \ + 0x3f800002, 0x3f800002, 0x3f800003, 0x3f800002 +test_end + +test msub_s + test_op3 msub.s, f0, f1, f2, f0, 0x3f800000, 0x3f800001, 0x3f800001, \ + 0xb4800000, 0xb4800000, 0xb4800000, 0xb4800001 +test_end + +#endif + +test_suite_end diff --git a/tests/tcg/xtensa/test_fp0_conv.S b/tests/tcg/xtensa/test_fp0_conv.S new file mode 100644 index 0000000000..147e3d5062 --- /dev/null +++ b/tests/tcg/xtensa/test_fp0_conv.S @@ -0,0 +1,304 @@ +#include "macros.inc" + +test_suite fp0_conv + +#if XCHAL_HAVE_FP + +.macro movfp fr, v + movi a2, \v + wfr \fr, a2 +.endm + +.macro test_ftoi_ex op, r0, fr0, v, c, r + movi a2, 0 + wur a2, fsr + movfp \fr0, \v + \op \r0, \fr0, \c + dump \r0 + movi a3, \r + assert eq, \r0, a3 + rur a2, fsr + assert eqi, a2, 0 +.endm + +.macro test_ftoi op, r0, fr0, v, c, r + movi a2, 0 + wur a2, fcr + test_ftoi_ex \op, \r0, \fr0, \v, \c, \r + movi a2, 0x7c + wur a2, fcr + test_ftoi_ex \op, \r0, \fr0, \v, \c, \r +.endm + + +.macro test_itof_ex op, fr0, ar0, v, c, r + movi a2, 0 + wur a2, fsr + movi \ar0, \v + \op \fr0, \ar0, \c + + rfr a2, \fr0 + dump a2 + movi a3, \r + assert eq, a2, a3 + rur a2, fsr + assert eqi, a2, 0 +.endm + +.macro test_itof_rm op, fr0, ar0, v, c, rm, r + movi a2, \rm + wur a2, fcr + test_itof_ex \op, \fr0, \ar0, \v, \c, \r + movi a2, (\rm) | 0x7c + wur a2, fcr + test_itof_ex \op, \fr0, \ar0, \v, \c, \r +.endm + +.macro test_itof op, fr0, ar0, v, c, r0, r1, r2, r3 + test_itof_rm \op, \fr0, \ar0, \v, \c, 0, \r0 + test_itof_rm \op, \fr0, \ar0, \v, \c, 1, \r1 + test_itof_rm \op, \fr0, \ar0, \v, \c, 2, \r2 + test_itof_rm \op, \fr0, \ar0, \v, \c, 3, \r3 +.endm + +test round_s + movi a2, 1 + wsr a2, cpenable + + /* NaN */ + test_ftoi round.s, a2, f0, 0xffc00001, 0, 0x7fffffff + test_ftoi round.s, a2, f0, 0xff800001, 0, 0x7fffffff + + /* -inf */ + test_ftoi round.s, a2, f0, 0xff800000, 0, 0x80000000 + + /* negative overflow */ + test_ftoi round.s, a2, f0, 0xceffffff, 1, 0x80000000 + test_ftoi round.s, a2, f0, 0xcf000000, 0, 0x80000000 + test_ftoi round.s, a2, f0, 0xceffffff, 0, 0x80000080 + + /* negative */ + test_ftoi round.s, a2, f0, 0xbfa00000, 1, -2 /* -1.25 * 2 */ + test_ftoi round.s, a2, f0, 0xbfc00000, 0, -2 /* -1.5 */ + test_ftoi round.s, a2, f0, 0xbf800000, 1, -2 /* -1 * 2 */ + test_ftoi round.s, a2, f0, 0xbf800000, 0, -1 /* -1 */ + test_ftoi round.s, a2, f0, 0xbf400000, 0, -1 /* -0.75 */ + test_ftoi round.s, a2, f0, 0xbf000000, 0, 0 /* -0.5 */ + + /* positive */ + test_ftoi round.s, a2, f0, 0x3f000000, 0, 0 /* 0.5 */ + test_ftoi round.s, a2, f0, 0x3f400000, 0, 1 /* 0.75 */ + test_ftoi round.s, a2, f0, 0x3f800000, 0, 1 /* 1 */ + test_ftoi round.s, a2, f0, 0x3f800000, 1, 2 /* 1 * 2 */ + test_ftoi round.s, a2, f0, 0x3fc00000, 0, 2 /* 1.5 */ + test_ftoi round.s, a2, f0, 0x3fa00000, 1, 2 /* 1.25 * 2 */ + + /* positive overflow */ + test_ftoi round.s, a2, f0, 0x4effffff, 0, 0x7fffff80 + test_ftoi round.s, a2, f0, 0x4f000000, 0, 0x7fffffff + test_ftoi round.s, a2, f0, 0x4effffff, 1, 0x7fffffff + + /* +inf */ + test_ftoi round.s, a2, f0, 0x7f800000, 0, 0x7fffffff + + /* NaN */ + test_ftoi round.s, a2, f0, 0x7f800001, 0, 0x7fffffff + test_ftoi round.s, a2, f0, 0x7fc00000, 0, 0x7fffffff +test_end + +test trunc_s + /* NaN */ + test_ftoi trunc.s, a2, f0, 0xffc00001, 0, 0x7fffffff + test_ftoi trunc.s, a2, f0, 0xff800001, 0, 0x7fffffff + + /* -inf */ + test_ftoi trunc.s, a2, f0, 0xff800000, 0, 0x80000000 + + /* negative overflow */ + test_ftoi trunc.s, a2, f0, 0xceffffff, 1, 0x80000000 + test_ftoi trunc.s, a2, f0, 0xcf000000, 0, 0x80000000 + test_ftoi trunc.s, a2, f0, 0xceffffff, 0, 0x80000080 + + /* negative */ + test_ftoi trunc.s, a2, f0, 0xbfa00000, 1, -2 /* -1.25 * 2 */ + test_ftoi trunc.s, a2, f0, 0xbfc00000, 0, -1 /* -1.5 */ + test_ftoi trunc.s, a2, f0, 0xbf800000, 1, -2 /* -1 * 2 */ + test_ftoi trunc.s, a2, f0, 0xbf800000, 0, -1 /* -1 */ + test_ftoi trunc.s, a2, f0, 0xbf400000, 0, 0 /* -0.75 */ + test_ftoi trunc.s, a2, f0, 0xbf000000, 0, 0 /* -0.5 */ + + /* positive */ + test_ftoi trunc.s, a2, f0, 0x3f000000, 0, 0 /* 0.5 */ + test_ftoi trunc.s, a2, f0, 0x3f400000, 0, 0 /* 0.75 */ + test_ftoi trunc.s, a2, f0, 0x3f800000, 0, 1 /* 1 */ + test_ftoi trunc.s, a2, f0, 0x3f800000, 1, 2 /* 1 * 2 */ + test_ftoi trunc.s, a2, f0, 0x3fc00000, 0, 1 /* 1.5 */ + test_ftoi trunc.s, a2, f0, 0x3fa00000, 1, 2 /* 1.25 * 2 */ + + /* positive overflow */ + test_ftoi trunc.s, a2, f0, 0x4effffff, 0, 0x7fffff80 + test_ftoi trunc.s, a2, f0, 0x4f000000, 0, 0x7fffffff + test_ftoi trunc.s, a2, f0, 0x4effffff, 1, 0x7fffffff + + /* +inf */ + test_ftoi trunc.s, a2, f0, 0x7f800000, 0, 0x7fffffff + + /* NaN */ + test_ftoi trunc.s, a2, f0, 0x7f800001, 0, 0x7fffffff + test_ftoi trunc.s, a2, f0, 0x7fc00000, 0, 0x7fffffff +test_end + +test floor_s + /* NaN */ + test_ftoi floor.s, a2, f0, 0xffc00001, 0, 0x7fffffff + test_ftoi floor.s, a2, f0, 0xff800001, 0, 0x7fffffff + + /* -inf */ + test_ftoi floor.s, a2, f0, 0xff800000, 0, 0x80000000 + + /* negative overflow */ + test_ftoi floor.s, a2, f0, 0xceffffff, 1, 0x80000000 + test_ftoi floor.s, a2, f0, 0xcf000000, 0, 0x80000000 + test_ftoi floor.s, a2, f0, 0xceffffff, 0, 0x80000080 + + /* negative */ + test_ftoi floor.s, a2, f0, 0xbfa00000, 1, -3 /* -1.25 * 2 */ + test_ftoi floor.s, a2, f0, 0xbfc00000, 0, -2 /* -1.5 */ + test_ftoi floor.s, a2, f0, 0xbf800000, 1, -2 /* -1 * 2 */ + test_ftoi floor.s, a2, f0, 0xbf800000, 0, -1 /* -1 */ + test_ftoi floor.s, a2, f0, 0xbf400000, 0, -1 /* -0.75 */ + test_ftoi floor.s, a2, f0, 0xbf000000, 0, -1 /* -0.5 */ + + /* positive */ + test_ftoi floor.s, a2, f0, 0x3f000000, 0, 0 /* 0.5 */ + test_ftoi floor.s, a2, f0, 0x3f400000, 0, 0 /* 0.75 */ + test_ftoi floor.s, a2, f0, 0x3f800000, 0, 1 /* 1 */ + test_ftoi floor.s, a2, f0, 0x3f800000, 1, 2 /* 1 * 2 */ + test_ftoi floor.s, a2, f0, 0x3fc00000, 0, 1 /* 1.5 */ + test_ftoi floor.s, a2, f0, 0x3fa00000, 1, 2 /* 1.25 * 2 */ + + /* positive overflow */ + test_ftoi floor.s, a2, f0, 0x4effffff, 0, 0x7fffff80 + test_ftoi floor.s, a2, f0, 0x4f000000, 0, 0x7fffffff + test_ftoi floor.s, a2, f0, 0x4effffff, 1, 0x7fffffff + + /* +inf */ + test_ftoi floor.s, a2, f0, 0x7f800000, 0, 0x7fffffff + + /* NaN */ + test_ftoi floor.s, a2, f0, 0x7f800001, 0, 0x7fffffff + test_ftoi floor.s, a2, f0, 0x7fc00000, 0, 0x7fffffff +test_end + +test ceil_s + /* NaN */ + test_ftoi ceil.s, a2, f0, 0xffc00001, 0, 0x7fffffff + test_ftoi ceil.s, a2, f0, 0xff800001, 0, 0x7fffffff + + /* -inf */ + test_ftoi ceil.s, a2, f0, 0xff800000, 0, 0x80000000 + + /* negative overflow */ + test_ftoi ceil.s, a2, f0, 0xceffffff, 1, 0x80000000 + test_ftoi ceil.s, a2, f0, 0xcf000000, 0, 0x80000000 + test_ftoi ceil.s, a2, f0, 0xceffffff, 0, 0x80000080 + + /* negative */ + test_ftoi ceil.s, a2, f0, 0xbfa00000, 1, -2 /* -1.25 * 2 */ + test_ftoi ceil.s, a2, f0, 0xbfc00000, 0, -1 /* -1.5 */ + test_ftoi ceil.s, a2, f0, 0xbf800000, 1, -2 /* -1 * 2 */ + test_ftoi ceil.s, a2, f0, 0xbf800000, 0, -1 /* -1 */ + test_ftoi ceil.s, a2, f0, 0xbf400000, 0, 0 /* -0.75 */ + test_ftoi ceil.s, a2, f0, 0xbf000000, 0, 0 /* -0.5 */ + + /* positive */ + test_ftoi ceil.s, a2, f0, 0x3f000000, 0, 1 /* 0.5 */ + test_ftoi ceil.s, a2, f0, 0x3f400000, 0, 1 /* 0.75 */ + test_ftoi ceil.s, a2, f0, 0x3f800000, 0, 1 /* 1 */ + test_ftoi ceil.s, a2, f0, 0x3f800000, 1, 2 /* 1 * 2 */ + test_ftoi ceil.s, a2, f0, 0x3fc00000, 0, 2 /* 1.5 */ + test_ftoi ceil.s, a2, f0, 0x3fa00000, 1, 3 /* 1.25 * 2 */ + + /* positive overflow */ + test_ftoi ceil.s, a2, f0, 0x4effffff, 0, 0x7fffff80 + test_ftoi ceil.s, a2, f0, 0x4f000000, 0, 0x7fffffff + test_ftoi ceil.s, a2, f0, 0x4effffff, 1, 0x7fffffff + + /* +inf */ + test_ftoi ceil.s, a2, f0, 0x7f800000, 0, 0x7fffffff + + /* NaN */ + test_ftoi ceil.s, a2, f0, 0x7f800001, 0, 0x7fffffff + test_ftoi ceil.s, a2, f0, 0x7fc00000, 0, 0x7fffffff +test_end + +test utrunc_s + /* NaN */ + test_ftoi utrunc.s, a2, f0, 0xffc00001, 0, 0xffffffff + test_ftoi utrunc.s, a2, f0, 0xff800001, 0, 0xffffffff + + /* -inf */ + test_ftoi utrunc.s, a2, f0, 0xff800000, 0, 0x80000000 + + /* negative overflow */ + test_ftoi utrunc.s, a2, f0, 0xceffffff, 1, 0x80000000 + test_ftoi utrunc.s, a2, f0, 0xcf000000, 0, 0x80000000 + test_ftoi utrunc.s, a2, f0, 0xceffffff, 0, 0x80000080 + + /* negative */ + test_ftoi utrunc.s, a2, f0, 0xbfa00000, 1, -2 /* -1.25 * 2 */ + test_ftoi utrunc.s, a2, f0, 0xbfc00000, 0, -1 /* -1.5 */ + test_ftoi utrunc.s, a2, f0, 0xbf800000, 1, -2 /* -1 * 2 */ + test_ftoi utrunc.s, a2, f0, 0xbf800000, 0, -1 /* -1 */ + test_ftoi utrunc.s, a2, f0, 0xbf400000, 0, 0 /* -0.75 */ + test_ftoi utrunc.s, a2, f0, 0xbf000000, 0, 0 /* -0.5 */ + + /* positive */ + test_ftoi utrunc.s, a2, f0, 0x3f000000, 0, 0 /* 0.5 */ + test_ftoi utrunc.s, a2, f0, 0x3f400000, 0, 0 /* 0.75 */ + test_ftoi utrunc.s, a2, f0, 0x3f800000, 0, 1 /* 1 */ + test_ftoi utrunc.s, a2, f0, 0x3f800000, 1, 2 /* 1 * 2 */ + test_ftoi utrunc.s, a2, f0, 0x3fc00000, 0, 1 /* 1.5 */ + test_ftoi utrunc.s, a2, f0, 0x3fa00000, 1, 2 /* 1.25 * 2 */ + + /* positive overflow */ + test_ftoi utrunc.s, a2, f0, 0x4effffff, 0, 0x7fffff80 + test_ftoi utrunc.s, a2, f0, 0x4f000000, 0, 0x80000000 + test_ftoi utrunc.s, a2, f0, 0x4effffff, 1, 0xffffff00 + test_ftoi utrunc.s, a2, f0, 0x4f800000, 1, 0xffffffff + + /* +inf */ + test_ftoi utrunc.s, a2, f0, 0x7f800000, 0, 0xffffffff + + /* NaN */ + test_ftoi utrunc.s, a2, f0, 0x7f800001, 0, 0xffffffff + test_ftoi utrunc.s, a2, f0, 0x7fc00000, 0, 0xffffffff +test_end + +test float_s + test_itof float.s, f0, a2, -1, 0, \ + 0xbf800000, 0xbf800000, 0xbf800000, 0xbf800000 + test_itof float.s, f0, a2, 0, 0, 0, 0, 0, 0 + test_itof float.s, f0, a2, 1, 1, \ + 0x3f000000, 0x3f000000, 0x3f000000, 0x3f000000 + test_itof float.s, f0, a2, 1, 0, \ + 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 + test_itof float.s, f0, a2, 0x7fffffff, 0, \ + 0x4f000000, 0x4effffff, 0x4f000000, 0x4effffff +test_end + +test ufloat_s + test_itof ufloat.s, f0, a2, 0, 0, 0, 0, 0, 0 + test_itof ufloat.s, f0, a2, 1, 1, \ + 0x3f000000, 0x3f000000, 0x3f000000, 0x3f000000 + test_itof ufloat.s, f0, a2, 1, 0, \ + 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 + test_itof ufloat.s, f0, a2, 0x7fffffff, 0, \ + 0x4f000000, 0x4effffff, 0x4f000000, 0x4effffff + test_itof ufloat.s, f0, a2, 0xffffffff, 0, \ + 0x4f800000, 0x4f7fffff, 0x4f800000, 0x4f7fffff +test_end + +#endif + +test_suite_end diff --git a/tests/tcg/xtensa/test_fp1.S b/tests/tcg/xtensa/test_fp1.S new file mode 100644 index 0000000000..6e182e5964 --- /dev/null +++ b/tests/tcg/xtensa/test_fp1.S @@ -0,0 +1,141 @@ +#include "macros.inc" + +test_suite fp1 + +#if XCHAL_HAVE_FP + +.macro movfp fr, v + movi a2, \v + wfr \fr, a2 +.endm + +.macro test_ord_ex op, br, fr0, fr1, v0, v1, r + movi a2, 0 + wur a2, fsr + movfp \fr0, \v0 + movfp \fr1, \v1 + \op \br, \fr0, \fr1 + movi a2, 0 + movi a3, 1 + movt a2, a3, \br + assert eqi, a2, \r + rur a2, fsr + assert eqi, a2, 0 +.endm + +.macro test_ord op, br, fr0, fr1, v0, v1, r + movi a2, 0 + wur a2, fcr + test_ord_ex \op, \br, \fr0, \fr1, \v0, \v1, \r + movi a2, 0x7c + wur a2, fcr + test_ord_ex \op, \br, \fr0, \fr1, \v0, \v1, \r +.endm + +.macro test_ord_all op, aa, ab, ba, aPI, PIa, aN, Na, II, IN, NI + test_ord \op b0, f0, f1, 0x3f800000, 0x3f800000, \aa + test_ord \op b1, f2, f3, 0x3f800000, 0x3fc00000, \ab + test_ord \op b2, f4, f5, 0x3fc00000, 0x3f800000, \ba + test_ord \op b3, f6, f7, 0x3f800000, 0x7f800000, \aPI + test_ord \op b4, f8, f9, 0x7f800000, 0x3f800000, \PIa + test_ord \op b5, f10, f11, 0x3f800000, 0xffc00001, \aN + test_ord \op b6, f12, f13, 0x3f800000, 0xff800001, \aN + test_ord \op b7, f14, f15, 0x3f800000, 0x7f800001, \aN + test_ord \op b8, f0, f1, 0x3f800000, 0x7fc00000, \aN + test_ord \op b9, f2, f3, 0xffc00001, 0x3f800000, \Na + test_ord \op b10, f4, f5, 0xff800001, 0x3f800000, \Na + test_ord \op b11, f6, f7, 0x7f800001, 0x3f800000, \Na + test_ord \op b12, f8, f9, 0x7fc00000, 0x3f800000, \Na + test_ord \op b13, f10, f11, 0x7f800000, 0x7f800000, \II + test_ord \op b14, f12, f13, 0x7f800000, 0x7fc00000, \IN + test_ord \op b15, f14, f15, 0x7fc00000, 0x7f800000, \NI +.endm + +test un_s + movi a2, 1 + wsr a2, cpenable + test_ord_all un.s, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1 +test_end + +test oeq_s + test_ord_all oeq.s, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 +test_end + +test ueq_s + test_ord_all ueq.s, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1 +test_end + +test olt_s + test_ord_all olt.s, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 +test_end + +test ult_s + test_ord_all ult.s, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1 +test_end + +test ole_s + test_ord_all ole.s, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0 +test_end + +test ule_s + test_ord_all ule.s, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1 +test_end + +.macro test_cond op, fr0, fr1, cr, v0, v1, r + movfp \fr0, \v0 + movfp \fr1, \v1 + \op \fr0, \fr1, \cr + rfr a2, \fr0 + movi a3, \r + assert eq, a2, a3 +.endm + +test moveqz_s + movi a3, 0 + test_cond moveqz.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 + movi a3, 1 + test_cond moveqz.s, f0, f1, a3, 0, 0x3f800000, 0 +test_end + +test movnez_s + movi a3, 0 + test_cond movnez.s, f0, f1, a3, 0, 0x3f800000, 0 + movi a3, 1 + test_cond movnez.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 +test_end + +test movltz_s + movi a3, -1 + test_cond movltz.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 + movi a3, 0 + test_cond movltz.s, f0, f1, a3, 0, 0x3f800000, 0 + movi a3, 1 + test_cond movltz.s, f0, f1, a3, 0, 0x3f800000, 0 +test_end + +test movgez_s + movi a3, -1 + test_cond movgez.s, f0, f1, a3, 0, 0x3f800000, 0 + movi a3, 0 + test_cond movgez.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 + movi a3, 1 + test_cond movgez.s, f0, f1, a3, 0, 0x3f800000, 0x3f800000 +test_end + +test movf_s + olt.s b0, f0, f0 + test_cond movf.s, f0, f1, b0, 0, 0x3f800000, 0x3f800000 + ueq.s b0, f0, f0 + test_cond movf.s, f0, f1, b0, 0, 0x3f800000, 0 +test_end + +test movt_s + ueq.s b0, f0, f0 + test_cond movt.s, f0, f1, b0, 0, 0x3f800000, 0x3f800000 + olt.s b0, f0, f0 + test_cond movt.s, f0, f1, b0, 0, 0x3f800000, 0 +test_end + +#endif + +test_suite_end diff --git a/tests/tcg/xtensa/test_fp_cpenable.S b/tests/tcg/xtensa/test_fp_cpenable.S new file mode 100644 index 0000000000..882bb2f3ce --- /dev/null +++ b/tests/tcg/xtensa/test_fp_cpenable.S @@ -0,0 +1,27 @@ +#include "macros.inc" + +test_suite fp_cpenable + +#if XCHAL_HAVE_FP + +test rur + set_vector kernel, 2f + movi a2, 0 + wsr a2, cpenable + isync +1: + rur a2, fsr + //wfr f0, a2 + test_fail +2: + movi a2, 1b + rsr a3, epc1 + assert eq, a2, a3 + movi a2, 32 + rsr a3, exccause + assert eq, a2, a3 +test_end + +#endif + +test_suite_end diff --git a/tests/tcg/xtensa/test_interrupt.S b/tests/tcg/xtensa/test_interrupt.S index 876683518e..efedc43f60 100644 --- a/tests/tcg/xtensa/test_interrupt.S +++ b/tests/tcg/xtensa/test_interrupt.S @@ -1,15 +1,59 @@ #include "macros.inc" -#define LSBIT(v) ((v) ^ ((v) & ((v) - 1))) +#define LSBIT(v) ((v) & -(v)) + +#define LEVEL_MASK(x) glue3(XCHAL_INTLEVEL, x, _MASK) +#define LEVEL_SOFT_MASK(x) (LEVEL_MASK(x) & XCHAL_INTTYPE_MASK_SOFTWARE) + +#define L1_SOFT_MASK LEVEL_SOFT_MASK(1) +#define L1_SOFT LSBIT(L1_SOFT_MASK) + +#if LEVEL_SOFT_MASK(2) +#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(2) +#elif LEVEL_SOFT_MASK(3) +#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(3) +#elif LEVEL_SOFT_MASK(4) +#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(4) +#elif LEVEL_SOFT_MASK(5) +#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(5) +#elif LEVEL_SOFT_MASK(6) +#define HIGH_LEVEL_SOFT_MASK LEVEL_SOFT_MASK(6) +#else +#define HIGH_LEVEL_SOFT_MASK 0 +#endif + +#define HIGH_LEVEL_SOFT LSBIT(HIGH_LEVEL_SOFT_MASK) + +#if LEVEL_SOFT_MASK(2) +#define HIGH_LEVEL_SOFT_LEVEL 2 +#elif LEVEL_SOFT_MASK(3) +#define HIGH_LEVEL_SOFT_LEVEL 3 +#elif LEVEL_SOFT_MASK(4) +#define HIGH_LEVEL_SOFT_LEVEL 4 +#elif LEVEL_SOFT_MASK(5) +#define HIGH_LEVEL_SOFT_LEVEL 5 +#elif LEVEL_SOFT_MASK(6) +#define HIGH_LEVEL_SOFT_LEVEL 6 +#else +#define HIGH_LEVEL_SOFT_LEVEL 0 +#endif test_suite interrupt +#if XCHAL_HAVE_INTERRUPTS + .macro clear_interrupts movi a2, 0 wsr a2, intenable +#if XCHAL_NUM_TIMERS wsr a2, ccompare0 +#endif +#if XCHAL_NUM_TIMERS > 1 wsr a2, ccompare1 +#endif +#if XCHAL_NUM_TIMERS > 2 wsr a2, ccompare2 +#endif esync rsr a2, interrupt wsr a2, intclear @@ -44,11 +88,12 @@ test rsil assert eqi, a2, 0 test_end +#if L1_SOFT test soft_disabled set_vector kernel, 1f clear_interrupts - movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) + movi a2, L1_SOFT wsr a2, intset esync rsr a3, interrupt @@ -70,7 +115,7 @@ test soft_intenable set_vector kernel, 1f clear_interrupts - movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) + movi a2, L1_SOFT wsr a2, intset esync rsr a3, interrupt @@ -89,7 +134,7 @@ test soft_rsil set_vector kernel, 1f clear_interrupts - movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) + movi a2, L1_SOFT wsr a2, intset esync rsr a3, interrupt @@ -108,7 +153,7 @@ test soft_waiti set_vector kernel, 1f clear_interrupts - movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) + movi a2, L1_SOFT wsr a2, intset esync rsr a3, interrupt @@ -127,7 +172,7 @@ test soft_user set_vector user, 2f clear_interrupts - movi a2, LSBIT(XCHAL_INTTYPE_MASK_SOFTWARE) + movi a2, L1_SOFT wsr a2, intset esync rsr a3, interrupt @@ -147,12 +192,13 @@ test soft_user check_l1 test_end +#if HIGH_LEVEL_SOFT test soft_priority set_vector kernel, 1f - set_vector level3, 2f + set_vector glue(level, HIGH_LEVEL_SOFT_LEVEL), 2f clear_interrupts - movi a2, XCHAL_INTTYPE_MASK_SOFTWARE + movi a2, L1_SOFT | HIGH_LEVEL_SOFT wsr a2, intenable rsil a3, 0 esync @@ -164,17 +210,20 @@ test soft_priority rsr a2, ps movi a3, 0x1f /* EXCM | INTMASK */ and a2, a2, a3 - movi a3, 0x13 + movi a3, 0x10 | HIGH_LEVEL_SOFT_LEVEL assert eq, a2, a3 /* EXCM and INTMASK are set for high-priority interrupt */ test_end +#endif +#endif +#if HIGH_LEVEL_SOFT test eps_epc_rfi - set_vector level3, 3f + set_vector glue(level, HIGH_LEVEL_SOFT_LEVEL), 3f clear_interrupts reset_ps - movi a2, XCHAL_INTTYPE_MASK_SOFTWARE + movi a2, L1_SOFT_MASK | HIGH_LEVEL_SOFT_MASK wsr a2, intenable rsil a3, 0 rsr a3, ps @@ -185,23 +234,26 @@ test eps_epc_rfi 2: test_fail 3: - rsr a2, eps3 + rsr a2, glue(eps, HIGH_LEVEL_SOFT_LEVEL) assert eq, a2, a3 - rsr a2, epc3 + rsr a2, glue(epc, HIGH_LEVEL_SOFT_LEVEL) movi a3, 1b assert ge, a2, a3 movi a3, 2b assert ge, a3, a2 movi a2, 4f - wsr a2, epc3 - movi a2, 0x40003 - wsr a2, eps3 - rfi 3 + wsr a2, glue(epc, HIGH_LEVEL_SOFT_LEVEL) + movi a2, 0x40000 | HIGH_LEVEL_SOFT_LEVEL + wsr a2, glue(eps, HIGH_LEVEL_SOFT_LEVEL) + rfi HIGH_LEVEL_SOFT_LEVEL test_fail 4: rsr a2, ps - movi a3, 0x40003 + movi a3, 0x40000 | HIGH_LEVEL_SOFT_LEVEL assert eq, a2, a3 test_end +#endif + +#endif test_suite_end diff --git a/tests/tcg/xtensa/test_loop.S b/tests/tcg/xtensa/test_loop.S index 5755578d01..0cfd8661ea 100644 --- a/tests/tcg/xtensa/test_loop.S +++ b/tests/tcg/xtensa/test_loop.S @@ -2,6 +2,8 @@ test_suite loop +#if XCHAL_HAVE_LOOPS + test loop movi a2, 0 movi a3, 5 @@ -160,4 +162,6 @@ test loopgtz 1: test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_lsc.S b/tests/tcg/xtensa/test_lsc.S new file mode 100644 index 0000000000..0578bf19e7 --- /dev/null +++ b/tests/tcg/xtensa/test_lsc.S @@ -0,0 +1,122 @@ +#include "macros.inc" + +test_suite lsc + +#if XCHAL_HAVE_FP + +test lsi + movi a2, 1 + wsr a2, cpenable + + movi a2, 1f + lsi f0, a2, 0 + lsi f1, a2, 4 + lsiu f2, a2, 8 + movi a3, 1f + 8 + assert eq, a2, a3 + rfr a2, f0 + movi a3, 0x3f800000 + assert eq, a2, a3 + rfr a2, f1 + movi a3, 0x40000000 + assert eq, a2, a3 + rfr a2, f2 + movi a3, 0x40400000 + assert eq, a2, a3 +.data + .align 4 +1: +.float 1, 2, 3 +.text +test_end + +test ssi + movi a2, 1f + movi a3, 0x40800000 + wfr f3, a3 + ssi f3, a2, 0 + movi a3, 0x40a00000 + wfr f4, a3 + ssi f4, a2, 4 + movi a3, 0x40c00000 + wfr f5, a3 + ssiu f5, a2, 8 + movi a3, 1f + 8 + assert eq, a2, a3 + l32i a4, a2, -8 + movi a3, 0x40800000 + assert eq, a4, a3 + l32i a4, a2, -4 + movi a3, 0x40a00000 + assert eq, a4, a3 + l32i a4, a2, 0 + movi a3, 0x40c00000 + assert eq, a4, a3 +.data + .align 4 +1: +.float 0, 0, 0 +.text +test_end + +test lsx + movi a2, 1f + movi a3, 0 + lsx f6, a2, a3 + movi a3, 4 + lsx f7, a2, a3 + movi a3, 8 + lsxu f8, a2, a3 + movi a3, 1f + 8 + assert eq, a2, a3 + rfr a2, f6 + movi a3, 0x40e00000 + assert eq, a2, a3 + rfr a2, f7 + movi a3, 0x41000000 + assert eq, a2, a3 + rfr a2, f8 + movi a3, 0x41100000 + assert eq, a2, a3 +.data + .align 4 +1: +.float 7, 8, 9 +.text +test_end + +test ssx + movi a2, 1f + movi a3, 0 + movi a4, 0x41200000 + wfr f9, a4 + ssx f9, a2, a3 + movi a3, 4 + movi a4, 0x41300000 + wfr f10, a4 + ssx f10, a2, a3 + movi a3, 8 + movi a4, 0x41400000 + wfr f11, a4 + ssxu f11, a2, a3 + movi a3, 1f + 8 + assert eq, a2, a3 + l32i a4, a2, -8 + movi a3, 0x41200000 + assert eq, a4, a3 + l32i a4, a2, -4 + movi a3, 0x41300000 + assert eq, a4, a3 + l32i a4, a2, 0 + movi a3, 0x41400000 + assert eq, a4, a3 +.data + .align 4 +1: +.float 0, 0, 0 +.text +test_end + +#endif + +test_suite_end diff --git a/tests/tcg/xtensa/test_mac16.S b/tests/tcg/xtensa/test_mac16.S index 512025d842..ee0cedd2ae 100644 --- a/tests/tcg/xtensa/test_mac16.S +++ b/tests/tcg/xtensa/test_mac16.S @@ -2,6 +2,8 @@ test_suite mac16 +#if XCHAL_HAVE_MAC16 + #define ext16(v) (((v) & 0xffff) | (((v) & 0x8000) * 0x1ffffffe)) #define mul16(a, b) ((ext16(a) * ext16(b))) @@ -240,4 +242,6 @@ test mula_dd_lddec .text test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_max.S b/tests/tcg/xtensa/test_max.S index 3caa207ea5..f349d578e3 100644 --- a/tests/tcg/xtensa/test_max.S +++ b/tests/tcg/xtensa/test_max.S @@ -2,6 +2,8 @@ test_suite max +#if XCHAL_HAVE_MINMAX + test max movi a2, 0xffffffff movi a3, 1 @@ -78,4 +80,6 @@ test maxu assert eq, a3, a4 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_min.S b/tests/tcg/xtensa/test_min.S index 551cf591e5..89ee10334f 100644 --- a/tests/tcg/xtensa/test_min.S +++ b/tests/tcg/xtensa/test_min.S @@ -2,6 +2,8 @@ test_suite min +#if XCHAL_HAVE_MINMAX + test min movi a2, 0xffffffff movi a3, 1 @@ -78,4 +80,6 @@ test minu assert eq, a3, a4 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_mmu.S b/tests/tcg/xtensa/test_mmu.S index a15316ffb3..4cbd6ef4f9 100644 --- a/tests/tcg/xtensa/test_mmu.S +++ b/tests/tcg/xtensa/test_mmu.S @@ -2,6 +2,8 @@ test_suite mmu +#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY + .purgem test_init .macro clean_tlb_way way, page_size, n_entries @@ -740,4 +742,6 @@ test cross_page_tb assert eq, a2, a3 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_mul16.S b/tests/tcg/xtensa/test_mul16.S index 98fa7042b5..32507f7f1e 100644 --- a/tests/tcg/xtensa/test_mul16.S +++ b/tests/tcg/xtensa/test_mul16.S @@ -2,6 +2,8 @@ test_suite mul16 +#if XCHAL_HAVE_MUL16 + test mul16u_pp movi a2, 0x137f5a5a mov a3, a2 @@ -80,4 +82,6 @@ test mul16s_nn assert eq, a3, a6 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_mul32.S b/tests/tcg/xtensa/test_mul32.S index b288ead9f6..862d45abce 100644 --- a/tests/tcg/xtensa/test_mul32.S +++ b/tests/tcg/xtensa/test_mul32.S @@ -2,6 +2,8 @@ test_suite mul32 +#if XCHAL_HAVE_MUL32 + test mull movi a2, 0x137f5a5a mov a3, a2 @@ -15,6 +17,8 @@ test mull assert eq, a3, a6 test_end +#endif + /* unfortunately dc232b doesn't have muluh/mulsh*/ test_suite_end diff --git a/tests/tcg/xtensa/test_nsa.S b/tests/tcg/xtensa/test_nsa.S index 479b2e2429..0af7d1f50d 100644 --- a/tests/tcg/xtensa/test_nsa.S +++ b/tests/tcg/xtensa/test_nsa.S @@ -2,6 +2,8 @@ test_suite nsa +#if XCHAL_HAVE_NSA + test nsa movi a2, 0 movi a3, 31 @@ -56,4 +58,6 @@ test nsau assert eq, a3, a2 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_phys_mem.S b/tests/tcg/xtensa/test_phys_mem.S index aae0a793a7..9bb3ee3866 100644 --- a/tests/tcg/xtensa/test_phys_mem.S +++ b/tests/tcg/xtensa/test_phys_mem.S @@ -2,6 +2,8 @@ test_suite phys_mem +#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY + .purgem test_init .macro test_init @@ -67,6 +69,8 @@ test write_get_pte_no_phys assert eq, a2, a3 test_end +#endif + test inst_fetch_no_phys set_vector kernel, 2f diff --git a/tests/tcg/xtensa/test_quo.S b/tests/tcg/xtensa/test_quo.S index 5b3ae383d0..32886b913b 100644 --- a/tests/tcg/xtensa/test_quo.S +++ b/tests/tcg/xtensa/test_quo.S @@ -2,6 +2,8 @@ test_suite quo +#if XCHAL_HAVE_DIV32 + test quou_pp movi a2, 0x5a5a137f mov a3, a2 @@ -144,4 +146,6 @@ test quos_exc assert eq, a2, a3 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_rem.S b/tests/tcg/xtensa/test_rem.S index 6357e520d9..0b96bb3390 100644 --- a/tests/tcg/xtensa/test_rem.S +++ b/tests/tcg/xtensa/test_rem.S @@ -2,6 +2,8 @@ test_suite rem +#if XCHAL_HAVE_DIV32 + test remu_pp movi a2, 0x5a5a137f mov a3, a2 @@ -144,4 +146,6 @@ test rems_exc assert eq, a2, a3 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_rst0.S b/tests/tcg/xtensa/test_rst0.S index a73366b120..143e90b401 100644 --- a/tests/tcg/xtensa/test_rst0.S +++ b/tests/tcg/xtensa/test_rst0.S @@ -54,6 +54,8 @@ test add assert eq, a4, a6 test_end +#if XCHAL_HAVE_ADDX + test addx2 movi a2, 0x137fa5a5 mov a3, a2 @@ -93,6 +95,8 @@ test addx8 assert eq, a4, a6 test_end +#endif + test sub movi a2, 0x137fa5a5 mov a3, a2 @@ -106,6 +110,8 @@ test sub assert eq, a4, a6 test_end +#if XCHAL_HAVE_ADDX + test subx2 movi a2, 0x137fa5a5 mov a3, a2 @@ -145,4 +151,6 @@ test subx8 assert eq, a4, a6 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_s32c1i.S b/tests/tcg/xtensa/test_s32c1i.S index 93b575db95..2885d9d003 100644 --- a/tests/tcg/xtensa/test_s32c1i.S +++ b/tests/tcg/xtensa/test_s32c1i.S @@ -2,7 +2,13 @@ test_suite s32c1i +#if XCHAL_HAVE_S32C1I + test s32c1i_nowrite +#if XCHAL_HW_VERSION >= 230000 + movi a2, 0x29 + wsr a2, atomctl +#endif movi a2, 1f movi a3, 1 wsr a3, scompare1 @@ -20,6 +26,10 @@ test s32c1i_nowrite test_end test s32c1i_write +#if XCHAL_HW_VERSION >= 230000 + movi a2, 0x29 + wsr a2, atomctl +#endif movi a2, 1f movi a3, 3 wsr a3, scompare1 @@ -36,4 +46,6 @@ test s32c1i_write .text test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_sext.S b/tests/tcg/xtensa/test_sext.S index 087a6333a4..483d2176e4 100644 --- a/tests/tcg/xtensa/test_sext.S +++ b/tests/tcg/xtensa/test_sext.S @@ -2,6 +2,8 @@ test_suite sext +#if XCHAL_HAVE_SEXT + test sext movi a2, 0xffffff5a movi a3, 0x0000005a @@ -66,4 +68,6 @@ test sext_same_rs assert eq, a3, a2 test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_sr.S b/tests/tcg/xtensa/test_sr.S index 052f1e04a7..b1a91a0637 100644 --- a/tests/tcg/xtensa/test_sr.S +++ b/tests/tcg/xtensa/test_sr.S @@ -2,11 +2,23 @@ test_suite sr +#if XCHAL_HAVE_BE +#define LOW__SR 0x04 +#define HI_RSR 0x30 +#define HI_WSR 0x31 +#define HI_XSR 0x16 +#else +#define LOW__SR 0x40 +#define HI_RSR 0x03 +#define HI_WSR 0x13 +#define HI_XSR 0x61 +#endif + .macro sr_op sym, op_sym, op_byte, sr .if \sym \op_sym a4, \sr .else - .byte 0x40, \sr, \op_byte + .byte LOW__SR, \sr, \op_byte .endif .endm @@ -32,9 +44,9 @@ test_suite sr .macro test_sr_mask sr, sym, mask test \sr - test_sr_op \sym, \mask & 1, rsr, 0x03, \sr - test_sr_op \sym, \mask & 2, wsr, 0x13, \sr - test_sr_op \sym, \mask & 4, xsr, 0x61, \sr + test_sr_op \sym, \mask & 1, rsr, HI_RSR, \sr + test_sr_op \sym, \mask & 2, wsr, HI_WSR, \sr + test_sr_op \sym, \mask & 4, xsr, HI_XSR, \sr test_end .endm @@ -42,50 +54,183 @@ test_end test_sr_mask \sr, \conf, 7 .endm +#if XCHAL_HAVE_MAC16 test_sr acchi, 1 test_sr acclo, 1 +#else +test_sr_mask /*acchi*/17, 0, 0 +test_sr_mask /*acclo*/16, 0, 0 +#endif + +#if XCHAL_HAVE_S32C1I && XCHAL_HW_VERSION >= 230000 +test_sr atomctl, 1 +#else test_sr_mask /*atomctl*/99, 0, 0 +#endif + +#if XCHAL_HAVE_BOOLEANS +test_sr br, 1 +#else test_sr_mask /*br*/4, 0, 0 +#endif + test_sr_mask /*cacheattr*/98, 0, 0 + +#if XCHAL_HAVE_CCOUNT test_sr ccompare0, 1 test_sr ccount, 1 +#else +test_sr_mask /*ccompare0*/240, 0, 0 +test_sr_mask /*ccount*/234, 0, 0 +#endif + +#if XCHAL_HAVE_CP test_sr cpenable, 1 +#else +test_sr_mask /*cpenable*/224, 0, 0 +#endif + +#if XCHAL_HAVE_DEBUG +#if XCHAL_NUM_DBREAK test_sr dbreaka0, 1 test_sr dbreakc0, 1 +#endif test_sr_mask debugcause, 1, 1 +#else +test_sr_mask /*dbreaka0*/144, 0, 0 +test_sr_mask /*dbreakc0*/160, 0, 0 +test_sr_mask /*debugcause*/233, 0, 0 +#endif + test_sr depc, 1 + +#if XCHAL_HAVE_PTP_MMU test_sr dtlbcfg, 1 +#else +test_sr_mask /*dtlbcfg*/92, 0, 0 +#endif + test_sr epc1, 1 + +#if XCHAL_NUM_INTLEVELS > 1 test_sr epc2, 1 test_sr eps2, 1 +#else +test_sr_mask /*epc2*/178, 0, 0 +test_sr_mask /*eps2*/194, 0, 0 +#endif + test_sr exccause, 1 test_sr excsave1, 1 + +#if XCHAL_NUM_INTLEVELS > 1 test_sr excsave2, 1 +#else +test_sr_mask /*excsave2*/210, 0, 0 +#endif + test_sr excvaddr, 1 + +#if XCHAL_HAVE_DEBUG +#if XCHAL_NUM_IBREAK test_sr ibreaka0, 1 test_sr ibreakenable, 1 +#endif test_sr icount, 1 test_sr icountlevel, 1 +#else +test_sr_mask /*ibreaka0*/128, 0, 0 +test_sr_mask /*ibreakenable*/96, 0, 0 +test_sr_mask /*icount*/236, 0, 0 +test_sr_mask /*icountlevel*/237, 0, 0 +#endif + test_sr_mask /*intclear*/227, 0, 2 test_sr_mask /*interrupt*/226, 0, 3 test_sr intenable, 1 + +#if XCHAL_HAVE_PTP_MMU test_sr itlbcfg, 1 +#else +test_sr_mask /*itlbcfg*/91, 0, 0 +#endif + +#if XCHAL_HAVE_LOOPS test_sr lbeg, 1 test_sr lcount, 1 test_sr lend, 1 +#else +test_sr_mask /*lbeg*/0, 0, 0 +test_sr_mask /*lcount*/2, 0, 0 +test_sr_mask /*lend*/1, 0, 0 +#endif + +#if XCHAL_HAVE_ABSOLUTE_LITERALS test_sr litbase, 1 +#else +test_sr_mask /*litbase*/5, 0, 0 +#endif + +#if XCHAL_HAVE_MAC16 test_sr m0, 1 +#else +test_sr_mask /*m0*/32, 0, 0 +#endif + +#if XCHAL_HW_VERSION >= 250000 +test_sr_mask /*memctl*/97, 0, 7 +#else test_sr_mask /*memctl*/97, 0, 0 +#endif + +#if XCHAL_NUM_MISC_REGS test_sr misc0, 1 +#else +test_sr_mask /*misc0*/244, 0, 0 +#endif + +#if XCHAL_HAVE_PREFETCH +test_sr prefctl, 1 +#else test_sr_mask /*prefctl*/40, 0, 0 +#endif + +#if XCHAL_HAVE_PRID test_sr_mask /*prid*/235, 0, 1 +#else +test_sr_mask /*prid*/235, 0, 0 +#endif + test_sr ps, 1 + +#if XCHAL_HAVE_PTP_MMU test_sr ptevaddr, 1 test_sr rasid, 1 +#else +test_sr_mask /*ptevaddr*/83, 0, 0 +test_sr_mask /*rasid*/90, 0, 0 +#endif + test_sr sar, 1 + +#if XCHAL_HAVE_S32C1I test_sr scompare1, 1 +#else +test_sr_mask /*scompare1*/12, 0, 0 +#endif + +#if XCHAL_HAVE_VECBASE test_sr vecbase, 1 +#else +test_sr_mask /*vecbase*/231, 0, 0 +#endif + +#if XCHAL_HAVE_WINDOWED test_sr windowbase, 1 test_sr windowstart, 1 +#else +test_sr_mask /*windowbase*/72, 0, 0 +test_sr_mask /*windowstart*/73, 0, 0 +#endif test_suite_end diff --git a/tests/tcg/xtensa/test_timer.S b/tests/tcg/xtensa/test_timer.S index 6cda71adbb..1ec8e20883 100644 --- a/tests/tcg/xtensa/test_timer.S +++ b/tests/tcg/xtensa/test_timer.S @@ -2,6 +2,8 @@ #define CCOUNT_SHIFT 4 #define WAIT_LOOPS 20 +#define level1 kernel +#define INTERRUPT_LEVEL(n) glue3(XCHAL_INT, n, _LEVEL) .macro make_ccount_delta target, delta rsr \delta, ccount @@ -13,6 +15,8 @@ test_suite timer +#if XCHAL_HAVE_CCOUNT + test ccount rsr a3, ccount rsr a4, ccount @@ -32,14 +36,20 @@ test ccount_write assert ltu, a3, a4 test_end +#if XCHAL_NUM_TIMERS + test ccount_update_deadline movi a2, 0 wsr a2, intenable rsr a2, interrupt wsr a2, intclear movi a2, 0 +#if XCHAL_NUM_TIMERS > 1 wsr a2, ccompare1 +#endif +#if XCHAL_NUM_TIMERS > 2 wsr a2, ccompare2 +#endif movi a2, 0x12345678 wsr a2, ccompare0 rsr a3, interrupt @@ -59,8 +69,12 @@ test ccompare rsr a2, interrupt wsr a2, intclear movi a2, 0 +#if XCHAL_NUM_TIMERS > 1 wsr a2, ccompare1 +#endif +#if XCHAL_NUM_TIMERS > 2 wsr a2, ccompare2 +#endif make_ccount_delta a2, a15 wsr a2, ccompare0 @@ -76,6 +90,7 @@ test ccompare assert nei, a5, 0 test_end +#if INTERRUPT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1 test ccompare0_interrupt set_vector kernel, 2f movi a2, 0 @@ -83,8 +98,12 @@ test ccompare0_interrupt rsr a2, interrupt wsr a2, intclear movi a2, 0 +#if XCHAL_NUM_TIMERS > 1 wsr a2, ccompare1 +#endif +#if XCHAL_NUM_TIMERS > 2 wsr a2, ccompare2 +#endif movi a3, WAIT_LOOPS make_ccount_delta a2, a15 @@ -104,16 +123,21 @@ test ccompare0_interrupt rsr a2, exccause assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ test_end +#endif + +#if XCHAL_NUM_TIMERS > 1 test ccompare1_interrupt - set_vector level3, 2f + set_vector glue(level, INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT)), 2f movi a2, 0 wsr a2, intenable rsr a2, interrupt wsr a2, intclear movi a2, 0 wsr a2, ccompare0 +#if XCHAL_NUM_TIMERS > 2 wsr a2, ccompare2 +#endif movi a3, WAIT_LOOPS make_ccount_delta a2, a15 @@ -123,7 +147,7 @@ test ccompare1_interrupt assert eqi, a2, 0 movi a2, 1 << XCHAL_TIMER1_INTERRUPT wsr a2, intenable - rsil a2, 2 + rsil a2, INTERRUPT_LEVEL(XCHAL_TIMER1_INTERRUPT) - 1 loop a3, 1f nop 1: @@ -131,8 +155,11 @@ test ccompare1_interrupt 2: test_end +#endif +#if XCHAL_NUM_TIMERS > 2 + test ccompare2_interrupt - set_vector level5, 2f + set_vector glue(level, INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT)), 2f movi a2, 0 wsr a2, intenable rsr a2, interrupt @@ -149,7 +176,7 @@ test ccompare2_interrupt assert eqi, a2, 0 movi a2, 1 << XCHAL_TIMER2_INTERRUPT wsr a2, intenable - rsil a2, 4 + rsil a2, INTERRUPT_LEVEL(XCHAL_TIMER2_INTERRUPT) - 1 loop a3, 1f nop 1: @@ -157,6 +184,8 @@ test ccompare2_interrupt 2: test_end +#endif + test ccompare_interrupt_masked set_vector kernel, 2f movi a2, 0 @@ -164,11 +193,15 @@ test ccompare_interrupt_masked rsr a2, interrupt wsr a2, intclear movi a2, 0 +#if XCHAL_NUM_TIMERS > 2 wsr a2, ccompare2 +#endif movi a3, 2 * WAIT_LOOPS make_ccount_delta a2, a15 +#if XCHAL_NUM_TIMERS > 1 wsr a2, ccompare1 +#endif add a2, a2, a15 wsr a2, ccompare0 rsync @@ -194,11 +227,15 @@ test ccompare_interrupt_masked_waiti rsr a2, interrupt wsr a2, intclear movi a2, 0 +#if XCHAL_NUM_TIMERS > 2 wsr a2, ccompare2 +#endif movi a3, 2 * WAIT_LOOPS make_ccount_delta a2, a15 +#if XCHAL_NUM_TIMERS > 1 wsr a2, ccompare1 +#endif add a2, a2, a15 wsr a2, ccompare0 rsync @@ -214,4 +251,7 @@ test ccompare_interrupt_masked_waiti assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ test_end +#endif +#endif + test_suite_end diff --git a/tests/tcg/xtensa/test_windowed.S b/tests/tcg/xtensa/test_windowed.S index d851e8f43c..5ead90a790 100644 --- a/tests/tcg/xtensa/test_windowed.S +++ b/tests/tcg/xtensa/test_windowed.S @@ -2,10 +2,12 @@ test_suite windowed +#if XCHAL_HAVE_WINDOWED + .altmacro .macro reset_window start - movi a2, 0xff + movi a2, 0xffff wsr a2, windowstart rsync movi a2, 0 @@ -105,7 +107,8 @@ test_end movi a3, 0x4001f assert eq, a2, a3 rsr a2, windowbase - assert eqi, a2, 8 - ((\window) / 4) + movi a3, (XCHAL_NUM_AREGS - (\window)) / 4 + assert eq, a2, a3 rsr a2, windowstart assert eqi, a2, 1 rfwu @@ -116,8 +119,8 @@ test_end rsr a2, windowbase assert eqi, a2, 0 rsr a2, windowstart - assert bsi, a2, 0 - assert bsi, a2, 8 - ((\window) / 4) + assert bsi.l, a2, 0 + assert bsi.l, a2, (XCHAL_NUM_AREGS - (\window)) / 4 .endm test underflow @@ -132,7 +135,7 @@ test_end .macro retw_test window - reset_window %(1 | (1 << (8 - (\window) / 4))) + reset_window %(1 | (1 << ((XCHAL_NUM_AREGS - \window) / 4))) reset_ps ssai 2 @@ -147,10 +150,11 @@ test_end movi a3, 0x4000f assert eq, a2, a3 rsr a2, windowbase - assert eqi, a2, 8 - ((\window) / 4) + movi a3, (XCHAL_NUM_AREGS - (\window)) / 4 + assert eq, a2, a3 rsr a2, windowstart - assert bci, a2, 0 - assert bsi, a2, 8 - ((\window) / 4) + assert bci.l, a2, 0 + assert bsi.l, a2, (XCHAL_NUM_AREGS - (\window)) / 4 .endm test retw @@ -180,7 +184,7 @@ test movsp set_vector kernel, 0 - reset_window 0x81 + reset_window %(0x1 | (1 << ((XCHAL_NUM_AREGS / 4) - 1))) reset_ps movsp a2, a3 @@ -211,8 +215,16 @@ test rotw movi a3, 0x16 movi a7, 0x17 +#if XCHAL_NUM_AREGS == 32 movi a2, 0x44 wsr a2, windowstart +#elif XCHAL_NUM_AREGS == 64 + movi a2, 0x4004 + wsr a2, windowstart + rotw -8 +#else +#error XCHAL_NUM_AREGS unsupported +#endif rsync movi a2, 0x10 @@ -350,4 +362,6 @@ test entry_overflow all_entry_overflow_tests test_end +#endif + test_suite_end diff --git a/tests/tcg/xtensa/vectors.S b/tests/tcg/xtensa/vectors.S index 6a9cb3cde4..cd48cfb656 100644 --- a/tests/tcg/xtensa/vectors.S +++ b/tests/tcg/xtensa/vectors.S @@ -2,10 +2,20 @@ .macro vector name -.section .vector.\name +.section .vector.\name, "ax" +.global vector_\name +vector_\name\(): j 1f -.section .vector.\name\().text + .literal_position 1: + wsr a0, excsave1 + movi a0, 1f + ret.n + +.section .vector.\name\().text, "ax" + .literal_position +1: + rsr a0, excsave1 wsr a2, excsave1 movi a2, handler_\name l32i a2, a2, 0 diff --git a/tests/test-authz-list.c b/tests/test-authz-list.c new file mode 100644 index 0000000000..24347a6ac3 --- /dev/null +++ b/tests/test-authz-list.c @@ -0,0 +1,159 @@ +/* + * QEMU list file authorization object tests + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" + +#include "authz/list.h" + +static void test_authz_default_deny(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_default_allow(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_ALLOW, + &error_abort); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_explicit_deny(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_ALLOW, + &error_abort); + + qauthz_list_append_rule(auth, "fred", QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_explicit_allow(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); + + qauthz_list_append_rule(auth, "fred", QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + + +static void test_authz_complex(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); + + qauthz_list_append_rule(auth, "fred", QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + qauthz_list_append_rule(auth, "bob", QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + qauthz_list_append_rule(auth, "dan", QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + qauthz_list_append_rule(auth, "dan*", QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_GLOB, &error_abort); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "bob", &error_abort)); + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "danb", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_add_remove(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_ALLOW, + &error_abort); + + g_assert_cmpint(qauthz_list_append_rule(auth, "fred", + QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, + &error_abort), + ==, 0); + g_assert_cmpint(qauthz_list_append_rule(auth, "bob", + QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, + &error_abort), + ==, 1); + g_assert_cmpint(qauthz_list_append_rule(auth, "dan", + QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, + &error_abort), + ==, 2); + g_assert_cmpint(qauthz_list_append_rule(auth, "frank", + QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, + &error_abort), + ==, 3); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + + g_assert_cmpint(qauthz_list_delete_rule(auth, "dan"), + ==, 2); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + + g_assert_cmpint(qauthz_list_insert_rule(auth, "dan", + QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, + 2, + &error_abort), + ==, 2); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + + g_test_add_func("/auth/list/default/deny", test_authz_default_deny); + g_test_add_func("/auth/list/default/allow", test_authz_default_allow); + g_test_add_func("/auth/list/explicit/deny", test_authz_explicit_deny); + g_test_add_func("/auth/list/explicit/allow", test_authz_explicit_allow); + g_test_add_func("/auth/list/complex", test_authz_complex); + g_test_add_func("/auth/list/add-remove", test_authz_add_remove); + + return g_test_run(); +} diff --git a/tests/test-authz-listfile.c b/tests/test-authz-listfile.c new file mode 100644 index 0000000000..1e452fef6d --- /dev/null +++ b/tests/test-authz-listfile.c @@ -0,0 +1,195 @@ +/* + * QEMU list authorization object tests + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "authz/listfile.h" + +static char *workdir; + +static gchar *qemu_authz_listfile_test_save(const gchar *name, + const gchar *cfg) +{ + gchar *path = g_strdup_printf("%s/default-deny.cfg", workdir); + GError *gerr = NULL; + + if (!g_file_set_contents(path, cfg, -1, &gerr)) { + g_printerr("Unable to save config %s: %s\n", + path, gerr->message); + g_error_free(gerr); + g_free(path); + rmdir(workdir); + abort(); + } + + return path; +} + +static void test_authz_default_deny(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "default-deny.cfg", + "{ \"policy\": \"deny\" }"); + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_default_allow(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "default-allow.cfg", + "{ \"policy\": \"allow\" }"); + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_explicit_deny(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "explicit-deny.cfg", + "{ \"rules\": [ " + " { \"match\": \"fred\"," + " \"policy\": \"deny\"," + " \"format\": \"exact\" } ]," + " \"policy\": \"allow\" }"); + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_explicit_allow(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "explicit-allow.cfg", + "{ \"rules\": [ " + " { \"match\": \"fred\"," + " \"policy\": \"allow\"," + " \"format\": \"exact\" } ]," + " \"policy\": \"deny\" }"); + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + + +static void test_authz_complex(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "complex.cfg", + "{ \"rules\": [ " + " { \"match\": \"fred\"," + " \"policy\": \"allow\"," + " \"format\": \"exact\" }," + " { \"match\": \"bob\"," + " \"policy\": \"allow\"," + " \"format\": \"exact\" }," + " { \"match\": \"dan\"," + " \"policy\": \"deny\"," + " \"format\": \"exact\" }," + " { \"match\": \"dan*\"," + " \"policy\": \"allow\"," + " \"format\": \"glob\" } ]," + " \"policy\": \"deny\" }"); + + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "bob", &error_abort)); + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "danb", &error_abort)); + + object_unparent(OBJECT(auth)); +} + + +int main(int argc, char **argv) +{ + int ret; + GError *gerr = NULL; + + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + + workdir = g_dir_make_tmp("qemu-test-authz-listfile-XXXXXX", + &gerr); + if (!workdir) { + g_printerr("Unable to create temporary dir: %s\n", + gerr->message); + g_error_free(gerr); + abort(); + } + + g_test_add_func("/auth/list/default/deny", test_authz_default_deny); + g_test_add_func("/auth/list/default/allow", test_authz_default_allow); + g_test_add_func("/auth/list/explicit/deny", test_authz_explicit_deny); + g_test_add_func("/auth/list/explicit/allow", test_authz_explicit_allow); + g_test_add_func("/auth/list/complex", test_authz_complex); + + ret = g_test_run(); + + rmdir(workdir); + g_free(workdir); + + return ret; +} diff --git a/tests/test-authz-pam.c b/tests/test-authz-pam.c new file mode 100644 index 0000000000..93d5ac8bbf --- /dev/null +++ b/tests/test-authz-pam.c @@ -0,0 +1,124 @@ +/* + * QEMU PAM authorization object tests + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "authz/pamacct.h" + +#include <security/pam_appl.h> + +static bool failauth; + +/* + * These two functions are exported by libpam.so. + * + * By defining them again here, our impls are resolved + * by the linker instead of those in libpam.so + * + * The test suite is thus isolated from the host system + * PAM setup, so we can do predictable test scenarios + */ +int +pam_start(const char *service_name, const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh) +{ + failauth = true; + if (!g_str_equal(service_name, "qemu-vnc")) { + return PAM_AUTH_ERR; + } + + if (g_str_equal(user, "fred")) { + failauth = false; + } + + return PAM_SUCCESS; +} + + +int +pam_acct_mgmt(pam_handle_t *pamh, int flags) +{ + if (failauth) { + return PAM_AUTH_ERR; + } + + return PAM_SUCCESS; +} + + +static void test_authz_unknown_service(void) +{ + Error *local_err = NULL; + QAuthZPAM *auth = qauthz_pam_new("auth0", + "qemu-does-not-exist", + &error_abort); + + g_assert_nonnull(auth); + + g_assert_false(qauthz_is_allowed(QAUTHZ(auth), "fred", &local_err)); + + error_free_or_abort(&local_err); + object_unparent(OBJECT(auth)); +} + + +static void test_authz_good_user(void) +{ + QAuthZPAM *auth = qauthz_pam_new("auth0", + "qemu-vnc", + &error_abort); + + g_assert_nonnull(auth); + + g_assert_true(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + + +static void test_authz_bad_user(void) +{ + Error *local_err = NULL; + QAuthZPAM *auth = qauthz_pam_new("auth0", + "qemu-vnc", + &error_abort); + + g_assert_nonnull(auth); + + g_assert_false(qauthz_is_allowed(QAUTHZ(auth), "bob", &local_err)); + + error_free_or_abort(&local_err); + object_unparent(OBJECT(auth)); +} + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + + g_test_add_func("/auth/pam/unknown-service", test_authz_unknown_service); + g_test_add_func("/auth/pam/good-user", test_authz_good_user); + g_test_add_func("/auth/pam/bad-user", test_authz_bad_user); + + return g_test_run(); +} diff --git a/tests/test-authz-simple.c b/tests/test-authz-simple.c new file mode 100644 index 0000000000..2cf14fb87e --- /dev/null +++ b/tests/test-authz-simple.c @@ -0,0 +1,50 @@ +/* + * QEMU simple authorization object testing + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "authz/simple.h" + + +static void test_authz_simple(void) +{ + QAuthZSimple *authz = qauthz_simple_new("authz0", + "cthulu", + &error_abort); + + g_assert(!qauthz_is_allowed(QAUTHZ(authz), "cthul", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(authz), "cthulu", &error_abort)); + g_assert(!qauthz_is_allowed(QAUTHZ(authz), "cthuluu", &error_abort)); + g_assert(!qauthz_is_allowed(QAUTHZ(authz), "fred", &error_abort)); + + object_unparent(OBJECT(authz)); +} + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + module_call_init(MODULE_INIT_QOM); + + g_test_add_func("/authz/simple", test_authz_simple); + + return g_test_run(); +} diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index ee1740ff06..eda90750eb 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -204,12 +204,7 @@ static void test_drv_cb_common(enum drain_type drain_type, bool recursive) BlockAIOCB *acb; int aio_ret; - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = NULL, - .iov_len = 0, - }; - qemu_iovec_init_external(&qiov, &iov, 1); + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0); blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, @@ -670,12 +665,7 @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread) AioContext *ctx_a = iothread_get_aio_context(a); AioContext *ctx_b = iothread_get_aio_context(b); - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = NULL, - .iov_len = 0, - }; - qemu_iovec_init_external(&qiov, &iov, 1); + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0); /* bdrv_drain_all() may only be called from the main loop thread */ if (drain_type == BDRV_DRAIN_ALL && drain_thread != 0) { @@ -1148,13 +1138,7 @@ static void coroutine_fn test_co_delete_by_drain(void *opaque) BlockDriverState *bs = blk_bs(blk); BDRVTestTopState *tts = bs->opaque; void *buffer = g_malloc(65536); - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = buffer, - .iov_len = 65536, - }; - - qemu_iovec_init_external(&qiov, &iov, 1); + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buffer, 65536); /* Pretend some internal write operation from parent to child. * Important: We have to read from the child, not from the parent! @@ -1365,12 +1349,7 @@ static void test_detach_indirect(bool by_parent_cb) BdrvChild *child_a, *child_b; BlockAIOCB *acb; - QEMUIOVector qiov; - struct iovec iov = { - .iov_base = NULL, - .iov_len = 0, - }; - qemu_iovec_init_external(&qiov, &iov, 1); + QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0); if (!by_parent_cb) { detach_by_driver_cb_role = child_file; @@ -1522,6 +1501,36 @@ static void test_append_to_drained(void) blk_unref(blk); } +static void test_set_aio_context(void) +{ + BlockDriverState *bs; + IOThread *a = iothread_new(); + IOThread *b = iothread_new(); + AioContext *ctx_a = iothread_get_aio_context(a); + AioContext *ctx_b = iothread_get_aio_context(b); + + bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, + &error_abort); + + bdrv_drained_begin(bs); + bdrv_set_aio_context(bs, ctx_a); + + aio_context_acquire(ctx_a); + bdrv_drained_end(bs); + + bdrv_drained_begin(bs); + bdrv_set_aio_context(bs, ctx_b); + aio_context_release(ctx_a); + aio_context_acquire(ctx_b); + bdrv_set_aio_context(bs, qemu_get_aio_context()); + aio_context_release(ctx_b); + bdrv_drained_end(bs); + + bdrv_unref(bs); + iothread_join(a); + iothread_join(b); +} + int main(int argc, char **argv) { int ret; @@ -1603,6 +1612,8 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/attach/drain", test_append_to_drained); + g_test_add_func("/bdrv-drain/set_aio_context", test_set_aio_context); + ret = g_test_run(); qemu_event_destroy(&done_event); return ret; diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c new file mode 100644 index 0000000000..458dfa6661 --- /dev/null +++ b/tests/test-bdrv-graph-mod.c @@ -0,0 +1,198 @@ +/* + * Block node graph modifications tests + * + * Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "block/block_int.h" +#include "sysemu/block-backend.h" + +static BlockDriver bdrv_pass_through = { + .format_name = "pass-through", + .bdrv_child_perm = bdrv_filter_default_perms, +}; + +static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, + const BdrvChildRole *role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) +{ + *nperm = 0; + *nshared = BLK_PERM_ALL; +} + +static BlockDriver bdrv_no_perm = { + .format_name = "no-perm", + .bdrv_child_perm = no_perm_default_perms, +}; + +static BlockDriverState *no_perm_node(const char *name) +{ + return bdrv_new_open_driver(&bdrv_no_perm, name, BDRV_O_RDWR, &error_abort); +} + +static BlockDriverState *pass_through_node(const char *name) +{ + return bdrv_new_open_driver(&bdrv_pass_through, name, + BDRV_O_RDWR, &error_abort); +} + +/* + * test_update_perm_tree + * + * When checking node for a possibility to update permissions, it's subtree + * should be correctly checked too. New permissions for each node should be + * calculated and checked in context of permissions of other nodes. If we + * check new permissions of the node only in context of old permissions of + * its neighbors, we can finish up with wrong permission graph. + * + * This test firstly create the following graph: + * +--------+ + * | root | + * +--------+ + * | + * | perm: write, read + * | shared: except write + * v + * +-------------------+ +----------------+ + * | passtrough filter |---------->| null-co node | + * +-------------------+ +----------------+ + * + * + * and then, tries to append filter under node. Expected behavior: fail. + * Otherwise we'll get the following picture, with two BdrvChild'ren, having + * write permission to one node, without actually sharing it. + * + * +--------+ + * | root | + * +--------+ + * | + * | perm: write, read + * | shared: except write + * v + * +-------------------+ + * | passtrough filter | + * +-------------------+ + * | | + * perm: write, read | | perm: write, read + * shared: except write | | shared: except write + * v v + * +----------------+ + * | null co node | + * +----------------+ + */ +static void test_update_perm_tree(void) +{ + Error *local_err = NULL; + + BlockBackend *root = blk_new(BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ, + BLK_PERM_ALL & ~BLK_PERM_WRITE); + BlockDriverState *bs = no_perm_node("node"); + BlockDriverState *filter = pass_through_node("filter"); + + blk_insert_bs(root, bs, &error_abort); + + bdrv_attach_child(filter, bs, "child", &child_file, &error_abort); + + bdrv_append(filter, bs, &local_err); + + g_assert_nonnull(local_err); + + bdrv_unref(bs); + blk_unref(root); +} + +/* + * test_should_update_child + * + * Test that bdrv_replace_node, and concretely should_update_child + * do the right thing, i.e. not creating loops on the graph. + * + * The test does the following: + * 1. initial graph: + * + * +------+ +--------+ + * | root | | filter | + * +------+ +--------+ + * | | + * root| target| + * v v + * +------+ +--------+ + * | node |<---------| target | + * +------+ backing +--------+ + * + * 2. Append @filter above @node. If should_update_child works correctly, + * it understands, that backing child of @target should not be updated, + * as it will create a loop on node graph. Resulting picture should + * be the left one, not the right: + * + * +------+ +------+ + * | root | | root | + * +------+ +------+ + * | | + * root| root| + * v v + * +--------+ target +--------+ target + * | filter |--------------+ | filter |--------------+ + * +--------+ | +--------+ | + * | | | ^ v + * backing| | backing| | +--------+ + * v v | +-----------| target | + * +------+ +--------+ v backing +--------+ + * | node |<---------| target | +------+ + * +------+ backing +--------+ | node | + * +------+ + * + * (good picture) (bad picture) + * + */ +static void test_should_update_child(void) +{ + BlockBackend *root = blk_new(0, BLK_PERM_ALL); + BlockDriverState *bs = no_perm_node("node"); + BlockDriverState *filter = no_perm_node("filter"); + BlockDriverState *target = no_perm_node("target"); + + blk_insert_bs(root, bs, &error_abort); + + bdrv_set_backing_hd(target, bs, &error_abort); + + g_assert(target->backing->bs == bs); + bdrv_attach_child(filter, target, "target", &child_file, &error_abort); + bdrv_append(filter, bs, &error_abort); + g_assert(target->backing->bs == bs); + + bdrv_unref(bs); + blk_unref(root); +} + +int main(int argc, char *argv[]) +{ + bdrv_init(); + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/bdrv-graph-mod/update-perm-tree", test_update_perm_tree); + g_test_add_func("/bdrv-graph-mod/should-update-child", + test_should_update_child); + + return g_test_run(); +} diff --git a/tests/test-crypto-tlssession.c b/tests/test-crypto-tlssession.c index 6fa9950afb..15212ec276 100644 --- a/tests/test-crypto-tlssession.c +++ b/tests/test-crypto-tlssession.c @@ -28,7 +28,7 @@ #include "qom/object_interfaces.h" #include "qapi/error.h" #include "qemu/sockets.h" -#include "qemu/acl.h" +#include "authz/list.h" #ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT @@ -229,7 +229,7 @@ static void test_crypto_tls_session_x509(const void *opaque) QCryptoTLSCreds *serverCreds; QCryptoTLSSession *clientSess = NULL; QCryptoTLSSession *serverSess = NULL; - qemu_acl *acl; + QAuthZList *auth; const char * const *wildcards; int channel[2]; bool clientShake = false; @@ -285,11 +285,15 @@ static void test_crypto_tls_session_x509(const void *opaque) SERVER_CERT_DIR); g_assert(serverCreds != NULL); - acl = qemu_acl_init("tlssessionacl"); - qemu_acl_reset(acl); + auth = qauthz_list_new("tlssessionacl", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); wildcards = data->wildcards; while (wildcards && *wildcards) { - qemu_acl_append(acl, 0, *wildcards); + qauthz_list_append_rule(auth, *wildcards, + QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_GLOB, + &error_abort); wildcards++; } @@ -377,6 +381,7 @@ static void test_crypto_tls_session_x509(const void *opaque) object_unparent(OBJECT(serverCreds)); object_unparent(OBJECT(clientCreds)); + object_unparent(OBJECT(auth)); qcrypto_tls_session_free(serverSess); qcrypto_tls_session_free(clientSess); diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c index 4900c6d433..43b707eba7 100644 --- a/tests/test-io-channel-tls.c +++ b/tests/test-io-channel-tls.c @@ -29,8 +29,8 @@ #include "io-channel-helpers.h" #include "crypto/init.h" #include "crypto/tlscredsx509.h" -#include "qemu/acl.h" #include "qapi/error.h" +#include "authz/list.h" #include "qom/object_interfaces.h" #ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT @@ -113,7 +113,7 @@ static void test_io_channel_tls(const void *opaque) QIOChannelTLS *serverChanTLS; QIOChannelSocket *clientChanSock; QIOChannelSocket *serverChanSock; - qemu_acl *acl; + QAuthZList *auth; const char * const *wildcards; int channel[2]; struct QIOChannelTLSHandshakeData clientHandshake = { false, false }; @@ -161,11 +161,15 @@ static void test_io_channel_tls(const void *opaque) SERVER_CERT_DIR); g_assert(serverCreds != NULL); - acl = qemu_acl_init("channeltlsacl"); - qemu_acl_reset(acl); + auth = qauthz_list_new("channeltlsacl", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); wildcards = data->wildcards; while (wildcards && *wildcards) { - qemu_acl_append(acl, 0, *wildcards); + qauthz_list_append_rule(auth, *wildcards, + QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_GLOB, + &error_abort); wildcards++; } @@ -253,6 +257,8 @@ static void test_io_channel_tls(const void *opaque) object_unref(OBJECT(serverChanSock)); object_unref(OBJECT(clientChanSock)); + object_unparent(OBJECT(auth)); + close(channel[0]); close(channel[1]); } diff --git a/tests/test-util-filemonitor.c b/tests/test-util-filemonitor.c new file mode 100644 index 0000000000..5d95cea5ee --- /dev/null +++ b/tests/test-util-filemonitor.c @@ -0,0 +1,685 @@ +/* + * Tests for util/filemonitor-*.c + * + * Copyright 2018 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qapi/error.h" +#include "qemu/filemonitor.h" + +#include <utime.h> + +enum { + QFILE_MONITOR_TEST_OP_CREATE, + QFILE_MONITOR_TEST_OP_APPEND, + QFILE_MONITOR_TEST_OP_TRUNC, + QFILE_MONITOR_TEST_OP_RENAME, + QFILE_MONITOR_TEST_OP_TOUCH, + QFILE_MONITOR_TEST_OP_UNLINK, +}; + +typedef struct { + int type; + const char *filesrc; + const char *filedst; +} QFileMonitorTestOp; + +typedef struct { + const char *file; +} QFileMonitorTestWatch; + +typedef struct { + gsize nwatches; + const QFileMonitorTestWatch *watches; + + gsize nops; + const QFileMonitorTestOp *ops; +} QFileMonitorTestPlan; + +typedef struct { + int id; + QFileMonitorEvent event; + char *filename; +} QFileMonitorTestRecord; + + +typedef struct { + QemuMutex lock; + GList *records; +} QFileMonitorTestData; + +static QemuMutex evlock; +static bool evstopping; +static bool evrunning; + +/* + * Main function for a background thread that is + * running the event loop during the test + */ +static void * +qemu_file_monitor_test_event_loop(void *opaque G_GNUC_UNUSED) +{ + qemu_mutex_lock(&evlock); + + while (!evstopping) { + qemu_mutex_unlock(&evlock); + main_loop_wait(true); + qemu_mutex_lock(&evlock); + } + + evrunning = false; + qemu_mutex_unlock(&evlock); + return NULL; +} + + +/* + * File monitor event handler which simply maintains + * an ordered list of all events that it receives + */ +static void +qemu_file_monitor_test_handler(int id, + QFileMonitorEvent event, + const char *filename, + void *opaque) +{ + QFileMonitorTestData *data = opaque; + QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1); + + rec->id = id; + rec->event = event; + rec->filename = g_strdup(filename); + + qemu_mutex_lock(&data->lock); + data->records = g_list_append(data->records, rec); + qemu_mutex_unlock(&data->lock); +} + + +static void +qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec) +{ + g_free(rec->filename); + g_free(rec); +} + + +/* + * Get the next event record that has been received by + * the file monitor event handler. Since events are + * emitted in the background thread running the event + * loop, we can't assume there is a record available + * immediately. Thus we will sleep for upto 5 seconds + * to wait for the event to be queued for us. + */ +static QFileMonitorTestRecord * +qemu_file_monitor_test_next_record(QFileMonitorTestData *data) +{ + GTimer *timer = g_timer_new(); + QFileMonitorTestRecord *record = NULL; + GList *tmp; + + qemu_mutex_lock(&data->lock); + while (!data->records && g_timer_elapsed(timer, NULL) < 5) { + qemu_mutex_unlock(&data->lock); + usleep(10 * 1000); + qemu_mutex_lock(&data->lock); + } + if (data->records) { + record = data->records->data; + tmp = data->records; + data->records = g_list_remove_link(data->records, tmp); + g_list_free(tmp); + } + qemu_mutex_unlock(&data->lock); + + g_timer_destroy(timer); + return record; +} + + +/* + * Check whether the event record we retrieved matches + * data we were expecting to see for the event + */ +static bool +qemu_file_monitor_test_expect(QFileMonitorTestData *data, + int id, + QFileMonitorEvent event, + const char *filename) +{ + QFileMonitorTestRecord *rec; + bool ret = false; + + rec = qemu_file_monitor_test_next_record(data); + + if (!rec) { + g_printerr("Missing event watch id %d event %d file %s\n", + id, event, filename); + return false; + } + + if (id != rec->id) { + g_printerr("Expected watch id %d but got %d\n", id, rec->id); + goto cleanup; + } + + if (event != rec->event) { + g_printerr("Expected event %d but got %d\n", event, rec->event); + goto cleanup; + } + + if (!g_str_equal(filename, rec->filename)) { + g_printerr("Expected filename %s but got %s\n", + filename, rec->filename); + goto cleanup; + } + + ret = true; + + cleanup: + qemu_file_monitor_test_record_free(rec); + return ret; +} + + +static void +test_file_monitor_events(const void *opaque) +{ + const QFileMonitorTestPlan *plan = opaque; + Error *local_err = NULL; + GError *gerr = NULL; + QFileMonitor *mon = qemu_file_monitor_new(&local_err); + QemuThread th; + GTimer *timer; + gchar *dir = NULL; + int err = -1; + gsize i, j; + char *pathsrc = NULL; + char *pathdst = NULL; + QFileMonitorTestData data; + + qemu_mutex_init(&data.lock); + data.records = NULL; + + /* + * The file monitor needs the main loop running in + * order to receive events from inotify. We must + * thus spawn a background thread to run an event + * loop impl, while this thread triggers the + * actual file operations we're testing + */ + evrunning = 1; + evstopping = 0; + qemu_thread_create(&th, "event-loop", + qemu_file_monitor_test_event_loop, NULL, + QEMU_THREAD_JOINABLE); + + if (local_err) { + g_printerr("File monitoring not available: %s", + error_get_pretty(local_err)); + error_free(local_err); + return; + } + + dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX", + &gerr); + if (!dir) { + g_printerr("Unable to create tmp dir %s", + gerr->message); + g_error_free(gerr); + abort(); + } + + /* + * First register all the directory / file watches + * we're interested in seeing events against + */ + for (i = 0; i < plan->nwatches; i++) { + int watchid; + watchid = qemu_file_monitor_add_watch(mon, + dir, + plan->watches[i].file, + qemu_file_monitor_test_handler, + &data, + &local_err); + if (watchid < 0) { + g_printerr("Unable to add watch %s", + error_get_pretty(local_err)); + goto cleanup; + } + } + + + /* + * Now invoke all the file operations (create, + * delete, rename, chmod, etc). These operations + * will trigger the various file monitor events + */ + for (i = 0; i < plan->nops; i++) { + const QFileMonitorTestOp *op = &(plan->ops[i]); + int fd; + struct utimbuf ubuf; + + pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc); + if (op->filedst) { + pathdst = g_strdup_printf("%s/%s", dir, op->filedst); + } + + switch (op->type) { + case QFILE_MONITOR_TEST_OP_CREATE: + fd = open(pathsrc, O_WRONLY | O_CREAT, 0700); + if (fd < 0) { + g_printerr("Unable to create %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + close(fd); + break; + + case QFILE_MONITOR_TEST_OP_APPEND: + fd = open(pathsrc, O_WRONLY | O_APPEND, 0700); + if (fd < 0) { + g_printerr("Unable to open %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + + if (write(fd, "Hello World", 10) != 10) { + g_printerr("Unable to write %s: %s", + pathsrc, strerror(errno)); + close(fd); + goto cleanup; + } + close(fd); + break; + + case QFILE_MONITOR_TEST_OP_TRUNC: + if (truncate(pathsrc, 4) < 0) { + g_printerr("Unable to truncate %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_RENAME: + if (rename(pathsrc, pathdst) < 0) { + g_printerr("Unable to rename %s to %s: %s", + pathsrc, pathdst, strerror(errno)); + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_UNLINK: + if (unlink(pathsrc) < 0) { + g_printerr("Unable to unlink %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_TOUCH: + ubuf.actime = 1024; + ubuf.modtime = 1025; + if (utime(pathsrc, &ubuf) < 0) { + g_printerr("Unable to touch %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + break; + + default: + g_assert_not_reached(); + } + + g_free(pathsrc); + g_free(pathdst); + pathsrc = pathdst = NULL; + } + + + /* + * Finally validate that we have received all the events + * we expect to see for the combination of watches and + * file operations + */ + for (i = 0; i < plan->nops; i++) { + const QFileMonitorTestOp *op = &(plan->ops[i]); + + switch (op->type) { + case QFILE_MONITOR_TEST_OP_CREATE: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_CREATED, op->filesrc)) + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_APPEND: + case QFILE_MONITOR_TEST_OP_TRUNC: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_MODIFIED, op->filesrc)) + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_RENAME: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_DELETED, op->filesrc)) + goto cleanup; + } + + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filedst)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_CREATED, op->filedst)) + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_TOUCH: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_ATTRIBUTES, op->filesrc)) + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_UNLINK: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_DELETED, op->filesrc)) + goto cleanup; + } + break; + + default: + g_assert_not_reached(); + } + } + + err = 0; + + cleanup: + g_free(pathsrc); + g_free(pathdst); + + qemu_mutex_lock(&evlock); + evstopping = 1; + timer = g_timer_new(); + while (evrunning && g_timer_elapsed(timer, NULL) < 5) { + qemu_mutex_unlock(&evlock); + usleep(10 * 1000); + qemu_mutex_lock(&evlock); + } + qemu_mutex_unlock(&evlock); + + if (g_timer_elapsed(timer, NULL) >= 5) { + g_printerr("Event loop failed to quit after 5 seconds\n"); + } + g_timer_destroy(timer); + + for (i = 0; i < plan->nops; i++) { + const QFileMonitorTestOp *op = &(plan->ops[i]); + pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc); + unlink(pathsrc); + g_free(pathsrc); + if (op->filedst) { + pathdst = g_strdup_printf("%s/%s", dir, op->filedst); + unlink(pathdst); + g_free(pathdst); + } + } + + qemu_file_monitor_free(mon); + g_list_foreach(data.records, + (GFunc)qemu_file_monitor_test_record_free, NULL); + g_list_free(data.records); + qemu_mutex_destroy(&data.lock); + if (dir) { + rmdir(dir); + } + g_free(dir); + g_assert(err == 0); +} + + +/* + * Set of structs which define which file name patterns + * we're trying to watch against. NULL, means all files + * in the directory + */ +static const QFileMonitorTestWatch watches_any[] = { + { NULL }, +}; + +static const QFileMonitorTestWatch watches_one[] = { + { "one.txt" }, +}; + +static const QFileMonitorTestWatch watches_two[] = { + { "two.txt" }, +}; + +static const QFileMonitorTestWatch watches_many[] = { + { NULL }, + { "one.txt" }, + { "two.txt" }, +}; + + +/* + * Various sets of file operations we're going to + * trigger and validate events for + */ +static const QFileMonitorTestOp ops_create_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", } +}; + +static const QFileMonitorTestOp ops_delete_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_UNLINK, + .filesrc = "one.txt", } +}; + +static const QFileMonitorTestOp ops_create_many[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "two.txt", }, + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "three.txt", } +}; + +static const QFileMonitorTestOp ops_rename_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_RENAME, + .filesrc = "one.txt", .filedst = "two.txt" } +}; + +static const QFileMonitorTestOp ops_rename_many[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "two.txt", }, + { .type = QFILE_MONITOR_TEST_OP_RENAME, + .filesrc = "one.txt", .filedst = "two.txt" } +}; + +static const QFileMonitorTestOp ops_append_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_APPEND, + .filesrc = "one.txt", }, +}; + +static const QFileMonitorTestOp ops_trunc_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_TRUNC, + .filesrc = "one.txt", }, +}; + +static const QFileMonitorTestOp ops_touch_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_TOUCH, + .filesrc = "one.txt", }, +}; + + +/* + * No we define data sets for the combinatorial + * expansion of file watches and operation sets + */ +#define PLAN_DATA(o, w) \ + static const QFileMonitorTestPlan plan_ ## o ## _ ## w = { \ + .nops = G_N_ELEMENTS(ops_ ##o), \ + .ops = ops_ ##o, \ + .nwatches = G_N_ELEMENTS(watches_ ##w), \ + .watches = watches_ ## w, \ + } + +PLAN_DATA(create_one, any); +PLAN_DATA(create_one, one); +PLAN_DATA(create_one, two); +PLAN_DATA(create_one, many); + +PLAN_DATA(delete_one, any); +PLAN_DATA(delete_one, one); +PLAN_DATA(delete_one, two); +PLAN_DATA(delete_one, many); + +PLAN_DATA(create_many, any); +PLAN_DATA(create_many, one); +PLAN_DATA(create_many, two); +PLAN_DATA(create_many, many); + +PLAN_DATA(rename_one, any); +PLAN_DATA(rename_one, one); +PLAN_DATA(rename_one, two); +PLAN_DATA(rename_one, many); + +PLAN_DATA(rename_many, any); +PLAN_DATA(rename_many, one); +PLAN_DATA(rename_many, two); +PLAN_DATA(rename_many, many); + +PLAN_DATA(append_one, any); +PLAN_DATA(append_one, one); +PLAN_DATA(append_one, two); +PLAN_DATA(append_one, many); + +PLAN_DATA(trunc_one, any); +PLAN_DATA(trunc_one, one); +PLAN_DATA(trunc_one, two); +PLAN_DATA(trunc_one, many); + +PLAN_DATA(touch_one, any); +PLAN_DATA(touch_one, one); +PLAN_DATA(touch_one, two); +PLAN_DATA(touch_one, many); + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qemu_init_main_loop(&error_abort); + + qemu_mutex_init(&evlock); + + /* + * Register test cases for the combinatorial + * expansion of file watches and operation sets + */ + #define PLAN_REGISTER(o, w) \ + g_test_add_data_func("/util/filemonitor/" # o "/" # w, \ + &plan_ ## o ## _ ## w, test_file_monitor_events) + + PLAN_REGISTER(create_one, any); + PLAN_REGISTER(create_one, one); + PLAN_REGISTER(create_one, two); + PLAN_REGISTER(create_one, many); + + PLAN_REGISTER(delete_one, any); + PLAN_REGISTER(delete_one, one); + PLAN_REGISTER(delete_one, two); + PLAN_REGISTER(delete_one, many); + + PLAN_REGISTER(create_many, any); + PLAN_REGISTER(create_many, one); + PLAN_REGISTER(create_many, two); + PLAN_REGISTER(create_many, many); + + PLAN_REGISTER(rename_one, any); + PLAN_REGISTER(rename_one, one); + PLAN_REGISTER(rename_one, two); + PLAN_REGISTER(rename_one, many); + + PLAN_REGISTER(rename_many, any); + PLAN_REGISTER(rename_many, one); + PLAN_REGISTER(rename_many, two); + PLAN_REGISTER(rename_many, many); + + PLAN_REGISTER(append_one, any); + PLAN_REGISTER(append_one, one); + PLAN_REGISTER(append_one, two); + PLAN_REGISTER(append_one, many); + + PLAN_REGISTER(trunc_one, any); + PLAN_REGISTER(trunc_one, one); + PLAN_REGISTER(trunc_one, two); + PLAN_REGISTER(trunc_one, many); + + PLAN_REGISTER(touch_one, any); + PLAN_REGISTER(touch_one, one); + PLAN_REGISTER(touch_one, two); + PLAN_REGISTER(touch_one, many); + + return g_test_run(); +} diff --git a/tests/uefi-test-tools/.gitignore b/tests/uefi-test-tools/.gitignore new file mode 100644 index 0000000000..9f246701de --- /dev/null +++ b/tests/uefi-test-tools/.gitignore @@ -0,0 +1,3 @@ +Build +Conf +log diff --git a/tests/uefi-test-tools/LICENSE b/tests/uefi-test-tools/LICENSE new file mode 100644 index 0000000000..38b78aecdb --- /dev/null +++ b/tests/uefi-test-tools/LICENSE @@ -0,0 +1,25 @@ +All the files in this directory and subdirectories are released under the +2-Clause BSD License (see header in each file). + +Copyright (C) 2019, Red Hat, Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/uefi-test-tools/Makefile b/tests/uefi-test-tools/Makefile new file mode 100644 index 0000000000..1d78bc14d5 --- /dev/null +++ b/tests/uefi-test-tools/Makefile @@ -0,0 +1,106 @@ +# Makefile for the test helper UEFI applications that run in guests. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +edk2_dir := ../../roms/edk2 +images_dir := ../data/uefi-boot-images +emulation_targets := arm aarch64 i386 x86_64 +uefi_binaries := bios-tables-test +intermediate_suffixes := .efi .fat .iso.raw + +images: $(foreach binary,$(uefi_binaries), \ + $(foreach target,$(emulation_targets), \ + $(images_dir)/$(binary).$(target).iso.qcow2)) + +# Preserve all intermediate targets if the build succeeds. +# - Intermediate targets help with development & debugging. +# - Preserving intermediate targets also keeps spurious changes out of the +# final build products, in case the user re-runs "make" without any changes +# to the UEFI source code. Normally, the intermediate files would have been +# removed by the last "make" invocation, hence the re-run would rebuild them +# from the unchanged UEFI sources. Unfortunately, the "mkdosfs" and +# "genisoimage" utilities embed timestamp-based information in their outputs, +# which causes git to report differences for the tracked qcow2 ISO images. +.SECONDARY: $(foreach binary,$(uefi_binaries), \ + $(foreach target,$(emulation_targets), \ + $(foreach suffix,$(intermediate_suffixes), \ + Build/$(binary).$(target)$(suffix)))) + +# In the pattern rules below, the stem (%, $*) stands for +# "$(binary).$(target)". + +# Convert the raw ISO image to a qcow2 one, enabling compression, and using a +# small cluster size. This allows for small binary files under git control, +# hence for small binary patches. +$(images_dir)/%.iso.qcow2: Build/%.iso.raw + mkdir -p -- $(images_dir) + $${QTEST_QEMU_IMG:-qemu-img} convert -f raw -O qcow2 -c \ + -o cluster_size=512 -- $< $@ + +# Embed the "UEFI system partition" into an ISO9660 file system as an ElTorito +# boot image. +Build/%.iso.raw: Build/%.fat + genisoimage -input-charset ASCII -efi-boot $(notdir $<) -no-emul-boot \ + -quiet -o $@ -- $< + +# Define chained macros in order to map QEMU system emulation targets to +# *short* UEFI architecture identifiers. Periods are allowed in, and ultimately +# stripped from, the argument. +map_arm_to_uefi = $(subst arm,ARM,$(1)) +map_aarch64_to_uefi = $(subst aarch64,AA64,$(call map_arm_to_uefi,$(1))) +map_i386_to_uefi = $(subst i386,IA32,$(call map_aarch64_to_uefi,$(1))) +map_x86_64_to_uefi = $(subst x86_64,X64,$(call map_i386_to_uefi,$(1))) +map_to_uefi = $(subst .,,$(call map_x86_64_to_uefi,$(1))) + +# Format a "UEFI system partition", using the UEFI binary as the default boot +# loader. Add 10% size for filesystem metadata, round up to the next KB, and +# make sure the size is large enough for a FAT filesystem. Name the filesystem +# after the UEFI binary. (Excess characters are automatically dropped from the +# filesystem label.) +Build/%.fat: Build/%.efi + rm -f -- $@ + uefi_bin_b=$$(stat --format=%s -- $<) && \ + uefi_fat_kb=$$(( (uefi_bin_b * 11 / 10 + 1023) / 1024 )) && \ + uefi_fat_kb=$$(( uefi_fat_kb >= 64 ? uefi_fat_kb : 64 )) && \ + mkdosfs -C $@ -n $(basename $(@F)) -- $$uefi_fat_kb + MTOOLS_SKIP_CHECK=1 mmd -i $@ ::EFI + MTOOLS_SKIP_CHECK=1 mmd -i $@ ::EFI/BOOT + MTOOLS_SKIP_CHECK=1 mcopy -i $@ -- $< \ + ::EFI/BOOT/BOOT$(call map_to_uefi,$(suffix $*)).EFI + +# In the pattern rules below, the stem (%, $*) stands for "$(target)" only. The +# association between the UEFI binary (such as "bios-tables-test") and the +# component name from the edk2 platform DSC file (such as "BiosTablesTest") is +# explicit in each rule. + +# "build.sh" invokes the "build" utility of edk2 BaseTools. In any given edk2 +# workspace, at most one "build" instance may be operating at a time. Therefore +# we must serialize the rebuilding of targets in this Makefile. +.NOTPARALLEL: + +# In turn, the "build" utility of edk2 BaseTools invokes another "make". +# Although the outer "make" process advertizes its job server to all child +# processes via MAKEFLAGS in the environment, the outer "make" closes the job +# server file descriptors (exposed in MAKEFLAGS) before executing a recipe -- +# unless the recipe is recognized as a recursive "make" recipe. Recipes that +# call $(MAKE) are classified automatically as recursive; for "build.sh" below, +# we must mark the recipe manually as recursive, by using the "+" indicator. +# This way, when the inner "make" starts a parallel build of the target edk2 +# module, it can communicate with the outer "make"'s job server. +Build/bios-tables-test.%.efi: build-edk2-tools + +./build.sh $(edk2_dir) BiosTablesTest $* $@ + +build-edk2-tools: + $(MAKE) -C $(edk2_dir)/BaseTools + +clean: + rm -rf Build Conf log + $(MAKE) -C $(edk2_dir)/BaseTools clean diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.c b/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.c new file mode 100644 index 0000000000..b208e17fb0 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.c @@ -0,0 +1,130 @@ +/** @file + Populate the BIOS_TABLES_TEST structure. + + Copyright (C) 2019, Red Hat, Inc. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + <http://opensource.org/licenses/bsd-license.php>. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include <Guid/Acpi.h> +#include <Guid/BiosTablesTest.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +/** + Wait for a keypress with a message that the application is about to exit. +**/ +STATIC +VOID +WaitForExitKeyPress ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Idx; + EFI_INPUT_KEY Key; + + if (gST->ConIn == NULL) { + return; + } + AsciiPrint ("%a: press any key to exit\n", gEfiCallerBaseName); + Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Idx); + if (EFI_ERROR (Status)) { + return; + } + gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); +} + +EFI_STATUS +EFIAPI +BiosTablesTestMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *Pages; + volatile BIOS_TABLES_TEST *BiosTablesTest; + CONST VOID *Rsdp10; + CONST VOID *Rsdp20; + CONST EFI_CONFIGURATION_TABLE *ConfigTable; + CONST EFI_CONFIGURATION_TABLE *ConfigTablesEnd; + volatile EFI_GUID *InverseSignature; + UINTN Idx; + + Pages = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof *BiosTablesTest), + SIZE_1MB); + if (Pages == NULL) { + AsciiErrorPrint ("%a: AllocateAlignedPages() failed\n", + gEfiCallerBaseName); + // + // Assuming the application was launched by the boot manager as a boot + // loader, exiting with error will cause the boot manager to proceed with + // the remaining boot options. If there are no other boot options, the boot + // manager menu will be pulled up. Give the user a chance to read the error + // message. + // + WaitForExitKeyPress (); + return EFI_OUT_OF_RESOURCES; + } + + // + // Locate both gEfiAcpi10TableGuid and gEfiAcpi20TableGuid config tables in + // one go. + // + Rsdp10 = NULL; + Rsdp20 = NULL; + ConfigTable = gST->ConfigurationTable; + ConfigTablesEnd = gST->ConfigurationTable + gST->NumberOfTableEntries; + while ((Rsdp10 == NULL || Rsdp20 == NULL) && ConfigTable < ConfigTablesEnd) { + if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi10TableGuid)) { + Rsdp10 = ConfigTable->VendorTable; + } else if (CompareGuid (&ConfigTable->VendorGuid, &gEfiAcpi20TableGuid)) { + Rsdp20 = ConfigTable->VendorTable; + } + ++ConfigTable; + } + + AsciiPrint ("%a: BiosTablesTest=%p Rsdp10=%p Rsdp20=%p\n", + gEfiCallerBaseName, Pages, Rsdp10, Rsdp20); + + // + // Store the RSD PTR address(es) first, then the signature second. + // + BiosTablesTest = Pages; + BiosTablesTest->Rsdp10 = (UINTN)Rsdp10; + BiosTablesTest->Rsdp20 = (UINTN)Rsdp20; + + MemoryFence(); + + InverseSignature = &BiosTablesTest->InverseSignatureGuid; + InverseSignature->Data1 = gBiosTablesTestGuid.Data1; + InverseSignature->Data1 ^= MAX_UINT32; + InverseSignature->Data2 = gBiosTablesTestGuid.Data2; + InverseSignature->Data2 ^= MAX_UINT16; + InverseSignature->Data3 = gBiosTablesTestGuid.Data3; + InverseSignature->Data3 ^= MAX_UINT16; + for (Idx = 0; Idx < sizeof InverseSignature->Data4; ++Idx) { + InverseSignature->Data4[Idx] = gBiosTablesTestGuid.Data4[Idx]; + InverseSignature->Data4[Idx] ^= MAX_UINT8; + } + + // + // The wait below has dual purpose. First, it blocks the application without + // wasting VCPU cycles while the hypervisor is scanning guest RAM. Second, + // assuming the application was launched by the boot manager as a boot + // loader, exiting the app with success causes the boot manager to pull up + // the boot manager menu at once (regardless of other boot options); the wait + // gives the user a chance to read the info printed above. + // + WaitForExitKeyPress (); + return EFI_SUCCESS; +} diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf b/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf new file mode 100644 index 0000000000..924d8a80d0 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf @@ -0,0 +1,41 @@ +## @file +# Populate the BIOS_TABLES_TEST structure. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = BiosTablesTest + UEFI_SPECIFICATION_VERSION = 2.31 + FILE_GUID = 87f00433-3b7c-45c3-ae78-a56495bd4e62 + MODULE_TYPE = UEFI_APPLICATION + ENTRY_POINT = BiosTablesTestMain + +[Sources] + BiosTablesTest.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiLib + +[Guids] + gBiosTablesTestGuid + gEfiAcpi10TableGuid + gEfiAcpi20TableGuid + +[Packages] + MdePkg/MdePkg.dec + UefiTestToolsPkg/UefiTestToolsPkg.dec diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/Include/Guid/BiosTablesTest.h b/tests/uefi-test-tools/UefiTestToolsPkg/Include/Guid/BiosTablesTest.h new file mode 100644 index 0000000000..0b72c61254 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/Include/Guid/BiosTablesTest.h @@ -0,0 +1,67 @@ +/** @file + Expose the address(es) of the ACPI RSD PTR table(s) in a MB-aligned structure + to the hypervisor. + + The hypervisor locates the MB-aligned structure based on the signature GUID + that is at offset 0 in the structure. Once the RSD PTR address(es) are + retrieved, the hypervisor may perform various ACPI checks. + + This feature is a development aid, for supporting ACPI table unit tests in + hypervisors. Do not enable in production builds. + + Copyright (C) 2019, Red Hat, Inc. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + <http://opensource.org/licenses/bsd-license.php>. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#ifndef __BIOS_TABLES_TEST_H__ +#define __BIOS_TABLES_TEST_H__ + +#include <Uefi/UefiBaseType.h> + +#define BIOS_TABLES_TEST_GUID \ + { \ + 0x5478594e, \ + 0xdfcb, \ + 0x425f, \ + { 0x8e, 0x42, 0xc8, 0xaf, 0xf8, 0x8a, 0x88, 0x7a } \ + } + +extern EFI_GUID gBiosTablesTestGuid; + +// +// The following structure must be allocated in Boot Services Data type memory, +// aligned at a 1MB boundary. +// +#pragma pack (1) +typedef struct { + // + // The signature GUID is written to the MB-aligned structure from + // gBiosTablesTestGuid, but with all bits inverted. That's the actual GUID + // value that the hypervisor should look for at each MB boundary, looping + // over all guest RAM pages with that alignment, until a match is found. The + // bit-flipping occurs in order not to store the actual GUID in any UEFI + // executable, which might confuse guest memory analysis. Note that EFI_GUID + // has little endian representation. + // + EFI_GUID InverseSignatureGuid; + // + // The Rsdp10 and Rsdp20 fields may be read when the signature GUID matches. + // Rsdp10 is the guest-physical address of the ACPI 1.0 specification RSD PTR + // table, in 8-byte little endian representation. Rsdp20 is the same, for the + // ACPI 2.0 or later specification RSD PTR table. Each of these fields may be + // zero (independently of the other) if the UEFI System Table does not + // provide the corresponding UEFI Configuration Table. + // + EFI_PHYSICAL_ADDRESS Rsdp10; + EFI_PHYSICAL_ADDRESS Rsdp20; +} BIOS_TABLES_TEST; +#pragma pack () + +#endif // __BIOS_TABLES_TEST_H__ diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dec b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dec new file mode 100644 index 0000000000..ed3a2fe110 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dec @@ -0,0 +1,27 @@ +## @file +# edk2 package declaration for the test helper UEFI applications that run in +# guests. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + +[Defines] + DEC_SPECIFICATION = 1.27 + PACKAGE_NAME = UefiTestToolsPkg + PACKAGE_GUID = 7b3f1794-0c85-4b27-a536-44dbf0b0669c + PACKAGE_VERSION = 0.1 + +[Includes] + Include + +[Guids] + gBiosTablesTestGuid = {0x5478594e, 0xdfcb, 0x425f, {0x8e, 0x42, 0xc8, 0xaf, 0xf8, 0x8a, 0x88, 0x7a}} + diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc new file mode 100644 index 0000000000..c8511cd732 --- /dev/null +++ b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc @@ -0,0 +1,69 @@ +## @file +# edk2 platform description for the test helper UEFI applications that run in +# guests. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + +[Defines] + DSC_SPECIFICATION = 1.28 + PLATFORM_GUID = 6750ccc1-8365-49f0-8437-948e516a9f55 + PLATFORM_VERSION = 0.1 + PLATFORM_NAME = UefiTestTools + SKUID_IDENTIFIER = DEFAULT + SUPPORTED_ARCHITECTURES = ARM|AARCH64|IA32|X64 + BUILD_TARGETS = DEBUG + +[BuildOptions.IA32] + GCC:*_*_IA32_CC_FLAGS = -mno-mmx -mno-sse + +[BuildOptions.X64] + GCC:*_*_X64_CC_FLAGS = -mno-mmx -mno-sse + +[BuildOptions.ARM.EDKII.UEFI_APPLICATION] + GCC:*_*_ARM_DLINK_FLAGS = -z common-page-size=0x1000 + +[BuildOptions.AARCH64.EDKII.UEFI_APPLICATION] + GCC:*_*_AARCH64_DLINK_FLAGS = -z common-page-size=0x1000 + +[BuildOptions] + GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES + +[SkuIds] + 0|DEFAULT + +[LibraryClasses] + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + +[LibraryClasses.ARM, LibraryClasses.AARCH64] + BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + +[LibraryClasses.IA32, LibraryClasses.X64] + BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf + +[PcdsFixedAtBuild] + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8040004F + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F + +[Components] + UefiTestToolsPkg/BiosTablesTest/BiosTablesTest.inf diff --git a/tests/uefi-test-tools/build.sh b/tests/uefi-test-tools/build.sh new file mode 100755 index 0000000000..155cb75c4d --- /dev/null +++ b/tests/uefi-test-tools/build.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +# Build script that determines the edk2 toolchain to use, invokes the edk2 +# "build" utility, and copies the built UEFI binary to the requested location. +# +# Copyright (C) 2019, Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# <http://opensource.org/licenses/bsd-license.php>. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +set -e -u -C + +# Save the command line arguments. We need to reset $# to 0 before sourcing +# "edksetup.sh", as it will inherit $@. +program_name=$(basename -- "$0") +edk2_dir=$1 +dsc_component=$2 +emulation_target=$3 +uefi_binary=$4 +shift 4 + +# Set up the environment for edk2 building. +export PACKAGES_PATH=$(realpath -- "$edk2_dir") +export WORKSPACE=$PWD +mkdir -p Conf + +# Source "edksetup.sh" carefully. +set +e +u +C +source "$PACKAGES_PATH/edksetup.sh" +ret=$? +set -e -u -C +if [ $ret -ne 0 ]; then + exit $ret +fi + +# Map the QEMU system emulation target to the following types of architecture +# identifiers: +# - edk2, +# - gcc cross-compilation. +# Cover only those targets that are supported by the UEFI spec and edk2. +case "$emulation_target" in + (arm) + edk2_arch=ARM + gcc_arch=arm + ;; + (aarch64) + edk2_arch=AARCH64 + gcc_arch=aarch64 + ;; + (i386) + edk2_arch=IA32 + gcc_arch=i686 + ;; + (x86_64) + edk2_arch=X64 + gcc_arch=x86_64 + ;; + (*) + printf '%s: unknown/unsupported QEMU system emulation target "%s"\n' \ + "$program_name" "$emulation_target" >&2 + exit 1 + ;; +esac + +# Check if cross-compilation is needed. +host_arch=$(uname -m) +if [ "$gcc_arch" == "$host_arch" ] || + ( [ "$gcc_arch" == i686 ] && [ "$host_arch" == x86_64 ] ); then + cross_prefix= +else + cross_prefix=${gcc_arch}-linux-gnu- +fi + +# Expose cross_prefix (which is possibly empty) to the edk2 tools. While at it, +# determine the suitable edk2 toolchain as well. +# - For ARM and AARCH64, edk2 only offers the GCC5 toolchain tag, which covers +# the gcc-5+ releases. +# - For IA32 and X64, edk2 offers the GCC44 through GCC49 toolchain tags, in +# addition to GCC5. Unfortunately, the mapping between the toolchain tags and +# the actual gcc releases isn't entirely trivial. Run "git-blame" on +# "OvmfPkg/build.sh" in edk2 for more information. +# And, because the above is too simple, we have to assign cross_prefix to an +# edk2 build variable that is specific to both the toolchain tag and the target +# architecture. +case "$edk2_arch" in + (ARM) + edk2_toolchain=GCC5 + export GCC5_ARM_PREFIX=$cross_prefix + ;; + (AARCH64) + edk2_toolchain=GCC5 + export GCC5_AARCH64_PREFIX=$cross_prefix + ;; + (IA32|X64) + gcc_version=$("${cross_prefix}gcc" -v 2>&1 | tail -1 | awk '{print $3}') + case "$gcc_version" in + ([1-3].*|4.[0-3].*) + printf '%s: unsupported gcc version "%s"\n' \ + "$program_name" "$gcc_version" >&2 + exit 1 + ;; + (4.4.*) + edk2_toolchain=GCC44 + ;; + (4.5.*) + edk2_toolchain=GCC45 + ;; + (4.6.*) + edk2_toolchain=GCC46 + ;; + (4.7.*) + edk2_toolchain=GCC47 + ;; + (4.8.*) + edk2_toolchain=GCC48 + ;; + (4.9.*|6.[0-2].*) + edk2_toolchain=GCC49 + ;; + (*) + edk2_toolchain=GCC5 + ;; + esac + eval "export ${edk2_toolchain}_BIN=\$cross_prefix" + ;; +esac + +# Build the UEFI binary +mkdir -p log +build \ + --arch="$edk2_arch" \ + --buildtarget=DEBUG \ + --platform=UefiTestToolsPkg/UefiTestToolsPkg.dsc \ + --tagname="$edk2_toolchain" \ + --module="UefiTestToolsPkg/$dsc_component/$dsc_component.inf" \ + --log="log/$dsc_component.$edk2_arch.log" \ + --report-file="log/$dsc_component.$edk2_arch.report" +cp -a -- \ + "Build/UefiTestTools/DEBUG_${edk2_toolchain}/$edk2_arch/$dsc_component.efi" \ + "$uefi_binary" diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index d961bd09d1..4cd0a97f13 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -27,10 +27,13 @@ #include "libqos/malloc-pc.h" #include "hw/virtio/virtio-net.h" -#include <linux/vhost.h> -#include <linux/virtio_ids.h> -#include <linux/virtio_net.h> +#include "standard-headers/linux/vhost_types.h" +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_net.h" + +#ifdef CONFIG_LINUX #include <sys/vfs.h> +#endif #define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM," \ @@ -139,10 +142,15 @@ typedef struct TestServer { gchar *socket_path; gchar *mig_path; gchar *chr_name; + const gchar *mem_path; + gchar *tmpfs; CharBackend chr; int fds_num; int fds[VHOST_MEMORY_MAX_NREGIONS]; VhostUserMemory memory; + GMainContext *context; + GMainLoop *loop; + GThread *thread; GMutex data_mutex; GCond data_cond; int log_fd; @@ -157,9 +165,6 @@ static TestServer *test_server_new(const gchar *name); static void test_server_free(TestServer *server); static void test_server_listen(TestServer *server); -static const char *tmpfs; -static const char *root; - enum test_memfd { TEST_MEMFD_AUTO, TEST_MEMFD_YES, @@ -167,7 +172,7 @@ enum test_memfd { }; static char *get_qemu_cmd(TestServer *s, - int mem, enum test_memfd memfd, const char *mem_path, + int mem, enum test_memfd memfd, const char *chr_opts, const char *extra) { if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check(0)) { @@ -182,7 +187,7 @@ static char *get_qemu_cmd(TestServer *s, } else { return g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem, - mem_path, s->chr_name, s->socket_path, + s->mem_path, s->chr_name, s->socket_path, chr_opts, s->chr_name, extra); } } @@ -459,13 +464,20 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) g_mutex_unlock(&s->data_mutex); } -static const char *init_hugepagefs(const char *path) +static const char *init_hugepagefs(void) { +#ifdef CONFIG_LINUX + const char *path = getenv("QTEST_HUGETLBFS_PATH"); struct statfs fs; int ret; + if (!path) { + return NULL; + } + if (access(path, R_OK | W_OK | X_OK)) { g_test_message("access on path (%s): %s\n", path, strerror(errno)); + abort(); return NULL; } @@ -475,21 +487,42 @@ static const char *init_hugepagefs(const char *path) if (ret != 0) { g_test_message("statfs on path (%s): %s\n", path, strerror(errno)); + abort(); return NULL; } if (fs.f_type != HUGETLBFS_MAGIC) { g_test_message("Warning: path not on HugeTLBFS: %s\n", path); + abort(); return NULL; } return path; +#else + return NULL; +#endif } static TestServer *test_server_new(const gchar *name) { TestServer *server = g_new0(TestServer, 1); + char template[] = "/tmp/vhost-test-XXXXXX"; + const char *tmpfs; + + server->context = g_main_context_new(); + server->loop = g_main_loop_new(server->context, FALSE); + + /* run the main loop thread so the chardev may operate */ + server->thread = g_thread_new(NULL, thread_function, server->loop); + + tmpfs = mkdtemp(template); + if (!tmpfs) { + g_test_message("mkdtemp on path (%s): %s", template, strerror(errno)); + } + g_assert(tmpfs); + server->tmpfs = g_strdup(tmpfs); + server->mem_path = init_hugepagefs() ? : server->tmpfs; server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name); server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name); server->chr_name = g_strdup_printf("chr-%s", name); @@ -519,13 +552,13 @@ static void test_server_create_chr(TestServer *server, const gchar *opt) Chardev *chr; chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt); - chr = qemu_chr_new(server->chr_name, chr_path, NULL); + chr = qemu_chr_new(server->chr_name, chr_path, server->context); g_free(chr_path); g_assert_nonnull(chr); qemu_chr_fe_init(&server->chr, chr, &error_abort); qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read, - chr_event, NULL, server, NULL, true); + chr_event, NULL, server, server->context, true); } static void test_server_listen(TestServer *server) @@ -533,9 +566,28 @@ static void test_server_listen(TestServer *server) test_server_create_chr(server, ",server,nowait"); } -static gboolean _test_server_free(TestServer *server) +static void test_server_free(TestServer *server) { - int i; + int i, ret; + + /* finish the helper thread and dispatch pending sources */ + g_main_loop_quit(server->loop); + g_thread_join(server->thread); + while (g_main_context_pending(NULL)) { + g_main_context_iteration(NULL, TRUE); + } + + unlink(server->socket_path); + g_free(server->socket_path); + + unlink(server->mig_path); + g_free(server->mig_path); + + ret = rmdir(server->tmpfs); + if (ret != 0) { + g_test_message("unable to rmdir: path (%s): %s", + server->tmpfs, strerror(errno)); + } qemu_chr_fe_deinit(&server->chr, true); @@ -547,24 +599,13 @@ static gboolean _test_server_free(TestServer *server) close(server->log_fd); } - unlink(server->socket_path); - g_free(server->socket_path); - - unlink(server->mig_path); - g_free(server->mig_path); - g_free(server->chr_name); g_assert(server->bus); qpci_free_pc(server->bus); + g_main_loop_unref(server->loop); + g_main_context_unref(server->context); g_free(server); - - return FALSE; -} - -static void test_server_free(TestServer *server) -{ - g_idle_add((GSourceFunc)_test_server_free, server); } static void wait_for_log_fd(TestServer *s) @@ -665,7 +706,7 @@ static void test_read_guest_mem(const void *arg) "read-guest-memfd" : "read-guest-mem"); test_server_listen(server); - qemu_cmd = get_qemu_cmd(server, 512, memfd, root, "", ""); + qemu_cmd = get_qemu_cmd(server, 512, memfd, "", ""); s = qtest_start(qemu_cmd); g_free(qemu_cmd); @@ -700,7 +741,7 @@ static void test_migrate(void) test_server_listen(s); test_server_listen(dest); - cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, "", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, "", ""); from = qtest_start(cmd); g_free(cmd); @@ -713,7 +754,7 @@ static void test_migrate(void) g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8)); tmp = g_strdup_printf(" -incoming %s", uri); - cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, root, "", tmp); + cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, "", tmp); g_free(tmp); to = qtest_init(cmd); g_free(cmd); @@ -723,7 +764,7 @@ static void test_migrate(void) sizeof(TestMigrateSource)); ((TestMigrateSource *)source)->src = s; ((TestMigrateSource *)source)->dest = dest; - g_source_attach(source, NULL); + g_source_attach(source, s->context); /* slow down migration to have time to fiddle with log */ /* TODO: qtest could learn to break on some places */ @@ -820,10 +861,11 @@ connect_thread(gpointer data) static void test_reconnect_subprocess(void) { TestServer *s = test_server_new("reconnect"); + GSource *src; char *cmd; g_thread_new("connect", connect_thread, s); - cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -837,7 +879,10 @@ static void test_reconnect_subprocess(void) /* reconnect */ s->fds_num = 0; s->rings = 0; - g_idle_add(reconnect_cb, s); + src = g_idle_source_new(); + g_source_set_callback(src, reconnect_cb, s, NULL); + g_source_attach(src, s->context); + g_source_unref(src); g_assert(wait_for_fds(s)); wait_for_rings_started(s, 2); @@ -865,7 +910,7 @@ static void test_connect_fail_subprocess(void) s->test_fail = true; g_thread_new("connect", connect_thread, s); - cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -898,7 +943,7 @@ static void test_flags_mismatch_subprocess(void) s->test_flags = TEST_FLAGS_DISCONNECT; g_thread_new("connect", connect_thread, s); - cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -946,7 +991,7 @@ static void test_multiqueue(void) cmd = g_strdup_printf( QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", - 512, 512, root, s->chr_name, + 512, 512, s->mem_path, s->chr_name, s->socket_path, "", s->chr_name, s->queues, s->queues * 2 + 2); } @@ -966,35 +1011,11 @@ static void test_multiqueue(void) int main(int argc, char **argv) { - const char *hugefs; - int ret; - char template[] = "/tmp/vhost-test-XXXXXX"; - GMainLoop *loop; - GThread *thread; - g_test_init(&argc, &argv, NULL); module_call_init(MODULE_INIT_QOM); qemu_add_opts(&qemu_chardev_opts); - tmpfs = mkdtemp(template); - if (!tmpfs) { - g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno)); - } - g_assert(tmpfs); - - hugefs = getenv("QTEST_HUGETLBFS_PATH"); - if (hugefs) { - root = init_hugepagefs(hugefs); - g_assert(root); - } else { - root = tmpfs; - } - - loop = g_main_loop_new(NULL, FALSE); - /* run the main loop thread so the chardev may operate */ - thread = g_thread_new(NULL, thread_function, loop); - if (qemu_memfd_check(0)) { qtest_add_data_func("/vhost-user/read-guest-mem/memfd", GINT_TO_POINTER(TEST_MEMFD_YES), @@ -1018,24 +1039,5 @@ int main(int argc, char **argv) qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch); } - ret = g_test_run(); - - /* cleanup */ - - /* finish the helper thread and dispatch pending sources */ - g_main_loop_quit(loop); - g_thread_join(thread); - while (g_main_context_pending(NULL)) { - g_main_context_iteration (NULL, TRUE); - } - g_main_loop_unref(loop); - - ret = rmdir(tmpfs); - if (ret != 0) { - g_test_message("unable to rmdir: path (%s): %s\n", - tmpfs, strerror(errno)); - } - g_assert_cmpint(ret, ==, 0); - - return ret; + return g_test_run(); } diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 04c608764b..8d2fc9c710 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -46,6 +46,12 @@ typedef struct QVirtioBlkReq { uint8_t status; } QVirtioBlkReq; +#ifdef HOST_WORDS_BIGENDIAN +const bool host_is_big_endian = true; +#else +const bool host_is_big_endian; /* false */ +#endif + static char *drive_create(void) { int fd, ret; @@ -125,12 +131,6 @@ static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot) static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req) { -#ifdef HOST_WORDS_BIGENDIAN - const bool host_is_big_endian = true; -#else - const bool host_is_big_endian = false; -#endif - if (qvirtio_is_big_endian(d) != host_is_big_endian) { req->type = bswap32(req->type); req->ioprio = bswap32(req->ioprio); @@ -138,13 +138,37 @@ static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req) } } + +static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d, + struct virtio_blk_discard_write_zeroes *dwz_hdr) +{ + if (qvirtio_is_big_endian(d) != host_is_big_endian) { + dwz_hdr->sector = bswap64(dwz_hdr->sector); + dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors); + dwz_hdr->flags = bswap32(dwz_hdr->flags); + } +} + static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d, QVirtioBlkReq *req, uint64_t data_size) { uint64_t addr; uint8_t status = 0xFF; - g_assert_cmpuint(data_size % 512, ==, 0); + switch (req->type) { + case VIRTIO_BLK_T_IN: + case VIRTIO_BLK_T_OUT: + g_assert_cmpuint(data_size % 512, ==, 0); + break; + case VIRTIO_BLK_T_DISCARD: + case VIRTIO_BLK_T_WRITE_ZEROES: + g_assert_cmpuint(data_size % + sizeof(struct virtio_blk_discard_write_zeroes), ==, 0); + break; + default: + g_assert_cmpuint(data_size, ==, 0); + } + addr = guest_alloc(alloc, sizeof(*req) + data_size); virtio_blk_fix_request(d, req); @@ -231,6 +255,95 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, guest_free(alloc, req_addr); + if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) { + struct virtio_blk_discard_write_zeroes dwz_hdr; + void *expected; + + /* + * WRITE_ZEROES request on the same sector of previous test where + * we wrote "TEST". + */ + req.type = VIRTIO_BLK_T_WRITE_ZEROES; + req.data = (char *) &dwz_hdr; + dwz_hdr.sector = 0; + dwz_hdr.num_sectors = 1; + dwz_hdr.flags = 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head = qvirtqueue_add(vq, req_addr, 16, false, true); + qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true); + qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false); + + qvirtqueue_kick(dev, vq, free_head); + + qvirtio_wait_used_elem(dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status = readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, ==, 0); + + guest_free(alloc, req_addr); + + /* Read request to check if the sector contains all zeroes */ + req.type = VIRTIO_BLK_T_IN; + req.ioprio = 1; + req.sector = 0; + req.data = g_malloc0(512); + + req_addr = virtio_blk_request(alloc, dev, &req, 512); + + g_free(req.data); + + free_head = qvirtqueue_add(vq, req_addr, 16, false, true); + qvirtqueue_add(vq, req_addr + 16, 512, true, true); + qvirtqueue_add(vq, req_addr + 528, 1, true, false); + + qvirtqueue_kick(dev, vq, free_head); + + qvirtio_wait_used_elem(dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status = readb(req_addr + 528); + g_assert_cmpint(status, ==, 0); + + data = g_malloc(512); + expected = g_malloc0(512); + memread(req_addr + 16, data, 512); + g_assert_cmpmem(data, 512, expected, 512); + g_free(expected); + g_free(data); + + guest_free(alloc, req_addr); + } + + if (features & (1u << VIRTIO_BLK_F_DISCARD)) { + struct virtio_blk_discard_write_zeroes dwz_hdr; + + req.type = VIRTIO_BLK_T_DISCARD; + req.data = (char *) &dwz_hdr; + dwz_hdr.sector = 0; + dwz_hdr.num_sectors = 1; + dwz_hdr.flags = 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head = qvirtqueue_add(vq, req_addr, 16, false, true); + qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true); + qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false); + + qvirtqueue_kick(dev, vq, free_head); + + qvirtio_wait_used_elem(dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status = readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, ==, 0); + + guest_free(alloc, req_addr); + } + if (features & (1u << VIRTIO_F_ANY_LAYOUT)) { /* Write and read with 2 descriptor layout */ /* Write request */ diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 7f8b3da791..fe1a7aed97 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -49,6 +49,11 @@ curses.mo-objs := curses.o curses.mo-cflags := $(CURSES_CFLAGS) curses.mo-libs := $(CURSES_LIBS) +common-obj-$(call land,$(CONFIG_SPICE),$(CONFIG_GIO)) += spice-app.mo +spice-app.mo-objs := spice-app.o +spice-app.mo-cflags := $(GIO_CFLAGS) +spice-app.mo-libs := $(GIO_LIBS) + common-obj-$(CONFIG_OPENGL) += shader.o common-obj-$(CONFIG_OPENGL) += console-gl.o common-obj-$(CONFIG_OPENGL) += egl-helpers.o @@ -6,29 +6,25 @@ * Authors: * Anthony Liguori <aliguori@us.ibm.com> * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * Portions from gtk-vnc: + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Portions from gtk-vnc (originally licensed under the LGPL v2+): * * GTK VNC Widget * * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define GETTEXT_PACKAGE "qemu" diff --git a/ui/kbd-state.c b/ui/kbd-state.c index ac14add70e..f3ab2d7a66 100644 --- a/ui/kbd-state.c +++ b/ui/kbd-state.c @@ -42,14 +42,18 @@ void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down) { bool state = test_bit(qcode, kbd->keys); - if (state == down) { + if (down == false /* got key-up event */ && + state == false /* key is not pressed */) { /* - * Filter out events which don't change the keyboard state. + * Filter out suspicious key-up events. * - * Most notably this allows to simply send along all key-up - * events, and this function will filter out everything where - * the corresponding key-down event wasn't send to the guest, - * for example due to being a host hotkey. + * This allows simply sending along all key-up events, and + * this function will filter out everything where the + * corresponding key-down event wasn't sent to the guest, for + * example due to being a host hotkey. + * + * Note that key-down events on already pressed keys are *not* + * suspicious, those are keyboard autorepeat events. */ return; } diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c index 664364a5e5..fb345f45fb 100644 --- a/ui/sdl2-input.c +++ b/ui/sdl2-input.c @@ -54,8 +54,5 @@ void sdl2_process_key(struct sdl2_console *scon, break; } } - } else { - qemu_input_event_send_key_qcode(con, qcode, - ev->type == SDL_KEYDOWN); } } diff --git a/ui/spice-app.c b/ui/spice-app.c new file mode 100644 index 0000000000..925b27b708 --- /dev/null +++ b/ui/spice-app.c @@ -0,0 +1,202 @@ +/* + * QEMU external Spice client display driver + * + * Copyright (c) 2018 Marc-André Lureau <marcandre.lureau@redhat.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" + +#include <gio/gio.h> + +#include "qemu-common.h" +#include "ui/console.h" +#include "qemu/config-file.h" +#include "qemu/option.h" +#include "qemu/cutils.h" +#include "qapi/error.h" +#include "io/channel-command.h" +#include "chardev/spice.h" +#include "sysemu/sysemu.h" + +static const char *tmp_dir; +static char *app_dir; +static char *sock_path; + +typedef struct VCChardev { + SpiceChardev parent; +} VCChardev; + +#define TYPE_CHARDEV_VC "chardev-vc" +#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC) + +static ChardevBackend * +chr_spice_backend_new(void) +{ + ChardevBackend *be = g_new0(ChardevBackend, 1); + + be->type = CHARDEV_BACKEND_KIND_SPICEPORT; + be->u.spiceport.data = g_new0(ChardevSpicePort, 1); + + return be; +} + +static void vc_chr_open(Chardev *chr, + ChardevBackend *backend, + bool *be_opened, + Error **errp) +{ + ChardevBackend *be; + const char *fqdn = NULL; + + if (strstart(chr->label, "serial", NULL)) { + fqdn = "org.qemu.console.serial.0"; + } else if (strstart(chr->label, "parallel", NULL)) { + fqdn = "org.qemu.console.parallel.0"; + } else if (strstart(chr->label, "compat_monitor", NULL)) { + fqdn = "org.qemu.monitor.hmp.0"; + } + + be = chr_spice_backend_new(); + be->u.spiceport.data->fqdn = fqdn ? + g_strdup(fqdn) : g_strdup_printf("org.qemu.console.%s", chr->label); + qemu_chr_open_spice_port(chr, be, be_opened, errp); + qapi_free_ChardevBackend(be); +} + +static void vc_chr_set_echo(Chardev *chr, bool echo) +{ + /* TODO: set echo for frontends QMP and qtest */ +} + +static void char_vc_class_init(ObjectClass *oc, void *data) +{ + ChardevClass *cc = CHARDEV_CLASS(oc); + + cc->parse = qemu_chr_parse_vc; + cc->open = vc_chr_open; + cc->chr_set_echo = vc_chr_set_echo; +} + +static const TypeInfo char_vc_type_info = { + .name = TYPE_CHARDEV_VC, + .parent = TYPE_CHARDEV_SPICEPORT, + .instance_size = sizeof(VCChardev), + .class_init = char_vc_class_init, +}; + +static void spice_app_atexit(void) +{ + if (sock_path) { + unlink(sock_path); + } + if (tmp_dir) { + rmdir(tmp_dir); + } + g_free(sock_path); + g_free(app_dir); +} + +static void spice_app_display_early_init(DisplayOptions *opts) +{ + QemuOpts *qopts; + ChardevBackend *be = chr_spice_backend_new(); + GError *err = NULL; + + if (opts->has_full_screen) { + error_report("spice-app full-screen isn't supported yet."); + exit(1); + } + if (opts->has_window_close) { + error_report("spice-app window-close isn't supported yet."); + exit(1); + } + + atexit(spice_app_atexit); + + if (qemu_name) { + app_dir = g_build_filename(g_get_user_runtime_dir(), + "qemu", qemu_name, NULL); + if (g_mkdir_with_parents(app_dir, S_IRWXU) < -1) { + error_report("Failed to create directory %s: %s", + app_dir, strerror(errno)); + exit(1); + } + } else { + app_dir = g_dir_make_tmp(NULL, &err); + tmp_dir = app_dir; + if (err) { + error_report("Failed to create temporary directory: %s", + err->message); + exit(1); + } + } + + type_register(&char_vc_type_info); + + sock_path = g_strjoin("", app_dir, "/", "spice.sock", NULL); + qopts = qemu_opts_create(qemu_find_opts("spice"), NULL, 0, &error_abort); + qemu_opt_set(qopts, "disable-ticketing", "on", &error_abort); + qemu_opt_set(qopts, "unix", "on", &error_abort); + qemu_opt_set(qopts, "addr", sock_path, &error_abort); + qemu_opt_set(qopts, "image-compression", "off", &error_abort); + qemu_opt_set(qopts, "streaming-video", "off", &error_abort); + qemu_opt_set(qopts, "gl", opts->has_gl ? "on" : "off", &error_abort); + display_opengl = opts->has_gl; + + be->u.spiceport.data->fqdn = g_strdup("org.qemu.monitor.qmp.0"); + qemu_chardev_new("org.qemu.monitor.qmp", TYPE_CHARDEV_SPICEPORT, + be, NULL, &error_abort); + qopts = qemu_opts_create(qemu_find_opts("mon"), + NULL, 0, &error_fatal); + qemu_opt_set(qopts, "chardev", "org.qemu.monitor.qmp", &error_abort); + qemu_opt_set(qopts, "mode", "control", &error_abort); + + qapi_free_ChardevBackend(be); +} + +static void spice_app_display_init(DisplayState *ds, DisplayOptions *opts) +{ + GError *err = NULL; + gchar *uri; + + uri = g_strjoin("", "spice+unix://", app_dir, "/", "spice.sock", NULL); + info_report("Launching display with URI: %s", uri); + g_app_info_launch_default_for_uri(uri, NULL, &err); + if (err) { + error_report("Failed to launch %s URI: %s", uri, err->message); + error_report("You need a capable Spice client, " + "such as virt-viewer 8.0"); + exit(1); + } + g_free(uri); +} + +static QemuDisplay qemu_display_spice_app = { + .type = DISPLAY_TYPE_SPICE_APP, + .early_init = spice_app_display_early_init, + .init = spice_app_display_init, +}; + +static void register_spice_app(void) +{ + qemu_display_register(&qemu_display_spice_app); +} + +type_init(register_spice_app); diff --git a/ui/spice-core.c b/ui/spice-core.c index a40fb2c00d..0632c74e9f 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -34,6 +34,7 @@ #include "qemu/option.h" #include "migration/misc.h" #include "hw/hw.h" +#include "hw/pci/pci_bus.h" #include "ui/spice-display.h" /* core bits */ @@ -397,6 +398,7 @@ static SpiceChannelList *qmp_query_spice_channels(void) static QemuOptsList qemu_spice_opts = { .name = "spice", .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), + .merge_lists = true, .desc = { { .name = "port", @@ -626,7 +628,7 @@ static void vm_change_state_handler(void *opaque, int running, { if (running) { qemu_spice_display_start(); - } else { + } else if (state != RUN_STATE_PAUSED) { qemu_spice_display_stop(); } } @@ -783,7 +785,7 @@ void qemu_spice_init(void) qemu_opt_foreach(opts, add_channel, &tls_port, &error_fatal); - spice_server_set_name(spice_server, qemu_name); + spice_server_set_name(spice_server, qemu_name ?: "QEMU " QEMU_VERSION); spice_server_set_uuid(spice_server, (unsigned char *)&qemu_uuid); seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); @@ -863,6 +865,56 @@ bool qemu_spice_have_display_interface(QemuConsole *con) return false; } +/* + * Recursively (in reverse order) appends addresses of PCI devices as it moves + * up in the PCI hierarchy. + * + * @returns true on success, false when the buffer wasn't large enough + */ +static bool append_pci_address(char *buf, size_t buf_size, const PCIDevice *pci) +{ + PCIBus *bus = pci_get_bus(pci); + /* + * equivalent to if (!pci_bus_is_root(bus)), but the function is not built + * with PCI_CONFIG=n, avoid using an #ifdef by checking directly + */ + if (bus->parent_dev != NULL) { + append_pci_address(buf, buf_size, bus->parent_dev); + } + + size_t len = strlen(buf); + ssize_t written = snprintf(buf + len, buf_size - len, "/%02x.%x", + PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn)); + + return written > 0 && written < buf_size - len; +} + +bool qemu_spice_fill_device_address(QemuConsole *con, + char *device_address, + size_t size) +{ + DeviceState *dev = DEVICE(object_property_get_link(OBJECT(con), + "device", + &error_abort)); + PCIDevice *pci = (PCIDevice *) object_dynamic_cast(OBJECT(dev), + TYPE_PCI_DEVICE); + + if (pci == NULL) { + warn_report("Setting device address of a display device to SPICE: " + "Not a PCI device."); + return false; + } + + strncpy(device_address, "pci/0000", size); + if (!append_pci_address(device_address, size, pci)) { + warn_report("Setting device address of a display device to SPICE: " + "Too many PCI devices in the chain."); + return false; + } + + return true; +} + int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con) { if (g_slist_find(spice_consoles, con)) { @@ -921,12 +973,20 @@ int qemu_spice_display_add_client(int csock, int skipauth, int tls) void qemu_spice_display_start(void) { + if (spice_display_is_running) { + return; + } + spice_display_is_running = true; spice_server_vm_start(spice_server); } void qemu_spice_display_stop(void) { + if (!spice_display_is_running) { + return; + } + spice_server_vm_stop(spice_server); spice_display_is_running = false; } diff --git a/ui/spice-display.c b/ui/spice-display.c index aea6f6ebce..a5e26479a8 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -1147,6 +1147,17 @@ static void qemu_spice_display_init_one(QemuConsole *con) ssd->qxl.base.sif = &dpy_interface.base; qemu_spice_add_display_interface(&ssd->qxl, con); + +#if SPICE_SERVER_VERSION >= 0x000e02 /* release 0.14.2 */ + char device_address[256] = ""; + if (qemu_spice_fill_device_address(con, device_address, 256)) { + spice_qxl_set_device_info(&ssd->qxl, + device_address, + qemu_console_get_head(con), + 1); + } +#endif + qemu_spice_create_host_memslot(ssd); register_displaychangelistener(&ssd->dcl); diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c index 3751a777a4..7b2b09f242 100644 --- a/ui/vnc-auth-sasl.c +++ b/ui/vnc-auth-sasl.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "authz/base.h" #include "vnc.h" #include "trace.h" @@ -146,13 +147,14 @@ size_t vnc_client_read_sasl(VncState *vs) static int vnc_auth_sasl_check_access(VncState *vs) { const void *val; - int err; - int allow; + int rv; + Error *err = NULL; + bool allow; - err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val); - if (err != SASL_OK) { + rv = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val); + if (rv != SASL_OK) { trace_vnc_auth_fail(vs, vs->auth, "Cannot fetch SASL username", - sasl_errstring(err, NULL, NULL)); + sasl_errstring(rv, NULL, NULL)); return -1; } if (val == NULL) { @@ -163,12 +165,19 @@ static int vnc_auth_sasl_check_access(VncState *vs) vs->sasl.username = g_strdup((const char*)val); trace_vnc_auth_sasl_username(vs, vs->sasl.username); - if (vs->vd->sasl.acl == NULL) { + if (vs->vd->sasl.authzid == NULL) { trace_vnc_auth_sasl_acl(vs, 1); return 0; } - allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username); + allow = qauthz_is_allowed_by_id(vs->vd->sasl.authzid, + vs->sasl.username, &err); + if (err) { + trace_vnc_auth_fail(vs, vs->auth, "Error from authz", + error_get_pretty(err)); + error_free(err); + return -1; + } trace_vnc_auth_sasl_acl(vs, allow); return allow ? 0 : -1; diff --git a/ui/vnc-auth-sasl.h b/ui/vnc-auth-sasl.h index 2ae224ee3a..fb55fe04ca 100644 --- a/ui/vnc-auth-sasl.h +++ b/ui/vnc-auth-sasl.h @@ -30,8 +30,8 @@ typedef struct VncStateSASL VncStateSASL; typedef struct VncDisplaySASL VncDisplaySASL; -#include "qemu/acl.h" #include "qemu/main-loop.h" +#include "authz/base.h" struct VncStateSASL { sasl_conn_t *conn; @@ -60,7 +60,8 @@ struct VncStateSASL { }; struct VncDisplaySASL { - qemu_acl *acl; + QAuthZ *authz; + char *authzid; }; void vnc_sasl_client_cleanup(VncState *vs); diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c index d99ea362c1..f072e16ace 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c @@ -109,7 +109,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len tls = qio_channel_tls_new_server( vs->ioc, vs->vd->tlscreds, - vs->vd->tlsaclname, + vs->vd->tlsauthzid, &err); if (!tls) { trace_vnc_auth_fail(vs, vs->auth, "TLS setup failed", diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c index 950f1cd2ac..95c9703c72 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -62,7 +62,7 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, tls = qio_channel_tls_new_server( vs->ioc, vs->vd->tlscreds, - vs->vd->tlsaclname, + vs->vd->tlsauthzid, &err); if (!tls) { VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err)); @@ -33,7 +33,7 @@ #include "qemu/option.h" #include "qemu/sockets.h" #include "qemu/timer.h" -#include "qemu/acl.h" +#include "authz/list.h" #include "qemu/config-file.h" #include "qapi/qapi-emit-events.h" #include "qapi/qapi-events-ui.h" @@ -3229,12 +3229,24 @@ static void vnc_display_close(VncDisplay *vd) object_unparent(OBJECT(vd->tlscreds)); vd->tlscreds = NULL; } - g_free(vd->tlsaclname); - vd->tlsaclname = NULL; + if (vd->tlsauthz) { + object_unparent(OBJECT(vd->tlsauthz)); + vd->tlsauthz = NULL; + } + g_free(vd->tlsauthzid); + vd->tlsauthzid = NULL; if (vd->lock_key_sync) { qemu_remove_led_event_handler(vd->led); vd->led = NULL; } +#ifdef CONFIG_VNC_SASL + if (vd->sasl.authz) { + object_unparent(OBJECT(vd->sasl.authz)); + vd->sasl.authz = NULL; + } + g_free(vd->sasl.authzid); + vd->sasl.authzid = NULL; +#endif } int vnc_display_password(const char *id, const char *password) @@ -3887,23 +3899,24 @@ void vnc_display_open(const char *id, Error **errp) if (acl) { if (strcmp(vd->id, "default") == 0) { - vd->tlsaclname = g_strdup("vnc.x509dname"); + vd->tlsauthzid = g_strdup("vnc.x509dname"); } else { - vd->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vd->id); + vd->tlsauthzid = g_strdup_printf("vnc.%s.x509dname", vd->id); } - qemu_acl_init(vd->tlsaclname); + vd->tlsauthz = QAUTHZ(qauthz_list_new(vd->tlsauthzid, + QAUTHZ_LIST_POLICY_DENY, + &error_abort)); } #ifdef CONFIG_VNC_SASL if (acl && sasl) { - char *aclname; - if (strcmp(vd->id, "default") == 0) { - aclname = g_strdup("vnc.username"); + vd->sasl.authzid = g_strdup("vnc.username"); } else { - aclname = g_strdup_printf("vnc.%s.username", vd->id); + vd->sasl.authzid = g_strdup_printf("vnc.%s.username", vd->id); } - vd->sasl.acl = qemu_acl_init(aclname); - g_free(aclname); + vd->sasl.authz = QAUTHZ(qauthz_list_new(vd->sasl.authzid, + QAUTHZ_LIST_POLICY_DENY, + &error_abort)); } #endif @@ -39,6 +39,7 @@ #include "io/channel-socket.h" #include "io/channel-tls.h" #include "io/net-listener.h" +#include "authz/base.h" #include <zlib.h> #include "keymaps.h" @@ -178,7 +179,8 @@ struct VncDisplay bool lossy; bool non_adaptive; QCryptoTLSCreds *tlscreds; - char *tlsaclname; + QAuthZ *tlsauthz; + char *tlsauthzid; #ifdef CONFIG_VNC_SASL VncDisplaySASL sasl; #endif diff --git a/util/Makefile.objs b/util/Makefile.objs index 0820923c18..0808575e3e 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -20,7 +20,6 @@ util-obj-y += envlist.o path.o module.o util-obj-y += host-utils.o util-obj-y += bitmap.o bitops.o hbitmap.o util-obj-y += fifo8.o -util-obj-y += acl.o util-obj-y += cacheinfo.o util-obj-y += error.o qemu-error.o util-obj-y += id.o @@ -50,5 +49,8 @@ util-obj-y += range.o util-obj-y += stats64.o util-obj-y += systemd.o util-obj-y += iova-tree.o +util-obj-$(CONFIG_INOTIFY1) += filemonitor-inotify.o util-obj-$(CONFIG_LINUX) += vfio-helpers.o util-obj-$(CONFIG_OPENGL) += drm.o + +stub-obj-y += filemonitor-stub.o diff --git a/util/acl.c b/util/acl.c deleted file mode 100644 index c105addadc..0000000000 --- a/util/acl.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * QEMU access control list management - * - * Copyright (C) 2009 Red Hat, Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "qemu/acl.h" - -#ifdef CONFIG_FNMATCH -#include <fnmatch.h> -#endif - - -static unsigned int nacls = 0; -static qemu_acl **acls = NULL; - - - -qemu_acl *qemu_acl_find(const char *aclname) -{ - int i; - for (i = 0 ; i < nacls ; i++) { - if (strcmp(acls[i]->aclname, aclname) == 0) - return acls[i]; - } - - return NULL; -} - -qemu_acl *qemu_acl_init(const char *aclname) -{ - qemu_acl *acl; - - acl = qemu_acl_find(aclname); - if (acl) - return acl; - - acl = g_malloc(sizeof(*acl)); - acl->aclname = g_strdup(aclname); - /* Deny by default, so there is no window of "open - * access" between QEMU starting, and the user setting - * up ACLs in the monitor */ - acl->defaultDeny = 1; - - acl->nentries = 0; - QTAILQ_INIT(&acl->entries); - - acls = g_realloc(acls, sizeof(*acls) * (nacls +1)); - acls[nacls] = acl; - nacls++; - - return acl; -} - -int qemu_acl_party_is_allowed(qemu_acl *acl, - const char *party) -{ - qemu_acl_entry *entry; - - QTAILQ_FOREACH(entry, &acl->entries, next) { -#ifdef CONFIG_FNMATCH - if (fnmatch(entry->match, party, 0) == 0) - return entry->deny ? 0 : 1; -#else - /* No fnmatch, so fallback to exact string matching - * instead of allowing wildcards */ - if (strcmp(entry->match, party) == 0) - return entry->deny ? 0 : 1; -#endif - } - - return acl->defaultDeny ? 0 : 1; -} - - -void qemu_acl_reset(qemu_acl *acl) -{ - qemu_acl_entry *entry, *next_entry; - - /* Put back to deny by default, so there is no window - * of "open access" while the user re-initializes the - * access control list */ - acl->defaultDeny = 1; - QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) { - QTAILQ_REMOVE(&acl->entries, entry, next); - g_free(entry->match); - g_free(entry); - } - acl->nentries = 0; -} - - -int qemu_acl_append(qemu_acl *acl, - int deny, - const char *match) -{ - qemu_acl_entry *entry; - - entry = g_malloc(sizeof(*entry)); - entry->match = g_strdup(match); - entry->deny = deny; - - QTAILQ_INSERT_TAIL(&acl->entries, entry, next); - acl->nentries++; - - return acl->nentries; -} - - -int qemu_acl_insert(qemu_acl *acl, - int deny, - const char *match, - int index) -{ - qemu_acl_entry *tmp; - int i = 0; - - if (index <= 0) - return -1; - if (index > acl->nentries) { - return qemu_acl_append(acl, deny, match); - } - - QTAILQ_FOREACH(tmp, &acl->entries, next) { - i++; - if (i == index) { - qemu_acl_entry *entry; - entry = g_malloc(sizeof(*entry)); - entry->match = g_strdup(match); - entry->deny = deny; - - QTAILQ_INSERT_BEFORE(tmp, entry, next); - acl->nentries++; - break; - } - } - - return i; -} - -int qemu_acl_remove(qemu_acl *acl, - const char *match) -{ - qemu_acl_entry *entry; - int i = 0; - - QTAILQ_FOREACH(entry, &acl->entries, next) { - i++; - if (strcmp(entry->match, match) == 0) { - QTAILQ_REMOVE(&acl->entries, entry, next); - acl->nentries--; - g_free(entry->match); - g_free(entry); - return i; - } - } - return -1; -} diff --git a/util/aio-posix.c b/util/aio-posix.c index 8640dfde9f..6fbfa7924f 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -613,6 +613,8 @@ bool aio_poll(AioContext *ctx, bool blocking) int64_t timeout; int64_t start = 0; + assert(in_aio_context_home_thread(ctx)); + /* aio_notify can avoid the expensive event_notifier_set if * everything (file descriptors, bottom halves, timers) will * be re-evaluated before the next blocking poll(). This is @@ -621,7 +623,6 @@ bool aio_poll(AioContext *ctx, bool blocking) * so disable the optimization now. */ if (blocking) { - assert(in_aio_context_home_thread(ctx)); atomic_add(&ctx->notify_me, 2); } diff --git a/util/filemonitor-inotify.c b/util/filemonitor-inotify.c new file mode 100644 index 0000000000..3a72be037f --- /dev/null +++ b/util/filemonitor-inotify.c @@ -0,0 +1,339 @@ +/* + * QEMU file monitor Linux inotify impl + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qemu/filemonitor.h" +#include "qemu/main-loop.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "trace.h" + +#include <sys/inotify.h> + +struct QFileMonitor { + int fd; + + QemuMutex lock; /* protects dirs & idmap */ + GHashTable *dirs; /* dirname => QFileMonitorDir */ + GHashTable *idmap; /* inotify ID => dirname */ +}; + + +typedef struct { + int id; /* watch ID */ + char *filename; /* optional filter */ + QFileMonitorHandler cb; + void *opaque; +} QFileMonitorWatch; + + +typedef struct { + char *path; + int id; /* inotify ID */ + int nextid; /* watch ID counter */ + GArray *watches; /* QFileMonitorWatch elements */ +} QFileMonitorDir; + + +static void qemu_file_monitor_watch(void *arg) +{ + QFileMonitor *mon = arg; + char buf[4096] + __attribute__ ((aligned(__alignof__(struct inotify_event)))); + int used = 0; + int len; + + qemu_mutex_lock(&mon->lock); + + if (mon->fd == -1) { + qemu_mutex_unlock(&mon->lock); + return; + } + + len = read(mon->fd, buf, sizeof(buf)); + + if (len < 0) { + if (errno != EAGAIN) { + error_report("Failure monitoring inotify FD '%s'," + "disabling events", strerror(errno)); + goto cleanup; + } + + /* no more events right now */ + goto cleanup; + } + + /* Loop over all events in the buffer */ + while (used < len) { + struct inotify_event *ev = + (struct inotify_event *)(buf + used); + const char *name = ev->len ? ev->name : ""; + QFileMonitorDir *dir = g_hash_table_lookup(mon->idmap, + GINT_TO_POINTER(ev->wd)); + uint32_t iev = ev->mask & + (IN_CREATE | IN_MODIFY | IN_DELETE | IN_IGNORED | + IN_MOVED_TO | IN_MOVED_FROM | IN_ATTRIB); + int qev; + gsize i; + + used += sizeof(struct inotify_event) + ev->len; + + if (!dir) { + continue; + } + + /* + * During a rename operation, the old name gets + * IN_MOVED_FROM and the new name gets IN_MOVED_TO. + * To simplify life for callers, we turn these into + * DELETED and CREATED events + */ + switch (iev) { + case IN_CREATE: + case IN_MOVED_TO: + qev = QFILE_MONITOR_EVENT_CREATED; + break; + case IN_MODIFY: + qev = QFILE_MONITOR_EVENT_MODIFIED; + break; + case IN_DELETE: + case IN_MOVED_FROM: + qev = QFILE_MONITOR_EVENT_DELETED; + break; + case IN_ATTRIB: + qev = QFILE_MONITOR_EVENT_ATTRIBUTES; + break; + case IN_IGNORED: + qev = QFILE_MONITOR_EVENT_IGNORED; + break; + default: + g_assert_not_reached(); + } + + trace_qemu_file_monitor_event(mon, dir->path, name, ev->mask, dir->id); + for (i = 0; i < dir->watches->len; i++) { + QFileMonitorWatch *watch = &g_array_index(dir->watches, + QFileMonitorWatch, + i); + + if (watch->filename == NULL || + (name && g_str_equal(watch->filename, name))) { + trace_qemu_file_monitor_dispatch(mon, dir->path, name, + qev, watch->cb, + watch->opaque, watch->id); + watch->cb(watch->id, qev, name, watch->opaque); + } + } + } + + cleanup: + qemu_mutex_unlock(&mon->lock); +} + + +static void +qemu_file_monitor_dir_free(void *data) +{ + QFileMonitorDir *dir = data; + gsize i; + + for (i = 0; i < dir->watches->len; i++) { + QFileMonitorWatch *watch = &g_array_index(dir->watches, + QFileMonitorWatch, i); + g_free(watch->filename); + } + g_array_unref(dir->watches); + g_free(dir->path); + g_free(dir); +} + + +QFileMonitor * +qemu_file_monitor_new(Error **errp) +{ + int fd; + QFileMonitor *mon; + + fd = inotify_init1(IN_NONBLOCK); + if (fd < 0) { + error_setg_errno(errp, errno, + "Unable to initialize inotify"); + return NULL; + } + + mon = g_new0(QFileMonitor, 1); + qemu_mutex_init(&mon->lock); + mon->fd = fd; + + mon->dirs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + qemu_file_monitor_dir_free); + mon->idmap = g_hash_table_new(g_direct_hash, g_direct_equal); + + trace_qemu_file_monitor_new(mon, mon->fd); + + return mon; +} + +static gboolean +qemu_file_monitor_free_idle(void *opaque) +{ + QFileMonitor *mon = opaque; + + if (!mon) { + return G_SOURCE_REMOVE; + } + + qemu_mutex_lock(&mon->lock); + + g_hash_table_unref(mon->idmap); + g_hash_table_unref(mon->dirs); + + qemu_mutex_unlock(&mon->lock); + + qemu_mutex_destroy(&mon->lock); + g_free(mon); + + return G_SOURCE_REMOVE; +} + +void +qemu_file_monitor_free(QFileMonitor *mon) +{ + if (!mon) { + return; + } + + qemu_mutex_lock(&mon->lock); + if (mon->fd != -1) { + qemu_set_fd_handler(mon->fd, NULL, NULL, NULL); + close(mon->fd); + mon->fd = -1; + } + qemu_mutex_unlock(&mon->lock); + + /* + * Can't free it yet, because another thread + * may be running event loop, so the inotify + * callback might be pending. Using an idle + * source ensures we'll only free after the + * pending callback is done + */ + g_idle_add((GSourceFunc)qemu_file_monitor_free_idle, mon); +} + +int +qemu_file_monitor_add_watch(QFileMonitor *mon, + const char *dirpath, + const char *filename, + QFileMonitorHandler cb, + void *opaque, + Error **errp) +{ + QFileMonitorDir *dir; + QFileMonitorWatch watch; + int ret = -1; + + qemu_mutex_lock(&mon->lock); + dir = g_hash_table_lookup(mon->dirs, dirpath); + if (!dir) { + int rv = inotify_add_watch(mon->fd, dirpath, + IN_CREATE | IN_DELETE | IN_MODIFY | + IN_MOVED_TO | IN_MOVED_FROM | IN_ATTRIB); + + if (rv < 0) { + error_setg_errno(errp, errno, "Unable to watch '%s'", dirpath); + goto cleanup; + } + + trace_qemu_file_monitor_enable_watch(mon, dirpath, rv); + + dir = g_new0(QFileMonitorDir, 1); + dir->path = g_strdup(dirpath); + dir->id = rv; + dir->watches = g_array_new(FALSE, TRUE, sizeof(QFileMonitorWatch)); + + g_hash_table_insert(mon->dirs, dir->path, dir); + g_hash_table_insert(mon->idmap, GINT_TO_POINTER(rv), dir); + + if (g_hash_table_size(mon->dirs) == 1) { + qemu_set_fd_handler(mon->fd, qemu_file_monitor_watch, NULL, mon); + } + } + + watch.id = dir->nextid++; + watch.filename = g_strdup(filename); + watch.cb = cb; + watch.opaque = opaque; + + g_array_append_val(dir->watches, watch); + + trace_qemu_file_monitor_add_watch(mon, dirpath, + filename ? filename : "<none>", + cb, opaque, watch.id); + + ret = watch.id; + + cleanup: + qemu_mutex_unlock(&mon->lock); + return ret; +} + + +void qemu_file_monitor_remove_watch(QFileMonitor *mon, + const char *dirpath, + int id) +{ + QFileMonitorDir *dir; + gsize i; + + qemu_mutex_lock(&mon->lock); + + trace_qemu_file_monitor_remove_watch(mon, dirpath, id); + + dir = g_hash_table_lookup(mon->dirs, dirpath); + if (!dir) { + goto cleanup; + } + + for (i = 0; i < dir->watches->len; i++) { + QFileMonitorWatch *watch = &g_array_index(dir->watches, + QFileMonitorWatch, i); + if (watch->id == id) { + g_free(watch->filename); + g_array_remove_index(dir->watches, i); + break; + } + } + + if (dir->watches->len == 0) { + inotify_rm_watch(mon->fd, dir->id); + trace_qemu_file_monitor_disable_watch(mon, dir->path, dir->id); + + g_hash_table_remove(mon->idmap, GINT_TO_POINTER(dir->id)); + g_hash_table_remove(mon->dirs, dir->path); + + if (g_hash_table_size(mon->dirs) == 0) { + qemu_set_fd_handler(mon->fd, NULL, NULL, NULL); + } + } + + cleanup: + qemu_mutex_unlock(&mon->lock); +} diff --git a/util/filemonitor-stub.c b/util/filemonitor-stub.c new file mode 100644 index 0000000000..48268b2bb6 --- /dev/null +++ b/util/filemonitor-stub.c @@ -0,0 +1,59 @@ +/* + * QEMU file monitor stub impl + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qemu/filemonitor.h" +#include "qemu/error-report.h" +#include "qapi/error.h" + + +QFileMonitor * +qemu_file_monitor_new(Error **errp) +{ + error_setg(errp, "File monitoring not available on this platform"); + return NULL; +} + + +void +qemu_file_monitor_free(QFileMonitor *mon G_GNUC_UNUSED) +{ +} + + +int +qemu_file_monitor_add_watch(QFileMonitor *mon G_GNUC_UNUSED, + const char *dirpath G_GNUC_UNUSED, + const char *filename G_GNUC_UNUSED, + QFileMonitorHandler cb G_GNUC_UNUSED, + void *opaque G_GNUC_UNUSED, + Error **errp) +{ + error_setg(errp, "File monitoring not available on this platform"); + return -1; +} + + +void +qemu_file_monitor_remove_watch(QFileMonitor *mon G_GNUC_UNUSED, + const char *dirpath G_GNUC_UNUSED, + int id G_GNUC_UNUSED) +{ +} diff --git a/util/trace-events b/util/trace-events index 79569b7fdf..ff19b253e2 100644 --- a/util/trace-events +++ b/util/trace-events @@ -21,6 +21,15 @@ buffer_move_empty(const char *buf, size_t len, const char *from) "%s: %zd bytes buffer_move(const char *buf, size_t len, const char *from) "%s: %zd bytes from %s" buffer_free(const char *buf, size_t len) "%s: capacity %zd" +# util/filemonitor.c +qemu_file_monitor_add_watch(void *mon, const char *dirpath, const char *filename, void *cb, void *opaque, int id) "File monitor %p add watch dir='%s' file='%s' cb=%p opaque=%p id=%u" +qemu_file_monitor_remove_watch(void *mon, const char *dirpath, int id) "File monitor %p remove watch dir='%s' id=%u" +qemu_file_monitor_new(void *mon, int fd) "File monitor %p created fd=%d" +qemu_file_monitor_enable_watch(void *mon, const char *dirpath, int id) "File monitor %p enable watch dir='%s' id=%u" +qemu_file_monitor_disable_watch(void *mon, const char *dirpath, int id) "Fle monitor %p disable watch dir='%s' id=%u" +qemu_file_monitor_event(void *mon, const char *dirpath, const char *filename, int mask, unsigned int id) "File monitor %p event dir='%s' file='%s' mask=0x%x id=%u" +qemu_file_monitor_dispatch(void *mon, const char *dirpath, const char *filename, int ev, void *cb, void *opaque, unsigned int id) "File monitor %p dispatch dir='%s' file='%s' ev=%d cb=%p opaque=%p id=%u" + # util/qemu-coroutine.c qemu_aio_coroutine_enter(void *ctx, void *from, void *to, void *opaque) "ctx %p from %p to %p opaque %p" qemu_coroutine_yield(void *from, void *to) "from %p to %p" |