On 30/10/16 22:11, David Gibson wrote: > This rewrites the ppc_set_compat() function so that instead of open coding > the various compatibility modes, it reads the relevant data from a table. > This is a first step in consolidating the information on compatibility > modes scattered across the code into a single place. > > It also makes one change to the logic. The old code masked the bits to be > set in the PCR (Processor Compatibility Register) by which bits are valid > on the host CPU. This made no sense, since it was done regardless of > whether our guest CPU was the same as the host CPU or not. Futhermore,
s/Futhermore/Furthermore/ > the actual PCR bits are only relevant for TCG[1] - KVM instead uses the > compatibility mode we tell it in kvmppc_set_compat(). When using TCG > host cpu information usually isn't even present. > > While we're at it, we put the new implementation in a new file to make the > enormouse translate_init.c a little smaller. s/enormouse/enormous/ > > [1] Actually it doesn't even do anything in TCG, but it will if / when we > get to implementing compatibility mode logic at that level. > > Signed-off-by: David Gibson <da...@gibson.dropbear.id.au> Reviewed-by: Alexey Kardashevskiy <a...@ozlabs.ru> > --- > target-ppc/Makefile.objs | 1 + > target-ppc/compat.c | 91 > +++++++++++++++++++++++++++++++++++++++++++++ > target-ppc/cpu.h | 6 ++- > target-ppc/translate_init.c | 41 -------------------- > 4 files changed, 97 insertions(+), 42 deletions(-) > create mode 100644 target-ppc/compat.c > > diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs > index e667e69..feb5c30 100644 > --- a/target-ppc/Makefile.objs > +++ b/target-ppc/Makefile.objs > @@ -15,3 +15,4 @@ obj-y += misc_helper.o > obj-y += mem_helper.o > obj-$(CONFIG_USER_ONLY) += user_only_helper.o > obj-y += gdbstub.o > +obj-$(TARGET_PPC64) += compat.o > diff --git a/target-ppc/compat.c b/target-ppc/compat.c > new file mode 100644 > index 0000000..f3fd9c6 > --- /dev/null > +++ b/target-ppc/compat.c > @@ -0,0 +1,91 @@ > +/* > + * PowerPC CPU initialization for qemu. > + * > + * Copyright 2016, David Gibson, Red Hat Inc. <dgib...@redhat.com> > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + */ > + > +#include "qemu/osdep.h" > +#include "sysemu/kvm.h" > +#include "kvm_ppc.h" > +#include "sysemu/cpus.h" > +#include "qemu/error-report.h" > +#include "qapi/error.h" > +#include "cpu-models.h" > + > +typedef struct { > + uint32_t pvr; > + uint64_t pcr; > +} CompatInfo; > + > +static const CompatInfo compat_table[] = { > + { /* POWER6, ISA2.05 */ > + .pvr = CPU_POWERPC_LOGICAL_2_05, > + .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05 > + | PCR_TM_DIS | PCR_VSX_DIS, > + }, > + { /* POWER7, ISA2.06 */ > + .pvr = CPU_POWERPC_LOGICAL_2_06, > + .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS, > + }, > + { > + .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS, > + .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS, > + }, > + { /* POWER8, ISA2.07 */ > + .pvr = CPU_POWERPC_LOGICAL_2_07, > + .pcr = PCR_COMPAT_2_07, > + }, > +}; > + > +static const CompatInfo *compat_by_pvr(uint32_t pvr) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(compat_table); i++) { > + if (compat_table[i].pvr == pvr) { > + return &compat_table[i]; > + } > + } > + return NULL; > +} > + > +void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp) > +{ > + const CompatInfo *compat = compat_by_pvr(compat_pvr); > + CPUPPCState *env = &cpu->env; > + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); > + uint64_t pcr; > + > + if (!compat_pvr) { > + pcr = 0; > + } else if (!compat) { > + error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, > compat_pvr); > + return; > + } else { > + pcr = compat->pcr; > + } > + > + cpu->compat_pvr = compat_pvr; > + env->spr[SPR_PCR] = pcr & pcc->pcr_mask; > + > + if (kvm_enabled()) { > + int ret = kvmppc_set_compat(cpu, cpu->compat_pvr); > + if (ret < 0) { > + error_setg_errno(errp, -ret, > + "Unable to set CPU compatibility mode in KVM"); > + } > + } > +} > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h > index f7656cb..15d5e4b 100644 > --- a/target-ppc/cpu.h > +++ b/target-ppc/cpu.h > @@ -1243,7 +1243,6 @@ void ppc_store_msr (CPUPPCState *env, target_ulong > value); > void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); > int ppc_get_compat_smt_threads(PowerPCCPU *cpu); > #if defined(TARGET_PPC64) > -void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp); > #endif > > /* Time-base and decrementer management */ > @@ -1314,6 +1313,11 @@ static inline int cpu_mmu_index (CPUPPCState *env, > bool ifetch) > return ifetch ? env->immu_idx : env->dmmu_idx; > } > > +/* Compatibility modes */ > +#if defined(TARGET_PPC64) > +void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp); > +#endif /* defined(TARGET_PPC64) */ > + > #include "exec/cpu-all.h" > > > /*****************************************************************************/ > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c > index c35065d..a70eafb 100644 > --- a/target-ppc/translate_init.c > +++ b/target-ppc/translate_init.c > @@ -9972,47 +9972,6 @@ int ppc_get_compat_smt_threads(PowerPCCPU *cpu) > return ret; > } > > -#ifdef TARGET_PPC64 > -void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp) > -{ > - int ret = 0; > - CPUPPCState *env = &cpu->env; > - PowerPCCPUClass *host_pcc; > - > - cpu->compat_pvr = compat_pvr; > - > - switch (compat_pvr) { > - case CPU_POWERPC_LOGICAL_2_05: > - env->spr[SPR_PCR] = PCR_TM_DIS | PCR_VSX_DIS | PCR_COMPAT_2_07 | > - PCR_COMPAT_2_06 | PCR_COMPAT_2_05; > - break; > - case CPU_POWERPC_LOGICAL_2_06: > - case CPU_POWERPC_LOGICAL_2_06_PLUS: > - env->spr[SPR_PCR] = PCR_TM_DIS | PCR_COMPAT_2_07 | PCR_COMPAT_2_06; > - break; > - case CPU_POWERPC_LOGICAL_2_07: > - env->spr[SPR_PCR] = PCR_COMPAT_2_07; > - break; > - default: > - env->spr[SPR_PCR] = 0; > - break; > - } > - > - host_pcc = kvm_ppc_get_host_cpu_class(); > - if (host_pcc) { > - env->spr[SPR_PCR] &= host_pcc->pcr_mask; > - } > - > - if (kvm_enabled()) { > - ret = kvmppc_set_compat(cpu, cpu->compat_pvr); > - if (ret < 0) { > - error_setg_errno(errp, -ret, > - "Unable to set CPU compatibility mode in KVM"); > - } > - } > -} > -#endif > - > static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) > { > ObjectClass *oc = (ObjectClass *)a; > -- Alexey