diff options
78 files changed, 1480 insertions, 3512 deletions
diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 6af7920b35..01e8470a69 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -641,12 +641,15 @@ build-oss-fuzz: - CC="clang" CXX="clang++" CFLAGS="-fsanitize=address" ./scripts/oss-fuzz/build.sh - export ASAN_OPTIONS="fast_unwind_on_malloc=0" + - failures=0 - for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f | grep -v slirp); do grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ; echo Testing ${fuzzer} ... ; - "${fuzzer}" -runs=1 -seed=1 || exit 1 ; + "${fuzzer}" -runs=1 -seed=1 || { echo "FAILED:"" ${fuzzer} exit code is $?"; failures=$(($failures+1)); }; done + - echo "Number of failures:"" $failures" + - test $failures = 0 build-tci: extends: .native_build_job_template diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index e49e1b61f0..5708c2bbab 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -60,13 +60,13 @@ x64-freebsd-14-build: CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblaze-softmmu,mips64el-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,xtensa-softmmu TEST_TARGETS: check -aarch64-macos-13-base-build: +aarch64-macos-14-base-build: extends: .cirrus_build_job variables: - NAME: macos-13 + NAME: macos-14 CIRRUS_VM_INSTANCE_TYPE: macos_instance CIRRUS_VM_IMAGE_SELECTOR: image - CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-ventura-base:latest + CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-sonoma-base:latest CIRRUS_VM_CPUS: 12 CIRRUS_VM_RAM: 24G UPDATE_COMMAND: brew update @@ -76,13 +76,13 @@ aarch64-macos-13-base-build: CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblazeel-softmmu,mips64-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,sh4-softmmu,xtensaeb-softmmu TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64 -aarch64-macos-14-base-build: +aarch64-macos-15-base-build: extends: .cirrus_build_job variables: - NAME: macos-14 + NAME: macos-15 CIRRUS_VM_INSTANCE_TYPE: macos_instance CIRRUS_VM_IMAGE_SELECTOR: image - CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-sonoma-base:latest + CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-sequoia-base:latest CIRRUS_VM_CPUS: 12 CIRRUS_VM_RAM: 24G UPDATE_COMMAND: brew update diff --git a/.gitlab-ci.d/cirrus/macos-13.vars b/.gitlab-ci.d/cirrus/macos-15.vars index ac3fa3a847..23b2c1d22f 100644 --- a/.gitlab-ci.d/cirrus/macos-13.vars +++ b/.gitlab-ci.d/cirrus/macos-15.vars @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool variables macos-13 qemu +# $ lcitool variables macos-15 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/MAINTAINERS b/MAINTAINERS index 539d59c195..dab931a3c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -224,11 +224,6 @@ F: gdb-xml/avr-cpu.xml F: target/avr/ F: tests/functional/test_avr_mega2560.py -CRIS TCG CPUs -M: Edgar E. Iglesias <edgar.iglesias@gmail.com> -S: Maintained -F: disas/cris.c - Hexagon TCG CPUs M: Brian Cain <bcain@quicinc.com> S: Supported diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 7ddc47b0ba..11b6d45e90 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -485,11 +485,6 @@ static bool pageflags_set_clear(target_ulong start, target_ulong last, return inval_tb; } -/* - * Modify the flags of a page and invalidate the code if necessary. - * The flag PAGE_WRITE_ORG is positioned automatically depending - * on PAGE_WRITE. The mmap_lock should already be held. - */ void page_set_flags(target_ulong start, target_ulong last, int flags) { bool reset = false; diff --git a/block/gluster.c b/block/gluster.c index f8b415f381..f03d05251e 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -809,6 +809,8 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options, goto out; } + warn_report_once("'gluster' is deprecated"); + filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME); s->debug = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG, diff --git a/chardev/char-pty.c b/chardev/char-pty.c index cc2f7617fe..cbb21b76ae 100644 --- a/chardev/char-pty.c +++ b/chardev/char-pty.c @@ -29,6 +29,7 @@ #include "qemu/sockets.h" #include "qemu/error-report.h" #include "qemu/module.h" +#include "qemu/option.h" #include "qemu/qemu-print.h" #include "chardev/char-io.h" @@ -41,6 +42,7 @@ struct PtyChardev { int connected; GSource *timer_src; + char *path; }; typedef struct PtyChardev PtyChardev; @@ -204,6 +206,12 @@ static void char_pty_finalize(Object *obj) Chardev *chr = CHARDEV(obj); PtyChardev *s = PTY_CHARDEV(obj); + /* unlink symlink */ + if (s->path) { + unlink(s->path); + g_free(s->path); + } + pty_chr_state(chr, 0); object_unref(OBJECT(s->ioc)); pty_chr_timer_cancel(s); @@ -330,6 +338,7 @@ static void char_pty_open(Chardev *chr, int master_fd, slave_fd; char pty_name[PATH_MAX]; char *name; + char *path = backend->u.pty.data->path; master_fd = qemu_openpty_raw(&slave_fd, pty_name); if (master_fd < 0) { @@ -354,12 +363,36 @@ static void char_pty_open(Chardev *chr, g_free(name); s->timer_src = NULL; *be_opened = false; + + /* create symbolic link */ + if (path) { + int res = symlink(pty_name, path); + + if (res != 0) { + error_setg_errno(errp, errno, "Failed to create PTY symlink"); + } else { + s->path = g_strdup(path); + } + } +} + +static void char_pty_parse(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *path = qemu_opt_get(opts, "path"); + ChardevPty *pty; + + backend->type = CHARDEV_BACKEND_KIND_PTY; + pty = backend->u.pty.data = g_new0(ChardevPty, 1); + qemu_chr_parse_common(opts, qapi_ChardevPty_base(pty)); + pty->path = g_strdup(path); } static void char_pty_class_init(ObjectClass *oc, void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); + cc->parse = char_pty_parse; cc->open = char_pty_open; cc->chr_write = char_pty_chr_write; cc->chr_update_read_handler = pty_chr_update_read_handler; diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 1ca9441b1b..91496ceda9 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -74,7 +74,7 @@ static void qemu_chr_socket_restart_timer(Chardev *chr) assert(!s->reconnect_timer); name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label); s->reconnect_timer = qemu_chr_timeout_add_ms(chr, - s->reconnect_time * 1000, + s->reconnect_time_ms, socket_reconnect_timeout, chr); g_source_set_name(s->reconnect_timer, name); @@ -481,7 +481,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr) if (emit_close) { qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } - if (s->reconnect_time && !s->reconnect_timer) { + if (s->reconnect_time_ms && !s->reconnect_timer) { qemu_chr_socket_restart_timer(chr); } } @@ -1080,9 +1080,9 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp) } else { Error *err = NULL; if (tcp_chr_connect_client_sync(chr, &err) < 0) { - if (s->reconnect_time) { + if (s->reconnect_time_ms) { error_free(err); - g_usleep(s->reconnect_time * 1000ULL * 1000ULL); + g_usleep(s->reconnect_time_ms * 1000ULL); } else { error_propagate(errp, err); return -1; @@ -1267,13 +1267,13 @@ skip_listen: static int qmp_chardev_open_socket_client(Chardev *chr, - int64_t reconnect, + int64_t reconnect_ms, Error **errp) { SocketChardev *s = SOCKET_CHARDEV(chr); - if (reconnect > 0) { - s->reconnect_time = reconnect; + if (reconnect_ms > 0) { + s->reconnect_time_ms = reconnect_ms; tcp_chr_connect_client_async(chr); return 0; } else { @@ -1354,6 +1354,12 @@ static bool qmp_chardev_validate_socket(ChardevSocket *sock, } } + if (sock->has_reconnect_ms && sock->has_reconnect) { + error_setg(errp, + "'reconnect' and 'reconnect-ms' are mutually exclusive"); + return false; + } + return true; } @@ -1371,7 +1377,7 @@ static void qmp_chardev_open_socket(Chardev *chr, bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false; bool is_waitconnect = sock->has_wait ? sock->wait : false; bool is_websock = sock->has_websocket ? sock->websocket : false; - int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0; + int64_t reconnect_ms = 0; SocketAddress *addr; s->is_listen = is_listen; @@ -1443,7 +1449,13 @@ static void qmp_chardev_open_socket(Chardev *chr, return; } } else { - if (qmp_chardev_open_socket_client(chr, reconnect, errp) < 0) { + if (sock->has_reconnect) { + reconnect_ms = sock->reconnect * 1000ULL; + } else if (sock->has_reconnect_ms) { + reconnect_ms = sock->reconnect_ms; + } + + if (qmp_chardev_open_socket_client(chr, reconnect_ms, errp) < 0) { return; } } @@ -1509,6 +1521,9 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, sock->wait = qemu_opt_get_bool(opts, "wait", true); sock->has_reconnect = qemu_opt_find(opts, "reconnect"); sock->reconnect = qemu_opt_get_number(opts, "reconnect", 0); + sock->has_reconnect_ms = qemu_opt_find(opts, "reconnect-ms"); + sock->reconnect_ms = qemu_opt_get_number(opts, "reconnect-ms", 0); + sock->tls_creds = g_strdup(qemu_opt_get(opts, "tls-creds")); sock->tls_authz = g_strdup(qemu_opt_get(opts, "tls-authz")); diff --git a/chardev/char.c b/chardev/char.c index ba847b6e9e..c0cc52824b 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -428,6 +428,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename, qemu_opt_set(opts, "path", p, &error_abort); return opts; } + if (strstart(filename, "pty:", &p)) { + qemu_opt_set(opts, "backend", "pty", &error_abort); + qemu_opt_set(opts, "path", p, &error_abort); + return opts; + } if (strstart(filename, "tcp:", &p) || strstart(filename, "telnet:", &p) || strstart(filename, "tn3270:", &p) || @@ -889,6 +894,9 @@ QemuOptsList qemu_chardev_opts = { .name = "reconnect", .type = QEMU_OPT_NUMBER, },{ + .name = "reconnect-ms", + .type = QEMU_OPT_NUMBER, + },{ .name = "telnet", .type = QEMU_OPT_BOOL, },{ diff --git a/crypto/hash-afalg.c b/crypto/hash-afalg.c index 28ab899b18..06e1e4699c 100644 --- a/crypto/hash-afalg.c +++ b/crypto/hash-afalg.c @@ -1,6 +1,7 @@ /* * QEMU Crypto af_alg-backend hash/hmac support * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD. * * Authors: @@ -113,74 +114,145 @@ qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgo alg, return qcrypto_afalg_hash_hmac_ctx_new(alg, key, nkey, true, errp); } -static int -qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo *hmac, - QCryptoHashAlgo alg, - const struct iovec *iov, - size_t niov, uint8_t **result, - size_t *resultlen, - Error **errp) +static +QCryptoHash *qcrypto_afalg_hash_new(QCryptoHashAlgo alg, Error **errp) { - QCryptoAFAlgo *afalg; - struct iovec outv; - int ret = 0; - bool is_hmac = (hmac != NULL) ? true : false; - const int expect_len = qcrypto_hash_digest_len(alg); + /* Check if hash algorithm is supported */ + char *alg_name = qcrypto_afalg_hash_format_name(alg, false, NULL); + QCryptoHash *hash; - if (*resultlen == 0) { - *resultlen = expect_len; - *result = g_new0(uint8_t, *resultlen); - } else if (*resultlen != expect_len) { - error_setg(errp, - "Result buffer size %zu is not match hash %d", - *resultlen, expect_len); - return -1; + if (alg_name == NULL) { + error_setg(errp, "Unknown hash algorithm %d", alg); + return NULL; } - if (is_hmac) { - afalg = hmac; - } else { - afalg = qcrypto_afalg_hash_ctx_new(alg, errp); - if (!afalg) { - return -1; - } + g_free(alg_name); + + hash = g_new(QCryptoHash, 1); + hash->alg = alg; + hash->opaque = qcrypto_afalg_hash_ctx_new(alg, errp); + if (!hash->opaque) { + free(hash); + return NULL; } + return hash; +} + +static +void qcrypto_afalg_hash_free(QCryptoHash *hash) +{ + QCryptoAFAlg *ctx = hash->opaque; + + if (ctx) { + qcrypto_afalg_comm_free(ctx); + } + + g_free(hash); +} + +/** + * Send data to the kernel's crypto core. + * + * The more_data parameter is used to notify the crypto engine + * that this is an "update" operation, and that more data will + * be provided to calculate the final hash. + */ +static +int qcrypto_afalg_send_to_kernel(QCryptoAFAlg *afalg, + const struct iovec *iov, + size_t niov, + bool more_data, + Error **errp) +{ + int ret = 0; + int flags = (more_data ? MSG_MORE : 0); + /* send data to kernel's crypto core */ - ret = iov_send_recv(afalg->opfd, iov, niov, - 0, iov_size(iov, niov), true); + ret = iov_send_recv_with_flags(afalg->opfd, flags, iov, niov, + 0, iov_size(iov, niov), true); if (ret < 0) { error_setg_errno(errp, errno, "Send data to afalg-core failed"); - goto out; + ret = -1; + } else { + /* No error, so return 0 */ + ret = 0; + } + + return ret; +} + +static +int qcrypto_afalg_recv_from_kernel(QCryptoAFAlg *afalg, + QCryptoHashAlgo alg, + uint8_t **result, + size_t *result_len, + Error **errp) +{ + struct iovec outv; + int ret; + const int expected_len = qcrypto_hash_digest_len(alg); + + if (*result_len == 0) { + *result_len = expected_len; + *result = g_new0(uint8_t, *result_len); + } else if (*result_len != expected_len) { + error_setg(errp, + "Result buffer size %zu is not match hash %d", + *result_len, expected_len); + return -1; } /* hash && get result */ outv.iov_base = *result; - outv.iov_len = *resultlen; + outv.iov_len = *result_len; ret = iov_send_recv(afalg->opfd, &outv, 1, 0, iov_size(&outv, 1), false); if (ret < 0) { error_setg_errno(errp, errno, "Recv result from afalg-core failed"); - } else { - ret = 0; + return -1; } -out: - if (!is_hmac) { - qcrypto_afalg_comm_free(afalg); - } - return ret; + return 0; +} + +static +int qcrypto_afalg_hash_update(QCryptoHash *hash, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + return qcrypto_afalg_send_to_kernel((QCryptoAFAlg *) hash->opaque, + iov, niov, true, errp); +} + +static +int qcrypto_afalg_hash_finalize(QCryptoHash *hash, + uint8_t **result, + size_t *result_len, + Error **errp) +{ + return qcrypto_afalg_recv_from_kernel((QCryptoAFAlg *) hash->opaque, + hash->alg, result, result_len, errp); } static int -qcrypto_afalg_hash_bytesv(QCryptoHashAlgo alg, - const struct iovec *iov, - size_t niov, uint8_t **result, - size_t *resultlen, - Error **errp) +qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo *hmac, + QCryptoHashAlgo alg, + const struct iovec *iov, + size_t niov, uint8_t **result, + size_t *resultlen, + Error **errp) { - return qcrypto_afalg_hash_hmac_bytesv(NULL, alg, iov, niov, result, - resultlen, errp); + int ret = 0; + + ret = qcrypto_afalg_send_to_kernel(hmac, iov, niov, false, errp); + if (ret == 0) { + ret = qcrypto_afalg_recv_from_kernel(hmac, alg, result, + resultlen, errp); + } + + return ret; } static int @@ -204,7 +276,10 @@ static void qcrypto_afalg_hmac_ctx_free(QCryptoHmac *hmac) } QCryptoHashDriver qcrypto_hash_afalg_driver = { - .hash_bytesv = qcrypto_afalg_hash_bytesv, + .hash_new = qcrypto_afalg_hash_new, + .hash_free = qcrypto_afalg_hash_free, + .hash_update = qcrypto_afalg_hash_update, + .hash_finalize = qcrypto_afalg_hash_finalize }; QCryptoHmacDriver qcrypto_hmac_afalg_driver = { diff --git a/crypto/hash-gcrypt.c b/crypto/hash-gcrypt.c index 0973cc0d93..ccc3cce3f8 100644 --- a/crypto/hash-gcrypt.c +++ b/crypto/hash-gcrypt.c @@ -1,6 +1,7 @@ /* * QEMU Crypto hash algorithms * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2016 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -44,73 +45,84 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) return false; } - -static int -qcrypto_gcrypt_hash_bytesv(QCryptoHashAlgo alg, - const struct iovec *iov, - size_t niov, - uint8_t **result, - size_t *resultlen, - Error **errp) +static +QCryptoHash *qcrypto_gcrypt_hash_new(QCryptoHashAlgo alg, Error **errp) { - int i, ret; - gcry_md_hd_t md; - unsigned char *digest; - - if (!qcrypto_hash_supports(alg)) { - error_setg(errp, - "Unknown hash algorithm %d", - alg); - return -1; - } + QCryptoHash *hash; + int ret; - ret = gcry_md_open(&md, qcrypto_hash_alg_map[alg], 0); + hash = g_new(QCryptoHash, 1); + hash->alg = alg; + hash->opaque = g_new(gcry_md_hd_t, 1); + ret = gcry_md_open((gcry_md_hd_t *) hash->opaque, + qcrypto_hash_alg_map[alg], 0); if (ret < 0) { error_setg(errp, "Unable to initialize hash algorithm: %s", gcry_strerror(ret)); - return -1; + g_free(hash->opaque); + g_free(hash); + return NULL; } + return hash; +} - for (i = 0; i < niov; i++) { - gcry_md_write(md, iov[i].iov_base, iov[i].iov_len); - } +static +void qcrypto_gcrypt_hash_free(QCryptoHash *hash) +{ + gcry_md_hd_t *ctx = hash->opaque; - ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[alg]); - if (ret <= 0) { - error_setg(errp, - "Unable to get hash length: %s", - gcry_strerror(ret)); - goto error; - } - if (*resultlen == 0) { - *resultlen = ret; - *result = g_new0(uint8_t, *resultlen); - } else if (*resultlen != ret) { - error_setg(errp, - "Result buffer size %zu is smaller than hash %d", - *resultlen, ret); - goto error; + if (ctx) { + gcry_md_close(*ctx); + g_free(ctx); } - digest = gcry_md_read(md, 0); - if (!digest) { - error_setg(errp, - "No digest produced"); - goto error; + g_free(hash); +} + + +static +int qcrypto_gcrypt_hash_update(QCryptoHash *hash, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + gcry_md_hd_t *ctx = hash->opaque; + + for (int i = 0; i < niov; i++) { + gcry_md_write(*ctx, iov[i].iov_base, iov[i].iov_len); } - memcpy(*result, digest, *resultlen); - gcry_md_close(md); return 0; - - error: - gcry_md_close(md); - return -1; } +static +int qcrypto_gcrypt_hash_finalize(QCryptoHash *hash, + uint8_t **result, + size_t *result_len, + Error **errp) +{ + unsigned char *digest; + gcry_md_hd_t *ctx = hash->opaque; + + *result_len = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[hash->alg]); + if (*result_len == 0) { + error_setg(errp, "Unable to get hash length"); + return -1; + } + + *result = g_new(uint8_t, *result_len); + + /* Digest is freed by gcry_md_close(), copy it */ + digest = gcry_md_read(*ctx, 0); + memcpy(*result, digest, *result_len); + return 0; +} QCryptoHashDriver qcrypto_hash_lib_driver = { - .hash_bytesv = qcrypto_gcrypt_hash_bytesv, + .hash_new = qcrypto_gcrypt_hash_new, + .hash_update = qcrypto_gcrypt_hash_update, + .hash_finalize = qcrypto_gcrypt_hash_finalize, + .hash_free = qcrypto_gcrypt_hash_free, }; diff --git a/crypto/hash-glib.c b/crypto/hash-glib.c index a5a2949333..02a6ec1edf 100644 --- a/crypto/hash-glib.c +++ b/crypto/hash-glib.c @@ -1,6 +1,7 @@ /* * QEMU Crypto hash algorithms * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2016 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -43,58 +44,71 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) return false; } - -static int -qcrypto_glib_hash_bytesv(QCryptoHashAlgo alg, - const struct iovec *iov, - size_t niov, - uint8_t **result, - size_t *resultlen, - Error **errp) +static +QCryptoHash *qcrypto_glib_hash_new(QCryptoHashAlgo alg, + Error **errp) { - int i, ret; - GChecksum *cs; + QCryptoHash *hash; - if (!qcrypto_hash_supports(alg)) { - error_setg(errp, - "Unknown hash algorithm %d", - alg); - return -1; + hash = g_new(QCryptoHash, 1); + hash->alg = alg; + hash->opaque = g_checksum_new(qcrypto_hash_alg_map[alg]); + + return hash; +} + +static +void qcrypto_glib_hash_free(QCryptoHash *hash) +{ + if (hash->opaque) { + g_checksum_free(hash->opaque); } - cs = g_checksum_new(qcrypto_hash_alg_map[alg]); + g_free(hash); +} + + +static +int qcrypto_glib_hash_update(QCryptoHash *hash, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + GChecksum *ctx = hash->opaque; - for (i = 0; i < niov; i++) { - g_checksum_update(cs, iov[i].iov_base, iov[i].iov_len); + for (int i = 0; i < niov; i++) { + g_checksum_update(ctx, iov[i].iov_base, iov[i].iov_len); } - ret = g_checksum_type_get_length(qcrypto_hash_alg_map[alg]); + return 0; +} + +static +int qcrypto_glib_hash_finalize(QCryptoHash *hash, + uint8_t **result, + size_t *result_len, + Error **errp) +{ + int ret; + GChecksum *ctx = hash->opaque; + + ret = g_checksum_type_get_length(qcrypto_hash_alg_map[hash->alg]); if (ret < 0) { - error_setg(errp, "%s", - "Unable to get hash length"); - goto error; - } - if (*resultlen == 0) { - *resultlen = ret; - *result = g_new0(uint8_t, *resultlen); - } else if (*resultlen != ret) { - error_setg(errp, - "Result buffer size %zu is smaller than hash %d", - *resultlen, ret); - goto error; + error_setg(errp, "Unable to get hash length"); + *result_len = 0; + return -1; } - g_checksum_get_digest(cs, *result, resultlen); + *result_len = ret; + *result = g_new(uint8_t, *result_len); - g_checksum_free(cs); + g_checksum_get_digest(ctx, *result, result_len); return 0; - - error: - g_checksum_free(cs); - return -1; } - QCryptoHashDriver qcrypto_hash_lib_driver = { - .hash_bytesv = qcrypto_glib_hash_bytesv, + .hash_new = qcrypto_glib_hash_new, + .hash_update = qcrypto_glib_hash_update, + .hash_finalize = qcrypto_glib_hash_finalize, + .hash_free = qcrypto_glib_hash_free, }; diff --git a/crypto/hash-gnutls.c b/crypto/hash-gnutls.c index 0636c0727a..34a63994c9 100644 --- a/crypto/hash-gnutls.c +++ b/crypto/hash-gnutls.c @@ -1,6 +1,7 @@ /* * QEMU Crypto hash algorithms * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2021 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -52,53 +53,83 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) return false; } - -static int -qcrypto_gnutls_hash_bytesv(QCryptoHashAlgo alg, - const struct iovec *iov, - size_t niov, - uint8_t **result, - size_t *resultlen, - Error **errp) +static +QCryptoHash *qcrypto_gnutls_hash_new(QCryptoHashAlgo alg, Error **errp) { - int i, ret; - gnutls_hash_hd_t hash; + QCryptoHash *hash; + int ret; - if (!qcrypto_hash_supports(alg)) { - error_setg(errp, - "Unknown hash algorithm %d", - alg); - return -1; - } + hash = g_new(QCryptoHash, 1); + hash->alg = alg; + hash->opaque = g_new(gnutls_hash_hd_t, 1); - ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]); - if (*resultlen == 0) { - *resultlen = ret; - *result = g_new0(uint8_t, *resultlen); - } else if (*resultlen != ret) { - error_setg(errp, - "Result buffer size %zu is smaller than hash %d", - *resultlen, ret); - return -1; - } - - ret = gnutls_hash_init(&hash, qcrypto_hash_alg_map[alg]); + ret = gnutls_hash_init(hash->opaque, qcrypto_hash_alg_map[alg]); if (ret < 0) { error_setg(errp, "Unable to initialize hash algorithm: %s", gnutls_strerror(ret)); - return -1; + g_free(hash->opaque); + g_free(hash); + return NULL; } - for (i = 0; i < niov; i++) { - gnutls_hash(hash, iov[i].iov_base, iov[i].iov_len); + return hash; +} + +static +void qcrypto_gnutls_hash_free(QCryptoHash *hash) +{ + gnutls_hash_hd_t *ctx = hash->opaque; + + gnutls_hash_deinit(*ctx, NULL); + g_free(ctx); + g_free(hash); +} + + +static +int qcrypto_gnutls_hash_update(QCryptoHash *hash, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + int ret = 0; + gnutls_hash_hd_t *ctx = hash->opaque; + + for (int i = 0; i < niov; i++) { + ret = gnutls_hash(*ctx, iov[i].iov_base, iov[i].iov_len); + if (ret != 0) { + error_setg(errp, "Failed to hash data: %s", + gnutls_strerror(ret)); + return -1; + } } - gnutls_hash_deinit(hash, *result); return 0; } +static +int qcrypto_gnutls_hash_finalize(QCryptoHash *hash, + uint8_t **result, + size_t *result_len, + Error **errp) +{ + gnutls_hash_hd_t *ctx = hash->opaque; + + *result_len = gnutls_hash_get_len(qcrypto_hash_alg_map[hash->alg]); + if (*result_len == 0) { + error_setg(errp, "Unable to get hash length"); + return -1; + } + + *result = g_new(uint8_t, *result_len); + gnutls_hash_output(*ctx, *result); + return 0; +} QCryptoHashDriver qcrypto_hash_lib_driver = { - .hash_bytesv = qcrypto_gnutls_hash_bytesv, + .hash_new = qcrypto_gnutls_hash_new, + .hash_update = qcrypto_gnutls_hash_update, + .hash_finalize = qcrypto_gnutls_hash_finalize, + .hash_free = qcrypto_gnutls_hash_free, }; diff --git a/crypto/hash-nettle.c b/crypto/hash-nettle.c index 8b08a9c675..3b847aa60e 100644 --- a/crypto/hash-nettle.c +++ b/crypto/hash-nettle.c @@ -1,6 +1,7 @@ /* * QEMU Crypto hash algorithms * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2016 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -103,59 +104,64 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) return false; } +static +QCryptoHash *qcrypto_nettle_hash_new(QCryptoHashAlgo alg, Error **errp) +{ + QCryptoHash *hash; + + hash = g_new(QCryptoHash, 1); + hash->alg = alg; + hash->opaque = g_new(union qcrypto_hash_ctx, 1); + + qcrypto_hash_alg_map[alg].init(hash->opaque); + return hash; +} -static int -qcrypto_nettle_hash_bytesv(QCryptoHashAlgo alg, - const struct iovec *iov, - size_t niov, - uint8_t **result, - size_t *resultlen, - Error **errp) +static +void qcrypto_nettle_hash_free(QCryptoHash *hash) { - size_t i; - union qcrypto_hash_ctx ctx; - - if (!qcrypto_hash_supports(alg)) { - error_setg(errp, - "Unknown hash algorithm %d", - alg); - return -1; - } + union qcrypto_hash_ctx *ctx = hash->opaque; - qcrypto_hash_alg_map[alg].init(&ctx); - - for (i = 0; i < niov; i++) { - /* Some versions of nettle have functions - * declared with 'int' instead of 'size_t' - * so to be safe avoid writing more than - * UINT_MAX bytes at a time - */ - size_t len = iov[i].iov_len; - uint8_t *base = iov[i].iov_base; - while (len) { - size_t shortlen = MIN(len, UINT_MAX); - qcrypto_hash_alg_map[alg].write(&ctx, len, base); - len -= shortlen; - base += len; - } - } + g_free(ctx); + g_free(hash); +} - if (*resultlen == 0) { - *resultlen = qcrypto_hash_alg_map[alg].len; - *result = g_new0(uint8_t, *resultlen); - } else if (*resultlen != qcrypto_hash_alg_map[alg].len) { - error_setg(errp, - "Result buffer size %zu is smaller than hash %zu", - *resultlen, qcrypto_hash_alg_map[alg].len); - return -1; - } +static +int qcrypto_nettle_hash_update(QCryptoHash *hash, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + union qcrypto_hash_ctx *ctx = hash->opaque; - qcrypto_hash_alg_map[alg].result(&ctx, *resultlen, *result); + for (int i = 0; i < niov; i++) { + qcrypto_hash_alg_map[hash->alg].write(ctx, + iov[i].iov_len, + iov[i].iov_base); + } return 0; } +static +int qcrypto_nettle_hash_finalize(QCryptoHash *hash, + uint8_t **result, + size_t *result_len, + Error **errp) +{ + union qcrypto_hash_ctx *ctx = hash->opaque; + + *result_len = qcrypto_hash_alg_map[hash->alg].len; + *result = g_new(uint8_t, *result_len); + + qcrypto_hash_alg_map[hash->alg].result(ctx, *result_len, *result); + + return 0; +} QCryptoHashDriver qcrypto_hash_lib_driver = { - .hash_bytesv = qcrypto_nettle_hash_bytesv, + .hash_new = qcrypto_nettle_hash_new, + .hash_update = qcrypto_nettle_hash_update, + .hash_finalize = qcrypto_nettle_hash_finalize, + .hash_free = qcrypto_nettle_hash_free, }; diff --git a/crypto/hash.c b/crypto/hash.c index 4a265582b8..0c8548c568 100644 --- a/crypto/hash.c +++ b/crypto/hash.c @@ -1,6 +1,7 @@ /* * QEMU Crypto hash algorithms * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -19,6 +20,8 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi-types-crypto.h" #include "crypto/hash.h" #include "hashpriv.h" @@ -45,23 +48,18 @@ int qcrypto_hash_bytesv(QCryptoHashAlgo alg, size_t *resultlen, Error **errp) { -#ifdef CONFIG_AF_ALG - int ret; - /* - * TODO: - * Maybe we should treat some afalg errors as fatal - */ - ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov, - result, resultlen, - NULL); - if (ret == 0) { - return ret; + g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp); + + if (!ctx) { + return -1; + } + + if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 || + qcrypto_hash_finalize_bytes(ctx, result, resultlen, errp) < 0) { + return -1; } -#endif - return qcrypto_hash_lib_driver.hash_bytesv(alg, iov, niov, - result, resultlen, - errp); + return 0; } @@ -77,29 +75,130 @@ int qcrypto_hash_bytes(QCryptoHashAlgo alg, return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp); } +int qcrypto_hash_updatev(QCryptoHash *hash, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + QCryptoHashDriver *drv = hash->driver; + + return drv->hash_update(hash, iov, niov, errp); +} + +int qcrypto_hash_update(QCryptoHash *hash, + const char *buf, + size_t len, + Error **errp) +{ + struct iovec iov = { .iov_base = (char *)buf, .iov_len = len }; + + return qcrypto_hash_updatev(hash, &iov, 1, errp); +} + +QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp) +{ + QCryptoHash *hash = NULL; + + if (!qcrypto_hash_supports(alg)) { + error_setg(errp, "Unsupported hash algorithm %s", + QCryptoHashAlgo_str(alg)); + return NULL; + } + +#ifdef CONFIG_AF_ALG + hash = qcrypto_hash_afalg_driver.hash_new(alg, NULL); + if (hash) { + hash->driver = &qcrypto_hash_afalg_driver; + return hash; + } +#endif + + hash = qcrypto_hash_lib_driver.hash_new(alg, errp); + if (!hash) { + return NULL; + } + + hash->driver = &qcrypto_hash_lib_driver; + return hash; +} + +void qcrypto_hash_free(QCryptoHash *hash) +{ + QCryptoHashDriver *drv; + + if (hash) { + drv = hash->driver; + drv->hash_free(hash); + } +} + +int qcrypto_hash_finalize_bytes(QCryptoHash *hash, + uint8_t **result, + size_t *result_len, + Error **errp) +{ + QCryptoHashDriver *drv = hash->driver; + + return drv->hash_finalize(hash, result, result_len, errp); +} + static const char hex[] = "0123456789abcdef"; +int qcrypto_hash_finalize_digest(QCryptoHash *hash, + char **digest, + Error **errp) +{ + int ret; + g_autofree uint8_t *result = NULL; + size_t resultlen = 0; + size_t i; + + ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp); + if (ret == 0) { + *digest = g_new0(char, (resultlen * 2) + 1); + for (i = 0 ; i < resultlen ; i++) { + (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf]; + (*digest)[(i * 2) + 1] = hex[result[i] & 0xf]; + } + (*digest)[resultlen * 2] = '\0'; + } + + return ret; +} + +int qcrypto_hash_finalize_base64(QCryptoHash *hash, + char **base64, + Error **errp) +{ + int ret; + g_autofree uint8_t *result = NULL; + size_t resultlen = 0; + + ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp); + if (ret == 0) { + *base64 = g_base64_encode(result, resultlen); + } + + return ret; +} + int qcrypto_hash_digestv(QCryptoHashAlgo alg, const struct iovec *iov, size_t niov, char **digest, Error **errp) { - uint8_t *result = NULL; - size_t resultlen = 0; - size_t i; + g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp); - if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) { + if (!ctx) { return -1; } - *digest = g_new0(char, (resultlen * 2) + 1); - for (i = 0 ; i < resultlen ; i++) { - (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf]; - (*digest)[(i * 2) + 1] = hex[result[i] & 0xf]; + if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 || + qcrypto_hash_finalize_digest(ctx, digest, errp) < 0) { + return -1; } - (*digest)[resultlen * 2] = '\0'; - g_free(result); + return 0; } @@ -120,15 +219,17 @@ int qcrypto_hash_base64v(QCryptoHashAlgo alg, char **base64, Error **errp) { - uint8_t *result = NULL; - size_t resultlen = 0; + g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp); + + if (!ctx) { + return -1; + } - if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) { + if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 || + qcrypto_hash_finalize_base64(ctx, base64, errp) < 0) { return -1; } - *base64 = g_base64_encode(result, resultlen); - g_free(result); return 0; } diff --git a/crypto/hashpriv.h b/crypto/hashpriv.h index 47daec3f7a..83b9256886 100644 --- a/crypto/hashpriv.h +++ b/crypto/hashpriv.h @@ -1,6 +1,7 @@ /* * QEMU Crypto hash driver supports * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD. * * Authors: @@ -15,15 +16,21 @@ #ifndef QCRYPTO_HASHPRIV_H #define QCRYPTO_HASHPRIV_H +#include "crypto/hash.h" + typedef struct QCryptoHashDriver QCryptoHashDriver; struct QCryptoHashDriver { - int (*hash_bytesv)(QCryptoHashAlgo alg, + QCryptoHash *(*hash_new)(QCryptoHashAlgo alg, Error **errp); + int (*hash_update)(QCryptoHash *hash, const struct iovec *iov, size_t niov, - uint8_t **result, - size_t *resultlen, Error **errp); + int (*hash_finalize)(QCryptoHash *hash, + uint8_t **result, + size_t *resultlen, + Error **errp); + void (*hash_free)(QCryptoHash *hash); }; extern QCryptoHashDriver qcrypto_hash_lib_driver; diff --git a/disas/cris.c b/disas/cris.c deleted file mode 100644 index 409a224c5d..0000000000 --- a/disas/cris.c +++ /dev/null @@ -1,2863 +0,0 @@ -/* Disassembler code for CRIS. - Copyright 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. - Contributed by Axis Communications AB, Lund, Sweden. - Written by Hans-Peter Nilsson. - - This file is part of the GNU binutils and GDB, the GNU debugger. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any later - version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" -#include "target/cris/opcode-cris.h" - -#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) - -/* cris-opc.c -- Table of opcodes for the CRIS processor. - Copyright 2000, 2001, 2004 Free Software Foundation, Inc. - Contributed by Axis Communications AB, Lund, Sweden. - Originally written for GAS 1.38.1 by Mikael Asker. - Reorganized by Hans-Peter Nilsson. - -This file is part of GAS, GDB and the GNU binutils. - -GAS, GDB, and GNU binutils is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2, or (at your -option) any later version. - -GAS, GDB, and GNU binutils are distributed in the hope that they will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, see <http://www.gnu.org/licenses/>. */ - -#ifndef NULL -#define NULL (0) -#endif - -/* This table isn't used for CRISv32 and the size of immediate operands. */ -const struct cris_spec_reg -cris_spec_regs[] = -{ - {"bz", 0, 1, cris_ver_v32p, NULL}, - {"p0", 0, 1, 0, NULL}, - {"vr", 1, 1, 0, NULL}, - {"p1", 1, 1, 0, NULL}, - {"pid", 2, 1, cris_ver_v32p, NULL}, - {"p2", 2, 1, cris_ver_v32p, NULL}, - {"p2", 2, 1, cris_ver_warning, NULL}, - {"srs", 3, 1, cris_ver_v32p, NULL}, - {"p3", 3, 1, cris_ver_v32p, NULL}, - {"p3", 3, 1, cris_ver_warning, NULL}, - {"wz", 4, 2, cris_ver_v32p, NULL}, - {"p4", 4, 2, 0, NULL}, - {"ccr", 5, 2, cris_ver_v0_10, NULL}, - {"exs", 5, 4, cris_ver_v32p, NULL}, - {"p5", 5, 2, cris_ver_v0_10, NULL}, - {"p5", 5, 4, cris_ver_v32p, NULL}, - {"dcr0",6, 2, cris_ver_v0_3, NULL}, - {"eda", 6, 4, cris_ver_v32p, NULL}, - {"p6", 6, 2, cris_ver_v0_3, NULL}, - {"p6", 6, 4, cris_ver_v32p, NULL}, - {"dcr1/mof", 7, 4, cris_ver_v10p, - "Register `dcr1/mof' with ambiguous size specified. Guessing 4 bytes"}, - {"dcr1/mof", 7, 2, cris_ver_v0_3, - "Register `dcr1/mof' with ambiguous size specified. Guessing 2 bytes"}, - {"mof", 7, 4, cris_ver_v10p, NULL}, - {"dcr1",7, 2, cris_ver_v0_3, NULL}, - {"p7", 7, 4, cris_ver_v10p, NULL}, - {"p7", 7, 2, cris_ver_v0_3, NULL}, - {"dz", 8, 4, cris_ver_v32p, NULL}, - {"p8", 8, 4, 0, NULL}, - {"ibr", 9, 4, cris_ver_v0_10, NULL}, - {"ebp", 9, 4, cris_ver_v32p, NULL}, - {"p9", 9, 4, 0, NULL}, - {"irp", 10, 4, cris_ver_v0_10, NULL}, - {"erp", 10, 4, cris_ver_v32p, NULL}, - {"p10", 10, 4, 0, NULL}, - {"srp", 11, 4, 0, NULL}, - {"p11", 11, 4, 0, NULL}, - /* For disassembly use only. Accept at assembly with a warning. */ - {"bar/dtp0", 12, 4, cris_ver_warning, - "Ambiguous register `bar/dtp0' specified"}, - {"nrp", 12, 4, cris_ver_v32p, NULL}, - {"bar", 12, 4, cris_ver_v8_10, NULL}, - {"dtp0",12, 4, cris_ver_v0_3, NULL}, - {"p12", 12, 4, 0, NULL}, - /* For disassembly use only. Accept at assembly with a warning. */ - {"dccr/dtp1",13, 4, cris_ver_warning, - "Ambiguous register `dccr/dtp1' specified"}, - {"ccs", 13, 4, cris_ver_v32p, NULL}, - {"dccr",13, 4, cris_ver_v8_10, NULL}, - {"dtp1",13, 4, cris_ver_v0_3, NULL}, - {"p13", 13, 4, 0, NULL}, - {"brp", 14, 4, cris_ver_v3_10, NULL}, - {"usp", 14, 4, cris_ver_v32p, NULL}, - {"p14", 14, 4, cris_ver_v3p, NULL}, - {"usp", 15, 4, cris_ver_v10, NULL}, - {"spc", 15, 4, cris_ver_v32p, NULL}, - {"p15", 15, 4, cris_ver_v10p, NULL}, - {NULL, 0, 0, cris_ver_version_all, NULL} -}; - -/* Add version specifiers to this table when necessary. - The (now) regular coding of register names suggests a simpler - implementation. */ -const struct cris_support_reg cris_support_regs[] = -{ - {"s0", 0}, - {"s1", 1}, - {"s2", 2}, - {"s3", 3}, - {"s4", 4}, - {"s5", 5}, - {"s6", 6}, - {"s7", 7}, - {"s8", 8}, - {"s9", 9}, - {"s10", 10}, - {"s11", 11}, - {"s12", 12}, - {"s13", 13}, - {"s14", 14}, - {"s15", 15}, - {NULL, 0} -}; - -/* All CRIS opcodes are 16 bits. - - - The match component is a mask saying which bits must match a - particular opcode in order for an instruction to be an instance - of that opcode. - - - The args component is a string containing characters symbolically - matching the operands of an instruction. Used for both assembly - and disassembly. - - Operand-matching characters: - [ ] , space - Verbatim. - A The string "ACR" (case-insensitive). - B Not really an operand. It causes a "BDAP -size,SP" prefix to be - output for the PUSH alias-instructions and recognizes a push- - prefix at disassembly. This letter isn't recognized for v32. - Must be followed by a R or P letter. - ! Non-match pattern, will not match if there's a prefix insn. - b Non-matching operand, used for branches with 16-bit - displacement. Only recognized by the disassembler. - c 5-bit unsigned immediate in bits <4:0>. - C 4-bit unsigned immediate in bits <3:0>. - d At assembly, optionally (as in put other cases before this one) - ".d" or ".D" at the start of the operands, followed by one space - character. At disassembly, nothing. - D General register in bits <15:12> and <3:0>. - f List of flags in bits <15:12> and <3:0>. - i 6-bit signed immediate in bits <5:0>. - I 6-bit unsigned immediate in bits <5:0>. - M Size modifier (B, W or D) for CLEAR instructions. - m Size modifier (B, W or D) in bits <5:4> - N A 32-bit dword, like in the difference between s and y. - This has no effect on bits in the opcode. Can also be expressed - as "[pc+]" in input. - n As N, but PC-relative (to the start of the instruction). - o [-128..127] word offset in bits <7:1> and <0>. Used by 8-bit - branch instructions. - O [-128..127] offset in bits <7:0>. Also matches a comma and a - general register after the expression, in bits <15:12>. Used - only for the BDAP prefix insn (in v32 the ADDOQ insn; same opcode). - P Special register in bits <15:12>. - p Indicates that the insn is a prefix insn. Must be first - character. - Q As O, but don't relax; force an 8-bit offset. - R General register in bits <15:12>. - r General register in bits <3:0>. - S Source operand in bit <10> and a prefix; a 3-operand prefix - without side-effect. - s Source operand in bits <10> and <3:0>, optionally with a - side-effect prefix, except [pc] (the name, not R15 as in ACR) - isn't allowed for v32 and higher. - T Support register in bits <15:12>. - u 4-bit (PC-relative) unsigned immediate word offset in bits <3:0>. - U Relaxes to either u or n, instruction is assumed LAPCQ or LAPC. - Not recognized at disassembly. - x Register-dot-modifier, for example "r5.w" in bits <15:12> and <5:4>. - y Like 's' but do not allow an integer at assembly. - Y The difference s-y; only an integer is allowed. - z Size modifier (B or W) in bit <4>. */ - - -/* Please note the order of the opcodes in this table is significant. - The assembler requires that all instances of the same mnemonic must - be consecutive. If they aren't, the assembler might not recognize - them, or may indicate an internal error. - - The disassembler should not normally care about the order of the - opcodes, but will prefer an earlier alternative if the "match-score" - (see cris-dis.c) is computed as equal. - - It should not be significant for proper execution that this table is - in alphabetical order, but please follow that convention for an easy - overview. */ - -const struct cris_opcode -cris_opcodes[] = -{ - {"abs", 0x06B0, 0x0940, "r,R", 0, SIZE_NONE, 0, - cris_abs_op}, - - {"add", 0x0600, 0x09c0, "m r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"add", 0x0A00, 0x01c0, "m S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"add", 0x0a00, 0x05c0, "m S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_add_sub_cmp_and_or_op}, - - {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, - cris_ver_v32p, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"addc", 0x0570, 0x0A80, "r,R", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_not_implemented_op}, - - {"addc", 0x09A0, 0x0250, "s,R", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_not_implemented_op}, - - {"addi", 0x0540, 0x0A80, "x,r,A", 0, SIZE_NONE, - cris_ver_v32p, - cris_addi_op}, - - {"addi", 0x0500, 0x0Ac0, "x,r", 0, SIZE_NONE, 0, - cris_addi_op}, - - /* This collates after "addo", but we want to disassemble as "addoq", - not "addo". */ - {"addoq", 0x0100, 0x0E00, "Q,A", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"addo", 0x0940, 0x0280, "m s,R,A", 0, SIZE_FIELD_SIGNED, - cris_ver_v32p, - cris_not_implemented_op}, - - /* This must be located after the insn above, lest we misinterpret - "addo.b -1,r0,acr" as "addo .b-1,r0,acr". FIXME: Sounds like a - parser bug. */ - {"addo", 0x0100, 0x0E00, "O,A", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"addq", 0x0200, 0x0Dc0, "I,R", 0, SIZE_NONE, 0, - cris_quick_mode_add_sub_op}, - - {"adds", 0x0420, 0x0Bc0, "z r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ - {"adds", 0x0820, 0x03c0, "z s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"adds", 0x0820, 0x03c0, "z S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"adds", 0x0820, 0x07c0, "z S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_add_sub_cmp_and_or_op}, - - {"addu", 0x0400, 0x0be0, "z r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ - {"addu", 0x0800, 0x03e0, "z s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"addu", 0x0800, 0x03e0, "z S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"addu", 0x0800, 0x07e0, "z S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_add_sub_cmp_and_or_op}, - - {"and", 0x0700, 0x08C0, "m r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - {"and", 0x0B00, 0x00C0, "m s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"and", 0x0B00, 0x00C0, "m S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"and", 0x0B00, 0x04C0, "m S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_add_sub_cmp_and_or_op}, - - {"andq", 0x0300, 0x0CC0, "i,R", 0, SIZE_NONE, 0, - cris_quick_mode_and_cmp_move_or_op}, - - {"asr", 0x0780, 0x0840, "m r,R", 0, SIZE_NONE, 0, - cris_asr_op}, - - {"asrq", 0x03a0, 0x0c40, "c,R", 0, SIZE_NONE, 0, - cris_asrq_op}, - - {"ax", 0x15B0, 0xEA4F, "", 0, SIZE_NONE, 0, - cris_ax_ei_setf_op}, - - /* FIXME: Should use branch #defines. */ - {"b", 0x0dff, 0x0200, "b", 1, SIZE_NONE, 0, - cris_sixteen_bit_offset_branch_op}, - - {"ba", - BA_QUICK_OPCODE, - 0x0F00+(0xF-CC_A)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - /* Needs to come after the usual "ba o", which might be relaxed to - this one. */ - {"ba", BA_DWORD_OPCODE, - 0xffff & (~BA_DWORD_OPCODE), "n", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_none_reg_mode_jump_op}, - - {"bas", 0x0EBF, 0x0140, "n,P", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_none_reg_mode_jump_op}, - - {"basc", 0x0EFF, 0x0100, "n,P", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_none_reg_mode_jump_op}, - - {"bcc", - BRANCH_QUICK_OPCODE+CC_CC*0x1000, - 0x0f00+(0xF-CC_CC)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bcs", - BRANCH_QUICK_OPCODE+CC_CS*0x1000, - 0x0f00+(0xF-CC_CS)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bdap", - BDAP_INDIR_OPCODE, BDAP_INDIR_Z_BITS, "pm s,R", 0, SIZE_FIELD_SIGNED, - cris_ver_v0_10, - cris_bdap_prefix}, - - {"bdap", - BDAP_QUICK_OPCODE, BDAP_QUICK_Z_BITS, "pO", 0, SIZE_NONE, - cris_ver_v0_10, - cris_quick_mode_bdap_prefix}, - - {"beq", - BRANCH_QUICK_OPCODE+CC_EQ*0x1000, - 0x0f00+(0xF-CC_EQ)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - /* This is deliberately put before "bext" to trump it, even though not - in alphabetical order, since we don't do excluding version checks - for v0..v10. */ - {"bwf", - BRANCH_QUICK_OPCODE+CC_EXT*0x1000, - 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, - cris_ver_v10, - cris_eight_bit_offset_branch_op}, - - {"bext", - BRANCH_QUICK_OPCODE+CC_EXT*0x1000, - 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, - cris_ver_v0_3, - cris_eight_bit_offset_branch_op}, - - {"bge", - BRANCH_QUICK_OPCODE+CC_GE*0x1000, - 0x0f00+(0xF-CC_GE)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bgt", - BRANCH_QUICK_OPCODE+CC_GT*0x1000, - 0x0f00+(0xF-CC_GT)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bhi", - BRANCH_QUICK_OPCODE+CC_HI*0x1000, - 0x0f00+(0xF-CC_HI)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bhs", - BRANCH_QUICK_OPCODE+CC_HS*0x1000, - 0x0f00+(0xF-CC_HS)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"biap", BIAP_OPCODE, BIAP_Z_BITS, "pm r,R", 0, SIZE_NONE, - cris_ver_v0_10, - cris_biap_prefix}, - - {"ble", - BRANCH_QUICK_OPCODE+CC_LE*0x1000, - 0x0f00+(0xF-CC_LE)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"blo", - BRANCH_QUICK_OPCODE+CC_LO*0x1000, - 0x0f00+(0xF-CC_LO)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bls", - BRANCH_QUICK_OPCODE+CC_LS*0x1000, - 0x0f00+(0xF-CC_LS)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"blt", - BRANCH_QUICK_OPCODE+CC_LT*0x1000, - 0x0f00+(0xF-CC_LT)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bmi", - BRANCH_QUICK_OPCODE+CC_MI*0x1000, - 0x0f00+(0xF-CC_MI)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bmod", 0x0ab0, 0x0140, "s,R", 0, SIZE_FIX_32, - cris_ver_sim_v0_10, - cris_not_implemented_op}, - - {"bmod", 0x0ab0, 0x0140, "S,D", 0, SIZE_NONE, - cris_ver_sim_v0_10, - cris_not_implemented_op}, - - {"bmod", 0x0ab0, 0x0540, "S,R,r", 0, SIZE_NONE, - cris_ver_sim_v0_10, - cris_not_implemented_op}, - - {"bne", - BRANCH_QUICK_OPCODE+CC_NE*0x1000, - 0x0f00+(0xF-CC_NE)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bound", 0x05c0, 0x0A00, "m r,R", 0, SIZE_NONE, 0, - cris_two_operand_bound_op}, - /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ - {"bound", 0x09c0, 0x0200, "m s,R", 0, SIZE_FIELD, - cris_ver_v0_10, - cris_two_operand_bound_op}, - /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ - {"bound", 0x0dcf, 0x0200, "m Y,R", 0, SIZE_FIELD, 0, - cris_two_operand_bound_op}, - {"bound", 0x09c0, 0x0200, "m S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_two_operand_bound_op}, - {"bound", 0x09c0, 0x0600, "m S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_bound_op}, - - {"bpl", - BRANCH_QUICK_OPCODE+CC_PL*0x1000, - 0x0f00+(0xF-CC_PL)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"break", 0xe930, 0x16c0, "C", 0, SIZE_NONE, - cris_ver_v3p, - cris_break_op}, - - {"bsb", - BRANCH_QUICK_OPCODE+CC_EXT*0x1000, - 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, - cris_ver_v32p, - cris_eight_bit_offset_branch_op}, - - {"bsr", 0xBEBF, 0x4140, "n", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_none_reg_mode_jump_op}, - - {"bsrc", 0xBEFF, 0x4100, "n", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_none_reg_mode_jump_op}, - - {"bstore", 0x0af0, 0x0100, "s,R", 0, SIZE_FIX_32, - cris_ver_warning, - cris_not_implemented_op}, - - {"bstore", 0x0af0, 0x0100, "S,D", 0, SIZE_NONE, - cris_ver_warning, - cris_not_implemented_op}, - - {"bstore", 0x0af0, 0x0500, "S,R,r", 0, SIZE_NONE, - cris_ver_warning, - cris_not_implemented_op}, - - {"btst", 0x04F0, 0x0B00, "r,R", 0, SIZE_NONE, 0, - cris_btst_nop_op}, - {"btstq", 0x0380, 0x0C60, "c,R", 0, SIZE_NONE, 0, - cris_btst_nop_op}, - - {"bvc", - BRANCH_QUICK_OPCODE+CC_VC*0x1000, - 0x0f00+(0xF-CC_VC)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"bvs", - BRANCH_QUICK_OPCODE+CC_VS*0x1000, - 0x0f00+(0xF-CC_VS)*0x1000, "o", 1, SIZE_NONE, 0, - cris_eight_bit_offset_branch_op}, - - {"clear", 0x0670, 0x3980, "M r", 0, SIZE_NONE, 0, - cris_reg_mode_clear_op}, - - {"clear", 0x0A70, 0x3180, "M y", 0, SIZE_NONE, 0, - cris_none_reg_mode_clear_test_op}, - - {"clear", 0x0A70, 0x3180, "M S", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_clear_test_op}, - - {"clearf", 0x05F0, 0x0A00, "f", 0, SIZE_NONE, 0, - cris_clearf_di_op}, - - {"cmp", 0x06C0, 0x0900, "m r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - {"cmp", 0x0Ac0, 0x0100, "m s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"cmp", 0x0Ac0, 0x0100, "m S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"cmpq", 0x02C0, 0x0D00, "i,R", 0, SIZE_NONE, 0, - cris_quick_mode_and_cmp_move_or_op}, - - /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ - {"cmps", 0x08e0, 0x0300, "z s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"cmps", 0x08e0, 0x0300, "z S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ - {"cmpu", 0x08c0, 0x0320, "z s,R" , 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"cmpu", 0x08c0, 0x0320, "z S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"di", 0x25F0, 0xDA0F, "", 0, SIZE_NONE, 0, - cris_clearf_di_op}, - - {"dip", DIP_OPCODE, DIP_Z_BITS, "ps", 0, SIZE_FIX_32, - cris_ver_v0_10, - cris_dip_prefix}, - - {"div", 0x0980, 0x0640, "m R,r", 0, SIZE_FIELD, 0, - cris_not_implemented_op}, - - {"dstep", 0x06f0, 0x0900, "r,R", 0, SIZE_NONE, 0, - cris_dstep_logshift_mstep_neg_not_op}, - - {"ei", 0x25B0, 0xDA4F, "", 0, SIZE_NONE, 0, - cris_ax_ei_setf_op}, - - {"fidxd", 0x0ab0, 0xf540, "[r]", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"fidxi", 0x0d30, 0xF2C0, "[r]", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"ftagd", 0x1AB0, 0xE540, "[r]", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"ftagi", 0x1D30, 0xE2C0, "[r]", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"halt", 0xF930, 0x06CF, "", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"jas", 0x09B0, 0x0640, "r,P", 0, SIZE_NONE, - cris_ver_v32p, - cris_reg_mode_jump_op}, - - {"jas", 0x0DBF, 0x0240, "N,P", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_reg_mode_jump_op}, - - {"jasc", 0x0B30, 0x04C0, "r,P", 0, SIZE_NONE, - cris_ver_v32p, - cris_reg_mode_jump_op}, - - {"jasc", 0x0F3F, 0x00C0, "N,P", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_reg_mode_jump_op}, - - {"jbrc", 0x69b0, 0x9640, "r", 0, SIZE_NONE, - cris_ver_v8_10, - cris_reg_mode_jump_op}, - - {"jbrc", 0x6930, 0x92c0, "s", 0, SIZE_FIX_32, - cris_ver_v8_10, - cris_none_reg_mode_jump_op}, - - {"jbrc", 0x6930, 0x92c0, "S", 0, SIZE_NONE, - cris_ver_v8_10, - cris_none_reg_mode_jump_op}, - - {"jir", 0xA9b0, 0x5640, "r", 0, SIZE_NONE, - cris_ver_v8_10, - cris_reg_mode_jump_op}, - - {"jir", 0xA930, 0x52c0, "s", 0, SIZE_FIX_32, - cris_ver_v8_10, - cris_none_reg_mode_jump_op}, - - {"jir", 0xA930, 0x52c0, "S", 0, SIZE_NONE, - cris_ver_v8_10, - cris_none_reg_mode_jump_op}, - - {"jirc", 0x29b0, 0xd640, "r", 0, SIZE_NONE, - cris_ver_v8_10, - cris_reg_mode_jump_op}, - - {"jirc", 0x2930, 0xd2c0, "s", 0, SIZE_FIX_32, - cris_ver_v8_10, - cris_none_reg_mode_jump_op}, - - {"jirc", 0x2930, 0xd2c0, "S", 0, SIZE_NONE, - cris_ver_v8_10, - cris_none_reg_mode_jump_op}, - - {"jsr", 0xB9b0, 0x4640, "r", 0, SIZE_NONE, 0, - cris_reg_mode_jump_op}, - - {"jsr", 0xB930, 0x42c0, "s", 0, SIZE_FIX_32, - cris_ver_v0_10, - cris_none_reg_mode_jump_op}, - - {"jsr", 0xBDBF, 0x4240, "N", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_none_reg_mode_jump_op}, - - {"jsr", 0xB930, 0x42c0, "S", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_jump_op}, - - {"jsrc", 0x39b0, 0xc640, "r", 0, SIZE_NONE, - cris_ver_v8_10, - cris_reg_mode_jump_op}, - - {"jsrc", 0x3930, 0xc2c0, "s", 0, SIZE_FIX_32, - cris_ver_v8_10, - cris_none_reg_mode_jump_op}, - - {"jsrc", 0x3930, 0xc2c0, "S", 0, SIZE_NONE, - cris_ver_v8_10, - cris_none_reg_mode_jump_op}, - - {"jsrc", 0xBB30, 0x44C0, "r", 0, SIZE_NONE, - cris_ver_v32p, - cris_reg_mode_jump_op}, - - {"jsrc", 0xBF3F, 0x40C0, "N", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_reg_mode_jump_op}, - - {"jump", 0x09b0, 0xF640, "r", 0, SIZE_NONE, 0, - cris_reg_mode_jump_op}, - - {"jump", - JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "s", 0, SIZE_FIX_32, - cris_ver_v0_10, - cris_none_reg_mode_jump_op}, - - {"jump", - JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "S", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_jump_op}, - - {"jump", 0x09F0, 0x060F, "P", 0, SIZE_NONE, - cris_ver_v32p, - cris_none_reg_mode_jump_op}, - - {"jump", - JUMP_PC_INCR_OPCODE_V32, - (0xffff & ~JUMP_PC_INCR_OPCODE_V32), "N", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_none_reg_mode_jump_op}, - - {"jmpu", 0x8930, 0x72c0, "s", 0, SIZE_FIX_32, - cris_ver_v10, - cris_none_reg_mode_jump_op}, - - {"jmpu", 0x8930, 0x72c0, "S", 0, SIZE_NONE, - cris_ver_v10, - cris_none_reg_mode_jump_op}, - - {"lapc", 0x0970, 0x0680, "U,R", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"lapc", 0x0D7F, 0x0280, "dn,R", 0, SIZE_FIX_32, - cris_ver_v32p, - cris_not_implemented_op}, - - {"lapcq", 0x0970, 0x0680, "u,R", 0, SIZE_NONE, - cris_ver_v32p, - cris_addi_op}, - - {"lsl", 0x04C0, 0x0B00, "m r,R", 0, SIZE_NONE, 0, - cris_dstep_logshift_mstep_neg_not_op}, - - {"lslq", 0x03c0, 0x0C20, "c,R", 0, SIZE_NONE, 0, - cris_dstep_logshift_mstep_neg_not_op}, - - {"lsr", 0x07C0, 0x0800, "m r,R", 0, SIZE_NONE, 0, - cris_dstep_logshift_mstep_neg_not_op}, - - {"lsrq", 0x03e0, 0x0C00, "c,R", 0, SIZE_NONE, 0, - cris_dstep_logshift_mstep_neg_not_op}, - - {"lz", 0x0730, 0x08C0, "r,R", 0, SIZE_NONE, - cris_ver_v3p, - cris_not_implemented_op}, - - {"mcp", 0x07f0, 0x0800, "P,r", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"move", 0x0640, 0x0980, "m r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - {"move", 0x0A40, 0x0180, "m s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"move", 0x0A40, 0x0180, "m S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"move", 0x0630, 0x09c0, "r,P", 0, SIZE_NONE, 0, - cris_move_to_preg_op}, - - {"move", 0x0670, 0x0980, "P,r", 0, SIZE_NONE, 0, - cris_reg_mode_move_from_preg_op}, - - {"move", 0x0BC0, 0x0000, "m R,y", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"move", 0x0BC0, 0x0000, "m D,S", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"move", - MOVE_M_TO_PREG_OPCODE, MOVE_M_TO_PREG_ZBITS, - "s,P", 0, SIZE_SPEC_REG, 0, - cris_move_to_preg_op}, - - {"move", 0x0A30, 0x01c0, "S,P", 0, SIZE_NONE, - cris_ver_v0_10, - cris_move_to_preg_op}, - - {"move", 0x0A70, 0x0180, "P,y", 0, SIZE_SPEC_REG, 0, - cris_none_reg_mode_move_from_preg_op}, - - {"move", 0x0A70, 0x0180, "P,S", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_move_from_preg_op}, - - {"move", 0x0B70, 0x0480, "r,T", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"move", 0x0F70, 0x0080, "T,r", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"movem", 0x0BF0, 0x0000, "R,y", 0, SIZE_FIX_32, 0, - cris_move_reg_to_mem_movem_op}, - - {"movem", 0x0BF0, 0x0000, "D,S", 0, SIZE_NONE, - cris_ver_v0_10, - cris_move_reg_to_mem_movem_op}, - - {"movem", 0x0BB0, 0x0040, "s,R", 0, SIZE_FIX_32, 0, - cris_move_mem_to_reg_movem_op}, - - {"movem", 0x0BB0, 0x0040, "S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_move_mem_to_reg_movem_op}, - - {"moveq", 0x0240, 0x0D80, "i,R", 0, SIZE_NONE, 0, - cris_quick_mode_and_cmp_move_or_op}, - - {"movs", 0x0460, 0x0B80, "z r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ - {"movs", 0x0860, 0x0380, "z s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"movs", 0x0860, 0x0380, "z S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"movu", 0x0440, 0x0Ba0, "z r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ - {"movu", 0x0840, 0x03a0, "z s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"movu", 0x0840, 0x03a0, "z S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"mstep", 0x07f0, 0x0800, "r,R", 0, SIZE_NONE, - cris_ver_v0_10, - cris_dstep_logshift_mstep_neg_not_op}, - - {"muls", 0x0d00, 0x02c0, "m r,R", 0, SIZE_NONE, - cris_ver_v10p, - cris_muls_op}, - - {"mulu", 0x0900, 0x06c0, "m r,R", 0, SIZE_NONE, - cris_ver_v10p, - cris_mulu_op}, - - {"neg", 0x0580, 0x0A40, "m r,R", 0, SIZE_NONE, 0, - cris_dstep_logshift_mstep_neg_not_op}, - - {"nop", NOP_OPCODE, NOP_Z_BITS, "", 0, SIZE_NONE, - cris_ver_v0_10, - cris_btst_nop_op}, - - {"nop", NOP_OPCODE_V32, NOP_Z_BITS_V32, "", 0, SIZE_NONE, - cris_ver_v32p, - cris_btst_nop_op}, - - {"not", 0x8770, 0x7880, "r", 0, SIZE_NONE, 0, - cris_dstep_logshift_mstep_neg_not_op}, - - {"or", 0x0740, 0x0880, "m r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - {"or", 0x0B40, 0x0080, "m s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"or", 0x0B40, 0x0080, "m S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"or", 0x0B40, 0x0480, "m S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_add_sub_cmp_and_or_op}, - - {"orq", 0x0340, 0x0C80, "i,R", 0, SIZE_NONE, 0, - cris_quick_mode_and_cmp_move_or_op}, - - {"pop", 0x0E6E, 0x0191, "!R", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"pop", 0x0e3e, 0x01c1, "!P", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_move_from_preg_op}, - - {"push", 0x0FEE, 0x0011, "BR", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"push", 0x0E7E, 0x0181, "BP", 0, SIZE_NONE, - cris_ver_v0_10, - cris_move_to_preg_op}, - - {"rbf", 0x3b30, 0xc0c0, "y", 0, SIZE_NONE, - cris_ver_v10, - cris_not_implemented_op}, - - {"rbf", 0x3b30, 0xc0c0, "S", 0, SIZE_NONE, - cris_ver_v10, - cris_not_implemented_op}, - - {"rfe", 0x2930, 0xD6CF, "", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"rfg", 0x4930, 0xB6CF, "", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"rfn", 0x5930, 0xA6CF, "", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - {"ret", 0xB67F, 0x4980, "", 1, SIZE_NONE, - cris_ver_v0_10, - cris_reg_mode_move_from_preg_op}, - - {"ret", 0xB9F0, 0x460F, "", 1, SIZE_NONE, - cris_ver_v32p, - cris_reg_mode_move_from_preg_op}, - - {"retb", 0xe67f, 0x1980, "", 1, SIZE_NONE, - cris_ver_v0_10, - cris_reg_mode_move_from_preg_op}, - - {"rete", 0xA9F0, 0x560F, "", 1, SIZE_NONE, - cris_ver_v32p, - cris_reg_mode_move_from_preg_op}, - - {"reti", 0xA67F, 0x5980, "", 1, SIZE_NONE, - cris_ver_v0_10, - cris_reg_mode_move_from_preg_op}, - - {"retn", 0xC9F0, 0x360F, "", 1, SIZE_NONE, - cris_ver_v32p, - cris_reg_mode_move_from_preg_op}, - - {"sbfs", 0x3b70, 0xc080, "y", 0, SIZE_NONE, - cris_ver_v10, - cris_not_implemented_op}, - - {"sbfs", 0x3b70, 0xc080, "S", 0, SIZE_NONE, - cris_ver_v10, - cris_not_implemented_op}, - - {"sa", - 0x0530+CC_A*0x1000, - 0x0AC0+(0xf-CC_A)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"ssb", - 0x0530+CC_EXT*0x1000, - 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, - cris_ver_v32p, - cris_scc_op}, - - {"scc", - 0x0530+CC_CC*0x1000, - 0x0AC0+(0xf-CC_CC)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"scs", - 0x0530+CC_CS*0x1000, - 0x0AC0+(0xf-CC_CS)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"seq", - 0x0530+CC_EQ*0x1000, - 0x0AC0+(0xf-CC_EQ)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"setf", 0x05b0, 0x0A40, "f", 0, SIZE_NONE, 0, - cris_ax_ei_setf_op}, - - {"sfe", 0x3930, 0xC6CF, "", 0, SIZE_NONE, - cris_ver_v32p, - cris_not_implemented_op}, - - /* Need to have "swf" in front of "sext" so it is the one displayed in - disassembly. */ - {"swf", - 0x0530+CC_EXT*0x1000, - 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, - cris_ver_v10, - cris_scc_op}, - - {"sext", - 0x0530+CC_EXT*0x1000, - 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, - cris_ver_v0_3, - cris_scc_op}, - - {"sge", - 0x0530+CC_GE*0x1000, - 0x0AC0+(0xf-CC_GE)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"sgt", - 0x0530+CC_GT*0x1000, - 0x0AC0+(0xf-CC_GT)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"shi", - 0x0530+CC_HI*0x1000, - 0x0AC0+(0xf-CC_HI)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"shs", - 0x0530+CC_HS*0x1000, - 0x0AC0+(0xf-CC_HS)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"sle", - 0x0530+CC_LE*0x1000, - 0x0AC0+(0xf-CC_LE)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"slo", - 0x0530+CC_LO*0x1000, - 0x0AC0+(0xf-CC_LO)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"sls", - 0x0530+CC_LS*0x1000, - 0x0AC0+(0xf-CC_LS)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"slt", - 0x0530+CC_LT*0x1000, - 0x0AC0+(0xf-CC_LT)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"smi", - 0x0530+CC_MI*0x1000, - 0x0AC0+(0xf-CC_MI)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"sne", - 0x0530+CC_NE*0x1000, - 0x0AC0+(0xf-CC_NE)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"spl", - 0x0530+CC_PL*0x1000, - 0x0AC0+(0xf-CC_PL)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"sub", 0x0680, 0x0940, "m r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - {"sub", 0x0a80, 0x0140, "m s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"sub", 0x0a80, 0x0140, "m S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"sub", 0x0a80, 0x0540, "m S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_add_sub_cmp_and_or_op}, - - {"subq", 0x0280, 0x0d40, "I,R", 0, SIZE_NONE, 0, - cris_quick_mode_add_sub_op}, - - {"subs", 0x04a0, 0x0b40, "z r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ - {"subs", 0x08a0, 0x0340, "z s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"subs", 0x08a0, 0x0340, "z S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"subs", 0x08a0, 0x0740, "z S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_add_sub_cmp_and_or_op}, - - {"subu", 0x0480, 0x0b60, "z r,R", 0, SIZE_NONE, 0, - cris_reg_mode_add_sub_cmp_and_or_move_op}, - - /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ - {"subu", 0x0880, 0x0360, "z s,R", 0, SIZE_FIELD, 0, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"subu", 0x0880, 0x0360, "z S,D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_add_sub_cmp_and_or_move_op}, - - {"subu", 0x0880, 0x0760, "z S,R,r", 0, SIZE_NONE, - cris_ver_v0_10, - cris_three_operand_add_sub_cmp_and_or_op}, - - {"svc", - 0x0530+CC_VC*0x1000, - 0x0AC0+(0xf-CC_VC)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - {"svs", - 0x0530+CC_VS*0x1000, - 0x0AC0+(0xf-CC_VS)*0x1000, "r", 0, SIZE_NONE, 0, - cris_scc_op}, - - /* The insn "swapn" is the same as "not" and will be disassembled as - such, but the swap* family of mnmonics are generally v8-and-higher - only, so count it in. */ - {"swapn", 0x8770, 0x7880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapw", 0x4770, 0xb880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapnw", 0xc770, 0x3880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapb", 0x2770, 0xd880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapnb", 0xA770, 0x5880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapwb", 0x6770, 0x9880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapnwb", 0xE770, 0x1880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapr", 0x1770, 0xe880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapnr", 0x9770, 0x6880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapwr", 0x5770, 0xa880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapnwr", 0xd770, 0x2880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapbr", 0x3770, 0xc880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapnbr", 0xb770, 0x4880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapwbr", 0x7770, 0x8880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"swapnwbr", 0xf770, 0x0880, "r", 0, SIZE_NONE, - cris_ver_v8p, - cris_not_implemented_op}, - - {"test", 0x0640, 0x0980, "m D", 0, SIZE_NONE, - cris_ver_v0_10, - cris_reg_mode_test_op}, - - {"test", 0x0b80, 0xf040, "m y", 0, SIZE_FIELD, 0, - cris_none_reg_mode_clear_test_op}, - - {"test", 0x0b80, 0xf040, "m S", 0, SIZE_NONE, - cris_ver_v0_10, - cris_none_reg_mode_clear_test_op}, - - {"xor", 0x07B0, 0x0840, "r,R", 0, SIZE_NONE, 0, - cris_xor_op}, - - {NULL, 0, 0, NULL, 0, 0, 0, cris_not_implemented_op} -}; - -/* Condition-names, indexed by the CC_* numbers as found in cris.h. */ -const char * const -cris_cc_strings[] = -{ - "hs", - "lo", - "ne", - "eq", - "vc", - "vs", - "pl", - "mi", - "ls", - "hi", - "ge", - "lt", - "gt", - "le", - "a", - /* This is a placeholder. In v0, this would be "ext". In v32, this - is "sb". */ - "wf" -}; - -/* - * Local variables: - * eval: (c-set-style "gnu") - * indent-tabs-mode: t - * End: - */ - - -/* No instruction will be disassembled longer than this. In theory, and - in silicon, address prefixes can be cascaded. In practice, cascading - is not used by GCC, and not supported by the assembler. */ -#ifndef MAX_BYTES_PER_CRIS_INSN -#define MAX_BYTES_PER_CRIS_INSN 8 -#endif - -/* Whether or not to decode prefixes, folding it into the following - instruction. FIXME: Make this optional later. */ -#ifndef PARSE_PREFIX -#define PARSE_PREFIX 1 -#endif - -/* Sometimes we prefix all registers with this character. */ -#define REGISTER_PREFIX_CHAR '$' - -/* Whether or not to trace the following sequence: - sub* X,r%d - bound* Y,r%d - adds.w [pc+r%d.w],pc - - This is the assembly form of a switch-statement in C. - The "sub is optional. If there is none, then X will be zero. - X is the value of the first case, - Y is the number of cases (including default). - - This results in case offsets printed on the form: - case N: -> case_address - where N is an estimation on the corresponding 'case' operand in C, - and case_address is where execution of that case continues after the - sequence presented above. - - The old style of output was to print the offsets as instructions, - which made it hard to follow "case"-constructs in the disassembly, - and caused a lot of annoying warnings about undefined instructions. - - FIXME: Make this optional later. */ -#ifndef TRACE_CASE -#define TRACE_CASE (disdata->trace_case) -#endif - -enum cris_disass_family - { cris_dis_v0_v10, cris_dis_common_v10_v32, cris_dis_v32 }; - -/* Stored in the disasm_info->private_data member. */ -struct cris_disasm_data -{ - /* Whether to print something less confusing if we find something - matching a switch-construct. */ - bfd_boolean trace_case; - - /* Whether this code is flagged as crisv32. FIXME: Should be an enum - that includes "compatible". */ - enum cris_disass_family distype; -}; - -/* Value of first element in switch. */ -static long case_offset = 0; - -/* How many more case-offsets to print. */ -static long case_offset_counter = 0; - -/* Number of case offsets. */ -static long no_of_case_offsets = 0; - -/* Candidate for next case_offset. */ -static long last_immediate = 0; - -static int cris_constraint - (const char *, unsigned, unsigned, struct cris_disasm_data *); - -/* Parse disassembler options and store state in info. FIXME: For the - time being, we abuse static variables. */ - -static void -cris_parse_disassembler_options (struct cris_disasm_data *disdata, - char *disassembler_options, - enum cris_disass_family distype) -{ - /* Default true. */ - disdata->trace_case - = (disassembler_options == NULL - || (strcmp (disassembler_options, "nocase") != 0)); - - disdata->distype = distype; -} - -static const struct cris_spec_reg * -spec_reg_info (unsigned int sreg, enum cris_disass_family distype) -{ - int i; - - for (i = 0; cris_spec_regs[i].name != NULL; i++) - { - if (cris_spec_regs[i].number == sreg) - { - if (distype == cris_dis_v32) - switch (cris_spec_regs[i].applicable_version) - { - case cris_ver_warning: - case cris_ver_version_all: - case cris_ver_v3p: - case cris_ver_v8p: - case cris_ver_v10p: - case cris_ver_v32p: - /* No ambiguous sizes or register names with CRISv32. */ - if (cris_spec_regs[i].warning == NULL) - return &cris_spec_regs[i]; - default: - ; - } - else if (cris_spec_regs[i].applicable_version != cris_ver_v32p) - return &cris_spec_regs[i]; - } - } - - return NULL; -} - -/* Return the number of bits in the argument. */ - -static int -number_of_bits (unsigned int val) -{ - int bits; - - for (bits = 0; val != 0; val &= val - 1) - bits++; - - return bits; -} - -/* Get an entry in the opcode-table. */ - -static const struct cris_opcode * -get_opcode_entry (unsigned int insn, - unsigned int prefix_insn, - struct cris_disasm_data *disdata) -{ - /* For non-prefixed insns, we keep a table of pointers, indexed by the - insn code. Each entry is initialized when found to be NULL. */ - static const struct cris_opcode **opc_table = NULL; - - const struct cris_opcode *max_matchedp = NULL; - const struct cris_opcode **prefix_opc_table = NULL; - - /* We hold a table for each prefix that need to be handled differently. */ - static const struct cris_opcode **dip_prefixes = NULL; - static const struct cris_opcode **bdapq_m1_prefixes = NULL; - static const struct cris_opcode **bdapq_m2_prefixes = NULL; - static const struct cris_opcode **bdapq_m4_prefixes = NULL; - static const struct cris_opcode **rest_prefixes = NULL; - - /* Allocate and clear the opcode-table. */ - if (opc_table == NULL) - { - opc_table = g_new0(const struct cris_opcode *, 65536); - dip_prefixes = g_new0(const struct cris_opcode *, 65536); - bdapq_m1_prefixes = g_new0(const struct cris_opcode *, 65536); - bdapq_m2_prefixes = g_new0(const struct cris_opcode *, 65536); - bdapq_m4_prefixes = g_new0(const struct cris_opcode *, 65536); - rest_prefixes = g_new0(const struct cris_opcode *, 65536); - } - - /* Get the right table if this is a prefix. - This code is connected to cris_constraints in that it knows what - prefixes play a role in recognition of patterns; the necessary - state is reflected by which table is used. If constraints - involving match or non-match of prefix insns are changed, then this - probably needs changing too. */ - if (prefix_insn != NO_CRIS_PREFIX) - { - const struct cris_opcode *popcodep - = (opc_table[prefix_insn] != NULL - ? opc_table[prefix_insn] - : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata)); - - if (popcodep == NULL) - return NULL; - - if (popcodep->match == BDAP_QUICK_OPCODE) - { - /* Since some offsets are recognized with "push" macros, we - have to have different tables for them. */ - int offset = (prefix_insn & 255); - - if (offset > 127) - offset -= 256; - - switch (offset) - { - case -4: - prefix_opc_table = bdapq_m4_prefixes; - break; - - case -2: - prefix_opc_table = bdapq_m2_prefixes; - break; - - case -1: - prefix_opc_table = bdapq_m1_prefixes; - break; - - default: - prefix_opc_table = rest_prefixes; - break; - } - } - else if (popcodep->match == DIP_OPCODE) - /* We don't allow postincrement when the prefix is DIP, so use a - different table for DIP. */ - prefix_opc_table = dip_prefixes; - else - prefix_opc_table = rest_prefixes; - } - - if (prefix_insn != NO_CRIS_PREFIX - && prefix_opc_table[insn] != NULL) - max_matchedp = prefix_opc_table[insn]; - else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL) - max_matchedp = opc_table[insn]; - else - { - const struct cris_opcode *opcodep; - int max_level_of_match = -1; - - for (opcodep = cris_opcodes; - opcodep->name != NULL; - opcodep++) - { - int level_of_match; - - if (disdata->distype == cris_dis_v32) - { - switch (opcodep->applicable_version) - { - case cris_ver_version_all: - break; - - case cris_ver_v0_3: - case cris_ver_v0_10: - case cris_ver_v3_10: - case cris_ver_sim_v0_10: - case cris_ver_v8_10: - case cris_ver_v10: - case cris_ver_warning: - continue; - - case cris_ver_v3p: - case cris_ver_v8p: - case cris_ver_v10p: - case cris_ver_v32p: - break; - - case cris_ver_v8: - abort (); - default: - abort (); - } - } - else - { - switch (opcodep->applicable_version) - { - case cris_ver_version_all: - case cris_ver_v0_3: - case cris_ver_v3p: - case cris_ver_v0_10: - case cris_ver_v8p: - case cris_ver_v8_10: - case cris_ver_v10: - case cris_ver_sim_v0_10: - case cris_ver_v10p: - case cris_ver_warning: - break; - - case cris_ver_v32p: - continue; - - case cris_ver_v8: - abort (); - default: - abort (); - } - } - - /* We give a double lead for bits matching the template in - cris_opcodes. Not even, because then "move p8,r10" would - be given 2 bits lead over "clear.d r10". When there's a - tie, the first entry in the table wins. This is - deliberate, to avoid a more complicated recognition - formula. */ - if ((opcodep->match & insn) == opcodep->match - && (opcodep->lose & insn) == 0 - && ((level_of_match - = cris_constraint (opcodep->args, - insn, - prefix_insn, - disdata)) - >= 0) - && ((level_of_match - += 2 * number_of_bits (opcodep->match - | opcodep->lose)) - > max_level_of_match)) - { - max_matchedp = opcodep; - max_level_of_match = level_of_match; - - /* If there was a full match, never mind looking - further. */ - if (level_of_match >= 2 * 16) - break; - } - } - /* Fill in the new entry. - - If there are changes to the opcode-table involving prefixes, and - disassembly then does not work correctly, try removing the - else-clause below that fills in the prefix-table. If that - helps, you need to change the prefix_opc_table setting above, or - something related. */ - if (prefix_insn == NO_CRIS_PREFIX) - opc_table[insn] = max_matchedp; - else - prefix_opc_table[insn] = max_matchedp; - } - - return max_matchedp; -} - -/* Return -1 if the constraints of a bitwise-matched instruction say - that there is no match. Otherwise return a nonnegative number - indicating the confidence in the match (higher is better). */ - -static int -cris_constraint (const char *cs, - unsigned int insn, - unsigned int prefix_insn, - struct cris_disasm_data *disdata) -{ - int retval = 0; - int tmp; - int prefix_ok = 0; - const char *s; - - for (s = cs; *s; s++) - switch (*s) - { - case '!': - /* Do not recognize "pop" if there's a prefix and then only for - v0..v10. */ - if (prefix_insn != NO_CRIS_PREFIX - || disdata->distype != cris_dis_v0_v10) - return -1; - break; - - case 'U': - /* Not recognized at disassembly. */ - return -1; - - case 'M': - /* Size modifier for "clear", i.e. special register 0, 4 or 8. - Check that it is one of them. Only special register 12 could - be mismatched, but checking for matches is more logical than - checking for mismatches when there are only a few cases. */ - tmp = ((insn >> 12) & 0xf); - if (tmp != 0 && tmp != 4 && tmp != 8) - return -1; - break; - - case 'm': - if ((insn & 0x30) == 0x30) - return -1; - break; - - case 'S': - /* A prefix operand without side-effect. */ - if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0) - { - prefix_ok = 1; - break; - } - else - return -1; - - case 's': - case 'y': - case 'Y': - /* If this is a prefixed insn with postincrement (side-effect), - the prefix must not be DIP. */ - if (prefix_insn != NO_CRIS_PREFIX) - { - if (insn & 0x400) - { - const struct cris_opcode *prefix_opcodep - = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); - - if (prefix_opcodep->match == DIP_OPCODE) - return -1; - } - - prefix_ok = 1; - } - break; - - case 'B': - /* If we don't fall through, then the prefix is ok. */ - prefix_ok = 1; - - /* A "push" prefix. Check for valid "push" size. - In case of special register, it may be != 4. */ - if (prefix_insn != NO_CRIS_PREFIX) - { - /* Match the prefix insn to BDAPQ. */ - const struct cris_opcode *prefix_opcodep - = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); - - if (prefix_opcodep->match == BDAP_QUICK_OPCODE) - { - int pushsize = (prefix_insn & 255); - - if (pushsize > 127) - pushsize -= 256; - - if (s[1] == 'P') - { - unsigned int spec_reg = (insn >> 12) & 15; - const struct cris_spec_reg *sregp - = spec_reg_info (spec_reg, disdata->distype); - - /* For a special-register, the "prefix size" must - match the size of the register. */ - if (sregp && sregp->reg_size == (unsigned int) -pushsize) - break; - } - else if (s[1] == 'R') - { - if ((insn & 0x30) == 0x20 && pushsize == -4) - break; - } - /* FIXME: Should abort here; next constraint letter - *must* be 'P' or 'R'. */ - } - } - return -1; - - case 'D': - retval = (((insn >> 12) & 15) == (insn & 15)); - if (!retval) - return -1; - else - retval += 4; - break; - - case 'P': - { - const struct cris_spec_reg *sregp - = spec_reg_info ((insn >> 12) & 15, disdata->distype); - - /* Since we match four bits, we will give a value of 4-1 = 3 - in a match. If there is a corresponding exact match of a - special register in another pattern, it will get a value of - 4, which will be higher. This should be correct in that an - exact pattern would match better than a general pattern. - - Note that there is a reason for not returning zero; the - pattern for "clear" is partly matched in the bit-pattern - (the two lower bits must be zero), while the bit-pattern - for a move from a special register is matched in the - register constraint. */ - - if (sregp != NULL) - { - retval += 3; - break; - } - else - return -1; - } - } - - if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok) - return -1; - - return retval; -} - -/* Format number as hex with a leading "0x" into outbuffer. */ - -static char * -format_hex (unsigned long number, - char *outbuffer, - struct cris_disasm_data *disdata) -{ - /* Truncate negative numbers on >32-bit hosts. */ - number &= 0xffffffff; - - sprintf (outbuffer, "0x%lx", number); - - /* Save this value for the "case" support. */ - if (TRACE_CASE) - last_immediate = number; - - return outbuffer + strlen (outbuffer); -} - -/* Format number as decimal into outbuffer. Parameter signedp says - whether the number should be formatted as signed (!= 0) or - unsigned (== 0). */ - -static char * -format_dec (long number, char *outbuffer, size_t outsize, int signedp) -{ - last_immediate = number; - snprintf (outbuffer, outsize, signedp ? "%ld" : "%lu", number); - - return outbuffer + strlen (outbuffer); -} - -/* Format the name of the general register regno into outbuffer. */ - -static char * -format_reg (struct cris_disasm_data *disdata, - int regno, - char *outbuffer_start, - bfd_boolean with_reg_prefix) -{ - char *outbuffer = outbuffer_start; - - if (with_reg_prefix) - *outbuffer++ = REGISTER_PREFIX_CHAR; - - switch (regno) - { - case 15: - /* For v32, there is no context in which we output PC. */ - if (disdata->distype == cris_dis_v32) - strcpy (outbuffer, "acr"); - else - strcpy (outbuffer, "pc"); - break; - - case 14: - strcpy (outbuffer, "sp"); - break; - - default: - sprintf (outbuffer, "r%d", regno); - break; - } - - return outbuffer_start + strlen (outbuffer_start); -} - -/* Format the name of a support register into outbuffer. */ - -static char * -format_sup_reg (unsigned int regno, - char *outbuffer_start, - bfd_boolean with_reg_prefix) -{ - char *outbuffer = outbuffer_start; - int i; - - if (with_reg_prefix) - *outbuffer++ = REGISTER_PREFIX_CHAR; - - for (i = 0; cris_support_regs[i].name != NULL; i++) - if (cris_support_regs[i].number == regno) - { - sprintf (outbuffer, "%s", cris_support_regs[i].name); - return outbuffer_start + strlen (outbuffer_start); - } - - /* There's supposed to be register names covering all numbers, though - some may be generic names. */ - sprintf (outbuffer, "format_sup_reg-BUG"); - return outbuffer_start + strlen (outbuffer_start); -} - -/* Return the length of an instruction. */ - -static unsigned -bytes_to_skip (unsigned int insn, - const struct cris_opcode *matchedp, - enum cris_disass_family distype, - const struct cris_opcode *prefix_matchedp) -{ - /* Each insn is a word plus "immediate" operands. */ - unsigned to_skip = 2; - const char *template = matchedp->args; - const char *s; - - for (s = template; *s; s++) - if ((*s == 's' || *s == 'N' || *s == 'Y') - && (insn & 0x400) && (insn & 15) == 15 - && prefix_matchedp == NULL) - { - /* Immediate via [pc+], so we have to check the size of the - operand. */ - int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3)); - - if (matchedp->imm_oprnd_size == SIZE_FIX_32) - to_skip += 4; - else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG) - { - const struct cris_spec_reg *sregp - = spec_reg_info ((insn >> 12) & 15, distype); - - /* FIXME: Improve error handling; should have been caught - earlier. */ - if (sregp == NULL) - return 2; - - /* PC is incremented by two, not one, for a byte. Except on - CRISv32, where constants are always DWORD-size for - special registers. */ - to_skip += - distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1; - } - else - to_skip += (mode_size + 1) & ~1; - } - else if (*s == 'n') - to_skip += 4; - else if (*s == 'b') - to_skip += 2; - - return to_skip; -} - -/* Print condition code flags. */ - -static char * -print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp) -{ - /* Use the v8 (Etrax 100) flag definitions for disassembly. - The differences with v0 (Etrax 1..4) vs. Svinto are: - v0 'd' <=> v8 'm' - v0 'e' <=> v8 'b'. - FIXME: Emit v0..v3 flag names somehow. */ - static const char v8_fnames[] = "cvznxibm"; - static const char v32_fnames[] = "cvznxiup"; - const char *fnames - = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames; - - unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15)); - int i; - - for (i = 0; i < 8; i++) - if (flagbits & (1 << i)) - *cp++ = fnames[i]; - - return cp; -} - -#define FORMAT_DEC(number, tp, signedp) \ - format_dec (number, tp, ({ \ - assert(tp >= temp && tp <= temp + sizeof(temp)); \ - temp + sizeof(temp) - tp; \ - }), signedp) - -/* Print out an insn with its operands, and update the info->insn_type - fields. The prefix_opcodep and the rest hold a prefix insn that is - supposed to be output as an address mode. */ - -static void -print_with_operands (const struct cris_opcode *opcodep, - unsigned int insn, - unsigned char *buffer, - bfd_vma addr, - disassemble_info *info, - /* If a prefix insn was before this insn (and is supposed - to be output as an address), here is a description of - it. */ - const struct cris_opcode *prefix_opcodep, - unsigned int prefix_insn, - unsigned char *prefix_buffer, - bfd_boolean with_reg_prefix) -{ - /* Get a buffer of somewhat reasonable size where we store - intermediate parts of the insn. */ - char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2]; - char *tp = temp; - static const char mode_char[] = "bwd?"; - const char *s; - const char *cs; - struct cris_disasm_data *disdata - = (struct cris_disasm_data *) info->private_data; - - /* Print out the name first thing we do. */ - (*info->fprintf_func) (info->stream, "%s", opcodep->name); - - cs = opcodep->args; - s = cs; - - /* Ignore any prefix indicator. */ - if (*s == 'p') - s++; - - if (*s == 'm' || *s == 'M' || *s == 'z') - { - *tp++ = '.'; - - /* Get the size-letter. */ - *tp++ = *s == 'M' - ? (insn & 0x8000 ? 'd' - : insn & 0x4000 ? 'w' : 'b') - : mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)]; - - /* Ignore the size and the space character that follows. */ - s += 2; - } - - /* Add a space if this isn't a long-branch, because for those will add - the condition part of the name later. */ - if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256)) - *tp++ = ' '; - - /* Fill in the insn-type if deducible from the name (and there's no - better way). */ - if (opcodep->name[0] == 'j') - { - if (CONST_STRNEQ (opcodep->name, "jsr")) - /* It's "jsr" or "jsrc". */ - info->insn_type = dis_jsr; - else - /* Any other jump-type insn is considered a branch. */ - info->insn_type = dis_branch; - } - - /* We might know some more fields right now. */ - info->branch_delay_insns = opcodep->delayed; - - /* Handle operands. */ - for (; *s; s++) - { - switch (*s) - { - case 'T': - tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix); - break; - - case 'A': - if (with_reg_prefix) - *tp++ = REGISTER_PREFIX_CHAR; - *tp++ = 'a'; - *tp++ = 'c'; - *tp++ = 'r'; - break; - - case '[': - case ']': - case ',': - *tp++ = *s; - break; - - case '!': - /* Ignore at this point; used at earlier stages to avoid - recognition if there's a prefix at something that in other - ways looks like a "pop". */ - break; - - case 'd': - /* Ignore. This is an optional ".d " on the large one of - relaxable insns. */ - break; - - case 'B': - /* This was the prefix that made this a "push". We've already - handled it by recognizing it, so signal that the prefix is - handled by setting it to NULL. */ - prefix_opcodep = NULL; - break; - - case 'D': - case 'r': - tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); - break; - - case 'R': - tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); - break; - - case 'n': - { - /* Like N but pc-relative to the start of the insn. */ - uint32_t number - = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536 - + buffer[5] * 0x1000000 + addr); - - /* Finish off and output previous formatted bytes. */ - *tp = 0; - if (temp[0]) - (*info->fprintf_func) (info->stream, "%s", temp); - tp = temp; - - (*info->print_address_func) ((bfd_vma) number, info); - } - break; - - case 'u': - { - /* Like n but the offset is bits <3:0> in the instruction. */ - unsigned long number = (buffer[0] & 0xf) * 2 + addr; - - /* Finish off and output previous formatted bytes. */ - *tp = 0; - if (temp[0]) - (*info->fprintf_func) (info->stream, "%s", temp); - tp = temp; - - (*info->print_address_func) ((bfd_vma) number, info); - } - break; - - case 'N': - case 'y': - case 'Y': - case 'S': - case 's': - /* Any "normal" memory operand. */ - if ((insn & 0x400) && (insn & 15) == 15 && prefix_opcodep == NULL) - { - /* We're looking at [pc+], i.e. we need to output an immediate - number, where the size can depend on different things. */ - int32_t number; - int signedp - = ((*cs == 'z' && (insn & 0x20)) - || opcodep->match == BDAP_QUICK_OPCODE); - int nbytes; - - if (opcodep->imm_oprnd_size == SIZE_FIX_32) - nbytes = 4; - else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) - { - const struct cris_spec_reg *sregp - = spec_reg_info ((insn >> 12) & 15, disdata->distype); - - /* A NULL return should have been as a non-match earlier, - so catch it as an internal error in the error-case - below. */ - if (sregp == NULL) - /* Whatever non-valid size. */ - nbytes = 42; - else - /* PC is always incremented by a multiple of two. - For CRISv32, immediates are always 4 bytes for - special registers. */ - nbytes = disdata->distype == cris_dis_v32 - ? 4 : (sregp->reg_size + 1) & ~1; - } - else - { - int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3)); - - if (mode_size == 1) - nbytes = 2; - else - nbytes = mode_size; - } - - switch (nbytes) - { - case 1: - number = buffer[2]; - if (signedp && number > 127) - number -= 256; - break; - - case 2: - number = buffer[2] + buffer[3] * 256; - if (signedp && number > 32767) - number -= 65536; - break; - - case 4: - number - = buffer[2] + buffer[3] * 256 + buffer[4] * 65536 - + buffer[5] * 0x1000000; - break; - - default: - strcpy (tp, "bug"); - tp += 3; - number = 42; - } - - if ((*cs == 'z' && (insn & 0x20)) - || (opcodep->match == BDAP_QUICK_OPCODE - && (nbytes <= 2 || buffer[1 + nbytes] == 0))) - tp = FORMAT_DEC (number, tp, signedp); - else - { - unsigned int highbyte = (number >> 24) & 0xff; - - /* Either output this as an address or as a number. If it's - a dword with the same high-byte as the address of the - insn, assume it's an address, and also if it's a non-zero - non-0xff high-byte. If this is a jsr or a jump, then - it's definitely an address. */ - if (nbytes == 4 - && (highbyte == ((addr >> 24) & 0xff) - || (highbyte != 0 && highbyte != 0xff) - || info->insn_type == dis_branch - || info->insn_type == dis_jsr)) - { - /* Finish off and output previous formatted bytes. */ - *tp = 0; - tp = temp; - if (temp[0]) - (*info->fprintf_func) (info->stream, "%s", temp); - - (*info->print_address_func) ((bfd_vma) number, info); - - info->target = number; - } - else - tp = format_hex (number, tp, disdata); - } - } - else - { - /* Not an immediate number. Then this is a (possibly - prefixed) memory operand. */ - if (info->insn_type != dis_nonbranch) - { - int mode_size - = 1 << ((insn >> 4) - & (opcodep->args[0] == 'z' ? 1 : 3)); - int size; - info->insn_type = dis_dref; - info->flags |= CRIS_DIS_FLAG_MEMREF; - - if (opcodep->imm_oprnd_size == SIZE_FIX_32) - size = 4; - else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) - { - const struct cris_spec_reg *sregp - = spec_reg_info ((insn >> 12) & 15, disdata->distype); - - /* FIXME: Improve error handling; should have been caught - earlier. */ - if (sregp == NULL) - size = 4; - else - size = sregp->reg_size; - } - else - size = mode_size; - - info->data_size = size; - } - - *tp++ = '['; - - if (prefix_opcodep - /* We don't match dip with a postincremented field - as a side-effect address mode. */ - && ((insn & 0x400) == 0 - || prefix_opcodep->match != DIP_OPCODE)) - { - if (insn & 0x400) - { - tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); - *tp++ = '='; - } - - - /* We mainly ignore the prefix format string when the - address-mode syntax is output. */ - switch (prefix_opcodep->match) - { - case DIP_OPCODE: - /* It's [r], [r+] or [pc+]. */ - if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) - { - /* It's [pc+]. This cannot possibly be anything - but an address. */ - uint32_t number - = prefix_buffer[2] + prefix_buffer[3] * 256 - + prefix_buffer[4] * 65536 - + prefix_buffer[5] * 0x1000000; - - info->target = (bfd_vma) number; - - /* Finish off and output previous formatted - data. */ - *tp = 0; - tp = temp; - if (temp[0]) - (*info->fprintf_func) (info->stream, "%s", temp); - - (*info->print_address_func) ((bfd_vma) number, info); - } - else - { - /* For a memref in an address, we use target2. - In this case, target is zero. */ - info->flags - |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG - | CRIS_DIS_FLAG_MEM_TARGET2_MEM); - - info->target2 = prefix_insn & 15; - - *tp++ = '['; - tp = format_reg (disdata, prefix_insn & 15, tp, - with_reg_prefix); - if (prefix_insn & 0x400) - *tp++ = '+'; - *tp++ = ']'; - } - break; - - case BDAP_QUICK_OPCODE: - { - int number; - - number = prefix_buffer[0]; - if (number > 127) - number -= 256; - - /* Output "reg+num" or, if num < 0, "reg-num". */ - tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, - with_reg_prefix); - if (number >= 0) - *tp++ = '+'; - tp = FORMAT_DEC (number, tp, 1); - - info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; - info->target = (prefix_insn >> 12) & 15; - info->target2 = (bfd_vma) number; - break; - } - - case BIAP_OPCODE: - /* Output "r+R.m". */ - tp = format_reg (disdata, prefix_insn & 15, tp, - with_reg_prefix); - *tp++ = '+'; - tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, - with_reg_prefix); - *tp++ = '.'; - *tp++ = mode_char[(prefix_insn >> 4) & 3]; - - info->flags - |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG - | CRIS_DIS_FLAG_MEM_TARGET_IS_REG - - | ((prefix_insn & 0x8000) - ? CRIS_DIS_FLAG_MEM_TARGET2_MULT4 - : ((prefix_insn & 0x8000) - ? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0))); - - /* Is it the casejump? It's a "adds.w [pc+r%d.w],pc". */ - if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f) - /* Then start interpreting data as offsets. */ - case_offset_counter = no_of_case_offsets; - break; - - case BDAP_INDIR_OPCODE: - /* Output "r+s.m", or, if "s" is [pc+], "r+s" or - "r-s". */ - tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, - with_reg_prefix); - - if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) - { - int32_t number; - unsigned int nbytes; - - /* It's a value. Get its size. */ - int mode_size = 1 << ((prefix_insn >> 4) & 3); - - if (mode_size == 1) - nbytes = 2; - else - nbytes = mode_size; - - switch (nbytes) - { - case 1: - number = prefix_buffer[2]; - if (number > 127) - number -= 256; - break; - - case 2: - number = prefix_buffer[2] + prefix_buffer[3] * 256; - if (number > 32767) - number -= 65536; - break; - - case 4: - number - = prefix_buffer[2] + prefix_buffer[3] * 256 - + prefix_buffer[4] * 65536 - + prefix_buffer[5] * 0x1000000; - break; - - default: - strcpy (tp, "bug"); - tp += 3; - number = 42; - } - - info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; - info->target2 = (bfd_vma) number; - - /* If the size is dword, then assume it's an - address. */ - if (nbytes == 4) - { - /* Finish off and output previous formatted - bytes. */ - *tp++ = '+'; - *tp = 0; - tp = temp; - (*info->fprintf_func) (info->stream, "%s", temp); - - (*info->print_address_func) ((bfd_vma) number, info); - } - else - { - if (number >= 0) - *tp++ = '+'; - tp = FORMAT_DEC (number, tp, 1); - } - } - else - { - /* Output "r+[R].m" or "r+[R+].m". */ - *tp++ = '+'; - *tp++ = '['; - tp = format_reg (disdata, prefix_insn & 15, tp, - with_reg_prefix); - if (prefix_insn & 0x400) - *tp++ = '+'; - *tp++ = ']'; - *tp++ = '.'; - *tp++ = mode_char[(prefix_insn >> 4) & 3]; - - info->flags - |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG - | CRIS_DIS_FLAG_MEM_TARGET2_MEM - | CRIS_DIS_FLAG_MEM_TARGET_IS_REG - - | (((prefix_insn >> 4) == 2) - ? 0 - : (((prefix_insn >> 4) & 3) == 1 - ? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD - : CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE))); - } - break; - - default: - (*info->fprintf_func) (info->stream, "?prefix-bug"); - } - - /* To mark that the prefix is used, reset it. */ - prefix_opcodep = NULL; - } - else - { - tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); - - info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; - info->target = insn & 15; - - if (insn & 0x400) - *tp++ = '+'; - } - *tp++ = ']'; - } - break; - - case 'x': - tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); - *tp++ = '.'; - *tp++ = mode_char[(insn >> 4) & 3]; - break; - - case 'I': - tp = FORMAT_DEC (insn & 63, tp, 0); - break; - - case 'b': - { - int where = buffer[2] + buffer[3] * 256; - - if (where > 32767) - where -= 65536; - - where += addr + ((disdata->distype == cris_dis_v32) ? 0 : 4); - - if (insn == BA_PC_INCR_OPCODE) - info->insn_type = dis_branch; - else - info->insn_type = dis_condbranch; - - info->target = (bfd_vma) where; - - *tp = 0; - tp = temp; - (*info->fprintf_func) (info->stream, "%s%s ", - temp, cris_cc_strings[insn >> 12]); - - (*info->print_address_func) ((bfd_vma) where, info); - } - break; - - case 'c': - tp = FORMAT_DEC (insn & 31, tp, 0); - break; - - case 'C': - tp = FORMAT_DEC (insn & 15, tp, 0); - break; - - case 'o': - { - long offset = insn & 0xfe; - bfd_vma target; - - if (insn & 1) - offset |= ~0xff; - - if (opcodep->match == BA_QUICK_OPCODE) - info->insn_type = dis_branch; - else - info->insn_type = dis_condbranch; - - target = addr + ((disdata->distype == cris_dis_v32) ? 0 : 2) + offset; - info->target = target; - *tp = 0; - tp = temp; - (*info->fprintf_func) (info->stream, "%s", temp); - (*info->print_address_func) (target, info); - } - break; - - case 'Q': - case 'O': - { - long number = buffer[0]; - - if (number > 127) - number = number - 256; - - tp = FORMAT_DEC (number, tp, 1); - *tp++ = ','; - tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); - } - break; - - case 'f': - tp = print_flags (disdata, insn, tp); - break; - - case 'i': - tp = FORMAT_DEC ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1); - break; - - case 'P': - { - const struct cris_spec_reg *sregp - = spec_reg_info ((insn >> 12) & 15, disdata->distype); - - if (sregp == NULL || sregp->name == NULL) - /* Should have been caught as a non-match earlier. */ - *tp++ = '?'; - else - { - if (with_reg_prefix) - *tp++ = REGISTER_PREFIX_CHAR; - strcpy (tp, sregp->name); - tp += strlen (tp); - } - } - break; - - default: - strcpy (tp, "???"); - tp += 3; - } - } - - *tp = 0; - - if (prefix_opcodep) - (*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")", - prefix_opcodep->name, prefix_opcodep->args); - - (*info->fprintf_func) (info->stream, "%s", temp); - - /* Get info for matching case-tables, if we don't have any active. - We assume that the last constant seen is used; either in the insn - itself or in a "move.d const,rN, sub.d rN,rM"-like sequence. */ - if (TRACE_CASE && case_offset_counter == 0) - { - if (CONST_STRNEQ (opcodep->name, "sub")) - case_offset = last_immediate; - - /* It could also be an "add", if there are negative case-values. */ - else if (CONST_STRNEQ (opcodep->name, "add")) - /* The first case is the negated operand to the add. */ - case_offset = -last_immediate; - - /* A bound insn will tell us the number of cases. */ - else if (CONST_STRNEQ (opcodep->name, "bound")) - no_of_case_offsets = last_immediate + 1; - - /* A jump or jsr or branch breaks the chain of insns for a - case-table, so assume default first-case again. */ - else if (info->insn_type == dis_jsr - || info->insn_type == dis_branch - || info->insn_type == dis_condbranch) - case_offset = 0; - } -} - - -/* Print the CRIS instruction at address memaddr on stream. Returns - length of the instruction, in bytes. Prefix register names with `$' if - WITH_REG_PREFIX. */ - -static int -print_insn_cris_generic (bfd_vma memaddr, - disassemble_info *info, - bfd_boolean with_reg_prefix) -{ - int nbytes; - unsigned int insn; - const struct cris_opcode *matchedp; - int advance = 0; - struct cris_disasm_data *disdata - = (struct cris_disasm_data *) info->private_data; - - /* No instruction will be disassembled as longer than this number of - bytes; stacked prefixes will not be expanded. */ - unsigned char buffer[MAX_BYTES_PER_CRIS_INSN]; - unsigned char *bufp; - int status = 0; - bfd_vma addr; - - /* There will be an "out of range" error after the last instruction. - Reading pairs of bytes in decreasing number, we hope that we will get - at least the amount that we will consume. - - If we can't get any data, or we do not get enough data, we print - the error message. */ - - nbytes = info->buffer_length ? info->buffer_length - : MAX_BYTES_PER_CRIS_INSN; - nbytes = MIN(nbytes, MAX_BYTES_PER_CRIS_INSN); - status = (*info->read_memory_func) (memaddr, buffer, nbytes, info); - - /* If we did not get all we asked for, then clear the rest. - Hopefully this makes a reproducible result in case of errors. */ - if (nbytes != MAX_BYTES_PER_CRIS_INSN) - memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes); - - addr = memaddr; - bufp = buffer; - - /* Set some defaults for the insn info. */ - info->insn_info_valid = 1; - info->branch_delay_insns = 0; - info->data_size = 0; - info->insn_type = dis_nonbranch; - info->flags = 0; - info->target = 0; - info->target2 = 0; - - /* If we got any data, disassemble it. */ - if (nbytes != 0) - { - matchedp = NULL; - - insn = bufp[0] + bufp[1] * 256; - - /* If we're in a case-table, don't disassemble the offsets. */ - if (TRACE_CASE && case_offset_counter != 0) - { - info->insn_type = dis_noninsn; - advance += 2; - - /* If to print data as offsets, then shortcut here. */ - (*info->fprintf_func) (info->stream, "case %ld%s: -> ", - case_offset + no_of_case_offsets - - case_offset_counter, - case_offset_counter == 1 ? "/default" : - ""); - - (*info->print_address_func) ((bfd_vma) - ((short) (insn) - + (long) (addr - - (no_of_case_offsets - - case_offset_counter) - * 2)), info); - case_offset_counter--; - - /* The default case start (without a "sub" or "add") must be - zero. */ - if (case_offset_counter == 0) - case_offset = 0; - } - else if (insn == 0) - { - /* We're often called to disassemble zeroes. While this is a - valid "bcc .+2" insn, it is also useless enough and enough - of a nuiscance that we will just output "bcc .+2" for it - and signal it as a noninsn. */ - (*info->fprintf_func) (info->stream, - disdata->distype == cris_dis_v32 - ? "bcc ." : "bcc .+2"); - info->insn_type = dis_noninsn; - advance += 2; - } - else - { - const struct cris_opcode *prefix_opcodep = NULL; - unsigned char *prefix_buffer = bufp; - unsigned int prefix_insn = insn; - int prefix_size = 0; - - matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX, disdata); - - /* Check if we're supposed to write out prefixes as address - modes and if this was a prefix. */ - if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p') - { - /* If it's a prefix, put it into the prefix vars and get the - main insn. */ - prefix_size = bytes_to_skip (prefix_insn, matchedp, - disdata->distype, NULL); - prefix_opcodep = matchedp; - - insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256; - matchedp = get_opcode_entry (insn, prefix_insn, disdata); - - if (matchedp != NULL) - { - addr += prefix_size; - bufp += prefix_size; - advance += prefix_size; - } - else - { - /* The "main" insn wasn't valid, at least not when - prefixed. Put back things enough to output the - prefix insn only, as a normal insn. */ - matchedp = prefix_opcodep; - insn = prefix_insn; - prefix_opcodep = NULL; - } - } - - if (matchedp == NULL) - { - (*info->fprintf_func) (info->stream, "??0x%x", insn); - advance += 2; - - info->insn_type = dis_noninsn; - } - else - { - advance - += bytes_to_skip (insn, matchedp, disdata->distype, - prefix_opcodep); - - /* The info_type and assorted fields will be set according - to the operands. */ - print_with_operands (matchedp, insn, bufp, addr, info, - prefix_opcodep, prefix_insn, - prefix_buffer, with_reg_prefix); - } - } - } - else - info->insn_type = dis_noninsn; - - /* If we read less than MAX_BYTES_PER_CRIS_INSN, i.e. we got an error - status when reading that much, and the insn decoding indicated a - length exceeding what we read, there is an error. */ - if (status != 0 && (nbytes == 0 || advance > nbytes)) - { - (*info->memory_error_func) (status, memaddr, info); - return -1; - } - - /* Max supported insn size with one folded prefix insn. */ - info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN; - - /* I would like to set this to a fixed value larger than the actual - number of bytes to print in order to avoid spaces between bytes, - but objdump.c (2.9.1) does not like that, so we print 16-bit - chunks, which is the next choice. */ - info->bytes_per_chunk = 2; - - /* Printing bytes in order of increasing addresses makes sense, - especially on a little-endian target. - This is completely the opposite of what you think; setting this to - BFD_ENDIAN_LITTLE will print bytes in order N..0 rather than the 0..N - we want. */ - info->display_endian = BFD_ENDIAN_BIG; - - return advance; -} - -/* Disassemble, prefixing register names with `$'. CRIS v0..v10. */ -static int -print_insn_cris_with_register_prefix (bfd_vma vma, - disassemble_info *info) -{ - struct cris_disasm_data disdata; - info->private_data = &disdata; - cris_parse_disassembler_options (&disdata, info->disassembler_options, - cris_dis_v0_v10); - return print_insn_cris_generic (vma, info, true); -} -/* Disassemble, prefixing register names with `$'. CRIS v32. */ - -static int -print_insn_crisv32_with_register_prefix (bfd_vma vma, - disassemble_info *info) -{ - struct cris_disasm_data disdata; - info->private_data = &disdata; - cris_parse_disassembler_options (&disdata, info->disassembler_options, - cris_dis_v32); - return print_insn_cris_generic (vma, info, true); -} - -#if 0 -/* Disassemble, prefixing register names with `$'. - Common v10 and v32 subset. */ - -static int -print_insn_crisv10_v32_with_register_prefix (bfd_vma vma, - disassemble_info *info) -{ - struct cris_disasm_data disdata; - info->private_data = &disdata; - cris_parse_disassembler_options (&disdata, info->disassembler_options, - cris_dis_common_v10_v32); - return print_insn_cris_generic (vma, info, true); -} - -/* Disassemble, no prefixes on register names. CRIS v0..v10. */ - -static int -print_insn_cris_without_register_prefix (bfd_vma vma, - disassemble_info *info) -{ - struct cris_disasm_data disdata; - info->private_data = &disdata; - cris_parse_disassembler_options (&disdata, info->disassembler_options, - cris_dis_v0_v10); - return print_insn_cris_generic (vma, info, false); -} - -/* Disassemble, no prefixes on register names. CRIS v32. */ - -static int -print_insn_crisv32_without_register_prefix (bfd_vma vma, - disassemble_info *info) -{ - struct cris_disasm_data disdata; - info->private_data = &disdata; - cris_parse_disassembler_options (&disdata, info->disassembler_options, - cris_dis_v32); - return print_insn_cris_generic (vma, info, false); -} - -/* Disassemble, no prefixes on register names. - Common v10 and v32 subset. */ - -static int -print_insn_crisv10_v32_without_register_prefix (bfd_vma vma, - disassemble_info *info) -{ - struct cris_disasm_data disdata; - info->private_data = &disdata; - cris_parse_disassembler_options (&disdata, info->disassembler_options, - cris_dis_common_v10_v32); - return print_insn_cris_generic (vma, info, false); -} -#endif - -int -print_insn_crisv10 (bfd_vma vma, - disassemble_info *info) -{ - return print_insn_cris_with_register_prefix(vma, info); -} - -int -print_insn_crisv32 (bfd_vma vma, - disassemble_info *info) -{ - return print_insn_crisv32_with_register_prefix(vma, info); -} - -/* Return a disassembler-function that prints registers with a `$' prefix, - or one that prints registers without a prefix. - FIXME: We should improve the solution to avoid the multitude of - functions seen above. */ -#if 0 -disassembler_ftype -cris_get_disassembler (bfd *abfd) -{ - /* If there's no bfd in sight, we return what is valid as input in all - contexts if fed back to the assembler: disassembly *with* register - prefix. Unfortunately this will be totally wrong for v32. */ - if (abfd == NULL) - return print_insn_cris_with_register_prefix; - - if (bfd_get_symbol_leading_char (abfd) == 0) - { - if (bfd_get_mach (abfd) == bfd_mach_cris_v32) - return print_insn_crisv32_with_register_prefix; - if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32) - return print_insn_crisv10_v32_with_register_prefix; - - /* We default to v10. This may be specifically specified in the - bfd mach, but is also the default setting. */ - return print_insn_cris_with_register_prefix; - } - - if (bfd_get_mach (abfd) == bfd_mach_cris_v32) - return print_insn_crisv32_without_register_prefix; - if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32) - return print_insn_crisv10_v32_without_register_prefix; - return print_insn_cris_without_register_prefix; -} -#endif -/* Local variables: - eval: (c-set-style "gnu") - indent-tabs-mode: t - End: */ diff --git a/disas/meson.build b/disas/meson.build index 20d6aef9a7..bbfa119783 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -1,5 +1,4 @@ common_ss.add(when: 'CONFIG_ALPHA_DIS', if_true: files('alpha.c')) -common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c')) common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c')) common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c')) common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 48b230b0a0..ce38a3d0cf 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -377,6 +377,15 @@ Specifying the iSCSI password in plain text on the command line using the used instead, to refer to a ``--object secret...`` instance that provides a password via a file, or encrypted. +``gluster`` backend (since 9.2) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +According to https://marc.info/?l=fedora-devel-list&m=171934833215726 +the GlusterFS development effectively ended. Unless the development +gains momentum again, the QEMU project will remove the gluster backend +in a future release. + + Character device options '''''''''''''''''''''''' @@ -385,6 +394,12 @@ Backend ``memory`` (since 9.0) ``memory`` is a deprecated synonym for ``ringbuf``. +``reconnect`` (since 9.2) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``reconnect`` option only allows specifiying second granularity timeouts, +which is not enough for all types of use cases, use ``reconnect-ms`` instead. + CPU device properties ''''''''''''''''''''' @@ -458,3 +473,9 @@ usage of providing a file descriptor to a plain file has been deprecated in favor of explicitly using the ``file:`` URI with the file descriptor being passed as an ``fdset``. Refer to the ``add-fd`` command documentation for details on the ``fdset`` usage. + +``zero-blocks`` capability (since 9.2) +'''''''''''''''''''''''''''''''''''''' + +The ``zero-blocks`` capability was part of the block migration which +doesn't exist anymore since it was removed in QEMU v9.1. diff --git a/hw/m68k/bootinfo.h b/hw/m68k/bootinfo.h index 70c1dc0e8c..0b3e7c4ea0 100644 --- a/hw/m68k/bootinfo.h +++ b/hw/m68k/bootinfo.h @@ -14,39 +14,39 @@ #define BOOTINFO0(base, id) \ do { \ - stw_p(base, id); \ + stw_be_p(base, id); \ base += 2; \ - stw_p(base, sizeof(struct bi_record)); \ + stw_be_p(base, sizeof(struct bi_record)); \ base += 2; \ } while (0) #define BOOTINFO1(base, id, value) \ do { \ - stw_p(base, id); \ + stw_be_p(base, id); \ base += 2; \ - stw_p(base, sizeof(struct bi_record) + 4); \ + stw_be_p(base, sizeof(struct bi_record) + 4); \ base += 2; \ - stl_p(base, value); \ + stl_be_p(base, value); \ base += 4; \ } while (0) #define BOOTINFO2(base, id, value1, value2) \ do { \ - stw_p(base, id); \ + stw_be_p(base, id); \ base += 2; \ - stw_p(base, sizeof(struct bi_record) + 8); \ + stw_be_p(base, sizeof(struct bi_record) + 8); \ base += 2; \ - stl_p(base, value1); \ + stl_be_p(base, value1); \ base += 4; \ - stl_p(base, value2); \ + stl_be_p(base, value2); \ base += 4; \ } while (0) #define BOOTINFOSTR(base, id, string) \ do { \ - stw_p(base, id); \ + stw_be_p(base, id); \ base += 2; \ - stw_p(base, \ + stw_be_p(base, \ (sizeof(struct bi_record) + strlen(string) + \ 1 /* null termination */ + 3 /* padding */) & ~3); \ base += 2; \ @@ -59,13 +59,13 @@ #define BOOTINFODATA(base, id, data, len) \ do { \ - stw_p(base, id); \ + stw_be_p(base, id); \ base += 2; \ - stw_p(base, \ + stw_be_p(base, \ (sizeof(struct bi_record) + len + \ 2 /* length field */ + 3 /* padding */) & ~3); \ base += 2; \ - stw_p(base, len); \ + stw_be_p(base, len); \ base += 2; \ for (unsigned i_ = 0; i_ < len; ++i_) { \ stb_p(base++, data[i_]); \ diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index b6677ad6bc..e37cd50d18 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -359,7 +359,7 @@ static void mcf5208evb_init(MachineState *machine) /* Initial PC is always at offset 4 in firmware binaries */ ptr = rom_ptr(0x4, 4); assert(ptr != NULL); - env->pc = ldl_p(ptr); + env->pc = ldl_be_p(ptr); } /* Load kernel. */ diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index 9b78767ea8..9832213e7e 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -1036,7 +1036,7 @@ static void next_cube_init(MachineState *machine) /* Initial PC is always at offset 4 in firmware binaries */ ptr = rom_ptr(0x01000004, 4); g_assert(ptr != NULL); - env->pc = ldl_p(ptr); + env->pc = ldl_be_p(ptr); if (env->pc >= 0x01020000) { error_report("'%s' does not seem to be a valid firmware image.", bios_name); diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index fa7683bf76..556604e1dc 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -684,9 +684,9 @@ static void q800_machine_init(MachineState *machine) ptr = rom_ptr(MACROM_ADDR, bios_size); assert(ptr != NULL); - stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */ + stl_phys(cs->as, 0, ldl_be_p(ptr)); /* reset initial SP */ stl_phys(cs->as, 4, - MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */ + MACROM_ADDR + ldl_be_p(ptr + 4)); /* reset initial PC */ } } } diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index dd71689642..5ab7433908 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -252,8 +252,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) */ romptr = rom_ptr(INITRD_PARM_START, 16); if (romptr) { - stq_p(romptr, initrd_offset); - stq_p(romptr + 1, initrd_size); + stq_be_p(romptr, initrd_offset); + stq_be_p(romptr + 1, initrd_size); } } } diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 30149546c0..41655082da 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -55,26 +55,26 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) uint64_t resume_token; rc = 0; - if (lduw_p(&rrb->request.hdr.len) != 32) { + if (lduw_be_p(&rrb->request.hdr.len) != 32) { res_code = CLP_RC_LEN; rc = -EINVAL; goto out; } - if ((ldl_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) { + if ((ldl_be_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) { res_code = CLP_RC_FMT; rc = -EINVAL; goto out; } - if ((ldl_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 || - ldq_p(&rrb->request.reserved1) != 0) { + if ((ldl_be_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 || + ldq_be_p(&rrb->request.reserved1) != 0) { res_code = CLP_RC_RESNOT0; rc = -EINVAL; goto out; } - resume_token = ldq_p(&rrb->request.resume_token); + resume_token = ldq_be_p(&rrb->request.resume_token); if (resume_token) { pbdev = s390_pci_find_dev_by_idx(s, resume_token); @@ -87,13 +87,13 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) pbdev = s390_pci_find_next_avail_dev(s, NULL); } - if (lduw_p(&rrb->response.hdr.len) < 48) { + if (lduw_be_p(&rrb->response.hdr.len) < 48) { res_code = CLP_RC_8K; rc = -EINVAL; goto out; } - initial_l2 = lduw_p(&rrb->response.hdr.len); + initial_l2 = lduw_be_p(&rrb->response.hdr.len); if ((initial_l2 - LIST_PCI_HDR_LEN) % sizeof(ClpFhListEntry) != 0) { res_code = CLP_RC_LEN; @@ -102,33 +102,33 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) goto out; } - stl_p(&rrb->response.fmt, 0); - stq_p(&rrb->response.reserved1, 0); - stl_p(&rrb->response.mdd, FH_MASK_SHM); - stw_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS); + stl_be_p(&rrb->response.fmt, 0); + stq_be_p(&rrb->response.reserved1, 0); + stl_be_p(&rrb->response.mdd, FH_MASK_SHM); + stw_be_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS); rrb->response.flags = UID_CHECKING_ENABLED; rrb->response.entry_size = sizeof(ClpFhListEntry); i = 0; g_l2 = LIST_PCI_HDR_LEN; while (g_l2 < initial_l2 && pbdev) { - stw_p(&rrb->response.fh_list[i].device_id, + stw_be_p(&rrb->response.fh_list[i].device_id, pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID)); - stw_p(&rrb->response.fh_list[i].vendor_id, + stw_be_p(&rrb->response.fh_list[i].vendor_id, pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID)); /* Ignore RESERVED devices. */ - stl_p(&rrb->response.fh_list[i].config, + stl_be_p(&rrb->response.fh_list[i].config, pbdev->state == ZPCI_FS_STANDBY ? 0 : 1 << 31); - stl_p(&rrb->response.fh_list[i].fid, pbdev->fid); - stl_p(&rrb->response.fh_list[i].fh, pbdev->fh); + stl_be_p(&rrb->response.fh_list[i].fid, pbdev->fid); + stl_be_p(&rrb->response.fh_list[i].fh, pbdev->fh); g_l2 += sizeof(ClpFhListEntry); /* Add endian check for DPRINTF? */ trace_s390_pci_list_entry(g_l2, - lduw_p(&rrb->response.fh_list[i].vendor_id), - lduw_p(&rrb->response.fh_list[i].device_id), - ldl_p(&rrb->response.fh_list[i].fid), - ldl_p(&rrb->response.fh_list[i].fh)); + lduw_be_p(&rrb->response.fh_list[i].vendor_id), + lduw_be_p(&rrb->response.fh_list[i].device_id), + ldl_be_p(&rrb->response.fh_list[i].fid), + ldl_be_p(&rrb->response.fh_list[i].fh)); pbdev = s390_pci_find_next_avail_dev(s, pbdev); i++; } @@ -138,13 +138,13 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) } else { resume_token = pbdev->fh & FH_MASK_INDEX; } - stq_p(&rrb->response.resume_token, resume_token); - stw_p(&rrb->response.hdr.len, g_l2); - stw_p(&rrb->response.hdr.rsp, CLP_RC_OK); + stq_be_p(&rrb->response.resume_token, resume_token); + stw_be_p(&rrb->response.hdr.len, g_l2); + stw_be_p(&rrb->response.hdr.rsp, CLP_RC_OK); out: if (rc) { trace_s390_pci_list(rc); - stw_p(&rrb->response.hdr.rsp, res_code); + stw_be_p(&rrb->response.hdr.rsp, res_code); } return rc; } @@ -172,7 +172,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) return 0; } reqh = (ClpReqHdr *)buffer; - req_len = lduw_p(&reqh->len); + req_len = lduw_be_p(&reqh->len); if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) { s390_program_interrupt(env, PGM_OPERAND, ra); return 0; @@ -184,7 +184,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) return 0; } resh = (ClpRspHdr *)(buffer + req_len); - res_len = lduw_p(&resh->len); + res_len = lduw_be_p(&resh->len); if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) { s390_program_interrupt(env, PGM_OPERAND, ra); return 0; @@ -201,11 +201,11 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) } if (req_len != 32) { - stw_p(&resh->rsp, CLP_RC_LEN); + stw_be_p(&resh->rsp, CLP_RC_LEN); goto out; } - switch (lduw_p(&reqh->cmd)) { + switch (lduw_be_p(&reqh->cmd)) { case CLP_LIST_PCI: { ClpReqRspListPci *rrb = (ClpReqRspListPci *)buffer; list_pci(rrb, &cc); @@ -215,9 +215,9 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh; ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh; - pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqsetpci->fh)); + pbdev = s390_pci_find_dev_by_fh(s, ldl_be_p(&reqsetpci->fh)); if (!pbdev) { - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH); goto out; } @@ -225,17 +225,17 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) case CLP_SET_ENABLE_PCI_FN: switch (reqsetpci->ndas) { case 0: - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_DMAAS); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_DMAAS); goto out; case 1: break; default: - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_RES); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_RES); goto out; } if (pbdev->fh & FH_MASK_ENABLE) { - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); goto out; } @@ -249,29 +249,29 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) /* Take this opportunity to make sure we are sync'd with host */ if (!s390_pci_get_host_fh(pbdev, &pbdev->fh) || !(pbdev->fh & FH_MASK_ENABLE)) { - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH); goto out; } } pbdev->fh |= FH_MASK_ENABLE; pbdev->state = ZPCI_FS_ENABLED; - stl_p(&ressetpci->fh, pbdev->fh); - stw_p(&ressetpci->hdr.rsp, CLP_RC_OK); + stl_be_p(&ressetpci->fh, pbdev->fh); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_OK); break; case CLP_SET_DISABLE_PCI_FN: if (!(pbdev->fh & FH_MASK_ENABLE)) { - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); goto out; } device_cold_reset(DEVICE(pbdev)); pbdev->fh &= ~FH_MASK_ENABLE; pbdev->state = ZPCI_FS_DISABLED; - stl_p(&ressetpci->fh, pbdev->fh); - stw_p(&ressetpci->hdr.rsp, CLP_RC_OK); + stl_be_p(&ressetpci->fh, pbdev->fh); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_OK); break; default: trace_s390_pci_unknown("set-pci", reqsetpci->oc); - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); + stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); break; } break; @@ -280,23 +280,23 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh; ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh; - pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqquery->fh)); + pbdev = s390_pci_find_dev_by_fh(s, ldl_be_p(&reqquery->fh)); if (!pbdev) { - trace_s390_pci_nodev("query", ldl_p(&reqquery->fh)); - stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH); + trace_s390_pci_nodev("query", ldl_be_p(&reqquery->fh)); + stw_be_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH); goto out; } - stq_p(&resquery->sdma, pbdev->zpci_fn.sdma); - stq_p(&resquery->edma, pbdev->zpci_fn.edma); - stw_p(&resquery->pchid, pbdev->zpci_fn.pchid); - stw_p(&resquery->vfn, pbdev->zpci_fn.vfn); + stq_be_p(&resquery->sdma, pbdev->zpci_fn.sdma); + stq_be_p(&resquery->edma, pbdev->zpci_fn.edma); + stw_be_p(&resquery->pchid, pbdev->zpci_fn.pchid); + stw_be_p(&resquery->vfn, pbdev->zpci_fn.vfn); resquery->flags = pbdev->zpci_fn.flags; resquery->pfgid = pbdev->zpci_fn.pfgid; resquery->pft = pbdev->zpci_fn.pft; resquery->fmbl = pbdev->zpci_fn.fmbl; - stl_p(&resquery->fid, pbdev->zpci_fn.fid); - stl_p(&resquery->uid, pbdev->zpci_fn.uid); + stl_be_p(&resquery->fid, pbdev->zpci_fn.fid); + stl_be_p(&resquery->uid, pbdev->zpci_fn.uid); memcpy(resquery->pfip, pbdev->zpci_fn.pfip, CLP_PFIP_NR_SEGMENTS); memcpy(resquery->util_str, pbdev->zpci_fn.util_str, CLP_UTIL_STR_LEN); @@ -304,16 +304,16 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) uint32_t data = pci_get_long(pbdev->pdev->config + PCI_BASE_ADDRESS_0 + (i * 4)); - stl_p(&resquery->bar[i], data); + stl_be_p(&resquery->bar[i], data); resquery->bar_size[i] = pbdev->pdev->io_regions[i].size ? ctz64(pbdev->pdev->io_regions[i].size) : 0; trace_s390_pci_bar(i, - ldl_p(&resquery->bar[i]), + ldl_be_p(&resquery->bar[i]), pbdev->pdev->io_regions[i].size, resquery->bar_size[i]); } - stw_p(&resquery->hdr.rsp, CLP_RC_OK); + stw_be_p(&resquery->hdr.rsp, CLP_RC_OK); break; } case CLP_QUERY_PCI_FNGRP: { @@ -326,23 +326,23 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) if (!group) { /* We do not allow access to unknown groups */ /* The group must have been obtained with a vfio device */ - stw_p(&resgrp->hdr.rsp, CLP_RC_QUERYPCIFG_PFGID); + stw_be_p(&resgrp->hdr.rsp, CLP_RC_QUERYPCIFG_PFGID); goto out; } resgrp->fr = group->zpci_group.fr; - stq_p(&resgrp->dasm, group->zpci_group.dasm); - stq_p(&resgrp->msia, group->zpci_group.msia); - stw_p(&resgrp->mui, group->zpci_group.mui); - stw_p(&resgrp->i, group->zpci_group.i); - stw_p(&resgrp->maxstbl, group->zpci_group.maxstbl); + stq_be_p(&resgrp->dasm, group->zpci_group.dasm); + stq_be_p(&resgrp->msia, group->zpci_group.msia); + stw_be_p(&resgrp->mui, group->zpci_group.mui); + stw_be_p(&resgrp->i, group->zpci_group.i); + stw_be_p(&resgrp->maxstbl, group->zpci_group.maxstbl); resgrp->version = group->zpci_group.version; resgrp->dtsm = group->zpci_group.dtsm; - stw_p(&resgrp->hdr.rsp, CLP_RC_OK); + stw_be_p(&resgrp->hdr.rsp, CLP_RC_OK); break; } default: - trace_s390_pci_unknown("clp", lduw_p(&reqh->cmd)); - stw_p(&resh->rsp, CLP_RC_CMD); + trace_s390_pci_unknown("clp", lduw_be_p(&reqh->cmd)); + stw_be_p(&resh->rsp, CLP_RC_CMD); break; } @@ -914,7 +914,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, for (i = 0; i < len / 8; i++) { result = memory_region_dispatch_write(mr, offset + i * 8, - ldq_p(buffer + i * 8), + ldq_be_p(buffer + i * 8), MO_64, MEMTXATTRS_UNSPECIFIED); if (result != MEMTX_OK) { s390_program_interrupt(env, PGM_OPERAND, ra); @@ -935,13 +935,13 @@ specification_error: static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) { int ret, len; - uint8_t isc = FIB_DATA_ISC(ldl_p(&fib.data)); + uint8_t isc = FIB_DATA_ISC(ldl_be_p(&fib.data)); pbdev->routes.adapter.adapter_id = css_get_adapter_id( CSS_IO_ADAPTER_PCI, isc); - pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t)); - len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long); - pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len); + pbdev->summary_ind = get_indicator(ldq_be_p(&fib.aisb), sizeof(uint64_t)); + len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_be_p(&fib.data))) * sizeof(unsigned long); + pbdev->indicator = get_indicator(ldq_be_p(&fib.aibv), len); ret = map_indicator(&pbdev->routes.adapter, pbdev->summary_ind); if (ret) { @@ -953,13 +953,13 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) goto out; } - pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb); - pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data)); - pbdev->routes.adapter.ind_addr = ldq_p(&fib.aibv); - pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_p(&fib.data)); + pbdev->routes.adapter.summary_addr = ldq_be_p(&fib.aisb); + pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_be_p(&fib.data)); + pbdev->routes.adapter.ind_addr = ldq_be_p(&fib.aibv); + pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_be_p(&fib.data)); pbdev->isc = isc; - pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data)); - pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data)); + pbdev->noi = FIB_DATA_NOI(ldl_be_p(&fib.data)); + pbdev->sum = FIB_DATA_SUM(ldl_be_p(&fib.data)); trace_s390_pci_irqs("register", pbdev->routes.adapter.adapter_id); return 0; @@ -994,9 +994,9 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, uintptr_t ra) { S390PCIIOMMU *iommu = pbdev->iommu; - uint64_t pba = ldq_p(&fib.pba); - uint64_t pal = ldq_p(&fib.pal); - uint64_t g_iota = ldq_p(&fib.iota); + uint64_t pba = ldq_be_p(&fib.pba); + uint64_t pal = ldq_be_p(&fib.pal); + uint64_t g_iota = ldq_be_p(&fib.iota); uint8_t dt = (g_iota >> 2) & 0x7; uint8_t t = (g_iota >> 11) & 0x1; @@ -1289,7 +1289,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, } break; case ZPCI_MOD_FC_SET_MEASURE: { - uint64_t fmb_addr = ldq_p(&fib.fmb_addr); + uint64_t fmb_addr = ldq_be_p(&fib.fmb_addr); if (fmb_addr & FMBK_MASK) { cc = ZPCI_PCI_LS_ERR; @@ -1399,17 +1399,17 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, return 0; } - stq_p(&fib.pba, pbdev->iommu->pba); - stq_p(&fib.pal, pbdev->iommu->pal); - stq_p(&fib.iota, pbdev->iommu->g_iota); - stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr); - stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr); - stq_p(&fib.fmb_addr, pbdev->fmb_addr); + stq_be_p(&fib.pba, pbdev->iommu->pba); + stq_be_p(&fib.pal, pbdev->iommu->pal); + stq_be_p(&fib.iota, pbdev->iommu->g_iota); + stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr); + stq_be_p(&fib.aisb, pbdev->routes.adapter.summary_addr); + stq_be_p(&fib.fmb_addr, pbdev->fmb_addr); data = ((uint32_t)pbdev->isc << 28) | ((uint32_t)pbdev->noi << 16) | ((uint32_t)pbdev->routes.adapter.ind_offset << 8) | ((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset; - stl_p(&fib.data, data); + stl_be_p(&fib.data, data); out: if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { diff --git a/include/chardev/char-socket.h b/include/chardev/char-socket.h index 0708ca6fa9..d6d13ad37f 100644 --- a/include/chardev/char-socket.h +++ b/include/chardev/char-socket.h @@ -74,7 +74,7 @@ struct SocketChardev { bool is_websock; GSource *reconnect_timer; - int64_t reconnect_time; + int64_t reconnect_time_ms; bool connect_err_reported; QIOTask *connect_task; diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 6038a52d0e..b791ca92a4 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -1,6 +1,7 @@ /* * QEMU Crypto hash algorithms * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -33,6 +34,13 @@ /* See also "QCryptoHashAlgo" defined in qapi/crypto.json */ +typedef struct QCryptoHash QCryptoHash; +struct QCryptoHash { + QCryptoHashAlgo alg; + void *opaque; + void *driver; +}; + /** * qcrypto_hash_supports: * @alg: the hash algorithm @@ -129,6 +137,117 @@ int qcrypto_hash_digestv(QCryptoHashAlgo alg, Error **errp); /** + * qcrypto_hash_updatev: + * @hash: hash object from qcrypto_hash_new + * @iov: the array of memory regions to hash + * @niov: the length of @iov + * @errp: pointer to a NULL-initialized error object + * + * Updates the given hash object with all the memory regions + * present in @iov. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_hash_updatev(QCryptoHash *hash, + const struct iovec *iov, + size_t niov, + Error **errp); +/** + * qcrypto_hash_update: + * @hash: hash object from qcrypto_hash_new + * @buf: the memory region to hash + * @len: the length of @buf + * @errp: pointer to a NULL-initialized error object + * + * Updates the given hash object with the data from + * the given buffer. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_hash_update(QCryptoHash *hash, + const char *buf, + size_t len, + Error **errp); + +/** + * qcrypto_hash_finalize_digest: + * @hash: the hash object to finalize + * @digest: pointer to hold output hash + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash from the given hash object. Hash object + * is expected to have its data updated from the qcrypto_hash_update function. + * The @digest pointer will be filled with the printable hex digest of the + * computed hash, which will be terminated by '\0'. The memory pointer + * in @digest must be released with a call to g_free() when + * no longer required. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_hash_finalize_digest(QCryptoHash *hash, + char **digest, + Error **errp); + +/** + * qcrypto_hash_finalize_base64: + * @hash_ctx: hash object to finalize + * @base64: pointer to store the hash result in + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash from the given hash object. Hash object + * is expected to have it's data updated from the qcrypto_hash_update function. + * The @base64 pointer will be filled with the base64 encoding of the computed + * hash, which will be terminated by '\0'. The memory pointer in @base64 + * must be released with a call to g_free() when no longer required. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_hash_finalize_base64(QCryptoHash *hash, + char **base64, + Error **errp); + +/** + * qcrypto_hash_finalize_bytes: + * @hash_ctx: hash object to finalize + * @result: pointer to store the hash result in + * @result_len: Pointer to store the length of the result in + * @errp: pointer to a NULL-initialized error object + * + * Computes the hash from the given hash object. Hash object + * is expected to have it's data updated from the qcrypto_hash_update function. + * The memory pointer in @result must be released with a call to g_free() + * when no longer required. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_hash_finalize_bytes(QCryptoHash *hash, + uint8_t **result, + size_t *result_len, + Error **errp); + +/** + * qcrypto_hash_new: + * @alg: the hash algorithm + * @errp: pointer to a NULL-initialized error object + * + * Creates a new hashing context for the chosen algorithm for + * usage with qcrypto_hash_update. + * + * Returns: New hash object with the given algorithm, or NULL on error. + */ +QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp); + +/** + * qcrypto_hash_free: + * @hash: hash object to free + * + * Frees a hashing context for the chosen algorithm. + */ +void qcrypto_hash_free(QCryptoHash *hash); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHash, qcrypto_hash_free) + +/** * qcrypto_hash_digest: * @alg: the hash algorithm * @buf: the memory region to hash diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index a1d26ce903..3b50ecfb54 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -232,10 +232,6 @@ enum bfd_architecture #define bfd_mach_avrxmega5 105 #define bfd_mach_avrxmega6 106 #define bfd_mach_avrxmega7 107 - bfd_arch_cris, /* Axis CRIS */ -#define bfd_mach_cris_v0_v10 255 -#define bfd_mach_cris_v32 32 -#define bfd_mach_cris_v10_v32 1032 bfd_arch_microblaze, /* Xilinx MicroBlaze. */ bfd_arch_moxie, /* The Moxie core. */ bfd_arch_ia64, /* HP/Intel ia64 */ @@ -448,8 +444,6 @@ int print_insn_w65 (bfd_vma, disassemble_info*); int print_insn_d10v (bfd_vma, disassemble_info*); int print_insn_v850 (bfd_vma, disassemble_info*); int print_insn_tic30 (bfd_vma, disassemble_info*); -int print_insn_crisv32 (bfd_vma, disassemble_info*); -int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); int print_insn_ia64 (bfd_vma, disassemble_info*); int print_insn_xtensa (bfd_vma, disassemble_info*); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 6f09b86e7f..45e6676938 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -166,7 +166,20 @@ typedef int (*walk_memory_regions_fn)(void *, target_ulong, int walk_memory_regions(void *, walk_memory_regions_fn); int page_get_flags(target_ulong address); + +/** + * page_set_flags: + * @start: first byte of range + * @last: last byte of range + * @flags: flags to set + * Context: holding mmap lock + * + * Modify the flags of a page and invalidate the code if necessary. + * The flag PAGE_WRITE_ORG is positioned automatically depending + * on PAGE_WRITE. The mmap_lock should already be held. + */ void page_set_flags(target_ulong start, target_ulong last, int flags); + void page_reset_target_data(target_ulong start, target_ulong last); /** diff --git a/include/exec/poison.h b/include/exec/poison.h index 79d7930e73..f4283f693a 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -63,7 +63,6 @@ #pragma GCC poison CPU_INTERRUPT_TGT_INT_2 #pragma GCC poison CONFIG_ALPHA_DIS -#pragma GCC poison CONFIG_CRIS_DIS #pragma GCC poison CONFIG_HPPA_DIS #pragma GCC poison CONFIG_I386_DIS #pragma GCC poison CONFIG_HEXAGON_DIS diff --git a/include/qemu/iov.h b/include/qemu/iov.h index 63a1c01965..44f9db5cee 100644 --- a/include/qemu/iov.h +++ b/include/qemu/iov.h @@ -1,6 +1,7 @@ /* * Helpers for using (partial) iovecs. * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (C) 2010 Red Hat, Inc. * * Author(s): @@ -76,6 +77,32 @@ size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt, size_t offset, int fillc, size_t bytes); /* + * Send/recv data from/to iovec buffers directly, with the provided + * socket flags. + * + * `offset' bytes in the beginning of iovec buffer are skipped and + * next `bytes' bytes are used, which must be within data of iovec. + * + * r = iov_send_recv_with_flags(sockfd, sockflags, iov, iovcnt, + * offset, bytes, true); + * + * is logically equivalent to + * + * char *buf = malloc(bytes); + * iov_to_buf(iov, iovcnt, offset, buf, bytes); + * r = send(sockfd, buf, bytes, sockflags); + * free(buf); + * + * For iov_send_recv_with_flags() _whole_ area being sent or received + * should be within the iovec, not only beginning of it. + */ +ssize_t iov_send_recv_with_flags(int sockfd, int sockflags, + const struct iovec *iov, + unsigned iov_cnt, size_t offset, + size_t bytes, + bool do_send); + +/* * Send/recv data from/to iovec buffers directly * * `offset' bytes in the beginning of iovec buffer are skipped and diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h index 2a10a7052e..44a45931d5 100644 --- a/include/qemu/iova-tree.h +++ b/include/qemu/iova-tree.h @@ -112,31 +112,6 @@ const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map); const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map); /** - * iova_tree_find_address: - * - * @tree: the iova tree to search from - * @iova: the iova address to find - * - * Similar to iova_tree_find(), but it tries to find mapping with - * range iova=iova & size=0. - * - * Return: same as iova_tree_find(). - */ -const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova); - -/** - * iova_tree_foreach: - * - * @tree: the iova tree to iterate on - * @iterator: the iterator for the mappings, return true to stop - * - * Iterate over the iova tree. - * - * Return: 1 if found any overlap, 0 if not, <0 if error. - */ -void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator); - -/** * iova_tree_alloc_map: * * @tree: the iova tree to allocate from diff --git a/include/qemu/userfaultfd.h b/include/qemu/userfaultfd.h index 18a4314212..a1979308d7 100644 --- a/include/qemu/userfaultfd.h +++ b/include/qemu/userfaultfd.h @@ -39,7 +39,6 @@ int uffd_copy_page(int uffd_fd, void *dst_addr, void *src_addr, int uffd_zero_page(int uffd_fd, void *addr, uint64_t length, bool dont_wake); int uffd_wakeup(int uffd_fd, void *addr, uint64_t length); int uffd_read_events(int uffd_fd, struct uffd_msg *msgs, int count); -bool uffd_poll_events(int uffd_fd, int tmo); #endif /* CONFIG_LINUX */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 0678c9d506..52c88a68a9 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3121,11 +3121,11 @@ static bool parse_elf_properties(const ImageSource *src, } /* - * The contents of a valid PT_GNU_PROPERTY is a sequence - * of uint32_t -- swap them all now. + * The contents of a valid PT_GNU_PROPERTY is a sequence of uint32_t. + * Swap most of them now, beyond the header and namesz. */ #ifdef BSWAP_NEEDED - for (int i = 0; i < n / 4; i++) { + for (int i = 4; i < n / 4; i++) { bswap32s(note.data + i); } #endif @@ -3135,15 +3135,15 @@ static bool parse_elf_properties(const ImageSource *src, * immediately follows nhdr and is thus at the 4th word. Further, all * of the inputs to the kernel's round_up are multiples of 4. */ - if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 || - note.nhdr.n_namesz != NOTE_NAME_SZ || + if (tswap32(note.nhdr.n_type) != NT_GNU_PROPERTY_TYPE_0 || + tswap32(note.nhdr.n_namesz) != NOTE_NAME_SZ || note.data[3] != GNU0_MAGIC) { error_setg(errp, "Invalid note in PT_GNU_PROPERTY"); return false; } off = sizeof(note.nhdr) + NOTE_NAME_SZ; - datasz = note.nhdr.n_descsz + off; + datasz = tswap32(note.nhdr.n_descsz) + off; if (datasz > n) { error_setg(errp, "Invalid note size in PT_GNU_PROPERTY"); return false; diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 04d8138d12..0e4be5bf44 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -487,7 +487,10 @@ int load_flt_binary(struct linux_binprm *bprm, struct image_info *info) stack_len += (bprm->envc + 1) * 4; /* the envp array */ + mmap_lock(); res = load_flat_file(bprm, libinfo, 0, &stack_len); + mmap_unlock(); + if (is_error(res)) { return res; } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 2e90a97175..98ad848ab2 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -313,6 +313,15 @@ static inline bool access_ok(CPUState *cpu, int type, int copy_from_user(void *hptr, abi_ulong gaddr, ssize_t len); int copy_to_user(abi_ulong gaddr, void *hptr, ssize_t len); +/* + * copy_struct_from_user() copies a target struct to a host struct, in + * a way that guarantees backwards-compatibility for struct syscall + * arguments. + * + * Similar to kernels uaccess.h:copy_struct_from_user() + */ +int copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize); + /* Functions for accessing guest memory. The tget and tput functions read/write single values, byteswapping as necessary. The lock_user function gets a pointer to a contiguous area of guest memory, but does not perform diff --git a/linux-user/strace.c b/linux-user/strace.c index b4d1098170..c3eb3a2706 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -13,6 +13,9 @@ #include <linux/if_packet.h> #include <linux/in6.h> #include <linux/netlink.h> +#ifdef HAVE_OPENAT2_H +#include <linux/openat2.h> +#endif #include <sched.h> #include "qemu.h" #include "user-internals.h" @@ -373,7 +376,7 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last) un->sun_path[i]; i++) { qemu_log("%c", un->sun_path[i]); } - qemu_log("\"}"); + qemu_log("\"},"); break; } case AF_INET: { @@ -383,7 +386,7 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last) ntohs(in->sin_port)); qemu_log("sin_addr=inet_addr(\"%d.%d.%d.%d\")", c[0], c[1], c[2], c[3]); - qemu_log("}"); + qemu_log("},"); break; } case AF_PACKET: { @@ -414,12 +417,12 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last) } qemu_log(",sll_addr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); - qemu_log("}"); + qemu_log("},"); break; } case AF_NETLINK: { struct target_sockaddr_nl *nl = (struct target_sockaddr_nl *)sa; - qemu_log("{nl_family=AF_NETLINK,nl_pid=%u,nl_groups=%u}", + qemu_log("{nl_family=AF_NETLINK,nl_pid=%u,nl_groups=%u},", tswap32(nl->nl_pid), tswap32(nl->nl_groups)); break; } @@ -429,14 +432,14 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last) qemu_log("%02x, ", sa->sa_data[i]); } qemu_log("%02x}", sa->sa_data[i]); - qemu_log("}"); + qemu_log("},"); break; } unlock_user(sa, addr, 0); } else { - print_raw_param("0x"TARGET_ABI_FMT_lx, addr, 0); + print_pointer(addr, 0); } - qemu_log(", "TARGET_ABI_FMT_ld"%s", addrlen, get_comma(last)); + qemu_log(TARGET_ABI_FMT_ld"%s", addrlen, get_comma(last)); } static void @@ -1063,6 +1066,18 @@ UNUSED static const struct flags open_flags[] = { FLAG_END, }; +UNUSED static const struct flags openat2_resolve_flags[] = { +#ifdef HAVE_OPENAT2_H + FLAG_GENERIC(RESOLVE_NO_XDEV), + FLAG_GENERIC(RESOLVE_NO_MAGICLINKS), + FLAG_GENERIC(RESOLVE_NO_SYMLINKS), + FLAG_GENERIC(RESOLVE_BENEATH), + FLAG_GENERIC(RESOLVE_IN_ROOT), + FLAG_GENERIC(RESOLVE_CACHED), +#endif + FLAG_END, +}; + UNUSED static const struct flags mount_flags[] = { #ifdef MS_BIND FLAG_GENERIC(MS_BIND), @@ -1655,6 +1670,13 @@ print_buf(abi_long addr, abi_long len, int last) } } +static void +print_buf_len(abi_long addr, abi_long len, int last) +{ + print_buf(addr, len, 0); + print_raw_param(TARGET_ABI_FMT_ld, len, last); +} + /* * Prints out raw parameter using given format. Caller needs * to do byte swapping if needed. @@ -2742,8 +2764,7 @@ static void do_print_sendrecv(const char *name, abi_long arg1) qemu_log("%s(", name); print_sockfd(sockfd, 0); - print_buf(msg, len, 0); - print_raw_param(TARGET_ABI_FMT_ld, len, 0); + print_buf_len(msg, len, 0); print_flags(msg_flags, flags, 1); qemu_log(")"); } @@ -2761,8 +2782,7 @@ static void do_print_msgaddr(const char *name, abi_long arg1) qemu_log("%s(", name); print_sockfd(sockfd, 0); - print_buf(msg, len, 0); - print_raw_param(TARGET_ABI_FMT_ld, len, 0); + print_buf_len(msg, len, 0); print_flags(msg_flags, flags, 0); print_sockaddr(addr, addrlen, 0); qemu_log(")"); @@ -3122,6 +3142,38 @@ print_bind(CPUArchState *cpu_env, const struct syscallname *name, } #endif +#ifdef TARGET_NR_recvfrom +static void +print_recvfrom(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_sockfd(arg0, 0); + print_pointer(arg1, 0); /* output */ + print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); + print_flags(msg_flags, arg3, 0); + print_pointer(arg4, 0); /* output */ + print_pointer(arg5, 1); /* in/out */ + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_sendto +static void +print_sendto(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_sockfd(arg0, 0); + print_buf_len(arg1, arg2, 0); + print_flags(msg_flags, arg3, 0); + print_sockaddr(arg4, arg5, 1); + print_syscall_epilogue(name); +} +#endif + #if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \ defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) static void @@ -3483,6 +3535,38 @@ print_openat(CPUArchState *cpu_env, const struct syscallname *name, } #endif +#ifdef TARGET_NR_openat2 +static void +print_openat2(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + struct open_how_ver0 how; + + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + + if ((abi_ulong)arg3 >= sizeof(struct target_open_how_ver0) && + copy_struct_from_user(&how, sizeof(how), arg2, arg3) == 0) { + how.flags = tswap64(how.flags); + how.mode = tswap64(how.mode); + how.resolve = tswap64(how.resolve); + qemu_log("{"); + print_open_flags(how.flags, 0); + if (how.flags & TARGET_O_CREAT) { + print_file_mode(how.mode, 0); + } + print_flags(openat2_resolve_flags, how.resolve, 1); + qemu_log("},"); + } else { + print_pointer(arg2, 0); + } + print_raw_param(TARGET_ABI_FMT_lu, arg3, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_pidfd_send_signal static void print_pidfd_send_signal(CPUArchState *cpu_env, const struct syscallname *name, @@ -4168,6 +4252,63 @@ print_ioctl(CPUArchState *cpu_env, const struct syscallname *name, } #endif +#if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid) +static void print_wstatus(int wstatus) +{ + if (WIFSIGNALED(wstatus)) { + qemu_log("{WIFSIGNALED(s) && WTERMSIG(s) == "); + print_signal(WTERMSIG(wstatus), 1); + if (WCOREDUMP(wstatus)) { + qemu_log(" && WCOREDUMP(s)"); + } + qemu_log("}"); + } else if (WIFEXITED(wstatus)) { + qemu_log("{WIFEXITED(s) && WEXITSTATUS(s) == %d}", + WEXITSTATUS(wstatus)); + } else { + print_number(wstatus, 1); + } +} + +static void print_ret_wstatus(abi_long ret, abi_long wstatus_addr) +{ + int wstatus; + + if (!print_syscall_err(ret) + && wstatus_addr + && get_user_s32(wstatus, wstatus_addr)) { + qemu_log(TARGET_ABI_FMT_ld " (wstatus=", ret); + print_wstatus(wstatus); + qemu_log(")"); + } + qemu_log("\n"); +} +#endif + +#ifdef TARGET_NR_wait4 +static void +print_syscall_ret_wait4(CPUArchState *cpu_env, + const struct syscallname *name, + abi_long ret, abi_long arg0, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5) +{ + print_ret_wstatus(ret, arg1); +} +#endif + +#ifdef TARGET_NR_waitpid +static void +print_syscall_ret_waitpid(CPUArchState *cpu_env, + const struct syscallname *name, + abi_long ret, abi_long arg0, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5) +{ + print_ret_wstatus(ret, arg1); +} +#endif + /* * An array of all of the syscalls we know about */ diff --git a/linux-user/strace.list b/linux-user/strace.list index dfd4237d14..0d69fb3150 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -715,6 +715,9 @@ #ifdef TARGET_NR_openat { TARGET_NR_openat, "openat" , NULL, print_openat, NULL }, #endif +#ifdef TARGET_NR_openat2 +{ TARGET_NR_openat2, "openat2" , NULL, print_openat2, NULL }, +#endif #ifdef TARGET_NR_osf_adjtime { TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL }, #endif @@ -1135,7 +1138,7 @@ { TARGET_NR_recv, "recv" , "%s(%d,%p,%u,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_recvfrom -{ TARGET_NR_recvfrom, "recvfrom" , NULL, NULL, NULL }, +{ TARGET_NR_recvfrom, "recvfrom" , NULL, print_recvfrom, NULL }, #endif #ifdef TARGET_NR_recvmmsg { TARGET_NR_recvmmsg, "recvmmsg" , NULL, NULL, NULL }, @@ -1285,7 +1288,7 @@ { TARGET_NR_sendmsg, "sendmsg" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_sendto -{ TARGET_NR_sendto, "sendto" , NULL, NULL, NULL }, +{ TARGET_NR_sendto, "sendto" , NULL, print_sendto, NULL }, #endif #ifdef TARGET_NR_setdomainname { TARGET_NR_setdomainname, "setdomainname" , NULL, NULL, NULL }, @@ -1659,13 +1662,15 @@ { TARGET_NR_vserver, "vserver" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_wait4 -{ TARGET_NR_wait4, "wait4" , "%s(%d,%p,%d,%p)", NULL, NULL }, +{ TARGET_NR_wait4, "wait4" , "%s(%d,%p,%d,%p)", NULL, + print_syscall_ret_wait4 }, #endif #ifdef TARGET_NR_waitid { TARGET_NR_waitid, "waitid" , "%s(%#x,%d,%p,%#x)", NULL, NULL }, #endif #ifdef TARGET_NR_waitpid -{ TARGET_NR_waitpid, "waitpid" , "%s(%d,%p,%#x)", NULL, NULL }, +{ TARGET_NR_waitpid, "waitpid", "%s(%d,%p,%#x)", NULL, + print_syscall_ret_waitpid }, #endif #ifdef TARGET_NR_write { TARGET_NR_write, "write" , "%s(%d,%#x,%d)", NULL, NULL }, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a666986189..1354e75694 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -602,6 +602,33 @@ static int check_zeroed_user(abi_long addr, size_t ksize, size_t usize) return 1; } +/* + * Copies a target struct to a host struct, in a way that guarantees + * backwards-compatibility for struct syscall arguments. + * + * Similar to kernels uaccess.h:copy_struct_from_user() + */ +int copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize) +{ + size_t size = MIN(ksize, usize); + size_t rest = MAX(ksize, usize) - size; + + /* Deal with trailing bytes. */ + if (usize < ksize) { + memset(dst + size, 0, rest); + } else if (usize > ksize) { + int ret = check_zeroed_user(src, ksize, usize); + if (ret <= 0) { + return ret ?: -TARGET_E2BIG; + } + } + /* Copy the interoperable parts of the struct. */ + if (copy_from_user(dst, src, size)) { + return -TARGET_EFAULT; + } + return 0; +} + #define safe_syscall0(type, name) \ static type safe_##name(void) \ { \ @@ -653,6 +680,10 @@ safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count) safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count) safe_syscall4(int, openat, int, dirfd, const char *, pathname, \ int, flags, mode_t, mode) + +safe_syscall4(int, openat2, int, dirfd, const char *, pathname, \ + const struct open_how_ver0 *, how, size_t, size) + #if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid) safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \ struct rusage *, rusage) @@ -8332,8 +8363,9 @@ static int open_net_route(CPUArchState *cpu_env, int fd) } #endif -int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, - int flags, mode_t mode, bool safe) +static int maybe_do_fake_open(CPUArchState *cpu_env, int dirfd, + const char *fname, int flags, mode_t mode, + int openat2_resolve, bool safe) { g_autofree char *proc_name = NULL; const char *pathname; @@ -8370,6 +8402,12 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, } if (is_proc_myself(pathname, "exe")) { + /* Honor openat2 resolve flags */ + if ((openat2_resolve & RESOLVE_NO_MAGICLINKS) || + (openat2_resolve & RESOLVE_NO_SYMLINKS)) { + errno = ELOOP; + return -1; + } if (safe) { return safe_openat(dirfd, exec_path, flags, mode); } else { @@ -8416,6 +8454,17 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, return fd; } + return -2; +} + +int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, + int flags, mode_t mode, bool safe) +{ + int fd = maybe_do_fake_open(cpu_env, dirfd, pathname, flags, mode, 0, safe); + if (fd > -2) { + return fd; + } + if (safe) { return safe_openat(dirfd, path(pathname), flags, mode); } else { @@ -8423,6 +8472,49 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, } } + +static int do_openat2(CPUArchState *cpu_env, abi_long dirfd, + abi_ptr guest_pathname, abi_ptr guest_open_how, + abi_ulong guest_size) +{ + struct open_how_ver0 how = {0}; + char *pathname; + int ret; + + if (guest_size < sizeof(struct target_open_how_ver0)) { + return -TARGET_EINVAL; + } + ret = copy_struct_from_user(&how, sizeof(how), guest_open_how, guest_size); + if (ret) { + if (ret == -TARGET_E2BIG) { + qemu_log_mask(LOG_UNIMP, + "Unimplemented openat2 open_how size: " + TARGET_ABI_FMT_lu "\n", guest_size); + } + return ret; + } + pathname = lock_user_string(guest_pathname); + if (!pathname) { + return -TARGET_EFAULT; + } + + how.flags = target_to_host_bitmask(tswap64(how.flags), fcntl_flags_tbl); + how.mode = tswap64(how.mode); + how.resolve = tswap64(how.resolve); + int fd = maybe_do_fake_open(cpu_env, dirfd, pathname, how.flags, how.mode, + how.resolve, true); + if (fd > -2) { + ret = get_errno(fd); + } else { + ret = get_errno(safe_openat2(dirfd, pathname, &how, + sizeof(struct open_how_ver0))); + } + + fd_trans_unregister(ret); + unlock_user(pathname, guest_pathname, 0); + return ret; +} + ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz) { ssize_t ret; @@ -9195,6 +9287,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, fd_trans_unregister(ret); unlock_user(p, arg2, 0); return ret; + case TARGET_NR_openat2: + ret = do_openat2(cpu_env, arg1, arg2, arg3, arg4); + return ret; #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) case TARGET_NR_name_to_handle_at: ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index e08d088740..0ade83745e 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2748,4 +2748,22 @@ struct target_sched_param { abi_int sched_priority; }; +/* from kernel's include/uapi/linux/openat2.h */ +struct open_how_ver0 { + __u64 flags; + __u64 mode; + __u64 resolve; +}; +struct target_open_how_ver0 { + abi_ullong flags; + abi_ullong mode; + abi_ullong resolve; +}; +#ifndef RESOLVE_NO_MAGICLINKS +#define RESOLVE_NO_MAGICLINKS 0x02 +#endif +#ifndef RESOLVE_NO_SYMLINKS +#define RESOLVE_NO_SYMLINKS 0x04 +#endif + #endif diff --git a/meson.build b/meson.build index e4b2af138d..aecc381932 100644 --- a/meson.build +++ b/meson.build @@ -2506,6 +2506,7 @@ config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h')) config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h')) config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h')) config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h')) +config_host_data.set('HAVE_OPENAT2_H', cc.has_header('linux/openat2.h')) config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h')) config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h')) config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h')) @@ -3088,7 +3089,6 @@ config_target_mak = {} disassemblers = { 'alpha' : ['CONFIG_ALPHA_DIS'], 'avr' : ['CONFIG_AVR_DIS'], - 'cris' : ['CONFIG_CRIS_DIS'], 'hexagon' : ['CONFIG_HEXAGON_DIS'], 'hppa' : ['CONFIG_HPPA_DIS'], 'i386' : ['CONFIG_I386_DIS'], diff --git a/migration/multifd-nocomp.c b/migration/multifd-nocomp.c index 07c63f4a72..55191152f9 100644 --- a/migration/multifd-nocomp.c +++ b/migration/multifd-nocomp.c @@ -17,6 +17,7 @@ #include "multifd.h" #include "options.h" #include "qapi/error.h" +#include "qemu/cutils.h" #include "qemu/error-report.h" #include "trace.h" @@ -201,7 +202,8 @@ void multifd_ram_fill_packet(MultiFDSendParams *p) packet->zero_pages = cpu_to_be32(zero_num); if (pages->block) { - strncpy(packet->ramblock, pages->block->idstr, 256); + pstrcpy(packet->ramblock, sizeof(packet->ramblock), + pages->block->idstr); } for (int i = 0; i < pages->num; i++) { diff --git a/migration/multifd-qpl.c b/migration/multifd-qpl.c index b0f1e2ba46..bbe466617f 100644 --- a/migration/multifd-qpl.c +++ b/migration/multifd-qpl.c @@ -389,7 +389,7 @@ static void multifd_qpl_compress_pages_slow_path(MultiFDSendParams *p) { QplData *qpl = p->compress_data; MultiFDPages_t *pages = &p->data->u.ram; - uint32_t size = p->page_size; + uint32_t size = multifd_ram_page_size(); qpl_job *job = qpl->sw_job; uint8_t *zbuf = qpl->zbuf; uint8_t *buf; @@ -420,7 +420,7 @@ static void multifd_qpl_compress_pages(MultiFDSendParams *p) { QplData *qpl = p->compress_data; MultiFDPages_t *pages = &p->data->u.ram; - uint32_t size = p->page_size; + uint32_t size = multifd_ram_page_size(); QplHwJob *hw_job; uint8_t *buf; uint8_t *zbuf; @@ -560,7 +560,7 @@ static int multifd_qpl_decompress_pages_slow_path(MultiFDRecvParams *p, Error **errp) { QplData *qpl = p->compress_data; - uint32_t size = p->page_size; + uint32_t size = multifd_ram_page_size(); qpl_job *job = qpl->sw_job; uint8_t *zbuf = qpl->zbuf; uint8_t *addr; @@ -598,7 +598,7 @@ static int multifd_qpl_decompress_pages_slow_path(MultiFDRecvParams *p, static int multifd_qpl_decompress_pages(MultiFDRecvParams *p, Error **errp) { QplData *qpl = p->compress_data; - uint32_t size = p->page_size; + uint32_t size = multifd_ram_page_size(); uint8_t *zbuf = qpl->zbuf; uint8_t *addr; uint32_t len; @@ -677,7 +677,7 @@ static int multifd_qpl_recv(MultiFDRecvParams *p, Error **errp) } for (int i = 0; i < p->normal_num; i++) { qpl->zlen[i] = be32_to_cpu(qpl->zlen[i]); - assert(qpl->zlen[i] <= p->page_size); + assert(qpl->zlen[i] <= multifd_ram_page_size()); zbuf_len += qpl->zlen[i]; } diff --git a/migration/options.c b/migration/options.c index 147cd2b8fd..ad8d6989a8 100644 --- a/migration/options.c +++ b/migration/options.c @@ -339,13 +339,6 @@ bool migrate_xbzrle(void) return s->capabilities[MIGRATION_CAPABILITY_XBZRLE]; } -bool migrate_zero_blocks(void) -{ - MigrationState *s = migrate_get_current(); - - return s->capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS]; -} - bool migrate_zero_copy_send(void) { MigrationState *s = migrate_get_current(); @@ -457,6 +450,10 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) ERRP_GUARD(); MigrationIncomingState *mis = migration_incoming_get_current(); + if (new_caps[MIGRATION_CAPABILITY_ZERO_BLOCKS]) { + warn_report("zero-blocks capability is deprecated"); + } + #ifndef CONFIG_REPLICATION if (new_caps[MIGRATION_CAPABILITY_X_COLO]) { error_setg(errp, "QEMU compiled without replication module" @@ -605,26 +602,6 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) return true; } -bool migrate_cap_set(int cap, bool value, Error **errp) -{ - MigrationState *s = migrate_get_current(); - bool new_caps[MIGRATION_CAPABILITY__MAX]; - - if (migration_is_running()) { - error_setg(errp, "There's a migration process in progress"); - return false; - } - - memcpy(new_caps, s->capabilities, sizeof(new_caps)); - new_caps[cap] = value; - - if (!migrate_caps_check(s->capabilities, new_caps, errp)) { - return false; - } - s->capabilities[cap] = value; - return true; -} - MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp) { MigrationCapabilityStatusList *head = NULL, **tail = &head; diff --git a/migration/options.h b/migration/options.h index a0bd6edc06..79084eed0d 100644 --- a/migration/options.h +++ b/migration/options.h @@ -40,7 +40,6 @@ bool migrate_release_ram(void); bool migrate_return_path(void); bool migrate_validate_uuid(void); bool migrate_xbzrle(void); -bool migrate_zero_blocks(void); bool migrate_zero_copy_send(void); /* @@ -58,7 +57,6 @@ bool migrate_tls(void); /* capabilities helpers */ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp); -bool migrate_cap_set(int cap, bool value, Error **errp); /* parameters */ diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 0fe9d83d44..83f6160a36 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -746,18 +746,10 @@ int postcopy_wake_shared(struct PostCopyFD *pcfd, RAMBlock *rb) { size_t pagesize = qemu_ram_pagesize(rb); - struct uffdio_range range; - int ret; trace_postcopy_wake_shared(client_addr, qemu_ram_get_idstr(rb)); - range.start = ROUND_DOWN(client_addr, pagesize); - range.len = pagesize; - ret = ioctl(pcfd->fd, UFFDIO_WAKE, &range); - if (ret) { - error_report("%s: Failed to wake: %zx in %s (%s)", - __func__, (size_t)client_addr, qemu_ram_get_idstr(rb), - strerror(errno)); - } - return ret; + return uffd_wakeup(pcfd->fd, + (void *)(uintptr_t)ROUND_DOWN(client_addr, pagesize), + pagesize); } static int postcopy_request_page(MigrationIncomingState *mis, RAMBlock *rb, @@ -1275,18 +1267,10 @@ static int qemu_ufd_copy_ioctl(MigrationIncomingState *mis, void *host_addr, int ret; if (from_addr) { - struct uffdio_copy copy_struct; - copy_struct.dst = (uint64_t)(uintptr_t)host_addr; - copy_struct.src = (uint64_t)(uintptr_t)from_addr; - copy_struct.len = pagesize; - copy_struct.mode = 0; - ret = ioctl(userfault_fd, UFFDIO_COPY, ©_struct); + ret = uffd_copy_page(userfault_fd, host_addr, from_addr, pagesize, + false); } else { - struct uffdio_zeropage zero_struct; - zero_struct.range.start = (uint64_t)(uintptr_t)host_addr; - zero_struct.range.len = pagesize; - zero_struct.mode = 0; - ret = ioctl(userfault_fd, UFFDIO_ZEROPAGE, &zero_struct); + ret = uffd_zero_page(userfault_fd, host_addr, pagesize, false); } if (!ret) { qemu_mutex_lock(&mis->page_request_mutex); @@ -1343,18 +1327,16 @@ int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from, RAMBlock *rb) { size_t pagesize = qemu_ram_pagesize(rb); + int e; /* copy also acks to the kernel waking the stalled thread up * TODO: We can inhibit that ack and only do it if it was requested * which would be slightly cheaper, but we'd have to be careful * of the order of updating our page state. */ - if (qemu_ufd_copy_ioctl(mis, host, from, pagesize, rb)) { - int e = errno; - error_report("%s: %s copy host: %p from: %p (size: %zd)", - __func__, strerror(e), host, from, pagesize); - - return -e; + e = qemu_ufd_copy_ioctl(mis, host, from, pagesize, rb); + if (e) { + return e; } trace_postcopy_place_page(host); @@ -1376,12 +1358,10 @@ int postcopy_place_page_zero(MigrationIncomingState *mis, void *host, * but it's not available for everything (e.g. hugetlbpages) */ if (qemu_ram_is_uf_zeroable(rb)) { - if (qemu_ufd_copy_ioctl(mis, host, NULL, pagesize, rb)) { - int e = errno; - error_report("%s: %s zero host: %p", - __func__, strerror(e), host); - - return -e; + int e; + e = qemu_ufd_copy_ioctl(mis, host, NULL, pagesize, rb); + if (e) { + return e; } return postcopy_notify_shared_wake(rb, qemu_ram_block_host_offset(rb, diff --git a/migration/socket.c b/migration/socket.c index 9ab89b1e08..5ec65b8c03 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -42,24 +42,6 @@ void socket_send_channel_create(QIOTaskFunc f, void *data) f, data, NULL, NULL); } -QIOChannel *socket_send_channel_create_sync(Error **errp) -{ - QIOChannelSocket *sioc = qio_channel_socket_new(); - - if (!outgoing_args.saddr) { - object_unref(OBJECT(sioc)); - error_setg(errp, "Initial sock address not set!"); - return NULL; - } - - if (qio_channel_socket_connect_sync(sioc, outgoing_args.saddr, errp) < 0) { - object_unref(OBJECT(sioc)); - return NULL; - } - - return QIO_CHANNEL(sioc); -} - struct SocketConnectData { MigrationState *s; char *hostname; diff --git a/migration/socket.h b/migration/socket.h index 46c233ecd2..04ebbe95a1 100644 --- a/migration/socket.h +++ b/migration/socket.h @@ -22,7 +22,6 @@ #include "qemu/sockets.h" void socket_send_channel_create(QIOTaskFunc f, void *data); -QIOChannel *socket_send_channel_create_sync(Error **errp); void socket_start_incoming_migration(SocketAddress *saddr, Error **errp); diff --git a/qapi/block-core.json b/qapi/block-core.json index 5c2b3ac0d4..2feae8e697 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3190,12 +3190,18 @@ # # @snapshot-access: Since 7.0 # +# Features: +# +# @deprecated: Member @gluster is deprecated because GlusterFS +# development ceased. +# # Since: 2.9 ## { 'enum': 'BlockdevDriver', 'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs', 'cloop', 'compress', 'copy-before-write', 'copy-on-read', 'dmg', - 'file', 'snapshot-access', 'ftp', 'ftps', 'gluster', + 'file', 'snapshot-access', 'ftp', 'ftps', + {'name': 'gluster', 'features': [ 'deprecated' ] }, {'name': 'host_cdrom', 'if': 'HAVE_HOST_BLOCK_DEVICE' }, {'name': 'host_device', 'if': 'HAVE_HOST_BLOCK_DEVICE' }, 'http', 'https', diff --git a/qapi/char.json b/qapi/char.json index 0d6de1ee35..e045354350 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -273,7 +273,19 @@ # # @reconnect: For a client socket, if a socket is disconnected, then # attempt a reconnect after the given number of seconds. Setting -# this to zero disables this function. (default: 0) (Since: 2.2) +# this to zero disables this function. The use of this member is +# deprecated, use @reconnect-ms instead. (default: 0) (Since: 2.2) +# +# @reconnect-ms: For a client socket, if a socket is disconnected, +# then attempt a reconnect after the given number of milliseconds. +# Setting this to zero disables this function. This member is +# mutually exclusive with @reconnect. +# (default: 0) (Since: 9.2) +# +# Features: +# +# @deprecated: Member @reconnect is deprecated. Use @reconnect-ms +# instead. # # Since: 1.4 ## @@ -287,7 +299,8 @@ '*telnet': 'bool', '*tn3270': 'bool', '*websocket': 'bool', - '*reconnect': 'int' }, + '*reconnect': { 'type': 'int', 'features': [ 'deprecated' ] }, + '*reconnect-ms': 'int' }, 'base': 'ChardevCommon' } ## @@ -432,6 +445,20 @@ 'if': 'CONFIG_SPICE_PROTOCOL' } ## +# @ChardevPty: +# +# Configuration info for pty implementation. +# +# @path: optional path to create a symbolic link that points to the +# allocated PTY +# +# Since: 9.2 +## +{ 'struct': 'ChardevPty', + 'data': { '*path': 'str' }, + 'base': 'ChardevCommon' } + +## # @ChardevBackendKind: # # @file: regular files @@ -642,6 +669,17 @@ { 'struct': 'ChardevRingbufWrapper', 'data': { 'data': 'ChardevRingbuf' } } + +## +# @ChardevPtyWrapper: +# +# @data: Configuration info for pty chardevs +# +# Since: 9.2 +## +{ 'struct': 'ChardevPtyWrapper', + 'data': { 'data': 'ChardevPty' } } + ## # @ChardevBackend: # @@ -662,7 +700,7 @@ 'pipe': 'ChardevHostdevWrapper', 'socket': 'ChardevSocketWrapper', 'udp': 'ChardevUdpWrapper', - 'pty': 'ChardevCommonWrapper', + 'pty': 'ChardevPtyWrapper', 'null': 'ChardevCommonWrapper', 'mux': 'ChardevMuxWrapper', 'msmouse': 'ChardevCommonWrapper', diff --git a/qapi/migration.json b/qapi/migration.json index b66cccf107..3af6aa1740 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -479,11 +479,14 @@ # Features: # # @unstable: Members @x-colo and @x-ignore-shared are experimental. +# @deprecated: Member @zero-blocks is deprecated as being part of +# block migration which was already removed. # # Since: 1.2 ## { 'enum': 'MigrationCapability', - 'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', 'zero-blocks', + 'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', + { 'name': 'zero-blocks', 'features': [ 'deprecated' ] }, 'events', 'postcopy-ram', { 'name': 'x-colo', 'features': [ 'unstable' ] }, 'release-ram', diff --git a/qemu-options.hx b/qemu-options.hx index 20a1ce0d43..d5afefe5b6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3712,7 +3712,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev console,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n" "-chardev serial,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n" #else - "-chardev pty,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n" + "-chardev pty,id=id[,path=path][,mux=on|off][,logfile=PATH][,logappend=on|off]\n" "-chardev stdio,id=id[,mux=on|off][,signal=on|off][,logfile=PATH][,logappend=on|off]\n" #endif #ifdef CONFIG_BRLAPI @@ -3951,12 +3951,22 @@ The available backends are: ``path`` specifies the name of the serial device to open. -``-chardev pty,id=id`` - Create a new pseudo-terminal on the host and connect to it. ``pty`` - does not take any options. +``-chardev pty,id=id[,path=path]`` + Create a new pseudo-terminal on the host and connect to it. ``pty`` is not available on Windows hosts. + If ``path`` is specified, QEMU will create a symbolic link at + that location which points to the new PTY device. + + This avoids having to make QMP or HMP monitor queries to find out + what the new PTY device path is. + + Note that while QEMU will remove the symlink when it exits + gracefully, it will not do so in case of crashes or on certain + startup errors. It is recommended that the user checks and removes + the symlink after QEMU terminates to account for this. + ``-chardev stdio,id=id[,signal=on|off]`` Connect to standard input and standard output of the QEMU process. @@ -4314,8 +4324,19 @@ SRST vc:80Cx24C - ``pty`` - [Linux only] Pseudo TTY (a new PTY is automatically allocated) + ``pty[:path]`` + [Linux only] Pseudo TTY (a new PTY is automatically allocated). + + If ``path`` is specified, QEMU will create a symbolic link at + that location which points to the new PTY device. + + This avoids having to make QMP or HMP monitor queries to find + out what the new PTY device path is. + + Note that while QEMU will remove the symlink when it exits + gracefully, it will not do so in case of crashes or on certain + startup errors. It is recommended that the user checks and + removes the symlink after QEMU terminates to account for this. ``none`` No device is allocated. Note that for machine types which diff --git a/system/memory.c b/system/memory.c index f6f6fee6d8..85f6834cb3 100644 --- a/system/memory.c +++ b/system/memory.c @@ -941,6 +941,38 @@ static void flat_range_coalesced_io_add(FlatRange *fr, AddressSpace *as) } } +static void +flat_range_coalesced_io_notify_listener_add_del(FlatRange *fr, + MemoryRegionSection *mrs, + MemoryListener *listener, + AddressSpace *as, bool add) +{ + CoalescedMemoryRange *cmr; + MemoryRegion *mr = fr->mr; + AddrRange tmp; + + QTAILQ_FOREACH(cmr, &mr->coalesced, link) { + tmp = addrrange_shift(cmr->addr, + int128_sub(fr->addr.start, + int128_make64(fr->offset_in_region))); + + if (!addrrange_intersects(tmp, fr->addr)) { + return; + } + tmp = addrrange_intersection(tmp, fr->addr); + + if (add && listener->coalesced_io_add) { + listener->coalesced_io_add(listener, mrs, + int128_get64(tmp.start), + int128_get64(tmp.size)); + } else if (!add && listener->coalesced_io_del) { + listener->coalesced_io_del(listener, mrs, + int128_get64(tmp.start), + int128_get64(tmp.size)); + } + } +} + static void address_space_update_topology_pass(AddressSpace *as, const FlatView *old_view, const FlatView *new_view, @@ -3015,8 +3047,10 @@ void memory_global_dirty_log_stop(unsigned int flags) static void listener_add_address_space(MemoryListener *listener, AddressSpace *as) { + unsigned i; FlatView *view; FlatRange *fr; + MemoryRegionIoeventfd *fd; if (listener->begin) { listener->begin(listener); @@ -3041,10 +3075,34 @@ static void listener_add_address_space(MemoryListener *listener, if (listener->region_add) { listener->region_add(listener, §ion); } + + /* send coalesced io add notifications */ + flat_range_coalesced_io_notify_listener_add_del(fr, §ion, + listener, as, true); + if (fr->dirty_log_mask && listener->log_start) { listener->log_start(listener, §ion, 0, fr->dirty_log_mask); } } + + /* + * register all eventfds for this address space for the newly registered + * listener. + */ + for (i = 0; i < as->ioeventfd_nb; i++) { + fd = &as->ioeventfds[i]; + MemoryRegionSection section = (MemoryRegionSection) { + .fv = view, + .offset_within_address_space = int128_get64(fd->addr.start), + .size = fd->addr.size, + }; + + if (listener->eventfd_add) { + listener->eventfd_add(listener, §ion, + fd->match_data, fd->data, fd->e); + } + } + if (listener->commit) { listener->commit(listener); } @@ -3054,8 +3112,10 @@ static void listener_add_address_space(MemoryListener *listener, static void listener_del_address_space(MemoryListener *listener, AddressSpace *as) { + unsigned i; FlatView *view; FlatRange *fr; + MemoryRegionIoeventfd *fd; if (listener->begin) { listener->begin(listener); @@ -3067,10 +3127,33 @@ static void listener_del_address_space(MemoryListener *listener, if (fr->dirty_log_mask && listener->log_stop) { listener->log_stop(listener, §ion, fr->dirty_log_mask, 0); } + + /* send coalesced io del notifications */ + flat_range_coalesced_io_notify_listener_add_del(fr, §ion, + listener, as, false); if (listener->region_del) { listener->region_del(listener, §ion); } } + + /* + * de-register all eventfds for this address space for the current + * listener. + */ + for (i = 0; i < as->ioeventfd_nb; i++) { + fd = &as->ioeventfds[i]; + MemoryRegionSection section = (MemoryRegionSection) { + .fv = view, + .offset_within_address_space = int128_get64(fd->addr.start), + .size = fd->addr.size, + }; + + if (listener->eventfd_del) { + listener->eventfd_del(listener, §ion, + fd->match_data, fd->data, fd->e); + } + } + if (listener->commit) { listener->commit(listener); } diff --git a/target/m68k/gdbstub.c b/target/m68k/gdbstub.c index 15547e2313..136159f98f 100644 --- a/target/m68k/gdbstub.c +++ b/target/m68k/gdbstub.c @@ -52,7 +52,7 @@ int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) CPUM68KState *env = cpu_env(cs); uint32_t tmp; - tmp = ldl_p(mem_buf); + tmp = ldl_be_p(mem_buf); if (n < 8) { /* D0-D7 */ diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 4c85badd5d..9d3db8419d 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -57,15 +57,15 @@ static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n) if (n < 8) { float_status s; - env->fregs[n].d = float64_to_floatx80(ldq_p(mem_buf), &s); + env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s); return 8; } switch (n) { case 8: /* fpcontrol */ - cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); + cpu_m68k_set_fpcr(env, ldl_be_p(mem_buf)); return 4; case 9: /* fpstatus */ - env->fpsr = ldl_p(mem_buf); + env->fpsr = ldl_be_p(mem_buf); return 4; case 10: /* fpiar, not implemented */ return 4; @@ -107,10 +107,10 @@ static int m68k_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n) } switch (n) { case 8: /* fpcontrol */ - cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); + cpu_m68k_set_fpcr(env, ldl_be_p(mem_buf)); return 4; case 9: /* fpstatus */ - cpu_m68k_set_fpsr(env, ldl_p(mem_buf)); + cpu_m68k_set_fpsr(env, ldl_be_p(mem_buf)); return 4; case 10: /* fpiar, not implemented */ return 4; diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 445966fb6a..ad3ce34501 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -720,7 +720,9 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s, } /* fallthru */ case 2: /* Indirect register */ - return get_areg(s, reg0); + tmp = tcg_temp_new(); + tcg_gen_mov_i32(tmp, get_areg(s, reg0)); + return tmp; case 4: /* Indirect predecrememnt. */ if (opsize == OS_UNSIZED) { return NULL_QREG; @@ -747,20 +749,23 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s, switch (reg0) { case 0: /* Absolute short. */ offset = (int16_t)read_im16(env, s); - return tcg_constant_i32(offset); + break; case 1: /* Absolute long. */ offset = read_im32(env, s); - return tcg_constant_i32(offset); + break; case 2: /* pc displacement */ offset = s->pc; offset += (int16_t)read_im16(env, s); - return tcg_constant_i32(offset); + break; case 3: /* pc index+displacement. */ return gen_lea_indexed(env, s, NULL_QREG); case 4: /* Immediate. */ default: return NULL_QREG; } + tmp = tcg_temp_new(); + tcg_gen_movi_i32(tmp, offset); + return tmp; } /* Should never happen. */ return NULL_QREG; diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c index a9f4eb92ad..63373f02ce 100644 --- a/target/s390x/gdbstub.c +++ b/target/s390x/gdbstub.c @@ -46,7 +46,7 @@ int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { CPUS390XState *env = cpu_env(cs); - target_ulong tmpl = ldtul_p(mem_buf); + target_ulong tmpl = ldq_be_p(mem_buf); switch (n) { case S390_PSWM_REGNUM: @@ -88,7 +88,7 @@ static int cpu_write_ac_reg(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case S390_A0_REGNUM ... S390_A15_REGNUM: - env->aregs[n] = ldl_p(mem_buf); + env->aregs[n] = ldl_be_p(mem_buf); cpu_synchronize_post_init(env_cpu(env)); return 4; default: @@ -123,10 +123,10 @@ static int cpu_write_fp_reg(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case S390_FPC_REGNUM: - env->fpc = ldl_p(mem_buf); + env->fpc = ldl_be_p(mem_buf); return 4; case S390_F0_REGNUM ... S390_F15_REGNUM: - *get_freg(env, n - S390_F0_REGNUM) = ldtul_p(mem_buf); + *get_freg(env, n - S390_F0_REGNUM) = ldq_be_p(mem_buf); return 8; default: return 0; @@ -167,11 +167,11 @@ static int cpu_write_vreg(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case S390_V0L_REGNUM ... S390_V15L_REGNUM: - env->vregs[n][1] = ldtul_p(mem_buf + 8); + env->vregs[n][1] = ldq_be_p(mem_buf + 8); return 8; case S390_V16_REGNUM ... S390_V31_REGNUM: - env->vregs[n][0] = ldtul_p(mem_buf); - env->vregs[n][1] = ldtul_p(mem_buf + 8); + env->vregs[n][0] = ldq_be_p(mem_buf); + env->vregs[n][1] = ldq_be_p(mem_buf + 8); return 16; default: return 0; @@ -203,7 +203,7 @@ static int cpu_write_c_reg(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case S390_C0_REGNUM ... S390_C15_REGNUM: - env->cregs[n] = ldtul_p(mem_buf); + env->cregs[n] = ldq_be_p(mem_buf); if (tcg_enabled()) { tlb_flush(env_cpu(env)); } @@ -246,19 +246,19 @@ static int cpu_write_virt_reg(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case S390_VIRT_CKC_REGNUM: - env->ckc = ldtul_p(mem_buf); + env->ckc = ldq_be_p(mem_buf); cpu_synchronize_post_init(cs); return 8; case S390_VIRT_CPUTM_REGNUM: - env->cputm = ldtul_p(mem_buf); + env->cputm = ldq_be_p(mem_buf); cpu_synchronize_post_init(cs); return 8; case S390_VIRT_BEA_REGNUM: - env->gbea = ldtul_p(mem_buf); + env->gbea = ldq_be_p(mem_buf); cpu_synchronize_post_init(cs); return 8; case S390_VIRT_PREFIX_REGNUM: - env->psa = ldtul_p(mem_buf); + env->psa = ldq_be_p(mem_buf); cpu_synchronize_post_init(cs); return 8; default: @@ -298,19 +298,19 @@ static int cpu_write_virt_kvm_reg(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case S390_VIRT_KVM_PP_REGNUM: - env->pp = ldtul_p(mem_buf); + env->pp = ldq_be_p(mem_buf); cpu_synchronize_post_init(env_cpu(env)); return 8; case S390_VIRT_KVM_PFT_REGNUM: - env->pfault_token = ldtul_p(mem_buf); + env->pfault_token = ldq_be_p(mem_buf); cpu_synchronize_post_init(env_cpu(env)); return 8; case S390_VIRT_KVM_PFS_REGNUM: - env->pfault_select = ldtul_p(mem_buf); + env->pfault_select = ldq_be_p(mem_buf); cpu_synchronize_post_init(env_cpu(env)); return 8; case S390_VIRT_KVM_PFC_REGNUM: - env->pfault_compare = ldtul_p(mem_buf); + env->pfault_compare = ldq_be_p(mem_buf); cpu_synchronize_post_init(env_cpu(env)); return 8; default: @@ -338,7 +338,7 @@ static int cpu_write_gs_reg(CPUState *cs, uint8_t *mem_buf, int n) S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; - env->gscb[n] = ldtul_p(mem_buf); + env->gscb[n] = ldq_be_p(mem_buf); cpu_synchronize_post_init(env_cpu(env)); return 8; } diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index bbe45a497a..a944f16c25 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -603,7 +603,7 @@ static int chsc_sei_nt2_have_event(void) #define CHSC_SEI_NT2 (1ULL << 61) static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res) { - uint64_t selection_mask = ldq_p(&req->param1); + uint64_t selection_mask = ldq_be_p(&req->param1); uint8_t *res_flags = (uint8_t *)res->data; int have_event = 0; int have_more = 0; diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 3f413ce3c1..223f079524 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2617,8 +2617,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, if (TCG_TARGET_REG_BITS == 64 && addr_type == TCG_TYPE_I32) { /* Zero-extend the guest address for use in the host address. */ - tcg_out_ext32u(s, TCG_REG_R0, addrlo); - h->index = TCG_REG_R0; + tcg_out_ext32u(s, TCG_REG_TMP2, addrlo); + h->index = TCG_REG_TMP2; } else { h->index = addrlo; } @@ -2704,9 +2704,9 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, uint32_t insn = qemu_stx_opc[opc & (MO_BSWAP | MO_SIZE)]; if (!have_isa_2_06 && insn == STDBRX) { tcg_out32(s, STWBRX | SAB(datalo, h.base, h.index)); - tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, h.index, 4)); + tcg_out32(s, ADDI | TAI(TCG_REG_TMP2, h.index, 4)); tcg_out_shri64(s, TCG_REG_R0, datalo, 32); - tcg_out32(s, STWBRX | SAB(TCG_REG_R0, h.base, TCG_REG_TMP1)); + tcg_out32(s, STWBRX | SAB(TCG_REG_R0, h.base, TCG_REG_TMP2)); } else { tcg_out32(s, insn | SAB(datalo, h.base, h.index)); } diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index a64fcacae2..a1c3b1cb75 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -4,7 +4,7 @@ # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.opensuse.org/opensuse/leap:15.5 +FROM registry.opensuse.org/opensuse/leap:15.6 RUN zypper update -y && \ zypper install -y \ diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 7713f8eb55..c90c02517a 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -11,15 +11,18 @@ endif # Timeouts for individual tests that can be slow e.g. with debugging enabled test_timeouts = { + 'aarch64_raspi4' : 120, 'aarch64_sbsaref' : 600, 'aarch64_virt' : 360, 'acpi_bits' : 240, + 'arm_raspi2' : 120, + 'mips_malta' : 120, 'netdev_ethtool' : 180, 'ppc_40p' : 240, 'ppc64_hv' : 1000, - 'ppc64_powernv' : 120, - 'ppc64_pseries' : 120, - 's390x_ccw_virtio' : 180, + 'ppc64_powernv' : 240, + 'ppc64_pseries' : 240, + 's390x_ccw_virtio' : 240, } tests_generic_system = [ diff --git a/tests/functional/test_arm_vexpress.py b/tests/functional/test_arm_vexpress.py index cc6015112b..6bd6290030 100755 --- a/tests/functional/test_arm_vexpress.py +++ b/tests/functional/test_arm_vexpress.py @@ -11,7 +11,7 @@ from qemu_test.utils import archive_extract class VExpressTest(LinuxKernelTest): ASSET_DAY16 = Asset( - 'https://www.qemu-advent-calendar.org/2018/download/day16.tar.xz', + 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day16.tar.xz', '63311adb2d4c4e7a73214a86d29988add87266a909719c56acfadd026b4110a7') def test_arm_vexpressa9(self): diff --git a/tests/functional/test_m68k_mcf5208evb.py b/tests/functional/test_m68k_mcf5208evb.py index 869ccc88df..00c59590c3 100755 --- a/tests/functional/test_m68k_mcf5208evb.py +++ b/tests/functional/test_m68k_mcf5208evb.py @@ -13,7 +13,7 @@ from qemu_test.utils import archive_extract class Mcf5208EvbTest(LinuxKernelTest): ASSET_DAY07 = Asset( - 'https://www.qemu-advent-calendar.org/2018/download/day07.tar.xz', + 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day07.tar.xz', '753c2f3837126b7c6ba92d0b1e0b156e8a2c5131d2d576bb0b9a763fae73c08a') def test_m68k_mcf5208evb(self): diff --git a/tests/functional/test_or1k_sim.py b/tests/functional/test_or1k_sim.py index aa2a1f08d2..10e0437c50 100755 --- a/tests/functional/test_or1k_sim.py +++ b/tests/functional/test_or1k_sim.py @@ -13,7 +13,7 @@ from qemu_test.utils import archive_extract class OpenRISC1kSimTest(LinuxKernelTest): ASSET_DAY20 = Asset( - 'https://www.qemu-advent-calendar.org/2018/download/day20.tar.xz', + 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day20.tar.xz', 'ff9d7dd7c6bdba325bd85ee85c02db61ff653e129558aeffe6aff55bffb6763a') def test_or1k_sim(self): diff --git a/tests/functional/test_ppc64_e500.py b/tests/functional/test_ppc64_e500.py index 3558ae0c8c..f1af92373e 100755 --- a/tests/functional/test_ppc64_e500.py +++ b/tests/functional/test_ppc64_e500.py @@ -10,7 +10,7 @@ from qemu_test.utils import archive_extract class E500Test(LinuxKernelTest): ASSET_DAY19 = Asset( - 'https://www.qemu-advent-calendar.org/2018/download/day19.tar.xz', + 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day19.tar.xz', '20b1bb5a8488c664defbb5d283addc91a05335a936c63b3f5ff7eee74b725755') def test_ppc64_e500(self): diff --git a/tests/functional/test_ppc_mac.py b/tests/functional/test_ppc_mac.py index a6b1ca2d4c..3f45e37a45 100755 --- a/tests/functional/test_ppc_mac.py +++ b/tests/functional/test_ppc_mac.py @@ -10,7 +10,7 @@ from qemu_test.utils import archive_extract class MacTest(LinuxKernelTest): ASSET_DAY15 = Asset( - 'https://www.qemu-advent-calendar.org/2018/download/day15.tar.xz', + 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day15.tar.xz', '03e0757c131d2959decf293a3572d3b96c5a53587165bf05ce41b2818a2bccd5') def do_day15_test(self): diff --git a/tests/functional/test_sh4_r2d.py b/tests/functional/test_sh4_r2d.py index 5fe8cf9f8d..c3cfff79ad 100755 --- a/tests/functional/test_sh4_r2d.py +++ b/tests/functional/test_sh4_r2d.py @@ -13,7 +13,7 @@ from unittest import skipUnless class R2dTest(LinuxKernelTest): ASSET_DAY09 = Asset( - 'https://www.qemu-advent-calendar.org/2018/download/day09.tar.xz', + 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day09.tar.xz', 'a61b44d2630a739d1380cc4ff4b80981d47ccfd5992f1484ccf48322c35f09ac') # This test has a 6-10% failure rate on various hosts that look diff --git a/tests/functional/test_sparc_sun4m.py b/tests/functional/test_sparc_sun4m.py index b334375820..573f85222a 100755 --- a/tests/functional/test_sparc_sun4m.py +++ b/tests/functional/test_sparc_sun4m.py @@ -11,7 +11,7 @@ from qemu_test.utils import archive_extract class Sun4mTest(LinuxKernelTest): ASSET_DAY11 = Asset( - 'https://www.qemu-advent-calendar.org/2018/download/day11.tar.xz', + 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day11.tar.xz', 'c776533ba756bf4dd3f1fc4c024fb50ef0d853e05c5f5ddf0900a32d1eaa49e0') def test_sparc_ss20(self): diff --git a/tests/functional/test_xtensa_lx60.py b/tests/functional/test_xtensa_lx60.py index 8ce5206a4f..d4ad92dc6c 100755 --- a/tests/functional/test_xtensa_lx60.py +++ b/tests/functional/test_xtensa_lx60.py @@ -11,7 +11,7 @@ from qemu_test.utils import archive_extract class XTensaLX60Test(LinuxKernelTest): ASSET_DAY02 = Asset( - 'https://www.qemu-advent-calendar.org/2018/download/day02.tar.xz', + 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day02.tar.xz', '68ff07f9b3fd3df36d015eb46299ba44748e94bfbb2d5295fddc1a8d4a9fd324') def test_xtensa_lx60(self): diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci -Subproject 789b4601bce4e01f43fdb6ad4ce5ab4e4667444 +Subproject c0fc6fab5cdc839a70d4148aa9809504bc96196 diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 1ae0962f04..0f16f4d525 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -228,8 +228,8 @@ try: # Cirrus packages lists for GitLab # generate_cirrus("freebsd-14") - generate_cirrus("macos-13") generate_cirrus("macos-14") + generate_cirrus("macos-15") # # VM packages lists diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 2b90abf000..b207e38696 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -7,6 +7,7 @@ slow_qtests = { 'migration-test' : 480, 'npcm7xx_pwm-test': 300, 'npcm7xx_watchdog_timer-test': 120, + 'qmp-cmd-test' : 120, 'qom-test' : 900, 'stm32l4x5_usart-test' : 600, 'test-hmp' : 240, diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 814ec109a6..95e45b5029 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -3267,6 +3267,16 @@ static void test_multifd_tcp_cancel(void) qtest_wait_qemu(to); qtest_quit(to); + /* + * Ensure the source QEMU finishes its cancellation process before we + * proceed with the setup of the next migration. The test_migrate_start() + * function and others might want to interact with the source in a way that + * is not possible while the migration is not canceled properly. For + * example, setting migration capabilities when the migration is still + * running leads to an error. + */ + wait_for_migration_status(from, "cancelled", NULL); + args = (MigrateStart){ .only_target = true, }; @@ -3282,8 +3292,6 @@ static void test_multifd_tcp_cancel(void) /* Start incoming migration from the 1st socket */ migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", "{}"); - wait_for_migration_status(from, "cancelled", NULL); - migrate_ensure_non_converge(from); migrate_qmp(from, to2, NULL, NULL, "{}"); diff --git a/tests/unit/test-crypto-hash.c b/tests/unit/test-crypto-hash.c index 124d204485..e5829ca766 100644 --- a/tests/unit/test-crypto-hash.c +++ b/tests/unit/test-crypto-hash.c @@ -1,6 +1,7 @@ /* * QEMU Crypto hash algorithms * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (c) 2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -241,6 +242,50 @@ static void test_hash_base64(void) } } +static void test_hash_accumulate(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { + g_autoptr(QCryptoHash) hash = NULL; + struct iovec iov[] = { + { .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) }, + { .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) }, + { .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) }, + }; + g_autofree uint8_t *result = NULL; + size_t resultlen = 0; + int ret; + size_t j; + + if (!qcrypto_hash_supports(i)) { + continue; + } + + hash = qcrypto_hash_new(i, &error_fatal); + g_assert(hash != NULL); + + /* Add each iovec to the hash context separately */ + for (j = 0; j < G_N_ELEMENTS(iov); j++) { + ret = qcrypto_hash_updatev(hash, + &iov[j], 1, + &error_fatal); + + g_assert(ret == 0); + } + + ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, + &error_fatal); + + g_assert(ret == 0); + g_assert(resultlen == expected_lens[i]); + for (j = 0; j < resultlen; j++) { + g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]); + } + } +} + int main(int argc, char **argv) { int ret = qcrypto_init(&error_fatal); @@ -252,5 +297,6 @@ int main(int argc, char **argv) g_test_add_func("/crypto/hash/prealloc", test_hash_prealloc); g_test_add_func("/crypto/hash/digest", test_hash_digest); g_test_add_func("/crypto/hash/base64", test_hash_base64); + g_test_add_func("/crypto/hash/accumulate", test_hash_accumulate); return g_test_run(); } diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c index b964bb202d..dc7be96e9c 100644 --- a/tests/unit/test-io-channel-socket.c +++ b/tests/unit/test-io-channel-socket.c @@ -506,7 +506,7 @@ static void test_io_channel_unix_listen_cleanup(void) { QIOChannelSocket *ioc; struct sockaddr_un un; - int sock; + int sock, ret = 0; #define TEST_SOCKET "test-io-channel-socket.sock" @@ -519,7 +519,9 @@ static void test_io_channel_unix_listen_cleanup(void) un.sun_family = AF_UNIX; snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET); unlink(TEST_SOCKET); - bind(sock, (struct sockaddr *)&un, sizeof(un)); + ret = bind(sock, (struct sockaddr *)&un, sizeof(un)); + g_assert_cmpint(ret, ==, 0); + ioc->fd = sock; ioc->localAddrLen = sizeof(ioc->localAddr); getsockname(sock, (struct sockaddr *)&ioc->localAddr, diff --git a/util/iov.c b/util/iov.c index 7e73948f5e..7777116123 100644 --- a/util/iov.c +++ b/util/iov.c @@ -3,6 +3,7 @@ * * Copyright IBM, Corp. 2007, 2008 * Copyright (C) 2010 Red Hat, Inc. + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * * Author(s): * Anthony Liguori <aliguori@us.ibm.com> @@ -92,7 +93,8 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt) /* helper function for iov_send_recv() */ static ssize_t -do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send) +do_send_recv(int sockfd, int flags, struct iovec *iov, unsigned iov_cnt, + bool do_send) { #ifdef CONFIG_POSIX ssize_t ret; @@ -102,8 +104,8 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send) msg.msg_iovlen = iov_cnt; do { ret = do_send - ? sendmsg(sockfd, &msg, 0) - : recvmsg(sockfd, &msg, 0); + ? sendmsg(sockfd, &msg, flags) + : recvmsg(sockfd, &msg, flags); } while (ret < 0 && errno == EINTR); return ret; #else @@ -114,8 +116,8 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send) ssize_t off = 0; while (i < iov_cnt) { ssize_t r = do_send - ? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0) - : recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0); + ? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, flags) + : recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, flags); if (r > 0) { ret += r; off += r; @@ -145,6 +147,15 @@ ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt, size_t offset, size_t bytes, bool do_send) { + return iov_send_recv_with_flags(sockfd, 0, _iov, iov_cnt, offset, bytes, + do_send); +} + +ssize_t iov_send_recv_with_flags(int sockfd, int sockflags, + const struct iovec *_iov, + unsigned iov_cnt, size_t offset, + size_t bytes, bool do_send) +{ ssize_t total = 0; ssize_t ret; size_t orig_len, tail; @@ -192,11 +203,11 @@ ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt, assert(iov[niov].iov_len > tail); orig_len = iov[niov].iov_len; iov[niov++].iov_len = tail; - ret = do_send_recv(sockfd, iov, niov, do_send); + ret = do_send_recv(sockfd, sockflags, iov, niov, do_send); /* Undo the changes above before checking for errors */ iov[niov-1].iov_len = orig_len; } else { - ret = do_send_recv(sockfd, iov, niov, do_send); + ret = do_send_recv(sockfd, sockflags, iov, niov, do_send); } if (offset) { iov[0].iov_base -= offset; diff --git a/util/iova-tree.c b/util/iova-tree.c index 536789797e..06295e2755 100644 --- a/util/iova-tree.c +++ b/util/iova-tree.c @@ -115,13 +115,6 @@ const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map) return args.result; } -const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova) -{ - const DMAMap map = { .iova = iova, .size = 0 }; - - return iova_tree_find(tree, &map); -} - static inline void iova_tree_insert_internal(GTree *gtree, DMAMap *range) { /* Key and value are sharing the same range data */ @@ -148,22 +141,6 @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map) return IOVA_OK; } -static gboolean iova_tree_traverse(gpointer key, gpointer value, - gpointer data) -{ - iova_tree_iterator iterator = data; - DMAMap *map = key; - - g_assert(key == value); - - return iterator(map); -} - -void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator) -{ - g_tree_foreach(tree->tree, iova_tree_traverse, iterator); -} - void iova_tree_remove(IOVATree *tree, DMAMap map) { const DMAMap *overlap; diff --git a/util/userfaultfd.c b/util/userfaultfd.c index 1b2fa949d4..2396104f23 100644 --- a/util/userfaultfd.c +++ b/util/userfaultfd.c @@ -240,7 +240,7 @@ int uffd_change_protection(int uffd_fd, void *addr, uint64_t length, * Copy range of source pages to the destination to resolve * missing page fault somewhere in the destination range. * - * Returns 0 on success, negative value in case of an error + * Returns 0 on success, -errno in case of an error * * @uffd_fd: UFFD file descriptor * @dst_addr: destination base address @@ -259,10 +259,11 @@ int uffd_copy_page(int uffd_fd, void *dst_addr, void *src_addr, uffd_copy.mode = dont_wake ? UFFDIO_COPY_MODE_DONTWAKE : 0; if (ioctl(uffd_fd, UFFDIO_COPY, &uffd_copy)) { + int e = errno; error_report("uffd_copy_page() failed: dst_addr=%p src_addr=%p length=%" PRIu64 " mode=%" PRIx64 " errno=%i", dst_addr, src_addr, - length, (uint64_t) uffd_copy.mode, errno); - return -1; + length, (uint64_t) uffd_copy.mode, e); + return -e; } return 0; @@ -273,7 +274,7 @@ int uffd_copy_page(int uffd_fd, void *dst_addr, void *src_addr, * * Fill range pages with zeroes to resolve missing page fault within the range. * - * Returns 0 on success, negative value in case of an error + * Returns 0 on success, -errno in case of an error * * @uffd_fd: UFFD file descriptor * @addr: base address @@ -289,10 +290,11 @@ int uffd_zero_page(int uffd_fd, void *addr, uint64_t length, bool dont_wake) uffd_zeropage.mode = dont_wake ? UFFDIO_ZEROPAGE_MODE_DONTWAKE : 0; if (ioctl(uffd_fd, UFFDIO_ZEROPAGE, &uffd_zeropage)) { + int e = errno; error_report("uffd_zero_page() failed: addr=%p length=%" PRIu64 " mode=%" PRIx64 " errno=%i", addr, length, - (uint64_t) uffd_zeropage.mode, errno); - return -1; + (uint64_t) uffd_zeropage.mode, e); + return -e; } return 0; @@ -306,7 +308,7 @@ int uffd_zero_page(int uffd_fd, void *addr, uint64_t length, bool dont_wake) * via UFFD-IO IOCTLs with MODE_DONTWAKE flag set, then after that all waits * for the whole memory range are satisfied in a single call to uffd_wakeup(). * - * Returns 0 on success, negative value in case of an error + * Returns 0 on success, -errno in case of an error * * @uffd_fd: UFFD file descriptor * @addr: base address @@ -320,9 +322,10 @@ int uffd_wakeup(int uffd_fd, void *addr, uint64_t length) uffd_range.len = length; if (ioctl(uffd_fd, UFFDIO_WAKE, &uffd_range)) { + int e = errno; error_report("uffd_wakeup() failed: addr=%p length=%" PRIu64 " errno=%i", - addr, length, errno); - return -1; + addr, length, e); + return -e; } return 0; @@ -355,31 +358,3 @@ int uffd_read_events(int uffd_fd, struct uffd_msg *msgs, int count) return (int) (res / sizeof(struct uffd_msg)); } - -/** - * uffd_poll_events: poll UFFD file descriptor for read - * - * Returns true if events are available for read, false otherwise - * - * @uffd_fd: UFFD file descriptor - * @tmo: timeout value - */ -bool uffd_poll_events(int uffd_fd, int tmo) -{ - int res; - struct pollfd poll_fd = { .fd = uffd_fd, .events = POLLIN, .revents = 0 }; - - do { - res = poll(&poll_fd, 1, tmo); - } while (res < 0 && errno == EINTR); - - if (res == 0) { - return false; - } - if (res < 0) { - error_report("uffd_poll_events() failed: errno=%i", errno); - return false; - } - - return (poll_fd.revents & POLLIN) != 0; -} |