git: 67c26eb2a57c - main - bhyve: add cmdline option for TPM emulation

From: Corvin Köhne <corvink_at_FreeBSD.org>
Date: Thu, 17 Aug 2023 07:08:54 UTC
The branch main has been updated by corvink:

URL: https://cgit.FreeBSD.org/src/commit/?id=67c26eb2a57cd1f103d77db3b894a25f4bc10402

commit 67c26eb2a57cd1f103d77db3b894a25f4bc10402
Author:     Corvin Köhne <corvink@FreeBSD.org>
AuthorDate: 2021-10-07 14:20:37 +0000
Commit:     Corvin Köhne <corvink@FreeBSD.org>
CommitDate: 2023-08-17 06:17:59 +0000

    bhyve: add cmdline option for TPM emulation
    
    At the moment, only a TPM passthru is supported. The cmdline looks like:
    
    -l tpm,passthru,/dev/tpm0
    
    Reviewed by:            markj
    MFC after:              1 week
    Sponsored by:           Beckhoff Automation GmbH & Co. KG
    Differential Revision:  https://reviews.freebsd.org/D32961
---
 usr.sbin/bhyve/bhyve.8        | 39 +++++++++++++++++++++++++++++++++++++++
 usr.sbin/bhyve/bhyve_config.5 |  9 +++++++++
 usr.sbin/bhyve/bhyverun.c     |  5 +++++
 usr.sbin/bhyve/pci_lpc.c      | 25 ++++++++++++++++++++++++-
 usr.sbin/bhyve/tpm_device.c   | 22 ++++++++++++++++++++++
 usr.sbin/bhyve/tpm_device.h   |  2 ++
 6 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index 2979f90d34cf..7eddeec4647a 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -215,6 +215,8 @@ The only supported devices are the TTY-class devices
 .Cm com1 , com2 , com3 ,
 and
 .Cm com4 ,
+the TPM module
+.Cm tpm ,
 the boot ROM device
 .Cm bootrom ,
 the
@@ -538,6 +540,23 @@ process.
 Use the host TTY device for serial port I/O.
 .El
 .Pp
+TPM device backends:
+.Bl -tag -width 10n
+.It Ar type Ns \&, Ns Ar path Ns Op Cm \&, Ns Ar tpm-device-options
+Emulate a TPM device.
+.El
+.Pp
+The
+.Ar tpm-device-options
+are:
+.Bl -tag -width 10n
+.It Cm version= Ns Ar version
+Version of the TPM device according to the TCG specification.
+Defaults to
+.Cm 2.0
+.El
+.El
+.Pp
 Boot ROM device backends:
 .Bl -tag -width 10n
 .It Ar romfile Ns Op Cm \&, Ns Ar varfile
@@ -623,6 +642,26 @@ The host device must have been reserved at boot-time using the
 loader variable as described in
 .Xr vmm 4 .
 .Pp
+TPM devices:
+.Bl -tag -width 10n
+.It Ns Ar type
+Specifies the type of the TPM device.
+.Pp
+Supported types:
+.Bl -tag -width 10n
+.It Cm passthru
+.El
+.It Cm version= Ns Ar version
+The
+.Ar version
+of the emulated TPM device according to the TCG specification.
+.Pp
+Supported versions:
+.Bl -tag -width 10n
+.It Cm 2.0
+.El
+.El
+.Pp
 Virtio console device backends:
 .Bl -bullet
 .Sm off
diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5
index 8063df763689..d074d4503894 100644
--- a/usr.sbin/bhyve/bhyve_config.5
+++ b/usr.sbin/bhyve/bhyve_config.5
@@ -139,6 +139,15 @@ Specify the keyboard layout name with the file name in
 This value only works when loaded with UEFI mode for VNC, and
 used a VNC client that don't support QEMU Extended Key Event
 Message (e.g. TightVNC).
+.It Va tpm.path Ta string Ta Ta
+Path to the host TPM device.
+This is typically /dev/tpm0.
+.It Va tpm.type Ta string Ta Ta
+Type of the TPM device passed to the guest.
+Currently, only "passthru" is supported.
+.It Va tpm.version Ta string Ta 2.0 Ta
+Version of the TPM device according to the TCG specification.
+Currently, only version 2.0 is supported.
 .It Va rtc.use_localtime Ta bool Ta true Ta
 The real time clock uses the local time of the host.
 If this is set to false, the real time clock uses UTC.
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index 384c469f9ce7..3d32bfd35408 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -103,6 +103,7 @@
 #ifdef BHYVE_SNAPSHOT
 #include "snapshot.h"
 #endif
+#include "tpm_device.h"
 #include "xmsr.h"
 #include "spinup_ap.h"
 #include "rtc.h"
@@ -1474,6 +1475,10 @@ main(int argc, char *argv[])
 		perror("device emulation initialization error");
 		exit(4);
 	}
+	if (init_tpm(ctx) != 0) {
+		fprintf(stderr, "Failed to init TPM device");
+		exit(4);
+	}
 
 	/*
 	 * Initialize after PCI, to allow a bootrom file to reserve the high
diff --git a/usr.sbin/bhyve/pci_lpc.c b/usr.sbin/bhyve/pci_lpc.c
index ebda61aaea60..2ff9bbc27774 100644
--- a/usr.sbin/bhyve/pci_lpc.c
+++ b/usr.sbin/bhyve/pci_lpc.c
@@ -49,6 +49,7 @@
 #include "pci_lpc.h"
 #include "pci_passthru.h"
 #include "pctestdev.h"
+#include "tpm_device.h"
 #include "uart_emul.h"
 
 #define	IO_ICU1		0x20
@@ -93,7 +94,7 @@ lpc_device_parse(const char *opts)
 {
 	int unit, error;
 	char *str, *cpy, *lpcdev, *node_name;
-	const char *romfile, *varfile;
+	const char *romfile, *varfile, *tpm_type, *tpm_path;
 
 	error = -1;
 	str = cpy = strdup(opts);
@@ -124,6 +125,27 @@ lpc_device_parse(const char *opts)
 			error = 0;
 			goto done;
 		}
+		if (strcasecmp(lpcdev, "tpm") == 0) {
+			nvlist_t *nvl = create_config_node("tpm");
+
+			tpm_type = strsep(&str, ",");
+			if (tpm_type == NULL) {
+				errx(4, "invalid tpm type \"%s\"", opts);
+			}
+			set_config_value_node(nvl, "type", tpm_type);
+
+			tpm_path = strsep(&str, ",");
+			if (tpm_path == NULL) {
+				errx(4, "invalid tpm path \"%s\"", opts);
+			}
+			set_config_value_node(nvl, "path", tpm_path);
+
+			pci_parse_legacy_config(find_config_node("tpm"), str);
+
+			set_config_value_node_if_unset(nvl, "version", "2.0");
+			error = 0;
+			goto done;
+		}
 		for (unit = 0; unit < LPC_UART_NUM; unit++) {
 			if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) {
 				asprintf(&node_name, "lpc.%s.path",
@@ -157,6 +179,7 @@ lpc_print_supported_devices(void)
 	printf("bootrom\n");
 	for (i = 0; i < LPC_UART_NUM; i++)
 		printf("%s\n", lpc_uart_names[i]);
+	printf("tpm\n");
 	printf("%s\n", pctestdev_getname());
 }
 
diff --git a/usr.sbin/bhyve/tpm_device.c b/usr.sbin/bhyve/tpm_device.c
index 4c40db419380..3a4a8c577345 100644
--- a/usr.sbin/bhyve/tpm_device.c
+++ b/usr.sbin/bhyve/tpm_device.c
@@ -232,3 +232,25 @@ err_out:
 
 	return (error);
 }
+
+static struct tpm_device *lpc_tpm;
+
+int
+init_tpm(struct vmctx *ctx)
+{
+	nvlist_t *nvl;
+	int error;
+
+	nvl = find_config_node("tpm");
+	if (nvl == NULL)
+		return (0);
+
+	error = tpm_device_create(&lpc_tpm, ctx, nvl);
+	if (error) {
+		warnx("%s: unable to create a TPM device (%d)",
+		    __func__, error);
+		return (error);
+	}
+
+	return (0);
+}
diff --git a/usr.sbin/bhyve/tpm_device.h b/usr.sbin/bhyve/tpm_device.h
index a17c85c2ed47..0dd4c27999df 100644
--- a/usr.sbin/bhyve/tpm_device.h
+++ b/usr.sbin/bhyve/tpm_device.h
@@ -16,3 +16,5 @@ struct tpm_device;
 int tpm_device_create(struct tpm_device **new_dev, struct vmctx *vm_ctx,
     nvlist_t *nvl);
 void tpm_device_destroy(struct tpm_device *dev);
+
+int init_tpm(struct vmctx *ctx);