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