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