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/qobject-input-visitor.h"
21 #include "qapi/qmp/qdict.h"
22 #include "qapi/qapi-commands-machine-target.h"
24 static void list_add_feat(const char *name
, void *opaque
);
26 static void check_unavailable_features(const S390CPUModel
*max_model
,
27 const S390CPUModel
*model
,
28 strList
**unavailable
)
30 S390FeatBitmap missing
;
32 /* check general model compatibility */
33 if (max_model
->def
->gen
< model
->def
->gen
||
34 (max_model
->def
->gen
== model
->def
->gen
&&
35 max_model
->def
->ec_ga
< model
->def
->ec_ga
)) {
36 list_add_feat("type", unavailable
);
39 /* detect missing features if any to properly report them */
40 bitmap_andnot(missing
, model
->features
, max_model
->features
,
42 if (!bitmap_empty(missing
, S390_FEAT_MAX
)) {
43 s390_feat_bitmap_to_ascii(missing
, unavailable
, list_add_feat
);
47 struct CpuDefinitionInfoListData
{
48 CpuDefinitionInfoList
*list
;
52 static void create_cpu_model_list(ObjectClass
*klass
, void *opaque
)
54 struct CpuDefinitionInfoListData
*cpu_list_data
= opaque
;
55 CpuDefinitionInfoList
**cpu_list
= &cpu_list_data
->list
;
56 CpuDefinitionInfo
*info
;
57 char *name
= g_strdup(object_class_get_name(klass
));
58 S390CPUClass
*scc
= S390_CPU_CLASS(klass
);
60 /* strip off the -s390x-cpu */
61 g_strrstr(name
, "-" TYPE_S390_CPU
)[0] = 0;
62 info
= g_new0(CpuDefinitionInfo
, 1);
64 info
->has_migration_safe
= true;
65 info
->migration_safe
= scc
->is_migration_safe
;
66 info
->q_static
= scc
->is_static
;
67 info
->q_typename
= g_strdup(object_class_get_name(klass
));
68 /* check for unavailable features */
69 if (cpu_list_data
->model
) {
72 obj
= object_new_with_class(klass
);
75 info
->has_unavailable_features
= true;
76 check_unavailable_features(cpu_list_data
->model
, sc
->model
,
77 &info
->unavailable_features
);
82 QAPI_LIST_PREPEND(*cpu_list
, info
);
85 CpuDefinitionInfoList
*qmp_query_cpu_definitions(Error
**errp
)
87 struct CpuDefinitionInfoListData list_data
= {
91 list_data
.model
= get_max_cpu_model(NULL
);
93 object_class_foreach(create_cpu_model_list
, TYPE_S390_CPU
, false,
96 return list_data
.list
;
99 static void cpu_model_from_info(S390CPUModel
*model
, const CpuModelInfo
*info
,
100 const char *info_arg_name
, Error
**errp
)
110 oc
= cpu_class_by_name(TYPE_S390_CPU
, info
->name
);
112 error_setg(errp
, "The CPU definition \'%s\' is unknown.", info
->name
);
115 if (S390_CPU_CLASS(oc
)->kvm_required
&& !kvm_enabled()) {
116 error_setg(errp
, "The CPU definition '%s' requires KVM", info
->name
);
119 obj
= object_new_with_class(oc
);
123 error_setg(errp
, "Details about the host CPU model are not available, "
124 "it cannot be used.");
130 g_autofree
const char *props_name
= g_strdup_printf("%s.props",
133 visitor
= qobject_input_visitor_new(info
->props
);
134 if (!visit_start_struct(visitor
, props_name
, NULL
, 0, errp
)) {
139 qdict
= qobject_to(QDict
, info
->props
);
140 for (e
= qdict_first(qdict
); e
; e
= qdict_next(qdict
, e
)) {
141 if (!object_property_set(obj
, e
->key
, visitor
, &err
)) {
146 visit_check_struct(visitor
, &err
);
148 visit_end_struct(visitor
, NULL
);
151 error_propagate(errp
, err
);
157 /* copy the model and throw the cpu away */
158 memcpy(model
, cpu
->model
, sizeof(*model
));
162 static void qdict_add_disabled_feat(const char *name
, void *opaque
)
164 qdict_put_bool(opaque
, name
, false);
167 static void qdict_add_enabled_feat(const char *name
, void *opaque
)
169 qdict_put_bool(opaque
, name
, true);
172 /* convert S390CPUDef into a static CpuModelInfo */
173 static void cpu_info_from_model(CpuModelInfo
*info
, const S390CPUModel
*model
,
176 QDict
*qdict
= qdict_new();
177 S390FeatBitmap bitmap
;
179 /* always fallback to the static base model */
180 info
->name
= g_strdup_printf("%s-base", model
->def
->name
);
183 /* features deleted from the base feature set */
184 bitmap_andnot(bitmap
, model
->def
->base_feat
, model
->features
,
186 if (!bitmap_empty(bitmap
, S390_FEAT_MAX
)) {
187 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_disabled_feat
);
190 /* features added to the base feature set */
191 bitmap_andnot(bitmap
, model
->features
, model
->def
->base_feat
,
193 if (!bitmap_empty(bitmap
, S390_FEAT_MAX
)) {
194 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_enabled_feat
);
197 /* expand all features */
198 s390_feat_bitmap_to_ascii(model
->features
, qdict
,
199 qdict_add_enabled_feat
);
200 bitmap_complement(bitmap
, model
->features
, S390_FEAT_MAX
);
201 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_disabled_feat
);
204 if (!qdict_size(qdict
)) {
205 qobject_unref(qdict
);
207 info
->props
= QOBJECT(qdict
);
210 /* features flagged as deprecated */
211 bitmap_zero(bitmap
, S390_FEAT_MAX
);
212 s390_get_deprecated_features(bitmap
);
214 bitmap_and(bitmap
, bitmap
, model
->def
->full_feat
, S390_FEAT_MAX
);
215 s390_feat_bitmap_to_ascii(bitmap
, &info
->deprecated_props
, list_add_feat
);
216 info
->has_deprecated_props
= !!info
->deprecated_props
;
219 CpuModelExpansionInfo
*qmp_query_cpu_model_expansion(CpuModelExpansionType type
,
224 CpuModelExpansionInfo
*expansion_info
= NULL
;
225 S390CPUModel s390_model
;
226 bool delta_changes
= false;
228 /* convert it to our internal representation */
229 cpu_model_from_info(&s390_model
, model
, "model", &err
);
231 error_propagate(errp
, err
);
235 if (type
== CPU_MODEL_EXPANSION_TYPE_STATIC
) {
236 delta_changes
= true;
237 } else if (type
!= CPU_MODEL_EXPANSION_TYPE_FULL
) {
238 error_setg(errp
, "The requested expansion type is not supported.");
242 /* convert it back to a static representation */
243 expansion_info
= g_new0(CpuModelExpansionInfo
, 1);
244 expansion_info
->model
= g_malloc0(sizeof(*expansion_info
->model
));
245 cpu_info_from_model(expansion_info
->model
, &s390_model
, delta_changes
);
246 return expansion_info
;
249 static void list_add_feat(const char *name
, void *opaque
)
251 strList
**last
= (strList
**) opaque
;
253 QAPI_LIST_PREPEND(*last
, g_strdup(name
));
256 CpuModelCompareInfo
*qmp_query_cpu_model_comparison(CpuModelInfo
*infoa
,
261 CpuModelCompareResult feat_result
, gen_result
;
262 CpuModelCompareInfo
*compare_info
;
263 S390FeatBitmap missing
, added
;
264 S390CPUModel modela
, modelb
;
266 /* convert both models to our internal representation */
267 cpu_model_from_info(&modela
, infoa
, "modela", &err
);
269 error_propagate(errp
, err
);
272 cpu_model_from_info(&modelb
, infob
, "modelb", &err
);
274 error_propagate(errp
, err
);
277 compare_info
= g_new0(CpuModelCompareInfo
, 1);
279 /* check the cpu generation and ga level */
280 if (modela
.def
->gen
== modelb
.def
->gen
) {
281 if (modela
.def
->ec_ga
== modelb
.def
->ec_ga
) {
282 /* ec and corresponding bc are identical */
283 gen_result
= CPU_MODEL_COMPARE_RESULT_IDENTICAL
;
284 } else if (modela
.def
->ec_ga
< modelb
.def
->ec_ga
) {
285 gen_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
287 gen_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
289 } else if (modela
.def
->gen
< modelb
.def
->gen
) {
290 gen_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
292 gen_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
294 if (gen_result
!= CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
295 /* both models cannot be made identical */
296 list_add_feat("type", &compare_info
->responsible_properties
);
299 /* check the feature set */
300 if (bitmap_equal(modela
.features
, modelb
.features
, S390_FEAT_MAX
)) {
301 feat_result
= CPU_MODEL_COMPARE_RESULT_IDENTICAL
;
303 bitmap_andnot(missing
, modela
.features
, modelb
.features
, S390_FEAT_MAX
);
304 s390_feat_bitmap_to_ascii(missing
,
305 &compare_info
->responsible_properties
,
307 bitmap_andnot(added
, modelb
.features
, modela
.features
, S390_FEAT_MAX
);
308 s390_feat_bitmap_to_ascii(added
, &compare_info
->responsible_properties
,
310 if (bitmap_empty(missing
, S390_FEAT_MAX
)) {
311 feat_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
312 } else if (bitmap_empty(added
, S390_FEAT_MAX
)) {
313 feat_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
315 feat_result
= CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE
;
319 /* combine the results */
320 if (gen_result
== feat_result
) {
321 compare_info
->result
= gen_result
;
322 } else if (feat_result
== CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
323 compare_info
->result
= gen_result
;
324 } else if (gen_result
== CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
325 compare_info
->result
= feat_result
;
327 compare_info
->result
= CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE
;
332 CpuModelBaselineInfo
*qmp_query_cpu_model_baseline(CpuModelInfo
*infoa
,
337 CpuModelBaselineInfo
*baseline_info
;
338 S390CPUModel modela
, modelb
, model
;
343 /* convert both models to our internal representation */
344 cpu_model_from_info(&modela
, infoa
, "modela", &err
);
346 error_propagate(errp
, err
);
350 cpu_model_from_info(&modelb
, infob
, "modelb", &err
);
352 error_propagate(errp
, err
);
356 /* features both models support */
357 bitmap_and(model
.features
, modela
.features
, modelb
.features
, S390_FEAT_MAX
);
359 /* detect the maximum model not regarding features */
360 if (modela
.def
->gen
== modelb
.def
->gen
) {
361 if (modela
.def
->type
== modelb
.def
->type
) {
362 cpu_type
= modela
.def
->type
;
366 max_gen
= modela
.def
->gen
;
367 max_gen_ga
= MIN(modela
.def
->ec_ga
, modelb
.def
->ec_ga
);
368 } else if (modela
.def
->gen
> modelb
.def
->gen
) {
369 cpu_type
= modelb
.def
->type
;
370 max_gen
= modelb
.def
->gen
;
371 max_gen_ga
= modelb
.def
->ec_ga
;
373 cpu_type
= modela
.def
->type
;
374 max_gen
= modela
.def
->gen
;
375 max_gen_ga
= modela
.def
->ec_ga
;
378 model
.def
= s390_find_cpu_def(cpu_type
, max_gen
, max_gen_ga
,
381 /* models without early base features (esan3) are bad */
383 error_setg(errp
, "No compatible CPU model could be created as"
384 " important base features are disabled");
388 /* strip off features not part of the max model */
389 bitmap_and(model
.features
, model
.features
, model
.def
->full_feat
,
392 baseline_info
= g_new0(CpuModelBaselineInfo
, 1);
393 baseline_info
->model
= g_malloc0(sizeof(*baseline_info
->model
));
394 cpu_info_from_model(baseline_info
->model
, &model
, true);
395 return baseline_info
;
398 void apply_cpu_model(const S390CPUModel
*model
, Error
**errp
)
400 static S390CPUModel applied_model
;
404 * We have the same model for all VCPUs. KVM can only be configured before
405 * any VCPUs are defined in KVM.
408 if (model
&& memcmp(&applied_model
, model
, sizeof(S390CPUModel
))) {
409 error_setg(errp
, "Mixed CPU models are not supported on s390x.");
415 if (!kvm_s390_apply_cpu_model(model
, errp
)) {
422 applied_model
= *model
;