ppc/spapr-caps: Convert cap-cfpc to custom spapr-cap
[qemu.git] / hw / ppc / spapr_caps.c
blobb5a991f97af839da2d0ef31f28be7d63a0f5fc86
1 /*
2 * QEMU PowerPC pSeries Logical Partition capabilities handling
4 * Copyright (c) 2017 David Gibson, Red Hat Inc.
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
24 #include "qemu/osdep.h"
25 #include "qemu/error-report.h"
26 #include "qapi/error.h"
27 #include "qapi/visitor.h"
28 #include "sysemu/hw_accel.h"
29 #include "target/ppc/cpu.h"
30 #include "cpu-models.h"
31 #include "kvm_ppc.h"
33 #include "hw/ppc/spapr.h"
35 typedef struct sPAPRCapPossible {
36 int num; /* size of vals array below */
37 const char *help; /* help text for vals */
39 * Note:
40 * - because of the way compatibility is determined vals MUST be ordered
41 * such that later options are a superset of all preceding options.
42 * - the order of vals must be preserved, that is their index is important,
43 * however vals may be added to the end of the list so long as the above
44 * point is observed
46 const char *vals[];
47 } sPAPRCapPossible;
49 typedef struct sPAPRCapabilityInfo {
50 const char *name;
51 const char *description;
52 int index;
54 /* Getter and Setter Function Pointers */
55 ObjectPropertyAccessor *get;
56 ObjectPropertyAccessor *set;
57 const char *type;
58 /* Possible values if this is a custom string type */
59 sPAPRCapPossible *possible;
60 /* Make sure the virtual hardware can support this capability */
61 void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
62 } sPAPRCapabilityInfo;
64 static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
65 void *opaque, Error **errp)
67 sPAPRCapabilityInfo *cap = opaque;
68 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
69 bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
71 visit_type_bool(v, name, &value, errp);
74 static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
75 void *opaque, Error **errp)
77 sPAPRCapabilityInfo *cap = opaque;
78 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
79 bool value;
80 Error *local_err = NULL;
82 visit_type_bool(v, name, &value, &local_err);
83 if (local_err) {
84 error_propagate(errp, local_err);
85 return;
88 spapr->cmd_line_caps[cap->index] = true;
89 spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
92 static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
93 void *opaque, Error **errp)
95 sPAPRCapabilityInfo *cap = opaque;
96 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
97 char *val = NULL;
98 uint8_t value = spapr_get_cap(spapr, cap->index);
100 switch (value) {
101 case SPAPR_CAP_BROKEN:
102 val = g_strdup("broken");
103 break;
104 case SPAPR_CAP_WORKAROUND:
105 val = g_strdup("workaround");
106 break;
107 case SPAPR_CAP_FIXED:
108 val = g_strdup("fixed");
109 break;
110 default:
111 error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
112 return;
115 visit_type_str(v, name, &val, errp);
116 g_free(val);
119 static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
120 void *opaque, Error **errp)
122 sPAPRCapabilityInfo *cap = opaque;
123 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
124 char *val;
125 Error *local_err = NULL;
126 uint8_t value;
128 visit_type_str(v, name, &val, &local_err);
129 if (local_err) {
130 error_propagate(errp, local_err);
131 return;
134 if (!strcasecmp(val, "broken")) {
135 value = SPAPR_CAP_BROKEN;
136 } else if (!strcasecmp(val, "workaround")) {
137 value = SPAPR_CAP_WORKAROUND;
138 } else if (!strcasecmp(val, "fixed")) {
139 value = SPAPR_CAP_FIXED;
140 } else {
141 error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
142 cap->name);
143 goto out;
146 spapr->cmd_line_caps[cap->index] = true;
147 spapr->eff.caps[cap->index] = value;
148 out:
149 g_free(val);
152 static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
153 void *opaque, Error **errp)
155 sPAPRCapabilityInfo *cap = opaque;
156 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
157 char *val = NULL;
158 uint8_t value = spapr_get_cap(spapr, cap->index);
160 if (value >= cap->possible->num) {
161 error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
162 return;
165 val = g_strdup(cap->possible->vals[value]);
167 visit_type_str(v, name, &val, errp);
168 g_free(val);
171 static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name,
172 void *opaque, Error **errp)
174 sPAPRCapabilityInfo *cap = opaque;
175 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
176 Error *local_err = NULL;
177 uint8_t i;
178 char *val;
180 visit_type_str(v, name, &val, &local_err);
181 if (local_err) {
182 error_propagate(errp, local_err);
183 return;
186 if (!strcmp(val, "?")) {
187 error_setg(errp, "%s", cap->possible->help);
188 goto out;
190 for (i = 0; i < cap->possible->num; i++) {
191 if (!strcasecmp(val, cap->possible->vals[i])) {
192 spapr->cmd_line_caps[cap->index] = true;
193 spapr->eff.caps[cap->index] = i;
194 goto out;
198 error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
199 cap->name);
200 out:
201 g_free(val);
204 static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
206 if (!val) {
207 /* TODO: We don't support disabling htm yet */
208 return;
210 if (tcg_enabled()) {
211 error_setg(errp,
212 "No Transactional Memory support in TCG, try cap-htm=off");
213 } else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
214 error_setg(errp,
215 "KVM implementation does not support Transactional Memory, try cap-htm=off"
220 static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
222 PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
223 CPUPPCState *env = &cpu->env;
225 if (!val) {
226 /* TODO: We don't support disabling vsx yet */
227 return;
229 /* Allowable CPUs in spapr_cpu_core.c should already have gotten
230 * rid of anything that doesn't do VMX */
231 g_assert(env->insns_flags & PPC_ALTIVEC);
232 if (!(env->insns_flags2 & PPC2_VSX)) {
233 error_setg(errp, "VSX support not available, try cap-vsx=off");
237 static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
239 PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
240 CPUPPCState *env = &cpu->env;
242 if (!val) {
243 /* TODO: We don't support disabling dfp yet */
244 return;
246 if (!(env->insns_flags2 & PPC2_DFP)) {
247 error_setg(errp, "DFP support not available, try cap-dfp=off");
251 sPAPRCapPossible cap_cfpc_possible = {
252 .num = 3,
253 .vals = {"broken", "workaround", "fixed"},
254 .help = "broken - no protection, workaround - workaround available,"
255 " fixed - fixed in hardware",
258 static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
259 Error **errp)
261 uint8_t kvm_val = kvmppc_get_cap_safe_cache();
263 if (tcg_enabled() && val) {
264 /* TODO - for now only allow broken for TCG */
265 error_setg(errp,
266 "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
267 } else if (kvm_enabled() && (val > kvm_val)) {
268 error_setg(errp,
269 "Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
270 cap_cfpc_possible.vals[kvm_val]);
274 static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
275 Error **errp)
277 if (tcg_enabled() && val) {
278 /* TODO - for now only allow broken for TCG */
279 error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
280 } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) {
281 error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc");
285 static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
286 uint8_t val, Error **errp)
288 if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */
289 error_setg(errp, "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=fixed");
290 } else if (tcg_enabled() && val) {
291 /* TODO - for now only allow broken for TCG */
292 error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
293 } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) {
294 error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs");
298 #define VALUE_DESC_TRISTATE " (broken, workaround, fixed)"
300 sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
301 [SPAPR_CAP_HTM] = {
302 .name = "htm",
303 .description = "Allow Hardware Transactional Memory (HTM)",
304 .index = SPAPR_CAP_HTM,
305 .get = spapr_cap_get_bool,
306 .set = spapr_cap_set_bool,
307 .type = "bool",
308 .apply = cap_htm_apply,
310 [SPAPR_CAP_VSX] = {
311 .name = "vsx",
312 .description = "Allow Vector Scalar Extensions (VSX)",
313 .index = SPAPR_CAP_VSX,
314 .get = spapr_cap_get_bool,
315 .set = spapr_cap_set_bool,
316 .type = "bool",
317 .apply = cap_vsx_apply,
319 [SPAPR_CAP_DFP] = {
320 .name = "dfp",
321 .description = "Allow Decimal Floating Point (DFP)",
322 .index = SPAPR_CAP_DFP,
323 .get = spapr_cap_get_bool,
324 .set = spapr_cap_set_bool,
325 .type = "bool",
326 .apply = cap_dfp_apply,
328 [SPAPR_CAP_CFPC] = {
329 .name = "cfpc",
330 .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE,
331 .index = SPAPR_CAP_CFPC,
332 .get = spapr_cap_get_string,
333 .set = spapr_cap_set_string,
334 .type = "string",
335 .possible = &cap_cfpc_possible,
336 .apply = cap_safe_cache_apply,
338 [SPAPR_CAP_SBBC] = {
339 .name = "sbbc",
340 .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE,
341 .index = SPAPR_CAP_SBBC,
342 .get = spapr_cap_get_tristate,
343 .set = spapr_cap_set_tristate,
344 .type = "string",
345 .apply = cap_safe_bounds_check_apply,
347 [SPAPR_CAP_IBS] = {
348 .name = "ibs",
349 .description = "Indirect Branch Serialisation (broken, fixed)",
350 .index = SPAPR_CAP_IBS,
351 .get = spapr_cap_get_tristate,
352 .set = spapr_cap_set_tristate,
353 .type = "string",
354 .apply = cap_safe_indirect_branch_apply,
358 static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
359 CPUState *cs)
361 sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
362 PowerPCCPU *cpu = POWERPC_CPU(cs);
363 sPAPRCapabilities caps;
365 caps = smc->default_caps;
367 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
368 0, spapr->max_compat_pvr)) {
369 caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
372 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
373 0, spapr->max_compat_pvr)) {
374 caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
375 caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
378 return caps;
381 int spapr_caps_pre_load(void *opaque)
383 sPAPRMachineState *spapr = opaque;
385 /* Set to default so we can tell if this came in with the migration */
386 spapr->mig = spapr->def;
387 return 0;
390 int spapr_caps_pre_save(void *opaque)
392 sPAPRMachineState *spapr = opaque;
394 spapr->mig = spapr->eff;
395 return 0;
398 /* This has to be called from the top-level spapr post_load, not the
399 * caps specific one. Otherwise it wouldn't be called when the source
400 * caps are all defaults, which could still conflict with overridden
401 * caps on the destination */
402 int spapr_caps_post_migration(sPAPRMachineState *spapr)
404 int i;
405 bool ok = true;
406 sPAPRCapabilities dstcaps = spapr->eff;
407 sPAPRCapabilities srccaps;
409 srccaps = default_caps_with_cpu(spapr, first_cpu);
410 for (i = 0; i < SPAPR_CAP_NUM; i++) {
411 /* If not default value then assume came in with the migration */
412 if (spapr->mig.caps[i] != spapr->def.caps[i]) {
413 srccaps.caps[i] = spapr->mig.caps[i];
417 for (i = 0; i < SPAPR_CAP_NUM; i++) {
418 sPAPRCapabilityInfo *info = &capability_table[i];
420 if (srccaps.caps[i] > dstcaps.caps[i]) {
421 error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)",
422 info->name, srccaps.caps[i], dstcaps.caps[i]);
423 ok = false;
426 if (srccaps.caps[i] < dstcaps.caps[i]) {
427 warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)",
428 info->name, srccaps.caps[i], dstcaps.caps[i]);
432 return ok ? 0 : -EINVAL;
435 /* Used to generate the migration field and needed function for a spapr cap */
436 #define SPAPR_CAP_MIG_STATE(sname, cap) \
437 static bool spapr_cap_##sname##_needed(void *opaque) \
439 sPAPRMachineState *spapr = opaque; \
441 return spapr->cmd_line_caps[cap] && \
442 (spapr->eff.caps[cap] != \
443 spapr->def.caps[cap]); \
446 const VMStateDescription vmstate_spapr_cap_##sname = { \
447 .name = "spapr/cap/" #sname, \
448 .version_id = 1, \
449 .minimum_version_id = 1, \
450 .needed = spapr_cap_##sname##_needed, \
451 .fields = (VMStateField[]) { \
452 VMSTATE_UINT8(mig.caps[cap], \
453 sPAPRMachineState), \
454 VMSTATE_END_OF_LIST() \
455 }, \
458 SPAPR_CAP_MIG_STATE(htm, SPAPR_CAP_HTM);
459 SPAPR_CAP_MIG_STATE(vsx, SPAPR_CAP_VSX);
460 SPAPR_CAP_MIG_STATE(dfp, SPAPR_CAP_DFP);
461 SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC);
462 SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC);
463 SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS);
465 void spapr_caps_reset(sPAPRMachineState *spapr)
467 sPAPRCapabilities default_caps;
468 int i;
470 /* First compute the actual set of caps we're running with.. */
471 default_caps = default_caps_with_cpu(spapr, first_cpu);
473 for (i = 0; i < SPAPR_CAP_NUM; i++) {
474 /* Store the defaults */
475 spapr->def.caps[i] = default_caps.caps[i];
476 /* If not set on the command line then apply the default value */
477 if (!spapr->cmd_line_caps[i]) {
478 spapr->eff.caps[i] = default_caps.caps[i];
482 /* .. then apply those caps to the virtual hardware */
484 for (i = 0; i < SPAPR_CAP_NUM; i++) {
485 sPAPRCapabilityInfo *info = &capability_table[i];
488 * If the apply function can't set the desired level and thinks it's
489 * fatal, it should cause that.
491 info->apply(spapr, spapr->eff.caps[i], &error_fatal);
495 void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
497 Error *local_err = NULL;
498 ObjectClass *klass = OBJECT_CLASS(smc);
499 int i;
501 for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
502 sPAPRCapabilityInfo *cap = &capability_table[i];
503 const char *name = g_strdup_printf("cap-%s", cap->name);
504 char *desc;
506 object_class_property_add(klass, name, cap->type,
507 cap->get, cap->set,
508 NULL, cap, &local_err);
509 if (local_err) {
510 error_propagate(errp, local_err);
511 return;
514 desc = g_strdup_printf("%s", cap->description);
515 object_class_property_set_description(klass, name, desc, &local_err);
516 g_free(desc);
517 if (local_err) {
518 error_propagate(errp, local_err);
519 return;