Probe for QEMU's QMP TPM support by querying the lists of supported TPM models (query-tpm-models) and backend types (query-tpm-types). The setting of the capability flags following the strings returned from the commands above is only provided in the patch where domain_conf.c gets TPM support due to dependencies on functions only introduced there. Signed-off-by: Stefan Berger --- src/libvirt_private.syms | 1 src/qemu/qemu_capabilities.c | 61 ++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 3 + src/qemu/qemu_monitor.c | 44 ++++++++++++++++++++ src/qemu/qemu_monitor.h | 6 ++ src/qemu/qemu_monitor_json.c | 91 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 8 +++ src/util/virutil.c | 14 ++++++ src/util/virutil.h | 3 + 9 files changed, 231 insertions(+) Index: libvirt/src/qemu/qemu_capabilities.c =================================================================== --- libvirt.orig/src/qemu/qemu_capabilities.c +++ libvirt/src/qemu/qemu_capabilities.c @@ -210,6 +210,8 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAS "rng-random", /* 130 */ "rng-egd", + "tpm-passthrough", + "tpm-tis", ); struct _virQEMUCaps { Index: libvirt/src/qemu/qemu_capabilities.h =================================================================== --- libvirt.orig/src/qemu/qemu_capabilities.h +++ libvirt/src/qemu/qemu_capabilities.h @@ -171,6 +171,8 @@ enum virQEMUCapsFlags { QEMU_CAPS_OBJECT_RNG_RANDOM = 130, /* the rng-random backend for virtio rng */ QEMU_CAPS_OBJECT_RNG_EGD = 131, /* EGD protocol daemon for rng */ + QEMU_CAPS_DEVICE_TPM_PASSTHROUGH = 132, /* -tpmdev passthrough */ + QEMU_CAPS_DEVICE_TPM_TIS = 133, /* -device tpm_tis */ QEMU_CAPS_LAST, /* this must always be the last item */ }; @@ -252,4 +254,5 @@ int virQEMUCapsParseDeviceStr(virQEMUCap VIR_ENUM_DECL(virQEMUCaps); bool virQEMUCapsUsedQMP(virQEMUCapsPtr qemuCaps); + #endif /* __QEMU_CAPABILITIES_H__*/ Index: libvirt/src/qemu/qemu_monitor.c =================================================================== --- libvirt.orig/src/qemu/qemu_monitor.c +++ libvirt/src/qemu/qemu_monitor.c @@ -3522,3 +3522,47 @@ int qemuMonitorNBDServerStop(qemuMonitor return qemuMonitorJSONNBDServerStop(mon); } + + +int qemuMonitorGetTPMModels(qemuMonitorPtr mon, + char ***tpmmodels) +{ + VIR_DEBUG("mon=%p tpmmodels=%p", + mon, tpmmodels); + + if (!mon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("monitor must not be NULL")); + return -1; + } + + if (!mon->json) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("JSON monitor is required")); + return -1; + } + + return qemuMonitorJSONGetTPMModels(mon, tpmmodels); +} + + +int qemuMonitorGetTPMTypes(qemuMonitorPtr mon, + char ***tpmtypes) +{ + VIR_DEBUG("mon=%p tpmtypes=%p", + mon, tpmtypes); + + if (!mon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("monitor must not be NULL")); + return -1; + } + + if (!mon->json) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("JSON monitor is required")); + return -1; + } + + return qemuMonitorJSONGetTPMTypes(mon, tpmtypes); +} Index: libvirt/src/qemu/qemu_monitor.h =================================================================== --- libvirt.orig/src/qemu/qemu_monitor.h +++ libvirt/src/qemu/qemu_monitor.h @@ -683,6 +683,12 @@ int qemuMonitorNBDServerAdd(qemuMonitorP const char *deviceID, bool writable); int qemuMonitorNBDServerStop(qemuMonitorPtr); +int qemuMonitorGetTPMModels(qemuMonitorPtr mon, + char ***tpmmodels); + +int qemuMonitorGetTPMTypes(qemuMonitorPtr mon, + char ***tpmtypes); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that Index: libvirt/src/qemu/qemu_monitor_json.c =================================================================== --- libvirt.orig/src/qemu/qemu_monitor_json.c +++ libvirt/src/qemu/qemu_monitor_json.c @@ -4707,3 +4707,94 @@ qemuMonitorJSONNBDServerStop(qemuMonitor virJSONValueFree(reply); return ret; } + + +static int +qemuMonitorJSONGetStringArray(qemuMonitorPtr mon, const char *qmpCmd, + char ***array) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + char **list = NULL; + int n = 0; + size_t i; + + *array = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand(qmpCmd, NULL))) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + if (ret < 0) + goto cleanup; + + ret = -1; + + if (!(data = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s reply was missing return data"), + qmpCmd); + goto cleanup; + } + + if ((n = virJSONValueArraySize(data)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s reply data was not an array"), + qmpCmd); + goto cleanup; + } + + if (VIR_ALLOC_N(list, n) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0 ; i < n ; i++) { + virJSONValuePtr child = virJSONValueArrayGet(data, i); + const char *tmp; + + if (!(tmp = virJSONValueGetString(child))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s array element does not contain data"), + qmpCmd); + goto cleanup; + } + + if (!(list[i] = strdup(tmp))) { + virReportOOMError(); + goto cleanup; + } + } + + ret = n; + *array = list; + +cleanup: + if (ret < 0 && list) { + for (i = 0 ; i < n ; i++) + VIR_FREE(list[i]); + VIR_FREE(list); + } + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +int qemuMonitorJSONGetTPMModels(qemuMonitorPtr mon, + char ***tpmmodels) +{ + return qemuMonitorJSONGetStringArray(mon, "query-tpm-models", tpmmodels); +} + + +int qemuMonitorJSONGetTPMTypes(qemuMonitorPtr mon, + char ***tpmtypes) +{ + return qemuMonitorJSONGetStringArray(mon, "query-tpm-types", tpmtypes); +} Index: libvirt/src/qemu/qemu_monitor_json.h =================================================================== --- libvirt.orig/src/qemu/qemu_monitor_json.h +++ libvirt/src/qemu/qemu_monitor_json.h @@ -341,4 +341,12 @@ int qemuMonitorJSONNBDServerAdd(qemuMoni const char *deviceID, bool writable); int qemuMonitorJSONNBDServerStop(qemuMonitorPtr mon); +int qemuMonitorJSONGetTPMModels(qemuMonitorPtr mon, + char ***tpmmodels) + ATTRIBUTE_NONNULL(2); + +int qemuMonitorJSONGetTPMTypes(qemuMonitorPtr mon, + char ***tpmtypes) + ATTRIBUTE_NONNULL(2); + #endif /* QEMU_MONITOR_JSON_H */ Index: libvirt/src/libvirt_private.syms =================================================================== --- libvirt.orig/src/libvirt_private.syms +++ libvirt/src/libvirt_private.syms @@ -1886,6 +1886,7 @@ virSetUIDGIDWithCaps; virSkipSpaces; virSkipSpacesAndBackslash; virSkipSpacesBackwards; +virStrArrayHasString; virStrcpy; virStrIsPrint; virStrncpy; Index: libvirt/src/util/virutil.c =================================================================== --- libvirt.orig/src/util/virutil.c +++ libvirt/src/util/virutil.c @@ -3379,3 +3379,17 @@ cleanup: VIR_FREE(buf); return ret; } + + +bool +virStrArrayHasString(char **strings, size_t n_strings, const char *needle) +{ + size_t i; + + for (i = 0; i < n_strings; i++) { + if (STREQ(strings[i], needle)) + return true; + } + + return false; +} Index: libvirt/src/util/virutil.h =================================================================== --- libvirt.orig/src/util/virutil.h +++ libvirt/src/util/virutil.h @@ -297,4 +297,7 @@ int virGetDeviceUnprivSGIO(const char *p char * virGetUnprivSGIOSysfsPath(const char *path, const char *sysfs_dir); +bool virStrArrayHasString(char **strings, size_t n_strings, + const char *needle); + #endif /* __VIR_UTIL_H__ */