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