diff --git a/Makefile b/Makefile index e5fd1ebdf6..b842dbccdb 100644 --- a/Makefile +++ b/Makefile @@ -165,10 +165,7 @@ ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),) endif endif -# Force configure to re-run if the API symbols are updated ifeq ($(CONFIG_PLUGIN),y) -config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols - .PHONY: plugins plugins: $(call quiet-command,\ diff --git a/audio/audio.c b/audio/audio.c index 9e91a5a4f2..a02f3ce5c6 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2099,13 +2099,19 @@ static void audio_validate_opts(Audiodev *dev, Error **errp) void audio_parse_option(const char *opt) { - AudiodevListEntry *e; Audiodev *dev = NULL; Visitor *v = qobject_input_visitor_new_str(opt, "driver", &error_fatal); visit_type_Audiodev(v, NULL, &dev, &error_fatal); visit_free(v); + audio_define(dev); +} + +void audio_define(Audiodev *dev) +{ + AudiodevListEntry *e; + audio_validate_opts(dev, &error_fatal); e = g_new0(AudiodevListEntry, 1); diff --git a/audio/audio.h b/audio/audio.h index 3d5ecdecd5..b5e17cd218 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -168,6 +168,7 @@ void audio_sample_to_uint64(const void *samples, int pos, void audio_sample_from_uint64(void *samples, int pos, uint64_t left, uint64_t right); +void audio_define(Audiodev *audio); void audio_parse_option(const char *opt); void audio_init_audiodevs(void); void audio_legacy_help(void); diff --git a/backends/rng.c b/backends/rng.c index 3757b04485..6c7bf64426 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -48,24 +48,10 @@ static bool rng_backend_prop_get_opened(Object *obj, Error **errp) static void rng_backend_complete(UserCreatable *uc, Error **errp) { - object_property_set_bool(OBJECT(uc), "opened", true, errp); -} - -static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp) -{ - RngBackend *s = RNG_BACKEND(obj); + RngBackend *s = RNG_BACKEND(uc); RngBackendClass *k = RNG_BACKEND_GET_CLASS(s); Error *local_err = NULL; - if (value == s->opened) { - return; - } - - if (!value && s->opened) { - error_setg(errp, QERR_PERMISSION_DENIED); - return; - } - if (k->opened) { k->opened(s, &local_err); if (local_err) { @@ -122,7 +108,7 @@ static void rng_backend_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "opened", rng_backend_prop_get_opened, - rng_backend_prop_set_opened); + NULL); } static const TypeInfo rng_backend_info = { diff --git a/configure b/configure index c8b5b99532..0cc8c876f7 100755 --- a/configure +++ b/configure @@ -1043,10 +1043,6 @@ Advanced options (experts only): --enable-tsan enable thread sanitizer --disable-werror disable compilation abort on warning --disable-stack-protector disable compiler-provided stack protection - --audio-drv-list=LIST set audio drivers to try if -audiodev is not used - --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L - --with-trace-file=NAME Full PATH,NAME of file to store traces - Default:trace- --cpu=CPU Build for host CPU [$cpu] --with-coroutine=BACKEND coroutine backend. Supported options: ucontext, sigaltstack, windows @@ -1992,7 +1988,6 @@ fi if test "$static" = "yes" ; then echo "CONFIG_STATIC=y" >> $config_host_mak fi -qemu_version=$(head $source_path/VERSION) echo "SRC_PATH=$source_path" >> $config_host_mak echo "TARGET_DIRS=$target_list" >> $config_host_mak if test "$modules" = "yes"; then diff --git a/crypto/secret_common.c b/crypto/secret_common.c index 714a15d5e5..3441c44ca8 100644 --- a/crypto/secret_common.c +++ b/crypto/secret_common.c @@ -138,36 +138,44 @@ static void qcrypto_secret_decode(const uint8_t *input, static void -qcrypto_secret_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_secret_complete(UserCreatable *uc, Error **errp) { - QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); + QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(uc); QCryptoSecretCommonClass *sec_class - = QCRYPTO_SECRET_COMMON_GET_CLASS(obj); + = QCRYPTO_SECRET_COMMON_GET_CLASS(uc); - if (value) { - Error *local_err = NULL; - uint8_t *input = NULL; - size_t inputlen = 0; - uint8_t *output = NULL; - size_t outputlen = 0; + Error *local_err = NULL; + uint8_t *input = NULL; + size_t inputlen = 0; + uint8_t *output = NULL; + size_t outputlen = 0; - if (sec_class->load_data) { - sec_class->load_data(secret, &input, &inputlen, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } else { - error_setg(errp, "%s provides no 'load_data' method'", - object_get_typename(obj)); + if (sec_class->load_data) { + sec_class->load_data(secret, &input, &inputlen, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } + } else { + error_setg(errp, "%s provides no 'load_data' method'", + object_get_typename(OBJECT(uc))); + return; + } - if (secret->keyid) { - qcrypto_secret_decrypt(secret, input, inputlen, - &output, &outputlen, &local_err); + if (secret->keyid) { + qcrypto_secret_decrypt(secret, input, inputlen, + &output, &outputlen, &local_err); + g_free(input); + if (local_err) { + error_propagate(errp, local_err); + return; + } + input = output; + inputlen = outputlen; + } else { + if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { + qcrypto_secret_decode(input, inputlen, + &output, &outputlen, &local_err); g_free(input); if (local_err) { error_propagate(errp, local_err); @@ -175,26 +183,11 @@ qcrypto_secret_prop_set_loaded(Object *obj, } input = output; inputlen = outputlen; - } else { - if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { - qcrypto_secret_decode(input, inputlen, - &output, &outputlen, &local_err); - g_free(input); - if (local_err) { - error_propagate(errp, local_err); - return; - } - input = output; - inputlen = outputlen; - } } - - secret->rawdata = input; - secret->rawlen = inputlen; - } else if (secret->rawdata) { - error_setg(errp, "Cannot unload secret"); - return; } + + secret->rawdata = input; + secret->rawlen = inputlen; } @@ -268,13 +261,6 @@ qcrypto_secret_prop_get_keyid(Object *obj, } -static void -qcrypto_secret_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_secret_finalize(Object *obj) { @@ -294,7 +280,7 @@ qcrypto_secret_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_secret_prop_get_loaded, - qcrypto_secret_prop_set_loaded); + NULL); object_class_property_add_enum(oc, "format", "QCryptoSecretFormat", &QCryptoSecretFormat_lookup, diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index 6fb83639ec..c0d23a0ef3 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -119,16 +119,11 @@ qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_anon_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj); + QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(uc); - qcrypto_tls_creds_anon_unload(creds); - if (value) { - qcrypto_tls_creds_anon_load(creds, errp); - } + qcrypto_tls_creds_anon_load(creds, errp); } @@ -163,13 +158,6 @@ qcrypto_tls_creds_anon_prop_get_loaded(Object *obj G_GNUC_UNUSED, #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_anon_finalize(Object *obj) { @@ -188,7 +176,7 @@ qcrypto_tls_creds_anon_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_anon_prop_get_loaded, - qcrypto_tls_creds_anon_prop_set_loaded); + NULL); } diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index 752f2d92be..a4f9891274 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -188,16 +188,11 @@ qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_psk_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj); + QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(uc); - qcrypto_tls_creds_psk_unload(creds); - if (value) { - qcrypto_tls_creds_psk_load(creds, errp); - } + qcrypto_tls_creds_psk_load(creds, errp); } @@ -232,13 +227,6 @@ qcrypto_tls_creds_psk_prop_get_loaded(Object *obj G_GNUC_UNUSED, #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_psk_finalize(Object *obj) { @@ -276,7 +264,7 @@ qcrypto_tls_creds_psk_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_psk_prop_get_loaded, - qcrypto_tls_creds_psk_prop_set_loaded); + NULL); object_class_property_add_str(oc, "username", qcrypto_tls_creds_psk_prop_get_username, qcrypto_tls_creds_psk_prop_set_username); diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index 32948a6bdc..d14313925d 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -687,16 +687,11 @@ qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED) static void -qcrypto_tls_creds_x509_prop_set_loaded(Object *obj, - bool value, - Error **errp) +qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) { - QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); + QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(uc); - qcrypto_tls_creds_x509_unload(creds); - if (value) { - qcrypto_tls_creds_x509_load(creds, errp); - } + qcrypto_tls_creds_x509_load(creds, errp); } @@ -814,13 +809,6 @@ qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp) #endif /* ! CONFIG_GNUTLS */ -static void -qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) -{ - object_property_set_bool(OBJECT(uc), "loaded", true, errp); -} - - static void qcrypto_tls_creds_x509_init(Object *obj) { @@ -852,7 +840,7 @@ qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "loaded", qcrypto_tls_creds_x509_prop_get_loaded, - qcrypto_tls_creds_x509_prop_set_loaded); + NULL); object_class_property_add_bool(oc, "sanity-check", qcrypto_tls_creds_x509_prop_get_sanity, qcrypto_tls_creds_x509_prop_set_sanity); diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 896e5a97ab..a92ae0f162 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -39,15 +39,6 @@ should specify an ``audiodev=`` property. Additionally, when using vnc, you should specify an ``audiodev=`` property if you plan to transmit audio through the VNC protocol. -Creating sound card devices using ``-soundhw`` (since 5.1) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Sound card devices should be created using ``-device`` instead. The -names are the same for most devices. The exceptions are ``hda`` which -needs two devices (``-device intel-hda -device hda-duplex``) and -``pcspk`` which can be activated using ``-machine -pcspk-audiodev=``. - ``-chardev`` backend aliases ``tty`` and ``parport`` (since 6.0) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -90,25 +81,6 @@ the process listing. This is replaced by the new ``password-secret`` option which lets the password be securely provided on the command line using a ``secret`` object instance. -``opened`` property of ``rng-*`` objects (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''' - -The only effect of specifying ``opened=on`` in the command line or QMP -``object-add`` is that the device is opened immediately, possibly before all -other options have been processed. This will either have no effect (if -``opened`` was the last option) or cause errors. The property is therefore -useless and should not be specified. - -``loaded`` property of ``secret`` and ``secret_keyring`` objects (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The only effect of specifying ``loaded=on`` in the command line or QMP -``object-add`` is that the secret is loaded immediately, possibly before all -other options have been processed. This will either have no effect (if -``loaded`` was the last option) or cause options to be effectively ignored as -if they were not given. The property is therefore useless and should not be -specified. - ``-display sdl,window_close=...`` (since 6.1) ''''''''''''''''''''''''''''''''''''''''''''' @@ -270,12 +242,6 @@ from Linux upstream kernel, declare it deprecated. System emulator CPUS -------------------- -``Icelake-Client`` CPU Model (since 5.2) -'''''''''''''''''''''''''''''''''''''''' - -``Icelake-Client`` CPU Models are deprecated. Use ``Icelake-Server`` CPU -Models instead. - MIPS ``I7200`` CPU Model (since 5.2) '''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 4a0b270296..eb76974347 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -355,6 +355,21 @@ The ``-writeconfig`` option was not able to serialize the entire contents of the QEMU command line. It is thus considered a failed experiment and removed without a replacement. +``loaded`` property of ``secret`` and ``secret_keyring`` objects (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``loaded=on`` option in the command line or QMP ``object-add`` either had +no effect (if ``loaded`` was the last option) or caused options to be +effectively ignored as if they were not given. The property is therefore +useless and should simply be removed. + +``opened`` property of ``rng-*`` objects (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``opened=on`` option in the command line or QMP ``object-add`` either had +no effect (if ``opened`` was the last option) or caused errors. The property +is therefore useless and should simply be removed. + QEMU Machine Protocol (QMP) commands ------------------------------------ @@ -557,6 +572,12 @@ Support for this CPU was removed from the upstream Linux kernel, and there is no available upstream toolchain to build binaries for it. Removed without replacement. +x86 ``Icelake-Client`` CPU (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''' + +There isn't ever Icelake Client CPU, it is some wrong and imaginary one. +Use ``Icelake-Server`` instead. + System emulator machines ------------------------ @@ -633,6 +654,13 @@ tripped up the CI testing and was suspected to be quite broken. For that reason the maintainers strongly suspected no one actually used it. +Creating sound card devices using ``-soundhw`` (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Sound card devices should be created using ``-device`` or ``-audio``. +The exception is ``pcspk`` which can be activated using ``-machine +pcspk-audiodev=``. + TCG introspection features -------------------------- diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index bc77e3d8c9..f38117057b 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -1311,17 +1311,16 @@ static const TypeInfo hda_codec_device_type_info = { * create intel hda controller with codec attached to it, * so '-soundhw hda' works. */ -static int intel_hda_and_codec_init(PCIBus *bus) +static int intel_hda_and_codec_init(PCIBus *bus, const char *audiodev) { DeviceState *controller; BusState *hdabus; DeviceState *codec; - warn_report("'-soundhw hda' is deprecated, " - "please use '-device intel-hda -device hda-duplex' instead"); controller = DEVICE(pci_create_simple(bus, -1, "intel-hda")); hdabus = QLIST_FIRST(&controller->child_bus); codec = qdev_new("hda-duplex"); + qdev_prop_set_string(codec, "audiodev", audiodev); qdev_realize_and_unref(codec, hdabus, &error_fatal); return 0; } diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c index f7d94d7dfa..94d9463e42 100644 --- a/hw/audio/soundhw.c +++ b/hw/audio/soundhw.c @@ -25,7 +25,9 @@ #include "qemu/option.h" #include "qemu/help_option.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "qom/object.h" +#include "hw/qdev-properties.h" #include "hw/isa/isa.h" #include "hw/pci/pci.h" #include "hw/audio/soundhw.h" @@ -34,16 +36,15 @@ struct soundhw { const char *name; const char *descr; const char *typename; - int enabled; int isa; - int (*init_pci) (PCIBus *bus); + int (*init_pci) (PCIBus *bus, const char *audiodev); }; static struct soundhw soundhw[9]; static int soundhw_count; void pci_register_soundhw(const char *name, const char *descr, - int (*init_pci)(PCIBus *bus)) + int (*init_pci)(PCIBus *bus, const char *audiodev)) { assert(soundhw_count < ARRAY_SIZE(soundhw) - 1); soundhw[soundhw_count].name = name; @@ -64,95 +65,78 @@ void deprecated_register_soundhw(const char *name, const char *descr, soundhw_count++; } -void select_soundhw(const char *optarg) +void show_valid_soundhw(void) { struct soundhw *c; - if (is_help_option(optarg)) { - show_valid_cards: - - if (soundhw_count) { - printf("Valid sound card names (comma separated):\n"); - for (c = soundhw; c->name; ++c) { - printf ("%-11s %s\n", c->name, c->descr); - } - printf("\n-soundhw all will enable all of the above\n"); - } else { - printf("Machine has no user-selectable audio hardware " - "(it may or may not have always-present audio hardware).\n"); - } - exit(!is_help_option(optarg)); + if (soundhw_count) { + printf("Valid sound card names (comma separated):\n"); + for (c = soundhw; c->name; ++c) { + printf ("%-11s %s\n", c->name, c->descr); + } + } else { + printf("Machine has no user-selectable audio hardware " + "(it may or may not have always-present audio hardware).\n"); } - else { - size_t l; - const char *p; - char *e; - int bad_card = 0; +} - if (!strcmp(optarg, "all")) { - for (c = soundhw; c->name; ++c) { - c->enabled = 1; - } - return; +static struct soundhw *selected = NULL; +static const char *audiodev_id; + +void select_soundhw(const char *optarg, const char *audiodev) +{ + struct soundhw *c; + + if (selected) { + error_setg(&error_fatal, "only one -soundhw option is allowed"); + } + + for (c = soundhw; c->name; ++c) { + if (g_str_equal(c->name, optarg)) { + selected = c; + audiodev_id = audiodev; + break; } + } - p = optarg; - while (*p) { - e = strchr(p, ','); - l = !e ? strlen(p) : (size_t) (e - p); - - for (c = soundhw; c->name; ++c) { - if (!strncmp(c->name, p, l) && !c->name[l]) { - c->enabled = 1; - break; - } - } - - if (!c->name) { - if (l > 80) { - error_report("Unknown sound card name (too big to show)"); - } - else { - error_report("Unknown sound card name `%.*s'", - (int) l, p); - } - bad_card = 1; - } - p += l + (e != NULL); - } - - if (bad_card) { - goto show_valid_cards; - } + if (!c->name) { + error_report("Unknown sound card name `%s'", optarg); + show_valid_soundhw(); + exit(1); } } void soundhw_init(void) { - struct soundhw *c; + struct soundhw *c = selected; ISABus *isa_bus = (ISABus *) object_resolve_path_type("", TYPE_ISA_BUS, NULL); PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL); + BusState *bus; - for (c = soundhw; c->name; ++c) { - if (c->enabled) { - if (c->typename) { - warn_report("'-soundhw %s' is deprecated, " - "please use '-device %s' instead", - c->name, c->typename); - if (c->isa) { - isa_create_simple(isa_bus, c->typename); - } else { - pci_create_simple(pci_bus, -1, c->typename); - } - } else { - assert(!c->isa); - if (!pci_bus) { - error_report("PCI bus not available for %s", c->name); - exit(1); - } - c->init_pci(pci_bus); - } + if (!c) { + return; + } + if (c->isa) { + if (!isa_bus) { + error_report("ISA bus not available for %s", c->name); + exit(1); } + bus = BUS(isa_bus); + } else { + if (!pci_bus) { + error_report("PCI bus not available for %s", c->name); + exit(1); + } + bus = BUS(pci_bus); + } + + if (c->typename) { + DeviceState *dev = qdev_new(c->typename); + qdev_prop_set_string(dev, "audiodev", audiodev_id); + qdev_realize_and_unref(dev, bus, &error_fatal); + } else { + assert(!c->isa); + c->init_pci(pci_bus, audiodev_id); } } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index c34aac6ebc..357b8761b5 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -428,6 +428,25 @@ const PropertyInfo qdev_prop_int64 = { .set_default_value = qdev_propinfo_set_default_value_int, }; +static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + Property *prop = opaque; + uint64_t *ptr = object_field_prop_ptr(obj, prop); + + visit_type_uint64(v, name, ptr, errp); + if (*ptr & ~prop->bitmask) { + error_setg(errp, "Property value for '%s' has bits outside mask '0x%" PRIx64 "'", + name, prop->bitmask); + } +} + +const PropertyInfo qdev_prop_uint64_checkmask = { + .name = "uint64", + .get = get_uint64, + .set = set_uint64_checkmask, +}; + /* --- string --- */ static void release_string(Object *obj, const char *name, void *opaque) diff --git a/include/hw/audio/soundhw.h b/include/hw/audio/soundhw.h index e68685fcda..270717a06a 100644 --- a/include/hw/audio/soundhw.h +++ b/include/hw/audio/soundhw.h @@ -2,11 +2,12 @@ #define HW_SOUNDHW_H void pci_register_soundhw(const char *name, const char *descr, - int (*init_pci)(PCIBus *bus)); + int (*init_pci)(PCIBus *bus, const char *audiodev)); void deprecated_register_soundhw(const char *name, const char *descr, int isa, const char *typename); void soundhw_init(void); -void select_soundhw(const char *optarg); +void show_valid_soundhw(void); +void select_soundhw(const char *optarg, const char *audiodev); #endif diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index f7925f67d0..e1df08876c 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -17,6 +17,7 @@ struct Property { const PropertyInfo *info; ptrdiff_t offset; uint8_t bitnr; + uint64_t bitmask; bool set_default; union { int64_t i; @@ -54,6 +55,7 @@ extern const PropertyInfo qdev_prop_uint16; extern const PropertyInfo qdev_prop_uint32; extern const PropertyInfo qdev_prop_int32; extern const PropertyInfo qdev_prop_uint64; +extern const PropertyInfo qdev_prop_uint64_checkmask; extern const PropertyInfo qdev_prop_int64; extern const PropertyInfo qdev_prop_size; extern const PropertyInfo qdev_prop_string; @@ -103,6 +105,16 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (bool)_defval) +/** + * The DEFINE_PROP_UINT64_CHECKMASK macro checks a user-supplied value + * against corresponding bitmask, rejects the value if it violates. + * The default value is set in instance_init(). + */ +#define DEFINE_PROP_UINT64_CHECKMASK(_name, _state, _field, _bitmask) \ + DEFINE_PROP(_name, _state, _field, qdev_prop_uint64_checkmask, uint64_t, \ + .bitmask = (_bitmask), \ + .set_default = false) + #define PROP_ARRAY_LEN_PREFIX "len-" /** diff --git a/qemu-options.hx b/qemu-options.hx index 796229c433..60d2d728d6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -661,6 +661,30 @@ SRST (deprecated) environment variables. ERST +DEF("audio", HAS_ARG, QEMU_OPTION_audio, + "-audio [driver=]driver,model=value[,prop[=value][,...]]\n" + " specifies the audio backend and device to use;\n" + " apart from 'model', options are the same as for -audiodev.\n" + " use '-audio model=help' to show possible devices.\n", + QEMU_ARCH_ALL) +SRST +``-audio [driver=]driver,model=value[,prop[=value][,...]]`` + This option is a shortcut for configuring both the guest audio + hardware and the host audio backend in one go. + The host backend options are the same as with the corresponding + ``-audiodev`` options below. The guest hardware model can be set with + ``model=modelname``. Use ``model=help`` to list the available device + types. + + The following two example do exactly the same, to show how ``-audio`` + can be used to shorten the command line length: + + .. parsed-literal:: + + |qemu_system| -audiodev pa,id=pa -device sb16,audiodev=pa + |qemu_system| -audio pa,model=sb16 +ERST + DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev, "-audiodev [driver=]driver,id=id[,prop[=value][,...]]\n" " specifies the audio backend to use\n" @@ -892,33 +916,6 @@ SRST ``qemu.wav``. ERST -DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw, - "-soundhw c1,... enable audio support\n" - " and only specified sound cards (comma separated list)\n" - " use '-soundhw help' to get the list of supported cards\n" - " use '-soundhw all' to enable all of them\n", QEMU_ARCH_ALL) -SRST -``-soundhw card1[,card2,...] or -soundhw all`` - Enable audio and selected sound hardware. Use 'help' to print all - available sound hardware. For example: - - .. parsed-literal:: - - |qemu_system_x86| -soundhw sb16,adlib disk.img - |qemu_system_x86| -soundhw es1370 disk.img - |qemu_system_x86| -soundhw ac97 disk.img - |qemu_system_x86| -soundhw hda disk.img - |qemu_system_x86| -soundhw all disk.img - |qemu_system_x86| -soundhw help - - Note that Linux's i810\_audio OSS kernel (for AC97) module might - require manually specifying clocking. - - :: - - modprobe i810_audio clocking=48000 -ERST - DEF("device", HAS_ARG, QEMU_OPTION_device, "-device driver[,prop[=value][,...]]\n" " add device (based on driver)\n" diff --git a/qga/vss-win32/meson.build b/qga/vss-win32/meson.build index 26c5dd6e0e..9483ccd3b8 100644 --- a/qga/vss-win32/meson.build +++ b/qga/vss-win32/meson.build @@ -7,7 +7,7 @@ link_args = cc.get_supported_link_arguments([ qga_vss = shared_module( 'qga-vss', - ['requester.cpp', 'provider.cpp', 'install.cpp'], + ['requester.cpp', 'provider.cpp', 'install.cpp', genh], name_prefix: '', cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'], link_args: link_args, diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp index 4513324dd2..b371affeab 100644 --- a/qga/vss-win32/requester.cpp +++ b/qga/vss-win32/requester.cpp @@ -354,12 +354,12 @@ void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) if (FAILED(hr)) { err_set(errset, hr, "failed to add %S to snapshot set", volume_name_wchar); - delete volume_name_wchar; + delete[] volume_name_wchar; goto out; } num_mount_points++; - delete volume_name_wchar; + delete[] volume_name_wchar; } if (num_mount_points == 0) { diff --git a/softmmu/vl.c b/softmmu/vl.c index 817d515783..219b23a573 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -116,6 +116,8 @@ #include "crypto/init.h" #include "sysemu/replay.h" #include "qapi/qapi-events-run-state.h" +#include "qapi/qapi-types-audio.h" +#include "qapi/qapi-visit-audio.h" #include "qapi/qapi-visit-block-core.h" #include "qapi/qapi-visit-compat.h" #include "qapi/qapi-visit-ui.h" @@ -2930,9 +2932,33 @@ void qemu_init(int argc, char **argv, char **envp) case QEMU_OPTION_audiodev: audio_parse_option(optarg); break; - case QEMU_OPTION_soundhw: - select_soundhw (optarg); + case QEMU_OPTION_audio: { + QDict *dict = keyval_parse(optarg, "driver", NULL, &error_fatal); + char *model; + Audiodev *dev = NULL; + Visitor *v; + + if (!qdict_haskey(dict, "id")) { + qdict_put_str(dict, "id", "audiodev0"); + } + if (!qdict_haskey(dict, "model")) { + error_setg(&error_fatal, "Parameter 'model' is missing"); + } + model = g_strdup(qdict_get_str(dict, "model")); + qdict_del(dict, "model"); + if (is_help_option(model)) { + show_valid_soundhw(); + exit(0); + } + v = qobject_input_visitor_new_keyval(QOBJECT(dict)); + qobject_unref(dict); + visit_type_Audiodev(v, NULL, &dev, &error_fatal); + visit_free(v); + audio_define(dev); + select_soundhw(model, dev->id); + g_free(model); break; + } case QEMU_OPTION_h: help(0); break; diff --git a/target/i386/cpu.c b/target/i386/cpu.c index c4a17c93f6..35c3475e6c 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -855,7 +855,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "fsrm", NULL, NULL, NULL, "avx512-vp2intersect", NULL, "md-clear", NULL, NULL, NULL, "serialize", NULL, - "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, + "tsx-ldtrk", NULL, NULL /* pconfig */, "arch-lbr", NULL, NULL, "amx-bf16", "avx512-fp16", "amx-tile", "amx-int8", "spec-ctrl", "stibp", NULL, "arch-capabilities", "core-capability", "ssbd", @@ -937,6 +937,34 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, .tcg_features = TCG_XSAVE_FEATURES, }, + [FEAT_XSAVE_XSS_LO] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .cpuid = { + .eax = 0xD, + .needs_ecx = true, + .ecx = 1, + .reg = R_ECX, + }, + }, + [FEAT_XSAVE_XSS_HI] = { + .type = CPUID_FEATURE_WORD, + .cpuid = { + .eax = 0xD, + .needs_ecx = true, + .ecx = 1, + .reg = R_EDX + }, + }, [FEAT_6_EAX] = { .type = CPUID_FEATURE_WORD, .feat_names = { @@ -952,7 +980,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid = { .eax = 6, .reg = R_EAX, }, .tcg_features = TCG_6_EAX_FEATURES, }, - [FEAT_XSAVE_COMP_LO] = { + [FEAT_XSAVE_XCR0_LO] = { .type = CPUID_FEATURE_WORD, .cpuid = { .eax = 0xD, @@ -965,7 +993,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK | XSTATE_PKRU_MASK, }, - [FEAT_XSAVE_COMP_HI] = { + [FEAT_XSAVE_XCR0_HI] = { .type = CPUID_FEATURE_WORD, .cpuid = { .eax = 0xD, @@ -1382,6 +1410,9 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { }; #undef REGISTER +/* CPUID feature bits available in XSS */ +#define CPUID_XSTATE_XSS_MASK (XSTATE_ARCH_LBR_MASK) + ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_FP_BIT] = { /* x87 FP state component is always enabled if XSAVE is supported */ @@ -1414,6 +1445,10 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_PKRU_BIT] = { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, .size = sizeof(XSavePKRU) }, + [XSTATE_ARCH_LBR_BIT] = { + .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_ARCH_LBR, + .offset = 0 /*supervisor mode component, offset = 0 */, + .size = sizeof(XSavesArchLBR) }, [XSTATE_XTILE_CFG_BIT] = { .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_AMX_TILE, .size = sizeof(XSaveXTILECFG), @@ -1424,15 +1459,18 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { }, }; -static uint32_t xsave_area_size(uint64_t mask) +static uint32_t xsave_area_size(uint64_t mask, bool compacted) { + uint64_t ret = x86_ext_save_areas[0].size; + const ExtSaveArea *esa; + uint32_t offset = 0; int i; - uint64_t ret = 0; - for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) { - const ExtSaveArea *esa = &x86_ext_save_areas[i]; + for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + esa = &x86_ext_save_areas[i]; if ((mask >> i) & 1) { - ret = MAX(ret, esa->offset + esa->size); + offset = compacted ? ret : esa->offset; + ret = MAX(ret, offset + esa->size); } } return ret; @@ -1443,10 +1481,10 @@ static inline bool accel_uses_host_cpuid(void) return kvm_enabled() || hvf_enabled(); } -static inline uint64_t x86_cpu_xsave_components(X86CPU *cpu) +static inline uint64_t x86_cpu_xsave_xcr0_components(X86CPU *cpu) { - return ((uint64_t)cpu->env.features[FEAT_XSAVE_COMP_HI]) << 32 | - cpu->env.features[FEAT_XSAVE_COMP_LO]; + return ((uint64_t)cpu->env.features[FEAT_XSAVE_XCR0_HI]) << 32 | + cpu->env.features[FEAT_XSAVE_XCR0_LO]; } /* Return name of 32-bit register, from a R_* constant */ @@ -1458,6 +1496,12 @@ static const char *get_register_name_32(unsigned int reg) return x86_reg_info_32[reg].name; } +static inline uint64_t x86_cpu_xsave_xss_components(X86CPU *cpu) +{ + return ((uint64_t)cpu->env.features[FEAT_XSAVE_XSS_HI]) << 32 | + cpu->env.features[FEAT_XSAVE_XSS_LO]; +} + /* * Returns the set of feature flags that are supported and migratable by * QEMU, for a given FeatureWord. @@ -3258,128 +3302,6 @@ static const X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } } }, - { - .name = "Icelake-Client", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, - .family = 6, - .model = 126, - .stepping = 0, - .features[FEAT_1_EDX] = - CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | - CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | - CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | - CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | - CPUID_DE | CPUID_FP87, - .features[FEAT_1_ECX] = - CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | - CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | - CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | - CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | - CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | - CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, - .features[FEAT_8000_0001_EDX] = - CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | - CPUID_EXT2_SYSCALL, - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, - .features[FEAT_8000_0008_EBX] = - CPUID_8000_0008_EBX_WBNOINVD, - .features[FEAT_7_0_EBX] = - CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | - CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | - CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | - CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | - CPUID_7_0_EBX_SMAP, - .features[FEAT_7_0_ECX] = - CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | - CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | - CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | - CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | - CPUID_7_0_ECX_AVX512_VPOPCNTDQ, - .features[FEAT_7_0_EDX] = - CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_SPEC_CTRL_SSBD, - /* XSAVES is added in version 3 */ - .features[FEAT_XSAVE] = - CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | - CPUID_XSAVE_XGETBV1, - .features[FEAT_6_EAX] = - CPUID_6_EAX_ARAT, - /* Missing: Mode-based execute control (XS/XU), processor tracing, TSC scaling */ - .features[FEAT_VMX_BASIC] = MSR_VMX_BASIC_INS_OUTS | - MSR_VMX_BASIC_TRUE_CTLS, - .features[FEAT_VMX_ENTRY_CTLS] = VMX_VM_ENTRY_IA32E_MODE | - VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VMX_VM_ENTRY_LOAD_IA32_PAT | - VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_LOAD_IA32_EFER, - .features[FEAT_VMX_EPT_VPID_CAPS] = MSR_VMX_EPT_EXECONLY | - MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | - MSR_VMX_EPT_1GB | MSR_VMX_EPT_INVEPT | - MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | - MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | - MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | MSR_VMX_EPT_INVVPID_ALL_CONTEXT | - MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS | MSR_VMX_EPT_AD_BITS, - .features[FEAT_VMX_EXIT_CTLS] = - VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | - VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | - VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_LOAD_IA32_EFER | - VMX_VM_EXIT_SAVE_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | - VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, - .features[FEAT_VMX_MISC] = MSR_VMX_MISC_ACTIVITY_HLT | - MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_VMWRITE_VMEXIT, - .features[FEAT_VMX_PINBASED_CTLS] = VMX_PIN_BASED_EXT_INTR_MASK | - VMX_PIN_BASED_NMI_EXITING | VMX_PIN_BASED_VIRTUAL_NMIS | - VMX_PIN_BASED_VMX_PREEMPTION_TIMER, - .features[FEAT_VMX_PROCBASED_CTLS] = VMX_CPU_BASED_VIRTUAL_INTR_PENDING | - VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | - VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | - VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | - VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | - VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_MOV_DR_EXITING | - VMX_CPU_BASED_UNCOND_IO_EXITING | VMX_CPU_BASED_USE_IO_BITMAPS | - VMX_CPU_BASED_MONITOR_EXITING | VMX_CPU_BASED_PAUSE_EXITING | - VMX_CPU_BASED_VIRTUAL_NMI_PENDING | VMX_CPU_BASED_USE_MSR_BITMAPS | - VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | - VMX_CPU_BASED_MONITOR_TRAP_FLAG | - VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, - .features[FEAT_VMX_SECONDARY_CTLS] = - VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | - VMX_SECONDARY_EXEC_WBINVD_EXITING | VMX_SECONDARY_EXEC_ENABLE_EPT | - VMX_SECONDARY_EXEC_DESC | VMX_SECONDARY_EXEC_RDTSCP | - VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | - VMX_SECONDARY_EXEC_RDRAND_EXITING | VMX_SECONDARY_EXEC_ENABLE_INVPCID | - VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | - VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML, - .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, - .xlevel = 0x80000008, - .model_id = "Intel Core Processor (Icelake)", - .versions = (X86CPUVersionDefinition[]) { - { - .version = 1, - .note = "deprecated" - }, - { - .version = 2, - .note = "no TSX, deprecated", - .alias = "Icelake-Client-noTSX", - .props = (PropValue[]) { - { "hle", "off" }, - { "rtm", "off" }, - { /* end of list */ } - }, - }, - { - .version = 3, - .note = "no TSX, XSAVES, deprecated", - .props = (PropValue[]) { - { "xsaves", "on" }, - { "vmx-xsaves", "on" }, - { /* end of list */ } - }, - }, - { /* end of list */ } - }, - .deprecation_note = "use Icelake-Server instead" - }, { .name = "Icelake-Server", .level = 0xd, @@ -4633,8 +4555,8 @@ static const char *x86_cpu_feature_name(FeatureWord w, int bitnr) /* XSAVE components are automatically enabled by other features, * so return the original feature name instead */ - if (w == FEAT_XSAVE_COMP_LO || w == FEAT_XSAVE_COMP_HI) { - int comp = (w == FEAT_XSAVE_COMP_HI) ? bitnr + 32 : bitnr; + if (w == FEAT_XSAVE_XCR0_LO || w == FEAT_XSAVE_XCR0_HI) { + int comp = (w == FEAT_XSAVE_XCR0_HI) ? bitnr + 32 : bitnr; if (comp < ARRAY_SIZE(x86_ext_save_areas) && x86_ext_save_areas[comp].bits) { @@ -5022,6 +4944,28 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, return r; } +static void x86_cpu_get_supported_cpuid(uint32_t func, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + if (kvm_enabled()) { + *eax = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EAX); + *ebx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EBX); + *ecx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_ECX); + *edx = kvm_arch_get_supported_cpuid(kvm_state, func, index, R_EDX); + } else if (hvf_enabled()) { + *eax = hvf_get_supported_cpuid(func, index, R_EAX); + *ebx = hvf_get_supported_cpuid(func, index, R_EBX); + *ecx = hvf_get_supported_cpuid(func, index, R_ECX); + *edx = hvf_get_supported_cpuid(func, index, R_EDX); + } else { + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + } +} + static void x86_cpu_get_cache_cpuid(uint32_t func, uint32_t index, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -5437,18 +5381,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0xA: /* Architectural Performance Monitoring Leaf */ - if (kvm_enabled() && cpu->enable_pmu) { - KVMState *s = cs->kvm_state; - - *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); - *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); - *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX); - *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX); - } else if (hvf_enabled() && cpu->enable_pmu) { - *eax = hvf_get_supported_cpuid(0xA, count, R_EAX); - *ebx = hvf_get_supported_cpuid(0xA, count, R_EBX); - *ecx = hvf_get_supported_cpuid(0xA, count, R_ECX); - *edx = hvf_get_supported_cpuid(0xA, count, R_EDX); + if (accel_uses_host_cpuid() && cpu->enable_pmu) { + x86_cpu_get_supported_cpuid(0xA, count, eax, ebx, ecx, edx); } else { *eax = 0; *ebx = 0; @@ -5486,6 +5420,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, assert(!(*eax & ~0x1f)); *ebx &= 0xffff; /* The count doesn't need to be reliable. */ break; + case 0x1C: + if (accel_uses_host_cpuid() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + x86_cpu_get_supported_cpuid(0x1C, 0, eax, ebx, ecx, edx); + *edx = 0; + } + break; case 0x1F: /* V2 Extended Topology Enumeration Leaf */ if (env->nr_dies < 2) { @@ -5530,25 +5471,47 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } if (count == 0) { - *ecx = xsave_area_size(x86_cpu_xsave_components(cpu)); - *eax = env->features[FEAT_XSAVE_COMP_LO]; - *edx = env->features[FEAT_XSAVE_COMP_HI]; + *ecx = xsave_area_size(x86_cpu_xsave_xcr0_components(cpu), false); + *eax = env->features[FEAT_XSAVE_XCR0_LO]; + *edx = env->features[FEAT_XSAVE_XCR0_HI]; /* * The initial value of xcr0 and ebx == 0, On host without kvm * commit 412a3c41(e.g., CentOS 6), the ebx's value always == 0 * even through guest update xcr0, this will crash some legacy guest * (e.g., CentOS 6), So set ebx == ecx to workaroud it. */ - *ebx = kvm_enabled() ? *ecx : xsave_area_size(env->xcr0); + *ebx = kvm_enabled() ? *ecx : xsave_area_size(env->xcr0, false); } else if (count == 1) { + uint64_t xstate = x86_cpu_xsave_xcr0_components(cpu) | + x86_cpu_xsave_xss_components(cpu); + *eax = env->features[FEAT_XSAVE]; + *ebx = xsave_area_size(xstate, true); + *ecx = env->features[FEAT_XSAVE_XSS_LO]; + *edx = env->features[FEAT_XSAVE_XSS_HI]; + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR) && + (*eax & CPUID_XSAVE_XSAVES)) { + *ecx |= XSTATE_ARCH_LBR_MASK; + } else { + *ecx &= ~XSTATE_ARCH_LBR_MASK; + } + } else if (count == 0xf && + accel_uses_host_cpuid() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + x86_cpu_get_supported_cpuid(0xD, count, eax, ebx, ecx, edx); } else if (count < ARRAY_SIZE(x86_ext_save_areas)) { - if ((x86_cpu_xsave_components(cpu) >> count) & 1) { - const ExtSaveArea *esa = &x86_ext_save_areas[count]; + const ExtSaveArea *esa = &x86_ext_save_areas[count]; + + if (x86_cpu_xsave_xcr0_components(cpu) & (1ULL << count)) { *eax = esa->size; *ebx = esa->offset; *ecx = esa->ecx & (ESA_FEATURE_ALIGN64_MASK | ESA_FEATURE_XFD_MASK); + } else if (x86_cpu_xsave_xss_components(cpu) & (1ULL << count)) { + *eax = esa->size; + *ebx = 0; + *ecx = 1; } } break; @@ -5588,10 +5551,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, * supports. Features can be further restricted by userspace, but not * made more permissive. */ - *eax = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EAX); - *ebx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EBX); - *ecx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_ECX); - *edx = kvm_arch_get_supported_cpuid(cs->kvm_state, 0x12, count, R_EDX); + x86_cpu_get_supported_cpuid(0x12, index, eax, ebx, ecx, edx); if (count == 0) { *eax &= env->features[FEAT_SGX_12_0_EAX]; @@ -5599,8 +5559,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } else { *eax &= env->features[FEAT_SGX_12_1_EAX]; *ebx &= 0; /* ebx reserve */ - *ecx &= env->features[FEAT_XSAVE_COMP_LO]; - *edx &= env->features[FEAT_XSAVE_COMP_HI]; + *ecx &= env->features[FEAT_XSAVE_XSS_LO]; + *edx &= env->features[FEAT_XSAVE_XSS_HI]; /* FP and SSE are always allowed regardless of XSAVE/XCR0. */ *ecx |= XSTATE_FP_MASK | XSTATE_SSE_MASK; @@ -5996,6 +5956,9 @@ static void x86_cpu_reset(DeviceState *dev) } for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; + if (!((1 << i) & CPUID_XSTATE_XCR0_MASK)) { + continue; + } if (env->features[esa->feature] & esa->bits) { xcr0 |= 1ull << i; } @@ -6110,8 +6073,8 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) static bool request_perm; if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { - env->features[FEAT_XSAVE_COMP_LO] = 0; - env->features[FEAT_XSAVE_COMP_HI] = 0; + env->features[FEAT_XSAVE_XCR0_LO] = 0; + env->features[FEAT_XSAVE_XCR0_HI] = 0; return; } @@ -6129,8 +6092,10 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) request_perm = true; } - env->features[FEAT_XSAVE_COMP_LO] = mask; - env->features[FEAT_XSAVE_COMP_HI] = mask >> 32; + env->features[FEAT_XSAVE_XCR0_LO] = mask & CPUID_XSTATE_XCR0_MASK; + env->features[FEAT_XSAVE_XCR0_HI] = mask >> 32; + env->features[FEAT_XSAVE_XSS_LO] = mask & CPUID_XSTATE_XSS_MASK; + env->features[FEAT_XSAVE_XSS_HI] = mask >> 32; } /***** Steps involved on loading and filtering CPUID data @@ -6397,6 +6362,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) CPUX86State *env = &cpu->env; Error *local_err = NULL; static bool ht_warned; + unsigned requested_lbr_fmt; if (cpu->apic_id == UNASSIGNED_APIC_ID) { error_setg(errp, "apic-id property was not initialized properly"); @@ -6414,6 +6380,42 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) goto out; } + /* + * Override env->features[FEAT_PERF_CAPABILITIES].LBR_FMT + * with user-provided setting. + */ + if (cpu->lbr_fmt != ~PERF_CAP_LBR_FMT) { + if ((cpu->lbr_fmt & PERF_CAP_LBR_FMT) != cpu->lbr_fmt) { + error_setg(errp, "invalid lbr-fmt"); + return; + } + env->features[FEAT_PERF_CAPABILITIES] &= ~PERF_CAP_LBR_FMT; + env->features[FEAT_PERF_CAPABILITIES] |= cpu->lbr_fmt; + } + + /* + * vPMU LBR is supported when 1) KVM is enabled 2) Option pmu=on and + * 3)vPMU LBR format matches that of host setting. + */ + requested_lbr_fmt = + env->features[FEAT_PERF_CAPABILITIES] & PERF_CAP_LBR_FMT; + if (requested_lbr_fmt && kvm_enabled()) { + uint64_t host_perf_cap = + x86_cpu_get_supported_feature_word(FEAT_PERF_CAPABILITIES, false); + unsigned host_lbr_fmt = host_perf_cap & PERF_CAP_LBR_FMT; + + if (!cpu->enable_pmu) { + error_setg(errp, "vPMU: LBR is unsupported without pmu=on"); + return; + } + if (requested_lbr_fmt != host_lbr_fmt) { + error_setg(errp, "vPMU: the lbr-fmt value (0x%x) does not match " + "the host value (0x%x).", + requested_lbr_fmt, host_lbr_fmt); + return; + } + } + x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid); if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) { @@ -6766,6 +6768,8 @@ static void x86_cpu_initfn(Object *obj) object_property_add_alias(obj, "sse4_2", obj, "sse4.2"); object_property_add_alias(obj, "hv-apicv", obj, "hv-avic"); + cpu->lbr_fmt = ~PERF_CAP_LBR_FMT; + object_property_add_alias(obj, "lbr_fmt", obj, "lbr-fmt"); if (xcc->model) { x86_cpu_load_model(cpu, xcc->model); @@ -6920,6 +6924,7 @@ static Property x86_cpu_properties[] = { #endif DEFINE_PROP_INT32("node-id", X86CPU, node_id, CPU_UNSET_NUMA_NODE_ID), DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false), + DEFINE_PROP_UINT64_CHECKMASK("lbr-fmt", X86CPU, lbr_fmt, PERF_CAP_LBR_FMT), DEFINE_PROP_UINT32("hv-spinlocks", X86CPU, hyperv_spinlock_attempts, HYPERV_SPINLOCK_NEVER_NOTIFY), diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 9661f9fbd1..0d528ac58f 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -386,10 +386,16 @@ typedef enum X86Seg { #define ARCH_CAP_TSX_CTRL_MSR (1<<7) #define MSR_IA32_PERF_CAPABILITIES 0x345 +#define PERF_CAP_LBR_FMT 0x3f #define MSR_IA32_TSX_CTRL 0x122 #define MSR_IA32_TSCDEADLINE 0x6e0 #define MSR_IA32_PKRS 0x6e1 +#define MSR_ARCH_LBR_CTL 0x000014ce +#define MSR_ARCH_LBR_DEPTH 0x000014cf +#define MSR_ARCH_LBR_FROM_0 0x00001500 +#define MSR_ARCH_LBR_TO_0 0x00001600 +#define MSR_ARCH_LBR_INFO_0 0x00001200 #define FEATURE_CONTROL_LOCKED (1<<0) #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1ULL << 1) @@ -543,6 +549,7 @@ typedef enum X86Seg { #define XSTATE_ZMM_Hi256_BIT 6 #define XSTATE_Hi16_ZMM_BIT 7 #define XSTATE_PKRU_BIT 9 +#define XSTATE_ARCH_LBR_BIT 15 #define XSTATE_XTILE_CFG_BIT 17 #define XSTATE_XTILE_DATA_BIT 18 @@ -555,6 +562,7 @@ typedef enum X86Seg { #define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT) #define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT) #define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT) +#define XSTATE_ARCH_LBR_MASK (1ULL << XSTATE_ARCH_LBR_BIT) #define XSTATE_XTILE_CFG_MASK (1ULL << XSTATE_XTILE_CFG_BIT) #define XSTATE_XTILE_DATA_MASK (1ULL << XSTATE_XTILE_DATA_BIT) @@ -567,6 +575,14 @@ typedef enum X86Seg { #define ESA_FEATURE_XFD_MASK (1U << ESA_FEATURE_XFD_BIT) +/* CPUID feature bits available in XCR0 */ +#define CPUID_XSTATE_XCR0_MASK (XSTATE_FP_MASK | XSTATE_SSE_MASK | \ + XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | \ + XSTATE_BNDCSR_MASK | XSTATE_OPMASK_MASK | \ + XSTATE_ZMM_Hi256_MASK | \ + XSTATE_Hi16_ZMM_MASK | XSTATE_PKRU_MASK | \ + XSTATE_XTILE_CFG_MASK | XSTATE_XTILE_DATA_MASK) + /* CPUID feature words */ typedef enum FeatureWord { FEAT_1_EDX, /* CPUID[1].EDX */ @@ -585,8 +601,8 @@ typedef enum FeatureWord { FEAT_SVM, /* CPUID[8000_000A].EDX */ FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ FEAT_6_EAX, /* CPUID[6].EAX */ - FEAT_XSAVE_COMP_LO, /* CPUID[EAX=0xd,ECX=0].EAX */ - FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ + FEAT_XSAVE_XCR0_LO, /* CPUID[EAX=0xd,ECX=0].EAX */ + FEAT_XSAVE_XCR0_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ FEAT_ARCH_CAPABILITIES, FEAT_CORE_CAPABILITY, FEAT_PERF_CAPABILITIES, @@ -603,6 +619,8 @@ typedef enum FeatureWord { FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */ FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ + FEAT_XSAVE_XSS_LO, /* CPUID[EAX=0xd,ECX=1].ECX */ + FEAT_XSAVE_XSS_HI, /* CPUID[EAX=0xd,ECX=1].EDX */ FEATURE_WORDS, } FeatureWord; @@ -859,6 +877,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define CPUID_7_0_EDX_SERIALIZE (1U << 14) /* TSX Suspend Load Address Tracking instruction */ #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) +/* Architectural LBRs */ +#define CPUID_7_0_EDX_ARCH_LBR (1U << 19) /* AVX512_FP16 instruction */ #define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) /* AMX tile (two-dimensional register) */ @@ -1365,6 +1385,24 @@ typedef struct XSaveXTILEDATA { uint8_t xtiledata[8][1024]; } XSaveXTILEDATA; +typedef struct { + uint64_t from; + uint64_t to; + uint64_t info; +} LBREntry; + +#define ARCH_LBR_NR_ENTRIES 32 + +/* Ext. save area 19: Supervisor mode Arch LBR state */ +typedef struct XSavesArchLBR { + uint64_t lbr_ctl; + uint64_t lbr_depth; + uint64_t ler_from; + uint64_t ler_to; + uint64_t ler_info; + LBREntry lbr_records[ARCH_LBR_NR_ENTRIES]; +} XSavesArchLBR; + QEMU_BUILD_BUG_ON(sizeof(XSaveAVX) != 0x100); QEMU_BUILD_BUG_ON(sizeof(XSaveBNDREG) != 0x40); QEMU_BUILD_BUG_ON(sizeof(XSaveBNDCSR) != 0x40); @@ -1374,6 +1412,7 @@ QEMU_BUILD_BUG_ON(sizeof(XSaveHi16_ZMM) != 0x400); QEMU_BUILD_BUG_ON(sizeof(XSavePKRU) != 0x8); QEMU_BUILD_BUG_ON(sizeof(XSaveXTILECFG) != 0x40); QEMU_BUILD_BUG_ON(sizeof(XSaveXTILEDATA) != 0x2000); +QEMU_BUILD_BUG_ON(sizeof(XSavesArchLBR) != 0x328); typedef struct ExtSaveArea { uint32_t feature, bits; @@ -1616,6 +1655,11 @@ typedef struct CPUArchState { uint64_t msr_xfd; uint64_t msr_xfd_err; + /* Per-VCPU Arch LBR MSRs */ + uint64_t msr_lbr_ctl; + uint64_t msr_lbr_depth; + LBREntry lbr_records[ARCH_LBR_NR_ENTRIES]; + /* exception/interrupt handling */ int error_code; int exception_is_int; @@ -1810,6 +1854,15 @@ struct ArchCPU { */ bool enable_pmu; + /* + * Enable LBR_FMT bits of IA32_PERF_CAPABILITIES MSR. + * This can't be initialized with a default because it doesn't have + * stable ABI support yet. It is only allowed to pass all LBR_FMT bits + * returned by kvm_arch_get_supported_msr_feature()(which depends on both + * host CPU and kernel capabilities) to the guest. + */ + uint64_t lbr_fmt; + /* LMCE support can be enabled/disabled via cpu option 'lmce=on/off'. It is * disabled by default to avoid breaking migration between QEMU with * different LMCE configurations. diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index c885763a5b..a9ee8eebd7 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -141,6 +141,7 @@ static struct kvm_msr_list *kvm_feature_msrs; #define BUS_LOCK_SLICE_TIME 1000000000ULL /* ns */ static RateLimit bus_lock_ratelimit_ctrl; +static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value); int kvm_has_pit_state2(void) { @@ -211,28 +212,21 @@ static int kvm_get_tsc(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; - struct { - struct kvm_msrs info; - struct kvm_msr_entry entries[1]; - } msr_data = {}; + uint64_t value; int ret; if (env->tsc_valid) { return 0; } - memset(&msr_data, 0, sizeof(msr_data)); - msr_data.info.nmsrs = 1; - msr_data.entries[0].index = MSR_IA32_TSC; env->tsc_valid = !runstate_is_running(); - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data); + ret = kvm_get_one_msr(cpu, MSR_IA32_TSC, &value); if (ret < 0) { return ret; } - assert(ret == 1); - env->tsc = msr_data.entries[0].data; + env->tsc = value; return 0; } @@ -1566,21 +1560,14 @@ static int hyperv_init_vcpu(X86CPU *cpu) * the kernel doesn't support setting vp_index; assert that its value * is in sync */ - struct { - struct kvm_msrs info; - struct kvm_msr_entry entries[1]; - } msr_data = { - .info.nmsrs = 1, - .entries[0].index = HV_X64_MSR_VP_INDEX, - }; + uint64_t value; - ret = kvm_vcpu_ioctl(cs, KVM_GET_MSRS, &msr_data); + ret = kvm_get_one_msr(cpu, HV_X64_MSR_VP_INDEX, &value); if (ret < 0) { return ret; } - assert(ret == 1); - if (msr_data.entries[0].data != hyperv_vp_index(CPU(cpu))) { + if (value != hyperv_vp_index(CPU(cpu))) { error_report("kernel's vp_index != QEMU's vp_index"); return -ENXIO; } @@ -2839,6 +2826,25 @@ static int kvm_put_one_msr(X86CPU *cpu, int index, uint64_t value) return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); } +static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value) +{ + int ret; + struct { + struct kvm_msrs info; + struct kvm_msr_entry entries[1]; + } msr_data = { + .info.nmsrs = 1, + .entries[0].index = index, + }; + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data); + if (ret < 0) { + return ret; + } + assert(ret == 1); + *value = msr_data.entries[0].data; + return ret; +} void kvm_put_apicbase(X86CPU *cpu, uint64_t value) { int ret; @@ -3361,6 +3367,38 @@ static int kvm_put_msrs(X86CPU *cpu, int level) env->msr_xfd_err); } + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + uint64_t depth; + int i, ret; + + /* + * Only migrate Arch LBR states when: 1) Arch LBR is enabled + * for migrated vcpu. 2) the host Arch LBR depth equals that + * of source guest's, this is to avoid mismatch of guest/host + * config for the msr hence avoid unexpected misbehavior. + */ + ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); + + if (ret == 1 && (env->msr_lbr_ctl & 0x1) && !!depth && + depth == env->msr_lbr_depth) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, env->msr_lbr_ctl); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, env->msr_lbr_depth); + + for (i = 0; i < ARCH_LBR_NR_ENTRIES; i++) { + if (!env->lbr_records[i].from) { + continue; + } + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_FROM_0 + i, + env->lbr_records[i].from); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_TO_0 + i, + env->lbr_records[i].to); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_INFO_0 + i, + env->lbr_records[i].info); + } + } + } + /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see * kvm_put_msr_feature_control. */ } @@ -3761,6 +3799,26 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, 0); } + if (kvm_enabled() && cpu->enable_pmu && + (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { + uint64_t ctl, depth; + int i, ret2; + + ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_CTL, &ctl); + ret2 = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); + if (ret == 1 && ret2 == 1 && (ctl & 0x1) && + depth == ARCH_LBR_NR_ENTRIES) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, 0); + + for (i = 0; i < ARCH_LBR_NR_ENTRIES; i++) { + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_FROM_0 + i, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_TO_0 + i, 0); + kvm_msr_entry_add(cpu, MSR_ARCH_LBR_INFO_0 + i, 0); + } + } + } + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); if (ret < 0) { return ret; @@ -4066,6 +4124,21 @@ static int kvm_get_msrs(X86CPU *cpu) case MSR_IA32_XFD_ERR: env->msr_xfd_err = msrs[i].data; break; + case MSR_ARCH_LBR_CTL: + env->msr_lbr_ctl = msrs[i].data; + break; + case MSR_ARCH_LBR_DEPTH: + env->msr_lbr_depth = msrs[i].data; + break; + case MSR_ARCH_LBR_FROM_0 ... MSR_ARCH_LBR_FROM_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_FROM_0].from = msrs[i].data; + break; + case MSR_ARCH_LBR_TO_0 ... MSR_ARCH_LBR_TO_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_TO_0].to = msrs[i].data; + break; + case MSR_ARCH_LBR_INFO_0 ... MSR_ARCH_LBR_INFO_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_INFO_0].info = msrs[i].data; + break; } } diff --git a/target/i386/machine.c b/target/i386/machine.c index 7c54bada81..cecd476e98 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -136,6 +136,22 @@ static const VMStateDescription vmstate_mtrr_var = { #define VMSTATE_MTRR_VARS(_field, _state, _n, _v) \ VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_mtrr_var, MTRRVar) +static const VMStateDescription vmstate_lbr_records_var = { + .name = "lbr_records_var", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(from, LBREntry), + VMSTATE_UINT64(to, LBREntry), + VMSTATE_UINT64(info, LBREntry), + VMSTATE_END_OF_LIST() + } +}; + +#define VMSTATE_LBR_VARS(_field, _state, _n, _v) \ + VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_lbr_records_var, \ + LBREntry) + typedef struct x86_FPReg_tmp { FPReg *parent; uint64_t tmp_mant; @@ -1525,6 +1541,27 @@ static const VMStateDescription vmstate_amx_xtile = { }; #endif +static bool arch_lbr_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return !!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR); +} + +static const VMStateDescription vmstate_arch_lbr = { + .name = "cpu/arch_lbr", + .version_id = 1, + .minimum_version_id = 1, + .needed = arch_lbr_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.msr_lbr_ctl, X86CPU), + VMSTATE_UINT64(env.msr_lbr_depth, X86CPU), + VMSTATE_LBR_VARS(env.lbr_records, X86CPU, ARCH_LBR_NR_ENTRIES, 1), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_x86_cpu = { .name = "cpu", .version_id = 12, @@ -1668,6 +1705,7 @@ const VMStateDescription vmstate_x86_cpu = { #ifdef TARGET_X86_64 &vmstate_amx_xtile, #endif + &vmstate_arch_lbr, NULL } }; diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 23ae639b23..b22a3314b4 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -373,6 +373,8 @@ static int whpx_set_tsc(CPUState *cpu) * * This mechanism is described in section 10.8.6.1 of Volume 3 of Intel 64 * and IA-32 Architectures Software Developer's Manual. + * + * The functions below translate the value of CR8 to TPR and vice versa. */ static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr) @@ -380,6 +382,11 @@ static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr) return tpr >> 4; } +static uint64_t whpx_cr8_to_apic_tpr(uint64_t cr8) +{ + return cr8 << 4; +} + static void whpx_set_registers(CPUState *cpu, int level) { struct whpx_state *whpx = &whpx_global; @@ -687,7 +694,7 @@ static void whpx_get_registers(CPUState *cpu) tpr = vcxt.values[idx++].Reg64; if (tpr != vcpu->tpr) { vcpu->tpr = tpr; - cpu_set_apic_tpr(x86_cpu->apic_state, tpr); + cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr)); } /* 8 Debug Registers - Skipped */ @@ -1547,7 +1554,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu) } /* Sync the TPR to the CR8 if was modified during the intercept */ - tpr = cpu_get_apic_tpr(x86_cpu->apic_state); + tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state)); if (tpr != vcpu->tpr) { vcpu->tpr = tpr; reg_values[reg_count].Reg64 = tpr; @@ -1596,7 +1603,7 @@ static void whpx_vcpu_post_run(CPUState *cpu) if (vcpu->tpr != tpr) { vcpu->tpr = tpr; qemu_mutex_lock_iothread(); - cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr); + cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(vcpu->tpr)); qemu_mutex_unlock_iothread(); }