diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 344aac09f02e5c36410a995702f8d8cb0ee77080..99aadba2e2dfcf845fc9ac9718ff044ffa20d2a1 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4107,6 +4107,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 f166f5f949464422e9a47d1e6fbfe2af246e561d..209bf2af56d42822d84c26fbbcf9606ccf540ad6 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1153,6 +1153,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 efcef211ed1badb30d6277d67b33d830f14b49e0..96f44bc7604a93f2404651caf2763c35514a8b75 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6137,6 +6137,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, \ @@ -7369,6 +7420,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 1bc1df0e3bcc6e658b3c9dd83fc660e09a19542b..d0b519c88ecb943a17da3963666ca478833921a9 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -492,6 +492,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,