Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxxxxxxx> --- src/qemu/qemu_command.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) Index: libvirt/src/qemu/qemu_command.c =================================================================== --- libvirt.orig/src/qemu/qemu_command.c +++ libvirt/src/qemu/qemu_command.c @@ -856,6 +856,10 @@ qemuAssignDeviceAliases(virDomainDefPtr if (virAsprintf(&def->rng->info.alias, "rng%d", 0) < 0) goto no_memory; } + if (def->tpm) { + if (virAsprintf(&def->tpm->info.alias, "tpm%d", 0) < 0) + goto no_memory; + } return 0; @@ -4437,6 +4441,111 @@ cleanup: } +static char *qemuBuildTPMBackendStr(virCommandPtr cmd, + virQEMUDriverPtr driver, + const virDomainDefPtr def, + virQEMUCapsPtr qemuCaps, + virFdSetPtr fdset, + const char *emulator) +{ + const char *path; + const virDomainTPMDefPtr tpm = def->tpm; + virBuffer buf = VIR_BUFFER_INITIALIZER; + const char *type = virDomainTPMBackendTypeToString(tpm->type); + virDomainDeviceInfo info = { 0, }; + + virBufferAsprintf(&buf, "%s,id=tpm-%s", type, tpm->info.alias); + + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_TPM_PASSTHROUGH)) + goto no_support; + + if (qemuCreatePathForFilePath(driver, &buf, + ",path=", tpm->data.passthrough.path, + (int[]){O_RDWR, -1}, + cmd, fdset, &tpm->info, + qemuCaps) < 0) + goto error; + + path = tpm->data.passthrough.cancel_path; + if (!path) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("TPM cancel path could not be determined")); + goto error; + } + + if (virAsprintf(&info.alias, "%s-cancel", tpm->info.alias) < 0) { + virReportOOMError(); + goto error; + } + + if (qemuCreatePathForFilePath(driver, &buf, + ",cancel-path=", path, + (int[]){O_WRONLY, -1}, + cmd, fdset, &info, + qemuCaps) < 0) + goto error; + + break; + case VIR_DOMAIN_TPM_TYPE_LAST: + goto error; + } + + if (virBufferError(&buf)) { + virReportOOMError(); + goto error; + } + + VIR_FREE(info.alias); + + return virBufferContentAndReset(&buf); + + no_support: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("The QEMU executable %s does not support TPM " + "backend type %s"), + emulator, type); + + error: + virBufferFreeAndReset(&buf); + VIR_FREE(info.alias); + return NULL; +} + + +static char *qemuBuildTPMDevStr(const virDomainDefPtr def, + virQEMUCapsPtr qemuCaps, + const char *emulator) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + const virDomainTPMDefPtr tpm = def->tpm; + const char *model = virDomainTPMModelTypeToString(tpm->model); + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_TPM_TIS)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("The QEMU executable %s does not support TPM " + "model %s"), + emulator, model); + goto error; + } + + virBufferAsprintf(&buf, "%s,tpmdev=tpm-%s,id=%s", + model, tpm->info.alias, tpm->info.alias); + + if (virBufferError(&buf)) { + virReportOOMError(); + goto error; + } + + return virBufferContentAndReset(&buf); + + error: + virBufferFreeAndReset(&buf); + return NULL; +} + + static char *qemuBuildSmbiosBiosStr(virSysinfoDefPtr def) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -6779,6 +6888,23 @@ qemuBuildCommandLine(virConnectPtr conn, } } + if (def->tpm) { + char *optstr; + + if (!(optstr = qemuBuildTPMBackendStr(cmd, driver, def, + qemuCaps, fdset, emulator))) + goto error; + + virCommandAddArgList(cmd, "-tpmdev", optstr, NULL); + VIR_FREE(optstr); + + if (!(optstr = qemuBuildTPMDevStr(def, qemuCaps, emulator))) + goto error; + + virCommandAddArgList(cmd, "-device", optstr, NULL); + VIR_FREE(optstr); + } + for (i = 0 ; i < def->ninputs ; i++) { virDomainInputDefPtr input = def->inputs[i]; @@ -8632,6 +8758,125 @@ error: static int +qemuParseCommandLineTPM(virDomainDefPtr dom, + const char *val) +{ + int rc = 0; + virDomainTPMDefPtr tpm; + char **keywords; + char **values; + int nkeywords; + int i; + + if (dom->tpm) + goto error; + + nkeywords = qemuParseKeywords(val, &keywords, &values, 1); + if (nkeywords < 0) + goto error; + + if (VIR_ALLOC(tpm) < 0) + goto no_memory; + + tpm->model = VIR_DOMAIN_TPM_MODEL_TIS; + + for (i = 0; i < nkeywords; i++) { + if (STREQ(keywords[i], "type")) { + if (values[i] && + STREQ(values[i], + virDomainTPMBackendTypeToString(VIR_DOMAIN_TPM_TYPE_PASSTHROUGH))) + tpm->type = VIR_DOMAIN_TPM_TYPE_PASSTHROUGH; + } else if (STREQ(keywords[i], + virDomainTPMBackendTypeToString(VIR_DOMAIN_TPM_TYPE_PASSTHROUGH))) { + tpm->type = VIR_DOMAIN_TPM_TYPE_PASSTHROUGH; + } else if (STREQ(keywords[i], "path")) { + if (values[i]) { + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: + tpm->data.passthrough.path = values[i]; + values[i] = NULL; + break; + case VIR_DOMAIN_TPM_TYPE_LAST: + break; + } + } else { + goto syntax; + } + } else if (STREQ(keywords[i], "cancel-path")) { + if (values[i]) { + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: + tpm->data.passthrough.cancel_path = values[i]; + values[i] = NULL; + break; + case VIR_DOMAIN_TPM_TYPE_LAST: + break; + } + } else { + goto syntax; + } + } + } + + /* sanity checks */ + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: + if (!tpm->data.passthrough.path) { + if (!(tpm->data.passthrough.path = + strdup(VIR_DOMAIN_TPM_DEFAULT_DEVICE))) { + virReportOOMError(); + goto bad_definition; + } + } + break; + case VIR_DOMAIN_TPM_TYPE_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("unknown TPM type")); + goto bad_definition; + } + + /* all ok */ + dom->tpm = tpm; + +cleanup: + for (i = 0 ; i < nkeywords ; i++) { + VIR_FREE(keywords[i]); + VIR_FREE(values[i]); + } + VIR_FREE(keywords); + VIR_FREE(values); + + + return rc; + +syntax: + virDomainTPMDefFree(tpm); + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown TPM syntax '%s'"), val); + rc = -1; + goto cleanup; + +bad_definition: + virDomainTPMDefFree(tpm); + + rc = -1; + goto cleanup; + +no_memory: + virReportOOMError(); + + rc = -1; + goto cleanup; + + +error: + return -1; +} + + +static int qemuParseCommandLineSmp(virDomainDefPtr dom, const char *val) { @@ -9440,6 +9685,10 @@ virDomainDefPtr qemuParseCommandLine(vir } else if (STREQ(arg, "-S")) { /* ignore, always added by libvirt */ + } else if (STREQ(arg, "-tpmdev")) { + WANT_VALUE(); + if (qemuParseCommandLineTPM(def, val) < 0) + goto error; } else { /* something we can't yet parse. Add it to the qemu namespace * cmdline/environment advanced options and hope for the best -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list