git: b9ef152bec6c - main - vmm: Merge vmm_dev.c
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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], ®val[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 ***