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"
24407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h"
2568192a5fSMarkus Armbruster #include "qapi/qobject-input-visitor.h"
2679f1a68aSClaudio Fontana #include "qom/qom-qobject.h"
27*d6758495SDaniel P. Berrangé #include "qapi/qapi-commands-machine.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 */
x86_cpu_static_props(void)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. */
x86_cpu_expand_prop(X86CPU * cpu,QDict * props,const char * prop)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 */
x86_cpu_to_dict(X86CPU * cpu,QDict * props)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 */
x86_cpu_to_dict_full(X86CPU * cpu,QDict * props)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
object_apply_props(Object * obj,QObject * props,const char * props_arg_name,Error ** errp)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 */
x86_cpu_from_model(const char * model,QObject * props,const char * props_arg_name,Error ** errp)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 *
qmp_query_cpu_model_expansion(CpuModelExpansionType type,CpuModelInfo * model,Error ** errp)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
cpu_clear_apic_feature(CPUX86State * env)24279f1a68aSClaudio Fontana void cpu_clear_apic_feature(CPUX86State *env)
24379f1a68aSClaudio Fontana {
24479f1a68aSClaudio Fontana env->features[FEAT_1_EDX] &= ~CPUID_APIC;
24579f1a68aSClaudio Fontana }
24679f1a68aSClaudio Fontana
cpu_set_apic_feature(CPUX86State * env)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
cpu_has_x2apic_feature(CPUX86State * env)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
cpu_is_bsp(X86CPU * cpu)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 */
x86_cpu_machine_reset_cb(void * opaque)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
x86_cpu_get_crash_info(CPUState * cs)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 }
x86_cpu_get_crash_info_qom(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)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 }
312d3bb5d0dSXiaoyao Li
cpu_x86_get_msr_core_thread_count(X86CPU * cpu)313d3bb5d0dSXiaoyao Li uint64_t cpu_x86_get_msr_core_thread_count(X86CPU *cpu)
314d3bb5d0dSXiaoyao Li {
31584b71a13SXiaoyao Li CPUX86State *env = &cpu->env;
316d3bb5d0dSXiaoyao Li uint64_t val;
317d3bb5d0dSXiaoyao Li
31884b71a13SXiaoyao Li val = x86_threads_per_pkg(&env->topo_info); /* thread count, bits 15..0 */
31984b71a13SXiaoyao Li val |= x86_cores_per_pkg(&env->topo_info) << 16; /* core count, bits 31..16 */
320d3bb5d0dSXiaoyao Li
321d3bb5d0dSXiaoyao Li return val;
322d3bb5d0dSXiaoyao Li }
323