xref: /openbmc/qemu/hw/ppc/spapr_caps.c (revision 39aeba6caa4b9de8b195fddddae5cc5835d19b04)
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 #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"
32 
33 #include "hw/ppc/spapr.h"
34 
35 typedef struct sPAPRCapPossible {
36     int num;            /* size of vals array below */
37     const char *help;   /* help text for vals */
38     /*
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
45      */
46     const char *vals[];
47 } sPAPRCapPossible;
48 
49 typedef struct sPAPRCapabilityInfo {
50     const char *name;
51     const char *description;
52     int index;
53 
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     void (*cpu_apply)(sPAPRMachineState *spapr, PowerPCCPU *cpu,
63                       uint8_t val, Error **errp);
64 } sPAPRCapabilityInfo;
65 
66 static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
67                                void *opaque, Error **errp)
68 {
69     sPAPRCapabilityInfo *cap = opaque;
70     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
71     bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
72 
73     visit_type_bool(v, name, &value, errp);
74 }
75 
76 static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
77                                void *opaque, Error **errp)
78 {
79     sPAPRCapabilityInfo *cap = opaque;
80     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
81     bool value;
82     Error *local_err = NULL;
83 
84     visit_type_bool(v, name, &value, &local_err);
85     if (local_err) {
86         error_propagate(errp, local_err);
87         return;
88     }
89 
90     spapr->cmd_line_caps[cap->index] = true;
91     spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
92 }
93 
94 
95 static void  spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
96                                   void *opaque, Error **errp)
97 {
98     sPAPRCapabilityInfo *cap = opaque;
99     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
100     char *val = NULL;
101     uint8_t value = spapr_get_cap(spapr, cap->index);
102 
103     if (value >= cap->possible->num) {
104         error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
105         return;
106     }
107 
108     val = g_strdup(cap->possible->vals[value]);
109 
110     visit_type_str(v, name, &val, errp);
111     g_free(val);
112 }
113 
114 static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name,
115                                  void *opaque, Error **errp)
116 {
117     sPAPRCapabilityInfo *cap = opaque;
118     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
119     Error *local_err = NULL;
120     uint8_t i;
121     char *val;
122 
123     visit_type_str(v, name, &val, &local_err);
124     if (local_err) {
125         error_propagate(errp, local_err);
126         return;
127     }
128 
129     if (!strcmp(val, "?")) {
130         error_setg(errp, "%s", cap->possible->help);
131         goto out;
132     }
133     for (i = 0; i < cap->possible->num; i++) {
134         if (!strcasecmp(val, cap->possible->vals[i])) {
135             spapr->cmd_line_caps[cap->index] = true;
136             spapr->eff.caps[cap->index] = i;
137             goto out;
138         }
139     }
140 
141     error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
142                cap->name);
143 out:
144     g_free(val);
145 }
146 
147 static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
148 {
149     if (!val) {
150         /* TODO: We don't support disabling htm yet */
151         return;
152     }
153     if (tcg_enabled()) {
154         error_setg(errp,
155                    "No Transactional Memory support in TCG, try cap-htm=off");
156     } else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
157         error_setg(errp,
158 "KVM implementation does not support Transactional Memory, try cap-htm=off"
159             );
160     }
161 }
162 
163 static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
164 {
165     PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
166     CPUPPCState *env = &cpu->env;
167 
168     if (!val) {
169         /* TODO: We don't support disabling vsx yet */
170         return;
171     }
172     /* Allowable CPUs in spapr_cpu_core.c should already have gotten
173      * rid of anything that doesn't do VMX */
174     g_assert(env->insns_flags & PPC_ALTIVEC);
175     if (!(env->insns_flags2 & PPC2_VSX)) {
176         error_setg(errp, "VSX support not available, try cap-vsx=off");
177     }
178 }
179 
180 static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
181 {
182     PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
183     CPUPPCState *env = &cpu->env;
184 
185     if (!val) {
186         /* TODO: We don't support disabling dfp yet */
187         return;
188     }
189     if (!(env->insns_flags2 & PPC2_DFP)) {
190         error_setg(errp, "DFP support not available, try cap-dfp=off");
191     }
192 }
193 
194 sPAPRCapPossible cap_cfpc_possible = {
195     .num = 3,
196     .vals = {"broken", "workaround", "fixed"},
197     .help = "broken - no protection, workaround - workaround available,"
198             " fixed - fixed in hardware",
199 };
200 
201 static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
202                                  Error **errp)
203 {
204     uint8_t kvm_val =  kvmppc_get_cap_safe_cache();
205 
206     if (tcg_enabled() && val) {
207         /* TODO - for now only allow broken for TCG */
208         error_setg(errp,
209 "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
210     } else if (kvm_enabled() && (val > kvm_val)) {
211         error_setg(errp,
212 "Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
213                    cap_cfpc_possible.vals[kvm_val]);
214     }
215 }
216 
217 sPAPRCapPossible cap_sbbc_possible = {
218     .num = 3,
219     .vals = {"broken", "workaround", "fixed"},
220     .help = "broken - no protection, workaround - workaround available,"
221             " fixed - fixed in hardware",
222 };
223 
224 static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
225                                         Error **errp)
226 {
227     uint8_t kvm_val =  kvmppc_get_cap_safe_bounds_check();
228 
229     if (tcg_enabled() && val) {
230         /* TODO - for now only allow broken for TCG */
231         error_setg(errp,
232 "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
233     } else if (kvm_enabled() && (val > kvm_val)) {
234         error_setg(errp,
235 "Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
236                    cap_sbbc_possible.vals[kvm_val]);
237     }
238 }
239 
240 sPAPRCapPossible cap_ibs_possible = {
241     .num = 4,
242     /* Note workaround only maintained for compatibility */
243     .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"},
244     .help = "broken - no protection, fixed-ibs - indirect branch serialisation,"
245             " fixed-ccd - cache count disabled",
246 };
247 
248 static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
249                                            uint8_t val, Error **errp)
250 {
251     uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch();
252 
253     if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */
254         error_setg(errp,
255 "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s",
256                    cap_ibs_possible.vals[kvm_val]);
257     } else if (tcg_enabled() && val) {
258         /* TODO - for now only allow broken for TCG */
259         error_setg(errp,
260 "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
261     } else if (kvm_enabled() && val && (val != kvm_val)) {
262         error_setg(errp,
263 "Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
264                    cap_ibs_possible.vals[kvm_val]);
265     }
266 }
267 
268 #define VALUE_DESC_TRISTATE     " (broken, workaround, fixed)"
269 
270 sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
271     [SPAPR_CAP_HTM] = {
272         .name = "htm",
273         .description = "Allow Hardware Transactional Memory (HTM)",
274         .index = SPAPR_CAP_HTM,
275         .get = spapr_cap_get_bool,
276         .set = spapr_cap_set_bool,
277         .type = "bool",
278         .apply = cap_htm_apply,
279     },
280     [SPAPR_CAP_VSX] = {
281         .name = "vsx",
282         .description = "Allow Vector Scalar Extensions (VSX)",
283         .index = SPAPR_CAP_VSX,
284         .get = spapr_cap_get_bool,
285         .set = spapr_cap_set_bool,
286         .type = "bool",
287         .apply = cap_vsx_apply,
288     },
289     [SPAPR_CAP_DFP] = {
290         .name = "dfp",
291         .description = "Allow Decimal Floating Point (DFP)",
292         .index = SPAPR_CAP_DFP,
293         .get = spapr_cap_get_bool,
294         .set = spapr_cap_set_bool,
295         .type = "bool",
296         .apply = cap_dfp_apply,
297     },
298     [SPAPR_CAP_CFPC] = {
299         .name = "cfpc",
300         .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE,
301         .index = SPAPR_CAP_CFPC,
302         .get = spapr_cap_get_string,
303         .set = spapr_cap_set_string,
304         .type = "string",
305         .possible = &cap_cfpc_possible,
306         .apply = cap_safe_cache_apply,
307     },
308     [SPAPR_CAP_SBBC] = {
309         .name = "sbbc",
310         .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE,
311         .index = SPAPR_CAP_SBBC,
312         .get = spapr_cap_get_string,
313         .set = spapr_cap_set_string,
314         .type = "string",
315         .possible = &cap_sbbc_possible,
316         .apply = cap_safe_bounds_check_apply,
317     },
318     [SPAPR_CAP_IBS] = {
319         .name = "ibs",
320         .description =
321             "Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)",
322         .index = SPAPR_CAP_IBS,
323         .get = spapr_cap_get_string,
324         .set = spapr_cap_set_string,
325         .type = "string",
326         .possible = &cap_ibs_possible,
327         .apply = cap_safe_indirect_branch_apply,
328     },
329 };
330 
331 static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
332                                                const char *cputype)
333 {
334     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
335     sPAPRCapabilities caps;
336 
337     caps = smc->default_caps;
338 
339     if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_07,
340                                0, spapr->max_compat_pvr)) {
341         caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
342         caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
343     }
344 
345     if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_06_PLUS,
346                                0, spapr->max_compat_pvr)) {
347         caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
348     }
349 
350     if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_06,
351                                0, spapr->max_compat_pvr)) {
352         caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
353         caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
354         caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
355     }
356 
357     return caps;
358 }
359 
360 int spapr_caps_pre_load(void *opaque)
361 {
362     sPAPRMachineState *spapr = opaque;
363 
364     /* Set to default so we can tell if this came in with the migration */
365     spapr->mig = spapr->def;
366     return 0;
367 }
368 
369 int spapr_caps_pre_save(void *opaque)
370 {
371     sPAPRMachineState *spapr = opaque;
372 
373     spapr->mig = spapr->eff;
374     return 0;
375 }
376 
377 /* This has to be called from the top-level spapr post_load, not the
378  * caps specific one.  Otherwise it wouldn't be called when the source
379  * caps are all defaults, which could still conflict with overridden
380  * caps on the destination */
381 int spapr_caps_post_migration(sPAPRMachineState *spapr)
382 {
383     int i;
384     bool ok = true;
385     sPAPRCapabilities dstcaps = spapr->eff;
386     sPAPRCapabilities srccaps;
387 
388     srccaps = default_caps_with_cpu(spapr, MACHINE(spapr)->cpu_type);
389     for (i = 0; i < SPAPR_CAP_NUM; i++) {
390         /* If not default value then assume came in with the migration */
391         if (spapr->mig.caps[i] != spapr->def.caps[i]) {
392             srccaps.caps[i] = spapr->mig.caps[i];
393         }
394     }
395 
396     for (i = 0; i < SPAPR_CAP_NUM; i++) {
397         sPAPRCapabilityInfo *info = &capability_table[i];
398 
399         if (srccaps.caps[i] > dstcaps.caps[i]) {
400             error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)",
401                          info->name, srccaps.caps[i], dstcaps.caps[i]);
402             ok = false;
403         }
404 
405         if (srccaps.caps[i] < dstcaps.caps[i]) {
406             warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)",
407                          info->name, srccaps.caps[i], dstcaps.caps[i]);
408         }
409     }
410 
411     return ok ? 0 : -EINVAL;
412 }
413 
414 /* Used to generate the migration field and needed function for a spapr cap */
415 #define SPAPR_CAP_MIG_STATE(sname, cap)                 \
416 static bool spapr_cap_##sname##_needed(void *opaque)    \
417 {                                                       \
418     sPAPRMachineState *spapr = opaque;                  \
419                                                         \
420     return spapr->cmd_line_caps[cap] &&                 \
421            (spapr->eff.caps[cap] !=                     \
422             spapr->def.caps[cap]);                      \
423 }                                                       \
424                                                         \
425 const VMStateDescription vmstate_spapr_cap_##sname = {  \
426     .name = "spapr/cap/" #sname,                        \
427     .version_id = 1,                                    \
428     .minimum_version_id = 1,                            \
429     .needed = spapr_cap_##sname##_needed,               \
430     .fields = (VMStateField[]) {                        \
431         VMSTATE_UINT8(mig.caps[cap],                    \
432                       sPAPRMachineState),               \
433         VMSTATE_END_OF_LIST()                           \
434     },                                                  \
435 }
436 
437 SPAPR_CAP_MIG_STATE(htm, SPAPR_CAP_HTM);
438 SPAPR_CAP_MIG_STATE(vsx, SPAPR_CAP_VSX);
439 SPAPR_CAP_MIG_STATE(dfp, SPAPR_CAP_DFP);
440 SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC);
441 SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC);
442 SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS);
443 
444 void spapr_caps_init(sPAPRMachineState *spapr)
445 {
446     sPAPRCapabilities default_caps;
447     int i;
448 
449     /* Compute the actual set of caps we should run with */
450     default_caps = default_caps_with_cpu(spapr, MACHINE(spapr)->cpu_type);
451 
452     for (i = 0; i < SPAPR_CAP_NUM; i++) {
453         /* Store the defaults */
454         spapr->def.caps[i] = default_caps.caps[i];
455         /* If not set on the command line then apply the default value */
456         if (!spapr->cmd_line_caps[i]) {
457             spapr->eff.caps[i] = default_caps.caps[i];
458         }
459     }
460 }
461 
462 void spapr_caps_apply(sPAPRMachineState *spapr)
463 {
464     int i;
465 
466     for (i = 0; i < SPAPR_CAP_NUM; i++) {
467         sPAPRCapabilityInfo *info = &capability_table[i];
468 
469         /*
470          * If the apply function can't set the desired level and thinks it's
471          * fatal, it should cause that.
472          */
473         info->apply(spapr, spapr->eff.caps[i], &error_fatal);
474     }
475 }
476 
477 void spapr_caps_cpu_apply(sPAPRMachineState *spapr, PowerPCCPU *cpu)
478 {
479     int i;
480 
481     for (i = 0; i < SPAPR_CAP_NUM; i++) {
482         sPAPRCapabilityInfo *info = &capability_table[i];
483 
484         /*
485          * If the apply function can't set the desired level and thinks it's
486          * fatal, it should cause that.
487          */
488         if (info->cpu_apply) {
489             info->cpu_apply(spapr, cpu, spapr->eff.caps[i], &error_fatal);
490         }
491     }
492 }
493 
494 void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
495 {
496     Error *local_err = NULL;
497     ObjectClass *klass = OBJECT_CLASS(smc);
498     int i;
499 
500     for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
501         sPAPRCapabilityInfo *cap = &capability_table[i];
502         const char *name = g_strdup_printf("cap-%s", cap->name);
503         char *desc;
504 
505         object_class_property_add(klass, name, cap->type,
506                                   cap->get, cap->set,
507                                   NULL, cap, &local_err);
508         if (local_err) {
509             error_propagate(errp, local_err);
510             return;
511         }
512 
513         desc = g_strdup_printf("%s", cap->description);
514         object_class_property_set_description(klass, name, desc, &local_err);
515         g_free(desc);
516         if (local_err) {
517             error_propagate(errp, local_err);
518             return;
519         }
520     }
521 }
522