mirror of https://github.com/proxmox/mirror_qemu
pseries: Correct vmx/dfp handling in both KVM and TCG cases
Currently, when KVM is enabled, the pseries machine checks if the host CPU supports VMX, VSX and/or DFP instructions and advertises accordingly in the guest device tree. It does this regardless of what CPU is selected on the command line. On the other hand, when in TCG mode, it never advertises any of these facilities, even basic VMX (Altivec) which is supported in TCG. Now that we have a -cpu host option for ppc, it is fairly straightforward to fix both problems. This patch changes the -cpu host code to override the basic cpu spec derived from the PVR with information queried from the host avout VMX, VSX and DFP capability. The pseries code then uses the instruction availability advertised in the cpu state to set the guest device tree correctly for both the KVM and TCG cases. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de>master
parent
f90a9d0240
commit
a7342588c0
10
hw/spapr.c
10
hw/spapr.c
|
@ -188,8 +188,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
0xffffffff, 0xffffffff};
|
0xffffffff, 0xffffffff};
|
||||||
uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
|
uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
|
||||||
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
|
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
|
||||||
uint32_t vmx = kvm_enabled() ? kvmppc_get_vmx() : 0;
|
|
||||||
uint32_t dfp = kvm_enabled() ? kvmppc_get_dfp() : 0;
|
|
||||||
|
|
||||||
if ((index % smt) != 0) {
|
if ((index % smt) != 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -241,15 +239,17 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
* 0 / no property == no vector extensions
|
* 0 / no property == no vector extensions
|
||||||
* 1 == VMX / Altivec available
|
* 1 == VMX / Altivec available
|
||||||
* 2 == VSX available */
|
* 2 == VSX available */
|
||||||
if (vmx) {
|
if (env->insns_flags & PPC_ALTIVEC) {
|
||||||
|
uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
|
||||||
|
|
||||||
_FDT((fdt_property_cell(fdt, "ibm,vmx", vmx)));
|
_FDT((fdt_property_cell(fdt, "ibm,vmx", vmx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advertise DFP (Decimal Floating Point) if available
|
/* Advertise DFP (Decimal Floating Point) if available
|
||||||
* 0 / no property == no DFP
|
* 0 / no property == no DFP
|
||||||
* 1 == DFP available */
|
* 1 == DFP available */
|
||||||
if (dfp) {
|
if (env->insns_flags2 & PPC2_DFP) {
|
||||||
_FDT((fdt_property_cell(fdt, "ibm,dfp", dfp)));
|
_FDT((fdt_property_cell(fdt, "ibm,dfp", 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_FDT((fdt_end_node(fdt)));
|
_FDT((fdt_end_node(fdt)));
|
||||||
|
|
|
@ -858,6 +858,22 @@ enum {
|
||||||
/* The whole PowerPC CPU context */
|
/* The whole PowerPC CPU context */
|
||||||
#define NB_MMU_MODES 3
|
#define NB_MMU_MODES 3
|
||||||
|
|
||||||
|
struct ppc_def_t {
|
||||||
|
const char *name;
|
||||||
|
uint32_t pvr;
|
||||||
|
uint32_t svr;
|
||||||
|
uint64_t insns_flags;
|
||||||
|
uint64_t insns_flags2;
|
||||||
|
uint64_t msr_mask;
|
||||||
|
powerpc_mmu_t mmu_model;
|
||||||
|
powerpc_excp_t excp_model;
|
||||||
|
powerpc_input_t bus_model;
|
||||||
|
uint32_t flags;
|
||||||
|
int bfd_mach;
|
||||||
|
void (*init_proc)(CPUPPCState *env);
|
||||||
|
int (*check_pow)(CPUPPCState *env);
|
||||||
|
};
|
||||||
|
|
||||||
struct CPUPPCState {
|
struct CPUPPCState {
|
||||||
/* First are the most commonly used resources
|
/* First are the most commonly used resources
|
||||||
* during translated code execution
|
* during translated code execution
|
||||||
|
@ -1844,6 +1860,10 @@ enum {
|
||||||
|
|
||||||
/* BookE 2.06 PowerPC specification */
|
/* BookE 2.06 PowerPC specification */
|
||||||
PPC2_BOOKE206 = 0x0000000000000001ULL,
|
PPC2_BOOKE206 = 0x0000000000000001ULL,
|
||||||
|
/* VSX (extensions to Altivec / VMX) */
|
||||||
|
PPC2_VSX = 0x0000000000000002ULL,
|
||||||
|
/* Decimal Floating Point (DFP) */
|
||||||
|
PPC2_DFP = 0x0000000000000004ULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -888,14 +888,35 @@ static inline uint32_t mfpvr(void)
|
||||||
return pvr;
|
return pvr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void alter_insns(uint64_t *word, uint64_t flags, bool on)
|
||||||
|
{
|
||||||
|
if (on) {
|
||||||
|
*word |= flags;
|
||||||
|
} else {
|
||||||
|
*word &= ~flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const ppc_def_t *kvmppc_host_cpu_def(void)
|
const ppc_def_t *kvmppc_host_cpu_def(void)
|
||||||
{
|
{
|
||||||
uint32_t host_pvr = mfpvr();
|
uint32_t host_pvr = mfpvr();
|
||||||
const ppc_def_t *base_spec;
|
const ppc_def_t *base_spec;
|
||||||
|
ppc_def_t *spec;
|
||||||
|
uint32_t vmx = kvmppc_get_vmx();
|
||||||
|
uint32_t dfp = kvmppc_get_dfp();
|
||||||
|
|
||||||
base_spec = ppc_find_by_pvr(host_pvr);
|
base_spec = ppc_find_by_pvr(host_pvr);
|
||||||
|
|
||||||
return base_spec;
|
spec = g_malloc0(sizeof(*spec));
|
||||||
|
memcpy(spec, base_spec, sizeof(*spec));
|
||||||
|
|
||||||
|
/* Now fix up the spec with information we can query from the host */
|
||||||
|
|
||||||
|
alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0);
|
||||||
|
alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1);
|
||||||
|
alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
|
||||||
|
|
||||||
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool kvm_arch_stop_on_emulation_error(CPUState *env)
|
bool kvm_arch_stop_on_emulation_error(CPUState *env)
|
||||||
|
|
|
@ -34,22 +34,6 @@
|
||||||
#define TODO_USER_ONLY 1
|
#define TODO_USER_ONLY 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ppc_def_t {
|
|
||||||
const char *name;
|
|
||||||
uint32_t pvr;
|
|
||||||
uint32_t svr;
|
|
||||||
uint64_t insns_flags;
|
|
||||||
uint64_t insns_flags2;
|
|
||||||
uint64_t msr_mask;
|
|
||||||
powerpc_mmu_t mmu_model;
|
|
||||||
powerpc_excp_t excp_model;
|
|
||||||
powerpc_input_t bus_model;
|
|
||||||
uint32_t flags;
|
|
||||||
int bfd_mach;
|
|
||||||
void (*init_proc)(CPUPPCState *env);
|
|
||||||
int (*check_pow)(CPUPPCState *env);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* For user-mode emulation, we don't emulate any IRQ controller */
|
/* For user-mode emulation, we don't emulate any IRQ controller */
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
#define PPC_IRQ_INIT_FN(name) \
|
#define PPC_IRQ_INIT_FN(name) \
|
||||||
|
@ -6535,6 +6519,8 @@ static void init_proc_970MP (CPUPPCState *env)
|
||||||
PPC_64B | PPC_ALTIVEC | \
|
PPC_64B | PPC_ALTIVEC | \
|
||||||
PPC_SEGMENT_64B | PPC_SLBI | \
|
PPC_SEGMENT_64B | PPC_SLBI | \
|
||||||
PPC_POPCNTB | PPC_POPCNTWD)
|
PPC_POPCNTB | PPC_POPCNTWD)
|
||||||
|
/* FIXME: Should also have PPC2_VSX and PPC2_DFP, but we don't
|
||||||
|
* implement those in TCG yet */
|
||||||
#define POWERPC_INSNS2_POWER7 (PPC_NONE)
|
#define POWERPC_INSNS2_POWER7 (PPC_NONE)
|
||||||
#define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL)
|
#define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL)
|
||||||
#define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06)
|
#define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06)
|
||||||
|
|
Loading…
Reference in New Issue