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_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
 161void 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;
 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;
 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;
 189        }
 190    }
 191
 192    cpu->compat_pvr = compat_pvr;
 193    env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
 194}
 195
 196typedef struct {
 197    uint32_t compat_pvr;
 198    Error *err;
 199} SetCompatState;
 200
 201static void do_set_compat(CPUState *cs, run_on_cpu_data arg)
 202{
 203    PowerPCCPU *cpu = POWERPC_CPU(cs);
 204    SetCompatState *s = arg.host_ptr;
 205
 206    ppc_set_compat(cpu, s->compat_pvr, &s->err);
 207}
 208
 209void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
 210{
 211    CPUState *cs;
 212
 213    CPU_FOREACH(cs) {
 214        SetCompatState s = {
 215            .compat_pvr = compat_pvr,
 216            .err = NULL,
 217        };
 218
 219        run_on_cpu(cs, do_set_compat, RUN_ON_CPU_HOST_PTR(&s));
 220
 221        if (s.err) {
 222            error_propagate(errp, s.err);
 223            return;
 224        }
 225    }
 226}
 227
 228int ppc_compat_max_vthreads(PowerPCCPU *cpu)
 229{
 230    const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
 231    int n_threads = CPU(cpu)->nr_threads;
 232
 233    if (cpu->compat_pvr) {
 234        g_assert(compat);
 235        n_threads = MIN(n_threads, compat->max_vthreads);
 236    }
 237
 238    return n_threads;
 239}
 240
 241static void ppc_compat_prop_get(Object *obj, Visitor *v, const char *name,
 242                                void *opaque, Error **errp)
 243{
 244    uint32_t compat_pvr = *((uint32_t *)opaque);
 245    const char *value;
 246
 247    if (!compat_pvr) {
 248        value = "";
 249    } else {
 250        const CompatInfo *compat = compat_by_pvr(compat_pvr);
 251
 252        g_assert(compat);
 253
 254        value = compat->name;
 255    }
 256
 257    visit_type_str(v, name, (char **)&value, errp);
 258}
 259
 260static void ppc_compat_prop_set(Object *obj, Visitor *v, const char *name,
 261                                void *opaque, Error **errp)
 262{
 263    char *value;
 264    uint32_t compat_pvr;
 265
 266    if (!visit_type_str(v, name, &value, errp)) {
 267        return;
 268    }
 269
 270    if (strcmp(value, "") == 0) {
 271        compat_pvr = 0;
 272    } else {
 273        int i;
 274        const CompatInfo *compat = NULL;
 275
 276        for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
 277            if (strcmp(value, compat_table[i].name) == 0) {
 278                compat = &compat_table[i];
 279                break;
 280
 281            }
 282        }
 283
 284        if (!compat) {
 285            error_setg(errp, "Invalid compatibility mode \"%s\"", value);
 286            goto out;
 287        }
 288        compat_pvr = compat->pvr;
 289    }
 290
 291    *((uint32_t *)opaque) = compat_pvr;
 292
 293out:
 294    g_free(value);
 295}
 296
 297void ppc_compat_add_property(Object *obj, const char *name,
 298                             uint32_t *compat_pvr, const char *basedesc)
 299{
 300    gchar *namesv[ARRAY_SIZE(compat_table) + 1];
 301    gchar *names, *desc;
 302    int i;
 303
 304    object_property_add(obj, name, "string",
 305                        ppc_compat_prop_get, ppc_compat_prop_set, NULL,
 306                        compat_pvr);
 307
 308    for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
 309        /*
 310         * Have to discard const here, because g_strjoinv() takes
 311         * (gchar **), not (const gchar **) :(
 312         */
 313        namesv[i] = (gchar *)compat_table[i].name;
 314    }
 315    namesv[ARRAY_SIZE(compat_table)] = NULL;
 316
 317    names = g_strjoinv(", ", namesv);
 318    desc = g_strdup_printf("%s. Valid values are %s.", basedesc, names);
 319    object_property_set_description(obj, name, desc);
 320
 321    g_free(names);
 322    g_free(desc);
 323}
 324