aboutsummaryrefslogtreecommitdiff
path: root/sys/amd64
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2020-05-15 15:54:22 +0000
committerConrad Meyer <cem@FreeBSD.org>2020-05-15 15:54:22 +0000
commit8a68ae80f67adcb35e6f9712384a3da6dca26de2 (patch)
tree759861464c206768f72c1a5c998d28a4a180bfb2 /sys/amd64
parente240ce42bf1fe705bbd2ba78a4761eee675fb786 (diff)
downloadsrc-8a68ae80f67adcb35e6f9712384a3da6dca26de2.tar.gz
src-8a68ae80f67adcb35e6f9712384a3da6dca26de2.zip
vmm(4), bhyve(8): Expose kernel-emulated special devices to userspace
Expose the special kernel LAPIC, IOAPIC, and HPET devices to userspace for use in, e.g., fallback instruction emulation (when userspace has a newer instruction decode/emulation layer than the kernel vmm(4)). Plumb the ioctl through libvmmapi and register the memory ranges in bhyve(8). Reviewed by: grehan Differential Revision: https://reviews.freebsd.org/D24525
Notes
Notes: svn path=/head/; revision=361082
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/include/vmm_dev.h17
-rw-r--r--sys/amd64/vmm/vmm_dev.c37
2 files changed, 54 insertions, 0 deletions
diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
index 21775b70718e..250eef9e7afc 100644
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -235,6 +235,15 @@ struct vm_cpu_topology {
uint16_t maxcpus;
};
+struct vm_readwrite_kernemu_device {
+ int vcpuid;
+ unsigned access_width : 3;
+ unsigned _unused : 29;
+ uint64_t gpa;
+ uint64_t value;
+};
+_Static_assert(sizeof(struct vm_readwrite_kernemu_device) == 24, "ABI");
+
enum {
/* general routines */
IOCNUM_ABIVERS = 0,
@@ -262,6 +271,8 @@ enum {
IOCNUM_GET_SEGMENT_DESCRIPTOR = 23,
IOCNUM_SET_REGISTER_SET = 24,
IOCNUM_GET_REGISTER_SET = 25,
+ IOCNUM_GET_KERNEMU_DEV = 26,
+ IOCNUM_SET_KERNEMU_DEV = 27,
/* interrupt injection */
IOCNUM_GET_INTINFO = 28,
@@ -347,6 +358,12 @@ enum {
_IOW('v', IOCNUM_SET_REGISTER_SET, struct vm_register_set)
#define VM_GET_REGISTER_SET \
_IOWR('v', IOCNUM_GET_REGISTER_SET, struct vm_register_set)
+#define VM_SET_KERNEMU_DEV \
+ _IOW('v', IOCNUM_SET_KERNEMU_DEV, \
+ struct vm_readwrite_kernemu_device)
+#define VM_GET_KERNEMU_DEV \
+ _IOWR('v', IOCNUM_GET_KERNEMU_DEV, \
+ struct vm_readwrite_kernemu_device)
#define VM_INJECT_EXCEPTION \
_IOW('v', IOCNUM_INJECT_EXCEPTION, struct vm_exception)
#define VM_LAPIC_IRQ \
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
index e47b7081b795..27849d883527 100644
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <machine/vmm_dev.h>
#include <machine/vmm_instruction_emul.h>
#include <machine/vmm_snapshot.h>
+#include <x86/apicreg.h>
#include "vmm_lapic.h"
#include "vmm_stat.h"
@@ -382,6 +383,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
struct vm_rtc_data *rtcdata;
struct vm_memmap *mm;
struct vm_cpu_topology *topology;
+ struct vm_readwrite_kernemu_device *kernemu;
uint64_t *regvals;
int *regnums;
#ifdef BHYVE_SNAPSHOT
@@ -561,6 +563,41 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
case VM_IOAPIC_PINCOUNT:
*(int *)data = vioapic_pincount(sc->vm);
break;
+ case VM_SET_KERNEMU_DEV:
+ case VM_GET_KERNEMU_DEV: {
+ mem_region_write_t mwrite;
+ mem_region_read_t mread;
+ bool arg;
+
+ kernemu = (void *)data;
+
+ if (kernemu->access_width > 0)
+ size = (1u << kernemu->access_width);
+ else
+ size = 1;
+
+ if (kernemu->gpa >= DEFAULT_APIC_BASE && kernemu->gpa < DEFAULT_APIC_BASE + PAGE_SIZE) {
+ mread = lapic_mmio_read;
+ mwrite = lapic_mmio_write;
+ } else if (kernemu->gpa >= VIOAPIC_BASE && kernemu->gpa < VIOAPIC_BASE + VIOAPIC_SIZE) {
+ mread = vioapic_mmio_read;
+ mwrite = vioapic_mmio_write;
+ } else if (kernemu->gpa >= VHPET_BASE && kernemu->gpa < VHPET_BASE + VHPET_SIZE) {
+ mread = vhpet_mmio_read;
+ mwrite = vhpet_mmio_write;
+ } else {
+ error = EINVAL;
+ break;
+ }
+
+ if (cmd == VM_SET_KERNEMU_DEV)
+ error = mwrite(sc->vm, kernemu->vcpuid, kernemu->gpa,
+ kernemu->value, size, &arg);
+ else
+ error = mread(sc->vm, kernemu->vcpuid, kernemu->gpa,
+ &kernemu->value, size, &arg);
+ break;
+ }
case VM_ISA_ASSERT_IRQ:
isa_irq = (struct vm_isa_irq *)data;
error = vatpic_assert_irq(sc->vm, isa_irq->atpic_irq);