132cad1ffSPhilippe Mathieu-Daudé /*
232cad1ffSPhilippe Mathieu-Daudé * CPU models for s390x - System-only
332cad1ffSPhilippe Mathieu-Daudé *
432cad1ffSPhilippe Mathieu-Daudé * Copyright 2016 IBM Corp.
532cad1ffSPhilippe Mathieu-Daudé *
632cad1ffSPhilippe Mathieu-Daudé * Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
732cad1ffSPhilippe Mathieu-Daudé *
832cad1ffSPhilippe Mathieu-Daudé * This work is licensed under the terms of the GNU GPL, version 2 or (at
932cad1ffSPhilippe Mathieu-Daudé * your option) any later version. See the COPYING file in the top-level
1032cad1ffSPhilippe Mathieu-Daudé * directory.
1132cad1ffSPhilippe Mathieu-Daudé */
1232cad1ffSPhilippe Mathieu-Daudé
1332cad1ffSPhilippe Mathieu-Daudé #include "qemu/osdep.h"
1432cad1ffSPhilippe Mathieu-Daudé #include "cpu.h"
1532cad1ffSPhilippe Mathieu-Daudé #include "s390x-internal.h"
1632cad1ffSPhilippe Mathieu-Daudé #include "kvm/kvm_s390x.h"
1732cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h"
1832cad1ffSPhilippe Mathieu-Daudé #include "qapi/error.h"
1932cad1ffSPhilippe Mathieu-Daudé #include "qapi/visitor.h"
2032cad1ffSPhilippe Mathieu-Daudé #include "qapi/qobject-input-visitor.h"
21*407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h"
2232cad1ffSPhilippe Mathieu-Daudé #include "qapi/qapi-commands-machine-target.h"
2332cad1ffSPhilippe Mathieu-Daudé
2432cad1ffSPhilippe Mathieu-Daudé static void list_add_feat(const char *name, void *opaque);
2532cad1ffSPhilippe Mathieu-Daudé
check_unavailable_features(const S390CPUModel * max_model,const S390CPUModel * model,strList ** unavailable)2632cad1ffSPhilippe Mathieu-Daudé static void check_unavailable_features(const S390CPUModel *max_model,
2732cad1ffSPhilippe Mathieu-Daudé const S390CPUModel *model,
2832cad1ffSPhilippe Mathieu-Daudé strList **unavailable)
2932cad1ffSPhilippe Mathieu-Daudé {
3032cad1ffSPhilippe Mathieu-Daudé S390FeatBitmap missing;
3132cad1ffSPhilippe Mathieu-Daudé
3232cad1ffSPhilippe Mathieu-Daudé /* check general model compatibility */
3332cad1ffSPhilippe Mathieu-Daudé if (max_model->def->gen < model->def->gen ||
3432cad1ffSPhilippe Mathieu-Daudé (max_model->def->gen == model->def->gen &&
3532cad1ffSPhilippe Mathieu-Daudé max_model->def->ec_ga < model->def->ec_ga)) {
3632cad1ffSPhilippe Mathieu-Daudé list_add_feat("type", unavailable);
3732cad1ffSPhilippe Mathieu-Daudé }
3832cad1ffSPhilippe Mathieu-Daudé
3932cad1ffSPhilippe Mathieu-Daudé /* detect missing features if any to properly report them */
4032cad1ffSPhilippe Mathieu-Daudé bitmap_andnot(missing, model->features, max_model->features,
4132cad1ffSPhilippe Mathieu-Daudé S390_FEAT_MAX);
4232cad1ffSPhilippe Mathieu-Daudé if (!bitmap_empty(missing, S390_FEAT_MAX)) {
4332cad1ffSPhilippe Mathieu-Daudé s390_feat_bitmap_to_ascii(missing, unavailable, list_add_feat);
4432cad1ffSPhilippe Mathieu-Daudé }
4532cad1ffSPhilippe Mathieu-Daudé }
4632cad1ffSPhilippe Mathieu-Daudé
4732cad1ffSPhilippe Mathieu-Daudé struct CpuDefinitionInfoListData {
4832cad1ffSPhilippe Mathieu-Daudé CpuDefinitionInfoList *list;
4932cad1ffSPhilippe Mathieu-Daudé S390CPUModel *model;
5032cad1ffSPhilippe Mathieu-Daudé };
5132cad1ffSPhilippe Mathieu-Daudé
create_cpu_model_list(ObjectClass * klass,void * opaque)5232cad1ffSPhilippe Mathieu-Daudé static void create_cpu_model_list(ObjectClass *klass, void *opaque)
5332cad1ffSPhilippe Mathieu-Daudé {
5432cad1ffSPhilippe Mathieu-Daudé struct CpuDefinitionInfoListData *cpu_list_data = opaque;
5532cad1ffSPhilippe Mathieu-Daudé CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
5632cad1ffSPhilippe Mathieu-Daudé CpuDefinitionInfo *info;
5732cad1ffSPhilippe Mathieu-Daudé char *name = g_strdup(object_class_get_name(klass));
5832cad1ffSPhilippe Mathieu-Daudé S390CPUClass *scc = S390_CPU_CLASS(klass);
5932cad1ffSPhilippe Mathieu-Daudé
6032cad1ffSPhilippe Mathieu-Daudé /* strip off the -s390x-cpu */
6132cad1ffSPhilippe Mathieu-Daudé g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
6232cad1ffSPhilippe Mathieu-Daudé info = g_new0(CpuDefinitionInfo, 1);
6332cad1ffSPhilippe Mathieu-Daudé info->name = name;
6432cad1ffSPhilippe Mathieu-Daudé info->has_migration_safe = true;
6532cad1ffSPhilippe Mathieu-Daudé info->migration_safe = scc->is_migration_safe;
6632cad1ffSPhilippe Mathieu-Daudé info->q_static = scc->is_static;
6732cad1ffSPhilippe Mathieu-Daudé info->q_typename = g_strdup(object_class_get_name(klass));
6832cad1ffSPhilippe Mathieu-Daudé /* check for unavailable features */
6932cad1ffSPhilippe Mathieu-Daudé if (cpu_list_data->model) {
7032cad1ffSPhilippe Mathieu-Daudé Object *obj;
7132cad1ffSPhilippe Mathieu-Daudé S390CPU *sc;
7232cad1ffSPhilippe Mathieu-Daudé obj = object_new_with_class(klass);
7332cad1ffSPhilippe Mathieu-Daudé sc = S390_CPU(obj);
7432cad1ffSPhilippe Mathieu-Daudé if (sc->model) {
7532cad1ffSPhilippe Mathieu-Daudé info->has_unavailable_features = true;
7632cad1ffSPhilippe Mathieu-Daudé check_unavailable_features(cpu_list_data->model, sc->model,
7732cad1ffSPhilippe Mathieu-Daudé &info->unavailable_features);
7832cad1ffSPhilippe Mathieu-Daudé }
7932cad1ffSPhilippe Mathieu-Daudé object_unref(obj);
8032cad1ffSPhilippe Mathieu-Daudé }
8132cad1ffSPhilippe Mathieu-Daudé
8232cad1ffSPhilippe Mathieu-Daudé QAPI_LIST_PREPEND(*cpu_list, info);
8332cad1ffSPhilippe Mathieu-Daudé }
8432cad1ffSPhilippe Mathieu-Daudé
qmp_query_cpu_definitions(Error ** errp)8532cad1ffSPhilippe Mathieu-Daudé CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
8632cad1ffSPhilippe Mathieu-Daudé {
8732cad1ffSPhilippe Mathieu-Daudé struct CpuDefinitionInfoListData list_data = {
8832cad1ffSPhilippe Mathieu-Daudé .list = NULL,
8932cad1ffSPhilippe Mathieu-Daudé };
9032cad1ffSPhilippe Mathieu-Daudé
9132cad1ffSPhilippe Mathieu-Daudé list_data.model = get_max_cpu_model(NULL);
9232cad1ffSPhilippe Mathieu-Daudé
9332cad1ffSPhilippe Mathieu-Daudé object_class_foreach(create_cpu_model_list, TYPE_S390_CPU, false,
9432cad1ffSPhilippe Mathieu-Daudé &list_data);
9532cad1ffSPhilippe Mathieu-Daudé
9632cad1ffSPhilippe Mathieu-Daudé return list_data.list;
9732cad1ffSPhilippe Mathieu-Daudé }
9832cad1ffSPhilippe Mathieu-Daudé
cpu_model_from_info(S390CPUModel * model,const CpuModelInfo * info,const char * info_arg_name,Error ** errp)9932cad1ffSPhilippe Mathieu-Daudé static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
10032cad1ffSPhilippe Mathieu-Daudé const char *info_arg_name, Error **errp)
10132cad1ffSPhilippe Mathieu-Daudé {
10232cad1ffSPhilippe Mathieu-Daudé Error *err = NULL;
10332cad1ffSPhilippe Mathieu-Daudé const QDict *qdict;
10432cad1ffSPhilippe Mathieu-Daudé const QDictEntry *e;
10532cad1ffSPhilippe Mathieu-Daudé Visitor *visitor;
10632cad1ffSPhilippe Mathieu-Daudé ObjectClass *oc;
10732cad1ffSPhilippe Mathieu-Daudé S390CPU *cpu;
10832cad1ffSPhilippe Mathieu-Daudé Object *obj;
10932cad1ffSPhilippe Mathieu-Daudé
11032cad1ffSPhilippe Mathieu-Daudé oc = cpu_class_by_name(TYPE_S390_CPU, info->name);
11132cad1ffSPhilippe Mathieu-Daudé if (!oc) {
11232cad1ffSPhilippe Mathieu-Daudé error_setg(errp, "The CPU definition \'%s\' is unknown.", info->name);
11332cad1ffSPhilippe Mathieu-Daudé return;
11432cad1ffSPhilippe Mathieu-Daudé }
11532cad1ffSPhilippe Mathieu-Daudé if (S390_CPU_CLASS(oc)->kvm_required && !kvm_enabled()) {
11632cad1ffSPhilippe Mathieu-Daudé error_setg(errp, "The CPU definition '%s' requires KVM", info->name);
11732cad1ffSPhilippe Mathieu-Daudé return;
11832cad1ffSPhilippe Mathieu-Daudé }
11932cad1ffSPhilippe Mathieu-Daudé obj = object_new_with_class(oc);
12032cad1ffSPhilippe Mathieu-Daudé cpu = S390_CPU(obj);
12132cad1ffSPhilippe Mathieu-Daudé
12232cad1ffSPhilippe Mathieu-Daudé if (!cpu->model) {
12332cad1ffSPhilippe Mathieu-Daudé error_setg(errp, "Details about the host CPU model are not available, "
12432cad1ffSPhilippe Mathieu-Daudé "it cannot be used.");
12532cad1ffSPhilippe Mathieu-Daudé object_unref(obj);
12632cad1ffSPhilippe Mathieu-Daudé return;
12732cad1ffSPhilippe Mathieu-Daudé }
12832cad1ffSPhilippe Mathieu-Daudé
12932cad1ffSPhilippe Mathieu-Daudé if (info->props) {
13032cad1ffSPhilippe Mathieu-Daudé g_autofree const char *props_name = g_strdup_printf("%s.props",
13132cad1ffSPhilippe Mathieu-Daudé info_arg_name);
13232cad1ffSPhilippe Mathieu-Daudé
13332cad1ffSPhilippe Mathieu-Daudé visitor = qobject_input_visitor_new(info->props);
13432cad1ffSPhilippe Mathieu-Daudé if (!visit_start_struct(visitor, props_name, NULL, 0, errp)) {
13532cad1ffSPhilippe Mathieu-Daudé visit_free(visitor);
13632cad1ffSPhilippe Mathieu-Daudé object_unref(obj);
13732cad1ffSPhilippe Mathieu-Daudé return;
13832cad1ffSPhilippe Mathieu-Daudé }
13932cad1ffSPhilippe Mathieu-Daudé qdict = qobject_to(QDict, info->props);
14032cad1ffSPhilippe Mathieu-Daudé for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
14132cad1ffSPhilippe Mathieu-Daudé if (!object_property_set(obj, e->key, visitor, &err)) {
14232cad1ffSPhilippe Mathieu-Daudé break;
14332cad1ffSPhilippe Mathieu-Daudé }
14432cad1ffSPhilippe Mathieu-Daudé }
14532cad1ffSPhilippe Mathieu-Daudé if (!err) {
14632cad1ffSPhilippe Mathieu-Daudé visit_check_struct(visitor, &err);
14732cad1ffSPhilippe Mathieu-Daudé }
14832cad1ffSPhilippe Mathieu-Daudé visit_end_struct(visitor, NULL);
14932cad1ffSPhilippe Mathieu-Daudé visit_free(visitor);
15032cad1ffSPhilippe Mathieu-Daudé if (err) {
15132cad1ffSPhilippe Mathieu-Daudé error_propagate(errp, err);
15232cad1ffSPhilippe Mathieu-Daudé object_unref(obj);
15332cad1ffSPhilippe Mathieu-Daudé return;
15432cad1ffSPhilippe Mathieu-Daudé }
15532cad1ffSPhilippe Mathieu-Daudé }
15632cad1ffSPhilippe Mathieu-Daudé
15732cad1ffSPhilippe Mathieu-Daudé /* copy the model and throw the cpu away */
15832cad1ffSPhilippe Mathieu-Daudé memcpy(model, cpu->model, sizeof(*model));
15932cad1ffSPhilippe Mathieu-Daudé object_unref(obj);
16032cad1ffSPhilippe Mathieu-Daudé }
16132cad1ffSPhilippe Mathieu-Daudé
qdict_add_disabled_feat(const char * name,void * opaque)16232cad1ffSPhilippe Mathieu-Daudé static void qdict_add_disabled_feat(const char *name, void *opaque)
16332cad1ffSPhilippe Mathieu-Daudé {
16432cad1ffSPhilippe Mathieu-Daudé qdict_put_bool(opaque, name, false);
16532cad1ffSPhilippe Mathieu-Daudé }
16632cad1ffSPhilippe Mathieu-Daudé
qdict_add_enabled_feat(const char * name,void * opaque)16732cad1ffSPhilippe Mathieu-Daudé static void qdict_add_enabled_feat(const char *name, void *opaque)
16832cad1ffSPhilippe Mathieu-Daudé {
16932cad1ffSPhilippe Mathieu-Daudé qdict_put_bool(opaque, name, true);
17032cad1ffSPhilippe Mathieu-Daudé }
17132cad1ffSPhilippe Mathieu-Daudé
17232cad1ffSPhilippe Mathieu-Daudé /* convert S390CPUDef into a static CpuModelInfo */
cpu_info_from_model(CpuModelInfo * info,const S390CPUModel * model,bool delta_changes)17332cad1ffSPhilippe Mathieu-Daudé static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
17432cad1ffSPhilippe Mathieu-Daudé bool delta_changes)
17532cad1ffSPhilippe Mathieu-Daudé {
17632cad1ffSPhilippe Mathieu-Daudé QDict *qdict = qdict_new();
17732cad1ffSPhilippe Mathieu-Daudé S390FeatBitmap bitmap;
17832cad1ffSPhilippe Mathieu-Daudé
17932cad1ffSPhilippe Mathieu-Daudé /* always fallback to the static base model */
18032cad1ffSPhilippe Mathieu-Daudé info->name = g_strdup_printf("%s-base", model->def->name);
18132cad1ffSPhilippe Mathieu-Daudé
18232cad1ffSPhilippe Mathieu-Daudé if (delta_changes) {
18332cad1ffSPhilippe Mathieu-Daudé /* features deleted from the base feature set */
18432cad1ffSPhilippe Mathieu-Daudé bitmap_andnot(bitmap, model->def->base_feat, model->features,
18532cad1ffSPhilippe Mathieu-Daudé S390_FEAT_MAX);
18632cad1ffSPhilippe Mathieu-Daudé if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
18732cad1ffSPhilippe Mathieu-Daudé s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
18832cad1ffSPhilippe Mathieu-Daudé }
18932cad1ffSPhilippe Mathieu-Daudé
19032cad1ffSPhilippe Mathieu-Daudé /* features added to the base feature set */
19132cad1ffSPhilippe Mathieu-Daudé bitmap_andnot(bitmap, model->features, model->def->base_feat,
19232cad1ffSPhilippe Mathieu-Daudé S390_FEAT_MAX);
19332cad1ffSPhilippe Mathieu-Daudé if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
19432cad1ffSPhilippe Mathieu-Daudé s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_enabled_feat);
19532cad1ffSPhilippe Mathieu-Daudé }
19632cad1ffSPhilippe Mathieu-Daudé } else {
19732cad1ffSPhilippe Mathieu-Daudé /* expand all features */
19832cad1ffSPhilippe Mathieu-Daudé s390_feat_bitmap_to_ascii(model->features, qdict,
19932cad1ffSPhilippe Mathieu-Daudé qdict_add_enabled_feat);
20032cad1ffSPhilippe Mathieu-Daudé bitmap_complement(bitmap, model->features, S390_FEAT_MAX);
20132cad1ffSPhilippe Mathieu-Daudé s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
20232cad1ffSPhilippe Mathieu-Daudé }
20332cad1ffSPhilippe Mathieu-Daudé
20432cad1ffSPhilippe Mathieu-Daudé if (!qdict_size(qdict)) {
20532cad1ffSPhilippe Mathieu-Daudé qobject_unref(qdict);
20632cad1ffSPhilippe Mathieu-Daudé } else {
20732cad1ffSPhilippe Mathieu-Daudé info->props = QOBJECT(qdict);
20832cad1ffSPhilippe Mathieu-Daudé }
20932cad1ffSPhilippe Mathieu-Daudé }
21032cad1ffSPhilippe Mathieu-Daudé
qmp_query_cpu_model_expansion(CpuModelExpansionType type,CpuModelInfo * model,Error ** errp)21132cad1ffSPhilippe Mathieu-Daudé CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
21232cad1ffSPhilippe Mathieu-Daudé CpuModelInfo *model,
21332cad1ffSPhilippe Mathieu-Daudé Error **errp)
21432cad1ffSPhilippe Mathieu-Daudé {
21532cad1ffSPhilippe Mathieu-Daudé Error *err = NULL;
21632cad1ffSPhilippe Mathieu-Daudé CpuModelExpansionInfo *expansion_info = NULL;
21732cad1ffSPhilippe Mathieu-Daudé S390CPUModel s390_model;
21832cad1ffSPhilippe Mathieu-Daudé bool delta_changes = false;
21932cad1ffSPhilippe Mathieu-Daudé S390FeatBitmap deprecated_feats;
22032cad1ffSPhilippe Mathieu-Daudé
22132cad1ffSPhilippe Mathieu-Daudé /* convert it to our internal representation */
22232cad1ffSPhilippe Mathieu-Daudé cpu_model_from_info(&s390_model, model, "model", &err);
22332cad1ffSPhilippe Mathieu-Daudé if (err) {
22432cad1ffSPhilippe Mathieu-Daudé error_propagate(errp, err);
22532cad1ffSPhilippe Mathieu-Daudé return NULL;
22632cad1ffSPhilippe Mathieu-Daudé }
22732cad1ffSPhilippe Mathieu-Daudé
22832cad1ffSPhilippe Mathieu-Daudé if (type == CPU_MODEL_EXPANSION_TYPE_STATIC) {
22932cad1ffSPhilippe Mathieu-Daudé delta_changes = true;
23032cad1ffSPhilippe Mathieu-Daudé } else if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
23132cad1ffSPhilippe Mathieu-Daudé error_setg(errp, "The requested expansion type is not supported.");
23232cad1ffSPhilippe Mathieu-Daudé return NULL;
23332cad1ffSPhilippe Mathieu-Daudé }
23432cad1ffSPhilippe Mathieu-Daudé
23532cad1ffSPhilippe Mathieu-Daudé /* convert it back to a static representation */
23632cad1ffSPhilippe Mathieu-Daudé expansion_info = g_new0(CpuModelExpansionInfo, 1);
23732cad1ffSPhilippe Mathieu-Daudé expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
23832cad1ffSPhilippe Mathieu-Daudé cpu_info_from_model(expansion_info->model, &s390_model, delta_changes);
23932cad1ffSPhilippe Mathieu-Daudé
24032cad1ffSPhilippe Mathieu-Daudé /* populate list of deprecated features */
24132cad1ffSPhilippe Mathieu-Daudé bitmap_zero(deprecated_feats, S390_FEAT_MAX);
24232cad1ffSPhilippe Mathieu-Daudé s390_get_deprecated_features(deprecated_feats);
24332cad1ffSPhilippe Mathieu-Daudé
24432cad1ffSPhilippe Mathieu-Daudé if (delta_changes) {
24532cad1ffSPhilippe Mathieu-Daudé /*
24632cad1ffSPhilippe Mathieu-Daudé * Only populate deprecated features that are a
24732cad1ffSPhilippe Mathieu-Daudé * subset of the features enabled on the CPU model.
24832cad1ffSPhilippe Mathieu-Daudé */
24932cad1ffSPhilippe Mathieu-Daudé bitmap_and(deprecated_feats, deprecated_feats,
25032cad1ffSPhilippe Mathieu-Daudé s390_model.features, S390_FEAT_MAX);
25132cad1ffSPhilippe Mathieu-Daudé }
25232cad1ffSPhilippe Mathieu-Daudé
25332cad1ffSPhilippe Mathieu-Daudé s390_feat_bitmap_to_ascii(deprecated_feats,
25432cad1ffSPhilippe Mathieu-Daudé &expansion_info->deprecated_props, list_add_feat);
25532cad1ffSPhilippe Mathieu-Daudé return expansion_info;
25632cad1ffSPhilippe Mathieu-Daudé }
25732cad1ffSPhilippe Mathieu-Daudé
list_add_feat(const char * name,void * opaque)25832cad1ffSPhilippe Mathieu-Daudé static void list_add_feat(const char *name, void *opaque)
25932cad1ffSPhilippe Mathieu-Daudé {
26032cad1ffSPhilippe Mathieu-Daudé strList **last = (strList **) opaque;
26132cad1ffSPhilippe Mathieu-Daudé
26232cad1ffSPhilippe Mathieu-Daudé QAPI_LIST_PREPEND(*last, g_strdup(name));
26332cad1ffSPhilippe Mathieu-Daudé }
26432cad1ffSPhilippe Mathieu-Daudé
qmp_query_cpu_model_comparison(CpuModelInfo * infoa,CpuModelInfo * infob,Error ** errp)26532cad1ffSPhilippe Mathieu-Daudé CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
26632cad1ffSPhilippe Mathieu-Daudé CpuModelInfo *infob,
26732cad1ffSPhilippe Mathieu-Daudé Error **errp)
26832cad1ffSPhilippe Mathieu-Daudé {
26932cad1ffSPhilippe Mathieu-Daudé Error *err = NULL;
27032cad1ffSPhilippe Mathieu-Daudé CpuModelCompareResult feat_result, gen_result;
27132cad1ffSPhilippe Mathieu-Daudé CpuModelCompareInfo *compare_info;
27232cad1ffSPhilippe Mathieu-Daudé S390FeatBitmap missing, added;
27332cad1ffSPhilippe Mathieu-Daudé S390CPUModel modela, modelb;
27432cad1ffSPhilippe Mathieu-Daudé
27532cad1ffSPhilippe Mathieu-Daudé /* convert both models to our internal representation */
27632cad1ffSPhilippe Mathieu-Daudé cpu_model_from_info(&modela, infoa, "modela", &err);
27732cad1ffSPhilippe Mathieu-Daudé if (err) {
27832cad1ffSPhilippe Mathieu-Daudé error_propagate(errp, err);
27932cad1ffSPhilippe Mathieu-Daudé return NULL;
28032cad1ffSPhilippe Mathieu-Daudé }
28132cad1ffSPhilippe Mathieu-Daudé cpu_model_from_info(&modelb, infob, "modelb", &err);
28232cad1ffSPhilippe Mathieu-Daudé if (err) {
28332cad1ffSPhilippe Mathieu-Daudé error_propagate(errp, err);
28432cad1ffSPhilippe Mathieu-Daudé return NULL;
28532cad1ffSPhilippe Mathieu-Daudé }
28632cad1ffSPhilippe Mathieu-Daudé compare_info = g_new0(CpuModelCompareInfo, 1);
28732cad1ffSPhilippe Mathieu-Daudé
28832cad1ffSPhilippe Mathieu-Daudé /* check the cpu generation and ga level */
28932cad1ffSPhilippe Mathieu-Daudé if (modela.def->gen == modelb.def->gen) {
29032cad1ffSPhilippe Mathieu-Daudé if (modela.def->ec_ga == modelb.def->ec_ga) {
29132cad1ffSPhilippe Mathieu-Daudé /* ec and corresponding bc are identical */
29232cad1ffSPhilippe Mathieu-Daudé gen_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
29332cad1ffSPhilippe Mathieu-Daudé } else if (modela.def->ec_ga < modelb.def->ec_ga) {
29432cad1ffSPhilippe Mathieu-Daudé gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
29532cad1ffSPhilippe Mathieu-Daudé } else {
29632cad1ffSPhilippe Mathieu-Daudé gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
29732cad1ffSPhilippe Mathieu-Daudé }
29832cad1ffSPhilippe Mathieu-Daudé } else if (modela.def->gen < modelb.def->gen) {
29932cad1ffSPhilippe Mathieu-Daudé gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
30032cad1ffSPhilippe Mathieu-Daudé } else {
30132cad1ffSPhilippe Mathieu-Daudé gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
30232cad1ffSPhilippe Mathieu-Daudé }
30332cad1ffSPhilippe Mathieu-Daudé if (gen_result != CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
30432cad1ffSPhilippe Mathieu-Daudé /* both models cannot be made identical */
30532cad1ffSPhilippe Mathieu-Daudé list_add_feat("type", &compare_info->responsible_properties);
30632cad1ffSPhilippe Mathieu-Daudé }
30732cad1ffSPhilippe Mathieu-Daudé
30832cad1ffSPhilippe Mathieu-Daudé /* check the feature set */
30932cad1ffSPhilippe Mathieu-Daudé if (bitmap_equal(modela.features, modelb.features, S390_FEAT_MAX)) {
31032cad1ffSPhilippe Mathieu-Daudé feat_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
31132cad1ffSPhilippe Mathieu-Daudé } else {
31232cad1ffSPhilippe Mathieu-Daudé bitmap_andnot(missing, modela.features, modelb.features, S390_FEAT_MAX);
31332cad1ffSPhilippe Mathieu-Daudé s390_feat_bitmap_to_ascii(missing,
31432cad1ffSPhilippe Mathieu-Daudé &compare_info->responsible_properties,
31532cad1ffSPhilippe Mathieu-Daudé list_add_feat);
31632cad1ffSPhilippe Mathieu-Daudé bitmap_andnot(added, modelb.features, modela.features, S390_FEAT_MAX);
31732cad1ffSPhilippe Mathieu-Daudé s390_feat_bitmap_to_ascii(added, &compare_info->responsible_properties,
31832cad1ffSPhilippe Mathieu-Daudé list_add_feat);
31932cad1ffSPhilippe Mathieu-Daudé if (bitmap_empty(missing, S390_FEAT_MAX)) {
32032cad1ffSPhilippe Mathieu-Daudé feat_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
32132cad1ffSPhilippe Mathieu-Daudé } else if (bitmap_empty(added, S390_FEAT_MAX)) {
32232cad1ffSPhilippe Mathieu-Daudé feat_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
32332cad1ffSPhilippe Mathieu-Daudé } else {
32432cad1ffSPhilippe Mathieu-Daudé feat_result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
32532cad1ffSPhilippe Mathieu-Daudé }
32632cad1ffSPhilippe Mathieu-Daudé }
32732cad1ffSPhilippe Mathieu-Daudé
32832cad1ffSPhilippe Mathieu-Daudé /* combine the results */
32932cad1ffSPhilippe Mathieu-Daudé if (gen_result == feat_result) {
33032cad1ffSPhilippe Mathieu-Daudé compare_info->result = gen_result;
33132cad1ffSPhilippe Mathieu-Daudé } else if (feat_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
33232cad1ffSPhilippe Mathieu-Daudé compare_info->result = gen_result;
33332cad1ffSPhilippe Mathieu-Daudé } else if (gen_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
33432cad1ffSPhilippe Mathieu-Daudé compare_info->result = feat_result;
33532cad1ffSPhilippe Mathieu-Daudé } else {
33632cad1ffSPhilippe Mathieu-Daudé compare_info->result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
33732cad1ffSPhilippe Mathieu-Daudé }
33832cad1ffSPhilippe Mathieu-Daudé return compare_info;
33932cad1ffSPhilippe Mathieu-Daudé }
34032cad1ffSPhilippe Mathieu-Daudé
qmp_query_cpu_model_baseline(CpuModelInfo * infoa,CpuModelInfo * infob,Error ** errp)34132cad1ffSPhilippe Mathieu-Daudé CpuModelBaselineInfo *qmp_query_cpu_model_baseline(CpuModelInfo *infoa,
34232cad1ffSPhilippe Mathieu-Daudé CpuModelInfo *infob,
34332cad1ffSPhilippe Mathieu-Daudé Error **errp)
34432cad1ffSPhilippe Mathieu-Daudé {
34532cad1ffSPhilippe Mathieu-Daudé Error *err = NULL;
34632cad1ffSPhilippe Mathieu-Daudé CpuModelBaselineInfo *baseline_info;
34732cad1ffSPhilippe Mathieu-Daudé S390CPUModel modela, modelb, model;
34832cad1ffSPhilippe Mathieu-Daudé uint16_t cpu_type;
34932cad1ffSPhilippe Mathieu-Daudé uint8_t max_gen_ga;
35032cad1ffSPhilippe Mathieu-Daudé uint8_t max_gen;
35132cad1ffSPhilippe Mathieu-Daudé
35232cad1ffSPhilippe Mathieu-Daudé /* convert both models to our internal representation */
35332cad1ffSPhilippe Mathieu-Daudé cpu_model_from_info(&modela, infoa, "modela", &err);
35432cad1ffSPhilippe Mathieu-Daudé if (err) {
35532cad1ffSPhilippe Mathieu-Daudé error_propagate(errp, err);
35632cad1ffSPhilippe Mathieu-Daudé return NULL;
35732cad1ffSPhilippe Mathieu-Daudé }
35832cad1ffSPhilippe Mathieu-Daudé
35932cad1ffSPhilippe Mathieu-Daudé cpu_model_from_info(&modelb, infob, "modelb", &err);
36032cad1ffSPhilippe Mathieu-Daudé if (err) {
36132cad1ffSPhilippe Mathieu-Daudé error_propagate(errp, err);
36232cad1ffSPhilippe Mathieu-Daudé return NULL;
36332cad1ffSPhilippe Mathieu-Daudé }
36432cad1ffSPhilippe Mathieu-Daudé
36532cad1ffSPhilippe Mathieu-Daudé /* features both models support */
36632cad1ffSPhilippe Mathieu-Daudé bitmap_and(model.features, modela.features, modelb.features, S390_FEAT_MAX);
36732cad1ffSPhilippe Mathieu-Daudé
36832cad1ffSPhilippe Mathieu-Daudé /* detect the maximum model not regarding features */
36932cad1ffSPhilippe Mathieu-Daudé if (modela.def->gen == modelb.def->gen) {
37032cad1ffSPhilippe Mathieu-Daudé if (modela.def->type == modelb.def->type) {
37132cad1ffSPhilippe Mathieu-Daudé cpu_type = modela.def->type;
37232cad1ffSPhilippe Mathieu-Daudé } else {
37332cad1ffSPhilippe Mathieu-Daudé cpu_type = 0;
37432cad1ffSPhilippe Mathieu-Daudé }
37532cad1ffSPhilippe Mathieu-Daudé max_gen = modela.def->gen;
37632cad1ffSPhilippe Mathieu-Daudé max_gen_ga = MIN(modela.def->ec_ga, modelb.def->ec_ga);
37732cad1ffSPhilippe Mathieu-Daudé } else if (modela.def->gen > modelb.def->gen) {
37832cad1ffSPhilippe Mathieu-Daudé cpu_type = modelb.def->type;
37932cad1ffSPhilippe Mathieu-Daudé max_gen = modelb.def->gen;
38032cad1ffSPhilippe Mathieu-Daudé max_gen_ga = modelb.def->ec_ga;
38132cad1ffSPhilippe Mathieu-Daudé } else {
38232cad1ffSPhilippe Mathieu-Daudé cpu_type = modela.def->type;
38332cad1ffSPhilippe Mathieu-Daudé max_gen = modela.def->gen;
38432cad1ffSPhilippe Mathieu-Daudé max_gen_ga = modela.def->ec_ga;
38532cad1ffSPhilippe Mathieu-Daudé }
38632cad1ffSPhilippe Mathieu-Daudé
38732cad1ffSPhilippe Mathieu-Daudé model.def = s390_find_cpu_def(cpu_type, max_gen, max_gen_ga,
38832cad1ffSPhilippe Mathieu-Daudé model.features);
38932cad1ffSPhilippe Mathieu-Daudé
39032cad1ffSPhilippe Mathieu-Daudé /* models without early base features (esan3) are bad */
39132cad1ffSPhilippe Mathieu-Daudé if (!model.def) {
39232cad1ffSPhilippe Mathieu-Daudé error_setg(errp, "No compatible CPU model could be created as"
39332cad1ffSPhilippe Mathieu-Daudé " important base features are disabled");
39432cad1ffSPhilippe Mathieu-Daudé return NULL;
39532cad1ffSPhilippe Mathieu-Daudé }
39632cad1ffSPhilippe Mathieu-Daudé
39732cad1ffSPhilippe Mathieu-Daudé /* strip off features not part of the max model */
39832cad1ffSPhilippe Mathieu-Daudé bitmap_and(model.features, model.features, model.def->full_feat,
39932cad1ffSPhilippe Mathieu-Daudé S390_FEAT_MAX);
40032cad1ffSPhilippe Mathieu-Daudé
40132cad1ffSPhilippe Mathieu-Daudé baseline_info = g_new0(CpuModelBaselineInfo, 1);
40232cad1ffSPhilippe Mathieu-Daudé baseline_info->model = g_malloc0(sizeof(*baseline_info->model));
40332cad1ffSPhilippe Mathieu-Daudé cpu_info_from_model(baseline_info->model, &model, true);
40432cad1ffSPhilippe Mathieu-Daudé return baseline_info;
40532cad1ffSPhilippe Mathieu-Daudé }
40632cad1ffSPhilippe Mathieu-Daudé
apply_cpu_model(const S390CPUModel * model,Error ** errp)40732cad1ffSPhilippe Mathieu-Daudé void apply_cpu_model(const S390CPUModel *model, Error **errp)
40832cad1ffSPhilippe Mathieu-Daudé {
40932cad1ffSPhilippe Mathieu-Daudé static S390CPUModel applied_model;
41032cad1ffSPhilippe Mathieu-Daudé static bool applied;
41132cad1ffSPhilippe Mathieu-Daudé
41232cad1ffSPhilippe Mathieu-Daudé /*
41332cad1ffSPhilippe Mathieu-Daudé * We have the same model for all VCPUs. KVM can only be configured before
41432cad1ffSPhilippe Mathieu-Daudé * any VCPUs are defined in KVM.
41532cad1ffSPhilippe Mathieu-Daudé */
41632cad1ffSPhilippe Mathieu-Daudé if (applied) {
41732cad1ffSPhilippe Mathieu-Daudé if (model && memcmp(&applied_model, model, sizeof(S390CPUModel))) {
41832cad1ffSPhilippe Mathieu-Daudé error_setg(errp, "Mixed CPU models are not supported on s390x.");
41932cad1ffSPhilippe Mathieu-Daudé }
42032cad1ffSPhilippe Mathieu-Daudé return;
42132cad1ffSPhilippe Mathieu-Daudé }
42232cad1ffSPhilippe Mathieu-Daudé
42332cad1ffSPhilippe Mathieu-Daudé if (kvm_enabled()) {
42432cad1ffSPhilippe Mathieu-Daudé if (!kvm_s390_apply_cpu_model(model, errp)) {
42532cad1ffSPhilippe Mathieu-Daudé return;
42632cad1ffSPhilippe Mathieu-Daudé }
42732cad1ffSPhilippe Mathieu-Daudé }
42832cad1ffSPhilippe Mathieu-Daudé
42932cad1ffSPhilippe Mathieu-Daudé applied = true;
43032cad1ffSPhilippe Mathieu-Daudé if (model) {
43132cad1ffSPhilippe Mathieu-Daudé applied_model = *model;
43232cad1ffSPhilippe Mathieu-Daudé }
43332cad1ffSPhilippe Mathieu-Daudé }
434