Author: cem
Date: Fri May 15 15:54:22 2020
New Revision: 361082
URL: https://svnweb.freebsd.org/changeset/base/361082

Log:
  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

Added:
  head/usr.sbin/bhyve/kernemu_dev.c   (contents, props changed)
  head/usr.sbin/bhyve/kernemu_dev.h   (contents, props changed)
Modified:
  head/lib/libvmmapi/vmmapi.c
  head/lib/libvmmapi/vmmapi.h
  head/sys/amd64/include/vmm_dev.h
  head/sys/amd64/vmm/vmm_dev.c
  head/usr.sbin/bhyve/Makefile
  head/usr.sbin/bhyve/bhyverun.c

Modified: head/lib/libvmmapi/vmmapi.c
==============================================================================
--- head/lib/libvmmapi/vmmapi.c Fri May 15 14:06:37 2020        (r361081)
+++ head/lib/libvmmapi/vmmapi.c Fri May 15 15:54:22 2020        (r361082)
@@ -799,6 +799,25 @@ vm_ioapic_pincount(struct vmctx *ctx, int *pincount)
 }
 
 int
+vm_readwrite_kernemu_device(struct vmctx *ctx, int vcpu, vm_paddr_t gpa,
+    bool write, int size, uint64_t *value)
+{
+       struct vm_readwrite_kernemu_device irp = {
+               .vcpuid = vcpu,
+               .access_width = fls(size) - 1,
+               .gpa = gpa,
+               .value = write ? *value : ~0ul,
+       };
+       long cmd = (write ? VM_SET_KERNEMU_DEV : VM_GET_KERNEMU_DEV);
+       int rc;
+
+       rc = ioctl(ctx->fd, cmd, &irp);
+       if (rc == 0 && !write)
+               *value = irp.value;
+       return (rc);
+}
+
+int
 vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq)
 {
        struct vm_isa_irq isa_irq;
@@ -1615,6 +1634,7 @@ vm_get_ioctls(size_t *len)
            VM_MMAP_GETNEXT, VM_SET_REGISTER, VM_GET_REGISTER,
            VM_SET_SEGMENT_DESCRIPTOR, VM_GET_SEGMENT_DESCRIPTOR,
            VM_SET_REGISTER_SET, VM_GET_REGISTER_SET,
+           VM_SET_KERNEMU_DEV, VM_GET_KERNEMU_DEV,
            VM_INJECT_EXCEPTION, VM_LAPIC_IRQ, VM_LAPIC_LOCAL_IRQ,
            VM_LAPIC_MSI, VM_IOAPIC_ASSERT_IRQ, VM_IOAPIC_DEASSERT_IRQ,
            VM_IOAPIC_PULSE_IRQ, VM_IOAPIC_PINCOUNT, VM_ISA_ASSERT_IRQ,

Modified: head/lib/libvmmapi/vmmapi.h
==============================================================================
--- head/lib/libvmmapi/vmmapi.h Fri May 15 14:06:37 2020        (r361081)
+++ head/lib/libvmmapi/vmmapi.h Fri May 15 15:54:22 2020        (r361082)
@@ -35,6 +35,8 @@
 #include <sys/cpuset.h>
 #include <machine/vmm_dev.h>
 
+#include <stdbool.h>
+
 /*
  * API version for out-of-tree consumers like grub-bhyve for making compile
  * time decisions.
@@ -156,6 +158,8 @@ int vm_ioapic_assert_irq(struct vmctx *ctx, int irq);
 int    vm_ioapic_deassert_irq(struct vmctx *ctx, int irq);
 int    vm_ioapic_pulse_irq(struct vmctx *ctx, int irq);
 int    vm_ioapic_pincount(struct vmctx *ctx, int *pincount);
+int    vm_readwrite_kernemu_device(struct vmctx *ctx, int vcpu,
+           vm_paddr_t gpa, bool write, int size, uint64_t *value);
 int    vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
 int    vm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
 int    vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);

Modified: head/sys/amd64/include/vmm_dev.h
==============================================================================
--- head/sys/amd64/include/vmm_dev.h    Fri May 15 14:06:37 2020        
(r361081)
+++ head/sys/amd64/include/vmm_dev.h    Fri May 15 15:54:22 2020        
(r361082)
@@ -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            \

Modified: head/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- head/sys/amd64/vmm/vmm_dev.c        Fri May 15 14:06:37 2020        
(r361081)
+++ head/sys/amd64/vmm/vmm_dev.c        Fri May 15 15:54:22 2020        
(r361082)
@@ -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 da
        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 da
        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);

Modified: head/usr.sbin/bhyve/Makefile
==============================================================================
--- head/usr.sbin/bhyve/Makefile        Fri May 15 14:06:37 2020        
(r361081)
+++ head/usr.sbin/bhyve/Makefile        Fri May 15 15:54:22 2020        
(r361082)
@@ -31,6 +31,7 @@ SRCS= \
        hda_codec.c             \
        inout.c                 \
        ioapic.c                \
+       kernemu_dev.c           \
        mem.c                   \
        mevent.c                \
        mptbl.c                 \
@@ -75,6 +76,8 @@ SRCS= \
 .if ${MK_BHYVE_SNAPSHOT} != "no"
 SRCS+= snapshot.c
 .endif
+
+CFLAGS.kernemu_dev.c+= -I${SRCTOP}/sys/amd64
 
 .PATH:  ${BHYVE_SYSDIR}/sys/amd64/vmm
 SRCS+= vmm_instruction_emul.c

Modified: head/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- head/usr.sbin/bhyve/bhyverun.c      Fri May 15 14:06:37 2020        
(r361081)
+++ head/usr.sbin/bhyve/bhyverun.c      Fri May 15 15:54:22 2020        
(r361082)
@@ -92,6 +92,7 @@ __FBSDID("$FreeBSD$");
 #include "fwctl.h"
 #include "gdb.h"
 #include "ioapic.h"
+#include "kernemu_dev.h"
 #include "mem.h"
 #include "mevent.h"
 #include "mptbl.h"
@@ -1268,6 +1269,7 @@ main(int argc, char *argv[])
 
        init_mem();
        init_inout();
+       kernemu_dev_init();
        init_bootrom(ctx);
        atkbdc_init(ctx);
        pci_irq_init(ctx);

Added: head/usr.sbin/bhyve/kernemu_dev.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.sbin/bhyve/kernemu_dev.c   Fri May 15 15:54:22 2020        
(r361082)
@@ -0,0 +1,98 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2020 Conrad Meyer <c...@freebsd.org>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/tree.h>
+
+#include <amd64/include/vmm.h>
+#include <x86/include/apicreg.h>
+struct vm;
+struct vm_hpet_cap;
+#include <vmm/io/vioapic.h>
+#include <vmm/io/vhpet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <vmmapi.h>
+
+#include "kernemu_dev.h"
+#include "mem.h"
+
+static int
+apic_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr, int size,
+    uint64_t *val, void *arg1 __unused, long arg2 __unused)
+{
+       if (vm_readwrite_kernemu_device(ctx, vcpu, addr, (dir == MEM_F_WRITE),
+           size, val) != 0)
+               return (errno);
+       return (0);
+}
+
+static struct mem_range lapic_mmio = {
+       .name = "kern-lapic-mmio",
+       .base = DEFAULT_APIC_BASE,
+       .size = PAGE_SIZE,
+       .flags = MEM_F_RW | MEM_F_IMMUTABLE,
+       .handler = apic_handler,
+
+};
+static struct mem_range ioapic_mmio = {
+       .name = "kern-ioapic-mmio",
+       .base = VIOAPIC_BASE,
+       .size = VIOAPIC_SIZE,
+       .flags = MEM_F_RW | MEM_F_IMMUTABLE,
+       .handler = apic_handler,
+};
+static struct mem_range hpet_mmio = {
+       .name = "kern-hpet-mmio",
+       .base = VHPET_BASE,
+       .size = VHPET_SIZE,
+       .flags = MEM_F_RW | MEM_F_IMMUTABLE,
+       .handler = apic_handler,
+};
+
+void
+kernemu_dev_init(void)
+{
+       int rc;
+
+       rc = register_mem(&lapic_mmio);
+       if (rc != 0)
+               errc(4, rc, "register_mem: LAPIC (0x%08x)",
+                   (unsigned)lapic_mmio.base);
+       rc = register_mem(&ioapic_mmio);
+       if (rc != 0)
+               errc(4, rc, "register_mem: IOAPIC (0x%08x)",
+                   (unsigned)ioapic_mmio.base);
+       rc = register_mem(&hpet_mmio);
+       if (rc != 0)
+               errc(4, rc, "register_mem: HPET (0x%08x)",
+                   (unsigned)hpet_mmio.base);
+}

Added: head/usr.sbin/bhyve/kernemu_dev.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.sbin/bhyve/kernemu_dev.h   Fri May 15 15:54:22 2020        
(r361082)
@@ -0,0 +1,32 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2020 Conrad Meyer <c...@freebsd.org>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#pragma once
+
+void kernemu_dev_init(void);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to