1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
35typedef struct sPAPRCapabilityInfo {
36 const char *name;
37 const char *description;
38 const char *options;
39 int index;
40
41
42 ObjectPropertyAccessor *get;
43 ObjectPropertyAccessor *set;
44 const char *type;
45
46 void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
47} sPAPRCapabilityInfo;
48
49static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
50 void *opaque, Error **errp)
51{
52 sPAPRCapabilityInfo *cap = opaque;
53 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
54 bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
55
56 visit_type_bool(v, name, &value, errp);
57}
58
59static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
60 void *opaque, Error **errp)
61{
62 sPAPRCapabilityInfo *cap = opaque;
63 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
64 bool value;
65 Error *local_err = NULL;
66
67 visit_type_bool(v, name, &value, &local_err);
68 if (local_err) {
69 error_propagate(errp, local_err);
70 return;
71 }
72
73 spapr->cmd_line_caps[cap->index] = true;
74 spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
75}
76
77static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
78 void *opaque, Error **errp)
79{
80 sPAPRCapabilityInfo *cap = opaque;
81 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
82 char *val = NULL;
83 uint8_t value = spapr_get_cap(spapr, cap->index);
84
85 switch (value) {
86 case SPAPR_CAP_BROKEN:
87 val = g_strdup("broken");
88 break;
89 case SPAPR_CAP_WORKAROUND:
90 val = g_strdup("workaround");
91 break;
92 case SPAPR_CAP_FIXED:
93 val = g_strdup("fixed");
94 break;
95 default:
96 error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
97 return;
98 }
99
100 visit_type_str(v, name, &val, errp);
101 g_free(val);
102}
103
104static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
105 void *opaque, Error **errp)
106{
107 sPAPRCapabilityInfo *cap = opaque;
108 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
109 char *val;
110 Error *local_err = NULL;
111 uint8_t value;
112
113 visit_type_str(v, name, &val, &local_err);
114 if (local_err) {
115 error_propagate(errp, local_err);
116 return;
117 }
118
119 if (!strcasecmp(val, "broken")) {
120 value = SPAPR_CAP_BROKEN;
121 } else if (!strcasecmp(val, "workaround")) {
122 value = SPAPR_CAP_WORKAROUND;
123 } else if (!strcasecmp(val, "fixed")) {
124 value = SPAPR_CAP_FIXED;
125 } else {
126 error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
127 cap->name);
128 goto out;
129 }
130
131 spapr->cmd_line_caps[cap->index] = true;
132 spapr->eff.caps[cap->index] = value;
133out:
134 g_free(val);
135}
136
137static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
138{
139 if (!val) {
140
141 return;
142 }
143 if (tcg_enabled()) {
144 error_setg(errp,
145 "No Transactional Memory support in TCG, try cap-htm=off");
146 } else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
147 error_setg(errp,
148"KVM implementation does not support Transactional Memory, try cap-htm=off"
149 );
150 }
151}
152
153static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
154{
155 PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
156 CPUPPCState *env = &cpu->env;
157
158 if (!val) {
159
160 return;
161 }
162
163
164 g_assert(env->insns_flags & PPC_ALTIVEC);
165 if (!(env->insns_flags2 & PPC2_VSX)) {
166 error_setg(errp, "VSX support not available, try cap-vsx=off");
167 }
168}
169
170static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
171{
172 PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
173 CPUPPCState *env = &cpu->env;
174
175 if (!val) {
176
177 return;
178 }
179 if (!(env->insns_flags2 & PPC2_DFP)) {
180 error_setg(errp, "DFP support not available, try cap-dfp=off");
181 }
182}
183
184static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
185 Error **errp)
186{
187 if (tcg_enabled() && val) {
188
189 error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
190 } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) {
191 error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc");
192 }
193}
194
195static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
196 Error **errp)
197{
198 if (tcg_enabled() && val) {
199
200 error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
201 } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) {
202 error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc");
203 }
204}
205
206static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
207 uint8_t val, Error **errp)
208{
209 if (tcg_enabled() && val) {
210
211 error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
212 } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) {
213 error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs");
214 }
215}
216
217#define VALUE_DESC_TRISTATE " (broken, workaround, fixed)"
218
219sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
220 [SPAPR_CAP_HTM] = {
221 .name = "htm",
222 .description = "Allow Hardware Transactional Memory (HTM)",
223 .options = "",
224 .index = SPAPR_CAP_HTM,
225 .get = spapr_cap_get_bool,
226 .set = spapr_cap_set_bool,
227 .type = "bool",
228 .apply = cap_htm_apply,
229 },
230 [SPAPR_CAP_VSX] = {
231 .name = "vsx",
232 .description = "Allow Vector Scalar Extensions (VSX)",
233 .options = "",
234 .index = SPAPR_CAP_VSX,
235 .get = spapr_cap_get_bool,
236 .set = spapr_cap_set_bool,
237 .type = "bool",
238 .apply = cap_vsx_apply,
239 },
240 [SPAPR_CAP_DFP] = {
241 .name = "dfp",
242 .description = "Allow Decimal Floating Point (DFP)",
243 .options = "",
244 .index = SPAPR_CAP_DFP,
245 .get = spapr_cap_get_bool,
246 .set = spapr_cap_set_bool,
247 .type = "bool",
248 .apply = cap_dfp_apply,
249 },
250 [SPAPR_CAP_CFPC] = {
251 .name = "cfpc",
252 .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE,
253 .index = SPAPR_CAP_CFPC,
254 .get = spapr_cap_get_tristate,
255 .set = spapr_cap_set_tristate,
256 .type = "string",
257 .apply = cap_safe_cache_apply,
258 },
259 [SPAPR_CAP_SBBC] = {
260 .name = "sbbc",
261 .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE,
262 .index = SPAPR_CAP_SBBC,
263 .get = spapr_cap_get_tristate,
264 .set = spapr_cap_set_tristate,
265 .type = "string",
266 .apply = cap_safe_bounds_check_apply,
267 },
268 [SPAPR_CAP_IBS] = {
269 .name = "ibs",
270 .description = "Indirect Branch Serialisation" VALUE_DESC_TRISTATE,
271 .index = SPAPR_CAP_IBS,
272 .get = spapr_cap_get_tristate,
273 .set = spapr_cap_set_tristate,
274 .type = "string",
275 .apply = cap_safe_indirect_branch_apply,
276 },
277};
278
279static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
280 CPUState *cs)
281{
282 sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
283 PowerPCCPU *cpu = POWERPC_CPU(cs);
284 sPAPRCapabilities caps;
285
286 caps = smc->default_caps;
287
288 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
289 0, spapr->max_compat_pvr)) {
290 caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
291 }
292
293 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
294 0, spapr->max_compat_pvr)) {
295 caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
296 caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
297 }
298
299 return caps;
300}
301
302int spapr_caps_pre_load(void *opaque)
303{
304 sPAPRMachineState *spapr = opaque;
305
306
307 spapr->mig = spapr->def;
308 return 0;
309}
310
311int spapr_caps_pre_save(void *opaque)
312{
313 sPAPRMachineState *spapr = opaque;
314
315 spapr->mig = spapr->eff;
316 return 0;
317}
318
319
320
321
322
323int spapr_caps_post_migration(sPAPRMachineState *spapr)
324{
325 int i;
326 bool ok = true;
327 sPAPRCapabilities dstcaps = spapr->eff;
328 sPAPRCapabilities srccaps;
329
330 srccaps = default_caps_with_cpu(spapr, first_cpu);
331 for (i = 0; i < SPAPR_CAP_NUM; i++) {
332
333 if (spapr->mig.caps[i] != spapr->def.caps[i]) {
334 srccaps.caps[i] = spapr->mig.caps[i];
335 }
336 }
337
338 for (i = 0; i < SPAPR_CAP_NUM; i++) {
339 sPAPRCapabilityInfo *info = &capability_table[i];
340
341 if (srccaps.caps[i] > dstcaps.caps[i]) {
342 error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)",
343 info->name, srccaps.caps[i], dstcaps.caps[i]);
344 ok = false;
345 }
346
347 if (srccaps.caps[i] < dstcaps.caps[i]) {
348 warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)",
349 info->name, srccaps.caps[i], dstcaps.caps[i]);
350 }
351 }
352
353 return ok ? 0 : -EINVAL;
354}
355
356
357#define SPAPR_CAP_MIG_STATE(cap, ccap) \
358static bool spapr_cap_##cap##_needed(void *opaque) \
359{ \
360 sPAPRMachineState *spapr = opaque; \
361 \
362 return spapr->cmd_line_caps[SPAPR_CAP_##ccap] && \
363 (spapr->eff.caps[SPAPR_CAP_##ccap] != \
364 spapr->def.caps[SPAPR_CAP_##ccap]); \
365} \
366 \
367const VMStateDescription vmstate_spapr_cap_##cap = { \
368 .name = "spapr/cap/" #cap, \
369 .version_id = 1, \
370 .minimum_version_id = 1, \
371 .needed = spapr_cap_##cap##_needed, \
372 .fields = (VMStateField[]) { \
373 VMSTATE_UINT8(mig.caps[SPAPR_CAP_##ccap], \
374 sPAPRMachineState), \
375 VMSTATE_END_OF_LIST() \
376 }, \
377}
378
379SPAPR_CAP_MIG_STATE(htm, HTM);
380SPAPR_CAP_MIG_STATE(vsx, VSX);
381SPAPR_CAP_MIG_STATE(dfp, DFP);
382SPAPR_CAP_MIG_STATE(cfpc, CFPC);
383SPAPR_CAP_MIG_STATE(sbbc, SBBC);
384SPAPR_CAP_MIG_STATE(ibs, IBS);
385
386void spapr_caps_reset(sPAPRMachineState *spapr)
387{
388 sPAPRCapabilities default_caps;
389 int i;
390
391
392 default_caps = default_caps_with_cpu(spapr, first_cpu);
393
394 for (i = 0; i < SPAPR_CAP_NUM; i++) {
395
396 spapr->def.caps[i] = default_caps.caps[i];
397
398 if (!spapr->cmd_line_caps[i]) {
399 spapr->eff.caps[i] = default_caps.caps[i];
400 }
401 }
402
403
404
405 for (i = 0; i < SPAPR_CAP_NUM; i++) {
406 sPAPRCapabilityInfo *info = &capability_table[i];
407
408
409
410
411
412 info->apply(spapr, spapr->eff.caps[i], &error_fatal);
413 }
414}
415
416void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
417{
418 Error *local_err = NULL;
419 ObjectClass *klass = OBJECT_CLASS(smc);
420 int i;
421
422 for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
423 sPAPRCapabilityInfo *cap = &capability_table[i];
424 const char *name = g_strdup_printf("cap-%s", cap->name);
425 char *desc;
426
427 object_class_property_add(klass, name, cap->type,
428 cap->get, cap->set,
429 NULL, cap, &local_err);
430 if (local_err) {
431 error_propagate(errp, local_err);
432 return;
433 }
434
435 desc = g_strdup_printf("%s%s", cap->description, cap->options);
436 object_class_property_set_description(klass, name, desc, &local_err);
437 g_free(desc);
438 if (local_err) {
439 error_propagate(errp, local_err);
440 return;
441 }
442 }
443}
444