From a2d57703b3e735c700689b030c126fa8ba6793b9 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 29 Jun 2020 15:25:03 +0200 Subject: [PATCH 01/47] tcg/svm: use host cr4 during NPT page table walk During a page table walk of TCG+SVM the code in target/i386/excp_helper.c get_hphys() uses the cr4 register of the guest instead of the hypervisor to check for the PSE bit. In the test case we have, the guest have not enabled (yet) the PSE bit and so the page table walk results in a wrong host physical address resolution and wrong content read by the guest. Attached patch is against 4.2.1, but works also on 3.1.0. It fixes the issue for our automated testcase, which is a 32bit hypervisor w/o PAE support running a guest VM with tcg+svm. The test worked beforehand up to qemu 2.12, started to fail with qemu 3.0 and later. The added TCG/SVM NPT commit seems to introduce the regression. In case someone want to try to reproduce it, the iso is at [0], the good case is [1] and the failing case is [2]. The used commandline is: qemu-system-i386 -no-kvm -nographic -cpu phenom -m 512 -machine q35 -cdrom seoul-vmm-test.iso [0] https://depot.genode.org/alex-ab/images/seoul-vmm-test.iso [1] https://depot.genode.org/alex-ab/images/seoul-vmm-good.txt [2] https://depot.genode.org/alex-ab/images/seoul-vmm-bad.txt Signed-off-by: Alexander Boettcher Signed-off-by: Paolo Bonzini --- target/i386/excp_helper.c | 4 ++-- target/i386/svm.h | 1 + target/i386/svm_helper.c | 7 ++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/target/i386/excp_helper.c b/target/i386/excp_helper.c index 1447bda7a9..b10c7ecbcc 100644 --- a/target/i386/excp_helper.c +++ b/target/i386/excp_helper.c @@ -262,8 +262,8 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, } ptep = pde | PG_NX_MASK; - /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + /* if host cr4 PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) { page_size = 4096 * 1024; pte_addr = pde_addr; diff --git a/target/i386/svm.h b/target/i386/svm.h index 23a3a040b8..ae30fc6f79 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -135,6 +135,7 @@ #define SVM_NPT_PAE (1 << 0) #define SVM_NPT_LMA (1 << 1) #define SVM_NPT_NXE (1 << 2) +#define SVM_NPT_PSE (1 << 3) #define SVM_NPTEXIT_P (1ULL << 0) #define SVM_NPTEXIT_RW (1ULL << 1) diff --git a/target/i386/svm_helper.c b/target/i386/svm_helper.c index 7b8105a1c3..6224387eab 100644 --- a/target/i386/svm_helper.c +++ b/target/i386/svm_helper.c @@ -209,16 +209,21 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.nested_ctl)); + + env->nested_pg_mode = 0; + if (nested_ctl & SVM_NPT_ENABLED) { env->nested_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.nested_cr3)); env->hflags2 |= HF2_NPT_MASK; - env->nested_pg_mode = 0; if (env->cr[4] & CR4_PAE_MASK) { env->nested_pg_mode |= SVM_NPT_PAE; } + if (env->cr[4] & CR4_PSE_MASK) { + env->nested_pg_mode |= SVM_NPT_PSE; + } if (env->hflags & HF_LMA_MASK) { env->nested_pg_mode |= SVM_NPT_LMA; } From 3bcb5840f1b3ef9970da963bf94f637b665387ef Mon Sep 17 00:00:00 2001 From: Havard Skinnemoen Date: Sun, 28 Jun 2020 14:30:46 -0700 Subject: [PATCH 02/47] tests: Inject test name also when the test fails If a test is unsuccessful, the result is "not ok", which does not match the regex because it includes a space. This regex matches both "ok" and "not ok". Signed-off-by: Havard Skinnemoen Message-Id: <20200628213046.2028271-1-hskinnemoen@google.com> Signed-off-by: Paolo Bonzini --- tests/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 3f4448a20b..09df2d3f86 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -637,7 +637,7 @@ define do_test_tap { export MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$(( $${RANDOM:-0} % 255 + 1))} $2; \ $(foreach COMMAND, $1, \ $(COMMAND) -m=$(SPEED) -k --tap < /dev/null \ - | sed "s/^[a-z][a-z]* [0-9]* /&$(notdir $(COMMAND)) /" || true; ) } \ + | sed "s/^\(not \)\?ok [0-9]* /&$(notdir $(COMMAND)) /" || true; ) } \ | ./scripts/tap-merge.pl | tee "$@" \ | ./scripts/tap-driver.pl $(if $(V),, --show-failures-only), \ "TAP","$@") From 2880ffb08995238714b175db703c13fac4725cc1 Mon Sep 17 00:00:00 2001 From: Mario Smarduch Date: Fri, 26 Jun 2020 13:19:00 -0700 Subject: [PATCH 03/47] util/qemu-error: prepend guest name to error message to identify affected VM owner This is followup patch to the one submitted back in Oct, 19 https://lists.gnu.org/archive/html/qemu-devel/2019-10/msg02102.html My mistake here, I took my eyes of the mailing list after I got the initial thumbs up. This patch follows up on Markus comments in the above link. Purpose of this patch: We want to print guest name for errors, warnings and info messages. This was the first of two patches the second being MCE errors targeting a VM with guest name prepended. But in a large fleet we see many other errors that disable a VM or crash it. In a large fleet and centralized logging having the guest name enables identify of owner and customer. Signed-off-by: Mario Smarduch Message-Id: <20200626201900.8876-1-msmarduch@digitalocean.com> Signed-off-by: Paolo Bonzini --- include/qemu/error-report.h | 2 ++ qemu-options.hx | 12 +++++++++--- softmmu/vl.c | 9 +++++++++ util/qemu-error.c | 7 +++++++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h index 87532d8596..a5ad95ff1b 100644 --- a/include/qemu/error-report.h +++ b/include/qemu/error-report.h @@ -75,5 +75,7 @@ void error_init(const char *argv0); const char *error_get_progname(void); extern bool error_with_timestamp; +extern bool error_with_guestname; +extern const char *error_guest_name; #endif diff --git a/qemu-options.hx b/qemu-options.hx index c6edb4047b..d2c1e95bcf 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4303,16 +4303,22 @@ HXCOMM Deprecated by -accel tcg DEF("no-kvm", 0, QEMU_OPTION_no_kvm, "", QEMU_ARCH_I386) DEF("msg", HAS_ARG, QEMU_OPTION_msg, - "-msg timestamp[=on|off]\n" + "-msg [timestamp[=on|off]][,guest-name=[on|off]]\n" " control error message format\n" - " timestamp=on enables timestamps (default: off)\n", + " timestamp=on enables timestamps (default: off)\n" + " guest-name=on enables guest name prefix but only if\n" + " -name guest option is set (default: off)\n", QEMU_ARCH_ALL) SRST -``-msg timestamp[=on|off]`` +``-msg [timestamp[=on|off]][,guest-name[=on|off]]`` Control error message format. ``timestamp=on|off`` Prefix messages with a timestamp. Default is off. + + ``guest-name=on|off`` + Prefix messages with guest name but only if -name guest option is set + otherwise the option is ignored. Default is off. ERST DEF("dump-vmstate", HAS_ARG, QEMU_OPTION_dump_vmstate, diff --git a/softmmu/vl.c b/softmmu/vl.c index 96417a7c3a..a7a2e9e44a 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -389,6 +389,12 @@ static QemuOptsList qemu_msg_opts = { .name = "timestamp", .type = QEMU_OPT_BOOL, }, + { + .name = "guest-name", + .type = QEMU_OPT_BOOL, + .help = "Prepends guest name for error messages but only if " + "-name guest is set otherwise option is ignored\n", + }, { /* end of list */ } }, }; @@ -1114,6 +1120,7 @@ static void realtime_init(void) static void configure_msg(QemuOpts *opts) { error_with_timestamp = qemu_opt_get_bool(opts, "timestamp", false); + error_with_guestname = qemu_opt_get_bool(opts, "guest-name", false); } @@ -3592,6 +3599,8 @@ void qemu_init(int argc, char **argv, char **envp) if (!opts) { exit(1); } + /* Capture guest name if -msg guest-name is used later */ + error_guest_name = qemu_opt_get(opts, "guest"); break; case QEMU_OPTION_prom_env: if (nb_prom_envs >= MAX_PROM_ENVS) { diff --git a/util/qemu-error.c b/util/qemu-error.c index dac7c7dc50..3ee41438e9 100644 --- a/util/qemu-error.c +++ b/util/qemu-error.c @@ -26,6 +26,8 @@ typedef enum { /* Prepend timestamp to messages */ bool error_with_timestamp; +bool error_with_guestname; +const char *error_guest_name; int error_printf(const char *fmt, ...) { @@ -213,6 +215,11 @@ static void vreport(report_type type, const char *fmt, va_list ap) g_free(timestr); } + /* Only prepend guest name if -msg guest-name and -name guest=... are set */ + if (error_with_guestname && error_guest_name && !cur_mon) { + error_printf("%s ", error_guest_name); + } + print_loc(); switch (type) { From db57fef1e285a1f56a2d99b83456abf2f0b86e96 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 29 Jun 2020 21:34:22 +0200 Subject: [PATCH 04/47] qom: Introduce object_property_try_add_child() object_property_add() does not allow object_property_try_add() to gracefully fail as &error_abort is passed as an error handle. However such failure can easily be triggered from the QMP shell when, for instance, one attempts to create an object with an id that already exists. This is achieved from the following call path: qmp_object_add -> user_creatable_add_dict -> user_creatable_add_type -> object_property_add_child -> object_property_add For instance, from the qmp-shell, call twice: object-add qom-type=memory-backend-ram id=mem1 props.size=1073741824 and QEMU aborts. This behavior is undesired as a user/management application mistake in reusing a property ID shouldn't result in loss of the VM and live data within. This patch introduces a new function, object_property_try_add_child() which takes an error handle and turn object_property_try_add() into a non-static one. Now the call path becomes: user_creatable_add_type -> object_property_try_add_child -> object_property_try_add and the error is returned gracefully to the QMP client. (QEMU) object-add qom-type=memory-backend-ram id=mem2 props.size=4294967296 {"return": {}} (QEMU) object-add qom-type=memory-backend-ram id=mem2 props.size=4294967296 {"error": {"class": "GenericError", "desc": "attempt to add duplicate property 'mem2' to object (type 'container')"}} Signed-off-by: Eric Auger Fixes: d2623129a7de ("qom: Drop parameter @errp of object_property_add() & friends") Reviewed-by: Markus Armbruster Reviewed-by: Greg Kurz Tested-by: Greg Kurz Message-Id: <20200629193424.30280-2-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 26 ++++++++++++++++++++++++-- qom/object.c | 21 ++++++++++++++++----- qom/object_interfaces.c | 7 +++++-- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 10fd4a2d4c..79c8f838b6 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1047,7 +1047,7 @@ Object *object_ref(Object *obj); void object_unref(Object *obj); /** - * object_property_add: + * object_property_try_add: * @obj: the object to add a property to * @name: the name of the property. This can contain any character except for * a forward slash. In general, you should use hyphens '-' instead of @@ -1064,10 +1064,23 @@ void object_unref(Object *obj); * meant to allow a property to free its opaque upon object * destruction. This may be NULL. * @opaque: an opaque pointer to pass to the callbacks for the property + * @errp: pointer to error object * * Returns: The #ObjectProperty; this can be used to set the @resolve * callback for child and link properties. */ +ObjectProperty *object_property_try_add(Object *obj, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp); + +/** + * object_property_add: + * Same as object_property_try_add() with @errp hardcoded to + * &error_abort. + */ ObjectProperty *object_property_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, @@ -1518,10 +1531,11 @@ Object *object_resolve_path_type(const char *path, const char *typename, Object *object_resolve_path_component(Object *parent, const char *part); /** - * object_property_add_child: + * object_property_try_add_child: * @obj: the object to add a property to * @name: the name of the property * @child: the child object + * @errp: pointer to error object * * Child properties form the composition tree. All objects need to be a child * of another object. Objects can only be a child of one object. @@ -1535,6 +1549,14 @@ Object *object_resolve_path_component(Object *parent, const char *part); * * Returns: The newly added property on success, or %NULL on failure. */ +ObjectProperty *object_property_try_add_child(Object *obj, const char *name, + Object *child, Error **errp); + +/** + * object_property_add_child: + * Same as object_property_try_add_child() with @errp hardcoded to + * &error_abort + */ ObjectProperty *object_property_add_child(Object *obj, const char *name, Object *child); diff --git a/qom/object.c b/qom/object.c index 4c91de8183..76f5f75239 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1146,7 +1146,7 @@ void object_unref(Object *obj) } } -static ObjectProperty * +ObjectProperty * object_property_try_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, @@ -1675,8 +1675,8 @@ static void object_finalize_child_property(Object *obj, const char *name, } ObjectProperty * -object_property_add_child(Object *obj, const char *name, - Object *child) +object_property_try_add_child(Object *obj, const char *name, + Object *child, Error **errp) { g_autofree char *type = NULL; ObjectProperty *op; @@ -1685,14 +1685,25 @@ object_property_add_child(Object *obj, const char *name, type = g_strdup_printf("child<%s>", object_get_typename(child)); - op = object_property_add(obj, name, type, object_get_child_property, NULL, - object_finalize_child_property, child); + op = object_property_try_add(obj, name, type, object_get_child_property, + NULL, object_finalize_child_property, + child, errp); + if (!op) { + return NULL; + } op->resolve = object_resolve_child_property; object_ref(child); child->parent = obj; return op; } +ObjectProperty * +object_property_add_child(Object *obj, const char *name, + Object *child) +{ + return object_property_try_add_child(obj, name, child, &error_abort); +} + void object_property_allow_set_link(const Object *obj, const char *name, Object *val, Error **errp) { diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 15fff66c3c..e8e1523960 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -83,8 +83,11 @@ Object *user_creatable_add_type(const char *type, const char *id, } if (id != NULL) { - object_property_add_child(object_get_objects_root(), - id, obj); + object_property_try_add_child(object_get_objects_root(), + id, obj, &local_err); + if (local_err) { + goto out; + } } if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) { From 9fc719b869264824db0be615122754909facc929 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 29 Jun 2020 21:34:23 +0200 Subject: [PATCH 05/47] tests/qmp-cmd-test: Add qmp/object-add-duplicate-id This new test checks that attempting to create an object with an existing ID gracefully fails. Signed-off-by: Eric Auger Acked-by: Thomas Huth Reviewed-by: Markus Armbruster Message-Id: <20200629193424.30280-3-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qtest/qmp-cmd-test.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index 9f5228cd99..fc65fa3726 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -213,6 +213,23 @@ static void test_object_add_without_props(void) qtest_quit(qts); } +static void test_object_add_with_duplicate_id(void) +{ + QTestState *qts; + QDict *resp; + + qts = qtest_init(common_args); + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1', 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1', 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + qtest_quit(qts); +} + int main(int argc, char *argv[]) { QmpSchema schema; @@ -225,6 +242,8 @@ int main(int argc, char *argv[]) qtest_add_func("qmp/object-add-without-props", test_object_add_without_props); + qtest_add_func("qmp/object-add-duplicate-id", + test_object_add_with_duplicate_id); /* TODO: add coverage of generic object-add failure modes */ ret = g_test_run(); From 5b88849e7b92945c4d4a6bc1a84ea463242c9fb3 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 29 Jun 2020 21:34:24 +0200 Subject: [PATCH 06/47] tests/qmp-cmd-test: Add qmp/object-add-failure-modes Merge the existing object-add test cases into a single test functions and cover more failure cases. Signed-off-by: Eric Auger Message-Id: <20200629193424.30280-4-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qtest/qmp-cmd-test.c | 114 +++++++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 17 deletions(-) diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index fc65fa3726..c68f99f659 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -200,33 +200,116 @@ static void add_query_tests(QmpSchema *schema) } } -static void test_object_add_without_props(void) +static void test_object_add_failure_modes(void) { QTestState *qts; QDict *resp; + /* attempt to create an object without props */ qts = qtest_init(common_args); resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" - " {'qom-type': 'memory-backend-ram', 'id': 'ram1' } }"); + " {'qom-type': 'memory-backend-ram', 'id': 'ram1' } }"); g_assert_nonnull(resp); qmp_assert_error_class(resp, "GenericError"); - qtest_quit(qts); -} -static void test_object_add_with_duplicate_id(void) -{ - QTestState *qts; - QDict *resp; - - qts = qtest_init(common_args); + /* attempt to create an object without qom-type */ resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" - " {'qom-type': 'memory-backend-ram', 'id': 'ram1', 'props': {'size': 1048576 } } }"); + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + + /* attempt to delete an object that does not exist */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + + /* attempt to create 2 objects with duplicate id */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); g_assert(qdict_haskey(resp, "return")); resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" - " {'qom-type': 'memory-backend-ram', 'id': 'ram1', 'props': {'size': 1048576 } } }"); + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); g_assert_nonnull(resp); qmp_assert_error_class(resp, "GenericError"); + + /* delete ram1 object */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* attempt to create an object with a property of a wrong type */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': '1048576' } } }"); + g_assert_nonnull(resp); + /* now do it right */ + qmp_assert_error_class(resp, "GenericError"); + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* delete ram1 object */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* attempt to create an object without the id */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram'," + " 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + /* now do it right */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* delete ram1 object */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* attempt to set a non existing property */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'sized': 1048576 } } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + /* now do it right */ + resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':" + " {'qom-type': 'memory-backend-ram', 'id': 'ram1'," + " 'props': {'size': 1048576 } } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* delete ram1 object without id */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'ida': 'ram1' } }"); + g_assert_nonnull(resp); + + /* delete ram1 object */ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + g_assert(qdict_haskey(resp, "return")); + + /* delete ram1 object that does not exist anymore*/ + resp = qtest_qmp(qts, "{'execute': 'object-del', 'arguments':" + " {'id': 'ram1' } }"); + g_assert_nonnull(resp); + qmp_assert_error_class(resp, "GenericError"); + qtest_quit(qts); } @@ -240,11 +323,8 @@ int main(int argc, char *argv[]) qmp_schema_init(&schema); add_query_tests(&schema); - qtest_add_func("qmp/object-add-without-props", - test_object_add_without_props); - qtest_add_func("qmp/object-add-duplicate-id", - test_object_add_with_duplicate_id); - /* TODO: add coverage of generic object-add failure modes */ + qtest_add_func("qmp/object-add-failure-modes", + test_object_add_failure_modes); ret = g_test_run(); From 9e7871b1fca452e6ca125ff74baa3332e99ad5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Jun 2020 12:56:11 +0200 Subject: [PATCH 07/47] hw/core/null-machine: Do not initialize unused chardev backends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MachineClass uses an inverted logic (inherited from the PC machines [*]) to create the chardev backends for the default devices (see commits 998bbd74b9d..aa40fc9c964 and ac33f8fad14). As the none-machine doesn't have any hardware device, it is pointless to initialize chardev backends. Fix by setting the 'no_defaults' bits in its MachineClass. Suggested-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Message-Id: <20200624105611.1049-1-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/core/null-machine.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c index cb47d9d4f8..7e693523d7 100644 --- a/hw/core/null-machine.c +++ b/hw/core/null-machine.c @@ -50,6 +50,11 @@ static void machine_none_machine_init(MachineClass *mc) mc->max_cpus = 1; mc->default_ram_size = 0; mc->default_ram_id = "ram"; + mc->no_serial = 1; + mc->no_parallel = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_sdcard = 1; } DEFINE_MACHINE("none", machine_none_machine_init) From 3ddc0eca2229846bfecc3485648a6cb85a466dc7 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 25 Jun 2020 23:57:44 +0000 Subject: [PATCH 08/47] target/i386: set SSE FTZ in correct floating-point state The code to set floating-point state when MXCSR changes calls set_flush_to_zero on &env->fp_status, so affecting the x87 floating-point state rather than the SSE state. Fix to call it for &env->sse_status instead. Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/fpu_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 71cec3962f..ec5b9db8b9 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -2972,7 +2972,7 @@ void update_mxcsr_status(CPUX86State *env) set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status); /* set flush to zero */ - set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status); + set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->sse_status); } void helper_ldmxcsr(CPUX86State *env, uint32_t val) From 418b0f93d12a1589d5031405de857844f32e9ccc Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 25 Jun 2020 23:58:31 +0000 Subject: [PATCH 09/47] target/i386: fix IEEE SSE floating-point exception raising The SSE instruction implementations all fail to raise the expected IEEE floating-point exceptions because they do nothing to convert the exception state from the softfloat machinery into the exception flags in MXCSR. Fix this by adding such conversions. Unlike for x87, emulated SSE floating-point operations might be optimized using hardware floating point on the host, and so a different approach is taken that is compatible with such optimizations. The required invariant is that all exceptions set in env->sse_status (other than "denormal operand", for which the SSE semantics are different from those in the softfloat code) are ones that are set in the MXCSR; the emulated MXCSR is updated lazily when code reads MXCSR, while when code sets MXCSR, the exceptions in env->sse_status are set accordingly. A few instructions do not raise all the exceptions that would be raised by the softfloat code, and those instructions are made to save and restore the softfloat exception state accordingly. Nothing is done about "denormal operand"; setting that (only for the case when input denormals are *not* flushed to zero, the opposite of the logic in the softfloat code for such an exception) will require custom code for relevant instructions, or else architecture-specific conditionals in the softfloat code for when to set such an exception together with custom code for various SSE conversion and rounding instructions that do not set that exception. Nothing is done about trapping exceptions (for which there is minimal and largely broken support in QEMU's emulation in the x87 case and no support at all in the SSE case). Signed-off-by: Joseph Myers Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/Makefile.objs | 1 + target/i386/cpu.h | 1 + target/i386/fpu_helper.c | 35 + target/i386/gdbstub.c | 1 + target/i386/helper.c | 1 + target/i386/helper.h | 1 + target/i386/ops_sse.h | 28 +- target/i386/tcg-stub.c | 25 + target/i386/translate.c | 1 + tests/tcg/i386/Makefile.target | 4 + tests/tcg/i386/test-i386-sse-exceptions.c | 813 ++++++++++++++++++++++ 11 files changed, 899 insertions(+), 12 deletions(-) create mode 100644 target/i386/tcg-stub.c create mode 100644 tests/tcg/i386/test-i386-sse-exceptions.c diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index 48e0c28434..0b93143e27 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-$(CONFIG_TCG) += translate.o obj-$(CONFIG_TCG) += bpt_helper.o cc_helper.o excp_helper.o fpu_helper.o obj-$(CONFIG_TCG) += int_helper.o mem_helper.o misc_helper.o mpx_helper.o obj-$(CONFIG_TCG) += seg_helper.o smm_helper.o svm_helper.o +obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o ifeq ($(CONFIG_SOFTMMU),y) obj-y += machine.o arch_memory_mapping.o arch_dump.o monitor.o diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 7d77efd9e4..06b2e3a5c6 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2143,6 +2143,7 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env) /* fpu_helper.c */ void update_fp_status(CPUX86State *env); void update_mxcsr_status(CPUX86State *env); +void update_mxcsr_from_sse_status(CPUX86State *env); static inline void cpu_set_mxcsr(CPUX86State *env, uint32_t mxcsr) { diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index ec5b9db8b9..f5e6c4b88d 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -2539,6 +2539,7 @@ static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) static void do_xsave_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra) { + update_mxcsr_from_sse_status(env); cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr), env->mxcsr, ra); cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr_mask), 0x0000ffff, ra); } @@ -2968,6 +2969,14 @@ void update_mxcsr_status(CPUX86State *env) } set_float_rounding_mode(rnd_type, &env->sse_status); + /* Set exception flags. */ + set_float_exception_flags((mxcsr & FPUS_IE ? float_flag_invalid : 0) | + (mxcsr & FPUS_ZE ? float_flag_divbyzero : 0) | + (mxcsr & FPUS_OE ? float_flag_overflow : 0) | + (mxcsr & FPUS_UE ? float_flag_underflow : 0) | + (mxcsr & FPUS_PE ? float_flag_inexact : 0), + &env->sse_status); + /* set denormals are zero */ set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status); @@ -2975,6 +2984,32 @@ void update_mxcsr_status(CPUX86State *env) set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->sse_status); } +void update_mxcsr_from_sse_status(CPUX86State *env) +{ + if (tcg_enabled()) { + uint8_t flags = get_float_exception_flags(&env->sse_status); + /* + * The MXCSR denormal flag has opposite semantics to + * float_flag_input_denormal (the softfloat code sets that flag + * only when flushing input denormals to zero, but SSE sets it + * only when not flushing them to zero), so is not converted + * here. + */ + env->mxcsr |= ((flags & float_flag_invalid ? FPUS_IE : 0) | + (flags & float_flag_divbyzero ? FPUS_ZE : 0) | + (flags & float_flag_overflow ? FPUS_OE : 0) | + (flags & float_flag_underflow ? FPUS_UE : 0) | + (flags & float_flag_inexact ? FPUS_PE : 0) | + (flags & float_flag_output_denormal ? FPUS_UE | FPUS_PE : + 0)); + } +} + +void helper_update_mxcsr(CPUX86State *env) +{ + update_mxcsr_from_sse_status(env); +} + void helper_ldmxcsr(CPUX86State *env, uint32_t val) { cpu_set_mxcsr(env, val); diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c index b98a99500a..9ae43bda0f 100644 --- a/target/i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -184,6 +184,7 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return gdb_get_reg32(mem_buf, 0); /* fop */ case IDX_MXCSR_REG: + update_mxcsr_from_sse_status(env); return gdb_get_reg32(mem_buf, env->mxcsr); case IDX_CTL_CR0_REG: diff --git a/target/i386/helper.c b/target/i386/helper.c index c3a6e4fabe..fa2a1dcdda 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -544,6 +544,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags) for(i = 0; i < 8; i++) { fptag |= ((!env->fptags[i]) << i); } + update_mxcsr_from_sse_status(env); qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n", env->fpuc, (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11, diff --git a/target/i386/helper.h b/target/i386/helper.h index 8f9e1905c3..c2ae2f7e61 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -207,6 +207,7 @@ DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl) /* MMX/SSE */ DEF_HELPER_2(ldmxcsr, void, env, i32) +DEF_HELPER_1(update_mxcsr, void, env) DEF_HELPER_1(enter_mmx, void, env) DEF_HELPER_1(emms, void, env) DEF_HELPER_3(movq, void, env, ptr, ptr) diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index 14f2b16abd..c7614f8b0b 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -843,6 +843,7 @@ int64_t helper_cvttsd2sq(CPUX86State *env, ZMMReg *s) void helper_rsqrtps(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, float32_sqrt(s->ZMM_S(0), &env->sse_status), &env->sse_status); @@ -855,26 +856,33 @@ void helper_rsqrtps(CPUX86State *env, ZMMReg *d, ZMMReg *s) d->ZMM_S(3) = float32_div(float32_one, float32_sqrt(s->ZMM_S(3), &env->sse_status), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } void helper_rsqrtss(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, float32_sqrt(s->ZMM_S(0), &env->sse_status), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } void helper_rcpps(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, s->ZMM_S(0), &env->sse_status); d->ZMM_S(1) = float32_div(float32_one, s->ZMM_S(1), &env->sse_status); d->ZMM_S(2) = float32_div(float32_one, s->ZMM_S(2), &env->sse_status); d->ZMM_S(3) = float32_div(float32_one, s->ZMM_S(3), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } void helper_rcpss(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, s->ZMM_S(0), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } static inline uint64_t helper_extrq(uint64_t src, int shift, int len) @@ -1764,6 +1772,7 @@ void glue(helper_phminposuw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; prev_rounding_mode = env->sse_status.float_rounding_mode; @@ -1789,19 +1798,18 @@ void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->ZMM_S(2) = float32_round_to_int(s->ZMM_S(2), &env->sse_status); d->ZMM_S(3) = float32_round_to_int(s->ZMM_S(3), &env->sse_status); -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode = prev_rounding_mode; } void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; prev_rounding_mode = env->sse_status.float_rounding_mode; @@ -1825,19 +1833,18 @@ void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->ZMM_D(0) = float64_round_to_int(s->ZMM_D(0), &env->sse_status); d->ZMM_D(1) = float64_round_to_int(s->ZMM_D(1), &env->sse_status); -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode = prev_rounding_mode; } void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; prev_rounding_mode = env->sse_status.float_rounding_mode; @@ -1860,19 +1867,18 @@ void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->ZMM_S(0) = float32_round_to_int(s->ZMM_S(0), &env->sse_status); -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode = prev_rounding_mode; } void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; prev_rounding_mode = env->sse_status.float_rounding_mode; @@ -1895,13 +1901,11 @@ void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->ZMM_D(0) = float64_round_to_int(s->ZMM_D(0), &env->sse_status); -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode = prev_rounding_mode; } diff --git a/target/i386/tcg-stub.c b/target/i386/tcg-stub.c new file mode 100644 index 0000000000..b00e23d606 --- /dev/null +++ b/target/i386/tcg-stub.c @@ -0,0 +1,25 @@ +/* + * x86 FPU, MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI helpers + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" + +void update_mxcsr_from_sse_status(CPUX86State *env) +{ +} diff --git a/target/i386/translate.c b/target/i386/translate.c index 5e5dbb41b0..b3fea54411 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -8157,6 +8157,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } + gen_helper_update_mxcsr(cpu_env); gen_lea_modrm(env, s, modrm); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, mxcsr)); gen_op_st_v(s, MO_32, s->T0, s->A0); diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index 1a6463a7dc..a66232a67d 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -10,6 +10,10 @@ ALL_X86_TESTS=$(I386_SRCS:.c=) SKIP_I386_TESTS=test-i386-ssse3 X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS)) +test-i386-sse-exceptions: CFLAGS += -msse4.1 -mfpmath=sse +run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max +run-plugin-test-i386-sse-exceptions-%: QEMU_OPTS += -cpu max + test-i386-pcmpistri: CFLAGS += -msse4.2 run-test-i386-pcmpistri: QEMU_OPTS += -cpu max run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max diff --git a/tests/tcg/i386/test-i386-sse-exceptions.c b/tests/tcg/i386/test-i386-sse-exceptions.c new file mode 100644 index 0000000000..a104f46c11 --- /dev/null +++ b/tests/tcg/i386/test-i386-sse-exceptions.c @@ -0,0 +1,813 @@ +/* Test SSE exceptions. */ + +#include +#include +#include + +volatile float f_res; +volatile double d_res; + +volatile float f_snan = __builtin_nansf(""); +volatile float f_half = 0.5f; +volatile float f_third = 1.0f / 3.0f; +volatile float f_nan = __builtin_nanl(""); +volatile float f_inf = __builtin_inff(); +volatile float f_ninf = -__builtin_inff(); +volatile float f_one = 1.0f; +volatile float f_two = 2.0f; +volatile float f_zero = 0.0f; +volatile float f_nzero = -0.0f; +volatile float f_min = FLT_MIN; +volatile float f_true_min = 0x1p-149f; +volatile float f_max = FLT_MAX; +volatile float f_nmax = -FLT_MAX; + +volatile double d_snan = __builtin_nans(""); +volatile double d_half = 0.5; +volatile double d_third = 1.0 / 3.0; +volatile double d_nan = __builtin_nan(""); +volatile double d_inf = __builtin_inf(); +volatile double d_ninf = -__builtin_inf(); +volatile double d_one = 1.0; +volatile double d_two = 2.0; +volatile double d_zero = 0.0; +volatile double d_nzero = -0.0; +volatile double d_min = DBL_MIN; +volatile double d_true_min = 0x1p-1074; +volatile double d_max = DBL_MAX; +volatile double d_nmax = -DBL_MAX; + +volatile int32_t i32_max = INT32_MAX; + +#define IE (1 << 0) +#define ZE (1 << 2) +#define OE (1 << 3) +#define UE (1 << 4) +#define PE (1 << 5) +#define EXC (IE | ZE | OE | UE | PE) + +uint32_t mxcsr_default = 0x1f80; +uint32_t mxcsr_ftz = 0x9f80; + +int main(void) +{ + uint32_t mxcsr; + int32_t i32_res; + int ret = 0; + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = f_snan; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: widen float snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: narrow float underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = d_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: narrow float overflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: narrow float inexact\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = d_snan; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: narrow float snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $4, %0, %0" : "=x" (f_res) : "0" (f_min)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: roundss min\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $12, %0, %0" : "=x" (f_res) : "0" (f_min)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: roundss no-inexact min\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $4, %0, %0" : "=x" (f_res) : "0" (f_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: roundss snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $12, %0, %0" : "=x" (f_res) : "0" (f_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: roundss no-inexact snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $4, %0, %0" : "=x" (d_res) : "0" (d_min)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: roundsd min\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $12, %0, %0" : "=x" (d_res) : "0" (d_min)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: roundsd no-inexact min\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $4, %0, %0" : "=x" (d_res) : "0" (d_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: roundsd snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $12, %0, %0" : "=x" (d_res) : "0" (d_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: roundsd no-inexact snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("comiss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: comiss nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomiss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: ucomiss nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomiss %1, %0" : : "x" (f_snan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: ucomiss snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("comisd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: comisd nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomisd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: ucomisd nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomisd %1, %0" : : "x" (d_snan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: ucomisd snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max + f_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: float add overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max + f_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: float add inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf + f_ninf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float add inf -inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_snan + f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float add snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res = f_true_min + f_true_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float add FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max + d_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: double add overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max + d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: double add inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf + d_ninf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double add inf -inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_snan + d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double add snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res = d_true_min + d_true_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double add FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max - f_nmax; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: float sub overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max - f_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: float sub inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf - f_inf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float sub inf inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_snan - f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float sub snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res = f_min - f_true_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float sub FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max - d_nmax; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: double sub overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max - d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: double sub inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf - d_inf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double sub inf inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_snan - d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double sub snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res = d_min - d_true_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double sub FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max * f_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: float mul overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_third * f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: float mul inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_min * f_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float mul underflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf * f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float mul inf 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_snan * f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float mul snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res = f_min * f_half; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float mul FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max * d_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: double mul overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_third * d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: double mul inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_min * d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double mul underflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf * d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double mul inf 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_snan * d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double mul snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res = d_min * d_half; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double mul FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_max / f_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: float div overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_one / f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: float div inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_min / f_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float div underflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_one / f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != ZE) { + printf("FAIL: float div 1 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf / f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: float div inf 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_nan / f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: float div nan 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_zero / f_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float div 0 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_inf / f_inf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float div inf inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res = f_snan / f_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: float div snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res = f_min / f_two; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: float div FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_max / d_min; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (OE | PE)) { + printf("FAIL: double div overflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_one / d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: double div inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_min / d_max; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double div underflow\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_one / d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != ZE) { + printf("FAIL: double div 1 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf / d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: double div inf 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_nan / d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: double div nan 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_zero / d_zero; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double div 0 0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_inf / d_inf; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double div inf inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res = d_snan / d_third; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: double div snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res = d_min / d_two; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != (UE | PE)) { + printf("FAIL: double div FTZ underflow\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_max)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: sqrtss inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_nmax)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtss -max\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_ninf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtss -inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtss snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : "0" (f_nzero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: sqrtss -0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=x" (f_res) : + "0" (-__builtin_nanf(""))); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: sqrtss -nan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_max)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: sqrtsd inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_nmax)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtsd -max\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_ninf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtsd -inf\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_snan)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: sqrtsd snan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : "0" (d_nzero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: sqrtsd -0\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=x" (d_res) : + "0" (-__builtin_nan(""))); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: sqrtsd -nan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("maxss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: maxss nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("minss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: minss nan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("maxsd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: maxsd nan\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("minsd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: minsd nan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsi2ss %1, %0" : "=x" (f_res) : "m" (i32_max)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvtsi2ss inexact\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsi2sd %1, %0" : "=x" (d_res) : "m" (i32_max)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: cvtsi2sd exact\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (1.5f)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvtss2si inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (0x1p31f)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvtss2si 0x1p31\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=r" (i32_res) : "x" (f_inf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvtss2si inf\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (1.5)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvtsd2si inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (0x1p31)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvtsd2si 0x1p31\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=r" (i32_res) : "x" (d_inf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvtsd2si inf\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (1.5f)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvttss2si inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (0x1p31f)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvttss2si 0x1p31\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=r" (i32_res) : "x" (f_inf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvttss2si inf\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (1.5)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != PE) { + printf("FAIL: cvttsd2si inexact\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (0x1p31)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvttsd2si 0x1p31\n"); + ret = 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=r" (i32_res) : "x" (d_inf)); + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != IE) { + printf("FAIL: cvttsd2si inf\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("rcpss %0, %0" : "=x" (f_res) : "0" (f_snan)); + f_res += f_one; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: rcpss snan\n"); + ret = 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("rsqrtss %0, %0" : "=x" (f_res) : "0" (f_snan)); + f_res += f_one; + __asm__ volatile ("stmxcsr %0" : "=m" (mxcsr)); + if ((mxcsr & EXC) != 0) { + printf("FAIL: rsqrtss snan\n"); + ret = 1; + } + + return ret; +} From b16c0e20c74218f2d69710cedad11da7dd4d2190 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 May 2020 10:49:22 -0400 Subject: [PATCH 10/47] KVM: add support for AMD nested live migration Support for nested guest live migration is part of Linux 5.8, add the corresponding code to QEMU. The migration format consists of a few flags, is an opaque 4k blob. The blob is in VMCB format (the control area represents the L1 VMCB control fields, the save area represents the pre-vmentry state; KVM does not use the host save area since the AMD manual allows that) but QEMU does not really care about that. However, the flags need to be copied to hflags/hflags2 and back. In addition, support for retrieving and setting the AMD nested virtualization states allows the L1 guest to be reset while running a nested guest, but a small bug in CPU reset needs to be fixed for that to work. Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 1 + target/i386/cpu.h | 5 +++++ target/i386/kvm.c | 42 ++++++++++++++++++++++++++++++++++-------- target/i386/machine.c | 31 ++++++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index e46ab8f774..008fd93ff1 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5968,6 +5968,7 @@ static void x86_cpu_reset(DeviceState *dev) /* init to reset state */ env->hflags2 |= HF2_GIF_MASK; + env->hflags &= ~HF_GUEST_MASK; cpu_x86_update_cr0(env, 0x60000010); env->a20_mask = ~0x0; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 06b2e3a5c6..9284f96896 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2118,6 +2118,11 @@ static inline bool cpu_has_vmx(CPUX86State *env) return env->features[FEAT_1_ECX] & CPUID_EXT_VMX; } +static inline bool cpu_has_svm(CPUX86State *env) +{ + return env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM; +} + /* * In order for a vCPU to enter VMX operation it must have CR4.VMXE set. * Since it was set, CR4.VMXE must remain set as long as vCPU is in diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 6adbff3d74..2b6b7443d2 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1840,16 +1840,18 @@ int kvm_arch_init_vcpu(CPUState *cs) if (max_nested_state_len > 0) { assert(max_nested_state_len >= offsetof(struct kvm_nested_state, data)); - if (cpu_has_vmx(env)) { + if (cpu_has_vmx(env) || cpu_has_svm(env)) { struct kvm_vmx_nested_state_hdr *vmx_hdr; env->nested_state = g_malloc0(max_nested_state_len); env->nested_state->size = max_nested_state_len; env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX; - vmx_hdr = &env->nested_state->hdr.vmx; - vmx_hdr->vmxon_pa = -1ull; - vmx_hdr->vmcs12_pa = -1ull; + if (cpu_has_vmx(env)) { + vmx_hdr = &env->nested_state->hdr.vmx; + vmx_hdr->vmxon_pa = -1ull; + vmx_hdr->vmcs12_pa = -1ull; + } } } @@ -3873,6 +3875,20 @@ static int kvm_put_nested_state(X86CPU *cpu) return 0; } + /* + * Copy flags that are affected by reset from env->hflags and env->hflags2. + */ + if (env->hflags & HF_GUEST_MASK) { + env->nested_state->flags |= KVM_STATE_NESTED_GUEST_MODE; + } else { + env->nested_state->flags &= ~KVM_STATE_NESTED_GUEST_MODE; + } + if (env->hflags2 & HF2_GIF_MASK) { + env->nested_state->flags |= KVM_STATE_NESTED_GIF_SET; + } else { + env->nested_state->flags &= ~KVM_STATE_NESTED_GIF_SET; + } + assert(env->nested_state->size <= max_nested_state_len); return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_NESTED_STATE, env->nested_state); } @@ -3901,11 +3917,19 @@ static int kvm_get_nested_state(X86CPU *cpu) return ret; } + /* + * Copy flags that are affected by reset to env->hflags and env->hflags2. + */ if (env->nested_state->flags & KVM_STATE_NESTED_GUEST_MODE) { env->hflags |= HF_GUEST_MASK; } else { env->hflags &= ~HF_GUEST_MASK; } + if (env->nested_state->flags & KVM_STATE_NESTED_GIF_SET) { + env->hflags2 |= HF2_GIF_MASK; + } else { + env->hflags2 &= ~HF2_GIF_MASK; + } return ret; } @@ -3917,6 +3941,12 @@ int kvm_arch_put_registers(CPUState *cpu, int level) assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); + /* must be before kvm_put_nested_state so that EFER.SVME is set */ + ret = kvm_put_sregs(x86_cpu); + if (ret < 0) { + return ret; + } + if (level >= KVM_PUT_RESET_STATE) { ret = kvm_put_nested_state(x86_cpu); if (ret < 0) { @@ -3950,10 +3980,6 @@ int kvm_arch_put_registers(CPUState *cpu, int level) if (ret < 0) { return ret; } - ret = kvm_put_sregs(x86_cpu); - if (ret < 0) { - return ret; - } /* must be before kvm_put_msrs */ ret = kvm_inject_mce_oldstyle(x86_cpu); if (ret < 0) { diff --git a/target/i386/machine.c b/target/i386/machine.c index 0c96531a56..b1acf7d0ef 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -1071,13 +1071,41 @@ static const VMStateDescription vmstate_vmx_nested_state = { } }; +static bool svm_nested_state_needed(void *opaque) +{ + struct kvm_nested_state *nested_state = opaque; + + /* + * HF_GUEST_MASK and HF2_GIF_MASK are already serialized + * via hflags and hflags2, all that's left is the opaque + * nested state blob. + */ + return (nested_state->format == KVM_STATE_NESTED_FORMAT_SVM && + nested_state->size > offsetof(struct kvm_nested_state, data)); +} + +static const VMStateDescription vmstate_svm_nested_state = { + .name = "cpu/kvm_nested_state/svm", + .version_id = 1, + .minimum_version_id = 1, + .needed = svm_nested_state_needed, + .fields = (VMStateField[]) { + VMSTATE_U64(hdr.svm.vmcb_pa, struct kvm_nested_state), + VMSTATE_UINT8_ARRAY(data.svm[0].vmcb12, + struct kvm_nested_state, + KVM_STATE_NESTED_SVM_VMCB_SIZE), + VMSTATE_END_OF_LIST() + } +}; + static bool nested_state_needed(void *opaque) { X86CPU *cpu = opaque; CPUX86State *env = &cpu->env; return (env->nested_state && - vmx_nested_state_needed(env->nested_state)); + (vmx_nested_state_needed(env->nested_state) || + svm_nested_state_needed(env->nested_state))); } static int nested_state_post_load(void *opaque, int version_id) @@ -1139,6 +1167,7 @@ static const VMStateDescription vmstate_kvm_nested_state = { }, .subsections = (const VMStateDescription*[]) { &vmstate_vmx_nested_state, + &vmstate_svm_nested_state, NULL } }; From 6553aa1d1166b4257f1294b898fc9f09e7276639 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 29 Jun 2020 11:28:04 -0500 Subject: [PATCH 11/47] coverity: provide Coverity-friendly MIN_CONST and MAX_CONST Coverity has problems seeing through __builtin_choose_expr, which result in it abandoning analysis of later functions that utilize a definition that used MIN_CONST or MAX_CONST, such as in qemu-file.c: 50 DECLARE_BITMAP(may_free, MAX_IOV_SIZE); CID 1429992 (#1 of 1): Unrecoverable parse warning (PARSE_ERROR)1. expr_not_constant: expression must have a constant value As has been done in the past (see 07d66672), it's okay to dumb things down when compiling for static analyzers. (Of course, now the syntax-checker has a false positive on our reference to __COVERITY__...) Reported-by: Peter Maydell Fixes: CID 1429992, CID 1429995, CID 1429997, CID 1429999 Signed-off-by: Eric Blake Message-Id: <20200629162804.1096180-1-eblake@redhat.com> Signed-off-by: Paolo Bonzini --- include/qemu/osdep.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 0d26a1b9bd..0fc206ae61 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -250,7 +250,8 @@ extern int daemon(int, int); * Note that neither form is usable as an #if condition; if you truly * need to write conditional code that depends on a minimum or maximum * determined by the pre-processor instead of the compiler, you'll - * have to open-code it. + * have to open-code it. Sadly, Coverity is severely confused by the + * constant variants, so we have to dumb things down there. */ #undef MIN #define MIN(a, b) \ @@ -258,22 +259,28 @@ extern int daemon(int, int); typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a < _b ? _a : _b; \ }) -#define MIN_CONST(a, b) \ - __builtin_choose_expr( \ - __builtin_constant_p(a) && __builtin_constant_p(b), \ - (a) < (b) ? (a) : (b), \ - ((void)0)) #undef MAX #define MAX(a, b) \ ({ \ typeof(1 ? (a) : (b)) _a = (a), _b = (b); \ _a > _b ? _a : _b; \ }) -#define MAX_CONST(a, b) \ + +#ifdef __COVERITY__ +# define MIN_CONST(a, b) ((a) < (b) ? (a) : (b)) +# define MAX_CONST(a, b) ((a) > (b) ? (a) : (b)) +#else +# define MIN_CONST(a, b) \ + __builtin_choose_expr( \ + __builtin_constant_p(a) && __builtin_constant_p(b), \ + (a) < (b) ? (a) : (b), \ + ((void)0)) +# define MAX_CONST(a, b) \ __builtin_choose_expr( \ __builtin_constant_p(a) && __builtin_constant_p(b), \ (a) > (b) ? (a) : (b), \ ((void)0)) +#endif /* * Minimum function that returns zero only if both values are zero. From b8d864f64341eb5825aed28aa9a6d1c98316b3e9 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:16 +0300 Subject: [PATCH 12/47] i386: hvf: Set env->eip in macvm_set_rip() cpu_synchronize_state() is currently no-op for hvf but BIOS will hang in vAPIC option ROM when cpu_synchronize_state() is wired to hvf_cpu_synchronize_state(). cpu_synchronize_state() state is called from vapic_write() during option ROM initialization. It sets dirty flag on the cpu. macvm_set_rip() is then invoked to advance IP after the I/O write to vAPIC port. macvm_set_rip() only modifies VMCS, it doesn't change env->eip. Therefore on the next iteration of vCPU loop, vcpu_dirty flag is checked and hvf_put_registers() overwrites correct RIP in VMCS with the value of env->eip that points to the I/O write instruction. Execution of the CPU gets stuck on the instruction. The issue can be avoided if eip doesn't contain stale value when dirty flag is set on cpu. Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-2-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/vmx.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index ce2a1532d5..1e8b29bf7d 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -173,6 +173,7 @@ static inline void macvm_set_rip(CPUState *cpu, uint64_t rip) /* BUG, should take considering overlap.. */ wreg(cpu->hvf_fd, HV_X86_RIP, rip); + env->eip = rip; /* after moving forward in rip, we need to clean INTERRUPTABILITY */ val = rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY); From 4bb19f98d34302d627a1267b608de4df6d0988f9 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:17 +0300 Subject: [PATCH 13/47] i386: hvf: Move synchronize functions to sysemu Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-3-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- cpus.c | 12 ------------ include/sysemu/hw_accel.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/cpus.c b/cpus.c index 41d1c5099f..d94456ed29 100644 --- a/cpus.c +++ b/cpus.c @@ -1017,10 +1017,6 @@ void cpu_synchronize_all_states(void) CPU_FOREACH(cpu) { cpu_synchronize_state(cpu); - /* TODO: move to cpu_synchronize_state() */ - if (hvf_enabled()) { - hvf_cpu_synchronize_state(cpu); - } } } @@ -1030,10 +1026,6 @@ void cpu_synchronize_all_post_reset(void) CPU_FOREACH(cpu) { cpu_synchronize_post_reset(cpu); - /* TODO: move to cpu_synchronize_post_reset() */ - if (hvf_enabled()) { - hvf_cpu_synchronize_post_reset(cpu); - } } } @@ -1043,10 +1035,6 @@ void cpu_synchronize_all_post_init(void) CPU_FOREACH(cpu) { cpu_synchronize_post_init(cpu); - /* TODO: move to cpu_synchronize_post_init() */ - if (hvf_enabled()) { - hvf_cpu_synchronize_post_init(cpu); - } } } diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index 0ec2372477..80bce75921 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -14,6 +14,7 @@ #include "hw/core/cpu.h" #include "sysemu/hax.h" #include "sysemu/kvm.h" +#include "sysemu/hvf.h" #include "sysemu/whpx.h" static inline void cpu_synchronize_state(CPUState *cpu) @@ -24,6 +25,9 @@ static inline void cpu_synchronize_state(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_state(cpu); } + if (hvf_enabled()) { + hvf_cpu_synchronize_state(cpu); + } if (whpx_enabled()) { whpx_cpu_synchronize_state(cpu); } @@ -37,6 +41,9 @@ static inline void cpu_synchronize_post_reset(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_post_reset(cpu); } + if (hvf_enabled()) { + hvf_cpu_synchronize_post_reset(cpu); + } if (whpx_enabled()) { whpx_cpu_synchronize_post_reset(cpu); } @@ -50,6 +57,9 @@ static inline void cpu_synchronize_post_init(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_post_init(cpu); } + if (hvf_enabled()) { + hvf_cpu_synchronize_post_init(cpu); + } if (whpx_enabled()) { whpx_cpu_synchronize_post_init(cpu); } From 5536c98e449fe832c6cb59612baf0f2936fb436d Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:18 +0300 Subject: [PATCH 14/47] i386: hvf: Add hvf_cpu_synchronize_pre_loadvm() hvf lacks an implementation of cpu_synchronize_pre_loadvm(). Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-4-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 1 + include/sysemu/hw_accel.h | 3 +++ target/i386/hvf/hvf.c | 11 +++++++++++ 3 files changed, 15 insertions(+) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 5214ed5202..1d40a8ec01 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -28,6 +28,7 @@ int hvf_vcpu_exec(CPUState *); void hvf_cpu_synchronize_state(CPUState *); void hvf_cpu_synchronize_post_reset(CPUState *); void hvf_cpu_synchronize_post_init(CPUState *); +void hvf_cpu_synchronize_pre_loadvm(CPUState *); void hvf_vcpu_destroy(CPUState *); void hvf_reset_vcpu(CPUState *); diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index 80bce75921..e128f8b06b 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -73,6 +73,9 @@ static inline void cpu_synchronize_pre_loadvm(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_pre_loadvm(cpu); } + if (hvf_enabled()) { + hvf_cpu_synchronize_pre_loadvm(cpu); + } if (whpx_enabled()) { whpx_cpu_synchronize_pre_loadvm(cpu); } diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index be016b951a..efe9802962 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -325,6 +325,17 @@ void hvf_cpu_synchronize_post_init(CPUState *cpu_state) run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); } +static void do_hvf_cpu_synchronize_pre_loadvm(CPUState *cpu, + run_on_cpu_data arg) +{ + cpu->vcpu_dirty = true; +} + +void hvf_cpu_synchronize_pre_loadvm(CPUState *cpu) +{ + run_on_cpu(cpu, do_hvf_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); +} + static bool ept_emulation_fault(hvf_slot *slot, uint64_t gpa, uint64_t ept_qual) { int read, write; From a4e26fa8583a215aa61107a623bfa25afd09a860 Mon Sep 17 00:00:00 2001 From: Cameron Esfahani Date: Tue, 30 Jun 2020 13:28:20 +0300 Subject: [PATCH 15/47] i386: hvf: Make long mode enter and exit clearer Intel SDM "9.8.5 Initializing IA-32e Mode" and "9.8.5.4 Switching Out of IA-32e Mode Operation" define activation and deactivation of long mode only upon a change of CR0.PG but current code invokes exit_long_mode() unconditionally until LME is cleared. Signed-off-by: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-6-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/vmx.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 1e8b29bf7d..437238f11d 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -121,6 +121,7 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) uint64_t pdpte[4] = {0, 0, 0, 0}; uint64_t efer = rvmcs(vcpu, VMCS_GUEST_IA32_EFER); uint64_t old_cr0 = rvmcs(vcpu, VMCS_GUEST_CR0); + uint64_t changed_cr0 = old_cr0 ^ cr0; uint64_t mask = CR0_PG | CR0_CD | CR0_NW | CR0_NE | CR0_ET; if ((cr0 & CR0_PG) && (rvmcs(vcpu, VMCS_GUEST_CR4) & CR4_PAE) && @@ -138,11 +139,12 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) wvmcs(vcpu, VMCS_CR0_SHADOW, cr0); if (efer & MSR_EFER_LME) { - if (!(old_cr0 & CR0_PG) && (cr0 & CR0_PG)) { - enter_long_mode(vcpu, cr0, efer); - } - if (/*(old_cr0 & CR0_PG) &&*/ !(cr0 & CR0_PG)) { - exit_long_mode(vcpu, cr0, efer); + if (changed_cr0 & CR0_PG) { + if (cr0 & CR0_PG) { + enter_long_mode(vcpu, cr0, efer); + } else { + exit_long_mode(vcpu, cr0, efer); + } } } From 82695a1b9c696aaea491e932548f9787adb7d78b Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:21 +0300 Subject: [PATCH 16/47] i386: hvf: Move Guest LMA reset to macvm_set_cr0() The only useful purpose of hvf_reset_vcpu() is to clear "IA-32e mode guest" (LMA) VM-Entry control. But it can be moved to macvm_set_cr0() which is indirectly used by post-init and post-reset to flush emulator state. That enables clean removal of hvf_reset_vcpu(). LMA is set only if IA32_EFER.LME = 1, according to Intel SDM "9.8.5 Initializing IA-32e Mode" and "9.8.5.4 Switching Out of IA-32e Mode Operation", otherwise the entry control can be safely cleared. Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-7-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 1 - target/i386/hvf/vmx.h | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index efe9802962..31980f9076 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -459,7 +459,6 @@ void hvf_reset_vcpu(CPUState *cpu) { /* TODO: this shouldn't be needed; there is already a call to * cpu_synchronize_all_post_reset in vl.c */ - wvmcs(cpu->hvf_fd, VMCS_ENTRY_CTLS, 0); wvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER, 0); /* Initialize PDPTE */ diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 437238f11d..75ba1e2a5f 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -123,6 +123,7 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) uint64_t old_cr0 = rvmcs(vcpu, VMCS_GUEST_CR0); uint64_t changed_cr0 = old_cr0 ^ cr0; uint64_t mask = CR0_PG | CR0_CD | CR0_NW | CR0_NE | CR0_ET; + uint64_t entry_ctls; if ((cr0 & CR0_PG) && (rvmcs(vcpu, VMCS_GUEST_CR4) & CR4_PAE) && !(efer & MSR_EFER_LME)) { @@ -146,6 +147,9 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) exit_long_mode(vcpu, cr0, efer); } } + } else { + entry_ctls = rvmcs(vcpu, VMCS_ENTRY_CTLS); + wvmcs(vcpu, VMCS_ENTRY_CTLS, entry_ctls & ~VM_ENTRY_GUEST_LMA); } /* Filter new CR0 after we are finished examining it above. */ From 5009ef22c6bb21aa741e9e354ccaa97edf56911d Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:22 +0300 Subject: [PATCH 17/47] i386: hvf: Don't duplicate register reset hvf_reset_vcpu() duplicates actions performed by x86_cpu_reset(). The difference is that hvf_reset_vcpu() stores initial values directly to VMCS while x86_cpu_reset() stores it in CPUX86State and then cpu_synchronize_all_post_init() or cpu_synchronize_all_post_reset() flushes CPUX86State into VMCS. That makes hvf_reset_vcpu() a kind of no-op. Here's the trace of CPU state modifications during VM start: hvf_reset_vcpu (resets VMCS) cpu_synchronize_all_post_init (overwrites VMCS fields written by hvf_reset_vcpu()) cpu_synchronize_all_states hvf_reset_vcpu (resets VMCS) cpu_synchronize_all_post_reset (overwrites VMCS fields written by hvf_reset_vcpu()) General purpose registers, system registers, segment descriptors, flags and IP are set by hvf_put_segments() in post-init and post-reset, therefore it's safe to remove them from hvf_reset_vcpu(). PDPTE initialization can be dropped because Intel SDM (26.3.1.6 Checks on Guest Page-Directory-Pointer-Table Entries) doesn't require PDPTE to be clear unless PAE is used: "A VM entry to a guest that does not use PAE paging does not check the validity of any PDPTEs." And if PAE is used, PDPTE's are initialized from CR3 in macvm_set_cr0(). Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-8-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 1 - target/i386/cpu.c | 3 -- target/i386/hvf/hvf.c | 89 ------------------------------------------- 3 files changed, 93 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 1d40a8ec01..6d3ee4fdb7 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -30,7 +30,6 @@ void hvf_cpu_synchronize_post_reset(CPUState *); void hvf_cpu_synchronize_post_init(CPUState *); void hvf_cpu_synchronize_pre_loadvm(CPUState *); void hvf_vcpu_destroy(CPUState *); -void hvf_reset_vcpu(CPUState *); #define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf") diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 008fd93ff1..1546cd78ff 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6080,9 +6080,6 @@ static void x86_cpu_reset(DeviceState *dev) if (kvm_enabled()) { kvm_arch_reset_vcpu(cpu); } - else if (hvf_enabled()) { - hvf_reset_vcpu(s); - } #endif } diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 31980f9076..2a12867ef0 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -452,95 +452,6 @@ static MemoryListener hvf_memory_listener = { .log_sync = hvf_log_sync, }; -void hvf_reset_vcpu(CPUState *cpu) { - uint64_t pdpte[4] = {0, 0, 0, 0}; - int i; - - /* TODO: this shouldn't be needed; there is already a call to - * cpu_synchronize_all_post_reset in vl.c - */ - wvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER, 0); - - /* Initialize PDPTE */ - for (i = 0; i < 4; i++) { - wvmcs(cpu->hvf_fd, VMCS_GUEST_PDPTE0 + i * 2, pdpte[i]); - } - - macvm_set_cr0(cpu->hvf_fd, 0x60000010); - - wvmcs(cpu->hvf_fd, VMCS_CR4_MASK, CR4_VMXE_MASK); - wvmcs(cpu->hvf_fd, VMCS_CR4_SHADOW, 0x0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_CR4, CR4_VMXE_MASK); - - /* set VMCS guest state fields */ - wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_SELECTOR, 0xf000); - wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_ACCESS_RIGHTS, 0x9b); - wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_BASE, 0xffff0000); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_LIMIT, 0xffff); - wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_ACCESS_RIGHTS, 0x93); - wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_LIMIT, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_ACCESS_RIGHTS, 0x10000); - wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_SELECTOR, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_LIMIT, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_ACCESS_RIGHTS, 0x83); - wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_LIMIT, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_BASE, 0); - - wvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_LIMIT, 0); - wvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_BASE, 0); - - /*wvmcs(cpu->hvf_fd, VMCS_GUEST_CR2, 0x0);*/ - wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, 0x0); - - wreg(cpu->hvf_fd, HV_X86_RIP, 0xfff0); - wreg(cpu->hvf_fd, HV_X86_RDX, 0x623); - wreg(cpu->hvf_fd, HV_X86_RFLAGS, 0x2); - wreg(cpu->hvf_fd, HV_X86_RSP, 0x0); - wreg(cpu->hvf_fd, HV_X86_RAX, 0x0); - wreg(cpu->hvf_fd, HV_X86_RBX, 0x0); - wreg(cpu->hvf_fd, HV_X86_RCX, 0x0); - wreg(cpu->hvf_fd, HV_X86_RSI, 0x0); - wreg(cpu->hvf_fd, HV_X86_RDI, 0x0); - wreg(cpu->hvf_fd, HV_X86_RBP, 0x0); - - for (int i = 0; i < 8; i++) { - wreg(cpu->hvf_fd, HV_X86_R8 + i, 0x0); - } - - hv_vcpu_invalidate_tlb(cpu->hvf_fd); - hv_vcpu_flush(cpu->hvf_fd); -} - void hvf_vcpu_destroy(CPUState *cpu) { X86CPU *x86_cpu = X86_CPU(cpu); From eae009de78b62e67ec887b4934cf62f4f5fb33c8 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Tue, 30 Jun 2020 13:28:23 +0300 Subject: [PATCH 18/47] i386: hvf: Clean up synchronize functions Make them more concise and consitent with the rest of the code in the file and drop non-relevant TODO. Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200630102824.77604-9-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 44 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 2a12867ef0..d81f569aed 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -282,47 +282,43 @@ void hvf_handle_io(CPUArchState *env, uint16_t port, void *buffer, } } -/* TODO: synchronize vcpu state */ static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) { - CPUState *cpu_state = cpu; - if (cpu_state->vcpu_dirty == 0) { - hvf_get_registers(cpu_state); - } - - cpu_state->vcpu_dirty = 1; -} - -void hvf_cpu_synchronize_state(CPUState *cpu_state) -{ - if (cpu_state->vcpu_dirty == 0) { - run_on_cpu(cpu_state, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL); + if (!cpu->vcpu_dirty) { + hvf_get_registers(cpu); + cpu->vcpu_dirty = true; } } -static void do_hvf_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) +void hvf_cpu_synchronize_state(CPUState *cpu) { - CPUState *cpu_state = cpu; - hvf_put_registers(cpu_state); - cpu_state->vcpu_dirty = false; + if (!cpu->vcpu_dirty) { + run_on_cpu(cpu, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL); + } } -void hvf_cpu_synchronize_post_reset(CPUState *cpu_state) +static void do_hvf_cpu_synchronize_post_reset(CPUState *cpu, + run_on_cpu_data arg) { - run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); + hvf_put_registers(cpu); + cpu->vcpu_dirty = false; +} + +void hvf_cpu_synchronize_post_reset(CPUState *cpu) +{ + run_on_cpu(cpu, do_hvf_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); } static void do_hvf_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) { - CPUState *cpu_state = cpu; - hvf_put_registers(cpu_state); - cpu_state->vcpu_dirty = false; + hvf_put_registers(cpu); + cpu->vcpu_dirty = false; } -void hvf_cpu_synchronize_post_init(CPUState *cpu_state) +void hvf_cpu_synchronize_post_init(CPUState *cpu) { - run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); + run_on_cpu(cpu, do_hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); } static void do_hvf_cpu_synchronize_pre_loadvm(CPUState *cpu, From de6b528be41fabfdde32982ba62f2cddc7e10330 Mon Sep 17 00:00:00 2001 From: Roman Bolshakov Date: Thu, 25 Jun 2020 01:58:51 +0300 Subject: [PATCH 19/47] MAINTAINERS: Add Cameron as HVF co-maintainer Similar patch was sent a while ago but got lost. While at it, add a status wiki page. Cc: Cameron Esfahani Signed-off-by: Roman Bolshakov Message-Id: <20200624225850.16982-9-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6aa54f7f8f..ee89d67d68 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -417,7 +417,9 @@ F: target/i386/kvm.c F: scripts/kvm/vmxcap X86 HVF CPUs +M: Cameron Esfahani M: Roman Bolshakov +W: https://wiki.qemu.org/Features/HVF S: Maintained F: accel/stubs/hvf-stub.c F: target/i386/hvf/ From a6bb42f2239b85fccf93734bfb73bb8b2ddc8cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:33 +0200 Subject: [PATCH 20/47] MAINTAINERS: Fix KVM path expansion glob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KVM files has been moved from target-ARCH to the target/ARCH/ folder in commit fcf5ef2a. Fix the pathname expansion. Fixes: fcf5ef2a ("Move target-* CPU file into a target/ folder") Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ee89d67d68..4f001eda15 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -362,7 +362,7 @@ Overall KVM CPUs M: Paolo Bonzini L: kvm@vger.kernel.org S: Supported -F: */kvm.* +F: */*/kvm* F: accel/kvm/ F: accel/stubs/kvm-stub.c F: include/hw/kvm/ From 79ac391592c4853bc4d83bba6e513324ea56e44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:34 +0200 Subject: [PATCH 21/47] MAINTAINERS: Add an 'overall' entry for accelerators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4f001eda15..39bea4a0f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -416,6 +416,17 @@ S: Supported F: target/i386/kvm.c F: scripts/kvm/vmxcap +Guest CPU Cores (other accelerators) +------------------------------------ +Overall +M: Richard Henderson +R: Paolo Bonzini +S: Maintained +F: include/sysemu/accel.h +F: accel/accel.c +F: accel/Makefile.objs +F: accel/stubs/Makefile.objs + X86 HVF CPUs M: Cameron Esfahani M: Roman Bolshakov From f7091f5f052a6173a563319cb8c6c48f861276d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:35 +0200 Subject: [PATCH 22/47] MAINTAINERS: Cover the HAX accelerator stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cover accel/stubs/hax-stub.c in the HAXM section. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 39bea4a0f1..51f6ddf814 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -478,6 +478,7 @@ M: Colin Xu L: haxm-team@intel.com W: https://github.com/intel/haxm/issues S: Maintained +F: accel/stubs/hax-stub.c F: include/sysemu/hax.h F: target/i386/hax-* From f4bda37d3d580d5d28a07f7290f23be005322c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:37 +0200 Subject: [PATCH 23/47] Makefile: Remove dangerous EOL trailing backslash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One might get caught trying to understand unexpected Makefile behavior. Trailing backslash can help to split very long lines, but are rather dangerous when nothing follow. Preserve other developers debugging time by removing this one. Reviewed-by: Thomas Huth Reviewed-by: Alistair Francis Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b1b8a5a6d0..e7d8f1f027 100644 --- a/Makefile +++ b/Makefile @@ -420,7 +420,7 @@ MINIKCONF_ARGS = \ MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/backends/Kconfig $(SRC_PATH)/hw/Kconfig MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig) -MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \ +MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py $(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_DEPS) $(BUILD_DIR)/config-host.mak $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) > $@.tmp, "GEN", "$@.tmp") From 1e0ef873d9b271d373ce6d3aac6c99552b0d4a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:38 +0200 Subject: [PATCH 24/47] Makefile: Write MINIKCONF variables as one entry per line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having one entry per line helps reviews/refactors. As we are going to modify the MINIKCONF variables, split them now to ease further review. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index e7d8f1f027..b96a2d8790 100644 --- a/Makefile +++ b/Makefile @@ -418,12 +418,16 @@ MINIKCONF_ARGS = \ CONFIG_LINUX=$(CONFIG_LINUX) \ CONFIG_PVRDMA=$(CONFIG_PVRDMA) -MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/backends/Kconfig $(SRC_PATH)/hw/Kconfig -MINIKCONF_DEPS = $(MINIKCONF_INPUTS) $(wildcard $(SRC_PATH)/hw/*/Kconfig) +MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host \ + $(SRC_PATH)/backends/Kconfig \ + $(SRC_PATH)/hw/Kconfig +MINIKCONF_DEPS = $(MINIKCONF_INPUTS) \ + $(wildcard $(SRC_PATH)/hw/*/Kconfig) MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py $(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_DEPS) $(BUILD_DIR)/config-host.mak - $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) > $@.tmp, "GEN", "$@.tmp") + $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) \ + > $@.tmp, "GEN", "$@.tmp") $(call quiet-command, if test -f $@; then \ if cmp -s $@.old $@; then \ mv $@.tmp $@; \ From 06e89e13be25ef48196cb8ff40e9aeb3bf72f86b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:39 +0200 Subject: [PATCH 25/47] accel/Kconfig: Extract accel selectors into their own config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the accel selectors from the global Kconfig.host to their own Kconfig file. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Kconfig.host | 7 ------- Makefile | 1 + accel/Kconfig | 6 ++++++ 3 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 accel/Kconfig diff --git a/Kconfig.host b/Kconfig.host index 55136e037d..a6d871c399 100644 --- a/Kconfig.host +++ b/Kconfig.host @@ -2,9 +2,6 @@ # down to Kconfig. See also MINIKCONF_ARGS in the Makefile: # these two need to be kept in sync. -config KVM - bool - config LINUX bool @@ -31,10 +28,6 @@ config VHOST_KERNEL bool select VHOST -config XEN - bool - select FSDEV_9P if VIRTFS - config VIRTFS bool diff --git a/Makefile b/Makefile index b96a2d8790..ae025d41ea 100644 --- a/Makefile +++ b/Makefile @@ -420,6 +420,7 @@ MINIKCONF_ARGS = \ MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host \ $(SRC_PATH)/backends/Kconfig \ + $(SRC_PATH)/accel/Kconfig \ $(SRC_PATH)/hw/Kconfig MINIKCONF_DEPS = $(MINIKCONF_INPUTS) \ $(wildcard $(SRC_PATH)/hw/*/Kconfig) diff --git a/accel/Kconfig b/accel/Kconfig new file mode 100644 index 0000000000..c21802bb49 --- /dev/null +++ b/accel/Kconfig @@ -0,0 +1,6 @@ +config KVM + bool + +config XEN + bool + select FSDEV_9P if VIRTFS From 96df0fdd7f14107c1fb223742340c76669bcc9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:40 +0200 Subject: [PATCH 26/47] accel/Kconfig: Add the TCG selector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose the CONFIG_TCG selector to let minikconf.py uses it. When building with --disable-tcg build, this helps to deselect devices that are TCG-dependent. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- Makefile | 1 + accel/Kconfig | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Makefile b/Makefile index ae025d41ea..d4a971283c 100644 --- a/Makefile +++ b/Makefile @@ -405,6 +405,7 @@ endif MINIKCONF_ARGS = \ $(CONFIG_MINIKCONF_MODE) \ $@ $*/config-devices.mak.d $< $(MINIKCONF_INPUTS) \ + CONFIG_TCG=$(CONFIG_TCG) \ CONFIG_KVM=$(CONFIG_KVM) \ CONFIG_SPICE=$(CONFIG_SPICE) \ CONFIG_IVSHMEM=$(CONFIG_IVSHMEM) \ diff --git a/accel/Kconfig b/accel/Kconfig index c21802bb49..2ad94a3839 100644 --- a/accel/Kconfig +++ b/accel/Kconfig @@ -1,3 +1,6 @@ +config TCG + bool + config KVM bool From bb321b299e6879cd602bf6509eeecd62d3098d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 18 Jun 2020 14:33:42 +0200 Subject: [PATCH 27/47] accel/tcg: Add stub for probe_access() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TCG helpers were added in b92e5a22ec3 in softmmu_template.h. probe_write() was added in there in 3b4afc9e75a to be moved out to accel/tcg/cputlb.c in 3b08f0a9254, and was later refactored as probe_access() in c25c283df0f. Since it is a TCG specific helper, add a stub to avoid failures when building without TCG, such: target/arm/helper.o: In function `probe_read': include/exec/exec-all.h:362: undefined reference to `probe_access' Reviewed-by: Richard Henderson Reviewed-by: David Hildenbrand Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- accel/stubs/tcg-stub.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index 677191a69c..e4bbf997aa 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -22,3 +22,10 @@ void tb_flush(CPUState *cpu) void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) { } + +void *probe_access(CPUArchState *env, target_ulong addr, int size, + MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) +{ + /* Handled by hardware accelerator. */ + g_assert_not_reached(); +} From aaa1b70a0bb1fc1357c6c6828bcc8ff702e7eac4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Jun 2020 07:18:16 -0400 Subject: [PATCH 28/47] Makefile: simplify MINIKCONF rules There is no reason to write MINIKCONF_DEPS manually, since minikconf.py emits a dependency file, and also no reason to list multiple Kconfig files on the command line since they can be included from a master file in the top-level source directory. Signed-off-by: Paolo Bonzini --- Kconfig | 4 ++++ Makefile | 10 ++-------- 2 files changed, 6 insertions(+), 8 deletions(-) create mode 100644 Kconfig diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000000..bf694c42af --- /dev/null +++ b/Kconfig @@ -0,0 +1,4 @@ +source Kconfig.host +source backends/Kconfig +source accel/Kconfig +source hw/Kconfig diff --git a/Makefile b/Makefile index d4a971283c..32345c610e 100644 --- a/Makefile +++ b/Makefile @@ -404,7 +404,7 @@ endif # This has to be kept in sync with Kconfig.host. MINIKCONF_ARGS = \ $(CONFIG_MINIKCONF_MODE) \ - $@ $*/config-devices.mak.d $< $(MINIKCONF_INPUTS) \ + $@ $*/config-devices.mak.d $< $(SRC_PATH)/Kconfig \ CONFIG_TCG=$(CONFIG_TCG) \ CONFIG_KVM=$(CONFIG_KVM) \ CONFIG_SPICE=$(CONFIG_SPICE) \ @@ -419,15 +419,9 @@ MINIKCONF_ARGS = \ CONFIG_LINUX=$(CONFIG_LINUX) \ CONFIG_PVRDMA=$(CONFIG_PVRDMA) -MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host \ - $(SRC_PATH)/backends/Kconfig \ - $(SRC_PATH)/accel/Kconfig \ - $(SRC_PATH)/hw/Kconfig -MINIKCONF_DEPS = $(MINIKCONF_INPUTS) \ - $(wildcard $(SRC_PATH)/hw/*/Kconfig) MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py -$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_DEPS) $(BUILD_DIR)/config-host.mak +$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(SRC_PATH)/Kconfig $(BUILD_DIR)/config-host.mak $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) \ > $@.tmp, "GEN", "$@.tmp") $(call quiet-command, if test -f $@; then \ From 6c9cce1ff348709869262e4bd15ad4fedf513f17 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Jun 2020 05:19:27 -0400 Subject: [PATCH 29/47] target/i386: remove gen_io_end Force the end of a translation block after an I/O instruction in icount mode. For consistency, all CF_USE_ICOUNT code is kept in disas_insn instead of having it in gen_ins and gen_outs. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/translate.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/target/i386/translate.c b/target/i386/translate.c index b3fea54411..5ef72ff401 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -1128,9 +1128,6 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot) static inline void gen_ins(DisasContext *s, MemOp ot) { - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } gen_string_movl_A0_EDI(s); /* Note: we must do this dummy write first to be restartable in case of page fault. */ @@ -1143,16 +1140,10 @@ static inline void gen_ins(DisasContext *s, MemOp ot) gen_op_movl_T0_Dshift(s, ot); gen_op_add_reg_T0(s, s->aflag, R_EDI); gen_bpt_io(s, s->tmp2_i32, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } } static inline void gen_outs(DisasContext *s, MemOp ot) { - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } gen_string_movl_A0_ESI(s); gen_op_ld_v(s, ot, s->T0, s->A0); @@ -1163,9 +1154,6 @@ static inline void gen_outs(DisasContext *s, MemOp ot) gen_op_movl_T0_Dshift(s, ot); gen_op_add_reg_T0(s, s->aflag, R_ESI); gen_bpt_io(s, s->tmp2_i32, ot); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } } /* same method as Valgrind : we generate jumps to current or next @@ -6400,8 +6388,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]); gen_check_io(s, ot, pc_start - s->cs_base, SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4); + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + /* jump generated by gen_repz_ins */ } else { gen_ins(s, ot); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { @@ -6415,8 +6407,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]); gen_check_io(s, ot, pc_start - s->cs_base, svm_is_rep(prefixes) | 4); + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + /* jump generated by gen_repz_outs */ } else { gen_outs(s, ot); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { @@ -8039,7 +8035,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_helper_read_crN(s->T0, cpu_env, tcg_const_i32(reg)); gen_op_mov_reg_v(s, ot, rm, s->T0); if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); + gen_jmp(s, s->pc - s->cs_base); } } break; From c0c8445255b2b5b440c355431c8b01b7b7b7c8cf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Jun 2020 05:53:36 -0400 Subject: [PATCH 30/47] target/i386: implement undocumented "smsw r32" behavior In 32-bit mode, the higher 16 bits of the destination register are undefined. In practice CR0[31:0] is stored, just like in 64-bit mode, so just remove the "if" that currently differentiates the behavior. Reviewed-by: Richard Henderson Reported-by: Roman Bolshakov Reviewed-by: Roman Bolshakov Signed-off-by: Paolo Bonzini --- target/i386/translate.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/target/i386/translate.c b/target/i386/translate.c index 5ef72ff401..a1d31f09c1 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -7579,12 +7579,13 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) CASE_MODRM_OP(4): /* smsw */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0); tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, cr[0])); - if (CODE64(s)) { - mod = (modrm >> 6) & 3; - ot = (mod != 3 ? MO_16 : s->dflag); - } else { - ot = MO_16; - } + /* + * In 32-bit mode, the higher 16 bits of the destination + * register are undefined. In practice CR0[31:0] is stored + * just like in 64-bit mode. + */ + mod = (modrm >> 6) & 3; + ot = (mod != 3 ? MO_16 : s->dflag); gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1); break; case 0xee: /* rdpkru */ From e1e43813e7908b063938a3d01f172f88f6190c80 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 30 Jun 2020 09:49:27 -0400 Subject: [PATCH 31/47] KVM: x86: believe what KVM says about WAITPKG Currently, QEMU is overriding KVM_GET_SUPPORTED_CPUID's answer for the WAITPKG bit depending on the "-overcommit cpu-pm" setting. This is a bad idea because it does not even check if the host supports it, but it can be done in x86_cpu_realizefn just like we do for the MONITOR bit. This patch moves it there, while making it conditional on host support for the related UMWAIT MSR. Cc: qemu-stable@nongnu.org Reported-by: Maxim Levitsky Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 +++ target/i386/kvm.c | 11 +++++------ target/i386/kvm_i386.h | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1546cd78ff..105eb47eab 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6509,6 +6509,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx, &cpu->mwait.ecx, &cpu->mwait.edx); env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR; + if (kvm_enabled() && kvm_has_waitpkg()) { + env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG; + } } if (kvm_enabled() && cpu->ucode_rev == 0) { cpu->ucode_rev = kvm_arch_get_supported_msr_feature(kvm_state, diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 2b6b7443d2..b8455c89ed 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -411,12 +411,6 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, if (host_tsx_blacklisted()) { ret &= ~(CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_HLE); } - } else if (function == 7 && index == 0 && reg == R_ECX) { - if (enable_cpu_pm) { - ret |= CPUID_7_0_ECX_WAITPKG; - } else { - ret &= ~CPUID_7_0_ECX_WAITPKG; - } } else if (function == 7 && index == 0 && reg == R_EDX) { /* * Linux v4.17-v4.20 incorrectly return ARCH_CAPABILITIES on SVM hosts. @@ -4730,3 +4724,8 @@ int kvm_arch_msi_data_to_gsi(uint32_t data) { abort(); } + +bool kvm_has_waitpkg(void) +{ + return has_msr_umwait; +} diff --git a/target/i386/kvm_i386.h b/target/i386/kvm_i386.h index 00bde7acaf..064b8798a2 100644 --- a/target/i386/kvm_i386.h +++ b/target/i386/kvm_i386.h @@ -44,6 +44,7 @@ void kvm_put_apicbase(X86CPU *cpu, uint64_t value); bool kvm_enable_x2apic(void); bool kvm_has_x2apic_api(void); +bool kvm_has_waitpkg(void); bool kvm_hv_vpindex_settable(void); From e4f6278557148151e77260b872b41bcd7ceb4737 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 30 Jun 2020 11:35:46 -0400 Subject: [PATCH 32/47] target/i386: sev: provide proper error reporting for query-sev-capabilities The query-sev-capabilities was reporting errors through error_report; change it to use Error** so that the cause of the failure is clearer. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini --- target/i386/monitor.c | 10 +--------- target/i386/sev-stub.c | 3 ++- target/i386/sev.c | 18 +++++++++--------- target/i386/sev_i386.h | 2 +- 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/target/i386/monitor.c b/target/i386/monitor.c index 27ebfa3ad2..7abae3c8df 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -726,13 +726,5 @@ SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp) SevCapability *qmp_query_sev_capabilities(Error **errp) { - SevCapability *data; - - data = sev_get_capabilities(); - if (!data) { - error_setg(errp, "SEV feature is not available"); - return NULL; - } - - return data; + return sev_get_capabilities(errp); } diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c index e5ee13309c..88e3f39a1e 100644 --- a/target/i386/sev-stub.c +++ b/target/i386/sev-stub.c @@ -44,7 +44,8 @@ char *sev_get_launch_measurement(void) return NULL; } -SevCapability *sev_get_capabilities(void) +SevCapability *sev_get_capabilities(Error **errp) { + error_setg(errp, "SEV is not available in this QEMU"); return NULL; } diff --git a/target/i386/sev.c b/target/i386/sev.c index f100a53231..7012b1d4b1 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -399,7 +399,7 @@ sev_get_info(void) static int sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, - size_t *cert_chain_len) + size_t *cert_chain_len, Error **errp) { guchar *pdh_data = NULL; guchar *cert_chain_data = NULL; @@ -410,8 +410,8 @@ sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err); if (r < 0) { if (err != SEV_RET_INVALID_LEN) { - error_report("failed to export PDH cert ret=%d fw_err=%d (%s)", - r, err, fw_error_to_str(err)); + error_setg(errp, "failed to export PDH cert ret=%d fw_err=%d (%s)", + r, err, fw_error_to_str(err)); return 1; } } @@ -423,8 +423,8 @@ sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err); if (r < 0) { - error_report("failed to export PDH cert ret=%d fw_err=%d (%s)", - r, err, fw_error_to_str(err)); + error_setg(errp, "failed to export PDH cert ret=%d fw_err=%d (%s)", + r, err, fw_error_to_str(err)); goto e_free; } @@ -441,7 +441,7 @@ e_free: } SevCapability * -sev_get_capabilities(void) +sev_get_capabilities(Error **errp) { SevCapability *cap = NULL; guchar *pdh_data = NULL; @@ -452,13 +452,13 @@ sev_get_capabilities(void) fd = open(DEFAULT_SEV_DEVICE, O_RDWR); if (fd < 0) { - error_report("%s: Failed to open %s '%s'", __func__, - DEFAULT_SEV_DEVICE, strerror(errno)); + error_setg_errno(errp, errno, "Failed to open %s", + DEFAULT_SEV_DEVICE); return NULL; } if (sev_get_pdh_info(fd, &pdh_data, &pdh_len, - &cert_chain_data, &cert_chain_len)) { + &cert_chain_data, &cert_chain_len, errp)) { goto out; } diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h index 8eb7de1bef..4db6960f60 100644 --- a/target/i386/sev_i386.h +++ b/target/i386/sev_i386.h @@ -34,6 +34,6 @@ extern SevInfo *sev_get_info(void); extern uint32_t sev_get_cbit_position(void); extern uint32_t sev_get_reduced_phys_bits(void); extern char *sev_get_launch_measurement(void); -extern SevCapability *sev_get_capabilities(void); +extern SevCapability *sev_get_capabilities(Error **errp); #endif From 1b38750c40281dd0d068f8536b2ea95d7b9bd585 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 30 Jun 2020 11:38:18 -0400 Subject: [PATCH 33/47] target/i386: sev: fail query-sev-capabilities if QEMU cannot use SEV In some cases, such as if the kvm-amd "sev" module parameter is set to 0, SEV will be unavailable but query-sev-capabilities will still return all the information. This tricks libvirt into erroneously reporting that SEV is available. Check the actual usability of the feature and return the appropriate error if QEMU cannot use KVM or KVM cannot use SEV. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/i386/sev.c b/target/i386/sev.c index 7012b1d4b1..c3ecf86704 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -450,6 +450,15 @@ sev_get_capabilities(Error **errp) uint32_t ebx; int fd; + if (!kvm_enabled()) { + error_setg(errp, "KVM not enabled"); + return NULL; + } + if (kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, NULL) < 0) { + error_setg(errp, "SEV is not enabled in KVM"); + return NULL; + } + fd = open(DEFAULT_SEV_DEVICE, O_RDWR); if (fd < 0) { error_setg_errno(errp, errno, "Failed to open %s", From dd3b00202a5ff4153a0088917ac69d2e6cd2bc1f Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Wed, 1 Jul 2020 18:54:43 +0800 Subject: [PATCH 34/47] iscsi: handle check condition status in retry loop The handling of check condition was incorrect because we would only do it after retries exceed maximum. Fixes: 8c460269aa ("iscsi: base all handling of check condition on scsi_sense_to_errno") Signed-off-by: Xie Yongji Message-Id: <20200701105444.3226-1-xieyongji@bytedance.com> Signed-off-by: Paolo Bonzini --- block/iscsi.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 6c2e353e1a..7519b0970f 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -266,16 +266,16 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, timer_mod(&iTask->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + retry_time); iTask->do_retry = 1; - } - } else if (status == SCSI_STATUS_CHECK_CONDITION) { - int error = iscsi_translate_sense(&task->sense); - if (error == EAGAIN) { - error_report("iSCSI CheckCondition: %s", - iscsi_get_error(iscsi)); - iTask->do_retry = 1; - } else { - iTask->err_code = -error; - iTask->err_str = g_strdup(iscsi_get_error(iscsi)); + } else if (status == SCSI_STATUS_CHECK_CONDITION) { + int error = iscsi_translate_sense(&task->sense); + if (error == EAGAIN) { + error_report("iSCSI CheckCondition: %s", + iscsi_get_error(iscsi)); + iTask->do_retry = 1; + } else { + iTask->err_code = -error; + iTask->err_str = g_strdup(iscsi_get_error(iscsi)); + } } } } From c58daf76a6d9aee7502d0fcd5f3e7ec9b9861646 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Wed, 1 Jul 2020 18:54:44 +0800 Subject: [PATCH 35/47] iscsi: return -EIO when sense fields are meaningless When an I/O request failed, now we only return correct value on scsi check condition. We should also have a default errno such as -EIO in other case. Signed-off-by: Xie Yongji Message-Id: <20200701105444.3226-2-xieyongji@bytedance.com> Signed-off-by: Paolo Bonzini --- block/iscsi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 7519b0970f..bd2122a3a4 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -241,9 +241,11 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, iTask->status = status; iTask->do_retry = 0; + iTask->err_code = 0; iTask->task = task; if (status != SCSI_STATUS_GOOD) { + iTask->err_code = -EIO; if (iTask->retries++ < ISCSI_CMD_RETRIES) { if (status == SCSI_STATUS_BUSY || status == SCSI_STATUS_TIMEOUT || From 143a768c57b8d77b348f727c55f073eb40360955 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Sat, 20 Jun 2020 15:32:07 +0200 Subject: [PATCH 36/47] checkpatch: Change occurences of 'kernel' to 'qemu' in user messages It is odd that we inform user that, for example, his current working directory is not kernel root, when, in face, we mean qemu root. Replace that and few other similar odd user messages. Signed-off-by: Aleksandar Markovic Message-Id: <20200620133207.26849-3-aleksandar.qemu.devel@gmail.com> Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 2d2e922d89..bd3faa154c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -49,7 +49,7 @@ Version: $V Options: -q, --quiet quiet - --no-tree run without a kernel tree + --no-tree run without a qemu tree --no-signoff do not check for 'Signed-off-by' line --patch treat FILE as patchfile --branch treat args as GIT revision list @@ -57,7 +57,7 @@ Options: --terse one line per report -f, --file treat FILE as regular source file --strict fail if only warnings are found - --root=PATH PATH to the kernel tree root + --root=PATH PATH to the qemu tree root --no-summary suppress the per-file summary --mailback only produce a report in case of warnings/errors --summary-file include the filename in summary @@ -203,7 +203,7 @@ if ($tree) { } if (!defined $root) { - print "Must be run from the top-level dir. of a kernel tree\n"; + print "Must be run from the top-level dir. of a qemu tree\n"; exit(2); } } From cbe0dad1906d29d9ea83169b672e9e709c9fc1f8 Mon Sep 17 00:00:00 2001 From: Luwei Kang Date: Tue, 30 Jun 2020 14:38:33 +0800 Subject: [PATCH 37/47] target/i386: Correct the warning message of Intel PT The CPUID level need to be set to 0x14 manually on old machine-type if Intel PT is enabled in guest. E.g. the CPUID[0].EAX(level)=7 and CPUID[7].EBX[25](intel-pt)=1 when the Qemu with "-machine pc-i440fx-3.1 -cpu qemu64,+intel-pt" parameter. This patch corrects the warning message of the previous submission(ddc2fc9). Signed-off-by: Luwei Kang Message-Id: <1593499113-4768-1-git-send-email-luwei.kang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 105eb47eab..1dde34dce7 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6398,7 +6398,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) } else if (cpu->env.cpuid_min_level < 0x14) { mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, - "Intel PT need CPUID leaf 0x14, please set by \"-cpu ...,+intel-pt,level=0x14\""); + "Intel PT need CPUID leaf 0x14, please set by \"-cpu ...,+intel-pt,min-level=0x14\""); } } From 421a75e283f6bad2ac64119ecf6a1dfd3ebfda61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 2 Jul 2020 12:40:17 +0200 Subject: [PATCH 38/47] cpus: Move CPU code from exec.c to cpus-common.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code was introduced with SMP support in commit 6a00d60127, later commit 267f685b8b moved CPU list management to common code but forgot this code. Move now and simplify ifdef'ry. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200702104017.14057-1-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- cpus-common.c | 18 ++++++++++++++++++ exec.c | 22 ---------------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 8f5512b3d7..34044f4e4c 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -72,6 +72,8 @@ static int cpu_get_free_index(void) return max_cpu_index; } +CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); + void cpu_list_add(CPUState *cpu) { QEMU_LOCK_GUARD(&qemu_cpu_list_lock); @@ -96,6 +98,22 @@ void cpu_list_remove(CPUState *cpu) cpu->cpu_index = UNASSIGNED_CPU_INDEX; } +CPUState *qemu_get_cpu(int index) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + if (cpu->cpu_index == index) { + return cpu; + } + } + + return NULL; +} + +/* current CPU in the current thread. It is only valid inside cpu_exec() */ +__thread CPUState *current_cpu; + struct qemu_work_item { QSIMPLEQ_ENTRY(qemu_work_item) node; run_on_cpu_func func; diff --git a/exec.c b/exec.c index 893636176e..6f381f98e2 100644 --- a/exec.c +++ b/exec.c @@ -98,12 +98,6 @@ AddressSpace address_space_memory; static MemoryRegion io_mem_unassigned; #endif -CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); - -/* current CPU in the current thread. It is only valid inside - cpu_exec() */ -__thread CPUState *current_cpu; - uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; @@ -832,22 +826,6 @@ const VMStateDescription vmstate_cpu_common = { } }; -#endif - -CPUState *qemu_get_cpu(int index) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - if (cpu->cpu_index == index) { - return cpu; - } - } - - return NULL; -} - -#if !defined(CONFIG_USER_ONLY) void cpu_address_space_init(CPUState *cpu, int asidx, const char *prefix, MemoryRegion *mr) { From 0b33521ea16463d7f942ddb2b354fa029c96231f Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Wed, 1 Jul 2020 10:52:31 -0400 Subject: [PATCH 39/47] pc: fix leak in pc_system_flash_cleanup_unused tries to fix a leak detected when building with --enable-sanitizers: ./i386-softmmu/qemu-system-i386 Upon exit: ==13576==ERROR: LeakSanitizer: detected memory leaks Direct leak of 1216 byte(s) in 1 object(s) allocated from: #0 0x7f9d2ed5c628 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5) #1 0x7f9d2e963500 in g_malloc (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.) #2 0x55fa646d25cc in object_new_with_type /tmp/qemu/qom/object.c:686 #3 0x55fa63dbaa88 in qdev_new /tmp/qemu/hw/core/qdev.c:140 #4 0x55fa638a533f in pc_pflash_create /tmp/qemu/hw/i386/pc_sysfw.c:88 #5 0x55fa638a54c4 in pc_system_flash_create /tmp/qemu/hw/i386/pc_sysfw.c:106 #6 0x55fa646caa1d in object_init_with_type /tmp/qemu/qom/object.c:369 #7 0x55fa646d20b5 in object_initialize_with_type /tmp/qemu/qom/object.c:511 #8 0x55fa646d2606 in object_new_with_type /tmp/qemu/qom/object.c:687 #9 0x55fa639431e9 in qemu_init /tmp/qemu/softmmu/vl.c:3878 #10 0x55fa6335c1b8 in main /tmp/qemu/softmmu/main.c:48 #11 0x7f9d2cf06e0a in __libc_start_main ../csu/libc-start.c:308 #12 0x55fa6335f8e9 in _start (/tmp/qemu/build/i386-softmmu/qemu-system-i386) Signed-off-by: Alexander Bulekov Message-Id: <20200701145231.19531-1-alxndr@bu.edu> Signed-off-by: Paolo Bonzini --- hw/i386/pc_sysfw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index ec2a3b3e7e..71ce273a14 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -93,6 +93,11 @@ static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms, object_property_add_child(OBJECT(pcms), name, OBJECT(dev)); object_property_add_alias(OBJECT(pcms), alias_prop_name, OBJECT(dev), "drive"); + /* + * The returned reference is tied to the child property and + * will be removed with object_unparent. + */ + object_unref(OBJECT(dev)); return PFLASH_CFI01(dev); } From c7f419f5841a840f3b90e839ef014b94131e5df8 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 29 Jun 2020 11:35:02 +0200 Subject: [PATCH 40/47] softmmu: move softmmu only files from root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit move arch_init, balloon, cpus, ioport, memory, memory_mapping, qtest. They are all specific to CONFIG_SOFTMMU. Signed-off-by: Claudio Fontana Reviewed-by: Alex Bennée Reviewed-by: Laurent Vivier Reviewed-by: Thomas Huth Message-Id: <20200629093504.3228-2-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 12 ++++++------ Makefile.target | 7 ++----- softmmu/Makefile.objs | 10 ++++++++++ arch_init.c => softmmu/arch_init.c | 0 balloon.c => softmmu/balloon.c | 0 cpus.c => softmmu/cpus.c | 0 ioport.c => softmmu/ioport.c | 0 memory.c => softmmu/memory.c | 0 memory_mapping.c => softmmu/memory_mapping.c | 0 qtest.c => softmmu/qtest.c | 0 10 files changed, 18 insertions(+), 11 deletions(-) rename arch_init.c => softmmu/arch_init.c (100%) rename balloon.c => softmmu/balloon.c (100%) rename cpus.c => softmmu/cpus.c (100%) rename ioport.c => softmmu/ioport.c (100%) rename memory.c => softmmu/memory.c (100%) rename memory_mapping.c => softmmu/memory_mapping.c (100%) rename qtest.c => softmmu/qtest.c (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 51f6ddf814..28f33123ec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -115,7 +115,7 @@ Overall TCG CPUs M: Richard Henderson R: Paolo Bonzini S: Maintained -F: cpus.c +F: softmmu/cpus.c F: cpus-common.c F: exec.c F: accel/tcg/ @@ -1724,7 +1724,7 @@ M: David Hildenbrand S: Maintained F: hw/virtio/virtio-balloon*.c F: include/hw/virtio/virtio-balloon.h -F: balloon.c +F: softmmu/balloon.c F: include/sysemu/balloon.h virtio-9p @@ -2203,12 +2203,12 @@ Memory API M: Paolo Bonzini S: Supported F: include/exec/ioport.h -F: ioport.c F: include/exec/memop.h F: include/exec/memory.h F: include/exec/ram_addr.h F: include/exec/ramblock.h -F: memory.c +F: softmmu/ioport.c +F: softmmu/memory.c F: include/exec/memory-internal.h F: exec.c F: scripts/coccinelle/memory-region-housekeeping.cocci @@ -2240,13 +2240,13 @@ F: ui/cocoa.m Main loop M: Paolo Bonzini S: Maintained -F: cpus.c F: include/qemu/main-loop.h F: include/sysemu/runstate.h F: util/main-loop.c F: util/qemu-timer.c F: softmmu/vl.c F: softmmu/main.c +F: softmmu/cpus.c F: qapi/run-state.json Human Monitor (HMP) @@ -2401,7 +2401,7 @@ M: Thomas Huth M: Laurent Vivier R: Paolo Bonzini S: Maintained -F: qtest.c +F: softmmu/qtest.c F: accel/qtest.c F: tests/qtest/ X: tests/qtest/bios-tables-test-allowed-diff.h diff --git a/Makefile.target b/Makefile.target index 02bd9d7117..ffa2657269 100644 --- a/Makefile.target +++ b/Makefile.target @@ -152,16 +152,13 @@ endif #CONFIG_BSD_USER ######################################################### # System emulator target ifdef CONFIG_SOFTMMU -obj-y += arch_init.o cpus.o gdbstub.o balloon.o ioport.o -obj-y += qtest.o +obj-y += softmmu/ +obj-y += gdbstub.o obj-y += dump/ obj-y += hw/ obj-y += monitor/ obj-y += qapi/ -obj-y += memory.o -obj-y += memory_mapping.o obj-y += migration/ram.o -obj-y += softmmu/ LIBS := $(libs_softmmu) $(LIBS) # Hardware support diff --git a/softmmu/Makefile.objs b/softmmu/Makefile.objs index dd15c24346..a4bd9f2f52 100644 --- a/softmmu/Makefile.objs +++ b/softmmu/Makefile.objs @@ -1,3 +1,13 @@ softmmu-main-y = softmmu/main.o + +obj-y += arch_init.o +obj-y += cpus.o +obj-y += balloon.o +obj-y += ioport.o +obj-y += memory.o +obj-y += memory_mapping.o + +obj-y += qtest.o + obj-y += vl.o vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS) diff --git a/arch_init.c b/softmmu/arch_init.c similarity index 100% rename from arch_init.c rename to softmmu/arch_init.c diff --git a/balloon.c b/softmmu/balloon.c similarity index 100% rename from balloon.c rename to softmmu/balloon.c diff --git a/cpus.c b/softmmu/cpus.c similarity index 100% rename from cpus.c rename to softmmu/cpus.c diff --git a/ioport.c b/softmmu/ioport.c similarity index 100% rename from ioport.c rename to softmmu/ioport.c diff --git a/memory.c b/softmmu/memory.c similarity index 100% rename from memory.c rename to softmmu/memory.c diff --git a/memory_mapping.c b/softmmu/memory_mapping.c similarity index 100% rename from memory_mapping.c rename to softmmu/memory_mapping.c diff --git a/qtest.c b/softmmu/qtest.c similarity index 100% rename from qtest.c rename to softmmu/qtest.c From b0c3cf9407e642d74d1bbd18f8846872152a92df Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 29 Jun 2020 11:35:03 +0200 Subject: [PATCH 41/47] cpu-throttle: new module, extracted from cpus.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit move the vcpu throttling functionality into its own module. This functionality is not specific to any accelerator, and it is used currently by migration to slow down guests to try to have migrations converge, and by the cocoa MacOS UI to throttle speed. cpu-throttle contains the controls to adjust and inspect throttle settings, start (set) and stop vcpu throttling, and the throttling function itself that is run periodically on vcpus to make them take a nap. Execution of the throttling function on all vcpus is triggered by a timer, registered at module initialization. No functionality change. Signed-off-by: Claudio Fontana Reviewed-by: Alex Bennée Reviewed-by: Laurent Vivier Message-Id: <20200629093504.3228-3-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + include/hw/core/cpu.h | 37 ----------- include/qemu/main-loop.h | 5 ++ include/sysemu/cpu-throttle.h | 68 +++++++++++++++++++ migration/migration.c | 1 + migration/ram.c | 1 + softmmu/Makefile.objs | 1 + softmmu/cpu-throttle.c | 122 ++++++++++++++++++++++++++++++++++ softmmu/cpus.c | 95 +++----------------------- ui/cocoa.m | 1 + 10 files changed, 208 insertions(+), 124 deletions(-) create mode 100644 include/sysemu/cpu-throttle.h create mode 100644 softmmu/cpu-throttle.c diff --git a/MAINTAINERS b/MAINTAINERS index 28f33123ec..361ae5c662 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2247,6 +2247,7 @@ F: util/qemu-timer.c F: softmmu/vl.c F: softmmu/main.c F: softmmu/cpus.c +F: softmmu/cpu-throttle.c F: qapi/run-state.json Human Monitor (HMP) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index b3f4b79318..5542577d2b 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -822,43 +822,6 @@ bool cpu_exists(int64_t id); */ CPUState *cpu_by_arch_id(int64_t id); -/** - * cpu_throttle_set: - * @new_throttle_pct: Percent of sleep time. Valid range is 1 to 99. - * - * Throttles all vcpus by forcing them to sleep for the given percentage of - * time. A throttle_percentage of 25 corresponds to a 75% duty cycle roughly. - * (example: 10ms sleep for every 30ms awake). - * - * cpu_throttle_set can be called as needed to adjust new_throttle_pct. - * Once the throttling starts, it will remain in effect until cpu_throttle_stop - * is called. - */ -void cpu_throttle_set(int new_throttle_pct); - -/** - * cpu_throttle_stop: - * - * Stops the vcpu throttling started by cpu_throttle_set. - */ -void cpu_throttle_stop(void); - -/** - * cpu_throttle_active: - * - * Returns: %true if the vcpus are currently being throttled, %false otherwise. - */ -bool cpu_throttle_active(void); - -/** - * cpu_throttle_get_percentage: - * - * Returns the vcpu throttle percentage. See cpu_throttle_set for details. - * - * Returns: The throttle percentage in range 1 to 99. - */ -int cpu_throttle_get_percentage(void); - #ifndef CONFIG_USER_ONLY typedef void (*CPUInterruptHandler)(CPUState *, int); diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index a6d20b0719..8e98613656 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -303,6 +303,11 @@ void qemu_mutex_unlock_iothread(void); */ void qemu_cond_wait_iothread(QemuCond *cond); +/* + * qemu_cond_timedwait_iothread: like the previous, but with timeout + */ +void qemu_cond_timedwait_iothread(QemuCond *cond, int ms); + /* internal interfaces */ void qemu_fd_register(int fd); diff --git a/include/sysemu/cpu-throttle.h b/include/sysemu/cpu-throttle.h new file mode 100644 index 0000000000..d65bdef6d0 --- /dev/null +++ b/include/sysemu/cpu-throttle.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012 SUSE LINUX Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + * + */ + +#ifndef SYSEMU_CPU_THROTTLE_H +#define SYSEMU_CPU_THROTTLE_H + +#include "qemu/timer.h" + +/** + * cpu_throttle_init: + * + * Initialize the CPU throttling API. + */ +void cpu_throttle_init(void); + +/** + * cpu_throttle_set: + * @new_throttle_pct: Percent of sleep time. Valid range is 1 to 99. + * + * Throttles all vcpus by forcing them to sleep for the given percentage of + * time. A throttle_percentage of 25 corresponds to a 75% duty cycle roughly. + * (example: 10ms sleep for every 30ms awake). + * + * cpu_throttle_set can be called as needed to adjust new_throttle_pct. + * Once the throttling starts, it will remain in effect until cpu_throttle_stop + * is called. + */ +void cpu_throttle_set(int new_throttle_pct); + +/** + * cpu_throttle_stop: + * + * Stops the vcpu throttling started by cpu_throttle_set. + */ +void cpu_throttle_stop(void); + +/** + * cpu_throttle_active: + * + * Returns: %true if the vcpus are currently being throttled, %false otherwise. + */ +bool cpu_throttle_active(void); + +/** + * cpu_throttle_get_percentage: + * + * Returns the vcpu throttle percentage. See cpu_throttle_set for details. + * + * Returns: The throttle percentage in range 1 to 99. + */ +int cpu_throttle_get_percentage(void); + +#endif /* SYSEMU_CPU_THROTTLE_H */ diff --git a/migration/migration.c b/migration/migration.c index 92e44e021e..4e658c397e 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -23,6 +23,7 @@ #include "socket.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" +#include "sysemu/cpu-throttle.h" #include "rdma.h" #include "ram.h" #include "migration/global_state.h" diff --git a/migration/ram.c b/migration/ram.c index 5554a7d2d8..76d4fee5d5 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -52,6 +52,7 @@ #include "migration/colo.h" #include "block.h" #include "sysemu/sysemu.h" +#include "sysemu/cpu-throttle.h" #include "savevm.h" #include "qemu/iov.h" #include "multifd.h" diff --git a/softmmu/Makefile.objs b/softmmu/Makefile.objs index a4bd9f2f52..a414a74c50 100644 --- a/softmmu/Makefile.objs +++ b/softmmu/Makefile.objs @@ -2,6 +2,7 @@ softmmu-main-y = softmmu/main.o obj-y += arch_init.o obj-y += cpus.o +obj-y += cpu-throttle.o obj-y += balloon.o obj-y += ioport.o obj-y += memory.o diff --git a/softmmu/cpu-throttle.c b/softmmu/cpu-throttle.c new file mode 100644 index 0000000000..4e6b2818ca --- /dev/null +++ b/softmmu/cpu-throttle.c @@ -0,0 +1,122 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/thread.h" +#include "hw/core/cpu.h" +#include "qemu/main-loop.h" +#include "sysemu/cpus.h" +#include "sysemu/cpu-throttle.h" + +/* vcpu throttling controls */ +static QEMUTimer *throttle_timer; +static unsigned int throttle_percentage; + +#define CPU_THROTTLE_PCT_MIN 1 +#define CPU_THROTTLE_PCT_MAX 99 +#define CPU_THROTTLE_TIMESLICE_NS 10000000 + +static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque) +{ + double pct; + double throttle_ratio; + int64_t sleeptime_ns, endtime_ns; + + if (!cpu_throttle_get_percentage()) { + return; + } + + pct = (double)cpu_throttle_get_percentage() / 100; + throttle_ratio = pct / (1 - pct); + /* Add 1ns to fix double's rounding error (like 0.9999999...) */ + sleeptime_ns = (int64_t)(throttle_ratio * CPU_THROTTLE_TIMESLICE_NS + 1); + endtime_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + sleeptime_ns; + while (sleeptime_ns > 0 && !cpu->stop) { + if (sleeptime_ns > SCALE_MS) { + qemu_cond_timedwait_iothread(cpu->halt_cond, + sleeptime_ns / SCALE_MS); + } else { + qemu_mutex_unlock_iothread(); + g_usleep(sleeptime_ns / SCALE_US); + qemu_mutex_lock_iothread(); + } + sleeptime_ns = endtime_ns - qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + } + atomic_set(&cpu->throttle_thread_scheduled, 0); +} + +static void cpu_throttle_timer_tick(void *opaque) +{ + CPUState *cpu; + double pct; + + /* Stop the timer if needed */ + if (!cpu_throttle_get_percentage()) { + return; + } + CPU_FOREACH(cpu) { + if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) { + async_run_on_cpu(cpu, cpu_throttle_thread, + RUN_ON_CPU_NULL); + } + } + + pct = (double)cpu_throttle_get_percentage() / 100; + timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + + CPU_THROTTLE_TIMESLICE_NS / (1 - pct)); +} + +void cpu_throttle_set(int new_throttle_pct) +{ + /* Ensure throttle percentage is within valid range */ + new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX); + new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN); + + atomic_set(&throttle_percentage, new_throttle_pct); + + timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + + CPU_THROTTLE_TIMESLICE_NS); +} + +void cpu_throttle_stop(void) +{ + atomic_set(&throttle_percentage, 0); +} + +bool cpu_throttle_active(void) +{ + return (cpu_throttle_get_percentage() != 0); +} + +int cpu_throttle_get_percentage(void) +{ + return atomic_read(&throttle_percentage); +} + +void cpu_throttle_init(void) +{ + throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, + cpu_throttle_timer_tick, NULL); +} diff --git a/softmmu/cpus.c b/softmmu/cpus.c index d94456ed29..a802e899ab 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -61,6 +61,8 @@ #include "hw/boards.h" #include "hw/hw.h" +#include "sysemu/cpu-throttle.h" + #ifdef CONFIG_LINUX #include @@ -84,14 +86,6 @@ static QemuMutex qemu_global_mutex; int64_t max_delay; int64_t max_advance; -/* vcpu throttling controls */ -static QEMUTimer *throttle_timer; -static unsigned int throttle_percentage; - -#define CPU_THROTTLE_PCT_MIN 1 -#define CPU_THROTTLE_PCT_MAX 99 -#define CPU_THROTTLE_TIMESLICE_NS 10000000 - bool cpu_is_stopped(CPUState *cpu) { return cpu->stopped || !runstate_is_running(); @@ -738,90 +732,12 @@ static const VMStateDescription vmstate_timers = { } }; -static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque) -{ - double pct; - double throttle_ratio; - int64_t sleeptime_ns, endtime_ns; - - if (!cpu_throttle_get_percentage()) { - return; - } - - pct = (double)cpu_throttle_get_percentage()/100; - throttle_ratio = pct / (1 - pct); - /* Add 1ns to fix double's rounding error (like 0.9999999...) */ - sleeptime_ns = (int64_t)(throttle_ratio * CPU_THROTTLE_TIMESLICE_NS + 1); - endtime_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + sleeptime_ns; - while (sleeptime_ns > 0 && !cpu->stop) { - if (sleeptime_ns > SCALE_MS) { - qemu_cond_timedwait(cpu->halt_cond, &qemu_global_mutex, - sleeptime_ns / SCALE_MS); - } else { - qemu_mutex_unlock_iothread(); - g_usleep(sleeptime_ns / SCALE_US); - qemu_mutex_lock_iothread(); - } - sleeptime_ns = endtime_ns - qemu_clock_get_ns(QEMU_CLOCK_REALTIME); - } - atomic_set(&cpu->throttle_thread_scheduled, 0); -} - -static void cpu_throttle_timer_tick(void *opaque) -{ - CPUState *cpu; - double pct; - - /* Stop the timer if needed */ - if (!cpu_throttle_get_percentage()) { - return; - } - CPU_FOREACH(cpu) { - if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) { - async_run_on_cpu(cpu, cpu_throttle_thread, - RUN_ON_CPU_NULL); - } - } - - pct = (double)cpu_throttle_get_percentage()/100; - timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + - CPU_THROTTLE_TIMESLICE_NS / (1-pct)); -} - -void cpu_throttle_set(int new_throttle_pct) -{ - /* Ensure throttle percentage is within valid range */ - new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX); - new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN); - - atomic_set(&throttle_percentage, new_throttle_pct); - - timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + - CPU_THROTTLE_TIMESLICE_NS); -} - -void cpu_throttle_stop(void) -{ - atomic_set(&throttle_percentage, 0); -} - -bool cpu_throttle_active(void) -{ - return (cpu_throttle_get_percentage() != 0); -} - -int cpu_throttle_get_percentage(void) -{ - return atomic_read(&throttle_percentage); -} - void cpu_ticks_init(void) { seqlock_init(&timers_state.vm_clock_seqlock); qemu_spin_init(&timers_state.vm_clock_lock); vmstate_register(NULL, 0, &vmstate_timers, &timers_state); - throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, - cpu_throttle_timer_tick, NULL); + cpu_throttle_init(); } void configure_icount(QemuOpts *opts, Error **errp) @@ -1879,6 +1795,11 @@ void qemu_cond_wait_iothread(QemuCond *cond) qemu_cond_wait(cond, &qemu_global_mutex); } +void qemu_cond_timedwait_iothread(QemuCond *cond, int ms) +{ + qemu_cond_timedwait(cond, &qemu_global_mutex, ms); +} + static bool all_vcpus_paused(void) { CPUState *cpu; diff --git a/ui/cocoa.m b/ui/cocoa.m index cb556e4e66..0910b4a716 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -32,6 +32,7 @@ #include "ui/input.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" +#include "sysemu/cpu-throttle.h" #include "qapi/error.h" #include "qapi/qapi-commands-block.h" #include "qapi/qapi-commands-misc.h" From 2f7057ac97579f940139ac85d8b757d47ef0efab Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 18 Jun 2020 09:40:01 +0200 Subject: [PATCH 42/47] softmmu/vl: Remove the check for colons in -accel parameters The new -accel option does not accept colons in the parameters anymore (since it does not convert the parameters to -machine accel=... parameters anymore). Thus we can now remove the check for colons in -accel: $ qemu-system-x86_64 -accel kvm:tcg qemu-system-x86_64: -accel kvm:tcg: invalid accelerator kvm:tcg Signed-off-by: Thomas Huth Reviewed-by: Claudio Fontana Message-Id: <20200618074001.13642-1-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index a7a2e9e44a..f476ef89ed 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3506,11 +3506,6 @@ void qemu_init(int argc, char **argv, char **envp) g_slist_free(accel_list); exit(0); } - if (optarg && strchr(optarg, ':')) { - error_report("Don't use ':' with -accel, " - "use -M accel=... for now instead"); - exit(1); - } break; case QEMU_OPTION_usb: olist = qemu_find_opts("machine"); From 5dd13f2a5b4d7335b2b0924e6fb28b63b34e70fe Mon Sep 17 00:00:00 2001 From: Cathy Zhang Date: Mon, 6 Jul 2020 07:17:15 +0800 Subject: [PATCH 43/47] target/i386: Add SERIALIZE cpu feature The availability of the SERIALIZATION instruction is indicated by the presence of the CPUID feature flag SERIALIZE, which is defined as CPUID.(EAX=7,ECX=0):ECX[bit 14]. The release spec link is as follows: https://software.intel.com/content/dam/develop/public/us/en/documents/\ architecture-instruction-set-extensions-programming-reference.pdf The associated kvm patch link is as follows: https://lore.kernel.org/patchwork/patch/1268025/ Signed-off-by: Cathy Zhang Message-Id: <1593991036-12183-2-git-send-email-cathy.zhang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- target/i386/cpu.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1dde34dce7..a05d3a641b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -986,7 +986,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { NULL, NULL, "avx512-4vnniw", "avx512-4fmaps", NULL, NULL, NULL, NULL, "avx512-vp2intersect", NULL, "md-clear", NULL, - NULL, NULL, NULL, NULL, + NULL, NULL, "serialize", NULL, NULL, NULL, NULL /* pconfig */, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "spec-ctrl", "stibp", diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 9284f96896..bd71fe3ef2 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -777,6 +777,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Vector Pair Intersection to a Pair of Mask Registers */ #define CPUID_7_0_EDX_AVX512_VP2INTERSECT (1U << 8) +/* SERIALIZE instruction */ +#define CPUID_7_0_EDX_SERIALIZE (1U << 14) /* Speculation Control */ #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Single Thread Indirect Branch Predictors */ From b3c7344e338b04be9feaf7ac6693c2f7fc951b89 Mon Sep 17 00:00:00 2001 From: Cathy Zhang Date: Mon, 6 Jul 2020 07:17:16 +0800 Subject: [PATCH 44/47] target/i386: Enable TSX Suspend Load Address Tracking feature This instruction aims to give a way to choose which memory accesses do not need to be tracked in the TSX read set, which is defined as CPUID.(EAX=7,ECX=0):EDX[bit 16]. The release spec link is as follows: https://software.intel.com/content/dam/develop/public/us/en/documents/\ architecture-instruction-set-extensions-programming-reference.pdf The associated kvm patch link is as follows: https://lore.kernel.org/patchwork/patch/1268026/ Signed-off-by: Cathy Zhang Message-Id: <1593991036-12183-3-git-send-email-cathy.zhang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 +- target/i386/cpu.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index a05d3a641b..1e5123251d 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -987,7 +987,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { NULL, NULL, NULL, NULL, "avx512-vp2intersect", NULL, "md-clear", NULL, NULL, NULL, "serialize", NULL, - NULL, NULL, NULL /* pconfig */, NULL, + "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "spec-ctrl", "stibp", NULL, "arch-capabilities", "core-capability", "ssbd", diff --git a/target/i386/cpu.h b/target/i386/cpu.h index bd71fe3ef2..37fffa5cac 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -779,6 +779,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_AVX512_VP2INTERSECT (1U << 8) /* SERIALIZE instruction */ #define CPUID_7_0_EDX_SERIALIZE (1U << 14) +/* TSX Suspend Load Address Tracking instruction */ +#define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) /* Speculation Control */ #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Single Thread Indirect Branch Predictors */ From 86f13ef31806e5f829ee3d9ed82694f44dd1c02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 6 Jul 2020 13:50:54 +0100 Subject: [PATCH 45/47] scripts: improve message when TAP based tests fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If one of the qtests fails, the TAP driver prints out a message like: ERROR - too few tests run (expected 3, got 1) which fails to tell you which test program failed. This is a critical ommission when many tests are running in parallel as their output is interleaved. The improved message is: ERROR endianness-test - too few tests run (expected 3, got 1) Signed-off-by: Daniel P. Berrangé Message-Id: <20200706125054.2619012-1-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- scripts/tap-driver.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tap-driver.pl b/scripts/tap-driver.pl index 6621a5cd67..b1d3880c50 100755 --- a/scripts/tap-driver.pl +++ b/scripts/tap-driver.pl @@ -217,7 +217,7 @@ sub report ($;$) sub testsuite_error ($) { - report "ERROR", "- $_[0]"; + report "ERROR", "$test_name - $_[0]"; } sub handle_tap_result ($) From 6e083c0de41a606f304168fce75ea77f3c031f98 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 7 Feb 2020 07:43:42 +0100 Subject: [PATCH 46/47] apic: Report current_count via 'info lapic' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is helpful when debugging stuck guest timers. As we need apic_get_current_count for that, and it is really not emulation specific, move it to apic_common.c and export it. Fix its style at this chance as well. Signed-off-by: Jan Kiszka Reviewed-by: Philippe Mathieu-Daudé Message-Id: Signed-off-by: Paolo Bonzini --- hw/intc/apic.c | 18 ------------------ hw/intc/apic_common.c | 19 +++++++++++++++++++ include/hw/i386/apic_internal.h | 1 + target/i386/helper.c | 5 +++-- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 6b46839ef4..38aabd60cd 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -615,24 +615,6 @@ int apic_accept_pic_intr(DeviceState *dev) return 0; } -static uint32_t apic_get_current_count(APICCommonState *s) -{ - int64_t d; - uint32_t val; - d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >> - s->count_shift; - if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { - /* periodic */ - val = s->initial_count - (d % ((uint64_t)s->initial_count + 1)); - } else { - if (d >= s->initial_count) - val = 0; - else - val = s->initial_count - d; - } - return val; -} - static void apic_timer_update(APICCommonState *s, int64_t current_time) { if (apic_next_timer(s, current_time)) { diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index dc070343c0..81addd6390 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -189,6 +189,25 @@ bool apic_next_timer(APICCommonState *s, int64_t current_time) return true; } +uint32_t apic_get_current_count(APICCommonState *s) +{ + int64_t d; + uint32_t val; + d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >> + s->count_shift; + if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { + /* periodic */ + val = s->initial_count - (d % ((uint64_t)s->initial_count + 1)); + } else { + if (d >= s->initial_count) { + val = 0; + } else { + val = s->initial_count - d; + } + } + return val; +} + void apic_init_reset(DeviceState *dev) { APICCommonState *s; diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index b04bdd947f..2597000e03 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -211,6 +211,7 @@ void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip, TPRAccess access); int apic_get_ppr(APICCommonState *s); +uint32_t apic_get_current_count(APICCommonState *s); static inline void apic_set_bit(uint32_t *tab, int index) { diff --git a/target/i386/helper.c b/target/i386/helper.c index fa2a1dcdda..70be53e2c3 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -370,10 +370,11 @@ void x86_cpu_dump_local_apic_state(CPUState *cs, int flags) dump_apic_lvt("LVTTHMR", lvt[APIC_LVT_THERMAL], false); dump_apic_lvt("LVTT", lvt[APIC_LVT_TIMER], true); - qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u\n", + qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u" + " current_count = %u\n", s->divide_conf & APIC_DCR_MASK, divider_conf(s->divide_conf), - s->initial_count); + s->initial_count, apic_get_current_count(s)); qemu_printf("SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n", s->spurious_vec, From 56908dc5041aa424fd1495b6c6beb78c539d93e1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 9 Jul 2020 14:27:34 -0400 Subject: [PATCH 47/47] linux-headers: update again to 5.8 5.8-rc1 inadvertently broke userspace ABI compatibility. Merge again with latest kvm/master to undo that. Signed-off-by: Paolo Bonzini --- linux-headers/asm-arm/unistd-common.h | 1 + linux-headers/asm-x86/kvm.h | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-headers/asm-arm/unistd-common.h b/linux-headers/asm-arm/unistd-common.h index 23de64e44c..57cd1f21db 100644 --- a/linux-headers/asm-arm/unistd-common.h +++ b/linux-headers/asm-arm/unistd-common.h @@ -392,5 +392,6 @@ #define __NR_clone3 (__NR_SYSCALL_BASE + 435) #define __NR_openat2 (__NR_SYSCALL_BASE + 437) #define __NR_pidfd_getfd (__NR_SYSCALL_BASE + 438) +#define __NR_faccessat2 (__NR_SYSCALL_BASE + 439) #endif /* _ASM_ARM_UNISTD_COMMON_H */ diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 17c5a038f4..0780f97c18 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -408,14 +408,15 @@ struct kvm_vmx_nested_state_data { }; struct kvm_vmx_nested_state_hdr { - __u32 flags; __u64 vmxon_pa; __u64 vmcs12_pa; - __u64 preemption_timer_deadline; struct { __u16 flags; } smm; + + __u32 flags; + __u64 preemption_timer_deadline; }; struct kvm_svm_nested_state_data {