Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
src/qemu/qemu_command.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 217 insertions(+)
Index: libvirt/src/qemu/qemu_command.c
===================================================================
--- libvirt.orig/src/qemu/qemu_command.c
+++ libvirt/src/qemu/qemu_command.c
@@ -46,6 +46,7 @@
#include "base64.h"
#include "device_conf.h"
#include "virstoragefile.h"
+#include "virtpm.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -791,6 +792,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;
@@ -4533,6 +4538,92 @@ cleanup:
}
+static char *qemuBuildTPMBackendStr(const virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ const char *emulator)
+{
+ const virDomainTPMDefPtr tpm = def->tpm;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ const char *type = virDomainTPMBackendTypeToString(tpm->type);
+ const char *cancel_path;
+
+ 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;
+
+ virBufferAddLit(&buf, ",path=");
+ virBufferEscape(&buf, ',', ",", "%s",
+ tpm->data.passthrough.source.data.file.path);
+
+ if (!(cancel_path = virTPMFindCancelPath())) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("TPM cancel path could not be determined"));
+ goto error;
+ }
+
+ virBufferAddLit(&buf, ",cancel-path=");
+ virBufferEscape(&buf, ',', ",", "%s",
cancel_path);
+ VIR_FREE(cancel_path);
+
+ break;
+ case VIR_DOMAIN_TPM_TYPE_LAST:
+ goto error;
+ }
+
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto error;
+ }
+
+ 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);
+ 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;
@@ -6824,6 +6915,22 @@ qemuBuildCommandLine(virConnectPtr conn,
}
}
+ if (def->tpm) {
+ char *optstr;
+
+ if (!(optstr = qemuBuildTPMBackendStr(def, qemuCaps, 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];
@@ -8677,6 +8784,112 @@ 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.source.data.file.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.source.data.file.path) {
+ if (!(tpm->data.passthrough.source.data.file.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)
{
@@ -9486,6 +9699,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