qemu/hw/ppc/spapr_caps.c
<<
>>
Prefs
   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
  35typedef struct sPAPRCapPossible {
  36    int num;            /* size of vals array below */
  37    const char *help;   /* help text for vals */
  38    /*
  39     * Note:
  40     * - because of the way compatibility is determined vals MUST be ordered
  41     *   such that later options are a superset of all preceding options.
  42     * - the order of vals must be preserved, that is their index is important,
  43     *   however vals may be added to the end of the list so long as the above
  44     *   point is observed
  45     */
  46    const char *vals[];
  47} sPAPRCapPossible;
  48
  49typedef struct sPAPRCapabilityInfo {
  50    const char *name;
  51    const char *description;
  52    int index;
  53
  54    /* Getter and Setter Function Pointers */
  55    ObjectPropertyAccessor *get;
  56    ObjectPropertyAccessor *set;
  57    const char *type;
  58    /* Possible values if this is a custom string type */
  59    sPAPRCapPossible *possible;
  60    /* Make sure the virtual hardware can support this capability */
  61    void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
  62} sPAPRCapabilityInfo;
  63
  64static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
  65                               void *opaque, Error **errp)
  66{
  67    sPAPRCapabilityInfo *cap = opaque;
  68    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
  69    bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
  70
  71    visit_type_bool(v, name, &value, errp);
  72}
  73
  74static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
  75                               void *opaque, Error **errp)
  76{
  77    sPAPRCapabilityInfo *cap = opaque;
  78    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
  79    bool value;
  80    Error *local_err = NULL;
  81
  82    visit_type_bool(v, name, &value, &local_err);
  83    if (local_err) {
  84        error_propagate(errp, local_err);
  85        return;
  86    }
  87
  88    spapr->cmd_line_caps[cap->index] = true;
  89    spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
  90}
  91
  92
  93static void  spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
  94                                  void *opaque, Error **errp)
  95{
  96    sPAPRCapabilityInfo *cap = opaque;
  97    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
  98    char *val = NULL;
  99    uint8_t value = spapr_get_cap(spapr, cap->index);
 100
 101    if (value >= cap->possible->num) {
 102        error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
 103        return;
 104    }
 105
 106    val = g_strdup(cap->possible->vals[value]);
 107
 108    visit_type_str(v, name, &val, errp);
 109    g_free(val);
 110}
 111
 112static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name,
 113                                 void *opaque, Error **errp)
 114{
 115    sPAPRCapabilityInfo *cap = opaque;
 116    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
 117    Error *local_err = NULL;
 118    uint8_t i;
 119    char *val;
 120
 121    visit_type_str(v, name, &val, &local_err);
 122    if (local_err) {
 123        error_propagate(errp, local_err);
 124        return;
 125    }
 126
 127    if (!strcmp(val, "?")) {
 128        error_setg(errp, "%s", cap->possible->help);
 129        goto out;
 130    }
 131    for (i = 0; i < cap->possible->num; i++) {
 132        if (!strcasecmp(val, cap->possible->vals[i])) {
 133            spapr->cmd_line_caps[cap->index] = true;
 134            spapr->eff.caps[cap->index] = i;
 135            goto out;
 136        }
 137    }
 138
 139    error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
 140               cap->name);
 141out:
 142    g_free(val);
 143}
 144
 145static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
 146{
 147    if (!val) {
 148        /* TODO: We don't support disabling htm yet */
 149        return;
 150    }
 151    if (tcg_enabled()) {
 152        error_setg(errp,
 153                   "No Transactional Memory support in TCG, try cap-htm=off");
 154    } else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
 155        error_setg(errp,
 156"KVM implementation does not support Transactional Memory, try cap-htm=off"
 157            );
 158    }
 159}
 160
 161static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
 162{
 163    PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
 164    CPUPPCState *env = &cpu->env;
 165
 166    if (!val) {
 167        /* TODO: We don't support disabling vsx yet */
 168        return;
 169    }
 170    /* Allowable CPUs in spapr_cpu_core.c should already have gotten
 171     * rid of anything that doesn't do VMX */
 172    g_assert(env->insns_flags & PPC_ALTIVEC);
 173    if (!(env->insns_flags2 & PPC2_VSX)) {
 174        error_setg(errp, "VSX support not available, try cap-vsx=off");
 175    }
 176}
 177
 178static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
 179{
 180    PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
 181    CPUPPCState *env = &cpu->env;
 182
 183    if (!val) {
 184        /* TODO: We don't support disabling dfp yet */
 185        return;
 186    }
 187    if (!(env->insns_flags2 & PPC2_DFP)) {
 188        error_setg(errp, "DFP support not available, try cap-dfp=off");
 189    }
 190}
 191
 192sPAPRCapPossible cap_cfpc_possible = {
 193    .num = 3,
 194    .vals = {"broken", "workaround", "fixed"},
 195    .help = "broken - no protection, workaround - workaround available,"
 196            " fixed - fixed in hardware",
 197};
 198
 199static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
 200                                 Error **errp)
 201{
 202    uint8_t kvm_val =  kvmppc_get_cap_safe_cache();
 203
 204    if (tcg_enabled() && val) {
 205        /* TODO - for now only allow broken for TCG */
 206        error_setg(errp,
 207"Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
 208    } else if (kvm_enabled() && (val > kvm_val)) {
 209        error_setg(errp,
 210"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
 211                   cap_cfpc_possible.vals[kvm_val]);
 212    }
 213}
 214
 215sPAPRCapPossible cap_sbbc_possible = {
 216    .num = 3,
 217    .vals = {"broken", "workaround", "fixed"},
 218    .help = "broken - no protection, workaround - workaround available,"
 219            " fixed - fixed in hardware",
 220};
 221
 222static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
 223                                        Error **errp)
 224{
 225    uint8_t kvm_val =  kvmppc_get_cap_safe_bounds_check();
 226
 227    if (tcg_enabled() && val) {
 228        /* TODO - for now only allow broken for TCG */
 229        error_setg(errp,
 230"Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
 231    } else if (kvm_enabled() && (val > kvm_val)) {
 232        error_setg(errp,
 233"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
 234                   cap_sbbc_possible.vals[kvm_val]);
 235    }
 236}
 237
 238sPAPRCapPossible cap_ibs_possible = {
 239    .num = 4,
 240    /* Note workaround only maintained for compatibility */
 241    .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"},
 242    .help = "broken - no protection, fixed-ibs - indirect branch serialisation,"
 243            " fixed-ccd - cache count disabled",
 244};
 245
 246static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
 247                                           uint8_t val, Error **errp)
 248{
 249    uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch();
 250
 251    if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */
 252        error_setg(errp,
 253"Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s",
 254                   cap_ibs_possible.vals[kvm_val]);
 255    } else if (tcg_enabled() && val) {
 256        /* TODO - for now only allow broken for TCG */
 257        error_setg(errp,
 258"Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
 259    } else if (kvm_enabled() && val && (val != kvm_val)) {
 260        error_setg(errp,
 261"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
 262                   cap_ibs_possible.vals[kvm_val]);
 263    }
 264}
 265
 266#define VALUE_DESC_TRISTATE     " (broken, workaround, fixed)"
 267
 268sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
 269    [SPAPR_CAP_HTM] = {
 270        .name = "htm",
 271        .description = "Allow Hardware Transactional Memory (HTM)",
 272        .index = SPAPR_CAP_HTM,
 273        .get = spapr_cap_get_bool,
 274        .set = spapr_cap_set_bool,
 275        .type = "bool",
 276        .apply = cap_htm_apply,
 277    },
 278    [SPAPR_CAP_VSX] = {
 279        .name = "vsx",
 280        .description = "Allow Vector Scalar Extensions (VSX)",
 281        .index = SPAPR_CAP_VSX,
 282        .get = spapr_cap_get_bool,
 283        .set = spapr_cap_set_bool,
 284        .type = "bool",
 285        .apply = cap_vsx_apply,
 286    },
 287    [SPAPR_CAP_DFP] = {
 288        .name = "dfp",
 289        .description = "Allow Decimal Floating Point (DFP)",
 290        .index = SPAPR_CAP_DFP,
 291        .get = spapr_cap_get_bool,
 292        .set = spapr_cap_set_bool,
 293        .type = "bool",
 294        .apply = cap_dfp_apply,
 295    },
 296    [SPAPR_CAP_CFPC] = {
 297        .name = "cfpc",
 298        .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE,
 299        .index = SPAPR_CAP_CFPC,
 300        .get = spapr_cap_get_string,
 301        .set = spapr_cap_set_string,
 302        .type = "string",
 303        .possible = &cap_cfpc_possible,
 304        .apply = cap_safe_cache_apply,
 305    },
 306    [SPAPR_CAP_SBBC] = {
 307        .name = "sbbc",
 308        .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE,
 309        .index = SPAPR_CAP_SBBC,
 310        .get = spapr_cap_get_string,
 311        .set = spapr_cap_set_string,
 312        .type = "string",
 313        .possible = &cap_sbbc_possible,
 314        .apply = cap_safe_bounds_check_apply,
 315    },
 316    [SPAPR_CAP_IBS] = {
 317        .name = "ibs",
 318        .description =
 319            "Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)",
 320        .index = SPAPR_CAP_IBS,
 321        .get = spapr_cap_get_string,
 322        .set = spapr_cap_set_string,
 323        .type = "string",
 324        .possible = &cap_ibs_possible,
 325        .apply = cap_safe_indirect_branch_apply,
 326    },
 327};
 328
 329static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
 330                                               CPUState *cs)
 331{
 332    sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
 333    PowerPCCPU *cpu = POWERPC_CPU(cs);
 334    sPAPRCapabilities caps;
 335
 336    caps = smc->default_caps;
 337
 338    if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00,
 339                          0, spapr->max_compat_pvr)) {
 340        caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
 341    }
 342
 343    if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
 344                          0, spapr->max_compat_pvr)) {
 345        caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
 346    }
 347
 348    if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS,
 349                          0, spapr->max_compat_pvr)) {
 350        caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
 351    }
 352
 353    if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
 354                          0, spapr->max_compat_pvr)) {
 355        caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
 356        caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
 357        caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
 358    }
 359
 360    return caps;
 361}
 362
 363int spapr_caps_pre_load(void *opaque)
 364{
 365    sPAPRMachineState *spapr = opaque;
 366
 367    /* Set to default so we can tell if this came in with the migration */
 368    spapr->mig = spapr->def;
 369    return 0;
 370}
 371
 372int spapr_caps_pre_save(void *opaque)
 373{
 374    sPAPRMachineState *spapr = opaque;
 375
 376    spapr->mig = spapr->eff;
 377    return 0;
 378}
 379
 380/* This has to be called from the top-level spapr post_load, not the
 381 * caps specific one.  Otherwise it wouldn't be called when the source
 382 * caps are all defaults, which could still conflict with overridden
 383 * caps on the destination */
 384int spapr_caps_post_migration(sPAPRMachineState *spapr)
 385{
 386    int i;
 387    bool ok = true;
 388    sPAPRCapabilities dstcaps = spapr->eff;
 389    sPAPRCapabilities srccaps;
 390
 391    srccaps = default_caps_with_cpu(spapr, first_cpu);
 392    for (i = 0; i < SPAPR_CAP_NUM; i++) {
 393        /* If not default value then assume came in with the migration */
 394        if (spapr->mig.caps[i] != spapr->def.caps[i]) {
 395            srccaps.caps[i] = spapr->mig.caps[i];
 396        }
 397    }
 398
 399    for (i = 0; i < SPAPR_CAP_NUM; i++) {
 400        sPAPRCapabilityInfo *info = &capability_table[i];
 401
 402        if (srccaps.caps[i] > dstcaps.caps[i]) {
 403            error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)",
 404                         info->name, srccaps.caps[i], dstcaps.caps[i]);
 405            ok = false;
 406        }
 407
 408        if (srccaps.caps[i] < dstcaps.caps[i]) {
 409            warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)",
 410                         info->name, srccaps.caps[i], dstcaps.caps[i]);
 411        }
 412    }
 413
 414    return ok ? 0 : -EINVAL;
 415}
 416
 417/* Used to generate the migration field and needed function for a spapr cap */
 418#define SPAPR_CAP_MIG_STATE(sname, cap)                 \
 419static bool spapr_cap_##sname##_needed(void *opaque)    \
 420{                                                       \
 421    sPAPRMachineState *spapr = opaque;                  \
 422                                                        \
 423    return spapr->cmd_line_caps[cap] &&                 \
 424           (spapr->eff.caps[cap] !=                     \
 425            spapr->def.caps[cap]);                      \
 426}                                                       \
 427                                                        \
 428const VMStateDescription vmstate_spapr_cap_##sname = {  \
 429    .name = "spapr/cap/" #sname,                        \
 430    .version_id = 1,                                    \
 431    .minimum_version_id = 1,                            \
 432    .needed = spapr_cap_##sname##_needed,               \
 433    .fields = (VMStateField[]) {                        \
 434        VMSTATE_UINT8(mig.caps[cap],                    \
 435                      sPAPRMachineState),               \
 436        VMSTATE_END_OF_LIST()                           \
 437    },                                                  \
 438}
 439
 440SPAPR_CAP_MIG_STATE(htm, SPAPR_CAP_HTM);
 441SPAPR_CAP_MIG_STATE(vsx, SPAPR_CAP_VSX);
 442SPAPR_CAP_MIG_STATE(dfp, SPAPR_CAP_DFP);
 443SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC);
 444SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC);
 445SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS);
 446
 447void spapr_caps_reset(sPAPRMachineState *spapr)
 448{
 449    sPAPRCapabilities default_caps;
 450    int i;
 451
 452    /* First compute the actual set of caps we're running with.. */
 453    default_caps = default_caps_with_cpu(spapr, first_cpu);
 454
 455    for (i = 0; i < SPAPR_CAP_NUM; i++) {
 456        /* Store the defaults */
 457        spapr->def.caps[i] = default_caps.caps[i];
 458        /* If not set on the command line then apply the default value */
 459        if (!spapr->cmd_line_caps[i]) {
 460            spapr->eff.caps[i] = default_caps.caps[i];
 461        }
 462    }
 463
 464    /* .. then apply those caps to the virtual hardware */
 465
 466    for (i = 0; i < SPAPR_CAP_NUM; i++) {
 467        sPAPRCapabilityInfo *info = &capability_table[i];
 468
 469        /*
 470         * If the apply function can't set the desired level and thinks it's
 471         * fatal, it should cause that.
 472         */
 473        info->apply(spapr, spapr->eff.caps[i], &error_fatal);
 474    }
 475}
 476
 477void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
 478{
 479    Error *local_err = NULL;
 480    ObjectClass *klass = OBJECT_CLASS(smc);
 481    int i;
 482
 483    for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
 484        sPAPRCapabilityInfo *cap = &capability_table[i];
 485        const char *name = g_strdup_printf("cap-%s", cap->name);
 486        char *desc;
 487
 488        object_class_property_add(klass, name, cap->type,
 489                                  cap->get, cap->set,
 490                                  NULL, cap, &local_err);
 491        if (local_err) {
 492            error_propagate(errp, local_err);
 493            return;
 494        }
 495
 496        desc = g_strdup_printf("%s", cap->description);
 497        object_class_property_set_description(klass, name, desc, &local_err);
 498        g_free(desc);
 499        if (local_err) {
 500            error_propagate(errp, local_err);
 501            return;
 502        }
 503    }
 504}
 505