Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 16 Jun 2023 06:23:05 GMT
From:      =?utf-8?Q?Corvin=20K=C3=B6hne?= <corvink@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0917f925b46e - main - bhyve: add basic CRB interface for TPM devices
Message-ID:  <202306160623.35G6N5E7051650@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by corvink:

URL: https://cgit.FreeBSD.org/src/commit/?id=0917f925b46e3142c4373d1591bf22014d0f338e

commit 0917f925b46e3142c4373d1591bf22014d0f338e
Author:     Corvin Köhne <corvink@FreeBSD.org>
AuthorDate: 2022-08-29 10:10:43 +0000
Commit:     Corvin Köhne <corvink@FreeBSD.org>
CommitDate: 2023-06-16 06:22:53 +0000

    bhyve: add basic CRB interface for TPM devices
    
    Add a basic emulation for the command and response buffer interface of
    TPM devices. This commit only implements some CRB register and resets
    them.
    
    Reviewed by:            markj
    MFC after:              1 week
    Sponsored by:           Beckhoff Automation GmbH & Co. KG
    Differential Revision:  https://reviews.freebsd.org/D40456
---
 usr.sbin/bhyve/Makefile       |   1 +
 usr.sbin/bhyve/tpm_device.c   |  29 ++++++
 usr.sbin/bhyve/tpm_intf.h     |  35 +++++++
 usr.sbin/bhyve/tpm_intf_crb.c | 232 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 297 insertions(+)

diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
index fc880566228b..9b8a7274d793 100644
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -77,6 +77,7 @@ SRCS=	\
 	task_switch.c		\
 	tpm_device.c		\
 	tpm_emul_passthru.c	\
+	tpm_intf_crb.c		\
 	uart_emul.c		\
 	usb_emul.c		\
 	usb_mouse.c		\
diff --git a/usr.sbin/bhyve/tpm_device.c b/usr.sbin/bhyve/tpm_device.c
index 3a847cc53a9b..e1db0bab1ee9 100644
--- a/usr.sbin/bhyve/tpm_device.c
+++ b/usr.sbin/bhyve/tpm_device.c
@@ -18,17 +18,21 @@
 #include "config.h"
 #include "tpm_device.h"
 #include "tpm_emul.h"
+#include "tpm_intf.h"
 
 #define TPM_ACPI_DEVICE_NAME "TPM"
 #define TPM_ACPI_HARDWARE_ID "MSFT0101"
 
 SET_DECLARE(tpm_emul_set, struct tpm_emul);
+SET_DECLARE(tpm_intf_set, struct tpm_intf);
 
 struct tpm_device {
 	struct vmctx *vm_ctx;
 	struct acpi_device *acpi_dev;
 	struct tpm_emul *emul;
 	void *emul_sc;
+	struct tpm_intf *intf;
+	void *intf_sc;
 };
 
 static const struct acpi_device_emul tpm_acpi_device_emul = {
@@ -42,6 +46,8 @@ tpm_device_destroy(struct tpm_device *const dev)
 	if (dev == NULL)
 		return;
 
+	if (dev->intf != NULL && dev->intf->deinit != NULL)
+		dev->intf->deinit(dev->intf_sc);
 	if (dev->emul != NULL && dev->emul->deinit != NULL)
 		dev->emul->deinit(dev->emul_sc);
 
@@ -55,6 +61,7 @@ tpm_device_create(struct tpm_device **const new_dev, struct vmctx *const vm_ctx,
 {
 	struct tpm_device *dev = NULL;
 	struct tpm_emul **ppemul;
+	struct tpm_intf **ppintf;
 	const char *value;
 	int error;
 
@@ -63,6 +70,8 @@ tpm_device_create(struct tpm_device **const new_dev, struct vmctx *const vm_ctx,
 		goto err_out;
 	}
 
+	set_config_value_node_if_unset(nvl, "intf", "crb");
+
 	value = get_config_value_node(nvl, "version");
 	assert(value != NULL);
 	if (strcmp(value, "2.0")) {
@@ -104,6 +113,26 @@ tpm_device_create(struct tpm_device **const new_dev, struct vmctx *const vm_ctx,
 			goto err_out;
 	}
 
+	value = get_config_value_node(nvl, "intf");
+	SET_FOREACH(ppintf, tpm_intf_set) {
+		if (strcmp(value, (*ppintf)->name)) {
+			continue;
+		}
+		dev->intf = *ppintf;
+		break;
+	}
+	if (dev->intf == NULL) {
+		warnx("TPM interface \"%s\" not found", value);
+		error = EINVAL;
+		goto err_out;
+	}
+
+	if (dev->intf->init) {
+		error = dev->intf->init(&dev->intf_sc);
+		if (error)
+			goto err_out;
+	}
+
 	*new_dev = dev;
 
 	return (0);
diff --git a/usr.sbin/bhyve/tpm_intf.h b/usr.sbin/bhyve/tpm_intf.h
new file mode 100644
index 000000000000..7de7bc6d4435
--- /dev/null
+++ b/usr.sbin/bhyve/tpm_intf.h
@@ -0,0 +1,35 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#pragma once
+
+#include "config.h"
+#include "tpm_device.h"
+
+#define TPM_INTF_TYPE_FIFO_PTP 0x0
+#define TPM_INTF_TYPE_CRB 0x1
+#define TPM_INTF_TYPE_FIFO_TIS 0xF
+
+#define TPM_INTF_VERSION_FIFO 0
+#define TPM_INTF_VERSION_CRB 1
+
+#define TPM_INTF_CAP_CRB_DATA_XFER_SIZE_4 0
+#define TPM_INTF_CAP_CRB_DATA_XFER_SIZE_8 1
+#define TPM_INTF_CAP_CRB_DATA_XFER_SIZE_32 2
+#define TPM_INTF_CAP_CRB_DATA_XFER_SIZE_64 3
+
+#define TPM_INTF_SELECTOR_FIFO 0
+#define TPM_INTF_SELECTOR_CRB 1
+
+struct tpm_intf {
+	const char *name;
+
+	int (*init)(void **sc);
+	void (*deinit)(void *sc);
+	int (*build_acpi_table)(void *sc);
+};
+#define TPM_INTF_SET(x) DATA_SET(tpm_intf_set, x)
diff --git a/usr.sbin/bhyve/tpm_intf_crb.c b/usr.sbin/bhyve/tpm_intf_crb.c
new file mode 100644
index 000000000000..5fd640b2d5c9
--- /dev/null
+++ b/usr.sbin/bhyve/tpm_intf_crb.c
@@ -0,0 +1,232 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/linker_set.h>
+
+#include <machine/vmm.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vmmapi.h>
+
+#include "basl.h"
+#include "config.h"
+#include "mem.h"
+#include "qemu_fwcfg.h"
+#include "tpm_intf.h"
+
+#define TPM_CRB_ADDRESS 0xFED40000
+#define TPM_CRB_REGS_SIZE 0x1000
+
+#define TPM_CRB_DATA_BUFFER_ADDRESS \
+	(TPM_CRB_ADDRESS + offsetof(struct tpm_crb_regs, data_buffer))
+#define TPM_CRB_DATA_BUFFER_SIZE 0xF80
+
+#define TPM_CRB_LOCALITIES_MAX 5
+
+struct tpm_crb_regs {
+	union tpm_crb_reg_loc_state {
+		struct {
+			uint32_t tpm_established : 1;
+			uint32_t loc_assigned : 1;
+			uint32_t active_locality : 3;
+			uint32_t _reserved : 2;
+			uint32_t tpm_req_valid_sts : 1;
+		};
+		uint32_t val;
+	} loc_state;	       /* 0h */
+	uint8_t _reserved1[4]; /* 4h */
+	union tpm_crb_reg_loc_ctrl {
+		struct {
+			uint32_t request_access : 1;
+			uint32_t relinquish : 1;
+			uint32_t seize : 1;
+			uint32_t reset_establishment_bit : 1;
+		};
+		uint32_t val;
+	} loc_ctrl; /* 8h */
+	union tpm_crb_reg_loc_sts {
+		struct {
+			uint32_t granted : 1;
+			uint32_t been_seized : 1;
+		};
+		uint32_t val;
+	} loc_sts;		  /* Ch */
+	uint8_t _reserved2[0x20]; /* 10h */
+	union tpm_crb_reg_intf_id {
+		struct {
+			uint64_t interface_type : 4;
+			uint64_t interface_version : 4;
+			uint64_t cap_locality : 1;
+			uint64_t cap_crb_idle_bypass : 1;
+			uint64_t _reserved1 : 1;
+			uint64_t cap_data_xfer_size_support : 2;
+			uint64_t cap_fifo : 1;
+			uint64_t cap_crb : 1;
+			uint64_t _reserved2 : 2;
+			uint64_t interface_selector : 2;
+			uint64_t intf_sel_lock : 1;
+			uint64_t _reserved3 : 4;
+			uint64_t rid : 8;
+			uint64_t vid : 16;
+			uint64_t did : 16;
+		};
+		uint64_t val;
+	} intf_id; /* 30h */
+	union tpm_crb_reg_ctrl_ext {
+		struct {
+			uint32_t clear;
+			uint32_t remaining_bytes;
+		};
+		uint64_t val;
+	} ctrl_ext; /* 38 */
+	union tpm_crb_reg_ctrl_req {
+		struct {
+			uint32_t cmd_ready : 1;
+			uint32_t go_idle : 1;
+		};
+		uint32_t val;
+	} ctrl_req; /* 40h */
+	union tpm_crb_reg_ctrl_sts {
+		struct {
+			uint32_t tpm_sts : 1;
+			uint32_t tpm_idle : 1;
+		};
+		uint32_t val;
+	} ctrl_sts; /* 44h */
+	union tpm_crb_reg_ctrl_cancel {
+		struct {
+			uint32_t cancel : 1;
+		};
+		uint32_t val;
+	} ctrl_cancel; /* 48h */
+	union tpm_crb_reg_ctrl_start {
+		struct {
+			uint32_t start : 1;
+		};
+		uint32_t val;
+	} ctrl_start;				       /* 4Ch*/
+	uint32_t int_enable;			       /* 50h */
+	uint32_t int_sts;			       /* 54h */
+	uint32_t cmd_size;			       /* 58h */
+	uint32_t cmd_addr_lo;			       /* 5Ch */
+	uint32_t cmd_addr_hi;			       /* 60h */
+	uint32_t rsp_size;			       /* 64h */
+	uint64_t rsp_addr;			       /* 68h */
+	uint8_t _reserved3[0x10];		       /* 70h */
+	uint8_t data_buffer[TPM_CRB_DATA_BUFFER_SIZE]; /* 80h */
+} __packed;
+static_assert(sizeof(struct tpm_crb_regs) == TPM_CRB_REGS_SIZE,
+    "Invalid size of tpm_crb");
+
+#define CRB_CMD_SIZE_READ(regs) (regs.cmd_size)
+#define CRB_CMD_SIZE_WRITE(regs, val) \
+	do {                          \
+		regs.cmd_size = val;  \
+	} while (0)
+#define CRB_CMD_ADDR_READ(regs) \
+	(((uint64_t)regs.cmd_addr_hi << 32) | regs.cmd_addr_lo)
+#define CRB_CMD_ADDR_WRITE(regs, val)                \
+	do {                                         \
+		regs.cmd_addr_lo = val & 0xFFFFFFFF; \
+		regs.cmd_addr_hi = val >> 32;        \
+	} while (0)
+#define CRB_RSP_SIZE_READ(regs) (regs.rsp_size)
+#define CRB_RSP_SIZE_WRITE(regs, val) \
+	do {                          \
+		regs.rsp_size = val;  \
+	} while (0)
+#define CRB_RSP_ADDR_READ(regs) (regs.rsp_addr)
+#define CRB_RSP_ADDR_WRITE(regs, val) \
+	do {                          \
+		regs.rsp_addr = val;  \
+	} while (0)
+
+struct tpm_crb {
+	struct tpm_crb_regs regs;
+};
+
+static int
+tpm_crb_init(void **sc)
+{
+	struct tpm_crb *crb = NULL;
+	int error;
+
+	assert(sc != NULL);
+
+	crb = calloc(1, sizeof(struct tpm_crb));
+	if (crb == NULL) {
+		warnx("%s: failed to allocate tpm crb", __func__);
+		error = ENOMEM;
+		goto err_out;
+	}
+
+	memset(crb, 0, sizeof(*crb));
+
+	crb->regs.loc_state.tpm_req_valid_sts = true;
+	crb->regs.loc_state.tpm_established = true;
+
+	crb->regs.intf_id.interface_type = TPM_INTF_TYPE_CRB;
+	crb->regs.intf_id.interface_version = TPM_INTF_VERSION_CRB;
+	crb->regs.intf_id.cap_locality = false;
+	crb->regs.intf_id.cap_crb_idle_bypass = false;
+	crb->regs.intf_id.cap_data_xfer_size_support =
+	    TPM_INTF_CAP_CRB_DATA_XFER_SIZE_64;
+	crb->regs.intf_id.cap_fifo = false;
+	crb->regs.intf_id.cap_crb = true;
+	crb->regs.intf_id.interface_selector = TPM_INTF_SELECTOR_CRB;
+	crb->regs.intf_id.intf_sel_lock = false;
+	crb->regs.intf_id.rid = 0;
+	crb->regs.intf_id.vid = 0x1014; /* IBM */
+	crb->regs.intf_id.did = 0x1014; /* IBM */
+
+	crb->regs.ctrl_sts.tpm_idle = true;
+
+	CRB_CMD_SIZE_WRITE(crb->regs, TPM_CRB_DATA_BUFFER_SIZE);
+	CRB_CMD_ADDR_WRITE(crb->regs, TPM_CRB_DATA_BUFFER_ADDRESS);
+	CRB_RSP_SIZE_WRITE(crb->regs, TPM_CRB_DATA_BUFFER_SIZE);
+	CRB_RSP_ADDR_WRITE(crb->regs, TPM_CRB_DATA_BUFFER_ADDRESS);
+
+	*sc = crb;
+
+	return (0);
+
+err_out:
+	free(crb);
+
+	return (error);
+}
+
+static void
+tpm_crb_deinit(void *sc)
+{
+	struct tpm_crb *crb;
+
+	if (sc == NULL) {
+		return;
+	}
+
+	crb = sc;
+
+	free(crb);
+}
+
+static struct tpm_intf tpm_intf_crb = {
+	.name = "crb",
+	.init = tpm_crb_init,
+	.deinit = tpm_crb_deinit,
+};
+TPM_INTF_SET(tpm_intf_crb);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202306160623.35G6N5E7051650>