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.1 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_10 | PCR_COMPAT_3_00 | PCR_COMPAT_2_07 |
  55               PCR_COMPAT_2_06 | 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_10 | PCR_COMPAT_3_00 | PCR_COMPAT_2_07 |
  63               PCR_COMPAT_2_06 | PCR_TM_DIS,
  64        .pcr_level = PCR_COMPAT_2_06,
  65        .max_vthreads = 4,
  66    },
  67    {
  68        .name = "power7+",
  69        .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
  70        .pcr = PCR_COMPAT_3_10 | PCR_COMPAT_3_00 | PCR_COMPAT_2_07 |
  71               PCR_COMPAT_2_06 | PCR_TM_DIS,
  72        .pcr_level = PCR_COMPAT_2_06,
  73        .max_vthreads = 4,
  74    },
  75    { /* POWER8, ISA2.07 */
  76        .name = "power8",
  77        .pvr = CPU_POWERPC_LOGICAL_2_07,
  78        .pcr = PCR_COMPAT_3_10 | PCR_COMPAT_3_00 | PCR_COMPAT_2_07,
  79        .pcr_level = PCR_COMPAT_2_07,
  80        .max_vthreads = 8,
  81    },
  82    { /* POWER9, ISA3.00 */
  83        .name = "power9",
  84        .pvr = CPU_POWERPC_LOGICAL_3_00,
  85        .pcr = PCR_COMPAT_3_10 | PCR_COMPAT_3_00,
  86        .pcr_level = PCR_COMPAT_3_00,
  87        /*
  88         * POWER9 hardware only supports 4 threads / core, but this
  89         * limit is for guests.  We need to support 8 vthreads/vcore
  90         * on POWER9 for POWER8 compatibility guests, and it's very
  91         * confusing if half of the threads disappear from the guest
  92         * if it announces it's POWER9 aware at CAS time.
  93         */
  94        .max_vthreads = 8,
  95    },
  96    { /* POWER10, ISA3.10 */
  97        .name = "power10",
  98        .pvr = CPU_POWERPC_LOGICAL_3_10,
  99        .pcr = PCR_COMPAT_3_10,
 100        .pcr_level = PCR_COMPAT_3_10,
 101        .max_vthreads = 8,
 102    },
 103};
 104
 105static const CompatInfo *compat_by_pvr(uint32_t pvr)
 106{
 107    int i;
 108
 109    for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
 110        if (compat_table[i].pvr == pvr) {
 111            return &compat_table[i];
 112        }
 113    }
 114    return NULL;
 115}
 116
 117static bool pcc_compat(PowerPCCPUClass *pcc, uint32_t compat_pvr,
 118                       uint32_t min_compat_pvr, uint32_t max_compat_pvr)
 119{
 120    const CompatInfo *compat = compat_by_pvr(compat_pvr);
 121    const CompatInfo *min = compat_by_pvr(min_compat_pvr);
 122    const CompatInfo *max = compat_by_pvr(max_compat_pvr);
 123
 124    g_assert(!min_compat_pvr || min);
 125    g_assert(!max_compat_pvr || max);
 126
 127    if (!compat) {
 128        /* Not a recognized logical PVR */
 129        return false;
 130    }
 131    if ((min && (compat < min)) || (max && (compat > max))) {
 132        /* Outside specified range */
 133        return false;
 134    }
 135    if (!(pcc->pcr_supported & compat->pcr_level)) {
 136        /* Not supported by this CPU */
 137        return false;
 138    }
 139    return true;
 140}
 141
 142bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
 143                      uint32_t min_compat_pvr, uint32_t max_compat_pvr)
 144{
 145    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
 146
 147#if !defined(CONFIG_USER_ONLY)
 148    g_assert(cpu->vhyp);
 149#endif
 150
 151    return pcc_compat(pcc, compat_pvr, min_compat_pvr, max_compat_pvr);
 152}
 153
 154bool ppc_type_check_compat(const char *cputype, uint32_t compat_pvr,
 155                           uint32_t min_compat_pvr, uint32_t max_compat_pvr)
 156{
 157    PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(object_class_by_name(cputype));
 158    return pcc_compat(pcc, compat_pvr, min_compat_pvr, max_compat_pvr);
 159}
 160
 161int ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
 162{
 163    const CompatInfo *compat = compat_by_pvr(compat_pvr);
 164    CPUPPCState *env = &cpu->env;
 165    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
 166    uint64_t pcr;
 167
 168    if (!compat_pvr) {
 169        pcr = 0;
 170    } else if (!compat) {
 171        error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
 172        return -EINVAL;
 173    } else if (!ppc_check_compat(cpu, compat_pvr, 0, 0)) {
 174        error_setg(errp, "Compatibility PVR 0x%08"PRIx32" not valid for CPU",
 175                   compat_pvr);
 176        return -EINVAL;
 177    } else {
 178        pcr = compat->pcr;
 179    }
 180
 181    cpu_synchronize_state(CPU(cpu));
 182
 183    if (kvm_enabled() && cpu->compat_pvr != compat_pvr) {
 184        int ret = kvmppc_set_compat(cpu, compat_pvr);
 185        if (ret < 0) {
 186            error_setg_errno(errp, -ret,
 187                             "Unable to set CPU compatibility mode in KVM");
 188            return ret;
 189        }
 190    }
 191
 192    cpu->compat_pvr = compat_pvr;
 193    env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
 194    return 0;
 195}
 196
 197typedef struct {
 198    uint32_t compat_pvr;
 199    Error **errp;
 200    int ret;
 201} SetCompatState;
 202
 203static void do_set_compat(CPUState *cs, run_on_cpu_data arg)
 204{
 205    PowerPCCPU *cpu = POWERPC_CPU(cs);
 206    SetCompatState *s = arg.host_ptr;
 207
 208    s->ret = ppc_set_compat(cpu, s->compat_pvr, s->errp);
 209}
 210
 211int ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
 212{
 213    CPUState *cs;
 214
 215    CPU_FOREACH(cs) {
 216        SetCompatState s = {
 217            .compat_pvr = compat_pvr,
 218            .errp = errp,
 219            .ret = 0,
 220        };
 221
 222        run_on_cpu(cs, do_set_compat, RUN_ON_CPU_HOST_PTR(&s));
 223
 224        if (s.ret < 0) {
 225            return s.ret;
 226        }
 227    }
 228
 229    return 0;
 230}
 231
 232int ppc_compat_max_vthreads(PowerPCCPU *cpu)
 233{
 234    const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
 235    int n_threads = CPU(cpu)->nr_threads;
 236
 237    if (cpu->compat_pvr) {
 238        g_assert(compat);
 239        n_threads = MIN(n_threads, compat->max_vthreads);
 240    }
 241
 242    return n_threads;
 243}
 244
 245static void ppc_compat_prop_get(Object *obj, Visitor *v, const char *name,
 246                                void *opaque, Error **errp)
 247{
 248    uint32_t compat_pvr = *((uint32_t *)opaque);
 249    const char *value;
 250
 251    if (!compat_pvr) {
 252        value = "";
 253    } else {
 254        const CompatInfo *compat = compat_by_pvr(compat_pvr);
 255
 256        g_assert(compat);
 257
 258        value = compat->name;
 259    }
 260
 261    visit_type_str(v, name, (char **)&value, errp);
 262}
 263
 264static void ppc_compat_prop_set(Object *obj, Visitor *v, const char *name,
 265                                void *opaque, Error **errp)
 266{
 267    char *value;
 268    uint32_t compat_pvr;
 269
 270    if (!visit_type_str(v, name, &value, errp)) {
 271        return;
 272    }
 273
 274    if (strcmp(value, "") == 0) {
 275        compat_pvr = 0;
 276    } else {
 277        int i;
 278        const CompatInfo *compat = NULL;
 279
 280        for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
 281            if (strcmp(value, compat_table[i].name) == 0) {
 282                compat = &compat_table[i];
 283                break;
 284
 285            }
 286        }
 287
 288        if (!compat) {
 289            error_setg(errp, "Invalid compatibility mode \"%s\"", value);
 290            goto out;
 291        }
 292        compat_pvr = compat->pvr;
 293    }
 294
 295    *((uint32_t *)opaque) = compat_pvr;
 296
 297out:
 298    g_free(value);
 299}
 300
 301void ppc_compat_add_property(Object *obj, const char *name,
 302                             uint32_t *compat_pvr, const char *basedesc)
 303{
 304    gchar *namesv[ARRAY_SIZE(compat_table) + 1];
 305    gchar *names, *desc;
 306    int i;
 307
 308    object_property_add(obj, name, "string",
 309                        ppc_compat_prop_get, ppc_compat_prop_set, NULL,
 310                        compat_pvr);
 311
 312    for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
 313        /*
 314         * Have to discard const here, because g_strjoinv() takes
 315         * (gchar **), not (const gchar **) :(
 316         */
 317        namesv[i] = (gchar *)compat_table[i].name;
 318    }
 319    namesv[ARRAY_SIZE(compat_table)] = NULL;
 320
 321    names = g_strjoinv(", ", namesv);
 322    desc = g_strdup_printf("%s. Valid values are %s.", basedesc, names);
 323    object_property_set_description(obj, name, desc);
 324
 325    g_free(names);
 326    g_free(desc);
 327}
 328