]>
Commit | Line | Data |
---|---|---|
41868f84 DH |
1 | /* |
2 | * CPU models for s390x | |
3 | * | |
4 | * Copyright 2016 IBM Corp. | |
5 | * | |
6 | * Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com> | |
7 | * | |
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 | |
10 | * directory. | |
11 | */ | |
12 | ||
13 | #include "qemu/osdep.h" | |
14 | #include "cpu.h" | |
b6b47223 | 15 | #include "s390x-internal.h" |
67043607 | 16 | #include "kvm/kvm_s390x.h" |
f16bbb9b | 17 | #include "sysemu/kvm.h" |
14a48c1d | 18 | #include "sysemu/tcg.h" |
41868f84 | 19 | #include "qapi/error.h" |
cc37d98b | 20 | #include "qemu/error-report.h" |
0754f604 | 21 | #include "qapi/visitor.h" |
0b8fa32f | 22 | #include "qemu/module.h" |
15e09912 | 23 | #include "qemu/hw-version.h" |
0442428a | 24 | #include "qemu/qemu-print.h" |
41868f84 | 25 | #ifndef CONFIG_USER_ONLY |
0110253e | 26 | #include "sysemu/sysemu.h" |
f5f9c6ea | 27 | #include "target/s390x/kvm/pv.h" |
3ea7e312 | 28 | #endif |
41868f84 | 29 | |
6c064de1 DH |
30 | #define CPUDEF_INIT(_type, _gen, _ec_ga, _mha_pow, _hmfai, _name, _desc) \ |
31 | { \ | |
32 | .name = _name, \ | |
33 | .type = _type, \ | |
34 | .gen = _gen, \ | |
35 | .ec_ga = _ec_ga, \ | |
36 | .mha_pow = _mha_pow, \ | |
37 | .hmfai = _hmfai, \ | |
38 | .desc = _desc, \ | |
39 | .base_init = { S390_FEAT_LIST_GEN ## _gen ## _GA ## _ec_ga ## _BASE }, \ | |
40 | .default_init = { S390_FEAT_LIST_GEN ## _gen ## _GA ## _ec_ga ## _DEFAULT }, \ | |
41 | .full_init = { S390_FEAT_LIST_GEN ## _gen ## _GA ## _ec_ga ## _FULL }, \ | |
42 | } | |
43 | ||
44 | /* | |
c657e84f CB |
45 | * CPU definition list in order of release. Up to generation 14 base features |
46 | * of a following release have been a superset of the previous release. With | |
47 | * generation 15 one base feature and one optional feature have been deprecated. | |
6c064de1 DH |
48 | */ |
49 | static S390CPUDef s390_cpu_defs[] = { | |
50 | CPUDEF_INIT(0x2064, 7, 1, 38, 0x00000000U, "z900", "IBM zSeries 900 GA1"), | |
51 | CPUDEF_INIT(0x2064, 7, 2, 38, 0x00000000U, "z900.2", "IBM zSeries 900 GA2"), | |
52 | CPUDEF_INIT(0x2064, 7, 3, 38, 0x00000000U, "z900.3", "IBM zSeries 900 GA3"), | |
53 | CPUDEF_INIT(0x2066, 7, 3, 38, 0x00000000U, "z800", "IBM zSeries 800 GA1"), | |
54 | CPUDEF_INIT(0x2084, 8, 1, 38, 0x00000000U, "z990", "IBM zSeries 990 GA1"), | |
55 | CPUDEF_INIT(0x2084, 8, 2, 38, 0x00000000U, "z990.2", "IBM zSeries 990 GA2"), | |
56 | CPUDEF_INIT(0x2084, 8, 3, 38, 0x00000000U, "z990.3", "IBM zSeries 990 GA3"), | |
57 | CPUDEF_INIT(0x2086, 8, 3, 38, 0x00000000U, "z890", "IBM zSeries 880 GA1"), | |
58 | CPUDEF_INIT(0x2084, 8, 4, 38, 0x00000000U, "z990.4", "IBM zSeries 990 GA4"), | |
59 | CPUDEF_INIT(0x2086, 8, 4, 38, 0x00000000U, "z890.2", "IBM zSeries 880 GA2"), | |
60 | CPUDEF_INIT(0x2084, 8, 5, 38, 0x00000000U, "z990.5", "IBM zSeries 990 GA5"), | |
61 | CPUDEF_INIT(0x2086, 8, 5, 38, 0x00000000U, "z890.3", "IBM zSeries 880 GA3"), | |
62 | CPUDEF_INIT(0x2094, 9, 1, 40, 0x00000000U, "z9EC", "IBM System z9 EC GA1"), | |
63 | CPUDEF_INIT(0x2094, 9, 2, 40, 0x00000000U, "z9EC.2", "IBM System z9 EC GA2"), | |
64 | CPUDEF_INIT(0x2096, 9, 2, 40, 0x00000000U, "z9BC", "IBM System z9 BC GA1"), | |
65 | CPUDEF_INIT(0x2094, 9, 3, 40, 0x00000000U, "z9EC.3", "IBM System z9 EC GA3"), | |
66 | CPUDEF_INIT(0x2096, 9, 3, 40, 0x00000000U, "z9BC.2", "IBM System z9 BC GA2"), | |
67 | CPUDEF_INIT(0x2097, 10, 1, 43, 0x00000000U, "z10EC", "IBM System z10 EC GA1"), | |
68 | CPUDEF_INIT(0x2097, 10, 2, 43, 0x00000000U, "z10EC.2", "IBM System z10 EC GA2"), | |
69 | CPUDEF_INIT(0x2098, 10, 2, 43, 0x00000000U, "z10BC", "IBM System z10 BC GA1"), | |
70 | CPUDEF_INIT(0x2097, 10, 3, 43, 0x00000000U, "z10EC.3", "IBM System z10 EC GA3"), | |
71 | CPUDEF_INIT(0x2098, 10, 3, 43, 0x00000000U, "z10BC.2", "IBM System z10 BC GA2"), | |
72 | CPUDEF_INIT(0x2817, 11, 1, 44, 0x08000000U, "z196", "IBM zEnterprise 196 GA1"), | |
73 | CPUDEF_INIT(0x2817, 11, 2, 44, 0x08000000U, "z196.2", "IBM zEnterprise 196 GA2"), | |
74 | CPUDEF_INIT(0x2818, 11, 2, 44, 0x08000000U, "z114", "IBM zEnterprise 114 GA1"), | |
75 | CPUDEF_INIT(0x2827, 12, 1, 44, 0x08000000U, "zEC12", "IBM zEnterprise EC12 GA1"), | |
76 | CPUDEF_INIT(0x2827, 12, 2, 44, 0x08000000U, "zEC12.2", "IBM zEnterprise EC12 GA2"), | |
77 | CPUDEF_INIT(0x2828, 12, 2, 44, 0x08000000U, "zBC12", "IBM zEnterprise BC12 GA1"), | |
78 | CPUDEF_INIT(0x2964, 13, 1, 47, 0x08000000U, "z13", "IBM z13 GA1"), | |
79 | CPUDEF_INIT(0x2964, 13, 2, 47, 0x08000000U, "z13.2", "IBM z13 GA2"), | |
80 | CPUDEF_INIT(0x2965, 13, 2, 47, 0x08000000U, "z13s", "IBM z13s GA1"), | |
cc28a594 | 81 | CPUDEF_INIT(0x3906, 14, 1, 47, 0x08000000U, "z14", "IBM z14 GA1"), |
f2a7d157 | 82 | CPUDEF_INIT(0x3906, 14, 2, 47, 0x08000000U, "z14.2", "IBM z14 GA2"), |
23ad956b | 83 | CPUDEF_INIT(0x3907, 14, 1, 47, 0x08000000U, "z14ZR1", "IBM z14 Model ZR1 GA1"), |
d66a52b5 CH |
84 | CPUDEF_INIT(0x8561, 15, 1, 47, 0x08000000U, "gen15a", "IBM z15 T01 GA1"), |
85 | CPUDEF_INIT(0x8562, 15, 1, 47, 0x08000000U, "gen15b", "IBM z15 T02 GA1"), | |
fb4a0812 CB |
86 | CPUDEF_INIT(0x3931, 16, 1, 47, 0x08000000U, "gen16a", "IBM 3931 GA1"), |
87 | CPUDEF_INIT(0x3932, 16, 1, 47, 0x08000000U, "gen16b", "IBM 3932 GA1"), | |
6c064de1 DH |
88 | }; |
89 | ||
8a4eafb6 DM |
90 | #define QEMU_MAX_CPU_TYPE 0x8561 |
91 | #define QEMU_MAX_CPU_GEN 15 | |
92 | #define QEMU_MAX_CPU_EC_GA 1 | |
35b4df64 DH |
93 | static S390FeatBitmap qemu_max_cpu_feat; |
94 | ||
30e82de7 DH |
95 | /* features part of a base model but not relevant for finding a base model */ |
96 | S390FeatBitmap ignored_base_feat; | |
97 | ||
c9ad8a7a JH |
98 | void s390_cpudef_featoff(uint8_t gen, uint8_t ec_ga, S390Feat feat) |
99 | { | |
100 | const S390CPUDef *def; | |
101 | ||
102 | def = s390_find_cpu_def(0, gen, ec_ga, NULL); | |
103 | clear_bit(feat, (unsigned long *)&def->default_feat); | |
104 | } | |
105 | ||
106 | void s390_cpudef_featoff_greater(uint8_t gen, uint8_t ec_ga, S390Feat feat) | |
107 | { | |
108 | int i; | |
109 | ||
110 | for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { | |
111 | const S390CPUDef *def = &s390_cpu_defs[i]; | |
112 | ||
113 | if (def->gen < gen) { | |
114 | continue; | |
115 | } | |
116 | if (def->gen == gen && def->ec_ga < ec_ga) { | |
117 | continue; | |
118 | } | |
119 | ||
120 | clear_bit(feat, (unsigned long *)&def->default_feat); | |
121 | } | |
122 | } | |
123 | ||
84176c79 CW |
124 | void s390_cpudef_group_featoff_greater(uint8_t gen, uint8_t ec_ga, |
125 | S390FeatGroup group) | |
126 | { | |
127 | const S390FeatGroupDef *group_def = s390_feat_group_def(group); | |
128 | S390FeatBitmap group_def_off; | |
129 | int i; | |
130 | ||
131 | bitmap_complement(group_def_off, group_def->feat, S390_FEAT_MAX); | |
132 | ||
133 | for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { | |
134 | const S390CPUDef *cpu_def = &s390_cpu_defs[i]; | |
135 | ||
136 | if (cpu_def->gen < gen) { | |
137 | continue; | |
138 | } | |
139 | if (cpu_def->gen == gen && cpu_def->ec_ga < ec_ga) { | |
140 | continue; | |
141 | } | |
142 | ||
143 | bitmap_and((unsigned long *)&cpu_def->default_feat, | |
144 | cpu_def->default_feat, group_def_off, S390_FEAT_MAX); | |
145 | } | |
146 | } | |
147 | ||
a3669307 DH |
148 | uint32_t s390_get_hmfai(void) |
149 | { | |
150 | static S390CPU *cpu; | |
151 | ||
152 | if (!cpu) { | |
153 | cpu = S390_CPU(qemu_get_cpu(0)); | |
154 | } | |
155 | ||
156 | if (!cpu || !cpu->model) { | |
157 | return 0; | |
158 | } | |
159 | return cpu->model->def->hmfai; | |
160 | } | |
161 | ||
3fad3252 DH |
162 | uint8_t s390_get_mha_pow(void) |
163 | { | |
164 | static S390CPU *cpu; | |
165 | ||
166 | if (!cpu) { | |
167 | cpu = S390_CPU(qemu_get_cpu(0)); | |
168 | } | |
169 | ||
170 | if (!cpu || !cpu->model) { | |
171 | return 0; | |
172 | } | |
173 | return cpu->model->def->mha_pow; | |
174 | } | |
175 | ||
059be520 DH |
176 | uint32_t s390_get_ibc_val(void) |
177 | { | |
178 | uint16_t unblocked_ibc, lowest_ibc; | |
179 | static S390CPU *cpu; | |
180 | ||
181 | if (!cpu) { | |
182 | cpu = S390_CPU(qemu_get_cpu(0)); | |
183 | } | |
184 | ||
185 | if (!cpu || !cpu->model) { | |
186 | return 0; | |
187 | } | |
188 | unblocked_ibc = s390_ibc_from_cpu_model(cpu->model); | |
189 | lowest_ibc = cpu->model->lowest_ibc; | |
190 | /* the lowest_ibc always has to be <= unblocked_ibc */ | |
191 | if (!lowest_ibc || lowest_ibc > unblocked_ibc) { | |
192 | return 0; | |
193 | } | |
194 | return ((uint32_t) lowest_ibc << 16) | unblocked_ibc; | |
195 | } | |
196 | ||
4dd4200e DH |
197 | void s390_get_feat_block(S390FeatType type, uint8_t *data) |
198 | { | |
ad63e6d6 | 199 | S390CPU *cpu = S390_CPU(first_cpu); |
4dd4200e DH |
200 | |
201 | if (!cpu || !cpu->model) { | |
202 | return; | |
203 | } | |
204 | s390_fill_feat_block(cpu->model->features, type, data); | |
205 | } | |
206 | ||
7c72ac49 DH |
207 | bool s390_has_feat(S390Feat feat) |
208 | { | |
209 | static S390CPU *cpu; | |
210 | ||
211 | if (!cpu) { | |
212 | cpu = S390_CPU(qemu_get_cpu(0)); | |
213 | } | |
214 | ||
215 | if (!cpu || !cpu->model) { | |
216 | #ifdef CONFIG_KVM | |
217 | if (kvm_enabled()) { | |
218 | if (feat == S390_FEAT_VECTOR) { | |
219 | return kvm_check_extension(kvm_state, | |
220 | KVM_CAP_S390_VECTOR_REGISTERS); | |
221 | } | |
222 | if (feat == S390_FEAT_RUNTIME_INSTRUMENTATION) { | |
223 | return kvm_s390_get_ri(); | |
224 | } | |
c85d21c7 DH |
225 | if (feat == S390_FEAT_MSA_EXT_3) { |
226 | return true; | |
227 | } | |
7c72ac49 DH |
228 | } |
229 | #endif | |
8ad9087c CH |
230 | if (feat == S390_FEAT_ZPCI) { |
231 | return true; | |
232 | } | |
7c72ac49 DH |
233 | return 0; |
234 | } | |
10248418 | 235 | |
3ea7e312 | 236 | #ifndef CONFIG_USER_ONLY |
10248418 JF |
237 | if (s390_is_pv()) { |
238 | switch (feat) { | |
239 | case S390_FEAT_DIAG_318: | |
240 | case S390_FEAT_HPMA2: | |
241 | case S390_FEAT_SIE_F2: | |
242 | case S390_FEAT_SIE_SKEY: | |
243 | case S390_FEAT_SIE_GPERE: | |
244 | case S390_FEAT_SIE_SIIF: | |
245 | case S390_FEAT_SIE_SIGPIF: | |
246 | case S390_FEAT_SIE_IB: | |
247 | case S390_FEAT_SIE_CEI: | |
248 | case S390_FEAT_SIE_KSS: | |
249 | case S390_FEAT_SIE_GSLS: | |
250 | case S390_FEAT_SIE_64BSCAO: | |
251 | case S390_FEAT_SIE_CMMA: | |
252 | case S390_FEAT_SIE_PFMFI: | |
253 | case S390_FEAT_SIE_IBS: | |
f530b9e7 | 254 | case S390_FEAT_CONFIGURATION_TOPOLOGY: |
10248418 JF |
255 | return false; |
256 | break; | |
257 | default: | |
258 | break; | |
259 | } | |
3ded270a | 260 | } |
3ea7e312 | 261 | #endif |
7c72ac49 DH |
262 | return test_bit(feat, cpu->model->features); |
263 | } | |
264 | ||
3b84c25c DH |
265 | uint8_t s390_get_gen_for_cpu_type(uint16_t type) |
266 | { | |
267 | int i; | |
268 | ||
269 | for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { | |
270 | if (s390_cpu_defs[i].type == type) { | |
271 | return s390_cpu_defs[i].gen; | |
272 | } | |
273 | } | |
274 | return 0; | |
275 | } | |
276 | ||
277 | const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, | |
278 | S390FeatBitmap features) | |
279 | { | |
280 | const S390CPUDef *last_compatible = NULL; | |
fbe8202e | 281 | const S390CPUDef *matching_cpu_type = NULL; |
3b84c25c DH |
282 | int i; |
283 | ||
284 | if (!gen) { | |
285 | ec_ga = 0; | |
286 | } | |
287 | if (!gen && type) { | |
288 | gen = s390_get_gen_for_cpu_type(type); | |
289 | } | |
290 | ||
291 | for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { | |
292 | const S390CPUDef *def = &s390_cpu_defs[i]; | |
293 | S390FeatBitmap missing; | |
294 | ||
295 | /* don't even try newer generations if we know the generation */ | |
296 | if (gen) { | |
297 | if (def->gen > gen) { | |
298 | break; | |
299 | } else if (def->gen == gen && ec_ga && def->ec_ga > ec_ga) { | |
300 | break; | |
301 | } | |
302 | } | |
303 | ||
304 | if (features) { | |
305 | /* see if the model satisfies the minimum features */ | |
306 | bitmap_andnot(missing, def->base_feat, features, S390_FEAT_MAX); | |
30e82de7 DH |
307 | /* |
308 | * Ignore certain features that are in the base model, but not | |
309 | * relevant for the search (esp. MSA subfunctions). | |
310 | */ | |
311 | bitmap_andnot(missing, missing, ignored_base_feat, S390_FEAT_MAX); | |
3b84c25c DH |
312 | if (!bitmap_empty(missing, S390_FEAT_MAX)) { |
313 | break; | |
314 | } | |
315 | } | |
316 | ||
317 | /* stop the search if we found the exact model */ | |
318 | if (def->type == type && def->ec_ga == ec_ga) { | |
319 | return def; | |
320 | } | |
fbe8202e DH |
321 | /* remember if we've at least seen one with the same cpu type */ |
322 | if (def->type == type) { | |
323 | matching_cpu_type = def; | |
324 | } | |
3b84c25c DH |
325 | last_compatible = def; |
326 | } | |
fbe8202e DH |
327 | /* prefer the model with the same cpu type, esp. don't take the BC for EC */ |
328 | if (matching_cpu_type) { | |
329 | return matching_cpu_type; | |
330 | } | |
3b84c25c DH |
331 | return last_compatible; |
332 | } | |
333 | ||
99aa6bf2 | 334 | static void s390_print_cpu_model_list_entry(gpointer data, gpointer user_data) |
41868f84 | 335 | { |
99aa6bf2 | 336 | const S390CPUClass *scc = S390_CPU_CLASS((ObjectClass *)data); |
738cdc2f | 337 | CPUClass *cc = CPU_CLASS(scc); |
99aa6bf2 | 338 | char *name = g_strdup(object_class_get_name((ObjectClass *)data)); |
738cdc2f | 339 | g_autoptr(GString) details = g_string_new(""); |
41868f84 DH |
340 | |
341 | if (scc->is_static) { | |
738cdc2f DB |
342 | g_string_append(details, "static, "); |
343 | } | |
344 | if (scc->is_migration_safe) { | |
345 | g_string_append(details, "migration-safe, "); | |
346 | } | |
347 | if (cc->deprecation_note) { | |
348 | g_string_append(details, "deprecated, "); | |
349 | } | |
350 | if (details->len) { | |
351 | /* cull trailing ', ' */ | |
352 | g_string_truncate(details, details->len - 2); | |
41868f84 DH |
353 | } |
354 | ||
e555cbe7 | 355 | /* strip off the -s390x-cpu */ |
41868f84 | 356 | g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0; |
738cdc2f | 357 | if (details->len) { |
7febce36 | 358 | qemu_printf(" %-15s %-35s (%s)\n", name, scc->desc, details->str); |
738cdc2f | 359 | } else { |
7febce36 | 360 | qemu_printf(" %-15s %-35s\n", name, scc->desc); |
738cdc2f | 361 | } |
41868f84 DH |
362 | g_free(name); |
363 | } | |
364 | ||
99aa6bf2 DH |
365 | static gint s390_cpu_list_compare(gconstpointer a, gconstpointer b) |
366 | { | |
367 | const S390CPUClass *cc_a = S390_CPU_CLASS((ObjectClass *)a); | |
368 | const S390CPUClass *cc_b = S390_CPU_CLASS((ObjectClass *)b); | |
369 | const char *name_a = object_class_get_name((ObjectClass *)a); | |
370 | const char *name_b = object_class_get_name((ObjectClass *)b); | |
371 | ||
c6117788 DH |
372 | /* |
373 | * Move qemu, host and max to the top of the list, qemu first, host second, | |
374 | * max third. | |
375 | */ | |
99aa6bf2 DH |
376 | if (name_a[0] == 'q') { |
377 | return -1; | |
378 | } else if (name_b[0] == 'q') { | |
379 | return 1; | |
380 | } else if (name_a[0] == 'h') { | |
381 | return -1; | |
382 | } else if (name_b[0] == 'h') { | |
383 | return 1; | |
c6117788 DH |
384 | } else if (name_a[0] == 'm') { |
385 | return -1; | |
386 | } else if (name_b[0] == 'm') { | |
387 | return 1; | |
99aa6bf2 DH |
388 | } |
389 | ||
390 | /* keep the same order we have in our table (sorted by release date) */ | |
391 | if (cc_a->cpu_def != cc_b->cpu_def) { | |
392 | return cc_a->cpu_def - cc_b->cpu_def; | |
393 | } | |
394 | ||
395 | /* exact same definition - list base model first */ | |
396 | return cc_a->is_static ? -1 : 1; | |
397 | } | |
398 | ||
0442428a | 399 | void s390_cpu_list(void) |
41868f84 | 400 | { |
0754f604 DH |
401 | S390FeatGroup group; |
402 | S390Feat feat; | |
99aa6bf2 | 403 | GSList *list; |
41868f84 | 404 | |
7febce36 | 405 | qemu_printf("Available CPUs:\n"); |
99aa6bf2 DH |
406 | list = object_class_get_list(TYPE_S390_CPU, false); |
407 | list = g_slist_sort(list, s390_cpu_list_compare); | |
0442428a | 408 | g_slist_foreach(list, s390_print_cpu_model_list_entry, NULL); |
99aa6bf2 | 409 | g_slist_free(list); |
0754f604 | 410 | |
0442428a | 411 | qemu_printf("\nRecognized feature flags:\n"); |
0754f604 DH |
412 | for (feat = 0; feat < S390_FEAT_MAX; feat++) { |
413 | const S390FeatDef *def = s390_feat_def(feat); | |
414 | ||
7febce36 | 415 | qemu_printf(" %-20s %s\n", def->name, def->desc); |
0754f604 DH |
416 | } |
417 | ||
0442428a | 418 | qemu_printf("\nRecognized feature groups:\n"); |
0754f604 DH |
419 | for (group = 0; group < S390_FEAT_GROUP_MAX; group++) { |
420 | const S390FeatGroupDef *def = s390_feat_group_def(group); | |
421 | ||
7febce36 | 422 | qemu_printf(" %-20s %s\n", def->name, def->desc); |
0754f604 | 423 | } |
41868f84 DH |
424 | } |
425 | ||
80560137 DH |
426 | static void check_consistency(const S390CPUModel *model) |
427 | { | |
428 | static int dep[][2] = { | |
429 | { S390_FEAT_IPTE_RANGE, S390_FEAT_DAT_ENH }, | |
430 | { S390_FEAT_IDTE_SEGMENT, S390_FEAT_DAT_ENH }, | |
431 | { S390_FEAT_IDTE_REGION, S390_FEAT_DAT_ENH }, | |
432 | { S390_FEAT_IDTE_REGION, S390_FEAT_IDTE_SEGMENT }, | |
433 | { S390_FEAT_LOCAL_TLB_CLEARING, S390_FEAT_DAT_ENH}, | |
434 | { S390_FEAT_LONG_DISPLACEMENT_FAST, S390_FEAT_LONG_DISPLACEMENT }, | |
435 | { S390_FEAT_DFP_FAST, S390_FEAT_DFP }, | |
436 | { S390_FEAT_TRANSACTIONAL_EXE, S390_FEAT_STFLE_49 }, | |
437 | { S390_FEAT_EDAT_2, S390_FEAT_EDAT}, | |
438 | { S390_FEAT_MSA_EXT_5, S390_FEAT_KIMD_SHA_512 }, | |
439 | { S390_FEAT_MSA_EXT_5, S390_FEAT_KLMD_SHA_512 }, | |
440 | { S390_FEAT_MSA_EXT_4, S390_FEAT_MSA_EXT_3 }, | |
441 | { S390_FEAT_SIE_CMMA, S390_FEAT_CMM }, | |
442 | { S390_FEAT_SIE_CMMA, S390_FEAT_SIE_GSLS }, | |
443 | { S390_FEAT_SIE_PFMFI, S390_FEAT_EDAT }, | |
6da5c593 | 444 | { S390_FEAT_MSA_EXT_8, S390_FEAT_MSA_EXT_3 }, |
5dacbe23 CB |
445 | { S390_FEAT_MSA_EXT_9, S390_FEAT_MSA_EXT_3 }, |
446 | { S390_FEAT_MSA_EXT_9, S390_FEAT_MSA_EXT_4 }, | |
6da5c593 JH |
447 | { S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_TOD_CLOCK_STEERING }, |
448 | { S390_FEAT_VECTOR_PACKED_DECIMAL, S390_FEAT_VECTOR }, | |
fb4a0812 CB |
449 | { S390_FEAT_VECTOR_PACKED_DECIMAL_ENH, S390_FEAT_VECTOR_PACKED_DECIMAL }, |
450 | { S390_FEAT_VECTOR_PACKED_DECIMAL_ENH2, S390_FEAT_VECTOR_PACKED_DECIMAL_ENH }, | |
6da5c593 JH |
451 | { S390_FEAT_VECTOR_ENH, S390_FEAT_VECTOR }, |
452 | { S390_FEAT_INSTRUCTION_EXEC_PROT, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2 }, | |
453 | { S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2, S390_FEAT_ESOP }, | |
454 | { S390_FEAT_CMM_NT, S390_FEAT_CMM }, | |
455 | { S390_FEAT_GUARDED_STORAGE, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2 }, | |
456 | { S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_STORE_CLOCK_FAST }, | |
457 | { S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_TOD_CLOCK_STEERING }, | |
458 | { S390_FEAT_SEMAPHORE_ASSIST, S390_FEAT_STFLE_49 }, | |
459 | { S390_FEAT_KIMD_SHA3_224, S390_FEAT_MSA }, | |
460 | { S390_FEAT_KIMD_SHA3_256, S390_FEAT_MSA }, | |
461 | { S390_FEAT_KIMD_SHA3_384, S390_FEAT_MSA }, | |
462 | { S390_FEAT_KIMD_SHA3_512, S390_FEAT_MSA }, | |
463 | { S390_FEAT_KIMD_SHAKE_128, S390_FEAT_MSA }, | |
464 | { S390_FEAT_KIMD_SHAKE_256, S390_FEAT_MSA }, | |
465 | { S390_FEAT_KLMD_SHA3_224, S390_FEAT_MSA }, | |
466 | { S390_FEAT_KLMD_SHA3_256, S390_FEAT_MSA }, | |
467 | { S390_FEAT_KLMD_SHA3_384, S390_FEAT_MSA }, | |
468 | { S390_FEAT_KLMD_SHA3_512, S390_FEAT_MSA }, | |
469 | { S390_FEAT_KLMD_SHAKE_128, S390_FEAT_MSA }, | |
470 | { S390_FEAT_KLMD_SHAKE_256, S390_FEAT_MSA }, | |
471 | { S390_FEAT_PRNO_TRNG_QRTCR, S390_FEAT_MSA_EXT_5 }, | |
472 | { S390_FEAT_PRNO_TRNG, S390_FEAT_MSA_EXT_5 }, | |
c1b364ff | 473 | { S390_FEAT_SIE_KSS, S390_FEAT_SIE_F2 }, |
c5cd17af TK |
474 | { S390_FEAT_AP_QUERY_CONFIG_INFO, S390_FEAT_AP }, |
475 | { S390_FEAT_AP_FACILITIES_TEST, S390_FEAT_AP }, | |
ddf5d18a CW |
476 | { S390_FEAT_PTFF_QSIE, S390_FEAT_MULTIPLE_EPOCH }, |
477 | { S390_FEAT_PTFF_QTOUE, S390_FEAT_MULTIPLE_EPOCH }, | |
478 | { S390_FEAT_PTFF_STOE, S390_FEAT_MULTIPLE_EPOCH }, | |
479 | { S390_FEAT_PTFF_STOUE, S390_FEAT_MULTIPLE_EPOCH }, | |
9ef2d19e | 480 | { S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL, S390_FEAT_AP }, |
fabdada9 | 481 | { S390_FEAT_DIAG_318, S390_FEAT_EXTENDED_LENGTH_SCCB }, |
fb4a0812 CB |
482 | { S390_FEAT_NNPA, S390_FEAT_VECTOR }, |
483 | { S390_FEAT_RDP, S390_FEAT_LOCAL_TLB_CLEARING }, | |
5ac95151 SE |
484 | { S390_FEAT_UV_FEAT_AP, S390_FEAT_AP }, |
485 | { S390_FEAT_UV_FEAT_AP_INTR, S390_FEAT_UV_FEAT_AP }, | |
80560137 DH |
486 | }; |
487 | int i; | |
488 | ||
489 | for (i = 0; i < ARRAY_SIZE(dep); i++) { | |
490 | if (test_bit(dep[i][0], model->features) && | |
491 | !test_bit(dep[i][1], model->features)) { | |
3dc6f869 AF |
492 | warn_report("\'%s\' requires \'%s\'.", |
493 | s390_feat_def(dep[i][0])->name, | |
494 | s390_feat_def(dep[i][1])->name); | |
80560137 DH |
495 | } |
496 | } | |
497 | } | |
498 | ||
499 | static void error_prepend_missing_feat(const char *name, void *opaque) | |
500 | { | |
501 | error_prepend((Error **) opaque, "%s ", name); | |
502 | } | |
503 | ||
ff7c98a9 CF |
504 | static void check_compat_model_failed(Error **errp, |
505 | const S390CPUModel *max_model, | |
506 | const char *msg) | |
507 | { | |
508 | error_setg(errp, "%s. Maximum supported model in the current configuration: \'%s\'", | |
509 | msg, max_model->def->name); | |
510 | error_append_hint(errp, "Consider a different accelerator, try \"-accel help\"\n"); | |
511 | return; | |
512 | } | |
513 | ||
7c0c099a | 514 | static bool check_compatibility(const S390CPUModel *max_model, |
80560137 DH |
515 | const S390CPUModel *model, Error **errp) |
516 | { | |
95e9053a | 517 | ERRP_GUARD(); |
80560137 DH |
518 | S390FeatBitmap missing; |
519 | ||
520 | if (model->def->gen > max_model->def->gen) { | |
ff7c98a9 | 521 | check_compat_model_failed(errp, max_model, "Selected CPU generation is too new"); |
7c0c099a | 522 | return false; |
80560137 DH |
523 | } else if (model->def->gen == max_model->def->gen && |
524 | model->def->ec_ga > max_model->def->ec_ga) { | |
ff7c98a9 | 525 | check_compat_model_failed(errp, max_model, "Selected CPU GA level is too new"); |
7c0c099a | 526 | return false; |
80560137 DH |
527 | } |
528 | ||
0110253e CB |
529 | #ifndef CONFIG_USER_ONLY |
530 | if (only_migratable && test_bit(S390_FEAT_UNPACK, model->features)) { | |
531 | error_setg(errp, "The unpack facility is not compatible with " | |
532 | "the --only-migratable option. You must remove either " | |
533 | "the 'unpack' facility or the --only-migratable option"); | |
7c0c099a | 534 | return false; |
0110253e CB |
535 | } |
536 | #endif | |
537 | ||
80560137 DH |
538 | /* detect the missing features to properly report them */ |
539 | bitmap_andnot(missing, model->features, max_model->features, S390_FEAT_MAX); | |
540 | if (bitmap_empty(missing, S390_FEAT_MAX)) { | |
7c0c099a | 541 | return true; |
80560137 DH |
542 | } |
543 | ||
544 | error_setg(errp, " "); | |
545 | s390_feat_bitmap_to_ascii(missing, errp, error_prepend_missing_feat); | |
546 | error_prepend(errp, "Some features requested in the CPU model are not " | |
ff7c98a9 CF |
547 | "available in the current configuration: "); |
548 | error_append_hint(errp, | |
549 | "Consider a different accelerator, QEMU, or kernel version\n"); | |
7c0c099a | 550 | return false; |
80560137 DH |
551 | } |
552 | ||
7ab3eb42 | 553 | S390CPUModel *get_max_cpu_model(Error **errp) |
80560137 | 554 | { |
80560137 DH |
555 | static S390CPUModel max_model; |
556 | static bool cached; | |
557 | ||
558 | if (cached) { | |
559 | return &max_model; | |
560 | } | |
561 | ||
562 | if (kvm_enabled()) { | |
c6f1baf2 | 563 | if (!kvm_s390_get_host_cpu_model(&max_model, errp)) { |
47ab3b21 ZL |
564 | return NULL; |
565 | } | |
80560137 | 566 | } else { |
35b4df64 DH |
567 | max_model.def = s390_find_cpu_def(QEMU_MAX_CPU_TYPE, QEMU_MAX_CPU_GEN, |
568 | QEMU_MAX_CPU_EC_GA, NULL); | |
569 | bitmap_copy(max_model.features, qemu_max_cpu_feat, S390_FEAT_MAX); | |
80560137 | 570 | } |
d687ae1a MA |
571 | cached = true; |
572 | return &max_model; | |
80560137 DH |
573 | } |
574 | ||
41868f84 DH |
575 | void s390_realize_cpu_model(CPUState *cs, Error **errp) |
576 | { | |
95e9053a | 577 | ERRP_GUARD(); |
41868f84 | 578 | S390CPUClass *xcc = S390_CPU_GET_CLASS(cs); |
80560137 DH |
579 | S390CPU *cpu = S390_CPU(cs); |
580 | const S390CPUModel *max_model; | |
41868f84 DH |
581 | |
582 | if (xcc->kvm_required && !kvm_enabled()) { | |
583 | error_setg(errp, "CPU definition requires KVM"); | |
584 | return; | |
585 | } | |
80560137 DH |
586 | |
587 | if (!cpu->model) { | |
588 | /* no host model support -> perform compatibility stuff */ | |
589 | apply_cpu_model(NULL, errp); | |
590 | return; | |
591 | } | |
592 | ||
593 | max_model = get_max_cpu_model(errp); | |
d687ae1a | 594 | if (!max_model) { |
80560137 DH |
595 | error_prepend(errp, "CPU models are not available: "); |
596 | return; | |
597 | } | |
598 | ||
599 | /* copy over properties that can vary */ | |
600 | cpu->model->lowest_ibc = max_model->lowest_ibc; | |
601 | cpu->model->cpu_id = max_model->cpu_id; | |
64bc98f4 | 602 | cpu->model->cpu_id_format = max_model->cpu_id_format; |
80560137 DH |
603 | cpu->model->cpu_ver = max_model->cpu_ver; |
604 | ||
605 | check_consistency(cpu->model); | |
9c2df9c5 | 606 | if (!check_compatibility(max_model, cpu->model, errp)) { |
80560137 DH |
607 | return; |
608 | } | |
609 | ||
610 | apply_cpu_model(cpu->model, errp); | |
076d4d39 | 611 | |
1e70ba24 | 612 | #if !defined(CONFIG_USER_ONLY) |
076d4d39 DH |
613 | cpu->env.cpuid = s390_cpuid_from_cpu_model(cpu->model); |
614 | if (tcg_enabled()) { | |
71b11cbe IL |
615 | cpu->env.cpuid = deposit64(cpu->env.cpuid, CPU_PHYS_ADDR_SHIFT, |
616 | CPU_PHYS_ADDR_BITS, cpu->env.core_id); | |
076d4d39 | 617 | } |
1e70ba24 | 618 | #endif |
41868f84 DH |
619 | } |
620 | ||
0754f604 DH |
621 | static void get_feature(Object *obj, Visitor *v, const char *name, |
622 | void *opaque, Error **errp) | |
623 | { | |
074df27f | 624 | S390Feat feat = (S390Feat) (uintptr_t) opaque; |
0754f604 DH |
625 | S390CPU *cpu = S390_CPU(obj); |
626 | bool value; | |
627 | ||
628 | if (!cpu->model) { | |
629 | error_setg(errp, "Details about the host CPU model are not available, " | |
630 | "features cannot be queried."); | |
631 | return; | |
632 | } | |
633 | ||
634 | value = test_bit(feat, cpu->model->features); | |
635 | visit_type_bool(v, name, &value, errp); | |
636 | } | |
637 | ||
638 | static void set_feature(Object *obj, Visitor *v, const char *name, | |
639 | void *opaque, Error **errp) | |
640 | { | |
074df27f | 641 | S390Feat feat = (S390Feat) (uintptr_t) opaque; |
0754f604 DH |
642 | DeviceState *dev = DEVICE(obj); |
643 | S390CPU *cpu = S390_CPU(obj); | |
644 | bool value; | |
645 | ||
646 | if (dev->realized) { | |
647 | error_setg(errp, "Attempt to set property '%s' on '%s' after " | |
648 | "it was realized", name, object_get_typename(obj)); | |
649 | return; | |
650 | } else if (!cpu->model) { | |
651 | error_setg(errp, "Details about the host CPU model are not available, " | |
652 | "features cannot be changed."); | |
653 | return; | |
654 | } | |
655 | ||
668f62ec | 656 | if (!visit_type_bool(v, name, &value, errp)) { |
0754f604 DH |
657 | return; |
658 | } | |
659 | if (value) { | |
660 | if (!test_bit(feat, cpu->model->def->full_feat)) { | |
661 | error_setg(errp, "Feature '%s' is not available for CPU model '%s'," | |
662 | " it was introduced with later models.", | |
663 | name, cpu->model->def->name); | |
664 | return; | |
665 | } | |
666 | set_bit(feat, cpu->model->features); | |
667 | } else { | |
668 | clear_bit(feat, cpu->model->features); | |
669 | } | |
670 | } | |
671 | ||
672 | static void get_feature_group(Object *obj, Visitor *v, const char *name, | |
673 | void *opaque, Error **errp) | |
674 | { | |
074df27f | 675 | S390FeatGroup group = (S390FeatGroup) (uintptr_t) opaque; |
0754f604 DH |
676 | const S390FeatGroupDef *def = s390_feat_group_def(group); |
677 | S390CPU *cpu = S390_CPU(obj); | |
678 | S390FeatBitmap tmp; | |
679 | bool value; | |
680 | ||
681 | if (!cpu->model) { | |
682 | error_setg(errp, "Details about the host CPU model are not available, " | |
683 | "features cannot be queried."); | |
684 | return; | |
685 | } | |
686 | ||
687 | /* a group is enabled if all features are enabled */ | |
688 | bitmap_and(tmp, cpu->model->features, def->feat, S390_FEAT_MAX); | |
689 | value = bitmap_equal(tmp, def->feat, S390_FEAT_MAX); | |
690 | visit_type_bool(v, name, &value, errp); | |
691 | } | |
692 | ||
693 | static void set_feature_group(Object *obj, Visitor *v, const char *name, | |
694 | void *opaque, Error **errp) | |
695 | { | |
074df27f | 696 | S390FeatGroup group = (S390FeatGroup) (uintptr_t) opaque; |
0754f604 DH |
697 | const S390FeatGroupDef *def = s390_feat_group_def(group); |
698 | DeviceState *dev = DEVICE(obj); | |
699 | S390CPU *cpu = S390_CPU(obj); | |
700 | bool value; | |
701 | ||
702 | if (dev->realized) { | |
703 | error_setg(errp, "Attempt to set property '%s' on '%s' after " | |
704 | "it was realized", name, object_get_typename(obj)); | |
705 | return; | |
706 | } else if (!cpu->model) { | |
707 | error_setg(errp, "Details about the host CPU model are not available, " | |
708 | "features cannot be changed."); | |
709 | return; | |
710 | } | |
711 | ||
668f62ec | 712 | if (!visit_type_bool(v, name, &value, errp)) { |
0754f604 DH |
713 | return; |
714 | } | |
715 | if (value) { | |
716 | /* groups are added in one shot, so an intersect is sufficient */ | |
717 | if (!bitmap_intersects(def->feat, cpu->model->def->full_feat, | |
718 | S390_FEAT_MAX)) { | |
719 | error_setg(errp, "Group '%s' is not available for CPU model '%s'," | |
720 | " it was introduced with later models.", | |
721 | name, cpu->model->def->name); | |
722 | return; | |
723 | } | |
724 | bitmap_or(cpu->model->features, cpu->model->features, def->feat, | |
725 | S390_FEAT_MAX); | |
726 | } else { | |
727 | bitmap_andnot(cpu->model->features, cpu->model->features, def->feat, | |
728 | S390_FEAT_MAX); | |
729 | } | |
730 | } | |
731 | ||
6c064de1 DH |
732 | static void s390_cpu_model_initfn(Object *obj) |
733 | { | |
ad5afd07 DH |
734 | S390CPU *cpu = S390_CPU(obj); |
735 | S390CPUClass *xcc = S390_CPU_GET_CLASS(cpu); | |
736 | ||
737 | cpu->model = g_malloc0(sizeof(*cpu->model)); | |
738 | /* copy the model, so we can modify it */ | |
739 | cpu->model->def = xcc->cpu_def; | |
740 | if (xcc->is_static) { | |
741 | /* base model - features will never change */ | |
742 | bitmap_copy(cpu->model->features, cpu->model->def->base_feat, | |
743 | S390_FEAT_MAX); | |
744 | } else { | |
745 | /* latest model - features can change */ | |
746 | bitmap_copy(cpu->model->features, | |
747 | cpu->model->def->default_feat, S390_FEAT_MAX); | |
748 | } | |
6c064de1 DH |
749 | } |
750 | ||
35b4df64 DH |
751 | static S390CPUModel s390_qemu_cpu_model; |
752 | ||
753 | /* Set the qemu CPU model (on machine initialization). Must not be called | |
754 | * once CPUs have been created. | |
755 | */ | |
756 | void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga, | |
757 | const S390FeatInit feat_init) | |
758 | { | |
759 | const S390CPUDef *def = s390_find_cpu_def(type, gen, ec_ga, NULL); | |
760 | ||
761 | g_assert(def); | |
3c55dd58 | 762 | g_assert(QTAILQ_EMPTY_RCU(&cpus_queue)); |
35b4df64 | 763 | |
35b4df64 | 764 | /* build the CPU model */ |
d98ed7d9 | 765 | s390_qemu_cpu_model.def = def; |
35b4df64 DH |
766 | bitmap_zero(s390_qemu_cpu_model.features, S390_FEAT_MAX); |
767 | s390_init_feat_bitmap(feat_init, s390_qemu_cpu_model.features); | |
768 | } | |
769 | ||
41868f84 DH |
770 | static void s390_qemu_cpu_model_initfn(Object *obj) |
771 | { | |
ad5afd07 DH |
772 | S390CPU *cpu = S390_CPU(obj); |
773 | ||
774 | cpu->model = g_malloc0(sizeof(*cpu->model)); | |
35b4df64 DH |
775 | /* copy the CPU model so we can modify it */ |
776 | memcpy(cpu->model, &s390_qemu_cpu_model, sizeof(*cpu->model)); | |
41868f84 DH |
777 | } |
778 | ||
c6117788 DH |
779 | static void s390_max_cpu_model_initfn(Object *obj) |
780 | { | |
781 | const S390CPUModel *max_model; | |
782 | S390CPU *cpu = S390_CPU(obj); | |
783 | Error *local_err = NULL; | |
784 | ||
785 | if (kvm_enabled() && !kvm_s390_cpu_models_supported()) { | |
786 | /* "max" and "host" always work, even without CPU model support */ | |
787 | return; | |
788 | } | |
789 | ||
790 | max_model = get_max_cpu_model(&local_err); | |
791 | if (local_err) { | |
792 | /* we expect errors only under KVM, when actually querying the kernel */ | |
793 | g_assert(kvm_enabled()); | |
794 | error_report_err(local_err); | |
795 | /* fallback to unsupported CPU models */ | |
796 | return; | |
797 | } | |
798 | ||
799 | cpu->model = g_new(S390CPUModel, 1); | |
800 | /* copy the CPU model so we can modify it */ | |
801 | memcpy(cpu->model, max_model, sizeof(*cpu->model)); | |
802 | } | |
803 | ||
41868f84 DH |
804 | static void s390_cpu_model_finalize(Object *obj) |
805 | { | |
ad5afd07 DH |
806 | S390CPU *cpu = S390_CPU(obj); |
807 | ||
808 | g_free(cpu->model); | |
809 | cpu->model = NULL; | |
41868f84 DH |
810 | } |
811 | ||
6efadc90 DH |
812 | static bool get_is_migration_safe(Object *obj, Error **errp) |
813 | { | |
814 | return S390_CPU_GET_CLASS(obj)->is_migration_safe; | |
815 | } | |
816 | ||
817 | static bool get_is_static(Object *obj, Error **errp) | |
818 | { | |
819 | return S390_CPU_GET_CLASS(obj)->is_static; | |
820 | } | |
821 | ||
822 | static char *get_description(Object *obj, Error **errp) | |
823 | { | |
824 | return g_strdup(S390_CPU_GET_CLASS(obj)->desc); | |
825 | } | |
826 | ||
827 | void s390_cpu_model_class_register_props(ObjectClass *oc) | |
828 | { | |
ab76d63a EH |
829 | S390FeatGroup group; |
830 | S390Feat feat; | |
831 | ||
6efadc90 | 832 | object_class_property_add_bool(oc, "migration-safe", get_is_migration_safe, |
d2623129 | 833 | NULL); |
6efadc90 | 834 | object_class_property_add_bool(oc, "static", get_is_static, |
d2623129 MA |
835 | NULL); |
836 | object_class_property_add_str(oc, "description", get_description, NULL); | |
ab76d63a EH |
837 | |
838 | for (feat = 0; feat < S390_FEAT_MAX; feat++) { | |
839 | const S390FeatDef *def = s390_feat_def(feat); | |
840 | object_class_property_add(oc, def->name, "bool", get_feature, | |
841 | set_feature, NULL, (void *) feat); | |
842 | object_class_property_set_description(oc, def->name, def->desc); | |
843 | } | |
844 | for (group = 0; group < S390_FEAT_GROUP_MAX; group++) { | |
845 | const S390FeatGroupDef *def = s390_feat_group_def(group); | |
846 | object_class_property_add(oc, def->name, "bool", get_feature_group, | |
847 | set_feature_group, NULL, (void *) group); | |
848 | object_class_property_set_description(oc, def->name, def->desc); | |
849 | } | |
6efadc90 DH |
850 | } |
851 | ||
41868f84 DH |
852 | #ifdef CONFIG_KVM |
853 | static void s390_host_cpu_model_class_init(ObjectClass *oc, void *data) | |
854 | { | |
855 | S390CPUClass *xcc = S390_CPU_CLASS(oc); | |
856 | ||
857 | xcc->kvm_required = true; | |
858 | xcc->desc = "KVM only: All recognized features"; | |
859 | } | |
860 | #endif | |
861 | ||
6c064de1 DH |
862 | static void s390_base_cpu_model_class_init(ObjectClass *oc, void *data) |
863 | { | |
864 | S390CPUClass *xcc = S390_CPU_CLASS(oc); | |
865 | ||
866 | /* all base models are migration safe */ | |
867 | xcc->cpu_def = (const S390CPUDef *) data; | |
868 | xcc->is_migration_safe = true; | |
869 | xcc->is_static = true; | |
870 | xcc->desc = xcc->cpu_def->desc; | |
871 | } | |
872 | ||
873 | static void s390_cpu_model_class_init(ObjectClass *oc, void *data) | |
874 | { | |
875 | S390CPUClass *xcc = S390_CPU_CLASS(oc); | |
876 | ||
877 | /* model that can change between QEMU versions */ | |
878 | xcc->cpu_def = (const S390CPUDef *) data; | |
879 | xcc->is_migration_safe = true; | |
880 | xcc->desc = xcc->cpu_def->desc; | |
881 | } | |
882 | ||
41868f84 DH |
883 | static void s390_qemu_cpu_model_class_init(ObjectClass *oc, void *data) |
884 | { | |
885 | S390CPUClass *xcc = S390_CPU_CLASS(oc); | |
886 | ||
887 | xcc->is_migration_safe = true; | |
888 | xcc->desc = g_strdup_printf("QEMU Virtual CPU version %s", | |
889 | qemu_hw_version()); | |
890 | } | |
891 | ||
c6117788 DH |
892 | static void s390_max_cpu_model_class_init(ObjectClass *oc, void *data) |
893 | { | |
894 | S390CPUClass *xcc = S390_CPU_CLASS(oc); | |
895 | ||
896 | /* | |
897 | * The "max" model is neither static nor migration safe. Under KVM | |
d98ed7d9 DH |
898 | * it represents the "host" model. Under TCG it represents the "qemu" CPU |
899 | * model of the latest QEMU machine. | |
c6117788 DH |
900 | */ |
901 | xcc->desc = | |
902 | "Enables all features supported by the accelerator in the current host"; | |
903 | } | |
904 | ||
41868f84 DH |
905 | /* Generate type name for a cpu model. Caller has to free the string. */ |
906 | static char *s390_cpu_type_name(const char *model_name) | |
907 | { | |
908 | return g_strdup_printf(S390_CPU_TYPE_NAME("%s"), model_name); | |
909 | } | |
910 | ||
6c064de1 DH |
911 | /* Generate type name for a base cpu model. Caller has to free the string. */ |
912 | static char *s390_base_cpu_type_name(const char *model_name) | |
913 | { | |
914 | return g_strdup_printf(S390_CPU_TYPE_NAME("%s-base"), model_name); | |
915 | } | |
916 | ||
41868f84 DH |
917 | ObjectClass *s390_cpu_class_by_name(const char *name) |
918 | { | |
919 | char *typename = s390_cpu_type_name(name); | |
920 | ObjectClass *oc; | |
921 | ||
922 | oc = object_class_by_name(typename); | |
923 | g_free(typename); | |
924 | return oc; | |
925 | } | |
926 | ||
927 | static const TypeInfo qemu_s390_cpu_type_info = { | |
928 | .name = S390_CPU_TYPE_NAME("qemu"), | |
929 | .parent = TYPE_S390_CPU, | |
930 | .instance_init = s390_qemu_cpu_model_initfn, | |
931 | .instance_finalize = s390_cpu_model_finalize, | |
932 | .class_init = s390_qemu_cpu_model_class_init, | |
933 | }; | |
934 | ||
c6117788 DH |
935 | static const TypeInfo max_s390_cpu_type_info = { |
936 | .name = S390_CPU_TYPE_NAME("max"), | |
937 | .parent = TYPE_S390_CPU, | |
938 | .instance_init = s390_max_cpu_model_initfn, | |
939 | .instance_finalize = s390_cpu_model_finalize, | |
940 | .class_init = s390_max_cpu_model_class_init, | |
941 | }; | |
942 | ||
41868f84 DH |
943 | #ifdef CONFIG_KVM |
944 | static const TypeInfo host_s390_cpu_type_info = { | |
945 | .name = S390_CPU_TYPE_NAME("host"), | |
c6117788 | 946 | .parent = S390_CPU_TYPE_NAME("max"), |
41868f84 DH |
947 | .class_init = s390_host_cpu_model_class_init, |
948 | }; | |
949 | #endif | |
950 | ||
30e82de7 DH |
951 | static void init_ignored_base_feat(void) |
952 | { | |
953 | static const int feats[] = { | |
954 | /* MSA subfunctions that could not be available on certain machines */ | |
955 | S390_FEAT_KMAC_DEA, | |
956 | S390_FEAT_KMAC_TDEA_128, | |
957 | S390_FEAT_KMAC_TDEA_192, | |
958 | S390_FEAT_KMC_DEA, | |
959 | S390_FEAT_KMC_TDEA_128, | |
960 | S390_FEAT_KMC_TDEA_192, | |
961 | S390_FEAT_KM_DEA, | |
962 | S390_FEAT_KM_TDEA_128, | |
963 | S390_FEAT_KM_TDEA_192, | |
964 | S390_FEAT_KIMD_SHA_1, | |
965 | S390_FEAT_KLMD_SHA_1, | |
eaf6f642 CB |
966 | /* CSSKE is deprecated on newer generations */ |
967 | S390_FEAT_CONDITIONAL_SSKE, | |
30e82de7 DH |
968 | }; |
969 | int i; | |
970 | ||
971 | for (i = 0; i < ARRAY_SIZE(feats); i++) { | |
972 | set_bit(feats[i], ignored_base_feat); | |
973 | } | |
974 | } | |
975 | ||
41868f84 DH |
976 | static void register_types(void) |
977 | { | |
d98ed7d9 | 978 | static const S390FeatInit qemu_max_init = { S390_FEAT_LIST_QEMU_MAX }; |
6c064de1 DH |
979 | int i; |
980 | ||
30e82de7 DH |
981 | init_ignored_base_feat(); |
982 | ||
cced0d65 | 983 | /* init all bitmaps from generated data initially */ |
d98ed7d9 | 984 | s390_init_feat_bitmap(qemu_max_init, qemu_max_cpu_feat); |
6c064de1 DH |
985 | for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { |
986 | s390_init_feat_bitmap(s390_cpu_defs[i].base_init, | |
987 | s390_cpu_defs[i].base_feat); | |
988 | s390_init_feat_bitmap(s390_cpu_defs[i].default_init, | |
989 | s390_cpu_defs[i].default_feat); | |
990 | s390_init_feat_bitmap(s390_cpu_defs[i].full_init, | |
991 | s390_cpu_defs[i].full_feat); | |
992 | } | |
993 | ||
d98ed7d9 | 994 | /* initialize the qemu model with the maximum definition ("max" model) */ |
35b4df64 | 995 | s390_set_qemu_cpu_model(QEMU_MAX_CPU_TYPE, QEMU_MAX_CPU_GEN, |
d98ed7d9 | 996 | QEMU_MAX_CPU_EC_GA, qemu_max_init); |
35b4df64 | 997 | |
6c064de1 DH |
998 | for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { |
999 | char *base_name = s390_base_cpu_type_name(s390_cpu_defs[i].name); | |
1000 | TypeInfo ti_base = { | |
1001 | .name = base_name, | |
1002 | .parent = TYPE_S390_CPU, | |
1003 | .instance_init = s390_cpu_model_initfn, | |
1004 | .instance_finalize = s390_cpu_model_finalize, | |
1005 | .class_init = s390_base_cpu_model_class_init, | |
1006 | .class_data = (void *) &s390_cpu_defs[i], | |
1007 | }; | |
1008 | char *name = s390_cpu_type_name(s390_cpu_defs[i].name); | |
1009 | TypeInfo ti = { | |
1010 | .name = name, | |
1011 | .parent = TYPE_S390_CPU, | |
1012 | .instance_init = s390_cpu_model_initfn, | |
1013 | .instance_finalize = s390_cpu_model_finalize, | |
1014 | .class_init = s390_cpu_model_class_init, | |
1015 | .class_data = (void *) &s390_cpu_defs[i], | |
1016 | }; | |
1017 | ||
1018 | type_register_static(&ti_base); | |
1019 | type_register_static(&ti); | |
1020 | g_free(base_name); | |
1021 | g_free(name); | |
1022 | } | |
1023 | ||
41868f84 | 1024 | type_register_static(&qemu_s390_cpu_type_info); |
c6117788 | 1025 | type_register_static(&max_s390_cpu_type_info); |
41868f84 DH |
1026 | #ifdef CONFIG_KVM |
1027 | type_register_static(&host_s390_cpu_type_info); | |
1028 | #endif | |
1029 | } | |
1030 | ||
1031 | type_init(register_types) |