diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 7f4de657c6..1f1fda9dd3 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -7750,6 +7750,26 @@ qemu-kvm -net nic,model=? /dev/null </tpm> </devices> ... + + +

+ The emulator device type gives access to a TPM emulator providing + TPM functionality for each VM. QEMU talks to it over a Unix socket. With + the emulator device type each guest gets its own private TPM. + 'emulator' since 4.5.0 +

+

+ Example: usage of the TPM Emulator +

+
+  ...
+  <devices>
+    <tpm model='tpm-tis'>
+      <backend type='emulator'>
+      </backend>
+    </tpm>
+  </devices>
+  ...
 
model
@@ -7784,6 +7804,16 @@ qemu-kvm -net nic,model=? /dev/null

+
+
emulator
+
+

+ For this backend type the 'swtpm' TPM Emulator must be installed on the + host. Libvirt will automatically start an independent TPM emulator + for each QEMU guest requesting access to it. +

+
+
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 6379ab1e63..8ee6eebcf4 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4138,6 +4138,11 @@ + + + emulator + + diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index 14138d93af..b92779ce40 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -595,6 +595,8 @@ virDomainAuditTPM(virDomainObjPtr vm, virDomainTPMDefPtr tpm, "virt=%s resrc=dev reason=%s %s uuid=%s %s", virt, reason, vmname, uuidstr, device); break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: + break; case VIR_DOMAIN_TPM_TYPE_LAST: default: break; diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4aaad2a1d4..4e3861d227 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -866,7 +866,8 @@ VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST, "tpm-crb") VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST, - "passthrough") + "passthrough", + "emulator") VIR_ENUM_IMPL(virDomainIOMMUModel, VIR_DOMAIN_IOMMU_MODEL_LAST, "intel") @@ -2641,6 +2642,11 @@ void virDomainTPMDefFree(virDomainTPMDefPtr def) case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: VIR_FREE(def->data.passthrough.source.data.file.path); break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: + virDomainChrSourceDefClear(&def->data.emulator.source); + VIR_FREE(def->data.emulator.storagepath); + VIR_FREE(def->data.emulator.logfile); + break; case VIR_DOMAIN_TPM_TYPE_LAST: break; } @@ -12757,6 +12763,11 @@ virDomainSmartcardDefParseXML(virDomainXMLOptionPtr xmlopt, * * * + * or like this: + * + * + * + * */ static virDomainTPMDefPtr virDomainTPMDefParseXML(virDomainXMLOptionPtr xmlopt, @@ -12823,6 +12834,8 @@ virDomainTPMDefParseXML(virDomainXMLOptionPtr xmlopt, def->data.passthrough.source.type = VIR_DOMAIN_CHR_TYPE_DEV; path = NULL; break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: + break; case VIR_DOMAIN_TPM_TYPE_LAST: goto error; } @@ -25223,22 +25236,25 @@ virDomainTPMDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "\n", virDomainTPMModelTypeToString(def->model)); virBufferAdjustIndent(buf, 2); - virBufferAsprintf(buf, "\n", + virBufferAsprintf(buf, "type)); - virBufferAdjustIndent(buf, 2); switch (def->type) { case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); virBufferEscapeString(buf, "\n", def->data.passthrough.source.data.file.path); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: + virBufferAddLit(buf, "/>\n"); break; case VIR_DOMAIN_TPM_TYPE_LAST: break; } - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); - virDomainDeviceInfoFormat(buf, &def->info, flags); virBufferAdjustIndent(buf, -2); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index b6c4090ea1..066d8bbb44 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1291,6 +1291,7 @@ typedef enum { typedef enum { VIR_DOMAIN_TPM_TYPE_PASSTHROUGH, + VIR_DOMAIN_TPM_TYPE_EMULATOR, VIR_DOMAIN_TPM_TYPE_LAST } virDomainTPMBackendType; @@ -1305,6 +1306,11 @@ struct _virDomainTPMDef { struct { virDomainChrSourceDef source; } passthrough; + struct { + virDomainChrSourceDef source; + char *storagepath; + char *logfile; + } emulator; } data; }; diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 546a4c8e63..54b00a5da5 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -305,6 +305,7 @@ qemuSetupTPMCgroup(virDomainObjPtr vm) case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: ret = qemuSetupChrSourceCgroup(vm, &dev->data.passthrough.source); break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: case VIR_DOMAIN_TPM_TYPE_LAST: break; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1324c672ba..11ada72dfd 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -9580,6 +9580,7 @@ qemuBuildTPMBackendStr(const virDomainDef *def, VIR_FREE(cancel_path); break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: case VIR_DOMAIN_TPM_TYPE_LAST: goto error; } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 1fb1ef1deb..efe494d2e1 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -11012,6 +11012,7 @@ qemuDomainSetupTPM(virQEMUDriverConfigPtr cfg ATTRIBUTE_UNUSED, return -1; break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: case VIR_DOMAIN_TPM_TYPE_LAST: /* nada */ break; diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 8938e2dd89..3ab229992a 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -1372,6 +1372,7 @@ virSecurityDACSetTPMFileLabel(virSecurityManagerPtr mgr, &tpm->data.passthrough.source, false); break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: case VIR_DOMAIN_TPM_TYPE_LAST: break; } @@ -1393,6 +1394,7 @@ virSecurityDACRestoreTPMFileLabel(virSecurityManagerPtr mgr, &tpm->data.passthrough.source, false); break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: case VIR_DOMAIN_TPM_TYPE_LAST: break; } diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 5f74ef739b..5d20fdae70 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -1472,6 +1472,7 @@ virSecuritySELinuxSetTPMFileLabel(virSecurityManagerPtr mgr, return -1; } break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: case VIR_DOMAIN_TPM_TYPE_LAST: break; } @@ -1505,6 +1506,7 @@ virSecuritySELinuxRestoreTPMFileLabelInt(virSecurityManagerPtr mgr, VIR_FREE(cancel_path); } break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: case VIR_DOMAIN_TPM_TYPE_LAST: break; } diff --git a/tests/qemuxml2argvdata/tpm-emulator.xml b/tests/qemuxml2argvdata/tpm-emulator.xml new file mode 100644 index 0000000000..7f1e5756cb --- /dev/null +++ b/tests/qemuxml2argvdata/tpm-emulator.xml @@ -0,0 +1,30 @@ + + TPM-VM + 11d7cd22-da89-3094-6212-079a48a309a1 + 2097152 + 512288 + 1 + + hvm + + + + + + + + destroy + restart + destroy + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + diff --git a/tests/qemuxml2xmloutdata/tpm-emulator.xml b/tests/qemuxml2xmloutdata/tpm-emulator.xml new file mode 100644 index 0000000000..1b66e8b08a --- /dev/null +++ b/tests/qemuxml2xmloutdata/tpm-emulator.xml @@ -0,0 +1,34 @@ + + TPM-VM + 11d7cd22-da89-3094-6212-079a48a309a1 + 2097152 + 512288 + 1 + + hvm + + + + + + + + destroy + restart + destroy + + /usr/bin/qemu-system-x86_64 + +
+ + + + + + + + +
+ + + diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 56b666256f..115db6e64b 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -677,6 +677,7 @@ mymain(void) DO_TEST("disk-copy_on_read", NONE); DO_TEST("tpm-passthrough", NONE); DO_TEST("tpm-passthrough-crb", NONE); + DO_TEST("tpm-emulator", NONE); DO_TEST("metadata", NONE); DO_TEST("metadata-duplicate", NONE);