diff options
Diffstat (limited to 'target-i386/cpu.c')
-rw-r--r-- | target-i386/cpu.c | 137 |
1 files changed, 89 insertions, 48 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 3bd3cfc3ad..fc209ee1cb 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -245,6 +245,47 @@ static const char *kvm_feature_name[] = { NULL, NULL, NULL, NULL, }; +static const char *hyperv_priv_feature_name[] = { + NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */, + NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */, + NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */, + NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */, + NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */, + NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + +static const char *hyperv_ident_feature_name[] = { + NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */, + NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */, + NULL /* hv_post_messages */, NULL /* hv_signal_events */, + NULL /* hv_create_port */, NULL /* hv_connect_port */, + NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */, + NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */, + NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + +static const char *hyperv_misc_feature_name[] = { + NULL /* hv_mwait */, NULL /* hv_guest_debugging */, + NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */, + NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */, + NULL, NULL, + NULL, NULL, NULL /* hv_guest_crash_msr */, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + static const char *svm_feature_name[] = { "npt", "lbrv", "svm_lock", "nrip_save", "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists", @@ -358,10 +399,11 @@ static const char *cpuid_6_feature_name[] = { #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP | \ CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \ - CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE) + CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \ + CPUID_7_0_EBX_ERMS) /* missing: CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, - CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, + CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, CPUID_7_0_EBX_RDSEED */ #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE) #define TCG_APM_FEATURES 0 @@ -411,6 +453,18 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, .tcg_features = TCG_KVM_FEATURES, }, + [FEAT_HYPERV_EAX] = { + .feat_names = hyperv_priv_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EAX, + }, + [FEAT_HYPERV_EBX] = { + .feat_names = hyperv_ident_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EBX, + }, + [FEAT_HYPERV_EDX] = { + .feat_names = hyperv_misc_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EDX, + }, [FEAT_SVM] = { .feat_names = svm_feature_name, .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX, @@ -1493,6 +1547,17 @@ static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, #ifdef CONFIG_KVM +static bool lmce_supported(void) +{ + uint64_t mce_cap; + + if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) { + return false; + } + + return !!(mce_cap & MCG_LMCE_P); +} + static int cpu_x86_fill_model_id(char *str) { uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; @@ -1565,6 +1630,10 @@ static void host_x86_cpu_initfn(Object *obj) env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); + + if (lmce_supported()) { + object_property_set_bool(OBJECT(cpu), true, "lmce", &error_abort); + } } object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort); @@ -1957,12 +2026,17 @@ static FeatureWordArray minus_features = { 0 }; /* Parse "+feature,-feature,feature=foo" CPU feature string */ -static void x86_cpu_parse_featurestr(CPUState *cs, char *features, +static void x86_cpu_parse_featurestr(const char *typename, char *features, Error **errp) { - X86CPU *cpu = X86_CPU(cs); char *featurestr; /* Single 'key=value" string being parsed */ Error *local_err = NULL; + static bool cpu_globals_initialized; + + if (cpu_globals_initialized) { + return; + } + cpu_globals_initialized = true; if (!features) { return; @@ -1974,6 +2048,8 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features, const char *name; const char *val = NULL; char *eq = NULL; + char num[32]; + GlobalProperty *prop; /* Compatibility syntax: */ if (featurestr[0] == '+') { @@ -1999,7 +2075,6 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features, if (!strcmp(name, "tsc-freq")) { int64_t tsc_freq; char *err; - char num[32]; tsc_freq = qemu_strtosz_suffix_unit(val, &err, QEMU_STRTOSZ_DEFSUFFIX_B, 1000); @@ -2012,7 +2087,12 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features, name = "tsc-frequency"; } - object_property_parse(OBJECT(cpu), val, name, &local_err); + prop = g_new0(typeof(*prop), 1); + prop->driver = typename; + prop->property = g_strdup(name); + prop->value = g_strdup(val); + prop->errp = &error_fatal; + qdev_prop_register_global(prop); } if (local_err) { @@ -2197,47 +2277,6 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) } -X86CPU *cpu_x86_create(const char *cpu_model, Error **errp) -{ - X86CPU *cpu = NULL; - ObjectClass *oc; - gchar **model_pieces; - char *name, *features; - Error *error = NULL; - - model_pieces = g_strsplit(cpu_model, ",", 2); - if (!model_pieces[0]) { - error_setg(&error, "Invalid/empty CPU model name"); - goto out; - } - name = model_pieces[0]; - features = model_pieces[1]; - - oc = x86_cpu_class_by_name(name); - if (oc == NULL) { - error_setg(&error, "Unable to find CPU definition: %s", name); - goto out; - } - - cpu = X86_CPU(object_new(object_class_get_name(oc))); - - x86_cpu_parse_featurestr(CPU(cpu), features, &error); - if (error) { - goto out; - } - -out: - if (error != NULL) { - error_propagate(errp, error); - if (cpu) { - object_unref(OBJECT(cpu)); - cpu = NULL; - } - } - g_strfreev(model_pieces); - return cpu; -} - X86CPU *cpu_x86_init(const char *cpu_model) { return X86_CPU(cpu_generic_init(TYPE_X86_CPU, cpu_model)); @@ -2815,7 +2854,8 @@ static void mce_init(X86CPU *cpu) if (((cenv->cpuid_version >> 8) & 0xf) >= 6 && (cenv->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) == (CPUID_MCE | CPUID_MCA)) { - cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF; + cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF | + (cpu->enable_lmce ? MCG_LMCE_P : 0); cenv->mcg_ctl = ~(uint64_t)0; for (bank = 0; bank < MCE_BANKS_DEF; bank++) { cenv->mce_banks[bank * 4] = ~(uint64_t)0; @@ -3262,6 +3302,7 @@ static Property x86_cpu_properties[] = { DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, 0), DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor_id), DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), + DEFINE_PROP_BOOL("lmce", X86CPU, enable_lmce, false), DEFINE_PROP_END_OF_LIST() }; |