Pablo Greco 40546a
From b61b68abeb8c2c93740698b81d59d2030eea8189 Mon Sep 17 00:00:00 2001
Pablo Greco 40546a
Message-Id: <b61b68abeb8c2c93740698b81d59d2030eea8189@dist-git>
Pablo Greco 40546a
From: Jiri Denemark <jdenemar@redhat.com>
Pablo Greco 40546a
Date: Fri, 21 Jun 2019 09:26:03 +0200
Pablo Greco 40546a
Subject: [PATCH] qemu: Introduce generic qemuMonitorGetGuestCPU
Pablo Greco 40546a
MIME-Version: 1.0
Pablo Greco 40546a
Content-Type: text/plain; charset=UTF-8
Pablo Greco 40546a
Content-Transfer-Encoding: 8bit
Pablo Greco 40546a
Pablo Greco 40546a
Unlike the old version (which is now called qemuMonitorGetGuestCPUx86),
Pablo Greco 40546a
this monitor API checks for individual features by their names rather
Pablo Greco 40546a
than processing CPUID bits. Thus we can get the list of enabled and
Pablo Greco 40546a
disabled features for both CPUID and MSR features.
Pablo Greco 40546a
Pablo Greco 40546a
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Pablo Greco 40546a
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Pablo Greco 40546a
(cherry picked from commit cc6d6b3cb995110a1d9da97f31ce68c2290f4332)
Pablo Greco 40546a
Pablo Greco 40546a
https://bugzilla.redhat.com/show_bug.cgi?id=1697627
Pablo Greco 40546a
Pablo Greco 40546a
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Pablo Greco 40546a
Message-Id: <29634994c64ffbf3509238ccbe1937b599e55838.1561068591.git.jdenemar@redhat.com>
Pablo Greco 40546a
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Pablo Greco 40546a
---
Pablo Greco 40546a
 src/qemu/qemu_monitor.c      |  36 +++++++
Pablo Greco 40546a
 src/qemu/qemu_monitor.h      |  10 ++
Pablo Greco 40546a
 src/qemu/qemu_monitor_json.c | 186 +++++++++++++++++++++++++++++++++++
Pablo Greco 40546a
 src/qemu/qemu_monitor_json.h |   7 ++
Pablo Greco 40546a
 4 files changed, 239 insertions(+)
Pablo Greco 40546a
Pablo Greco 40546a
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
Pablo Greco 40546a
index b35187b66d..ae666ce633 100644
Pablo Greco 40546a
--- a/src/qemu/qemu_monitor.c
Pablo Greco 40546a
+++ b/src/qemu/qemu_monitor.c
Pablo Greco 40546a
@@ -4074,6 +4074,42 @@ qemuMonitorGetGuestCPUx86(qemuMonitorPtr mon,
Pablo Greco 40546a
 }
Pablo Greco 40546a
 
Pablo Greco 40546a
 
Pablo Greco 40546a
+/**
Pablo Greco 40546a
+ * qemuMonitorGetGuestCPU:
Pablo Greco 40546a
+ * @mon: Pointer to the monitor
Pablo Greco 40546a
+ * @arch: CPU architecture
Pablo Greco 40546a
+ * @translate: callback for translating CPU feature names from QEMU to libvirt
Pablo Greco 40546a
+ * @opaque: data for @translate callback
Pablo Greco 40546a
+ * @enabled: returns the CPU data for all enabled features
Pablo Greco 40546a
+ * @disabled: returns the CPU data for features which we asked for
Pablo Greco 40546a
+ *      (either explicitly or via a named CPU model) but QEMU disabled them
Pablo Greco 40546a
+ *
Pablo Greco 40546a
+ * Retrieve the definition of the guest CPU from a running QEMU instance.
Pablo Greco 40546a
+ *
Pablo Greco 40546a
+ * Returns 0 on success, -1 on error.
Pablo Greco 40546a
+ */
Pablo Greco 40546a
+int
Pablo Greco 40546a
+qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
Pablo Greco 40546a
+                       virArch arch,
Pablo Greco 40546a
+                       qemuMonitorCPUFeatureTranslationCallback translate,
Pablo Greco 40546a
+                       void *opaque,
Pablo Greco 40546a
+                       virCPUDataPtr *enabled,
Pablo Greco 40546a
+                       virCPUDataPtr *disabled)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    VIR_DEBUG("arch=%s translate=%p opaque=%p enabled=%p disabled=%p",
Pablo Greco 40546a
+              virArchToString(arch), translate, opaque, enabled, disabled);
Pablo Greco 40546a
+
Pablo Greco 40546a
+    QEMU_CHECK_MONITOR(mon);
Pablo Greco 40546a
+
Pablo Greco 40546a
+    *enabled = NULL;
Pablo Greco 40546a
+    if (disabled)
Pablo Greco 40546a
+        *disabled = NULL;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    return qemuMonitorJSONGetGuestCPU(mon, arch, translate, opaque,
Pablo Greco 40546a
+                                      enabled, disabled);
Pablo Greco 40546a
+}
Pablo Greco 40546a
+
Pablo Greco 40546a
+
Pablo Greco 40546a
 /**
Pablo Greco 40546a
  * qemuMonitorRTCResetReinjection:
Pablo Greco 40546a
  * @mon: Pointer to the monitor
Pablo Greco 40546a
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
Pablo Greco 40546a
index b4d484c703..8d4f6e6062 100644
Pablo Greco 40546a
--- a/src/qemu/qemu_monitor.h
Pablo Greco 40546a
+++ b/src/qemu/qemu_monitor.h
Pablo Greco 40546a
@@ -1099,6 +1099,16 @@ int qemuMonitorGetGuestCPUx86(qemuMonitorPtr mon,
Pablo Greco 40546a
                               virCPUDataPtr *data,
Pablo Greco 40546a
                               virCPUDataPtr *disabled);
Pablo Greco 40546a
 
Pablo Greco 40546a
+typedef const char *(*qemuMonitorCPUFeatureTranslationCallback)(const char *name,
Pablo Greco 40546a
+                                                                void *opaque);
Pablo Greco 40546a
+
Pablo Greco 40546a
+int qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
Pablo Greco 40546a
+                           virArch arch,
Pablo Greco 40546a
+                           qemuMonitorCPUFeatureTranslationCallback translate,
Pablo Greco 40546a
+                           void *opaque,
Pablo Greco 40546a
+                           virCPUDataPtr *enabled,
Pablo Greco 40546a
+                           virCPUDataPtr *disabled);
Pablo Greco 40546a
+
Pablo Greco 40546a
 int qemuMonitorRTCResetReinjection(qemuMonitorPtr mon);
Pablo Greco 40546a
 
Pablo Greco 40546a
 typedef struct _qemuMonitorIOThreadInfo qemuMonitorIOThreadInfo;
Pablo Greco 40546a
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
Pablo Greco 40546a
index abf952cd34..00a0578809 100644
Pablo Greco 40546a
--- a/src/qemu/qemu_monitor_json.c
Pablo Greco 40546a
+++ b/src/qemu/qemu_monitor_json.c
Pablo Greco 40546a
@@ -5998,6 +5998,57 @@ int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon,
Pablo Greco 40546a
 }
Pablo Greco 40546a
 
Pablo Greco 40546a
 
Pablo Greco 40546a
+static int
Pablo Greco 40546a
+qemuMonitorJSONGetStringListProperty(qemuMonitorPtr mon,
Pablo Greco 40546a
+                                     const char *path,
Pablo Greco 40546a
+                                     const char *property,
Pablo Greco 40546a
+                                     char ***strList)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    VIR_AUTOPTR(virJSONValue) cmd = NULL;
Pablo Greco 40546a
+    VIR_AUTOPTR(virJSONValue) reply = NULL;
Pablo Greco 40546a
+    VIR_AUTOSTRINGLIST list = NULL;
Pablo Greco 40546a
+    virJSONValuePtr data;
Pablo Greco 40546a
+    size_t n;
Pablo Greco 40546a
+    size_t i;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    *strList = NULL;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
Pablo Greco 40546a
+                                           "s:path", path,
Pablo Greco 40546a
+                                           "s:property", property,
Pablo Greco 40546a
+                                           NULL)))
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    data = virJSONValueObjectGetArray(reply, "return");
Pablo Greco 40546a
+    n = virJSONValueArraySize(data);
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (VIR_ALLOC_N(list, n + 1) < 0)
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    for (i = 0; i < n; i++) {
Pablo Greco 40546a
+        virJSONValuePtr item = virJSONValueArrayGet(data, i);
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (virJSONValueGetType(item) != VIR_JSON_TYPE_STRING) {
Pablo Greco 40546a
+            virReportError(VIR_ERR_INTERNAL_ERROR,
Pablo Greco 40546a
+                           _("unexpected value in %s array"), property);
Pablo Greco 40546a
+            return -1;
Pablo Greco 40546a
+        }
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (VIR_STRDUP(list[i], virJSONValueGetString(item)) < 0)
Pablo Greco 40546a
+            return -1;
Pablo Greco 40546a
+    }
Pablo Greco 40546a
+
Pablo Greco 40546a
+    VIR_STEAL_PTR(*strList, list);
Pablo Greco 40546a
+    return n;
Pablo Greco 40546a
+}
Pablo Greco 40546a
+
Pablo Greco 40546a
+
Pablo Greco 40546a
 #define MAKE_SET_CMD(STRING, VALUE) \
Pablo Greco 40546a
     cmd = qemuMonitorJSONMakeCommand("qom-set", \
Pablo Greco 40546a
                                       "s:path", path, \
Pablo Greco 40546a
@@ -7207,6 +7258,141 @@ qemuMonitorJSONGetGuestCPUx86(qemuMonitorPtr mon,
Pablo Greco 40546a
     return -1;
Pablo Greco 40546a
 }
Pablo Greco 40546a
 
Pablo Greco 40546a
+
Pablo Greco 40546a
+static int
Pablo Greco 40546a
+qemuMonitorJSONGetCPUProperties(qemuMonitorPtr mon,
Pablo Greco 40546a
+                                char ***props)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    VIR_AUTOPTR(virJSONValue) cmd = NULL;
Pablo Greco 40546a
+    VIR_AUTOPTR(virJSONValue) reply = NULL;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    *props = NULL;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (!(cmd = qemuMonitorJSONMakeCommand("qom-list",
Pablo Greco 40546a
+                                           "s:path", QOM_CPU_PATH,
Pablo Greco 40546a
+                                           NULL)))
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (qemuMonitorJSONHasError(reply, "DeviceNotFound"))
Pablo Greco 40546a
+        return 0;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    return qemuMonitorJSONParsePropsList(cmd, reply, "bool", props);
Pablo Greco 40546a
+}
Pablo Greco 40546a
+
Pablo Greco 40546a
+
Pablo Greco 40546a
+static int
Pablo Greco 40546a
+qemuMonitorJSONGetCPUData(qemuMonitorPtr mon,
Pablo Greco 40546a
+                          qemuMonitorCPUFeatureTranslationCallback translate,
Pablo Greco 40546a
+                          void *opaque,
Pablo Greco 40546a
+                          virCPUDataPtr data)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    qemuMonitorJSONObjectProperty prop = { .type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN };
Pablo Greco 40546a
+    VIR_AUTOSTRINGLIST props = NULL;
Pablo Greco 40546a
+    char **p;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (qemuMonitorJSONGetCPUProperties(mon, &props) < 0)
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    for (p = props; p && *p; p++) {
Pablo Greco 40546a
+        const char *name = *p;
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (qemuMonitorJSONGetObjectProperty(mon, QOM_CPU_PATH, name, &prop) < 0)
Pablo Greco 40546a
+            return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (!prop.val.b)
Pablo Greco 40546a
+            continue;
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (translate)
Pablo Greco 40546a
+            name = translate(name, opaque);
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (virCPUDataAddFeature(data, name) < 0)
Pablo Greco 40546a
+            return -1;
Pablo Greco 40546a
+    }
Pablo Greco 40546a
+
Pablo Greco 40546a
+    return 0;
Pablo Greco 40546a
+}
Pablo Greco 40546a
+
Pablo Greco 40546a
+
Pablo Greco 40546a
+static int
Pablo Greco 40546a
+qemuMonitorJSONGetCPUDataDisabled(qemuMonitorPtr mon,
Pablo Greco 40546a
+                                  qemuMonitorCPUFeatureTranslationCallback translate,
Pablo Greco 40546a
+                                  void *opaque,
Pablo Greco 40546a
+                                  virCPUDataPtr data)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    VIR_AUTOSTRINGLIST props = NULL;
Pablo Greco 40546a
+    char **p;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (qemuMonitorJSONGetStringListProperty(mon, QOM_CPU_PATH,
Pablo Greco 40546a
+                                             "unavailable-features", &props) < 0)
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    for (p = props; p && *p; p++) {
Pablo Greco 40546a
+        const char *name = *p;
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (translate)
Pablo Greco 40546a
+            name = translate(name, opaque);
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (virCPUDataAddFeature(data, name) < 0)
Pablo Greco 40546a
+            return -1;
Pablo Greco 40546a
+    }
Pablo Greco 40546a
+
Pablo Greco 40546a
+    return 0;
Pablo Greco 40546a
+}
Pablo Greco 40546a
+
Pablo Greco 40546a
+
Pablo Greco 40546a
+/**
Pablo Greco 40546a
+ * qemuMonitorJSONGetGuestCPU:
Pablo Greco 40546a
+ * @mon: Pointer to the monitor
Pablo Greco 40546a
+ * @arch: CPU architecture
Pablo Greco 40546a
+ * @translate: callback for translating CPU feature names from QEMU to libvirt
Pablo Greco 40546a
+ * @opaque: data for @translate callback
Pablo Greco 40546a
+ * @enabled: returns the CPU data for all enabled features
Pablo Greco 40546a
+ * @disabled: returns the CPU data for features which we asked for
Pablo Greco 40546a
+ *      (either explicitly or via a named CPU model) but QEMU disabled them
Pablo Greco 40546a
+ *
Pablo Greco 40546a
+ * Retrieve the definition of the guest CPU from a running QEMU instance.
Pablo Greco 40546a
+ *
Pablo Greco 40546a
+ * Returns 0 on success, -1 on error.
Pablo Greco 40546a
+ */
Pablo Greco 40546a
+int
Pablo Greco 40546a
+qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon,
Pablo Greco 40546a
+                           virArch arch,
Pablo Greco 40546a
+                           qemuMonitorCPUFeatureTranslationCallback translate,
Pablo Greco 40546a
+                           void *opaque,
Pablo Greco 40546a
+                           virCPUDataPtr *enabled,
Pablo Greco 40546a
+                           virCPUDataPtr *disabled)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    virCPUDataPtr cpuEnabled = NULL;
Pablo Greco 40546a
+    virCPUDataPtr cpuDisabled = NULL;
Pablo Greco 40546a
+    int ret = -1;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (!(cpuEnabled = virCPUDataNew(arch)) ||
Pablo Greco 40546a
+        !(cpuDisabled = virCPUDataNew(arch)))
Pablo Greco 40546a
+        goto cleanup;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (qemuMonitorJSONGetCPUData(mon, translate, opaque, cpuEnabled) < 0)
Pablo Greco 40546a
+        goto cleanup;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (disabled &&
Pablo Greco 40546a
+        qemuMonitorJSONGetCPUDataDisabled(mon, translate, opaque, cpuDisabled) < 0)
Pablo Greco 40546a
+        goto cleanup;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    VIR_STEAL_PTR(*enabled, cpuEnabled);
Pablo Greco 40546a
+    if (disabled)
Pablo Greco 40546a
+        VIR_STEAL_PTR(*disabled, cpuDisabled);
Pablo Greco 40546a
+
Pablo Greco 40546a
+    ret = 0;
Pablo Greco 40546a
+
Pablo Greco 40546a
+ cleanup:
Pablo Greco 40546a
+    virCPUDataFree(cpuEnabled);
Pablo Greco 40546a
+    virCPUDataFree(cpuDisabled);
Pablo Greco 40546a
+    return ret;
Pablo Greco 40546a
+}
Pablo Greco 40546a
+
Pablo Greco 40546a
+
Pablo Greco 40546a
 int
Pablo Greco 40546a
 qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon)
Pablo Greco 40546a
 {
Pablo Greco 40546a
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
Pablo Greco 40546a
index 57bed027e2..29b10aad26 100644
Pablo Greco 40546a
--- a/src/qemu/qemu_monitor_json.h
Pablo Greco 40546a
+++ b/src/qemu/qemu_monitor_json.h
Pablo Greco 40546a
@@ -490,6 +490,13 @@ int qemuMonitorJSONGetGuestCPUx86(qemuMonitorPtr mon,
Pablo Greco 40546a
                                   virCPUDataPtr *data,
Pablo Greco 40546a
                                   virCPUDataPtr *disabled);
Pablo Greco 40546a
 
Pablo Greco 40546a
+int qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon,
Pablo Greco 40546a
+                               virArch arch,
Pablo Greco 40546a
+                               qemuMonitorCPUFeatureTranslationCallback translate,
Pablo Greco 40546a
+                               void *opaque,
Pablo Greco 40546a
+                               virCPUDataPtr *enabled,
Pablo Greco 40546a
+                               virCPUDataPtr *disabled);
Pablo Greco 40546a
+
Pablo Greco 40546a
 int qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon);
Pablo Greco 40546a
 
Pablo Greco 40546a
 int qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon,
Pablo Greco 40546a
-- 
Pablo Greco 40546a
2.22.0
Pablo Greco 40546a