1 /* 2 * QEMU PowerPC pSeries Logical Partition capabilities handling 3 * 4 * Copyright (c) 2017 David Gibson, Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 #include "qemu/osdep.h" 25 #include "qemu/error-report.h" 26 #include "qapi/error.h" 27 #include "qapi/visitor.h" 28 #include "sysemu/hw_accel.h" 29 #include "target/ppc/cpu.h" 30 #include "cpu-models.h" 31 #include "kvm_ppc.h" 32 33 #include "hw/ppc/spapr.h" 34 35 typedef struct sPAPRCapabilityInfo { 36 const char *name; 37 const char *description; 38 int index; 39 40 /* Getter and Setter Function Pointers */ 41 ObjectPropertyAccessor *get; 42 ObjectPropertyAccessor *set; 43 const char *type; 44 /* Make sure the virtual hardware can support this capability */ 45 void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp); 46 } sPAPRCapabilityInfo; 47 48 static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name, 49 void *opaque, Error **errp) 50 { 51 sPAPRCapabilityInfo *cap = opaque; 52 sPAPRMachineState *spapr = SPAPR_MACHINE(obj); 53 bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON; 54 55 visit_type_bool(v, name, &value, errp); 56 } 57 58 static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, 59 void *opaque, Error **errp) 60 { 61 sPAPRCapabilityInfo *cap = opaque; 62 sPAPRMachineState *spapr = SPAPR_MACHINE(obj); 63 bool value; 64 Error *local_err = NULL; 65 66 visit_type_bool(v, name, &value, &local_err); 67 if (local_err) { 68 error_propagate(errp, local_err); 69 return; 70 } 71 72 spapr->cmd_line_caps[cap->index] = true; 73 spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; 74 } 75 76 static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name, 77 void *opaque, Error **errp) 78 { 79 sPAPRCapabilityInfo *cap = opaque; 80 sPAPRMachineState *spapr = SPAPR_MACHINE(obj); 81 char *val = NULL; 82 uint8_t value = spapr_get_cap(spapr, cap->index); 83 84 switch (value) { 85 case SPAPR_CAP_BROKEN: 86 val = g_strdup("broken"); 87 break; 88 case SPAPR_CAP_WORKAROUND: 89 val = g_strdup("workaround"); 90 break; 91 case SPAPR_CAP_FIXED: 92 val = g_strdup("fixed"); 93 break; 94 default: 95 error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name); 96 return; 97 } 98 99 visit_type_str(v, name, &val, errp); 100 g_free(val); 101 } 102 103 static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name, 104 void *opaque, Error **errp) 105 { 106 sPAPRCapabilityInfo *cap = opaque; 107 sPAPRMachineState *spapr = SPAPR_MACHINE(obj); 108 char *val; 109 Error *local_err = NULL; 110 uint8_t value; 111 112 visit_type_str(v, name, &val, &local_err); 113 if (local_err) { 114 error_propagate(errp, local_err); 115 return; 116 } 117 118 if (!strcasecmp(val, "broken")) { 119 value = SPAPR_CAP_BROKEN; 120 } else if (!strcasecmp(val, "workaround")) { 121 value = SPAPR_CAP_WORKAROUND; 122 } else if (!strcasecmp(val, "fixed")) { 123 value = SPAPR_CAP_FIXED; 124 } else { 125 error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val, 126 cap->name); 127 goto out; 128 } 129 130 spapr->cmd_line_caps[cap->index] = true; 131 spapr->eff.caps[cap->index] = value; 132 out: 133 g_free(val); 134 } 135 136 static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) 137 { 138 if (!val) { 139 /* TODO: We don't support disabling htm yet */ 140 return; 141 } 142 if (tcg_enabled()) { 143 error_setg(errp, 144 "No Transactional Memory support in TCG, try cap-htm=off"); 145 } else if (kvm_enabled() && !kvmppc_has_cap_htm()) { 146 error_setg(errp, 147 "KVM implementation does not support Transactional Memory, try cap-htm=off" 148 ); 149 } 150 } 151 152 static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) 153 { 154 PowerPCCPU *cpu = POWERPC_CPU(first_cpu); 155 CPUPPCState *env = &cpu->env; 156 157 if (!val) { 158 /* TODO: We don't support disabling vsx yet */ 159 return; 160 } 161 /* Allowable CPUs in spapr_cpu_core.c should already have gotten 162 * rid of anything that doesn't do VMX */ 163 g_assert(env->insns_flags & PPC_ALTIVEC); 164 if (!(env->insns_flags2 & PPC2_VSX)) { 165 error_setg(errp, "VSX support not available, try cap-vsx=off"); 166 } 167 } 168 169 static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) 170 { 171 PowerPCCPU *cpu = POWERPC_CPU(first_cpu); 172 CPUPPCState *env = &cpu->env; 173 174 if (!val) { 175 /* TODO: We don't support disabling dfp yet */ 176 return; 177 } 178 if (!(env->insns_flags2 & PPC2_DFP)) { 179 error_setg(errp, "DFP support not available, try cap-dfp=off"); 180 } 181 } 182 183 static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, 184 Error **errp) 185 { 186 if (tcg_enabled() && val) { 187 /* TODO - for now only allow broken for TCG */ 188 error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc"); 189 } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) { 190 error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc"); 191 } 192 } 193 194 static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, 195 Error **errp) 196 { 197 if (tcg_enabled() && val) { 198 /* TODO - for now only allow broken for TCG */ 199 error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc"); 200 } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) { 201 error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc"); 202 } 203 } 204 205 static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr, 206 uint8_t val, Error **errp) 207 { 208 if (tcg_enabled() && val) { 209 /* TODO - for now only allow broken for TCG */ 210 error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); 211 } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) { 212 error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs"); 213 } 214 } 215 216 #define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" 217 218 sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { 219 [SPAPR_CAP_HTM] = { 220 .name = "htm", 221 .description = "Allow Hardware Transactional Memory (HTM)", 222 .index = SPAPR_CAP_HTM, 223 .get = spapr_cap_get_bool, 224 .set = spapr_cap_set_bool, 225 .type = "bool", 226 .apply = cap_htm_apply, 227 }, 228 [SPAPR_CAP_VSX] = { 229 .name = "vsx", 230 .description = "Allow Vector Scalar Extensions (VSX)", 231 .index = SPAPR_CAP_VSX, 232 .get = spapr_cap_get_bool, 233 .set = spapr_cap_set_bool, 234 .type = "bool", 235 .apply = cap_vsx_apply, 236 }, 237 [SPAPR_CAP_DFP] = { 238 .name = "dfp", 239 .description = "Allow Decimal Floating Point (DFP)", 240 .index = SPAPR_CAP_DFP, 241 .get = spapr_cap_get_bool, 242 .set = spapr_cap_set_bool, 243 .type = "bool", 244 .apply = cap_dfp_apply, 245 }, 246 [SPAPR_CAP_CFPC] = { 247 .name = "cfpc", 248 .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE, 249 .index = SPAPR_CAP_CFPC, 250 .get = spapr_cap_get_tristate, 251 .set = spapr_cap_set_tristate, 252 .type = "string", 253 .apply = cap_safe_cache_apply, 254 }, 255 [SPAPR_CAP_SBBC] = { 256 .name = "sbbc", 257 .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE, 258 .index = SPAPR_CAP_SBBC, 259 .get = spapr_cap_get_tristate, 260 .set = spapr_cap_set_tristate, 261 .type = "string", 262 .apply = cap_safe_bounds_check_apply, 263 }, 264 [SPAPR_CAP_IBS] = { 265 .name = "ibs", 266 .description = "Indirect Branch Serialisation" VALUE_DESC_TRISTATE, 267 .index = SPAPR_CAP_IBS, 268 .get = spapr_cap_get_tristate, 269 .set = spapr_cap_set_tristate, 270 .type = "string", 271 .apply = cap_safe_indirect_branch_apply, 272 }, 273 }; 274 275 static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, 276 CPUState *cs) 277 { 278 sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); 279 PowerPCCPU *cpu = POWERPC_CPU(cs); 280 sPAPRCapabilities caps; 281 282 caps = smc->default_caps; 283 284 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 285 0, spapr->max_compat_pvr)) { 286 caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; 287 } 288 289 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 290 0, spapr->max_compat_pvr)) { 291 caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF; 292 caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF; 293 } 294 295 return caps; 296 } 297 298 int spapr_caps_pre_load(void *opaque) 299 { 300 sPAPRMachineState *spapr = opaque; 301 302 /* Set to default so we can tell if this came in with the migration */ 303 spapr->mig = spapr->def; 304 return 0; 305 } 306 307 int spapr_caps_pre_save(void *opaque) 308 { 309 sPAPRMachineState *spapr = opaque; 310 311 spapr->mig = spapr->eff; 312 return 0; 313 } 314 315 /* This has to be called from the top-level spapr post_load, not the 316 * caps specific one. Otherwise it wouldn't be called when the source 317 * caps are all defaults, which could still conflict with overridden 318 * caps on the destination */ 319 int spapr_caps_post_migration(sPAPRMachineState *spapr) 320 { 321 int i; 322 bool ok = true; 323 sPAPRCapabilities dstcaps = spapr->eff; 324 sPAPRCapabilities srccaps; 325 326 srccaps = default_caps_with_cpu(spapr, first_cpu); 327 for (i = 0; i < SPAPR_CAP_NUM; i++) { 328 /* If not default value then assume came in with the migration */ 329 if (spapr->mig.caps[i] != spapr->def.caps[i]) { 330 srccaps.caps[i] = spapr->mig.caps[i]; 331 } 332 } 333 334 for (i = 0; i < SPAPR_CAP_NUM; i++) { 335 sPAPRCapabilityInfo *info = &capability_table[i]; 336 337 if (srccaps.caps[i] > dstcaps.caps[i]) { 338 error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)", 339 info->name, srccaps.caps[i], dstcaps.caps[i]); 340 ok = false; 341 } 342 343 if (srccaps.caps[i] < dstcaps.caps[i]) { 344 warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)", 345 info->name, srccaps.caps[i], dstcaps.caps[i]); 346 } 347 } 348 349 return ok ? 0 : -EINVAL; 350 } 351 352 /* Used to generate the migration field and needed function for a spapr cap */ 353 #define SPAPR_CAP_MIG_STATE(cap, ccap) \ 354 static bool spapr_cap_##cap##_needed(void *opaque) \ 355 { \ 356 sPAPRMachineState *spapr = opaque; \ 357 \ 358 return spapr->cmd_line_caps[SPAPR_CAP_##ccap] && \ 359 (spapr->eff.caps[SPAPR_CAP_##ccap] != \ 360 spapr->def.caps[SPAPR_CAP_##ccap]); \ 361 } \ 362 \ 363 const VMStateDescription vmstate_spapr_cap_##cap = { \ 364 .name = "spapr/cap/" #cap, \ 365 .version_id = 1, \ 366 .minimum_version_id = 1, \ 367 .needed = spapr_cap_##cap##_needed, \ 368 .fields = (VMStateField[]) { \ 369 VMSTATE_UINT8(mig.caps[SPAPR_CAP_##ccap], \ 370 sPAPRMachineState), \ 371 VMSTATE_END_OF_LIST() \ 372 }, \ 373 } 374 375 SPAPR_CAP_MIG_STATE(htm, HTM); 376 SPAPR_CAP_MIG_STATE(vsx, VSX); 377 SPAPR_CAP_MIG_STATE(dfp, DFP); 378 SPAPR_CAP_MIG_STATE(cfpc, CFPC); 379 SPAPR_CAP_MIG_STATE(sbbc, SBBC); 380 SPAPR_CAP_MIG_STATE(ibs, IBS); 381 382 void spapr_caps_reset(sPAPRMachineState *spapr) 383 { 384 sPAPRCapabilities default_caps; 385 int i; 386 387 /* First compute the actual set of caps we're running with.. */ 388 default_caps = default_caps_with_cpu(spapr, first_cpu); 389 390 for (i = 0; i < SPAPR_CAP_NUM; i++) { 391 /* Store the defaults */ 392 spapr->def.caps[i] = default_caps.caps[i]; 393 /* If not set on the command line then apply the default value */ 394 if (!spapr->cmd_line_caps[i]) { 395 spapr->eff.caps[i] = default_caps.caps[i]; 396 } 397 } 398 399 /* .. then apply those caps to the virtual hardware */ 400 401 for (i = 0; i < SPAPR_CAP_NUM; i++) { 402 sPAPRCapabilityInfo *info = &capability_table[i]; 403 404 /* 405 * If the apply function can't set the desired level and thinks it's 406 * fatal, it should cause that. 407 */ 408 info->apply(spapr, spapr->eff.caps[i], &error_fatal); 409 } 410 } 411 412 void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp) 413 { 414 Error *local_err = NULL; 415 ObjectClass *klass = OBJECT_CLASS(smc); 416 int i; 417 418 for (i = 0; i < ARRAY_SIZE(capability_table); i++) { 419 sPAPRCapabilityInfo *cap = &capability_table[i]; 420 const char *name = g_strdup_printf("cap-%s", cap->name); 421 char *desc; 422 423 object_class_property_add(klass, name, cap->type, 424 cap->get, cap->set, 425 NULL, cap, &local_err); 426 if (local_err) { 427 error_propagate(errp, local_err); 428 return; 429 } 430 431 desc = g_strdup_printf("%s", cap->description); 432 object_class_property_set_description(klass, name, desc, &local_err); 433 g_free(desc); 434 if (local_err) { 435 error_propagate(errp, local_err); 436 return; 437 } 438 } 439 } 440