2 * CPU models for s390x - System Emulation-only
4 * Copyright 2016 IBM Corp.
6 * Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
8 * This work is licensed under the terms of the GNU GPL, version 2 or (at
9 * your option) any later version. See the COPYING file in the top-level
13 #include "qemu/osdep.h"
15 #include "s390x-internal.h"
16 #include "kvm/kvm_s390x.h"
17 #include "sysemu/kvm.h"
18 #include "qapi/error.h"
19 #include "qapi/visitor.h"
20 #include "qapi/qmp/qerror.h"
21 #include "qapi/qobject-input-visitor.h"
22 #include "qapi/qmp/qdict.h"
23 #include "qapi/qapi-commands-machine-target.h"
25 static void list_add_feat(const char *name
, void *opaque
);
27 static void check_unavailable_features(const S390CPUModel
*max_model
,
28 const S390CPUModel
*model
,
29 strList
**unavailable
)
31 S390FeatBitmap missing
;
33 /* check general model compatibility */
34 if (max_model
->def
->gen
< model
->def
->gen
||
35 (max_model
->def
->gen
== model
->def
->gen
&&
36 max_model
->def
->ec_ga
< model
->def
->ec_ga
)) {
37 list_add_feat("type", unavailable
);
40 /* detect missing features if any to properly report them */
41 bitmap_andnot(missing
, model
->features
, max_model
->features
,
43 if (!bitmap_empty(missing
, S390_FEAT_MAX
)) {
44 s390_feat_bitmap_to_ascii(missing
, unavailable
, list_add_feat
);
48 struct CpuDefinitionInfoListData
{
49 CpuDefinitionInfoList
*list
;
53 static void create_cpu_model_list(ObjectClass
*klass
, void *opaque
)
55 struct CpuDefinitionInfoListData
*cpu_list_data
= opaque
;
56 CpuDefinitionInfoList
**cpu_list
= &cpu_list_data
->list
;
57 CpuDefinitionInfo
*info
;
58 char *name
= g_strdup(object_class_get_name(klass
));
59 S390CPUClass
*scc
= S390_CPU_CLASS(klass
);
61 /* strip off the -s390x-cpu */
62 g_strrstr(name
, "-" TYPE_S390_CPU
)[0] = 0;
63 info
= g_new0(CpuDefinitionInfo
, 1);
65 info
->has_migration_safe
= true;
66 info
->migration_safe
= scc
->is_migration_safe
;
67 info
->q_static
= scc
->is_static
;
68 info
->q_typename
= g_strdup(object_class_get_name(klass
));
69 /* check for unavailable features */
70 if (cpu_list_data
->model
) {
73 obj
= object_new_with_class(klass
);
76 info
->has_unavailable_features
= true;
77 check_unavailable_features(cpu_list_data
->model
, sc
->model
,
78 &info
->unavailable_features
);
83 QAPI_LIST_PREPEND(*cpu_list
, info
);
86 CpuDefinitionInfoList
*qmp_query_cpu_definitions(Error
**errp
)
88 struct CpuDefinitionInfoListData list_data
= {
92 list_data
.model
= get_max_cpu_model(NULL
);
94 object_class_foreach(create_cpu_model_list
, TYPE_S390_CPU
, false,
97 return list_data
.list
;
100 static void cpu_model_from_info(S390CPUModel
*model
, const CpuModelInfo
*info
,
104 const QDict
*qdict
= NULL
;
112 qdict
= qobject_to(QDict
, info
->props
);
114 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, "props", "dict");
119 oc
= cpu_class_by_name(TYPE_S390_CPU
, info
->name
);
121 error_setg(errp
, "The CPU definition \'%s\' is unknown.", info
->name
);
124 if (S390_CPU_CLASS(oc
)->kvm_required
&& !kvm_enabled()) {
125 error_setg(errp
, "The CPU definition '%s' requires KVM", info
->name
);
128 obj
= object_new_with_class(oc
);
132 error_setg(errp
, "Details about the host CPU model are not available, "
133 "it cannot be used.");
139 visitor
= qobject_input_visitor_new(info
->props
);
140 if (!visit_start_struct(visitor
, NULL
, NULL
, 0, errp
)) {
145 for (e
= qdict_first(qdict
); e
; e
= qdict_next(qdict
, e
)) {
146 if (!object_property_set(obj
, e
->key
, visitor
, &err
)) {
151 visit_check_struct(visitor
, &err
);
153 visit_end_struct(visitor
, NULL
);
156 error_propagate(errp
, err
);
162 /* copy the model and throw the cpu away */
163 memcpy(model
, cpu
->model
, sizeof(*model
));
167 static void qdict_add_disabled_feat(const char *name
, void *opaque
)
169 qdict_put_bool(opaque
, name
, false);
172 static void qdict_add_enabled_feat(const char *name
, void *opaque
)
174 qdict_put_bool(opaque
, name
, true);
177 /* convert S390CPUDef into a static CpuModelInfo */
178 static void cpu_info_from_model(CpuModelInfo
*info
, const S390CPUModel
*model
,
181 QDict
*qdict
= qdict_new();
182 S390FeatBitmap bitmap
;
184 /* always fallback to the static base model */
185 info
->name
= g_strdup_printf("%s-base", model
->def
->name
);
188 /* features deleted from the base feature set */
189 bitmap_andnot(bitmap
, model
->def
->base_feat
, model
->features
,
191 if (!bitmap_empty(bitmap
, S390_FEAT_MAX
)) {
192 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_disabled_feat
);
195 /* features added to the base feature set */
196 bitmap_andnot(bitmap
, model
->features
, model
->def
->base_feat
,
198 if (!bitmap_empty(bitmap
, S390_FEAT_MAX
)) {
199 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_enabled_feat
);
202 /* expand all features */
203 s390_feat_bitmap_to_ascii(model
->features
, qdict
,
204 qdict_add_enabled_feat
);
205 bitmap_complement(bitmap
, model
->features
, S390_FEAT_MAX
);
206 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_disabled_feat
);
209 if (!qdict_size(qdict
)) {
210 qobject_unref(qdict
);
212 info
->props
= QOBJECT(qdict
);
213 info
->has_props
= true;
217 CpuModelExpansionInfo
*qmp_query_cpu_model_expansion(CpuModelExpansionType type
,
222 CpuModelExpansionInfo
*expansion_info
= NULL
;
223 S390CPUModel s390_model
;
224 bool delta_changes
= false;
226 /* convert it to our internal representation */
227 cpu_model_from_info(&s390_model
, model
, &err
);
229 error_propagate(errp
, err
);
233 if (type
== CPU_MODEL_EXPANSION_TYPE_STATIC
) {
234 delta_changes
= true;
235 } else if (type
!= CPU_MODEL_EXPANSION_TYPE_FULL
) {
236 error_setg(errp
, "The requested expansion type is not supported.");
240 /* convert it back to a static representation */
241 expansion_info
= g_new0(CpuModelExpansionInfo
, 1);
242 expansion_info
->model
= g_malloc0(sizeof(*expansion_info
->model
));
243 cpu_info_from_model(expansion_info
->model
, &s390_model
, delta_changes
);
244 return expansion_info
;
247 static void list_add_feat(const char *name
, void *opaque
)
249 strList
**last
= (strList
**) opaque
;
251 QAPI_LIST_PREPEND(*last
, g_strdup(name
));
254 CpuModelCompareInfo
*qmp_query_cpu_model_comparison(CpuModelInfo
*infoa
,
259 CpuModelCompareResult feat_result
, gen_result
;
260 CpuModelCompareInfo
*compare_info
;
261 S390FeatBitmap missing
, added
;
262 S390CPUModel modela
, modelb
;
264 /* convert both models to our internal representation */
265 cpu_model_from_info(&modela
, infoa
, &err
);
267 error_propagate(errp
, err
);
270 cpu_model_from_info(&modelb
, infob
, &err
);
272 error_propagate(errp
, err
);
275 compare_info
= g_new0(CpuModelCompareInfo
, 1);
277 /* check the cpu generation and ga level */
278 if (modela
.def
->gen
== modelb
.def
->gen
) {
279 if (modela
.def
->ec_ga
== modelb
.def
->ec_ga
) {
280 /* ec and corresponding bc are identical */
281 gen_result
= CPU_MODEL_COMPARE_RESULT_IDENTICAL
;
282 } else if (modela
.def
->ec_ga
< modelb
.def
->ec_ga
) {
283 gen_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
285 gen_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
287 } else if (modela
.def
->gen
< modelb
.def
->gen
) {
288 gen_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
290 gen_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
292 if (gen_result
!= CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
293 /* both models cannot be made identical */
294 list_add_feat("type", &compare_info
->responsible_properties
);
297 /* check the feature set */
298 if (bitmap_equal(modela
.features
, modelb
.features
, S390_FEAT_MAX
)) {
299 feat_result
= CPU_MODEL_COMPARE_RESULT_IDENTICAL
;
301 bitmap_andnot(missing
, modela
.features
, modelb
.features
, S390_FEAT_MAX
);
302 s390_feat_bitmap_to_ascii(missing
,
303 &compare_info
->responsible_properties
,
305 bitmap_andnot(added
, modelb
.features
, modela
.features
, S390_FEAT_MAX
);
306 s390_feat_bitmap_to_ascii(added
, &compare_info
->responsible_properties
,
308 if (bitmap_empty(missing
, S390_FEAT_MAX
)) {
309 feat_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
310 } else if (bitmap_empty(added
, S390_FEAT_MAX
)) {
311 feat_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
313 feat_result
= CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE
;
317 /* combine the results */
318 if (gen_result
== feat_result
) {
319 compare_info
->result
= gen_result
;
320 } else if (feat_result
== CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
321 compare_info
->result
= gen_result
;
322 } else if (gen_result
== CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
323 compare_info
->result
= feat_result
;
325 compare_info
->result
= CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE
;
330 CpuModelBaselineInfo
*qmp_query_cpu_model_baseline(CpuModelInfo
*infoa
,
335 CpuModelBaselineInfo
*baseline_info
;
336 S390CPUModel modela
, modelb
, model
;
341 /* convert both models to our internal representation */
342 cpu_model_from_info(&modela
, infoa
, &err
);
344 error_propagate(errp
, err
);
348 cpu_model_from_info(&modelb
, infob
, &err
);
350 error_propagate(errp
, err
);
354 /* features both models support */
355 bitmap_and(model
.features
, modela
.features
, modelb
.features
, S390_FEAT_MAX
);
357 /* detect the maximum model not regarding features */
358 if (modela
.def
->gen
== modelb
.def
->gen
) {
359 if (modela
.def
->type
== modelb
.def
->type
) {
360 cpu_type
= modela
.def
->type
;
364 max_gen
= modela
.def
->gen
;
365 max_gen_ga
= MIN(modela
.def
->ec_ga
, modelb
.def
->ec_ga
);
366 } else if (modela
.def
->gen
> modelb
.def
->gen
) {
367 cpu_type
= modelb
.def
->type
;
368 max_gen
= modelb
.def
->gen
;
369 max_gen_ga
= modelb
.def
->ec_ga
;
371 cpu_type
= modela
.def
->type
;
372 max_gen
= modela
.def
->gen
;
373 max_gen_ga
= modela
.def
->ec_ga
;
376 model
.def
= s390_find_cpu_def(cpu_type
, max_gen
, max_gen_ga
,
379 /* models without early base features (esan3) are bad */
381 error_setg(errp
, "No compatible CPU model could be created as"
382 " important base features are disabled");
386 /* strip off features not part of the max model */
387 bitmap_and(model
.features
, model
.features
, model
.def
->full_feat
,
390 baseline_info
= g_new0(CpuModelBaselineInfo
, 1);
391 baseline_info
->model
= g_malloc0(sizeof(*baseline_info
->model
));
392 cpu_info_from_model(baseline_info
->model
, &model
, true);
393 return baseline_info
;
396 void apply_cpu_model(const S390CPUModel
*model
, Error
**errp
)
399 static S390CPUModel applied_model
;
403 * We have the same model for all VCPUs. KVM can only be configured before
404 * any VCPUs are defined in KVM.
407 if (model
&& memcmp(&applied_model
, model
, sizeof(S390CPUModel
))) {
408 error_setg(errp
, "Mixed CPU models are not supported on s390x.");
414 kvm_s390_apply_cpu_model(model
, &err
);
416 error_propagate(errp
, err
);
423 applied_model
= *model
;