[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH V1 5/6] TPM support for QEMU command line



Signed-off-by: Stefan Berger <stefanb linux vnet ibm com>

---
 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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]