Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153210314
D32961.id98414.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
41 KB
Referenced Files
None
Subscribers
None
D32961.id98414.diff
View Options
diff --git a/lib/libvmmapi/Makefile b/lib/libvmmapi/Makefile
--- a/lib/libvmmapi/Makefile
+++ b/lib/libvmmapi/Makefile
@@ -10,5 +10,6 @@
LIBADD= util
CFLAGS+= -I${.CURDIR}
+CFLAGS+= -I${SRCTOP}/sys
.include <bsd.lib.mk>
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -37,6 +37,8 @@
#include <stdbool.h>
+#include <contrib/dev/acpica/include/acpi.h>
+
/*
* API version for out-of-tree consumers like grub-bhyve for making compile
* time decisions.
@@ -180,6 +182,16 @@
vm_paddr_t gpa, size_t len, vm_paddr_t hpa);
int vm_unmap_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
vm_paddr_t gpa, size_t len);
+int vm_get_memory_region_info(struct vmctx *ctx, vm_paddr_t *base,
+ vm_paddr_t *size, enum vm_memory_region_type type);
+int vm_mmap_mmio(struct vmctx *const ctx, const vm_paddr_t gpa,
+ const vm_paddr_t len, const vm_paddr_t hpa);
+int vm_munmap_mmio(struct vmctx *const ctx, const vm_paddr_t gpa,
+ const vm_paddr_t len);
+int vm_mwire_gpa(struct vmctx *const ctx, const vm_paddr_t gpa,
+ const vm_paddr_t len);
+int vm_munwire_gpa(struct vmctx *const ctx, const vm_paddr_t gpa,
+ const vm_paddr_t len);
int vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot,
int func, uint64_t addr, uint64_t msg, int numvec);
int vm_setup_pptdev_msix(struct vmctx *ctx, int vcpu, int bus, int slot,
@@ -190,6 +202,11 @@
int vm_get_intinfo(struct vmctx *ctx, int vcpu, uint64_t *i1, uint64_t *i2);
int vm_set_intinfo(struct vmctx *ctx, int vcpu, uint64_t exit_intinfo);
+/*
+ * Return current resources (CRS) used by an ACPI device.
+ */
+int vm_acpi_device_get_crs(struct vmctx *const ctx, const char *const name, ACPI_BUFFER *const crs);
+
const cap_ioctl_t *vm_get_ioctls(size_t *len);
/*
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -1009,6 +1009,71 @@
return (ioctl(ctx->fd, VM_UNMAP_PPTDEV_MMIO, &pptmmio));
}
+int
+vm_get_memory_region_info(struct vmctx *ctx, vm_paddr_t *base, vm_paddr_t *size,
+ enum vm_memory_region_type type)
+{
+ struct vm_memory_region_info memory_region_info;
+
+ bzero(&memory_region_info, sizeof(memory_region_info));
+ memory_region_info.type = type;
+
+ const int error = ioctl(ctx->fd, VM_GET_MEMORY_REGION_INFO, &memory_region_info);
+
+ if (base)
+ *base = memory_region_info.base;
+ if (size)
+ *size = memory_region_info.size;
+
+ return (error);
+}
+
+/*
+ * Modifies the second level address translation (SLAT) of the guest memory
+ * space.
+ */
+static int
+vm_mmodify_slat(struct vmctx * const ctx, const vm_paddr_t gpa, const vm_paddr_t len,
+ const vm_paddr_t hpa, const enum slat_op_type type)
+{
+ struct vm_slat_op slat_op = {
+ .gpa = gpa,
+ .len = len,
+ .hpa = hpa,
+ .type = type,
+ };
+
+ return ioctl(ctx->fd, VM_MODIFY_SLAT, &slat_op);
+}
+
+int
+vm_mmap_mmio(struct vmctx *const ctx, const vm_paddr_t gpa,
+ const vm_paddr_t len, const vm_paddr_t hpa)
+{
+ return vm_mmodify_slat(ctx, gpa, len, hpa, VM_MAP_MMIO);
+}
+
+int
+vm_munmap_mmio(struct vmctx *const ctx, const vm_paddr_t gpa,
+ const vm_paddr_t len)
+{
+ return vm_mmodify_slat(ctx, gpa, len, 0, VM_UNMAP_MMIO);
+}
+
+int
+vm_mwire_gpa(struct vmctx *const ctx, const vm_paddr_t gpa,
+ const vm_paddr_t len)
+{
+ return vm_mmodify_slat(ctx, gpa, len, 0, VM_WIRE_GPA);
+}
+
+int
+vm_munwire_gpa(struct vmctx *const ctx, const vm_paddr_t gpa,
+ const vm_paddr_t len)
+{
+ return vm_mmodify_slat(ctx, gpa, len, 0, VM_UNWIRE_GPA);
+}
+
int
vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
uint64_t addr, uint64_t msg, int numvec)
@@ -1059,6 +1124,46 @@
return ioctl(ctx->fd, VM_PPTDEV_DISABLE_MSIX, &ppt);
}
+int
+vm_acpi_device_get_crs(struct vmctx *const ctx, const char *const name,
+ ACPI_BUFFER *const crs)
+{
+ if (crs == NULL) {
+ return (EINVAL);
+ }
+
+ char path[NAME_MAX];
+ snprintf(path, NAME_MAX, "\\_SB.%s", name);
+
+ /* get required size to hold CRS data */
+ struct vm_acpi_device_info acpi_device_info = {
+ .type = VM_ACPI_DEVICE_INFO_CRS,
+ .path = path,
+ };
+ int error = ioctl(ctx->fd, VM_GET_ACPI_DEVICE_INFO, &acpi_device_info);
+ if (error) {
+ return (error);
+ }
+
+ /* allocate buffer for CRS */
+ crs->Pointer = malloc(acpi_device_info.buffer_length);
+ if (crs->Pointer == NULL) {
+ return (ENOMEM);
+ }
+ crs->Length = acpi_device_info.buffer_length;
+
+ /* get CRS data */
+ acpi_device_info.buffer = crs->Pointer;
+ acpi_device_info.buffer_length = crs->Length;
+ error = ioctl(ctx->fd, VM_GET_ACPI_DEVICE_INFO, &acpi_device_info);
+ if (error) {
+ free(crs->Pointer);
+ crs->Length = 0;
+ }
+
+ return (error);
+}
+
uint64_t *
vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv,
int *ret_entries)
@@ -1684,14 +1789,15 @@
VM_SET_CAPABILITY, VM_GET_CAPABILITY, VM_BIND_PPTDEV,
VM_UNBIND_PPTDEV, VM_MAP_PPTDEV_MMIO, VM_PPTDEV_MSI,
VM_PPTDEV_MSIX, VM_UNMAP_PPTDEV_MMIO, VM_PPTDEV_DISABLE_MSIX,
- VM_INJECT_NMI, VM_STATS, VM_STAT_DESC,
- VM_SET_X2APIC_STATE, VM_GET_X2APIC_STATE,
+ VM_GET_MEMORY_REGION_INFO, VM_MODIFY_SLAT, VM_INJECT_NMI, VM_STATS,
+ VM_STAT_DESC, VM_SET_X2APIC_STATE, VM_GET_X2APIC_STATE,
VM_GET_HPET_CAPABILITIES, VM_GET_GPA_PMAP, VM_GLA2GPA,
VM_GLA2GPA_NOFAULT,
VM_ACTIVATE_CPU, VM_GET_CPUS, VM_SUSPEND_CPU, VM_RESUME_CPU,
VM_SET_INTINFO, VM_GET_INTINFO,
VM_RTC_WRITE, VM_RTC_READ, VM_RTC_SETTIME, VM_RTC_GETTIME,
- VM_RESTART_INSTRUCTION, VM_SET_TOPOLOGY, VM_GET_TOPOLOGY };
+ VM_RESTART_INSTRUCTION, VM_SET_TOPOLOGY, VM_GET_TOPOLOGY,
+ VM_GET_ACPI_DEVICE_INFO };
if (len == NULL) {
cmds = malloc(sizeof(vm_ioctl_cmds));
diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h
--- a/sys/amd64/include/vmm.h
+++ b/sys/amd64/include/vmm.h
@@ -236,6 +236,10 @@
void vm_free_memseg(struct vm *vm, int ident);
int vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa);
int vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len);
+int vm_wire_gpa(struct vm *const vm, const vm_paddr_t gpa,
+ const vm_paddr_t len);
+int vm_unwire_gpa(struct vm *const vm, const vm_paddr_t gpa,
+ const vm_paddr_t len);
int vm_assign_pptdev(struct vm *vm, int bus, int slot, int func);
int vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func);
@@ -741,6 +745,16 @@
} u;
};
+enum vm_acpi_device_info_type {
+ VM_ACPI_DEVICE_INFO_CRS,
+};
+
+enum vm_memory_region_type {
+ MEMORY_REGION_INTEL_GSM,
+ MEMORY_REGION_INTEL_OPREGION,
+ MEMORY_REGION_TPM_CONTROL_ADDRESS,
+};
+
/* APIs to inject faults into the guest */
void vm_inject_fault(void *vm, int vcpuid, int vector, int errcode_valid,
int errcode);
diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -146,6 +146,32 @@
size_t len;
};
+struct vm_memory_region_info {
+ vm_paddr_t base;
+ vm_paddr_t size;
+ enum vm_memory_region_type type;
+};
+
+#ifdef _KERNEL
+extern vm_paddr_t intel_graphics_stolen_base;
+extern vm_paddr_t intel_graphics_stolen_size;
+#endif
+
+/* second level address translation */
+enum slat_op_type {
+ VM_MAP_MMIO,
+ VM_UNMAP_MMIO,
+ VM_WIRE_GPA,
+ VM_UNWIRE_GPA
+};
+
+struct vm_slat_op {
+ vm_paddr_t gpa;
+ vm_paddr_t len;
+ vm_paddr_t hpa;
+ enum slat_op_type type;
+};
+
struct vm_pptdev_msi {
int vcpu;
int bus;
@@ -256,6 +282,13 @@
};
_Static_assert(sizeof(struct vm_readwrite_kernemu_device) == 24, "ABI");
+struct vm_acpi_device_info {
+ const char *path;
+ void *buffer;
+ size_t buffer_length;
+ enum vm_acpi_device_info_type type;
+};
+
enum {
/* general routines */
IOCNUM_ABIVERS = 0,
@@ -309,6 +342,8 @@
IOCNUM_PPTDEV_MSIX = 44,
IOCNUM_PPTDEV_DISABLE_MSIX = 45,
IOCNUM_UNMAP_PPTDEV_MMIO = 46,
+ IOCNUM_GET_MEMORY_REGION_INFO = 47,
+ IOCNUM_MODIFY_SLAT = 48,
/* statistics */
IOCNUM_VM_STATS = 50,
@@ -341,6 +376,9 @@
IOCNUM_RTC_SETTIME = 102,
IOCNUM_RTC_GETTIME = 103,
+ /* ACPI */
+ IOCNUM_GET_ACPI_DEVICE_INFO = 110,
+
/* checkpoint */
IOCNUM_SNAPSHOT_REQ = 113,
@@ -427,6 +465,10 @@
_IOW('v', IOCNUM_PPTDEV_DISABLE_MSIX, struct vm_pptdev)
#define VM_UNMAP_PPTDEV_MMIO \
_IOW('v', IOCNUM_UNMAP_PPTDEV_MMIO, struct vm_pptdev_mmio)
+#define VM_GET_MEMORY_REGION_INFO \
+ _IOWR('v', IOCNUM_GET_MEMORY_REGION_INFO, struct vm_memory_region_info)
+#define VM_MODIFY_SLAT \
+ _IOW('v', IOCNUM_MODIFY_SLAT, struct vm_slat_op)
#define VM_INJECT_NMI \
_IOW('v', IOCNUM_INJECT_NMI, struct vm_nmi)
#define VM_STATS \
@@ -471,6 +513,8 @@
_IOR('v', IOCNUM_RTC_GETTIME, struct vm_rtc_time)
#define VM_RESTART_INSTRUCTION \
_IOW('v', IOCNUM_RESTART_INSTRUCTION, int)
+#define VM_GET_ACPI_DEVICE_INFO \
+ _IOWR('v', IOCNUM_GET_ACPI_DEVICE_INFO, struct vm_acpi_device_info)
#define VM_SNAPSHOT_REQ \
_IOWR('v', IOCNUM_SNAPSHOT_REQ, struct vm_snapshot_meta)
#define VM_RESTORE_TIME \
diff --git a/sys/amd64/vmm/io/acpi.h b/sys/amd64/vmm/io/acpi.h
new file mode 100644
--- /dev/null
+++ b/sys/amd64/vmm/io/acpi.h
@@ -0,0 +1,19 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#pragma once
+
+#include <machine/vmm.h>
+#include <machine/vmm_dev.h>
+
+/*
+ * Executes the CRS (Current Resources) method of an ACPI device.
+ */
+int vmm_acpi_get_crs(const char *const device_path, void *const buffer,
+ size_t *const buffer_length);
+int vmm_tpm2_get_control_address(vm_paddr_t *const base,
+ vm_paddr_t *const size);
diff --git a/sys/amd64/vmm/io/acpi.c b/sys/amd64/vmm/io/acpi.c
new file mode 100644
--- /dev/null
+++ b/sys/amd64/vmm/io/acpi.c
@@ -0,0 +1,81 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/acpixf.h>
+
+#include "acpi.h"
+
+int
+vmm_acpi_get_crs(const char *const device_path, void *const buffer,
+ size_t *const buffer_length)
+{
+ if (device_path == NULL || buffer_length == NULL) {
+ return (EINVAL);
+ }
+
+ /* get device handle */
+ ACPI_HANDLE acpi_device;
+ ACPI_STRING const path = strdup(device_path, M_TEMP);
+ ACPI_STATUS status = AcpiGetHandle(NULL, path, &acpi_device);
+ if (!ACPI_SUCCESS(status)) {
+ printf("%s: failed to get handle for ACPI device \"%s\" (%x)\n",
+ __func__, device_path, status);
+ return (ENOENT);
+ }
+
+ /* get current resources */
+ ACPI_BUFFER resources = { ACPI_ALLOCATE_BUFFER };
+ status = AcpiGetCurrentResources(acpi_device, &resources);
+ if (!ACPI_SUCCESS(status)) {
+ printf(
+ "%s: failed to get current resources of ACPI device \"%s\" (%x)\n",
+ __func__, device_path, status);
+ return (ENODEV);
+ }
+
+ /* copy data to user space buffer */
+ int error = 0;
+ if (buffer == NULL) {
+ *buffer_length = resources.Length;
+ } else {
+ size_t bytes_to_write = MIN(*buffer_length, resources.Length);
+ error = copyout(resources.Pointer, buffer, bytes_to_write);
+ }
+
+ AcpiOsFree(resources.Pointer);
+
+ return (error);
+}
+
+int
+vmm_tpm2_get_control_address(vm_paddr_t *const base, vm_paddr_t *const size)
+{
+ ACPI_TABLE_HEADER *tpm_header;
+ if (!ACPI_SUCCESS(AcpiGetTable("TPM2", 1, &tpm_header))) {
+ return (ENOENT);
+ }
+
+ if (base) {
+ const ACPI_TABLE_TPM2 *const tpm_table = (ACPI_TABLE_TPM2 *)
+ tpm_header;
+ *base = tpm_table->ControlAddress;
+ }
+ if (size) {
+ *size = 0;
+ }
+
+ return (0);
+}
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -635,6 +635,20 @@
return (0);
}
+int
+vm_wire_gpa(struct vm *const vm, const vm_paddr_t gpa, const vm_paddr_t len)
+{
+ return vm_map_wire(&vm->vmspace->vm_map, gpa, gpa + len,
+ VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES);
+}
+
+int
+vm_unwire_gpa(struct vm *const vm, const vm_paddr_t gpa, const vm_paddr_t len)
+{
+ return vm_map_unwire(&vm->vmspace->vm_map, gpa, gpa + len,
+ VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES);
+}
+
/*
* Return 'true' if 'gpa' is allocated in the guest address space.
*
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -63,6 +63,7 @@
#include "vmm_lapic.h"
#include "vmm_stat.h"
#include "vmm_mem.h"
+#include "io/acpi.h"
#include "io/ppt.h"
#include "io/vatpic.h"
#include "io/vioapic.h"
@@ -366,6 +367,8 @@
struct vm_capability *vmcap;
struct vm_pptdev *pptdev;
struct vm_pptdev_mmio *pptmmio;
+ struct vm_memory_region_info *memory_region_info;
+ struct vm_slat_op *slat_op;
struct vm_pptdev_msi *pptmsi;
struct vm_pptdev_msix *pptmsix;
struct vm_nmi *vmnmi;
@@ -383,6 +386,8 @@
struct vm_memmap *mm;
struct vm_munmap *mu;
struct vm_cpu_topology *topology;
+ struct vm_acpi_device_info *acpi_device_info;
+ char acpi_device_path[NAME_MAX];
struct vm_readwrite_kernemu_device *kernemu;
uint64_t *regvals;
int *regnums;
@@ -446,6 +451,7 @@
case VM_MMAP_MEMSEG:
case VM_MUNMAP_MEMSEG:
case VM_REINIT:
+ case VM_MODIFY_SLAT:
/*
* ioctls that operate on the entire virtual machine must
* prevent all vcpus from running.
@@ -533,6 +539,39 @@
error = ppt_unmap_mmio(sc->vm, pptmmio->bus, pptmmio->slot,
pptmmio->func, pptmmio->gpa, pptmmio->len);
break;
+ case VM_GET_MEMORY_REGION_INFO:
+ memory_region_info = (struct vm_memory_region_info *)data;
+ switch (memory_region_info->type) {
+ case MEMORY_REGION_TPM_CONTROL_ADDRESS:
+ error = vmm_tpm2_get_control_address(
+ &memory_region_info->base,
+ &memory_region_info->size);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case VM_MODIFY_SLAT:
+ slat_op = (struct vm_slat_op *)data;
+ switch (slat_op->type) {
+ case VM_MAP_MMIO:
+ error = vm_map_mmio(sc->vm, slat_op->gpa, slat_op->len,
+ slat_op->hpa);
+ break;
+ case VM_UNMAP_MMIO:
+ error = vm_unmap_mmio(sc->vm, slat_op->gpa,
+ slat_op->len);
+ break;
+ case VM_WIRE_GPA:
+ error = vm_wire_gpa(sc->vm, slat_op->gpa, slat_op->len);
+ break;
+ case VM_UNWIRE_GPA:
+ error = vm_unwire_gpa(sc->vm, slat_op->gpa,
+ slat_op->len);
+ break;
+ }
+ break;
case VM_BIND_PPTDEV:
pptdev = (struct vm_pptdev *)data;
error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
@@ -863,6 +902,23 @@
&topology->threads, &topology->maxcpus);
error = 0;
break;
+ case VM_GET_ACPI_DEVICE_INFO:
+ acpi_device_info = (struct vm_acpi_device_info *)data;
+ /* copy device name into kernel space */
+ error = copyinstr(acpi_device_info->path, acpi_device_path,
+ sizeof(acpi_device_path), NULL);
+ if (error) {
+ break;
+ }
+ /* handle request */
+ switch (acpi_device_info->type) {
+ case VM_ACPI_DEVICE_INFO_CRS:
+ error = vmm_acpi_get_crs(acpi_device_path,
+ acpi_device_info->buffer,
+ &acpi_device_info->buffer_length);
+ break;
+ }
+ break;
#ifdef BHYVE_SNAPSHOT
case VM_SNAPSHOT_REQ:
snapshot_meta = (struct vm_snapshot_meta *)data;
diff --git a/sys/modules/vmm/Makefile b/sys/modules/vmm/Makefile
--- a/sys/modules/vmm/Makefile
+++ b/sys/modules/vmm/Makefile
@@ -30,6 +30,7 @@
.PATH: ${SRCTOP}/sys/amd64/vmm/io
SRCS+= iommu.c \
+ acpi.c \
ppt.c \
vatpic.c \
vatpit.c \
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -15,6 +15,7 @@
BHYVE_SYSDIR?=${SRCTOP}
SRCS= \
+ acpi_device.c \
atkbdc.c \
acpi.c \
audio.c \
@@ -64,6 +65,8 @@
smbiostbl.c \
sockstream.c \
task_switch.c \
+ tpm2_device.c \
+ tpm2_passthru.c \
uart_emul.c \
usb_emul.c \
usb_mouse.c \
diff --git a/usr.sbin/bhyve/acpi.h b/usr.sbin/bhyve/acpi.h
--- a/usr.sbin/bhyve/acpi.h
+++ b/usr.sbin/bhyve/acpi.h
@@ -31,6 +31,8 @@
#ifndef _ACPI_H_
#define _ACPI_H_
+#include "acpi_device.h"
+
#define SCI_INT 9
#define SMI_CMD 0xb2
@@ -55,6 +57,7 @@
int acpi_build(struct vmctx *ctx, int ncpu);
void acpi_raise_gpe(struct vmctx *ctx, unsigned bit);
+int acpi_tables_add_device(const struct acpi_device *const dev);
void dsdt_line(const char *fmt, ...);
void dsdt_fixed_ioport(uint16_t iobase, uint16_t length);
void dsdt_fixed_irq(uint8_t irq);
diff --git a/usr.sbin/bhyve/acpi.c b/usr.sbin/bhyve/acpi.c
--- a/usr.sbin/bhyve/acpi.c
+++ b/usr.sbin/bhyve/acpi.c
@@ -74,6 +74,7 @@
#include "bhyverun.h"
#include "acpi.h"
#include "pci_emul.h"
+#include "pci_lpc.h"
#include "vmgenc.h"
/*
@@ -101,7 +102,9 @@
#define MCFG_SIZE 0x40
#define FACS_OFFSET (MCFG_OFFSET + MCFG_SIZE)
#define FACS_SIZE 0x40
-#define DSDT_OFFSET (FACS_OFFSET + FACS_SIZE)
+#define TPM2_OFFSET (FACS_OFFSET + FACS_SIZE)
+#define TPM2_SIZE 0x80
+#define DSDT_OFFSET (TPM2_OFFSET + TPM2_SIZE)
#define BHYVE_ASL_TEMPLATE "bhyve.XXXXXXX"
#define BHYVE_ASL_SUFFIX ".aml"
@@ -139,6 +142,30 @@
#define EFFLUSH(x) \
if (fflush(x) != 0) goto err_exit;
+/*
+ * A list for additional ACPI devices like a TPM.
+ */
+struct acpi_device_list_entry {
+ SLIST_ENTRY(acpi_device_list_entry) chain;
+ const struct acpi_device *dev;
+};
+SLIST_HEAD(acpi_device_list,
+ acpi_device_list_entry) acpi_devices = SLIST_HEAD_INITIALIZER(acpi_devices);
+
+int
+acpi_tables_add_device(const struct acpi_device *const dev)
+{
+ struct acpi_device_list_entry *const entry = calloc(1, sizeof(*entry));
+ if (entry == NULL) {
+ return (ENOMEM);
+ }
+
+ entry->dev = dev;
+ SLIST_INSERT_HEAD(&acpi_devices, entry, chain);
+
+ return (0);
+}
+
static int
basl_fwrite_rsdp(FILE *fp)
{
@@ -184,15 +211,22 @@
EFPRINTF(fp, "\n");
/* Add in pointers to the MADT, FADT and HPET */
- EFPRINTF(fp, "[0004]\t\tACPI Table Address 0 : %08X\n",
+ uint32_t table = 0;
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : %08X\n", table++,
basl_acpi_base + MADT_OFFSET);
- EFPRINTF(fp, "[0004]\t\tACPI Table Address 1 : %08X\n",
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : %08X\n", table++,
basl_acpi_base + FADT_OFFSET);
- EFPRINTF(fp, "[0004]\t\tACPI Table Address 2 : %08X\n",
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : %08X\n", table++,
basl_acpi_base + HPET_OFFSET);
- EFPRINTF(fp, "[0004]\t\tACPI Table Address 3 : %08X\n",
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : %08X\n", table++,
basl_acpi_base + MCFG_OFFSET);
+ /* Add pointer for miscellaneous tables */
+ if (lpc_tpm2_in_use()) {
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : %08X\n",
+ table++, basl_acpi_base + TPM2_OFFSET);
+ }
+
EFFLUSH(fp);
return (0);
@@ -220,14 +254,21 @@
EFPRINTF(fp, "\n");
/* Add in pointers to the MADT, FADT and HPET */
- EFPRINTF(fp, "[0004]\t\tACPI Table Address 0 : 00000000%08X\n",
- basl_acpi_base + MADT_OFFSET);
- EFPRINTF(fp, "[0004]\t\tACPI Table Address 1 : 00000000%08X\n",
- basl_acpi_base + FADT_OFFSET);
- EFPRINTF(fp, "[0004]\t\tACPI Table Address 2 : 00000000%08X\n",
- basl_acpi_base + HPET_OFFSET);
- EFPRINTF(fp, "[0004]\t\tACPI Table Address 3 : 00000000%08X\n",
- basl_acpi_base + MCFG_OFFSET);
+ uint32_t table = 0;
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : 00000000%08X\n",
+ table++, basl_acpi_base + MADT_OFFSET);
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : 00000000%08X\n",
+ table++, basl_acpi_base + FADT_OFFSET);
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : 00000000%08X\n",
+ table++, basl_acpi_base + HPET_OFFSET);
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : 00000000%08X\n",
+ table++, basl_acpi_base + MCFG_OFFSET);
+
+ /* Add pointer for miscellaneous tables */
+ if (lpc_tpm2_in_use()) {
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : 00000000%08X\n",
+ table++, basl_acpi_base + TPM2_OFFSET);
+ }
EFFLUSH(fp);
@@ -647,6 +688,46 @@
return (errno);
}
+static int
+basl_fwrite_tpm2(FILE *const fp)
+{
+ if (!lpc_tpm2_in_use()) {
+ return (0);
+ }
+
+ EFPRINTF(fp, "/*\n");
+ EFPRINTF(fp, " * bhyve TPM2 template\n");
+ EFPRINTF(fp, " */\n");
+ EFPRINTF(fp, "[0004]\t\tSignature : \"TPM2\"\n");
+ EFPRINTF(fp, "[0004]\t\tTable Length : 0000004C\n");
+ EFPRINTF(fp, "[0001]\t\tRevision : 00\n");
+ EFPRINTF(fp, "[0001]\t\tChecksum : 00\n");
+ EFPRINTF(fp, "[0006]\t\tOem ID : \"BHYVE \"\n");
+ EFPRINTF(fp, "[0008]\t\tOem Table ID : \"BVTPM2 \"\n");
+ EFPRINTF(fp, "[0004]\t\tOem Revision : 00000000\n");
+
+ /* iasl will fill in the compiler ID/revision fields */
+ EFPRINTF(fp, "[0004]\t\tAsl Compiler ID : \"xxxx\"\n");
+ EFPRINTF(fp, "[0004]\t\tAsl Compiler Revision : 00000000\n");
+
+ EFPRINTF(fp, "[0002]\t\tPlatform Class : 0000\n");
+ EFPRINTF(fp, "[0002]\t\tReserved : 0000\n");
+ EFPRINTF(fp, "[0008]\t\tControl Address : %016lX\n",
+ lpc_tpm2_get_control_address());
+ EFPRINTF(fp, "[0004]\t\tStart Method : 00000007\n");
+ EFPRINTF(fp,
+ "[0012]\t\tMethod Parameters : 00 00 00 00 00 00 00 00 00 00 00 00\n");
+ EFPRINTF(fp, "[0004]\t\tMinimum Log Length : 00000000\n");
+ EFPRINTF(fp, "[0008]\t\tLog Address : 0000000000000000\n");
+
+ EFFLUSH(fp);
+
+ return (0);
+
+err_exit:
+ return (errno);
+}
+
/*
* Helper routines for writing to the DSDT from other modules.
*/
@@ -760,6 +841,11 @@
vmgenc_write_dsdt();
+ const struct acpi_device_list_entry *entry;
+ SLIST_FOREACH(entry, &acpi_devices, chain) {
+ acpi_device_write_dsdt(entry->dev);
+ }
+
dsdt_line("}");
if (dsdt_error != 0)
@@ -956,6 +1042,7 @@
{ basl_fwrite_hpet, HPET_OFFSET },
{ basl_fwrite_mcfg, MCFG_OFFSET },
{ basl_fwrite_facs, FACS_OFFSET },
+ { basl_fwrite_tpm2, TPM2_OFFSET },
{ basl_fwrite_dsdt, DSDT_OFFSET },
{ NULL }
};
diff --git a/usr.sbin/bhyve/acpi_device.h b/usr.sbin/bhyve/acpi_device.h
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/acpi_device.h
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#pragma once
+
+#include <contrib/dev/acpica/include/acpi.h>
+
+struct vmctx;
+
+struct acpi_device;
+
+/**
+ * Creates an ACPI device.
+ *
+ * @param[out] new_dev Returns the newly create ACPI device.
+ * @param[in] vm_ctx VM context the ACPI device is created in.
+ * @param[in] name Name of the ACPI device. Should always be a NULL
+ * terminated string.
+ * @param[in] hid Hardware ID of the ACPI device. Should always be a NULL
+ * terminated string.
+ */
+int acpi_device_create(struct acpi_device **const new_dev,
+ struct vmctx *const vm_ctx, const char *const name, const char *const hid);
+void acpi_device_destroy(struct acpi_device *const dev);
+
+/**
+ * @note: acpi_device_add_res_acpi_buffer doesn't ensure that no resources are
+ * added on an error condition. On error the caller should assume that
+ * the ACPI_BUFFER is partially added to the ACPI device.
+ */
+int acpi_device_add_res_acpi_buffer(struct acpi_device *const dev,
+ const ACPI_BUFFER resources);
+int acpi_device_add_res_fixed_ioport(struct acpi_device *const dev,
+ const UINT16 port, UINT8 length);
+int acpi_device_add_res_fixed_memory32(struct acpi_device *const dev,
+ const UINT8 write_protected, const UINT32 address, const UINT32 length);
+
+int acpi_device_get_physical_crs(const struct acpi_device *const dev,
+ ACPI_BUFFER *const crs);
+
+/**
+ * Maps the current resources (CRS) occupied by the ACPI device to the guest
+ * memory space.
+ */
+int acpi_device_map_crs(const struct acpi_device *const dev);
+
+void acpi_device_write_dsdt(const struct acpi_device *const dev);
diff --git a/usr.sbin/bhyve/acpi_device.c b/usr.sbin/bhyve/acpi_device.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/acpi_device.c
@@ -0,0 +1,297 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include <machine/vmm.h>
+
+#include <err.h>
+#include <errno.h>
+#include <vmmapi.h>
+
+#include "acpi.h"
+#include "acpi_device.h"
+
+/**
+ * List entry to enumerate all resources used by an ACPI device.
+ *
+ * @param chain Used to chain multiple elements together.
+ * @param type Type of the ACPI resource.
+ * @param data Data of the ACPI resource.
+ */
+struct acpi_resource_list_entry {
+ SLIST_ENTRY(acpi_resource_list_entry) chain;
+ UINT32 type;
+ ACPI_RESOURCE_DATA data;
+};
+
+/**
+ * Holds information about an ACPI device.
+ *
+ * @param vm_ctx VM context the ACPI device was created in.
+ * @param name Name of the ACPI device.
+ * @param hid Hardware ID of the ACPI device.
+ * @param crs Current resources used by the ACPI device.
+ */
+struct acpi_device {
+ struct vmctx *vm_ctx;
+ const char *name;
+ const char *hid;
+ SLIST_HEAD(acpi_resource_list, acpi_resource_list_entry) crs;
+};
+
+int
+acpi_device_create(struct acpi_device **const new_dev,
+ struct vmctx *const vm_ctx, const char *const name, const char *const hid)
+{
+ if (new_dev == NULL || vm_ctx == NULL || name == NULL || hid == NULL) {
+ return (EINVAL);
+ }
+
+ struct acpi_device *const dev = calloc(1, sizeof(*dev));
+ if (dev == NULL) {
+ return (ENOMEM);
+ }
+
+ dev->vm_ctx = vm_ctx;
+ dev->name = name;
+ dev->hid = hid;
+ SLIST_INIT(&dev->crs);
+
+ /* current resources always contain an end tag */
+ struct acpi_resource_list_entry *const crs_end_tag = calloc(1,
+ sizeof(*crs_end_tag));
+ if (crs_end_tag == NULL) {
+ acpi_device_destroy(dev);
+ return (ENOMEM);
+ }
+ crs_end_tag->type = ACPI_RESOURCE_TYPE_END_TAG;
+ SLIST_INSERT_HEAD(&dev->crs, crs_end_tag, chain);
+
+ const int error = acpi_tables_add_device(dev);
+ if (error) {
+ acpi_device_destroy(dev);
+ return (error);
+ }
+
+ *new_dev = dev;
+
+ return (0);
+}
+
+void
+acpi_device_destroy(struct acpi_device *const dev)
+{
+ if (dev == NULL) {
+ return;
+ }
+
+ struct acpi_resource_list_entry *res;
+ while (!SLIST_EMPTY(&dev->crs)) {
+ res = SLIST_FIRST(&dev->crs);
+ SLIST_REMOVE_HEAD(&dev->crs, chain);
+ free(res);
+ }
+}
+
+int
+acpi_device_add_res_acpi_buffer(struct acpi_device *const dev,
+ const ACPI_BUFFER resources)
+{
+ if (dev == NULL) {
+ return (EINVAL);
+ }
+
+ int error = 0;
+ size_t offset = 0;
+ while (offset < resources.Length) {
+ const ACPI_RESOURCE *const res =
+ (const ACPI_RESOURCE *)((UINT8 *)resources.Pointer +
+ offset);
+ switch (res->Type) {
+ case ACPI_RESOURCE_TYPE_FIXED_IO:
+ error = acpi_device_add_res_fixed_ioport(dev,
+ res->Data.FixedIo.Address,
+ res->Data.FixedIo.AddressLength);
+ break;
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+ error = acpi_device_add_res_fixed_memory32(dev,
+ res->Data.FixedMemory32.WriteProtect,
+ res->Data.FixedMemory32.Address,
+ res->Data.FixedMemory32.AddressLength);
+ break;
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ break;
+ default:
+ warnx("%s: unknown resource type %d", __func__,
+ res->Type);
+ return (ENODEV);
+ }
+ if (error) {
+ break;
+ }
+ offset += res->Length;
+ }
+
+ return (error);
+}
+
+int
+acpi_device_add_res_fixed_ioport(struct acpi_device *const dev,
+ const UINT16 port, const UINT8 length)
+{
+ if (dev == NULL) {
+ return (EINVAL);
+ }
+
+ struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
+ if (res == NULL) {
+ return (ENOMEM);
+ }
+
+ res->type = ACPI_RESOURCE_TYPE_FIXED_IO;
+ res->data.FixedIo.Address = port;
+ res->data.FixedIo.AddressLength = length;
+
+ SLIST_INSERT_HEAD(&dev->crs, res, chain);
+
+ return (0);
+}
+
+int
+acpi_device_add_res_fixed_memory32(struct acpi_device *const dev,
+ const UINT8 write_protected, const UINT32 address, const UINT32 length)
+{
+ if (dev == NULL) {
+ return (EINVAL);
+ }
+
+ struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
+ if (res == NULL) {
+ return (ENOMEM);
+ }
+
+ res->type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
+ res->data.FixedMemory32.WriteProtect = write_protected;
+ res->data.FixedMemory32.Address = address;
+ res->data.FixedMemory32.AddressLength = length;
+
+ SLIST_INSERT_HEAD(&dev->crs, res, chain);
+
+ return (0);
+}
+
+int
+acpi_device_get_physical_crs(const struct acpi_device *const dev,
+ ACPI_BUFFER *const crs)
+{
+ return vm_acpi_device_get_crs(dev->vm_ctx, dev->name, crs);
+}
+
+static int
+acpi_device_map_crs_resource(const struct acpi_device *const dev,
+ const struct acpi_resource_list_entry *const res)
+{
+ int error = 0;
+ switch (res->type) {
+ case ACPI_RESOURCE_TYPE_FIXED_IO:
+ warnx("%s: mapping IO is unsupported", __func__);
+ return (ENOTSUP);
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
+ /* get memory range */
+ const UINT32 base = rounddown2(res->data.FixedMemory32.Address,
+ PAGE_SIZE);
+ const UINT32 end = roundup2(res->data.FixedMemory32.Address +
+ res->data.FixedMemory32.AddressLength,
+ PAGE_SIZE);
+ /* map memory range */
+ error = vm_mmap_mmio(dev->vm_ctx, base, end - base, base);
+ if (error) {
+ return (error);
+ }
+ /* make memory range always visible by wiring it */
+ return vm_mwire_gpa(dev->vm_ctx, base, end - base);
+ }
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ return (0);
+ default:
+ warnx("%s: unknown resource type %d", __func__, res->type);
+ return (ENODEV);
+ }
+}
+
+int
+acpi_device_map_crs(const struct acpi_device *const dev)
+{
+ if (dev == NULL) {
+ return (EINVAL);
+ }
+
+ const struct acpi_resource_list_entry *res;
+ SLIST_FOREACH (res, &dev->crs, chain) {
+ const int error = acpi_device_map_crs_resource(dev, res);
+ if (error) {
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static void
+acpi_device_write_dsdt_crs(const struct acpi_device *const dev)
+{
+ const struct acpi_resource_list_entry *res;
+ SLIST_FOREACH (res, &dev->crs, chain) {
+ switch (res->type) {
+ case ACPI_RESOURCE_TYPE_FIXED_IO:
+ dsdt_fixed_ioport(res->data.FixedIo.Address,
+ res->data.FixedIo.AddressLength);
+ break;
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
+ dsdt_fixed_mem32(res->data.FixedMemory32.Address,
+ res->data.FixedMemory32.AddressLength);
+ break;
+ }
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ break;
+ default:
+ warnx("%s: unknown resource type %d", __func__,
+ res->type);
+ return;
+ }
+ }
+}
+
+void
+acpi_device_write_dsdt(const struct acpi_device *const dev)
+{
+ if (dev == NULL) {
+ return;
+ }
+
+ dsdt_line("");
+ dsdt_line(" Scope (\\_SB)");
+ dsdt_line(" {");
+ dsdt_line(" Device (%s)", dev->name);
+ dsdt_line(" {");
+ dsdt_line(" Name (_HID, \"%s\")", dev->hid);
+ dsdt_line(" Name (_STA, 0x0F)");
+ dsdt_line(" Name (_CRS, ResourceTemplate ()");
+ dsdt_line(" {");
+ dsdt_indent(4);
+ acpi_device_write_dsdt_crs(dev);
+ dsdt_unindent(4);
+ dsdt_line(" })");
+ dsdt_line(" }");
+ dsdt_line(" }");
+}
diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -155,6 +155,8 @@
.Ar com1
through
.Ar com4 ,
+the TPM2 module
+.Ar tpm2 ,
the boot ROM device
.Ar bootrom ,
and the debug/test device
@@ -420,6 +422,12 @@
loader variable as described in
.Xr vmm 4 .
.Pp
+TPM2 devices:
+.Bl -tag -width 10n
+.It Li passthru
+Give the guest direct access to the physical TPM2 device of the host.
+.El
+.Pp
Virtio console devices:
.Bl -tag -width 10n
.It Li port1= Ns Pa /path/to/port1.sock Ns ,anotherport= Ns Pa ...
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -1941,7 +1941,7 @@
} else {
x = *eax;
cfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE;
- cfgoff = x & PCI_REGMAX;
+ cfgoff = (x & PCI_REGMAX) & ~0x03;
cfgfunc = (x >> 8) & PCI_FUNCMAX;
cfgslot = (x >> 11) & PCI_SLOTMAX;
cfgbus = (x >> 16) & PCI_BUSMAX;
diff --git a/usr.sbin/bhyve/pci_lpc.h b/usr.sbin/bhyve/pci_lpc.h
--- a/usr.sbin/bhyve/pci_lpc.h
+++ b/usr.sbin/bhyve/pci_lpc.h
@@ -72,5 +72,7 @@
char *lpc_pirq_name(int pin);
void lpc_pirq_routed(void);
const char *lpc_bootrom(void);
+vm_paddr_t lpc_tpm2_get_control_address(void);
+int lpc_tpm2_in_use(void);
#endif
diff --git a/usr.sbin/bhyve/pci_lpc.c b/usr.sbin/bhyve/pci_lpc.c
--- a/usr.sbin/bhyve/pci_lpc.c
+++ b/usr.sbin/bhyve/pci_lpc.c
@@ -36,6 +36,7 @@
#include <machine/vmm.h>
#include <machine/vmm_snapshot.h>
+#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -50,6 +51,7 @@
#include "pci_irq.h"
#include "pci_lpc.h"
#include "pctestdev.h"
+#include "tpm2_device.h"
#include "uart_emul.h"
#define IO_ICU1 0x20
@@ -83,6 +85,9 @@
static bool pctestdev_present;
+static const char *lpc_tpm2_opts;
+static struct tpm2_device *lpc_tpm2;
+
/*
* LPC device configuration is in the following form:
* <lpc_device_name>[,<options>]
@@ -103,6 +108,21 @@
error = 0;
goto done;
}
+ if (strcasecmp(lpcdev, "tpm2") == 0) {
+ if (lpc_tpm2_opts != NULL) {
+ warnx("%s: only a single TPM allowed",
+ __func__);
+ error = EINVAL;
+ goto done;
+ }
+ lpc_tpm2_opts = str;
+ if (lpc_tpm2_opts == NULL) {
+ error = EINVAL;
+ goto done;
+ }
+ error = 0;
+ goto done;
+ }
for (unit = 0; unit < LPC_UART_NUM; unit++) {
if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) {
lpc_uart_softc[unit].opts = str;
@@ -139,6 +159,7 @@
printf("bootrom\n");
for (i = 0; i < LPC_UART_NUM; i++)
printf("%s\n", lpc_uart_names[i]);
+ printf("tpm2\n");
printf("%s\n", pctestdev_getname());
}
@@ -213,6 +234,15 @@
if (error)
return (error);
}
+ if (lpc_tpm2_opts != NULL) {
+ error = tpm2_device_create(&lpc_tpm2, ctx, lpc_tpm2_opts);
+ if (error) {
+ warnx(
+ "%s: unable to create a TPM device with opts \"%s\" (%d)",
+ __func__, lpc_tpm2_opts, error);
+ return (error);
+ }
+ }
/* COM1 and COM2 */
for (unit = 0; unit < LPC_UART_NUM; unit++) {
@@ -476,6 +506,18 @@
pci_set_cfgdata8(lpc_bridge, 0x68 + pin, pirq_read(pin + 5));
}
+vm_paddr_t
+lpc_tpm2_get_control_address(void)
+{
+ return tpm2_device_get_control_address(lpc_tpm2);
+}
+
+int
+lpc_tpm2_in_use(void)
+{
+ return (lpc_tpm2 != NULL);
+}
+
#ifdef BHYVE_SNAPSHOT
static int
pci_lpc_snapshot(struct vm_snapshot_meta *meta)
diff --git a/usr.sbin/bhyve/tpm2_device.h b/usr.sbin/bhyve/tpm2_device.h
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/tpm2_device.h
@@ -0,0 +1,23 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#pragma once
+
+#include <vmmapi.h>
+
+#include "acpi_device.h"
+
+struct tpm2_device;
+
+/* device creation and destruction */
+int tpm2_device_create(struct tpm2_device **const new_dev,
+ struct vmctx *const vm_ctx, const char *const opts);
+void tpm2_device_destroy(struct tpm2_device *const dev);
+/* device methods */
+vm_paddr_t tpm2_device_get_control_address(const struct tpm2_device *const dev);
+int tpm2_device_set_control_address(struct tpm2_device *const dev,
+ const vm_paddr_t control_address);
diff --git a/usr.sbin/bhyve/tpm2_device.c b/usr.sbin/bhyve/tpm2_device.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/tpm2_device.c
@@ -0,0 +1,134 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <machine/vmm.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <vmmapi.h>
+
+#include "acpi.h"
+#include "tpm2_device_priv.h"
+
+#define TPM2_ACPI_DEVICE_NAME "TPM"
+#define TPM2_ACPI_HARDWARE_ID "MSFT0101"
+
+SET_DECLARE(tpm2_device_emul_set, struct tpm2_device_emul);
+
+int
+tpm2_device_create(struct tpm2_device **const new_dev,
+ struct vmctx *const vm_ctx, const char *const opts)
+{
+ if (new_dev == NULL || vm_ctx == NULL) {
+ return (EINVAL);
+ }
+
+ struct tpm2_device *const dev = calloc(1, sizeof(*dev));
+ if (dev == NULL) {
+ return (ENOMEM);
+ }
+
+ int error = acpi_device_create(&dev->acpi_dev, vm_ctx,
+ TPM2_ACPI_DEVICE_NAME, TPM2_ACPI_HARDWARE_ID);
+ if (error) {
+ tpm2_device_destroy(dev);
+ return (error);
+ }
+
+ dev->control_address = 0;
+
+ struct tpm2_device_emul **ppemul;
+ SET_FOREACH(ppemul, tpm2_device_emul_set)
+ {
+ struct tpm2_device_emul *const pemul = *ppemul;
+ if (strcmp(opts, pemul->name))
+ continue;
+ dev->emul = pemul;
+ break;
+ }
+ if (dev->emul == NULL) {
+ tpm2_device_destroy(dev);
+ return (EINVAL);
+ }
+
+ if (dev->emul->init) {
+ error = dev->emul->init(dev, vm_ctx, opts);
+ if (error) {
+ tpm2_device_destroy(dev);
+ return (error);
+ }
+ }
+
+ *new_dev = dev;
+
+ return (0);
+}
+
+void
+tpm2_device_destroy(struct tpm2_device *const dev)
+{
+ if (dev == NULL) {
+ return;
+ }
+ if (dev->emul != NULL && dev->emul->deinit != NULL) {
+ dev->emul->deinit(dev);
+ }
+
+ acpi_device_destroy((struct acpi_device *)dev);
+ free(dev);
+}
+
+vm_paddr_t
+_tpm2_device_get_control_address(const struct tpm2_device *const dev)
+{
+ return (dev->control_address);
+}
+
+vm_paddr_t
+tpm2_device_get_control_address(const struct tpm2_device *const dev)
+{
+ if (dev == NULL || dev->emul == NULL) {
+ return (0);
+ }
+
+ if (dev->emul->get_control_address) {
+ return dev->emul->get_control_address(dev);
+ }
+
+ return _tpm2_device_get_control_address(dev);
+}
+
+int
+_tpm2_device_set_control_address(struct tpm2_device *const dev,
+ const vm_paddr_t control_address)
+{
+ dev->control_address = control_address;
+
+ return (0);
+}
+
+int
+tpm2_device_set_control_address(struct tpm2_device *const dev,
+ const vm_paddr_t control_address)
+{
+ if (dev == NULL || dev->emul == NULL) {
+ return (EINVAL);
+ }
+
+ if (dev->emul->set_control_address) {
+ dev->emul->set_control_address(dev, control_address);
+ }
+
+ return _tpm2_device_set_control_address(dev, control_address);
+}
diff --git a/usr.sbin/bhyve/tpm2_device_priv.h b/usr.sbin/bhyve/tpm2_device_priv.h
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/tpm2_device_priv.h
@@ -0,0 +1,49 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#pragma once
+
+#include <sys/linker_set.h>
+
+#include <vmmapi.h>
+
+#include "acpi_device.h"
+#include "tpm2_device.h"
+
+struct tpm2_device_emul {
+ const char *name;
+
+ int (*init)(struct tpm2_device *const dev, struct vmctx *const vm_ctx,
+ const char *const opts);
+ void (*deinit)(struct tpm2_device *const dev);
+ vm_paddr_t (*get_control_address)(const struct tpm2_device *const dev);
+ int (*set_control_address)(struct tpm2_device *const dev,
+ const vm_paddr_t control_address);
+};
+#define TPM2_DEVICE_EMUL_SET(x) DATA_SET(tpm2_device_emul_set, x)
+
+/**
+ * This struct represents a TPM2 device.
+ *
+ * @param acpi_dev A TPM2 device is an ACPI device.
+ * @param emul Emulation functions for different types of TPM2
+ * devices.
+ * @param control_address Control address of the TPM device.
+ * @param dev_data Device specific data for a specific TPM2 device type.
+ */
+struct tpm2_device {
+ struct acpi_device *acpi_dev;
+ struct tpm2_device_emul *emul;
+ vm_paddr_t control_address;
+ void *dev_data;
+};
+
+/* default emulation functions */
+vm_paddr_t _tpm2_device_get_control_address(
+ const struct tpm2_device *const dev);
+int _tpm2_device_set_control_address(struct tpm2_device *const dev,
+ const vm_paddr_t control_address);
diff --git a/usr.sbin/bhyve/tpm2_passthru.c b/usr.sbin/bhyve/tpm2_passthru.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/tpm2_passthru.c
@@ -0,0 +1,78 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Author: Corvin Köhne <c.koehne@beckhoff.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <machine/vmm.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <vmmapi.h>
+
+#include "acpi.h"
+#include "tpm2_device_priv.h"
+
+static int
+tpm2_passthru_device_init(struct tpm2_device *const dev,
+ struct vmctx *const vm_ctx, const char *const opts)
+{
+ ACPI_BUFFER crs;
+ int error = acpi_device_get_physical_crs(dev->acpi_dev, &crs);
+ if (error) {
+ warnx("%s: failed to get current resources of TPM2 device",
+ __func__);
+ return (error);
+ }
+ error = acpi_device_add_res_acpi_buffer(dev->acpi_dev, crs);
+ if (error) {
+ warnx("%s: failed to set current resources for TPM2 device",
+ __func__);
+ return (error);
+ }
+ /*
+ * TPM2 should use the address 0xFED40000. This address shouldn't
+ * conflict with any other device, yet. However, it could change in
+ * future. It may be a good idea to check whether we can dynamically
+ * allocate the TPM2 mmio address or not.
+ */
+ error = acpi_device_map_crs(dev->acpi_dev);
+ if (error) {
+ warnx(
+ "%s: failed to map current resources into guest memory space",
+ __func__);
+ return (error);
+ }
+
+ vm_paddr_t control_address;
+ error = vm_get_memory_region_info(vm_ctx, &control_address, NULL,
+ MEMORY_REGION_TPM_CONTROL_ADDRESS);
+ if (error) {
+ warnx("%s: failed to get control address of TPM2 device",
+ __func__);
+ return (error);
+ }
+
+ error = _tpm2_device_set_control_address(dev, control_address);
+ if (error) {
+ warnx("%s: unable to set control address of TPM2 device",
+ __func__);
+ return (error);
+ }
+
+ return (0);
+}
+
+struct tpm2_device_emul tpm2_passthru_device_emul = {
+ .name = "passthru",
+ .init = tpm2_passthru_device_init,
+};
+TPM2_DEVICE_EMUL_SET(tpm2_passthru_device_emul);
diff --git a/usr.sbin/bhyvectl/Makefile b/usr.sbin/bhyvectl/Makefile
--- a/usr.sbin/bhyvectl/Makefile
+++ b/usr.sbin/bhyvectl/Makefile
@@ -14,6 +14,7 @@
WARNS?= 3
+CFLAGS+= -I${SRCTOP}/sys
CFLAGS+= -I${SRCTOP}/sys/amd64/vmm
.if ${MK_BHYVE_SNAPSHOT} != "no"
diff --git a/usr.sbin/bhyveload/Makefile b/usr.sbin/bhyveload/Makefile
--- a/usr.sbin/bhyveload/Makefile
+++ b/usr.sbin/bhyveload/Makefile
@@ -10,5 +10,6 @@
WARNS?= 3
CFLAGS+=-I${SRCTOP}/stand/userboot
+CFLAGS+= -I${SRCTOP}/sys
.include <bsd.prog.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Apr 20, 8:10 PM (18 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31861822
Default Alt Text
D32961.id98414.diff (41 KB)
Attached To
Mode
D32961: bhyve: enable TPM2 passthrough
Attached
Detach File
Event Timeline
Log In to Comment