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 "sysemu/tcg.h"
19 #include "qapi/error.h"
20 #include "qapi/visitor.h"
21 #include "qapi/qmp/qerror.h"
22 #include "qapi/qobject-input-visitor.h"
23 #include "qapi/qmp/qdict.h"
24 #include "qapi/qapi-commands-machine-target.h"
26 static void list_add_feat(const char *name
, void *opaque
);
28 static void check_unavailable_features(const S390CPUModel
*max_model
,
29 const S390CPUModel
*model
,
30 strList
**unavailable
)
32 S390FeatBitmap missing
;
34 /* check general model compatibility */
35 if (max_model
->def
->gen
< model
->def
->gen
||
36 (max_model
->def
->gen
== model
->def
->gen
&&
37 max_model
->def
->ec_ga
< model
->def
->ec_ga
)) {
38 list_add_feat("type", unavailable
);
41 /* detect missing features if any to properly report them */
42 bitmap_andnot(missing
, model
->features
, max_model
->features
,
44 if (!bitmap_empty(missing
, S390_FEAT_MAX
)) {
45 s390_feat_bitmap_to_ascii(missing
, unavailable
, list_add_feat
);
49 struct CpuDefinitionInfoListData
{
50 CpuDefinitionInfoList
*list
;
54 static void create_cpu_model_list(ObjectClass
*klass
, void *opaque
)
56 struct CpuDefinitionInfoListData
*cpu_list_data
= opaque
;
57 CpuDefinitionInfoList
**cpu_list
= &cpu_list_data
->list
;
58 CpuDefinitionInfo
*info
;
59 char *name
= g_strdup(object_class_get_name(klass
));
60 S390CPUClass
*scc
= S390_CPU_CLASS(klass
);
62 /* strip off the -s390x-cpu */
63 g_strrstr(name
, "-" TYPE_S390_CPU
)[0] = 0;
64 info
= g_new0(CpuDefinitionInfo
, 1);
66 info
->has_migration_safe
= true;
67 info
->migration_safe
= scc
->is_migration_safe
;
68 info
->q_static
= scc
->is_static
;
69 info
->q_typename
= g_strdup(object_class_get_name(klass
));
70 /* check for unavailable features */
71 if (cpu_list_data
->model
) {
74 obj
= object_new_with_class(klass
);
77 info
->has_unavailable_features
= true;
78 check_unavailable_features(cpu_list_data
->model
, sc
->model
,
79 &info
->unavailable_features
);
84 QAPI_LIST_PREPEND(*cpu_list
, info
);
87 CpuDefinitionInfoList
*qmp_query_cpu_definitions(Error
**errp
)
89 struct CpuDefinitionInfoListData list_data
= {
93 list_data
.model
= get_max_cpu_model(NULL
);
95 object_class_foreach(create_cpu_model_list
, TYPE_S390_CPU
, false,
98 return list_data
.list
;
101 static void cpu_model_from_info(S390CPUModel
*model
, const CpuModelInfo
*info
,
105 const QDict
*qdict
= NULL
;
113 qdict
= qobject_to(QDict
, info
->props
);
115 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, "props", "dict");
120 oc
= cpu_class_by_name(TYPE_S390_CPU
, info
->name
);
122 error_setg(errp
, "The CPU definition \'%s\' is unknown.", info
->name
);
125 if (S390_CPU_CLASS(oc
)->kvm_required
&& !kvm_enabled()) {
126 error_setg(errp
, "The CPU definition '%s' requires KVM", info
->name
);
129 obj
= object_new_with_class(oc
);
133 error_setg(errp
, "Details about the host CPU model are not available, "
134 "it cannot be used.");
140 visitor
= qobject_input_visitor_new(info
->props
);
141 if (!visit_start_struct(visitor
, NULL
, NULL
, 0, errp
)) {
146 for (e
= qdict_first(qdict
); e
; e
= qdict_next(qdict
, e
)) {
147 if (!object_property_set(obj
, e
->key
, visitor
, &err
)) {
152 visit_check_struct(visitor
, &err
);
154 visit_end_struct(visitor
, NULL
);
157 error_propagate(errp
, err
);
163 /* copy the model and throw the cpu away */
164 memcpy(model
, cpu
->model
, sizeof(*model
));
168 static void qdict_add_disabled_feat(const char *name
, void *opaque
)
170 qdict_put_bool(opaque
, name
, false);
173 static void qdict_add_enabled_feat(const char *name
, void *opaque
)
175 qdict_put_bool(opaque
, name
, true);
178 /* convert S390CPUDef into a static CpuModelInfo */
179 static void cpu_info_from_model(CpuModelInfo
*info
, const S390CPUModel
*model
,
182 QDict
*qdict
= qdict_new();
183 S390FeatBitmap bitmap
;
185 /* always fallback to the static base model */
186 info
->name
= g_strdup_printf("%s-base", model
->def
->name
);
189 /* features deleted from the base feature set */
190 bitmap_andnot(bitmap
, model
->def
->base_feat
, model
->features
,
192 if (!bitmap_empty(bitmap
, S390_FEAT_MAX
)) {
193 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_disabled_feat
);
196 /* features added to the base feature set */
197 bitmap_andnot(bitmap
, model
->features
, model
->def
->base_feat
,
199 if (!bitmap_empty(bitmap
, S390_FEAT_MAX
)) {
200 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_enabled_feat
);
203 /* expand all features */
204 s390_feat_bitmap_to_ascii(model
->features
, qdict
,
205 qdict_add_enabled_feat
);
206 bitmap_complement(bitmap
, model
->features
, S390_FEAT_MAX
);
207 s390_feat_bitmap_to_ascii(bitmap
, qdict
, qdict_add_disabled_feat
);
210 if (!qdict_size(qdict
)) {
211 qobject_unref(qdict
);
213 info
->props
= QOBJECT(qdict
);
214 info
->has_props
= true;
218 CpuModelExpansionInfo
*qmp_query_cpu_model_expansion(CpuModelExpansionType type
,
223 CpuModelExpansionInfo
*expansion_info
= NULL
;
224 S390CPUModel s390_model
;
225 bool delta_changes
= false;
227 /* convert it to our internal representation */
228 cpu_model_from_info(&s390_model
, model
, &err
);
230 error_propagate(errp
, err
);
234 if (type
== CPU_MODEL_EXPANSION_TYPE_STATIC
) {
235 delta_changes
= true;
236 } else if (type
!= CPU_MODEL_EXPANSION_TYPE_FULL
) {
237 error_setg(errp
, "The requested expansion type is not supported.");
241 /* convert it back to a static representation */
242 expansion_info
= g_new0(CpuModelExpansionInfo
, 1);
243 expansion_info
->model
= g_malloc0(sizeof(*expansion_info
->model
));
244 cpu_info_from_model(expansion_info
->model
, &s390_model
, delta_changes
);
245 return expansion_info
;
248 static void list_add_feat(const char *name
, void *opaque
)
250 strList
**last
= (strList
**) opaque
;
252 QAPI_LIST_PREPEND(*last
, g_strdup(name
));
255 CpuModelCompareInfo
*qmp_query_cpu_model_comparison(CpuModelInfo
*infoa
,
260 CpuModelCompareResult feat_result
, gen_result
;
261 CpuModelCompareInfo
*compare_info
;
262 S390FeatBitmap missing
, added
;
263 S390CPUModel modela
, modelb
;
265 /* convert both models to our internal representation */
266 cpu_model_from_info(&modela
, infoa
, &err
);
268 error_propagate(errp
, err
);
271 cpu_model_from_info(&modelb
, infob
, &err
);
273 error_propagate(errp
, err
);
276 compare_info
= g_new0(CpuModelCompareInfo
, 1);
278 /* check the cpu generation and ga level */
279 if (modela
.def
->gen
== modelb
.def
->gen
) {
280 if (modela
.def
->ec_ga
== modelb
.def
->ec_ga
) {
281 /* ec and corresponding bc are identical */
282 gen_result
= CPU_MODEL_COMPARE_RESULT_IDENTICAL
;
283 } else if (modela
.def
->ec_ga
< modelb
.def
->ec_ga
) {
284 gen_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
286 gen_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
288 } else if (modela
.def
->gen
< modelb
.def
->gen
) {
289 gen_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
291 gen_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
293 if (gen_result
!= CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
294 /* both models cannot be made identical */
295 list_add_feat("type", &compare_info
->responsible_properties
);
298 /* check the feature set */
299 if (bitmap_equal(modela
.features
, modelb
.features
, S390_FEAT_MAX
)) {
300 feat_result
= CPU_MODEL_COMPARE_RESULT_IDENTICAL
;
302 bitmap_andnot(missing
, modela
.features
, modelb
.features
, S390_FEAT_MAX
);
303 s390_feat_bitmap_to_ascii(missing
,
304 &compare_info
->responsible_properties
,
306 bitmap_andnot(added
, modelb
.features
, modela
.features
, S390_FEAT_MAX
);
307 s390_feat_bitmap_to_ascii(added
, &compare_info
->responsible_properties
,
309 if (bitmap_empty(missing
, S390_FEAT_MAX
)) {
310 feat_result
= CPU_MODEL_COMPARE_RESULT_SUBSET
;
311 } else if (bitmap_empty(added
, S390_FEAT_MAX
)) {
312 feat_result
= CPU_MODEL_COMPARE_RESULT_SUPERSET
;
314 feat_result
= CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE
;
318 /* combine the results */
319 if (gen_result
== feat_result
) {
320 compare_info
->result
= gen_result
;
321 } else if (feat_result
== CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
322 compare_info
->result
= gen_result
;
323 } else if (gen_result
== CPU_MODEL_COMPARE_RESULT_IDENTICAL
) {
324 compare_info
->result
= feat_result
;
326 compare_info
->result
= CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE
;
331 CpuModelBaselineInfo
*qmp_query_cpu_model_baseline(CpuModelInfo
*infoa
,
336 CpuModelBaselineInfo
*baseline_info
;
337 S390CPUModel modela
, modelb
, model
;
342 /* convert both models to our internal representation */
343 cpu_model_from_info(&modela
, infoa
, &err
);
345 error_propagate(errp
, err
);
349 cpu_model_from_info(&modelb
, infob
, &err
);
351 error_propagate(errp
, err
);
355 /* features both models support */
356 bitmap_and(model
.features
, modela
.features
, modelb
.features
, S390_FEAT_MAX
);
358 /* detect the maximum model not regarding features */
359 if (modela
.def
->gen
== modelb
.def
->gen
) {
360 if (modela
.def
->type
== modelb
.def
->type
) {
361 cpu_type
= modela
.def
->type
;
365 max_gen
= modela
.def
->gen
;
366 max_gen_ga
= MIN(modela
.def
->ec_ga
, modelb
.def
->ec_ga
);
367 } else if (modela
.def
->gen
> modelb
.def
->gen
) {
368 cpu_type
= modelb
.def
->type
;
369 max_gen
= modelb
.def
->gen
;
370 max_gen_ga
= modelb
.def
->ec_ga
;
372 cpu_type
= modela
.def
->type
;
373 max_gen
= modela
.def
->gen
;
374 max_gen_ga
= modela
.def
->ec_ga
;
377 model
.def
= s390_find_cpu_def(cpu_type
, max_gen
, max_gen_ga
,
380 /* models without early base features (esan3) are bad */
382 error_setg(errp
, "No compatible CPU model could be created as"
383 " important base features are disabled");
387 /* strip off features not part of the max model */
388 bitmap_and(model
.features
, model
.features
, model
.def
->full_feat
,
391 baseline_info
= g_new0(CpuModelBaselineInfo
, 1);
392 baseline_info
->model
= g_malloc0(sizeof(*baseline_info
->model
));
393 cpu_info_from_model(baseline_info
->model
, &model
, true);
394 return baseline_info
;
397 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 kvm_s390_apply_cpu_model(model
, &err
);
417 error_propagate(errp
, err
);
424 applied_model
= *model
;