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