diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 108566f86cae025a94f6ac5d5f2f54f129ed492b..0454e7074003d013e291ddfc3719cbd68638e934 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -51,6 +51,7 @@
#include "netdev_bandwidth_conf.h"
#include "netdev_vlan_conf.h"
#include "device_conf.h"
+#include "virtpm.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -721,6 +722,13 @@ VIR_ENUM_IMPL(virDomainRNGBackend,
"random",
"egd");
+VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST,
+ "tpm-tis")
+
+VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST,
+ "passthrough")
+
+
#define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE
@@ -1619,6 +1627,23 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
}
}
+void virDomainTPMDefFree(virDomainTPMDefPtr def)
+{
+ if (!def)
+ return;
+
+ switch (def->type) {
+ case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
+ VIR_FREE(def->data.passthrough.source.data.file.path);
+ break;
+ case VIR_DOMAIN_TPM_TYPE_LAST:
+ break;
+ }
+
+ virDomainDeviceInfoClear(&def->info);
+ VIR_FREE(def);
+}
+
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
{
if (!def)
@@ -1880,6 +1905,8 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainRNGDefFree(def->rng);
+ virDomainTPMDefFree(def->tpm);
+
VIR_FREE(def->os.type);
VIR_FREE(def->os.machine);
VIR_FREE(def->os.init);
@@ -6771,6 +6798,103 @@ error:
goto cleanup;
}
+/* Parse the XML definition for a TPM device
+ *
+ * The XML looks like this:
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+static virDomainTPMDefPtr
+virDomainTPMDefParseXML(const xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ unsigned int flags)
+{
+ char *type = NULL;
+ char *path = NULL;
+ char *model = NULL;
+ char *backend = NULL;
+ virDomainTPMDefPtr def;
+ xmlNodePtr save = ctxt->node;
+ xmlNodePtr *backends = NULL;
+ int nbackends;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ model = virXMLPropString(node, "model");
+ if (model != NULL &&
+ (int)(def->model = virDomainTPMModelTypeFromString(model)) < 0) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("Unknown TPM frontend model '%s'"), model);
+ goto error;
+ } else {
+ def->model = VIR_DOMAIN_TPM_MODEL_TIS;
+ }
+
+ ctxt->node = node;
+
+ if ((nbackends = virXPathNodeSet("./backend", ctxt, &backends)) < 0)
+ goto error;
+
+ if (nbackends > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only one TPM backend is supported"));
+ goto error;
+ }
+
+ if (!(backend = virXMLPropString(backends[0], "type"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing TPM device backend type"));
+ goto error;
+ }
+
+ if ((int)(def->type = virDomainTPMBackendTypeFromString(backend)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Unknown TPM backend type '%s'"),
+ backend);
+ goto error;
+ }
+
+ switch (def->type) {
+ case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
+ path = virXPathString("string(./backend/device/@path)", ctxt);
+ if (!path && !(path = strdup(VIR_DOMAIN_TPM_DEFAULT_DEVICE))) {
+ virReportOOMError();
+ goto error;
+ }
+ def->data.passthrough.source.data.file.path = path;
+ def->data.passthrough.source.type = VIR_DOMAIN_CHR_TYPE_DEV;
+ path = NULL;
+ break;
+ case VIR_DOMAIN_TPM_TYPE_LAST:
+ goto error;
+ }
+
+ if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
+ goto error;
+
+cleanup:
+ VIR_FREE(type);
+ VIR_FREE(path);
+ VIR_FREE(model);
+ VIR_FREE(backend);
+ VIR_FREE(backends);
+ ctxt->node = save;
+ return def;
+
+error:
+ virDomainTPMDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
/* Parse the XML definition for an input device */
static virDomainInputDefPtr
virDomainInputDefParseXML(const char *ostype,
@@ -11099,6 +11223,23 @@ virDomainDefParseXML(xmlDocPtr xml,
goto error;
VIR_FREE(nodes);
}
+ VIR_FREE(nodes);
+
+ /* Parse the TPM devices */
+ if ((n = virXPathNodeSet("./devices/tpm", ctxt, &nodes)) < 0)
+ goto error;
+
+ if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only a single TPM device is supported"));
+ goto error;
+ }
+
+ if (n > 0) {
+ if (!(def->tpm = virDomainTPMDefParseXML(nodes[0], ctxt, flags)))
+ goto error;
+ }
+ VIR_FREE(nodes);
/* analysis of the hub devices */
if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) {
@@ -14082,6 +14223,39 @@ virDomainSoundCodecDefFormat(virBufferPtr buf,
return 0;
}
+static int
+virDomainTPMDefFormat(virBufferPtr buf,
+ virDomainTPMDefPtr def,
+ unsigned int flags)
+{
+ virBufferAsprintf(buf, " \n",
+ virDomainTPMModelTypeToString(def->model));
+
+ virBufferAsprintf(buf, " \n",
+ virDomainTPMBackendTypeToString(def->type));
+
+ switch (def->type) {
+ case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
+ virBufferEscapeString(buf, " \n",
+ def->data.passthrough.source.data.file.path);
+ break;
+ case VIR_DOMAIN_TPM_TYPE_LAST:
+ break;
+ }
+
+ virBufferAddLit(buf, " \n");
+
+ if (virDomainDeviceInfoIsSet(&def->info, flags)) {
+ if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+ return -1;
+ }
+
+ virBufferAddLit(buf, " \n");
+
+ return 0;
+}
+
+
static int
virDomainSoundDefFormat(virBufferPtr buf,
virDomainSoundDefPtr def,
@@ -15408,6 +15582,11 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virDomainInputDefFormat(buf, def->inputs[n], flags) < 0)
goto error;
+ if (def->tpm) {
+ if (virDomainTPMDefFormat(buf, def->tpm, flags) < 0)
+ goto error;
+ }
+
if (def->ngraphics > 0) {
/* If graphics is enabled, add the implicit mouse */
virDomainInputDef autoInput = {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 3ab0f15dc12bbeb2ab61dfeeaf484bb189ec4fca..b985393d739fcee7c01287b48aa4872aa94206b9 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1097,6 +1097,33 @@ struct _virDomainHubDef {
virDomainDeviceInfo info;
};
+enum virDomainTPMModel {
+ VIR_DOMAIN_TPM_MODEL_TIS,
+
+ VIR_DOMAIN_TPM_MODEL_LAST
+};
+
+enum virDomainTPMBackendType {
+ VIR_DOMAIN_TPM_TYPE_PASSTHROUGH,
+
+ VIR_DOMAIN_TPM_TYPE_LAST
+};
+
+# define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0"
+
+typedef struct _virDomainTPMDef virDomainTPMDef;
+typedef virDomainTPMDef *virDomainTPMDefPtr;
+struct _virDomainTPMDef {
+ enum virDomainTPMBackendType type;
+ virDomainDeviceInfo info;
+ enum virDomainTPMModel model;
+ union {
+ struct {
+ virDomainChrSourceDef source;
+ } passthrough;
+ } data;
+};
+
enum virDomainInputType {
VIR_DOMAIN_INPUT_TYPE_MOUSE,
VIR_DOMAIN_INPUT_TYPE_TABLET,
@@ -1883,6 +1910,7 @@ struct _virDomainDef {
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
+ virDomainTPMDefPtr tpm;
virCPUDefPtr cpu;
virSysinfoDefPtr sysinfo;
virDomainRedirFilterDefPtr redirfilter;
@@ -2062,6 +2090,7 @@ void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
void virDomainDefClearPCIAddresses(virDomainDefPtr def);
void virDomainDefClearCCWAddresses(virDomainDefPtr def);
void virDomainDefClearDeviceAliases(virDomainDefPtr def);
+void virDomainTPMDefFree(virDomainTPMDefPtr def);
typedef int (*virDomainDeviceInfoCallback)(virDomainDefPtr def,
virDomainDeviceDefPtr dev,
@@ -2433,6 +2462,8 @@ VIR_ENUM_DECL(virDomainGraphicsSpiceMouseMode)
VIR_ENUM_DECL(virDomainHyperv)
VIR_ENUM_DECL(virDomainRNGModel)
VIR_ENUM_DECL(virDomainRNGBackend)
+VIR_ENUM_DECL(virDomainTPMModel)
+VIR_ENUM_DECL(virDomainTPMBackend)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 8a7dfcf867125d70e21143f7e16683cccb8904b2..8d8d56d2e9e0276de71bcccf574dba28eceb4532 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -320,6 +320,11 @@ virDomainTimerTickpolicyTypeFromString;
virDomainTimerTickpolicyTypeToString;
virDomainTimerTrackTypeFromString;
virDomainTimerTrackTypeToString;
+virDomainTPMBackendTypeFromString;
+virDomainTPMBackendTypeToString;
+virDomainTPMDefFree;
+virDomainTPMModelTypeFromString;
+virDomainTPMModelTypeToString;
virDomainVcpuPinAdd;
virDomainVcpuPinDefArrayFree;
virDomainVcpuPinDefCopy;