qemu/target/ppc/compat.c
<<
>>
Prefs
   1/*
   2 *  PowerPC CPU initialization for qemu.
   3 *
   4 *  Copyright 2016, David Gibson, Red Hat Inc. <dgibson@redhat.com>
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "sysemu/hw_accel.h"
  22#include "sysemu/kvm.h"
  23#include "kvm_ppc.h"
  24#include "sysemu/cpus.h"
  25#include "qemu/error-report.h"
  26#include "qapi/error.h"
  27#include "qapi/visitor.h"
  28#include "cpu-models.h"
  29
  30typedef struct {
  31    const char *name;
  32    uint32_t pvr;
  33    uint64_t pcr;
  34    uint64_t pcr_level;
  35
  36    /*
  37     * Maximum allowed virtual threads per virtual core
  38     *
  39     * This is to stop older guests getting confused by seeing more
  40     * threads than they think the cpu can support.  Usually it's
  41     * equal to the number of threads supported on bare metal
  42     * hardware, but not always (see POWER9).
  43     */
  44    int max_vthreads;
  45} CompatInfo;
  46
  47static const CompatInfo compat_table[] = {
  48    /*
  49     * Ordered from oldest to newest - the code relies on this
  50     */
  51    { /* POWER6, ISA2.05 */
  52        .name = "power6",
  53        .pvr = CPU_POWERPC_LOGICAL_2_05,
  54        .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
  55               PCR_COMPAT_2_05 | PCR_TM_DIS | PCR_VSX_DIS,
  56        .pcr_level = PCR_COMPAT_2_05,
  57        .max_vthreads = 2,
  58    },
  59    { /* POWER7, ISA2.06 */
  60        .name = "power7",
  61        .pvr = CPU_POWERPC_LOGICAL_2_06,
  62        .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
  63        .pcr_level = PCR_COMPAT_2_06,
  64        .max_vthreads = 4,
  65    },
  66    {
  67        .name = "power7+",
  68        .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
  69        .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
  70        .pcr_level = PCR_COMPAT_2_06,
  71        .max_vthreads = 4,
  72    },
  73    { /* POWER8, ISA2.07 */
  74        .name = "power8",
  75        .pvr = CPU_POWERPC_LOGICAL_2_07,
  76        .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07,
  77        .pcr_level = PCR_COMPAT_2_07,
  78        .max_vthreads = 8,
  79    },
  80    { /* POWER9, ISA3.00 */
  81        .name = "power9",
  82        .pvr = CPU_POWERPC_LOGICAL_3_00,
  83        .pcr = PCR_COMPAT_3_00,
  84        .pcr_level = PCR_COMPAT_3_00,
  85        /*
  86         * POWER9 hardware only supports 4 threads / core, but this
  87         * limit is for guests.  We need to support 8 vthreads/vcore
  88         * on POWER9 for POWER8 compatibility guests, and it's very
  89         * confusing if half of the threads disappear from the guest
  90         * if it announces it's POWER9 aware at CAS time.
  91         */
  92        .max_vthreads = 8,
  93    },
  94};
  95
  96static const CompatInfo *compat_by_pvr(uint32_t pvr)
  97{
  98    int i;
  99
 100    for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
 101        if (compat_table[i].pvr == pvr) {
 102            return &compat_table[i];
 103        }
 104    }
 105    return NULL;
 106}
 107
 108static bool pcc_compat(PowerPCCPUClass *pcc, uint32_t compat_pvr,
 109                       uint32_t min_compat_pvr, uint32_t max_compat_pvr)
 110{
 111    const CompatInfo *compat = compat_by_pvr(compat_pvr);
 112    const CompatInfo *min = compat_by_pvr(min_compat_pvr);
 113    const CompatInfo *max = compat_by_pvr(max_compat_pvr);
 114
 115    g_assert(!min_compat_pvr || min);
 116    g_assert(!max_compat_pvr || max);
 117
 118    if (!compat) {
 119        /* Not a recognized logical PVR */
 120        return false;
 121    }
 122    if ((min && (compat < min)) || (max && (compat > max))) {
 123        /* Outside specified range */
 124        return false;
 125    }
 126    if (!(pcc->pcr_supported & compat->pcr_level)) {
 127        /* Not supported by this CPU */
 128        return false;
 129    }
 130    return true;
 131}
 132
 133bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
 134                      uint32_t min_compat_pvr, uint32_t max_compat_pvr)
 135{
 136    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
 137
 138#if !defined(CONFIG_USER_ONLY)
 139    g_assert(cpu->vhyp);
 140#endif
 141
 142    return pcc_compat(pcc, compat_pvr, min_compat_pvr, max_compat_pvr);
 143}
 144
 145bool ppc_type_check_compat(const char *cputype, uint32_t compat_pvr,
 146                           uint32_t min_compat_pvr, uint32_t max_compat_pvr)
 147{
 148    PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(object_class_by_name(cputype));
 149    return pcc_compat(pcc, compat_pvr, min_compat_pvr, max_compat_pvr);
 150}
 151
 152void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
 153{
 154    const CompatInfo *compat = compat_by_pvr(compat_pvr);
 155    CPUPPCState *env = &cpu->env;
 156    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
 157    uint64_t pcr;
 158
 159    if (!compat_pvr) {
 160        pcr = 0;
 161    } else if (!compat) {
 162        error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
 163        return;
 164    } else if (!ppc_check_compat(cpu, compat_pvr, 0, 0)) {
 165        error_setg(errp, "Compatibility PVR 0x%08"PRIx32" not valid for CPU",
 166                   compat_pvr);
 167        return;
 168    } else {
 169        pcr = compat->pcr;
 170    }
 171
 172    cpu_synchronize_state(CPU(cpu));
 173
 174    if (kvm_enabled() && cpu->compat_pvr != compat_pvr) {
 175        int ret = kvmppc_set_compat(cpu, compat_pvr);
 176        if (ret < 0) {
 177            error_setg_errno(errp, -ret,
 178                             "Unable to set CPU compatibility mode in KVM");
 179            return;
 180        }
 181    }
 182
 183    cpu->compat_pvr = compat_pvr;
 184    env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
 185}
 186
 187typedef struct {
 188    uint32_t compat_pvr;
 189    Error *err;
 190} SetCompatState;
 191
 192static void do_set_compat(CPUState *cs, run_on_cpu_data arg)
 193{
 194    PowerPCCPU *cpu = POWERPC_CPU(cs);
 195    SetCompatState *s = arg.host_ptr;
 196
 197    ppc_set_compat(cpu, s->compat_pvr, &s->err);
 198}
 199
 200void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
 201{
 202    CPUState *cs;
 203
 204    CPU_FOREACH(cs) {
 205        SetCompatState s = {
 206            .compat_pvr = compat_pvr,
 207            .err = NULL,
 208        };
 209
 210        run_on_cpu(cs, do_set_compat, RUN_ON_CPU_HOST_PTR(&s));
 211
 212        if (s.err) {
 213            error_propagate(errp, s.err);
 214            return;
 215        }
 216    }
 217}
 218
 219int ppc_compat_max_vthreads(PowerPCCPU *cpu)
 220{
 221    const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
 222    int n_threads = CPU(cpu)->nr_threads;
 223
 224    if (cpu->compat_pvr) {
 225        g_assert(compat);
 226        n_threads = MIN(n_threads, compat->max_vthreads);
 227    }
 228
 229    return n_threads;
 230}
 231
 232static void ppc_compat_prop_get(Object *obj, Visitor *v, const char *name,
 233                                void *opaque, Error **errp)
 234{
 235    uint32_t compat_pvr = *((uint32_t *)opaque);
 236    const char *value;
 237
 238    if (!compat_pvr) {
 239        value = "";
 240    } else {
 241        const CompatInfo *compat = compat_by_pvr(compat_pvr);
 242
 243        g_assert(compat);
 244
 245        value = compat->name;
 246    }
 247
 248    visit_type_str(v, name, (char **)&value, errp);
 249}
 250
 251static void ppc_compat_prop_set(Object *obj, Visitor *v, const char *name,
 252                                void *opaque, Error **errp)
 253{
 254    Error *local_err = NULL;
 255    char *value;
 256    uint32_t compat_pvr;
 257
 258    visit_type_str(v, name, &value, &local_err);
 259    if (local_err) {
 260        error_propagate(errp, local_err);
 261        return;
 262    }
 263
 264    if (strcmp(value, "") == 0) {
 265        compat_pvr = 0;
 266    } else {
 267        int i;
 268        const CompatInfo *compat = NULL;
 269
 270        for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
 271            if (strcmp(value, compat_table[i].name) == 0) {
 272                compat = &compat_table[i];
 273                break;
 274
 275            }
 276        }
 277
 278        if (!compat) {
 279            error_setg(errp, "Invalid compatibility mode \"%s\"", value);
 280            goto out;
 281        }
 282        compat_pvr = compat->pvr;
 283    }
 284
 285    *((uint32_t *)opaque) = compat_pvr;
 286
 287out:
 288    g_free(value);
 289}
 290
 291void ppc_compat_add_property(Object *obj, const char *name,
 292                             uint32_t *compat_pvr, const char *basedesc,
 293                             Error **errp)
 294{
 295    Error *local_err = NULL;
 296    gchar *namesv[ARRAY_SIZE(compat_table) + 1];
 297    gchar *names, *desc;
 298    int i;
 299
 300    object_property_add(obj, name, "string",
 301                        ppc_compat_prop_get, ppc_compat_prop_set, NULL,
 302                        compat_pvr, &local_err);
 303    if (local_err) {
 304        goto out;
 305    }
 306
 307    for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
 308        /*
 309         * Have to discard const here, because g_strjoinv() takes
 310         * (gchar **), not (const gchar **) :(
 311         */
 312        namesv[i] = (gchar *)compat_table[i].name;
 313    }
 314    namesv[ARRAY_SIZE(compat_table)] = NULL;
 315
 316    names = g_strjoinv(", ", namesv);
 317    desc = g_strdup_printf("%s. Valid values are %s.", basedesc, names);
 318    object_property_set_description(obj, name, desc, &local_err);
 319
 320    g_free(names);
 321    g_free(desc);
 322
 323out:
 324    error_propagate(errp, local_err);
 325}
 326