179f1a68aSClaudio Fontana /* 232cad1ffSPhilippe Mathieu-Daudé * i386 CPUID, CPU class, definitions, models: system-only code 379f1a68aSClaudio Fontana * 479f1a68aSClaudio Fontana * Copyright (c) 2003 Fabrice Bellard 579f1a68aSClaudio Fontana * 679f1a68aSClaudio Fontana * This library is free software; you can redistribute it and/or 779f1a68aSClaudio Fontana * modify it under the terms of the GNU Lesser General Public 879f1a68aSClaudio Fontana * License as published by the Free Software Foundation; either 979f1a68aSClaudio Fontana * version 2.1 of the License, or (at your option) any later version. 1079f1a68aSClaudio Fontana * 1179f1a68aSClaudio Fontana * This library is distributed in the hope that it will be useful, 1279f1a68aSClaudio Fontana * but WITHOUT ANY WARRANTY; without even the implied warranty of 1379f1a68aSClaudio Fontana * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1479f1a68aSClaudio Fontana * Lesser General Public License for more details. 1579f1a68aSClaudio Fontana * 1679f1a68aSClaudio Fontana * You should have received a copy of the GNU Lesser General Public 1779f1a68aSClaudio Fontana * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1879f1a68aSClaudio Fontana */ 1979f1a68aSClaudio Fontana 2079f1a68aSClaudio Fontana #include "qemu/osdep.h" 2179f1a68aSClaudio Fontana #include "cpu.h" 2279f1a68aSClaudio Fontana #include "qapi/error.h" 2379f1a68aSClaudio Fontana #include "qapi/qapi-visit-run-state.h" 2479f1a68aSClaudio Fontana #include "qapi/qmp/qdict.h" 2568192a5fSMarkus Armbruster #include "qapi/qobject-input-visitor.h" 2679f1a68aSClaudio Fontana #include "qom/qom-qobject.h" 2779f1a68aSClaudio Fontana #include "qapi/qapi-commands-machine-target.h" 2879f1a68aSClaudio Fontana 2979f1a68aSClaudio Fontana #include "cpu-internal.h" 3079f1a68aSClaudio Fontana 3179f1a68aSClaudio Fontana /* Return a QDict containing keys for all properties that can be included 3279f1a68aSClaudio Fontana * in static expansion of CPU models. All properties set by x86_cpu_load_model() 3379f1a68aSClaudio Fontana * must be included in the dictionary. 3479f1a68aSClaudio Fontana */ 3579f1a68aSClaudio Fontana static QDict *x86_cpu_static_props(void) 3679f1a68aSClaudio Fontana { 3779f1a68aSClaudio Fontana FeatureWord w; 3879f1a68aSClaudio Fontana int i; 3979f1a68aSClaudio Fontana static const char *props[] = { 4079f1a68aSClaudio Fontana "min-level", 4179f1a68aSClaudio Fontana "min-xlevel", 4279f1a68aSClaudio Fontana "family", 4379f1a68aSClaudio Fontana "model", 4479f1a68aSClaudio Fontana "stepping", 4579f1a68aSClaudio Fontana "model-id", 4679f1a68aSClaudio Fontana "vendor", 4779f1a68aSClaudio Fontana "lmce", 4879f1a68aSClaudio Fontana NULL, 4979f1a68aSClaudio Fontana }; 5079f1a68aSClaudio Fontana static QDict *d; 5179f1a68aSClaudio Fontana 5279f1a68aSClaudio Fontana if (d) { 5379f1a68aSClaudio Fontana return d; 5479f1a68aSClaudio Fontana } 5579f1a68aSClaudio Fontana 5679f1a68aSClaudio Fontana d = qdict_new(); 5779f1a68aSClaudio Fontana for (i = 0; props[i]; i++) { 5879f1a68aSClaudio Fontana qdict_put_null(d, props[i]); 5979f1a68aSClaudio Fontana } 6079f1a68aSClaudio Fontana 6179f1a68aSClaudio Fontana for (w = 0; w < FEATURE_WORDS; w++) { 6279f1a68aSClaudio Fontana FeatureWordInfo *fi = &feature_word_info[w]; 6379f1a68aSClaudio Fontana int bit; 6479f1a68aSClaudio Fontana for (bit = 0; bit < 64; bit++) { 6579f1a68aSClaudio Fontana if (!fi->feat_names[bit]) { 6679f1a68aSClaudio Fontana continue; 6779f1a68aSClaudio Fontana } 6879f1a68aSClaudio Fontana qdict_put_null(d, fi->feat_names[bit]); 6979f1a68aSClaudio Fontana } 7079f1a68aSClaudio Fontana } 7179f1a68aSClaudio Fontana 7279f1a68aSClaudio Fontana return d; 7379f1a68aSClaudio Fontana } 7479f1a68aSClaudio Fontana 7579f1a68aSClaudio Fontana /* Add an entry to @props dict, with the value for property. */ 7679f1a68aSClaudio Fontana static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop) 7779f1a68aSClaudio Fontana { 7879f1a68aSClaudio Fontana QObject *value = object_property_get_qobject(OBJECT(cpu), prop, 7979f1a68aSClaudio Fontana &error_abort); 8079f1a68aSClaudio Fontana 8179f1a68aSClaudio Fontana qdict_put_obj(props, prop, value); 8279f1a68aSClaudio Fontana } 8379f1a68aSClaudio Fontana 8479f1a68aSClaudio Fontana /* Convert CPU model data from X86CPU object to a property dictionary 8579f1a68aSClaudio Fontana * that can recreate exactly the same CPU model. 8679f1a68aSClaudio Fontana */ 8779f1a68aSClaudio Fontana static void x86_cpu_to_dict(X86CPU *cpu, QDict *props) 8879f1a68aSClaudio Fontana { 8979f1a68aSClaudio Fontana QDict *sprops = x86_cpu_static_props(); 9079f1a68aSClaudio Fontana const QDictEntry *e; 9179f1a68aSClaudio Fontana 9279f1a68aSClaudio Fontana for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) { 9379f1a68aSClaudio Fontana const char *prop = qdict_entry_key(e); 9479f1a68aSClaudio Fontana x86_cpu_expand_prop(cpu, props, prop); 9579f1a68aSClaudio Fontana } 9679f1a68aSClaudio Fontana } 9779f1a68aSClaudio Fontana 9879f1a68aSClaudio Fontana /* Convert CPU model data from X86CPU object to a property dictionary 9979f1a68aSClaudio Fontana * that can recreate exactly the same CPU model, including every 1009323e79fSPeter Maydell * writable QOM property. 10179f1a68aSClaudio Fontana */ 10279f1a68aSClaudio Fontana static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props) 10379f1a68aSClaudio Fontana { 10479f1a68aSClaudio Fontana ObjectPropertyIterator iter; 10579f1a68aSClaudio Fontana ObjectProperty *prop; 10679f1a68aSClaudio Fontana 10779f1a68aSClaudio Fontana object_property_iter_init(&iter, OBJECT(cpu)); 10879f1a68aSClaudio Fontana while ((prop = object_property_iter_next(&iter))) { 10979f1a68aSClaudio Fontana /* skip read-only or write-only properties */ 11079f1a68aSClaudio Fontana if (!prop->get || !prop->set) { 11179f1a68aSClaudio Fontana continue; 11279f1a68aSClaudio Fontana } 11379f1a68aSClaudio Fontana 11479f1a68aSClaudio Fontana /* "hotplugged" is the only property that is configurable 11579f1a68aSClaudio Fontana * on the command-line but will be set differently on CPUs 11679f1a68aSClaudio Fontana * created using "-cpu ... -smp ..." and by CPUs created 11779f1a68aSClaudio Fontana * on the fly by x86_cpu_from_model() for querying. Skip it. 11879f1a68aSClaudio Fontana */ 11979f1a68aSClaudio Fontana if (!strcmp(prop->name, "hotplugged")) { 12079f1a68aSClaudio Fontana continue; 12179f1a68aSClaudio Fontana } 12279f1a68aSClaudio Fontana x86_cpu_expand_prop(cpu, props, prop->name); 12379f1a68aSClaudio Fontana } 12479f1a68aSClaudio Fontana } 12579f1a68aSClaudio Fontana 1268934643aSMarkus Armbruster static void object_apply_props(Object *obj, QObject *props, 1278934643aSMarkus Armbruster const char *props_arg_name, Error **errp) 12879f1a68aSClaudio Fontana { 12968192a5fSMarkus Armbruster Visitor *visitor; 13068192a5fSMarkus Armbruster QDict *qdict; 13179f1a68aSClaudio Fontana const QDictEntry *prop; 13279f1a68aSClaudio Fontana 13368192a5fSMarkus Armbruster visitor = qobject_input_visitor_new(props); 1348934643aSMarkus Armbruster if (!visit_start_struct(visitor, props_arg_name, NULL, 0, errp)) { 13568192a5fSMarkus Armbruster visit_free(visitor); 13668192a5fSMarkus Armbruster return; 13768192a5fSMarkus Armbruster } 13868192a5fSMarkus Armbruster 13968192a5fSMarkus Armbruster qdict = qobject_to(QDict, props); 14068192a5fSMarkus Armbruster for (prop = qdict_first(qdict); prop; prop = qdict_next(qdict, prop)) { 14168192a5fSMarkus Armbruster if (!object_property_set(obj, qdict_entry_key(prop), 14268192a5fSMarkus Armbruster visitor, errp)) { 14368192a5fSMarkus Armbruster goto out; 14479f1a68aSClaudio Fontana } 14579f1a68aSClaudio Fontana } 14668192a5fSMarkus Armbruster 14768192a5fSMarkus Armbruster visit_check_struct(visitor, errp); 14868192a5fSMarkus Armbruster out: 14968192a5fSMarkus Armbruster visit_end_struct(visitor, NULL); 15068192a5fSMarkus Armbruster visit_free(visitor); 15179f1a68aSClaudio Fontana } 15279f1a68aSClaudio Fontana 15379f1a68aSClaudio Fontana /* Create X86CPU object according to model+props specification */ 15468192a5fSMarkus Armbruster static X86CPU *x86_cpu_from_model(const char *model, QObject *props, 1558934643aSMarkus Armbruster const char *props_arg_name, Error **errp) 15679f1a68aSClaudio Fontana { 15779f1a68aSClaudio Fontana X86CPU *xc = NULL; 15879f1a68aSClaudio Fontana X86CPUClass *xcc; 15979f1a68aSClaudio Fontana Error *err = NULL; 16079f1a68aSClaudio Fontana 16179f1a68aSClaudio Fontana xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model)); 16279f1a68aSClaudio Fontana if (xcc == NULL) { 16379f1a68aSClaudio Fontana error_setg(&err, "CPU model '%s' not found", model); 16479f1a68aSClaudio Fontana goto out; 16579f1a68aSClaudio Fontana } 16679f1a68aSClaudio Fontana 16779f1a68aSClaudio Fontana xc = X86_CPU(object_new_with_class(OBJECT_CLASS(xcc))); 16879f1a68aSClaudio Fontana if (props) { 1698934643aSMarkus Armbruster object_apply_props(OBJECT(xc), props, props_arg_name, &err); 17079f1a68aSClaudio Fontana if (err) { 17179f1a68aSClaudio Fontana goto out; 17279f1a68aSClaudio Fontana } 17379f1a68aSClaudio Fontana } 17479f1a68aSClaudio Fontana 17579f1a68aSClaudio Fontana x86_cpu_expand_features(xc, &err); 17679f1a68aSClaudio Fontana if (err) { 17779f1a68aSClaudio Fontana goto out; 17879f1a68aSClaudio Fontana } 17979f1a68aSClaudio Fontana 18079f1a68aSClaudio Fontana out: 18179f1a68aSClaudio Fontana if (err) { 18279f1a68aSClaudio Fontana error_propagate(errp, err); 18379f1a68aSClaudio Fontana object_unref(OBJECT(xc)); 18479f1a68aSClaudio Fontana xc = NULL; 18579f1a68aSClaudio Fontana } 18679f1a68aSClaudio Fontana return xc; 18779f1a68aSClaudio Fontana } 18879f1a68aSClaudio Fontana 18979f1a68aSClaudio Fontana CpuModelExpansionInfo * 19079f1a68aSClaudio Fontana qmp_query_cpu_model_expansion(CpuModelExpansionType type, 19179f1a68aSClaudio Fontana CpuModelInfo *model, 19279f1a68aSClaudio Fontana Error **errp) 19379f1a68aSClaudio Fontana { 19479f1a68aSClaudio Fontana X86CPU *xc = NULL; 19579f1a68aSClaudio Fontana Error *err = NULL; 19679f1a68aSClaudio Fontana CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1); 19779f1a68aSClaudio Fontana QDict *props = NULL; 19879f1a68aSClaudio Fontana const char *base_name; 19979f1a68aSClaudio Fontana 2008934643aSMarkus Armbruster xc = x86_cpu_from_model(model->name, model->props, "model.props", &err); 20179f1a68aSClaudio Fontana if (err) { 20279f1a68aSClaudio Fontana goto out; 20379f1a68aSClaudio Fontana } 20479f1a68aSClaudio Fontana 20579f1a68aSClaudio Fontana props = qdict_new(); 20679f1a68aSClaudio Fontana ret->model = g_new0(CpuModelInfo, 1); 20779f1a68aSClaudio Fontana ret->model->props = QOBJECT(props); 20879f1a68aSClaudio Fontana 20979f1a68aSClaudio Fontana switch (type) { 21079f1a68aSClaudio Fontana case CPU_MODEL_EXPANSION_TYPE_STATIC: 21179f1a68aSClaudio Fontana /* Static expansion will be based on "base" only */ 21279f1a68aSClaudio Fontana base_name = "base"; 21379f1a68aSClaudio Fontana x86_cpu_to_dict(xc, props); 21479f1a68aSClaudio Fontana break; 21579f1a68aSClaudio Fontana case CPU_MODEL_EXPANSION_TYPE_FULL: 21679f1a68aSClaudio Fontana /* As we don't return every single property, full expansion needs 21779f1a68aSClaudio Fontana * to keep the original model name+props, and add extra 21879f1a68aSClaudio Fontana * properties on top of that. 21979f1a68aSClaudio Fontana */ 22079f1a68aSClaudio Fontana base_name = model->name; 22179f1a68aSClaudio Fontana x86_cpu_to_dict_full(xc, props); 22279f1a68aSClaudio Fontana break; 22379f1a68aSClaudio Fontana default: 22479f1a68aSClaudio Fontana error_setg(&err, "Unsupported expansion type"); 22579f1a68aSClaudio Fontana goto out; 22679f1a68aSClaudio Fontana } 22779f1a68aSClaudio Fontana 22879f1a68aSClaudio Fontana x86_cpu_to_dict(xc, props); 22979f1a68aSClaudio Fontana 23079f1a68aSClaudio Fontana ret->model->name = g_strdup(base_name); 23179f1a68aSClaudio Fontana 23279f1a68aSClaudio Fontana out: 23379f1a68aSClaudio Fontana object_unref(OBJECT(xc)); 23479f1a68aSClaudio Fontana if (err) { 23579f1a68aSClaudio Fontana error_propagate(errp, err); 23679f1a68aSClaudio Fontana qapi_free_CpuModelExpansionInfo(ret); 23779f1a68aSClaudio Fontana ret = NULL; 23879f1a68aSClaudio Fontana } 23979f1a68aSClaudio Fontana return ret; 24079f1a68aSClaudio Fontana } 24179f1a68aSClaudio Fontana 24279f1a68aSClaudio Fontana void cpu_clear_apic_feature(CPUX86State *env) 24379f1a68aSClaudio Fontana { 24479f1a68aSClaudio Fontana env->features[FEAT_1_EDX] &= ~CPUID_APIC; 24579f1a68aSClaudio Fontana } 24679f1a68aSClaudio Fontana 247b5ee0468SBui Quang Minh void cpu_set_apic_feature(CPUX86State *env) 248b5ee0468SBui Quang Minh { 249b5ee0468SBui Quang Minh env->features[FEAT_1_EDX] |= CPUID_APIC; 250b5ee0468SBui Quang Minh } 251b5ee0468SBui Quang Minh 252b5ee0468SBui Quang Minh bool cpu_has_x2apic_feature(CPUX86State *env) 253b5ee0468SBui Quang Minh { 254b5ee0468SBui Quang Minh return env->features[FEAT_1_ECX] & CPUID_EXT_X2APIC; 255b5ee0468SBui Quang Minh } 256b5ee0468SBui Quang Minh 25779f1a68aSClaudio Fontana bool cpu_is_bsp(X86CPU *cpu) 25879f1a68aSClaudio Fontana { 25979f1a68aSClaudio Fontana return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP; 26079f1a68aSClaudio Fontana } 26179f1a68aSClaudio Fontana 26279f1a68aSClaudio Fontana /* TODO: remove me, when reset over QOM tree is implemented */ 26379f1a68aSClaudio Fontana void x86_cpu_machine_reset_cb(void *opaque) 26479f1a68aSClaudio Fontana { 26579f1a68aSClaudio Fontana X86CPU *cpu = opaque; 26679f1a68aSClaudio Fontana cpu_reset(CPU(cpu)); 26779f1a68aSClaudio Fontana } 26879f1a68aSClaudio Fontana 26979f1a68aSClaudio Fontana GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs) 27079f1a68aSClaudio Fontana { 27179f1a68aSClaudio Fontana X86CPU *cpu = X86_CPU(cs); 27279f1a68aSClaudio Fontana CPUX86State *env = &cpu->env; 27379f1a68aSClaudio Fontana GuestPanicInformation *panic_info = NULL; 27479f1a68aSClaudio Fontana 275061817a7SVitaly Kuznetsov if (hyperv_feat_enabled(cpu, HYPERV_FEAT_CRASH)) { 276b21e2380SMarkus Armbruster panic_info = g_new0(GuestPanicInformation, 1); 27779f1a68aSClaudio Fontana 27879f1a68aSClaudio Fontana panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V; 27979f1a68aSClaudio Fontana 28079f1a68aSClaudio Fontana assert(HV_CRASH_PARAMS >= 5); 28179f1a68aSClaudio Fontana panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0]; 28279f1a68aSClaudio Fontana panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1]; 28379f1a68aSClaudio Fontana panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2]; 28479f1a68aSClaudio Fontana panic_info->u.hyper_v.arg4 = env->msr_hv_crash_params[3]; 28579f1a68aSClaudio Fontana panic_info->u.hyper_v.arg5 = env->msr_hv_crash_params[4]; 28679f1a68aSClaudio Fontana } 28779f1a68aSClaudio Fontana 28879f1a68aSClaudio Fontana return panic_info; 28979f1a68aSClaudio Fontana } 29079f1a68aSClaudio Fontana void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, 29179f1a68aSClaudio Fontana const char *name, void *opaque, 29279f1a68aSClaudio Fontana Error **errp) 29379f1a68aSClaudio Fontana { 29479f1a68aSClaudio Fontana CPUState *cs = CPU(obj); 29579f1a68aSClaudio Fontana GuestPanicInformation *panic_info; 29679f1a68aSClaudio Fontana 29779f1a68aSClaudio Fontana if (!cs->crash_occurred) { 2987916b5fcSMichael Tokarev error_setg(errp, "No crash occurred"); 29979f1a68aSClaudio Fontana return; 30079f1a68aSClaudio Fontana } 30179f1a68aSClaudio Fontana 30279f1a68aSClaudio Fontana panic_info = x86_cpu_get_crash_info(cs); 30379f1a68aSClaudio Fontana if (panic_info == NULL) { 30479f1a68aSClaudio Fontana error_setg(errp, "No crash information"); 30579f1a68aSClaudio Fontana return; 30679f1a68aSClaudio Fontana } 30779f1a68aSClaudio Fontana 30879f1a68aSClaudio Fontana visit_type_GuestPanicInformation(v, "crash-information", &panic_info, 30979f1a68aSClaudio Fontana errp); 31079f1a68aSClaudio Fontana qapi_free_GuestPanicInformation(panic_info); 31179f1a68aSClaudio Fontana } 312*d3bb5d0dSXiaoyao Li 313*d3bb5d0dSXiaoyao Li uint64_t cpu_x86_get_msr_core_thread_count(X86CPU *cpu) 314*d3bb5d0dSXiaoyao Li { 315*d3bb5d0dSXiaoyao Li CPUState *cs = CPU(cpu); 316*d3bb5d0dSXiaoyao Li uint64_t val; 317*d3bb5d0dSXiaoyao Li 318*d3bb5d0dSXiaoyao Li val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */ 319*d3bb5d0dSXiaoyao Li val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */ 320*d3bb5d0dSXiaoyao Li 321*d3bb5d0dSXiaoyao Li return val; 322*d3bb5d0dSXiaoyao Li } 323