]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * QEMU PowerPC pSeries Logical Partition capabilities handling | |
3 | * | |
4 | * Copyright (c) 2017 David Gibson, Red Hat Inc. | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | * of this software and associated documentation files (the "Software"), to deal | |
8 | * in the Software without restriction, including without limitation the rights | |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | * copies of the Software, and to permit persons to whom the Software is | |
11 | * furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | * THE SOFTWARE. | |
23 | */ | |
24 | ||
25 | #include "qemu/osdep.h" | |
26 | #include "qemu/error-report.h" | |
27 | #include "qapi/error.h" | |
28 | #include "qapi/visitor.h" | |
29 | #include "sysemu/hw_accel.h" | |
30 | #include "exec/ram_addr.h" | |
31 | #include "target/ppc/cpu.h" | |
32 | #include "target/ppc/mmu-hash64.h" | |
33 | #include "cpu-models.h" | |
34 | #include "kvm_ppc.h" | |
35 | #include "migration/vmstate.h" | |
36 | #include "sysemu/qtest.h" | |
37 | #include "sysemu/tcg.h" | |
38 | ||
39 | #include "hw/ppc/spapr.h" | |
40 | ||
41 | typedef struct SpaprCapPossible { | |
42 | int num; /* size of vals array below */ | |
43 | const char *help; /* help text for vals */ | |
44 | /* | |
45 | * Note: | |
46 | * - because of the way compatibility is determined vals MUST be ordered | |
47 | * such that later options are a superset of all preceding options. | |
48 | * - the order of vals must be preserved, that is their index is important, | |
49 | * however vals may be added to the end of the list so long as the above | |
50 | * point is observed | |
51 | */ | |
52 | const char *vals[]; | |
53 | } SpaprCapPossible; | |
54 | ||
55 | typedef struct SpaprCapabilityInfo { | |
56 | const char *name; | |
57 | const char *description; | |
58 | int index; | |
59 | ||
60 | /* Getter and Setter Function Pointers */ | |
61 | ObjectPropertyAccessor *get; | |
62 | ObjectPropertyAccessor *set; | |
63 | const char *type; | |
64 | /* Possible values if this is a custom string type */ | |
65 | SpaprCapPossible *possible; | |
66 | /* Make sure the virtual hardware can support this capability */ | |
67 | void (*apply)(SpaprMachineState *spapr, uint8_t val, Error **errp); | |
68 | void (*cpu_apply)(SpaprMachineState *spapr, PowerPCCPU *cpu, | |
69 | uint8_t val, Error **errp); | |
70 | bool (*migrate_needed)(void *opaque); | |
71 | } SpaprCapabilityInfo; | |
72 | ||
73 | static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name, | |
74 | void *opaque, Error **errp) | |
75 | { | |
76 | SpaprCapabilityInfo *cap = opaque; | |
77 | SpaprMachineState *spapr = SPAPR_MACHINE(obj); | |
78 | bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON; | |
79 | ||
80 | visit_type_bool(v, name, &value, errp); | |
81 | } | |
82 | ||
83 | static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, | |
84 | void *opaque, Error **errp) | |
85 | { | |
86 | SpaprCapabilityInfo *cap = opaque; | |
87 | SpaprMachineState *spapr = SPAPR_MACHINE(obj); | |
88 | bool value; | |
89 | Error *local_err = NULL; | |
90 | ||
91 | visit_type_bool(v, name, &value, &local_err); | |
92 | if (local_err) { | |
93 | error_propagate(errp, local_err); | |
94 | return; | |
95 | } | |
96 | ||
97 | spapr->cmd_line_caps[cap->index] = true; | |
98 | spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; | |
99 | } | |
100 | ||
101 | ||
102 | static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name, | |
103 | void *opaque, Error **errp) | |
104 | { | |
105 | SpaprCapabilityInfo *cap = opaque; | |
106 | SpaprMachineState *spapr = SPAPR_MACHINE(obj); | |
107 | char *val = NULL; | |
108 | uint8_t value = spapr_get_cap(spapr, cap->index); | |
109 | ||
110 | if (value >= cap->possible->num) { | |
111 | error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name); | |
112 | return; | |
113 | } | |
114 | ||
115 | val = g_strdup(cap->possible->vals[value]); | |
116 | ||
117 | visit_type_str(v, name, &val, errp); | |
118 | g_free(val); | |
119 | } | |
120 | ||
121 | static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name, | |
122 | void *opaque, Error **errp) | |
123 | { | |
124 | SpaprCapabilityInfo *cap = opaque; | |
125 | SpaprMachineState *spapr = SPAPR_MACHINE(obj); | |
126 | Error *local_err = NULL; | |
127 | uint8_t i; | |
128 | char *val; | |
129 | ||
130 | visit_type_str(v, name, &val, &local_err); | |
131 | if (local_err) { | |
132 | error_propagate(errp, local_err); | |
133 | return; | |
134 | } | |
135 | ||
136 | if (!strcmp(val, "?")) { | |
137 | error_setg(errp, "%s", cap->possible->help); | |
138 | goto out; | |
139 | } | |
140 | for (i = 0; i < cap->possible->num; i++) { | |
141 | if (!strcasecmp(val, cap->possible->vals[i])) { | |
142 | spapr->cmd_line_caps[cap->index] = true; | |
143 | spapr->eff.caps[cap->index] = i; | |
144 | goto out; | |
145 | } | |
146 | } | |
147 | ||
148 | error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val, | |
149 | cap->name); | |
150 | out: | |
151 | g_free(val); | |
152 | } | |
153 | ||
154 | static void spapr_cap_get_pagesize(Object *obj, Visitor *v, const char *name, | |
155 | void *opaque, Error **errp) | |
156 | { | |
157 | SpaprCapabilityInfo *cap = opaque; | |
158 | SpaprMachineState *spapr = SPAPR_MACHINE(obj); | |
159 | uint8_t val = spapr_get_cap(spapr, cap->index); | |
160 | uint64_t pagesize = (1ULL << val); | |
161 | ||
162 | visit_type_size(v, name, &pagesize, errp); | |
163 | } | |
164 | ||
165 | static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name, | |
166 | void *opaque, Error **errp) | |
167 | { | |
168 | SpaprCapabilityInfo *cap = opaque; | |
169 | SpaprMachineState *spapr = SPAPR_MACHINE(obj); | |
170 | uint64_t pagesize; | |
171 | uint8_t val; | |
172 | Error *local_err = NULL; | |
173 | ||
174 | visit_type_size(v, name, &pagesize, &local_err); | |
175 | if (local_err) { | |
176 | error_propagate(errp, local_err); | |
177 | return; | |
178 | } | |
179 | ||
180 | if (!is_power_of_2(pagesize)) { | |
181 | error_setg(errp, "cap-%s must be a power of 2", cap->name); | |
182 | return; | |
183 | } | |
184 | ||
185 | val = ctz64(pagesize); | |
186 | spapr->cmd_line_caps[cap->index] = true; | |
187 | spapr->eff.caps[cap->index] = val; | |
188 | } | |
189 | ||
190 | static void cap_htm_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) | |
191 | { | |
192 | if (!val) { | |
193 | /* TODO: We don't support disabling htm yet */ | |
194 | return; | |
195 | } | |
196 | if (tcg_enabled()) { | |
197 | error_setg(errp, | |
198 | "No Transactional Memory support in TCG," | |
199 | " try appending -machine cap-htm=off"); | |
200 | } else if (kvm_enabled() && !kvmppc_has_cap_htm()) { | |
201 | error_setg(errp, | |
202 | "KVM implementation does not support Transactional Memory," | |
203 | " try appending -machine cap-htm=off" | |
204 | ); | |
205 | } | |
206 | } | |
207 | ||
208 | static void cap_vsx_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) | |
209 | { | |
210 | PowerPCCPU *cpu = POWERPC_CPU(first_cpu); | |
211 | CPUPPCState *env = &cpu->env; | |
212 | ||
213 | if (!val) { | |
214 | /* TODO: We don't support disabling vsx yet */ | |
215 | return; | |
216 | } | |
217 | /* Allowable CPUs in spapr_cpu_core.c should already have gotten | |
218 | * rid of anything that doesn't do VMX */ | |
219 | g_assert(env->insns_flags & PPC_ALTIVEC); | |
220 | if (!(env->insns_flags2 & PPC2_VSX)) { | |
221 | error_setg(errp, "VSX support not available," | |
222 | " try appending -machine cap-vsx=off"); | |
223 | } | |
224 | } | |
225 | ||
226 | static void cap_dfp_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) | |
227 | { | |
228 | PowerPCCPU *cpu = POWERPC_CPU(first_cpu); | |
229 | CPUPPCState *env = &cpu->env; | |
230 | ||
231 | if (!val) { | |
232 | /* TODO: We don't support disabling dfp yet */ | |
233 | return; | |
234 | } | |
235 | if (!(env->insns_flags2 & PPC2_DFP)) { | |
236 | error_setg(errp, "DFP support not available," | |
237 | " try appending -machine cap-dfp=off"); | |
238 | } | |
239 | } | |
240 | ||
241 | SpaprCapPossible cap_cfpc_possible = { | |
242 | .num = 3, | |
243 | .vals = {"broken", "workaround", "fixed"}, | |
244 | .help = "broken - no protection, workaround - workaround available," | |
245 | " fixed - fixed in hardware", | |
246 | }; | |
247 | ||
248 | static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val, | |
249 | Error **errp) | |
250 | { | |
251 | Error *local_err = NULL; | |
252 | uint8_t kvm_val = kvmppc_get_cap_safe_cache(); | |
253 | ||
254 | if (tcg_enabled() && val) { | |
255 | /* TCG only supports broken, allow other values and print a warning */ | |
256 | error_setg(&local_err, | |
257 | "TCG doesn't support requested feature, cap-cfpc=%s", | |
258 | cap_cfpc_possible.vals[val]); | |
259 | } else if (kvm_enabled() && (val > kvm_val)) { | |
260 | error_setg(errp, | |
261 | "Requested safe cache capability level not supported by kvm," | |
262 | " try appending -machine cap-cfpc=%s", | |
263 | cap_cfpc_possible.vals[kvm_val]); | |
264 | } | |
265 | ||
266 | if (local_err != NULL) | |
267 | warn_report_err(local_err); | |
268 | } | |
269 | ||
270 | SpaprCapPossible cap_sbbc_possible = { | |
271 | .num = 3, | |
272 | .vals = {"broken", "workaround", "fixed"}, | |
273 | .help = "broken - no protection, workaround - workaround available," | |
274 | " fixed - fixed in hardware", | |
275 | }; | |
276 | ||
277 | static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val, | |
278 | Error **errp) | |
279 | { | |
280 | Error *local_err = NULL; | |
281 | uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check(); | |
282 | ||
283 | if (tcg_enabled() && val) { | |
284 | /* TCG only supports broken, allow other values and print a warning */ | |
285 | error_setg(&local_err, | |
286 | "TCG doesn't support requested feature, cap-sbbc=%s", | |
287 | cap_sbbc_possible.vals[val]); | |
288 | } else if (kvm_enabled() && (val > kvm_val)) { | |
289 | error_setg(errp, | |
290 | "Requested safe bounds check capability level not supported by kvm," | |
291 | " try appending -machine cap-sbbc=%s", | |
292 | cap_sbbc_possible.vals[kvm_val]); | |
293 | } | |
294 | ||
295 | if (local_err != NULL) | |
296 | warn_report_err(local_err); | |
297 | } | |
298 | ||
299 | SpaprCapPossible cap_ibs_possible = { | |
300 | .num = 5, | |
301 | /* Note workaround only maintained for compatibility */ | |
302 | .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd", "fixed-na"}, | |
303 | .help = "broken - no protection, workaround - count cache flush" | |
304 | ", fixed-ibs - indirect branch serialisation," | |
305 | " fixed-ccd - cache count disabled," | |
306 | " fixed-na - fixed in hardware (no longer applicable)", | |
307 | }; | |
308 | ||
309 | static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr, | |
310 | uint8_t val, Error **errp) | |
311 | { | |
312 | Error *local_err = NULL; | |
313 | uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch(); | |
314 | ||
315 | if (tcg_enabled() && val) { | |
316 | /* TCG only supports broken, allow other values and print a warning */ | |
317 | error_setg(&local_err, | |
318 | "TCG doesn't support requested feature, cap-ibs=%s", | |
319 | cap_ibs_possible.vals[val]); | |
320 | } else if (kvm_enabled() && (val > kvm_val)) { | |
321 | error_setg(errp, | |
322 | "Requested safe indirect branch capability level not supported by kvm," | |
323 | " try appending -machine cap-ibs=%s", | |
324 | cap_ibs_possible.vals[kvm_val]); | |
325 | } | |
326 | ||
327 | if (local_err != NULL) { | |
328 | warn_report_err(local_err); | |
329 | } | |
330 | } | |
331 | ||
332 | #define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" | |
333 | ||
334 | void spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize, | |
335 | Error **errp) | |
336 | { | |
337 | hwaddr maxpagesize = (1ULL << spapr->eff.caps[SPAPR_CAP_HPT_MAXPAGESIZE]); | |
338 | ||
339 | if (!kvmppc_hpt_needs_host_contiguous_pages()) { | |
340 | return; | |
341 | } | |
342 | ||
343 | if (maxpagesize > pagesize) { | |
344 | error_setg(errp, | |
345 | "Can't support %"HWADDR_PRIu" kiB guest pages with %" | |
346 | HWADDR_PRIu" kiB host pages with this KVM implementation", | |
347 | maxpagesize >> 10, pagesize >> 10); | |
348 | } | |
349 | } | |
350 | ||
351 | static void cap_hpt_maxpagesize_apply(SpaprMachineState *spapr, | |
352 | uint8_t val, Error **errp) | |
353 | { | |
354 | if (val < 12) { | |
355 | error_setg(errp, "Require at least 4kiB hpt-max-page-size"); | |
356 | return; | |
357 | } else if (val < 16) { | |
358 | warn_report("Many guests require at least 64kiB hpt-max-page-size"); | |
359 | } | |
360 | ||
361 | spapr_check_pagesize(spapr, qemu_minrampagesize(), errp); | |
362 | } | |
363 | ||
364 | static bool cap_hpt_maxpagesize_migrate_needed(void *opaque) | |
365 | { | |
366 | return !SPAPR_MACHINE_GET_CLASS(opaque)->pre_4_1_migration; | |
367 | } | |
368 | ||
369 | static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift, | |
370 | uint32_t pshift) | |
371 | { | |
372 | unsigned maxshift = *((unsigned *)opaque); | |
373 | ||
374 | assert(pshift >= seg_pshift); | |
375 | ||
376 | /* Don't allow the guest to use pages bigger than the configured | |
377 | * maximum size */ | |
378 | if (pshift > maxshift) { | |
379 | return false; | |
380 | } | |
381 | ||
382 | /* For whatever reason, KVM doesn't allow multiple pagesizes | |
383 | * within a segment, *except* for the case of 16M pages in a 4k or | |
384 | * 64k segment. Always exclude other cases, so that TCG and KVM | |
385 | * guests see a consistent environment */ | |
386 | if ((pshift != seg_pshift) && (pshift != 24)) { | |
387 | return false; | |
388 | } | |
389 | ||
390 | return true; | |
391 | } | |
392 | ||
393 | static void cap_hpt_maxpagesize_cpu_apply(SpaprMachineState *spapr, | |
394 | PowerPCCPU *cpu, | |
395 | uint8_t val, Error **errp) | |
396 | { | |
397 | unsigned maxshift = val; | |
398 | ||
399 | ppc_hash64_filter_pagesizes(cpu, spapr_pagesize_cb, &maxshift); | |
400 | } | |
401 | ||
402 | static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, | |
403 | uint8_t val, Error **errp) | |
404 | { | |
405 | if (!val) { | |
406 | /* capability disabled by default */ | |
407 | return; | |
408 | } | |
409 | ||
410 | if (tcg_enabled()) { | |
411 | error_setg(errp, | |
412 | "No Nested KVM-HV support in tcg," | |
413 | " try appending -machine cap-nested-hv=off"); | |
414 | } else if (kvm_enabled()) { | |
415 | if (!kvmppc_has_cap_nested_kvm_hv()) { | |
416 | error_setg(errp, | |
417 | "KVM implementation does not support Nested KVM-HV," | |
418 | " try appending -machine cap-nested-hv=off"); | |
419 | } else if (kvmppc_set_cap_nested_kvm_hv(val) < 0) { | |
420 | error_setg(errp, | |
421 | "Error enabling cap-nested-hv with KVM, try cap-nested-hv=off"); | |
422 | } | |
423 | } | |
424 | } | |
425 | ||
426 | static void cap_large_decr_apply(SpaprMachineState *spapr, | |
427 | uint8_t val, Error **errp) | |
428 | { | |
429 | PowerPCCPU *cpu = POWERPC_CPU(first_cpu); | |
430 | PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); | |
431 | ||
432 | if (!val) { | |
433 | return; /* Disabled by default */ | |
434 | } | |
435 | ||
436 | if (tcg_enabled()) { | |
437 | if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, | |
438 | spapr->max_compat_pvr)) { | |
439 | error_setg(errp, | |
440 | "Large decrementer only supported on POWER9, try -cpu POWER9"); | |
441 | return; | |
442 | } | |
443 | } else if (kvm_enabled()) { | |
444 | int kvm_nr_bits = kvmppc_get_cap_large_decr(); | |
445 | ||
446 | if (!kvm_nr_bits) { | |
447 | error_setg(errp, | |
448 | "No large decrementer support," | |
449 | " try appending -machine cap-large-decr=off"); | |
450 | } else if (pcc->lrg_decr_bits != kvm_nr_bits) { | |
451 | error_setg(errp, | |
452 | "KVM large decrementer size (%d) differs to model (%d)," | |
453 | " try appending -machine cap-large-decr=off", | |
454 | kvm_nr_bits, pcc->lrg_decr_bits); | |
455 | } | |
456 | } | |
457 | } | |
458 | ||
459 | static void cap_large_decr_cpu_apply(SpaprMachineState *spapr, | |
460 | PowerPCCPU *cpu, | |
461 | uint8_t val, Error **errp) | |
462 | { | |
463 | CPUPPCState *env = &cpu->env; | |
464 | target_ulong lpcr = env->spr[SPR_LPCR]; | |
465 | ||
466 | if (kvm_enabled()) { | |
467 | if (kvmppc_enable_cap_large_decr(cpu, val)) { | |
468 | error_setg(errp, | |
469 | "No large decrementer support," | |
470 | " try appending -machine cap-large-decr=off"); | |
471 | } | |
472 | } | |
473 | ||
474 | if (val) { | |
475 | lpcr |= LPCR_LD; | |
476 | } else { | |
477 | lpcr &= ~LPCR_LD; | |
478 | } | |
479 | ppc_store_lpcr(cpu, lpcr); | |
480 | } | |
481 | ||
482 | static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val, | |
483 | Error **errp) | |
484 | { | |
485 | uint8_t kvm_val = kvmppc_get_cap_count_cache_flush_assist(); | |
486 | ||
487 | if (tcg_enabled() && val) { | |
488 | /* TCG doesn't implement anything here, but allow with a warning */ | |
489 | warn_report("TCG doesn't support requested feature, cap-ccf-assist=on"); | |
490 | } else if (kvm_enabled() && (val > kvm_val)) { | |
491 | uint8_t kvm_ibs = kvmppc_get_cap_safe_indirect_branch(); | |
492 | ||
493 | if (kvm_ibs == SPAPR_CAP_FIXED_CCD) { | |
494 | /* | |
495 | * If we don't have CCF assist on the host, the assist | |
496 | * instruction is a harmless no-op. It won't correctly | |
497 | * implement the cache count flush *but* if we have | |
498 | * count-cache-disabled in the host, that flush is | |
499 | * unnnecessary. So, specifically allow this case. This | |
500 | * allows us to have better performance on POWER9 DD2.3, | |
501 | * while still working on POWER9 DD2.2 and POWER8 host | |
502 | * cpus. | |
503 | */ | |
504 | return; | |
505 | } | |
506 | error_setg(errp, | |
507 | "Requested count cache flush assist capability level not supported by kvm," | |
508 | " try appending -machine cap-ccf-assist=off"); | |
509 | } | |
510 | } | |
511 | ||
512 | static void cap_fwnmi_apply(SpaprMachineState *spapr, uint8_t val, | |
513 | Error **errp) | |
514 | { | |
515 | if (!val) { | |
516 | return; /* Disabled by default */ | |
517 | } | |
518 | ||
519 | if (kvm_enabled()) { | |
520 | if (!kvmppc_get_fwnmi()) { | |
521 | error_setg(errp, | |
522 | "Firmware Assisted Non-Maskable Interrupts(FWNMI) not supported by KVM."); | |
523 | error_append_hint(errp, "Try appending -machine cap-fwnmi=off\n"); | |
524 | } | |
525 | } | |
526 | } | |
527 | ||
528 | SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = { | |
529 | [SPAPR_CAP_HTM] = { | |
530 | .name = "htm", | |
531 | .description = "Allow Hardware Transactional Memory (HTM)", | |
532 | .index = SPAPR_CAP_HTM, | |
533 | .get = spapr_cap_get_bool, | |
534 | .set = spapr_cap_set_bool, | |
535 | .type = "bool", | |
536 | .apply = cap_htm_apply, | |
537 | }, | |
538 | [SPAPR_CAP_VSX] = { | |
539 | .name = "vsx", | |
540 | .description = "Allow Vector Scalar Extensions (VSX)", | |
541 | .index = SPAPR_CAP_VSX, | |
542 | .get = spapr_cap_get_bool, | |
543 | .set = spapr_cap_set_bool, | |
544 | .type = "bool", | |
545 | .apply = cap_vsx_apply, | |
546 | }, | |
547 | [SPAPR_CAP_DFP] = { | |
548 | .name = "dfp", | |
549 | .description = "Allow Decimal Floating Point (DFP)", | |
550 | .index = SPAPR_CAP_DFP, | |
551 | .get = spapr_cap_get_bool, | |
552 | .set = spapr_cap_set_bool, | |
553 | .type = "bool", | |
554 | .apply = cap_dfp_apply, | |
555 | }, | |
556 | [SPAPR_CAP_CFPC] = { | |
557 | .name = "cfpc", | |
558 | .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE, | |
559 | .index = SPAPR_CAP_CFPC, | |
560 | .get = spapr_cap_get_string, | |
561 | .set = spapr_cap_set_string, | |
562 | .type = "string", | |
563 | .possible = &cap_cfpc_possible, | |
564 | .apply = cap_safe_cache_apply, | |
565 | }, | |
566 | [SPAPR_CAP_SBBC] = { | |
567 | .name = "sbbc", | |
568 | .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE, | |
569 | .index = SPAPR_CAP_SBBC, | |
570 | .get = spapr_cap_get_string, | |
571 | .set = spapr_cap_set_string, | |
572 | .type = "string", | |
573 | .possible = &cap_sbbc_possible, | |
574 | .apply = cap_safe_bounds_check_apply, | |
575 | }, | |
576 | [SPAPR_CAP_IBS] = { | |
577 | .name = "ibs", | |
578 | .description = | |
579 | "Indirect Branch Speculation (broken, workaround, fixed-ibs," | |
580 | "fixed-ccd, fixed-na)", | |
581 | .index = SPAPR_CAP_IBS, | |
582 | .get = spapr_cap_get_string, | |
583 | .set = spapr_cap_set_string, | |
584 | .type = "string", | |
585 | .possible = &cap_ibs_possible, | |
586 | .apply = cap_safe_indirect_branch_apply, | |
587 | }, | |
588 | [SPAPR_CAP_HPT_MAXPAGESIZE] = { | |
589 | .name = "hpt-max-page-size", | |
590 | .description = "Maximum page size for Hash Page Table guests", | |
591 | .index = SPAPR_CAP_HPT_MAXPAGESIZE, | |
592 | .get = spapr_cap_get_pagesize, | |
593 | .set = spapr_cap_set_pagesize, | |
594 | .type = "int", | |
595 | .apply = cap_hpt_maxpagesize_apply, | |
596 | .cpu_apply = cap_hpt_maxpagesize_cpu_apply, | |
597 | .migrate_needed = cap_hpt_maxpagesize_migrate_needed, | |
598 | }, | |
599 | [SPAPR_CAP_NESTED_KVM_HV] = { | |
600 | .name = "nested-hv", | |
601 | .description = "Allow Nested KVM-HV", | |
602 | .index = SPAPR_CAP_NESTED_KVM_HV, | |
603 | .get = spapr_cap_get_bool, | |
604 | .set = spapr_cap_set_bool, | |
605 | .type = "bool", | |
606 | .apply = cap_nested_kvm_hv_apply, | |
607 | }, | |
608 | [SPAPR_CAP_LARGE_DECREMENTER] = { | |
609 | .name = "large-decr", | |
610 | .description = "Allow Large Decrementer", | |
611 | .index = SPAPR_CAP_LARGE_DECREMENTER, | |
612 | .get = spapr_cap_get_bool, | |
613 | .set = spapr_cap_set_bool, | |
614 | .type = "bool", | |
615 | .apply = cap_large_decr_apply, | |
616 | .cpu_apply = cap_large_decr_cpu_apply, | |
617 | }, | |
618 | [SPAPR_CAP_CCF_ASSIST] = { | |
619 | .name = "ccf-assist", | |
620 | .description = "Count Cache Flush Assist via HW Instruction", | |
621 | .index = SPAPR_CAP_CCF_ASSIST, | |
622 | .get = spapr_cap_get_bool, | |
623 | .set = spapr_cap_set_bool, | |
624 | .type = "bool", | |
625 | .apply = cap_ccf_assist_apply, | |
626 | }, | |
627 | [SPAPR_CAP_FWNMI] = { | |
628 | .name = "fwnmi", | |
629 | .description = "Implements PAPR FWNMI option", | |
630 | .index = SPAPR_CAP_FWNMI, | |
631 | .get = spapr_cap_get_bool, | |
632 | .set = spapr_cap_set_bool, | |
633 | .type = "bool", | |
634 | .apply = cap_fwnmi_apply, | |
635 | }, | |
636 | }; | |
637 | ||
638 | static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr, | |
639 | const char *cputype) | |
640 | { | |
641 | SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); | |
642 | SpaprCapabilities caps; | |
643 | ||
644 | caps = smc->default_caps; | |
645 | ||
646 | if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_3_00, | |
647 | 0, spapr->max_compat_pvr)) { | |
648 | caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF; | |
649 | } | |
650 | ||
651 | if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_07, | |
652 | 0, spapr->max_compat_pvr)) { | |
653 | caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; | |
654 | caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; | |
655 | } | |
656 | ||
657 | if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_06_PLUS, | |
658 | 0, spapr->max_compat_pvr)) { | |
659 | caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN; | |
660 | } | |
661 | ||
662 | if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_06, | |
663 | 0, spapr->max_compat_pvr)) { | |
664 | caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF; | |
665 | caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF; | |
666 | caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN; | |
667 | } | |
668 | ||
669 | /* This is for pseries-2.12 and older */ | |
670 | if (smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] == 0) { | |
671 | uint8_t mps; | |
672 | ||
673 | if (kvmppc_hpt_needs_host_contiguous_pages()) { | |
674 | mps = ctz64(qemu_minrampagesize()); | |
675 | } else { | |
676 | mps = 34; /* allow everything up to 16GiB, i.e. everything */ | |
677 | } | |
678 | ||
679 | caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = mps; | |
680 | } | |
681 | ||
682 | return caps; | |
683 | } | |
684 | ||
685 | int spapr_caps_pre_load(void *opaque) | |
686 | { | |
687 | SpaprMachineState *spapr = opaque; | |
688 | ||
689 | /* Set to default so we can tell if this came in with the migration */ | |
690 | spapr->mig = spapr->def; | |
691 | return 0; | |
692 | } | |
693 | ||
694 | int spapr_caps_pre_save(void *opaque) | |
695 | { | |
696 | SpaprMachineState *spapr = opaque; | |
697 | ||
698 | spapr->mig = spapr->eff; | |
699 | return 0; | |
700 | } | |
701 | ||
702 | /* This has to be called from the top-level spapr post_load, not the | |
703 | * caps specific one. Otherwise it wouldn't be called when the source | |
704 | * caps are all defaults, which could still conflict with overridden | |
705 | * caps on the destination */ | |
706 | int spapr_caps_post_migration(SpaprMachineState *spapr) | |
707 | { | |
708 | int i; | |
709 | bool ok = true; | |
710 | SpaprCapabilities dstcaps = spapr->eff; | |
711 | SpaprCapabilities srccaps; | |
712 | ||
713 | srccaps = default_caps_with_cpu(spapr, MACHINE(spapr)->cpu_type); | |
714 | for (i = 0; i < SPAPR_CAP_NUM; i++) { | |
715 | /* If not default value then assume came in with the migration */ | |
716 | if (spapr->mig.caps[i] != spapr->def.caps[i]) { | |
717 | srccaps.caps[i] = spapr->mig.caps[i]; | |
718 | } | |
719 | } | |
720 | ||
721 | for (i = 0; i < SPAPR_CAP_NUM; i++) { | |
722 | SpaprCapabilityInfo *info = &capability_table[i]; | |
723 | ||
724 | if (srccaps.caps[i] > dstcaps.caps[i]) { | |
725 | error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)", | |
726 | info->name, srccaps.caps[i], dstcaps.caps[i]); | |
727 | ok = false; | |
728 | } | |
729 | ||
730 | if (srccaps.caps[i] < dstcaps.caps[i]) { | |
731 | warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)", | |
732 | info->name, srccaps.caps[i], dstcaps.caps[i]); | |
733 | } | |
734 | } | |
735 | ||
736 | return ok ? 0 : -EINVAL; | |
737 | } | |
738 | ||
739 | /* Used to generate the migration field and needed function for a spapr cap */ | |
740 | #define SPAPR_CAP_MIG_STATE(sname, cap) \ | |
741 | static bool spapr_cap_##sname##_needed(void *opaque) \ | |
742 | { \ | |
743 | SpaprMachineState *spapr = opaque; \ | |
744 | bool (*needed)(void *opaque) = \ | |
745 | capability_table[cap].migrate_needed; \ | |
746 | \ | |
747 | return needed ? needed(opaque) : true && \ | |
748 | spapr->cmd_line_caps[cap] && \ | |
749 | (spapr->eff.caps[cap] != \ | |
750 | spapr->def.caps[cap]); \ | |
751 | } \ | |
752 | \ | |
753 | const VMStateDescription vmstate_spapr_cap_##sname = { \ | |
754 | .name = "spapr/cap/" #sname, \ | |
755 | .version_id = 1, \ | |
756 | .minimum_version_id = 1, \ | |
757 | .needed = spapr_cap_##sname##_needed, \ | |
758 | .fields = (VMStateField[]) { \ | |
759 | VMSTATE_UINT8(mig.caps[cap], \ | |
760 | SpaprMachineState), \ | |
761 | VMSTATE_END_OF_LIST() \ | |
762 | }, \ | |
763 | } | |
764 | ||
765 | SPAPR_CAP_MIG_STATE(htm, SPAPR_CAP_HTM); | |
766 | SPAPR_CAP_MIG_STATE(vsx, SPAPR_CAP_VSX); | |
767 | SPAPR_CAP_MIG_STATE(dfp, SPAPR_CAP_DFP); | |
768 | SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC); | |
769 | SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC); | |
770 | SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS); | |
771 | SPAPR_CAP_MIG_STATE(hpt_maxpagesize, SPAPR_CAP_HPT_MAXPAGESIZE); | |
772 | SPAPR_CAP_MIG_STATE(nested_kvm_hv, SPAPR_CAP_NESTED_KVM_HV); | |
773 | SPAPR_CAP_MIG_STATE(large_decr, SPAPR_CAP_LARGE_DECREMENTER); | |
774 | SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST); | |
775 | SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI); | |
776 | ||
777 | void spapr_caps_init(SpaprMachineState *spapr) | |
778 | { | |
779 | SpaprCapabilities default_caps; | |
780 | int i; | |
781 | ||
782 | /* Compute the actual set of caps we should run with */ | |
783 | default_caps = default_caps_with_cpu(spapr, MACHINE(spapr)->cpu_type); | |
784 | ||
785 | for (i = 0; i < SPAPR_CAP_NUM; i++) { | |
786 | /* Store the defaults */ | |
787 | spapr->def.caps[i] = default_caps.caps[i]; | |
788 | /* If not set on the command line then apply the default value */ | |
789 | if (!spapr->cmd_line_caps[i]) { | |
790 | spapr->eff.caps[i] = default_caps.caps[i]; | |
791 | } | |
792 | } | |
793 | } | |
794 | ||
795 | void spapr_caps_apply(SpaprMachineState *spapr) | |
796 | { | |
797 | int i; | |
798 | ||
799 | for (i = 0; i < SPAPR_CAP_NUM; i++) { | |
800 | SpaprCapabilityInfo *info = &capability_table[i]; | |
801 | ||
802 | /* | |
803 | * If the apply function can't set the desired level and thinks it's | |
804 | * fatal, it should cause that. | |
805 | */ | |
806 | info->apply(spapr, spapr->eff.caps[i], &error_fatal); | |
807 | } | |
808 | } | |
809 | ||
810 | void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu) | |
811 | { | |
812 | int i; | |
813 | ||
814 | for (i = 0; i < SPAPR_CAP_NUM; i++) { | |
815 | SpaprCapabilityInfo *info = &capability_table[i]; | |
816 | ||
817 | /* | |
818 | * If the apply function can't set the desired level and thinks it's | |
819 | * fatal, it should cause that. | |
820 | */ | |
821 | if (info->cpu_apply) { | |
822 | info->cpu_apply(spapr, cpu, spapr->eff.caps[i], &error_fatal); | |
823 | } | |
824 | } | |
825 | } | |
826 | ||
827 | void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp) | |
828 | { | |
829 | Error *local_err = NULL; | |
830 | ObjectClass *klass = OBJECT_CLASS(smc); | |
831 | int i; | |
832 | ||
833 | for (i = 0; i < ARRAY_SIZE(capability_table); i++) { | |
834 | SpaprCapabilityInfo *cap = &capability_table[i]; | |
835 | char *name = g_strdup_printf("cap-%s", cap->name); | |
836 | char *desc; | |
837 | ||
838 | object_class_property_add(klass, name, cap->type, | |
839 | cap->get, cap->set, | |
840 | NULL, cap, &local_err); | |
841 | if (local_err) { | |
842 | error_propagate(errp, local_err); | |
843 | g_free(name); | |
844 | return; | |
845 | } | |
846 | ||
847 | desc = g_strdup_printf("%s", cap->description); | |
848 | object_class_property_set_description(klass, name, desc, &local_err); | |
849 | g_free(name); | |
850 | g_free(desc); | |
851 | if (local_err) { | |
852 | error_propagate(errp, local_err); | |
853 | return; | |
854 | } | |
855 | } | |
856 | } |