]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
cpu: Better support for ppc64 compatibility modes
authorAndrea Bolognani <abologna@redhat.com>
Thu, 13 Aug 2015 15:50:37 +0000 (17:50 +0200)
committerAndrea Bolognani <abologna@redhat.com>
Fri, 21 Aug 2015 22:42:33 +0000 (15:42 -0700)
Not all combinations of host CPU models and compatibility modes
are valid, so we need to make sure we don't try to do something
that QEMU will reject.

Moreover, we need to apply a different logic to guests using
host-model and host-passthrough modes when testing them for host
compatibility.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1251927

src/cpu/cpu_ppc64.c

index 72b8fa05a366724a80900599beca1b16baa30ab2..a72cc32ae4327cf6934d9d4ba3cd83e0ba60854b 100644 (file)
@@ -84,6 +84,53 @@ ppc64ConvertLegacyCPUDef(const virCPUDef *legacy)
     return cpu;
 }
 
+/* Some hosts can run guests in compatibility mode, but not all
+ * host CPUs support this and not all combinations are valid.
+ * This function performs the necessary checks */
+static virCPUCompareResult
+ppc64CheckCompatibilityMode(const char *host_model,
+                            const char *compat_mode)
+{
+    int host;
+    int compat;
+    char *tmp;
+    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
+
+    if (!compat_mode)
+        return VIR_CPU_COMPARE_IDENTICAL;
+
+    /* Valid host CPUs: POWER6, POWER7, POWER8 */
+    if (!STRPREFIX(host_model, "POWER") ||
+        !(tmp = (char *) host_model + strlen("POWER")) ||
+        virStrToLong_i(tmp, NULL, 10, &host) < 0 ||
+        host < 6 || host > 8) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Host CPU does not support compatibility modes"));
+        goto out;
+    }
+
+    /* Valid compatibility modes: power6, power7, power8 */
+    if (!STRPREFIX(compat_mode, "power") ||
+        !(tmp = (char *) compat_mode + strlen("power")) ||
+        virStrToLong_i(tmp, NULL, 10, &compat) < 0 ||
+        compat < 6 || compat > 8) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unknown compatibility mode %s"),
+                       compat_mode);
+        goto out;
+    }
+
+    /* Version check */
+    if (compat > host)
+        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+    else
+        ret = VIR_CPU_COMPARE_IDENTICAL;
+
+ out:
+    return ret;
+}
+
 static void
 ppc64DataFree(virCPUppc64Data *data)
 {
@@ -509,11 +556,47 @@ ppc64Compute(virCPUDefPtr host,
         goto cleanup;
     }
 
-    if (!(map = ppc64LoadMap()) ||
-        !(host_model = ppc64ModelFromCPU(host, map)) ||
-        !(guest_model = ppc64ModelFromCPU(cpu, map)))
+    if (!(map = ppc64LoadMap()))
+        goto cleanup;
+
+    /* Host CPU information */
+    if (!(host_model = ppc64ModelFromCPU(host, map)))
         goto cleanup;
 
+    if (cpu->type == VIR_CPU_TYPE_GUEST) {
+        /* Guest CPU information */
+        virCPUCompareResult tmp;
+        switch (cpu->mode) {
+        case VIR_CPU_MODE_HOST_MODEL:
+            /* host-model only:
+             * we need to take compatibility modes into account */
+            tmp = ppc64CheckCompatibilityMode(host->model, cpu->model);
+            if (tmp != VIR_CPU_COMPARE_IDENTICAL) {
+                ret = tmp;
+                goto cleanup;
+            }
+            /* fallthrough */
+
+        case VIR_CPU_MODE_HOST_PASSTHROUGH:
+            /* host-model and host-passthrough:
+             * the guest CPU is the same as the host */
+            if (!(guest_model = ppc64ModelCopy(host_model)))
+                goto cleanup;
+            break;
+
+        case VIR_CPU_MODE_CUSTOM:
+            /* custom:
+             * look up guest CPU information */
+            if (!(guest_model = ppc64ModelFromCPU(cpu, map)))
+                goto cleanup;
+            break;
+        }
+    } else {
+        /* Other host CPU information */
+        if (!(guest_model = ppc64ModelFromCPU(cpu, map)))
+            goto cleanup;
+    }
+
     if (STRNEQ(guest_model->name, host_model->name)) {
         VIR_DEBUG("host CPU model does not match required CPU model %s",
                   guest_model->name);