diff options
author | Conrad Meyer <cem@FreeBSD.org> | 2020-05-15 15:54:22 +0000 |
---|---|---|
committer | Conrad Meyer <cem@FreeBSD.org> | 2020-05-15 15:54:22 +0000 |
commit | 8a68ae80f67adcb35e6f9712384a3da6dca26de2 (patch) | |
tree | 759861464c206768f72c1a5c998d28a4a180bfb2 /sys/amd64 | |
parent | e240ce42bf1fe705bbd2ba78a4761eee675fb786 (diff) | |
download | src-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.h | 17 | ||||
-rw-r--r-- | sys/amd64/vmm/vmm_dev.c | 37 |
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); |