diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index fda1c6caa6..242100fcdd 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3276,6 +3276,22 @@ void virDomainHostdevDefClear(virDomainHostdevDef *def) } } +static virDomainTPMDef * +virDomainTPMDefNew(virDomainXMLOption *xmlopt) +{ + virDomainTPMDef *def; + + def = g_new0(virDomainTPMDef, 1); + + if (xmlopt && xmlopt->privateData.tpmNew && + !(def->privateData = xmlopt->privateData.tpmNew())) { + VIR_FREE(def); + return NULL; + } + + return def; +} + void virDomainTPMDefFree(virDomainTPMDef *def) { if (!def) @@ -3296,6 +3312,7 @@ void virDomainTPMDefFree(virDomainTPMDef *def) } virDomainDeviceInfoClear(&def->info); + virObjectUnref(def->privateData); g_free(def); } @@ -10240,7 +10257,8 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt, g_autofree xmlNodePtr *nodes = NULL; int bank; - def = g_new0(virDomainTPMDef, 1); + if (!(def = virDomainTPMDefNew(xmlopt))) + return NULL; if (virXMLPropEnum(node, "model", virDomainTPMModelTypeFromString, @@ -10331,6 +10349,14 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt, if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0) goto error; + if (flags & VIR_DOMAIN_DEF_PARSE_STATUS && + xmlopt && xmlopt->privateData.tpmParse) { + if ((ctxt->node = virXPathNode("./privateData", ctxt))) { + if (xmlopt->privateData.tpmParse(ctxt, def) < 0) + goto error; + } + } + return def; error: @@ -23921,10 +23947,32 @@ virDomainSoundCodecDefFormat(virBuffer *buf, return 0; } -static void +static int +virDomainTPMDefFormatPrivateData(virBuffer *buf, + const virDomainTPMDef *tpm, + unsigned int flags, + virDomainXMLOption *xmlopt) +{ + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + + if (!(flags & VIR_DOMAIN_DEF_FORMAT_STATUS) || + !xmlopt || + !xmlopt->privateData.tpmFormat) + return 0; + + if (xmlopt->privateData.tpmFormat(tpm, &childBuf) < 0) + return -1; + + virXMLFormatElement(buf, "privateData", NULL, &childBuf); + return 0; +} + + +static int virDomainTPMDefFormat(virBuffer *buf, const virDomainTPMDef *def, - unsigned int flags) + unsigned int flags, + virDomainXMLOption *xmlopt) { g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); @@ -23973,8 +24021,12 @@ virDomainTPMDefFormat(virBuffer *buf, virXMLFormatElement(&childBuf, "backend", &backendAttrBuf, &backendChildBuf); virDomainDeviceInfoFormat(&childBuf, &def->info, flags); + if (virDomainTPMDefFormatPrivateData(&childBuf, def, flags, xmlopt) < 0) + return -1; virXMLFormatElement(buf, "tpm", &attrBuf, &childBuf); + + return 0; } @@ -27060,7 +27112,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, } for (n = 0; n < def->ntpms; n++) { - virDomainTPMDefFormat(buf, def->tpms[n], flags); + if (virDomainTPMDefFormat(buf, def->tpms[n], flags, xmlopt) < 0) + return -1; } for (n = 0; n < def->ngraphics; n++) { @@ -28326,7 +28379,7 @@ virDomainDeviceDefCopy(virDomainDeviceDef *src, rc = virDomainChrDefFormat(&buf, src->data.chr, flags); break; case VIR_DOMAIN_DEVICE_TPM: - virDomainTPMDefFormat(&buf, src->data.tpm, flags); + virDomainTPMDefFormat(&buf, src->data.tpm, flags, xmlopt); rc = 0; break; case VIR_DOMAIN_DEVICE_PANIC: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 54dc9098df..321fa216f8 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1445,6 +1445,8 @@ typedef enum { #define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0" struct _virDomainTPMDef { + virObject *privateData; + virDomainTPMModel model; virDomainTPMBackendType type; virDomainDeviceInfo info; @@ -3248,6 +3250,10 @@ typedef int (*virDomainXMLPrivateDataStorageSourceParseFunc)(xmlXPathContextPtr typedef int (*virDomainXMLPrivateDataStorageSourceFormatFunc)(virStorageSource *src, virBuffer *buf); +typedef int (*virDomainXMLPrivateDataTPMParseFunc)(xmlXPathContextPtr ctxt, + virDomainTPMDef *disk); +typedef int (*virDomainXMLPrivateDataTPMFormatFunc)(const virDomainTPMDef *tpm, + virBuffer *buf); struct _virDomainXMLPrivateDataCallbacks { virDomainXMLPrivateDataAllocFunc alloc; @@ -3264,6 +3270,9 @@ struct _virDomainXMLPrivateDataCallbacks { virDomainXMLPrivateDataNewFunc networkNew; virDomainXMLPrivateDataNewFunc videoNew; virDomainXMLPrivateDataNewFunc fsNew; + virDomainXMLPrivateDataTPMParseFunc tpmParse; + virDomainXMLPrivateDataTPMFormatFunc tpmFormat; + virDomainXMLPrivateDataNewFunc tpmNew; virDomainXMLPrivateDataFormatFunc format; virDomainXMLPrivateDataParseFunc parse; /* following function shall return a pointer which will be used as the diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index c9a622e75a..ec785af5bb 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1138,6 +1138,76 @@ qemuDomainVideoPrivateDispose(void *obj) } +static virClass *qemuDomainTPMPrivateClass; +static void qemuDomainTPMPrivateDispose(void *obj); + + +static int +qemuDomainTPMPrivateOnceInit(void) +{ + if (!VIR_CLASS_NEW(qemuDomainTPMPrivate, virClassForObject())) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(qemuDomainTPMPrivate); + + +static virObject * +qemuDomainTPMPrivateNew(void) +{ + qemuDomainTPMPrivate *priv; + + if (qemuDomainTPMPrivateInitialize() < 0) + return NULL; + + if (!(priv = virObjectNew(qemuDomainTPMPrivateClass))) + return NULL; + + return (virObject *) priv; +} + + +static void +qemuDomainTPMPrivateDispose(void *obj G_GNUC_UNUSED) +{ +} + + +static int +qemuDomainTPMPrivateParse(xmlXPathContextPtr ctxt, + virDomainTPMDef *tpm) +{ + qemuDomainTPMPrivate *priv = QEMU_DOMAIN_TPM_PRIVATE(tpm); + + priv->swtpm.can_migrate_shared_storage = + virXPathBoolean("string(./swtpm/@can_migrate_shared_storage)", ctxt); + + return 0; +} + + +static int +qemuDomainTPMPrivateFormat(const virDomainTPMDef *tpm, + virBuffer *buf) +{ + qemuDomainTPMPrivate *priv = QEMU_DOMAIN_TPM_PRIVATE(tpm); + + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_EMULATOR: + if (priv->swtpm.can_migrate_shared_storage) + virBufferAddLit(buf, "\n"); + break; + + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: + case VIR_DOMAIN_TPM_TYPE_LAST: + } + + return 0; +} + + /* qemuDomainSecretInfoSetup: * @priv: pointer to domain private object * @alias: alias of the secret @@ -3212,6 +3282,9 @@ virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks = { .graphicsNew = qemuDomainGraphicsPrivateNew, .networkNew = qemuDomainNetworkPrivateNew, .videoNew = qemuDomainVideoPrivateNew, + .tpmNew = qemuDomainTPMPrivateNew, + .tpmParse = qemuDomainTPMPrivateParse, + .tpmFormat = qemuDomainTPMPrivateFormat, .parse = qemuDomainObjPrivateXMLParse, .format = qemuDomainObjPrivateXMLFormat, .getParseOpaque = qemuDomainObjPrivateXMLGetParseOpaque, diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 2bbd492d62..919ce16097 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -414,6 +414,20 @@ struct _qemuDomainNetworkPrivate { qemuFDPass *vdpafd; }; + +#define QEMU_DOMAIN_TPM_PRIVATE(dev) \ + ((qemuDomainTPMPrivate *) (dev)->privateData) + +typedef struct _qemuDomainTPMPrivate qemuDomainTPMPrivate; +struct _qemuDomainTPMPrivate { + virObject parent; + + struct { + bool can_migrate_shared_storage; + } swtpm; +}; + + void qemuDomainNetworkPrivateClearFDs(qemuDomainNetworkPrivate *priv);