Page MenuHomeFreeBSD

D40462.diff
No OneTemporary

D40462.diff

diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -78,6 +78,7 @@
tpm_device.c \
tpm_emul_passthru.c \
tpm_intf_crb.c \
+ tpm_ppi_qemu.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
--- a/usr.sbin/bhyve/tpm_device.c
+++ b/usr.sbin/bhyve/tpm_device.c
@@ -14,17 +14,20 @@
#include <string.h>
#include <vmmapi.h>
+#include "acpi.h"
#include "acpi_device.h"
#include "config.h"
#include "tpm_device.h"
#include "tpm_emul.h"
#include "tpm_intf.h"
+#include "tpm_ppi.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);
+SET_DECLARE(tpm_ppi_set, struct tpm_ppi);
struct tpm_device {
struct vmctx *vm_ctx;
@@ -33,6 +36,8 @@
void *emul_sc;
struct tpm_intf *intf;
void *intf_sc;
+ struct tpm_ppi *ppi;
+ void *ppi_sc;
};
static int
@@ -47,10 +52,57 @@
return (tpm->intf->build_acpi_table(tpm->intf_sc, tpm->vm_ctx));
}
+static int
+tpm_write_dsdt(const struct acpi_device *const dev)
+{
+ int error;
+
+ const struct tpm_device *const tpm = acpi_device_get_softc(dev);
+ const struct tpm_ppi *const ppi = tpm->ppi;
+
+ /*
+ * packages for returns
+ */
+ dsdt_line("Name(TPM2, Package(2) {0, 0})");
+ dsdt_line("Name(TPM3, Package(3) {0, 0, 0})");
+
+ if (ppi->write_dsdt_regions) {
+ error = ppi->write_dsdt_regions(tpm->ppi_sc);
+ if (error) {
+ warnx("%s: failed to write ppi dsdt regions\n",
+ __func__);
+ return (error);
+ }
+ }
+
+ /*
+ * Device Specific Method
+ * Arg0: UUID
+ * Arg1: Revision ID
+ * Arg2: Function Index
+ * Arg3: Arguments
+ */
+ dsdt_line("Method(_DSM, 4, Serialized)");
+ dsdt_line("{");
+ dsdt_indent(1);
+ if (ppi->write_dsdt_dsm) {
+ error = ppi->write_dsdt_dsm(tpm->ppi_sc);
+ if (error) {
+ warnx("%s: failed to write ppi dsdt dsm\n", __func__);
+ return (error);
+ }
+ }
+ dsdt_unindent(1);
+ dsdt_line("}");
+
+ return (0);
+}
+
static const struct acpi_device_emul tpm_acpi_device_emul = {
.name = TPM_ACPI_DEVICE_NAME,
.hid = TPM_ACPI_HARDWARE_ID,
.build_table = tpm_build_acpi_table,
+ .write_dsdt = tpm_write_dsdt,
};
void
@@ -59,6 +111,8 @@
if (dev == NULL)
return;
+ if (dev->ppi != NULL && dev->ppi->deinit != NULL)
+ dev->ppi->deinit(dev->ppi_sc);
if (dev->intf != NULL && dev->intf->deinit != NULL)
dev->intf->deinit(dev->intf_sc);
if (dev->emul != NULL && dev->emul->deinit != NULL)
@@ -75,6 +129,7 @@
struct tpm_device *dev = NULL;
struct tpm_emul **ppemul;
struct tpm_intf **ppintf;
+ struct tpm_ppi **pp_ppi;
const char *value;
int error;
@@ -84,6 +139,7 @@
}
set_config_value_node_if_unset(nvl, "intf", "crb");
+ set_config_value_node_if_unset(nvl, "ppi", "qemu");
value = get_config_value_node(nvl, "version");
assert(value != NULL);
@@ -147,6 +203,26 @@
goto err_out;
}
+ value = get_config_value_node(nvl, "ppi");
+ SET_FOREACH(pp_ppi, tpm_ppi_set) {
+ if (strcmp(value, (*pp_ppi)->name)) {
+ continue;
+ }
+ dev->ppi = *pp_ppi;
+ break;
+ }
+ if (dev->ppi == NULL) {
+ warnx("TPM PPI \"%s\" not found\n", value);
+ error = EINVAL;
+ goto err_out;
+ }
+
+ if (dev->ppi->init) {
+ error = dev->ppi->init(&dev->ppi_sc);
+ if (error)
+ goto err_out;
+ }
+
*new_dev = dev;
return (0);
diff --git a/usr.sbin/bhyve/tpm_ppi.h b/usr.sbin/bhyve/tpm_ppi.h
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/tpm_ppi.h
@@ -0,0 +1,20 @@
+/*-
+ * 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"
+
+struct tpm_ppi {
+ const char *name;
+
+ int (*init)(void **sc);
+ void (*deinit)(void *sc);
+ int (*write_dsdt_regions)(void *sc);
+ int (*write_dsdt_dsm)(void *sc);
+};
+#define TPM_PPI_SET(x) DATA_SET(tpm_ppi_set, x)
diff --git a/usr.sbin/bhyve/tpm_ppi_qemu.c b/usr.sbin/bhyve/tpm_ppi_qemu.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/tpm_ppi_qemu.c
@@ -0,0 +1,476 @@
+/*-
+ * 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/endian.h>
+#include <sys/linker_set.h>
+
+#include <machine/vmm.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <vmmapi.h>
+
+#include "acpi.h"
+#include "acpi_device.h"
+#include "config.h"
+#include "mem.h"
+#include "qemu_fwcfg.h"
+#include "tpm_ppi.h"
+
+#define TPM_PPI_ADDRESS 0xFED45000
+#define TPM_PPI_SIZE 0x1000
+
+#define TPM_PPI_FWCFG_FILE "etc/tpm/config"
+
+#define TPM_PPI_QEMU_NAME "qemu"
+
+struct tpm_ppi_qemu {
+ uint8_t func[256]; // FUNC
+ uint8_t in; // PPIN
+ uint32_t ip; // PPIP
+ uint32_t response; // PPRP
+ uint32_t request; // PPRQ
+ uint32_t request_parameter; // PPRM
+ uint32_t last_request; // LPPR
+ uint32_t func_ret; // FRET
+ uint8_t _reserved1[0x40]; // RES1
+ uint8_t next_step; // next_step
+} __packed;
+static_assert(sizeof(struct tpm_ppi_qemu) <= TPM_PPI_SIZE,
+ "Wrong size of tpm_ppi_qemu");
+
+struct tpm_ppi_fwcfg {
+ uint32_t ppi_address;
+ uint8_t tpm_version;
+ uint8_t ppi_version;
+} __packed;
+
+static int
+tpm_ppi_mem_handler(struct vcpu *const vcpu __unused, const int dir,
+ const uint64_t addr, const int size, uint64_t *const val, void *const arg1,
+ const long arg2 __unused)
+{
+ struct tpm_ppi_qemu *ppi;
+ uint8_t *ptr;
+ uint64_t off;
+
+ if ((addr & (size - 1)) != 0) {
+ warnx("%s: unaligned %s access @ %16lx [size = %x]", __func__,
+ (dir == MEM_F_READ) ? "read" : "write", addr, size);
+ }
+
+ ppi = arg1;
+
+ off = addr - TPM_PPI_ADDRESS;
+ ptr = (uint8_t *)ppi + off;
+
+ if (off > TPM_PPI_SIZE || off + size > TPM_PPI_SIZE) {
+ return (EINVAL);
+ }
+
+ assert(size == 1 || size == 2 || size == 4 || size == 8);
+ if (dir == MEM_F_READ) {
+ memcpy(val, ptr, size);
+ } else {
+ memcpy(ptr, val, size);
+ }
+
+ return (0);
+}
+
+static struct mem_range ppi_mmio = {
+ .name = "ppi-mmio",
+ .base = TPM_PPI_ADDRESS,
+ .size = TPM_PPI_SIZE,
+ .flags = MEM_F_RW,
+ .handler = tpm_ppi_mem_handler,
+};
+
+static int
+tpm_ppi_init(void **sc)
+{
+ struct tpm_ppi_qemu *ppi = NULL;
+ struct tpm_ppi_fwcfg *fwcfg = NULL;
+ int error;
+
+ ppi = calloc(1, sizeof(*ppi));
+ if (ppi == NULL) {
+ warnx("%s: failed to allocate acpi region for ppi", __func__);
+ error = ENOMEM;
+ goto err_out;
+ }
+
+ fwcfg = calloc(1, sizeof(struct tpm_ppi_fwcfg));
+ if (fwcfg == NULL) {
+ warnx("%s: failed to allocate fwcfg item", __func__);
+ error = ENOMEM;
+ goto err_out;
+ }
+
+ fwcfg->ppi_address = htole32(TPM_PPI_ADDRESS);
+ fwcfg->tpm_version = 2;
+ fwcfg->ppi_version = 1;
+
+ error = qemu_fwcfg_add_file(TPM_PPI_FWCFG_FILE,
+ sizeof(struct tpm_ppi_fwcfg), fwcfg);
+ if (error) {
+ warnx("%s: failed to add fwcfg file", __func__);
+ goto err_out;
+ }
+
+ /*
+ * We would just need to create some guest memory for the PPI region.
+ * Sadly, bhyve has a strange memory interface. We can't just add more
+ * memory to the VM. So, create a trap instead which reads and writes to
+ * the ppi region. It's very slow but ppi shouldn't be used frequently.
+ */
+ ppi_mmio.arg1 = ppi;
+ error = register_mem(&ppi_mmio);
+ if (error) {
+ warnx("%s: failed to create trap for ppi accesses", __func__);
+ goto err_out;
+ }
+
+ *sc = ppi;
+
+ return (0);
+
+err_out:
+ free(fwcfg);
+ free(ppi);
+
+ return (error);
+}
+
+static void
+tpm_ppi_deinit(void *sc)
+{
+ struct tpm_ppi_qemu *ppi;
+ int error;
+
+ if (sc == NULL)
+ return;
+
+ ppi = sc;
+
+ error = unregister_mem(&ppi_mmio);
+ assert(error = 0);
+
+ free(ppi);
+}
+
+static int
+tpm_ppi_write_dsdt_regions(void *sc __unused)
+{
+ /*
+ * struct tpm_ppi_qemu
+ */
+ /*
+ * According to qemu the Windows ACPI parser has a bug that DerefOf is
+ * broken for SYSTEM_MEMORY. Due to that bug, qemu uses a dynamic
+ * operation region inside a method.
+ */
+ dsdt_line("Method(TPFN, 1, Serialized)");
+ dsdt_line("{");
+ dsdt_line(" If(LGreaterEqual(Arg0, 0x100))");
+ dsdt_line(" {");
+ dsdt_line(" Return(Zero)");
+ dsdt_line(" }");
+ dsdt_line(
+ " OperationRegion(TPP1, SystemMemory, Add(0x%8x, Arg0), One)",
+ TPM_PPI_ADDRESS);
+ dsdt_line(" Field(TPP1, ByteAcc, NoLock, Preserve)");
+ dsdt_line(" {");
+ dsdt_line(" TPPF, 8,");
+ dsdt_line(" }");
+ dsdt_line(" Return(TPPF)");
+ dsdt_line("}");
+ dsdt_line("OperationRegion(TPP2, SystemMemory, 0x%8x, 0x%x)",
+ TPM_PPI_ADDRESS + 0x100, 0x5A);
+ dsdt_line("Field(TPP2, AnyAcc, NoLock, Preserve)");
+ dsdt_line("{");
+ dsdt_line(" PPIN, 8,");
+ dsdt_line(" PPIP, 32,");
+ dsdt_line(" PPRP, 32,");
+ dsdt_line(" PPRQ, 32,");
+ dsdt_line(" PPRM, 32,");
+ dsdt_line(" LPPR, 32,");
+ dsdt_line("}");
+ /*
+ * Used for TCG Platform Reset Attack Mitigation
+ */
+ dsdt_line("OperationRegion(TPP3, SystemMemory, 0x%8x, 1)",
+ TPM_PPI_ADDRESS + sizeof(struct tpm_ppi_qemu));
+ dsdt_line("Field(TPP3, ByteAcc, NoLock, Preserve)");
+ dsdt_line("{");
+ dsdt_line(" MOVV, 8,");
+ dsdt_line("}");
+
+ return (0);
+}
+
+static int
+tpm_ppi_write_dsdt_dsm(void *sc __unused)
+{
+ /*
+ * Physical Presence Interface
+ */
+ dsdt_line(
+ "If(LEqual(Arg0, ToUUID(\"3DDDFAA6-361B-4EB4-A424-8D10089D1653\"))) /* UUID */");
+ dsdt_line("{");
+ /*
+ * Function 0 - _DSM Query Function
+ * Arguments:
+ * Empty Package
+ * Return:
+ * Buffer - Index field of supported functions
+ */
+ dsdt_line(" If(LEqual(Arg2, 0)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Return(Buffer(0x02)");
+ dsdt_line(" {");
+ dsdt_line(" 0xFF, 0x01");
+ dsdt_line(" })");
+ dsdt_line(" }");
+ /*
+ * Function 1 - Get Physical Presence Interface Version
+ * Arguments:
+ * Empty Package
+ * Return:
+ * String - Supported Physical Presence Interface revision
+ */
+ dsdt_line(" If(LEqual(Arg2, 1)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Return(\"1.3\")");
+ dsdt_line(" }");
+ /*
+ * Function 2 - Submit TPM Operation Request to Pre-OS Environment
+ * !!!DEPRECATED BUT MANDATORY!!!
+ * Arguments:
+ * Integer - Operation Value of the Request
+ * Return:
+ * Integer - Function Return Code
+ * 0 - Success
+ * 1 - Operation Value of the Request Not Supported
+ * 2 - General Failure
+ */
+ dsdt_line(" If(LEqual(Arg2, 2)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Store(DerefOf(Index(Arg3, 0)), Local0)");
+ dsdt_line(" Store(TPFN(Local0), Local1)");
+ dsdt_line(" If (LEqual(And(Local1, 7), 0))");
+ dsdt_line(" {");
+ dsdt_line(" Return(1)");
+ dsdt_line(" }");
+ dsdt_line(" Store(Local0, PPRQ)");
+ dsdt_line(" Store(0, PPRM)");
+ dsdt_line(" Return(0)");
+ dsdt_line(" }");
+ /*
+ * Function 3 - Get Pending TPM Operation Request By the OS
+ * Arguments:
+ * Empty Package
+ * Return:
+ * Package
+ * Integer 1 - Function Return Code
+ * 0 - Success
+ * 1 - General Failure
+ * Integer 2 - Pending operation requested by the OS
+ * 0 - None
+ * >0 - Operation Value of the Pending Request
+ * Integer 3 - Optional argument to pending operation requested by
+ * the OS
+ * 0 - None
+ * >0 - Argument of the Pending Request
+ */
+ dsdt_line(" If(LEqual(Arg2, 3)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" If(LEqual(Arg1, 1)) /* Revision */");
+ dsdt_line(" {");
+ dsdt_line(" Store(PPRQ, Index(TPM2, 1))");
+ dsdt_line(" Return(TPM2)");
+ dsdt_line(" }");
+ dsdt_line(" If(LEqual(Arg1, 2)) /* Revision */");
+ dsdt_line(" {");
+ dsdt_line(" Store(PPRQ, Index(TPM3, 1))");
+ dsdt_line(" Store(PPRM, Index(TPM3, 2))");
+ dsdt_line(" Return(TPM3)");
+ dsdt_line(" }");
+ dsdt_line(" }");
+ /*
+ * Function 4 - Get Platform-Specific Action to Transition to Pre-OS
+ * Environment
+ * Arguments:
+ * Empty Package
+ * Return:
+ * Integer - Action that the OS should take to transition to the
+ * pre-OS environment for execution of a requested operation
+ * 0 - None
+ * 1 - Shutdown
+ * 2 - Reboot
+ * 3 - OS Vendor-specific
+ */
+ dsdt_line(" If(LEqual(Arg2, 4)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Return(2)");
+ dsdt_line(" }");
+ /*
+ * Function 5 - Return TPM Operation Response to OS Environment
+ * Arguments:
+ * Empty Package
+ * Return:
+ * Package
+ * Integer 1 - Function Return Code
+ * 0 - Success
+ * 1 - General Failure
+ * Integer 2 - Most recent operation request
+ * 0 - None
+ * >0 - Operation value of the most recent request
+ * Integer 3 - Response to the most recent operation request
+ * 0 - Success
+ * 0x00000001..0x000000FF - Corresponding TPM error code
+ * 0xFFFFFFF0 - User Abort or timeout of dialog
+ * 0xFFFFFFF1 - firmware failure
+ */
+ dsdt_line(" If(LEqual(Arg2, 5)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Store(LPPR, Index(TPM3, 1))");
+ dsdt_line(" Store(PPRP, Index(TPM3, 2))");
+ dsdt_line(" Return(TPM3)");
+ dsdt_line(" }");
+ /*
+ * Function 6 - Submit preferred user language
+ * !!!DEPRECATED BUT MANDATORY!!!
+ * Arguments:
+ * Package
+ * String - Preferred language code
+ * Return:
+ * Integer
+ * 3 - Not implemented
+ */
+ dsdt_line(" If(LEqual(Arg2, 6)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Return(3)");
+ dsdt_line(" }");
+ /*
+ * Function 7 - Submit TPM Operation Request to Pre-OS Environment 2
+ * Arguments:
+ * Package
+ * Integer 1 - Operation Value of the Request
+ * Integer 2 - Argument for Operation
+ * Return:
+ * Integer - Function Return Code
+ * 0 - Success
+ * 1 - Not Implemented
+ * 2 - General Failure
+ * 3 - Operation blocked by current firmware settings
+ */
+ dsdt_line(" If(LEqual(Arg2, 7)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Store(DerefOf(Index(Arg3, 0)), Local0)");
+ dsdt_line(" Store(TPFN(Local0), Local1)");
+ dsdt_line(" If (LEqual(And(Local1, 7), 0)) /* Not Implemented */");
+ dsdt_line(" {");
+ dsdt_line(" Return(1)");
+ dsdt_line(" }");
+ dsdt_line(" If (LEqual(And(Local1, 7), 2)) /* Blocked */ ");
+ dsdt_line(" {");
+ dsdt_line(" Return(3)");
+ dsdt_line(" }");
+ dsdt_line(" If(LEqual(Arg1, 1)) /* Revision */");
+ dsdt_line(" {");
+ dsdt_line(" Store(Local0, PPRQ)");
+ dsdt_line(" Store(0, PPRM)");
+ dsdt_line(" }");
+ dsdt_line(" If(LEqual(Arg1, 2)) /* Revision */");
+ dsdt_line(" {");
+ dsdt_line(" Store(Local0, PPRQ)");
+ dsdt_line(" Store(DerefOf(Index(Arg3, 1)), PPRM)");
+ dsdt_line(" }");
+ dsdt_line(" Return(0)");
+ dsdt_line(" }");
+ /*
+ * Function 8 - Get User Confirmation Status for Operation
+ * Arguments:
+ * Package
+ * Integer - Operation Value that may need user confirmation
+ * Return:
+ * Integer - Function Return Code
+ * 0 - Not implemented
+ * 1 - Firmware only
+ * 2 - Blocked for OS by firmware configuration
+ * 3 - Allowed and physically present user required
+ * 4 - Allowed and physically present user not required
+ */
+ dsdt_line(" If(LEqual(Arg2, 8)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Store(DerefOf(Index(Arg3, 0)), Local0)");
+ dsdt_line(" Store(TPFN(Local0), Local1)");
+ dsdt_line(" Return(And(Local1, 7))");
+ dsdt_line(" }");
+ /*
+ * Unknown function
+ */
+ dsdt_line(" Return(Buffer(1)");
+ dsdt_line(" {");
+ dsdt_line(" 0x00");
+ dsdt_line(" })");
+ dsdt_line("}");
+
+ /*
+ * TCG Platform Reset Attack Mitigation
+ */
+ dsdt_line(
+ "If(LEqual(Arg0, ToUUID(\"376054ED-CC13-4675-901C-4756D7F2D45D\"))) /* UUID */");
+ dsdt_line("{");
+ /*
+ * Function 0 - _DSM Query Function
+ * Arguments:
+ * Empty Package
+ * Return:
+ * Buffer - Index field of supported functions
+ */
+ dsdt_line(" If(LEqual(Arg2, 0)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Return(Buffer(1)");
+ dsdt_line(" {");
+ dsdt_line(" 0x03");
+ dsdt_line(" })");
+ dsdt_line(" }");
+ /*
+ * Function 1 - Memory Clear
+ * Arguments:
+ * Package
+ * Integer - Operation Value of the Request
+ * Return:
+ * Integer - Function Return Code
+ * 0 - Success
+ * 1 - General Failure
+ */
+ dsdt_line(" If(LEqual(Arg2, 1)) /* Function */");
+ dsdt_line(" {");
+ dsdt_line(" Store(DerefOf(Index(Arg3, 0)), Local0)");
+ dsdt_line(" Store(Local0, MOVV)");
+ dsdt_line(" Return(0)");
+ dsdt_line(" }");
+ dsdt_line("}");
+
+ return (0);
+}
+
+static struct tpm_ppi tpm_ppi_qemu = {
+ .name = TPM_PPI_QEMU_NAME,
+ .init = tpm_ppi_init,
+ .deinit = tpm_ppi_deinit,
+ .write_dsdt_regions = tpm_ppi_write_dsdt_regions,
+ .write_dsdt_dsm = tpm_ppi_write_dsdt_dsm,
+};
+TPM_PPI_SET(tpm_ppi_qemu);

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 13, 3:16 PM (17 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15783436
Default Alt Text
D40462.diff (16 KB)

Event Timeline