[libvirt] [PATCH 01/10] Move QEMU capabilities management into a separate file

Daniel P. Berrange berrange at redhat.com
Thu Dec 16 16:50:01 UTC 2010


The qemu_conf.c code is doing three jobs, driver config file
loading, QEMU capabilities management and QEMU command line
management. Move the capabilities code into its own file

* src/qemu/qemu_capabilities.c, src/qemu/qemu_capabilities.h: New
  capabilities management code
* src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Delete capabilities
  code
* src/qemu/qemu_conf.h: Adapt for API renames
* src/Makefile.am: add src/qemu/qemu_capabilities.c
---
 src/Makefile.am              |    1 +
 src/qemu/qemu_capabilities.c | 1253 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_capabilities.h |  113 ++++
 src/qemu/qemu_conf.c         | 1191 +---------------------------------------
 src/qemu/qemu_conf.h         |   81 ---
 src/qemu/qemu_driver.c       |   55 +-
 6 files changed, 1398 insertions(+), 1296 deletions(-)
 create mode 100644 src/qemu/qemu_capabilities.c
 create mode 100644 src/qemu/qemu_capabilities.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 196d8af..4ce0b35 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -267,6 +267,7 @@ VBOX_DRIVER_SOURCES =						\
 VBOX_DRIVER_EXTRA_DIST = vbox/vbox_tmpl.c vbox/README
 
 QEMU_DRIVER_SOURCES =						\
+		qemu/qemu_capabilities.c qemu/qemu_capabilities.h\
 		qemu/qemu_conf.c qemu/qemu_conf.h		\
 		qemu/qemu_monitor.c qemu/qemu_monitor.h		\
 		qemu/qemu_monitor_text.c			\
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
new file mode 100644
index 0000000..913fbf7
--- /dev/null
+++ b/src/qemu/qemu_capabilities.c
@@ -0,0 +1,1253 @@
+/*
+ * qemu_capabilities.c: QEMU capabilities generation
+ *
+ * Copyright (C) 2006-2007, 2009-2010 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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.1 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include "qemu_capabilities.h"
+#include "memory.h"
+#include "logging.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "files.h"
+#include "nodeinfo.h"
+#include "cpu/cpu.h"
+#include "domain_conf.h"
+#include "qemu_conf.h"
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+struct qemu_feature_flags {
+    const char *name;
+    const int default_on;
+    const int toggle;
+};
+
+struct qemu_arch_info {
+    const char *arch;
+    int wordsize;
+    const char *machine;
+    const char *binary;
+    const char *altbinary;
+    const struct qemu_feature_flags *flags;
+    int nflags;
+};
+
+/* Feature flags for the architecture info */
+static const struct qemu_feature_flags const arch_info_i686_flags [] = {
+    { "pae",  1, 0 },
+    { "nonpae",  1, 0 },
+    { "acpi", 1, 1 },
+    { "apic", 1, 0 },
+};
+
+static const struct qemu_feature_flags const arch_info_x86_64_flags [] = {
+    { "acpi", 1, 1 },
+    { "apic", 1, 0 },
+};
+
+/* The archicture tables for supported QEMU archs */
+static const struct qemu_arch_info const arch_info_hvm[] = {
+    {  "i686",   32, NULL, "qemu",
+       "qemu-system-x86_64", arch_info_i686_flags, 4 },
+    {  "x86_64", 64, NULL, "qemu-system-x86_64",
+       NULL, arch_info_x86_64_flags, 2 },
+    {  "arm",    32, NULL, "qemu-system-arm",    NULL, NULL, 0 },
+    {  "mips",   32, NULL, "qemu-system-mips",   NULL, NULL, 0 },
+    {  "mipsel", 32, NULL, "qemu-system-mipsel", NULL, NULL, 0 },
+    {  "sparc",  32, NULL, "qemu-system-sparc",  NULL, NULL, 0 },
+    {  "ppc",    32, NULL, "qemu-system-ppc",    NULL, NULL, 0 },
+    {  "itanium", 64, NULL, "qemu-system-ia64",  NULL, NULL, 0 },
+    {  "s390x",  64, NULL, "qemu-system-s390x",  NULL, NULL, 0 },
+};
+
+static const struct qemu_arch_info const arch_info_xen[] = {
+    {  "i686",   32, "xenner", "xenner", NULL, arch_info_i686_flags, 4 },
+    {  "x86_64", 64, "xenner", "xenner", NULL, arch_info_x86_64_flags, 2 },
+};
+
+
+/* Format is:
+ * <machine> <desc> [(default)|(alias of <canonical>)]
+ */
+static int
+qemuCapsParseMachineTypesStr(const char *output,
+                             virCapsGuestMachinePtr **machines,
+                             int *nmachines)
+{
+    const char *p = output;
+    const char *next;
+    virCapsGuestMachinePtr *list = NULL;
+    int nitems = 0;
+
+    do {
+        const char *t;
+        virCapsGuestMachinePtr machine;
+
+        if ((next = strchr(p, '\n')))
+            ++next;
+
+        if (STRPREFIX(p, "Supported machines are:"))
+            continue;
+
+        if (!(t = strchr(p, ' ')) || (next && t >= next))
+            continue;
+
+        if (VIR_ALLOC(machine) < 0)
+            goto no_memory;
+
+        if (!(machine->name = strndup(p, t - p))) {
+            VIR_FREE(machine);
+            goto no_memory;
+        }
+
+        if (VIR_REALLOC_N(list, nitems + 1) < 0) {
+            VIR_FREE(machine->name);
+            VIR_FREE(machine);
+            goto no_memory;
+        }
+
+        p = t;
+        if (!(t = strstr(p, "(default)")) || (next && t >= next)) {
+            list[nitems++] = machine;
+        } else {
+            /* put the default first in the list */
+            memmove(list + 1, list, sizeof(*list) * nitems);
+            list[0] = machine;
+            nitems++;
+        }
+
+        if ((t = strstr(p, "(alias of ")) && (!next || t < next)) {
+            p = t + strlen("(alias of ");
+            if (!(t = strchr(p, ')')) || (next && t >= next))
+                continue;
+
+            if (!(machine->canonical = strndup(p, t - p)))
+                goto no_memory;
+        }
+    } while ((p = next));
+
+    *machines = list;
+    *nmachines = nitems;
+
+    return 0;
+
+  no_memory:
+    virReportOOMError();
+    virCapabilitiesFreeMachines(list, nitems);
+    return -1;
+}
+
+int
+qemuCapsProbeMachineTypes(const char *binary,
+                          virCapsGuestMachinePtr **machines,
+                          int *nmachines)
+{
+    const char *const qemuarg[] = { binary, "-M", "?", NULL };
+    const char *const qemuenv[] = { "LC_ALL=C", NULL };
+    char *output;
+    enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
+    pid_t child;
+    int newstdout = -1, len;
+    int ret = -1, status;
+
+    if (virExec(qemuarg, qemuenv, NULL,
+                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
+        return -1;
+
+    len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &output);
+    if (len < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to read 'qemu -M ?' output"));
+        goto cleanup;
+    }
+
+    if (qemuCapsParseMachineTypesStr(output, machines, nmachines) < 0)
+        goto cleanup2;
+
+    ret = 0;
+
+cleanup2:
+    VIR_FREE(output);
+cleanup:
+    if (VIR_CLOSE(newstdout) < 0)
+        ret = -1;
+
+rewait:
+    if (waitpid(child, &status, 0) != child) {
+        if (errno == EINTR)
+            goto rewait;
+
+        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
+                  WEXITSTATUS(status), (unsigned long)child);
+        ret = -1;
+    }
+    /* Check & log unexpected exit status, but don't fail,
+     * as there's really no need to throw an error if we did
+     * actually read a valid version number above */
+    if (WEXITSTATUS(status) != 0) {
+        VIR_WARN("Unexpected exit status '%d', qemu probably failed",
+                 WEXITSTATUS(status));
+    }
+
+    return ret;
+}
+
+static int
+qemuCapsGetOldMachinesFromInfo(virCapsGuestDomainInfoPtr info,
+                               const char *emulator,
+                               time_t emulator_mtime,
+                               virCapsGuestMachinePtr **machines,
+                               int *nmachines)
+{
+    virCapsGuestMachinePtr *list;
+    int i;
+
+    if (!info->nmachines)
+        return 0;
+
+    if (!info->emulator || !STREQ(emulator, info->emulator))
+        return 0;
+
+    if (emulator_mtime != info->emulator_mtime) {
+        VIR_DEBUG("mtime on %s has changed, refreshing machine types",
+                  info->emulator);
+        return 0;
+    }
+
+    if (VIR_ALLOC_N(list, info->nmachines) < 0) {
+        virReportOOMError();
+        return 0;
+    }
+
+    for (i = 0; i < info->nmachines; i++) {
+        if (VIR_ALLOC(list[i]) < 0) {
+            goto no_memory;
+        }
+        if (info->machines[i]->name &&
+            !(list[i]->name = strdup(info->machines[i]->name))) {
+            goto no_memory;
+        }
+        if (info->machines[i]->canonical &&
+            !(list[i]->canonical = strdup(info->machines[i]->canonical))) {
+            goto no_memory;
+        }
+    }
+
+    *machines = list;
+    *nmachines = info->nmachines;
+
+    return 1;
+
+  no_memory:
+    virReportOOMError();
+    virCapabilitiesFreeMachines(list, info->nmachines);
+    return 0;
+}
+
+static int
+qemuCapsGetOldMachines(const char *ostype,
+                       const char *arch,
+                       int wordsize,
+                       const char *emulator,
+                       time_t emulator_mtime,
+                       virCapsPtr old_caps,
+                       virCapsGuestMachinePtr **machines,
+                       int *nmachines)
+{
+    int i;
+
+    for (i = 0; i < old_caps->nguests; i++) {
+        virCapsGuestPtr guest = old_caps->guests[i];
+        int j;
+
+        if (!STREQ(ostype, guest->ostype) ||
+            !STREQ(arch, guest->arch.name) ||
+            wordsize != guest->arch.wordsize)
+            continue;
+
+        for (j = 0; j < guest->arch.ndomains; j++) {
+            virCapsGuestDomainPtr dom = guest->arch.domains[j];
+
+            if (qemuCapsGetOldMachinesFromInfo(&dom->info,
+                                               emulator, emulator_mtime,
+                                               machines, nmachines))
+                return 1;
+        }
+
+        if (qemuCapsGetOldMachinesFromInfo(&guest->arch.defaultInfo,
+                                           emulator, emulator_mtime,
+                                           machines, nmachines))
+            return 1;
+    }
+
+    return 0;
+}
+
+
+typedef int
+(*qemuCapsParseCPUModels)(const char *output,
+                       unsigned int *retcount,
+                       const char ***retcpus);
+
+/* Format:
+ *      <arch> <model>
+ * qemu-0.13 encloses some model names in []:
+ *      <arch> [<model>]
+ */
+static int
+qemuCapsParseX86Models(const char *output,
+                       unsigned int *retcount,
+                       const char ***retcpus)
+{
+    const char *p = output;
+    const char *next;
+    unsigned int count = 0;
+    const char **cpus = NULL;
+    int i;
+
+    do {
+        const char *t;
+
+        if ((next = strchr(p, '\n')))
+            next++;
+
+        if (!(t = strchr(p, ' ')) || (next && t >= next))
+            continue;
+
+        if (!STRPREFIX(p, "x86"))
+            continue;
+
+        p = t;
+        while (*p == ' ')
+            p++;
+
+        if (*p == '\0' || *p == '\n')
+            continue;
+
+        if (retcpus) {
+            unsigned int len;
+
+            if (VIR_REALLOC_N(cpus, count + 1) < 0)
+                goto error;
+
+            if (next)
+                len = next - p - 1;
+            else
+                len = strlen(p);
+
+            if (len > 2 && *p == '[' && p[len - 1] == ']') {
+                p++;
+                len -= 2;
+            }
+
+            if (!(cpus[count] = strndup(p, len)))
+                goto error;
+        }
+        count++;
+    } while ((p = next));
+
+    if (retcount)
+        *retcount = count;
+    if (retcpus)
+        *retcpus = cpus;
+
+    return 0;
+
+error:
+    if (cpus) {
+        for (i = 0; i < count; i++)
+            VIR_FREE(cpus[i]);
+    }
+    VIR_FREE(cpus);
+
+    return -1;
+}
+
+
+int
+qemuCapsProbeCPUModels(const char *qemu,
+                       unsigned long long qemuCmdFlags,
+                       const char *arch,
+                       unsigned int *count,
+                       const char ***cpus)
+{
+    const char *const qemuarg[] = {
+        qemu,
+        "-cpu", "?",
+        (qemuCmdFlags & QEMUD_CMD_FLAG_NODEFCONFIG) ? "-nodefconfig" : NULL,
+        NULL
+    };
+    const char *const qemuenv[] = { "LC_ALL=C", NULL };
+    enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
+    char *output = NULL;
+    int newstdout = -1;
+    int ret = -1;
+    pid_t child;
+    int status;
+    int len;
+    qemuCapsParseCPUModels parse;
+
+    if (count)
+        *count = 0;
+    if (cpus)
+        *cpus = NULL;
+
+    if (STREQ(arch, "i686") || STREQ(arch, "x86_64"))
+        parse = qemuCapsParseX86Models;
+    else {
+        VIR_DEBUG("don't know how to parse %s CPU models", arch);
+        return 0;
+    }
+
+    if (virExec(qemuarg, qemuenv, NULL,
+                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
+        return -1;
+
+    len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &output);
+    if (len < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to read QEMU supported CPU models"));
+        goto cleanup;
+    }
+
+    if (parse(output, count, cpus) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    VIR_FREE(output);
+    if (VIR_CLOSE(newstdout) < 0)
+        ret = -1;
+
+rewait:
+    if (waitpid(child, &status, 0) != child) {
+        if (errno == EINTR)
+            goto rewait;
+
+        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
+                  WEXITSTATUS(status), (unsigned long)child);
+        ret = -1;
+    }
+    /* Check & log unexpected exit status, but don't fail,
+     * as there's really no need to throw an error if we did
+     * actually read a valid version number above */
+    if (WEXITSTATUS(status) != 0) {
+        VIR_WARN("Unexpected exit status '%d', qemu probably failed",
+                 WEXITSTATUS(status));
+    }
+
+    return ret;
+}
+
+
+static int
+qemuCapsInitGuest(virCapsPtr caps,
+                  virCapsPtr old_caps,
+                  const char *hostmachine,
+                  const struct qemu_arch_info *info,
+                  int hvm)
+{
+    virCapsGuestPtr guest;
+    int i;
+    int haskvm = 0;
+    int haskqemu = 0;
+    char *kvmbin = NULL;
+    char *binary = NULL;
+    time_t binary_mtime;
+    virCapsGuestMachinePtr *machines = NULL;
+    int nmachines = 0;
+    struct stat st;
+    unsigned int ncpus;
+    int ret = -1;
+
+    /* Check for existance of base emulator, or alternate base
+     * which can be used with magic cpu choice
+     */
+    binary = virFindFileInPath(info->binary);
+
+    if (binary == NULL || access(binary, X_OK) != 0) {
+        VIR_FREE(binary);
+        binary = virFindFileInPath(info->altbinary);
+
+        if (binary != NULL && access(binary, X_OK) != 0)
+            VIR_FREE(binary);
+    }
+
+    /* Can use acceleration for KVM/KQEMU if
+     *  - host & guest arches match
+     * Or
+     *  - hostarch is x86_64 and guest arch is i686
+     * The latter simply needs "-cpu qemu32"
+     */
+    if (STREQ(info->arch, hostmachine) ||
+        (STREQ(hostmachine, "x86_64") && STREQ(info->arch, "i686"))) {
+        if (access("/dev/kvm", F_OK) == 0) {
+            const char *const kvmbins[] = { "/usr/libexec/qemu-kvm", /* RHEL */
+                                            "qemu-kvm", /* Fedora */
+                                            "kvm" }; /* Upstream .spec */
+
+            for (i = 0; i < ARRAY_CARDINALITY(kvmbins); ++i) {
+                kvmbin = virFindFileInPath(kvmbins[i]);
+
+                if (kvmbin == NULL || access(kvmbin, X_OK) != 0) {
+                    VIR_FREE(kvmbin);
+                    continue;
+                }
+
+                haskvm = 1;
+                if (!binary)
+                    binary = kvmbin;
+
+                break;
+            }
+        }
+
+        if (access("/dev/kqemu", F_OK) == 0)
+            haskqemu = 1;
+    }
+
+    if (!binary)
+        return 0;
+
+    if (stat(binary, &st) == 0) {
+        binary_mtime = st.st_mtime;
+    } else {
+        char ebuf[1024];
+        VIR_WARN("Failed to stat %s, most peculiar : %s",
+                 binary, virStrerror(errno, ebuf, sizeof(ebuf)));
+        binary_mtime = 0;
+    }
+
+    if (info->machine) {
+        virCapsGuestMachinePtr machine;
+
+        if (VIR_ALLOC(machine) < 0) {
+            goto no_memory;
+        }
+
+        if (!(machine->name = strdup(info->machine))) {
+            VIR_FREE(machine);
+            goto no_memory;
+        }
+
+        nmachines = 1;
+
+        if (VIR_ALLOC_N(machines, nmachines) < 0) {
+            VIR_FREE(machine->name);
+            VIR_FREE(machine);
+            goto no_memory;
+        }
+
+        machines[0] = machine;
+    } else {
+        int probe = 1;
+        if (old_caps && binary_mtime)
+            probe = !qemuCapsGetOldMachines(hvm ? "hvm" : "xen", info->arch,
+                                            info->wordsize, binary, binary_mtime,
+                                            old_caps, &machines, &nmachines);
+        if (probe &&
+            qemuCapsProbeMachineTypes(binary, &machines, &nmachines) < 0)
+            goto error;
+    }
+
+    /* We register kvm as the base emulator too, since we can
+     * just give -no-kvm to disable acceleration if required */
+    if ((guest = virCapabilitiesAddGuest(caps,
+                                         hvm ? "hvm" : "xen",
+                                         info->arch,
+                                         info->wordsize,
+                                         binary,
+                                         NULL,
+                                         nmachines,
+                                         machines)) == NULL)
+        goto error;
+
+    machines = NULL;
+    nmachines = 0;
+
+    guest->arch.defaultInfo.emulator_mtime = binary_mtime;
+
+    if (caps->host.cpu &&
+        qemuCapsProbeCPUModels(binary, 0, info->arch, &ncpus, NULL) == 0 &&
+        ncpus > 0 &&
+        !virCapabilitiesAddGuestFeature(guest, "cpuselection", 1, 0))
+        goto error;
+
+    if (hvm) {
+        if (virCapabilitiesAddGuestDomain(guest,
+                                          "qemu",
+                                          NULL,
+                                          NULL,
+                                          0,
+                                          NULL) == NULL)
+            goto error;
+
+        if (haskqemu &&
+            virCapabilitiesAddGuestDomain(guest,
+                                          "kqemu",
+                                          NULL,
+                                          NULL,
+                                          0,
+                                          NULL) == NULL)
+            goto error;
+
+        if (haskvm) {
+            virCapsGuestDomainPtr dom;
+
+            if (stat(kvmbin, &st) == 0) {
+                binary_mtime = st.st_mtime;
+            } else {
+                char ebuf[1024];
+                VIR_WARN("Failed to stat %s, most peculiar : %s",
+                         binary, virStrerror(errno, ebuf, sizeof(ebuf)));
+                binary_mtime = 0;
+            }
+
+            if (!STREQ(binary, kvmbin)) {
+                int probe = 1;
+                if (old_caps && binary_mtime)
+                    probe = !qemuCapsGetOldMachines("hvm", info->arch, info->wordsize,
+                                                    kvmbin, binary_mtime,
+                                                    old_caps, &machines, &nmachines);
+                if (probe &&
+                    qemuCapsProbeMachineTypes(kvmbin, &machines, &nmachines) < 0)
+                    goto error;
+            }
+
+            if ((dom = virCapabilitiesAddGuestDomain(guest,
+                                                     "kvm",
+                                                     kvmbin,
+                                                     NULL,
+                                                     nmachines,
+                                                     machines)) == NULL) {
+                goto error;
+            }
+
+            machines = NULL;
+            nmachines = 0;
+
+            dom->info.emulator_mtime = binary_mtime;
+        }
+    } else {
+        if (virCapabilitiesAddGuestDomain(guest,
+                                          "kvm",
+                                          NULL,
+                                          NULL,
+                                          0,
+                                          NULL) == NULL)
+            goto error;
+    }
+
+    if (info->nflags) {
+        for (i = 0 ; i < info->nflags ; i++) {
+            if (virCapabilitiesAddGuestFeature(guest,
+                                               info->flags[i].name,
+                                               info->flags[i].default_on,
+                                               info->flags[i].toggle) == NULL)
+                goto error;
+        }
+    }
+
+    ret = 0;
+
+cleanup:
+    if (binary == kvmbin) {
+        /* don't double free */
+        VIR_FREE(binary);
+    } else {
+        VIR_FREE(binary);
+        VIR_FREE(kvmbin);
+    }
+
+    return ret;
+
+no_memory:
+    virReportOOMError();
+
+error:
+    virCapabilitiesFreeMachines(machines, nmachines);
+
+    goto cleanup;
+}
+
+
+static int
+qemuCapsInitCPU(virCapsPtr caps,
+                 const char *arch)
+{
+    virCPUDefPtr cpu = NULL;
+    union cpuData *data = NULL;
+    virNodeInfo nodeinfo;
+    int ret = -1;
+
+    if (VIR_ALLOC(cpu) < 0
+        || !(cpu->arch = strdup(arch))) {
+        virReportOOMError();
+        goto error;
+    }
+
+    if (nodeGetInfo(NULL, &nodeinfo))
+        goto error;
+
+    cpu->type = VIR_CPU_TYPE_HOST;
+    cpu->sockets = nodeinfo.sockets;
+    cpu->cores = nodeinfo.cores;
+    cpu->threads = nodeinfo.threads;
+
+    if (!(data = cpuNodeData(arch))
+        || cpuDecode(cpu, data, NULL, 0, NULL) < 0)
+        goto error;
+
+    caps->host.cpu = cpu;
+
+    ret = 0;
+
+cleanup:
+    cpuDataFree(arch, data);
+
+    return ret;
+
+error:
+    virCPUDefFree(cpu);
+    goto cleanup;
+}
+
+
+virCapsPtr qemuCapsInit(virCapsPtr old_caps)
+{
+    struct utsname utsname;
+    virCapsPtr caps;
+    int i;
+    char *xenner = NULL;
+
+    /* Really, this never fails - look at the man-page. */
+    uname (&utsname);
+
+    if ((caps = virCapabilitiesNew(utsname.machine,
+                                   1, 1)) == NULL)
+        goto no_memory;
+
+    /* Using KVM's mac prefix for QEMU too */
+    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x52, 0x54, 0x00 });
+
+    /* Some machines have problematic NUMA toplogy causing
+     * unexpected failures. We don't want to break the QEMU
+     * driver in this scenario, so log errors & carry on
+     */
+    if (nodeCapsInitNUMA(caps) < 0) {
+        virCapabilitiesFreeNUMAInfo(caps);
+        VIR_WARN0("Failed to query host NUMA topology, disabling NUMA capabilities");
+    }
+
+    if (old_caps == NULL || old_caps->host.cpu == NULL) {
+        if (qemuCapsInitCPU(caps, utsname.machine) < 0)
+            VIR_WARN0("Failed to get host CPU");
+    }
+    else {
+        caps->host.cpu = old_caps->host.cpu;
+        old_caps->host.cpu = NULL;
+    }
+
+    virCapabilitiesAddHostMigrateTransport(caps,
+                                           "tcp");
+
+    /* First the pure HVM guests */
+    for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_hvm) ; i++)
+        if (qemuCapsInitGuest(caps, old_caps,
+                              utsname.machine,
+                              &arch_info_hvm[i], 1) < 0)
+            goto no_memory;
+
+    /* Then possibly the Xen paravirt guests (ie Xenner */
+    xenner = virFindFileInPath("xenner");
+
+    if (xenner != NULL && access(xenner, X_OK) == 0 &&
+        access("/dev/kvm", F_OK) == 0) {
+        for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_xen) ; i++)
+            /* Allow Xen 32-on-32, 32-on-64 and 64-on-64 */
+            if (STREQ(arch_info_xen[i].arch, utsname.machine) ||
+                (STREQ(utsname.machine, "x86_64") &&
+                 STREQ(arch_info_xen[i].arch, "i686"))) {
+                if (qemuCapsInitGuest(caps, old_caps,
+                                      utsname.machine,
+                                      &arch_info_xen[i], 0) < 0)
+                    goto no_memory;
+            }
+    }
+
+    VIR_FREE(xenner);
+
+    /* QEMU Requires an emulator in the XML */
+    virCapabilitiesSetEmulatorRequired(caps);
+
+    caps->defaultConsoleTargetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
+
+    return caps;
+
+ no_memory:
+    VIR_FREE(xenner);
+    virCapabilitiesFree(caps);
+    return NULL;
+}
+
+
+static unsigned long long
+qemuCapsComputeCmdFlags(const char *help,
+                        unsigned int version,
+                        unsigned int is_kvm,
+                        unsigned int kvm_version)
+{
+    unsigned long long flags = 0;
+    const char *p;
+
+    if (strstr(help, "-no-kqemu"))
+        flags |= QEMUD_CMD_FLAG_KQEMU;
+    if (strstr(help, "-enable-kqemu"))
+        flags |= QEMUD_CMD_FLAG_ENABLE_KQEMU;
+    if (strstr(help, "-no-kvm"))
+        flags |= QEMUD_CMD_FLAG_KVM;
+    if (strstr(help, "-enable-kvm"))
+        flags |= QEMUD_CMD_FLAG_ENABLE_KVM;
+    if (strstr(help, "-no-reboot"))
+        flags |= QEMUD_CMD_FLAG_NO_REBOOT;
+    if (strstr(help, "-name")) {
+        flags |= QEMUD_CMD_FLAG_NAME;
+        if (strstr(help, ",process="))
+            flags |= QEMUD_CMD_FLAG_NAME_PROCESS;
+    }
+    if (strstr(help, "-uuid"))
+        flags |= QEMUD_CMD_FLAG_UUID;
+    if (strstr(help, "-xen-domid"))
+        flags |= QEMUD_CMD_FLAG_XEN_DOMID;
+    else if (strstr(help, "-domid"))
+        flags |= QEMUD_CMD_FLAG_DOMID;
+    if (strstr(help, "-drive")) {
+        flags |= QEMUD_CMD_FLAG_DRIVE;
+        if (strstr(help, "cache=") &&
+            !strstr(help, "cache=on|off"))
+            flags |= QEMUD_CMD_FLAG_DRIVE_CACHE_V2;
+        if (strstr(help, "format="))
+            flags |= QEMUD_CMD_FLAG_DRIVE_FORMAT;
+        if (strstr(help, "readonly="))
+            flags |= QEMUD_CMD_FLAG_DRIVE_READONLY;
+    }
+    if ((p = strstr(help, "-vga")) && !strstr(help, "-std-vga")) {
+        const char *nl = strstr(p, "\n");
+
+        flags |= QEMUD_CMD_FLAG_VGA;
+
+        if (strstr(p, "|qxl"))
+            flags |= QEMUD_CMD_FLAG_VGA_QXL;
+        if ((p = strstr(p, "|none")) && p < nl)
+            flags |= QEMUD_CMD_FLAG_VGA_NONE;
+    }
+    if (strstr(help, "-spice"))
+        flags |= QEMUD_CMD_FLAG_SPICE;
+    if (strstr(help, "boot=on"))
+        flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
+    if (strstr(help, "serial=s"))
+        flags |= QEMUD_CMD_FLAG_DRIVE_SERIAL;
+    if (strstr(help, "-pcidevice"))
+        flags |= QEMUD_CMD_FLAG_PCIDEVICE;
+    if (strstr(help, "-mem-path"))
+        flags |= QEMUD_CMD_FLAG_MEM_PATH;
+    if (strstr(help, "-chardev"))
+        flags |= QEMUD_CMD_FLAG_CHARDEV;
+    if (strstr(help, "-balloon"))
+        flags |= QEMUD_CMD_FLAG_BALLOON;
+    if (strstr(help, "-device")) {
+        flags |= QEMUD_CMD_FLAG_DEVICE;
+        /*
+         * When -device was introduced, qemu already supported drive's
+         * readonly option but didn't advertise that.
+         */
+        flags |= QEMUD_CMD_FLAG_DRIVE_READONLY;
+    }
+    if (strstr(help, "-nodefconfig"))
+        flags |= QEMUD_CMD_FLAG_NODEFCONFIG;
+    /* The trailing ' ' is important to avoid a bogus match */
+    if (strstr(help, "-rtc "))
+        flags |= QEMUD_CMD_FLAG_RTC;
+    /* to wit */
+    if (strstr(help, "-rtc-td-hack"))
+        flags |= QEMUD_CMD_FLAG_RTC_TD_HACK;
+    if (strstr(help, "-no-hpet"))
+        flags |= QEMUD_CMD_FLAG_NO_HPET;
+    if (strstr(help, "-no-kvm-pit-reinjection"))
+        flags |= QEMUD_CMD_FLAG_NO_KVM_PIT;
+    if (strstr(help, "-tdf"))
+        flags |= QEMUD_CMD_FLAG_TDF;
+    if (strstr(help, "-enable-nesting"))
+        flags |= QEMUD_CMD_FLAG_NESTING;
+    if (strstr(help, ",menu=on"))
+        flags |= QEMUD_CMD_FLAG_BOOT_MENU;
+    if (strstr(help, "-fsdev"))
+        flags |= QEMUD_CMD_FLAG_FSDEV;
+    if (strstr(help, "-smbios type"))
+        flags |= QEMUD_CMD_FLAG_SMBIOS_TYPE;
+
+    if (strstr(help, "-netdev")) {
+        /* Disable -netdev on 0.12 since although it exists,
+         * the corresponding netdev_add/remove monitor commands
+         * do not, and we need them to be able todo hotplug */
+        if (version >= 13000)
+            flags |= QEMUD_CMD_FLAG_NETDEV;
+    }
+
+    if (strstr(help, "-sdl"))
+        flags |= QEMUD_CMD_FLAG_SDL;
+    if (strstr(help, "cores=") &&
+        strstr(help, "threads=") &&
+        strstr(help, "sockets="))
+        flags |= QEMUD_CMD_FLAG_SMP_TOPOLOGY;
+
+    if (version >= 9000)
+        flags |= QEMUD_CMD_FLAG_VNC_COLON;
+
+    if (is_kvm && (version >= 10000 || kvm_version >= 74))
+        flags |= QEMUD_CMD_FLAG_VNET_HDR;
+
+    if (is_kvm && strstr(help, ",vhost=")) {
+        flags |= QEMUD_CMD_FLAG_VNET_HOST;
+    }
+
+    /*
+     * Handling of -incoming arg with varying features
+     *  -incoming tcp    (kvm >= 79, qemu >= 0.10.0)
+     *  -incoming exec   (kvm >= 80, qemu >= 0.10.0)
+     *  -incoming stdio  (all earlier kvm)
+     *
+     * NB, there was a pre-kvm-79 'tcp' support, but it
+     * was broken, because it blocked the monitor console
+     * while waiting for data, so pretend it doesn't exist
+     */
+    if (version >= 10000) {
+        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
+        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
+        if (version >= 12000)
+            flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX;
+    } else if (kvm_version >= 79) {
+        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
+        if (kvm_version >= 80)
+            flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
+    } else if (kvm_version > 0) {
+        flags |= QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO;
+    }
+
+    if (version >= 10000)
+        flags |= QEMUD_CMD_FLAG_0_10;
+
+    /* While JSON mode was available in 0.12.0, it was too
+     * incomplete to contemplate using. The 0.13.0 release
+     * is good enough to use, even though it lacks one or
+     * two features. The benefits of JSON mode now outweigh
+     * the downside.
+     */
+     if (version >= 13000)
+        flags |= QEMUD_CMD_FLAG_MONITOR_JSON;
+
+    return flags;
+}
+
+/* We parse the output of 'qemu -help' to get the QEMU
+ * version number. The first bit is easy, just parse
+ * 'QEMU PC emulator version x.y.z'
+ * or
+ * 'QEMU emulator version x.y.z'.
+ *
+ * With qemu-kvm, however, that is followed by a string
+ * in parenthesis as follows:
+ *  - qemu-kvm-x.y.z in stable releases
+ *  - kvm-XX for kvm versions up to kvm-85
+ *  - qemu-kvm-devel-XX for kvm version kvm-86 and later
+ *
+ * For qemu-kvm versions before 0.10.z, we need to detect
+ * the KVM version number for some features. With 0.10.z
+ * and later, we just need the QEMU version number and
+ * whether it is KVM QEMU or mainline QEMU.
+ */
+#define QEMU_VERSION_STR_1  "QEMU emulator version"
+#define QEMU_VERSION_STR_2  "QEMU PC emulator version"
+#define QEMU_KVM_VER_PREFIX "(qemu-kvm-"
+#define KVM_VER_PREFIX      "(kvm-"
+
+#define SKIP_BLANKS(p) do { while ((*(p) == ' ') || (*(p) == '\t')) (p)++; } while (0)
+
+int qemuCapsParseHelpStr(const char *qemu,
+                         const char *help,
+                         unsigned long long *flags,
+                         unsigned int *version,
+                         unsigned int *is_kvm,
+                         unsigned int *kvm_version)
+{
+    unsigned major, minor, micro;
+    const char *p = help;
+
+    *flags = *version = *is_kvm = *kvm_version = 0;
+
+    if (STRPREFIX(p, QEMU_VERSION_STR_1))
+        p += strlen(QEMU_VERSION_STR_1);
+    else if (STRPREFIX(p, QEMU_VERSION_STR_2))
+        p += strlen(QEMU_VERSION_STR_2);
+    else
+        goto fail;
+
+    SKIP_BLANKS(p);
+
+    major = virParseNumber(&p);
+    if (major == -1 || *p != '.')
+        goto fail;
+
+    ++p;
+
+    minor = virParseNumber(&p);
+    if (minor == -1 || *p != '.')
+        goto fail;
+
+    ++p;
+
+    micro = virParseNumber(&p);
+    if (micro == -1)
+        goto fail;
+
+    SKIP_BLANKS(p);
+
+    if (STRPREFIX(p, QEMU_KVM_VER_PREFIX)) {
+        *is_kvm = 1;
+        p += strlen(QEMU_KVM_VER_PREFIX);
+    } else if (STRPREFIX(p, KVM_VER_PREFIX)) {
+        int ret;
+
+        *is_kvm = 1;
+        p += strlen(KVM_VER_PREFIX);
+
+        ret = virParseNumber(&p);
+        if (ret == -1)
+            goto fail;
+
+        *kvm_version = ret;
+    }
+
+    *version = (major * 1000 * 1000) + (minor * 1000) + micro;
+
+    *flags = qemuCapsComputeCmdFlags(help, *version, *is_kvm, *kvm_version);
+
+    VIR_DEBUG("Version %u.%u.%u, cooked version %u, flags 0x%llx",
+              major, minor, micro, *version, *flags);
+    if (*kvm_version)
+        VIR_DEBUG("KVM version %d detected", *kvm_version);
+    else if (*is_kvm)
+        VIR_DEBUG("qemu-kvm version %u.%u.%u detected", major, minor, micro);
+
+    return 0;
+
+fail:
+    p = strchr(help, '\n');
+    if (p)
+        p = strndup(help, p - help);
+
+    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                    _("cannot parse %s version number in '%s'"),
+                    qemu, p ? p : help);
+
+    VIR_FREE(p);
+
+    return -1;
+}
+
+static void
+qemuCapsParsePCIDeviceStrs(const char *qemu,
+                           unsigned long long *flags)
+{
+    const char *const qemuarg[] = { qemu, "-device", "pci-assign,?", NULL };
+    const char *const qemuenv[] = { "LC_ALL=C", NULL };
+    pid_t child;
+    int status;
+    int newstderr = -1;
+
+    if (virExec(qemuarg, qemuenv, NULL,
+                &child, -1, NULL, &newstderr, VIR_EXEC_CLEAR_CAPS) < 0)
+        return;
+
+    char *pciassign = NULL;
+    enum { MAX_PCI_OUTPUT_SIZE = 1024*4 };
+    int len = virFileReadLimFD(newstderr, MAX_PCI_OUTPUT_SIZE, &pciassign);
+    if (len < 0) {
+        virReportSystemError(errno,
+                             _("Unable to read %s pci-assign device output"),
+                             qemu);
+        goto cleanup;
+    }
+
+    if (strstr(pciassign, "pci-assign.configfd"))
+        *flags |= QEMUD_CMD_FLAG_PCI_CONFIGFD;
+
+cleanup:
+    VIR_FREE(pciassign);
+    VIR_FORCE_CLOSE(newstderr);
+rewait:
+    if (waitpid(child, &status, 0) != child) {
+        if (errno == EINTR)
+            goto rewait;
+
+        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
+                  WEXITSTATUS(status), (unsigned long)child);
+    }
+    if (WEXITSTATUS(status) != 0) {
+        VIR_WARN("Unexpected exit status '%d', qemu probably failed",
+                 WEXITSTATUS(status));
+    }
+}
+
+int qemuCapsExtractVersionInfo(const char *qemu,
+                               unsigned int *retversion,
+                               unsigned long long *retflags)
+{
+    const char *const qemuarg[] = { qemu, "-help", NULL };
+    const char *const qemuenv[] = { "LC_ALL=C", NULL };
+    pid_t child;
+    int newstdout = -1;
+    int ret = -1, status;
+    unsigned int version, is_kvm, kvm_version;
+    unsigned long long flags = 0;
+
+    if (retflags)
+        *retflags = 0;
+    if (retversion)
+        *retversion = 0;
+
+    /* Make sure the binary we are about to try exec'ing exists.
+     * Technically we could catch the exec() failure, but that's
+     * in a sub-process so it's hard to feed back a useful error.
+     */
+    if (access(qemu, X_OK) < 0) {
+        virReportSystemError(errno, _("Cannot find QEMU binary %s"), qemu);
+        return -1;
+    }
+
+    if (virExec(qemuarg, qemuenv, NULL,
+                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
+        return -1;
+
+    char *help = NULL;
+    enum { MAX_HELP_OUTPUT_SIZE = 1024*64 };
+    int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help);
+    if (len < 0) {
+        virReportSystemError(errno,
+                             _("Unable to read %s help output"), qemu);
+        goto cleanup2;
+    }
+
+    if (qemuCapsParseHelpStr(qemu, help, &flags,
+                             &version, &is_kvm, &kvm_version) == -1)
+        goto cleanup2;
+
+    if (flags & QEMUD_CMD_FLAG_DEVICE)
+        qemuCapsParsePCIDeviceStrs(qemu, &flags);
+
+    if (retversion)
+        *retversion = version;
+    if (retflags)
+        *retflags = flags;
+
+    ret = 0;
+
+cleanup2:
+    VIR_FREE(help);
+    if (VIR_CLOSE(newstdout) < 0)
+        ret = -1;
+
+rewait:
+    if (waitpid(child, &status, 0) != child) {
+        if (errno == EINTR)
+            goto rewait;
+
+        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
+                  WEXITSTATUS(status), (unsigned long)child);
+        ret = -1;
+    }
+    /* Check & log unexpected exit status, but don't fail,
+     * as there's really no need to throw an error if we did
+     * actually read a valid version number above */
+    if (WEXITSTATUS(status) != 0) {
+        VIR_WARN("Unexpected exit status '%d', qemu probably failed",
+                 WEXITSTATUS(status));
+    }
+
+    return ret;
+}
+
+static void
+uname_normalize (struct utsname *ut)
+{
+    uname(ut);
+
+    /* Map i386, i486, i586 to i686.  */
+    if (ut->machine[0] == 'i' &&
+        ut->machine[1] != '\0' &&
+        ut->machine[2] == '8' &&
+        ut->machine[3] == '6' &&
+        ut->machine[4] == '\0')
+        ut->machine[1] = '6';
+}
+
+int qemuCapsExtractVersion(virCapsPtr caps,
+                           unsigned int *version)
+{
+    const char *binary;
+    struct stat sb;
+    struct utsname ut;
+
+    if (*version > 0)
+        return 0;
+
+    uname_normalize(&ut);
+    if ((binary = virCapabilitiesDefaultGuestEmulator(caps,
+                                                      "hvm",
+                                                      ut.machine,
+                                                      "qemu")) == NULL) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("Cannot find suitable emulator for %s"), ut.machine);
+        return -1;
+    }
+
+    if (stat(binary, &sb) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot find QEMU binary %s"), binary);
+        return -1;
+    }
+
+    if (qemuCapsExtractVersionInfo(binary, version, NULL) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
new file mode 100644
index 0000000..83afd9b
--- /dev/null
+++ b/src/qemu/qemu_capabilities.h
@@ -0,0 +1,113 @@
+/*
+ * qemu_capabilities.h: QEMU capabilities generation
+ *
+ * Copyright (C) 2006-2007, 2009-2010 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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.1 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __QEMU_CAPABILITIES_H__
+# define __QEMU_CAPABILITIES_H__
+
+# include "capabilities.h"
+
+/* Internal flags to keep track of qemu command line capabilities */
+enum qemuCapsFlags {
+    QEMUD_CMD_FLAG_KQEMU          = (1 << 0), /* Whether KQEMU is compiled in */
+    QEMUD_CMD_FLAG_VNC_COLON      = (1 << 1), /* Does the VNC take just port, or address + display */
+    QEMUD_CMD_FLAG_NO_REBOOT      = (1 << 2), /* Is the -no-reboot flag available */
+    QEMUD_CMD_FLAG_DRIVE          = (1 << 3), /* Is the new -drive arg available */
+    QEMUD_CMD_FLAG_DRIVE_BOOT     = (1 << 4), /* Does -drive support boot=on */
+    QEMUD_CMD_FLAG_NAME           = (1 << 5), /* Is the -name flag available */
+    QEMUD_CMD_FLAG_UUID           = (1 << 6), /* Is the -uuid flag available */
+    QEMUD_CMD_FLAG_DOMID          = (1 << 7), /* Xenner only, special -domid flag available */
+    QEMUD_CMD_FLAG_VNET_HDR        = (1 << 8),
+    QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO = (1 << 9),  /* Original migration code from KVM. Also had tcp, but we can't use that
+                                                   * since it had a design bug blocking the entire monitor console */
+    QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP  = (1 << 10), /* New migration syntax after merge to QEMU with TCP transport */
+    QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC = (1 << 11), /* New migration syntax after merge to QEMU with EXEC transport */
+    QEMUD_CMD_FLAG_DRIVE_CACHE_V2    = (1 << 12), /* Is the cache= flag wanting new v2 values */
+    QEMUD_CMD_FLAG_KVM               = (1 << 13), /* Whether KVM is compiled in */
+    QEMUD_CMD_FLAG_DRIVE_FORMAT      = (1 << 14), /* Is -drive format= avail */
+    QEMUD_CMD_FLAG_VGA               = (1 << 15), /* Is -vga avail */
+
+    /* features added in qemu-0.10.0 or later */
+    QEMUD_CMD_FLAG_0_10         = (1 << 16),
+    QEMUD_CMD_FLAG_NET_NAME     = QEMUD_CMD_FLAG_0_10, /* -net ...,name=str */
+    QEMUD_CMD_FLAG_HOST_NET_ADD = QEMUD_CMD_FLAG_0_10, /* host_net_add monitor command */
+
+    QEMUD_CMD_FLAG_PCIDEVICE     = (1 << 17), /* PCI device assignment only supported by qemu-kvm */
+    QEMUD_CMD_FLAG_MEM_PATH      = (1 << 18), /* mmap'ped guest backing supported */
+    QEMUD_CMD_FLAG_DRIVE_SERIAL  = (1 << 19), /* -driver serial=  available */
+    QEMUD_CMD_FLAG_XEN_DOMID     = (1 << 20), /* -xen-domid (new style xen integration) */
+    QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX = (1 << 21), /* Does qemu support unix domain sockets for migration? */
+    QEMUD_CMD_FLAG_CHARDEV       = (1 << 22), /* Is the new -chardev arg available */
+    QEMUD_CMD_FLAG_ENABLE_KVM    = (1 << 23), /* Is the -enable-kvm flag available to "enable KVM full virtualization support" */
+    QEMUD_CMD_FLAG_MONITOR_JSON  = (1 << 24), /* JSON mode for monitor */
+    QEMUD_CMD_FLAG_BALLOON       = (1 << 25), /* -balloon available */
+    QEMUD_CMD_FLAG_DEVICE        = (1 << 26), /* Is the new -device arg available */
+    QEMUD_CMD_FLAG_SDL           = (1 << 27), /* Is the new -sdl arg available */
+    QEMUD_CMD_FLAG_SMP_TOPOLOGY  = (1 << 28), /* Is sockets=s,cores=c,threads=t available for -smp? */
+    QEMUD_CMD_FLAG_NETDEV        = (1 << 29), /* The -netdev flag & netdev_add/remove monitor commands */
+    QEMUD_CMD_FLAG_RTC           = (1 << 30), /* The -rtc flag for clock options */
+    QEMUD_CMD_FLAG_VNET_HOST     = (1LL << 31), /* vnet-host support is available in qemu */
+    QEMUD_CMD_FLAG_RTC_TD_HACK   = (1LL << 32), /* -rtc-td-hack available */
+    QEMUD_CMD_FLAG_NO_HPET       = (1LL << 33), /* -no-hpet flag is supported */
+    QEMUD_CMD_FLAG_NO_KVM_PIT    = (1LL << 34), /* -no-kvm-pit-reinjection supported */
+    QEMUD_CMD_FLAG_TDF           = (1LL << 35), /* -tdf flag (user-mode pit catchup) */
+    QEMUD_CMD_FLAG_PCI_CONFIGFD  = (1LL << 36), /* pci-assign.configfd */
+    QEMUD_CMD_FLAG_NODEFCONFIG   = (1LL << 37), /* -nodefconfig */
+    QEMUD_CMD_FLAG_BOOT_MENU     = (1LL << 38), /* -boot menu=on support */
+    QEMUD_CMD_FLAG_ENABLE_KQEMU  = (1LL << 39), /* -enable-kqemu flag */
+    QEMUD_CMD_FLAG_FSDEV         = (1LL << 40), /* -fstype filesystem passthrough */
+    QEMUD_CMD_FLAG_NESTING       = (1LL << 41), /* -enable-nesting (SVM/VMX) */
+    QEMUD_CMD_FLAG_NAME_PROCESS  = (1LL << 42), /* Is -name process= available */
+    QEMUD_CMD_FLAG_DRIVE_READONLY= (1LL << 43), /* -drive readonly=on|off */
+    QEMUD_CMD_FLAG_SMBIOS_TYPE   = (1LL << 44), /* Is -smbios type= available */
+    QEMUD_CMD_FLAG_VGA_QXL       = (1LL << 45), /* The 'qxl' arg for '-vga' */
+    QEMUD_CMD_FLAG_SPICE         = (1LL << 46), /* Is -spice avail */
+    QEMUD_CMD_FLAG_VGA_NONE      = (1LL << 47), /* The 'none' arg for '-vga' */
+};
+
+virCapsPtr qemuCapsInit(virCapsPtr old_caps);
+
+int qemuCapsProbeMachineTypes(const char *binary,
+                              virCapsGuestMachinePtr **machines,
+                              int *nmachines);
+
+int qemuCapsProbeCPUModels(const char *qemu,
+                           unsigned long long qemuCmdFlags,
+                           const char *arch,
+                           unsigned int *count,
+                           const char ***cpus);
+
+int qemuCapsExtractVersion(virCapsPtr caps,
+                           unsigned int *version);
+int qemuCapsExtractVersionInfo(const char *qemu,
+                               unsigned int *version,
+                               unsigned long long *qemuCmdFlags);
+
+int qemuCapsParseHelpStr(const char *qemu,
+                         const char *str,
+                         unsigned long long *qemuCmdFlags,
+                         unsigned int *version,
+                         unsigned int *is_kvm,
+                         unsigned int *kvm_version);
+
+
+#endif /* __QEMU_CAPABILITIES_H__*/
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index f4b524e..0c9c676 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -40,6 +40,7 @@
 #include "c-ctype.h"
 #include "virterror_internal.h"
 #include "qemu_conf.h"
+#include "qemu_capabilities.h"
 #include "qemu_bridge_filter.h"
 #include "uuid.h"
 #include "buf.h"
@@ -450,1162 +451,6 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
     return 0;
 }
 
-struct qemu_feature_flags {
-    const char *name;
-    const int default_on;
-    const int toggle;
-};
-
-struct qemu_arch_info {
-    const char *arch;
-    int wordsize;
-    const char *machine;
-    const char *binary;
-    const char *altbinary;
-    const struct qemu_feature_flags *flags;
-    int nflags;
-};
-
-/* Feature flags for the architecture info */
-static const struct qemu_feature_flags const arch_info_i686_flags [] = {
-    { "pae",  1, 0 },
-    { "nonpae",  1, 0 },
-    { "acpi", 1, 1 },
-    { "apic", 1, 0 },
-};
-
-static const struct qemu_feature_flags const arch_info_x86_64_flags [] = {
-    { "acpi", 1, 1 },
-    { "apic", 1, 0 },
-};
-
-/* The archicture tables for supported QEMU archs */
-static const struct qemu_arch_info const arch_info_hvm[] = {
-    {  "i686",   32, NULL, "qemu",
-       "qemu-system-x86_64", arch_info_i686_flags, 4 },
-    {  "x86_64", 64, NULL, "qemu-system-x86_64",
-       NULL, arch_info_x86_64_flags, 2 },
-    {  "arm",    32, NULL, "qemu-system-arm",    NULL, NULL, 0 },
-    {  "mips",   32, NULL, "qemu-system-mips",   NULL, NULL, 0 },
-    {  "mipsel", 32, NULL, "qemu-system-mipsel", NULL, NULL, 0 },
-    {  "sparc",  32, NULL, "qemu-system-sparc",  NULL, NULL, 0 },
-    {  "ppc",    32, NULL, "qemu-system-ppc",    NULL, NULL, 0 },
-    {  "itanium", 64, NULL, "qemu-system-ia64",  NULL, NULL, 0 },
-    {  "s390x",  64, NULL, "qemu-system-s390x",  NULL, NULL, 0 },
-};
-
-static const struct qemu_arch_info const arch_info_xen[] = {
-    {  "i686",   32, "xenner", "xenner", NULL, arch_info_i686_flags, 4 },
-    {  "x86_64", 64, "xenner", "xenner", NULL, arch_info_x86_64_flags, 2 },
-};
-
-
-/* Format is:
- * <machine> <desc> [(default)|(alias of <canonical>)]
- */
-static int
-qemudParseMachineTypesStr(const char *output,
-                          virCapsGuestMachinePtr **machines,
-                          int *nmachines)
-{
-    const char *p = output;
-    const char *next;
-    virCapsGuestMachinePtr *list = NULL;
-    int nitems = 0;
-
-    do {
-        const char *t;
-        virCapsGuestMachinePtr machine;
-
-        if ((next = strchr(p, '\n')))
-            ++next;
-
-        if (STRPREFIX(p, "Supported machines are:"))
-            continue;
-
-        if (!(t = strchr(p, ' ')) || (next && t >= next))
-            continue;
-
-        if (VIR_ALLOC(machine) < 0)
-            goto no_memory;
-
-        if (!(machine->name = strndup(p, t - p))) {
-            VIR_FREE(machine);
-            goto no_memory;
-        }
-
-        if (VIR_REALLOC_N(list, nitems + 1) < 0) {
-            VIR_FREE(machine->name);
-            VIR_FREE(machine);
-            goto no_memory;
-        }
-
-        p = t;
-        if (!(t = strstr(p, "(default)")) || (next && t >= next)) {
-            list[nitems++] = machine;
-        } else {
-            /* put the default first in the list */
-            memmove(list + 1, list, sizeof(*list) * nitems);
-            list[0] = machine;
-            nitems++;
-        }
-
-        if ((t = strstr(p, "(alias of ")) && (!next || t < next)) {
-            p = t + strlen("(alias of ");
-            if (!(t = strchr(p, ')')) || (next && t >= next))
-                continue;
-
-            if (!(machine->canonical = strndup(p, t - p)))
-                goto no_memory;
-        }
-    } while ((p = next));
-
-    *machines = list;
-    *nmachines = nitems;
-
-    return 0;
-
-  no_memory:
-    virReportOOMError();
-    virCapabilitiesFreeMachines(list, nitems);
-    return -1;
-}
-
-int
-qemudProbeMachineTypes(const char *binary,
-                       virCapsGuestMachinePtr **machines,
-                       int *nmachines)
-{
-    const char *const qemuarg[] = { binary, "-M", "?", NULL };
-    const char *const qemuenv[] = { "LC_ALL=C", NULL };
-    char *output;
-    enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
-    pid_t child;
-    int newstdout = -1, len;
-    int ret = -1, status;
-
-    if (virExec(qemuarg, qemuenv, NULL,
-                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
-        return -1;
-
-    len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &output);
-    if (len < 0) {
-        virReportSystemError(errno, "%s",
-                             _("Unable to read 'qemu -M ?' output"));
-        goto cleanup;
-    }
-
-    if (qemudParseMachineTypesStr(output, machines, nmachines) < 0)
-        goto cleanup2;
-
-    ret = 0;
-
-cleanup2:
-    VIR_FREE(output);
-cleanup:
-    if (VIR_CLOSE(newstdout) < 0)
-        ret = -1;
-
-rewait:
-    if (waitpid(child, &status, 0) != child) {
-        if (errno == EINTR)
-            goto rewait;
-
-        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
-                  WEXITSTATUS(status), (unsigned long)child);
-        ret = -1;
-    }
-    /* Check & log unexpected exit status, but don't fail,
-     * as there's really no need to throw an error if we did
-     * actually read a valid version number above */
-    if (WEXITSTATUS(status) != 0) {
-        VIR_WARN("Unexpected exit status '%d', qemu probably failed",
-                 WEXITSTATUS(status));
-    }
-
-    return ret;
-}
-
-static int
-qemudGetOldMachinesFromInfo(virCapsGuestDomainInfoPtr info,
-                            const char *emulator,
-                            time_t emulator_mtime,
-                            virCapsGuestMachinePtr **machines,
-                            int *nmachines)
-{
-    virCapsGuestMachinePtr *list;
-    int i;
-
-    if (!info->nmachines)
-        return 0;
-
-    if (!info->emulator || !STREQ(emulator, info->emulator))
-        return 0;
-
-    if (emulator_mtime != info->emulator_mtime) {
-        VIR_DEBUG("mtime on %s has changed, refreshing machine types",
-                  info->emulator);
-        return 0;
-    }
-
-    if (VIR_ALLOC_N(list, info->nmachines) < 0) {
-        virReportOOMError();
-        return 0;
-    }
-
-    for (i = 0; i < info->nmachines; i++) {
-        if (VIR_ALLOC(list[i]) < 0) {
-            goto no_memory;
-        }
-        if (info->machines[i]->name &&
-            !(list[i]->name = strdup(info->machines[i]->name))) {
-            goto no_memory;
-        }
-        if (info->machines[i]->canonical &&
-            !(list[i]->canonical = strdup(info->machines[i]->canonical))) {
-            goto no_memory;
-        }
-    }
-
-    *machines = list;
-    *nmachines = info->nmachines;
-
-    return 1;
-
-  no_memory:
-    virReportOOMError();
-    virCapabilitiesFreeMachines(list, info->nmachines);
-    return 0;
-}
-
-static int
-qemudGetOldMachines(const char *ostype,
-                    const char *arch,
-                    int wordsize,
-                    const char *emulator,
-                    time_t emulator_mtime,
-                    virCapsPtr old_caps,
-                    virCapsGuestMachinePtr **machines,
-                    int *nmachines)
-{
-    int i;
-
-    for (i = 0; i < old_caps->nguests; i++) {
-        virCapsGuestPtr guest = old_caps->guests[i];
-        int j;
-
-        if (!STREQ(ostype, guest->ostype) ||
-            !STREQ(arch, guest->arch.name) ||
-            wordsize != guest->arch.wordsize)
-            continue;
-
-        for (j = 0; j < guest->arch.ndomains; j++) {
-            virCapsGuestDomainPtr dom = guest->arch.domains[j];
-
-            if (qemudGetOldMachinesFromInfo(&dom->info,
-                                            emulator, emulator_mtime,
-                                            machines, nmachines))
-                return 1;
-        }
-
-        if (qemudGetOldMachinesFromInfo(&guest->arch.defaultInfo,
-                                        emulator, emulator_mtime,
-                                        machines, nmachines))
-            return 1;
-    }
-
-    return 0;
-}
-
-
-typedef int
-(*qemudParseCPUModels)(const char *output,
-                       unsigned int *retcount,
-                       const char ***retcpus);
-
-/* Format:
- *      <arch> <model>
- * qemu-0.13 encloses some model names in []:
- *      <arch> [<model>]
- */
-static int
-qemudParseX86Models(const char *output,
-                    unsigned int *retcount,
-                    const char ***retcpus)
-{
-    const char *p = output;
-    const char *next;
-    unsigned int count = 0;
-    const char **cpus = NULL;
-    int i;
-
-    do {
-        const char *t;
-
-        if ((next = strchr(p, '\n')))
-            next++;
-
-        if (!(t = strchr(p, ' ')) || (next && t >= next))
-            continue;
-
-        if (!STRPREFIX(p, "x86"))
-            continue;
-
-        p = t;
-        while (*p == ' ')
-            p++;
-
-        if (*p == '\0' || *p == '\n')
-            continue;
-
-        if (retcpus) {
-            unsigned int len;
-
-            if (VIR_REALLOC_N(cpus, count + 1) < 0)
-                goto error;
-
-            if (next)
-                len = next - p - 1;
-            else
-                len = strlen(p);
-
-            if (len > 2 && *p == '[' && p[len - 1] == ']') {
-                p++;
-                len -= 2;
-            }
-
-            if (!(cpus[count] = strndup(p, len)))
-                goto error;
-        }
-        count++;
-    } while ((p = next));
-
-    if (retcount)
-        *retcount = count;
-    if (retcpus)
-        *retcpus = cpus;
-
-    return 0;
-
-error:
-    if (cpus) {
-        for (i = 0; i < count; i++)
-            VIR_FREE(cpus[i]);
-    }
-    VIR_FREE(cpus);
-
-    return -1;
-}
-
-
-int
-qemudProbeCPUModels(const char *qemu,
-                    unsigned long long qemuCmdFlags,
-                    const char *arch,
-                    unsigned int *count,
-                    const char ***cpus)
-{
-    const char *const qemuarg[] = {
-        qemu,
-        "-cpu", "?",
-        (qemuCmdFlags & QEMUD_CMD_FLAG_NODEFCONFIG) ? "-nodefconfig" : NULL,
-        NULL
-    };
-    const char *const qemuenv[] = { "LC_ALL=C", NULL };
-    enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
-    char *output = NULL;
-    int newstdout = -1;
-    int ret = -1;
-    pid_t child;
-    int status;
-    int len;
-    qemudParseCPUModels parse;
-
-    if (count)
-        *count = 0;
-    if (cpus)
-        *cpus = NULL;
-
-    if (STREQ(arch, "i686") || STREQ(arch, "x86_64"))
-        parse = qemudParseX86Models;
-    else {
-        VIR_DEBUG("don't know how to parse %s CPU models", arch);
-        return 0;
-    }
-
-    if (virExec(qemuarg, qemuenv, NULL,
-                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
-        return -1;
-
-    len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &output);
-    if (len < 0) {
-        virReportSystemError(errno, "%s",
-                             _("Unable to read QEMU supported CPU models"));
-        goto cleanup;
-    }
-
-    if (parse(output, count, cpus) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    ret = 0;
-
-cleanup:
-    VIR_FREE(output);
-    if (VIR_CLOSE(newstdout) < 0)
-        ret = -1;
-
-rewait:
-    if (waitpid(child, &status, 0) != child) {
-        if (errno == EINTR)
-            goto rewait;
-
-        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
-                  WEXITSTATUS(status), (unsigned long)child);
-        ret = -1;
-    }
-    /* Check & log unexpected exit status, but don't fail,
-     * as there's really no need to throw an error if we did
-     * actually read a valid version number above */
-    if (WEXITSTATUS(status) != 0) {
-        VIR_WARN("Unexpected exit status '%d', qemu probably failed",
-                 WEXITSTATUS(status));
-    }
-
-    return ret;
-}
-
-
-static int
-qemudCapsInitGuest(virCapsPtr caps,
-                   virCapsPtr old_caps,
-                   const char *hostmachine,
-                   const struct qemu_arch_info *info,
-                   int hvm) {
-    virCapsGuestPtr guest;
-    int i;
-    int haskvm = 0;
-    int haskqemu = 0;
-    char *kvmbin = NULL;
-    char *binary = NULL;
-    time_t binary_mtime;
-    virCapsGuestMachinePtr *machines = NULL;
-    int nmachines = 0;
-    struct stat st;
-    unsigned int ncpus;
-    int ret = -1;
-
-    /* Check for existance of base emulator, or alternate base
-     * which can be used with magic cpu choice
-     */
-    binary = virFindFileInPath(info->binary);
-
-    if (binary == NULL || access(binary, X_OK) != 0) {
-        VIR_FREE(binary);
-        binary = virFindFileInPath(info->altbinary);
-
-        if (binary != NULL && access(binary, X_OK) != 0)
-            VIR_FREE(binary);
-    }
-
-    /* Can use acceleration for KVM/KQEMU if
-     *  - host & guest arches match
-     * Or
-     *  - hostarch is x86_64 and guest arch is i686
-     * The latter simply needs "-cpu qemu32"
-     */
-    if (STREQ(info->arch, hostmachine) ||
-        (STREQ(hostmachine, "x86_64") && STREQ(info->arch, "i686"))) {
-        if (access("/dev/kvm", F_OK) == 0) {
-            const char *const kvmbins[] = { "/usr/libexec/qemu-kvm", /* RHEL */
-                                            "qemu-kvm", /* Fedora */
-                                            "kvm" }; /* Upstream .spec */
-
-            for (i = 0; i < ARRAY_CARDINALITY(kvmbins); ++i) {
-                kvmbin = virFindFileInPath(kvmbins[i]);
-
-                if (kvmbin == NULL || access(kvmbin, X_OK) != 0) {
-                    VIR_FREE(kvmbin);
-                    continue;
-                }
-
-                haskvm = 1;
-                if (!binary)
-                    binary = kvmbin;
-
-                break;
-            }
-        }
-
-        if (access("/dev/kqemu", F_OK) == 0)
-            haskqemu = 1;
-    }
-
-    if (!binary)
-        return 0;
-
-    if (stat(binary, &st) == 0) {
-        binary_mtime = st.st_mtime;
-    } else {
-        char ebuf[1024];
-        VIR_WARN("Failed to stat %s, most peculiar : %s",
-                 binary, virStrerror(errno, ebuf, sizeof(ebuf)));
-        binary_mtime = 0;
-    }
-
-    if (info->machine) {
-        virCapsGuestMachinePtr machine;
-
-        if (VIR_ALLOC(machine) < 0) {
-            goto no_memory;
-        }
-
-        if (!(machine->name = strdup(info->machine))) {
-            VIR_FREE(machine);
-            goto no_memory;
-        }
-
-        nmachines = 1;
-
-        if (VIR_ALLOC_N(machines, nmachines) < 0) {
-            VIR_FREE(machine->name);
-            VIR_FREE(machine);
-            goto no_memory;
-        }
-
-        machines[0] = machine;
-    } else {
-        int probe = 1;
-        if (old_caps && binary_mtime)
-            probe = !qemudGetOldMachines(hvm ? "hvm" : "xen", info->arch,
-                                         info->wordsize, binary, binary_mtime,
-                                         old_caps, &machines, &nmachines);
-        if (probe &&
-            qemudProbeMachineTypes(binary, &machines, &nmachines) < 0)
-            goto error;
-    }
-
-    /* We register kvm as the base emulator too, since we can
-     * just give -no-kvm to disable acceleration if required */
-    if ((guest = virCapabilitiesAddGuest(caps,
-                                         hvm ? "hvm" : "xen",
-                                         info->arch,
-                                         info->wordsize,
-                                         binary,
-                                         NULL,
-                                         nmachines,
-                                         machines)) == NULL)
-        goto error;
-
-    machines = NULL;
-    nmachines = 0;
-
-    guest->arch.defaultInfo.emulator_mtime = binary_mtime;
-
-    if (caps->host.cpu &&
-        qemudProbeCPUModels(binary, 0, info->arch, &ncpus, NULL) == 0 &&
-        ncpus > 0 &&
-        !virCapabilitiesAddGuestFeature(guest, "cpuselection", 1, 0))
-        goto error;
-
-    if (hvm) {
-        if (virCapabilitiesAddGuestDomain(guest,
-                                          "qemu",
-                                          NULL,
-                                          NULL,
-                                          0,
-                                          NULL) == NULL)
-            goto error;
-
-        if (haskqemu &&
-            virCapabilitiesAddGuestDomain(guest,
-                                          "kqemu",
-                                          NULL,
-                                          NULL,
-                                          0,
-                                          NULL) == NULL)
-            goto error;
-
-        if (haskvm) {
-            virCapsGuestDomainPtr dom;
-
-            if (stat(kvmbin, &st) == 0) {
-                binary_mtime = st.st_mtime;
-            } else {
-                char ebuf[1024];
-                VIR_WARN("Failed to stat %s, most peculiar : %s",
-                         binary, virStrerror(errno, ebuf, sizeof(ebuf)));
-                binary_mtime = 0;
-            }
-
-            if (!STREQ(binary, kvmbin)) {
-                int probe = 1;
-                if (old_caps && binary_mtime)
-                    probe = !qemudGetOldMachines("hvm", info->arch, info->wordsize,
-                                                 kvmbin, binary_mtime,
-                                                 old_caps, &machines, &nmachines);
-                if (probe &&
-                    qemudProbeMachineTypes(kvmbin, &machines, &nmachines) < 0)
-                    goto error;
-            }
-
-            if ((dom = virCapabilitiesAddGuestDomain(guest,
-                                                     "kvm",
-                                                     kvmbin,
-                                                     NULL,
-                                                     nmachines,
-                                                     machines)) == NULL) {
-                goto error;
-            }
-
-            machines = NULL;
-            nmachines = 0;
-
-            dom->info.emulator_mtime = binary_mtime;
-        }
-    } else {
-        if (virCapabilitiesAddGuestDomain(guest,
-                                          "kvm",
-                                          NULL,
-                                          NULL,
-                                          0,
-                                          NULL) == NULL)
-            goto error;
-    }
-
-    if (info->nflags) {
-        for (i = 0 ; i < info->nflags ; i++) {
-            if (virCapabilitiesAddGuestFeature(guest,
-                                               info->flags[i].name,
-                                               info->flags[i].default_on,
-                                               info->flags[i].toggle) == NULL)
-                goto error;
-        }
-    }
-
-    ret = 0;
-
-cleanup:
-    if (binary == kvmbin) {
-        /* don't double free */
-        VIR_FREE(binary);
-    } else {
-        VIR_FREE(binary);
-        VIR_FREE(kvmbin);
-    }
-
-    return ret;
-
-no_memory:
-    virReportOOMError();
-
-error:
-    virCapabilitiesFreeMachines(machines, nmachines);
-
-    goto cleanup;
-}
-
-
-static int
-qemudCapsInitCPU(virCapsPtr caps,
-                 const char *arch)
-{
-    virCPUDefPtr cpu = NULL;
-    union cpuData *data = NULL;
-    virNodeInfo nodeinfo;
-    int ret = -1;
-
-    if (VIR_ALLOC(cpu) < 0
-        || !(cpu->arch = strdup(arch))) {
-        virReportOOMError();
-        goto error;
-    }
-
-    if (nodeGetInfo(NULL, &nodeinfo))
-        goto error;
-
-    cpu->type = VIR_CPU_TYPE_HOST;
-    cpu->sockets = nodeinfo.sockets;
-    cpu->cores = nodeinfo.cores;
-    cpu->threads = nodeinfo.threads;
-
-    if (!(data = cpuNodeData(arch))
-        || cpuDecode(cpu, data, NULL, 0, NULL) < 0)
-        goto error;
-
-    caps->host.cpu = cpu;
-
-    ret = 0;
-
-cleanup:
-    cpuDataFree(arch, data);
-
-    return ret;
-
-error:
-    virCPUDefFree(cpu);
-    goto cleanup;
-}
-
-
-virCapsPtr qemudCapsInit(virCapsPtr old_caps) {
-    struct utsname utsname;
-    virCapsPtr caps;
-    int i;
-    char *xenner = NULL;
-
-    /* Really, this never fails - look at the man-page. */
-    uname (&utsname);
-
-    if ((caps = virCapabilitiesNew(utsname.machine,
-                                   1, 1)) == NULL)
-        goto no_memory;
-
-    /* Using KVM's mac prefix for QEMU too */
-    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x52, 0x54, 0x00 });
-
-    /* Some machines have problematic NUMA toplogy causing
-     * unexpected failures. We don't want to break the QEMU
-     * driver in this scenario, so log errors & carry on
-     */
-    if (nodeCapsInitNUMA(caps) < 0) {
-        virCapabilitiesFreeNUMAInfo(caps);
-        VIR_WARN0("Failed to query host NUMA topology, disabling NUMA capabilities");
-    }
-
-    if (old_caps == NULL || old_caps->host.cpu == NULL) {
-        if (qemudCapsInitCPU(caps, utsname.machine) < 0)
-            VIR_WARN0("Failed to get host CPU");
-    }
-    else {
-        caps->host.cpu = old_caps->host.cpu;
-        old_caps->host.cpu = NULL;
-    }
-
-    virCapabilitiesAddHostMigrateTransport(caps,
-                                           "tcp");
-
-    /* First the pure HVM guests */
-    for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_hvm) ; i++)
-        if (qemudCapsInitGuest(caps, old_caps,
-                               utsname.machine,
-                               &arch_info_hvm[i], 1) < 0)
-            goto no_memory;
-
-    /* Then possibly the Xen paravirt guests (ie Xenner */
-    xenner = virFindFileInPath("xenner");
-
-    if (xenner != NULL && access(xenner, X_OK) == 0 &&
-        access("/dev/kvm", F_OK) == 0) {
-        for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_xen) ; i++)
-            /* Allow Xen 32-on-32, 32-on-64 and 64-on-64 */
-            if (STREQ(arch_info_xen[i].arch, utsname.machine) ||
-                (STREQ(utsname.machine, "x86_64") &&
-                 STREQ(arch_info_xen[i].arch, "i686"))) {
-                if (qemudCapsInitGuest(caps, old_caps,
-                                       utsname.machine,
-                                       &arch_info_xen[i], 0) < 0)
-                    goto no_memory;
-            }
-    }
-
-    VIR_FREE(xenner);
-
-    /* QEMU Requires an emulator in the XML */
-    virCapabilitiesSetEmulatorRequired(caps);
-
-    caps->defaultConsoleTargetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
-
-    return caps;
-
- no_memory:
-    VIR_FREE(xenner);
-    virCapabilitiesFree(caps);
-    return NULL;
-}
-
-static unsigned long long qemudComputeCmdFlags(const char *help,
-                                               unsigned int version,
-                                               unsigned int is_kvm,
-                                               unsigned int kvm_version)
-{
-    unsigned long long flags = 0;
-    const char *p;
-
-    if (strstr(help, "-no-kqemu"))
-        flags |= QEMUD_CMD_FLAG_KQEMU;
-    if (strstr(help, "-enable-kqemu"))
-        flags |= QEMUD_CMD_FLAG_ENABLE_KQEMU;
-    if (strstr(help, "-no-kvm"))
-        flags |= QEMUD_CMD_FLAG_KVM;
-    if (strstr(help, "-enable-kvm"))
-        flags |= QEMUD_CMD_FLAG_ENABLE_KVM;
-    if (strstr(help, "-no-reboot"))
-        flags |= QEMUD_CMD_FLAG_NO_REBOOT;
-    if (strstr(help, "-name")) {
-        flags |= QEMUD_CMD_FLAG_NAME;
-        if (strstr(help, ",process="))
-            flags |= QEMUD_CMD_FLAG_NAME_PROCESS;
-    }
-    if (strstr(help, "-uuid"))
-        flags |= QEMUD_CMD_FLAG_UUID;
-    if (strstr(help, "-xen-domid"))
-        flags |= QEMUD_CMD_FLAG_XEN_DOMID;
-    else if (strstr(help, "-domid"))
-        flags |= QEMUD_CMD_FLAG_DOMID;
-    if (strstr(help, "-drive")) {
-        flags |= QEMUD_CMD_FLAG_DRIVE;
-        if (strstr(help, "cache=") &&
-            !strstr(help, "cache=on|off"))
-            flags |= QEMUD_CMD_FLAG_DRIVE_CACHE_V2;
-        if (strstr(help, "format="))
-            flags |= QEMUD_CMD_FLAG_DRIVE_FORMAT;
-        if (strstr(help, "readonly="))
-            flags |= QEMUD_CMD_FLAG_DRIVE_READONLY;
-    }
-    if ((p = strstr(help, "-vga")) && !strstr(help, "-std-vga")) {
-        const char *nl = strstr(p, "\n");
-
-        flags |= QEMUD_CMD_FLAG_VGA;
-
-        if (strstr(p, "|qxl"))
-            flags |= QEMUD_CMD_FLAG_VGA_QXL;
-        if ((p = strstr(p, "|none")) && p < nl)
-            flags |= QEMUD_CMD_FLAG_VGA_NONE;
-    }
-    if (strstr(help, "-spice"))
-        flags |= QEMUD_CMD_FLAG_SPICE;
-    if (strstr(help, "boot=on"))
-        flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
-    if (strstr(help, "serial=s"))
-        flags |= QEMUD_CMD_FLAG_DRIVE_SERIAL;
-    if (strstr(help, "-pcidevice"))
-        flags |= QEMUD_CMD_FLAG_PCIDEVICE;
-    if (strstr(help, "-mem-path"))
-        flags |= QEMUD_CMD_FLAG_MEM_PATH;
-    if (strstr(help, "-chardev"))
-        flags |= QEMUD_CMD_FLAG_CHARDEV;
-    if (strstr(help, "-balloon"))
-        flags |= QEMUD_CMD_FLAG_BALLOON;
-    if (strstr(help, "-device")) {
-        flags |= QEMUD_CMD_FLAG_DEVICE;
-        /*
-         * When -device was introduced, qemu already supported drive's
-         * readonly option but didn't advertise that.
-         */
-        flags |= QEMUD_CMD_FLAG_DRIVE_READONLY;
-    }
-    if (strstr(help, "-nodefconfig"))
-        flags |= QEMUD_CMD_FLAG_NODEFCONFIG;
-    /* The trailing ' ' is important to avoid a bogus match */
-    if (strstr(help, "-rtc "))
-        flags |= QEMUD_CMD_FLAG_RTC;
-    /* to wit */
-    if (strstr(help, "-rtc-td-hack"))
-        flags |= QEMUD_CMD_FLAG_RTC_TD_HACK;
-    if (strstr(help, "-no-hpet"))
-        flags |= QEMUD_CMD_FLAG_NO_HPET;
-    if (strstr(help, "-no-kvm-pit-reinjection"))
-        flags |= QEMUD_CMD_FLAG_NO_KVM_PIT;
-    if (strstr(help, "-tdf"))
-        flags |= QEMUD_CMD_FLAG_TDF;
-    if (strstr(help, "-enable-nesting"))
-        flags |= QEMUD_CMD_FLAG_NESTING;
-    if (strstr(help, ",menu=on"))
-        flags |= QEMUD_CMD_FLAG_BOOT_MENU;
-    if (strstr(help, "-fsdev"))
-        flags |= QEMUD_CMD_FLAG_FSDEV;
-    if (strstr(help, "-smbios type"))
-        flags |= QEMUD_CMD_FLAG_SMBIOS_TYPE;
-
-    if (strstr(help, "-netdev")) {
-        /* Disable -netdev on 0.12 since although it exists,
-         * the corresponding netdev_add/remove monitor commands
-         * do not, and we need them to be able todo hotplug */
-        if (version >= 13000)
-            flags |= QEMUD_CMD_FLAG_NETDEV;
-    }
-
-    if (strstr(help, "-sdl"))
-        flags |= QEMUD_CMD_FLAG_SDL;
-    if (strstr(help, "cores=") &&
-        strstr(help, "threads=") &&
-        strstr(help, "sockets="))
-        flags |= QEMUD_CMD_FLAG_SMP_TOPOLOGY;
-
-    if (version >= 9000)
-        flags |= QEMUD_CMD_FLAG_VNC_COLON;
-
-    if (is_kvm && (version >= 10000 || kvm_version >= 74))
-        flags |= QEMUD_CMD_FLAG_VNET_HDR;
-
-    if (is_kvm && strstr(help, ",vhost=")) {
-        flags |= QEMUD_CMD_FLAG_VNET_HOST;
-    }
-
-    /*
-     * Handling of -incoming arg with varying features
-     *  -incoming tcp    (kvm >= 79, qemu >= 0.10.0)
-     *  -incoming exec   (kvm >= 80, qemu >= 0.10.0)
-     *  -incoming stdio  (all earlier kvm)
-     *
-     * NB, there was a pre-kvm-79 'tcp' support, but it
-     * was broken, because it blocked the monitor console
-     * while waiting for data, so pretend it doesn't exist
-     */
-    if (version >= 10000) {
-        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
-        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
-        if (version >= 12000)
-            flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX;
-    } else if (kvm_version >= 79) {
-        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
-        if (kvm_version >= 80)
-            flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
-    } else if (kvm_version > 0) {
-        flags |= QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO;
-    }
-
-    if (version >= 10000)
-        flags |= QEMUD_CMD_FLAG_0_10;
-
-    /* While JSON mode was available in 0.12.0, it was too
-     * incomplete to contemplate using. The 0.13.0 release
-     * is good enough to use, even though it lacks one or
-     * two features. The benefits of JSON mode now outweigh
-     * the downside.
-     */
-     if (version >= 13000)
-        flags |= QEMUD_CMD_FLAG_MONITOR_JSON;
-
-    return flags;
-}
-
-/* We parse the output of 'qemu -help' to get the QEMU
- * version number. The first bit is easy, just parse
- * 'QEMU PC emulator version x.y.z'
- * or
- * 'QEMU emulator version x.y.z'.
- *
- * With qemu-kvm, however, that is followed by a string
- * in parenthesis as follows:
- *  - qemu-kvm-x.y.z in stable releases
- *  - kvm-XX for kvm versions up to kvm-85
- *  - qemu-kvm-devel-XX for kvm version kvm-86 and later
- *
- * For qemu-kvm versions before 0.10.z, we need to detect
- * the KVM version number for some features. With 0.10.z
- * and later, we just need the QEMU version number and
- * whether it is KVM QEMU or mainline QEMU.
- */
-#define QEMU_VERSION_STR_1  "QEMU emulator version"
-#define QEMU_VERSION_STR_2  "QEMU PC emulator version"
-#define QEMU_KVM_VER_PREFIX "(qemu-kvm-"
-#define KVM_VER_PREFIX      "(kvm-"
-
-#define SKIP_BLANKS(p) do { while ((*(p) == ' ') || (*(p) == '\t')) (p)++; } while (0)
-
-int qemudParseHelpStr(const char *qemu,
-                      const char *help,
-                      unsigned long long *flags,
-                      unsigned int *version,
-                      unsigned int *is_kvm,
-                      unsigned int *kvm_version)
-{
-    unsigned major, minor, micro;
-    const char *p = help;
-
-    *flags = *version = *is_kvm = *kvm_version = 0;
-
-    if (STRPREFIX(p, QEMU_VERSION_STR_1))
-        p += strlen(QEMU_VERSION_STR_1);
-    else if (STRPREFIX(p, QEMU_VERSION_STR_2))
-        p += strlen(QEMU_VERSION_STR_2);
-    else
-        goto fail;
-
-    SKIP_BLANKS(p);
-
-    major = virParseNumber(&p);
-    if (major == -1 || *p != '.')
-        goto fail;
-
-    ++p;
-
-    minor = virParseNumber(&p);
-    if (minor == -1 || *p != '.')
-        goto fail;
-
-    ++p;
-
-    micro = virParseNumber(&p);
-    if (micro == -1)
-        goto fail;
-
-    SKIP_BLANKS(p);
-
-    if (STRPREFIX(p, QEMU_KVM_VER_PREFIX)) {
-        *is_kvm = 1;
-        p += strlen(QEMU_KVM_VER_PREFIX);
-    } else if (STRPREFIX(p, KVM_VER_PREFIX)) {
-        int ret;
-
-        *is_kvm = 1;
-        p += strlen(KVM_VER_PREFIX);
-
-        ret = virParseNumber(&p);
-        if (ret == -1)
-            goto fail;
-
-        *kvm_version = ret;
-    }
-
-    *version = (major * 1000 * 1000) + (minor * 1000) + micro;
-
-    *flags = qemudComputeCmdFlags(help, *version, *is_kvm, *kvm_version);
-
-    VIR_DEBUG("Version %u.%u.%u, cooked version %u, flags 0x%llx",
-              major, minor, micro, *version, *flags);
-    if (*kvm_version)
-        VIR_DEBUG("KVM version %d detected", *kvm_version);
-    else if (*is_kvm)
-        VIR_DEBUG("qemu-kvm version %u.%u.%u detected", major, minor, micro);
-
-    return 0;
-
-fail:
-    p = strchr(help, '\n');
-    if (p)
-        p = strndup(help, p - help);
-
-    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                    _("cannot parse %s version number in '%s'"),
-                    qemu, p ? p : help);
-
-    VIR_FREE(p);
-
-    return -1;
-}
-
-static void qemudParsePCIDeviceStrs(const char *qemu, unsigned long long *flags)
-{
-    const char *const qemuarg[] = { qemu, "-device", "pci-assign,?", NULL };
-    const char *const qemuenv[] = { "LC_ALL=C", NULL };
-    pid_t child;
-    int status;
-    int newstderr = -1;
-
-    if (virExec(qemuarg, qemuenv, NULL,
-                &child, -1, NULL, &newstderr, VIR_EXEC_CLEAR_CAPS) < 0)
-        return;
-
-    char *pciassign = NULL;
-    enum { MAX_PCI_OUTPUT_SIZE = 1024*4 };
-    int len = virFileReadLimFD(newstderr, MAX_PCI_OUTPUT_SIZE, &pciassign);
-    if (len < 0) {
-        virReportSystemError(errno,
-                             _("Unable to read %s pci-assign device output"),
-                             qemu);
-        goto cleanup;
-    }
-
-    if (strstr(pciassign, "pci-assign.configfd"))
-        *flags |= QEMUD_CMD_FLAG_PCI_CONFIGFD;
-
-cleanup:
-    VIR_FREE(pciassign);
-    VIR_FORCE_CLOSE(newstderr);
-rewait:
-    if (waitpid(child, &status, 0) != child) {
-        if (errno == EINTR)
-            goto rewait;
-
-        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
-                  WEXITSTATUS(status), (unsigned long)child);
-    }
-    if (WEXITSTATUS(status) != 0) {
-        VIR_WARN("Unexpected exit status '%d', qemu probably failed",
-                 WEXITSTATUS(status));
-    }
-}
-
-int qemudExtractVersionInfo(const char *qemu,
-                            unsigned int *retversion,
-                            unsigned long long *retflags) {
-    const char *const qemuarg[] = { qemu, "-help", NULL };
-    const char *const qemuenv[] = { "LC_ALL=C", NULL };
-    pid_t child;
-    int newstdout = -1;
-    int ret = -1, status;
-    unsigned int version, is_kvm, kvm_version;
-    unsigned long long flags = 0;
-
-    if (retflags)
-        *retflags = 0;
-    if (retversion)
-        *retversion = 0;
-
-    /* Make sure the binary we are about to try exec'ing exists.
-     * Technically we could catch the exec() failure, but that's
-     * in a sub-process so it's hard to feed back a useful error.
-     */
-    if (access(qemu, X_OK) < 0) {
-        virReportSystemError(errno, _("Cannot find QEMU binary %s"), qemu);
-        return -1;
-    }
-
-    if (virExec(qemuarg, qemuenv, NULL,
-                &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
-        return -1;
-
-    char *help = NULL;
-    enum { MAX_HELP_OUTPUT_SIZE = 1024*64 };
-    int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help);
-    if (len < 0) {
-        virReportSystemError(errno,
-                             _("Unable to read %s help output"), qemu);
-        goto cleanup2;
-    }
-
-    if (qemudParseHelpStr(qemu, help, &flags,
-                          &version, &is_kvm, &kvm_version) == -1)
-        goto cleanup2;
-
-    if (flags & QEMUD_CMD_FLAG_DEVICE)
-        qemudParsePCIDeviceStrs(qemu, &flags);
-
-    if (retversion)
-        *retversion = version;
-    if (retflags)
-        *retflags = flags;
-
-    ret = 0;
-
-cleanup2:
-    VIR_FREE(help);
-    if (VIR_CLOSE(newstdout) < 0)
-        ret = -1;
-
-rewait:
-    if (waitpid(child, &status, 0) != child) {
-        if (errno == EINTR)
-            goto rewait;
-
-        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
-                  WEXITSTATUS(status), (unsigned long)child);
-        ret = -1;
-    }
-    /* Check & log unexpected exit status, but don't fail,
-     * as there's really no need to throw an error if we did
-     * actually read a valid version number above */
-    if (WEXITSTATUS(status) != 0) {
-        VIR_WARN("Unexpected exit status '%d', qemu probably failed",
-                 WEXITSTATUS(status));
-    }
-
-    return ret;
-}
 
 static void
 uname_normalize (struct utsname *ut)
@@ -1621,36 +466,6 @@ uname_normalize (struct utsname *ut)
         ut->machine[1] = '6';
 }
 
-int qemudExtractVersion(struct qemud_driver *driver) {
-    const char *binary;
-    struct stat sb;
-    struct utsname ut;
-
-    if (driver->qemuVersion > 0)
-        return 0;
-
-    uname_normalize(&ut);
-    if ((binary = virCapabilitiesDefaultGuestEmulator(driver->caps,
-                                                      "hvm",
-                                                      ut.machine,
-                                                      "qemu")) == NULL) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("Cannot find suitable emulator for %s"), ut.machine);
-        return -1;
-    }
-
-    if (stat(binary, &sb) < 0) {
-        virReportSystemError(errno,
-                             _("Cannot find QEMU binary %s"), binary);
-        return -1;
-    }
-
-    if (qemudExtractVersionInfo(binary, &driver->qemuVersion, NULL) < 0) {
-        return -1;
-    }
-
-    return 0;
-}
 
 /**
  * qemudPhysIfaceConnect:
@@ -3848,8 +2663,8 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
     *hasHwVirt = false;
 
     if (def->cpu && def->cpu->model) {
-        if (qemudProbeCPUModels(emulator, qemuCmdFlags, ut->machine,
-                                &ncpus, &cpus) < 0)
+        if (qemuCapsProbeCPUModels(emulator, qemuCmdFlags, ut->machine,
+                                   &ncpus, &cpus) < 0)
             goto cleanup;
 
         if (!ncpus || !host) {
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index e6b413d..86c65a6 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -47,63 +47,6 @@
 
 # define QEMUD_CPUMASK_LEN CPU_SETSIZE
 
-/* Internal flags to keep track of qemu command line capabilities */
-enum qemud_cmd_flags {
-    QEMUD_CMD_FLAG_KQEMU          = (1 << 0), /* Whether KQEMU is compiled in */
-    QEMUD_CMD_FLAG_VNC_COLON      = (1 << 1), /* Does the VNC take just port, or address + display */
-    QEMUD_CMD_FLAG_NO_REBOOT      = (1 << 2), /* Is the -no-reboot flag available */
-    QEMUD_CMD_FLAG_DRIVE          = (1 << 3), /* Is the new -drive arg available */
-    QEMUD_CMD_FLAG_DRIVE_BOOT     = (1 << 4), /* Does -drive support boot=on */
-    QEMUD_CMD_FLAG_NAME           = (1 << 5), /* Is the -name flag available */
-    QEMUD_CMD_FLAG_UUID           = (1 << 6), /* Is the -uuid flag available */
-    QEMUD_CMD_FLAG_DOMID          = (1 << 7), /* Xenner only, special -domid flag available */
-    QEMUD_CMD_FLAG_VNET_HDR        = (1 << 8),
-    QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO = (1 << 9),  /* Original migration code from KVM. Also had tcp, but we can't use that
-                                                   * since it had a design bug blocking the entire monitor console */
-    QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP  = (1 << 10), /* New migration syntax after merge to QEMU with TCP transport */
-    QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC = (1 << 11), /* New migration syntax after merge to QEMU with EXEC transport */
-    QEMUD_CMD_FLAG_DRIVE_CACHE_V2    = (1 << 12), /* Is the cache= flag wanting new v2 values */
-    QEMUD_CMD_FLAG_KVM               = (1 << 13), /* Whether KVM is compiled in */
-    QEMUD_CMD_FLAG_DRIVE_FORMAT      = (1 << 14), /* Is -drive format= avail */
-    QEMUD_CMD_FLAG_VGA               = (1 << 15), /* Is -vga avail */
-
-    /* features added in qemu-0.10.0 or later */
-    QEMUD_CMD_FLAG_0_10         = (1 << 16),
-    QEMUD_CMD_FLAG_NET_NAME     = QEMUD_CMD_FLAG_0_10, /* -net ...,name=str */
-    QEMUD_CMD_FLAG_HOST_NET_ADD = QEMUD_CMD_FLAG_0_10, /* host_net_add monitor command */
-
-    QEMUD_CMD_FLAG_PCIDEVICE     = (1 << 17), /* PCI device assignment only supported by qemu-kvm */
-    QEMUD_CMD_FLAG_MEM_PATH      = (1 << 18), /* mmap'ped guest backing supported */
-    QEMUD_CMD_FLAG_DRIVE_SERIAL  = (1 << 19), /* -driver serial=  available */
-    QEMUD_CMD_FLAG_XEN_DOMID     = (1 << 20), /* -xen-domid (new style xen integration) */
-    QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX = (1 << 21), /* Does qemu support unix domain sockets for migration? */
-    QEMUD_CMD_FLAG_CHARDEV       = (1 << 22), /* Is the new -chardev arg available */
-    QEMUD_CMD_FLAG_ENABLE_KVM    = (1 << 23), /* Is the -enable-kvm flag available to "enable KVM full virtualization support" */
-    QEMUD_CMD_FLAG_MONITOR_JSON  = (1 << 24), /* JSON mode for monitor */
-    QEMUD_CMD_FLAG_BALLOON       = (1 << 25), /* -balloon available */
-    QEMUD_CMD_FLAG_DEVICE        = (1 << 26), /* Is the new -device arg available */
-    QEMUD_CMD_FLAG_SDL           = (1 << 27), /* Is the new -sdl arg available */
-    QEMUD_CMD_FLAG_SMP_TOPOLOGY  = (1 << 28), /* Is sockets=s,cores=c,threads=t available for -smp? */
-    QEMUD_CMD_FLAG_NETDEV        = (1 << 29), /* The -netdev flag & netdev_add/remove monitor commands */
-    QEMUD_CMD_FLAG_RTC           = (1 << 30), /* The -rtc flag for clock options */
-    QEMUD_CMD_FLAG_VNET_HOST     = (1LL << 31), /* vnet-host support is available in qemu */
-    QEMUD_CMD_FLAG_RTC_TD_HACK   = (1LL << 32), /* -rtc-td-hack available */
-    QEMUD_CMD_FLAG_NO_HPET       = (1LL << 33), /* -no-hpet flag is supported */
-    QEMUD_CMD_FLAG_NO_KVM_PIT    = (1LL << 34), /* -no-kvm-pit-reinjection supported */
-    QEMUD_CMD_FLAG_TDF           = (1LL << 35), /* -tdf flag (user-mode pit catchup) */
-    QEMUD_CMD_FLAG_PCI_CONFIGFD  = (1LL << 36), /* pci-assign.configfd */
-    QEMUD_CMD_FLAG_NODEFCONFIG   = (1LL << 37), /* -nodefconfig */
-    QEMUD_CMD_FLAG_BOOT_MENU     = (1LL << 38), /* -boot menu=on support */
-    QEMUD_CMD_FLAG_ENABLE_KQEMU  = (1LL << 39), /* -enable-kqemu flag */
-    QEMUD_CMD_FLAG_FSDEV         = (1LL << 40), /* -fstype filesystem passthrough */
-    QEMUD_CMD_FLAG_NESTING       = (1LL << 41), /* -enable-nesting (SVM/VMX) */
-    QEMUD_CMD_FLAG_NAME_PROCESS  = (1LL << 42), /* Is -name process= available */
-    QEMUD_CMD_FLAG_DRIVE_READONLY= (1LL << 43), /* -drive readonly=on|off */
-    QEMUD_CMD_FLAG_SMBIOS_TYPE   = (1LL << 44), /* Is -smbios type= available */
-    QEMUD_CMD_FLAG_VGA_QXL       = (1LL << 45), /* The 'qxl' arg for '-vga' */
-    QEMUD_CMD_FLAG_SPICE         = (1LL << 46), /* Is -spice avail */
-    QEMUD_CMD_FLAG_VGA_NONE      = (1LL << 47), /* The 'none' arg for '-vga' */
-};
 
 /* Main driver state */
 struct qemud_driver {
@@ -220,20 +163,6 @@ struct _qemuDomainCmdlineDef {
 int qemudLoadDriverConfig(struct qemud_driver *driver,
                           const char *filename);
 
-virCapsPtr  qemudCapsInit               (virCapsPtr old_caps);
-
-int         qemudExtractVersion         (struct qemud_driver *driver);
-int         qemudExtractVersionInfo     (const char *qemu,
-                                         unsigned int *version,
-                                         unsigned long long *qemuCmdFlags);
-
-int         qemudParseHelpStr           (const char *qemu,
-                                         const char *str,
-                                         unsigned long long *qemuCmdFlags,
-                                         unsigned int *version,
-                                         unsigned int *is_kvm,
-                                         unsigned int *kvm_version);
-
 virCommandPtr qemudBuildCommandLine     (virConnectPtr conn,
                                          struct qemud_driver *driver,
                                          virDomainDefPtr def,
@@ -324,16 +253,6 @@ int qemudPhysIfaceConnect(virConnectPtr conn,
                           const unsigned char *vmuuid,
                           enum virVMOperationType vmop);
 
-int         qemudProbeMachineTypes      (const char *binary,
-                                         virCapsGuestMachinePtr **machines,
-                                         int *nmachines);
-
-int         qemudProbeCPUModels         (const char *qemu,
-                                         unsigned long long qemuCmdFlags,
-                                         const char *arch,
-                                         unsigned int *count,
-                                         const char ***cpus);
-
 int         qemudCanonicalizeMachine    (struct qemud_driver *driver,
                                          virDomainDefPtr def);
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c096890..f303075 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -54,6 +54,7 @@
 #include "datatypes.h"
 #include "qemu_driver.h"
 #include "qemu_conf.h"
+#include "qemu_capabilities.h"
 #include "qemu_monitor.h"
 #include "qemu_bridge_filter.h"
 #include "c-ctype.h"
@@ -1553,9 +1554,9 @@ qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaq
     /* XXX we should be persisting the original flags in the XML
      * not re-detecting them, since the binary may have changed
      * since launch time */
-    if (qemudExtractVersionInfo(obj->def->emulator,
-                                NULL,
-                                &qemuCmdFlags) >= 0 &&
+    if (qemuCapsExtractVersionInfo(obj->def->emulator,
+                                   NULL,
+                                   &qemuCmdFlags) >= 0 &&
         (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
         priv->persistentAddrs = 1;
 
@@ -1644,7 +1645,7 @@ qemuCreateCapabilities(virCapsPtr oldcaps,
     virCapsPtr caps;
 
     /* Basic host arch / guest machine capabilities */
-    if (!(caps = qemudCapsInit(oldcaps))) {
+    if (!(caps = qemuCapsInit(oldcaps))) {
         virReportOOMError();
         return NULL;
     }
@@ -3118,9 +3119,9 @@ qemuAssignPCIAddresses(virDomainDefPtr def)
     unsigned long long qemuCmdFlags = 0;
     qemuDomainPCIAddressSetPtr addrs = NULL;
 
-    if (qemudExtractVersionInfo(def->emulator,
-                                NULL,
-                                &qemuCmdFlags) < 0)
+    if (qemuCapsExtractVersionInfo(def->emulator,
+                                   NULL,
+                                   &qemuCmdFlags) < 0)
         goto cleanup;
 
     if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
@@ -4063,9 +4064,9 @@ static int qemudStartVMDaemon(virConnectPtr conn,
         goto cleanup;
 
     DEBUG0("Determining emulator version");
-    if (qemudExtractVersionInfo(vm->def->emulator,
-                                NULL,
-                                &qemuCmdFlags) < 0)
+    if (qemuCapsExtractVersionInfo(vm->def->emulator,
+                                   NULL,
+                                   &qemuCmdFlags) < 0)
         goto cleanup;
 
     DEBUG0("Setting up domain cgroup (if required)");
@@ -4851,10 +4852,10 @@ static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
     int ret = -1;
 
     qemuDriverLock(driver);
-    if (qemudExtractVersion(driver) < 0)
+    if (qemuCapsExtractVersion(driver->caps, &driver->qemuVersion) < 0)
         goto cleanup;
 
-    *version = qemu_driver->qemuVersion;
+    *version = driver->qemuVersion;
     ret = 0;
 
 cleanup:
@@ -7465,9 +7466,9 @@ static char *qemuDomainXMLToNative(virConnectPtr conn,
             def->graphics[i]->data.vnc.port = QEMU_VNC_PORT_MIN;
     }
 
-    if (qemudExtractVersionInfo(def->emulator,
-                                NULL,
-                                &qemuCmdFlags) < 0)
+    if (qemuCapsExtractVersionInfo(def->emulator,
+                                   NULL,
+                                   &qemuCmdFlags) < 0)
         goto cleanup;
 
     if (qemuPrepareMonitorChr(driver, &monConfig, def->name) < 0)
@@ -7637,7 +7638,7 @@ qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
     virCapsGuestMachinePtr *machines = NULL;
     int i, nmachines = 0;
 
-    if (qemudProbeMachineTypes(def->emulator, &machines, &nmachines) < 0) {
+    if (qemuCapsProbeMachineTypes(def->emulator, &machines, &nmachines) < 0) {
         virReportOOMError();
         return -1;
     }
@@ -8826,9 +8827,9 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
     if (dev == NULL)
         goto endjob;
 
-    if (qemudExtractVersionInfo(vm->def->emulator,
-                                NULL,
-                                &qemuCmdFlags) < 0)
+    if (qemuCapsExtractVersionInfo(vm->def->emulator,
+                                   NULL,
+                                   &qemuCmdFlags) < 0)
         goto endjob;
 
     if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
@@ -9073,9 +9074,9 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
     if (dev == NULL)
         goto endjob;
 
-    if (qemudExtractVersionInfo(vm->def->emulator,
-                                NULL,
-                                &qemuCmdFlags) < 0)
+    if (qemuCapsExtractVersionInfo(vm->def->emulator,
+                                   NULL,
+                                   &qemuCmdFlags) < 0)
         goto endjob;
 
     switch (dev->type) {
@@ -9793,9 +9794,9 @@ static int qemudDomainDetachDevice(virDomainPtr dom,
     if (dev == NULL)
         goto endjob;
 
-    if (qemudExtractVersionInfo(vm->def->emulator,
-                                NULL,
-                                &qemuCmdFlags) < 0)
+    if (qemuCapsExtractVersionInfo(vm->def->emulator,
+                                   NULL,
+                                   &qemuCmdFlags) < 0)
         goto endjob;
 
     if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
@@ -11060,7 +11061,7 @@ qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
     unlink(unixfile);
 
     /* check that this qemu version supports the interactive exec */
-    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
+    if (qemuCapsExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         _("Cannot determine QEMU argv syntax %s"),
                         vm->def->emulator);
@@ -11571,7 +11572,7 @@ static int doTunnelMigrate(virDomainPtr dom,
     }
 
     /* check that this qemu version supports the unix migration */
-    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
+    if (qemuCapsExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         _("Cannot extract Qemu version from '%s'"),
                         vm->def->emulator);
-- 
1.7.2.3




More information about the libvir-list mailing list