[libvirt] [PATCH 2/7] qemu: Probe GIC capabilities

Andrea Bolognani abologna at redhat.com
Mon Apr 18 17:43:58 UTC 2016


QEMU introduced the query-gic-capabilities QMP command
with commit 4468d4e0f383: use the command, if available,
to probe available GIC capabilities.

The information obtained is stored in a virQEMUCaps
instance, and will be later used to fill in a
virDomainCaps instance.
---
Changes from RFC:

  * Free qemuCaps->gicCapabilities when needed

  * Always return NULL when no capabilities have been found

  * Don't allocate (n+1) elements to store (n) capabilities

  * Check for ARM consistently with the rest of the code

  * Reference QEMU commit

  * Leave two empty lines between functions

  * Document all functions

 src/qemu/qemu_capabilities.c |  42 ++++++++++++++++
 src/qemu/qemu_monitor.c      |  17 +++++++
 src/qemu/qemu_monitor.h      |   4 ++
 src/qemu/qemu_monitor_json.c | 115 +++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor_json.h |   4 ++
 src/util/virgic.h            |  13 +++++
 6 files changed, 195 insertions(+)

diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 9ae7b27..4afc6b6 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -358,6 +358,9 @@ struct _virQEMUCaps {
     char **machineTypes;
     char **machineAliases;
     unsigned int *machineMaxCpus;
+
+    size_t ngicCapabilities;
+    virGICCapability *gicCapabilities;
 };
 
 struct virQEMUCapsSearchData {
@@ -2082,6 +2085,8 @@ void virQEMUCapsDispose(void *obj)
 
     VIR_FREE(qemuCaps->package);
     VIR_FREE(qemuCaps->binary);
+
+    VIR_FREE(qemuCaps->gicCapabilities);
 }
 
 void
@@ -2696,6 +2701,34 @@ virQEMUCapsProbeQMPMigrationCapabilities(virQEMUCapsPtr qemuCaps,
     return 0;
 }
 
+/**
+ * virQEMUCapsProbeQMPGICCapabilities:
+ * @qemuCaps: QEMU binary capabilities
+ * @mon: QEMU monitor
+ *
+ * Use @mon to obtain information about the GIC capabilities for the
+ * corresponding QEMU binary, and store them in @qemuCaps.
+ *
+ * Returns: 0 on success, <0 on failure
+ */
+static int
+virQEMUCapsProbeQMPGICCapabilities(virQEMUCapsPtr qemuCaps,
+                                   qemuMonitorPtr mon)
+{
+    virGICCapability *caps = NULL;
+    int ncaps;
+
+    if ((ncaps = qemuMonitorGetGICCapabilities(mon, &caps)) < 0)
+        return -1;
+
+    VIR_FREE(qemuCaps->gicCapabilities);
+
+    qemuCaps->gicCapabilities = caps;
+    qemuCaps->ngicCapabilities = ncaps;
+
+    return 0;
+}
+
 int virQEMUCapsProbeQMP(virQEMUCapsPtr qemuCaps,
                         qemuMonitorPtr mon)
 {
@@ -3047,6 +3080,9 @@ virQEMUCapsReset(virQEMUCapsPtr qemuCaps)
     VIR_FREE(qemuCaps->machineAliases);
     VIR_FREE(qemuCaps->machineMaxCpus);
     qemuCaps->nmachineTypes = 0;
+
+    VIR_FREE(qemuCaps->gicCapabilities);
+    qemuCaps->ngicCapabilities = 0;
 }
 
 
@@ -3411,6 +3447,12 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps,
     if (virQEMUCapsProbeQMPMigrationCapabilities(qemuCaps, mon) < 0)
         goto cleanup;
 
+    /* GIC capabilities, eg. available GIC versions */
+    if ((qemuCaps->arch == VIR_ARCH_AARCH64 ||
+         qemuCaps->arch == VIR_ARCH_ARMV7L) &&
+        virQEMUCapsProbeQMPGICCapabilities(qemuCaps, mon) < 0)
+        goto cleanup;
+
     ret = 0;
  cleanup:
     return ret;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 83551a8..7c9ea71 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3580,6 +3580,23 @@ qemuMonitorSetMigrationCapability(qemuMonitorPtr mon,
 }
 
 
+/**
+ * qemuMonitorGetGICCapabilities:
+ * @mon: QEMU monitor
+ * @capabilities: where to store the GIC capabilities
+ *
+ * See qemuMonitorJSONGetGICCapabilities().
+ */
+int
+qemuMonitorGetGICCapabilities(qemuMonitorPtr mon,
+                              virGICCapability **capabilities)
+{
+    QEMU_CHECK_MONITOR_JSON(mon);
+
+    return qemuMonitorJSONGetGICCapabilities(mon, capabilities);
+}
+
+
 int
 qemuMonitorNBDServerStart(qemuMonitorPtr mon,
                           const char *host,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index bd5d006..470c729 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -34,6 +34,7 @@
 # include "virnetdev.h"
 # include "device_conf.h"
 # include "cpu/cpu.h"
+# include "util/virgic.h"
 
 typedef struct _qemuMonitor qemuMonitor;
 typedef qemuMonitor *qemuMonitorPtr;
@@ -583,6 +584,9 @@ int qemuMonitorSetMigrationCapability(qemuMonitorPtr mon,
                                       qemuMonitorMigrationCaps capability,
                                       bool state);
 
+int qemuMonitorGetGICCapabilities(qemuMonitorPtr mon,
+                                  virGICCapability **capabilities);
+
 typedef enum {
   QEMU_MONITOR_MIGRATE_BACKGROUND	= 1 << 0,
   QEMU_MONITOR_MIGRATE_NON_SHARED_DISK  = 1 << 1, /* migration with non-shared storage with full disk copy */
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 29d6c8c..7bb9976 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -5855,6 +5855,121 @@ qemuMonitorJSONSetMigrationCapability(qemuMonitorPtr mon,
     return ret;
 }
 
+
+/**
+ * qemuMonitorJSONGetGICCapabilities:
+ * @mon: QEMU JSON monitor
+ * @capabilities: where to store the GIC capabilities
+ *
+ * Use @mon to obtain information about the GIC capabilities for the
+ * corresponding QEMU binary, and store them in @capabilities.
+ *
+ * If the QEMU binary has no GIC capabilities, or if GIC capabilities could
+ * not be determined due to the lack of 'query-gic-capabilities' QMP command,
+ * a NULL pointer will be returned instead of an empty array.
+ *
+ * Returns: the number of GIC capabilities obtained from the monitor,
+ *          <0 on failure
+ */
+int
+qemuMonitorJSONGetGICCapabilities(qemuMonitorPtr mon,
+                                  virGICCapability **capabilities)
+{
+    int ret;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    virJSONValuePtr caps;
+    virGICCapability *list = NULL;
+    size_t i;
+    ssize_t n;
+
+    *capabilities = NULL;
+
+    if (!(cmd = qemuMonitorJSONMakeCommand("query-gic-capabilities",
+                                           NULL)))
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0) {
+        /* If the 'query-gic-capabilities' QMP command was not available
+         * we simply successfully return zero capabilities.
+         * This is the case for QEMU <2.6 and all non-ARM architectures */
+        if (qemuMonitorJSONHasError(reply, "CommandNotFound"))
+            goto cleanup;
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+    }
+
+    if (ret < 0)
+        goto cleanup;
+
+    ret = -1;
+
+    if (!(caps = virJSONValueObjectGetArray(reply, "return")) ||
+        (n = virJSONValueArraySize(caps)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("missing GIC capabilities"));
+        goto cleanup;
+    }
+
+    /* If the returned array was empty we have to return successfully */
+    if (n == 0) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC_N(list, n) < 0)
+        goto cleanup;
+
+    for (i = 0; i < n; i++) {
+        virJSONValuePtr cap = virJSONValueArrayGet(caps, i);
+        int version;
+        bool kernel;
+        bool emulated;
+
+        if (!cap || cap->type != VIR_JSON_TYPE_OBJECT) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing entry in GIC capabilities list"));
+            goto cleanup;
+        }
+
+        if (virJSONValueObjectGetNumberInt(cap, "version", &version) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing GIC version"));
+            goto cleanup;
+        }
+
+        if (virJSONValueObjectGetBoolean(cap, "kernel", &kernel) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing in-kernel GIC information"));
+            goto cleanup;
+        }
+
+        if (virJSONValueObjectGetBoolean(cap, "emulated", &emulated) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing emulated GIC information"));
+            goto cleanup;
+        }
+
+        list[i].version = version;
+        if (kernel)
+            list[i].implementation |= VIR_GIC_IMPLEMENTATION_KERNEL;
+        if (emulated)
+            list[i].implementation |= VIR_GIC_IMPLEMENTATION_EMULATED;
+    }
+
+    ret = n;
+    *capabilities = list;
+
+ cleanup:
+    if (ret < 0)
+        VIR_FREE(list);
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+
+    return ret;
+}
+
 static virJSONValuePtr
 qemuMonitorJSONBuildInetSocketAddress(const char *host,
                                       const char *port)
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 5cbee1a..8b5d422 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -30,6 +30,7 @@
 # include "qemu_monitor.h"
 # include "virbitmap.h"
 # include "cpu/cpu.h"
+# include "util/virgic.h"
 
 int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
                              const char *data,
@@ -142,6 +143,9 @@ int qemuMonitorJSONSetMigrationCapability(qemuMonitorPtr mon,
                                           qemuMonitorMigrationCaps capability,
                                           bool state);
 
+int qemuMonitorJSONGetGICCapabilities(qemuMonitorPtr mon,
+                                      virGICCapability **capabilities);
+
 int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
                            unsigned int flags,
                            const char *uri);
diff --git a/src/util/virgic.h b/src/util/virgic.h
index 470ce95..1c9efd6 100644
--- a/src/util/virgic.h
+++ b/src/util/virgic.h
@@ -38,4 +38,17 @@ VIR_ENUM_DECL(virGICVersion);
 /* Consider GIC v2 the default */
 # define VIR_GIC_VERSION_DEFAULT VIR_GIC_VERSION_2
 
+typedef enum {
+    VIR_GIC_IMPLEMENTATION_NONE = 0,
+    VIR_GIC_IMPLEMENTATION_KERNEL = (1 << 1),
+    VIR_GIC_IMPLEMENTATION_EMULATED = (1 << 2)
+} virGICImplementation;
+
+typedef struct _virGICCapability virGICCapability;
+typedef virGICCapability *virGICCapabilityPtr;
+struct _virGICCapability {
+    virGICVersion version;
+    virGICImplementation implementation;
+};
+
 #endif /* __VIR_GIC_H__ */
-- 
2.5.5




More information about the libvir-list mailing list