qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

compat.c (9280B)


      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 
     30 typedef 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 
     47 static 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 
    105 static 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 
    117 static 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 
    142 bool 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 
    154 bool 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 
    161 int 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 
    197 typedef struct {
    198     uint32_t compat_pvr;
    199     Error **errp;
    200     int ret;
    201 } SetCompatState;
    202 
    203 static 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 
    211 int 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 
    232 int 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 
    245 static 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 
    264 static 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 
    297 out:
    298     g_free(value);
    299 }
    300 
    301 void 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 }