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