xref: /openbmc/qemu/target/s390x/cpu_models_system.c (revision 54e91d1523b412b4cff7cb36c898fa9dc133e886)
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