diff options
62 files changed, 2698 insertions, 619 deletions
diff --git a/.travis.yml b/.travis.yml index ec6367af1f..74158f741b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -293,7 +293,7 @@ jobs: - name: "GCC check-acceptance" dist: bionic env: - - CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu" + - CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sh4-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu" - TEST_CMD="make check-acceptance" - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-acceptance" after_script: @@ -496,7 +496,6 @@ jobs: - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user" - UNRELIABLE=true script: - - ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF ) - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$? - | if [ "$BUILD_RC" -eq 0 ] ; then diff --git a/MAINTAINERS b/MAINTAINERS index b69edc2d2f..955cc8dd5c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -296,7 +296,7 @@ F: tests/tcg/s390x/ L: qemu-s390x@nongnu.org SH4 TCG CPUs -M: Aurelien Jarno <aurelien@aurel32.net> +M: Yoshinori Sato <ysato@users.sourceforge.jp> S: Odd Fixes F: target/sh4/ F: hw/sh4/ @@ -1255,14 +1255,16 @@ F: include/hw/riscv/opentitan.h SH4 Machines ------------ R2D -M: Magnus Damm <magnus.damm@gmail.com> +M: Yoshinori Sato <ysato@users.sourceforge.jp> +R: Magnus Damm <magnus.damm@gmail.com> S: Maintained F: hw/sh4/r2d.c F: hw/intc/sh_intc.c F: hw/timer/sh_timer.c Shix -M: Magnus Damm <magnus.damm@gmail.com> +M: Yoshinori Sato <ysato@users.sourceforge.jp> +R: Magnus Damm <magnus.damm@gmail.com> S: Odd Fixes F: hw/sh4/shix.c @@ -2343,6 +2345,7 @@ R: Bandan Das <bsd@redhat.com> R: Stefan Hajnoczi <stefanha@redhat.com> S: Maintained F: tests/qtest/fuzz/ +F: scripts/oss-fuzz/ Register API M: Alistair Francis <alistair@alistair23.me> @@ -509,6 +509,8 @@ libpmem="" default_devices="yes" plugins="no" fuzzing="no" +rng_none="no" +secret_keyring="" supported_cpu="no" supported_os="no" @@ -1601,6 +1603,14 @@ for opt do ;; --gdb=*) gdb_bin="$optarg" ;; + --enable-rng-none) rng_none=yes + ;; + --disable-rng-none) rng_none=no + ;; + --enable-keyring) secret_keyring="yes" + ;; + --disable-keyring) secret_keyring="no" + ;; *) echo "ERROR: unknown option $opt" echo "Try '$0 --help' for more information" @@ -1898,6 +1908,7 @@ disabled with --disable-FEATURE, default is enabled if available: debug-mutex mutex debugging support libpmem libpmem support xkbcommon xkbcommon support + rng-none dummy RNG, avoid using /dev/(u)random and getrandom() NOTE: The object files are built at the place where configure is launched EOF @@ -6284,6 +6295,62 @@ case "$slirp" in ;; esac +########################################## +# check for usable __NR_keyctl syscall + +if test "$linux" = "yes" ; then + + have_keyring=no + cat > $TMPC << EOF +#include <errno.h> +#include <asm/unistd.h> +#include <linux/keyctl.h> +#include <unistd.h> +int main(void) { + return syscall(__NR_keyctl, KEYCTL_READ, 0, NULL, NULL, 0); +} +EOF + if compile_prog "" "" ; then + have_keyring=yes + fi +fi +if test "$secret_keyring" != "no" +then + if test "$have_keyring" == "yes" + then + secret_keyring=yes + else + if test "$secret_keyring" = "yes" + then + error_exit "syscall __NR_keyctl requested, \ +but not implemented on your system" + else + secret_keyring=no + fi + fi +fi + +########################################## +# check for usable keyutils.h + +if test "$linux" = "yes" ; then + + have_keyutils=no + cat > $TMPC << EOF +#include <errno.h> +#include <asm/unistd.h> +#include <unistd.h> +#include <sys/types.h> +#include <keyutils.h> +int main(void) { + return request_key("user", NULL, NULL, 0); +} +EOF + if compile_prog "" "-lkeyutils"; then + have_keyutils=yes + fi +fi + ########################################## # End of CC checks @@ -6533,6 +6600,11 @@ if test "$cpu" = "s390x" ; then write_c_skeleton if compile_prog "-march=z900" ""; then roms="$roms s390-ccw" + # SLOF is required for building the s390-ccw firmware on s390x, + # since it is using the libnet code from SLOF for network booting. + if test -e "${source_path}/.git" ; then + git_submodules="${git_submodules} roms/SLOF" + fi fi fi @@ -6767,6 +6839,8 @@ echo "default devices $default_devices" echo "plugin support $plugins" echo "fuzzing support $fuzzing" echo "gdb $gdb_bin" +echo "rng-none $rng_none" +echo "Linux keyring $secret_keyring" if test "$supported_cpu" = "no"; then echo @@ -7652,6 +7726,13 @@ if test -n "$gdb_bin" ; then echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak fi +if test "$secret_keyring" = "yes" ; then + echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak + if test "$have_keyutils" = "yes" ; then + echo "CONFIG_TEST_SECRET_KEYRING=y" >> $config_host_mak + fi +fi + if test "$tcg_interpreter" = "yes"; then QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES" elif test "$ARCH" = "sparc64" ; then @@ -7744,6 +7825,10 @@ if test "$edk2_blobs" = "yes" ; then echo "DECOMPRESS_EDK2_BLOBS=y" >> $config_host_mak fi +if test "$rng_none" = "yes"; then + echo "CONFIG_RNG_NONE=y" >> $config_host_mak +fi + # use included Linux headers if test "$linux" = "yes" ; then mkdir -p linux-headers diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index c2a371b0b4..707c02ad37 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -18,7 +18,9 @@ crypto-obj-y += tlscredsanon.o crypto-obj-y += tlscredspsk.o crypto-obj-y += tlscredsx509.o crypto-obj-y += tlssession.o +crypto-obj-y += secret_common.o crypto-obj-y += secret.o +crypto-obj-$(CONFIG_SECRET_KEYRING) += secret_keyring.o crypto-obj-y += pbkdf.o crypto-obj-$(CONFIG_NETTLE) += pbkdf-nettle.o crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT)) += pbkdf-gcrypt.o @@ -35,5 +37,6 @@ crypto-obj-y += block-luks.o util-obj-$(CONFIG_GCRYPT) += random-gcrypt.o util-obj-$(if $(CONFIG_GCRYPT),n,$(CONFIG_GNUTLS)) += random-gnutls.o -util-obj-$(if $(CONFIG_GCRYPT),n,$(if $(CONFIG_GNUTLS),n,y)) += random-platform.o +util-obj-$(if $(CONFIG_GCRYPT),n,$(if $(CONFIG_GNUTLS),n,$(CONFIG_RNG_NONE))) += random-none.o +util-obj-$(if $(CONFIG_GCRYPT),n,$(if $(CONFIG_GNUTLS),n,$(if $(CONFIG_RNG_NONE),n,y))) += random-platform.o util-obj-y += aes.o init.o diff --git a/crypto/init.c b/crypto/init.c index b305381ec5..ea233b9192 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -122,7 +122,7 @@ int qcrypto_init(Error **errp) #endif #ifdef CONFIG_GCRYPT - if (!gcry_check_version(GCRYPT_VERSION)) { + if (!gcry_check_version(NULL)) { error_setg(errp, "Unable to initialize gcrypt"); return -1; } diff --git a/crypto/random-none.c b/crypto/random-none.c new file mode 100644 index 0000000000..102f8a4dce --- /dev/null +++ b/crypto/random-none.c @@ -0,0 +1,38 @@ +/* + * QEMU Crypto "none" random number provider + * + * Copyright (c) 2020 Marek Marczykowski-Górecki + * <marmarek@invisiblethingslab.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.1 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 "crypto/random.h" +#include "qapi/error.h" + +int qcrypto_random_init(Error **errp) +{ + return 0; +} + +int qcrypto_random_bytes(void *buf, + size_t buflen, + Error **errp) +{ + error_setg(errp, "Random bytes not available with \"none\" rng"); + return -1; +} diff --git a/crypto/secret.c b/crypto/secret.c index 3107aecb47..3447e2f64b 100644 --- a/crypto/secret.c +++ b/crypto/secret.c @@ -20,16 +20,14 @@ #include "qemu/osdep.h" #include "crypto/secret.h" -#include "crypto/cipher.h" #include "qapi/error.h" #include "qom/object_interfaces.h" -#include "qemu/base64.h" #include "qemu/module.h" #include "trace.h" static void -qcrypto_secret_load_data(QCryptoSecret *secret, +qcrypto_secret_load_data(QCryptoSecretCommon *sec_common, uint8_t **output, size_t *outputlen, Error **errp) @@ -38,6 +36,8 @@ qcrypto_secret_load_data(QCryptoSecret *secret, size_t length = 0; GError *gerr = NULL; + QCryptoSecret *secret = QCRYPTO_SECRET(sec_common); + *output = NULL; *outputlen = 0; @@ -65,198 +65,6 @@ qcrypto_secret_load_data(QCryptoSecret *secret, } -static void qcrypto_secret_decrypt(QCryptoSecret *secret, - const uint8_t *input, - size_t inputlen, - uint8_t **output, - size_t *outputlen, - Error **errp) -{ - g_autofree uint8_t *key = NULL; - g_autofree uint8_t *ciphertext = NULL; - g_autofree uint8_t *iv = NULL; - size_t keylen, ciphertextlen, ivlen; - g_autoptr(QCryptoCipher) aes = NULL; - g_autofree uint8_t *plaintext = NULL; - - *output = NULL; - *outputlen = 0; - - if (qcrypto_secret_lookup(secret->keyid, - &key, &keylen, - errp) < 0) { - return; - } - - if (keylen != 32) { - error_setg(errp, "Key should be 32 bytes in length"); - return; - } - - if (!secret->iv) { - error_setg(errp, "IV is required to decrypt secret"); - return; - } - - iv = qbase64_decode(secret->iv, -1, &ivlen, errp); - if (!iv) { - return; - } - if (ivlen != 16) { - error_setg(errp, "IV should be 16 bytes in length not %zu", - ivlen); - return; - } - - aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256, - QCRYPTO_CIPHER_MODE_CBC, - key, keylen, - errp); - if (!aes) { - return; - } - - if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) { - return; - } - - if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { - ciphertext = qbase64_decode((const gchar*)input, - inputlen, - &ciphertextlen, - errp); - if (!ciphertext) { - return; - } - plaintext = g_new0(uint8_t, ciphertextlen + 1); - } else { - ciphertextlen = inputlen; - plaintext = g_new0(uint8_t, inputlen + 1); - } - if (qcrypto_cipher_decrypt(aes, - ciphertext ? ciphertext : input, - plaintext, - ciphertextlen, - errp) < 0) { - return; - } - - if (plaintext[ciphertextlen - 1] > 16 || - plaintext[ciphertextlen - 1] > ciphertextlen) { - error_setg(errp, "Incorrect number of padding bytes (%d) " - "found on decrypted data", - (int)plaintext[ciphertextlen - 1]); - return; - } - - /* Even though plaintext may contain arbitrary NUL - * ensure it is explicitly NUL terminated. - */ - ciphertextlen -= plaintext[ciphertextlen - 1]; - plaintext[ciphertextlen] = '\0'; - - *output = g_steal_pointer(&plaintext); - *outputlen = ciphertextlen; -} - - -static void qcrypto_secret_decode(const uint8_t *input, - size_t inputlen, - uint8_t **output, - size_t *outputlen, - Error **errp) -{ - *output = qbase64_decode((const gchar*)input, - inputlen, - outputlen, - errp); -} - - -static void -qcrypto_secret_prop_set_loaded(Object *obj, - bool value, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - - if (value) { - Error *local_err = NULL; - uint8_t *input = NULL; - size_t inputlen = 0; - uint8_t *output = NULL; - size_t outputlen = 0; - - qcrypto_secret_load_data(secret, &input, &inputlen, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - if (secret->keyid) { - qcrypto_secret_decrypt(secret, input, inputlen, - &output, &outputlen, &local_err); - g_free(input); - if (local_err) { - error_propagate(errp, local_err); - return; - } - input = output; - inputlen = outputlen; - } else { - if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { - qcrypto_secret_decode(input, inputlen, - &output, &outputlen, &local_err); - g_free(input); - if (local_err) { - error_propagate(errp, local_err); - return; - } - input = output; - inputlen = outputlen; - } - } - - secret->rawdata = input; - secret->rawlen = inputlen; - } else { - g_free(secret->rawdata); - secret->rawdata = NULL; - secret->rawlen = 0; - } -} - - -static bool -qcrypto_secret_prop_get_loaded(Object *obj, - Error **errp G_GNUC_UNUSED) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - return secret->rawdata != NULL; -} - - -static void -qcrypto_secret_prop_set_format(Object *obj, - int value, - Error **errp G_GNUC_UNUSED) -{ - QCryptoSecret *creds = QCRYPTO_SECRET(obj); - - creds->format = value; -} - - -static int -qcrypto_secret_prop_get_format(Object *obj, - Error **errp G_GNUC_UNUSED) -{ - QCryptoSecret *creds = QCRYPTO_SECRET(obj); - - return creds->format; -} - - static void qcrypto_secret_prop_set_data(Object *obj, const char *value, @@ -300,48 +108,6 @@ qcrypto_secret_prop_get_file(Object *obj, static void -qcrypto_secret_prop_set_iv(Object *obj, - const char *value, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - - g_free(secret->iv); - secret->iv = g_strdup(value); -} - - -static char * -qcrypto_secret_prop_get_iv(Object *obj, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - return g_strdup(secret->iv); -} - - -static void -qcrypto_secret_prop_set_keyid(Object *obj, - const char *value, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - - g_free(secret->keyid); - secret->keyid = g_strdup(value); -} - - -static char * -qcrypto_secret_prop_get_keyid(Object *obj, - Error **errp) -{ - QCryptoSecret *secret = QCRYPTO_SECRET(obj); - return g_strdup(secret->keyid); -} - - -static void qcrypto_secret_complete(UserCreatable *uc, Error **errp) { object_property_set_bool(OBJECT(uc), true, "loaded", errp); @@ -353,129 +119,30 @@ qcrypto_secret_finalize(Object *obj) { QCryptoSecret *secret = QCRYPTO_SECRET(obj); - g_free(secret->iv); g_free(secret->file); - g_free(secret->keyid); - g_free(secret->rawdata); g_free(secret->data); } static void qcrypto_secret_class_init(ObjectClass *oc, void *data) { - UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + QCryptoSecretCommonClass *sic = QCRYPTO_SECRET_COMMON_CLASS(oc); + sic->load_data = qcrypto_secret_load_data; + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); ucc->complete = qcrypto_secret_complete; - object_class_property_add_bool(oc, "loaded", - qcrypto_secret_prop_get_loaded, - qcrypto_secret_prop_set_loaded); - object_class_property_add_enum(oc, "format", - "QCryptoSecretFormat", - &QCryptoSecretFormat_lookup, - qcrypto_secret_prop_get_format, - qcrypto_secret_prop_set_format); object_class_property_add_str(oc, "data", qcrypto_secret_prop_get_data, qcrypto_secret_prop_set_data); object_class_property_add_str(oc, "file", qcrypto_secret_prop_get_file, qcrypto_secret_prop_set_file); - object_class_property_add_str(oc, "keyid", - qcrypto_secret_prop_get_keyid, - qcrypto_secret_prop_set_keyid); - object_class_property_add_str(oc, "iv", - qcrypto_secret_prop_get_iv, - qcrypto_secret_prop_set_iv); -} - - -int qcrypto_secret_lookup(const char *secretid, - uint8_t **data, - size_t *datalen, - Error **errp) -{ - Object *obj; - QCryptoSecret *secret; - - obj = object_resolve_path_component( - object_get_objects_root(), secretid); - if (!obj) { - error_setg(errp, "No secret with id '%s'", secretid); - return -1; - } - - secret = (QCryptoSecret *) - object_dynamic_cast(obj, - TYPE_QCRYPTO_SECRET); - if (!secret) { - error_setg(errp, "Object with id '%s' is not a secret", - secretid); - return -1; - } - - if (!secret->rawdata) { - error_setg(errp, "Secret with id '%s' has no data", - secretid); - return -1; - } - - *data = g_new0(uint8_t, secret->rawlen + 1); - memcpy(*data, secret->rawdata, secret->rawlen); - (*data)[secret->rawlen] = '\0'; - *datalen = secret->rawlen; - - return 0; -} - - -char *qcrypto_secret_lookup_as_utf8(const char *secretid, - Error **errp) -{ - uint8_t *data; - size_t datalen; - - if (qcrypto_secret_lookup(secretid, - &data, - &datalen, - errp) < 0) { - return NULL; - } - - if (!g_utf8_validate((const gchar*)data, datalen, NULL)) { - error_setg(errp, - "Data from secret %s is not valid UTF-8", - secretid); - g_free(data); - return NULL; - } - - return (char *)data; -} - - -char *qcrypto_secret_lookup_as_base64(const char *secretid, - Error **errp) -{ - uint8_t *data; - size_t datalen; - char *ret; - - if (qcrypto_secret_lookup(secretid, - &data, - &datalen, - errp) < 0) { - return NULL; - } - - ret = g_base64_encode(data, datalen); - g_free(data); - return ret; } static const TypeInfo qcrypto_secret_info = { - .parent = TYPE_OBJECT, + .parent = TYPE_QCRYPTO_SECRET_COMMON, .name = TYPE_QCRYPTO_SECRET, .instance_size = sizeof(QCryptoSecret), .instance_finalize = qcrypto_secret_finalize, diff --git a/crypto/secret_common.c b/crypto/secret_common.c new file mode 100644 index 0000000000..b03d530867 --- /dev/null +++ b/crypto/secret_common.c @@ -0,0 +1,403 @@ +/* + * QEMU crypto secret support + * + * Copyright (c) 2015 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.1 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 "crypto/secret_common.h" +#include "crypto/cipher.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "qemu/base64.h" +#include "qemu/module.h" +#include "trace.h" + + +static void qcrypto_secret_decrypt(QCryptoSecretCommon *secret, + const uint8_t *input, + size_t inputlen, + uint8_t **output, + size_t *outputlen, + Error **errp) +{ + g_autofree uint8_t *iv = NULL; + g_autofree uint8_t *key = NULL; + g_autofree uint8_t *ciphertext = NULL; + size_t keylen, ciphertextlen, ivlen; + g_autoptr(QCryptoCipher) aes = NULL; + g_autofree uint8_t *plaintext = NULL; + + *output = NULL; + *outputlen = 0; + + if (qcrypto_secret_lookup(secret->keyid, + &key, &keylen, + errp) < 0) { + return; + } + + if (keylen != 32) { + error_setg(errp, "Key should be 32 bytes in length"); + return; + } + + if (!secret->iv) { + error_setg(errp, "IV is required to decrypt secret"); + return; + } + + iv = qbase64_decode(secret->iv, -1, &ivlen, errp); + if (!iv) { + return; + } + if (ivlen != 16) { + error_setg(errp, "IV should be 16 bytes in length not %zu", + ivlen); + return; + } + + aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256, + QCRYPTO_CIPHER_MODE_CBC, + key, keylen, + errp); + if (!aes) { + return; + } + + if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) { + return; + } + + if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { + ciphertext = qbase64_decode((const gchar *)input, + inputlen, + &ciphertextlen, + errp); + if (!ciphertext) { + return; + } + plaintext = g_new0(uint8_t, ciphertextlen + 1); + } else { + ciphertextlen = inputlen; + plaintext = g_new0(uint8_t, inputlen + 1); + } + if (qcrypto_cipher_decrypt(aes, + ciphertext ? ciphertext : input, + plaintext, + ciphertextlen, + errp) < 0) { + return; + } + + if (plaintext[ciphertextlen - 1] > 16 || + plaintext[ciphertextlen - 1] > ciphertextlen) { + error_setg(errp, "Incorrect number of padding bytes (%d) " + "found on decrypted data", + (int)plaintext[ciphertextlen - 1]); + return; + } + + /* + * Even though plaintext may contain arbitrary NUL + * ensure it is explicitly NUL terminated. + */ + ciphertextlen -= plaintext[ciphertextlen - 1]; + plaintext[ciphertextlen] = '\0'; + + *output = g_steal_pointer(&plaintext); + *outputlen = ciphertextlen; +} + + +static void qcrypto_secret_decode(const uint8_t *input, + size_t inputlen, + uint8_t **output, + size_t *outputlen, + Error **errp) +{ + *output = qbase64_decode((const gchar *)input, + inputlen, + outputlen, + errp); +} + + +static void +qcrypto_secret_prop_set_loaded(Object *obj, + bool value, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + QCryptoSecretCommonClass *sec_class + = QCRYPTO_SECRET_COMMON_GET_CLASS(obj); + + if (value) { + Error *local_err = NULL; + uint8_t *input = NULL; + size_t inputlen = 0; + uint8_t *output = NULL; + size_t outputlen = 0; + + if (sec_class->load_data) { + sec_class->load_data(secret, &input, &inputlen, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } else { + error_setg(errp, "%s provides no 'load_data' method'", + object_get_typename(obj)); + return; + } + + if (secret->keyid) { + qcrypto_secret_decrypt(secret, input, inputlen, + &output, &outputlen, &local_err); + g_free(input); + if (local_err) { + error_propagate(errp, local_err); + return; + } + input = output; + inputlen = outputlen; + } else { + if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { + qcrypto_secret_decode(input, inputlen, + &output, &outputlen, &local_err); + g_free(input); + if (local_err) { + error_propagate(errp, local_err); + return; + } + input = output; + inputlen = outputlen; + } + } + + secret->rawdata = input; + secret->rawlen = inputlen; + } else { + g_free(secret->rawdata); + secret->rawlen = 0; + } +} + + +static bool +qcrypto_secret_prop_get_loaded(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + return secret->rawdata != NULL; +} + + +static void +qcrypto_secret_prop_set_format(Object *obj, + int value, + Error **errp G_GNUC_UNUSED) +{ + QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj); + creds->format = value; +} + + +static int +qcrypto_secret_prop_get_format(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj); + return creds->format; +} + + +static void +qcrypto_secret_prop_set_iv(Object *obj, + const char *value, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + + g_free(secret->iv); + secret->iv = g_strdup(value); +} + + +static char * +qcrypto_secret_prop_get_iv(Object *obj, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + return g_strdup(secret->iv); +} + + +static void +qcrypto_secret_prop_set_keyid(Object *obj, + const char *value, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + + g_free(secret->keyid); + secret->keyid = g_strdup(value); +} + + +static char * +qcrypto_secret_prop_get_keyid(Object *obj, + Error **errp) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + return g_strdup(secret->keyid); +} + + +static void +qcrypto_secret_finalize(Object *obj) +{ + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + + g_free(secret->iv); + g_free(secret->keyid); + g_free(secret->rawdata); +} + +static void +qcrypto_secret_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_bool(oc, "loaded", + qcrypto_secret_prop_get_loaded, + qcrypto_secret_prop_set_loaded); + object_class_property_add_enum(oc, "format", + "QCryptoSecretFormat", + &QCryptoSecretFormat_lookup, + qcrypto_secret_prop_get_format, + qcrypto_secret_prop_set_format); + object_class_property_add_str(oc, "keyid", + qcrypto_secret_prop_get_keyid, + qcrypto_secret_prop_set_keyid); + object_class_property_add_str(oc, "iv", + qcrypto_secret_prop_get_iv, + qcrypto_secret_prop_set_iv); +} + + +int qcrypto_secret_lookup(const char *secretid, + uint8_t **data, + size_t *datalen, + Error **errp) +{ + Object *obj; + QCryptoSecretCommon *secret; + + obj = object_resolve_path_component( + object_get_objects_root(), secretid); + if (!obj) { + error_setg(errp, "No secret with id '%s'", secretid); + return -1; + } + + secret = (QCryptoSecretCommon *) + object_dynamic_cast(obj, + TYPE_QCRYPTO_SECRET_COMMON); + if (!secret) { + error_setg(errp, "Object with id '%s' is not a secret", + secretid); + return -1; + } + + if (!secret->rawdata) { + error_setg(errp, "Secret with id '%s' has no data", + secretid); + return -1; + } + + *data = g_new0(uint8_t, secret->rawlen + 1); + memcpy(*data, secret->rawdata, secret->rawlen); + (*data)[secret->rawlen] = '\0'; + *datalen = secret->rawlen; + + return 0; +} + + +char *qcrypto_secret_lookup_as_utf8(const char *secretid, + Error **errp) +{ + uint8_t *data; + size_t datalen; + + if (qcrypto_secret_lookup(secretid, + &data, + &datalen, + errp) < 0) { + return NULL; + } + + if (!g_utf8_validate((const gchar *)data, datalen, NULL)) { + error_setg(errp, + "Data from secret %s is not valid UTF-8", + secretid); + g_free(data); + return NULL; + } + + return (char *)data; +} + + +char *qcrypto_secret_lookup_as_base64(const char *secretid, + Error **errp) +{ + uint8_t *data; + size_t datalen; + char *ret; + + if (qcrypto_secret_lookup(secretid, + &data, + &datalen, + errp) < 0) { + return NULL; + } + + ret = g_base64_encode(data, datalen); + g_free(data); + return ret; +} + + +static const TypeInfo qcrypto_secret_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QCRYPTO_SECRET_COMMON, + .instance_size = sizeof(QCryptoSecretCommon), + .instance_finalize = qcrypto_secret_finalize, + .class_size = sizeof(QCryptoSecretCommonClass), + .class_init = qcrypto_secret_class_init, + .abstract = true, +}; + + +static void +qcrypto_secret_register_types(void) +{ + type_register_static(&qcrypto_secret_info); +} + + +type_init(qcrypto_secret_register_types); diff --git a/crypto/secret_keyring.c b/crypto/secret_keyring.c new file mode 100644 index 0000000000..4f132d6370 --- /dev/null +++ b/crypto/secret_keyring.c @@ -0,0 +1,148 @@ +/* + * QEMU crypto secret support + * + * Copyright 2020 Yandex N.V. + * + * 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.1 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 <asm/unistd.h> +#include <linux/keyctl.h> +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "trace.h" +#include "crypto/secret_keyring.h" + + +static inline +long keyctl_read(int32_t key, uint8_t *buffer, size_t buflen) +{ + return syscall(__NR_keyctl, KEYCTL_READ, key, buffer, buflen, 0); +} + + +static void +qcrypto_secret_keyring_load_data(QCryptoSecretCommon *sec_common, + uint8_t **output, + size_t *outputlen, + Error **errp) +{ + QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(sec_common); + uint8_t *buffer = NULL; + long retcode; + + *output = NULL; + *outputlen = 0; + + if (!secret->serial) { + error_setg(errp, "'serial' parameter must be provided"); + return; + } + + retcode = keyctl_read(secret->serial, NULL, 0); + if (retcode <= 0) { + goto keyctl_error; + } + + buffer = g_new0(uint8_t, retcode); + + retcode = keyctl_read(secret->serial, buffer, retcode); + if (retcode < 0) { + g_free(buffer); + goto keyctl_error; + } + + *outputlen = retcode; + *output = buffer; + return; + +keyctl_error: + error_setg_errno(errp, errno, + "Unable to read serial key %08x", + secret->serial); +} + + +static void +qcrypto_secret_prop_set_key(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(obj); + int32_t value; + visit_type_int32(v, name, &value, errp); + if (!value) { + error_setg(errp, "'serial' should not be equal to 0"); + } + secret->serial = value; +} + + +static void +qcrypto_secret_prop_get_key(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(obj); + int32_t value = secret->serial; + visit_type_int32(v, name, &value, errp); +} + + +static void +qcrypto_secret_keyring_complete(UserCreatable *uc, Error **errp) +{ + object_property_set_bool(OBJECT(uc), true, "loaded", errp); +} + + +static void +qcrypto_secret_keyring_class_init(ObjectClass *oc, void *data) +{ + QCryptoSecretCommonClass *sic = QCRYPTO_SECRET_COMMON_CLASS(oc); + sic->load_data = qcrypto_secret_keyring_load_data; + + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + ucc->complete = qcrypto_secret_keyring_complete; + + object_class_property_add(oc, "serial", "int32_t", + qcrypto_secret_prop_get_key, + qcrypto_secret_prop_set_key, + NULL, NULL); +} + + +static const TypeInfo qcrypto_secret_info = { + .parent = TYPE_QCRYPTO_SECRET_COMMON, + .name = TYPE_QCRYPTO_SECRET_KEYRING, + .instance_size = sizeof(QCryptoSecretKeyring), + .class_size = sizeof(QCryptoSecretKeyringClass), + .class_init = qcrypto_secret_keyring_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + + +static void +qcrypto_secret_register_types(void) +{ + type_register_static(&qcrypto_secret_info); +} + + +type_init(qcrypto_secret_register_types); diff --git a/include/crypto/secret.h b/include/crypto/secret.h index 5e07e29bae..2deb461d2f 100644 --- a/include/crypto/secret.h +++ b/include/crypto/secret.h @@ -23,6 +23,7 @@ #include "qapi/qapi-types-crypto.h" #include "qom/object.h" +#include "crypto/secret_common.h" #define TYPE_QCRYPTO_SECRET "secret" #define QCRYPTO_SECRET(obj) \ @@ -119,29 +120,14 @@ typedef struct QCryptoSecretClass QCryptoSecretClass; */ struct QCryptoSecret { - Object parent_obj; - uint8_t *rawdata; - size_t rawlen; - QCryptoSecretFormat format; + QCryptoSecretCommon parent_obj; char *data; char *file; - char *keyid; - char *iv; }; struct QCryptoSecretClass { - ObjectClass parent_class; + QCryptoSecretCommonClass parent_class; }; - -extern int qcrypto_secret_lookup(const char *secretid, - uint8_t **data, - size_t *datalen, - Error **errp); -extern char *qcrypto_secret_lookup_as_utf8(const char *secretid, - Error **errp); -extern char *qcrypto_secret_lookup_as_base64(const char *secretid, - Error **errp); - #endif /* QCRYPTO_SECRET_H */ diff --git a/include/crypto/secret_common.h b/include/crypto/secret_common.h new file mode 100644 index 0000000000..980c02ab71 --- /dev/null +++ b/include/crypto/secret_common.h @@ -0,0 +1,68 @@ +/* + * QEMU crypto secret support + * + * Copyright (c) 2015 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.1 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 QCRYPTO_SECRET_COMMON_H +#define QCRYPTO_SECRET_COMMON_H + +#include "qapi/qapi-types-crypto.h" +#include "qom/object.h" + +#define TYPE_QCRYPTO_SECRET_COMMON "secret_common" +#define QCRYPTO_SECRET_COMMON(obj) \ + OBJECT_CHECK(QCryptoSecretCommon, (obj), TYPE_QCRYPTO_SECRET_COMMON) +#define QCRYPTO_SECRET_COMMON_CLASS(class) \ + OBJECT_CLASS_CHECK(QCryptoSecretCommonClass, \ + (class), TYPE_QCRYPTO_SECRET_COMMON) +#define QCRYPTO_SECRET_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(QCryptoSecretCommonClass, \ + (obj), TYPE_QCRYPTO_SECRET_COMMON) + +typedef struct QCryptoSecretCommon QCryptoSecretCommon; +typedef struct QCryptoSecretCommonClass QCryptoSecretCommonClass; + +struct QCryptoSecretCommon { + Object parent_obj; + uint8_t *rawdata; + size_t rawlen; + QCryptoSecretFormat format; + char *keyid; + char *iv; +}; + + +struct QCryptoSecretCommonClass { + ObjectClass parent_class; + void (*load_data)(QCryptoSecretCommon *secret, + uint8_t **output, + size_t *outputlen, + Error **errp); +}; + + +extern int qcrypto_secret_lookup(const char *secretid, + uint8_t **data, + size_t *datalen, + Error **errp); +extern char *qcrypto_secret_lookup_as_utf8(const char *secretid, + Error **errp); +extern char *qcrypto_secret_lookup_as_base64(const char *secretid, + Error **errp); + +#endif /* QCRYPTO_SECRET_COMMON_H */ diff --git a/include/crypto/secret_keyring.h b/include/crypto/secret_keyring.h new file mode 100644 index 0000000000..9f371ad251 --- /dev/null +++ b/include/crypto/secret_keyring.h @@ -0,0 +1,52 @@ +/* + * QEMU crypto secret support + * + * Copyright 2020 Yandex N.V. + * + * 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.1 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 QCRYPTO_SECRET_KEYRING_H +#define QCRYPTO_SECRET_KEYRING_H + +#include "qapi/qapi-types-crypto.h" +#include "qom/object.h" +#include "crypto/secret_common.h" + +#define TYPE_QCRYPTO_SECRET_KEYRING "secret_keyring" +#define QCRYPTO_SECRET_KEYRING(obj) \ + OBJECT_CHECK(QCryptoSecretKeyring, (obj), \ + TYPE_QCRYPTO_SECRET_KEYRING) +#define QCRYPTO_SECRET_KEYRING_CLASS(class) \ + OBJECT_CLASS_CHECK(QCryptoSecretKeyringClass, \ + (class), TYPE_QCRYPTO_SECRET_KEYRING) +#define QCRYPTO_SECRET_KEYRING_GET_CLASS(class) \ + OBJECT_GET_CLASS(QCryptoSecretKeyringClass, \ + (class), TYPE_QCRYPTO_SECRET_KEYRING) + +typedef struct QCryptoSecretKeyring QCryptoSecretKeyring; +typedef struct QCryptoSecretKeyringClass QCryptoSecretKeyringClass; + +typedef struct QCryptoSecretKeyring { + QCryptoSecretCommon parent; + int32_t serial; +} QCryptoSecretKeyring; + + +typedef struct QCryptoSecretKeyringClass { + QCryptoSecretCommonClass parent; +} QCryptoSecretKeyringClass; + +#endif /* QCRYPTO_SECRET_KEYRING_H */ diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 0000000000..1e430edd65 --- /dev/null +++ b/po/sv.po @@ -0,0 +1,75 @@ +# Swedish translation of qemu po-file. +# This file is put in the public domain. +# Sebastian Rasmussen <sebras@gmail.com>, 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: QEMU 2.12.91\n" +"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" +"POT-Creation-Date: 2018-07-18 07:56+0200\n" +"PO-Revision-Date: 2019-08-16 21:19+0200\n" +"Last-Translator: Sebastian Rasmussen <sebras@gmail.com>\n" +"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.2.3\n" + +msgid " - Press Ctrl+Alt+G to release grab" +msgstr " - Tryck Ctrl+Alt+G för att sluta fånga" + +msgid " [Paused]" +msgstr " [Pausad]" + +msgid "_Pause" +msgstr "_Paus" + +msgid "_Reset" +msgstr "_Starta om" + +msgid "Power _Down" +msgstr "Stäng _ner" + +msgid "_Quit" +msgstr "_Avsluta" + +msgid "_Fullscreen" +msgstr "_Helskärm" + +msgid "_Copy" +msgstr "_Kopiera" + +msgid "Zoom _In" +msgstr "Zooma _in" + +msgid "Zoom _Out" +msgstr "Zooma _ut" + +msgid "Best _Fit" +msgstr "Anpassad _storlek" + +msgid "Zoom To _Fit" +msgstr "Zooma ti_ll anpassad storlek" + +msgid "Grab On _Hover" +msgstr "Fånga vi_d hovring" + +msgid "_Grab Input" +msgstr "Fån_ga inmatning" + +msgid "Show _Tabs" +msgstr "Visa _flika" + +msgid "Detach Tab" +msgstr "Frigör flik" + +msgid "Show Menubar" +msgstr "Visa menyrad" + +msgid "_Machine" +msgstr "_Maskin" + +msgid "_View" +msgstr "_Visa" diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh new file mode 100755 index 0000000000..f5cee3d67e --- /dev/null +++ b/scripts/oss-fuzz/build.sh @@ -0,0 +1,105 @@ +#!/bin/sh -e +# +# OSS-Fuzz build script. See: +# https://google.github.io/oss-fuzz/getting-started/new-project-guide/#buildsh +# +# The file is consumed by: +# https://github.com/google/oss-fuzz/blob/master/projects/qemu/Dockerfiles +# +# This code is licensed under the GPL version 2 or later. See +# the COPYING file in the top-level directory. +# + +# build project +# e.g. +# ./autogen.sh +# ./configure +# make -j$(nproc) all + +# build fuzzers +# e.g. +# $CXX $CXXFLAGS -std=c++11 -Iinclude \ +# /path/to/name_of_fuzzer.cc -o $OUT/name_of_fuzzer \ +# $LIB_FUZZING_ENGINE /path/to/library.a + +fatal () { + echo "Error : ${*}, exiting." + exit 1 +} + +OSS_FUZZ_BUILD_DIR="./build-oss-fuzz/" + +# There seems to be a bug in clang-11 (used for builds on oss-fuzz) : +# accel/tcg/cputlb.o: In function `load_memop': +# accel/tcg/cputlb.c:1505: undefined reference to `qemu_build_not_reached' +# +# When building with optimization, the compiler is expected to prove that the +# statement cannot be reached, and remove it. For some reason clang-11 doesn't +# remove it, resulting in an unresolved reference to qemu_build_not_reached +# Undefine the __OPTIMIZE__ macro which compiler.h relies on to choose whether +# to " #define qemu_build_not_reached() g_assert_not_reached() " +EXTRA_CFLAGS="$CFLAGS -U __OPTIMIZE__" + +if ! { [ -e "./COPYING" ] && + [ -e "./MAINTAINERS" ] && + [ -e "./Makefile" ] && + [ -e "./docs" ] && + [ -e "./VERSION" ] && + [ -e "./linux-user" ] && + [ -e "./softmmu" ];} ; then + fatal "Please run the script from the top of the QEMU tree" +fi + +mkdir -p $OSS_FUZZ_BUILD_DIR || fatal "mkdir $OSS_FUZZ_BUILD_DIR failed" +cd $OSS_FUZZ_BUILD_DIR || fatal "cd $OSS_FUZZ_BUILD_DIR failed" + + +if [ -z ${LIB_FUZZING_ENGINE+x} ]; then + LIB_FUZZING_ENGINE="-fsanitize=fuzzer" +fi + +if [ -z ${OUT+x} ]; then + DEST_DIR=$(realpath "./DEST_DIR") +else + DEST_DIR=$OUT +fi + +mkdir -p "$DEST_DIR/lib/" # Copy the shared libraries here + +# Build once to get the list of dynamic lib paths, and copy them over +../configure --disable-werror --cc="$CC" --cxx="$CXX" \ + --extra-cflags="$EXTRA_CFLAGS" + +if ! make CONFIG_FUZZ=y CFLAGS="$LIB_FUZZING_ENGINE" "-j$(nproc)" \ + i386-softmmu/fuzz; then + fatal "Build failed. Please specify a compiler with fuzzing support"\ + "using the \$CC and \$CXX environemnt variables, or specify a"\ + "\$LIB_FUZZING_ENGINE compatible with your compiler"\ + "\nFor example: CC=clang CXX=clang++ $0" +fi + +for i in $(ldd ./i386-softmmu/qemu-fuzz-i386 | cut -f3 -d' '); do + cp "$i" "$DEST_DIR/lib/" +done +rm ./i386-softmmu/qemu-fuzz-i386 + +# Build a second time to build the final binary with correct rpath +../configure --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" --disable-werror \ + --cc="$CC" --cxx="$CXX" --extra-cflags="$EXTRA_CFLAGS" \ + --extra-ldflags="-Wl,-rpath,'\$\$ORIGIN/lib'" +make CONFIG_FUZZ=y CFLAGS="$LIB_FUZZING_ENGINE" "-j$(nproc)" i386-softmmu/fuzz + +# Copy over the datadir +cp -r ../pc-bios/ "$DEST_DIR/pc-bios" + +# Run the fuzzer with no arguments, to print the help-string and get the list +# of available fuzz-targets. Copy over the qemu-fuzz-i386, naming it according +# to each available fuzz target (See 05509c8e6d fuzz: select fuzz target using +# executable name) +for target in $(./i386-softmmu/qemu-fuzz-i386 | awk '$1 ~ /\*/ {print $2}'); +do + cp ./i386-softmmu/qemu-fuzz-i386 "$DEST_DIR/qemu-fuzz-i386-target-$target" +done + +echo "Done. The fuzzers are located in $DEST_DIR" +exit 0 diff --git a/target/mips/helper.h b/target/mips/helper.h index 84fdd9fd27..e97655dc0e 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -950,6 +950,21 @@ DEF_HELPER_4(msa_mod_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_mod_s_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_mod_s_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_maddv_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_maddv_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_maddv_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_maddv_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_msubv_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_msubv_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_msubv_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_msubv_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_mulv_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mulv_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mulv_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mulv_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_asub_s_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_asub_s_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_asub_s_w, void, env, i32, i32, i32) @@ -968,6 +983,31 @@ DEF_HELPER_4(msa_hsub_u_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_hsub_u_w, void, env, i32, i32, i32) DEF_HELPER_4(msa_hsub_u_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_s_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_subs_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subs_u_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_subsus_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsus_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsus_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsus_u_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_subsuu_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsuu_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsuu_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subsuu_s_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_subv_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subv_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subv_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_subv_d, void, env, i32, i32, i32) + DEF_HELPER_4(msa_ilvev_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_h, void, env, i32, i32, i32) DEF_HELPER_4(msa_ilvev_w, void, env, i32, i32, i32) @@ -1063,20 +1103,25 @@ DEF_HELPER_5(msa_srlri_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_binsl_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_binsr_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_subv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_subs_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_subs_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_subsus_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_maddv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_msubv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_dotp_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_dpadd_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_dpadd_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_dpsub_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32) + +DEF_HELPER_4(msa_dotp_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_s_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dotp_u_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_s_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpadd_u_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_s_d, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_dpsub_u_d, void, env, i32, i32, i32) DEF_HELPER_5(msa_sld_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_splat_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_vshf_df, void, env, i32, i32, i32, i32) diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h index 0c129106c8..ed6a7a9e54 100644 --- a/target/mips/mips-defs.h +++ b/target/mips/mips-defs.h @@ -57,9 +57,13 @@ /* * bits 52-63: vendor-specific ASEs */ +/* MultiMedia Instructions defined by R5900 */ #define ASE_MMI 0x0010000000000000ULL +/* MIPS eXtension/enhanced Unit defined by Ingenic */ #define ASE_MXU 0x0020000000000000ULL +/* Loongson MultiMedia Instructions */ #define ASE_LMMI 0x0040000000000000ULL +/* Loongson EXTensions */ #define ASE_LEXT 0x0080000000000000ULL /* MIPS CPU defines. */ @@ -70,7 +74,7 @@ #define CPU_VR54XX (CPU_MIPS4 | INSN_VR54XX) #define CPU_R5900 (CPU_MIPS3 | INSN_R5900) #define CPU_LOONGSON2E (CPU_MIPS3 | INSN_LOONGSON2E) -#define CPU_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F) +#define CPU_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F | ASE_LMMI) #define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5) @@ -97,7 +101,7 @@ /* Wave Computing: "nanoMIPS" */ #define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32) -#define CPU_LOONGSON3A (CPU_MIPS64R2 | INSN_LOONGSON3A) +#define CPU_LOONGSON3A (CPU_MIPS64R2 | INSN_LOONGSON3A | ASE_LMMI | ASE_LEXT) /* * Strictly follow the architecture standard: diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index c3b271934a..6865addaf6 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -2224,7 +2224,339 @@ void helper_msa_div_u_d(CPUMIPSState *env, * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Int Dot Product group helpers here */ +#define SIGNED_EXTRACT(e, o, a, df) \ + do { \ + e = SIGNED_EVEN(a, df); \ + o = SIGNED_ODD(a, df); \ + } while (0) + +#define UNSIGNED_EXTRACT(e, o, a, df) \ + do { \ + e = UNSIGNED_EVEN(a, df); \ + o = UNSIGNED_ODD(a, df); \ + } while (0) + + +static inline int64_t msa_dotp_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +void helper_msa_dotp_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_dotp_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dotp_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dotp_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dotp_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dotp_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dotp_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dotp_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dotp_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_dotp_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_dotp_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dotp_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dotp_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dotp_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_dotp_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_dotp_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dotp_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_dotp_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +void helper_msa_dotp_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_dotp_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dotp_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dotp_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dotp_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dotp_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dotp_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dotp_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dotp_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_dotp_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_dotp_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dotp_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dotp_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dotp_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_dotp_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_dotp_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dotp_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +void helper_msa_dpadd_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_dpadd_s_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dpadd_s_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dpadd_s_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dpadd_s_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dpadd_s_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dpadd_s_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dpadd_s_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dpadd_s_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_dpadd_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_dpadd_s_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dpadd_s_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dpadd_s_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dpadd_s_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_dpadd_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_dpadd_s_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dpadd_s_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_dpadd_u_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +void helper_msa_dpadd_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_dpadd_u_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dpadd_u_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dpadd_u_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dpadd_u_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dpadd_u_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dpadd_u_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dpadd_u_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dpadd_u_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_dpadd_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_dpadd_u_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dpadd_u_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dpadd_u_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dpadd_u_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_dpadd_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_dpadd_u_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dpadd_u_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_dpsub_s_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); +} + +void helper_msa_dpsub_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_dpsub_s_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dpsub_s_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dpsub_s_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dpsub_s_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dpsub_s_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dpsub_s_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dpsub_s_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dpsub_s_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_dpsub_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_dpsub_s_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dpsub_s_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dpsub_s_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dpsub_s_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_dpsub_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_dpsub_s_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dpsub_s_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); +} + +void helper_msa_dpsub_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_dpsub_u_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_dpsub_u_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_dpsub_u_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_dpsub_u_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_dpsub_u_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_dpsub_u_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_dpsub_u_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_dpsub_u_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_dpsub_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_dpsub_u_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_dpsub_u_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_dpsub_u_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_dpsub_u_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_dpsub_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_dpsub_u_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_dpsub_u_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} /* @@ -2883,7 +3215,221 @@ void helper_msa_mod_u_d(CPUMIPSState *env, * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Int Multiply group helpers here */ +static inline int64_t msa_maddv_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + return dest + arg1 * arg2; +} + +void helper_msa_maddv_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_maddv_df(DF_BYTE, pwt->b[0], pws->b[0], pwt->b[0]); + pwd->b[1] = msa_maddv_df(DF_BYTE, pwt->b[1], pws->b[1], pwt->b[1]); + pwd->b[2] = msa_maddv_df(DF_BYTE, pwt->b[2], pws->b[2], pwt->b[2]); + pwd->b[3] = msa_maddv_df(DF_BYTE, pwt->b[3], pws->b[3], pwt->b[3]); + pwd->b[4] = msa_maddv_df(DF_BYTE, pwt->b[4], pws->b[4], pwt->b[4]); + pwd->b[5] = msa_maddv_df(DF_BYTE, pwt->b[5], pws->b[5], pwt->b[5]); + pwd->b[6] = msa_maddv_df(DF_BYTE, pwt->b[6], pws->b[6], pwt->b[6]); + pwd->b[7] = msa_maddv_df(DF_BYTE, pwt->b[7], pws->b[7], pwt->b[7]); + pwd->b[8] = msa_maddv_df(DF_BYTE, pwt->b[8], pws->b[8], pwt->b[8]); + pwd->b[9] = msa_maddv_df(DF_BYTE, pwt->b[9], pws->b[9], pwt->b[9]); + pwd->b[10] = msa_maddv_df(DF_BYTE, pwt->b[10], pws->b[10], pwt->b[10]); + pwd->b[11] = msa_maddv_df(DF_BYTE, pwt->b[11], pws->b[11], pwt->b[11]); + pwd->b[12] = msa_maddv_df(DF_BYTE, pwt->b[12], pws->b[12], pwt->b[12]); + pwd->b[13] = msa_maddv_df(DF_BYTE, pwt->b[13], pws->b[13], pwt->b[13]); + pwd->b[14] = msa_maddv_df(DF_BYTE, pwt->b[14], pws->b[14], pwt->b[14]); + pwd->b[15] = msa_maddv_df(DF_BYTE, pwt->b[15], pws->b[15], pwt->b[15]); +} + +void helper_msa_maddv_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_maddv_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_maddv_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_maddv_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_maddv_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_maddv_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_maddv_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_maddv_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_maddv_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_maddv_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_maddv_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_maddv_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_maddv_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_maddv_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_maddv_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_maddv_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_maddv_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_msubv_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + return dest - arg1 * arg2; +} + +void helper_msa_msubv_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_msubv_df(DF_BYTE, pwt->b[0], pws->b[0], pwt->b[0]); + pwd->b[1] = msa_msubv_df(DF_BYTE, pwt->b[1], pws->b[1], pwt->b[1]); + pwd->b[2] = msa_msubv_df(DF_BYTE, pwt->b[2], pws->b[2], pwt->b[2]); + pwd->b[3] = msa_msubv_df(DF_BYTE, pwt->b[3], pws->b[3], pwt->b[3]); + pwd->b[4] = msa_msubv_df(DF_BYTE, pwt->b[4], pws->b[4], pwt->b[4]); + pwd->b[5] = msa_msubv_df(DF_BYTE, pwt->b[5], pws->b[5], pwt->b[5]); + pwd->b[6] = msa_msubv_df(DF_BYTE, pwt->b[6], pws->b[6], pwt->b[6]); + pwd->b[7] = msa_msubv_df(DF_BYTE, pwt->b[7], pws->b[7], pwt->b[7]); + pwd->b[8] = msa_msubv_df(DF_BYTE, pwt->b[8], pws->b[8], pwt->b[8]); + pwd->b[9] = msa_msubv_df(DF_BYTE, pwt->b[9], pws->b[9], pwt->b[9]); + pwd->b[10] = msa_msubv_df(DF_BYTE, pwt->b[10], pws->b[10], pwt->b[10]); + pwd->b[11] = msa_msubv_df(DF_BYTE, pwt->b[11], pws->b[11], pwt->b[11]); + pwd->b[12] = msa_msubv_df(DF_BYTE, pwt->b[12], pws->b[12], pwt->b[12]); + pwd->b[13] = msa_msubv_df(DF_BYTE, pwt->b[13], pws->b[13], pwt->b[13]); + pwd->b[14] = msa_msubv_df(DF_BYTE, pwt->b[14], pws->b[14], pwt->b[14]); + pwd->b[15] = msa_msubv_df(DF_BYTE, pwt->b[15], pws->b[15], pwt->b[15]); +} + +void helper_msa_msubv_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_msubv_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_msubv_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_msubv_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_msubv_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_msubv_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_msubv_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_msubv_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_msubv_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_msubv_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_msubv_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_msubv_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_msubv_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_msubv_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_msubv_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_msubv_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_msubv_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 * arg2; +} + +void helper_msa_mulv_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_mulv_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_mulv_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_mulv_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_mulv_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_mulv_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_mulv_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_mulv_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_mulv_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_mulv_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_mulv_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_mulv_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_mulv_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_mulv_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_mulv_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_mulv_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_mulv_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_mulv_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_mulv_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_mulv_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_mulv_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_mulv_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_mulv_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_mulv_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_mulv_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_mulv_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_mulv_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_mulv_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_mulv_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_mulv_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_mulv_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_mulv_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_mulv_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_mulv_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} /* @@ -3079,9 +3625,6 @@ void helper_msa_asub_u_d(CPUMIPSState *env, } -/* TODO: insert the rest of Int Subtract group helpers here */ - - static inline int64_t msa_hsub_s_df(uint32_t df, int64_t arg1, int64_t arg2) { return SIGNED_ODD(arg1, df) - SIGNED_EVEN(arg2, df); @@ -3176,6 +3719,398 @@ void helper_msa_hsub_u_d(CPUMIPSState *env, } +static inline int64_t msa_subs_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t max_int = DF_MAX_INT(df); + int64_t min_int = DF_MIN_INT(df); + if (arg2 > 0) { + return (min_int + arg2 < arg1) ? arg1 - arg2 : min_int; + } else { + return (arg1 < max_int + arg2) ? arg1 - arg2 : max_int; + } +} + +void helper_msa_subs_s_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_subs_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subs_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subs_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subs_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subs_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subs_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subs_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subs_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subs_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subs_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subs_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subs_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subs_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subs_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subs_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subs_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subs_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_subs_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subs_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subs_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subs_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subs_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subs_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subs_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subs_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subs_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_subs_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subs_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subs_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subs_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subs_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_subs_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subs_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_subs_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return (u_arg1 > u_arg2) ? u_arg1 - u_arg2 : 0; +} + +void helper_msa_subs_u_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_subs_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subs_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subs_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subs_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subs_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subs_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subs_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subs_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subs_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subs_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subs_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subs_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subs_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subs_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subs_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subs_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subs_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_subs_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subs_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subs_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subs_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subs_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subs_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subs_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subs_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subs_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_subs_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subs_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subs_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subs_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subs_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_subs_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subs_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_subsus_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t max_uint = DF_MAX_UINT(df); + if (arg2 >= 0) { + uint64_t u_arg2 = (uint64_t)arg2; + return (u_arg1 > u_arg2) ? + (int64_t)(u_arg1 - u_arg2) : + 0; + } else { + uint64_t u_arg2 = (uint64_t)(-arg2); + return (u_arg1 < max_uint - u_arg2) ? + (int64_t)(u_arg1 + u_arg2) : + (int64_t)max_uint; + } +} + +void helper_msa_subsus_u_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_subsus_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subsus_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subsus_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subsus_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subsus_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subsus_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subsus_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subsus_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subsus_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subsus_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subsus_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subsus_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subsus_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subsus_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subsus_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subsus_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subsus_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_subsus_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subsus_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subsus_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subsus_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subsus_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subsus_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subsus_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subsus_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subsus_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_subsus_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subsus_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subsus_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subsus_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subsus_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_subsus_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subsus_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_subsuu_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + int64_t max_int = DF_MAX_INT(df); + int64_t min_int = DF_MIN_INT(df); + if (u_arg1 > u_arg2) { + return u_arg1 - u_arg2 < (uint64_t)max_int ? + (int64_t)(u_arg1 - u_arg2) : + max_int; + } else { + return u_arg2 - u_arg1 < (uint64_t)(-min_int) ? + (int64_t)(u_arg1 - u_arg2) : + min_int; + } +} + +void helper_msa_subsuu_s_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_subsuu_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subsuu_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subsuu_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subsuu_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subsuu_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subsuu_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subsuu_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subsuu_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subsuu_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subsuu_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subsuu_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subsuu_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subsuu_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subsuu_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subsuu_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subsuu_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subsuu_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_subsuu_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subsuu_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subsuu_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subsuu_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subsuu_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subsuu_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subsuu_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subsuu_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subsuu_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_subsuu_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subsuu_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subsuu_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subsuu_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subsuu_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_subsuu_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subsuu_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + +static inline int64_t msa_subv_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 - arg2; +} + +void helper_msa_subv_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_subv_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_subv_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_subv_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_subv_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_subv_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_subv_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_subv_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_subv_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_subv_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_subv_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_subv_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_subv_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_subv_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_subv_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_subv_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_subv_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_subv_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_subv_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_subv_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_subv_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_subv_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_subv_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_subv_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_subv_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_subv_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_subv_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_subv_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_subv_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_subv_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_subv_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_subv_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_subv_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_subv_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + + /* * Interleave * ---------- @@ -4400,11 +5335,6 @@ void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } -static inline int64_t msa_subv_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - return arg1 - arg2; -} - #define MSA_BINOP_IMM_DF(helper, func) \ void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, \ uint32_t wd, uint32_t ws, int32_t u5) \ @@ -4586,97 +5516,6 @@ MSA_TEROP_IMMU_DF(binsli, binsl) MSA_TEROP_IMMU_DF(binsri, binsr) #undef MSA_TEROP_IMMU_DF -static inline int64_t msa_subs_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - int64_t max_int = DF_MAX_INT(df); - int64_t min_int = DF_MIN_INT(df); - if (arg2 > 0) { - return (min_int + arg2 < arg1) ? arg1 - arg2 : min_int; - } else { - return (arg1 < max_int + arg2) ? arg1 - arg2 : max_int; - } -} - -static inline int64_t msa_subs_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - return (u_arg1 > u_arg2) ? u_arg1 - u_arg2 : 0; -} - -static inline int64_t msa_subsus_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t max_uint = DF_MAX_UINT(df); - if (arg2 >= 0) { - uint64_t u_arg2 = (uint64_t)arg2; - return (u_arg1 > u_arg2) ? - (int64_t)(u_arg1 - u_arg2) : - 0; - } else { - uint64_t u_arg2 = (uint64_t)(-arg2); - return (u_arg1 < max_uint - u_arg2) ? - (int64_t)(u_arg1 + u_arg2) : - (int64_t)max_uint; - } -} - -static inline int64_t msa_subsuu_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - int64_t max_int = DF_MAX_INT(df); - int64_t min_int = DF_MIN_INT(df); - if (u_arg1 > u_arg2) { - return u_arg1 - u_arg2 < (uint64_t)max_int ? - (int64_t)(u_arg1 - u_arg2) : - max_int; - } else { - return u_arg2 - u_arg1 < (uint64_t)(-min_int) ? - (int64_t)(u_arg1 - u_arg2) : - min_int; - } -} - -static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - return arg1 * arg2; -} - -#define SIGNED_EXTRACT(e, o, a, df) \ - do { \ - e = SIGNED_EVEN(a, df); \ - o = SIGNED_ODD(a, df); \ - } while (0) - -#define UNSIGNED_EXTRACT(e, o, a, df) \ - do { \ - e = UNSIGNED_EVEN(a, df); \ - o = UNSIGNED_ODD(a, df); \ - } while (0) - -static inline int64_t msa_dotp_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); -} - -static inline int64_t msa_dotp_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); -} - #define CONCATENATE_AND_SLIDE(s, k) \ do { \ for (i = 0; i < s; i++) { \ @@ -4794,15 +5633,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ } \ } -MSA_BINOP_DF(subv) -MSA_BINOP_DF(subs_s) -MSA_BINOP_DF(subs_u) -MSA_BINOP_DF(subsus_u) -MSA_BINOP_DF(subsuu_s) -MSA_BINOP_DF(mulv) -MSA_BINOP_DF(dotp_s) -MSA_BINOP_DF(dotp_u) - MSA_BINOP_DF(mul_q) MSA_BINOP_DF(mulr_q) #undef MSA_BINOP_DF @@ -4816,66 +5646,6 @@ void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); } -static inline int64_t msa_maddv_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - return dest + arg1 * arg2; -} - -static inline int64_t msa_msubv_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - return dest - arg1 * arg2; -} - -static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); -} - -static inline int64_t msa_dpadd_u_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); -} - -static inline int64_t msa_dpsub_s_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); -} - -static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - int64_t even_arg1; - int64_t even_arg2; - int64_t odd_arg1; - int64_t odd_arg2; - UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); - UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); - return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); -} - static inline int64_t msa_madd_q_df(uint32_t df, int64_t dest, int64_t arg1, int64_t arg2) { @@ -5002,12 +5772,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ } \ } -MSA_TEROP_DF(maddv) -MSA_TEROP_DF(msubv) -MSA_TEROP_DF(dpadd_s) -MSA_TEROP_DF(dpadd_u) -MSA_TEROP_DF(dpsub_s) -MSA_TEROP_DF(dpsub_u) MSA_TEROP_DF(binsl) MSA_TEROP_DF(binsr) MSA_TEROP_DF(madd_q) diff --git a/target/mips/translate.c b/target/mips/translate.c index 2caf4cba5a..9fad58ea2c 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -1046,7 +1046,7 @@ enum { OPC_BC2NEZ = (0x0D << 21) | OPC_CP2, }; -#define MASK_LMI(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F)) +#define MASK_LMMI(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F)) enum { OPC_PADDSH = (24 << 21) | (0x00) | OPC_CP2, @@ -3421,7 +3421,8 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, TCGv t0, t1, t2; int mem_idx = ctx->mem_idx; - if (rt == 0 && ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) { + if (rt == 0 && ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F | + INSN_LOONGSON3A)) { /* * Loongson CPU uses a load to zero register for prefetch. * We emulate it as a NOP. On other CPU we must perform the @@ -5531,7 +5532,7 @@ static void gen_loongson_multimedia(DisasContext *ctx, int rd, int rs, int rt) TCGv_i64 t0, t1; TCGCond cond; - opc = MASK_LMI(ctx->opcode); + opc = MASK_LMMI(ctx->opcode); switch (opc) { case OPC_ADD_CP2: case OPC_SUB_CP2: @@ -27161,7 +27162,7 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) case OPC_MULTU_G_2F: case OPC_MOD_G_2F: case OPC_MODU_G_2F: - check_insn(ctx, INSN_LOONGSON2F); + check_insn(ctx, INSN_LOONGSON2F | ASE_LEXT); gen_loongson_integer(ctx, op1, rd, rs, rt); break; case OPC_CLO: @@ -27194,7 +27195,7 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) case OPC_DDIVU_G_2F: case OPC_DMOD_G_2F: case OPC_DMODU_G_2F: - check_insn(ctx, INSN_LOONGSON2F); + check_insn(ctx, INSN_LOONGSON2F | ASE_LEXT); gen_loongson_integer(ctx, op1, rd, rs, rt); break; #endif @@ -29057,6 +29058,38 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) break; } break; + case OPC_MADDV_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_maddv_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_maddv_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_maddv_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_maddv_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_MSUBV_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_msubv_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_msubv_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_msubv_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_msubv_d(cpu_env, twd, tws, twt); + break; + } + break; case OPC_ASUB_S_df: switch (df) { case DF_BYTE: @@ -29266,10 +29299,36 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_SUBS_S_df: - gen_helper_msa_subs_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subs_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subs_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subs_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subs_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_MULV_df: - gen_helper_msa_mulv_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_mulv_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_mulv_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_mulv_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_mulv_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_SLD_df: gen_helper_msa_sld_df(cpu_env, tdf, twd, tws, twt); @@ -29278,25 +29337,71 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) gen_helper_msa_vshf_df(cpu_env, tdf, twd, tws, twt); break; case OPC_SUBV_df: - gen_helper_msa_subv_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subv_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subv_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subv_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subv_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_SUBS_U_df: - gen_helper_msa_subs_u_df(cpu_env, tdf, twd, tws, twt); - break; - case OPC_MADDV_df: - gen_helper_msa_maddv_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subs_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subs_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subs_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subs_u_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_SPLAT_df: gen_helper_msa_splat_df(cpu_env, tdf, twd, tws, twt); break; case OPC_SUBSUS_U_df: - gen_helper_msa_subsus_u_df(cpu_env, tdf, twd, tws, twt); - break; - case OPC_MSUBV_df: - gen_helper_msa_msubv_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subsus_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subsus_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subsus_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subsus_u_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_SUBSUU_S_df: - gen_helper_msa_subsuu_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_BYTE: + gen_helper_msa_subsuu_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_subsuu_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_subsuu_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_subsuu_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DOTP_S_df: @@ -29367,22 +29472,82 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_DOTP_S_df: - gen_helper_msa_dotp_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dotp_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dotp_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dotp_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DOTP_U_df: - gen_helper_msa_dotp_u_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dotp_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dotp_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dotp_u_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DPADD_S_df: - gen_helper_msa_dpadd_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dpadd_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dpadd_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dpadd_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DPADD_U_df: - gen_helper_msa_dpadd_u_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dpadd_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dpadd_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dpadd_u_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DPSUB_S_df: - gen_helper_msa_dpsub_s_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dpsub_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dpsub_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dpsub_s_d(cpu_env, twd, tws, twt); + break; + } break; case OPC_DPSUB_U_df: - gen_helper_msa_dpsub_u_df(cpu_env, tdf, twd, tws, twt); + switch (df) { + case DF_HALF: + gen_helper_msa_dpsub_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_dpsub_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_dpsub_u_d(cpu_env, twd, tws, twt); + break; + } break; } break; @@ -30641,7 +30806,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_CP2: - check_insn(ctx, INSN_LOONGSON2F); + check_insn(ctx, ASE_LMMI); /* Note that these instructions use different fields. */ gen_loongson_multimedia(ctx, sa, rd, rt); break; diff --git a/tests/Makefile.include b/tests/Makefile.include index c2397de8ed..5607c7290d 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -540,6 +540,10 @@ tests/benchmark-crypto-cipher$(EXESUF): tests/benchmark-crypto-cipher.o $(test-c tests/test-crypto-secret$(EXESUF): tests/test-crypto-secret.o $(test-crypto-obj-y) tests/test-crypto-xts$(EXESUF): tests/test-crypto-xts.o $(test-crypto-obj-y) +ifeq ($(CONFIG_TEST_SECRET_KEYRING),y) +tests/test-crypto-secret.o-libs := -lkeyutils +endif + tests/crypto-tls-x509-helpers.o-cflags := $(TASN1_CFLAGS) tests/crypto-tls-x509-helpers.o-libs := $(TASN1_LIBS) tests/pkix_asn1_tab.o-cflags := $(TASN1_CFLAGS) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 3f3aa0c854..3d02519660 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -858,12 +858,12 @@ class BootLinuxConsole(LinuxKernelTest): console_pattern = 'No filesystem could mount root' self.wait_for_console_pattern(console_pattern) - def do_test_advcal_2018(self, day, tar_hash, kernel_name): + def do_test_advcal_2018(self, day, tar_hash, kernel_name, console=0): tar_url = ('https://www.qemu-advent-calendar.org' '/2018/download/day' + day + '.tar.xz') file_path = self.fetch_asset(tar_url, asset_hash=tar_hash) archive.extract(file_path, self.workdir) - self.vm.set_console() + self.vm.set_console(console_index=console) self.vm.add_args('-kernel', self.workdir + '/day' + day + '/' + kernel_name) self.vm.launch() @@ -937,6 +937,15 @@ class BootLinuxConsole(LinuxKernelTest): self.vm.add_args('-M', 'graphics=off') self.do_test_advcal_2018('15', tar_hash, 'invaders.elf') + def test_sh4_r2d(self): + """ + :avocado: tags=arch:sh4 + :avocado: tags=machine:r2d + """ + tar_hash = 'fe06a4fd8ccbf2e27928d64472939d47829d4c7e' + self.vm.add_args('-append', 'console=ttySC1') + self.do_test_advcal_2018('09', tar_hash, 'zImage', console=1) + def test_sparc_ss20(self): """ :avocado: tags=arch:sparc diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 53f104a9c5..b482f76c03 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -882,6 +882,7 @@ uint64_t tpm_tis_base_addr; static void test_acpi_tcg_tpm(const char *machine, const char *tpm_if, uint64_t base) { +#ifdef CONFIG_TPM gchar *tmp_dir_name = g_strdup_printf("qemu-test_acpi_%s_tcg_%s.XXXXXX", machine, tpm_if); char *tmp_path = g_dir_make_tmp(tmp_dir_name, NULL); @@ -924,6 +925,9 @@ static void test_acpi_tcg_tpm(const char *machine, const char *tpm_if, g_free(tmp_path); g_free(tmp_dir_name); free_test_data(&data); +#else + g_test_skip("TPM disabled"); +#endif } static void test_acpi_q35_tcg_tpm_tis(void) diff --git a/tests/qtest/e1000e-test.c b/tests/qtest/e1000e-test.c index 1a232a663a..fc226fdfeb 100644 --- a/tests/qtest/e1000e-test.c +++ b/tests/qtest/e1000e-test.c @@ -12,7 +12,7 @@ * 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. + * version 2.1 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 diff --git a/tests/qtest/fuzz/Makefile.include b/tests/qtest/fuzz/Makefile.include index f259d866c9..5bde793bf2 100644 --- a/tests/qtest/fuzz/Makefile.include +++ b/tests/qtest/fuzz/Makefile.include @@ -5,6 +5,7 @@ fuzz-obj-y += $(libqos-obj-y) fuzz-obj-y += tests/qtest/fuzz/fuzz.o # Fuzzer skeleton fuzz-obj-y += tests/qtest/fuzz/fork_fuzz.o fuzz-obj-y += tests/qtest/fuzz/qos_fuzz.o +fuzz-obj-y += tests/qtest/fuzz/qtest_wrappers.o # Targets fuzz-obj-$(CONFIG_PCI_I440FX) += tests/qtest/fuzz/i440fx_fuzz.o @@ -16,3 +17,23 @@ FUZZ_CFLAGS += -I$(SRC_PATH)/tests -I$(SRC_PATH)/tests/qtest # Linker Script to force coverage-counters into known regions which we can mark # shared FUZZ_LDFLAGS += -Xlinker -T$(SRC_PATH)/tests/qtest/fuzz/fork_fuzz.ld + +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readq +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writeb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writew +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writel +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writeq +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memread +FUZZ_LDFLAGS += -Wl,-wrap,qtest_bufread +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memwrite +FUZZ_LDFLAGS += -Wl,-wrap,qtest_bufwrite +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memset diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 33365c3782..a44fe479db 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -91,7 +91,12 @@ static void usage(char *path) printf(" * %s : %s\n", tmp->target->name, tmp->target->description); } - printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n"); + printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n\n" + "Set the environment variable FUZZ_SERIALIZE_QTEST=1 to serialize\n" + "QTest commands into an ASCII protocol. Useful for building crash\n" + "reproducers, but slows down execution.\n\n" + "Set the environment variable QTEST_LOG=1 to log all qtest commands" + "\n"); exit(0); } @@ -138,6 +143,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) char *target_name; char *dir; + bool serialize = false; /* Initialize qgraph and modules */ qos_graph_init(); @@ -172,6 +178,13 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) usage(**argv); } + /* Should we always serialize qtest commands? */ + if (getenv("FUZZ_SERIALIZE_QTEST")) { + serialize = true; + } + + fuzz_qtest_set_serialize(serialize); + /* Identify the fuzz target */ fuzz_target = fuzz_get_target(target_name); if (!fuzz_target) { @@ -186,6 +199,11 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) /* Run QEMU's softmmu main with the fuzz-target dependent arguments */ const char *init_cmdline = fuzz_target->get_init_cmdline(fuzz_target); + init_cmdline = g_strdup_printf("%s -qtest /dev/null -qtest-log %s", + init_cmdline, + getenv("QTEST_LOG") ? "/dev/fd/2" + : "/dev/null"); + /* Split the runcmd into an argv and argc */ wordexp_t result; diff --git a/tests/qtest/fuzz/fuzz.h b/tests/qtest/fuzz/fuzz.h index 03901d414e..72d5710f6c 100644 --- a/tests/qtest/fuzz/fuzz.h +++ b/tests/qtest/fuzz/fuzz.h @@ -82,6 +82,9 @@ typedef struct FuzzTarget { void flush_events(QTestState *); void reboot(QTestState *); +/* Use the QTest ASCII protocol or call address_space API directly?*/ +void fuzz_qtest_set_serialize(bool option); + /* * makes a copy of *target and adds it to the target-list. * i.e. fine to set up target on the caller's stack diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index 87eadb0889..0c68f5361f 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/fuzz/qtest_wrappers.c b/tests/qtest/fuzz/qtest_wrappers.c new file mode 100644 index 0000000000..713c830cdb --- /dev/null +++ b/tests/qtest/fuzz/qtest_wrappers.c @@ -0,0 +1,252 @@ +/* + * qtest function wrappers + * + * Copyright Red Hat Inc., 2019 + * + * Authors: + * Alexander Bulekov <alxndr@bu.edu> + * + * 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 "cpu.h" +#include "exec/ioport.h" + +#include "fuzz.h" + +static bool serialize = true; + +#define WRAP(RET_TYPE, NAME_AND_ARGS)\ + RET_TYPE __wrap_##NAME_AND_ARGS;\ + RET_TYPE __real_##NAME_AND_ARGS; + +WRAP(uint8_t , qtest_inb(QTestState *s, uint16_t addr)) +WRAP(uint16_t , qtest_inw(QTestState *s, uint16_t addr)) +WRAP(uint32_t , qtest_inl(QTestState *s, uint16_t addr)) +WRAP(void , qtest_outb(QTestState *s, uint16_t addr, uint8_t value)) +WRAP(void , qtest_outw(QTestState *s, uint16_t addr, uint16_t value)) +WRAP(void , qtest_outl(QTestState *s, uint16_t addr, uint32_t value)) +WRAP(uint8_t , qtest_readb(QTestState *s, uint64_t addr)) +WRAP(uint16_t , qtest_readw(QTestState *s, uint64_t addr)) +WRAP(uint32_t , qtest_readl(QTestState *s, uint64_t addr)) +WRAP(uint64_t , qtest_readq(QTestState *s, uint64_t addr)) +WRAP(void , qtest_writeb(QTestState *s, uint64_t addr, uint8_t value)) +WRAP(void , qtest_writew(QTestState *s, uint64_t addr, uint16_t value)) +WRAP(void , qtest_writel(QTestState *s, uint64_t addr, uint32_t value)) +WRAP(void , qtest_writeq(QTestState *s, uint64_t addr, uint64_t value)) +WRAP(void , qtest_memread(QTestState *s, uint64_t addr, + void *data, size_t size)) +WRAP(void , qtest_bufread(QTestState *s, uint64_t addr, void *data, + size_t size)) +WRAP(void , qtest_memwrite(QTestState *s, uint64_t addr, const void *data, + size_t size)) +WRAP(void, qtest_bufwrite(QTestState *s, uint64_t addr, + const void *data, size_t size)) +WRAP(void, qtest_memset(QTestState *s, uint64_t addr, + uint8_t patt, size_t size)) + + +uint8_t __wrap_qtest_inb(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inb(addr); + } else { + return __real_qtest_inb(s, addr); + } +} + +uint16_t __wrap_qtest_inw(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inw(addr); + } else { + return __real_qtest_inw(s, addr); + } +} + +uint32_t __wrap_qtest_inl(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inl(addr); + } else { + return __real_qtest_inl(s, addr); + } +} + +void __wrap_qtest_outb(QTestState *s, uint16_t addr, uint8_t value) +{ + if (!serialize) { + cpu_outb(addr, value); + } else { + __real_qtest_outb(s, addr, value); + } +} + +void __wrap_qtest_outw(QTestState *s, uint16_t addr, uint16_t value) +{ + if (!serialize) { + cpu_outw(addr, value); + } else { + __real_qtest_outw(s, addr, value); + } +} + +void __wrap_qtest_outl(QTestState *s, uint16_t addr, uint32_t value) +{ + if (!serialize) { + cpu_outl(addr, value); + } else { + __real_qtest_outl(s, addr, value); + } +} + +uint8_t __wrap_qtest_readb(QTestState *s, uint64_t addr) +{ + uint8_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 1); + return value; + } else { + return __real_qtest_readb(s, addr); + } +} + +uint16_t __wrap_qtest_readw(QTestState *s, uint64_t addr) +{ + uint16_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 2); + return value; + } else { + return __real_qtest_readw(s, addr); + } +} + +uint32_t __wrap_qtest_readl(QTestState *s, uint64_t addr) +{ + uint32_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 4); + return value; + } else { + return __real_qtest_readl(s, addr); + } +} + +uint64_t __wrap_qtest_readq(QTestState *s, uint64_t addr) +{ + uint64_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 8); + return value; + } else { + return __real_qtest_readq(s, addr); + } +} + +void __wrap_qtest_writeb(QTestState *s, uint64_t addr, uint8_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 1); + } else { + __real_qtest_writeb(s, addr, value); + } +} + +void __wrap_qtest_writew(QTestState *s, uint64_t addr, uint16_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 2); + } else { + __real_qtest_writew(s, addr, value); + } +} + +void __wrap_qtest_writel(QTestState *s, uint64_t addr, uint32_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 4); + } else { + __real_qtest_writel(s, addr, value); + } +} + +void __wrap_qtest_writeq(QTestState *s, uint64_t addr, uint64_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 8); + } else { + __real_qtest_writeq(s, addr, value); + } +} + +void __wrap_qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size) +{ + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data, + size); + } else { + __real_qtest_memread(s, addr, data, size); + } +} + +void __wrap_qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size) +{ + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data, + size); + } else { + __real_qtest_bufread(s, addr, data, size); + } +} + +void __wrap_qtest_memwrite(QTestState *s, uint64_t addr, const void *data, + size_t size) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_memwrite(s, addr, data, size); + } +} + +void __wrap_qtest_bufwrite(QTestState *s, uint64_t addr, + const void *data, size_t size) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_bufwrite(s, addr, data, size); + } +} +void __wrap_qtest_memset(QTestState *s, uint64_t addr, + uint8_t patt, size_t size) +{ + void *data; + if (!serialize) { + data = malloc(size); + memset(data, patt, size); + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_memset(s, addr, patt, size); + } +} + +void fuzz_qtest_set_serialize(bool option) +{ + serialize = option; +} diff --git a/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c b/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c index 1d5de5af00..8f827aeb52 100644 --- a/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c +++ b/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-imx25-pdk-machine.c b/tests/qtest/libqos/arm-imx25-pdk-machine.c index 25066fb8a9..0da3f19c0e 100644 --- a/tests/qtest/libqos/arm-imx25-pdk-machine.c +++ b/tests/qtest/libqos/arm-imx25-pdk-machine.c @@ -7,7 +7,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-n800-machine.c b/tests/qtest/libqos/arm-n800-machine.c index 87279bdb26..35f82070fa 100644 --- a/tests/qtest/libqos/arm-n800-machine.c +++ b/tests/qtest/libqos/arm-n800-machine.c @@ -7,7 +7,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-raspi2-machine.c b/tests/qtest/libqos/arm-raspi2-machine.c index 12a7cb7e4b..8480d80669 100644 --- a/tests/qtest/libqos/arm-raspi2-machine.c +++ b/tests/qtest/libqos/arm-raspi2-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-sabrelite-machine.c b/tests/qtest/libqos/arm-sabrelite-machine.c index e6df43795a..f6e403b538 100644 --- a/tests/qtest/libqos/arm-sabrelite-machine.c +++ b/tests/qtest/libqos/arm-sabrelite-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-smdkc210-machine.c b/tests/qtest/libqos/arm-smdkc210-machine.c index 215b628a7d..eebac7feeb 100644 --- a/tests/qtest/libqos/arm-smdkc210-machine.c +++ b/tests/qtest/libqos/arm-smdkc210-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-virt-machine.c b/tests/qtest/libqos/arm-virt-machine.c index 96ffe3ee5c..9316598f9e 100644 --- a/tests/qtest/libqos/arm-virt-machine.c +++ b/tests/qtest/libqos/arm-virt-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c b/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c index 5bc95f2e73..473acce993 100644 --- a/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c +++ b/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/e1000e.c b/tests/qtest/libqos/e1000e.c index 560e7a2bb2..e2927ed2da 100644 --- a/tests/qtest/libqos/e1000e.c +++ b/tests/qtest/libqos/e1000e.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/e1000e.h b/tests/qtest/libqos/e1000e.h index dc4ab10f58..35183b2875 100644 --- a/tests/qtest/libqos/e1000e.h +++ b/tests/qtest/libqos/e1000e.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/ppc64_pseries-machine.c b/tests/qtest/libqos/ppc64_pseries-machine.c index 867f27a3c8..5d7bd88f2f 100644 --- a/tests/qtest/libqos/ppc64_pseries-machine.c +++ b/tests/qtest/libqos/ppc64_pseries-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c index ca01de0743..eb0af8ab4a 100644 --- a/tests/qtest/libqos/qgraph.c +++ b/tests/qtest/libqos/qgraph.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h index 3a25dda4b2..db1244eb59 100644 --- a/tests/qtest/libqos/qgraph.h +++ b/tests/qtest/libqos/qgraph.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qgraph_internal.h b/tests/qtest/libqos/qgraph_internal.h index f4734c8681..aa3123f0f2 100644 --- a/tests/qtest/libqos/qgraph_internal.h +++ b/tests/qtest/libqos/qgraph_internal.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qos_external.c b/tests/qtest/libqos/qos_external.c index 9f5180e18d..0dfc05cfb6 100644 --- a/tests/qtest/libqos/qos_external.c +++ b/tests/qtest/libqos/qos_external.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/qos_external.h b/tests/qtest/libqos/qos_external.h index 72d7f91707..56a2f37fde 100644 --- a/tests/qtest/libqos/qos_external.h +++ b/tests/qtest/libqos/qos_external.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/sdhci.c b/tests/qtest/libqos/sdhci.c index 309794bc52..fbf2e36aec 100644 --- a/tests/qtest/libqos/sdhci.c +++ b/tests/qtest/libqos/sdhci.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/sdhci.h b/tests/qtest/libqos/sdhci.h index a88b45ae9d..1acd3096e2 100644 --- a/tests/qtest/libqos/sdhci.h +++ b/tests/qtest/libqos/sdhci.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c index 77dbfb62ad..c87b56132a 100644 --- a/tests/qtest/libqos/virtio-9p.c +++ b/tests/qtest/libqos/virtio-9p.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h index b54e89b3a1..be9621a5e3 100644 --- a/tests/qtest/libqos/virtio-9p.h +++ b/tests/qtest/libqos/virtio-9p.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-balloon.c b/tests/qtest/libqos/virtio-balloon.c index 42a4c5831e..9745f4a83c 100644 --- a/tests/qtest/libqos/virtio-balloon.c +++ b/tests/qtest/libqos/virtio-balloon.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-balloon.h b/tests/qtest/libqos/virtio-balloon.h index 52661cc87d..5b919303a6 100644 --- a/tests/qtest/libqos/virtio-balloon.h +++ b/tests/qtest/libqos/virtio-balloon.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-blk.c b/tests/qtest/libqos/virtio-blk.c index 726e93c5c1..5fc69401be 100644 --- a/tests/qtest/libqos/virtio-blk.c +++ b/tests/qtest/libqos/virtio-blk.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-blk.h b/tests/qtest/libqos/virtio-blk.h index c05adc659d..5170f13cfe 100644 --- a/tests/qtest/libqos/virtio-blk.h +++ b/tests/qtest/libqos/virtio-blk.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-net.c b/tests/qtest/libqos/virtio-net.c index 710d440c3d..a9e253afe4 100644 --- a/tests/qtest/libqos/virtio-net.c +++ b/tests/qtest/libqos/virtio-net.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-net.h b/tests/qtest/libqos/virtio-net.h index 855c67d00f..b8cbec04af 100644 --- a/tests/qtest/libqos/virtio-net.h +++ b/tests/qtest/libqos/virtio-net.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-rng.c b/tests/qtest/libqos/virtio-rng.c index b86349e2fd..46f8d95b1f 100644 --- a/tests/qtest/libqos/virtio-rng.c +++ b/tests/qtest/libqos/virtio-rng.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-rng.h b/tests/qtest/libqos/virtio-rng.h index 9e192f11f7..9342372efa 100644 --- a/tests/qtest/libqos/virtio-rng.h +++ b/tests/qtest/libqos/virtio-rng.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-scsi.c b/tests/qtest/libqos/virtio-scsi.c index de739bec5f..c8c3598428 100644 --- a/tests/qtest/libqos/virtio-scsi.c +++ b/tests/qtest/libqos/virtio-scsi.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-scsi.h b/tests/qtest/libqos/virtio-scsi.h index 4ca19a6a7a..9e3774d99a 100644 --- a/tests/qtest/libqos/virtio-scsi.h +++ b/tests/qtest/libqos/virtio-scsi.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-serial.c b/tests/qtest/libqos/virtio-serial.c index 3e5b8b82c7..b95654085d 100644 --- a/tests/qtest/libqos/virtio-serial.c +++ b/tests/qtest/libqos/virtio-serial.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/virtio-serial.h b/tests/qtest/libqos/virtio-serial.h index 080fa8428d..3328c6cf19 100644 --- a/tests/qtest/libqos/virtio-serial.h +++ b/tests/qtest/libqos/virtio-serial.h @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/libqos/x86_64_pc-machine.c b/tests/qtest/libqos/x86_64_pc-machine.c index 6dfa705217..0edb1c9144 100644 --- a/tests/qtest/libqos/x86_64_pc-machine.c +++ b/tests/qtest/libqos/x86_64_pc-machine.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c index 3062a13557..8fdf87b183 100644 --- a/tests/qtest/qos-test.c +++ b/tests/qtest/qos-test.c @@ -5,7 +5,7 @@ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. + * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/tests/test-crypto-secret.c b/tests/test-crypto-secret.c index 13fc6c4c75..603a093f10 100644 --- a/tests/test-crypto-secret.c +++ b/tests/test-crypto-secret.c @@ -24,6 +24,10 @@ #include "crypto/secret.h" #include "qapi/error.h" #include "qemu/module.h" +#ifdef CONFIG_TEST_SECRET_KEYRING +#include "crypto/secret_keyring.h" +#include <keyutils.h> +#endif static void test_secret_direct(void) { @@ -124,6 +128,147 @@ static void test_secret_indirect_emptyfile(void) g_free(fname); } +#ifdef CONFIG_TEST_SECRET_KEYRING + +#define DESCRIPTION "qemu_test_secret" +#define PAYLOAD "Test Payload" + + +static void test_secret_keyring_good(void) +{ + char key_str[16]; + Object *sec; + int32_t key = add_key("user", DESCRIPTION, PAYLOAD, + strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING); + + g_assert(key >= 0); + + snprintf(key_str, sizeof(key_str), "0x%08x", key); + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + &error_abort, + "serial", key_str, + NULL); + + assert(0 <= keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING)); + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + g_assert_cmpstr(pw, ==, PAYLOAD); + + object_unparent(sec); + g_free(pw); +} + + +static void test_secret_keyring_revoked_key(void) +{ + char key_str[16]; + Object *sec; + int32_t key = add_key("user", DESCRIPTION, PAYLOAD, + strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING); + g_assert(key >= 0); + g_assert_false(keyctl_revoke(key)); + + snprintf(key_str, sizeof(key_str), "0x%08x", key); + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + NULL, + "serial", key_str, + NULL); + + g_assert(errno == EKEYREVOKED); + g_assert(sec == NULL); + + keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING); +} + + +static void test_secret_keyring_expired_key(void) +{ + char key_str[16]; + Object *sec; + int32_t key = add_key("user", DESCRIPTION, PAYLOAD, + strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING); + g_assert(key >= 0); + g_assert_false(keyctl_set_timeout(key, 1)); + sleep(1); + + snprintf(key_str, sizeof(key_str), "0x%08x", key); + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + NULL, + "serial", key_str, + NULL); + + g_assert(errno == EKEYEXPIRED); + g_assert(sec == NULL); + + keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING); +} + + +static void test_secret_keyring_bad_serial_key(void) +{ + Object *sec; + + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + NULL, + "serial", "1", + NULL); + + g_assert(errno == ENOKEY); + g_assert(sec == NULL); +} + +/* + * TODO + * test_secret_keyring_bad_key_access_right() is not working yet. + * We don't know yet if this due a bug in the Linux kernel or + * whether it's normal syscall behavior. + * We've requested information from kernel maintainers. + * See: <https://www.spinics.net/lists/keyrings/index.html> + * Thread: 'security/keys: remove possessor verify after key permission check' + */ + +static void test_secret_keyring_bad_key_access_right(void) +{ + char key_str[16]; + Object *sec; + + g_test_skip("TODO: Need responce from Linux kernel maintainers"); + return; + + int32_t key = add_key("user", DESCRIPTION, PAYLOAD, + strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING); + g_assert(key >= 0); + g_assert_false(keyctl_setperm(key, KEY_POS_ALL & (~KEY_POS_READ))); + + snprintf(key_str, sizeof(key_str), "0x%08x", key); + + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET_KEYRING, + object_get_objects_root(), + "sec0", + NULL, + "serial", key_str, + NULL); + + g_assert(errno == EACCES); + g_assert(sec == NULL); + + keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING); +} + +#endif /* CONFIG_TEST_SECRET_KEYRING */ static void test_secret_noconv_base64_good(void) { @@ -426,6 +571,19 @@ int main(int argc, char **argv) g_test_add_func("/crypto/secret/indirect/emptyfile", test_secret_indirect_emptyfile); +#ifdef CONFIG_TEST_SECRET_KEYRING + g_test_add_func("/crypto/secret/keyring/good", + test_secret_keyring_good); + g_test_add_func("/crypto/secret/keyring/revoked_key", + test_secret_keyring_revoked_key); + g_test_add_func("/crypto/secret/keyring/expired_key", + test_secret_keyring_expired_key); + g_test_add_func("/crypto/secret/keyring/bad_serial_key", + test_secret_keyring_bad_serial_key); + g_test_add_func("/crypto/secret/keyring/bad_key_access_right", + test_secret_keyring_bad_key_access_right); +#endif /* CONFIG_TEST_SECRET_KEYRING */ + g_test_add_func("/crypto/secret/noconv/base64/good", test_secret_noconv_base64_good); g_test_add_func("/crypto/secret/noconv/base64/bad", |