From a2f9976ea83c50b452d46b8b1189242617e4ac73 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:35 -0300 Subject: [PATCH 01/21] tests: Add test case for x86 feature parsing compatibility Add a new test case to ensure the existing behavior of the feature parsing code will be kept. Signed-off-by: Eduardo Habkost --- tests/test-x86-cpuid-compat.c | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c index 83162a44c0..260dd2795c 100644 --- a/tests/test-x86-cpuid-compat.c +++ b/tests/test-x86-cpuid-compat.c @@ -3,6 +3,7 @@ #include "qapi/qmp/qlist.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qint.h" +#include "qapi/qmp/qbool.h" #include "libqtest.h" static char *get_cpu0_qom_path(void) @@ -34,6 +35,15 @@ static QObject *qom_get(const char *path, const char *prop) return ret; } +static bool qom_get_bool(const char *path, const char *prop) +{ + QBool *value = qobject_to_qbool(qom_get(path, prop)); + bool b = qbool_get_bool(value); + + QDECREF(value); + return b; +} + typedef struct CpuidTestArgs { const char *cmdline; const char *property; @@ -66,10 +76,44 @@ static void add_cpuid_test(const char *name, const char *cmdline, qtest_add_data_func(name, args, test_cpuid_prop); } +static void test_plus_minus(void) +{ + char *path; + + /* Rules: + * 1)"-foo" overrides "+foo" + * 2) "[+-]foo" overrides "foo=..." + * 3) Old feature names with underscores (e.g. "sse4_2") + * should keep working + * + * Note: rules 1 and 2 are planned to be removed soon, but we + * need to keep compatibility for a while until we start + * warning users about it. + */ + qtest_start("-cpu pentium,-fpu,+fpu,-mce,mce=on,+cx8,cx8=off,+sse4_1,sse4_2=on"); + path = get_cpu0_qom_path(); + + g_assert_false(qom_get_bool(path, "fpu")); + g_assert_false(qom_get_bool(path, "mce")); + g_assert_true(qom_get_bool(path, "cx8")); + + /* Test both the original and the alias feature names: */ + g_assert_true(qom_get_bool(path, "sse4-1")); + g_assert_true(qom_get_bool(path, "sse4.1")); + + g_assert_true(qom_get_bool(path, "sse4-2")); + g_assert_true(qom_get_bool(path, "sse4.2")); + + qtest_end(); + g_free(path); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); + qtest_add_func("x86/cpuid/parsing-plus-minus", test_plus_minus); + /* Original level values for CPU models: */ add_cpuid_test("x86/cpuid/phenom/level", "-cpu phenom", "level", 5); From ee465a3ef77c2b2975ffa71c72208c05b3f3970d Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:36 -0300 Subject: [PATCH 02/21] target-i386: List CPU models using subclass list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using the builtin_x86_defs array, use the QOM subclass list to list CPU models on "-cpu ?" and "query-cpu-definitions". Signed-off-by: Andreas Färber [ehabkost: copied code from a patch by Andreas: "target-i386: QOM'ify CPU", from March 2012] Signed-off-by: Eduardo Habkost --- target-i386/cpu-qom.h | 4 ++ target-i386/cpu.c | 105 ++++++++++++++++++++++++++++++------------ 2 files changed, 79 insertions(+), 30 deletions(-) diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 5dde658ac4..e724004a78 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -63,6 +63,10 @@ typedef struct X86CPUClass { bool kvm_required; + /* Optional description of CPU model. + * If unavailable, cpu_def->model_id is used */ + const char *model_description; + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } X86CPUClass; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 1c57fce81b..cad2759d1f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1628,6 +1628,9 @@ static void host_x86_cpu_class_init(ObjectClass *oc, void *data) cpu_x86_fill_model_id(host_cpudef.model_id); xcc->cpu_def = &host_cpudef; + xcc->model_description = + "KVM processor with all supported host features " + "(only available in KVM mode)"; /* level, xlevel, xlevel2, and the feature words are initialized on * instance_init, because they require KVM to be initialized. @@ -2098,23 +2101,62 @@ static void listflags(FILE *f, fprintf_function print, const char **featureset) } } -/* generate CPU information. */ +/* Sort alphabetically by type name, listing kvm_required models last. */ +static gint x86_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *class_a = (ObjectClass *)a; + ObjectClass *class_b = (ObjectClass *)b; + X86CPUClass *cc_a = X86_CPU_CLASS(class_a); + X86CPUClass *cc_b = X86_CPU_CLASS(class_b); + const char *name_a, *name_b; + + if (cc_a->kvm_required != cc_b->kvm_required) { + /* kvm_required items go last */ + return cc_a->kvm_required ? 1 : -1; + } else { + name_a = object_class_get_name(class_a); + name_b = object_class_get_name(class_b); + return strcmp(name_a, name_b); + } +} + +static GSList *get_sorted_cpu_model_list(void) +{ + GSList *list = object_class_get_list(TYPE_X86_CPU, false); + list = g_slist_sort(list, x86_cpu_list_compare); + return list; +} + +static void x86_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + X86CPUClass *cc = X86_CPU_CLASS(oc); + CPUListState *s = user_data; + char *name = x86_cpu_class_get_model_name(cc); + const char *desc = cc->model_description; + if (!desc) { + desc = cc->cpu_def->model_id; + } + + (*s->cpu_fprintf)(s->file, "x86 %16s %-48s\n", + name, desc); + g_free(name); +} + +/* list available CPU models and flags */ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf) { - X86CPUDefinition *def; - char buf[256]; int i; + CPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; - for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { - def = &builtin_x86_defs[i]; - snprintf(buf, sizeof(buf), "%s", def->name); - (*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id); - } -#ifdef CONFIG_KVM - (*cpu_fprintf)(f, "x86 %16s %-48s\n", "host", - "KVM processor with all supported host features " - "(only available in KVM mode)"); -#endif + (*cpu_fprintf)(f, "Available CPUs:\n"); + list = get_sorted_cpu_model_list(); + g_slist_foreach(list, x86_cpu_list_entry, &s); + g_slist_free(list); (*cpu_fprintf)(f, "\nRecognized CPUID flags:\n"); for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) { @@ -2126,26 +2168,29 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf) } } +static void x86_cpu_definition_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + X86CPUClass *cc = X86_CPU_CLASS(oc); + CpuDefinitionInfoList **cpu_list = user_data; + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + + info = g_malloc0(sizeof(*info)); + info->name = x86_cpu_class_get_model_name(cc); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = *cpu_list; + *cpu_list = entry; +} + CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) { CpuDefinitionInfoList *cpu_list = NULL; - X86CPUDefinition *def; - int i; - - for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { - CpuDefinitionInfoList *entry; - CpuDefinitionInfo *info; - - def = &builtin_x86_defs[i]; - info = g_malloc0(sizeof(*info)); - info->name = g_strdup(def->name); - - entry = g_malloc0(sizeof(*entry)); - entry->value = info; - entry->next = cpu_list; - cpu_list = entry; - } - + GSList *list = get_sorted_cpu_model_list(); + g_slist_foreach(list, x86_cpu_definition_entry, &cpu_list); + g_slist_free(list); return cpu_list; } From 04d99c3c61f4bdc0450dbeb6512b6dd743baca65 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:37 -0300 Subject: [PATCH 03/21] target-i386: Disable VME by default with TCG VME is already disabled automatically when using TCG. So, instead of pretending it is there when reporting CPU model data on query-cpu-* QMP commands (making every CPU model to be reported as not runnable), we can disable it by default on all CPU models when using TCG. Do that by adding a tcg_default_props array that will work like kvm_default_props. Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index cad2759d1f..25a3d80221 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1550,6 +1550,14 @@ static PropValue kvm_default_props[] = { { NULL, NULL }, }; +/* TCG-specific defaults that override all CPU models when using TCG + */ +static PropValue tcg_default_props[] = { + { "vme", "off" }, + { NULL, NULL }, +}; + + void x86_cpu_change_kvm_default(const char *prop, const char *value) { PropValue *pv; @@ -2283,6 +2291,8 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) } x86_cpu_apply_props(cpu, kvm_default_props); + } else if (tcg_enabled()) { + x86_cpu_apply_props(cpu, tcg_default_props); } env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR; From 54b8dc7c19cd781e96f1e9b001ca6001d804eb19 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:38 -0300 Subject: [PATCH 04/21] target-i386: Register aliases for feature names with underscores Registering the actual names containing underscores as aliases will allow management software to be aware that the old compatibility names are suported, and will make feat2prop() calls unnecessary when using feature names. Also, this will help us avoid making the code support underscores on feature names that never had them in the first place. e.g. "+tsc_deadline" was never supported and doesn't need to be translated to "+tsc-deadline". In other word: this will require less magic translation of strings, and simple 1:1 match between the config options and actual QOM properties. Note that the underscores are still present in the FeatureWordInfo::feat_names arrays, because add_flagname_to_bitmaps() needs them to be kept. The next patches will remove add_flagname_to_bitmaps() and will allow us to finally remove the aliases from feat_names. Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 25a3d80221..fe62ae124c 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3455,6 +3455,28 @@ static void x86_cpu_initfn(Object *obj) } } + object_property_add_alias(obj, "ds_cpl", obj, "ds-cpl", &error_abort); + object_property_add_alias(obj, "tsc_adjust", obj, "tsc-adjust", &error_abort); + object_property_add_alias(obj, "fxsr_opt", obj, "fxsr-opt", &error_abort); + object_property_add_alias(obj, "lahf_lm", obj, "lahf-lm", &error_abort); + object_property_add_alias(obj, "cmp_legacy", obj, "cmp-legacy", &error_abort); + object_property_add_alias(obj, "nodeid_msr", obj, "nodeid-msr", &error_abort); + object_property_add_alias(obj, "perfctr_core", obj, "perfctr-core", &error_abort); + object_property_add_alias(obj, "perfctr_nb", obj, "perfctr-nb", &error_abort); + object_property_add_alias(obj, "kvm_nopiodelay", obj, "kvm-nopiodelay", &error_abort); + object_property_add_alias(obj, "kvm_mmu", obj, "kvm-mmu", &error_abort); + object_property_add_alias(obj, "kvm_asyncpf", obj, "kvm-asyncpf", &error_abort); + object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time", &error_abort); + object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi", &error_abort); + object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt", &error_abort); + object_property_add_alias(obj, "svm_lock", obj, "svm-lock", &error_abort); + object_property_add_alias(obj, "nrip_save", obj, "nrip-save", &error_abort); + object_property_add_alias(obj, "tsc_scale", obj, "tsc-scale", &error_abort); + object_property_add_alias(obj, "vmcb_clean", obj, "vmcb-clean", &error_abort); + object_property_add_alias(obj, "pause_filter", obj, "pause-filter", &error_abort); + object_property_add_alias(obj, "sse4_1", obj, "sse4.1", &error_abort); + object_property_add_alias(obj, "sse4_2", obj, "sse4.2", &error_abort); + x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort); } From 2fae0d96e6834f3bf98065a9cddedad120f9b2b4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:39 -0300 Subject: [PATCH 05/21] target-i386: Make plus_features/minus_features QOM-based Instead of using custom feature name lookup code for plus_features/minus_features, save the property names used in "[+-]feature" and use object_property_set_bool() to set them. We don't need a feat2prop() call because we now have alias properties for the old names containing underscores. Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 106 +++++++++------------------------------------- 1 file changed, 20 insertions(+), 86 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index fe62ae124c..c5c767bb80 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -650,85 +650,6 @@ void host_cpuid(uint32_t function, uint32_t count, *edx = vec[3]; } -#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c))) - -/* general substring compare of *[s1..e1) and *[s2..e2). sx is start of - * a substring. ex if !NULL points to the first char after a substring, - * otherwise the string is assumed to sized by a terminating nul. - * Return lexical ordering of *s1:*s2. - */ -static int sstrcmp(const char *s1, const char *e1, - const char *s2, const char *e2) -{ - for (;;) { - if (!*s1 || !*s2 || *s1 != *s2) - return (*s1 - *s2); - ++s1, ++s2; - if (s1 == e1 && s2 == e2) - return (0); - else if (s1 == e1) - return (*s2); - else if (s2 == e2) - return (*s1); - } -} - -/* compare *[s..e) to *altstr. *altstr may be a simple string or multiple - * '|' delimited (possibly empty) strings in which case search for a match - * within the alternatives proceeds left to right. Return 0 for success, - * non-zero otherwise. - */ -static int altcmp(const char *s, const char *e, const char *altstr) -{ - const char *p, *q; - - for (q = p = altstr; ; ) { - while (*p && *p != '|') - ++p; - if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p))) - return (0); - if (!*p) - return (1); - else - q = ++p; - } -} - -/* search featureset for flag *[s..e), if found set corresponding bit in - * *pval and return true, otherwise return false - */ -static bool lookup_feature(uint32_t *pval, const char *s, const char *e, - const char **featureset) -{ - uint32_t mask; - const char **ppc; - bool found = false; - - for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) { - if (*ppc && !altcmp(s, e, *ppc)) { - *pval |= mask; - found = true; - } - } - return found; -} - -static void add_flagname_to_bitmaps(const char *flagname, - FeatureWordArray words, - Error **errp) -{ - FeatureWord w; - for (w = 0; w < FEATURE_WORDS; w++) { - FeatureWordInfo *wi = &feature_word_info[w]; - if (lookup_feature(&words[w], flagname, NULL, wi->feat_names)) { - break; - } - } - if (w == FEATURE_WORDS) { - error_setg(errp, "CPU feature %s not found", flagname); - } -} - /* CPU class name definitions: */ #define X86_CPU_TYPE_SUFFIX "-" TYPE_X86_CPU @@ -2015,8 +1936,7 @@ static inline void feat2prop(char *s) * feat=on|feat even if the later is parsed after +-feat * (i.e. "-x2apic,x2apic=on" will result in x2apic disabled) */ -static FeatureWordArray plus_features = { 0 }; -static FeatureWordArray minus_features = { 0 }; +static GList *plus_features, *minus_features; /* Parse "+feature,-feature,feature=foo" CPU feature string */ @@ -2047,10 +1967,12 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, /* Compatibility syntax: */ if (featurestr[0] == '+') { - add_flagname_to_bitmaps(featurestr + 1, plus_features, &local_err); + plus_features = g_list_append(plus_features, + g_strdup(featurestr + 1)); continue; } else if (featurestr[0] == '-') { - add_flagname_to_bitmaps(featurestr + 1, minus_features, &local_err); + minus_features = g_list_append(minus_features, + g_strdup(featurestr + 1)); continue; } @@ -3066,6 +2988,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) Error *local_err = NULL; static bool ht_warned; FeatureWord w; + GList *l; if (xcc->kvm_required && !kvm_enabled()) { char *name = x86_cpu_class_get_model_name(xcc); @@ -3091,9 +3014,20 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) } } - for (w = 0; w < FEATURE_WORDS; w++) { - cpu->env.features[w] |= plus_features[w]; - cpu->env.features[w] &= ~minus_features[w]; + for (l = plus_features; l; l = l->next) { + const char *prop = l->data; + object_property_set_bool(OBJECT(cpu), true, prop, &local_err); + if (local_err) { + goto out; + } + } + + for (l = minus_features; l; l = l->next) { + const char *prop = l->data; + object_property_set_bool(OBJECT(cpu), false, prop, &local_err); + if (local_err) { + goto out; + } } if (!kvm_enabled() || !cpu->expose_kvm) { From fc7dfd205f3287893c436d932a167bffa30579c8 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:40 -0300 Subject: [PATCH 06/21] target-i386: Remove underscores from feat_names arrays Instead of translating the feature name entries when adding property names, store the actual property names in the feature name array. For reference, here is the full list of functions that use FeatureWordInfo::feat_names: * x86_cpu_get_migratable_flags(): not affected, as it just check for non-NULL values. * report_unavailable_features(): informative only. It will start printing feature names with hyphens. * x86_cpu_list(): informative only. It will start printing feature names with hyphens * x86_cpu_register_feature_bit_props(): not affected, as it was already calling feat2prop(). Now we can remove the feat2prop() calls safely. So, the only user-visible effect of this patch are the new names being used in help and error messages for users. Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index c5c767bb80..483490dc6d 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -279,11 +279,11 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_1_ECX] = { .feat_names = { "pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor", - "ds_cpl", "vmx", "smx", "est", + "ds-cpl", "vmx", "smx", "est", "tm2", "ssse3", "cid", NULL, "fma", "cx16", "xtpr", "pdcm", - NULL, "pcid", "dca", "sse4.1|sse4_1", - "sse4.2|sse4_2", "x2apic", "movbe", "popcnt", + NULL, "pcid", "dca", "sse4.1|sse4-1", + "sse4.2|sse4-2", "x2apic", "movbe", "popcnt", "tsc-deadline", "aes", "xsave", "osxsave", "avx", "f16c", "rdrand", "hypervisor", }, @@ -303,7 +303,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { NULL /* mtrr */, NULL /* pge */, NULL /* mca */, NULL /* cmov */, NULL /* pat */, NULL /* pse36 */, NULL, NULL /* Linux mp */, "nx|xd", NULL, "mmxext", NULL /* mmx */, - NULL /* fxsr */, "fxsr_opt|ffxsr", "pdpe1gb", "rdtscp", + NULL /* fxsr */, "fxsr-opt|ffxsr", "pdpe1gb", "rdtscp", NULL, "lm|i64", "3dnowext", "3dnow", }, .cpuid_eax = 0x80000001, .cpuid_reg = R_EDX, @@ -311,13 +311,13 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, [FEAT_8000_0001_ECX] = { .feat_names = { - "lahf_lm", "cmp_legacy", "svm", "extapic", + "lahf-lm", "cmp-legacy", "svm", "extapic", "cr8legacy", "abm", "sse4a", "misalignsse", "3dnowprefetch", "osvw", "ibs", "xop", "skinit", "wdt", NULL, "lwp", - "fma4", "tce", NULL, "nodeid_msr", - NULL, "tbm", "topoext", "perfctr_core", - "perfctr_nb", NULL, NULL, NULL, + "fma4", "tce", NULL, "nodeid-msr", + NULL, "tbm", "topoext", "perfctr-core", + "perfctr-nb", NULL, NULL, NULL, NULL, NULL, NULL, NULL, }, .cpuid_eax = 0x80000001, .cpuid_reg = R_ECX, @@ -339,8 +339,8 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, [FEAT_KVM] = { .feat_names = { - "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", - "kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", "kvm_pv_unhalt", + "kvmclock", "kvm-nopiodelay", "kvm-mmu", "kvmclock", + "kvm-asyncpf", "kvm-steal-time", "kvm-pv-eoi", "kvm-pv-unhalt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -400,9 +400,9 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, [FEAT_SVM] = { .feat_names = { - "npt", "lbrv", "svm_lock", "nrip_save", - "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists", - NULL, NULL, "pause_filter", NULL, + "npt", "lbrv", "svm-lock", "nrip-save", + "tsc-scale", "vmcb-clean", "flushbyasid", "decodeassists", + NULL, NULL, "pause-filter", NULL, "pfthreshold", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -414,7 +414,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, [FEAT_7_0_EBX] = { .feat_names = { - "fsgsbase", "tsc_adjust", NULL, "bmi1", + "fsgsbase", "tsc-adjust", NULL, "bmi1", "hle", "avx2", NULL, "smep", "bmi2", "erms", "invpcid", "rtm", NULL, NULL, "mpx", NULL, @@ -3332,11 +3332,15 @@ static void x86_cpu_register_feature_bit_props(X86CPU *cpu, names = g_strsplit(fi->feat_names[bitnr], "|", 0); - feat2prop(names[0]); + /* Property names should use "-" instead of "_". + * Old names containing underscores are registered as aliases + * using object_property_add_alias() + */ + assert(!strchr(names[0], '_')); x86_cpu_register_bit_prop(cpu, names[0], &cpu->env.features[w], bitnr); for (i = 1; names[i]; i++) { - feat2prop(names[i]); + assert(!strchr(names[i], '_')); object_property_add_alias(obj, names[i], obj, names[0], &error_abort); } From 16d2fcaa509b1ca56eb2fcd8fe877279cf65cccc Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:41 -0300 Subject: [PATCH 07/21] target-i386: Register properties for feature aliases manually Instead of keeping the aliases inside the feature name arrays and require parsing the strings, just register alias properties manually. This simplifies the code for property registration and lookup. Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 483490dc6d..b9ef34e49f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -278,12 +278,12 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, [FEAT_1_ECX] = { .feat_names = { - "pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor", + "pni" /* Intel,AMD sse3 */, "pclmulqdq", "dtes64", "monitor", "ds-cpl", "vmx", "smx", "est", "tm2", "ssse3", "cid", NULL, "fma", "cx16", "xtpr", "pdcm", - NULL, "pcid", "dca", "sse4.1|sse4-1", - "sse4.2|sse4-2", "x2apic", "movbe", "popcnt", + NULL, "pcid", "dca", "sse4.1", + "sse4.2", "x2apic", "movbe", "popcnt", "tsc-deadline", "aes", "xsave", "osxsave", "avx", "f16c", "rdrand", "hypervisor", }, @@ -302,9 +302,9 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { NULL /* cx8 */, NULL /* apic */, NULL, "syscall", NULL /* mtrr */, NULL /* pge */, NULL /* mca */, NULL /* cmov */, NULL /* pat */, NULL /* pse36 */, NULL, NULL /* Linux mp */, - "nx|xd", NULL, "mmxext", NULL /* mmx */, - NULL /* fxsr */, "fxsr-opt|ffxsr", "pdpe1gb", "rdtscp", - NULL, "lm|i64", "3dnowext", "3dnow", + "nx", NULL, "mmxext", NULL /* mmx */, + NULL /* fxsr */, "fxsr-opt", "pdpe1gb", "rdtscp", + NULL, "lm", "3dnowext", "3dnow", }, .cpuid_eax = 0x80000001, .cpuid_reg = R_EDX, .tcg_features = TCG_EXT2_FEATURES, @@ -3321,31 +3321,22 @@ static void x86_cpu_register_feature_bit_props(X86CPU *cpu, FeatureWord w, int bitnr) { - Object *obj = OBJECT(cpu); - int i; - char **names; FeatureWordInfo *fi = &feature_word_info[w]; + const char *name = fi->feat_names[bitnr]; - if (!fi->feat_names[bitnr]) { + if (!name) { return; } - names = g_strsplit(fi->feat_names[bitnr], "|", 0); - /* Property names should use "-" instead of "_". * Old names containing underscores are registered as aliases * using object_property_add_alias() */ - assert(!strchr(names[0], '_')); - x86_cpu_register_bit_prop(cpu, names[0], &cpu->env.features[w], bitnr); - - for (i = 1; names[i]; i++) { - assert(!strchr(names[i], '_')); - object_property_add_alias(obj, names[i], obj, names[0], - &error_abort); - } - - g_strfreev(names); + assert(!strchr(name, '_')); + /* aliases don't use "|" delimiters anymore, they are registered + * manually using object_property_add_alias() */ + assert(!strchr(name, '|')); + x86_cpu_register_bit_prop(cpu, name, &cpu->env.features[w], bitnr); } static void x86_cpu_initfn(Object *obj) @@ -3393,6 +3384,14 @@ static void x86_cpu_initfn(Object *obj) } } + object_property_add_alias(obj, "sse3", obj, "pni", &error_abort); + object_property_add_alias(obj, "pclmuldq", obj, "pclmulqdq", &error_abort); + object_property_add_alias(obj, "sse4-1", obj, "sse4.1", &error_abort); + object_property_add_alias(obj, "sse4-2", obj, "sse4.2", &error_abort); + object_property_add_alias(obj, "xd", obj, "nx", &error_abort); + object_property_add_alias(obj, "ffxsr", obj, "fxsr-opt", &error_abort); + object_property_add_alias(obj, "i64", obj, "lm", &error_abort); + object_property_add_alias(obj, "ds_cpl", obj, "ds-cpl", &error_abort); object_property_add_alias(obj, "tsc_adjust", obj, "tsc-adjust", &error_abort); object_property_add_alias(obj, "fxsr_opt", obj, "fxsr-opt", &error_abort); From e3c9022b4e2b6a4deb6518361d2bbf33522b9198 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:42 -0300 Subject: [PATCH 08/21] target-i386: xsave: Add FP and SSE bits to x86_ext_save_areas Instead of treating the FP and SSE bits as special cases, add them to the x86_ext_save_areas array. This will simplify the code that calculates the supported xsave components and the size of the xsave area. Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b9ef34e49f..61240dd3ee 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -535,6 +535,20 @@ typedef struct ExtSaveArea { } ExtSaveArea; static const ExtSaveArea x86_ext_save_areas[] = { + [XSTATE_FP_BIT] = { + /* x87 FP state component is always enabled if XSAVE is supported */ + .feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE, + /* x87 state is in the legacy region of the XSAVE area */ + .offset = 0, + .size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader), + }, + [XSTATE_SSE_BIT] = { + /* SSE state component is always enabled if XSAVE is supported */ + .feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE, + /* SSE state is in the legacy region of the XSAVE area */ + .offset = 0, + .size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader), + }, [XSTATE_YMM_BIT] = { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX, .offset = offsetof(X86XSaveArea, avx_state), @@ -568,9 +582,9 @@ static const ExtSaveArea x86_ext_save_areas[] = { static uint32_t xsave_area_size(uint64_t mask) { int i; - uint64_t ret = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader); + uint64_t ret = 0; - for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; if ((mask >> i) & 1) { ret = MAX(ret, esa->offset + esa->size); @@ -2961,8 +2975,8 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) return; } - mask = (XSTATE_FP_MASK | XSTATE_SSE_MASK); - for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + mask = 0; + for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; if (env->features[esa->feature] & esa->bits) { mask |= (1ULL << i); From 9504e7100b74ae688601ec2c990bb80a47f263e3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 30 Sep 2016 15:49:45 -0300 Subject: [PATCH 09/21] qmp: Add runnability information to query-cpu-definitions Add a new optional field to query-cpu-definitions schema: "unavailable-features". It will contain a list of QOM properties that prevent the CPU model from running in the current host. Cc: David Hildenbrand Cc: Michael Mueller Cc: Christian Borntraeger Cc: Cornelia Huck Cc: Jiri Denemark Cc: libvir-list@redhat.com Reviewed-by: Eric Blake Signed-off-by: Eduardo Habkost --- qapi-schema.json | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/qapi-schema.json b/qapi-schema.json index ded1179f06..5a8ec38e10 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3101,10 +3101,31 @@ # QEMU version, machine type, machine options and accelerator options. # A static model is always migration-safe. (since 2.8) # +# @unavailable-features: #optional List of properties that prevent +# the CPU model from running in the current +# host. (since 2.8) +# +# @unavailable-features is a list of QOM property names that +# represent CPU model attributes that prevent the CPU from running. +# If the QOM property is read-only, that means there's no known +# way to make the CPU model run in the current host. Implementations +# that choose not to provide specific information return the +# property name "type". +# If the property is read-write, it means that it MAY be possible +# to run the CPU model in the current host if that property is +# changed. Management software can use it as hints to suggest or +# choose an alternative for the user, or just to generate meaningful +# error messages explaining why the CPU model can't be used. +# If @unavailable-features is an empty list, the CPU model is +# runnable using the current host and machine-type. +# If @unavailable-features is not present, runnability +# information for the CPU is not available. +# # Since: 1.2.0 ## { 'struct': 'CpuDefinitionInfo', - 'data': { 'name': 'str', '*migration-safe': 'bool', 'static': 'bool' } } + 'data': { 'name': 'str', '*migration-safe': 'bool', 'static': 'bool', + '*unavailable-features': [ 'str' ] } } ## # @query-cpu-definitions: From 8ca30e8673aff9bfcf8f969f8db4266b5f62e49c Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 4 May 2016 14:50:46 -0300 Subject: [PATCH 10/21] target-i386: Move warning code outside x86_cpu_filter_features() x86_cpu_filter_features() will be reused by code that shouldn't print any warning. Move the warning code to a new x86_cpu_report_filtered_features() function, and call it from x86_cpu_realizefn(). Reviewed-by: Igor Mammedov Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 61240dd3ee..1e8127b422 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2177,9 +2177,6 @@ static int x86_cpu_filter_features(X86CPU *cpu) env->features[w] &= host_feat; cpu->filtered_features[w] = requested_features & ~env->features[w]; if (cpu->filtered_features[w]) { - if (cpu->check_cpuid || cpu->enforce_cpuid) { - report_unavailable_features(w, cpu->filtered_features[w]); - } rv = 1; } } @@ -2187,6 +2184,15 @@ static int x86_cpu_filter_features(X86CPU *cpu) return rv; } +static void x86_cpu_report_filtered_features(X86CPU *cpu) +{ + FeatureWord w; + + for (w = 0; w < FEATURE_WORDS; w++) { + report_unavailable_features(w, cpu->filtered_features[w]); + } +} + static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) { PropValue *pv; @@ -3080,12 +3086,16 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) env->cpuid_xlevel2 = env->cpuid_min_xlevel2; } - if (x86_cpu_filter_features(cpu) && cpu->enforce_cpuid) { - error_setg(&local_err, - kvm_enabled() ? - "Host doesn't support requested features" : - "TCG doesn't support requested features"); - goto out; + if (x86_cpu_filter_features(cpu) && + (cpu->check_cpuid || cpu->enforce_cpuid)) { + x86_cpu_report_filtered_features(cpu); + if (cpu->enforce_cpuid) { + error_setg(&local_err, + kvm_enabled() ? + "Host doesn't support requested features" : + "TCG doesn't support requested features"); + goto out; + } } /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on From 2f114315dcf239bc513f18ae0b04b5df81cae059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Mon, 10 Oct 2016 17:28:42 +0200 Subject: [PATCH 11/21] apic: add global apic_get_class() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every configuration has only up to one APIC class and we'll be extending the class with a function that can be called without an instanced object, so a direct access to the class is convenient. This patch will break compilation if some code uses apic_get_class() with CONFIG_USER_ONLY. Suggested-by: Eduardo Habkost Reviewed-by: Eduardo Habkost Reviewed-by: Peter Xu Signed-off-by: Radim Krčmář Signed-off-by: Eduardo Habkost --- hw/intc/apic_common.c | 1 + include/hw/i386/apic_internal.h | 2 ++ target-i386/cpu.c | 13 ++++++++++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 14ac43c186..8d01c9c875 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -18,6 +18,7 @@ * License along with this library; if not, see */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index 06c4e9f6f9..286684857e 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -222,4 +222,6 @@ static inline int apic_get_bit(uint32_t *tab, int index) return !!(tab[i] & mask); } +APICCommonClass *apic_get_class(void); + #endif /* QEMU_APIC_INTERNAL_H */ diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 1e8127b422..5b3ad78758 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2845,9 +2845,8 @@ static void mce_init(X86CPU *cpu) } #ifndef CONFIG_USER_ONLY -static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) +APICCommonClass *apic_get_class(void) { - APICCommonState *apic; const char *apic_type = "apic"; if (kvm_apic_in_kernel()) { @@ -2856,7 +2855,15 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) apic_type = "xen-apic"; } - cpu->apic_state = DEVICE(object_new(apic_type)); + return APIC_COMMON_CLASS(object_class_by_name(apic_type)); +} + +static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) +{ + APICCommonState *apic; + ObjectClass *apic_class = OBJECT_CLASS(apic_get_class()); + + cpu->apic_state = DEVICE(object_new(object_class_get_name(apic_class))); object_property_add_child(OBJECT(cpu), "lapic", OBJECT(cpu->apic_state), &error_abort); From 267ee357153bb61870b60da69ba9f839ddb0e32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Mon, 10 Oct 2016 17:28:43 +0200 Subject: [PATCH 12/21] apic: add send_msi() to APICCommonClass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MMIO based interface to APIC doesn't work well with MSIs that have upper address bits set (remapped x2APIC MSIs). A specialized interface is a quick and dirty way to avoid the shortcoming. Reviewed-by: Igor Mammedov Reviewed-by: Peter Xu Signed-off-by: Radim Krčmář Signed-off-by: Eduardo Habkost --- hw/i386/kvm/apic.c | 19 +++++++++++++------ hw/i386/xen/xen_apic.c | 6 ++++++ hw/intc/apic.c | 8 ++++++-- include/hw/i386/apic_internal.h | 4 ++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index c016e63fc2..be55102c00 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -169,6 +169,17 @@ static void kvm_apic_external_nmi(APICCommonState *s) run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s); } +static void kvm_send_msi(MSIMessage *msg) +{ + int ret; + + ret = kvm_irqchip_send_msi(kvm_state, *msg); + if (ret < 0) { + fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n", + strerror(-ret)); + } +} + static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr, unsigned size) { @@ -179,13 +190,8 @@ static void kvm_apic_mem_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { MSIMessage msg = { .address = addr, .data = data }; - int ret; - ret = kvm_irqchip_send_msi(kvm_state, msg); - if (ret < 0) { - fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n", - strerror(-ret)); - } + kvm_send_msi(&msg); } static const MemoryRegionOps kvm_apic_io_ops = { @@ -232,6 +238,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data) k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting; k->vapic_base_update = kvm_apic_vapic_base_update; k->external_nmi = kvm_apic_external_nmi; + k->send_msi = kvm_send_msi; } static const TypeInfo kvm_apic_info = { diff --git a/hw/i386/xen/xen_apic.c b/hw/i386/xen/xen_apic.c index 21d68ee04b..55769eba7e 100644 --- a/hw/i386/xen/xen_apic.c +++ b/hw/i386/xen/xen_apic.c @@ -68,6 +68,11 @@ static void xen_apic_external_nmi(APICCommonState *s) { } +static void xen_send_msi(MSIMessage *msi) +{ + xen_hvm_inject_msi(msi->address, msi->data); +} + static void xen_apic_class_init(ObjectClass *klass, void *data) { APICCommonClass *k = APIC_COMMON_CLASS(klass); @@ -78,6 +83,7 @@ static void xen_apic_class_init(ObjectClass *klass, void *data) k->get_tpr = xen_apic_get_tpr; k->vapic_base_update = xen_apic_vapic_base_update; k->external_nmi = xen_apic_external_nmi; + k->send_msi = xen_send_msi; } static const TypeInfo xen_apic_info = { diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 7bd1d279c4..fe15fb6024 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -740,8 +740,10 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr) return val; } -static void apic_send_msi(hwaddr addr, uint32_t data) +static void apic_send_msi(MSIMessage *msi) { + uint64_t addr = msi->address; + uint32_t data = msi->data; uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; @@ -762,7 +764,8 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val) * APIC is connected directly to the CPU. * Mapping them on the global bus happens to work because * MSI registers are reserved in APIC MMIO and vice versa. */ - apic_send_msi(addr, val); + MSIMessage msi = { .address = addr, .data = val }; + apic_send_msi(&msi); return; } @@ -913,6 +916,7 @@ static void apic_class_init(ObjectClass *klass, void *data) k->external_nmi = apic_external_nmi; k->pre_save = apic_pre_save; k->post_load = apic_post_load; + k->send_msi = apic_send_msi; } static const TypeInfo apic_info = { diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index 286684857e..cdd11fb093 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -146,6 +146,10 @@ typedef struct APICCommonClass void (*pre_save)(APICCommonState *s); void (*post_load)(APICCommonState *s); void (*reset)(APICCommonState *s); + /* send_msi emulates an APIC bus and its proper place would be in a new + * device, but it's convenient to have it here for now. + */ + void (*send_msi)(MSIMessage *msi); } APICCommonClass; struct APICCommonState { From 329460191d527e0cfa9ddbd14c75994e73de1975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Mon, 10 Oct 2016 17:28:44 +0200 Subject: [PATCH 13/21] intel_iommu: pass whole remapped addresses to apic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MMIO interface to APIC only allowed 8 bit addresses, which is not enough for 32 bit addresses from EIM remapping. Intel stored upper 24 bits in the high MSI address, so use the same technique. The technique is also used in KVM MSI interface. Other APICs are unlikely to handle those upper bits. Reviewed-by: Peter Xu Signed-off-by: Radim Krčmář Signed-off-by: Eduardo Habkost --- hw/i386/intel_iommu.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 2efd69bbd7..d22a51c488 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -32,6 +32,7 @@ #include "hw/i386/x86-iommu.h" #include "hw/pci-host/q35.h" #include "sysemu/kvm.h" +#include "hw/i386/apic_internal.h" /*#define DEBUG_INTEL_IOMMU*/ #ifdef DEBUG_INTEL_IOMMU @@ -280,18 +281,17 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg, hwaddr mesg_data_reg) { - hwaddr addr; - uint32_t data; + MSIMessage msi; assert(mesg_data_reg < DMAR_REG_SIZE); assert(mesg_addr_reg < DMAR_REG_SIZE); - addr = vtd_get_long_raw(s, mesg_addr_reg); - data = vtd_get_long_raw(s, mesg_data_reg); + msi.address = vtd_get_long_raw(s, mesg_addr_reg); + msi.data = vtd_get_long_raw(s, mesg_data_reg); - VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32, addr, data); - address_space_stl_le(&address_space_memory, addr, data, - MEMTXATTRS_UNSPECIFIED, NULL); + VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32, + msi.address, msi.data); + apic_get_class()->send_msi(&msi); } /* Generate a fault event to software via MSI if conditions are met. @@ -2134,6 +2134,7 @@ static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out) msg.dest_mode = irq->dest_mode; msg.redir_hint = irq->redir_hint; msg.dest = irq->dest; + msg.__addr_hi = irq->dest & 0xffffff00; msg.__addr_head = cpu_to_le32(0xfee); /* Keep this from original MSI address bits */ msg.__not_used = irq->msi_addr_last_bits; @@ -2293,11 +2294,7 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, " for device sid 0x%04x", to.address, to.data, sid); - if (dma_memory_write(&address_space_memory, to.address, - &to.data, size)) { - VTD_DPRINTF(GENERAL, "error: fail to write 0x%"PRIx64 - " value 0x%"PRIx32, to.address, to.data); - } + apic_get_class()->send_msi(&to); return MEMTX_OK; } From 6333e93c772f78baf26a5c97c1a67ffa7cd76068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Mon, 10 Oct 2016 17:28:45 +0200 Subject: [PATCH 14/21] intel_iommu: redo configuraton check in realize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * there no point in configuring the device if realization is going to fail, so move the check to the beginning, * create a separate function for the check, * use error_setg() instead error_report(). Reviewed-by: Igor Mammedov Reviewed-by: Peter Xu Signed-off-by: Radim Krčmář Signed-off-by: Eduardo Habkost --- hw/i386/intel_iommu.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index d22a51c488..29cd2ae51d 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "intel_iommu_internal.h" @@ -2460,6 +2461,18 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &vtd_as->as; } +static bool vtd_check_config(X86IOMMUState *x86_iommu, Error **errp) +{ + /* Currently Intel IOMMU IR only support "kernel-irqchip={off|split}" */ + if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() && + !kvm_irqchip_is_split()) { + error_setg(errp, "Intel Interrupt Remapping cannot work with " + "kernel-irqchip=on, please use 'split|off'."); + return false; + } + return true; +} + static void vtd_realize(DeviceState *dev, Error **errp) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); @@ -2469,6 +2482,11 @@ static void vtd_realize(DeviceState *dev, Error **errp) VTD_DPRINTF(GENERAL, ""); x86_iommu->type = TYPE_INTEL; + + if (!vtd_check_config(x86_iommu, errp)) { + return; + } + memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, "intel_iommu", DMAR_REG_SIZE); @@ -2483,14 +2501,6 @@ static void vtd_realize(DeviceState *dev, Error **errp) pci_setup_iommu(bus, vtd_host_dma_iommu, dev); /* Pseudo address space under root PCI bus. */ pcms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC); - - /* Currently Intel IOMMU IR only support "kernel-irqchip={off|split}" */ - if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() && - !kvm_irqchip_is_split()) { - error_report("Intel Interrupt Remapping cannot work with " - "kernel-irqchip=on, please use 'split|off'."); - exit(1); - } } static void vtd_class_init(ObjectClass *klass, void *data) From e6b6af05607a8bc828c454f6830b5fc68e5a9ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Mon, 10 Oct 2016 17:28:46 +0200 Subject: [PATCH 15/21] intel_iommu: add OnOffAuto intr_eim as "eim" property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default (auto) emulates the current behavior. A user can now control EIM like -device intel-iommu,intremap=on,eim=off Reviewed-by: Igor Mammedov Reviewed-by: Peter Xu Signed-off-by: Radim Krčmář Signed-off-by: Eduardo Habkost --- hw/i386/intel_iommu.c | 24 +++++++++++++++++++++--- include/hw/i386/intel_iommu.h | 1 + 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 29cd2ae51d..a70aa8494e 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2013,6 +2013,8 @@ static const MemoryRegionOps vtd_mem_ops = { static Property vtd_properties[] = { DEFINE_PROP_UINT32("version", IntelIOMMUState, version, 0), + DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim, + ON_OFF_AUTO_AUTO), DEFINE_PROP_END_OF_LIST(), }; @@ -2380,7 +2382,11 @@ static void vtd_init(IntelIOMMUState *s) s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO; if (x86_iommu->intr_supported) { - s->ecap |= VTD_ECAP_IR | VTD_ECAP_EIM | VTD_ECAP_MHMV; + s->ecap |= VTD_ECAP_IR | VTD_ECAP_MHMV; + if (s->intr_eim == ON_OFF_AUTO_ON) { + s->ecap |= VTD_ECAP_EIM; + } + assert(s->intr_eim != ON_OFF_AUTO_AUTO); } vtd_reset_context_cache(s); @@ -2461,8 +2467,10 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &vtd_as->as; } -static bool vtd_check_config(X86IOMMUState *x86_iommu, Error **errp) +static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) { + X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); + /* Currently Intel IOMMU IR only support "kernel-irqchip={off|split}" */ if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() && !kvm_irqchip_is_split()) { @@ -2470,6 +2478,16 @@ static bool vtd_check_config(X86IOMMUState *x86_iommu, Error **errp) "kernel-irqchip=on, please use 'split|off'."); return false; } + if (s->intr_eim == ON_OFF_AUTO_ON && !x86_iommu->intr_supported) { + error_setg(errp, "eim=on cannot be selected without intremap=on"); + return false; + } + + if (s->intr_eim == ON_OFF_AUTO_AUTO) { + s->intr_eim = x86_iommu->intr_supported ? + ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; + } + return true; } @@ -2483,7 +2501,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) VTD_DPRINTF(GENERAL, ""); x86_iommu->type = TYPE_INTEL; - if (!vtd_check_config(x86_iommu, errp)) { + if (!vtd_decide_config(s, errp)) { return; } diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index a42dbd745a..b5ac60927b 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -289,6 +289,7 @@ struct IntelIOMMUState { dma_addr_t intr_root; /* Interrupt remapping table pointer */ uint32_t intr_size; /* Number of IR table entries */ bool intr_eime; /* Extended interrupt mode enabled */ + OnOffAuto intr_eim; /* Toggle for EIM cabability */ }; /* Find the VTD Address space associated with the given bus pointer, From fb506e701e9bafa3e0685747c1c98962c52d1962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Mon, 10 Oct 2016 17:28:47 +0200 Subject: [PATCH 16/21] intel_iommu: reject broken EIM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cluster x2APIC cannot work without KVM's x2apic API when the maximal APIC ID is greater than 8 and only KVM's LAPIC can support x2APIC, so we forbid other APICs and also the old KVM case with less than 9, to simplify the code. There is no point in enabling EIM in forbidden APICs, so we keep it enabled only for the KVM APIC; unconditionally, because making the option depend on KVM version would be a maintanance burden. Old QEMUs would enable eim whenever intremap was on, which would trick guests into thinking that they can enable cluster x2APIC even if any interrupt destination would get clamped to 8 bits. Depending on your configuration, QEMU could notice that the destination LAPIC is not present and report it with a very non-obvious: KVM: injection failed, MSI lost (Operation not permitted) Or the guest could say something about unexpected interrupts, because clamping leads to aliasing so interrupts were being delivered to incorrect VCPUs. KVM_X2APIC_API is the feature that allows us to enable EIM for KVM. QEMU 2.7 allowed EIM whenever interrupt remapping was enabled. In order to keep backward compatibility, we again allow guests to misbehave in non-obvious ways, and make it the default for old machine types. A user can enable the buggy mode it with "x-buggy-eim=on". Signed-off-by: Radim Krčmář Reviewed-by: Eduardo Habkost Reviewed-by: Peter Xu Signed-off-by: Eduardo Habkost --- hw/i386/intel_iommu.c | 16 +++++++++++++++- include/hw/compat.h | 4 ++++ include/hw/i386/intel_iommu.h | 1 + target-i386/kvm-stub.c | 5 +++++ target-i386/kvm.c | 13 +++++++++++++ target-i386/kvm_i386.h | 1 + 6 files changed, 39 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index a70aa8494e..1655a65bce 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -34,6 +34,7 @@ #include "hw/pci-host/q35.h" #include "sysemu/kvm.h" #include "hw/i386/apic_internal.h" +#include "kvm_i386.h" /*#define DEBUG_INTEL_IOMMU*/ #ifdef DEBUG_INTEL_IOMMU @@ -2015,6 +2016,7 @@ static Property vtd_properties[] = { DEFINE_PROP_UINT32("version", IntelIOMMUState, version, 0), DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim, ON_OFF_AUTO_AUTO), + DEFINE_PROP_BOOL("x-buggy-eim", IntelIOMMUState, buggy_eim, false), DEFINE_PROP_END_OF_LIST(), }; @@ -2484,9 +2486,21 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) } if (s->intr_eim == ON_OFF_AUTO_AUTO) { - s->intr_eim = x86_iommu->intr_supported ? + s->intr_eim = (kvm_irqchip_in_kernel() || s->buggy_eim) + && x86_iommu->intr_supported ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } + if (s->intr_eim == ON_OFF_AUTO_ON && !s->buggy_eim) { + if (!kvm_irqchip_in_kernel()) { + error_setg(errp, "eim=on requires accel=kvm,kernel-irqchip=split"); + return false; + } + if (!kvm_enable_x2apic()) { + error_setg(errp, "eim=on requires support on the KVM side" + "(X2APIC_API, first shipped in v4.7)"); + return false; + } + } return true; } diff --git a/include/hw/compat.h b/include/hw/compat.h index ef3fae3e1b..0f06e113be 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -14,6 +14,10 @@ .driver = "ioapic",\ .property = "version",\ .value = "0x11",\ + },{\ + .driver = "intel-iommu",\ + .property = "x-buggy-eim",\ + .value = "true",\ }, #define HW_COMPAT_2_6 \ diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index b5ac60927b..1989c1eec1 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -290,6 +290,7 @@ struct IntelIOMMUState { uint32_t intr_size; /* Number of IR table entries */ bool intr_eime; /* Extended interrupt mode enabled */ OnOffAuto intr_eim; /* Toggle for EIM cabability */ + bool buggy_eim; /* Force buggy EIM unless eim=off */ }; /* Find the VTD Address space associated with the given bus pointer, diff --git a/target-i386/kvm-stub.c b/target-i386/kvm-stub.c index cdf1506109..bda4dc2f0c 100644 --- a/target-i386/kvm-stub.c +++ b/target-i386/kvm-stub.c @@ -25,6 +25,11 @@ bool kvm_has_smm(void) return 1; } +bool kvm_enable_x2apic(void) +{ + return false; +} + /* This function is only called inside conditionals which we * rely on the compiler to optimize out when CONFIG_KVM is not * defined. diff --git a/target-i386/kvm.c b/target-i386/kvm.c index ee1f53e569..0fd6646486 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -122,6 +122,19 @@ bool kvm_allows_irq0_override(void) return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing(); } +static bool kvm_x2apic_api_set_flags(uint64_t flags) +{ + KVMState *s = KVM_STATE(current_machine->accelerator); + + return !kvm_vm_enable_cap(s, KVM_CAP_X2APIC_API, 0, flags); +} + +bool kvm_enable_x2apic(void) +{ + return kvm_x2apic_api_set_flags(KVM_X2APIC_API_USE_32BIT_IDS | + KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK); +} + static int kvm_get_tsc(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h index 36407e0a5d..5c369b1c5b 100644 --- a/target-i386/kvm_i386.h +++ b/target-i386/kvm_i386.h @@ -43,4 +43,5 @@ int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id); void kvm_put_apicbase(X86CPU *cpu, uint64_t value); +bool kvm_enable_x2apic(void); #endif From 2a138ec3af871cd42a982eb401f16dcb74cba8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Mon, 10 Oct 2016 17:28:48 +0200 Subject: [PATCH 17/21] target-i386/kvm: cache the return value of kvm_enable_x2apic() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assume that KVM would have returned the same on subsequent runs. Abstract the memoizaiton pattern into macros and call it memorize as adding the r makes it less obscure. Reviewed-by: Igor Mammedov Signed-off-by: Radim Krčmář Signed-off-by: Eduardo Habkost --- target-i386/kvm.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 0fd6646486..0472f45fd0 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -129,10 +129,23 @@ static bool kvm_x2apic_api_set_flags(uint64_t flags) return !kvm_vm_enable_cap(s, KVM_CAP_X2APIC_API, 0, flags); } +#define MEMORIZE(fn) \ + ({ \ + static typeof(fn) _result; \ + static bool _memorized; \ + \ + if (_memorized) { \ + return _result; \ + } \ + _memorized = true; \ + _result = fn; \ + }) + bool kvm_enable_x2apic(void) { - return kvm_x2apic_api_set_flags(KVM_X2APIC_API_USE_32BIT_IDS | - KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK); + return MEMORIZE( + kvm_x2apic_api_set_flags(KVM_X2APIC_API_USE_32BIT_IDS | + KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)); } static int kvm_get_tsc(CPUState *cs) From e9e60febc497ae9d446caba0bdb2e9597a72e37c Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 10 Oct 2016 16:31:45 -0300 Subject: [PATCH 18/21] target-i386: Unset cannot_destroy_with_object_finalize_yet TYPE_X86_CPU now call cpu_exec_init() on realize, so we don't need to set cannot_destroy_with_object_finalize_yet anymore. Reviewed-by: Igor Mammedov Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 5b3ad78758..1372419594 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3582,11 +3582,6 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->cpu_exec_exit = x86_cpu_exec_exit; dc->cannot_instantiate_with_device_add_yet = false; - /* - * Reason: x86_cpu_initfn() calls cpu_exec_init(), which saves the - * object in cpus -> dangling pointer after final object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo x86_cpu_type_info = { From 41f3d4d69a423dadb8431fda65d8d7c68c0de0fc Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 28 Sep 2016 15:03:26 -0300 Subject: [PATCH 19/21] target-i386: x86_cpu_load_features() function When probing for CPU model information, we need to reuse the code that initializes CPUID fields, but not the remaining side-effects of x86_cpu_realizefn(). Move that code to a separate function that can be reused later. Reviewed-by: Igor Mammedov Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 65 ++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 1372419594..19b8cc4090 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3000,34 +3000,13 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) env->features[FEAT_XSAVE_COMP_HI] = mask >> 32; } -#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \ - (env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \ - (env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3) -#define IS_AMD_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && \ - (env)->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && \ - (env)->cpuid_vendor3 == CPUID_VENDOR_AMD_3) -static void x86_cpu_realizefn(DeviceState *dev, Error **errp) +/* Load CPUID data based on configured features */ +static void x86_cpu_load_features(X86CPU *cpu, Error **errp) { - CPUState *cs = CPU(dev); - X86CPU *cpu = X86_CPU(dev); - X86CPUClass *xcc = X86_CPU_GET_CLASS(dev); CPUX86State *env = &cpu->env; - Error *local_err = NULL; - static bool ht_warned; FeatureWord w; GList *l; - - if (xcc->kvm_required && !kvm_enabled()) { - char *name = x86_cpu_class_get_model_name(xcc); - error_setg(&local_err, "CPU model '%s' requires KVM", name); - g_free(name); - goto out; - } - - if (cpu->apic_id == UNASSIGNED_APIC_ID) { - error_setg(errp, "apic-id property was not initialized properly"); - return; - } + Error *local_err = NULL; /*TODO: cpu->host_features incorrectly overwrites features * set using "feat=on|off". Once we fix this, we can convert @@ -3093,6 +3072,44 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) env->cpuid_xlevel2 = env->cpuid_min_xlevel2; } +out: + if (local_err != NULL) { + error_propagate(errp, local_err); + } +} + +#define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \ + (env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \ + (env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3) +#define IS_AMD_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && \ + (env)->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && \ + (env)->cpuid_vendor3 == CPUID_VENDOR_AMD_3) +static void x86_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + X86CPU *cpu = X86_CPU(dev); + X86CPUClass *xcc = X86_CPU_GET_CLASS(dev); + CPUX86State *env = &cpu->env; + Error *local_err = NULL; + static bool ht_warned; + + if (xcc->kvm_required && !kvm_enabled()) { + char *name = x86_cpu_class_get_model_name(xcc); + error_setg(&local_err, "CPU model '%s' requires KVM", name); + g_free(name); + goto out; + } + + if (cpu->apic_id == UNASSIGNED_APIC_ID) { + error_setg(errp, "apic-id property was not initialized properly"); + return; + } + + x86_cpu_load_features(cpu, &local_err); + if (local_err) { + goto out; + } + if (x86_cpu_filter_features(cpu) && (cpu->check_cpuid || cpu->enforce_cpuid)) { x86_cpu_report_filtered_features(cpu); From b54c93778b5850aaaea176803fe1e46f9732ee1a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 3 May 2016 13:48:13 -0300 Subject: [PATCH 20/21] target-i386: Return runnability information on query-cpu-definitions Fill the "unavailable-features" field on the x86 implementation of query-cpu-definitions. Cc: Jiri Denemark Cc: libvir-list@redhat.com Reviewed-by: Igor Mammedov Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 19b8cc4090..754e5750bc 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1945,6 +1945,27 @@ static inline void feat2prop(char *s) } } +/* Return the feature property name for a feature flag bit */ +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 (comp < ARRAY_SIZE(x86_ext_save_areas) && + x86_ext_save_areas[comp].bits) { + w = x86_ext_save_areas[comp].feature; + bitnr = ctz32(x86_ext_save_areas[comp].bits); + } + } + + assert(bitnr < 32); + assert(w < FEATURE_WORDS); + return feature_word_info[w].feat_names[bitnr]; +} + /* Compatibily hack to maintain legacy +-feat semantic, * where +-feat overwrites any feature set by * feat=on|feat even if the later is parsed after +-feat @@ -2030,6 +2051,59 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, } } +static void x86_cpu_load_features(X86CPU *cpu, Error **errp); +static int x86_cpu_filter_features(X86CPU *cpu); + +/* Check for missing features that may prevent the CPU class from + * running using the current machine and accelerator. + */ +static void x86_cpu_class_check_missing_features(X86CPUClass *xcc, + strList **missing_feats) +{ + X86CPU *xc; + FeatureWord w; + Error *err = NULL; + strList **next = missing_feats; + + if (xcc->kvm_required && !kvm_enabled()) { + strList *new = g_new0(strList, 1); + new->value = g_strdup("kvm");; + *missing_feats = new; + return; + } + + xc = X86_CPU(object_new(object_class_get_name(OBJECT_CLASS(xcc)))); + + x86_cpu_load_features(xc, &err); + if (err) { + /* Errors at x86_cpu_load_features should never happen, + * but in case it does, just report the model as not + * runnable at all using the "type" property. + */ + strList *new = g_new0(strList, 1); + new->value = g_strdup("type"); + *next = new; + next = &new->next; + } + + x86_cpu_filter_features(xc); + + for (w = 0; w < FEATURE_WORDS; w++) { + uint32_t filtered = xc->filtered_features[w]; + int i; + for (i = 0; i < 32; i++) { + if (filtered & (1UL << i)) { + strList *new = g_new0(strList, 1); + new->value = g_strdup(x86_cpu_feature_name(w, i)); + *next = new; + next = &new->next; + } + } + } + + object_unref(OBJECT(xc)); +} + /* Print all cpuid feature names in featureset */ static void listflags(FILE *f, fprintf_function print, const char **featureset) @@ -2122,6 +2196,8 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data) info = g_malloc0(sizeof(*info)); info->name = x86_cpu_class_get_model_name(cc); + x86_cpu_class_check_missing_features(cc, &info->unavailable_features); + info->has_unavailable_features = true; entry = g_malloc0(sizeof(*entry)); entry->value = info; From 46c032f3afcc05a0123914609f1003906ba63fda Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 14 Oct 2016 15:42:45 -0300 Subject: [PATCH 21/21] target-i386: Don't use cpu->migratable when filtering features When explicitly enabling unmigratable flags using "-cpu host" (e.g. "-cpu host,+invtsc"), the requested feature won't be enabled because cpu->migratable is true by default. This is inconsistent with all other CPU models, which don't have the "migratable" option, making "+invtsc" work without the need for extra options. This happens because x86_cpu_filter_features() uses cpu->migratable as an argument for x86_cpu_get_supported_feature_word(). This is not useful because: 2) on "-cpu host" it only makes QEMU disable features that were explicitly enabled in the command-line; 1) on all the other CPU models, cpu->migratable is already false. The fix is to just use 'false' as an argument to x86_cpu_get_supported_feature_word() in x86_cpu_filter_features(). Note that: * This won't change anything for people using using "-cpu host" or "-cpu host,migratable=" (with no extra features) because the x86_cpu_get_supported_feature_word() call on the cpu->host_features check uses cpu->migratable as argument. * This won't change anything for any CPU model except "host" because they all have cpu->migratable == false (and only "host" has the "migratable" property that allows it to be changed). * This will only change things for people using "-cpu host,+", where is a non-migratable feature. The only existing named non-migratable feature is "invtsc". In other words, this change will only affect people using "-cpu host,+invtsc" (that will now get what they asked for: the invtsc flag will be enabled). All other use cases are unaffected. Reviewed-by: Eric Blake Signed-off-by: Eduardo Habkost --- 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 754e5750bc..d95514c7dd 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2248,7 +2248,7 @@ static int x86_cpu_filter_features(X86CPU *cpu) for (w = 0; w < FEATURE_WORDS; w++) { uint32_t host_feat = - x86_cpu_get_supported_feature_word(w, cpu->migratable); + x86_cpu_get_supported_feature_word(w, false); uint32_t requested_features = env->features[w]; env->features[w] &= host_feat; cpu->filtered_features[w] = requested_features & ~env->features[w];