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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list