diff options
181 files changed, 2117 insertions, 1026 deletions
@@ -187,11 +187,6 @@ SUBDIR_RULES=$(foreach t, all clean distclean, $(addsuffix /$(t), $(SUBDIRS))) $(SUBDIR_RULES): $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),) -ifneq ($(filter contrib/plugins, $(SUBDIRS)),) -.PHONY: plugins -plugins: contrib/plugins/all -endif - .PHONY: recurse-all recurse-clean recurse-all: $(addsuffix /all, $(SUBDIRS)) recurse-clean: $(addsuffix /clean, $(SUBDIRS)) @@ -307,11 +302,6 @@ help: $(call print-help,cscope,Generate cscope index) $(call print-help,sparse,Run sparse on the QEMU source) @echo '' -ifneq ($(filter contrib/plugins, $(SUBDIRS)),) - @echo 'Plugin targets:' - $(call print-help,plugins,Build the example TCG plugins) - @echo '' -endif @echo 'Cleaning targets:' $(call print-help,clean,Remove most generated files but keep the config) $(call print-help,distclean,Remove all generated files) diff --git a/bsd-user/main.c b/bsd-user/main.c index cc980e6..61ca73c 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -60,6 +60,7 @@ uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; static bool opt_one_insn_per_tb; +static unsigned long opt_tb_size; uintptr_t guest_base; bool have_guest_base; /* @@ -169,6 +170,7 @@ static void usage(void) " (use '-d help' for a list of log items)\n" "-D logfile write logs to 'logfile' (default stderr)\n" "-one-insn-per-tb run with one guest instruction per emulated TB\n" + "-tb-size size TCG translation block cache size\n" "-strace log system calls\n" "-trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n" " specify tracing options\n" @@ -387,6 +389,11 @@ int main(int argc, char **argv) seed_optarg = optarg; } else if (!strcmp(r, "one-insn-per-tb")) { opt_one_insn_per_tb = true; + } else if (!strcmp(r, "tb-size")) { + r = argv[optind++]; + if (qemu_strtoul(r, NULL, 0, &opt_tb_size)) { + usage(); + } } else if (!strcmp(r, "strace")) { do_strace = 1; } else if (!strcmp(r, "trace")) { @@ -452,6 +459,8 @@ int main(int argc, char **argv) accel_init_interfaces(ac); object_property_set_bool(OBJECT(accel), "one-insn-per-tb", opt_one_insn_per_tb, &error_abort); + object_property_set_int(OBJECT(accel), "tb-size", + opt_tb_size, &error_abort); ac->init_machine(NULL); } @@ -601,6 +610,7 @@ int main(int argc, char **argv) init_task_state(ts); ts->info = info; ts->bprm = &bprm; + ts->ts_tid = qemu_get_thread_id(); cpu->opaque = ts; target_set_brk(info->brk); diff --git a/bsd-user/x86_64/target_arch_thread.h b/bsd-user/x86_64/target_arch_thread.h index 52c2890..7739bb2 100644 --- a/bsd-user/x86_64/target_arch_thread.h +++ b/bsd-user/x86_64/target_arch_thread.h @@ -31,7 +31,7 @@ static inline void target_thread_init(struct target_pt_regs *regs, struct image_info *infop) { regs->rax = 0; - regs->rsp = infop->start_stack; + regs->rsp = ((infop->start_stack - 8) & ~0xfUL) + 8; regs->rip = infop->entry; regs->rdi = infop->start_stack; } @@ -1077,7 +1077,6 @@ if test "$plugins" != "no" && test $host_bits -eq 64; then plugins="no" else plugins=yes - subdirs="$subdirs contrib/plugins" fi fi @@ -1708,7 +1707,6 @@ LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit LINKS="$LINKS tests/avocado tests/data" LINKS="$LINKS tests/qemu-iotests/check tests/qemu-iotests/Makefile" LINKS="$LINKS python" -LINKS="$LINKS contrib/plugins/Makefile " for f in $LINKS ; do if [ -e "$source_path/$f" ]; then symlink "$source_path/$f" "$f" @@ -1794,22 +1792,6 @@ if test "$default_targets" = "yes"; then echo "CONFIG_DEFAULT_TARGETS=y" >> $config_host_mak fi -# contrib/plugins configuration -echo "# Automatically generated by configure - do not modify" > contrib/plugins/$config_host_mak -echo "SRC_PATH=$source_path/contrib/plugins" >> contrib/plugins/$config_host_mak -echo "PKG_CONFIG=${pkg_config}" >> contrib/plugins/$config_host_mak -echo "CC=$cc $CPU_CFLAGS" >> contrib/plugins/$config_host_mak -echo "CFLAGS=${CFLAGS-$default_cflags} $EXTRA_CFLAGS" >> contrib/plugins/$config_host_mak -if test "$host_os" = windows; then - echo "DLLTOOL=$dlltool" >> contrib/plugins/$config_host_mak -fi -if test "$host_os" = darwin; then - echo "CONFIG_DARWIN=y" >> contrib/plugins/$config_host_mak -fi -if test "$host_os" = windows; then - echo "CONFIG_WIN32=y" >> contrib/plugins/$config_host_mak -fi - # tests/tcg configuration mkdir -p tests/tcg echo "# Automatically generated by configure - do not modify" > tests/tcg/$config_host_mak diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile deleted file mode 100644 index bbddd48..0000000 --- a/contrib/plugins/Makefile +++ /dev/null @@ -1,87 +0,0 @@ -# -*- Mode: makefile -*- -# -# This Makefile example is fairly independent from the main makefile -# so users can take and adapt it for their build. We only really -# include config-host.mak so we don't have to repeat probing for -# programs that the main configure has already done for us. -# - -include config-host.mak - -TOP_SRC_PATH = $(SRC_PATH)/../.. - -VPATH += $(SRC_PATH) - -NAMES := -NAMES += bbv -NAMES += execlog -NAMES += hotblocks -NAMES += hotpages -NAMES += howvec - -# The lockstep example communicates using unix sockets, -# and can't be easily made to work on windows. -ifneq ($(CONFIG_WIN32),y) -NAMES += lockstep -endif - -NAMES += hwprofile -NAMES += cache -NAMES += drcov -NAMES += ips -NAMES += stoptrigger -NAMES += cflow - -ifeq ($(CONFIG_WIN32),y) -SO_SUFFIX := .dll -LDLIBS += $(shell $(PKG_CONFIG) --libs glib-2.0) -else -SO_SUFFIX := .so -endif - -SONAMES := $(addsuffix $(SO_SUFFIX),$(addprefix lib,$(NAMES))) - -# The main QEMU uses Glib extensively so it is perfectly fine to use it -# in plugins (which many example do). -PLUGIN_CFLAGS := $(shell $(PKG_CONFIG) --cflags glib-2.0) -PLUGIN_CFLAGS += -fPIC -Wall -PLUGIN_CFLAGS += -I$(TOP_SRC_PATH)/include/qemu - -# Helper that honours V=1 so we get some output when compiling -quiet-@ = $(if $(V),,@$(if $1,printf " %-7s %s\n" "$(strip $1)" "$(strip $2)" && )) -quiet-command = $(call quiet-@,$2,$3)$1 - -# for including , in command strings -COMMA := , - -all: $(SONAMES) - -%.o: %.c - $(call quiet-command, \ - $(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<, \ - BUILD, plugin $@) - -ifeq ($(CONFIG_WIN32),y) -lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/libqemu_plugin_api.a - $(call quiet-command, \ - $(CC) -shared -o $@ $^ $(LDLIBS), \ - LINK, plugin $@) -else ifeq ($(CONFIG_DARWIN),y) -lib%$(SO_SUFFIX): %.o - $(call quiet-command, \ - $(CC) -bundle -Wl$(COMMA)-undefined$(COMMA)dynamic_lookup -o $@ $^ $(LDLIBS), \ - LINK, plugin $@) -else -lib%$(SO_SUFFIX): %.o - $(call quiet-command, \ - $(CC) -shared -o $@ $^ $(LDLIBS), \ - LINK, plugin $@) -endif - - -clean distclean: - rm -f *.o *$(SO_SUFFIX) *.d - rm -Rf .libs - -.PHONY: all clean -.SECONDARY: diff --git a/contrib/plugins/cflow.c b/contrib/plugins/cflow.c index 6faa55d..b39974d 100644 --- a/contrib/plugins/cflow.c +++ b/contrib/plugins/cflow.c @@ -136,7 +136,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) g_autoptr(GString) result = g_string_new("collected "); GList *data; GCompareFunc sort = &hottest; - int n = 0; + int i = 0; g_mutex_lock(&node_lock); g_string_append_printf(result, "%d control flow nodes in the hash table\n", @@ -162,8 +162,8 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) data = g_list_sort(data, sort); for (GList *l = data; - l != NULL && n < topn; - l = l->next, n++) { + l != NULL && i < topn; + l = l->next, i++) { NodeData *n = l->data; const char *type = n->mid_count ? "sync fault" : "branch"; g_string_append_printf(result, " addr: 0x%"PRIx64 " %s: %s (%s)\n", diff --git a/contrib/plugins/meson.build b/contrib/plugins/meson.build new file mode 100644 index 0000000..63a32c2 --- /dev/null +++ b/contrib/plugins/meson.build @@ -0,0 +1,28 @@ +contrib_plugins = ['bbv', 'cache', 'cflow', 'drcov', 'execlog', 'hotblocks', + 'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger'] +if host_os != 'windows' + # lockstep uses socket.h + contrib_plugins += 'lockstep' +endif + +t = [] +if get_option('plugins') + foreach i : contrib_plugins + if host_os == 'windows' + t += shared_module(i, files(i + '.c') + 'win32_linker.c', + include_directories: '../../include/qemu', + link_depends: [win32_qemu_plugin_api_lib], + link_args: ['-Lplugins', '-lqemu_plugin_api'], + dependencies: glib) + else + t += shared_module(i, files(i + '.c'), + include_directories: '../../include/qemu', + dependencies: glib) + endif + endforeach +endif +if t.length() > 0 + alias_target('contrib-plugins', t) +else + run_target('contrib-plugins', command: find_program('true')) +endif diff --git a/crypto/hash-gcrypt.c b/crypto/hash-gcrypt.c index 73533a4..af61c4e 100644 --- a/crypto/hash-gcrypt.c +++ b/crypto/hash-gcrypt.c @@ -34,13 +34,16 @@ static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = { [QCRYPTO_HASH_ALGO_SHA384] = GCRY_MD_SHA384, [QCRYPTO_HASH_ALGO_SHA512] = GCRY_MD_SHA512, [QCRYPTO_HASH_ALGO_RIPEMD160] = GCRY_MD_RMD160, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = GCRY_MD_SM3, +#endif }; gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) { if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) && qcrypto_hash_alg_map[alg] != GCRY_MD_NONE) { - return true; + return gcry_md_test_algo(qcrypto_hash_alg_map[alg]) == 0; } return false; } @@ -49,7 +52,7 @@ static QCryptoHash *qcrypto_gcrypt_hash_new(QCryptoHashAlgo alg, Error **errp) { QCryptoHash *hash; - int ret; + gcry_error_t ret; hash = g_new(QCryptoHash, 1); hash->alg = alg; @@ -57,7 +60,7 @@ QCryptoHash *qcrypto_gcrypt_hash_new(QCryptoHashAlgo alg, Error **errp) ret = gcry_md_open((gcry_md_hd_t *) hash->opaque, qcrypto_hash_alg_map[alg], 0); - if (ret < 0) { + if (ret != 0) { error_setg(errp, "Unable to initialize hash algorithm: %s", gcry_strerror(ret)); diff --git a/crypto/hash-nettle.c b/crypto/hash-nettle.c index c78624b..53f6830 100644 --- a/crypto/hash-nettle.c +++ b/crypto/hash-nettle.c @@ -26,6 +26,9 @@ #include <nettle/md5.h> #include <nettle/sha.h> #include <nettle/ripemd160.h> +#ifdef CONFIG_CRYPTO_SM3 +#include <nettle/sm3.h> +#endif typedef void (*qcrypto_nettle_init)(void *ctx); typedef void (*qcrypto_nettle_write)(void *ctx, @@ -43,6 +46,9 @@ union qcrypto_hash_ctx { struct sha384_ctx sha384; struct sha512_ctx sha512; struct ripemd160_ctx ripemd160; +#ifdef CONFIG_CRYPTO_SM3 + struct sm3_ctx sm3; +#endif }; struct qcrypto_hash_alg { @@ -93,6 +99,14 @@ struct qcrypto_hash_alg { .result = (qcrypto_nettle_result)ripemd160_digest, .len = RIPEMD160_DIGEST_SIZE, }, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = { + .init = (qcrypto_nettle_init)sm3_init, + .write = (qcrypto_nettle_write)sm3_update, + .result = (qcrypto_nettle_result)sm3_digest, + .len = SM3_DIGEST_SIZE, + }, +#endif }; gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) diff --git a/crypto/hash.c b/crypto/hash.c index 0c8548c..7513769 100644 --- a/crypto/hash.c +++ b/crypto/hash.c @@ -33,6 +33,9 @@ static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALGO__MAX] = { [QCRYPTO_HASH_ALGO_SHA384] = QCRYPTO_HASH_DIGEST_LEN_SHA384, [QCRYPTO_HASH_ALGO_SHA512] = QCRYPTO_HASH_DIGEST_LEN_SHA512, [QCRYPTO_HASH_ALGO_RIPEMD160] = QCRYPTO_HASH_DIGEST_LEN_RIPEMD160, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = QCRYPTO_HASH_DIGEST_LEN_SM3, +#endif }; size_t qcrypto_hash_digest_len(QCryptoHashAlgo alg) diff --git a/crypto/hmac-gcrypt.c b/crypto/hmac-gcrypt.c index 19990cb..5273086 100644 --- a/crypto/hmac-gcrypt.c +++ b/crypto/hmac-gcrypt.c @@ -26,6 +26,9 @@ static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALGO__MAX] = { [QCRYPTO_HASH_ALGO_SHA384] = GCRY_MAC_HMAC_SHA384, [QCRYPTO_HASH_ALGO_SHA512] = GCRY_MAC_HMAC_SHA512, [QCRYPTO_HASH_ALGO_RIPEMD160] = GCRY_MAC_HMAC_RMD160, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = GCRY_MAC_HMAC_SM3, +#endif }; typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt; @@ -37,7 +40,7 @@ bool qcrypto_hmac_supports(QCryptoHashAlgo alg) { if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) { - return true; + return gcry_mac_test_algo(qcrypto_hmac_alg_map[alg]) == 0; } return false; diff --git a/crypto/hmac-nettle.c b/crypto/hmac-nettle.c index 54dd75d..dd5b2ab 100644 --- a/crypto/hmac-nettle.c +++ b/crypto/hmac-nettle.c @@ -38,6 +38,9 @@ struct QCryptoHmacNettle { struct hmac_sha256_ctx sha256_ctx; /* equals hmac_sha224_ctx */ struct hmac_sha512_ctx sha512_ctx; /* equals hmac_sha384_ctx */ struct hmac_ripemd160_ctx ripemd160_ctx; +#ifdef CONFIG_CRYPTO_SM3 + struct hmac_sm3_ctx ctx; +#endif } u; }; @@ -89,6 +92,14 @@ struct qcrypto_nettle_hmac_alg { .digest = (qcrypto_nettle_hmac_digest)hmac_ripemd160_digest, .len = RIPEMD160_DIGEST_SIZE, }, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = { + .setkey = (qcrypto_nettle_hmac_setkey)hmac_sm3_set_key, + .update = (qcrypto_nettle_hmac_update)hmac_sm3_update, + .digest = (qcrypto_nettle_hmac_digest)hmac_sm3_digest, + .len = SM3_DIGEST_SIZE, + }, +#endif }; bool qcrypto_hmac_supports(QCryptoHashAlgo alg) diff --git a/crypto/pbkdf-gcrypt.c b/crypto/pbkdf-gcrypt.c index 76bbb55..e89b8b1 100644 --- a/crypto/pbkdf-gcrypt.c +++ b/crypto/pbkdf-gcrypt.c @@ -33,6 +33,9 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgo hash) case QCRYPTO_HASH_ALGO_SHA384: case QCRYPTO_HASH_ALGO_SHA512: case QCRYPTO_HASH_ALGO_RIPEMD160: +#ifdef CONFIG_CRYPTO_SM3 + case QCRYPTO_HASH_ALGO_SM3: +#endif return qcrypto_hash_supports(hash); default: return false; @@ -54,6 +57,9 @@ int qcrypto_pbkdf2(QCryptoHashAlgo hash, [QCRYPTO_HASH_ALGO_SHA384] = GCRY_MD_SHA384, [QCRYPTO_HASH_ALGO_SHA512] = GCRY_MD_SHA512, [QCRYPTO_HASH_ALGO_RIPEMD160] = GCRY_MD_RMD160, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = GCRY_MD_SM3, +#endif }; int ret; diff --git a/crypto/pbkdf-nettle.c b/crypto/pbkdf-nettle.c index 93e686c..3ef9c1b 100644 --- a/crypto/pbkdf-nettle.c +++ b/crypto/pbkdf-nettle.c @@ -34,6 +34,9 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgo hash) case QCRYPTO_HASH_ALGO_SHA384: case QCRYPTO_HASH_ALGO_SHA512: case QCRYPTO_HASH_ALGO_RIPEMD160: +#ifdef CONFIG_CRYPTO_SM3 + case QCRYPTO_HASH_ALGO_SM3: +#endif return true; default: return false; @@ -55,6 +58,9 @@ int qcrypto_pbkdf2(QCryptoHashAlgo hash, struct hmac_sha384_ctx sha384; struct hmac_sha512_ctx sha512; struct hmac_ripemd160_ctx ripemd160; +#ifdef CONFIG_CRYPTO_SM3 + struct hmac_sm3_ctx sm3; +#endif } ctx; if (iterations > UINT_MAX) { @@ -106,6 +112,13 @@ int qcrypto_pbkdf2(QCryptoHashAlgo hash, PBKDF2(&ctx.ripemd160, hmac_ripemd160_update, hmac_ripemd160_digest, RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out); break; +#ifdef CONFIG_CRYPTO_SM3 + case QCRYPTO_HASH_ALGO_SM3: + hmac_sm3_set_key(&ctx.sm3, nkey, key); + PBKDF2(&ctx.sm3, hmac_sm3_update, hmac_sm3_digest, + SM3_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; +#endif default: error_setg_errno(errp, ENOSYS, diff --git a/crypto/secret_common.c b/crypto/secret_common.c index 2c14110..dbda998 100644 --- a/crypto/secret_common.c +++ b/crypto/secret_common.c @@ -191,15 +191,6 @@ qcrypto_secret_complete(UserCreatable *uc, Error **errp) } -static bool -qcrypto_secret_prop_get_loaded(Object *obj, - Error **errp G_GNUC_UNUSED) -{ - QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); - return secret->rawdata != NULL; -} - - static void qcrypto_secret_prop_set_format(Object *obj, int value, @@ -278,9 +269,6 @@ qcrypto_secret_class_init(ObjectClass *oc, void *data) ucc->complete = qcrypto_secret_complete; - object_class_property_add_bool(oc, "loaded", - qcrypto_secret_prop_get_loaded, - NULL); object_class_property_add_enum(oc, "format", "QCryptoSecretFormat", &QCryptoSecretFormat_lookup, diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index c0d23a0..476cf89 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -127,37 +127,6 @@ qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp) } -#ifdef CONFIG_GNUTLS - - -static bool -qcrypto_tls_creds_anon_prop_get_loaded(Object *obj, - Error **errp G_GNUC_UNUSED) -{ - QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj); - - if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { - return creds->data.server != NULL; - } else { - return creds->data.client != NULL; - } -} - - -#else /* ! CONFIG_GNUTLS */ - - -static bool -qcrypto_tls_creds_anon_prop_get_loaded(Object *obj G_GNUC_UNUSED, - Error **errp G_GNUC_UNUSED) -{ - return false; -} - - -#endif /* ! CONFIG_GNUTLS */ - - static void qcrypto_tls_creds_anon_finalize(Object *obj) { @@ -173,10 +142,6 @@ qcrypto_tls_creds_anon_class_init(ObjectClass *oc, void *data) UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); ucc->complete = qcrypto_tls_creds_anon_complete; - - object_class_property_add_bool(oc, "loaded", - qcrypto_tls_creds_anon_prop_get_loaded, - NULL); } diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index 0d6b71a..aa270d7 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -206,37 +206,6 @@ qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp) } -#ifdef CONFIG_GNUTLS - - -static bool -qcrypto_tls_creds_psk_prop_get_loaded(Object *obj, - Error **errp G_GNUC_UNUSED) -{ - QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj); - - if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { - return creds->data.server != NULL; - } else { - return creds->data.client != NULL; - } -} - - -#else /* ! CONFIG_GNUTLS */ - - -static bool -qcrypto_tls_creds_psk_prop_get_loaded(Object *obj G_GNUC_UNUSED, - Error **errp G_GNUC_UNUSED) -{ - return false; -} - - -#endif /* ! CONFIG_GNUTLS */ - - static void qcrypto_tls_creds_psk_finalize(Object *obj) { @@ -273,9 +242,6 @@ qcrypto_tls_creds_psk_class_init(ObjectClass *oc, void *data) ucc->complete = qcrypto_tls_creds_psk_complete; - object_class_property_add_bool(oc, "loaded", - qcrypto_tls_creds_psk_prop_get_loaded, - NULL); object_class_property_add_str(oc, "username", qcrypto_tls_creds_psk_prop_get_username, qcrypto_tls_creds_psk_prop_set_username); diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index d143139..24ec584 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -695,33 +695,6 @@ qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) } -#ifdef CONFIG_GNUTLS - - -static bool -qcrypto_tls_creds_x509_prop_get_loaded(Object *obj, - Error **errp G_GNUC_UNUSED) -{ - QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); - - return creds->data != NULL; -} - - -#else /* ! CONFIG_GNUTLS */ - - -static bool -qcrypto_tls_creds_x509_prop_get_loaded(Object *obj G_GNUC_UNUSED, - Error **errp G_GNUC_UNUSED) -{ - return false; -} - - -#endif /* ! CONFIG_GNUTLS */ - - static void qcrypto_tls_creds_x509_prop_set_sanity(Object *obj, bool value, @@ -838,9 +811,6 @@ qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data) ucc->complete = qcrypto_tls_creds_x509_complete; - object_class_property_add_bool(oc, "loaded", - qcrypto_tls_creds_x509_prop_get_loaded, - NULL); object_class_property_add_bool(oc, "sanity-check", qcrypto_tls_creds_x509_prop_get_sanity, qcrypto_tls_creds_x509_prop_set_sanity); diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 912e0a1..ee6455a 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -355,13 +355,13 @@ The ``-writeconfig`` option was not able to serialize the entire contents of the QEMU command line. It is thus considered a failed experiment and removed without a replacement. -``loaded`` property of ``secret`` and ``secret_keyring`` objects (removed in 7.1) -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +``loaded`` property of secret and TLS credential objects (removed in 9.2) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' The ``loaded=on`` option in the command line or QMP ``object-add`` either had no effect (if ``loaded`` was the last option) or caused options to be effectively ignored as if they were not given. The property is therefore -useless and should simply be removed. +useless and has been removed. ``opened`` property of ``rng-*`` objects (removed in 7.1) ''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index d8419fd..2e50f2d 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -167,6 +167,8 @@ A vring address description Note that a ring address is an IOVA if ``VIRTIO_F_IOMMU_PLATFORM`` has been negotiated. Otherwise it is a user address. +.. _memory_region_description: + Memory region description ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -180,7 +182,7 @@ Memory region description :user address: a 64-bit user address -:mmap offset: 64-bit offset where region starts in the mapped memory +:mmap offset: a 64-bit offset where region starts in the mapped memory When the ``VHOST_USER_PROTOCOL_F_XEN_MMAP`` protocol feature has been successfully negotiated, the memory region description contains two extra @@ -190,7 +192,7 @@ fields at the end. | guest address | size | user address | mmap offset | xen mmap flags | domid | +---------------+------+--------------+-------------+----------------+-------+ -:xen mmap flags: 32-bit bit field +:xen mmap flags: a 32-bit bit field - Bit 0 is set for Xen foreign memory mapping. - Bit 1 is set for Xen grant memory mapping. @@ -211,7 +213,7 @@ Single memory region description :padding: 64-bit -A region is represented by Memory region description. +:region: region is represented by :ref:`Memory region description <memory_region_description>`. Multiple Memory regions description ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -224,7 +226,7 @@ Multiple Memory regions description :padding: 32-bit -A region is represented by Memory region description. +:regions: regions field contains 8 regions of type :ref:`Memory region description <memory_region_description>`. Log description ^^^^^^^^^^^^^^^ @@ -233,9 +235,9 @@ Log description | log size | log offset | +----------+------------+ -:log size: size of area used for logging +:log size: a 64-bit size of area used for logging -:log offset: offset from start of supplied file descriptor where +:log offset: a 64-bit offset from start of supplied file descriptor where logging starts (i.e. where guest address 0 would be logged) @@ -382,7 +384,7 @@ the kernel implementation. The communication consists of the *front-end* sending message requests and the *back-end* sending message replies. Most of the requests don't require -replies. Here is a list of the ones that do: +replies, except for the following requests: * ``VHOST_USER_GET_FEATURES`` * ``VHOST_USER_GET_PROTOCOL_FEATURES`` @@ -1239,11 +1241,11 @@ Front-end message types (*a vring descriptor index for split virtqueues* vs. *vring descriptor indices for packed virtqueues*). - When and as long as all of a device’s vrings are stopped, it is + When and as long as all of a device's vrings are stopped, it is *suspended*, see :ref:`Suspended device state <suspended_device_state>`. - The request payload’s *num* field is currently reserved and must be + The request payload's *num* field is currently reserved and must be set to 0. ``VHOST_USER_SET_VRING_KICK`` @@ -1662,7 +1664,7 @@ Front-end message types :reply payload: ``u64`` Front-end and back-end negotiate a channel over which to transfer the - back-end’s internal state during migration. Either side (front-end or + back-end's internal state during migration. Either side (front-end or back-end) may create the channel. The nature of this channel is not restricted or defined in this document, but whichever side creates it must create a file descriptor that is provided to the respectively @@ -1714,7 +1716,7 @@ Front-end message types :request payload: N/A :reply payload: ``u64`` - After transferring the back-end’s internal state during migration (see + After transferring the back-end's internal state during migration (see the :ref:`Migrating back-end state <migrating_backend_state>` section), check whether the back-end was able to successfully fully process the state. diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 35f52a5..a2a388f 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -26,6 +26,7 @@ the following architecture extensions: - FEAT_BF16 (AArch64 BFloat16 instructions) - FEAT_BTI (Branch Target Identification) - FEAT_CCIDX (Extended cache index) +- FEAT_CMOW (Control for cache maintenance permission) - FEAT_CRC32 (CRC32 instructions) - FEAT_Crypto (Cryptographic Extension) - FEAT_CSV2 (Cache speculation variant 2) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 4e279b9..b5a3208 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -390,118 +390,80 @@ bool float32_is_signaling_nan(float32 a_, float_status *status) static int pickNaN(FloatClass a_cls, FloatClass b_cls, bool aIsLargerSignificand, float_status *status) { -#if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_HPPA) || \ - defined(TARGET_LOONGARCH64) || defined(TARGET_S390X) - /* ARM mandated NaN propagation rules (see FPProcessNaNs()), take - * the first of: - * 1. A if it is signaling - * 2. B if it is signaling - * 3. A (quiet) - * 4. B (quiet) - * A signaling NaN is always quietened before returning it. - */ - /* According to MIPS specifications, if one of the two operands is - * a sNaN, a new qNaN has to be generated. This is done in - * floatXX_silence_nan(). For qNaN inputs the specifications - * says: "When possible, this QNaN result is one of the operand QNaN - * values." In practice it seems that most implementations choose - * the first operand if both operands are qNaN. In short this gives - * the following rules: - * 1. A if it is signaling - * 2. B if it is signaling - * 3. A (quiet) - * 4. B (quiet) - * A signaling NaN is always silenced before returning it. - */ - if (is_snan(a_cls)) { - return 0; - } else if (is_snan(b_cls)) { - return 1; - } else if (is_qnan(a_cls)) { - return 0; - } else { - return 1; - } -#elif defined(TARGET_PPC) || defined(TARGET_M68K) - /* PowerPC propagation rules: - * 1. A if it sNaN or qNaN - * 2. B if it sNaN or qNaN - * A signaling NaN is always silenced before returning it. - */ - /* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL - * 3.4 FLOATING-POINT INSTRUCTION DETAILS - * If either operand, but not both operands, of an operation is a - * nonsignaling NaN, then that NaN is returned as the result. If both - * operands are nonsignaling NaNs, then the destination operand - * nonsignaling NaN is returned as the result. - * If either operand to an operation is a signaling NaN (SNaN), then the - * SNaN bit is set in the FPSR EXC byte. If the SNaN exception enable bit - * is set in the FPCR ENABLE byte, then the exception is taken and the - * destination is not modified. If the SNaN exception enable bit is not - * set, setting the SNaN bit in the operand to a one converts the SNaN to - * a nonsignaling NaN. The operation then continues as described in the - * preceding paragraph for nonsignaling NaNs. - */ - if (is_nan(a_cls)) { - return 0; - } else { - return 1; - } -#elif defined(TARGET_SPARC) - /* Prefer SNaN over QNaN, order B then A. */ - if (is_snan(b_cls)) { - return 1; - } else if (is_snan(a_cls)) { - return 0; - } else if (is_qnan(b_cls)) { - return 1; - } else { - return 0; - } -#elif defined(TARGET_XTENSA) /* - * Xtensa has two NaN propagation modes. - * Which one is active is controlled by float_status::use_first_nan. + * We guarantee not to require the target to tell us how to + * pick a NaN if we're always returning the default NaN. + * But if we're not in default-NaN mode then the target must + * specify via set_float_2nan_prop_rule(). */ - if (status->use_first_nan) { - if (is_nan(a_cls)) { + assert(!status->default_nan_mode); + + switch (status->float_2nan_prop_rule) { + case float_2nan_prop_s_ab: + if (is_snan(a_cls)) { + return 0; + } else if (is_snan(b_cls)) { + return 1; + } else if (is_qnan(a_cls)) { return 0; } else { return 1; } - } else { - if (is_nan(b_cls)) { + break; + case float_2nan_prop_s_ba: + if (is_snan(b_cls)) { + return 1; + } else if (is_snan(a_cls)) { + return 0; + } else if (is_qnan(b_cls)) { return 1; } else { return 0; } - } -#else - /* This implements x87 NaN propagation rules: - * SNaN + QNaN => return the QNaN - * two SNaNs => return the one with the larger significand, silenced - * two QNaNs => return the one with the larger significand - * SNaN and a non-NaN => return the SNaN, silenced - * QNaN and a non-NaN => return the QNaN - * - * If we get down to comparing significands and they are the same, - * return the NaN with the positive sign bit (if any). - */ - if (is_snan(a_cls)) { - if (is_snan(b_cls)) { - return aIsLargerSignificand ? 0 : 1; + break; + case float_2nan_prop_ab: + if (is_nan(a_cls)) { + return 0; + } else { + return 1; } - return is_qnan(b_cls) ? 1 : 0; - } else if (is_qnan(a_cls)) { - if (is_snan(b_cls) || !is_qnan(b_cls)) { + break; + case float_2nan_prop_ba: + if (is_nan(b_cls)) { + return 1; + } else { return 0; + } + break; + case float_2nan_prop_x87: + /* + * This implements x87 NaN propagation rules: + * SNaN + QNaN => return the QNaN + * two SNaNs => return the one with the larger significand, silenced + * two QNaNs => return the one with the larger significand + * SNaN and a non-NaN => return the SNaN, silenced + * QNaN and a non-NaN => return the QNaN + * + * If we get down to comparing significands and they are the same, + * return the NaN with the positive sign bit (if any). + */ + if (is_snan(a_cls)) { + if (is_snan(b_cls)) { + return aIsLargerSignificand ? 0 : 1; + } + return is_qnan(b_cls) ? 1 : 0; + } else if (is_qnan(a_cls)) { + if (is_snan(b_cls) || !is_qnan(b_cls)) { + return 0; + } else { + return aIsLargerSignificand ? 0 : 1; + } } else { - return aIsLargerSignificand ? 0 : 1; + return 1; } - } else { - return 1; + default: + g_assert_not_reached(); } -#endif } /*---------------------------------------------------------------------------- diff --git a/hw/acpi/acpi_generic_initiator.c b/hw/acpi/acpi_generic_initiator.c deleted file mode 100644 index 17b9a05..0000000 --- a/hw/acpi/acpi_generic_initiator.c +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved - */ - -#include "qemu/osdep.h" -#include "hw/acpi/acpi_generic_initiator.h" -#include "hw/acpi/aml-build.h" -#include "hw/boards.h" -#include "hw/pci/pci_device.h" -#include "qemu/error-report.h" - -typedef struct AcpiGenericInitiatorClass { - ObjectClass parent_class; -} AcpiGenericInitiatorClass; - -OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator, - ACPI_GENERIC_INITIATOR, OBJECT, - { TYPE_USER_CREATABLE }, - { NULL }) - -OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR) - -static void acpi_generic_initiator_init(Object *obj) -{ - AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); - - gi->node = MAX_NODES; - gi->pci_dev = NULL; -} - -static void acpi_generic_initiator_finalize(Object *obj) -{ - AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); - - g_free(gi->pci_dev); -} - -static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val, - Error **errp) -{ - AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); - - gi->pci_dev = g_strdup(val); -} - -static void acpi_generic_initiator_set_node(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); - MachineState *ms = MACHINE(qdev_get_machine()); - uint32_t value; - - if (!visit_type_uint32(v, name, &value, errp)) { - return; - } - - if (value >= MAX_NODES) { - error_printf("%s: Invalid NUMA node specified\n", - TYPE_ACPI_GENERIC_INITIATOR); - exit(1); - } - - gi->node = value; - ms->numa_state->nodes[gi->node].has_gi = true; -} - -static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data) -{ - object_class_property_add_str(oc, "pci-dev", NULL, - acpi_generic_initiator_set_pci_device); - object_class_property_add(oc, "node", "int", NULL, - acpi_generic_initiator_set_node, NULL, NULL); -} - -/* - * ACPI 6.3: - * Table 5-78 Generic Initiator Affinity Structure - */ -static void -build_srat_generic_pci_initiator_affinity(GArray *table_data, int node, - PCIDeviceHandle *handle) -{ - uint8_t index; - - build_append_int_noprefix(table_data, 5, 1); /* Type */ - build_append_int_noprefix(table_data, 32, 1); /* Length */ - build_append_int_noprefix(table_data, 0, 1); /* Reserved */ - build_append_int_noprefix(table_data, 1, 1); /* Device Handle Type: PCI */ - build_append_int_noprefix(table_data, node, 4); /* Proximity Domain */ - - /* Device Handle - PCI */ - build_append_int_noprefix(table_data, handle->segment, 2); - build_append_int_noprefix(table_data, handle->bdf, 2); - for (index = 0; index < 12; index++) { - build_append_int_noprefix(table_data, 0, 1); - } - - build_append_int_noprefix(table_data, GEN_AFFINITY_ENABLED, 4); /* Flags */ - build_append_int_noprefix(table_data, 0, 4); /* Reserved */ -} - -static int build_all_acpi_generic_initiators(Object *obj, void *opaque) -{ - MachineState *ms = MACHINE(qdev_get_machine()); - AcpiGenericInitiator *gi; - GArray *table_data = opaque; - PCIDeviceHandle dev_handle; - PCIDevice *pci_dev; - Object *o; - - if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) { - return 0; - } - - gi = ACPI_GENERIC_INITIATOR(obj); - if (gi->node >= ms->numa_state->num_nodes) { - error_printf("%s: Specified node %d is invalid.\n", - TYPE_ACPI_GENERIC_INITIATOR, gi->node); - exit(1); - } - - o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL); - if (!o) { - error_printf("%s: Specified device must be a PCI device.\n", - TYPE_ACPI_GENERIC_INITIATOR); - exit(1); - } - - pci_dev = PCI_DEVICE(o); - - dev_handle.segment = 0; - dev_handle.bdf = PCI_BUILD_BDF(pci_bus_num(pci_get_bus(pci_dev)), - pci_dev->devfn); - - build_srat_generic_pci_initiator_affinity(table_data, - gi->node, &dev_handle); - - return 0; -} - -void build_srat_generic_pci_initiator(GArray *table_data) -{ - object_child_foreach_recursive(object_get_root(), - build_all_acpi_generic_initiators, - table_data); -} diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 34e0ddb..6a76626 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1938,6 +1938,89 @@ void build_srat_memory(GArray *table_data, uint64_t base, } /* + * ACPI Spec Revision 6.3 + * Table 5-80 Device Handle - PCI + */ +static void build_append_srat_pci_device_handle(GArray *table_data, + uint16_t segment, + uint8_t bus, uint8_t devfn) +{ + /* PCI segment number */ + build_append_int_noprefix(table_data, segment, 2); + /* PCI Bus Device Function */ + build_append_int_noprefix(table_data, bus, 1); + build_append_int_noprefix(table_data, devfn, 1); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 12); +} + +static void build_append_srat_acpi_device_handle(GArray *table_data, + const char *hid, + uint32_t uid) +{ + assert(strlen(hid) == 8); + /* Device Handle - ACPI */ + for (int i = 0; i < sizeof(hid); i++) { + build_append_int_noprefix(table_data, hid[i], 1); + } + build_append_int_noprefix(table_data, uid, 4); + build_append_int_noprefix(table_data, 0, 4); +} + +/* + * ACPI spec, Revision 6.3 + * 5.2.16.6 Generic Initiator Affinity Structure + * With PCI Device Handle. + */ +void build_srat_pci_generic_initiator(GArray *table_data, uint32_t node, + uint16_t segment, uint8_t bus, + uint8_t devfn) +{ + /* Type */ + build_append_int_noprefix(table_data, 5, 1); + /* Length */ + build_append_int_noprefix(table_data, 32, 1); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 1); + /* Device Handle Type: PCI */ + build_append_int_noprefix(table_data, 1, 1); + /* Proximity Domain */ + build_append_int_noprefix(table_data, node, 4); + /* Device Handle */ + build_append_srat_pci_device_handle(table_data, segment, bus, devfn); + /* Flags - GI Enabled */ + build_append_int_noprefix(table_data, 1, 4); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); +} + +/* + * ACPI spec, Revision 6.5 + * 5.2.16.7 Generic Port Affinity Structure + * With ACPI Device Handle. + */ +void build_srat_acpi_generic_port(GArray *table_data, uint32_t node, + const char *hid, uint32_t uid) +{ + /* Type */ + build_append_int_noprefix(table_data, 6, 1); + /* Length */ + build_append_int_noprefix(table_data, 32, 1); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 1); + /* Device Handle Type: ACPI */ + build_append_int_noprefix(table_data, 0, 1); + /* Proximity Domain */ + build_append_int_noprefix(table_data, node, 4); + /* Device Handle */ + build_append_srat_acpi_device_handle(table_data, hid, uid); + /* Flags - GP Enabled */ + build_append_int_noprefix(table_data, 1, 4); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); +} + +/* * ACPI spec 5.2.17 System Locality Distance Information Table * (Revision 2.0 or later) */ diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 5cb60ca..23443f0 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -50,6 +50,18 @@ void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list) } } +static bool check_cpu_enabled_status(DeviceState *dev) +{ + CPUClass *k = dev ? CPU_GET_CLASS(dev) : NULL; + CPUState *cpu = CPU(dev); + + if (cpu && (!k->cpu_enabled_status || k->cpu_enabled_status(cpu))) { + return true; + } + + return false; +} + static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size) { uint64_t val = 0; @@ -63,10 +75,11 @@ static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size) cdev = &cpu_st->devs[cpu_st->selector]; switch (addr) { case ACPI_CPU_FLAGS_OFFSET_RW: /* pack and return is_* fields */ - val |= cdev->cpu ? 1 : 0; + val |= check_cpu_enabled_status(DEVICE(cdev->cpu)) ? 1 : 0; val |= cdev->is_inserting ? 2 : 0; val |= cdev->is_removing ? 4 : 0; val |= cdev->fw_remove ? 16 : 0; + val |= cdev->cpu ? 32 : 0; trace_cpuhp_acpi_read_flags(cpu_st->selector, val); break; case ACPI_CPU_CMD_DATA_OFFSET_RW: @@ -233,6 +246,17 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, memory_region_add_subregion(as, base_addr, &state->ctrl_reg); } +static bool should_remain_acpi_present(DeviceState *dev) +{ + CPUClass *k = CPU_GET_CLASS(dev); + /* + * A system may contain CPUs that are always present on one die, NUMA node, + * or socket, yet may be non-present on another simultaneously. Check from + * architecture specific code. + */ + return k->cpu_persistent_status && k->cpu_persistent_status(CPU(dev)); +} + static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev) { CPUClass *k = CPU_GET_CLASS(dev); @@ -289,7 +313,9 @@ void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st, return; } - cdev->cpu = NULL; + if (!should_remain_acpi_present(dev)) { + cdev->cpu = NULL; + } } static const VMStateDescription vmstate_cpuhp_sts = { @@ -336,6 +362,7 @@ const VMStateDescription vmstate_cpu_hotplug = { #define CPU_REMOVE_EVENT "CRMV" #define CPU_EJECT_EVENT "CEJ0" #define CPU_FW_EJECT_EVENT "CEJF" +#define CPU_PRESENT "CPRS" void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, build_madt_cpu_fn build_madt_cpu, hwaddr base_addr, @@ -396,7 +423,9 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1)); /* tell firmware to do device eject, write only */ aml_append(field, aml_named_field(CPU_FW_EJECT_EVENT, 1)); - aml_append(field, aml_reserved_field(3)); + /* 1 if present, read only */ + aml_append(field, aml_named_field(CPU_PRESENT, 1)); + aml_append(field, aml_reserved_field(2)); aml_append(field, aml_named_field(CPU_COMMAND, 8)); aml_append(cpu_ctrl_dev, field); @@ -426,6 +455,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK); Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR); Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED); + Aml *is_present = aml_name("%s.%s", cphp_res_path, CPU_PRESENT); Aml *cpu_cmd = aml_name("%s.%s", cphp_res_path, CPU_COMMAND); Aml *cpu_data = aml_name("%s.%s", cphp_res_path, CPU_DATA); Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT); @@ -454,13 +484,26 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, { Aml *idx = aml_arg(0); Aml *sta = aml_local(0); + Aml *ifctx2; + Aml *else_ctx; aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); aml_append(method, aml_store(idx, cpu_selector)); aml_append(method, aml_store(zero, sta)); - ifctx = aml_if(aml_equal(is_enabled, one)); + ifctx = aml_if(aml_equal(is_present, one)); { - aml_append(ifctx, aml_store(aml_int(0xF), sta)); + ifctx2 = aml_if(aml_equal(is_enabled, one)); + { + /* cpu is present and enabled */ + aml_append(ifctx2, aml_store(aml_int(0xF), sta)); + } + aml_append(ifctx, ifctx2); + else_ctx = aml_else(); + { + /* cpu is present but disabled */ + aml_append(else_ctx, aml_store(aml_int(0xD), sta)); + } + aml_append(ifctx, else_ctx); } aml_append(method, ifctx); aml_append(method, aml_release(ctrl_lock)); diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index d00f5a6..663d9cb 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -331,6 +331,24 @@ static const VMStateDescription vmstate_memhp_state = { } }; +static bool cpuhp_needed(void *opaque) +{ + MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); + + return mc->has_hotpluggable_cpus; +} + +static const VMStateDescription vmstate_cpuhp_state = { + .name = "acpi-ged/cpuhp", + .version_id = 1, + .minimum_version_id = 1, + .needed = cpuhp_needed, + .fields = (VMStateField[]) { + VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_ged_state = { .name = "acpi-ged-state", .version_id = 1, @@ -379,6 +397,7 @@ static const VMStateDescription vmstate_acpi_ged = { }, .subsections = (const VMStateDescription * const []) { &vmstate_memhp_state, + &vmstate_cpuhp_state, &vmstate_ghes_state, NULL } diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 7f8ccc9..c8854f4 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -1,6 +1,5 @@ acpi_ss = ss.source_set() acpi_ss.add(files( - 'acpi_generic_initiator.c', 'acpi_interface.c', 'aml-build.c', 'bios-linker-loader.c', diff --git a/hw/acpi/pci.c b/hw/acpi/pci.c index 20b70dc..f88f450 100644 --- a/hw/acpi/pci.c +++ b/hw/acpi/pci.c @@ -24,8 +24,14 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qom/object_interfaces.h" +#include "qapi/error.h" +#include "hw/boards.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/pci.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_device.h" #include "hw/pci/pcie_host.h" /* @@ -59,3 +65,239 @@ void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info, acpi_table_end(linker, &table); } + +typedef struct AcpiGenericInitiator { + /* private */ + Object parent; + + /* public */ + char *pci_dev; + uint32_t node; +} AcpiGenericInitiator; + +typedef struct AcpiGenericInitiatorClass { + ObjectClass parent_class; +} AcpiGenericInitiatorClass; + +#define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator" + +OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator, + ACPI_GENERIC_INITIATOR, OBJECT, + { TYPE_USER_CREATABLE }, + { NULL }) + +OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR) + +static void acpi_generic_initiator_init(Object *obj) +{ + AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); + + gi->node = MAX_NODES; + gi->pci_dev = NULL; +} + +static void acpi_generic_initiator_finalize(Object *obj) +{ + AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); + + g_free(gi->pci_dev); +} + +static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val, + Error **errp) +{ + AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); + + gi->pci_dev = g_strdup(val); +} + +static void acpi_generic_initiator_set_node(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); + MachineState *ms = MACHINE(qdev_get_machine()); + uint32_t value; + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + + if (value >= MAX_NODES) { + error_printf("%s: Invalid NUMA node specified\n", + TYPE_ACPI_GENERIC_INITIATOR); + exit(1); + } + + gi->node = value; + ms->numa_state->nodes[gi->node].has_gi = true; +} + +static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_str(oc, "pci-dev", NULL, + acpi_generic_initiator_set_pci_device); + object_class_property_set_description(oc, "pci-dev", + "PCI device to associate with the node"); + object_class_property_add(oc, "node", "int", NULL, + acpi_generic_initiator_set_node, NULL, NULL); + object_class_property_set_description(oc, "node", + "NUMA node associated with the PCI device"); +} + +static int build_acpi_generic_initiator(Object *obj, void *opaque) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + AcpiGenericInitiator *gi; + GArray *table_data = opaque; + int32_t devfn; + uint8_t bus; + Object *o; + + if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) { + return 0; + } + + gi = ACPI_GENERIC_INITIATOR(obj); + if (gi->node >= ms->numa_state->num_nodes) { + error_printf("%s: Specified node %d is invalid.\n", + TYPE_ACPI_GENERIC_INITIATOR, gi->node); + exit(1); + } + + o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL); + if (!o) { + error_printf("%s: Specified device must be a PCI device.\n", + TYPE_ACPI_GENERIC_INITIATOR); + exit(1); + } + + bus = object_property_get_uint(o, "busnr", &error_fatal); + devfn = object_property_get_uint(o, "addr", &error_fatal); + /* devfn is constrained in PCI to be 8 bit but storage is an int32_t */ + assert(devfn >= 0 && devfn < PCI_DEVFN_MAX); + + build_srat_pci_generic_initiator(table_data, gi->node, 0, bus, devfn); + + return 0; +} + +typedef struct AcpiGenericPort { + /* private */ + Object parent; + + /* public */ + char *pci_bus; + uint32_t node; +} AcpiGenericPort; + +typedef struct AcpiGenericPortClass { + ObjectClass parent_class; +} AcpiGenericPortClass; + +#define TYPE_ACPI_GENERIC_PORT "acpi-generic-port" + +OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericPort, acpi_generic_port, + ACPI_GENERIC_PORT, OBJECT, + { TYPE_USER_CREATABLE }, + { NULL }) + +OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericPort, ACPI_GENERIC_PORT) + +static void acpi_generic_port_init(Object *obj) +{ + AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj); + + gp->node = MAX_NODES; + gp->pci_bus = NULL; +} + +static void acpi_generic_port_finalize(Object *obj) +{ + AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj); + + g_free(gp->pci_bus); +} + +static void acpi_generic_port_set_pci_bus(Object *obj, const char *val, + Error **errp) +{ + AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj); + + gp->pci_bus = g_strdup(val); +} + +static void acpi_generic_port_set_node(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj); + uint32_t value; + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + + if (value >= MAX_NODES) { + error_printf("%s: Invalid NUMA node specified\n", + TYPE_ACPI_GENERIC_INITIATOR); + exit(1); + } + + gp->node = value; +} + +static void acpi_generic_port_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_str(oc, "pci-bus", NULL, + acpi_generic_port_set_pci_bus); + object_class_property_set_description(oc, "pci-bus", + "PCI Bus of the host bridge associated with this GP affinity structure"); + object_class_property_add(oc, "node", "int", NULL, + acpi_generic_port_set_node, NULL, NULL); + object_class_property_set_description(oc, "node", + "The NUMA node like ID to index HMAT/SLIT NUMA properties involving GP"); +} + +static int build_acpi_generic_port(Object *obj, void *opaque) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + const char *hid = "ACPI0016"; + GArray *table_data = opaque; + AcpiGenericPort *gp; + uint32_t uid; + Object *o; + + if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_PORT)) { + return 0; + } + + gp = ACPI_GENERIC_PORT(obj); + + if (gp->node >= ms->numa_state->num_nodes) { + error_printf("%s: node %d is invalid.\n", + TYPE_ACPI_GENERIC_PORT, gp->node); + exit(1); + } + + o = object_resolve_path_type(gp->pci_bus, TYPE_PXB_CXL_BUS, NULL); + if (!o) { + error_printf("%s: device must be a CXL host bridge.\n", + TYPE_ACPI_GENERIC_PORT); + exit(1); + } + + uid = object_property_get_uint(o, "acpi_uid", &error_fatal); + build_srat_acpi_generic_port(table_data, gp->node, hid, uid); + + return 0; +} + +void build_srat_generic_affinity_structures(GArray *table_data) +{ + object_child_foreach_recursive(object_get_root(), + build_acpi_generic_initiator, + table_data); + object_child_foreach_recursive(object_get_root(), build_acpi_generic_port, + table_data); +} diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index f76fb11..620992c 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -57,7 +57,6 @@ #include "migration/vmstate.h" #include "hw/acpi/ghes.h" #include "hw/acpi/viot.h" -#include "hw/acpi/acpi_generic_initiator.h" #include "hw/virtio/virtio-acpi.h" #include "target/arm/multiprocessing.h" @@ -511,7 +510,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } } - build_srat_generic_pci_initiator(table_data); + build_srat_generic_affinity_structures(table_data); if (ms->nvdimms_state->is_enabled) { nvdimm_build_srat(table_data); diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 5b7f46b..7996e49 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -90,27 +90,39 @@ static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config) s->blkcfg.wce = blkcfg->wce; } +static int vhost_user_blk_sync_config(DeviceState *dev, Error **errp) +{ + int ret; + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBlk *s = VHOST_USER_BLK(vdev); + + ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, + vdev->config_len, errp); + if (ret < 0) { + return ret; + } + + memcpy(vdev->config, &s->blkcfg, vdev->config_len); + virtio_notify_config(vdev); + + return 0; +} + static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) { int ret; - VirtIODevice *vdev = dev->vdev; - VHostUserBlk *s = VHOST_USER_BLK(dev->vdev); Error *local_err = NULL; if (!dev->started) { return 0; } - ret = vhost_dev_get_config(dev, (uint8_t *)&s->blkcfg, - vdev->config_len, &local_err); + ret = vhost_user_blk_sync_config(DEVICE(dev->vdev), &local_err); if (ret < 0) { error_report_err(local_err); return ret; } - memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len); - virtio_notify_config(dev->vdev); - return 0; } @@ -579,6 +591,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, vhost_user_blk_properties); dc->vmsd = &vmstate_vhost_user_blk; + dc->sync_config = vhost_user_blk_sync_config; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->realize = vhost_user_blk_device_realize; vdc->unrealize = vhost_user_blk_device_unrealize; diff --git a/hw/core/machine.c b/hw/core/machine.c index e6c92fa..a35c4a8 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -36,7 +36,9 @@ #include "hw/virtio/virtio-iommu.h" #include "audio/audio.h" -GlobalProperty hw_compat_9_1[] = {}; +GlobalProperty hw_compat_9_1[] = { + { TYPE_PCI_DEVICE, "x-pcie-ext-tag", "false" }, +}; const size_t hw_compat_9_1_len = G_N_ELEMENTS(hw_compat_9_1); GlobalProperty hw_compat_9_0[] = { diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 9258e48..2d4d62c 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -151,6 +151,9 @@ static CXLRetCode cmd_tunnel_management_cmd(const struct cxl_cmd *cmd, in = (void *)payload_in; out = (void *)payload_out; + if (len_in < sizeof(*in)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } /* Enough room for minimum sized message - no payload */ if (in->size < sizeof(in->ccimessage)) { return CXL_MBOX_INVALID_PAYLOAD_LENGTH; @@ -266,6 +269,12 @@ static CXLRetCode cmd_events_clear_records(const struct cxl_cmd *cmd, CXLClearEventPayload *pl; pl = (CXLClearEventPayload *)payload_in; + + if (len_in < sizeof(*pl) || + len_in < sizeof(*pl) + sizeof(*pl->handle) * pl->nr_recs) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + *len_out = 0; return cxl_event_clear_records(cxlds, pl); } @@ -374,7 +383,7 @@ static CXLRetCode cmd_infostat_identify(const struct cxl_cmd *cmd, uint16_t pcie_subsys_vid; uint16_t pcie_subsys_id; uint64_t sn; - uint8_t max_message_size; + uint8_t max_message_size; uint8_t component_type; } QEMU_PACKED *is_identify; QEMU_BUILD_BUG_ON(sizeof(*is_identify) != 18); @@ -521,6 +530,9 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd, in = (struct cxl_fmapi_get_phys_port_state_req_pl *)payload_in; out = (struct cxl_fmapi_get_phys_port_state_resp_pl *)payload_out; + if (len_in < sizeof(*in)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } /* Check if what was requested can fit */ if (sizeof(*out) + sizeof(*out->ports) * in->num_ports > cci->payload_max) { return CXL_MBOX_INVALID_INPUT; @@ -649,9 +661,9 @@ static CXLRetCode cmd_firmware_update_get_info(const struct cxl_cmd *cmd, } QEMU_PACKED *fw_info; QEMU_BUILD_BUG_ON(sizeof(*fw_info) != 0x50); - if ((cxl_dstate->vmem_size < CXL_CAPACITY_MULTIPLIER) || - (cxl_dstate->pmem_size < CXL_CAPACITY_MULTIPLIER) || - (ct3d->dc.total_capacity < CXL_CAPACITY_MULTIPLIER)) { + if (!QEMU_IS_ALIGNED(cxl_dstate->vmem_size, CXL_CAPACITY_MULTIPLIER) || + !QEMU_IS_ALIGNED(cxl_dstate->pmem_size, CXL_CAPACITY_MULTIPLIER) || + !QEMU_IS_ALIGNED(ct3d->dc.total_capacity, CXL_CAPACITY_MULTIPLIER)) { return CXL_MBOX_INTERNAL_ERROR; } @@ -699,6 +711,10 @@ static CXLRetCode cmd_firmware_update_transfer(const struct cxl_cmd *cmd, } QEMU_PACKED *fw_transfer = (void *)payload_in; size_t offset, length; + if (len < sizeof(*fw_transfer)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + if (fw_transfer->action == CXL_FW_XFER_ACTION_ABORT) { /* * At this point there aren't any on-going transfers @@ -927,24 +943,28 @@ static CXLRetCode cmd_logs_get_log(const struct cxl_cmd *cmd, get_log = (void *)payload_in; + if (get_log->length > cci->payload_max) { + return CXL_MBOX_INVALID_INPUT; + } + + if (!qemu_uuid_is_equal(&get_log->uuid, &cel_uuid)) { + return CXL_MBOX_INVALID_LOG; + } + /* * CXL r3.1 Section 8.2.9.5.2: Get Log (Opcode 0401h) * The device shall return Invalid Input if the Offset or Length * fields attempt to access beyond the size of the log as reported by Get - * Supported Logs. + * Supported Log. * - * The CEL buffer is large enough to fit all commands in the emulation, so - * the only possible failure would be if the mailbox itself isn't big - * enough. + * Only valid for there to be one entry per opcode, but the length + offset + * may still be greater than that if the inputs are not valid and so access + * beyond the end of cci->cel_log. */ - if (get_log->offset + get_log->length > cci->payload_max) { + if ((uint64_t)get_log->offset + get_log->length >= sizeof(cci->cel_log)) { return CXL_MBOX_INVALID_INPUT; } - if (!qemu_uuid_is_equal(&get_log->uuid, &cel_uuid)) { - return CXL_MBOX_INVALID_LOG; - } - /* Store off everything to local variables so we can wipe out the payload */ *len_out = get_log->length; @@ -1133,10 +1153,8 @@ static CXLRetCode cmd_features_get_supported(const struct cxl_cmd *cmd, (struct CXLSupportedFeatureEntry) { .uuid = ecs_uuid, .feat_index = index, - .get_feat_size = CXL_ECS_NUM_MEDIA_FRUS * - sizeof(CXLMemECSReadAttrs), - .set_feat_size = CXL_ECS_NUM_MEDIA_FRUS * - sizeof(CXLMemECSWriteAttrs), + .get_feat_size = sizeof(CXLMemECSReadAttrs), + .set_feat_size = sizeof(CXLMemECSWriteAttrs), .attr_flags = CXL_FEAT_ENTRY_ATTR_FLAG_CHANGABLE, .get_feat_version = CXL_ECS_GET_FEATURE_VERSION, .set_feat_version = CXL_ECS_SET_FEATURE_VERSION, @@ -1204,13 +1222,10 @@ static CXLRetCode cmd_features_get_feature(const struct cxl_cmd *cmd, (uint8_t *)&ct3d->patrol_scrub_attrs + get_feature->offset, bytes_to_copy); } else if (qemu_uuid_is_equal(&get_feature->uuid, &ecs_uuid)) { - if (get_feature->offset >= CXL_ECS_NUM_MEDIA_FRUS * - sizeof(CXLMemECSReadAttrs)) { + if (get_feature->offset >= sizeof(CXLMemECSReadAttrs)) { return CXL_MBOX_INVALID_INPUT; } - bytes_to_copy = CXL_ECS_NUM_MEDIA_FRUS * - sizeof(CXLMemECSReadAttrs) - - get_feature->offset; + bytes_to_copy = sizeof(CXLMemECSReadAttrs) - get_feature->offset; bytes_to_copy = MIN(bytes_to_copy, get_feature->count); memcpy(payload_out, (uint8_t *)&ct3d->ecs_attrs + get_feature->offset, @@ -1243,6 +1258,9 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, CXLType3Dev *ct3d; uint16_t count; + if (len_in < sizeof(*hdr)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } if (!object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_TYPE3)) { return CXL_MBOX_UNSUPPORTED; @@ -1277,6 +1295,11 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, ps_set_feature = (void *)payload_in; ps_write_attrs = &ps_set_feature->feat_data; + + if ((uint32_t)hdr->offset + bytes_to_copy > + sizeof(ct3d->patrol_scrub_wr_attrs)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } memcpy((uint8_t *)&ct3d->patrol_scrub_wr_attrs + hdr->offset, ps_write_attrs, bytes_to_copy); @@ -1299,18 +1322,22 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, ecs_set_feature = (void *)payload_in; ecs_write_attrs = ecs_set_feature->feat_data; - memcpy((uint8_t *)ct3d->ecs_wr_attrs + hdr->offset, + + if ((uint32_t)hdr->offset + bytes_to_copy > + sizeof(ct3d->ecs_wr_attrs)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + memcpy((uint8_t *)&ct3d->ecs_wr_attrs + hdr->offset, ecs_write_attrs, bytes_to_copy); set_feat_info->data_size += bytes_to_copy; if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER || data_transfer_flag == CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER) { + ct3d->ecs_attrs.ecs_log_cap = ct3d->ecs_wr_attrs.ecs_log_cap; for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) { - ct3d->ecs_attrs[count].ecs_log_cap = - ct3d->ecs_wr_attrs[count].ecs_log_cap; - ct3d->ecs_attrs[count].ecs_config = - ct3d->ecs_wr_attrs[count].ecs_config & 0x1F; + ct3d->ecs_attrs.fru_attrs[count].ecs_config = + ct3d->ecs_wr_attrs.fru_attrs[count].ecs_config & 0x1F; } } } else { @@ -1324,7 +1351,7 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd, if (qemu_uuid_is_equal(&hdr->uuid, &patrol_scrub_uuid)) { memset(&ct3d->patrol_scrub_wr_attrs, 0, set_feat_info->data_size); } else if (qemu_uuid_is_equal(&hdr->uuid, &ecs_uuid)) { - memset(ct3d->ecs_wr_attrs, 0, set_feat_info->data_size); + memset(&ct3d->ecs_wr_attrs, 0, set_feat_info->data_size); } set_feat_info->data_transfer_flag = 0; set_feat_info->data_saved_across_reset = false; @@ -1445,7 +1472,7 @@ static CXLRetCode cmd_ccls_get_lsa(const struct cxl_cmd *cmd, } QEMU_PACKED *get_lsa; CXLType3Dev *ct3d = CXL_TYPE3(cci->d); CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d); - uint32_t offset, length; + uint64_t offset, length; get_lsa = (void *)payload_in; offset = get_lsa->offset; @@ -1479,8 +1506,8 @@ static CXLRetCode cmd_ccls_set_lsa(const struct cxl_cmd *cmd, const size_t hdr_len = offsetof(struct set_lsa_pl, data); *len_out = 0; - if (!len_in) { - return CXL_MBOX_SUCCESS; + if (len_in < hdr_len) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; } if (set_lsa_payload->offset + len_in > cvc->get_lsa_size(ct3d) + hdr_len) { @@ -2233,6 +2260,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd, stw_le_p(&out_rec->shared_seq, ent->shared_seq); record_done++; + out_rec++; if (record_done == record_count) { break; } @@ -2470,11 +2498,20 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd, uint64_t dpa, len; CXLRetCode ret; + if (len_in < sizeof(*in)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + if (in->num_entries_updated == 0) { cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); return CXL_MBOX_SUCCESS; } + if (len_in < + sizeof(*in) + sizeof(*in->updated_entries) * in->num_entries_updated) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + /* Adding extents causes exceeding device's extent tracking ability. */ if (in->num_entries_updated + ct3d->dc.total_extent_count > CXL_NUM_EXTENTS_SUPPORTED) { @@ -2629,10 +2666,19 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd, uint32_t updated_list_size; CXLRetCode ret; + if (len_in < sizeof(*in)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + if (in->num_entries_updated == 0) { return CXL_MBOX_INVALID_INPUT; } + if (len_in < + sizeof(*in) + sizeof(*in->updated_entries) * in->num_entries_updated) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + ret = cxl_detect_malformed_extent_list(ct3d, in); if (ret != CXL_MBOX_SUCCESS) { return ret; @@ -2879,7 +2925,8 @@ static void bg_timercb(void *opaque) } } else { /* estimate only */ - cci->bg.complete_pct = 100 * now / total_time; + cci->bg.complete_pct = + 100 * (now - cci->bg.starttime) / cci->bg.runtime; timer_mod(cci->bg.timer, now + CXL_MBOX_BG_UPDATE_FREQ); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 4967aa7..9fcc289 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -68,7 +68,6 @@ #include "hw/acpi/utils.h" #include "hw/acpi/pci.h" #include "hw/acpi/cxl.h" -#include "hw/acpi/acpi_generic_initiator.h" #include "qom/qom-qobject.h" #include "hw/i386/amd_iommu.h" @@ -741,7 +740,8 @@ static Aml *build_prt(bool is_pci0_prt) int pin; method = aml_method("_PRT", 0, AML_NOTSERIALIZED); - rt_pkg = aml_varpackage(nroutes); + assert(nroutes < 256); + rt_pkg = aml_package(nroutes); for (pin = 0; pin < nroutes; pin++) { Aml *pkg = aml_package(4); @@ -1476,6 +1476,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, QLIST_FOREACH(bus, &bus->child, sibling) { uint8_t bus_num = pci_bus_num(bus); uint8_t numa_node = pci_bus_numa_node(bus); + uint32_t uid; /* look only for expander root buses */ if (!pci_bus_is_root(bus)) { @@ -1486,6 +1487,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, root_bus_limit = bus_num - 1; } + uid = object_property_get_uint(OBJECT(bus), "acpi_uid", + &error_fatal); scope = aml_scope("\\_SB"); if (pci_bus_is_cxl(bus)) { @@ -1493,7 +1496,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } else { dev = aml_device("PC%.02X", bus_num); } - aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); + aml_append(dev, aml_name_decl("_UID", aml_int(uid))); aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); if (pci_bus_is_cxl(bus)) { struct Aml *aml_pkg = aml_package(2); @@ -1971,7 +1974,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) build_srat_memory(table_data, 0, 0, 0, MEM_AFFINITY_NOFLAGS); } - build_srat_generic_pci_initiator(table_data); + build_srat_generic_affinity_structures(table_data); /* * Entry is required for Windows to enable memory hotplug in OS @@ -2321,7 +2324,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id, /* Capability offset */ build_append_int_noprefix(table_data, s->pci.capab_offset, 2); /* IOMMU base address */ - build_append_int_noprefix(table_data, s->mmio.addr, 8); + build_append_int_noprefix(table_data, s->mr_mmio.addr, 8); /* PCI Segment Group */ build_append_int_noprefix(table_data, 0, 2); /* IOMMU info */ @@ -2356,7 +2359,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id, /* Capability offset */ build_append_int_noprefix(table_data, s->pci.capab_offset, 2); /* IOMMU base address */ - build_append_int_noprefix(table_data, s->mmio.addr, 8); + build_append_int_noprefix(table_data, s->mr_mmio.addr, 8); /* PCI Segment Group */ build_append_int_noprefix(table_data, 0, 2); /* IOMMU info */ diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 464f0b6..13af721 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -32,6 +32,7 @@ #include "trace.h" #include "hw/i386/apic-msidef.h" #include "hw/qdev-properties.h" +#include "kvm/kvm_i386.h" /* used AMD-Vi MMIO registers */ const char *amdvi_mmio_low[] = { @@ -60,8 +61,9 @@ struct AMDVIAddressSpace { uint8_t bus_num; /* bus number */ uint8_t devfn; /* device function */ AMDVIState *iommu_state; /* AMDVI - one per machine */ - MemoryRegion root; /* AMDVI Root memory map region */ + MemoryRegion root; /* AMDVI Root memory map region */ IOMMUMemoryRegion iommu; /* Device's address translation region */ + MemoryRegion iommu_nodma; /* Alias of shared nodma memory region */ MemoryRegion iommu_ir; /* Device's interrupt remapping region */ AddressSpace as; /* device's corresponding address space */ }; @@ -430,6 +432,12 @@ static void amdvi_complete_ppr(AMDVIState *s, uint64_t *cmd) trace_amdvi_ppr_exec(); } +static void amdvi_intremap_inval_notify_all(AMDVIState *s, bool global, + uint32_t index, uint32_t mask) +{ + x86_iommu_iec_notify_all(X86_IOMMU_DEVICE(s), global, index, mask); +} + static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd) { if (extract64(cmd[0], 0, 60) || cmd[1]) { @@ -437,6 +445,9 @@ static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd) s->cmdbuf + s->cmdbuf_head); } + /* Notify global invalidation */ + amdvi_intremap_inval_notify_all(s, true, 0, 0); + amdvi_iotlb_reset(s); trace_amdvi_all_inval(); } @@ -485,6 +496,9 @@ static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd) return; } + /* Notify global invalidation */ + amdvi_intremap_inval_notify_all(s, true, 0, 0); + trace_amdvi_intr_inval(); } @@ -1412,6 +1426,7 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) AMDVIState *s = opaque; AMDVIAddressSpace **iommu_as, *amdvi_dev_as; int bus_num = pci_bus_num(bus); + X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); iommu_as = s->address_spaces[bus_num]; @@ -1436,13 +1451,13 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) * Memory region relationships looks like (Address range shows * only lower 32 bits to make it short in length...): * - * |-----------------+-------------------+----------| - * | Name | Address range | Priority | - * |-----------------+-------------------+----------+ - * | amdvi_root | 00000000-ffffffff | 0 | - * | amdvi_iommu | 00000000-ffffffff | 1 | - * | amdvi_iommu_ir | fee00000-feefffff | 64 | - * |-----------------+-------------------+----------| + * |--------------------+-------------------+----------| + * | Name | Address range | Priority | + * |--------------------+-------------------+----------+ + * | amdvi-root | 00000000-ffffffff | 0 | + * | amdvi-iommu_nodma | 00000000-ffffffff | 0 | + * | amdvi-iommu_ir | fee00000-feefffff | 1 | + * |--------------------+-------------------+----------| */ memory_region_init_iommu(&amdvi_dev_as->iommu, sizeof(amdvi_dev_as->iommu), @@ -1452,16 +1467,34 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) memory_region_init(&amdvi_dev_as->root, OBJECT(s), "amdvi_root", UINT64_MAX); address_space_init(&amdvi_dev_as->as, &amdvi_dev_as->root, name); - memory_region_init_io(&amdvi_dev_as->iommu_ir, OBJECT(s), - &amdvi_ir_ops, s, "amd_iommu_ir", - AMDVI_INT_ADDR_SIZE); - memory_region_add_subregion_overlap(&amdvi_dev_as->root, - AMDVI_INT_ADDR_FIRST, - &amdvi_dev_as->iommu_ir, - 64); memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0, MEMORY_REGION(&amdvi_dev_as->iommu), - 1); + 0); + + /* Build the DMA Disabled alias to shared memory */ + memory_region_init_alias(&amdvi_dev_as->iommu_nodma, OBJECT(s), + "amdvi-sys", &s->mr_sys, 0, + memory_region_size(&s->mr_sys)); + memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0, + &amdvi_dev_as->iommu_nodma, + 0); + /* Build the Interrupt Remapping alias to shared memory */ + memory_region_init_alias(&amdvi_dev_as->iommu_ir, OBJECT(s), + "amdvi-ir", &s->mr_ir, 0, + memory_region_size(&s->mr_ir)); + memory_region_add_subregion_overlap(MEMORY_REGION(&amdvi_dev_as->iommu), + AMDVI_INT_ADDR_FIRST, + &amdvi_dev_as->iommu_ir, 1); + + if (!x86_iommu->pt_supported) { + memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false); + memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), + true); + } else { + memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), + false); + memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, true); + } } return &iommu_as[devfn]->as; } @@ -1598,10 +1631,37 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) x86ms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID); /* set up MMIO */ - memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio", - AMDVI_MMIO_SIZE); + memory_region_init_io(&s->mr_mmio, OBJECT(s), &mmio_mem_ops, s, + "amdvi-mmio", AMDVI_MMIO_SIZE); memory_region_add_subregion(get_system_memory(), AMDVI_BASE_ADDR, - &s->mmio); + &s->mr_mmio); + + /* Create the share memory regions by all devices */ + memory_region_init(&s->mr_sys, OBJECT(s), "amdvi-sys", UINT64_MAX); + + /* set up the DMA disabled memory region */ + memory_region_init_alias(&s->mr_nodma, OBJECT(s), + "amdvi-nodma", get_system_memory(), 0, + memory_region_size(get_system_memory())); + memory_region_add_subregion_overlap(&s->mr_sys, 0, + &s->mr_nodma, 0); + + /* set up the Interrupt Remapping memory region */ + memory_region_init_io(&s->mr_ir, OBJECT(s), &amdvi_ir_ops, + s, "amdvi-ir", AMDVI_INT_ADDR_SIZE); + memory_region_add_subregion_overlap(&s->mr_sys, AMDVI_INT_ADDR_FIRST, + &s->mr_ir, 1); + + /* AMD IOMMU with x2APIC mode requires xtsup=on */ + if (x86ms->apic_id_limit > 255 && !s->xtsup) { + error_report("AMD IOMMU with x2APIC confguration requires xtsup=on"); + exit(EXIT_FAILURE); + } + if (s->xtsup && kvm_irqchip_is_split() && !kvm_enable_x2apic()) { + error_report("AMD IOMMU xtsup=on requires support on the KVM side"); + exit(EXIT_FAILURE); + } + pci_setup_iommu(bus, &amdvi_iommu_ops, s); amdvi_init(s); } diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 73619fe..e0dac4d 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -353,7 +353,10 @@ struct AMDVIState { uint32_t pprlog_head; /* ppr log head */ uint32_t pprlog_tail; /* ppr log tail */ - MemoryRegion mmio; /* MMIO region */ + MemoryRegion mr_mmio; /* MMIO region */ + MemoryRegion mr_sys; + MemoryRegion mr_nodma; + MemoryRegion mr_ir; uint8_t mmior[AMDVI_MMIO_SIZE]; /* read/write MMIO */ uint8_t w1cmask[AMDVI_MMIO_SIZE]; /* read/write 1 clear mask */ uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */ diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 08fe218..4c0d1d7 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2532,15 +2532,51 @@ static bool vtd_get_inv_desc(IntelIOMMUState *s, return true; } +static bool vtd_inv_desc_reserved_check(IntelIOMMUState *s, + VTDInvDesc *inv_desc, + uint64_t mask[4], bool dw, + const char *func_name, + const char *desc_type) +{ + if (s->iq_dw) { + if (inv_desc->val[0] & mask[0] || inv_desc->val[1] & mask[1] || + inv_desc->val[2] & mask[2] || inv_desc->val[3] & mask[3]) { + error_report("%s: invalid %s desc val[3]: 0x%"PRIx64 + " val[2]: 0x%"PRIx64" val[1]=0x%"PRIx64 + " val[0]=0x%"PRIx64" (reserved nonzero)", + func_name, desc_type, inv_desc->val[3], + inv_desc->val[2], inv_desc->val[1], + inv_desc->val[0]); + return false; + } + } else { + if (dw) { + error_report("%s: 256-bit %s desc in 128-bit invalidation queue", + func_name, desc_type); + return false; + } + + if (inv_desc->lo & mask[0] || inv_desc->hi & mask[1]) { + error_report("%s: invalid %s desc: hi=%"PRIx64", lo=%"PRIx64 + " (reserved nonzero)", func_name, desc_type, + inv_desc->hi, inv_desc->lo); + return false; + } + } + + return true; +} + static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { - if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) || - (inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) { - error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64 - " (reserved nonzero)", __func__, inv_desc->hi, - inv_desc->lo); + uint64_t mask[4] = {VTD_INV_DESC_WAIT_RSVD_LO, VTD_INV_DESC_WAIT_RSVD_HI, + VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE}; + + if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false, + __func__, "wait")) { return false; } + if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) { /* Status Write */ uint32_t status_data = (uint32_t)(inv_desc->lo >> @@ -2574,13 +2610,14 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { uint16_t sid, fmask; + uint64_t mask[4] = {VTD_INV_DESC_CC_RSVD, VTD_INV_DESC_ALL_ONE, + VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE}; - if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) { - error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64 - " (reserved nonzero)", __func__, inv_desc->hi, - inv_desc->lo); + if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false, + __func__, "cc inv")) { return false; } + switch (inv_desc->lo & VTD_INV_DESC_CC_G) { case VTD_INV_DESC_CC_DOMAIN: trace_vtd_inv_desc_cc_domain( @@ -2610,12 +2647,11 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) uint16_t domain_id; uint8_t am; hwaddr addr; + uint64_t mask[4] = {VTD_INV_DESC_IOTLB_RSVD_LO, VTD_INV_DESC_IOTLB_RSVD_HI, + VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE}; - if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) || - (inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) { - error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64 - ", lo=0x%"PRIx64" (reserved bits unzero)", - __func__, inv_desc->hi, inv_desc->lo); + if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false, + __func__, "iotlb inv")) { return false; } @@ -2656,6 +2692,14 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { + uint64_t mask[4] = {VTD_INV_DESC_IEC_RSVD, VTD_INV_DESC_ALL_ONE, + VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE}; + + if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false, + __func__, "iec inv")) { + return false; + } + trace_vtd_inv_desc_iec(inv_desc->iec.granularity, inv_desc->iec.index, inv_desc->iec.index_mask); @@ -2705,19 +2749,19 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, hwaddr addr; uint16_t sid; bool size; + uint64_t mask[4] = {VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO, + VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI, + VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE}; + + if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false, + __func__, "dev-iotlb inv")) { + return false; + } addr = VTD_INV_DESC_DEVICE_IOTLB_ADDR(inv_desc->hi); sid = VTD_INV_DESC_DEVICE_IOTLB_SID(inv_desc->lo); size = VTD_INV_DESC_DEVICE_IOTLB_SIZE(inv_desc->hi); - if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) || - (inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) { - error_report_once("%s: invalid dev-iotlb inv desc: hi=%"PRIx64 - ", lo=%"PRIx64" (reserved nonzero)", __func__, - inv_desc->hi, inv_desc->lo); - return false; - } - /* * Using sid is OK since the guest should have finished the * initialization of both the bus and device. @@ -2847,6 +2891,7 @@ static void vtd_handle_iqt_write(IntelIOMMUState *s) if (s->iq_dw && (val & VTD_IQT_QT_256_RSV_BIT)) { error_report_once("%s: RSV bit is set: val=0x%"PRIx64, __func__, val); + vtd_handle_inv_queue_error(s); return; } s->iq_tail = VTD_IQT_QT(s->iq_dw, val); @@ -3372,6 +3417,7 @@ static Property vtd_properties[] = { DEFINE_PROP_BOOL("x-pasid-mode", IntelIOMMUState, pasid, false), DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true), DEFINE_PROP_BOOL("dma-translation", IntelIOMMUState, dma_translation, true), + DEFINE_PROP_BOOL("stale-tm", IntelIOMMUState, stale_tm, false), DEFINE_PROP_END_OF_LIST(), }; @@ -4138,15 +4184,15 @@ static void vtd_init(IntelIOMMUState *s) */ vtd_spte_rsvd[0] = ~0ULL; vtd_spte_rsvd[1] = VTD_SPTE_PAGE_L1_RSVD_MASK(s->aw_bits, - x86_iommu->dt_supported); + x86_iommu->dt_supported && s->stale_tm); vtd_spte_rsvd[2] = VTD_SPTE_PAGE_L2_RSVD_MASK(s->aw_bits); vtd_spte_rsvd[3] = VTD_SPTE_PAGE_L3_RSVD_MASK(s->aw_bits); vtd_spte_rsvd[4] = VTD_SPTE_PAGE_L4_RSVD_MASK(s->aw_bits); vtd_spte_rsvd_large[2] = VTD_SPTE_LPAGE_L2_RSVD_MASK(s->aw_bits, - x86_iommu->dt_supported); + x86_iommu->dt_supported && s->stale_tm); vtd_spte_rsvd_large[3] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits, - x86_iommu->dt_supported); + x86_iommu->dt_supported && s->stale_tm); if (s->scalable_mode || s->snoop_control) { vtd_spte_rsvd[1] &= ~VTD_SPTE_SNP; diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 13d5d12..4323fc5 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -356,6 +356,7 @@ union VTDInvDesc { typedef union VTDInvDesc VTDInvDesc; /* Masks for struct VTDInvDesc */ +#define VTD_INV_DESC_ALL_ONE -1ULL #define VTD_INV_DESC_TYPE(val) ((((val) >> 5) & 0x70ULL) | \ ((val) & 0xfULL)) #define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */ @@ -409,11 +410,14 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL #define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0f1f0 +/* Masks for Interrupt Entry Invalidate Descriptor */ +#define VTD_INV_DESC_IEC_RSVD 0xffff000007fff1e0ULL + /* Rsvd field masks for spte */ #define VTD_SPTE_SNP 0x800ULL -#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw, dt_supported) \ - dt_supported ? \ +#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw, stale_tm) \ + stale_tm ? \ (0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \ (0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM)) #define VTD_SPTE_PAGE_L2_RSVD_MASK(aw) \ @@ -423,12 +427,12 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_SPTE_PAGE_L4_RSVD_MASK(aw) \ (0x880ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM)) -#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw, dt_supported) \ - dt_supported ? \ +#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw, stale_tm) \ + stale_tm ? \ (0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \ (0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM)) -#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw, dt_supported) \ - dt_supported ? \ +#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw, stale_tm) \ + stale_tm ? \ (0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \ (0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM)) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 2047633..830614d 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -82,6 +82,7 @@ GlobalProperty pc_compat_9_1[] = { { "ICH9-LPC", "x-smi-swsmi-timer", "off" }, { "ICH9-LPC", "x-smi-periodic-timer", "off" }, + { TYPE_INTEL_IOMMU_DEVICE, "stale-tm", "on" }, }; const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1); diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 235ac40..5cf754b 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -17,6 +17,7 @@ #include "hw/mem/pc-dimm.h" #include "hw/pci/pci.h" #include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" @@ -919,16 +920,15 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) ct3d->patrol_scrub_attrs.scrub_flags = CXL_MEMDEV_PS_ENABLE_DEFAULT; /* Set default value for DDR5 ECS read attributes */ + ct3d->ecs_attrs.ecs_log_cap = CXL_ECS_LOG_ENTRY_TYPE_DEFAULT; for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) { - ct3d->ecs_attrs[count].ecs_log_cap = - CXL_ECS_LOG_ENTRY_TYPE_DEFAULT; - ct3d->ecs_attrs[count].ecs_cap = + ct3d->ecs_attrs.fru_attrs[count].ecs_cap = CXL_ECS_REALTIME_REPORT_CAP_DEFAULT; - ct3d->ecs_attrs[count].ecs_config = + ct3d->ecs_attrs.fru_attrs[count].ecs_config = CXL_ECS_THRESHOLD_COUNT_DEFAULT | (CXL_ECS_MODE_DEFAULT << 3); /* Reserved */ - ct3d->ecs_attrs[count].ecs_flags = 0; + ct3d->ecs_attrs.fru_attrs[count].ecs_flags = 0; } return; @@ -1200,6 +1200,7 @@ static void ct3d_reset(DeviceState *dev) uint32_t *reg_state = ct3d->cxl_cstate.crb.cache_mem_registers; uint32_t *write_msk = ct3d->cxl_cstate.crb.cache_mem_regs_write_mask; + pcie_cap_fill_link_ep_usp(PCI_DEVICE(dev), ct3d->width, ct3d->speed); cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE); cxl_device_register_init_t3(ct3d); @@ -1229,6 +1230,10 @@ static Property ct3_props[] = { DEFINE_PROP_UINT8("num-dc-regions", CXLType3Dev, dc.num_regions, 0), DEFINE_PROP_LINK("volatile-dc-memdev", CXLType3Dev, dc.host_dc, TYPE_MEMORY_BACKEND, HostMemoryBackend *), + DEFINE_PROP_PCIE_LINK_SPEED("x-speed", CXLType3Dev, + speed, PCIE_LINK_SPEED_32), + DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLType3Dev, + width, PCIE_LINK_WIDTH_16), DEFINE_PROP_END_OF_LIST(), }; @@ -1375,9 +1380,7 @@ void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length, ct3d = CXL_TYPE3(obj); QLIST_FOREACH(p, &ct3d->poison_list, node) { - if (((start >= p->start) && (start < p->start + p->length)) || - ((start + length > p->start) && - (start + length <= p->start + p->length))) { + if ((start < p->start + p->length) && (start + length > p->start)) { error_setg(errp, "Overlap with existing poisoned region not supported"); return; @@ -2060,11 +2063,11 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path, stw_le_p(&dCap.host_id, hid); /* only valid for DC_REGION_CONFIG_UPDATED event */ dCap.updated_region_id = 0; - dCap.flags = 0; for (i = 0; i < num_extents; i++) { memcpy(&dCap.dynamic_capacity_extent, &extents[i], sizeof(CXLDCExtentRaw)); + dCap.flags = 0; if (i < num_extents - 1) { /* Set "More" flag */ dCap.flags |= BIT(0); diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c index 6fa6bec..685905f 100644 --- a/hw/net/npcm_gmac.c +++ b/hw/net/npcm_gmac.c @@ -546,9 +546,8 @@ static void gmac_try_send_next_packet(NPCMGMACState *gmac) /* 1 = DMA Owned, 0 = Software Owned */ if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) { - qemu_log_mask(LOG_GUEST_ERROR, - "TX Descriptor @ 0x%x is owned by software\n", - desc_addr); + trace_npcm_gmac_tx_desc_owner(DEVICE(gmac)->canonical_path, + desc_addr); gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU; gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, NPCM_DMA_STATUS_TX_SUSPENDED_STATE); diff --git a/hw/net/trace-events b/hw/net/trace-events index 91a3d0c..d0f1d8c 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -478,6 +478,7 @@ npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finishe npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16 npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32 npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32 +npcm_gmac_tx_desc_owner(const char* name, uint32_t desc_addr) "%s: TX Descriptor @0x%04" PRIX32 " is owned by software" # npcm_pcs.c npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16 diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c index 4b42984..c347ac0 100644 --- a/hw/pci-bridge/cxl_downstream.c +++ b/hw/pci-bridge/cxl_downstream.c @@ -13,6 +13,8 @@ #include "hw/pci/msi.h" #include "hw/pci/pcie.h" #include "hw/pci/pcie_port.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" #include "hw/cxl/cxl.h" #include "qapi/error.h" @@ -210,24 +212,20 @@ static void cxl_dsp_exitfn(PCIDevice *d) pci_bridge_exitfn(d); } -static void cxl_dsp_instance_post_init(Object *obj) -{ - PCIESlot *s = PCIE_SLOT(obj); - - if (!s->speed) { - s->speed = QEMU_PCI_EXP_LNK_2_5GT; - } - - if (!s->width) { - s->width = QEMU_PCI_EXP_LNK_X1; - } -} +static Property cxl_dsp_props[] = { + DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot, + speed, PCIE_LINK_SPEED_64), + DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot, + width, PCIE_LINK_WIDTH_16), + DEFINE_PROP_END_OF_LIST() +}; static void cxl_dsp_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *k = PCI_DEVICE_CLASS(oc); + device_class_set_props(dc, cxl_dsp_props); k->config_write = cxl_dsp_config_write; k->realize = cxl_dsp_realize; k->exit = cxl_dsp_exitfn; @@ -243,7 +241,6 @@ static const TypeInfo cxl_dsp_info = { .name = TYPE_CXL_DSP, .instance_size = sizeof(CXLDownstreamPort), .parent = TYPE_PCIE_SLOT, - .instance_post_init = cxl_dsp_instance_post_init, .class_init = cxl_dsp_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c index 2dd1023..5e2156d 100644 --- a/hw/pci-bridge/cxl_root_port.c +++ b/hw/pci-bridge/cxl_root_port.c @@ -24,6 +24,7 @@ #include "hw/pci/pcie_port.h" #include "hw/pci/msi.h" #include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" #include "hw/sysbus.h" #include "qapi/error.h" #include "hw/cxl/cxl.h" @@ -206,6 +207,10 @@ static Property gen_rp_props[] = { -1), DEFINE_PROP_SIZE("pref64-reserve", CXLRootPort, res_reserve.mem_pref_64, -1), + DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot, + speed, PCIE_LINK_SPEED_64), + DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot, + width, PCIE_LINK_WIDTH_32), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c index a5a39cc..55f8b00 100644 --- a/hw/pci-bridge/cxl_upstream.c +++ b/hw/pci-bridge/cxl_upstream.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" #include "hw/pci/msi.h" #include "hw/pci/pcie.h" #include "hw/pci/pcie_port.h" @@ -100,6 +101,7 @@ static void cxl_usp_reset(DeviceState *qdev) pci_bridge_reset(qdev); pcie_cap_deverr_reset(d); + pcie_cap_fill_link_ep_usp(d, usp->width, usp->speed); latch_registers(usp); } @@ -363,6 +365,10 @@ static void cxl_usp_exitfn(PCIDevice *d) static Property cxl_upstream_props[] = { DEFINE_PROP_UINT64("sn", CXLUpstreamPort, sn, UI64_NULL), DEFINE_PROP_STRING("cdat", CXLUpstreamPort, cxl_cstate.cdat.filename), + DEFINE_PROP_PCIE_LINK_SPEED("x-speed", CXLUpstreamPort, + speed, PCIE_LINK_SPEED_32), + DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLUpstreamPort, + width, PCIE_LINK_WIDTH_16), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index dfaea6c..07d411c 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -38,7 +38,6 @@ DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS, DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS, TYPE_PXB_PCIE_BUS) -#define TYPE_PXB_CXL_BUS "pxb-cxl-bus" DECLARE_INSTANCE_CHECKER(PXBBus, PXB_CXL_BUS, TYPE_PXB_CXL_BUS) @@ -85,12 +84,25 @@ static uint16_t pxb_bus_numa_node(PCIBus *bus) return pxb->numa_node; } +static void prop_pxb_uid_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t uid = pci_bus_num(PCI_BUS(obj)); + + visit_type_uint32(v, name, &uid, errp); +} + static void pxb_bus_class_init(ObjectClass *class, void *data) { PCIBusClass *pbc = PCI_BUS_CLASS(class); pbc->bus_num = pxb_bus_num; pbc->numa_node = pxb_bus_numa_node; + + object_class_property_add(class, "acpi_uid", "uint32", + prop_pxb_uid_get, NULL, NULL, NULL); + object_class_property_set_description(class, "acpi_uid", + "ACPI Unique ID used to distinguish this PCI Host Bridge / ACPI00016"); } static const TypeInfo pxb_bus_info = { @@ -318,7 +330,7 @@ static gint pxb_compare(gconstpointer a, gconstpointer b) 0; } -static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type, +static bool pxb_dev_realize_common(PCIDevice *dev, enum BusType type, Error **errp) { PXBDev *pxb = PXB_DEV(dev); @@ -330,13 +342,13 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type, if (ms->numa_state == NULL) { error_setg(errp, "NUMA is not supported by this machine-type"); - return; + return false; } if (pxb->numa_node != NUMA_NODE_UNASSIGNED && pxb->numa_node >= ms->numa_state->num_nodes) { error_setg(errp, "Illegal numa node %d", pxb->numa_node); - return; + return false; } if (dev->qdev.id && *dev->qdev.id) { @@ -382,12 +394,13 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type, pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST); pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare); - return; + return true; err_register_bus: object_unref(OBJECT(bds)); object_unparent(OBJECT(bus)); object_unref(OBJECT(ds)); + return false; } static void pxb_dev_realize(PCIDevice *dev, Error **errp) @@ -488,7 +501,9 @@ static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp) return; } - pxb_dev_realize_common(dev, CXL, errp); + if (!pxb_dev_realize_common(dev, CXL, errp)) { + return; + } pxb_cxl_dev_reset(DEVICE(dev)); } diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index 391fabb..e8b4c64 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -141,6 +141,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) QLIST_FOREACH(bus, &bus->child, sibling) { uint8_t bus_num = pci_bus_num(bus); uint8_t numa_node = pci_bus_numa_node(bus); + uint32_t uid; bool is_cxl = pci_bus_is_cxl(bus); if (!pci_bus_is_root(bus)) { @@ -156,6 +157,8 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) nr_pcie_buses = bus_num; } + uid = object_property_get_uint(OBJECT(bus), "acpi_uid", + &error_fatal); dev = aml_device("PC%.02X", bus_num); if (is_cxl) { struct Aml *pkg = aml_package(2); @@ -168,7 +171,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); } aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); - aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); + aml_append(dev, aml_name_decl("_UID", aml_int(uid))); aml_append(dev, aml_name_decl("_STR", aml_unicode("pxb Device"))); aml_append(dev, aml_name_decl("_CCA", aml_int(1))); if (numa_node != NUMA_NODE_UNASSIGNED) { diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 87da35c..1416ae2 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -67,6 +67,19 @@ static char *pcibus_get_fw_dev_path(DeviceState *dev); static void pcibus_reset_hold(Object *obj, ResetType type); static bool pcie_has_upstream_port(PCIDevice *dev); +static void prop_pci_busnr_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint8_t busnr = pci_dev_bus_num(PCI_DEVICE(obj)); + + visit_type_uint8(v, name, &busnr, errp); +} + +static const PropertyInfo prop_pci_busnr = { + .name = "busnr", + .get = prop_pci_busnr_get, +}; + static Property pci_props[] = { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), DEFINE_PROP_STRING("romfile", PCIDevice, romfile), @@ -87,6 +100,9 @@ static Property pci_props[] = { QEMU_PCIE_ARI_NEXTFN_1_BITNR, false), DEFINE_PROP_SIZE32("x-max-bounce-buffer-size", PCIDevice, max_bounce_buffer_size, DEFAULT_MAX_BOUNCE_BUFFER_SIZE), + DEFINE_PROP_BIT("x-pcie-ext-tag", PCIDevice, cap_present, + QEMU_PCIE_EXT_TAG_BITNR, true), + { .name = "busnr", .info = &prop_pci_busnr }, DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 6a4e388..2c7bb1a 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -380,9 +380,12 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename) sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn; sec_bus->address_space_mem = &br->address_space_mem; memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX); + address_space_init(&br->as_mem, &br->address_space_mem, + "pci_bridge_pci_mem"); sec_bus->address_space_io = &br->address_space_io; memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", 4 * GiB); + address_space_init(&br->as_io, &br->address_space_io, "pci_bridge_pci_io"); pci_bridge_region_init(br); QLIST_INIT(&sec_bus->child); QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); @@ -399,6 +402,8 @@ void pci_bridge_exitfn(PCIDevice *pci_dev) PCIBridge *s = PCI_BRIDGE(pci_dev); assert(QLIST_EMPTY(&s->sec_bus.child)); QLIST_REMOVE(&s->sec_bus, sibling); + address_space_destroy(&s->as_mem); + address_space_destroy(&s->as_io); pci_bridge_region_del(s, &s->windows); pci_bridge_region_cleanup(s, &s->windows); /* object_unparent() is called automatically during device deletion */ diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 4b2f080..0b455c8 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -86,7 +86,13 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) * Specification, Revision 1.1., or subsequent PCI Express Base * Specification revisions. */ - pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER); + uint32_t devcap = PCI_EXP_DEVCAP_RBER; + + if (dev->cap_present & QEMU_PCIE_EXT_TAG) { + devcap = PCI_EXP_DEVCAP_RBER | PCI_EXP_DEVCAP_EXT_TAG; + } + + pci_set_long(exp_cap + PCI_EXP_DEVCAP, devcap); pci_set_long(exp_cap + PCI_EXP_LNKCAP, (port << PCI_EXP_LNKCAP_PN_SHIFT) | @@ -105,46 +111,18 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) pci_set_word(cmask + PCI_EXP_LNKSTA, 0); } -static void pcie_cap_fill_slot_lnk(PCIDevice *dev) +/* Includes setting the target speed default */ +static void pcie_cap_fill_lnk(uint8_t *exp_cap, PCIExpLinkWidth width, + PCIExpLinkSpeed speed) { - PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT); - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; - - /* Skip anything that isn't a PCIESlot */ - if (!s) { - return; - } - /* Clear and fill LNKCAP from what was configured above */ pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS); pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, - QEMU_PCI_EXP_LNKCAP_MLW(s->width) | - QEMU_PCI_EXP_LNKCAP_MLS(s->speed)); - - /* - * Link bandwidth notification is required for all root ports and - * downstream ports supporting links wider than x1 or multiple link - * speeds. - */ - if (s->width > QEMU_PCI_EXP_LNK_X1 || - s->speed > QEMU_PCI_EXP_LNK_2_5GT) { - pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, - PCI_EXP_LNKCAP_LBNC); - } - - if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) { - /* - * Hot-plug capable downstream ports and downstream ports supporting - * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC - * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which - * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also - * technically implement this, but it's not done here for compatibility. - */ - pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, - PCI_EXP_LNKCAP_DLLLARC); - /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */ + QEMU_PCI_EXP_LNKCAP_MLW(width) | + QEMU_PCI_EXP_LNKCAP_MLS(speed)); + if (speed > QEMU_PCI_EXP_LNK_2_5GT) { /* * Target Link Speed defaults to the highest link speed supported by * the component. 2.5GT/s devices are permitted to hardwire to zero. @@ -152,7 +130,7 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2, PCI_EXP_LNKCTL2_TLS); pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2, - QEMU_PCI_EXP_LNKCAP_MLS(s->speed) & + QEMU_PCI_EXP_LNKCAP_MLS(speed) & PCI_EXP_LNKCTL2_TLS); } @@ -161,27 +139,82 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) * actually a reference to the highest bit supported in this register. * We assume the device supports all link speeds. */ - if (s->speed > QEMU_PCI_EXP_LNK_5GT) { + if (speed > QEMU_PCI_EXP_LNK_5GT) { pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U); pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2, PCI_EXP_LNKCAP2_SLS_2_5GB | PCI_EXP_LNKCAP2_SLS_5_0GB | PCI_EXP_LNKCAP2_SLS_8_0GB); - if (s->speed > QEMU_PCI_EXP_LNK_8GT) { + if (speed > QEMU_PCI_EXP_LNK_8GT) { pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2, PCI_EXP_LNKCAP2_SLS_16_0GB); } - if (s->speed > QEMU_PCI_EXP_LNK_16GT) { + if (speed > QEMU_PCI_EXP_LNK_16GT) { pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2, PCI_EXP_LNKCAP2_SLS_32_0GB); } - if (s->speed > QEMU_PCI_EXP_LNK_32GT) { + if (speed > QEMU_PCI_EXP_LNK_32GT) { pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2, PCI_EXP_LNKCAP2_SLS_64_0GB); } } } +void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width, + PCIExpLinkSpeed speed) +{ + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; + + /* + * For an end point or USP need to set the current status as well + * as the capabilities. + */ + pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA, + PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW); + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, + QEMU_PCI_EXP_LNKSTA_NLW(width) | + QEMU_PCI_EXP_LNKSTA_CLS(speed)); + + pcie_cap_fill_lnk(exp_cap, width, speed); +} + +static void pcie_cap_fill_slot_lnk(PCIDevice *dev) +{ + PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT); + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; + + /* Skip anything that isn't a PCIESlot */ + if (!s) { + return; + } + + /* + * Link bandwidth notification is required for all root ports and + * downstream ports supporting links wider than x1 or multiple link + * speeds. + */ + if (s->width > QEMU_PCI_EXP_LNK_X1 || + s->speed > QEMU_PCI_EXP_LNK_2_5GT) { + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, + PCI_EXP_LNKCAP_LBNC); + } + + if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) { + /* + * Hot-plug capable downstream ports and downstream ports supporting + * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC + * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which + * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also + * technically implement this, but it's not done here for compatibility. + */ + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, + PCI_EXP_LNKCAP_DLLLARC); + /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */ + } + + pcie_cap_fill_lnk(exp_cap, s->width, s->speed); +} + int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port, Error **errp) diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c index 13472c5..c993182 100644 --- a/hw/rtc/ds1338.c +++ b/hw/rtc/ds1338.c @@ -16,6 +16,7 @@ #include "qemu/bcd.h" #include "qom/object.h" #include "sysemu/rtc.h" +#include "trace.h" /* Size of NVRAM including both the user-accessible area and the * secondary register area. @@ -125,6 +126,9 @@ static uint8_t ds1338_recv(I2CSlave *i2c) uint8_t res; res = s->nvram[s->ptr]; + + trace_ds1338_recv(s->ptr, res); + inc_regptr(s); return res; } @@ -133,6 +137,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) { DS1338State *s = DS1338(i2c); + trace_ds1338_send(s->ptr, data); + if (s->addr_byte) { s->ptr = data & (NVRAM_SIZE - 1); s->addr_byte = false; diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events index ebb311a..8012afe 100644 --- a/hw/rtc/trace-events +++ b/hw/rtc/trace-events @@ -22,6 +22,10 @@ pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks" aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64 aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64 +# ds1338.c +ds1338_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8 +ds1338_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8 + # m48t59.c m48txx_nvram_io_read(uint64_t addr, uint64_t value) "io read addr:0x%04" PRIx64 " value:0x%02" PRIx64 m48txx_nvram_io_write(uint64_t addr, uint64_t value) "io write addr:0x%04" PRIx64 " value:0x%02" PRIx64 diff --git a/hw/sensor/tmp105.c b/hw/sensor/tmp105.c index 9d7b911..ef2824f 100644 --- a/hw/sensor/tmp105.c +++ b/hw/sensor/tmp105.c @@ -27,6 +27,7 @@ #include "qapi/visitor.h" #include "qemu/module.h" #include "hw/registerfields.h" +#include "trace.h" FIELD(CONFIG, SHUTDOWN_MODE, 0, 1) FIELD(CONFIG, THERMOSTAT_MODE, 1, 1) @@ -150,17 +151,21 @@ static void tmp105_read(TMP105State *s) s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 0; break; } + + trace_tmp105_read(s->i2c.address, s->pointer); } static void tmp105_write(TMP105State *s) { + trace_tmp105_write(s->i2c.address, s->pointer); + switch (s->pointer & 3) { case TMP105_REG_TEMPERATURE: break; case TMP105_REG_CONFIG: if (FIELD_EX8(s->buf[0] & ~s->config, CONFIG, SHUTDOWN_MODE)) { - printf("%s: TMP105 shutdown\n", __func__); + trace_tmp105_write_shutdown(s->i2c.address); } s->config = FIELD_DP8(s->buf[0], CONFIG, ONE_SHOT, 0); s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)]; diff --git a/hw/sensor/trace-events b/hw/sensor/trace-events new file mode 100644 index 0000000..a3fe54f --- /dev/null +++ b/hw/sensor/trace-events @@ -0,0 +1,6 @@ +# See docs/devel/tracing.rst for syntax documentation. + +# tmp105.c +tmp105_read(uint8_t dev, uint8_t addr) "device: 0x%02x, addr: 0x%02x" +tmp105_write(uint8_t dev, uint8_t addr) "device: 0x%02x, addr 0x%02x" +tmp105_write_shutdown(uint8_t dev) "device: 0x%02x" diff --git a/hw/sensor/trace.h b/hw/sensor/trace.h new file mode 100644 index 0000000..e472156 --- /dev/null +++ b/hw/sensor/trace.h @@ -0,0 +1 @@ +#include "trace/trace-hw_sensor.h" diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 23b3d79..2663a9d 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -18,19 +18,12 @@ #include "migration/vmstate.h" #include "qemu/module.h" #include "qemu/log.h" +#include "trace.h" #ifndef DEBUG_IMX_GPT #define DEBUG_IMX_GPT 0 #endif -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_GPT) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \ - __func__, ##args); \ - } \ - } while (0) - static const char *imx_gpt_reg_name(uint32_t reg) { switch (reg) { @@ -145,7 +138,7 @@ static void imx_gpt_set_freq(IMXGPTState *s) s->freq = imx_ccm_get_clock_frequency(s->ccm, s->clocks[clksrc]) / (1 + s->pr); - DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq); + trace_imx_gpt_set_freq(clksrc, s->freq); if (s->freq) { ptimer_set_freq(s->timer, s->freq); @@ -317,7 +310,7 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) break; } - DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value); + trace_imx_gpt_read(imx_gpt_reg_name(offset >> 2), reg_value); return reg_value; } @@ -384,8 +377,7 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, IMXGPTState *s = IMX_GPT(opaque); uint32_t oldreg; - DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2), - (uint32_t)value); + trace_imx_gpt_write(imx_gpt_reg_name(offset >> 2), (uint32_t)value); switch (offset >> 2) { case 0: @@ -485,7 +477,7 @@ static void imx_gpt_timeout(void *opaque) { IMXGPTState *s = IMX_GPT(opaque); - DPRINTF("\n"); + trace_imx_gpt_timeout(); s->sr |= s->next_int; s->next_int = 0; diff --git a/hw/timer/trace-events b/hw/timer/trace-events index f48a712..5cfc369 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -49,6 +49,12 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset" +# imx_gpt.c +imx_gpt_set_freq(uint32_t clksrc, uint32_t freq) "Setting clksrc %u to %u Hz" +imx_gpt_read(const char *name, uint64_t value) "%s -> 0x%08" PRIx64 +imx_gpt_write(const char *name, uint64_t value) "%s <- 0x%08" PRIx64 +imx_gpt_timeout(void) "" + # npcm7xx_timer.c npcm7xx_timer_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64 npcm7xx_timer_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64 diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 992dc3b..01aa110 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -370,6 +370,10 @@ static ssize_t vfio_save_block(QEMUFile *f, VFIOMigration *migration) * please refer to the Linux kernel VFIO uAPI. */ if (errno == ENOMSG) { + if (!migration->event_precopy_empty_hit) { + trace_vfio_save_block_precopy_empty_hit(migration->vbasedev->name); + migration->event_precopy_empty_hit = true; + } return 0; } @@ -379,6 +383,9 @@ static ssize_t vfio_save_block(QEMUFile *f, VFIOMigration *migration) return 0; } + /* Non-empty read: re-arm the trace event */ + migration->event_precopy_empty_hit = false; + qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE); qemu_put_be64(f, data_size); qemu_put_buffer(f, migration->data_buffer, data_size); @@ -472,6 +479,9 @@ static int vfio_save_setup(QEMUFile *f, void *opaque, Error **errp) return -ENOMEM; } + migration->event_save_iterate_started = false; + migration->event_precopy_empty_hit = false; + if (vfio_precopy_supported(vbasedev)) { switch (migration->device_state) { case VFIO_DEVICE_STATE_RUNNING: @@ -602,6 +612,11 @@ static int vfio_save_iterate(QEMUFile *f, void *opaque) VFIOMigration *migration = vbasedev->migration; ssize_t data_size; + if (!migration->event_save_iterate_started) { + trace_vfio_save_iterate_start(vbasedev->name); + migration->event_save_iterate_started = true; + } + data_size = vfio_save_block(f, migration); if (data_size < 0) { return data_size; @@ -630,6 +645,8 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) int ret; Error *local_err = NULL; + trace_vfio_save_complete_precopy_start(vbasedev->name); + /* We reach here with device state STOP or STOP_COPY only */ ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_STOP_COPY, VFIO_DEVICE_STATE_STOP, &local_err); diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 29789e8..cab1cf1 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -157,10 +157,13 @@ vfio_migration_set_device_state(const char *name, const char *state) " (%s) stat vfio_migration_set_state(const char *name, const char *new_state, const char *recover_state) " (%s) new state %s, recover state %s" vfio_migration_state_notifier(const char *name, int state) " (%s) state %d" vfio_save_block(const char *name, int data_size) " (%s) data_size %d" +vfio_save_block_precopy_empty_hit(const char *name) " (%s)" vfio_save_cleanup(const char *name) " (%s)" vfio_save_complete_precopy(const char *name, int ret) " (%s) ret %d" +vfio_save_complete_precopy_start(const char *name) " (%s)" vfio_save_device_config_state(const char *name) " (%s)" vfio_save_iterate(const char *name, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy initial size %"PRIu64" precopy dirty size %"PRIu64 +vfio_save_iterate_start(const char *name) " (%s)" vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size %"PRIu64 vfio_state_pending_estimate(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy %"PRIu64" postcopy %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64 vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy %"PRIu64" postcopy %"PRIu64" stopcopy size %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64 diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 00561da..f170f0b 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1185,9 +1185,16 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev, static void vhost_user_host_notifier_free(VhostUserHostNotifier *n) { - assert(n && n->unmap_addr); - munmap(n->unmap_addr, qemu_real_host_page_size()); - n->unmap_addr = NULL; + if (n->unmap_addr) { + munmap(n->unmap_addr, qemu_real_host_page_size()); + n->unmap_addr = NULL; + } + if (n->destroy) { + memory_region_transaction_begin(); + object_unparent(OBJECT(&n->mr)); + memory_region_transaction_commit(); + g_free(n); + } } /* @@ -1195,17 +1202,28 @@ static void vhost_user_host_notifier_free(VhostUserHostNotifier *n) * under rcu. */ static void vhost_user_host_notifier_remove(VhostUserHostNotifier *n, - VirtIODevice *vdev) + VirtIODevice *vdev, bool destroy) { + /* + * if destroy == false and n->addr == NULL, we have nothing to do. + * so, just return. + */ + if (!n || (!destroy && !n->addr)) { + return; + } + if (n->addr) { if (vdev) { + memory_region_transaction_begin(); virtio_queue_set_host_notifier_mr(vdev, n->idx, &n->mr, false); + memory_region_transaction_commit(); } assert(!n->unmap_addr); n->unmap_addr = n->addr; n->addr = NULL; - call_rcu(n, vhost_user_host_notifier_free, rcu); } + n->destroy = destroy; + call_rcu(n, vhost_user_host_notifier_free, rcu); } static int vhost_user_set_vring_base(struct vhost_dev *dev, @@ -1279,9 +1297,7 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, struct vhost_user *u = dev->opaque; VhostUserHostNotifier *n = fetch_notifier(u->user, ring->index); - if (n) { - vhost_user_host_notifier_remove(n, dev->vdev); - } + vhost_user_host_notifier_remove(n, dev->vdev, false); ret = vhost_user_write(dev, &msg, NULL, 0); if (ret < 0) { @@ -1562,7 +1578,7 @@ static int vhost_user_backend_handle_vring_host_notifier(struct vhost_dev *dev, * new mapped address. */ n = fetch_or_create_notifier(user, queue_idx); - vhost_user_host_notifier_remove(n, vdev); + vhost_user_host_notifier_remove(n, vdev, false); if (area->u64 & VHOST_USER_VRING_NOFD_MASK) { return 0; @@ -1607,9 +1623,14 @@ vhost_user_backend_handle_shared_object_add(struct vhost_dev *dev, QemuUUID uuid; memcpy(uuid.data, object->uuid, sizeof(object->uuid)); - return virtio_add_vhost_device(&uuid, dev); + return !virtio_add_vhost_device(&uuid, dev); } +/* + * Handle VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE backend requests. + * + * Return: 0 on success, 1 on error. + */ static int vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev, VhostUserShared *object) @@ -1623,16 +1644,16 @@ vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev, struct vhost_dev *owner = virtio_lookup_vhost_device(&uuid); if (dev != owner) { /* Not allowed to remove non-owned entries */ - return 0; + return 1; } break; } default: /* Not allowed to remove non-owned entries */ - return 0; + return 1; } - return virtio_remove_resource(&uuid); + return !virtio_remove_resource(&uuid); } static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr, @@ -2736,15 +2757,7 @@ static int vhost_user_set_inflight_fd(struct vhost_dev *dev, static void vhost_user_state_destroy(gpointer data) { VhostUserHostNotifier *n = (VhostUserHostNotifier *) data; - if (n) { - vhost_user_host_notifier_remove(n, NULL); - object_unparent(OBJECT(&n->mr)); - /* - * We can't free until vhost_user_host_notifier_remove has - * done it's thing so schedule the free with RCU. - */ - g_free_rcu(n, rcu); - } + vhost_user_host_notifier_remove(n, NULL, true); } bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) @@ -2765,9 +2778,7 @@ void vhost_user_cleanup(VhostUserState *user) if (!user->chr) { return; } - memory_region_transaction_begin(); user->notifiers = (GPtrArray *) g_ptr_array_free(user->notifiers, true); - memory_region_transaction_commit(); user->chr = NULL; } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 4d832fe..5a39482 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2057,6 +2057,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (modern_pio) { memory_region_init(&proxy->io_bar, OBJECT(proxy), "virtio-pci-io", 0x4); + address_space_init(&proxy->modern_cfg_io_as, &proxy->io_bar, + "virtio-pci-cfg-io-as"); pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar_idx, PCI_BASE_ADDRESS_SPACE_IO, &proxy->io_bar); @@ -2180,6 +2182,9 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) /* PCI BAR regions must be powers of 2 */ pow2ceil(proxy->notify.offset + proxy->notify.size)); + address_space_init(&proxy->modern_cfg_mem_as, &proxy->modern_bar, + "virtio-pci-cfg-mem-as"); + if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) { proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } @@ -2269,12 +2274,17 @@ static void virtio_pci_exit(PCIDevice *pci_dev) VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); bool pcie_port = pci_bus_is_express(pci_get_bus(pci_dev)) && !pci_bus_is_root(pci_get_bus(pci_dev)); + bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; msix_uninit_exclusive_bar(pci_dev); if (proxy->flags & VIRTIO_PCI_FLAG_AER && pcie_port && pci_is_express(pci_dev)) { pcie_aer_exit(pci_dev); } + address_space_destroy(&proxy->modern_cfg_mem_as); + if (modern_pio) { + address_space_destroy(&proxy->modern_cfg_io_as); + } } static void virtio_pci_reset(DeviceState *qdev) @@ -2385,6 +2395,14 @@ static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp) vpciklass->parent_dc_realize(qdev, errp); } +static int virtio_pci_sync_config(DeviceState *dev, Error **errp) +{ + VirtIOPCIProxy *proxy = VIRTIO_PCI(dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + + return qdev_sync_config(DEVICE(vdev), errp); +} + static void virtio_pci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -2401,6 +2419,7 @@ static void virtio_pci_class_init(ObjectClass *klass, void *data) device_class_set_parent_realize(dc, virtio_pci_dc_realize, &vpciklass->parent_dc_realize); rc->phases.hold = virtio_pci_bus_reset_hold; + dc->sync_config = virtio_pci_sync_config; } static const TypeInfo virtio_pci_info = { diff --git a/hw/watchdog/wdt_imx2.c b/hw/watchdog/wdt_imx2.c index be63d42..8162d58 100644 --- a/hw/watchdog/wdt_imx2.c +++ b/hw/watchdog/wdt_imx2.c @@ -39,7 +39,6 @@ static void imx2_wdt_expired(void *opaque) /* Perform watchdog action if watchdog is enabled */ if (s->wcr & IMX2_WDT_WCR_WDE) { - s->wrsr = IMX2_WDT_WRSR_TOUT; watchdog_perform_action(); } } diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 712cac7..1868d4a 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -31,6 +31,7 @@ #define QCRYPTO_HASH_DIGEST_LEN_SHA384 48 #define QCRYPTO_HASH_DIGEST_LEN_SHA512 64 #define QCRYPTO_HASH_DIGEST_LEN_RIPEMD160 20 +#define QCRYPTO_HASH_DIGEST_LEN_SM3 32 /* See also "QCryptoHashAlgo" defined in qapi/crypto.json */ diff --git a/include/disas/capstone.h b/include/disas/capstone.h index a119851..c43033f 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -4,6 +4,7 @@ #ifdef CONFIG_CAPSTONE #define CAPSTONE_AARCH64_COMPAT_HEADER +#define CAPSTONE_SYSTEMZ_COMPAT_HEADER #include <capstone.h> #else diff --git a/include/exec/memory.h b/include/exec/memory.h index e5e865d..9458e28 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1104,7 +1104,14 @@ struct AddressSpace { QTAILQ_HEAD(, MemoryListener) listeners; QTAILQ_ENTRY(AddressSpace) address_spaces_link; - /* Maximum DMA bounce buffer size used for indirect memory map requests */ + /* + * Maximum DMA bounce buffer size used for indirect memory map requests. + * This limits the total size of bounce buffer allocations made for + * DMA requests to indirect memory regions within this AddressSpace. DMA + * requests that exceed the limit (e.g. due to overly large requested size + * or concurrent DMA requests having claimed too much buffer space) will be + * rejected and left to the caller to handle. + */ size_t max_bounce_buffer_size; /* Total size of bounce buffers currently allocated, atomically accessed */ size_t bounce_buffer_size; diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index 94cbe07..453188d 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -75,6 +75,12 @@ static inline void set_floatx80_rounding_precision(FloatX80RoundPrec val, status->floatx80_rounding_precision = val; } +static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule, + float_status *status) +{ + status->float_2nan_prop_rule = rule; +} + static inline void set_flush_to_zero(bool val, float_status *status) { status->flush_to_zero = val; @@ -126,6 +132,11 @@ get_floatx80_rounding_precision(float_status *status) return status->floatx80_rounding_precision; } +static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status) +{ + return status->float_2nan_prop_rule; +} + static inline bool get_flush_to_zero(float_status *status) { return status->flush_to_zero; diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index 0884ec4..8f39691 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -171,6 +171,43 @@ typedef enum __attribute__((__packed__)) { } FloatX80RoundPrec; /* + * 2-input NaN propagation rule. Individual architectures have + * different rules for which input NaN is propagated to the output + * when there is more than one NaN on the input. + * + * If default_nan_mode is enabled then it is valid not to set a + * NaN propagation rule, because the softfloat code guarantees + * not to try to pick a NaN to propagate in default NaN mode. + * When not in default-NaN mode, it is an error for the target + * not to set the rule in float_status, and we will assert if + * we need to handle an input NaN and no rule was selected. + */ +typedef enum __attribute__((__packed__)) { + /* No propagation rule specified */ + float_2nan_prop_none = 0, + /* Prefer SNaN over QNaN, then operand A over B */ + float_2nan_prop_s_ab, + /* Prefer SNaN over QNaN, then operand B over A */ + float_2nan_prop_s_ba, + /* Prefer A over B regardless of SNaN vs QNaN */ + float_2nan_prop_ab, + /* Prefer B over A regardless of SNaN vs QNaN */ + float_2nan_prop_ba, + /* + * This implements x87 NaN propagation rules: + * SNaN + QNaN => return the QNaN + * two SNaNs => return the one with the larger significand, silenced + * two QNaNs => return the one with the larger significand + * SNaN and a non-NaN => return the SNaN, silenced + * QNaN and a non-NaN => return the QNaN + * + * If we get down to comparing significands and they are the same, + * return the NaN with the positive sign bit (if any). + */ + float_2nan_prop_x87, +} Float2NaNPropRule; + +/* * Floating Point Status. Individual architectures may maintain * several versions of float_status for different functions. The * correct status for the operation is then passed by reference to @@ -181,6 +218,7 @@ typedef struct float_status { uint16_t float_exception_flags; FloatRoundMode float_rounding_mode; FloatX80RoundPrec floatx80_rounding_precision; + Float2NaNPropRule float_2nan_prop_rule; bool tininess_before_rounding; /* should denormalised results go to zero and set the inexact flag? */ bool flush_to_zero; diff --git a/include/hw/acpi/acpi_generic_initiator.h b/include/hw/acpi/acpi_generic_initiator.h deleted file mode 100644 index a304bad..0000000 --- a/include/hw/acpi/acpi_generic_initiator.h +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved - */ - -#ifndef ACPI_GENERIC_INITIATOR_H -#define ACPI_GENERIC_INITIATOR_H - -#include "qom/object_interfaces.h" - -#define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator" - -typedef struct AcpiGenericInitiator { - /* private */ - Object parent; - - /* public */ - char *pci_dev; - uint16_t node; -} AcpiGenericInitiator; - -/* - * ACPI 6.3: - * Table 5-81 Flags – Generic Initiator Affinity Structure - */ -typedef enum { - /* - * If clear, the OSPM ignores the contents of the Generic - * Initiator/Port Affinity Structure. This allows system firmware - * to populate the SRAT with a static number of structures, but only - * enable them as necessary. - */ - GEN_AFFINITY_ENABLED = (1 << 0), -} GenericAffinityFlags; - -/* - * ACPI 6.3: - * Table 5-80 Device Handle - PCI - */ -typedef struct PCIDeviceHandle { - uint16_t segment; - uint16_t bdf; -} PCIDeviceHandle; - -void build_srat_generic_pci_initiator(GArray *table_data); - -#endif diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index a378415..4fd5da4 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -486,6 +486,13 @@ Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set, uint32_t io_offset, void build_srat_memory(GArray *table_data, uint64_t base, uint64_t len, int node, MemoryAffinityFlags flags); +void build_srat_pci_generic_initiator(GArray *table_data, uint32_t node, + uint16_t segment, uint8_t bus, + uint8_t devfn); + +void build_srat_acpi_generic_port(GArray *table_data, uint32_t node, + const char *hid, uint32_t uid); + void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms, const char *oem_id, const char *oem_table_id); diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h index 467a994..6359d57 100644 --- a/include/hw/acpi/pci.h +++ b/include/hw/acpi/pci.h @@ -40,4 +40,7 @@ Aml *aml_pci_device_dsm(void); void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus); void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope); + +void build_srat_generic_affinity_structures(GArray *table_data); + #endif diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index c3ca0ba..db8a6fb 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -158,6 +158,8 @@ struct CPUClass { void (*dump_state)(CPUState *cpu, FILE *, int flags); void (*query_cpu_fast)(CPUState *cpu, CpuInfoFast *value); int64_t (*get_arch_id)(CPUState *cpu); + bool (*cpu_persistent_status)(CPUState *cpu); + bool (*cpu_enabled_status)(CPUState *cpu); void (*set_pc)(CPUState *cpu, vaddr value); vaddr (*get_pc)(CPUState *cpu); int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg); diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index fdd0f4e..561b375 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -463,18 +463,6 @@ typedef struct CXLMemPatrolScrubWriteAttrs { #define CXL_MEMDEV_PS_ENABLE_DEFAULT 0 /* CXL memory device DDR5 ECS control attributes */ -typedef struct CXLMemECSReadAttrs { - uint8_t ecs_log_cap; - uint8_t ecs_cap; - uint16_t ecs_config; - uint8_t ecs_flags; -} QEMU_PACKED CXLMemECSReadAttrs; - -typedef struct CXLMemECSWriteAttrs { - uint8_t ecs_log_cap; - uint16_t ecs_config; -} QEMU_PACKED CXLMemECSWriteAttrs; - #define CXL_ECS_GET_FEATURE_VERSION 0x01 #define CXL_ECS_SET_FEATURE_VERSION 0x01 #define CXL_ECS_LOG_ENTRY_TYPE_DEFAULT 0x01 @@ -483,6 +471,26 @@ typedef struct CXLMemECSWriteAttrs { #define CXL_ECS_MODE_DEFAULT 0 #define CXL_ECS_NUM_MEDIA_FRUS 3 /* Default */ +typedef struct CXLMemECSFRUReadAttrs { + uint8_t ecs_cap; + uint16_t ecs_config; + uint8_t ecs_flags; +} QEMU_PACKED CXLMemECSFRUReadAttrs; + +typedef struct CXLMemECSReadAttrs { + uint8_t ecs_log_cap; + CXLMemECSFRUReadAttrs fru_attrs[CXL_ECS_NUM_MEDIA_FRUS]; +} QEMU_PACKED CXLMemECSReadAttrs; + +typedef struct CXLMemECSFRUWriteAttrs { + uint16_t ecs_config; +} QEMU_PACKED CXLMemECSFRUWriteAttrs; + +typedef struct CXLMemECSWriteAttrs { + uint8_t ecs_log_cap; + CXLMemECSFRUWriteAttrs fru_attrs[CXL_ECS_NUM_MEDIA_FRUS]; +} QEMU_PACKED CXLMemECSWriteAttrs; + #define DCD_MAX_NUM_REGION 8 typedef struct CXLDCExtentRaw { @@ -549,6 +557,10 @@ struct CXLType3Dev { CXLCCI vdm_fm_owned_ld_mctp_cci; CXLCCI ld0_cci; + /* PCIe link characteristics */ + PCIExpLinkSpeed speed; + PCIExpLinkWidth width; + /* DOE */ DOECap doe_cdat; @@ -571,8 +583,8 @@ struct CXLType3Dev { CXLMemPatrolScrubReadAttrs patrol_scrub_attrs; CXLMemPatrolScrubWriteAttrs patrol_scrub_wr_attrs; /* ECS control attributes */ - CXLMemECSReadAttrs ecs_attrs[CXL_ECS_NUM_MEDIA_FRUS]; - CXLMemECSWriteAttrs ecs_wr_attrs[CXL_ECS_NUM_MEDIA_FRUS]; + CXLMemECSReadAttrs ecs_attrs; + CXLMemECSWriteAttrs ecs_wr_attrs; struct dynamic_capacity { HostMemoryBackend *host_dc; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 1eb05c2..d372cd3 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -306,6 +306,9 @@ struct IntelIOMMUState { bool dma_translation; /* Whether DMA translation supported */ bool pasid; /* Whether to support PASID */ + /* Transient Mapping, Reserved(0) since VTD spec revision 3.2 */ + bool stale_tm; + /* * Protects IOMMU states in general. Currently it protects the * per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace. diff --git a/include/hw/pci-bridge/cxl_upstream_port.h b/include/hw/pci-bridge/cxl_upstream_port.h index 1263513..f208397 100644 --- a/include/hw/pci-bridge/cxl_upstream_port.h +++ b/include/hw/pci-bridge/cxl_upstream_port.h @@ -12,6 +12,10 @@ typedef struct CXLUpstreamPort { /*< public >*/ CXLComponentState cxl_cstate; CXLCCI swcci; + + PCIExpLinkSpeed speed; + PCIExpLinkWidth width; + DOECap doe_cdat; uint64_t sn; } CXLUpstreamPort; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 35d4fe0..135695c 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -16,7 +16,7 @@ extern bool pci_available; #define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) -#define PCI_BUILD_BDF(bus, devfn) ((bus << 8) | (devfn)) +#define PCI_BUILD_BDF(bus, devfn) (((bus) << 8) | (devfn)) #define PCI_BDF_TO_DEVFN(x) ((x) & 0xff) #define PCI_BUS_MAX 256 #define PCI_DEVFN_MAX 256 @@ -214,6 +214,8 @@ enum { QEMU_PCIE_ERR_UNC_MASK = (1 << QEMU_PCIE_ERR_UNC_MASK_BITNR), #define QEMU_PCIE_ARI_NEXTFN_1_BITNR 12 QEMU_PCIE_ARI_NEXTFN_1 = (1 << QEMU_PCIE_ARI_NEXTFN_1_BITNR), +#define QEMU_PCIE_EXT_TAG_BITNR 13 + QEMU_PCIE_EXT_TAG = (1 << QEMU_PCIE_EXT_TAG_BITNR), }; typedef struct PCIINTxRoute { diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index 5cd4521..b0f5204 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -72,6 +72,8 @@ struct PCIBridge { */ MemoryRegion address_space_mem; MemoryRegion address_space_io; + AddressSpace as_mem; + AddressSpace as_io; PCIBridgeWindows windows; @@ -102,6 +104,7 @@ typedef struct PXBPCIEDev { PXBDev parent_obj; } PXBPCIEDev; +#define TYPE_PXB_CXL_BUS "pxb-cxl-bus" #define TYPE_PXB_DEV "pxb" OBJECT_DECLARE_SIMPLE_TYPE(PXBDev, PXB_DEV) diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h index 91df40f..8eaf0d5 100644 --- a/include/hw/pci/pci_device.h +++ b/include/hw/pci/pci_device.h @@ -168,7 +168,11 @@ struct PCIDevice { char *failover_pair_id; uint32_t acpi_index; - /* Maximum DMA bounce buffer size used for indirect memory map requests */ + /* + * Indirect DMA region bounce buffer size as configured for the device. This + * is a configuration parameter that is reflected into bus_master_as when + * realizing the device. + */ uint32_t max_bounce_buffer_size; }; diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index 5eddb90..b8d5973 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -141,6 +141,8 @@ void pcie_acs_reset(PCIDevice *dev); void pcie_ari_init(PCIDevice *dev, uint16_t offset); void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num); void pcie_ats_init(PCIDevice *dev, uint16_t offset, bool aligned); +void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width, + PCIExpLinkSpeed speed); void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index aa97c34..9491485 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -95,6 +95,7 @@ typedef void (*DeviceUnrealize)(DeviceState *dev); typedef void (*DeviceReset)(DeviceState *dev); typedef void (*BusRealize)(BusState *bus, Error **errp); typedef void (*BusUnrealize)(BusState *bus); +typedef int (*DeviceSyncConfig)(DeviceState *dev, Error **errp); /** * struct DeviceClass - The base class for all devices. @@ -103,6 +104,9 @@ typedef void (*BusUnrealize)(BusState *bus); * property is changed to %true. * @unrealize: Callback function invoked when the #DeviceState:realized * property is changed to %false. + * @sync_config: Callback function invoked when QMP command device-sync-config + * is called. Should synchronize device configuration from host to guest part + * and notify the guest about the change. * @hotpluggable: indicates if #DeviceClass is hotpluggable, available * as readonly "hotpluggable" property of #DeviceState instance * @@ -162,6 +166,7 @@ struct DeviceClass { DeviceReset legacy_reset; DeviceRealize realize; DeviceUnrealize unrealize; + DeviceSyncConfig sync_config; /** * @vmsd: device state serialisation description for @@ -547,6 +552,7 @@ bool qdev_hotplug_allowed(DeviceState *dev, Error **errp); */ HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev); void qdev_unplug(DeviceState *dev, Error **errp); +int qdev_sync_config(DeviceState *dev, Error **errp); void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); void qdev_machine_creation_done(void); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index fed499b..e0ce6ec 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -73,6 +73,9 @@ typedef struct VFIOMigration { uint64_t precopy_init_size; uint64_t precopy_dirty_size; bool initial_data_sent; + + bool event_save_iterate_started; + bool event_precopy_empty_hit; } VFIOMigration; struct VFIOGroup; diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index 324cd86..9a3f238 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -54,6 +54,7 @@ typedef struct VhostUserHostNotifier { void *addr; void *unmap_addr; int idx; + bool destroy; } VhostUserHostNotifier; /** diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h index 9e67ba3..971c5fa 100644 --- a/include/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -147,6 +147,9 @@ struct VirtIOPCIProxy { }; MemoryRegion modern_bar; MemoryRegion io_bar; + /* address space for VirtIOPCIRegions */ + AddressSpace modern_cfg_mem_as; + AddressSpace modern_cfg_io_as; uint32_t legacy_io_bar_idx; uint32_t msix_bar_idx; uint32_t modern_io_bar_idx; diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c index 9a93610..8356beb 100644 --- a/linux-user/arm/nwfpe/fpa11.c +++ b/linux-user/arm/nwfpe/fpa11.c @@ -51,6 +51,24 @@ void resetFPA11(void) #ifdef MAINTAIN_FPCR fpa11->fpcr = MASK_RESET; #endif + + /* + * Real FPA11 hardware does not handle NaNs, but always takes an + * exception for them to be software-emulated (ARM7500FE datasheet + * section 10.4). There is no documented architectural requirement + * for NaN propagation rules and it will depend on how the OS + * level software emulation opted to do it. We here use prop_s_ab + * which matches the later VFP hardware choice and how QEMU's + * fpa11 emulation has worked in the past. The real Linux kernel + * does something slightly different: arch/arm/nwfpe/softfloat-specialize + * propagateFloat64NaN() has the curious behaviour that it prefers + * the QNaN over the SNaN, but if both are QNaN it picks A and + * if both are SNaN it picks B. In theory we could add this as + * a NaN propagation rule, but in practice FPA11 emulation is so + * close to totally dead that it's not worth trying to match it at + * this late date. + */ + set_float_2nan_prop_rule(float_2nan_prop_s_ab, &fpa11->fp_status); } void SetRoundingMode(const unsigned int opcode) diff --git a/linux-user/gen-vdso-elfn.c.inc b/linux-user/gen-vdso-elfn.c.inc index 95856eb..b47019e 100644 --- a/linux-user/gen-vdso-elfn.c.inc +++ b/linux-user/gen-vdso-elfn.c.inc @@ -68,28 +68,45 @@ static void elfN(search_symtab)(ElfN(Shdr) *shdr, unsigned sym_idx, void *buf, bool need_bswap) { unsigned str_idx = shdr[sym_idx].sh_link; - ElfN(Sym) *sym = buf + shdr[sym_idx].sh_offset; - unsigned sym_n = shdr[sym_idx].sh_size / sizeof(*sym); + ElfN(Sym) *target_sym = buf + shdr[sym_idx].sh_offset; + unsigned sym_n = shdr[sym_idx].sh_size / sizeof(*target_sym); const char *str = buf + shdr[str_idx].sh_offset; for (unsigned i = 0; i < sym_n; ++i) { const char *name; + ElfN(Sym) sym; + memcpy(&sym, &target_sym[i], sizeof(sym)); if (need_bswap) { - elfN(bswap_sym)(sym + i); + elfN(bswap_sym)(&sym); } - name = str + sym[i].st_name; + name = str + sym.st_name; if (sigreturn_sym && strcmp(sigreturn_sym, name) == 0) { - sigreturn_addr = sym[i].st_value; + sigreturn_addr = sym.st_value; } if (rt_sigreturn_sym && strcmp(rt_sigreturn_sym, name) == 0) { - rt_sigreturn_addr = sym[i].st_value; + rt_sigreturn_addr = sym.st_value; } } } -static void elfN(process)(FILE *outf, void *buf, bool need_bswap) +static void elfN(bswap_ps_hdrs)(ElfN(Ehdr) *ehdr) +{ + ElfN(Phdr) *phdr = (void *)ehdr + ehdr->e_phoff; + ElfN(Shdr) *shdr = (void *)ehdr + ehdr->e_shoff; + ElfN(Half) i; + + for (i = 0; i < ehdr->e_phnum; ++i) { + elfN(bswap_phdr)(&phdr[i]); + } + + for (i = 0; i < ehdr->e_shnum; ++i) { + elfN(bswap_shdr)(&shdr[i]); + } +} + +static void elfN(process)(FILE *outf, void *buf, long len, bool need_bswap) { ElfN(Ehdr) *ehdr = buf; ElfN(Phdr) *phdr; @@ -103,24 +120,14 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) int errors = 0; if (need_bswap) { - elfN(bswap_ehdr)(ehdr); + elfN(bswap_ehdr)(buf); + elfN(bswap_ps_hdrs)(buf); } phnum = ehdr->e_phnum; phdr = buf + ehdr->e_phoff; - if (need_bswap) { - for (unsigned i = 0; i < phnum; ++i) { - elfN(bswap_phdr)(phdr + i); - } - } - shnum = ehdr->e_shnum; shdr = buf + ehdr->e_shoff; - if (need_bswap) { - for (unsigned i = 0; i < shnum; ++i) { - elfN(bswap_shdr)(shdr + i); - } - } for (unsigned i = 0; i < shnum; ++i) { switch (shdr[i].sh_type) { case SHT_SYMTAB: @@ -154,7 +161,24 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) fprintf(stderr, "LOAD segment not loaded at address 0\n"); errors++; } - first_segsz = phdr[i].p_filesz; + /* + * Extend the program header to cover the entire VDSO, so that + * load_elf_vdso() loads everything, including section headers. + * + * Require that there is no .bss, since it would break this + * approach. + */ + if (phdr[i].p_filesz != phdr[i].p_memsz) { + fprintf(stderr, "LOAD segment's filesz and memsz differ\n"); + errors++; + } + if (phdr[i].p_filesz > len) { + fprintf(stderr, "LOAD segment is larger than the whole VDSO\n"); + errors++; + } + phdr[i].p_filesz = len; + phdr[i].p_memsz = len; + first_segsz = len; if (first_segsz < ehdr->e_phoff + phnum * sizeof(*phdr)) { fprintf(stderr, "LOAD segment does not cover PHDRs\n"); errors++; @@ -197,17 +221,24 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) output_reloc(outf, buf, &phdr[i].p_paddr); } + /* Relocate the section headers. */ + for (unsigned i = 0; i < shnum; ++i) { + output_reloc(outf, buf, &shdr[i].sh_addr); + } + /* Relocate the DYNAMIC entries. */ if (dynamic_addr) { - ElfN(Dyn) *dyn = buf + dynamic_ofs; - __typeof(dyn->d_tag) tag; + ElfN(Dyn) *target_dyn = buf + dynamic_ofs; + __typeof(((ElfN(Dyn) *)target_dyn)->d_tag) tag; do { + ElfN(Dyn) dyn; + memcpy(&dyn, target_dyn, sizeof(dyn)); if (need_bswap) { - elfN(bswap_dyn)(dyn); + elfN(bswap_dyn)(&dyn); } - tag = dyn->d_tag; + tag = dyn.d_tag; switch (tag) { case DT_HASH: @@ -218,7 +249,7 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) case DT_PLTGOT: case DT_ADDRRNGLO ... DT_ADDRRNGHI: /* These entries store an address in the entry. */ - output_reloc(outf, buf, &dyn->d_un.d_val); + output_reloc(outf, buf, &target_dyn->d_un.d_val); break; case DT_NULL: @@ -235,7 +266,7 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) break; case DT_SYMENT: - if (dyn->d_un.d_val != sizeof(ElfN(Sym))) { + if (dyn.d_un.d_val != sizeof(ElfN(Sym))) { fprintf(stderr, "VDSO has incorrect dynamic symbol size\n"); errors++; } @@ -251,7 +282,7 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) * ??? The RISC-V toolchain will emit these even when there * are no relocations. Validate zeros. */ - if (dyn->d_un.d_val != 0) { + if (dyn.d_un.d_val != 0) { fprintf(stderr, "VDSO has dynamic relocations\n"); errors++; } @@ -287,7 +318,7 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) errors++; break; } - dyn++; + target_dyn++; } while (tag != DT_NULL); if (errors) { exit(EXIT_FAILURE); @@ -296,11 +327,11 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) /* Relocate the dynamic symbol table. */ if (dynsym_idx) { - ElfN(Sym) *sym = buf + shdr[dynsym_idx].sh_offset; - unsigned sym_n = shdr[dynsym_idx].sh_size / sizeof(*sym); + ElfN(Sym) *target_sym = buf + shdr[dynsym_idx].sh_offset; + unsigned sym_n = shdr[dynsym_idx].sh_size / sizeof(*target_sym); for (unsigned i = 0; i < sym_n; ++i) { - output_reloc(outf, buf, &sym[i].st_value); + output_reloc(outf, buf, &target_sym[i].st_value); } } @@ -311,4 +342,9 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap) if (symtab_idx) { elfN(search_symtab)(shdr, symtab_idx, buf, need_bswap); } + + if (need_bswap) { + elfN(bswap_ps_hdrs)(buf); + elfN(bswap_ehdr)(buf); + } } diff --git a/linux-user/gen-vdso.c b/linux-user/gen-vdso.c index 31e333b..721f38d 100644 --- a/linux-user/gen-vdso.c +++ b/linux-user/gen-vdso.c @@ -132,23 +132,6 @@ int main(int argc, char **argv) fclose(inf); /* - * Write out the vdso image now, before we make local changes. - */ - - fprintf(outf, - "/* Automatically generated from linux-user/gen-vdso.c. */\n" - "\n" - "static const uint8_t %s_image[] = {", - prefix); - for (long i = 0; i < total_len; ++i) { - if (i % 12 == 0) { - fputs("\n ", outf); - } - fprintf(outf, " 0x%02x,", buf[i]); - } - fprintf(outf, "\n};\n\n"); - - /* * Identify which elf flavor we're processing. * The first 16 bytes of the file are e_ident. */ @@ -179,14 +162,17 @@ int main(int argc, char **argv) * Output relocation addresses as we go. */ - fprintf(outf, "static const unsigned %s_relocs[] = {\n", prefix); + fprintf(outf, + "/* Automatically generated by linux-user/gen-vdso.c. */\n" + "\n" + "static const unsigned %s_relocs[] = {\n", prefix); switch (buf[EI_CLASS]) { case ELFCLASS32: - elf32_process(outf, buf, need_bswap); + elf32_process(outf, buf, total_len, need_bswap); break; case ELFCLASS64: - elf64_process(outf, buf, need_bswap); + elf64_process(outf, buf, total_len, need_bswap); break; default: fprintf(stderr, "%s: invalid elf EI_CLASS (%u)\n", @@ -196,6 +182,20 @@ int main(int argc, char **argv) fprintf(outf, "};\n\n"); /* end vdso_relocs. */ + /* + * Write out the vdso image now, after we made local changes. + */ + fprintf(outf, + "static const uint8_t %s_image[] = {", + prefix); + for (long i = 0; i < total_len; ++i) { + if (i % 12 == 0) { + fputs("\n ", outf); + } + fprintf(outf, " 0x%02x,", buf[i]); + } + fprintf(outf, "\n};\n\n"); + fprintf(outf, "static const VdsoImageInfo %s_image_info = {\n", prefix); fprintf(outf, " .image = %s_image,\n", prefix); fprintf(outf, " .relocs = %s_relocs,\n", prefix); diff --git a/linux-user/main.c b/linux-user/main.c index 8143a0d..b09af8d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -412,6 +412,13 @@ static void handle_arg_reserved_va(const char *arg) reserved_va = val ? val - 1 : 0; } +static const char *rtsig_map = CONFIG_QEMU_RTSIG_MAP; + +static void handle_arg_rtsig_map(const char *arg) +{ + rtsig_map = arg; +} + static void handle_arg_one_insn_per_tb(const char *arg) { opt_one_insn_per_tb = true; @@ -494,6 +501,9 @@ static const struct qemu_argument arg_table[] = { "address", "set guest_base address to 'address'"}, {"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va, "size", "reserve 'size' bytes for guest virtual address space"}, + {"t", "QEMU_RTSIG_MAP", true, handle_arg_rtsig_map, + "tsig hsig n[,...]", + "map target rt signals [tsig,tsig+n) to [hsig,hsig+n]"}, {"d", "QEMU_LOG", true, handle_arg_log, "item[,...]", "enable logging of specified items " "(use '-d help' for a list of items)"}, @@ -1002,7 +1012,7 @@ int main(int argc, char **argv, char **envp) target_set_brk(info->brk); syscall_init(); - signal_init(); + signal_init(rtsig_map); /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay generating the prologue until now so that the prologue can take diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index f4cbe61..8584d9e 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -56,7 +56,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUArchState *env); void process_pending_signals(CPUArchState *cpu_env); -void signal_init(void); +void signal_init(const char *rtsig_map); void queue_signal(CPUArchState *env, int sig, int si_type, target_siginfo_t *info); void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); diff --git a/linux-user/signal.c b/linux-user/signal.c index 63ac2df..9b6d772 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu/bitops.h" +#include "qemu/cutils.h" #include "gdbstub/user.h" #include "exec/page-protection.h" #include "hw/core/tcg-cpu-ops.h" @@ -513,20 +514,81 @@ static int core_dump_signal(int sig) } } -static void signal_table_init(void) +static void signal_table_init(const char *rtsig_map) { int hsig, tsig, count; + if (rtsig_map) { + /* + * Map host RT signals to target RT signals according to the + * user-provided specification. + */ + const char *s = rtsig_map; + + while (true) { + int i; + + if (qemu_strtoi(s, &s, 10, &tsig) || *s++ != ' ') { + fprintf(stderr, "Malformed target signal in QEMU_RTSIG_MAP\n"); + exit(EXIT_FAILURE); + } + if (qemu_strtoi(s, &s, 10, &hsig) || *s++ != ' ') { + fprintf(stderr, "Malformed host signal in QEMU_RTSIG_MAP\n"); + exit(EXIT_FAILURE); + } + if (qemu_strtoi(s, &s, 10, &count) || (*s && *s != ',')) { + fprintf(stderr, "Malformed signal count in QEMU_RTSIG_MAP\n"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < count; i++, tsig++, hsig++) { + if (tsig < TARGET_SIGRTMIN || tsig > TARGET_NSIG) { + fprintf(stderr, "%d is not a target rt signal\n", tsig); + exit(EXIT_FAILURE); + } + if (hsig < SIGRTMIN || hsig > SIGRTMAX) { + fprintf(stderr, "%d is not a host rt signal\n", hsig); + exit(EXIT_FAILURE); + } + if (host_to_target_signal_table[hsig]) { + fprintf(stderr, "%d already maps %d\n", + hsig, host_to_target_signal_table[hsig]); + exit(EXIT_FAILURE); + } + host_to_target_signal_table[hsig] = tsig; + } + + if (*s) { + s++; + } else { + break; + } + } + } else { + /* + * Default host-to-target RT signal mapping. + * + * Signals are supported starting from TARGET_SIGRTMIN and going up + * until we run out of host realtime signals. Glibc uses the lower 2 + * RT signals and (hopefully) nobody uses the upper ones. + * This is why SIGRTMIN (34) is generally greater than __SIGRTMIN (32). + * To fix this properly we would need to do manual signal delivery + * multiplexed over a single host signal. + * Attempts for configure "missing" signals via sigaction will be + * silently ignored. + * + * Reserve one signal for internal usage (see below). + */ + + hsig = SIGRTMIN + 1; + for (tsig = TARGET_SIGRTMIN; + hsig <= SIGRTMAX && tsig <= TARGET_NSIG; + hsig++, tsig++) { + host_to_target_signal_table[hsig] = tsig; + } + } + /* - * Signals are supported starting from TARGET_SIGRTMIN and going up - * until we run out of host realtime signals. Glibc uses the lower 2 - * RT signals and (hopefully) nobody uses the upper ones. - * This is why SIGRTMIN (34) is generally greater than __SIGRTMIN (32). - * To fix this properly we would need to do manual signal delivery - * multiplexed over a single host signal. - * Attempts for configure "missing" signals via sigaction will be - * silently ignored. - * * Remap the target SIGABRT, so that we can distinguish host abort * from guest abort. When the guest registers a signal handler or * calls raise(SIGABRT), the host will raise SIG_RTn. If the guest @@ -536,21 +598,27 @@ static void signal_table_init(void) * parent sees the correct mapping from wait status. */ - hsig = SIGRTMIN; host_to_target_signal_table[SIGABRT] = 0; - host_to_target_signal_table[hsig++] = TARGET_SIGABRT; - - for (tsig = TARGET_SIGRTMIN; - hsig <= SIGRTMAX && tsig <= TARGET_NSIG; - hsig++, tsig++) { - host_to_target_signal_table[hsig] = tsig; + for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) { + if (!host_to_target_signal_table[hsig]) { + host_to_target_signal_table[hsig] = TARGET_SIGABRT; + break; + } + } + if (hsig > SIGRTMAX) { + fprintf(stderr, "No rt signals left for SIGABRT mapping\n"); + exit(EXIT_FAILURE); } /* Invert the mapping that has already been assigned. */ for (hsig = 1; hsig < _NSIG; hsig++) { tsig = host_to_target_signal_table[hsig]; if (tsig) { - assert(target_to_host_signal_table[tsig] == 0); + if (target_to_host_signal_table[tsig]) { + fprintf(stderr, "%d is already mapped to %d\n", + tsig, target_to_host_signal_table[tsig]); + exit(EXIT_FAILURE); + } target_to_host_signal_table[tsig] = hsig; } } @@ -573,13 +641,13 @@ static void signal_table_init(void) trace_signal_table_init(count); } -void signal_init(void) +void signal_init(const char *rtsig_map) { TaskState *ts = get_task_state(thread_cpu); struct sigaction act, oact; /* initialize signal conversion tables */ - signal_table_init(); + signal_table_init(rtsig_map); /* Set the signal mask from the host mask. */ sigprocmask(0, 0, &ts->signal_mask); diff --git a/meson.build b/meson.build index c386593..34e2bdb 100644 --- a/meson.build +++ b/meson.build @@ -1760,6 +1760,7 @@ gcrypt = not_found nettle = not_found hogweed = not_found crypto_sm4 = not_found +crypto_sm3 = not_found xts = 'none' if get_option('nettle').enabled() and get_option('gcrypt').enabled() @@ -1795,6 +1796,17 @@ if not gnutls_crypto.found() }''', dependencies: gcrypt) crypto_sm4 = not_found endif + crypto_sm3 = gcrypt + # SM3 ALG is available in libgcrypt >= 1.9 + if gcrypt.found() and not cc.links(''' + #include <gcrypt.h> + int main(void) { + gcry_md_hd_t handler; + gcry_md_open(&handler, GCRY_MD_SM3, 0); + return 0; + }''', dependencies: gcrypt) + crypto_sm3 = not_found + endif endif if (not get_option('nettle').auto() or have_system) and not gcrypt.found() nettle = dependency('nettle', version: '>=3.4', @@ -1815,6 +1827,31 @@ if not gnutls_crypto.found() }''', dependencies: nettle) crypto_sm4 = not_found endif + crypto_sm3 = nettle + # SM3 ALG is available in nettle >= 3.8 + if nettle.found() and not cc.links(''' + #include <nettle/sm3.h> + #include <nettle/hmac.h> + int main(void) { + struct sm3_ctx ctx; + struct hmac_sm3_ctx hmac_ctx; + unsigned char data[64] = {0}; + unsigned char output[32]; + + // SM3 hash function test + sm3_init(&ctx); + sm3_update(&ctx, 64, data); + sm3_digest(&ctx, 32, data); + + // HMAC-SM3 test + hmac_sm3_set_key(&hmac_ctx, 32, data); + hmac_sm3_update(&hmac_ctx, 64, data); + hmac_sm3_digest(&hmac_ctx, 32, output); + + return 0; + }''', dependencies: nettle) + crypto_sm3 = not_found + endif endif endif @@ -2462,6 +2499,7 @@ config_host_data.set('CONFIG_TASN1', tasn1.found()) config_host_data.set('CONFIG_GCRYPT', gcrypt.found()) config_host_data.set('CONFIG_NETTLE', nettle.found()) config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found()) +config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found()) config_host_data.set('CONFIG_HOGWEED', hogweed.found()) config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) @@ -3178,7 +3216,8 @@ foreach target : target_dirs config_target += { 'CONFIG_USER_ONLY': 'y', 'CONFIG_QEMU_INTERP_PREFIX': - get_option('interp_prefix').replace('%M', config_target['TARGET_NAME']) + get_option('interp_prefix').replace('%M', config_target['TARGET_NAME']), + 'CONFIG_QEMU_RTSIG_MAP': get_option('rtsig_map'), } endif @@ -3484,6 +3523,7 @@ if have_system 'hw/s390x', 'hw/scsi', 'hw/sd', + 'hw/sensor', 'hw/sh4', 'hw/sparc', 'hw/sparc64', @@ -3690,6 +3730,10 @@ subdir('accel') subdir('plugins') subdir('ebpf') +if 'CONFIG_TCG' in config_all_accel + subdir('contrib/plugins') +endif + common_user_inc = [] subdir('common-user') @@ -4590,6 +4634,7 @@ if nettle.found() summary_info += {' XTS': xts != 'private'} endif summary_info += {'SM4 ALG support': crypto_sm4} +summary_info += {'SM3 ALG support': crypto_sm3} summary_info += {'AF_ALG support': have_afalg} summary_info += {'rng-none': get_option('rng_none')} summary_info += {'Linux keyring': have_keyring} diff --git a/meson_options.txt b/meson_options.txt index 24bf009..ac4887a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -27,6 +27,8 @@ option('block_drv_ro_whitelist', type : 'string', value : '', description: 'set block driver read-only whitelist (by default affects only QEMU, not tools like qemu-img)') option('interp_prefix', type : 'string', value : '/usr/gnemul/qemu-%M', description: 'where to find shared libraries etc., use %M for cpu name') +option('rtsig_map', type : 'string', value : 'NULL', + description: 'default value of QEMU_RTSIG_MAP') option('fuzzing_engine', type : 'string', value : '', description: 'fuzzing engine library for OSS-Fuzz') option('trace_file', type: 'string', value: 'trace', diff --git a/qapi/crypto.json b/qapi/crypto.json index 9431522..c9d967d 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -55,11 +55,12 @@ # @sha512: SHA-512. (since 2.7) # # @ripemd160: RIPEMD-160. (since 2.7) +# @sm3: SM3. (since 9.2.0) # # Since: 2.6 ## { 'enum': 'QCryptoHashAlgo', - 'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160']} + 'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160', 'sm3']} ## # @QCryptoCipherAlgo: @@ -419,11 +420,6 @@ # # Properties for objects of classes derived from secret-common. # -# @loaded: if true, the secret is loaded immediately when applying -# this option and will probably fail when processing the next -# option. Don't use; only provided for compatibility. -# (default: false) -# # @format: the data format that the secret is provided in # (default: raw) # @@ -436,16 +432,10 @@ # 16-byte IV. Mandatory if @keyid is given. Ignored if @keyid is # absent. # -# Features: -# -# @deprecated: Member @loaded is deprecated. Setting true doesn't -# make sense, and false is already the default. -# # Since: 2.6 ## { 'struct': 'SecretCommonProperties', - 'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] }, - '*format': 'QCryptoSecretFormat', + 'data': { '*format': 'QCryptoSecretFormat', '*keyid': 'str', '*iv': 'str' } } @@ -512,58 +502,32 @@ # # Properties for tls-creds-anon objects. # -# @loaded: if true, the credentials are loaded immediately when -# applying this option and will ignore options that are processed -# later. Don't use; only provided for compatibility. -# (default: false) -# -# Features: -# -# @deprecated: Member @loaded is deprecated. Setting true doesn't -# make sense, and false is already the default. -# # Since: 2.5 ## { 'struct': 'TlsCredsAnonProperties', 'base': 'TlsCredsProperties', - 'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] } } } + 'data': { } } ## # @TlsCredsPskProperties: # # Properties for tls-creds-psk objects. # -# @loaded: if true, the credentials are loaded immediately when -# applying this option and will ignore options that are processed -# later. Don't use; only provided for compatibility. -# (default: false) -# # @username: the username which will be sent to the server. For # clients only. If absent, "qemu" is sent and the property will # read back as an empty string. # -# Features: -# -# @deprecated: Member @loaded is deprecated. Setting true doesn't -# make sense, and false is already the default. -# # Since: 3.0 ## { 'struct': 'TlsCredsPskProperties', 'base': 'TlsCredsProperties', - 'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] }, - '*username': 'str' } } + 'data': { '*username': 'str' } } ## # @TlsCredsX509Properties: # # Properties for tls-creds-x509 objects. # -# @loaded: if true, the credentials are loaded immediately when -# applying this option and will ignore options that are processed -# later. Don't use; only provided for compatibility. -# (default: false) -# # @sanity-check: if true, perform some sanity checks before using the # credentials (default: true) # @@ -573,17 +537,11 @@ # provides the ID of a previously created secret object containing # the password for decryption. # -# Features: -# -# @deprecated: Member @loaded is deprecated. Setting true doesn't -# make sense, and false is already the default. -# # Since: 2.5 ## { 'struct': 'TlsCredsX509Properties', 'base': 'TlsCredsProperties', - 'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] }, - '*sanity-check': 'bool', + 'data': { '*sanity-check': 'bool', '*passwordid': 'str' } } ## # @QCryptoAkCipherAlgo: diff --git a/qapi/qdev.json b/qapi/qdev.json index 53d147c..2a58112 100644 --- a/qapi/qdev.json +++ b/qapi/qdev.json @@ -163,3 +163,27 @@ ## { 'event': 'DEVICE_UNPLUG_GUEST_ERROR', 'data': { '*device': 'str', 'path': 'str' } } + +## +# @device-sync-config: +# +# Synchronize device configuration from host to guest part. First, +# copy the configuration from the host part (backend) to the guest +# part (frontend). Then notify guest software that device +# configuration changed. +# +# The command may be used to notify the guest about block device +# capcity change. Currently only vhost-user-blk device supports +# this. +# +# @id: the device's ID or QOM path +# +# Features: +# +# @unstable: The command is experimental. +# +# Since: 9.1 +## +{ 'command': 'device-sync-config', + 'features': [ 'unstable' ], + 'data': {'id': 'str'} } diff --git a/qapi/qom.json b/qapi/qom.json index 321ccd7..a8beeab 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -845,6 +845,45 @@ 'node': 'uint32' } } ## +# @AcpiGenericPortProperties: +# +# Properties for acpi-generic-port objects. +# +# @pci-bus: QOM path of the PCI bus of the hostbridge associated with +# this SRAT Generic Port Affinity Structure. This is the same as +# the bus parameter for the root ports attached to this host +# bridge. The resulting SRAT Generic Port Affinity Structure will +# refer to the ACPI object in DSDT that represents the host bridge +# (e.g. ACPI0016 for CXL host bridges). See ACPI 6.5 Section +# 5.2.16.7 for more information. +# +# @node: Similar to a NUMA node ID, but instead of providing a +# reference point used for defining NUMA distances and access +# characteristics to memory or from an initiator (e.g. CPU), this +# node defines the boundary point between non-discoverable system +# buses which must be described by firmware, and a discoverable +# bus. NUMA distances and access characteristics are defined to +# and from that point. For system software to establish full +# initiator to target characteristics this information must be +# combined with information retrieved from the discoverable part +# of the path. An example would use CDAT (see UEFI.org) +# information read from devices and switches in conjunction with +# link characteristics read from PCIe Configuration space. +# To get the full path latency from CPU to CXL attached DRAM +# CXL device: Add the latency from CPU to Generic Port (from +# HMAT indexed via the the node ID in this SRAT structure) to +# that for CXL bus links, the latency across intermediate switches +# and from the EP port to the actual memory. Bandwidth is more +# complex as there may be interleaving across multiple devices +# and shared links in the path. +# +# Since: 9.1 +## +{ 'struct': 'AcpiGenericPortProperties', + 'data': { 'pci-bus': 'str', + 'node': 'uint32' } } + +## # @RngProperties: # # Properties for objects of classes derived from rng. @@ -1043,6 +1082,7 @@ { 'enum': 'ObjectType', 'data': [ 'acpi-generic-initiator', + 'acpi-generic-port', 'authz-list', 'authz-listfile', 'authz-pam', @@ -1118,6 +1158,7 @@ 'discriminator': 'qom-type', 'data': { 'acpi-generic-initiator': 'AcpiGenericInitiatorProperties', + 'acpi-generic-port': 'AcpiGenericPortProperties', 'authz-list': 'AuthZListProperties', 'authz-listfile': 'AuthZListFileProperties', 'authz-pam': 'AuthZPAMProperties', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 6f2bb08..51ed46e 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -72,6 +72,7 @@ meson_options_help() { printf "%s\n" ' "manufacturer" name for qemu-ga registry entries' printf "%s\n" ' [QEMU]' printf "%s\n" ' --qemu-ga-version=VALUE version number for qemu-ga installer' + printf "%s\n" ' --rtsig-map=VALUE default value of QEMU_RTSIG_MAP [NULL]' printf "%s\n" ' --smbd=VALUE Path to smbd for slirp networking' printf "%s\n" ' --sysconfdir=VALUE Sysconf data directory [etc]' printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' @@ -460,6 +461,7 @@ _meson_option_parse() { --disable-replication) printf "%s" -Dreplication=disabled ;; --enable-rng-none) printf "%s" -Drng_none=true ;; --disable-rng-none) printf "%s" -Drng_none=false ;; + --rtsig-map=*) quote_sh "-Drtsig_map=$2" ;; --enable-rust) printf "%s" -Drust=enabled ;; --disable-rust) printf "%s" -Drust=disabled ;; --enable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=enabled ;; diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index 320c47b..d25325c 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -23,6 +23,7 @@ #include "monitor/monitor.h" #include "monitor/qdev.h" #include "sysemu/arch_init.h" +#include "sysemu/runstate.h" #include "qapi/error.h" #include "qapi/qapi-commands-qdev.h" #include "qapi/qmp/dispatch.h" @@ -885,13 +886,20 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) object_unref(OBJECT(dev)); } -static DeviceState *find_device_state(const char *id, Error **errp) +/* + * Note that creating new APIs using error classes other than GenericError is + * not recommended. Set use_generic_error=true for new interfaces. + */ +static DeviceState *find_device_state(const char *id, bool use_generic_error, + Error **errp) { Object *obj = object_resolve_path_at(qdev_get_peripheral(), id); DeviceState *dev; if (!obj) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + error_set(errp, + (use_generic_error ? + ERROR_CLASS_GENERIC_ERROR : ERROR_CLASS_DEVICE_NOT_FOUND), "Device '%s' not found", id); return NULL; } @@ -956,7 +964,7 @@ void qdev_unplug(DeviceState *dev, Error **errp) void qmp_device_del(const char *id, Error **errp) { - DeviceState *dev = find_device_state(id, errp); + DeviceState *dev = find_device_state(id, false, errp); if (dev != NULL) { if (dev->pending_deleted_event && (dev->pending_deleted_expires_ms == 0 || @@ -970,6 +978,43 @@ void qmp_device_del(const char *id, Error **errp) } } +int qdev_sync_config(DeviceState *dev, Error **errp) +{ + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (!dc->sync_config) { + error_setg(errp, "device-sync-config is not supported for '%s'", + object_get_typename(OBJECT(dev))); + return -ENOTSUP; + } + + return dc->sync_config(dev, errp); +} + +void qmp_device_sync_config(const char *id, Error **errp) +{ + DeviceState *dev; + + /* + * During migration there is a race between syncing`configuration + * and migrating it (if migrate first, that target would get + * outdated version), so let's just not allow it. + */ + + if (migration_is_running()) { + error_setg(errp, "Config synchronization is not allowed " + "during migration"); + return; + } + + dev = find_device_state(id, true, errp); + if (!dev) { + return; + } + + qdev_sync_config(dev, errp); +} + void hmp_device_add(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -1076,7 +1121,7 @@ BlockBackend *blk_by_qdev_id(const char *id, Error **errp) GLOBAL_STATE_CODE(); - dev = find_device_state(id, errp); + dev = find_device_state(id, false, errp); if (dev == NULL) { return NULL; } diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 9db1dff..5d75c94 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -24,6 +24,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat.h" static void alpha_cpu_set_pc(CPUState *cs, vaddr value) @@ -187,7 +188,17 @@ static void alpha_cpu_initfn(Object *obj) { CPUAlphaState *env = cpu_env(CPU(obj)); + /* TODO all this should be done in reset, not init */ + env->lock_addr = -1; + + /* + * TODO: this is incorrect. The Alpha Architecture Handbook version 4 + * describes NaN propagation in section 4.7.10.4. We should prefer + * the operand in Fb (whether it is a QNaN or an SNaN), then the + * operand in Fa. That is float_2nan_prop_ba. + */ + set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status); #if defined(CONFIG_USER_ONLY) env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN; cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 04ce281..e806f13 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -802,6 +802,11 @@ static inline bool isar_feature_aa64_tidcp1(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, TIDCP1) != 0; } +static inline bool isar_feature_aa64_cmow(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, CMOW) != 0; +} + static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5b75143..6938161 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -168,6 +168,18 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node); } +/* + * Set the float_status behaviour to match the Arm defaults: + * * tininess-before-rounding + * * 2-input NaN propagation prefers SNaN over QNaN, and then + * operand A over operand B (see FPProcessNaNs() pseudocode) + */ +static void arm_set_default_fp_behaviours(float_status *s) +{ + set_float_detect_tininess(float_tininess_before_rounding, s); + set_float_2nan_prop_rule(float_2nan_prop_s_ab, s); +} + static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) { /* Reset a single ARMCPRegInfo register */ @@ -549,14 +561,11 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type) set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status); set_default_nan_mode(1, &env->vfp.standard_fp_status); set_default_nan_mode(1, &env->vfp.standard_fp_status_f16); - set_float_detect_tininess(float_tininess_before_rounding, - &env->vfp.fp_status); - set_float_detect_tininess(float_tininess_before_rounding, - &env->vfp.standard_fp_status); - set_float_detect_tininess(float_tininess_before_rounding, - &env->vfp.fp_status_f16); - set_float_detect_tininess(float_tininess_before_rounding, - &env->vfp.standard_fp_status_f16); + arm_set_default_fp_behaviours(&env->vfp.fp_status); + arm_set_default_fp_behaviours(&env->vfp.standard_fp_status); + arm_set_default_fp_behaviours(&env->vfp.fp_status_f16); + arm_set_default_fp_behaviours(&env->vfp.standard_fp_status_f16); + #ifndef CONFIG_USER_ONLY if (kvm_enabled()) { kvm_arm_reset_vcpu(cpu); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 8fc8b63..d86e641 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1367,6 +1367,7 @@ void pmu_init(ARMCPU *cpu); #define SCTLR_EnIB (1U << 30) /* v8.3, AArch64 only */ #define SCTLR_EnIA (1U << 31) /* v8.3, AArch64 only */ #define SCTLR_DSSBS_32 (1U << 31) /* v8.5, AArch32 only */ +#define SCTLR_CMOW (1ULL << 32) /* FEAT_CMOW */ #define SCTLR_MSCEN (1ULL << 33) /* FEAT_MOPS */ #define SCTLR_BT0 (1ULL << 35) /* v8.5-BTI */ #define SCTLR_BT1 (1ULL << 36) /* v8.5-BTI */ @@ -2805,38 +2806,38 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); * The only use of stage 2 translations is either as part of an s1+2 * lookup or when loading the descriptors during a stage 1 page table walk, * and in both those cases we don't use the TLB. - * 4. we want to be able to use the TLB for accesses done as part of a + * 4. we can also safely fold together the "32 bit EL3" and "64 bit EL3" + * translation regimes, because they map reasonably well to each other + * and they can't both be active at the same time. + * 5. we want to be able to use the TLB for accesses done as part of a * stage1 page table walk, rather than having to walk the stage2 page * table over and over. - * 5. we need separate EL1/EL2 mmu_idx for handling the Privileged Access + * 6. we need separate EL1/EL2 mmu_idx for handling the Privileged Access * Never (PAN) bit within PSTATE. - * 6. we fold together most secure and non-secure regimes for A-profile, + * 7. we fold together most secure and non-secure regimes for A-profile, * because there are no banked system registers for aarch64, so the * process of switching between secure and non-secure is * already heavyweight. - * 7. we cannot fold together Stage 2 Secure and Stage 2 NonSecure, + * 8. we cannot fold together Stage 2 Secure and Stage 2 NonSecure, * because both are in use simultaneously for Secure EL2. * * This gives us the following list of cases: * - * EL0 EL1&0 stage 1+2 (or AArch32 PL0 PL1&0 stage 1+2) - * EL1 EL1&0 stage 1+2 (or AArch32 PL1 PL1&0 stage 1+2) - * EL1 EL1&0 stage 1+2 +PAN (or AArch32 PL1 PL1&0 stage 1+2 +PAN) + * EL0 EL1&0 stage 1+2 (aka NS PL0 PL1&0 stage 1+2) + * EL1 EL1&0 stage 1+2 (aka NS PL1 PL1&0 stage 1+2) + * EL1 EL1&0 stage 1+2 +PAN (aka NS PL1 P1&0 stage 1+2 +PAN) * EL0 EL2&0 * EL2 EL2&0 * EL2 EL2&0 +PAN * EL2 (aka NS PL2) - * EL3 (not used when EL3 is AArch32) + * EL3 (aka AArch32 S PL1 PL1&0) + * AArch32 S PL0 PL1&0 (we call this EL30_0) + * AArch32 S PL1 PL1&0 +PAN (we call this EL30_3_PAN) * Stage2 Secure * Stage2 NonSecure * plus one TLB per Physical address space: S, NS, Realm, Root * - * for a total of 14 different mmu_idx. - * - * Note that when EL3 is AArch32, the usage is potentially confusing - * because the MMU indexes are named for their AArch64 use, so code - * using the ARMMMUIdx_E10_1 might be at EL3, not EL1. This is because - * Secure PL1 is always at EL3. + * for a total of 16 different mmu_idx. * * R profile CPUs have an MPU, but can use the same set of MMU indexes * as A profile. They only need to distinguish EL0 and EL1 (and @@ -2900,6 +2901,8 @@ typedef enum ARMMMUIdx { ARMMMUIdx_E20_2_PAN = 5 | ARM_MMU_IDX_A, ARMMMUIdx_E2 = 6 | ARM_MMU_IDX_A, ARMMMUIdx_E3 = 7 | ARM_MMU_IDX_A, + ARMMMUIdx_E30_0 = 8 | ARM_MMU_IDX_A, + ARMMMUIdx_E30_3_PAN = 9 | ARM_MMU_IDX_A, /* * Used for second stage of an S12 page table walk, or for descriptor @@ -2907,14 +2910,14 @@ typedef enum ARMMMUIdx { * are in use simultaneously for SecureEL2: the security state for * the S2 ptw is selected by the NS bit from the S1 ptw. */ - ARMMMUIdx_Stage2_S = 8 | ARM_MMU_IDX_A, - ARMMMUIdx_Stage2 = 9 | ARM_MMU_IDX_A, + ARMMMUIdx_Stage2_S = 10 | ARM_MMU_IDX_A, + ARMMMUIdx_Stage2 = 11 | ARM_MMU_IDX_A, /* TLBs with 1-1 mapping to the physical address spaces. */ - ARMMMUIdx_Phys_S = 10 | ARM_MMU_IDX_A, - ARMMMUIdx_Phys_NS = 11 | ARM_MMU_IDX_A, - ARMMMUIdx_Phys_Root = 12 | ARM_MMU_IDX_A, - ARMMMUIdx_Phys_Realm = 13 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_S = 12 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_NS = 13 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_Root = 14 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_Realm = 15 | ARM_MMU_IDX_A, /* * These are not allocated TLBs and are used only for AT system @@ -2953,6 +2956,8 @@ typedef enum ARMMMUIdxBit { TO_CORE_BIT(E20_2), TO_CORE_BIT(E20_2_PAN), TO_CORE_BIT(E3), + TO_CORE_BIT(E30_0), + TO_CORE_BIT(E30_3_PAN), TO_CORE_BIT(Stage2), TO_CORE_BIT(Stage2_S), @@ -3130,10 +3135,6 @@ FIELD(TBFLAG_A32, NS, 10, 1) * This requires an SME trap from AArch32 mode when using NEON. */ FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1) -/* - * Indicates whether we are in the Secure PL1&0 translation regime - */ -FIELD(TBFLAG_A32, S_PL1_0, 12, 1) /* * Bit usage when in AArch32 state, for M-profile only. diff --git a/target/arm/helper.c b/target/arm/helper.c index 0a731a3..f38eb05 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -444,6 +444,9 @@ static int alle1_tlbmask(CPUARMState *env) * Note that the 'ALL' scope must invalidate both stage 1 and * stage 2 translations, whereas most other scopes only invalidate * stage 1 translations. + * + * For AArch32 this is only used for TLBIALLNSNH and VTTBR + * writes, so only needs to apply to NS PL1&0, not S PL1&0. */ return (ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_1_PAN | @@ -3701,7 +3704,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, */ format64 = arm_s1_regime_using_lpae_format(env, mmu_idx); - if (arm_feature(env, ARM_FEATURE_EL2) && !arm_aa32_secure_pl1_0(env)) { + if (arm_feature(env, ARM_FEATURE_EL2)) { if (mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_E10_1 || mmu_idx == ARMMMUIdx_E10_1_PAN) { @@ -3775,11 +3778,17 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) case 0: /* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */ switch (el) { + case 3: + if (ri->crm == 9 && arm_pan_enabled(env)) { + mmu_idx = ARMMMUIdx_E30_3_PAN; + } else { + mmu_idx = ARMMMUIdx_E3; + } + break; case 2: g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */ /* fall through */ case 1: - case 3: if (ri->crm == 9 && arm_pan_enabled(env)) { mmu_idx = ARMMMUIdx_Stage1_E1_PAN; } else { @@ -3794,7 +3803,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) /* stage 1 current state PL0: ATS1CUR, ATS1CUW */ switch (el) { case 3: - mmu_idx = ARMMMUIdx_E10_0; + mmu_idx = ARMMMUIdx_E30_0; break; case 2: g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */ @@ -4904,11 +4913,14 @@ static int vae1_tlbmask(CPUARMState *env) uint64_t hcr = arm_hcr_el2_eff(env); uint16_t mask; + assert(arm_feature(env, ARM_FEATURE_AARCH64)); + if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { mask = ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_E20_2_PAN | ARMMMUIdxBit_E20_0; } else { + /* This is AArch64 only, so we don't need to touch the EL30_x TLBs */ mask = ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_1_PAN | ARMMMUIdxBit_E10_0; @@ -4947,6 +4959,8 @@ static int vae1_tlbbits(CPUARMState *env, uint64_t addr) uint64_t hcr = arm_hcr_el2_eff(env); ARMMMUIdx mmu_idx; + assert(arm_feature(env, ARM_FEATURE_AARCH64)); + /* Only the regime of the mmu_idx below is significant. */ if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { mmu_idx = ARMMMUIdx_E20_0; @@ -6215,6 +6229,11 @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri, if (cpu_isar_feature(aa64_nmi, cpu)) { valid_mask |= HCRX_TALLINT | HCRX_VINMI | HCRX_VFNMI; } + /* FEAT_CMOW adds CMOW */ + + if (cpu_isar_feature(aa64_cmow, cpu)) { + valid_mask |= HCRX_CMOW; + } /* Clear RES0 bits. */ env->cp15.hcrx_el2 = value & valid_mask; @@ -11860,13 +11879,20 @@ void arm_cpu_do_interrupt(CPUState *cs) uint64_t arm_sctlr(CPUARMState *env, int el) { - if (arm_aa32_secure_pl1_0(env)) { - /* In Secure PL1&0 SCTLR_S is always controlling */ - el = 3; - } else if (el == 0) { - /* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */ + /* Only EL0 needs to be adjusted for EL1&0 or EL2&0 or EL3&0 */ + if (el == 0) { ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0); - el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1; + switch (mmu_idx) { + case ARMMMUIdx_E20_0: + el = 2; + break; + case ARMMMUIdx_E30_0: + el = 3; + break; + default: + el = 1; + break; + } } return env->cp15.sctlr_el[el]; } @@ -12524,12 +12550,8 @@ int fp_exception_el(CPUARMState *env, int cur_el) return 0; } -/* - * Return the exception level we're running at if this is our mmu_idx. - * s_pl1_0 should be true if this is the AArch32 Secure PL1&0 translation - * regime. - */ -int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0) +/* Return the exception level we're running at if this is our mmu_idx */ +int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) { if (mmu_idx & ARM_MMU_IDX_M) { return mmu_idx & ARM_MMU_IDX_M_PRIV; @@ -12538,15 +12560,17 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0) switch (mmu_idx) { case ARMMMUIdx_E10_0: case ARMMMUIdx_E20_0: + case ARMMMUIdx_E30_0: return 0; case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1_PAN: - return s_pl1_0 ? 3 : 1; + return 1; case ARMMMUIdx_E2: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: return 2; case ARMMMUIdx_E3: + case ARMMMUIdx_E30_3_PAN: return 3; default: g_assert_not_reached(); @@ -12575,19 +12599,13 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) hcr = arm_hcr_el2_eff(env); if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { idx = ARMMMUIdx_E20_0; + } else if (arm_is_secure_below_el3(env) && + !arm_el_is_aa64(env, 3)) { + idx = ARMMMUIdx_E30_0; } else { idx = ARMMMUIdx_E10_0; } break; - case 3: - /* - * AArch64 EL3 has its own translation regime; AArch32 EL3 - * uses the Secure PL1&0 translation regime. - */ - if (arm_el_is_aa64(env, 3)) { - return ARMMMUIdx_E3; - } - /* fall through */ case 1: if (arm_pan_enabled(env)) { idx = ARMMMUIdx_E10_1_PAN; @@ -12607,6 +12625,11 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) idx = ARMMMUIdx_E2; } break; + case 3: + if (!arm_el_is_aa64(env, 3) && arm_pan_enabled(env)) { + return ARMMMUIdx_E30_3_PAN; + } + return ARMMMUIdx_E3; default: g_assert_not_reached(); } diff --git a/target/arm/internals.h b/target/arm/internals.h index fd8f7c8..e37f459 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -276,20 +276,6 @@ FIELD(CNTHCTL, CNTPMASK, 19, 1) #define M_FAKE_FSR_SFAULT 0xe /* SecureFault INVTRAN, INVEP or AUVIOL */ /** - * arm_aa32_secure_pl1_0(): Return true if in Secure PL1&0 regime - * - * Return true if the CPU is in the Secure PL1&0 translation regime. - * This requires that EL3 exists and is AArch32 and we are currently - * Secure. If this is the case then the ARMMMUIdx_E10* apply and - * mean we are in EL3, not EL1. - */ -static inline bool arm_aa32_secure_pl1_0(CPUARMState *env) -{ - return arm_feature(env, ARM_FEATURE_EL3) && - !arm_el_is_aa64(env, 3) && arm_is_secure(env); -} - -/** * raise_exception: Raise the specified exception. * Raise a guest exception with the specified value, syndrome register * and target exception level. This should be called from helper functions, @@ -841,12 +827,7 @@ static inline ARMMMUIdx core_to_aa64_mmu_idx(int mmu_idx) return mmu_idx | ARM_MMU_IDX_A; } -/** - * Return the exception level we're running at if our current MMU index - * is @mmu_idx. @s_pl1_0 should be true if this is the AArch32 - * Secure PL1&0 translation regime. - */ -int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0); +int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx); /* Return the MMU index for a v7M CPU in the specified security state */ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate); @@ -890,7 +871,16 @@ static inline void arm_call_el_change_hook(ARMCPU *cpu) } } -/* Return true if this address translation regime has two ranges. */ +/* + * Return true if this address translation regime has two ranges. + * Note that this will not return the correct answer for AArch32 + * Secure PL1&0 (i.e. mmu indexes E3, E30_0, E30_3_PAN), but it is + * never called from a context where EL3 can be AArch32. (The + * correct return value for ARMMMUIdx_E3 would be different for + * that case, so we can't just make the function return the + * correct value anyway; we would need an extra "bool e3_is_aarch32" + * argument which all the current callsites would pass as 'false'.) + */ static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx) { switch (mmu_idx) { @@ -915,6 +905,7 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_Stage1_E1_PAN: case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_E20_2_PAN: + case ARMMMUIdx_E30_3_PAN: return true; default: return false; @@ -938,14 +929,15 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_E2: return 2; case ARMMMUIdx_E3: + case ARMMMUIdx_E30_0: + case ARMMMUIdx_E30_3_PAN: return 3; case ARMMMUIdx_E10_0: case ARMMMUIdx_Stage1_E0: - case ARMMMUIdx_E10_1: - case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_Stage1_E1: case ARMMMUIdx_Stage1_E1_PAN: - return arm_el_is_aa64(env, 3) || !arm_is_secure_below_el3(env) ? 1 : 3; + case ARMMMUIdx_E10_1: + case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_MPrivNegPri: case ARMMMUIdx_MUserNegPri: case ARMMMUIdx_MPriv: @@ -965,6 +957,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) switch (mmu_idx) { case ARMMMUIdx_E10_0: case ARMMMUIdx_E20_0: + case ARMMMUIdx_E30_0: case ARMMMUIdx_Stage1_E0: case ARMMMUIdx_MUser: case ARMMMUIdx_MSUser: diff --git a/target/arm/ptw.c b/target/arm/ptw.c index dd40268..9849949 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -280,6 +280,8 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx, case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E2: case ARMMMUIdx_E3: + case ARMMMUIdx_E30_0: + case ARMMMUIdx_E30_3_PAN: break; case ARMMMUIdx_Phys_S: @@ -3607,11 +3609,7 @@ bool get_phys_addr(CPUARMState *env, vaddr address, case ARMMMUIdx_Stage1_E1: case ARMMMUIdx_Stage1_E1_PAN: case ARMMMUIdx_E2: - if (arm_aa32_secure_pl1_0(env)) { - ss = ARMSS_Secure; - } else { - ss = arm_security_space_below_el3(env); - } + ss = arm_security_space_below_el3(env); break; case ARMMMUIdx_Stage2: /* @@ -3639,6 +3637,8 @@ bool get_phys_addr(CPUARMState *env, vaddr address, ss = ARMSS_Secure; break; case ARMMMUIdx_E3: + case ARMMMUIdx_E30_0: + case ARMMMUIdx_E30_3_PAN: if (arm_feature(env, ARM_FEATURE_AARCH64) && cpu_isar_feature(aa64_rme, env_archcpu(env))) { ss = ARMSS_Root; diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 0168920..2963d75 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -1218,6 +1218,7 @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 2); /* FEAT_ETS2 */ t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ t = FIELD_DP64(t, ID_AA64MMFR1, TIDCP1, 1); /* FEAT_TIDCP1 */ + t = FIELD_DP64(t, ID_AA64MMFR1, CMOW, 1); /* FEAT_CMOW */ cpu->isar.id_aa64mmfr1 = t; t = cpu->isar.id_aa64mmfr2; diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index bab7822..f03977b 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -198,10 +198,6 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, DP_TBFLAG_A32(flags, SME_TRAP_NONSTREAMING, 1); } - if (arm_aa32_secure_pl1_0(env)) { - DP_TBFLAG_A32(flags, S_PL1_0, 1); - } - return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); } diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index c083e5c..1ecb465 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -912,7 +912,19 @@ void HELPER(tidcp_el0)(CPUARMState *env, uint32_t syndrome) { /* See arm_sctlr(), but we also need the sctlr el. */ ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0); - int target_el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1; + int target_el; + + switch (mmu_idx) { + case ARMMMUIdx_E20_0: + target_el = 2; + break; + case ARMMMUIdx_E30_0: + target_el = 3; + break; + default: + target_el = 1; + break; + } /* * The bit is not valid unless the target el is aa64, but since the diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index ec0b1ee..b2851ea 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -11690,7 +11690,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->tbii = EX_TBFLAG_A64(tb_flags, TBII); dc->tbid = EX_TBFLAG_A64(tb_flags, TBID); dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA); - dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx, false); + dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); #if !defined(CONFIG_USER_ONLY) dc->user = (dc->current_el == 0); #endif diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index e2748ff..9ee761f 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -228,6 +228,9 @@ static inline int get_a32_user_mem_index(DisasContext *s) */ switch (s->mmu_idx) { case ARMMMUIdx_E3: + case ARMMMUIdx_E30_0: + case ARMMMUIdx_E30_3_PAN: + return arm_to_core_mmu_idx(ARMMMUIdx_E30_0); case ARMMMUIdx_E2: /* this one is UNPREDICTABLE */ case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_1: @@ -7546,6 +7549,10 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX); dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx); + dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); +#if !defined(CONFIG_USER_ONLY) + dc->user = (dc->current_el == 0); +#endif dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); @@ -7576,12 +7583,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) } dc->sme_trap_nonstreaming = EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING); - dc->s_pl1_0 = EX_TBFLAG_A32(tb_flags, S_PL1_0); } - dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx, dc->s_pl1_0); -#if !defined(CONFIG_USER_ONLY) - dc->user = (dc->current_el == 0); -#endif dc->lse2 = false; /* applies only to aarch64 */ dc->cp_regs = cpu->cp_regs; dc->features = env->features; diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index 5a2e10d..20cd0e8 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -165,8 +165,6 @@ typedef struct DisasContext { uint8_t gm_blocksize; /* True if the current insn_start has been updated. */ bool insn_start_updated; - /* True if this is the AArch32 Secure PL1&0 translation regime */ - bool s_pl1_0; /* Bottom two bits of XScale c15_cpar coprocessor access control reg */ int c15_cpar; /* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */ diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index 22ddb96..e825d50 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -836,6 +836,13 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \ { \ intptr_t i = 0, opr_sz = simd_oprsz(desc); \ intptr_t opr_sz_n = opr_sz / sizeof(TYPED); \ + /* \ + * Special case: opr_sz == 8 from AA64/AA32 advsimd means the \ + * first iteration might not be a full 16 byte segment. But \ + * for vector lengths beyond that this must be SVE and we know \ + * opr_sz is a multiple of 16, so we need not clamp segend \ + * to opr_sz_n when we advance it at the end of the loop. \ + */ \ intptr_t segend = MIN(16 / sizeof(TYPED), opr_sz_n); \ intptr_t index = simd_data(desc); \ TYPED *d = vd, *a = va; \ @@ -853,7 +860,7 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \ n[i * 4 + 2] * m2 + \ n[i * 4 + 3] * m3); \ } while (++i < segend); \ - segend = i + 4; \ + segend = i + (16 / sizeof(TYPED)); \ } while (i < opr_sz_n); \ clear_tail(d, opr_sz, simd_maxsz(desc)); \ } diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c index deaed2b..0e44074 100644 --- a/target/hppa/fpu_helper.c +++ b/target/hppa/fpu_helper.c @@ -49,6 +49,12 @@ void HELPER(loaded_fr0)(CPUHPPAState *env) d = FIELD_EX32(shadow, FPSR, D); set_flush_to_zero(d, &env->fp_status); set_flush_inputs_to_zero(d, &env->fp_status); + + /* + * TODO: we only need to do this at CPU reset, but currently + * HPPA does note implement a CPU reset method at all... + */ + set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status); } void cpu_hppa_loaded_fr0(CPUHPPAState *env) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index d46710a..58c96ea 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -7203,6 +7203,10 @@ static void x86_cpu_reset_hold(Object *obj, ResetType type) memset(env, 0, offsetof(CPUX86State, end_reset_fields)); + if (tcg_enabled()) { + cpu_init_fp_statuses(env); + } + env->old_exception = -1; /* init to reset state */ diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 00b23bc..b65eedb 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2614,6 +2614,9 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env) int get_pg_mode(CPUX86State *env); /* fpu_helper.c */ + +/* Set all non-runtime-variable float_status fields to x86 handling */ +void cpu_init_fp_statuses(CPUX86State *env); void update_fp_status(CPUX86State *env); void update_mxcsr_status(CPUX86State *env); void update_mxcsr_from_sse_status(CPUX86State *env); diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index e1b850f..53b49bb 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -135,6 +135,46 @@ static void fpu_set_exception(CPUX86State *env, int mask) } } +void cpu_init_fp_statuses(CPUX86State *env) +{ + /* + * Initialise the non-runtime-varying fields of the various + * float_status words to x86 behaviour. This must be called at + * CPU reset because the float_status words are in the + * "zeroed on reset" portion of the CPU state struct. + * Fields in float_status that vary under guest control are set + * via the codepath for setting that register, eg cpu_set_fpuc(). + */ + /* + * Use x87 NaN propagation rules: + * SNaN + QNaN => return the QNaN + * two SNaNs => return the one with the larger significand, silenced + * two QNaNs => return the one with the larger significand + * SNaN and a non-NaN => return the SNaN, silenced + * QNaN and a non-NaN => return the QNaN + * + * If we get down to comparing significands and they are the same, + * return the NaN with the positive sign bit (if any). + */ + set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status); + /* + * TODO: These are incorrect: the x86 Software Developer's Manual vol 1 + * section 4.8.3.5 "Operating on SNaNs and QNaNs" says that the + * "larger significand" behaviour is only used for x87 FPU operations. + * For SSE the required behaviour is to always return the first NaN, + * which is float_2nan_prop_ab. + * + * mmx_status is used only for the AMD 3DNow! instructions, which + * are documented in the "3DNow! Technology Manual" as not supporting + * NaNs or infinities as inputs. The result of passing two NaNs is + * documented as "undefined", so we can do what we choose. + * (Strictly there is some behaviour we don't implement correctly + * for these "unsupported" NaN and Inf values, like "NaN * 0 == 0".) + */ + set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status); + set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status); +} + static inline uint8_t save_exception_flags(CPUX86State *env) { uint8_t old_flags = get_float_exception_flags(&env->fp_status); diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c index f6753c5..21bc3b0 100644 --- a/target/loongarch/tcg/fpu_helper.c +++ b/target/loongarch/tcg/fpu_helper.c @@ -31,6 +31,7 @@ void restore_fp_status(CPULoongArchState *env) set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], &env->fp_status); set_flush_to_zero(0, &env->fp_status); + set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status); } int ieee_ex_to_loongarch(int xcpt) diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 1d49f4c..5fe3355 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -93,6 +93,22 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type) env->fregs[i].d = nan; } cpu_m68k_set_fpcr(env, 0); + /* + * M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL + * 3.4 FLOATING-POINT INSTRUCTION DETAILS + * If either operand, but not both operands, of an operation is a + * nonsignaling NaN, then that NaN is returned as the result. If both + * operands are nonsignaling NaNs, then the destination operand + * nonsignaling NaN is returned as the result. + * If either operand to an operation is a signaling NaN (SNaN), then the + * SNaN bit is set in the FPSR EXC byte. If the SNaN exception enable bit + * is set in the FPCR ENABLE byte, then the exception is taken and the + * destination is not modified. If the SNaN exception enable bit is not + * set, setting the SNaN bit in the operand to a one converts the SNaN to + * a nonsignaling NaN. The operation then continues as described in the + * preceding paragraph for nonsignaling NaNs. + */ + set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status); env->fpsr = 0; /* TODO: We should set PC from the interrupt vector. */ diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 8314791..a605162 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -620,6 +620,7 @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) int sign; /* Calculate quotient directly using round to nearest mode */ + set_float_2nan_prop_rule(float_2nan_prop_ab, &fp_status); set_float_rounding_mode(float_round_nearest_even, &fp_status); set_floatx80_rounding_precision( get_floatx80_rounding_precision(&env->fp_status), &fp_status); diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 9d3db84..9bfc6ae 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -36,7 +36,7 @@ static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n) CPUM68KState *env = &cpu->env; if (n < 8) { - float_status s; + float_status s = {}; return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); } switch (n) { @@ -56,7 +56,7 @@ static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n) CPUM68KState *env = &cpu->env; if (n < 8) { - float_status s; + float_status s = {}; env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s); return 8; } diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index b322f06..710eb11 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -201,6 +201,13 @@ static void mb_cpu_reset_hold(Object *obj, ResetType type) env->pc = cpu->cfg.base_vectors; + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + /* + * TODO: this is probably not the correct NaN propagation rule for + * this architecture. + */ + set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status); + #if defined(CONFIG_USER_ONLY) /* start in user mode with interrupts enabled. */ mb_cpu_write_msr(env, MSR_EE | MSR_IE | MSR_VM | MSR_UM); @@ -311,15 +318,12 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) static void mb_cpu_initfn(Object *obj) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); - CPUMBState *env = &cpu->env; gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect, mb_cpu_gdb_write_stack_protect, gdb_find_static_feature("microblaze-stack-protect.xml"), 0); - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - #ifndef CONFIG_USER_ONLY /* Inbound IRQ and FIR lines */ qdev_init_gpio_in(DEVICE(cpu), microblaze_cpu_set_irq, 2); diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 9724e71..d0a43b6 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -407,9 +407,9 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type) } msa_reset(env); + fp_reset(env); compute_hflags(env); - restore_fp_status(env); restore_pamask(env); cs->exception_index = EXCP_NONE; diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h index ad1116e..7c3c789 100644 --- a/target/mips/fpu_helper.h +++ b/target/mips/fpu_helper.h @@ -44,6 +44,28 @@ static inline void restore_fp_status(CPUMIPSState *env) restore_snan_bit_mode(env); } +static inline void fp_reset(CPUMIPSState *env) +{ + restore_fp_status(env); + + /* + * According to MIPS specifications, if one of the two operands is + * a sNaN, a new qNaN has to be generated. This is done in + * floatXX_silence_nan(). For qNaN inputs the specifications + * says: "When possible, this QNaN result is one of the operand QNaN + * values." In practice it seems that most implementations choose + * the first operand if both operands are qNaN. In short this gives + * the following rules: + * 1. A if it is signaling + * 2. B if it is signaling + * 3. A (quiet) + * 4. B (quiet) + * A signaling NaN is always silenced before returning it. + */ + set_float_2nan_prop_rule(float_2nan_prop_s_ab, + &env->active_fpu.fp_status); +} + /* MSA */ enum CPUMIPSMSADataFormat { diff --git a/target/mips/msa.c b/target/mips/msa.c index 61f1a9a..9dffc42 100644 --- a/target/mips/msa.c +++ b/target/mips/msa.c @@ -49,6 +49,23 @@ void msa_reset(CPUMIPSState *env) set_float_detect_tininess(float_tininess_after_rounding, &env->active_tc.msa_fp_status); + /* + * According to MIPS specifications, if one of the two operands is + * a sNaN, a new qNaN has to be generated. This is done in + * floatXX_silence_nan(). For qNaN inputs the specifications + * says: "When possible, this QNaN result is one of the operand QNaN + * values." In practice it seems that most implementations choose + * the first operand if both operands are qNaN. In short this gives + * the following rules: + * 1. A if it is signaling + * 2. B if it is signaling + * 3. A (quiet) + * 4. B (quiet) + * A signaling NaN is always silenced before returning it. + */ + set_float_2nan_prop_rule(float_2nan_prop_s_ab, + &env->active_tc.msa_fp_status); + /* clear float_status exception flags */ set_float_exception_flags(0, &env->active_tc.msa_fp_status); diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 6ec54ad..b96561d 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -105,6 +105,12 @@ static void openrisc_cpu_reset_hold(Object *obj, ResetType type) set_float_detect_tininess(float_tininess_before_rounding, &cpu->env.fp_status); + /* + * TODO: this is probably not the correct NaN propagation rule for + * this architecture. + */ + set_float_2nan_prop_rule(float_2nan_prop_x87, &cpu->env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x00000000; diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 6f35255..efcb80d 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7262,6 +7262,14 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type) /* tininess for underflow is detected before rounding */ set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); + /* + * PowerPC propagation rules: + * 1. A if it sNaN or qNaN + * 2. B if it sNaN or qNaN + * A signaling NaN is always silenced before returning it. + */ + set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status); + set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status); for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { ppc_spr_t *spr = &env->spr_cb[i]; diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 36d2a6f..65a74ce 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -93,6 +93,13 @@ static void rx_cpu_reset_hold(Object *obj, ResetType type) env->fpsw = 0; set_flush_to_zero(1, &env->fp_status); set_flush_inputs_to_zero(1, &env->fp_status); + /* + * TODO: this is not the correct NaN propagation rule for this + * architecture. The "RX Family User's Manual: Software" table 1.6 + * defines the propagation rules as "prefer SNaN over QNaN; + * then prefer dest over source", which is float_2nan_prop_s_ab. + */ + set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status); } static ObjectClass *rx_cpu_class_by_name(const char *cpu_model) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 4e41a3d..514c70f 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -205,6 +205,7 @@ static void s390_cpu_reset_hold(Object *obj, ResetType type) /* tininess for underflow is detected before rounding */ set_float_detect_tininess(float_tininess_before_rounding, &env->fpu_status); + set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status); /* fall through */ case RESET_TYPE_S390_CPU_NORMAL: env->psw.mask &= ~PSW_MASK_RI; diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 54cb269..dd7af86 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -26,6 +26,7 @@ #include "hw/qdev-properties.h" #include "qapi/visitor.h" #include "tcg/tcg.h" +#include "fpu/softfloat.h" //#define DEBUG_FEATURES @@ -76,6 +77,7 @@ static void sparc_cpu_reset_hold(Object *obj, ResetType type) env->npc = env->pc + 4; #endif env->cache_control = 0; + cpu_put_fsr(env, 0); } #ifndef CONFIG_USER_ONLY @@ -805,7 +807,13 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) env->version |= env->def.maxtl << 8; env->version |= env->def.nwindows - 1; #endif - cpu_put_fsr(env, 0); + + /* + * Prefer SNaN over QNaN, order B then A. It's OK to do this in realize + * rather than reset, because fp_status is after 'end_reset_fields' in + * the CPU state struct so it won't get zeroed on reset. + */ + set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status); cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c index b669238..6f9ccc0 100644 --- a/target/sparc/fop_helper.c +++ b/target/sparc/fop_helper.c @@ -497,7 +497,10 @@ uint32_t helper_flcmps(float32 src1, float32 src2) * Perform the comparison with a dummy fp environment. */ float_status discard = { }; - FloatRelation r = float32_compare_quiet(src1, src2, &discard); + FloatRelation r; + + set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard); + r = float32_compare_quiet(src1, src2, &discard); switch (r) { case float_relation_equal: @@ -518,7 +521,10 @@ uint32_t helper_flcmps(float32 src1, float32 src2) uint32_t helper_flcmpd(float64 src1, float64 src2) { float_status discard = { }; - FloatRelation r = float64_compare_quiet(src1, src2, &discard); + FloatRelation r; + + set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard); + r = float64_compare_quiet(src1, src2, &discard); switch (r) { case float_relation_equal: diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index a08c7a0..6f9039a 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -134,7 +134,7 @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type) cs->halted = env->runstall; #endif set_no_signaling_nans(!dfpu, &env->fp_status); - set_use_first_nan(!dfpu, &env->fp_status); + xtensa_use_first_nan(env, !dfpu); } static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 9f2341d..77e48ee 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -802,4 +802,10 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc, XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk); +/* + * Set the NaN propagation rule for future FPU operations: + * use_first is true to pick the first NaN as the result if both + * inputs are NaNs, false to pick the second. + */ +void xtensa_use_first_nan(CPUXtensaState *env, bool use_first); #endif diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c index 381e83d..f2d212d 100644 --- a/target/xtensa/fpu_helper.c +++ b/target/xtensa/fpu_helper.c @@ -57,6 +57,13 @@ static const struct { { XTENSA_FP_V, float_flag_invalid, }, }; +void xtensa_use_first_nan(CPUXtensaState *env, bool use_first) +{ + set_use_first_nan(use_first, &env->fp_status); + set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba, + &env->fp_status); +} + void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v) { static const int rounding_mode[] = { @@ -171,87 +178,87 @@ float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env, float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b) { - set_use_first_nan(true, &env->fp_status); + xtensa_use_first_nan(env, true); return float64_add(a, b, &env->fp_status); } float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float32_add(a, b, &env->fp_status); } float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b) { - set_use_first_nan(true, &env->fp_status); + xtensa_use_first_nan(env, true); return float64_sub(a, b, &env->fp_status); } float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float32_sub(a, b, &env->fp_status); } float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b) { - set_use_first_nan(true, &env->fp_status); + xtensa_use_first_nan(env, true); return float64_mul(a, b, &env->fp_status); } float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float32_mul(a, b, &env->fp_status); } float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float64_muladd(b, c, a, 0, &env->fp_status); } float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float32_muladd(b, c, a, 0, &env->fp_status); } float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float64_muladd(b, c, a, float_muladd_negate_product, &env->fp_status); } float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float32_muladd(b, c, a, float_muladd_negate_product, &env->fp_status); } float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b) { - set_use_first_nan(true, &env->fp_status); + xtensa_use_first_nan(env, true); return float64_div(b, a, &env->fp_status); } float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float32_div(b, a, &env->fp_status); } float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v) { - set_use_first_nan(true, &env->fp_status); + xtensa_use_first_nan(env, true); return float64_sqrt(v, &env->fp_status); } float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v) { - set_use_first_nan(env->config->use_first_nan, &env->fp_status); + xtensa_use_first_nan(env, env->config->use_first_nan); return float32_sqrt(v, &env->fp_status); } diff --git a/tests/data/acpi/disassemle-aml.sh b/tests/data/acpi/disassemle-aml.sh index 253b762..89561d2 100755 --- a/tests/data/acpi/disassemle-aml.sh +++ b/tests/data/acpi/disassemle-aml.sh @@ -14,7 +14,7 @@ while getopts "o:" arg; do esac done -for machine in tests/data/acpi/* +for machine in tests/data/acpi/*/* do if [[ ! -d "$machine" ]]; then diff --git a/tests/data/acpi/x86/pc/DSDT b/tests/data/acpi/x86/pc/DSDT Binary files differindex 9222523..f68a32e 100644 --- a/tests/data/acpi/x86/pc/DSDT +++ b/tests/data/acpi/x86/pc/DSDT diff --git a/tests/data/acpi/x86/pc/DSDT.acpierst b/tests/data/acpi/x86/pc/DSDT.acpierst Binary files differindex 25b3995..0fd7969 100644 --- a/tests/data/acpi/x86/pc/DSDT.acpierst +++ b/tests/data/acpi/x86/pc/DSDT.acpierst diff --git a/tests/data/acpi/x86/pc/DSDT.acpihmat b/tests/data/acpi/x86/pc/DSDT.acpihmat Binary files differindex 73a9ce5..a4dd09e 100644 --- a/tests/data/acpi/x86/pc/DSDT.acpihmat +++ b/tests/data/acpi/x86/pc/DSDT.acpihmat diff --git a/tests/data/acpi/x86/pc/DSDT.bridge b/tests/data/acpi/x86/pc/DSDT.bridge Binary files differindex 4cef454..7ef5815 100644 --- a/tests/data/acpi/x86/pc/DSDT.bridge +++ b/tests/data/acpi/x86/pc/DSDT.bridge diff --git a/tests/data/acpi/x86/pc/DSDT.cphp b/tests/data/acpi/x86/pc/DSDT.cphp Binary files differindex 1dc9283..1079ff8 100644 --- a/tests/data/acpi/x86/pc/DSDT.cphp +++ b/tests/data/acpi/x86/pc/DSDT.cphp diff --git a/tests/data/acpi/x86/pc/DSDT.dimmpxm b/tests/data/acpi/x86/pc/DSDT.dimmpxm Binary files differindex 9f71d2e..34fe3fc 100644 --- a/tests/data/acpi/x86/pc/DSDT.dimmpxm +++ b/tests/data/acpi/x86/pc/DSDT.dimmpxm diff --git a/tests/data/acpi/x86/pc/DSDT.hpbridge b/tests/data/acpi/x86/pc/DSDT.hpbridge Binary files differindex db42059..33c7529 100644 --- a/tests/data/acpi/x86/pc/DSDT.hpbridge +++ b/tests/data/acpi/x86/pc/DSDT.hpbridge diff --git a/tests/data/acpi/x86/pc/DSDT.hpbrroot b/tests/data/acpi/x86/pc/DSDT.hpbrroot Binary files differindex 31b6adb..2661170 100644 --- a/tests/data/acpi/x86/pc/DSDT.hpbrroot +++ b/tests/data/acpi/x86/pc/DSDT.hpbrroot diff --git a/tests/data/acpi/x86/pc/DSDT.ipmikcs b/tests/data/acpi/x86/pc/DSDT.ipmikcs Binary files differindex c2a0330..688faf8 100644 --- a/tests/data/acpi/x86/pc/DSDT.ipmikcs +++ b/tests/data/acpi/x86/pc/DSDT.ipmikcs diff --git a/tests/data/acpi/x86/pc/DSDT.memhp b/tests/data/acpi/x86/pc/DSDT.memhp Binary files differindex c15a9fa..6ede436 100644 --- a/tests/data/acpi/x86/pc/DSDT.memhp +++ b/tests/data/acpi/x86/pc/DSDT.memhp diff --git a/tests/data/acpi/x86/pc/DSDT.nohpet b/tests/data/acpi/x86/pc/DSDT.nohpet Binary files differindex dd29f5c..9d60407 100644 --- a/tests/data/acpi/x86/pc/DSDT.nohpet +++ b/tests/data/acpi/x86/pc/DSDT.nohpet diff --git a/tests/data/acpi/x86/pc/DSDT.numamem b/tests/data/acpi/x86/pc/DSDT.numamem Binary files differindex 8a6b56f..aa9986f 100644 --- a/tests/data/acpi/x86/pc/DSDT.numamem +++ b/tests/data/acpi/x86/pc/DSDT.numamem diff --git a/tests/data/acpi/x86/pc/DSDT.roothp b/tests/data/acpi/x86/pc/DSDT.roothp Binary files differindex a16b0d9..86c2ae1 100644 --- a/tests/data/acpi/x86/pc/DSDT.roothp +++ b/tests/data/acpi/x86/pc/DSDT.roothp diff --git a/tests/data/acpi/x86/q35/DSDT b/tests/data/acpi/x86/q35/DSDT Binary files differindex fb89ae0..b0bbff7 100644 --- a/tests/data/acpi/x86/q35/DSDT +++ b/tests/data/acpi/x86/q35/DSDT diff --git a/tests/data/acpi/x86/q35/DSDT.acpierst b/tests/data/acpi/x86/q35/DSDT.acpierst Binary files differindex 46fd254..f91cbe5 100644 --- a/tests/data/acpi/x86/q35/DSDT.acpierst +++ b/tests/data/acpi/x86/q35/DSDT.acpierst diff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat b/tests/data/acpi/x86/q35/DSDT.acpihmat Binary files differindex 61c5bd5..0949fb9 100644 --- a/tests/data/acpi/x86/q35/DSDT.acpihmat +++ b/tests/data/acpi/x86/q35/DSDT.acpihmat diff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator Binary files differindex 3aaa2bb..0fa4daa 100644 --- a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator +++ b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator diff --git a/tests/data/acpi/x86/q35/DSDT.applesmc b/tests/data/acpi/x86/q35/DSDT.applesmc Binary files differindex 944209a..a5d032b 100644 --- a/tests/data/acpi/x86/q35/DSDT.applesmc +++ b/tests/data/acpi/x86/q35/DSDT.applesmc diff --git a/tests/data/acpi/x86/q35/DSDT.bridge b/tests/data/acpi/x86/q35/DSDT.bridge Binary files differindex d9938db..3464f55 100644 --- a/tests/data/acpi/x86/q35/DSDT.bridge +++ b/tests/data/acpi/x86/q35/DSDT.bridge diff --git a/tests/data/acpi/x86/q35/DSDT.core-count b/tests/data/acpi/x86/q35/DSDT.core-count Binary files differindex a24b04c..08f5d5f 100644 --- a/tests/data/acpi/x86/q35/DSDT.core-count +++ b/tests/data/acpi/x86/q35/DSDT.core-count diff --git a/tests/data/acpi/x86/q35/DSDT.core-count2 b/tests/data/acpi/x86/q35/DSDT.core-count2 Binary files differindex 3a0cb8c..d29a710 100644 --- a/tests/data/acpi/x86/q35/DSDT.core-count2 +++ b/tests/data/acpi/x86/q35/DSDT.core-count2 diff --git a/tests/data/acpi/x86/q35/DSDT.cphp b/tests/data/acpi/x86/q35/DSDT.cphp Binary files differindex 20955d0..7fd59bf 100644 --- a/tests/data/acpi/x86/q35/DSDT.cphp +++ b/tests/data/acpi/x86/q35/DSDT.cphp diff --git a/tests/data/acpi/x86/q35/DSDT.cxl b/tests/data/acpi/x86/q35/DSDT.cxl Binary files differindex f561750..613a40b 100644 --- a/tests/data/acpi/x86/q35/DSDT.cxl +++ b/tests/data/acpi/x86/q35/DSDT.cxl diff --git a/tests/data/acpi/x86/q35/DSDT.dimmpxm b/tests/data/acpi/x86/q35/DSDT.dimmpxm Binary files differindex 228374b..1db0bf4 100644 --- a/tests/data/acpi/x86/q35/DSDT.dimmpxm +++ b/tests/data/acpi/x86/q35/DSDT.dimmpxm diff --git a/tests/data/acpi/x86/q35/DSDT.ipmibt b/tests/data/acpi/x86/q35/DSDT.ipmibt Binary files differindex 45f911a..25f43ae 100644 --- a/tests/data/acpi/x86/q35/DSDT.ipmibt +++ b/tests/data/acpi/x86/q35/DSDT.ipmibt diff --git a/tests/data/acpi/x86/q35/DSDT.ipmismbus b/tests/data/acpi/x86/q35/DSDT.ipmismbus Binary files differindex e5d6811..32bcd25 100644 --- a/tests/data/acpi/x86/q35/DSDT.ipmismbus +++ b/tests/data/acpi/x86/q35/DSDT.ipmismbus diff --git a/tests/data/acpi/x86/q35/DSDT.ivrs b/tests/data/acpi/x86/q35/DSDT.ivrs Binary files differindex 46fd254..f91cbe5 100644 --- a/tests/data/acpi/x86/q35/DSDT.ivrs +++ b/tests/data/acpi/x86/q35/DSDT.ivrs diff --git a/tests/data/acpi/x86/q35/DSDT.memhp b/tests/data/acpi/x86/q35/DSDT.memhp Binary files differindex 5ce0811..be90eb7 100644 --- a/tests/data/acpi/x86/q35/DSDT.memhp +++ b/tests/data/acpi/x86/q35/DSDT.memhp diff --git a/tests/data/acpi/x86/q35/DSDT.mmio64 b/tests/data/acpi/x86/q35/DSDT.mmio64 Binary files differindex bdf36c4..01f276a 100644 --- a/tests/data/acpi/x86/q35/DSDT.mmio64 +++ b/tests/data/acpi/x86/q35/DSDT.mmio64 diff --git a/tests/data/acpi/x86/q35/DSDT.multi-bridge b/tests/data/acpi/x86/q35/DSDT.multi-bridge Binary files differindex 1db43a6..1bd2ee8 100644 --- a/tests/data/acpi/x86/q35/DSDT.multi-bridge +++ b/tests/data/acpi/x86/q35/DSDT.multi-bridge diff --git a/tests/data/acpi/x86/q35/DSDT.noacpihp b/tests/data/acpi/x86/q35/DSDT.noacpihp Binary files differindex 8bc1688..45cc2bc 100644 --- a/tests/data/acpi/x86/q35/DSDT.noacpihp +++ b/tests/data/acpi/x86/q35/DSDT.noacpihp diff --git a/tests/data/acpi/x86/q35/DSDT.nohpet b/tests/data/acpi/x86/q35/DSDT.nohpet Binary files differindex c13e45e..f110504 100644 --- a/tests/data/acpi/x86/q35/DSDT.nohpet +++ b/tests/data/acpi/x86/q35/DSDT.nohpet diff --git a/tests/data/acpi/x86/q35/DSDT.numamem b/tests/data/acpi/x86/q35/DSDT.numamem Binary files differindex ba66694..6090958 100644 --- a/tests/data/acpi/x86/q35/DSDT.numamem +++ b/tests/data/acpi/x86/q35/DSDT.numamem diff --git a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa Binary files differindex 6ad4287..7a8e568 100644 --- a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa +++ b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa diff --git a/tests/data/acpi/x86/q35/DSDT.thread-count b/tests/data/acpi/x86/q35/DSDT.thread-count Binary files differindex a24b04c..08f5d5f 100644 --- a/tests/data/acpi/x86/q35/DSDT.thread-count +++ b/tests/data/acpi/x86/q35/DSDT.thread-count diff --git a/tests/data/acpi/x86/q35/DSDT.thread-count2 b/tests/data/acpi/x86/q35/DSDT.thread-count2 Binary files differindex 3a0cb8c..d29a710 100644 --- a/tests/data/acpi/x86/q35/DSDT.thread-count2 +++ b/tests/data/acpi/x86/q35/DSDT.thread-count2 diff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm12 b/tests/data/acpi/x86/q35/DSDT.tis.tpm12 Binary files differindex e381ce4..29a416f 100644 --- a/tests/data/acpi/x86/q35/DSDT.tis.tpm12 +++ b/tests/data/acpi/x86/q35/DSDT.tis.tpm12 diff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm2 b/tests/data/acpi/x86/q35/DSDT.tis.tpm2 Binary files differindex a092530..59288f0 100644 --- a/tests/data/acpi/x86/q35/DSDT.tis.tpm2 +++ b/tests/data/acpi/x86/q35/DSDT.tis.tpm2 diff --git a/tests/data/acpi/x86/q35/DSDT.type4-count b/tests/data/acpi/x86/q35/DSDT.type4-count Binary files differindex edc2319..eaca76e 100644 --- a/tests/data/acpi/x86/q35/DSDT.type4-count +++ b/tests/data/acpi/x86/q35/DSDT.type4-count diff --git a/tests/data/acpi/x86/q35/DSDT.viot b/tests/data/acpi/x86/q35/DSDT.viot Binary files differindex 8d98dd8..de0942a 100644 --- a/tests/data/acpi/x86/q35/DSDT.viot +++ b/tests/data/acpi/x86/q35/DSDT.viot diff --git a/tests/data/acpi/x86/q35/DSDT.xapic b/tests/data/acpi/x86/q35/DSDT.xapic Binary files differindex d4acd85..9059812b 100644 --- a/tests/data/acpi/x86/q35/DSDT.xapic +++ b/tests/data/acpi/x86/q35/DSDT.xapic diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c index 8ce0ca1..75c07d5 100644 --- a/tests/fp/fp-bench.c +++ b/tests/fp/fp-bench.c @@ -488,6 +488,8 @@ static void run_bench(void) { bench_func_t f; + set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status); + f = bench_funcs[operation][precision]; g_assert(f); f(); diff --git a/tests/fp/fp-test-log2.c b/tests/fp/fp-test-log2.c index 4eae93e..de702c4 100644 --- a/tests/fp/fp-test-log2.c +++ b/tests/fp/fp-test-log2.c @@ -70,6 +70,7 @@ int main(int ac, char **av) float_status qsf = {0}; int i; + set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf); set_float_rounding_mode(float_round_nearest_even, &qsf); test.d = 0.0; diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index 36b5712..5f6f25c 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -935,6 +935,8 @@ void run_test(void) { unsigned int i; + set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf); + genCases_setLevel(test_level); verCases_maxErrorCount = n_max_errors; diff --git a/tests/qtest/fuzz-virtio-balloon-test.c b/tests/qtest/fuzz-virtio-balloon-test.c new file mode 100644 index 0000000..ecb597f --- /dev/null +++ b/tests/qtest/fuzz-virtio-balloon-test.c @@ -0,0 +1,37 @@ +/* + * QTest fuzzer-generated testcase for virtio balloon device + * + * Copyright (c) 2024 Gao Shiyuan <gaoshiyuan@baidu.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest.h" + +/* + * https://gitlab.com/qemu-project/qemu/-/issues/2576 + * Used to trigger: + * virtio_address_space_lookup: Assertion `mrs.mr' failed. + */ +static void oss_fuzz_71649(void) +{ + QTestState *s = qtest_init("-device virtio-balloon -machine q35" + " -nodefaults"); + + qtest_outl(s, 0xcf8, 0x80000890); + qtest_outl(s, 0xcfc, 0x2); + qtest_outl(s, 0xcf8, 0x80000891); + qtest_inl(s, 0xcfc); + qtest_quit(s); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("fuzz/virtio/oss_fuzz_71649", oss_fuzz_71649); + + return g_test_run(); +} + diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 0dbdb59..aa93e98 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -88,6 +88,7 @@ qtests_i386 = \ (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ (config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \ (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ + (config_all_devices.has_key('CONFIG_VIRTIO_BALLOON') ? ['fuzz-virtio-balloon-test'] : []) + \ (config_all_devices.has_key('CONFIG_Q35') ? ['q35-test'] : []) + \ (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \ (config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \ diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index 9722145..95ff76e 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -179,10 +179,10 @@ run-plugin-%-with-libmem.so: PLUGIN_ARGS=$(COMMA)inline=true ifeq ($(filter %-softmmu, $(TARGET)),) run-%: % - $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<) + $(call run-test, $<, env QEMU=$(QEMU) $(QEMU) $(QEMU_OPTS) $<) run-plugin-%: - $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ + $(call run-test, $@, env QEMU=$(QEMU) $(QEMU) $(QEMU_OPTS) \ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@)$(PLUGIN_ARGS) \ -d plugin -D $*.pout \ $(call strip-plugin,$<)) diff --git a/tests/tcg/multiarch/linux/linux-sigrtminmax.c b/tests/tcg/multiarch/linux/linux-sigrtminmax.c new file mode 100644 index 0000000..a7059aa --- /dev/null +++ b/tests/tcg/multiarch/linux/linux-sigrtminmax.c @@ -0,0 +1,74 @@ +/* + * Test the lowest and the highest real-time signals. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include <assert.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* For hexagon and microblaze. */ +#ifndef __SIGRTMIN +#define __SIGRTMIN 32 +#endif + +extern char **environ; + +static bool seen_sigrtmin, seen_sigrtmax; + +static void handle_signal(int sig) +{ + if (sig == SIGRTMIN) { + seen_sigrtmin = true; + } else if (sig == SIGRTMAX) { + seen_sigrtmax = true; + } else { + _exit(1); + } +} + +int main(int argc, char **argv) +{ + char *qemu = getenv("QEMU"); + struct sigaction act; + + assert(qemu); + + if (!getenv("QEMU_RTSIG_MAP")) { + char **new_argv = malloc((argc + 2) + sizeof(char *)); + int tsig1, hsig1, count1, tsig2, hsig2, count2; + char rt_sigmap[64]; + + /* Re-exec with a mapping that includes SIGRTMIN and SIGRTMAX. */ + new_argv[0] = qemu; + memcpy(&new_argv[1], argv, (argc + 1) * sizeof(char *)); + tsig1 = __SIGRTMIN; + /* The host must have a few signals starting from this one. */ + hsig1 = 36; + count1 = SIGRTMIN - __SIGRTMIN + 1; + tsig2 = SIGRTMAX; + hsig2 = hsig1 + count1; + count2 = 1; + snprintf(rt_sigmap, sizeof(rt_sigmap), "%d %d %d,%d %d %d", + tsig1, hsig1, count1, tsig2, hsig2, count2); + setenv("QEMU_RTSIG_MAP", rt_sigmap, 0); + assert(execve(new_argv[0], new_argv, environ) == 0); + return EXIT_FAILURE; + } + + memset(&act, 0, sizeof(act)); + act.sa_handler = handle_signal; + assert(sigaction(SIGRTMIN, &act, NULL) == 0); + assert(sigaction(SIGRTMAX, &act, NULL) == 0); + + assert(kill(getpid(), SIGRTMIN) == 0); + assert(seen_sigrtmin); + assert(kill(getpid(), SIGRTMAX) == 0); + assert(seen_sigrtmax); + + return EXIT_SUCCESS; +} diff --git a/tests/unit/test-crypto-hash.c b/tests/unit/test-crypto-hash.c index 76c4699..8fee159 100644 --- a/tests/unit/test-crypto-hash.c +++ b/tests/unit/test-crypto-hash.c @@ -43,6 +43,9 @@ "63b54e4cb2d2032b393994aa263c0dbb" \ "e00a9f2fe9ef6037352232a1eec55ee7" #define OUTPUT_RIPEMD160 "f3d658fad3fdfb2b52c9369cf0d441249ddfa8a0" +#ifdef CONFIG_CRYPTO_SM3 +#define OUTPUT_SM3 "d4a97db105b477b84c4f20ec9c31a6c814e2705a0b83a5a89748d75f0ef456a1" +#endif #define OUTPUT_MD5_B64 "Yo0gY3FWMDWrjvYvSSveyQ==" #define OUTPUT_SHA1_B64 "sudPJnWKOkIeUJzuBFJEt4dTzAI=" @@ -55,6 +58,10 @@ "7sVe5w==" #define OUTPUT_RIPEMD160_B64 "89ZY+tP9+ytSyTac8NRBJJ3fqKA=" +#ifdef CONFIG_CRYPTO_SM3 +#define OUTPUT_SM3_B64 "1Kl9sQW0d7hMTyDsnDGmyBTicFoLg6Wol0jXXw70VqE=" +#endif + static const char *expected_outputs[] = { [QCRYPTO_HASH_ALGO_MD5] = OUTPUT_MD5, [QCRYPTO_HASH_ALGO_SHA1] = OUTPUT_SHA1, @@ -63,6 +70,9 @@ static const char *expected_outputs[] = { [QCRYPTO_HASH_ALGO_SHA384] = OUTPUT_SHA384, [QCRYPTO_HASH_ALGO_SHA512] = OUTPUT_SHA512, [QCRYPTO_HASH_ALGO_RIPEMD160] = OUTPUT_RIPEMD160, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = OUTPUT_SM3, +#endif }; static const char *expected_outputs_b64[] = { [QCRYPTO_HASH_ALGO_MD5] = OUTPUT_MD5_B64, @@ -72,6 +82,9 @@ static const char *expected_outputs_b64[] = { [QCRYPTO_HASH_ALGO_SHA384] = OUTPUT_SHA384_B64, [QCRYPTO_HASH_ALGO_SHA512] = OUTPUT_SHA512_B64, [QCRYPTO_HASH_ALGO_RIPEMD160] = OUTPUT_RIPEMD160_B64, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = OUTPUT_SM3_B64, +#endif }; static const int expected_lens[] = { [QCRYPTO_HASH_ALGO_MD5] = 16, @@ -81,6 +94,9 @@ static const int expected_lens[] = { [QCRYPTO_HASH_ALGO_SHA384] = 48, [QCRYPTO_HASH_ALGO_SHA512] = 64, [QCRYPTO_HASH_ALGO_RIPEMD160] = 20, +#ifdef CONFIG_CRYPTO_SM3 + [QCRYPTO_HASH_ALGO_SM3] = 32, +#endif }; static const char hex[] = "0123456789abcdef"; diff --git a/tests/unit/test-crypto-hmac.c b/tests/unit/test-crypto-hmac.c index cdb8774..20c60eb 100644 --- a/tests/unit/test-crypto-hmac.c +++ b/tests/unit/test-crypto-hmac.c @@ -76,6 +76,14 @@ static QCryptoHmacTestData test_data[] = { "94964ed4c1155b62b668c241d67279e5" "8a711676", }, +#ifdef CONFIG_CRYPTO_SM3 + { + .alg = QCRYPTO_HASH_ALGO_SM3, + .hex_digest = + "760e3799332bc913819b930085360ddb" + "c05529261313d5b15b75bab4fd7ae91e", + }, +#endif }; static const char hex[] = "0123456789abcdef"; diff --git a/tests/unit/test-crypto-pbkdf.c b/tests/unit/test-crypto-pbkdf.c index 12ee808..ddb7244 100644 --- a/tests/unit/test-crypto-pbkdf.c +++ b/tests/unit/test-crypto-pbkdf.c @@ -325,6 +325,22 @@ static QCryptoPbkdfTestData test_data[] = { "\xce\xbf\x91\x14\x8b\x5c\x48\x41", .nout = 32 }, +#ifdef CONFIG_CRYPTO_SM3 + { + .path = "/crypto/pbkdf/nonrfc/sm3/iter2", + .hash = QCRYPTO_HASH_ALGO_SM3, + .iterations = 2, + .key = "password", + .nkey = 8, + .salt = "ATHENA.MIT.EDUraeburn", + .nsalt = 21, + .out = "\x48\x71\x1b\x58\xa3\xcb\xce\x06" + "\xba\xad\x77\xa8\xb5\xb9\xd8\x07" + "\x6a\xe2\xb3\x5b\x95\xce\xc8\xce" + "\xe7\xb1\xcb\xee\x61\xdf\x04\xea", + .nout = 32 + }, +#endif #if 0 { .path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200", |