Signed-off-by: Stefan Berger <stef...@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;
 
@@ -4674,6 +4679,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;
@@ -6974,6 +7065,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];
 
@@ -8801,6 +8908,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)
 {
@@ -9599,6 +9812,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@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to