git: b9ef152bec6c - main - vmm: Merge vmm_dev.c

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 26 Aug 2024 18:58:33 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=b9ef152bec6cff4cd82b68921f631bd6efb24ae6

commit b9ef152bec6cff4cd82b68921f631bd6efb24ae6
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-08-26 18:41:39 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-08-26 18:41:39 +0000

    vmm: Merge vmm_dev.c
    
    This file contains the vmm device file implementation.  Most of this
    code is not machine-dependent and so shouldn't be duplicated this way.
    Move most of it into a generic dev/vmm/vmm_dev.c.  This will make it
    easier to introduce a cdev-based interface for VM creation, which in
    turn makes it possible to implement support for running bhyve as an
    unprivileged user.
    
    Machine-dependent ioctls continue to be handled in machine-dependent
    code.  To make the split a bit easier to handle, introduce a pair of
    tables which define MI and MD ioctls.  Each table entry can set flags
    which determine which locks need to be held in order to execute the
    handler.  vmmdev_ioctl() now looks up the ioctl in one of the tables,
    acquires locks and either handles the ioctl directly or calls
    vmmdev_machdep_ioctl() to handle it.
    
    No functional change intended.  There is a lot of churn in this change
    but the underlying logic in the ioctl handlers is the same.  For now,
    vmm_dev.h is still mostly separate, even though some parts could be
    merged in principle.  This would involve changing include paths for
    userspace, though.
    
    Reviewed by:    corvink, jhb
    Differential Revision:  https://reviews.freebsd.org/D46431
---
 sys/amd64/include/vmm_dev.h      |    5 -
 sys/amd64/vmm/vmm.c              |    2 +-
 sys/amd64/vmm/vmm_dev.c          | 1452 --------------------------------------
 sys/amd64/vmm/vmm_dev_machdep.c  |  526 ++++++++++++++
 sys/arm64/include/vmm_dev.h      |    5 -
 sys/arm64/vmm/vmm.c              |    2 +-
 sys/arm64/vmm/vmm_dev_machdep.c  |  137 ++++
 sys/conf/files.arm64             |    1 +
 sys/{arm64 => dev}/vmm/vmm_dev.c |  443 ++++++------
 sys/dev/vmm/vmm_dev.h            |   57 ++
 sys/modules/vmm/Makefile         |    1 +
 11 files changed, 924 insertions(+), 1707 deletions(-)

diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
index aa265315f15e..a007ce5515a5 100644
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -31,11 +31,6 @@
 
 struct vm_snapshot_meta;
 
-#ifdef _KERNEL
-void	vmmdev_init(void);
-int	vmmdev_cleanup(void);
-#endif
-
 struct vm_memmap {
 	vm_paddr_t	gpa;
 	int		segid;		/* memory segment */
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index d0259b3b125f..20006e63cfeb 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -67,10 +67,10 @@
 #include <x86/ifunc.h>
 
 #include <machine/vmm.h>
-#include <machine/vmm_dev.h>
 #include <machine/vmm_instruction_emul.h>
 #include <machine/vmm_snapshot.h>
 
+#include <dev/vmm/vmm_dev.h>
 #include <dev/vmm/vmm_ktr.h>
 
 #include "vmm_ioport.h"
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
deleted file mode 100644
index 9acbfbb454e0..000000000000
--- a/sys/amd64/vmm/vmm_dev.c
+++ /dev/null
@@ -1,1452 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2011 NetApp, Inc.
- * 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 NETAPP, INC ``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 NETAPP, INC 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 "opt_bhyve_snapshot.h"
-
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/jail.h>
-#include <sys/queue.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/malloc.h>
-#include <sys/conf.h>
-#include <sys/sysctl.h>
-#include <sys/libkern.h>
-#include <sys/ioccom.h>
-#include <sys/mman.h>
-#include <sys/uio.h>
-#include <sys/proc.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <vm/vm_map.h>
-#include <vm/vm_object.h>
-
-#include <machine/vmparam.h>
-#include <machine/vmm.h>
-#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"
-#include "vmm_mem.h"
-#include "io/ppt.h"
-#include "io/vatpic.h"
-#include "io/vioapic.h"
-#include "io/vhpet.h"
-#include "io/vrtc.h"
-
-#ifdef COMPAT_FREEBSD13
-struct vm_stats_old {
-	int		cpuid;				/* in */
-	int		num_entries;			/* out */
-	struct timeval	tv;
-	uint64_t	statbuf[MAX_VM_STATS];
-};
-
-#define	VM_STATS_OLD \
-	_IOWR('v', IOCNUM_VM_STATS, struct vm_stats_old)
-
-struct vm_snapshot_meta_old {
-	void *ctx;			/* unused */
-	void *dev_data;
-	const char *dev_name;      /* identify userspace devices */
-	enum snapshot_req dev_req; /* identify kernel structs */
-
-	struct vm_snapshot_buffer buffer;
-
-	enum vm_snapshot_op op;
-};
-
-#define VM_SNAPSHOT_REQ_OLD \
-	_IOWR('v', IOCNUM_SNAPSHOT_REQ, struct vm_snapshot_meta_old)
-
-struct vm_exit_ipi_13 {
-	uint32_t	mode;
-	uint8_t		vector;
-	__BITSET_DEFINE(, 256) dmask;
-};
-
-struct vm_exit_13 {
-	uint32_t	exitcode;
-	int32_t		inst_length;
-	uint64_t	rip;
-	uint64_t	u[120 / sizeof(uint64_t)];
-};
-
-struct vm_run_13 {
-	int		cpuid;
-	struct vm_exit_13 vm_exit;
-};
-
-#define	VM_RUN_13 \
-	_IOWR('v', IOCNUM_RUN, struct vm_run_13)
-
-#endif /* COMPAT_FREEBSD13 */
-
-struct devmem_softc {
-	int	segid;
-	char	*name;
-	struct cdev *cdev;
-	struct vmmdev_softc *sc;
-	SLIST_ENTRY(devmem_softc) link;
-};
-
-struct vmmdev_softc {
-	struct vm	*vm;		/* vm instance cookie */
-	struct cdev	*cdev;
-	struct ucred	*ucred;
-	SLIST_ENTRY(vmmdev_softc) link;
-	SLIST_HEAD(, devmem_softc) devmem;
-	int		flags;
-};
-#define	VSC_LINKED		0x01
-
-static SLIST_HEAD(, vmmdev_softc) head;
-
-static unsigned pr_allow_flag;
-static struct mtx vmmdev_mtx;
-MTX_SYSINIT(vmmdev_mtx, &vmmdev_mtx, "vmm device mutex", MTX_DEF);
-
-static MALLOC_DEFINE(M_VMMDEV, "vmmdev", "vmmdev");
-
-SYSCTL_DECL(_hw_vmm);
-
-static int vmm_priv_check(struct ucred *ucred);
-static int devmem_create_cdev(const char *vmname, int id, char *devmem);
-static void devmem_destroy(void *arg);
-
-static int
-vmm_priv_check(struct ucred *ucred)
-{
-
-	if (jailed(ucred) &&
-	    !(ucred->cr_prison->pr_allow & pr_allow_flag))
-		return (EPERM);
-
-	return (0);
-}
-
-static int
-vcpu_lock_one(struct vcpu *vcpu)
-{
-	return (vcpu_set_state(vcpu, VCPU_FROZEN, true));
-}
-
-static void
-vcpu_unlock_one(struct vcpu *vcpu)
-{
-	enum vcpu_state state;
-
-	state = vcpu_get_state(vcpu, NULL);
-	if (state != VCPU_FROZEN) {
-		panic("vcpu %s(%d) has invalid state %d",
-		    vm_name(vcpu_vm(vcpu)), vcpu_vcpuid(vcpu), state);
-	}
-
-	vcpu_set_state(vcpu, VCPU_IDLE, false);
-}
-
-static int
-vcpu_lock_all(struct vmmdev_softc *sc)
-{
-	struct vcpu *vcpu;
-	int error;
-	uint16_t i, j, maxcpus;
-
-	error = 0;
-	vm_slock_vcpus(sc->vm);
-	maxcpus = vm_get_maxcpus(sc->vm);
-	for (i = 0; i < maxcpus; i++) {
-		vcpu = vm_vcpu(sc->vm, i);
-		if (vcpu == NULL)
-			continue;
-		error = vcpu_lock_one(vcpu);
-		if (error)
-			break;
-	}
-
-	if (error) {
-		for (j = 0; j < i; j++) {
-			vcpu = vm_vcpu(sc->vm, j);
-			if (vcpu == NULL)
-				continue;
-			vcpu_unlock_one(vcpu);
-		}
-		vm_unlock_vcpus(sc->vm);
-	}
-
-	return (error);
-}
-
-static void
-vcpu_unlock_all(struct vmmdev_softc *sc)
-{
-	struct vcpu *vcpu;
-	uint16_t i, maxcpus;
-
-	maxcpus = vm_get_maxcpus(sc->vm);
-	for (i = 0; i < maxcpus; i++) {
-		vcpu = vm_vcpu(sc->vm, i);
-		if (vcpu == NULL)
-			continue;
-		vcpu_unlock_one(vcpu);
-	}
-	vm_unlock_vcpus(sc->vm);
-}
-
-static struct vmmdev_softc *
-vmmdev_lookup(const char *name)
-{
-	struct vmmdev_softc *sc;
-
-	mtx_assert(&vmmdev_mtx, MA_OWNED);
-
-	SLIST_FOREACH(sc, &head, link) {
-		if (strcmp(name, vm_name(sc->vm)) == 0)
-			break;
-	}
-
-	if (sc == NULL)
-		return (NULL);
-
-	if (cr_cansee(curthread->td_ucred, sc->ucred))
-		return (NULL);
-
-	return (sc);
-}
-
-static struct vmmdev_softc *
-vmmdev_lookup2(struct cdev *cdev)
-{
-
-	return (cdev->si_drv1);
-}
-
-static int
-vmmdev_rw(struct cdev *cdev, struct uio *uio, int flags)
-{
-	int error, off, c, prot;
-	vm_paddr_t gpa, maxaddr;
-	void *hpa, *cookie;
-	struct vmmdev_softc *sc;
-
-	error = vmm_priv_check(curthread->td_ucred);
-	if (error)
-		return (error);
-
-	sc = vmmdev_lookup2(cdev);
-	if (sc == NULL)
-		return (ENXIO);
-
-	/*
-	 * Get a read lock on the guest memory map.
-	 */
-	vm_slock_memsegs(sc->vm);
-
-	prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ);
-	maxaddr = vmm_sysmem_maxaddr(sc->vm);
-	while (uio->uio_resid > 0 && error == 0) {
-		gpa = uio->uio_offset;
-		off = gpa & PAGE_MASK;
-		c = min(uio->uio_resid, PAGE_SIZE - off);
-
-		/*
-		 * The VM has a hole in its physical memory map. If we want to
-		 * use 'dd' to inspect memory beyond the hole we need to
-		 * provide bogus data for memory that lies in the hole.
-		 *
-		 * Since this device does not support lseek(2), dd(1) will
-		 * read(2) blocks of data to simulate the lseek(2).
-		 */
-		hpa = vm_gpa_hold_global(sc->vm, gpa, c, prot, &cookie);
-		if (hpa == NULL) {
-			if (uio->uio_rw == UIO_READ && gpa < maxaddr)
-				error = uiomove(__DECONST(void *, zero_region),
-				    c, uio);
-			else
-				error = EFAULT;
-		} else {
-			error = uiomove(hpa, c, uio);
-			vm_gpa_release(cookie);
-		}
-	}
-	vm_unlock_memsegs(sc->vm);
-	return (error);
-}
-
-CTASSERT(sizeof(((struct vm_memseg *)0)->name) >= VM_MAX_SUFFIXLEN + 1);
-
-static int
-get_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg, size_t len)
-{
-	struct devmem_softc *dsc;
-	int error;
-	bool sysmem;
-
-	error = vm_get_memseg(sc->vm, mseg->segid, &mseg->len, &sysmem, NULL);
-	if (error || mseg->len == 0)
-		return (error);
-
-	if (!sysmem) {
-		SLIST_FOREACH(dsc, &sc->devmem, link) {
-			if (dsc->segid == mseg->segid)
-				break;
-		}
-		KASSERT(dsc != NULL, ("%s: devmem segment %d not found",
-		    __func__, mseg->segid));
-		error = copystr(dsc->name, mseg->name, len, NULL);
-	} else {
-		bzero(mseg->name, len);
-	}
-
-	return (error);
-}
-
-static int
-alloc_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg, size_t len)
-{
-	char *name;
-	int error;
-	bool sysmem;
-
-	error = 0;
-	name = NULL;
-	sysmem = true;
-
-	/*
-	 * The allocation is lengthened by 1 to hold a terminating NUL.  It'll
-	 * by stripped off when devfs processes the full string.
-	 */
-	if (VM_MEMSEG_NAME(mseg)) {
-		sysmem = false;
-		name = malloc(len, M_VMMDEV, M_WAITOK);
-		error = copystr(mseg->name, name, len, NULL);
-		if (error)
-			goto done;
-	}
-
-	error = vm_alloc_memseg(sc->vm, mseg->segid, mseg->len, sysmem);
-	if (error)
-		goto done;
-
-	if (VM_MEMSEG_NAME(mseg)) {
-		error = devmem_create_cdev(vm_name(sc->vm), mseg->segid, name);
-		if (error)
-			vm_free_memseg(sc->vm, mseg->segid);
-		else
-			name = NULL;	/* freed when 'cdev' is destroyed */
-	}
-done:
-	free(name, M_VMMDEV);
-	return (error);
-}
-
-static int
-vm_get_register_set(struct vcpu *vcpu, unsigned int count, int *regnum,
-    uint64_t *regval)
-{
-	int error, i;
-
-	error = 0;
-	for (i = 0; i < count; i++) {
-		error = vm_get_register(vcpu, regnum[i], &regval[i]);
-		if (error)
-			break;
-	}
-	return (error);
-}
-
-static int
-vm_set_register_set(struct vcpu *vcpu, unsigned int count, int *regnum,
-    uint64_t *regval)
-{
-	int error, i;
-
-	error = 0;
-	for (i = 0; i < count; i++) {
-		error = vm_set_register(vcpu, regnum[i], regval[i]);
-		if (error)
-			break;
-	}
-	return (error);
-}
-
-static int
-vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
-	     struct thread *td)
-{
-	int error, vcpuid, size;
-	cpuset_t *cpuset;
-	struct vmmdev_softc *sc;
-	struct vcpu *vcpu;
-	struct vm_register *vmreg;
-	struct vm_seg_desc *vmsegdesc;
-	struct vm_register_set *vmregset;
-	struct vm_run *vmrun;
-#ifdef COMPAT_FREEBSD13
-	struct vm_run_13 *vmrun_13;
-#endif
-	struct vm_exception *vmexc;
-	struct vm_lapic_irq *vmirq;
-	struct vm_lapic_msi *vmmsi;
-	struct vm_ioapic_irq *ioapic_irq;
-	struct vm_isa_irq *isa_irq;
-	struct vm_isa_irq_trigger *isa_irq_trigger;
-	struct vm_capability *vmcap;
-	struct vm_pptdev *pptdev;
-	struct vm_pptdev_mmio *pptmmio;
-	struct vm_pptdev_msi *pptmsi;
-	struct vm_pptdev_msix *pptmsix;
-#ifdef COMPAT_FREEBSD13
-	struct vm_stats_old *vmstats_old;
-#endif
-	struct vm_stats *vmstats;
-	struct vm_stat_desc *statdesc;
-	struct vm_x2apic *x2apic;
-	struct vm_gpa_pte *gpapte;
-	struct vm_suspend *vmsuspend;
-	struct vm_gla2gpa *gg;
-	struct vm_cpuset *vm_cpuset;
-	struct vm_intinfo *vmii;
-	struct vm_rtc_time *rtctime;
-	struct vm_rtc_data *rtcdata;
-	struct vm_memmap *mm;
-	struct vm_munmap *mu;
-	struct vm_cpu_topology *topology;
-	struct vm_readwrite_kernemu_device *kernemu;
-	uint64_t *regvals;
-	int *regnums;
-	enum { NONE, SINGLE, ALL } vcpus_locked;
-	bool memsegs_locked;
-#ifdef BHYVE_SNAPSHOT
-	struct vm_snapshot_meta *snapshot_meta;
-#ifdef COMPAT_FREEBSD13
-	struct vm_snapshot_meta_old *snapshot_old;
-#endif
-#endif
-
-	error = vmm_priv_check(curthread->td_ucred);
-	if (error)
-		return (error);
-
-	sc = vmmdev_lookup2(cdev);
-	if (sc == NULL)
-		return (ENXIO);
-
-	vcpuid = -1;
-	vcpu = NULL;
-	vcpus_locked = NONE;
-	memsegs_locked = false;
-
-	/*
-	 * For VMM ioctls that operate on a single vCPU, lookup the
-	 * vcpu.  For VMM ioctls which require one or more vCPUs to
-	 * not be running, lock necessary vCPUs.
-	 *
-	 * XXX fragile, handle with care
-	 * Most of these assume that the first field of the ioctl data
-	 * is the vcpuid.
-	 */
-	switch (cmd) {
-	case VM_RUN:
-#ifdef COMPAT_FREEBSD13
-	case VM_RUN_13:
-#endif
-	case VM_GET_REGISTER:
-	case VM_SET_REGISTER:
-	case VM_GET_SEGMENT_DESCRIPTOR:
-	case VM_SET_SEGMENT_DESCRIPTOR:
-	case VM_GET_REGISTER_SET:
-	case VM_SET_REGISTER_SET:
-	case VM_INJECT_EXCEPTION:
-	case VM_GET_CAPABILITY:
-	case VM_SET_CAPABILITY:
-	case VM_SET_X2APIC_STATE:
-	case VM_GLA2GPA:
-	case VM_GLA2GPA_NOFAULT:
-	case VM_ACTIVATE_CPU:
-	case VM_SET_INTINFO:
-	case VM_GET_INTINFO:
-	case VM_RESTART_INSTRUCTION:
-	case VM_GET_KERNEMU_DEV:
-	case VM_SET_KERNEMU_DEV:
-		/*
-		 * ioctls that can operate only on vcpus that are not running.
-		 */
-		vcpuid = *(int *)data;
-		vcpu = vm_alloc_vcpu(sc->vm, vcpuid);
-		if (vcpu == NULL) {
-			error = EINVAL;
-			goto done;
-		}
-		error = vcpu_lock_one(vcpu);
-		if (error)
-			goto done;
-		vcpus_locked = SINGLE;
-		break;
-
-#ifdef COMPAT_FREEBSD12
-	case VM_ALLOC_MEMSEG_FBSD12:
-#endif
-	case VM_ALLOC_MEMSEG:
-	case VM_BIND_PPTDEV:
-	case VM_UNBIND_PPTDEV:
-	case VM_MMAP_MEMSEG:
-	case VM_MUNMAP_MEMSEG:
-	case VM_REINIT:
-		/*
-		 * ioctls that modify the memory map must lock memory
-		 * segments exclusively.
-		 */
-		vm_xlock_memsegs(sc->vm);
-		memsegs_locked = true;
-		/* FALLTHROUGH */
-	case VM_MAP_PPTDEV_MMIO:
-	case VM_UNMAP_PPTDEV_MMIO:
-#ifdef BHYVE_SNAPSHOT
-	case VM_SNAPSHOT_REQ:
-#ifdef COMPAT_FREEBSD13
-	case VM_SNAPSHOT_REQ_OLD:
-#endif
-	case VM_RESTORE_TIME:
-#endif
-		/*
-		 * ioctls that operate on the entire virtual machine must
-		 * prevent all vcpus from running.
-		 */
-		error = vcpu_lock_all(sc);
-		if (error)
-			goto done;
-		vcpus_locked = ALL;
-		break;
-
-#ifdef COMPAT_FREEBSD12
-	case VM_GET_MEMSEG_FBSD12:
-#endif
-	case VM_GET_MEMSEG:
-	case VM_MMAP_GETNEXT:
-		/*
-		 * Lock the memory map while it is being inspected.
-		 */
-		vm_slock_memsegs(sc->vm);
-		memsegs_locked = true;
-		break;
-
-#ifdef COMPAT_FREEBSD13
-	case VM_STATS_OLD:
-#endif
-	case VM_STATS:
-	case VM_INJECT_NMI:
-	case VM_LAPIC_IRQ:
-	case VM_GET_X2APIC_STATE:
-		/*
-		 * These do not need the vCPU locked but do operate on
-		 * a specific vCPU.
-		 */
-		vcpuid = *(int *)data;
-		vcpu = vm_alloc_vcpu(sc->vm, vcpuid);
-		if (vcpu == NULL) {
-			error = EINVAL;
-			goto done;
-		}
-		break;
-
-	case VM_LAPIC_LOCAL_IRQ:
-	case VM_SUSPEND_CPU:
-	case VM_RESUME_CPU:
-		/*
-		 * These can either operate on all CPUs via a vcpuid of
-		 * -1 or on a specific vCPU.
-		 */
-		vcpuid = *(int *)data;
-		if (vcpuid == -1)
-			break;
-		vcpu = vm_alloc_vcpu(sc->vm, vcpuid);
-		if (vcpu == NULL) {
-			error = EINVAL;
-			goto done;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	switch (cmd) {
-	case VM_RUN: {
-		struct vm_exit *vme;
-
-		vmrun = (struct vm_run *)data;
-		vme = vm_exitinfo(vcpu);
-
-		error = vm_run(vcpu);
-		if (error != 0)
-			break;
-
-		error = copyout(vme, vmrun->vm_exit, sizeof(*vme));
-		if (error != 0)
-			break;
-		if (vme->exitcode == VM_EXITCODE_IPI) {
-			error = copyout(vm_exitinfo_cpuset(vcpu),
-			    vmrun->cpuset,
-			    min(vmrun->cpusetsize, sizeof(cpuset_t)));
-			if (error != 0)
-				break;
-			if (sizeof(cpuset_t) < vmrun->cpusetsize) {
-				uint8_t *p;
-
-				p = (uint8_t *)vmrun->cpuset +
-				    sizeof(cpuset_t);
-				while (p < (uint8_t *)vmrun->cpuset +
-				    vmrun->cpusetsize) {
-					if (subyte(p++, 0) != 0) {
-						error = EFAULT;
-						break;
-					}
-				}
-			}
-		}
-		break;
-	}
-#ifdef COMPAT_FREEBSD13
-	case VM_RUN_13: {
-		struct vm_exit *vme;
-		struct vm_exit_13 *vme_13;
-
-		vmrun_13 = (struct vm_run_13 *)data;
-		vme_13 = &vmrun_13->vm_exit;
-		vme = vm_exitinfo(vcpu);
-
-		error = vm_run(vcpu);
-		if (error == 0) {
-			vme_13->exitcode = vme->exitcode;
-			vme_13->inst_length = vme->inst_length;
-			vme_13->rip = vme->rip;
-			memcpy(vme_13->u, &vme->u, sizeof(vme_13->u));
-			if (vme->exitcode == VM_EXITCODE_IPI) {
-				struct vm_exit_ipi_13 *ipi;
-				cpuset_t *dmask;
-				int cpu;
-
-				dmask = vm_exitinfo_cpuset(vcpu);
-				ipi = (struct vm_exit_ipi_13 *)&vme_13->u[0];
-				BIT_ZERO(256, &ipi->dmask);
-				CPU_FOREACH_ISSET(cpu, dmask) {
-					if (cpu >= 256)
-						break;
-					BIT_SET(256, cpu, &ipi->dmask);
-				}
-			}
-		}
-		break;
-	}
-#endif
-	case VM_SUSPEND:
-		vmsuspend = (struct vm_suspend *)data;
-		error = vm_suspend(sc->vm, vmsuspend->how);
-		break;
-	case VM_REINIT:
-		error = vm_reinit(sc->vm);
-		break;
-	case VM_STAT_DESC: {
-		statdesc = (struct vm_stat_desc *)data;
-		error = vmm_stat_desc_copy(statdesc->index,
-					statdesc->desc, sizeof(statdesc->desc));
-		break;
-	}
-#ifdef COMPAT_FREEBSD13
-	case VM_STATS_OLD:
-		vmstats_old = (struct vm_stats_old *)data;
-		getmicrotime(&vmstats_old->tv);
-		error = vmm_stat_copy(vcpu, 0,
-				      nitems(vmstats_old->statbuf),
-				      &vmstats_old->num_entries,
-				      vmstats_old->statbuf);
-		break;
-#endif
-	case VM_STATS: {
-		vmstats = (struct vm_stats *)data;
-		getmicrotime(&vmstats->tv);
-		error = vmm_stat_copy(vcpu, vmstats->index,
-				      nitems(vmstats->statbuf),
-				      &vmstats->num_entries, vmstats->statbuf);
-		break;
-	}
-	case VM_PPTDEV_MSI:
-		pptmsi = (struct vm_pptdev_msi *)data;
-		error = ppt_setup_msi(sc->vm,
-				      pptmsi->bus, pptmsi->slot, pptmsi->func,
-				      pptmsi->addr, pptmsi->msg,
-				      pptmsi->numvec);
-		break;
-	case VM_PPTDEV_MSIX:
-		pptmsix = (struct vm_pptdev_msix *)data;
-		error = ppt_setup_msix(sc->vm,
-				       pptmsix->bus, pptmsix->slot, 
-				       pptmsix->func, pptmsix->idx,
-				       pptmsix->addr, pptmsix->msg,
-				       pptmsix->vector_control);
-		break;
-	case VM_PPTDEV_DISABLE_MSIX:
-		pptdev = (struct vm_pptdev *)data;
-		error = ppt_disable_msix(sc->vm, pptdev->bus, pptdev->slot,
-					 pptdev->func);
-		break;
-	case VM_MAP_PPTDEV_MMIO:
-		pptmmio = (struct vm_pptdev_mmio *)data;
-		error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot,
-				     pptmmio->func, pptmmio->gpa, pptmmio->len,
-				     pptmmio->hpa);
-		break;
-	case VM_UNMAP_PPTDEV_MMIO:
-		pptmmio = (struct vm_pptdev_mmio *)data;
-		error = ppt_unmap_mmio(sc->vm, pptmmio->bus, pptmmio->slot,
-				       pptmmio->func, pptmmio->gpa, pptmmio->len);
-		break;
-	case VM_BIND_PPTDEV:
-		pptdev = (struct vm_pptdev *)data;
-		error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
-					 pptdev->func);
-		break;
-	case VM_UNBIND_PPTDEV:
-		pptdev = (struct vm_pptdev *)data;
-		error = vm_unassign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
-					   pptdev->func);
-		break;
-	case VM_INJECT_EXCEPTION:
-		vmexc = (struct vm_exception *)data;
-		error = vm_inject_exception(vcpu,
-		    vmexc->vector, vmexc->error_code_valid, vmexc->error_code,
-		    vmexc->restart_instruction);
-		break;
-	case VM_INJECT_NMI:
-		error = vm_inject_nmi(vcpu);
-		break;
-	case VM_LAPIC_IRQ:
-		vmirq = (struct vm_lapic_irq *)data;
-		error = lapic_intr_edge(vcpu, vmirq->vector);
-		break;
-	case VM_LAPIC_LOCAL_IRQ:
-		vmirq = (struct vm_lapic_irq *)data;
-		error = lapic_set_local_intr(sc->vm, vcpu, vmirq->vector);
-		break;
-	case VM_LAPIC_MSI:
-		vmmsi = (struct vm_lapic_msi *)data;
-		error = lapic_intr_msi(sc->vm, vmmsi->addr, vmmsi->msg);
-		break;
-	case VM_IOAPIC_ASSERT_IRQ:
-		ioapic_irq = (struct vm_ioapic_irq *)data;
-		error = vioapic_assert_irq(sc->vm, ioapic_irq->irq);
-		break;
-	case VM_IOAPIC_DEASSERT_IRQ:
-		ioapic_irq = (struct vm_ioapic_irq *)data;
-		error = vioapic_deassert_irq(sc->vm, ioapic_irq->irq);
-		break;
-	case VM_IOAPIC_PULSE_IRQ:
-		ioapic_irq = (struct vm_ioapic_irq *)data;
-		error = vioapic_pulse_irq(sc->vm, ioapic_irq->irq);
-		break;
-	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(vcpu, kernemu->gpa,
-			    kernemu->value, size, &arg);
-		else
-			error = mread(vcpu, 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);
-		if (error == 0 && isa_irq->ioapic_irq != -1)
-			error = vioapic_assert_irq(sc->vm,
-			    isa_irq->ioapic_irq);
-		break;
-	case VM_ISA_DEASSERT_IRQ:
-		isa_irq = (struct vm_isa_irq *)data;
-		error = vatpic_deassert_irq(sc->vm, isa_irq->atpic_irq);
-		if (error == 0 && isa_irq->ioapic_irq != -1)
-			error = vioapic_deassert_irq(sc->vm,
-			    isa_irq->ioapic_irq);
-		break;
-	case VM_ISA_PULSE_IRQ:
-		isa_irq = (struct vm_isa_irq *)data;
-		error = vatpic_pulse_irq(sc->vm, isa_irq->atpic_irq);
-		if (error == 0 && isa_irq->ioapic_irq != -1)
-			error = vioapic_pulse_irq(sc->vm, isa_irq->ioapic_irq);
-		break;
-	case VM_ISA_SET_IRQ_TRIGGER:
-		isa_irq_trigger = (struct vm_isa_irq_trigger *)data;
-		error = vatpic_set_irq_trigger(sc->vm,
-		    isa_irq_trigger->atpic_irq, isa_irq_trigger->trigger);
-		break;
-	case VM_MMAP_GETNEXT:
-		mm = (struct vm_memmap *)data;
-		error = vm_mmap_getnext(sc->vm, &mm->gpa, &mm->segid,
-		    &mm->segoff, &mm->len, &mm->prot, &mm->flags);
-		break;
-	case VM_MMAP_MEMSEG:
-		mm = (struct vm_memmap *)data;
-		error = vm_mmap_memseg(sc->vm, mm->gpa, mm->segid, mm->segoff,
-		    mm->len, mm->prot, mm->flags);
-		break;
-	case VM_MUNMAP_MEMSEG:
-		mu = (struct vm_munmap *)data;
-		error = vm_munmap_memseg(sc->vm, mu->gpa, mu->len);
-		break;
-#ifdef COMPAT_FREEBSD12
-	case VM_ALLOC_MEMSEG_FBSD12:
-		error = alloc_memseg(sc, (struct vm_memseg *)data,
-		    sizeof(((struct vm_memseg_fbsd12 *)0)->name));
-		break;
-#endif
-	case VM_ALLOC_MEMSEG:
-		error = alloc_memseg(sc, (struct vm_memseg *)data,
-		    sizeof(((struct vm_memseg *)0)->name));
-		break;
-#ifdef COMPAT_FREEBSD12
-	case VM_GET_MEMSEG_FBSD12:
-		error = get_memseg(sc, (struct vm_memseg *)data,
-		    sizeof(((struct vm_memseg_fbsd12 *)0)->name));
-		break;
-#endif
-	case VM_GET_MEMSEG:
-		error = get_memseg(sc, (struct vm_memseg *)data,
-		    sizeof(((struct vm_memseg *)0)->name));
-		break;
-	case VM_GET_REGISTER:
-		vmreg = (struct vm_register *)data;
-		error = vm_get_register(vcpu, vmreg->regnum, &vmreg->regval);
-		break;
-	case VM_SET_REGISTER:
-		vmreg = (struct vm_register *)data;
-		error = vm_set_register(vcpu, vmreg->regnum, vmreg->regval);
-		break;
-	case VM_SET_SEGMENT_DESCRIPTOR:
-		vmsegdesc = (struct vm_seg_desc *)data;
-		error = vm_set_seg_desc(vcpu,
-					vmsegdesc->regnum,
-					&vmsegdesc->desc);
-		break;
-	case VM_GET_SEGMENT_DESCRIPTOR:
-		vmsegdesc = (struct vm_seg_desc *)data;
-		error = vm_get_seg_desc(vcpu,
-					vmsegdesc->regnum,
-					&vmsegdesc->desc);
-		break;
-	case VM_GET_REGISTER_SET:
-		vmregset = (struct vm_register_set *)data;
-		if (vmregset->count > VM_REG_LAST) {
-			error = EINVAL;
-			break;
-		}
*** 1979 LINES SKIPPED ***