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