]> git.proxmox.com Git - qemu.git/blobdiff - target-ppc/kvm.c
KVM: PPC: Override host vmx/vsx/dfp only when information known
[qemu.git] / target-ppc / kvm.c
index 96139acb23b935857ec8ab0fe1cfb60f2a795cca..f3d0861a111e3fefd0f2d51b1161c263432b6309 100644 (file)
@@ -879,6 +879,52 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size)
     return 0;
 }
 
+static inline uint32_t mfpvr(void)
+{
+    uint32_t pvr;
+
+    asm ("mfpvr %0"
+         : "=r"(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)
+{
+    uint32_t host_pvr = mfpvr();
+    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);
+
+    spec = g_malloc0(sizeof(*spec));
+    memcpy(spec, base_spec, sizeof(*spec));
+
+    /* Now fix up the spec with information we can query from the host */
+
+    if (vmx != -1) {
+        /* Only override when we know what the host supports */
+        alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0);
+        alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1);
+    }
+    if (dfp != -1) {
+        /* Only override when we know what the host supports */
+        alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
+    }
+
+    return spec;
+}
+
 bool kvm_arch_stop_on_emulation_error(CPUState *env)
 {
     return true;