xref: /illumos-gate/usr/src/uts/intel/io/vmm/vmm_sol_dev.c (revision 54cf5b63)
1bf21cd93STycho Nightingale /*
2bf21cd93STycho Nightingale  * This file and its contents are supplied under the terms of the
3bf21cd93STycho Nightingale  * Common Development and Distribution License ("CDDL"), version 1.0.
4bf21cd93STycho Nightingale  * You may only use this file in accordance with the terms of version
5bf21cd93STycho Nightingale  * 1.0 of the CDDL.
6bf21cd93STycho Nightingale  *
7bf21cd93STycho Nightingale  * A full copy of the text of the CDDL should have accompanied this
8bf21cd93STycho Nightingale  * source.  A copy of the CDDL is also available via the Internet at
9bf21cd93STycho Nightingale  * http://www.illumos.org/license/CDDL.
10bf21cd93STycho Nightingale  */
111fa07ac7SMike Zeller /* This file is dual-licensed; see usr/src/contrib/bhyve/LICENSE */
12bf21cd93STycho Nightingale 
13bf21cd93STycho Nightingale /*
14bf21cd93STycho Nightingale  * Copyright 2015 Pluribus Networks Inc.
154c87aefeSPatrick Mooney  * Copyright 2019 Joyent, Inc.
168e3a263eSAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
173d097f7dSPatrick Mooney  * Copyright 2022 Oxide Computer Company
18bf21cd93STycho Nightingale  */
19bf21cd93STycho Nightingale 
20bf21cd93STycho Nightingale #include <sys/types.h>
21bf21cd93STycho Nightingale #include <sys/conf.h>
22bf21cd93STycho Nightingale #include <sys/cpuvar.h>
23bf21cd93STycho Nightingale #include <sys/ioccom.h>
24bf21cd93STycho Nightingale #include <sys/stat.h>
25bf21cd93STycho Nightingale #include <sys/vmsystm.h>
26bf21cd93STycho Nightingale #include <sys/ddi.h>
274c87aefeSPatrick Mooney #include <sys/mkdev.h>
28bf21cd93STycho Nightingale #include <sys/sunddi.h>
29bf21cd93STycho Nightingale #include <sys/fs/dv_node.h>
304c87aefeSPatrick Mooney #include <sys/cpuset.h>
314c87aefeSPatrick Mooney #include <sys/id_space.h>
324c87aefeSPatrick Mooney #include <sys/fs/sdev_plugin.h>
334c87aefeSPatrick Mooney #include <sys/smt.h>
3459460b49SPatrick Mooney #include <sys/kstat.h>
354c87aefeSPatrick Mooney 
364c87aefeSPatrick Mooney #include <sys/kernel.h>
374c87aefeSPatrick Mooney #include <sys/hma.h>
384c87aefeSPatrick Mooney #include <sys/x86_archext.h>
39154972afSPatrick Mooney #include <x86/apicreg.h>
40bf21cd93STycho Nightingale 
41bf21cd93STycho Nightingale #include <sys/vmm.h>
42b58b977eSPatrick Mooney #include <sys/vmm_kernel.h>
43bf21cd93STycho Nightingale #include <sys/vmm_instruction_emul.h>
44bf21cd93STycho Nightingale #include <sys/vmm_dev.h>
45bf21cd93STycho Nightingale #include <sys/vmm_impl.h>
464c87aefeSPatrick Mooney #include <sys/vmm_drv.h>
47cf409e3fSDan Cross #include <sys/vmm_vm.h>
48b57f5d3eSPatrick Mooney #include <sys/vmm_reservoir.h>
49bf21cd93STycho Nightingale 
50bf21cd93STycho Nightingale #include <vm/seg_dev.h>
51bf21cd93STycho Nightingale 
52eb9a1df2SHans Rosenfeld #include "io/ppt.h"
53bf21cd93STycho Nightingale #include "io/vatpic.h"
54bf21cd93STycho Nightingale #include "io/vioapic.h"
554c87aefeSPatrick Mooney #include "io/vrtc.h"
564c87aefeSPatrick Mooney #include "io/vhpet.h"
570e1453c3SPatrick Mooney #include "io/vpmtmr.h"
58bf21cd93STycho Nightingale #include "vmm_lapic.h"
594c87aefeSPatrick Mooney #include "vmm_stat.h"
604c87aefeSPatrick Mooney #include "vmm_util.h"
61bf21cd93STycho Nightingale 
624c87aefeSPatrick Mooney /*
634c87aefeSPatrick Mooney  * Locking details:
644c87aefeSPatrick Mooney  *
654c87aefeSPatrick Mooney  * Driver-wide data (vmmdev_*) , including HMA and sdev registration, is
664c87aefeSPatrick Mooney  * protected by vmmdev_mtx.  The list of vmm_softc_t instances and related data
674c87aefeSPatrick Mooney  * (vmm_*) are protected by vmm_mtx.  Actions requiring both locks must acquire
684c87aefeSPatrick Mooney  * vmmdev_mtx before vmm_mtx.  The sdev plugin functions must not attempt to
694c87aefeSPatrick Mooney  * acquire vmmdev_mtx, as they could deadlock with plugin unregistration.
704c87aefeSPatrick Mooney  */
71bf21cd93STycho Nightingale 
724c87aefeSPatrick Mooney static kmutex_t		vmmdev_mtx;
734c87aefeSPatrick Mooney static dev_info_t	*vmmdev_dip;
744c87aefeSPatrick Mooney static hma_reg_t	*vmmdev_hma_reg;
758e3a263eSAndy Fiddaman static uint_t		vmmdev_hma_ref;
764c87aefeSPatrick Mooney static sdev_plugin_hdl_t vmmdev_sdev_hdl;
77bf21cd93STycho Nightingale 
784c87aefeSPatrick Mooney static kmutex_t		vmm_mtx;
794c87aefeSPatrick Mooney static list_t		vmm_list;
804c87aefeSPatrick Mooney static list_t		vmm_destroy_list;
814c87aefeSPatrick Mooney static id_space_t	*vmm_minors;
824c87aefeSPatrick Mooney static void		*vmm_statep;
83bf21cd93STycho Nightingale 
84d515dd77SPatrick Mooney /* temporary safety switch */
85d515dd77SPatrick Mooney int		vmm_allow_state_writes;
86d515dd77SPatrick Mooney 
874c87aefeSPatrick Mooney static const char *vmmdev_hvm_name = "bhyve";
88bf21cd93STycho Nightingale 
894c87aefeSPatrick Mooney /* For sdev plugin (/dev) */
904c87aefeSPatrick Mooney #define	VMM_SDEV_ROOT "/dev/vmm"
914c87aefeSPatrick Mooney 
927c8c0b82SPatrick Mooney /* From uts/intel/io/vmm/intel/vmx.c */
934c87aefeSPatrick Mooney extern int vmx_x86_supported(const char **);
944c87aefeSPatrick Mooney 
954c87aefeSPatrick Mooney /* Holds and hooks from drivers external to vmm */
964c87aefeSPatrick Mooney struct vmm_hold {
974c87aefeSPatrick Mooney 	list_node_t	vmh_node;
984c87aefeSPatrick Mooney 	vmm_softc_t	*vmh_sc;
994c87aefeSPatrick Mooney 	boolean_t	vmh_release_req;
1004c87aefeSPatrick Mooney 	uint_t		vmh_ioport_hook_cnt;
1014c87aefeSPatrick Mooney };
1024c87aefeSPatrick Mooney 
1034c87aefeSPatrick Mooney struct vmm_lease {
1044c87aefeSPatrick Mooney 	list_node_t		vml_node;
1054c87aefeSPatrick Mooney 	struct vm		*vml_vm;
1060153d828SPatrick Mooney 	vm_client_t		*vml_vmclient;
1074c87aefeSPatrick Mooney 	boolean_t		vml_expired;
1086703a0e8SPatrick Mooney 	boolean_t		vml_break_deferred;
1094c87aefeSPatrick Mooney 	boolean_t		(*vml_expire_func)(void *);
1104c87aefeSPatrick Mooney 	void			*vml_expire_arg;
1114c87aefeSPatrick Mooney 	struct vmm_hold		*vml_hold;
1124c87aefeSPatrick Mooney };
1134c87aefeSPatrick Mooney 
1144c87aefeSPatrick Mooney static int vmm_drv_block_hook(vmm_softc_t *, boolean_t);
1156703a0e8SPatrick Mooney static void vmm_lease_block(vmm_softc_t *);
1166703a0e8SPatrick Mooney static void vmm_lease_unblock(vmm_softc_t *);
11759460b49SPatrick Mooney static int vmm_kstat_alloc(vmm_softc_t *, minor_t, const cred_t *);
11859460b49SPatrick Mooney static void vmm_kstat_init(vmm_softc_t *);
11959460b49SPatrick Mooney static void vmm_kstat_fini(vmm_softc_t *);
1204c87aefeSPatrick Mooney 
1213d066281SPatrick Mooney /*
1223d066281SPatrick Mooney  * The 'devmem' hack:
1233d066281SPatrick Mooney  *
1243d066281SPatrick Mooney  * On native FreeBSD, bhyve consumers are allowed to create 'devmem' segments
1253d066281SPatrick Mooney  * in the vm which appear with their own name related to the vm under /dev.
1263d066281SPatrick Mooney  * Since this would be a hassle from an sdev perspective and would require a
1273d066281SPatrick Mooney  * new cdev interface (or complicate the existing one), we choose to implement
1283d066281SPatrick Mooney  * this in a different manner.  Direct access to the underlying vm memory
1293d066281SPatrick Mooney  * segments is exposed by placing them in a range of offsets beyond the normal
1303d066281SPatrick Mooney  * guest memory space.  Userspace can query the appropriate offset to mmap()
1313d066281SPatrick Mooney  * for a given segment-id with the VM_DEVMEM_GETOFFSET ioctl.
1323d066281SPatrick Mooney  */
1333d066281SPatrick Mooney 
1343d066281SPatrick Mooney static vmm_devmem_entry_t *
1353d066281SPatrick Mooney vmmdev_devmem_find(vmm_softc_t *sc, int segid)
1363d066281SPatrick Mooney {
1373d066281SPatrick Mooney 	vmm_devmem_entry_t *ent = NULL;
1383d066281SPatrick Mooney 	list_t *dl = &sc->vmm_devmem_list;
1393d066281SPatrick Mooney 
1403d066281SPatrick Mooney 	for (ent = list_head(dl); ent != NULL; ent = list_next(dl, ent)) {
1413d066281SPatrick Mooney 		if (ent->vde_segid == segid) {
1423d066281SPatrick Mooney 			return (ent);
1433d066281SPatrick Mooney 		}
1443d066281SPatrick Mooney 	}
1453d066281SPatrick Mooney 	return (NULL);
1463d066281SPatrick Mooney }
1473d066281SPatrick Mooney 
1484c87aefeSPatrick Mooney static int
1494c87aefeSPatrick Mooney vmmdev_get_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
150bf21cd93STycho Nightingale {
1514c87aefeSPatrick Mooney 	int error;
1524c87aefeSPatrick Mooney 	bool sysmem;
153bf21cd93STycho Nightingale 
1544c87aefeSPatrick Mooney 	error = vm_get_memseg(sc->vmm_vm, mseg->segid, &mseg->len, &sysmem,
1554c87aefeSPatrick Mooney 	    NULL);
1564c87aefeSPatrick Mooney 	if (error || mseg->len == 0)
1574c87aefeSPatrick Mooney 		return (error);
158bf21cd93STycho Nightingale 
1594c87aefeSPatrick Mooney 	if (!sysmem) {
1604c87aefeSPatrick Mooney 		vmm_devmem_entry_t *de;
161bf21cd93STycho Nightingale 
1623d066281SPatrick Mooney 		de = vmmdev_devmem_find(sc, mseg->segid);
1634c87aefeSPatrick Mooney 		if (de != NULL) {
1644c87aefeSPatrick Mooney 			(void) strlcpy(mseg->name, de->vde_name,
1654c87aefeSPatrick Mooney 			    sizeof (mseg->name));
1664c87aefeSPatrick Mooney 		}
1674c87aefeSPatrick Mooney 	} else {
1684c87aefeSPatrick Mooney 		bzero(mseg->name, sizeof (mseg->name));
169bf21cd93STycho Nightingale 	}
1704c87aefeSPatrick Mooney 
1714c87aefeSPatrick Mooney 	return (error);
172bf21cd93STycho Nightingale }
173bf21cd93STycho Nightingale 
1744c87aefeSPatrick Mooney static int
1754c87aefeSPatrick Mooney vmmdev_devmem_create(vmm_softc_t *sc, struct vm_memseg *mseg, const char *name)
1764c87aefeSPatrick Mooney {
1774c87aefeSPatrick Mooney 	off_t map_offset;
1784c87aefeSPatrick Mooney 	vmm_devmem_entry_t *entry;
179bf21cd93STycho Nightingale 
1804c87aefeSPatrick Mooney 	if (list_is_empty(&sc->vmm_devmem_list)) {
1814c87aefeSPatrick Mooney 		map_offset = VM_DEVMEM_START;
1824c87aefeSPatrick Mooney 	} else {
1834c87aefeSPatrick Mooney 		entry = list_tail(&sc->vmm_devmem_list);
1844c87aefeSPatrick Mooney 		map_offset = entry->vde_off + entry->vde_len;
1854c87aefeSPatrick Mooney 		if (map_offset < entry->vde_off) {
1864c87aefeSPatrick Mooney 			/* Do not tolerate overflow */
1874c87aefeSPatrick Mooney 			return (ERANGE);
1884c87aefeSPatrick Mooney 		}
189bf21cd93STycho Nightingale 		/*
1904c87aefeSPatrick Mooney 		 * XXXJOY: We could choose to search the list for duplicate
1914c87aefeSPatrick Mooney 		 * names and toss an error.  Since we're using the offset
1924c87aefeSPatrick Mooney 		 * method for now, it does not make much of a difference.
193bf21cd93STycho Nightingale 		 */
194bf21cd93STycho Nightingale 	}
1954c87aefeSPatrick Mooney 
1964c87aefeSPatrick Mooney 	entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
1974c87aefeSPatrick Mooney 	entry->vde_segid = mseg->segid;
1984c87aefeSPatrick Mooney 	entry->vde_len = mseg->len;
1994c87aefeSPatrick Mooney 	entry->vde_off = map_offset;
2004c87aefeSPatrick Mooney 	(void) strlcpy(entry->vde_name, name, sizeof (entry->vde_name));
2014c87aefeSPatrick Mooney 	list_insert_tail(&sc->vmm_devmem_list, entry);
2024c87aefeSPatrick Mooney 
2034c87aefeSPatrick Mooney 	return (0);
204bf21cd93STycho Nightingale }
205bf21cd93STycho Nightingale 
2064c87aefeSPatrick Mooney static boolean_t
207c3d209caSPatrick Mooney vmmdev_devmem_segid(vmm_softc_t *sc, off_t off, off_t len, int *segidp,
208c3d209caSPatrick Mooney     off_t *map_offp)
209bf21cd93STycho Nightingale {
2104c87aefeSPatrick Mooney 	list_t *dl = &sc->vmm_devmem_list;
2114c87aefeSPatrick Mooney 	vmm_devmem_entry_t *de = NULL;
212c3d209caSPatrick Mooney 	const off_t map_end = off + len;
213bf21cd93STycho Nightingale 
2144c87aefeSPatrick Mooney 	VERIFY(off >= VM_DEVMEM_START);
215bf21cd93STycho Nightingale 
216c3d209caSPatrick Mooney 	if (map_end < off) {
217c3d209caSPatrick Mooney 		/* No match on overflow */
2184c87aefeSPatrick Mooney 		return (B_FALSE);
219bf21cd93STycho Nightingale 	}
220bf21cd93STycho Nightingale 
221c3d209caSPatrick Mooney 	for (de = list_head(dl); de != NULL; de = list_next(dl, de)) {
222c3d209caSPatrick Mooney 		const off_t item_end = de->vde_off + de->vde_len;
223c3d209caSPatrick Mooney 
224c3d209caSPatrick Mooney 		if (de->vde_off <= off && item_end >= map_end) {
225c3d209caSPatrick Mooney 			*segidp = de->vde_segid;
226c3d209caSPatrick Mooney 			*map_offp = off - de->vde_off;
227c3d209caSPatrick Mooney 			return (B_TRUE);
228c3d209caSPatrick Mooney 		}
229c3d209caSPatrick Mooney 	}
230c3d209caSPatrick Mooney 	return (B_FALSE);
2314c87aefeSPatrick Mooney }
232bf21cd93STycho Nightingale 
233bf21cd93STycho Nightingale static void
2344c87aefeSPatrick Mooney vmmdev_devmem_purge(vmm_softc_t *sc)
235bf21cd93STycho Nightingale {
2364c87aefeSPatrick Mooney 	vmm_devmem_entry_t *entry;
2374c87aefeSPatrick Mooney 
2384c87aefeSPatrick Mooney 	while ((entry = list_remove_head(&sc->vmm_devmem_list)) != NULL) {
2394c87aefeSPatrick Mooney 		kmem_free(entry, sizeof (*entry));
2404c87aefeSPatrick Mooney 	}
241bf21cd93STycho Nightingale }
242bf21cd93STycho Nightingale 
2434c87aefeSPatrick Mooney static int
2444c87aefeSPatrick Mooney vmmdev_alloc_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
245bf21cd93STycho Nightingale {
2464c87aefeSPatrick Mooney 	int error;
2474c87aefeSPatrick Mooney 	bool sysmem = true;
248bf21cd93STycho Nightingale 
2494c87aefeSPatrick Mooney 	if (VM_MEMSEG_NAME(mseg)) {
2504c87aefeSPatrick Mooney 		sysmem = false;
251bf21cd93STycho Nightingale 	}
2524c87aefeSPatrick Mooney 	error = vm_alloc_memseg(sc->vmm_vm, mseg->segid, mseg->len, sysmem);
253bf21cd93STycho Nightingale 
2543d066281SPatrick Mooney 	if (error == 0) {
2554c87aefeSPatrick Mooney 		/*
2564c87aefeSPatrick Mooney 		 * Rather than create a whole fresh device from which userspace
2574c87aefeSPatrick Mooney 		 * can mmap this segment, instead make it available at an
2584c87aefeSPatrick Mooney 		 * offset above where the main guest memory resides.
2594c87aefeSPatrick Mooney 		 */
2604c87aefeSPatrick Mooney 		error = vmmdev_devmem_create(sc, mseg, mseg->name);
2614c87aefeSPatrick Mooney 		if (error != 0) {
2624c87aefeSPatrick Mooney 			vm_free_memseg(sc->vmm_vm, mseg->segid);
2634c87aefeSPatrick Mooney 		}
264bf21cd93STycho Nightingale 	}
2654c87aefeSPatrick Mooney 	return (error);
2664c87aefeSPatrick Mooney }
267bf21cd93STycho Nightingale 
2684c87aefeSPatrick Mooney /*
2694c87aefeSPatrick Mooney  * Resource Locking and Exclusion
2704c87aefeSPatrick Mooney  *
2714c87aefeSPatrick Mooney  * Much of bhyve depends on key portions of VM state, such as the guest memory
2724c87aefeSPatrick Mooney  * map, to remain unchanged while the guest is running.  As ported from
2734c87aefeSPatrick Mooney  * FreeBSD, the initial strategy for this resource exclusion hinged on gating
2744c87aefeSPatrick Mooney  * access to the instance vCPUs.  Threads acting on a single vCPU, like those
2754c87aefeSPatrick Mooney  * performing the work of actually running the guest in VMX/SVM, would lock
2764c87aefeSPatrick Mooney  * only that vCPU during ioctl() entry.  For ioctls which would change VM-wide
2774c87aefeSPatrick Mooney  * state, all of the vCPUs would be first locked, ensuring that the
2784c87aefeSPatrick Mooney  * operation(s) could complete without any other threads stumbling into
2794c87aefeSPatrick Mooney  * intermediate states.
2804c87aefeSPatrick Mooney  *
2814c87aefeSPatrick Mooney  * This approach is largely effective for bhyve.  Common operations, such as
2824c87aefeSPatrick Mooney  * running the vCPUs, steer clear of lock contention.  The model begins to
2834c87aefeSPatrick Mooney  * break down for operations which do not occur in the context of a specific
2844c87aefeSPatrick Mooney  * vCPU.  LAPIC MSI delivery, for example, may be initiated from a worker
2854c87aefeSPatrick Mooney  * thread in the bhyve process.  In order to properly protect those vCPU-less
2864c87aefeSPatrick Mooney  * operations from encountering invalid states, additional locking is required.
2874c87aefeSPatrick Mooney  * This was solved by forcing those operations to lock the VM_MAXCPU-1 vCPU.
2884c87aefeSPatrick Mooney  * It does mean that class of operations will be serialized on locking the
2894c87aefeSPatrick Mooney  * specific vCPU and that instances sized at VM_MAXCPU will potentially see
2904c87aefeSPatrick Mooney  * undue contention on the VM_MAXCPU-1 vCPU.
2914c87aefeSPatrick Mooney  *
2924c87aefeSPatrick Mooney  * In order to address the shortcomings of this model, the concept of a
2934c87aefeSPatrick Mooney  * read/write lock has been added to bhyve.  Operations which change
2944c87aefeSPatrick Mooney  * fundamental aspects of a VM (such as the memory map) must acquire the write
2954c87aefeSPatrick Mooney  * lock, which also implies locking all of the vCPUs and waiting for all read
2964c87aefeSPatrick Mooney  * lock holders to release.  While it increases the cost and waiting time for
2974c87aefeSPatrick Mooney  * those few operations, it allows most hot-path operations on the VM (which
2984c87aefeSPatrick Mooney  * depend on its configuration remaining stable) to occur with minimal locking.
2994c87aefeSPatrick Mooney  *
3004c87aefeSPatrick Mooney  * Consumers of the Driver API (see below) are a special case when it comes to
3014c87aefeSPatrick Mooney  * this locking, since they may hold a read lock via the drv_lease mechanism
3024c87aefeSPatrick Mooney  * for an extended period of time.  Rather than forcing those consumers to
3034c87aefeSPatrick Mooney  * continuously poll for a write lock attempt, the lease system forces them to
3044c87aefeSPatrick Mooney  * provide a release callback to trigger their clean-up (and potential later
3054c87aefeSPatrick Mooney  * reacquisition) of the read lock.
3064c87aefeSPatrick Mooney  */
307bf21cd93STycho Nightingale 
3084c87aefeSPatrick Mooney static void
3094c87aefeSPatrick Mooney vcpu_lock_one(vmm_softc_t *sc, int vcpu)
3104c87aefeSPatrick Mooney {
3114c87aefeSPatrick Mooney 	ASSERT(vcpu >= 0 && vcpu < VM_MAXCPU);
312bf21cd93STycho Nightingale 
3134c87aefeSPatrick Mooney 	/*
3144c87aefeSPatrick Mooney 	 * Since this state transition is utilizing from_idle=true, it should
3154c87aefeSPatrick Mooney 	 * not fail, but rather block until it can be successful.
3164c87aefeSPatrick Mooney 	 */
3174c87aefeSPatrick Mooney 	VERIFY0(vcpu_set_state(sc->vmm_vm, vcpu, VCPU_FROZEN, true));
3184c87aefeSPatrick Mooney }
319bf21cd93STycho Nightingale 
3204c87aefeSPatrick Mooney static void
3214c87aefeSPatrick Mooney vcpu_unlock_one(vmm_softc_t *sc, int vcpu)
3224c87aefeSPatrick Mooney {
3234c87aefeSPatrick Mooney 	ASSERT(vcpu >= 0 && vcpu < VM_MAXCPU);
324bf21cd93STycho Nightingale 
3254c87aefeSPatrick Mooney 	VERIFY3U(vcpu_get_state(sc->vmm_vm, vcpu, NULL), ==, VCPU_FROZEN);
326e0994bd2SPatrick Mooney 	VERIFY0(vcpu_set_state(sc->vmm_vm, vcpu, VCPU_IDLE, false));
327bf21cd93STycho Nightingale }
328bf21cd93STycho Nightingale 
3294c87aefeSPatrick Mooney static void
3304c87aefeSPatrick Mooney vmm_read_lock(vmm_softc_t *sc)
331bf21cd93STycho Nightingale {
3324c87aefeSPatrick Mooney 	rw_enter(&sc->vmm_rwlock, RW_READER);
333bf21cd93STycho Nightingale }
334bf21cd93STycho Nightingale 
3354c87aefeSPatrick Mooney static void
3364c87aefeSPatrick Mooney vmm_read_unlock(vmm_softc_t *sc)
337bf21cd93STycho Nightingale {
3384c87aefeSPatrick Mooney 	rw_exit(&sc->vmm_rwlock);
339bf21cd93STycho Nightingale }
340bf21cd93STycho Nightingale 
3414c87aefeSPatrick Mooney static void
3424c87aefeSPatrick Mooney vmm_write_lock(vmm_softc_t *sc)
343bf21cd93STycho Nightingale {
3444c87aefeSPatrick Mooney 	int maxcpus;
345bf21cd93STycho Nightingale 
3464c87aefeSPatrick Mooney 	/* First lock all the vCPUs */
3474c87aefeSPatrick Mooney 	maxcpus = vm_get_maxcpus(sc->vmm_vm);
3484c87aefeSPatrick Mooney 	for (int vcpu = 0; vcpu < maxcpus; vcpu++) {
3494c87aefeSPatrick Mooney 		vcpu_lock_one(sc, vcpu);
3504c87aefeSPatrick Mooney 	}
351bf21cd93STycho Nightingale 
3526703a0e8SPatrick Mooney 	/*
3536703a0e8SPatrick Mooney 	 * Block vmm_drv leases from being acquired or held while the VM write
3546703a0e8SPatrick Mooney 	 * lock is held.
3556703a0e8SPatrick Mooney 	 */
3566703a0e8SPatrick Mooney 	vmm_lease_block(sc);
3574c87aefeSPatrick Mooney 
3584c87aefeSPatrick Mooney 	rw_enter(&sc->vmm_rwlock, RW_WRITER);
3594c87aefeSPatrick Mooney 	/*
3604c87aefeSPatrick Mooney 	 * For now, the 'maxcpus' value for an instance is fixed at the
3614c87aefeSPatrick Mooney 	 * compile-time constant of VM_MAXCPU at creation.  If this changes in
3624c87aefeSPatrick Mooney 	 * the future, allowing for dynamic vCPU resource sizing, acquisition
3634c87aefeSPatrick Mooney 	 * of the write lock will need to be wary of such changes.
3644c87aefeSPatrick Mooney 	 */
3654c87aefeSPatrick Mooney 	VERIFY(maxcpus == vm_get_maxcpus(sc->vmm_vm));
366bf21cd93STycho Nightingale }
367bf21cd93STycho Nightingale 
3684c87aefeSPatrick Mooney static void
3694c87aefeSPatrick Mooney vmm_write_unlock(vmm_softc_t *sc)
370bf21cd93STycho Nightingale {
3714c87aefeSPatrick Mooney 	int maxcpus;
3724c87aefeSPatrick Mooney 
3736703a0e8SPatrick Mooney 	/* Allow vmm_drv leases to be acquired once write lock is dropped */
3746703a0e8SPatrick Mooney 	vmm_lease_unblock(sc);
375bf21cd93STycho Nightingale 
376bf21cd93STycho Nightingale 	/*
3774c87aefeSPatrick Mooney 	 * The VM write lock _must_ be released from the same thread it was
3784c87aefeSPatrick Mooney 	 * acquired in, unlike the read lock.
379bf21cd93STycho Nightingale 	 */
3804c87aefeSPatrick Mooney 	VERIFY(rw_write_held(&sc->vmm_rwlock));
3814c87aefeSPatrick Mooney 	rw_exit(&sc->vmm_rwlock);
3824c87aefeSPatrick Mooney 
3834c87aefeSPatrick Mooney 	/* Unlock all the vCPUs */
3844c87aefeSPatrick Mooney 	maxcpus = vm_get_maxcpus(sc->vmm_vm);
3854c87aefeSPatrick Mooney 	for (int vcpu = 0; vcpu < maxcpus; vcpu++) {
3864c87aefeSPatrick Mooney 		vcpu_unlock_one(sc, vcpu);
3874c87aefeSPatrick Mooney 	}
3884c87aefeSPatrick Mooney }
3894c87aefeSPatrick Mooney 
3904c87aefeSPatrick Mooney static int
3914c87aefeSPatrick Mooney vmmdev_do_ioctl(vmm_softc_t *sc, int cmd, intptr_t arg, int md,
3924c87aefeSPatrick Mooney     cred_t *credp, int *rvalp)
3934c87aefeSPatrick Mooney {
3944c87aefeSPatrick Mooney 	int error = 0, vcpu = -1;
3954c87aefeSPatrick Mooney 	void *datap = (void *)arg;
3964c87aefeSPatrick Mooney 	enum vm_lock_type {
3974c87aefeSPatrick Mooney 		LOCK_NONE = 0,
3984c87aefeSPatrick Mooney 		LOCK_VCPU,
3994c87aefeSPatrick Mooney 		LOCK_READ_HOLD,
4004c87aefeSPatrick Mooney 		LOCK_WRITE_HOLD
4014c87aefeSPatrick Mooney 	} lock_type = LOCK_NONE;
4024c87aefeSPatrick Mooney 
4034c87aefeSPatrick Mooney 	/* Acquire any exclusion resources needed for the operation. */
404bf21cd93STycho Nightingale 	switch (cmd) {
405bf21cd93STycho Nightingale 	case VM_RUN:
406bf21cd93STycho Nightingale 	case VM_GET_REGISTER:
407bf21cd93STycho Nightingale 	case VM_SET_REGISTER:
408bf21cd93STycho Nightingale 	case VM_GET_SEGMENT_DESCRIPTOR:
409bf21cd93STycho Nightingale 	case VM_SET_SEGMENT_DESCRIPTOR:
4104c87aefeSPatrick Mooney 	case VM_GET_REGISTER_SET:
4114c87aefeSPatrick Mooney 	case VM_SET_REGISTER_SET:
412bf21cd93STycho Nightingale 	case VM_INJECT_EXCEPTION:
413bf21cd93STycho Nightingale 	case VM_GET_CAPABILITY:
414bf21cd93STycho Nightingale 	case VM_SET_CAPABILITY:
415bf21cd93STycho Nightingale 	case VM_PPTDEV_MSI:
416bf21cd93STycho Nightingale 	case VM_PPTDEV_MSIX:
417bf21cd93STycho Nightingale 	case VM_SET_X2APIC_STATE:
418bf21cd93STycho Nightingale 	case VM_GLA2GPA:
4194c87aefeSPatrick Mooney 	case VM_GLA2GPA_NOFAULT:
420bf21cd93STycho Nightingale 	case VM_ACTIVATE_CPU:
4214c87aefeSPatrick Mooney 	case VM_SET_INTINFO:
4224c87aefeSPatrick Mooney 	case VM_GET_INTINFO:
423bf21cd93STycho Nightingale 	case VM_RESTART_INSTRUCTION:
424154972afSPatrick Mooney 	case VM_SET_KERNEMU_DEV:
425154972afSPatrick Mooney 	case VM_GET_KERNEMU_DEV:
4262606939dSPatrick Mooney 	case VM_RESET_CPU:
4272606939dSPatrick Mooney 	case VM_GET_RUN_STATE:
4282606939dSPatrick Mooney 	case VM_SET_RUN_STATE:
429957246c9SPatrick Mooney 	case VM_GET_FPU:
430957246c9SPatrick Mooney 	case VM_SET_FPU:
431bf21cd93STycho Nightingale 		/*
4324c87aefeSPatrick Mooney 		 * Copy in the ID of the vCPU chosen for this operation.
4334c87aefeSPatrick Mooney 		 * Since a nefarious caller could update their struct between
4344c87aefeSPatrick Mooney 		 * this locking and when the rest of the ioctl data is copied
4354c87aefeSPatrick Mooney 		 * in, it is _critical_ that this local 'vcpu' variable be used
4364c87aefeSPatrick Mooney 		 * rather than the in-struct one when performing the ioctl.
437bf21cd93STycho Nightingale 		 */
4384c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vcpu, sizeof (vcpu), md)) {
439bf21cd93STycho Nightingale 			return (EFAULT);
440bf21cd93STycho Nightingale 		}
4414c87aefeSPatrick Mooney 		if (vcpu < 0 || vcpu > vm_get_maxcpus(sc->vmm_vm)) {
4424c87aefeSPatrick Mooney 			return (EINVAL);
443bf21cd93STycho Nightingale 		}
4444c87aefeSPatrick Mooney 		vcpu_lock_one(sc, vcpu);
4454c87aefeSPatrick Mooney 		lock_type = LOCK_VCPU;
446bf21cd93STycho Nightingale 		break;
447bf21cd93STycho Nightingale 
4484c87aefeSPatrick Mooney 	case VM_REINIT:
4494c87aefeSPatrick Mooney 	case VM_BIND_PPTDEV:
4504c87aefeSPatrick Mooney 	case VM_UNBIND_PPTDEV:
4514c87aefeSPatrick Mooney 	case VM_MAP_PPTDEV_MMIO:
4522b948146SAndy Fiddaman 	case VM_UNMAP_PPTDEV_MMIO:
4534c87aefeSPatrick Mooney 	case VM_ALLOC_MEMSEG:
4544c87aefeSPatrick Mooney 	case VM_MMAP_MEMSEG:
4552b948146SAndy Fiddaman 	case VM_MUNMAP_MEMSEG:
4564c87aefeSPatrick Mooney 	case VM_WRLOCK_CYCLE:
4570e1453c3SPatrick Mooney 	case VM_PMTMR_LOCATE:
4584c87aefeSPatrick Mooney 		vmm_write_lock(sc);
4594c87aefeSPatrick Mooney 		lock_type = LOCK_WRITE_HOLD;
4604c87aefeSPatrick Mooney 		break;
461bf21cd93STycho Nightingale 
4624c87aefeSPatrick Mooney 	case VM_GET_MEMSEG:
4634c87aefeSPatrick Mooney 	case VM_MMAP_GETNEXT:
4644c87aefeSPatrick Mooney 	case VM_LAPIC_IRQ:
4654c87aefeSPatrick Mooney 	case VM_INJECT_NMI:
4664c87aefeSPatrick Mooney 	case VM_IOAPIC_ASSERT_IRQ:
4674c87aefeSPatrick Mooney 	case VM_IOAPIC_DEASSERT_IRQ:
4684c87aefeSPatrick Mooney 	case VM_IOAPIC_PULSE_IRQ:
4694c87aefeSPatrick Mooney 	case VM_LAPIC_MSI:
4704c87aefeSPatrick Mooney 	case VM_LAPIC_LOCAL_IRQ:
4714c87aefeSPatrick Mooney 	case VM_GET_X2APIC_STATE:
4724c87aefeSPatrick Mooney 	case VM_RTC_READ:
4734c87aefeSPatrick Mooney 	case VM_RTC_WRITE:
4744c87aefeSPatrick Mooney 	case VM_RTC_SETTIME:
4754c87aefeSPatrick Mooney 	case VM_RTC_GETTIME:
4766960cd89SAndy Fiddaman 	case VM_PPTDEV_DISABLE_MSIX:
4774c87aefeSPatrick Mooney 	case VM_DEVMEM_GETOFFSET:
4788779b448SDan Cross 	case VM_TRACK_DIRTY_PAGES:
4794c87aefeSPatrick Mooney 		vmm_read_lock(sc);
4804c87aefeSPatrick Mooney 		lock_type = LOCK_READ_HOLD;
481bf21cd93STycho Nightingale 		break;
482bf21cd93STycho Nightingale 
483d515dd77SPatrick Mooney 	case VM_DATA_READ:
484d515dd77SPatrick Mooney 	case VM_DATA_WRITE:
485d515dd77SPatrick Mooney 		if (ddi_copyin(datap, &vcpu, sizeof (vcpu), md)) {
486d515dd77SPatrick Mooney 			return (EFAULT);
487d515dd77SPatrick Mooney 		}
488d515dd77SPatrick Mooney 		if (vcpu == -1) {
489d515dd77SPatrick Mooney 			/* Access data for VM-wide devices */
490d515dd77SPatrick Mooney 			vmm_write_lock(sc);
491d515dd77SPatrick Mooney 			lock_type = LOCK_WRITE_HOLD;
492d515dd77SPatrick Mooney 		} else if (vcpu >= 0 && vcpu < vm_get_maxcpus(sc->vmm_vm)) {
493d515dd77SPatrick Mooney 			/* Access data associated with a specific vCPU */
494d515dd77SPatrick Mooney 			vcpu_lock_one(sc, vcpu);
495d515dd77SPatrick Mooney 			lock_type = LOCK_VCPU;
496d515dd77SPatrick Mooney 		} else {
497d515dd77SPatrick Mooney 			return (EINVAL);
498d515dd77SPatrick Mooney 		}
499d515dd77SPatrick Mooney 		break;
500d515dd77SPatrick Mooney 
5010153d828SPatrick Mooney 	case VM_GET_GPA_PMAP:
5024c87aefeSPatrick Mooney 	case VM_IOAPIC_PINCOUNT:
50352fac30eSPatrick Mooney 	case VM_SUSPEND:
504957246c9SPatrick Mooney 	case VM_DESC_FPU_AREA:
505bf21cd93STycho Nightingale 	default:
506bf21cd93STycho Nightingale 		break;
507bf21cd93STycho Nightingale 	}
508bf21cd93STycho Nightingale 
5094c87aefeSPatrick Mooney 	/* Execute the primary logic for the ioctl. */
5104c87aefeSPatrick Mooney 	switch (cmd) {
5114c87aefeSPatrick Mooney 	case VM_RUN: {
512e0c0d44eSPatrick Mooney 		struct vm_entry entry;
5134c87aefeSPatrick Mooney 
514e0c0d44eSPatrick Mooney 		if (ddi_copyin(datap, &entry, sizeof (entry), md)) {
5154c87aefeSPatrick Mooney 			error = EFAULT;
5164c87aefeSPatrick Mooney 			break;
517bf21cd93STycho Nightingale 		}
5184c87aefeSPatrick Mooney 
5194c87aefeSPatrick Mooney 		if (!(curthread->t_schedflag & TS_VCPU))
5204c87aefeSPatrick Mooney 			smt_mark_as_vcpu();
5214c87aefeSPatrick Mooney 
522e0c0d44eSPatrick Mooney 		error = vm_run(sc->vmm_vm, vcpu, &entry);
523e0c0d44eSPatrick Mooney 
5243e1c5f3aSPatrick Mooney 		/*
5253e1c5f3aSPatrick Mooney 		 * Unexpected states in vm_run() are expressed through positive
5263e1c5f3aSPatrick Mooney 		 * errno-oriented return values.  VM states which expect further
5273e1c5f3aSPatrick Mooney 		 * processing in userspace (necessary context via exitinfo) are
5283e1c5f3aSPatrick Mooney 		 * expressed through negative return values.  For the time being
5293e1c5f3aSPatrick Mooney 		 * a return value of 0 is not expected from vm_run().
5303e1c5f3aSPatrick Mooney 		 */
5313e1c5f3aSPatrick Mooney 		ASSERT(error != 0);
5323e1c5f3aSPatrick Mooney 		if (error < 0) {
533e0c0d44eSPatrick Mooney 			const struct vm_exit *vme;
534e0c0d44eSPatrick Mooney 			void *outp = entry.exit_data;
535e0c0d44eSPatrick Mooney 
5363e1c5f3aSPatrick Mooney 			error = 0;
537e0c0d44eSPatrick Mooney 			vme = vm_exitinfo(sc->vmm_vm, vcpu);
538e0c0d44eSPatrick Mooney 			if (ddi_copyout(vme, outp, sizeof (*vme), md)) {
539e0c0d44eSPatrick Mooney 				error = EFAULT;
540e0c0d44eSPatrick Mooney 			}
541bf21cd93STycho Nightingale 		}
542bf21cd93STycho Nightingale 		break;
5434c87aefeSPatrick Mooney 	}
5444c87aefeSPatrick Mooney 	case VM_SUSPEND: {
5454c87aefeSPatrick Mooney 		struct vm_suspend vmsuspend;
5464c87aefeSPatrick Mooney 
5474c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmsuspend, sizeof (vmsuspend), md)) {
5484c87aefeSPatrick Mooney 			error = EFAULT;
5494c87aefeSPatrick Mooney 			break;
550bf21cd93STycho Nightingale 		}
5514c87aefeSPatrick Mooney 		error = vm_suspend(sc->vmm_vm, vmsuspend.how);
552bf21cd93STycho Nightingale 		break;
5534c87aefeSPatrick Mooney 	}
55452fac30eSPatrick Mooney 	case VM_REINIT: {
55552fac30eSPatrick Mooney 		struct vm_reinit reinit;
55652fac30eSPatrick Mooney 
55752fac30eSPatrick Mooney 		if (ddi_copyin(datap, &reinit, sizeof (reinit), md)) {
55852fac30eSPatrick Mooney 			error = EFAULT;
55952fac30eSPatrick Mooney 			break;
56052fac30eSPatrick Mooney 		}
5614c87aefeSPatrick Mooney 		if ((error = vmm_drv_block_hook(sc, B_TRUE)) != 0) {
5624c87aefeSPatrick Mooney 			/*
5634c87aefeSPatrick Mooney 			 * The VM instance should be free of driver-attached
5644c87aefeSPatrick Mooney 			 * hooks during the reinitialization process.
5654c87aefeSPatrick Mooney 			 */
5664c87aefeSPatrick Mooney 			break;
567bf21cd93STycho Nightingale 		}
56852fac30eSPatrick Mooney 		error = vm_reinit(sc->vmm_vm, reinit.flags);
5694c87aefeSPatrick Mooney 		(void) vmm_drv_block_hook(sc, B_FALSE);
570bf21cd93STycho Nightingale 		break;
57152fac30eSPatrick Mooney 	}
5724c87aefeSPatrick Mooney 	case VM_STAT_DESC: {
5734c87aefeSPatrick Mooney 		struct vm_stat_desc statdesc;
5744c87aefeSPatrick Mooney 
5754c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &statdesc, sizeof (statdesc), md)) {
5764c87aefeSPatrick Mooney 			error = EFAULT;
5774c87aefeSPatrick Mooney 			break;
578bf21cd93STycho Nightingale 		}
5794c87aefeSPatrick Mooney 		error = vmm_stat_desc_copy(statdesc.index, statdesc.desc,
5804c87aefeSPatrick Mooney 		    sizeof (statdesc.desc));
5814c87aefeSPatrick Mooney 		if (error == 0 &&
5824c87aefeSPatrick Mooney 		    ddi_copyout(&statdesc, datap, sizeof (statdesc), md)) {
5834c87aefeSPatrick Mooney 			error = EFAULT;
5844c87aefeSPatrick Mooney 			break;
585bf21cd93STycho Nightingale 		}
586bf21cd93STycho Nightingale 		break;
5874c87aefeSPatrick Mooney 	}
5884c87aefeSPatrick Mooney 	case VM_STATS_IOC: {
5894c87aefeSPatrick Mooney 		struct vm_stats vmstats;
5904c87aefeSPatrick Mooney 
5914c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmstats, sizeof (vmstats), md)) {
5924c87aefeSPatrick Mooney 			error = EFAULT;
5934c87aefeSPatrick Mooney 			break;
594bf21cd93STycho Nightingale 		}
5954c87aefeSPatrick Mooney 		hrt2tv(gethrtime(), &vmstats.tv);
596d7b72f7bSAndy Fiddaman 		error = vmm_stat_copy(sc->vmm_vm, vmstats.cpuid, vmstats.index,
597d7b72f7bSAndy Fiddaman 		    nitems(vmstats.statbuf),
5984c87aefeSPatrick Mooney 		    &vmstats.num_entries, vmstats.statbuf);
5994c87aefeSPatrick Mooney 		if (error == 0 &&
6004c87aefeSPatrick Mooney 		    ddi_copyout(&vmstats, datap, sizeof (vmstats), md)) {
6014c87aefeSPatrick Mooney 			error = EFAULT;
6024c87aefeSPatrick Mooney 			break;
603bf21cd93STycho Nightingale 		}
604bf21cd93STycho Nightingale 		break;
6054c87aefeSPatrick Mooney 	}
6064c87aefeSPatrick Mooney 
6074c87aefeSPatrick Mooney 	case VM_PPTDEV_MSI: {
6084c87aefeSPatrick Mooney 		struct vm_pptdev_msi pptmsi;
6094c87aefeSPatrick Mooney 
6104c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &pptmsi, sizeof (pptmsi), md)) {
6114c87aefeSPatrick Mooney 			error = EFAULT;
6124c87aefeSPatrick Mooney 			break;
613bf21cd93STycho Nightingale 		}
614eb9a1df2SHans Rosenfeld 		error = ppt_setup_msi(sc->vmm_vm, pptmsi.vcpu, pptmsi.pptfd,
615eb9a1df2SHans Rosenfeld 		    pptmsi.addr, pptmsi.msg, pptmsi.numvec);
616eb9a1df2SHans Rosenfeld 		break;
6174c87aefeSPatrick Mooney 	}
6184c87aefeSPatrick Mooney 	case VM_PPTDEV_MSIX: {
6194c87aefeSPatrick Mooney 		struct vm_pptdev_msix pptmsix;
6204c87aefeSPatrick Mooney 
6214c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &pptmsix, sizeof (pptmsix), md)) {
6224c87aefeSPatrick Mooney 			error = EFAULT;
6234c87aefeSPatrick Mooney 			break;
624bf21cd93STycho Nightingale 		}
625eb9a1df2SHans Rosenfeld 		error = ppt_setup_msix(sc->vmm_vm, pptmsix.vcpu, pptmsix.pptfd,
626eb9a1df2SHans Rosenfeld 		    pptmsix.idx, pptmsix.addr, pptmsix.msg,
627eb9a1df2SHans Rosenfeld 		    pptmsix.vector_control);
628eb9a1df2SHans Rosenfeld 		break;
6294c87aefeSPatrick Mooney 	}
6306960cd89SAndy Fiddaman 	case VM_PPTDEV_DISABLE_MSIX: {
6316960cd89SAndy Fiddaman 		struct vm_pptdev pptdev;
6326960cd89SAndy Fiddaman 
6336960cd89SAndy Fiddaman 		if (ddi_copyin(datap, &pptdev, sizeof (pptdev), md)) {
6346960cd89SAndy Fiddaman 			error = EFAULT;
6356960cd89SAndy Fiddaman 			break;
6366960cd89SAndy Fiddaman 		}
6376960cd89SAndy Fiddaman 		error = ppt_disable_msix(sc->vmm_vm, pptdev.pptfd);
6386960cd89SAndy Fiddaman 		break;
6396960cd89SAndy Fiddaman 	}
6404c87aefeSPatrick Mooney 	case VM_MAP_PPTDEV_MMIO: {
6414c87aefeSPatrick Mooney 		struct vm_pptdev_mmio pptmmio;
6424c87aefeSPatrick Mooney 
6434c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &pptmmio, sizeof (pptmmio), md)) {
6444c87aefeSPatrick Mooney 			error = EFAULT;
6454c87aefeSPatrick Mooney 			break;
646bf21cd93STycho Nightingale 		}
647eb9a1df2SHans Rosenfeld 		error = ppt_map_mmio(sc->vmm_vm, pptmmio.pptfd, pptmmio.gpa,
648eb9a1df2SHans Rosenfeld 		    pptmmio.len, pptmmio.hpa);
649eb9a1df2SHans Rosenfeld 		break;
650eb9a1df2SHans Rosenfeld 	}
6512b948146SAndy Fiddaman 	case VM_UNMAP_PPTDEV_MMIO: {
6522b948146SAndy Fiddaman 		struct vm_pptdev_mmio pptmmio;
6532b948146SAndy Fiddaman 
6542b948146SAndy Fiddaman 		if (ddi_copyin(datap, &pptmmio, sizeof (pptmmio), md)) {
6552b948146SAndy Fiddaman 			error = EFAULT;
6562b948146SAndy Fiddaman 			break;
6572b948146SAndy Fiddaman 		}
6582b948146SAndy Fiddaman 		error = ppt_unmap_mmio(sc->vmm_vm, pptmmio.pptfd, pptmmio.gpa,
6592b948146SAndy Fiddaman 		    pptmmio.len);
6602b948146SAndy Fiddaman 		break;
6612b948146SAndy Fiddaman 	}
662eb9a1df2SHans Rosenfeld 	case VM_BIND_PPTDEV: {
663eb9a1df2SHans Rosenfeld 		struct vm_pptdev pptdev;
664eb9a1df2SHans Rosenfeld 
665eb9a1df2SHans Rosenfeld 		if (ddi_copyin(datap, &pptdev, sizeof (pptdev), md)) {
666eb9a1df2SHans Rosenfeld 			error = EFAULT;
667eb9a1df2SHans Rosenfeld 			break;
668eb9a1df2SHans Rosenfeld 		}
669eb9a1df2SHans Rosenfeld 		error = vm_assign_pptdev(sc->vmm_vm, pptdev.pptfd);
670eb9a1df2SHans Rosenfeld 		break;
6714c87aefeSPatrick Mooney 	}
6724c87aefeSPatrick Mooney 	case VM_UNBIND_PPTDEV: {
6734c87aefeSPatrick Mooney 		struct vm_pptdev pptdev;
6744c87aefeSPatrick Mooney 
6754c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &pptdev, sizeof (pptdev), md)) {
6764c87aefeSPatrick Mooney 			error = EFAULT;
6774c87aefeSPatrick Mooney 			break;
678bf21cd93STycho Nightingale 		}
679eb9a1df2SHans Rosenfeld 		error = vm_unassign_pptdev(sc->vmm_vm, pptdev.pptfd);
680eb9a1df2SHans Rosenfeld 		break;
6814c87aefeSPatrick Mooney 	}
682eb9a1df2SHans Rosenfeld 	case VM_GET_PPTDEV_LIMITS: {
683eb9a1df2SHans Rosenfeld 		struct vm_pptdev_limits pptlimits;
6844c87aefeSPatrick Mooney 
685eb9a1df2SHans Rosenfeld 		if (ddi_copyin(datap, &pptlimits, sizeof (pptlimits), md)) {
686eb9a1df2SHans Rosenfeld 			error = EFAULT;
687eb9a1df2SHans Rosenfeld 			break;
688eb9a1df2SHans Rosenfeld 		}
689eb9a1df2SHans Rosenfeld 		error = ppt_get_limits(sc->vmm_vm, pptlimits.pptfd,
690eb9a1df2SHans Rosenfeld 		    &pptlimits.msi_limit, &pptlimits.msix_limit);
691eb9a1df2SHans Rosenfeld 		if (error == 0 &&
692eb9a1df2SHans Rosenfeld 		    ddi_copyout(&pptlimits, datap, sizeof (pptlimits), md)) {
693eb9a1df2SHans Rosenfeld 			error = EFAULT;
694eb9a1df2SHans Rosenfeld 			break;
695eb9a1df2SHans Rosenfeld 		}
696eb9a1df2SHans Rosenfeld 		break;
697eb9a1df2SHans Rosenfeld 	}
6984c87aefeSPatrick Mooney 	case VM_INJECT_EXCEPTION: {
6994c87aefeSPatrick Mooney 		struct vm_exception vmexc;
7004c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmexc, sizeof (vmexc), md)) {
7014c87aefeSPatrick Mooney 			error = EFAULT;
7024c87aefeSPatrick Mooney 			break;
703bf21cd93STycho Nightingale 		}
7044c87aefeSPatrick Mooney 		error = vm_inject_exception(sc->vmm_vm, vcpu, vmexc.vector,
7053d097f7dSPatrick Mooney 		    vmexc.error_code_valid != 0, vmexc.error_code,
7063d097f7dSPatrick Mooney 		    vmexc.restart_instruction != 0);
707bf21cd93STycho Nightingale 		break;
7084c87aefeSPatrick Mooney 	}
7094c87aefeSPatrick Mooney 	case VM_INJECT_NMI: {
7104c87aefeSPatrick Mooney 		struct vm_nmi vmnmi;
7114c87aefeSPatrick Mooney 
7124c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmnmi, sizeof (vmnmi), md)) {
7134c87aefeSPatrick Mooney 			error = EFAULT;
7144c87aefeSPatrick Mooney 			break;
715bf21cd93STycho Nightingale 		}
7164c87aefeSPatrick Mooney 		error = vm_inject_nmi(sc->vmm_vm, vmnmi.cpuid);
717bf21cd93STycho Nightingale 		break;
7184c87aefeSPatrick Mooney 	}
7194c87aefeSPatrick Mooney 	case VM_LAPIC_IRQ: {
7204c87aefeSPatrick Mooney 		struct vm_lapic_irq vmirq;
7214c87aefeSPatrick Mooney 
7224c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmirq, sizeof (vmirq), md)) {
7234c87aefeSPatrick Mooney 			error = EFAULT;
7244c87aefeSPatrick Mooney 			break;
725bf21cd93STycho Nightingale 		}
7264c87aefeSPatrick Mooney 		error = lapic_intr_edge(sc->vmm_vm, vmirq.cpuid, vmirq.vector);
727bf21cd93STycho Nightingale 		break;
7284c87aefeSPatrick Mooney 	}
7294c87aefeSPatrick Mooney 	case VM_LAPIC_LOCAL_IRQ: {
7304c87aefeSPatrick Mooney 		struct vm_lapic_irq vmirq;
7314c87aefeSPatrick Mooney 
7324c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmirq, sizeof (vmirq), md)) {
7334c87aefeSPatrick Mooney 			error = EFAULT;
7344c87aefeSPatrick Mooney 			break;
735bf21cd93STycho Nightingale 		}
7364c87aefeSPatrick Mooney 		error = lapic_set_local_intr(sc->vmm_vm, vmirq.cpuid,
7374c87aefeSPatrick Mooney 		    vmirq.vector);
738bf21cd93STycho Nightingale 		break;
7394c87aefeSPatrick Mooney 	}
7404c87aefeSPatrick Mooney 	case VM_LAPIC_MSI: {
7414c87aefeSPatrick Mooney 		struct vm_lapic_msi vmmsi;
7424c87aefeSPatrick Mooney 
7434c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmmsi, sizeof (vmmsi), md)) {
7444c87aefeSPatrick Mooney 			error = EFAULT;
7454c87aefeSPatrick Mooney 			break;
746bf21cd93STycho Nightingale 		}
7474c87aefeSPatrick Mooney 		error = lapic_intr_msi(sc->vmm_vm, vmmsi.addr, vmmsi.msg);
748bf21cd93STycho Nightingale 		break;
7494c87aefeSPatrick Mooney 	}
7504c87aefeSPatrick Mooney 
7514c87aefeSPatrick Mooney 	case VM_IOAPIC_ASSERT_IRQ: {
7524c87aefeSPatrick Mooney 		struct vm_ioapic_irq ioapic_irq;
7534c87aefeSPatrick Mooney 
7544c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &ioapic_irq, sizeof (ioapic_irq), md)) {
7554c87aefeSPatrick Mooney 			error = EFAULT;
7564c87aefeSPatrick Mooney 			break;
757bf21cd93STycho Nightingale 		}
7584c87aefeSPatrick Mooney 		error = vioapic_assert_irq(sc->vmm_vm, ioapic_irq.irq);
759bf21cd93STycho Nightingale 		break;
7604c87aefeSPatrick Mooney 	}
7614c87aefeSPatrick Mooney 	case VM_IOAPIC_DEASSERT_IRQ: {
7624c87aefeSPatrick Mooney 		struct vm_ioapic_irq ioapic_irq;
7634c87aefeSPatrick Mooney 
7644c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &ioapic_irq, sizeof (ioapic_irq), md)) {
7654c87aefeSPatrick Mooney 			error = EFAULT;
7664c87aefeSPatrick Mooney 			break;
767bf21cd93STycho Nightingale 		}
7684c87aefeSPatrick Mooney 		error = vioapic_deassert_irq(sc->vmm_vm, ioapic_irq.irq);
769bf21cd93STycho Nightingale 		break;
7704c87aefeSPatrick Mooney 	}
7714c87aefeSPatrick Mooney 	case VM_IOAPIC_PULSE_IRQ: {
7724c87aefeSPatrick Mooney 		struct vm_ioapic_irq ioapic_irq;
7734c87aefeSPatrick Mooney 
7744c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &ioapic_irq, sizeof (ioapic_irq), md)) {
7754c87aefeSPatrick Mooney 			error = EFAULT;
7764c87aefeSPatrick Mooney 			break;
777bf21cd93STycho Nightingale 		}
7784c87aefeSPatrick Mooney 		error = vioapic_pulse_irq(sc->vmm_vm, ioapic_irq.irq);
779bf21cd93STycho Nightingale 		break;
7804c87aefeSPatrick Mooney 	}
7814c87aefeSPatrick Mooney 	case VM_IOAPIC_PINCOUNT: {
7824c87aefeSPatrick Mooney 		int pincount;
7834c87aefeSPatrick Mooney 
7844c87aefeSPatrick Mooney 		pincount = vioapic_pincount(sc->vmm_vm);
7854c87aefeSPatrick Mooney 		if (ddi_copyout(&pincount, datap, sizeof (int), md)) {
7864c87aefeSPatrick Mooney 			error = EFAULT;
7874c87aefeSPatrick Mooney 			break;
788bf21cd93STycho Nightingale 		}
7894c87aefeSPatrick Mooney 		break;
7904c87aefeSPatrick Mooney 	}
791957246c9SPatrick Mooney 	case VM_DESC_FPU_AREA: {
792957246c9SPatrick Mooney 		struct vm_fpu_desc desc;
793957246c9SPatrick Mooney 		void *buf = NULL;
794957246c9SPatrick Mooney 
795957246c9SPatrick Mooney 		if (ddi_copyin(datap, &desc, sizeof (desc), md)) {
796957246c9SPatrick Mooney 			error = EFAULT;
797957246c9SPatrick Mooney 			break;
798957246c9SPatrick Mooney 		}
799957246c9SPatrick Mooney 		if (desc.vfd_num_entries > 64) {
800957246c9SPatrick Mooney 			error = EINVAL;
801957246c9SPatrick Mooney 			break;
802957246c9SPatrick Mooney 		}
803957246c9SPatrick Mooney 		const size_t buf_sz = sizeof (struct vm_fpu_desc_entry) *
804957246c9SPatrick Mooney 		    desc.vfd_num_entries;
805957246c9SPatrick Mooney 		if (buf_sz != 0) {
806957246c9SPatrick Mooney 			buf = kmem_zalloc(buf_sz, KM_SLEEP);
807957246c9SPatrick Mooney 		}
808957246c9SPatrick Mooney 
809957246c9SPatrick Mooney 		/*
810957246c9SPatrick Mooney 		 * For now, we are depending on vm_fpu_desc_entry and
811957246c9SPatrick Mooney 		 * hma_xsave_state_desc_t having the same format.
812957246c9SPatrick Mooney 		 */
813957246c9SPatrick Mooney 		CTASSERT(sizeof (struct vm_fpu_desc_entry) ==
814957246c9SPatrick Mooney 		    sizeof (hma_xsave_state_desc_t));
815957246c9SPatrick Mooney 
816957246c9SPatrick Mooney 		size_t req_size;
817957246c9SPatrick Mooney 		const uint_t max_entries = hma_fpu_describe_xsave_state(
818957246c9SPatrick Mooney 		    (hma_xsave_state_desc_t *)buf,
819957246c9SPatrick Mooney 		    desc.vfd_num_entries,
820957246c9SPatrick Mooney 		    &req_size);
821957246c9SPatrick Mooney 
822957246c9SPatrick Mooney 		desc.vfd_req_size = req_size;
823957246c9SPatrick Mooney 		desc.vfd_num_entries = max_entries;
824957246c9SPatrick Mooney 		if (buf_sz != 0) {
825957246c9SPatrick Mooney 			if (ddi_copyout(buf, desc.vfd_entry_data, buf_sz, md)) {
826957246c9SPatrick Mooney 				error = EFAULT;
827957246c9SPatrick Mooney 			}
828957246c9SPatrick Mooney 			kmem_free(buf, buf_sz);
829957246c9SPatrick Mooney 		}
830957246c9SPatrick Mooney 
831957246c9SPatrick Mooney 		if (error == 0) {
832957246c9SPatrick Mooney 			if (ddi_copyout(&desc, datap, sizeof (desc), md)) {
833957246c9SPatrick Mooney 				error = EFAULT;
834957246c9SPatrick Mooney 			}
835957246c9SPatrick Mooney 		}
836957246c9SPatrick Mooney 		break;
837957246c9SPatrick Mooney 	}
8384c87aefeSPatrick Mooney 
8394c87aefeSPatrick Mooney 	case VM_ISA_ASSERT_IRQ: {
8404c87aefeSPatrick Mooney 		struct vm_isa_irq isa_irq;
8414c87aefeSPatrick Mooney 
8424c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &isa_irq, sizeof (isa_irq), md)) {
8434c87aefeSPatrick Mooney 			error = EFAULT;
8444c87aefeSPatrick Mooney 			break;
8454c87aefeSPatrick Mooney 		}
8464c87aefeSPatrick Mooney 		error = vatpic_assert_irq(sc->vmm_vm, isa_irq.atpic_irq);
8474c87aefeSPatrick Mooney 		if (error == 0 && isa_irq.ioapic_irq != -1) {
8484c87aefeSPatrick Mooney 			error = vioapic_assert_irq(sc->vmm_vm,
8494c87aefeSPatrick Mooney 			    isa_irq.ioapic_irq);
8504c87aefeSPatrick Mooney 		}
8514c87aefeSPatrick Mooney 		break;
8524c87aefeSPatrick Mooney 	}
8534c87aefeSPatrick Mooney 	case VM_ISA_DEASSERT_IRQ: {
8544c87aefeSPatrick Mooney 		struct vm_isa_irq isa_irq;
8554c87aefeSPatrick Mooney 
8564c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &isa_irq, sizeof (isa_irq), md)) {
8574c87aefeSPatrick Mooney 			error = EFAULT;
8584c87aefeSPatrick Mooney 			break;
8594c87aefeSPatrick Mooney 		}
8604c87aefeSPatrick Mooney 		error = vatpic_deassert_irq(sc->vmm_vm, isa_irq.atpic_irq);
8614c87aefeSPatrick Mooney 		if (error == 0 && isa_irq.ioapic_irq != -1) {
8624c87aefeSPatrick Mooney 			error = vioapic_deassert_irq(sc->vmm_vm,
8634c87aefeSPatrick Mooney 			    isa_irq.ioapic_irq);
8644c87aefeSPatrick Mooney 		}
8654c87aefeSPatrick Mooney 		break;
8664c87aefeSPatrick Mooney 	}
8674c87aefeSPatrick Mooney 	case VM_ISA_PULSE_IRQ: {
8684c87aefeSPatrick Mooney 		struct vm_isa_irq isa_irq;
8694c87aefeSPatrick Mooney 
8704c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &isa_irq, sizeof (isa_irq), md)) {
8714c87aefeSPatrick Mooney 			error = EFAULT;
8724c87aefeSPatrick Mooney 			break;
8734c87aefeSPatrick Mooney 		}
8744c87aefeSPatrick Mooney 		error = vatpic_pulse_irq(sc->vmm_vm, isa_irq.atpic_irq);
8754c87aefeSPatrick Mooney 		if (error == 0 && isa_irq.ioapic_irq != -1) {
8764c87aefeSPatrick Mooney 			error = vioapic_pulse_irq(sc->vmm_vm,
8774c87aefeSPatrick Mooney 			    isa_irq.ioapic_irq);
8784c87aefeSPatrick Mooney 		}
8794c87aefeSPatrick Mooney 		break;
8804c87aefeSPatrick Mooney 	}
8814c87aefeSPatrick Mooney 	case VM_ISA_SET_IRQ_TRIGGER: {
8824c87aefeSPatrick Mooney 		struct vm_isa_irq_trigger isa_irq_trigger;
8834c87aefeSPatrick Mooney 
8844c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &isa_irq_trigger,
8854c87aefeSPatrick Mooney 		    sizeof (isa_irq_trigger), md)) {
8864c87aefeSPatrick Mooney 			error = EFAULT;
8874c87aefeSPatrick Mooney 			break;
8884c87aefeSPatrick Mooney 		}
8894c87aefeSPatrick Mooney 		error = vatpic_set_irq_trigger(sc->vmm_vm,
8904c87aefeSPatrick Mooney 		    isa_irq_trigger.atpic_irq, isa_irq_trigger.trigger);
8914c87aefeSPatrick Mooney 		break;
8924c87aefeSPatrick Mooney 	}
8934c87aefeSPatrick Mooney 
8944c87aefeSPatrick Mooney 	case VM_MMAP_GETNEXT: {
8954c87aefeSPatrick Mooney 		struct vm_memmap mm;
8964c87aefeSPatrick Mooney 
8974c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &mm, sizeof (mm), md)) {
8984c87aefeSPatrick Mooney 			error = EFAULT;
8994c87aefeSPatrick Mooney 			break;
9004c87aefeSPatrick Mooney 		}
9014c87aefeSPatrick Mooney 		error = vm_mmap_getnext(sc->vmm_vm, &mm.gpa, &mm.segid,
9024c87aefeSPatrick Mooney 		    &mm.segoff, &mm.len, &mm.prot, &mm.flags);
9034c87aefeSPatrick Mooney 		if (error == 0 && ddi_copyout(&mm, datap, sizeof (mm), md)) {
9044c87aefeSPatrick Mooney 			error = EFAULT;
9054c87aefeSPatrick Mooney 			break;
9064c87aefeSPatrick Mooney 		}
9074c87aefeSPatrick Mooney 		break;
9084c87aefeSPatrick Mooney 	}
9094c87aefeSPatrick Mooney 	case VM_MMAP_MEMSEG: {
9104c87aefeSPatrick Mooney 		struct vm_memmap mm;
9114c87aefeSPatrick Mooney 
9124c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &mm, sizeof (mm), md)) {
9134c87aefeSPatrick Mooney 			error = EFAULT;
9144c87aefeSPatrick Mooney 			break;
9154c87aefeSPatrick Mooney 		}
9164c87aefeSPatrick Mooney 		error = vm_mmap_memseg(sc->vmm_vm, mm.gpa, mm.segid, mm.segoff,
9174c87aefeSPatrick Mooney 		    mm.len, mm.prot, mm.flags);
9184c87aefeSPatrick Mooney 		break;
9194c87aefeSPatrick Mooney 	}
9202b948146SAndy Fiddaman 	case VM_MUNMAP_MEMSEG: {
9212b948146SAndy Fiddaman 		struct vm_munmap mu;
9222b948146SAndy Fiddaman 
9232b948146SAndy Fiddaman 		if (ddi_copyin(datap, &mu, sizeof (mu), md)) {
9242b948146SAndy Fiddaman 			error = EFAULT;
9252b948146SAndy Fiddaman 			break;
9262b948146SAndy Fiddaman 		}
9272b948146SAndy Fiddaman 		error = vm_munmap_memseg(sc->vmm_vm, mu.gpa, mu.len);
9282b948146SAndy Fiddaman 		break;
9292b948146SAndy Fiddaman 	}
9304c87aefeSPatrick Mooney 	case VM_ALLOC_MEMSEG: {
9314c87aefeSPatrick Mooney 		struct vm_memseg vmseg;
9324c87aefeSPatrick Mooney 
9334c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmseg, sizeof (vmseg), md)) {
9344c87aefeSPatrick Mooney 			error = EFAULT;
9354c87aefeSPatrick Mooney 			break;
9364c87aefeSPatrick Mooney 		}
9374c87aefeSPatrick Mooney 		error = vmmdev_alloc_memseg(sc, &vmseg);
9384c87aefeSPatrick Mooney 		break;
9394c87aefeSPatrick Mooney 	}
9404c87aefeSPatrick Mooney 	case VM_GET_MEMSEG: {
9414c87aefeSPatrick Mooney 		struct vm_memseg vmseg;
9424c87aefeSPatrick Mooney 
9434c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmseg, sizeof (vmseg), md)) {
9444c87aefeSPatrick Mooney 			error = EFAULT;
9454c87aefeSPatrick Mooney 			break;
9464c87aefeSPatrick Mooney 		}
9474c87aefeSPatrick Mooney 		error = vmmdev_get_memseg(sc, &vmseg);
9484c87aefeSPatrick Mooney 		if (error == 0 &&
9494c87aefeSPatrick Mooney 		    ddi_copyout(&vmseg, datap, sizeof (vmseg), md)) {
9504c87aefeSPatrick Mooney 			error = EFAULT;
9514c87aefeSPatrick Mooney 			break;
9524c87aefeSPatrick Mooney 		}
9534c87aefeSPatrick Mooney 		break;
9544c87aefeSPatrick Mooney 	}
9554c87aefeSPatrick Mooney 	case VM_GET_REGISTER: {
9564c87aefeSPatrick Mooney 		struct vm_register vmreg;
9574c87aefeSPatrick Mooney 
9584c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmreg, sizeof (vmreg), md)) {
9594c87aefeSPatrick Mooney 			error = EFAULT;
9604c87aefeSPatrick Mooney 			break;
9614c87aefeSPatrick Mooney 		}
9624c87aefeSPatrick Mooney 		error = vm_get_register(sc->vmm_vm, vcpu, vmreg.regnum,
9634c87aefeSPatrick Mooney 		    &vmreg.regval);
9644c87aefeSPatrick Mooney 		if (error == 0 &&
9654c87aefeSPatrick Mooney 		    ddi_copyout(&vmreg, datap, sizeof (vmreg), md)) {
9664c87aefeSPatrick Mooney 			error = EFAULT;
9674c87aefeSPatrick Mooney 			break;
9684c87aefeSPatrick Mooney 		}
9694c87aefeSPatrick Mooney 		break;
9704c87aefeSPatrick Mooney 	}
9714c87aefeSPatrick Mooney 	case VM_SET_REGISTER: {
9724c87aefeSPatrick Mooney 		struct vm_register vmreg;
9734c87aefeSPatrick Mooney 
9744c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmreg, sizeof (vmreg), md)) {
9754c87aefeSPatrick Mooney 			error = EFAULT;
9764c87aefeSPatrick Mooney 			break;
9774c87aefeSPatrick Mooney 		}
9784c87aefeSPatrick Mooney 		error = vm_set_register(sc->vmm_vm, vcpu, vmreg.regnum,
9794c87aefeSPatrick Mooney 		    vmreg.regval);
9804c87aefeSPatrick Mooney 		break;
9814c87aefeSPatrick Mooney 	}
9824c87aefeSPatrick Mooney 	case VM_SET_SEGMENT_DESCRIPTOR: {
9834c87aefeSPatrick Mooney 		struct vm_seg_desc vmsegd;
9844c87aefeSPatrick Mooney 
9854c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmsegd, sizeof (vmsegd), md)) {
9864c87aefeSPatrick Mooney 			error = EFAULT;
9874c87aefeSPatrick Mooney 			break;
9884c87aefeSPatrick Mooney 		}
9894c87aefeSPatrick Mooney 		error = vm_set_seg_desc(sc->vmm_vm, vcpu, vmsegd.regnum,
9904c87aefeSPatrick Mooney 		    &vmsegd.desc);
9914c87aefeSPatrick Mooney 		break;
9924c87aefeSPatrick Mooney 	}
9934c87aefeSPatrick Mooney 	case VM_GET_SEGMENT_DESCRIPTOR: {
9944c87aefeSPatrick Mooney 		struct vm_seg_desc vmsegd;
9954c87aefeSPatrick Mooney 
9964c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmsegd, sizeof (vmsegd), md)) {
9974c87aefeSPatrick Mooney 			error = EFAULT;
9984c87aefeSPatrick Mooney 			break;
9994c87aefeSPatrick Mooney 		}
10004c87aefeSPatrick Mooney 		error = vm_get_seg_desc(sc->vmm_vm, vcpu, vmsegd.regnum,
10014c87aefeSPatrick Mooney 		    &vmsegd.desc);
10024c87aefeSPatrick Mooney 		if (error == 0 &&
10034c87aefeSPatrick Mooney 		    ddi_copyout(&vmsegd, datap, sizeof (vmsegd), md)) {
10044c87aefeSPatrick Mooney 			error = EFAULT;
10054c87aefeSPatrick Mooney 			break;
10064c87aefeSPatrick Mooney 		}
10074c87aefeSPatrick Mooney 		break;
10084c87aefeSPatrick Mooney 	}
10094c87aefeSPatrick Mooney 	case VM_GET_REGISTER_SET: {
10104c87aefeSPatrick Mooney 		struct vm_register_set vrs;
10114c87aefeSPatrick Mooney 		int regnums[VM_REG_LAST];
10124c87aefeSPatrick Mooney 		uint64_t regvals[VM_REG_LAST];
10134c87aefeSPatrick Mooney 
10144c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vrs, sizeof (vrs), md)) {
10154c87aefeSPatrick Mooney 			error = EFAULT;
10164c87aefeSPatrick Mooney 			break;
10174c87aefeSPatrick Mooney 		}
10184c87aefeSPatrick Mooney 		if (vrs.count > VM_REG_LAST || vrs.count == 0) {
10194c87aefeSPatrick Mooney 			error = EINVAL;
10204c87aefeSPatrick Mooney 			break;
10214c87aefeSPatrick Mooney 		}
10224c87aefeSPatrick Mooney 		if (ddi_copyin(vrs.regnums, regnums,
10234c87aefeSPatrick Mooney 		    sizeof (int) * vrs.count, md)) {
10244c87aefeSPatrick Mooney 			error = EFAULT;
10254c87aefeSPatrick Mooney 			break;
10264c87aefeSPatrick Mooney 		}
10274c87aefeSPatrick Mooney 
10284c87aefeSPatrick Mooney 		error = 0;
10294c87aefeSPatrick Mooney 		for (uint_t i = 0; i < vrs.count && error == 0; i++) {
10304c87aefeSPatrick Mooney 			if (regnums[i] < 0) {
10314c87aefeSPatrick Mooney 				error = EINVAL;
10324c87aefeSPatrick Mooney 				break;
1033bf21cd93STycho Nightingale 			}
10344c87aefeSPatrick Mooney 			error = vm_get_register(sc->vmm_vm, vcpu, regnums[i],
10354c87aefeSPatrick Mooney 			    &regvals[i]);
10364c87aefeSPatrick Mooney 		}
10374c87aefeSPatrick Mooney 		if (error == 0 && ddi_copyout(regvals, vrs.regvals,
10384c87aefeSPatrick Mooney 		    sizeof (uint64_t) * vrs.count, md)) {
10394c87aefeSPatrick Mooney 			error = EFAULT;
1040bf21cd93STycho Nightingale 		}
1041bf21cd93STycho Nightingale 		break;
10424c87aefeSPatrick Mooney 	}
10434c87aefeSPatrick Mooney 	case VM_SET_REGISTER_SET: {
10444c87aefeSPatrick Mooney 		struct vm_register_set vrs;
10454c87aefeSPatrick Mooney 		int regnums[VM_REG_LAST];
10464c87aefeSPatrick Mooney 		uint64_t regvals[VM_REG_LAST];
10474c87aefeSPatrick Mooney 
10484c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vrs, sizeof (vrs), md)) {
10494c87aefeSPatrick Mooney 			error = EFAULT;
10504c87aefeSPatrick Mooney 			break;
1051bf21cd93STycho Nightingale 		}
10524c87aefeSPatrick Mooney 		if (vrs.count > VM_REG_LAST || vrs.count == 0) {
10534c87aefeSPatrick Mooney 			error = EINVAL;
10544c87aefeSPatrick Mooney 			break;
10554c87aefeSPatrick Mooney 		}
10564c87aefeSPatrick Mooney 		if (ddi_copyin(vrs.regnums, regnums,
10574c87aefeSPatrick Mooney 		    sizeof (int) * vrs.count, md)) {
10584c87aefeSPatrick Mooney 			error = EFAULT;
10594c87aefeSPatrick Mooney 			break;
10604c87aefeSPatrick Mooney 		}
10614c87aefeSPatrick Mooney 		if (ddi_copyin(vrs.regvals, regvals,
10624c87aefeSPatrick Mooney 		    sizeof (uint64_t) * vrs.count, md)) {
10634c87aefeSPatrick Mooney 			error = EFAULT;
10644c87aefeSPatrick Mooney 			break;
10654c87aefeSPatrick Mooney 		}
10664c87aefeSPatrick Mooney 
10674c87aefeSPatrick Mooney 		error = 0;
10684c87aefeSPatrick Mooney 		for (uint_t i = 0; i < vrs.count && error == 0; i++) {
10694c87aefeSPatrick Mooney 			/*
10704c87aefeSPatrick Mooney 			 * Setting registers in a set is not atomic, since a
10714c87aefeSPatrick Mooney 			 * failure in the middle of the set will cause a
10724c87aefeSPatrick Mooney 			 * bail-out and inconsistent register state.  Callers
10734c87aefeSPatrick Mooney 			 * should be wary of this.
10744c87aefeSPatrick Mooney 			 */
10754c87aefeSPatrick Mooney 			if (regnums[i] < 0) {
10764c87aefeSPatrick Mooney 				error = EINVAL;
10774c87aefeSPatrick Mooney 				break;
1078bf21cd93STycho Nightingale 			}
10794c87aefeSPatrick Mooney 			error = vm_set_register(sc->vmm_vm, vcpu, regnums[i],
10804c87aefeSPatrick Mooney 			    regvals[i]);
1081bf21cd93STycho Nightingale 		}
1082bf21cd93STycho Nightingale 		break;
10834c87aefeSPatrick Mooney 	}
10842606939dSPatrick Mooney 	case VM_RESET_CPU: {
10852606939dSPatrick Mooney 		struct vm_vcpu_reset vvr;
10862606939dSPatrick Mooney 
10872606939dSPatrick Mooney 		if (ddi_copyin(datap, &vvr, sizeof (vvr), md)) {
10882606939dSPatrick Mooney 			error = EFAULT;
10892606939dSPatrick Mooney 			break;
10902606939dSPatrick Mooney 		}
10912606939dSPatrick Mooney 		if (vvr.kind != VRK_RESET && vvr.kind != VRK_INIT) {
10922606939dSPatrick Mooney 			error = EINVAL;
10932606939dSPatrick Mooney 		}
10942606939dSPatrick Mooney 
10952606939dSPatrick Mooney 		error = vcpu_arch_reset(sc->vmm_vm, vcpu, vvr.kind == VRK_INIT);
10962606939dSPatrick Mooney 		break;
10972606939dSPatrick Mooney 	}
10982606939dSPatrick Mooney 	case VM_GET_RUN_STATE: {
10992606939dSPatrick Mooney 		struct vm_run_state vrs;
11002606939dSPatrick Mooney 
11012606939dSPatrick Mooney 		bzero(&vrs, sizeof (vrs));
11022606939dSPatrick Mooney 		error = vm_get_run_state(sc->vmm_vm, vcpu, &vrs.state,
11032606939dSPatrick Mooney 		    &vrs.sipi_vector);
11042606939dSPatrick Mooney 		if (error == 0) {
11052606939dSPatrick Mooney 			if (ddi_copyout(&vrs, datap, sizeof (vrs), md)) {
11062606939dSPatrick Mooney 				error = EFAULT;
11072606939dSPatrick Mooney 				break;
11082606939dSPatrick Mooney 			}
11092606939dSPatrick Mooney 		}
11102606939dSPatrick Mooney 		break;
11112606939dSPatrick Mooney 	}
11122606939dSPatrick Mooney 	case VM_SET_RUN_STATE: {
11132606939dSPatrick Mooney 		struct vm_run_state vrs;
11142606939dSPatrick Mooney 
11152606939dSPatrick Mooney 		if (ddi_copyin(datap, &vrs, sizeof (vrs), md)) {
11162606939dSPatrick Mooney 			error = EFAULT;
11172606939dSPatrick Mooney 			break;
11182606939dSPatrick Mooney 		}
11192606939dSPatrick Mooney 		error = vm_set_run_state(sc->vmm_vm, vcpu, vrs.state,
11202606939dSPatrick Mooney 		    vrs.sipi_vector);
11212606939dSPatrick Mooney 		break;
11222606939dSPatrick Mooney 	}
1123957246c9SPatrick Mooney 	case VM_GET_FPU: {
1124957246c9SPatrick Mooney 		struct vm_fpu_state req;
1125957246c9SPatrick Mooney 		const size_t max_len = (PAGESIZE * 2);
1126957246c9SPatrick Mooney 		void *kbuf;
1127957246c9SPatrick Mooney 
1128957246c9SPatrick Mooney 		if (ddi_copyin(datap, &req, sizeof (req), md)) {
1129957246c9SPatrick Mooney 			error = EFAULT;
1130957246c9SPatrick Mooney 			break;
1131957246c9SPatrick Mooney 		}
1132957246c9SPatrick Mooney 		if (req.len > max_len || req.len == 0) {
1133957246c9SPatrick Mooney 			error = EINVAL;
1134957246c9SPatrick Mooney 			break;
1135957246c9SPatrick Mooney 		}
1136957246c9SPatrick Mooney 		kbuf = kmem_zalloc(req.len, KM_SLEEP);
1137957246c9SPatrick Mooney 		error = vm_get_fpu(sc->vmm_vm, vcpu, kbuf, req.len);
1138957246c9SPatrick Mooney 		if (error == 0) {
1139957246c9SPatrick Mooney 			if (ddi_copyout(kbuf, req.buf, req.len, md)) {
1140957246c9SPatrick Mooney 				error = EFAULT;
1141957246c9SPatrick Mooney 			}
1142957246c9SPatrick Mooney 		}
1143957246c9SPatrick Mooney 		kmem_free(kbuf, req.len);
1144957246c9SPatrick Mooney 		break;
1145957246c9SPatrick Mooney 	}
1146957246c9SPatrick Mooney 	case VM_SET_FPU: {
1147957246c9SPatrick Mooney 		struct vm_fpu_state req;
1148957246c9SPatrick Mooney 		const size_t max_len = (PAGESIZE * 2);
1149957246c9SPatrick Mooney 		void *kbuf;
1150957246c9SPatrick Mooney 
1151957246c9SPatrick Mooney 		if (ddi_copyin(datap, &req, sizeof (req), md)) {
1152957246c9SPatrick Mooney 			error = EFAULT;
1153957246c9SPatrick Mooney 			break;
1154957246c9SPatrick Mooney 		}
1155957246c9SPatrick Mooney 		if (req.len > max_len || req.len == 0) {
1156957246c9SPatrick Mooney 			error = EINVAL;
1157957246c9SPatrick Mooney 			break;
1158957246c9SPatrick Mooney 		}
1159957246c9SPatrick Mooney 		kbuf = kmem_alloc(req.len, KM_SLEEP);
1160957246c9SPatrick Mooney 		if (ddi_copyin(req.buf, kbuf, req.len, md)) {
1161957246c9SPatrick Mooney 			error = EFAULT;
1162957246c9SPatrick Mooney 		} else {
1163957246c9SPatrick Mooney 			error = vm_set_fpu(sc->vmm_vm, vcpu, kbuf, req.len);
1164957246c9SPatrick Mooney 		}
1165957246c9SPatrick Mooney 		kmem_free(kbuf, req.len);
1166957246c9SPatrick Mooney 		break;
1167957246c9SPatrick Mooney 	}
11684c87aefeSPatrick Mooney 
1169154972afSPatrick Mooney 	case VM_SET_KERNEMU_DEV:
1170154972afSPatrick Mooney 	case VM_GET_KERNEMU_DEV: {
1171154972afSPatrick Mooney 		struct vm_readwrite_kernemu_device kemu;
1172154972afSPatrick Mooney 		size_t size = 0;
1173154972afSPatrick Mooney 
1174154972afSPatrick Mooney 		if (ddi_copyin(datap, &kemu, sizeof (kemu), md)) {
1175154972afSPatrick Mooney 			error = EFAULT;
1176154972afSPatrick Mooney 			break;
1177154972afSPatrick Mooney 		}
1178154972afSPatrick Mooney 
1179154972afSPatrick Mooney 		if (kemu.access_width > 3) {
1180154972afSPatrick Mooney 			error = EINVAL;
1181154972afSPatrick Mooney 			break;
1182154972afSPatrick Mooney 		}
1183154972afSPatrick Mooney 		size = (1 << kemu.access_width);
1184154972afSPatrick Mooney 		ASSERT(size >= 1 && size <= 8);
1185154972afSPatrick Mooney 
1186154972afSPatrick Mooney 		if (cmd == VM_SET_KERNEMU_DEV) {
1187e0c0d44eSPatrick Mooney 			error = vm_service_mmio_write(sc->vmm_vm, vcpu,
1188e0c0d44eSPatrick Mooney 			    kemu.gpa, kemu.value, size);
1189154972afSPatrick Mooney 		} else {
1190e0c0d44eSPatrick Mooney 			error = vm_service_mmio_read(sc->vmm_vm, vcpu,
1191e0c0d44eSPatrick Mooney 			    kemu.gpa, &kemu.value, size);
1192154972afSPatrick Mooney 		}
1193154972afSPatrick Mooney 
1194154972afSPatrick Mooney 		if (error == 0) {
1195154972afSPatrick Mooney 			if (ddi_copyout(&kemu, datap, sizeof (kemu), md)) {
1196154972afSPatrick Mooney 				error = EFAULT;
1197154972afSPatrick Mooney 				break;
1198154972afSPatrick Mooney 			}
1199154972afSPatrick Mooney 		}
1200154972afSPatrick Mooney 		break;
1201154972afSPatrick Mooney 	}
1202154972afSPatrick Mooney 
12034c87aefeSPatrick Mooney 	case VM_GET_CAPABILITY: {
12044c87aefeSPatrick Mooney 		struct vm_capability vmcap;
12054c87aefeSPatrick Mooney 
12064c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmcap, sizeof (vmcap), md)) {
12074c87aefeSPatrick Mooney 			error = EFAULT;
12084c87aefeSPatrick Mooney 			break;
12094c87aefeSPatrick Mooney 		}
12104c87aefeSPatrick Mooney 		error = vm_get_capability(sc->vmm_vm, vcpu, vmcap.captype,
12114c87aefeSPatrick Mooney 		    &vmcap.capval);
12124c87aefeSPatrick Mooney 		if (error == 0 &&
12134c87aefeSPatrick Mooney 		    ddi_copyout(&vmcap, datap, sizeof (vmcap), md)) {
12144c87aefeSPatrick Mooney 			error = EFAULT;
12154c87aefeSPatrick Mooney 			break;
1216bf21cd93STycho Nightingale 		}
1217bf21cd93STycho Nightingale 		break;
12184c87aefeSPatrick Mooney 	}
12194c87aefeSPatrick Mooney 	case VM_SET_CAPABILITY: {
12204c87aefeSPatrick Mooney 		struct vm_capability vmcap;
12214c87aefeSPatrick Mooney 
12224c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmcap, sizeof (vmcap), md)) {
12234c87aefeSPatrick Mooney 			error = EFAULT;
12244c87aefeSPatrick Mooney 			break;
1225bf21cd93STycho Nightingale 		}
12264c87aefeSPatrick Mooney 		error = vm_set_capability(sc->vmm_vm, vcpu, vmcap.captype,
12274c87aefeSPatrick Mooney 		    vmcap.capval);
1228bf21cd93STycho Nightingale 		break;
12294c87aefeSPatrick Mooney 	}
12304c87aefeSPatrick Mooney 	case VM_SET_X2APIC_STATE: {
12314c87aefeSPatrick Mooney 		struct vm_x2apic x2apic;
12324c87aefeSPatrick Mooney 
12334c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &x2apic, sizeof (x2apic), md)) {
12344c87aefeSPatrick Mooney 			error = EFAULT;
12354c87aefeSPatrick Mooney 			break;
1236bf21cd93STycho Nightingale 		}
12374c87aefeSPatrick Mooney 		error = vm_set_x2apic_state(sc->vmm_vm, vcpu, x2apic.state);
12384c87aefeSPatrick Mooney 		break;
12394c87aefeSPatrick Mooney 	}
12404c87aefeSPatrick Mooney 	case VM_GET_X2APIC_STATE: {
12414c87aefeSPatrick Mooney 		struct vm_x2apic x2apic;
12424c87aefeSPatrick Mooney 
12434c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &x2apic, sizeof (x2apic), md)) {
12444c87aefeSPatrick Mooney 			error = EFAULT;
12454c87aefeSPatrick Mooney 			break;
12464c87aefeSPatrick Mooney 		}
12474c87aefeSPatrick Mooney 		error = vm_get_x2apic_state(sc->vmm_vm, x2apic.cpuid,
12484c87aefeSPatrick Mooney 		    &x2apic.state);
12494c87aefeSPatrick Mooney 		if (error == 0 &&
12504c87aefeSPatrick Mooney 		    ddi_copyout(&x2apic, datap, sizeof (x2apic), md)) {
12514c87aefeSPatrick Mooney 			error = EFAULT;
12524c87aefeSPatrick Mooney 			break;
12534c87aefeSPatrick Mooney 		}
12544c87aefeSPatrick Mooney 		break;
12554c87aefeSPatrick Mooney 	}
12564c87aefeSPatrick Mooney 	case VM_GET_GPA_PMAP: {
12570153d828SPatrick Mooney 		/*
12580153d828SPatrick Mooney 		 * Until there is a necessity to leak EPT/RVI PTE values to
12590153d828SPatrick Mooney 		 * userspace, this will remain unimplemented
12600153d828SPatrick Mooney 		 */
12610153d828SPatrick Mooney 		error = EINVAL;
12624c87aefeSPatrick Mooney 		break;
12634c87aefeSPatrick Mooney 	}
12644c87aefeSPatrick Mooney 	case VM_GET_HPET_CAPABILITIES: {
12654c87aefeSPatrick Mooney 		struct vm_hpet_cap hpetcap;
12664c87aefeSPatrick Mooney 
12674c87aefeSPatrick Mooney 		error = vhpet_getcap(&hpetcap);
12684c87aefeSPatrick Mooney 		if (error == 0 &&
12694c87aefeSPatrick Mooney 		    ddi_copyout(&hpetcap, datap, sizeof (hpetcap), md)) {
12704c87aefeSPatrick Mooney 			error = EFAULT;
12714c87aefeSPatrick Mooney 			break;
1272bf21cd93STycho Nightingale 		}
1273bf21cd93STycho Nightingale 		break;
12744c87aefeSPatrick Mooney 	}
1275bf21cd93STycho Nightingale 	case VM_GLA2GPA: {
12764c87aefeSPatrick Mooney 		struct vm_gla2gpa gg;
12774c87aefeSPatrick Mooney 
12784c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &gg, sizeof (gg), md)) {
12794c87aefeSPatrick Mooney 			error = EFAULT;
12804c87aefeSPatrick Mooney 			break;
1281bf21cd93STycho Nightingale 		}
12824c87aefeSPatrick Mooney 		gg.vcpuid = vcpu;
12834c87aefeSPatrick Mooney 		error = vm_gla2gpa(sc->vmm_vm, vcpu, &gg.paging, gg.gla,
12844c87aefeSPatrick Mooney 		    gg.prot, &gg.gpa, &gg.fault);
12854c87aefeSPatrick Mooney 		if (error == 0 && ddi_copyout(&gg, datap, sizeof (gg), md)) {
12864c87aefeSPatrick Mooney 			error = EFAULT;
12874c87aefeSPatrick Mooney 			break;
12884c87aefeSPatrick Mooney 		}
12894c87aefeSPatrick Mooney 		break;
12904c87aefeSPatrick Mooney 	}
12914c87aefeSPatrick Mooney 	case VM_GLA2GPA_NOFAULT: {
12924c87aefeSPatrick Mooney 		struct vm_gla2gpa gg;
12934c87aefeSPatrick Mooney 
12944c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &gg, sizeof (gg), md)) {
12954c87aefeSPatrick Mooney 			error = EFAULT;
12964c87aefeSPatrick Mooney 			break;
12974c87aefeSPatrick Mooney 		}
12984c87aefeSPatrick Mooney 		gg.vcpuid = vcpu;
12994c87aefeSPatrick Mooney 		error = vm_gla2gpa_nofault(sc->vmm_vm, vcpu, &gg.paging,
13004c87aefeSPatrick Mooney 		    gg.gla, gg.prot, &gg.gpa, &gg.fault);
13014c87aefeSPatrick Mooney 		if (error == 0 && ddi_copyout(&gg, datap, sizeof (gg), md)) {
13024c87aefeSPatrick Mooney 			error = EFAULT;
13034c87aefeSPatrick Mooney 			break;
13044c87aefeSPatrick Mooney 		}
13054c87aefeSPatrick Mooney 		break;
13064c87aefeSPatrick Mooney 	}
13074c87aefeSPatrick Mooney 
13084c87aefeSPatrick Mooney 	case VM_ACTIVATE_CPU:
13094c87aefeSPatrick Mooney 		error = vm_activate_cpu(sc->vmm_vm, vcpu);
13104c87aefeSPatrick Mooney 		break;
13114c87aefeSPatrick Mooney 
13124c87aefeSPatrick Mooney 	case VM_SUSPEND_CPU:
13134c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vcpu, sizeof (vcpu), md)) {
13144c87aefeSPatrick Mooney 			error = EFAULT;
13154c87aefeSPatrick Mooney 		} else {
13164c87aefeSPatrick Mooney 			error = vm_suspend_cpu(sc->vmm_vm, vcpu);
13174c87aefeSPatrick Mooney 		}
13184c87aefeSPatrick Mooney 		break;
13194c87aefeSPatrick Mooney 
13204c87aefeSPatrick Mooney 	case VM_RESUME_CPU:
13214c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vcpu, sizeof (vcpu), md)) {
13224c87aefeSPatrick Mooney 			error = EFAULT;
13234c87aefeSPatrick Mooney 		} else {
13244c87aefeSPatrick Mooney 			error = vm_resume_cpu(sc->vmm_vm, vcpu);
13254c87aefeSPatrick Mooney 		}
13264c87aefeSPatrick Mooney 		break;
13274c87aefeSPatrick Mooney 
13284c87aefeSPatrick Mooney 	case VM_GET_CPUS: {
13294c87aefeSPatrick Mooney 		struct vm_cpuset vm_cpuset;
13304c87aefeSPatrick Mooney 		cpuset_t tempset;
13314c87aefeSPatrick Mooney 		void *srcp = &tempset;
13324c87aefeSPatrick Mooney 		int size;
13334c87aefeSPatrick Mooney 
13344c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vm_cpuset, sizeof (vm_cpuset), md)) {
13354c87aefeSPatrick Mooney 			error = EFAULT;
13364c87aefeSPatrick Mooney 			break;
13374c87aefeSPatrick Mooney 		}
13384c87aefeSPatrick Mooney 
13394c87aefeSPatrick Mooney 		/* Be more generous about sizing since our cpuset_t is large. */
13404c87aefeSPatrick Mooney 		size = vm_cpuset.cpusetsize;
13414c87aefeSPatrick Mooney 		if (size <= 0 || size > sizeof (cpuset_t)) {
13424c87aefeSPatrick Mooney 			error = ERANGE;
13434c87aefeSPatrick Mooney 		}
13444c87aefeSPatrick Mooney 		/*
13454c87aefeSPatrick Mooney 		 * If they want a ulong_t or less, make sure they receive the
13464c87aefeSPatrick Mooney 		 * low bits with all the useful information.
13474c87aefeSPatrick Mooney 		 */
13484c87aefeSPatrick Mooney 		if (size <= sizeof (tempset.cpub[0])) {
13494c87aefeSPatrick Mooney 			srcp = &tempset.cpub[0];
13504c87aefeSPatrick Mooney 		}
13514c87aefeSPatrick Mooney 
13524c87aefeSPatrick Mooney 		if (vm_cpuset.which == VM_ACTIVE_CPUS) {
13534c87aefeSPatrick Mooney 			tempset = vm_active_cpus(sc->vmm_vm);
13544c87aefeSPatrick Mooney 		} else if (vm_cpuset.which == VM_SUSPENDED_CPUS) {
13554c87aefeSPatrick Mooney 			tempset = vm_suspended_cpus(sc->vmm_vm);
13564c87aefeSPatrick Mooney 		} else if (vm_cpuset.which == VM_DEBUG_CPUS) {
13574c87aefeSPatrick Mooney 			tempset = vm_debug_cpus(sc->vmm_vm);
1358bf21cd93STycho Nightingale 		} else {
13594c87aefeSPatrick Mooney 			error = EINVAL;
13604c87aefeSPatrick Mooney 		}
13614c87aefeSPatrick Mooney 
13624c87aefeSPatrick Mooney 		ASSERT(size > 0 && size <= sizeof (tempset));
13634c87aefeSPatrick Mooney 		if (error == 0 &&
13644c87aefeSPatrick Mooney 		    ddi_copyout(srcp, vm_cpuset.cpus, size, md)) {
13654c87aefeSPatrick Mooney 			error = EFAULT;
13664c87aefeSPatrick Mooney 			break;
13674c87aefeSPatrick Mooney 		}
13684c87aefeSPatrick Mooney 		break;
13694c87aefeSPatrick Mooney 	}
13704c87aefeSPatrick Mooney 	case VM_SET_INTINFO: {
13714c87aefeSPatrick Mooney 		struct vm_intinfo vmii;
13724c87aefeSPatrick Mooney 
13734c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vmii, sizeof (vmii), md)) {
13744c87aefeSPatrick Mooney 			error = EFAULT;
13754c87aefeSPatrick Mooney 			break;
13764c87aefeSPatrick Mooney 		}
13774c87aefeSPatrick Mooney 		error = vm_exit_intinfo(sc->vmm_vm, vcpu, vmii.info1);
13784c87aefeSPatrick Mooney 		break;
13794c87aefeSPatrick Mooney 	}
13804c87aefeSPatrick Mooney 	case VM_GET_INTINFO: {
13814c87aefeSPatrick Mooney 		struct vm_intinfo vmii;
13824c87aefeSPatrick Mooney 
13834c87aefeSPatrick Mooney 		vmii.vcpuid = vcpu;
13844c87aefeSPatrick Mooney 		error = vm_get_intinfo(sc->vmm_vm, vcpu, &vmii.info1,
13854c87aefeSPatrick Mooney 		    &vmii.info2);
13864c87aefeSPatrick Mooney 		if (error == 0 &&
13874c87aefeSPatrick Mooney 		    ddi_copyout(&vmii, datap, sizeof (vmii), md)) {
13884c87aefeSPatrick Mooney 			error = EFAULT;
13894c87aefeSPatrick Mooney 			break;
13904c87aefeSPatrick Mooney 		}
13914c87aefeSPatrick Mooney 		break;
13924c87aefeSPatrick Mooney 	}
13934c87aefeSPatrick Mooney 	case VM_RTC_WRITE: {
13944c87aefeSPatrick Mooney 		struct vm_rtc_data rtcdata;
13954c87aefeSPatrick Mooney 
13964c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &rtcdata, sizeof (rtcdata), md)) {
13974c87aefeSPatrick Mooney 			error = EFAULT;
13984c87aefeSPatrick Mooney 			break;
13994c87aefeSPatrick Mooney 		}
14004c87aefeSPatrick Mooney 		error = vrtc_nvram_write(sc->vmm_vm, rtcdata.offset,
14014c87aefeSPatrick Mooney 		    rtcdata.value);
14024c87aefeSPatrick Mooney 		break;
14034c87aefeSPatrick Mooney 	}
14044c87aefeSPatrick Mooney 	case VM_RTC_READ: {
14054c87aefeSPatrick Mooney 		struct vm_rtc_data rtcdata;
14064c87aefeSPatrick Mooney 
14074c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &rtcdata, sizeof (rtcdata), md)) {
14084c87aefeSPatrick Mooney 			error = EFAULT;
14094c87aefeSPatrick Mooney 			break;
14104c87aefeSPatrick Mooney 		}
14114c87aefeSPatrick Mooney 		error = vrtc_nvram_read(sc->vmm_vm, rtcdata.offset,
14124c87aefeSPatrick Mooney 		    &rtcdata.value);
14134c87aefeSPatrick Mooney 		if (error == 0 &&
14144c87aefeSPatrick Mooney 		    ddi_copyout(&rtcdata, datap, sizeof (rtcdata), md)) {
14154c87aefeSPatrick Mooney 			error = EFAULT;
14164c87aefeSPatrick Mooney 			break;
14174c87aefeSPatrick Mooney 		}
14184c87aefeSPatrick Mooney 		break;
14194c87aefeSPatrick Mooney 	}
14204c87aefeSPatrick Mooney 	case VM_RTC_SETTIME: {
14214c87aefeSPatrick Mooney 		struct vm_rtc_time rtctime;
14224c87aefeSPatrick Mooney 
14234c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &rtctime, sizeof (rtctime), md)) {
14244c87aefeSPatrick Mooney 			error = EFAULT;
14254c87aefeSPatrick Mooney 			break;
14264c87aefeSPatrick Mooney 		}
14274c87aefeSPatrick Mooney 		error = vrtc_set_time(sc->vmm_vm, rtctime.secs);
14284c87aefeSPatrick Mooney 		break;
14294c87aefeSPatrick Mooney 	}
14304c87aefeSPatrick Mooney 	case VM_RTC_GETTIME: {
14314c87aefeSPatrick Mooney 		struct vm_rtc_time rtctime;
14324c87aefeSPatrick Mooney 
14334c87aefeSPatrick Mooney 		rtctime.secs = vrtc_get_time(sc->vmm_vm);
14344c87aefeSPatrick Mooney 		if (ddi_copyout(&rtctime, datap, sizeof (rtctime), md)) {
14354c87aefeSPatrick Mooney 			error = EFAULT;
14364c87aefeSPatrick Mooney 			break;
14374c87aefeSPatrick Mooney 		}
14384c87aefeSPatrick Mooney 		break;
14394c87aefeSPatrick Mooney 	}
14404c87aefeSPatrick Mooney 
14410e1453c3SPatrick Mooney 	case VM_PMTMR_LOCATE: {
14420e1453c3SPatrick Mooney 		uint16_t port = arg;
14430e1453c3SPatrick Mooney 		error = vpmtmr_set_location(sc->vmm_vm, port);
14440e1453c3SPatrick Mooney 		break;
14450e1453c3SPatrick Mooney 	}
14460e1453c3SPatrick Mooney 
14474c87aefeSPatrick Mooney 	case VM_RESTART_INSTRUCTION:
14484c87aefeSPatrick Mooney 		error = vm_restart_instruction(sc->vmm_vm, vcpu);
14494c87aefeSPatrick Mooney 		break;
14504c87aefeSPatrick Mooney 
14514c87aefeSPatrick Mooney 	case VM_SET_TOPOLOGY: {
14524c87aefeSPatrick Mooney 		struct vm_cpu_topology topo;
14534c87aefeSPatrick Mooney 
14544c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &topo, sizeof (topo), md) != 0) {
14554c87aefeSPatrick Mooney 			error = EFAULT;
14564c87aefeSPatrick Mooney 			break;
14574c87aefeSPatrick Mooney 		}
14584c87aefeSPatrick Mooney 		error = vm_set_topology(sc->vmm_vm, topo.sockets, topo.cores,
14594c87aefeSPatrick Mooney 		    topo.threads, topo.maxcpus);
14604c87aefeSPatrick Mooney 		break;
14614c87aefeSPatrick Mooney 	}
14624c87aefeSPatrick Mooney 	case VM_GET_TOPOLOGY: {
14634c87aefeSPatrick Mooney 		struct vm_cpu_topology topo;
14644c87aefeSPatrick Mooney 
14654c87aefeSPatrick Mooney 		vm_get_topology(sc->vmm_vm, &topo.sockets, &topo.cores,
14664c87aefeSPatrick Mooney 		    &topo.threads, &topo.maxcpus);
14674c87aefeSPatrick Mooney 		if (ddi_copyout(&topo, datap, sizeof (topo), md) != 0) {
14684c87aefeSPatrick Mooney 			error = EFAULT;
14694c87aefeSPatrick Mooney 			break;
14704c87aefeSPatrick Mooney 		}
14714c87aefeSPatrick Mooney 		break;
14724c87aefeSPatrick Mooney 	}
14734c87aefeSPatrick Mooney 	case VM_DEVMEM_GETOFFSET: {
14744c87aefeSPatrick Mooney 		struct vm_devmem_offset vdo;
14753d066281SPatrick Mooney 		vmm_devmem_entry_t *de;
14764c87aefeSPatrick Mooney 
14774c87aefeSPatrick Mooney 		if (ddi_copyin(datap, &vdo, sizeof (vdo), md) != 0) {
1478bf21cd93STycho Nightingale 			error = EFAULT;
14794c87aefeSPatrick Mooney 			break;
14804c87aefeSPatrick Mooney 		}
14814c87aefeSPatrick Mooney 
14823d066281SPatrick Mooney 		de = vmmdev_devmem_find(sc, vdo.segid);
14834c87aefeSPatrick Mooney 		if (de != NULL) {
14844c87aefeSPatrick Mooney 			vdo.offset = de->vde_off;
14854c87aefeSPatrick Mooney 			if (ddi_copyout(&vdo, datap, sizeof (vdo), md) != 0) {
14864c87aefeSPatrick Mooney 				error = EFAULT;
14874c87aefeSPatrick Mooney 			}
14884c87aefeSPatrick Mooney 		} else {
14894c87aefeSPatrick Mooney 			error = ENOENT;
1490bf21cd93STycho Nightingale 		}
1491bf21cd93STycho Nightingale 		break;
1492bf21cd93STycho Nightingale 	}
14938779b448SDan Cross 	case VM_TRACK_DIRTY_PAGES: {
14948779b448SDan Cross 		const size_t max_track_region_len = 8 * PAGESIZE * 8 * PAGESIZE;
14958779b448SDan Cross 		struct vmm_dirty_tracker tracker;
14968779b448SDan Cross 		uint8_t *bitmap;
14978779b448SDan Cross 		size_t len;
14988779b448SDan Cross 
14998779b448SDan Cross 		if (ddi_copyin(datap, &tracker, sizeof (tracker), md) != 0) {
15008779b448SDan Cross 			error = EFAULT;
15018779b448SDan Cross 			break;
15028779b448SDan Cross 		}
15038779b448SDan Cross 		if ((tracker.vdt_start_gpa & PAGEOFFSET) != 0) {
15048779b448SDan Cross 			error = EINVAL;
15058779b448SDan Cross 			break;
15068779b448SDan Cross 		}
15078779b448SDan Cross 		if (tracker.vdt_len == 0) {
15088779b448SDan Cross 			break;
15098779b448SDan Cross 		}
15108779b448SDan Cross 		if ((tracker.vdt_len & PAGEOFFSET) != 0) {
15118779b448SDan Cross 			error = EINVAL;
15128779b448SDan Cross 			break;
15138779b448SDan Cross 		}
15148779b448SDan Cross 		if (tracker.vdt_len > max_track_region_len) {
15158779b448SDan Cross 			error = EINVAL;
15168779b448SDan Cross 			break;
15178779b448SDan Cross 		}
15188779b448SDan Cross 		len = roundup(tracker.vdt_len / PAGESIZE, 8) / 8;
15198779b448SDan Cross 		bitmap = kmem_zalloc(len, KM_SLEEP);
15208779b448SDan Cross 		vm_track_dirty_pages(sc->vmm_vm, tracker.vdt_start_gpa,
15218779b448SDan Cross 		    tracker.vdt_len, bitmap);
15228779b448SDan Cross 		if (ddi_copyout(bitmap, tracker.vdt_pfns, len, md) != 0) {
15238779b448SDan Cross 			error = EFAULT;
15248779b448SDan Cross 		}
15258779b448SDan Cross 		kmem_free(bitmap, len);
15268779b448SDan Cross 
15278779b448SDan Cross 		break;
15288779b448SDan Cross 	}
15294c87aefeSPatrick Mooney 	case VM_WRLOCK_CYCLE: {
15304c87aefeSPatrick Mooney 		/*
15314c87aefeSPatrick Mooney 		 * Present a test mechanism to acquire/release the write lock
15324c87aefeSPatrick Mooney 		 * on the VM without any other effects.
15334c87aefeSPatrick Mooney 		 */
15344c87aefeSPatrick Mooney 		break;
15354c87aefeSPatrick Mooney 	}
1536d515dd77SPatrick Mooney 	case VM_DATA_READ: {
1537d515dd77SPatrick Mooney 		struct vm_data_xfer vdx;
1538d515dd77SPatrick Mooney 
1539d515dd77SPatrick Mooney 		if (ddi_copyin(datap, &vdx, sizeof (vdx), md) != 0) {
1540d515dd77SPatrick Mooney 			error = EFAULT;
1541d515dd77SPatrick Mooney 			break;
1542d515dd77SPatrick Mooney 		}
1543d515dd77SPatrick Mooney 		if ((vdx.vdx_flags & ~VDX_FLAGS_VALID) != 0) {
1544d515dd77SPatrick Mooney 			error = EINVAL;
1545d515dd77SPatrick Mooney 			break;
1546d515dd77SPatrick Mooney 		}
1547d515dd77SPatrick Mooney 		if (vdx.vdx_len > VM_DATA_XFER_LIMIT) {
1548d515dd77SPatrick Mooney 			error = EFBIG;
1549d515dd77SPatrick Mooney 			break;
1550d515dd77SPatrick Mooney 		}
1551d515dd77SPatrick Mooney 
1552d515dd77SPatrick Mooney 		const size_t len = vdx.vdx_len;
1553*54cf5b63SPatrick Mooney 		void *buf = NULL;
1554*54cf5b63SPatrick Mooney 		if (len != 0) {
1555*54cf5b63SPatrick Mooney 			buf = kmem_alloc(len, KM_SLEEP);
1556*54cf5b63SPatrick Mooney 			if ((vdx.vdx_flags & VDX_FLAG_READ_COPYIN) != 0 &&
1557*54cf5b63SPatrick Mooney 			    ddi_copyin(vdx.vdx_data, buf, len, md) != 0) {
1558d515dd77SPatrick Mooney 				kmem_free(buf, len);
1559d515dd77SPatrick Mooney 				error = EFAULT;
1560d515dd77SPatrick Mooney 				break;
1561*54cf5b63SPatrick Mooney 			} else {
1562*54cf5b63SPatrick Mooney 				bzero(buf, len);
1563d515dd77SPatrick Mooney 			}
1564d515dd77SPatrick Mooney 		}
1565d515dd77SPatrick Mooney 
1566*54cf5b63SPatrick Mooney 		vdx.vdx_result_len = 0;
1567d515dd77SPatrick Mooney 		vmm_data_req_t req = {
1568d515dd77SPatrick Mooney 			.vdr_class = vdx.vdx_class,
1569d515dd77SPatrick Mooney 			.vdr_version = vdx.vdx_version,
1570d515dd77SPatrick Mooney 			.vdr_flags = vdx.vdx_flags,
1571*54cf5b63SPatrick Mooney 			.vdr_len = len,
1572d515dd77SPatrick Mooney 			.vdr_data = buf,
1573*54cf5b63SPatrick Mooney 			.vdr_result_len = &vdx.vdx_result_len,
1574d515dd77SPatrick Mooney 		};
1575d515dd77SPatrick Mooney 		error = vmm_data_read(sc->vmm_vm, vdx.vdx_vcpuid, &req);
1576d515dd77SPatrick Mooney 
1577*54cf5b63SPatrick Mooney 		if (error == 0 && buf != NULL) {
1578d515dd77SPatrick Mooney 			if (ddi_copyout(buf, vdx.vdx_data, len, md) != 0) {
1579d515dd77SPatrick Mooney 				error = EFAULT;
1580d515dd77SPatrick Mooney 			}
1581d515dd77SPatrick Mooney 		}
1582*54cf5b63SPatrick Mooney 
1583*54cf5b63SPatrick Mooney 		/*
1584*54cf5b63SPatrick Mooney 		 * Copy out the transfer request so that the value of
1585*54cf5b63SPatrick Mooney 		 * vdx_result_len can be made available, regardless of any
1586*54cf5b63SPatrick Mooney 		 * error(s) which may have occurred.
1587*54cf5b63SPatrick Mooney 		 */
1588*54cf5b63SPatrick Mooney 		if (ddi_copyout(&vdx, datap, sizeof (vdx), md) != 0) {
1589*54cf5b63SPatrick Mooney 			error = (error != 0) ? error : EFAULT;
1590*54cf5b63SPatrick Mooney 		}
1591*54cf5b63SPatrick Mooney 
1592*54cf5b63SPatrick Mooney 		if (buf != NULL) {
1593*54cf5b63SPatrick Mooney 			kmem_free(buf, len);
1594*54cf5b63SPatrick Mooney 		}
1595d515dd77SPatrick Mooney 		break;
1596d515dd77SPatrick Mooney 	}
1597d515dd77SPatrick Mooney 	case VM_DATA_WRITE: {
1598d515dd77SPatrick Mooney 		struct vm_data_xfer vdx;
1599d515dd77SPatrick Mooney 
1600d515dd77SPatrick Mooney 		if (ddi_copyin(datap, &vdx, sizeof (vdx), md) != 0) {
1601d515dd77SPatrick Mooney 			error = EFAULT;
1602d515dd77SPatrick Mooney 			break;
1603d515dd77SPatrick Mooney 		}
1604d515dd77SPatrick Mooney 		if ((vdx.vdx_flags & ~VDX_FLAGS_VALID) != 0) {
1605d515dd77SPatrick Mooney 			error = EINVAL;
1606d515dd77SPatrick Mooney 			break;
1607d515dd77SPatrick Mooney 		}
1608d515dd77SPatrick Mooney 		if (vdx.vdx_len > VM_DATA_XFER_LIMIT) {
1609d515dd77SPatrick Mooney 			error = EFBIG;
1610d515dd77SPatrick Mooney 			break;
1611d515dd77SPatrick Mooney 		}
1612d515dd77SPatrick Mooney 
1613d515dd77SPatrick Mooney 		const size_t len = vdx.vdx_len;
1614*54cf5b63SPatrick Mooney 		void *buf = NULL;
1615*54cf5b63SPatrick Mooney 		if (len != 0) {
1616*54cf5b63SPatrick Mooney 			buf = kmem_alloc(len, KM_SLEEP);
1617*54cf5b63SPatrick Mooney 			if (ddi_copyin(vdx.vdx_data, buf, len, md) != 0) {
1618*54cf5b63SPatrick Mooney 				kmem_free(buf, len);
1619*54cf5b63SPatrick Mooney 				error = EFAULT;
1620*54cf5b63SPatrick Mooney 				break;
1621*54cf5b63SPatrick Mooney 			}
1622d515dd77SPatrick Mooney 		}
1623d515dd77SPatrick Mooney 
1624*54cf5b63SPatrick Mooney 		vdx.vdx_result_len = 0;
1625d515dd77SPatrick Mooney 		vmm_data_req_t req = {
1626d515dd77SPatrick Mooney 			.vdr_class = vdx.vdx_class,
1627d515dd77SPatrick Mooney 			.vdr_version = vdx.vdx_version,
1628d515dd77SPatrick Mooney 			.vdr_flags = vdx.vdx_flags,
1629*54cf5b63SPatrick Mooney 			.vdr_len = len,
1630d515dd77SPatrick Mooney 			.vdr_data = buf,
1631*54cf5b63SPatrick Mooney 			.vdr_result_len = &vdx.vdx_result_len,
1632d515dd77SPatrick Mooney 		};
1633d515dd77SPatrick Mooney 		if (vmm_allow_state_writes == 0) {
1634d515dd77SPatrick Mooney 			/* XXX: Play it safe for now */
1635d515dd77SPatrick Mooney 			error = EPERM;
1636d515dd77SPatrick Mooney 		} else {
1637d515dd77SPatrick Mooney 			error = vmm_data_write(sc->vmm_vm, vdx.vdx_vcpuid,
1638d515dd77SPatrick Mooney 			    &req);
1639d515dd77SPatrick Mooney 		}
1640d515dd77SPatrick Mooney 
1641*54cf5b63SPatrick Mooney 		if (error == 0 && buf != NULL &&
1642d515dd77SPatrick Mooney 		    (vdx.vdx_flags & VDX_FLAG_WRITE_COPYOUT) != 0) {
1643d515dd77SPatrick Mooney 			if (ddi_copyout(buf, vdx.vdx_data, len, md) != 0) {
1644d515dd77SPatrick Mooney 				error = EFAULT;
1645d515dd77SPatrick Mooney 			}
1646d515dd77SPatrick Mooney 		}
1647*54cf5b63SPatrick Mooney 
1648*54cf5b63SPatrick Mooney 		/*
1649*54cf5b63SPatrick Mooney 		 * Copy out the transfer request so that the value of
1650*54cf5b63SPatrick Mooney 		 * vdx_result_len can be made available, regardless of any
1651*54cf5b63SPatrick Mooney 		 * error(s) which may have occurred.
1652*54cf5b63SPatrick Mooney 		 */
1653*54cf5b63SPatrick Mooney 		if (ddi_copyout(&vdx, datap, sizeof (vdx), md) != 0) {
1654*54cf5b63SPatrick Mooney 			error = (error != 0) ? error : EFAULT;
1655*54cf5b63SPatrick Mooney 		}
1656*54cf5b63SPatrick Mooney 
1657*54cf5b63SPatrick Mooney 		if (buf != NULL) {
1658*54cf5b63SPatrick Mooney 			kmem_free(buf, len);
1659*54cf5b63SPatrick Mooney 		}
1660d515dd77SPatrick Mooney 		break;
1661d515dd77SPatrick Mooney 	}
1662f703164bSPatrick Mooney 
16634c87aefeSPatrick Mooney 	default:
16644c87aefeSPatrick Mooney 		error = ENOTTY;
16654c87aefeSPatrick Mooney 		break;
16664c87aefeSPatrick Mooney 	}
16674c87aefeSPatrick Mooney 
16684c87aefeSPatrick Mooney 	/* Release exclusion resources */
16694c87aefeSPatrick Mooney 	switch (lock_type) {
16704c87aefeSPatrick Mooney 	case LOCK_NONE:
16714c87aefeSPatrick Mooney 		break;
16724c87aefeSPatrick Mooney 	case LOCK_VCPU:
16734c87aefeSPatrick Mooney 		vcpu_unlock_one(sc, vcpu);
16744c87aefeSPatrick Mooney 		break;
16754c87aefeSPatrick Mooney 	case LOCK_READ_HOLD:
16764c87aefeSPatrick Mooney 		vmm_read_unlock(sc);
16774c87aefeSPatrick Mooney 		break;
16784c87aefeSPatrick Mooney 	case LOCK_WRITE_HOLD:
16794c87aefeSPatrick Mooney 		vmm_write_unlock(sc);
16804c87aefeSPatrick Mooney 		break;
16814c87aefeSPatrick Mooney 	default:
16824c87aefeSPatrick Mooney 		panic("unexpected lock type");
16834c87aefeSPatrick Mooney 		break;
16844c87aefeSPatrick Mooney 	}
16854c87aefeSPatrick Mooney 
16864c87aefeSPatrick Mooney 	return (error);
16874c87aefeSPatrick Mooney }
16884c87aefeSPatrick Mooney 
16894c87aefeSPatrick Mooney static vmm_softc_t *
16904c87aefeSPatrick Mooney vmm_lookup(const char *name)
16914c87aefeSPatrick Mooney {
16924c87aefeSPatrick Mooney 	list_t *vml = &vmm_list;
16934c87aefeSPatrick Mooney 	vmm_softc_t *sc;
16944c87aefeSPatrick Mooney 
16954c87aefeSPatrick Mooney 	ASSERT(MUTEX_HELD(&vmm_mtx));
16964c87aefeSPatrick Mooney 
16974c87aefeSPatrick Mooney 	for (sc = list_head(vml); sc != NULL; sc = list_next(vml, sc)) {
16984c87aefeSPatrick Mooney 		if (strcmp(sc->vmm_name, name) == 0) {
16994c87aefeSPatrick Mooney 			break;
17004c87aefeSPatrick Mooney 		}
17014c87aefeSPatrick Mooney 	}
17024c87aefeSPatrick Mooney 
17034c87aefeSPatrick Mooney 	return (sc);
17044c87aefeSPatrick Mooney }
17054c87aefeSPatrick Mooney 
17068e3a263eSAndy Fiddaman /*
17078e3a263eSAndy Fiddaman  * Acquire an HMA registration if not already held.
17088e3a263eSAndy Fiddaman  */
17098e3a263eSAndy Fiddaman static boolean_t
17108e3a263eSAndy Fiddaman vmm_hma_acquire(void)
17118e3a263eSAndy Fiddaman {
17128e3a263eSAndy Fiddaman 	ASSERT(MUTEX_NOT_HELD(&vmm_mtx));
17138e3a263eSAndy Fiddaman 
17148e3a263eSAndy Fiddaman 	mutex_enter(&vmmdev_mtx);
17158e3a263eSAndy Fiddaman 
17168e3a263eSAndy Fiddaman 	if (vmmdev_hma_reg == NULL) {
17178e3a263eSAndy Fiddaman 		VERIFY3U(vmmdev_hma_ref, ==, 0);
17188e3a263eSAndy Fiddaman 		vmmdev_hma_reg = hma_register(vmmdev_hvm_name);
17198e3a263eSAndy Fiddaman 		if (vmmdev_hma_reg == NULL) {
17208e3a263eSAndy Fiddaman 			cmn_err(CE_WARN, "%s HMA registration failed.",
17218e3a263eSAndy Fiddaman 			    vmmdev_hvm_name);
17228e3a263eSAndy Fiddaman 			mutex_exit(&vmmdev_mtx);
17238e3a263eSAndy Fiddaman 			return (B_FALSE);
17248e3a263eSAndy Fiddaman 		}
17258e3a263eSAndy Fiddaman 	}
17268e3a263eSAndy Fiddaman 
17278e3a263eSAndy Fiddaman 	vmmdev_hma_ref++;
17288e3a263eSAndy Fiddaman 
17298e3a263eSAndy Fiddaman 	mutex_exit(&vmmdev_mtx);
17308e3a263eSAndy Fiddaman 
17318e3a263eSAndy Fiddaman 	return (B_TRUE);
17328e3a263eSAndy Fiddaman }
17338e3a263eSAndy Fiddaman 
17348e3a263eSAndy Fiddaman /*
17358e3a263eSAndy Fiddaman  * Release the HMA registration if held and there are no remaining VMs.
17368e3a263eSAndy Fiddaman  */
17378e3a263eSAndy Fiddaman static void
17388e3a263eSAndy Fiddaman vmm_hma_release(void)
17398e3a263eSAndy Fiddaman {
17408e3a263eSAndy Fiddaman 	ASSERT(MUTEX_NOT_HELD(&vmm_mtx));
17418e3a263eSAndy Fiddaman 
17428e3a263eSAndy Fiddaman 	mutex_enter(&vmmdev_mtx);
17438e3a263eSAndy Fiddaman 
17448e3a263eSAndy Fiddaman 	VERIFY3U(vmmdev_hma_ref, !=, 0);
17458e3a263eSAndy Fiddaman 
17468e3a263eSAndy Fiddaman 	vmmdev_hma_ref--;
17478e3a263eSAndy Fiddaman 
17488e3a263eSAndy Fiddaman 	if (vmmdev_hma_ref == 0) {
17498e3a263eSAndy Fiddaman 		VERIFY(vmmdev_hma_reg != NULL);
17508e3a263eSAndy Fiddaman 		hma_unregister(vmmdev_hma_reg);
17518e3a263eSAndy Fiddaman 		vmmdev_hma_reg = NULL;
17528e3a263eSAndy Fiddaman 	}
17538e3a263eSAndy Fiddaman 	mutex_exit(&vmmdev_mtx);
17548e3a263eSAndy Fiddaman }
17558e3a263eSAndy Fiddaman 
17564c87aefeSPatrick Mooney static int
1757b57f5d3eSPatrick Mooney vmmdev_do_vm_create(const struct vm_create_req *req, cred_t *cr)
17584c87aefeSPatrick Mooney {
17594c87aefeSPatrick Mooney 	vmm_softc_t	*sc = NULL;
17604c87aefeSPatrick Mooney 	minor_t		minor;
17614c87aefeSPatrick Mooney 	int		error = ENOMEM;
1762b57f5d3eSPatrick Mooney 	size_t		len;
1763b57f5d3eSPatrick Mooney 	const char	*name = req->name;
17644c87aefeSPatrick Mooney 
1765b57f5d3eSPatrick Mooney 	len = strnlen(name, VM_MAX_NAMELEN);
1766b57f5d3eSPatrick Mooney 	if (len == 0) {
1767b57f5d3eSPatrick Mooney 		return (EINVAL);
1768b57f5d3eSPatrick Mooney 	}
1769b57f5d3eSPatrick Mooney 	if (len >= VM_MAX_NAMELEN) {
1770b57f5d3eSPatrick Mooney 		return (ENAMETOOLONG);
1771b57f5d3eSPatrick Mooney 	}
1772b57f5d3eSPatrick Mooney 	if (strchr(name, '/') != NULL) {
17734c87aefeSPatrick Mooney 		return (EINVAL);
17744c87aefeSPatrick Mooney 	}
17754c87aefeSPatrick Mooney 
17768e3a263eSAndy Fiddaman 	if (!vmm_hma_acquire())
17778e3a263eSAndy Fiddaman 		return (ENXIO);
17788e3a263eSAndy Fiddaman 
17794c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
17804c87aefeSPatrick Mooney 
17818e3a263eSAndy Fiddaman 	/* Look for duplicate names */
17824c87aefeSPatrick Mooney 	if (vmm_lookup(name) != NULL) {
17834c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
17848e3a263eSAndy Fiddaman 		vmm_hma_release();
17854c87aefeSPatrick Mooney 		return (EEXIST);
17864c87aefeSPatrick Mooney 	}
17874c87aefeSPatrick Mooney 
17884c87aefeSPatrick Mooney 	/* Allow only one instance per non-global zone. */
17894c87aefeSPatrick Mooney 	if (!INGLOBALZONE(curproc)) {
17904c87aefeSPatrick Mooney 		for (sc = list_head(&vmm_list); sc != NULL;
17914c87aefeSPatrick Mooney 		    sc = list_next(&vmm_list, sc)) {
17924c87aefeSPatrick Mooney 			if (sc->vmm_zone == curzone) {
17934c87aefeSPatrick Mooney 				mutex_exit(&vmm_mtx);
17948e3a263eSAndy Fiddaman 				vmm_hma_release();
17954c87aefeSPatrick Mooney 				return (EINVAL);
17964c87aefeSPatrick Mooney 			}
17974c87aefeSPatrick Mooney 		}
17984c87aefeSPatrick Mooney 	}
17994c87aefeSPatrick Mooney 
18004c87aefeSPatrick Mooney 	minor = id_alloc(vmm_minors);
18014c87aefeSPatrick Mooney 	if (ddi_soft_state_zalloc(vmm_statep, minor) != DDI_SUCCESS) {
18024c87aefeSPatrick Mooney 		goto fail;
18034c87aefeSPatrick Mooney 	} else if ((sc = ddi_get_soft_state(vmm_statep, minor)) == NULL) {
18044c87aefeSPatrick Mooney 		ddi_soft_state_free(vmm_statep, minor);
18054c87aefeSPatrick Mooney 		goto fail;
18064c87aefeSPatrick Mooney 	} else if (ddi_create_minor_node(vmmdev_dip, name, S_IFCHR, minor,
18074c87aefeSPatrick Mooney 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
18084c87aefeSPatrick Mooney 		goto fail;
18094c87aefeSPatrick Mooney 	}
18104c87aefeSPatrick Mooney 
181159460b49SPatrick Mooney 	if (vmm_kstat_alloc(sc, minor, cr) != 0) {
181259460b49SPatrick Mooney 		goto fail;
181359460b49SPatrick Mooney 	}
181459460b49SPatrick Mooney 
1815d4f59ae5SPatrick Mooney 	error = vm_create(req->flags, &sc->vmm_vm);
18164c87aefeSPatrick Mooney 	if (error == 0) {
18174c87aefeSPatrick Mooney 		/* Complete VM intialization and report success. */
18184c87aefeSPatrick Mooney 		(void) strlcpy(sc->vmm_name, name, sizeof (sc->vmm_name));
18194c87aefeSPatrick Mooney 		sc->vmm_minor = minor;
18204c87aefeSPatrick Mooney 		list_create(&sc->vmm_devmem_list, sizeof (vmm_devmem_entry_t),
18214c87aefeSPatrick Mooney 		    offsetof(vmm_devmem_entry_t, vde_node));
18224c87aefeSPatrick Mooney 
18234c87aefeSPatrick Mooney 		list_create(&sc->vmm_holds, sizeof (vmm_hold_t),
18244c87aefeSPatrick Mooney 		    offsetof(vmm_hold_t, vmh_node));
18254c87aefeSPatrick Mooney 		cv_init(&sc->vmm_cv, NULL, CV_DEFAULT, NULL);
18264c87aefeSPatrick Mooney 
18274c87aefeSPatrick Mooney 		mutex_init(&sc->vmm_lease_lock, NULL, MUTEX_DEFAULT, NULL);
18284c87aefeSPatrick Mooney 		list_create(&sc->vmm_lease_list, sizeof (vmm_lease_t),
18294c87aefeSPatrick Mooney 		    offsetof(vmm_lease_t, vml_node));
18304c87aefeSPatrick Mooney 		cv_init(&sc->vmm_lease_cv, NULL, CV_DEFAULT, NULL);
18314c87aefeSPatrick Mooney 		rw_init(&sc->vmm_rwlock, NULL, RW_DEFAULT, NULL);
18324c87aefeSPatrick Mooney 
18334c87aefeSPatrick Mooney 		sc->vmm_zone = crgetzone(cr);
18344c87aefeSPatrick Mooney 		zone_hold(sc->vmm_zone);
18354c87aefeSPatrick Mooney 		vmm_zsd_add_vm(sc);
183659460b49SPatrick Mooney 		vmm_kstat_init(sc);
18374c87aefeSPatrick Mooney 
18384c87aefeSPatrick Mooney 		list_insert_tail(&vmm_list, sc);
18394c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
18404c87aefeSPatrick Mooney 		return (0);
18414c87aefeSPatrick Mooney 	}
18424c87aefeSPatrick Mooney 
184359460b49SPatrick Mooney 	vmm_kstat_fini(sc);
18444c87aefeSPatrick Mooney 	ddi_remove_minor_node(vmmdev_dip, name);
18454c87aefeSPatrick Mooney fail:
18464c87aefeSPatrick Mooney 	id_free(vmm_minors, minor);
18474c87aefeSPatrick Mooney 	if (sc != NULL) {
18484c87aefeSPatrick Mooney 		ddi_soft_state_free(vmm_statep, minor);
18494c87aefeSPatrick Mooney 	}
18504c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
18518e3a263eSAndy Fiddaman 	vmm_hma_release();
18524c87aefeSPatrick Mooney 
18534c87aefeSPatrick Mooney 	return (error);
18544c87aefeSPatrick Mooney }
18554c87aefeSPatrick Mooney 
18564c87aefeSPatrick Mooney /*
18574c87aefeSPatrick Mooney  * Bhyve 'Driver' Interface
18584c87aefeSPatrick Mooney  *
18594c87aefeSPatrick Mooney  * While many devices are emulated in the bhyve userspace process, there are
18604c87aefeSPatrick Mooney  * others with performance constraints which require that they run mostly or
18614c87aefeSPatrick Mooney  * entirely in-kernel.  For those not integrated directly into bhyve, an API is
18624c87aefeSPatrick Mooney  * needed so they can query/manipulate the portions of VM state needed to
18634c87aefeSPatrick Mooney  * fulfill their purpose.
18644c87aefeSPatrick Mooney  *
18654c87aefeSPatrick Mooney  * This includes:
18664c87aefeSPatrick Mooney  * - Translating guest-physical addresses to host-virtual pointers
18674c87aefeSPatrick Mooney  * - Injecting MSIs
18684c87aefeSPatrick Mooney  * - Hooking IO port addresses
18694c87aefeSPatrick Mooney  *
18704c87aefeSPatrick Mooney  * The vmm_drv interface exists to provide that functionality to its consumers.
18714c87aefeSPatrick Mooney  * (At this time, 'viona' is the only user)
18724c87aefeSPatrick Mooney  */
18734c87aefeSPatrick Mooney int
18744c87aefeSPatrick Mooney vmm_drv_hold(file_t *fp, cred_t *cr, vmm_hold_t **holdp)
18754c87aefeSPatrick Mooney {
18764c87aefeSPatrick Mooney 	vnode_t *vp = fp->f_vnode;
18774c87aefeSPatrick Mooney 	const dev_t dev = vp->v_rdev;
18784c87aefeSPatrick Mooney 	vmm_softc_t *sc;
18794c87aefeSPatrick Mooney 	vmm_hold_t *hold;
18804c87aefeSPatrick Mooney 	int err = 0;
18814c87aefeSPatrick Mooney 
18824c87aefeSPatrick Mooney 	if (vp->v_type != VCHR) {
18834c87aefeSPatrick Mooney 		return (ENXIO);
18844c87aefeSPatrick Mooney 	}
18854c87aefeSPatrick Mooney 	const major_t major = getmajor(dev);
18864c87aefeSPatrick Mooney 	const minor_t minor = getminor(dev);
18874c87aefeSPatrick Mooney 
18884c87aefeSPatrick Mooney 	mutex_enter(&vmmdev_mtx);
18894c87aefeSPatrick Mooney 	if (vmmdev_dip == NULL || major != ddi_driver_major(vmmdev_dip)) {
18904c87aefeSPatrick Mooney 		mutex_exit(&vmmdev_mtx);
18914c87aefeSPatrick Mooney 		return (ENOENT);
1892bf21cd93STycho Nightingale 	}
18934c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
18944c87aefeSPatrick Mooney 	mutex_exit(&vmmdev_mtx);
1895bf21cd93STycho Nightingale 
18964c87aefeSPatrick Mooney 	if ((sc = ddi_get_soft_state(vmm_statep, minor)) == NULL) {
18974c87aefeSPatrick Mooney 		err = ENOENT;
18984c87aefeSPatrick Mooney 		goto out;
1899bf21cd93STycho Nightingale 	}
19004c87aefeSPatrick Mooney 	/* XXXJOY: check cred permissions against instance */
1901bf21cd93STycho Nightingale 
19024c87aefeSPatrick Mooney 	if ((sc->vmm_flags & (VMM_CLEANUP|VMM_PURGED|VMM_DESTROY)) != 0) {
19034c87aefeSPatrick Mooney 		err = EBUSY;
19044c87aefeSPatrick Mooney 		goto out;
19054c87aefeSPatrick Mooney 	}
19064c87aefeSPatrick Mooney 
19074c87aefeSPatrick Mooney 	hold = kmem_zalloc(sizeof (*hold), KM_SLEEP);
19084c87aefeSPatrick Mooney 	hold->vmh_sc = sc;
19094c87aefeSPatrick Mooney 	hold->vmh_release_req = B_FALSE;
19104c87aefeSPatrick Mooney 
19114c87aefeSPatrick Mooney 	list_insert_tail(&sc->vmm_holds, hold);
19124c87aefeSPatrick Mooney 	sc->vmm_flags |= VMM_HELD;
19134c87aefeSPatrick Mooney 	*holdp = hold;
19144c87aefeSPatrick Mooney 
19154c87aefeSPatrick Mooney out:
19164c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
19174c87aefeSPatrick Mooney 	return (err);
1918bf21cd93STycho Nightingale }
1919bf21cd93STycho Nightingale 
19204c87aefeSPatrick Mooney void
19214c87aefeSPatrick Mooney vmm_drv_rele(vmm_hold_t *hold)
1922bf21cd93STycho Nightingale {
19234c87aefeSPatrick Mooney 	vmm_softc_t *sc;
19244c87aefeSPatrick Mooney 
19254c87aefeSPatrick Mooney 	ASSERT(hold != NULL);
19264c87aefeSPatrick Mooney 	ASSERT(hold->vmh_sc != NULL);
19274c87aefeSPatrick Mooney 	VERIFY(hold->vmh_ioport_hook_cnt == 0);
19284c87aefeSPatrick Mooney 
19294c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
19304c87aefeSPatrick Mooney 	sc = hold->vmh_sc;
19314c87aefeSPatrick Mooney 	list_remove(&sc->vmm_holds, hold);
19324c87aefeSPatrick Mooney 	if (list_is_empty(&sc->vmm_holds)) {
19334c87aefeSPatrick Mooney 		sc->vmm_flags &= ~VMM_HELD;
19344c87aefeSPatrick Mooney 		cv_broadcast(&sc->vmm_cv);
1935bf21cd93STycho Nightingale 	}
19364c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
19374c87aefeSPatrick Mooney 	kmem_free(hold, sizeof (*hold));
19384c87aefeSPatrick Mooney }
19394c87aefeSPatrick Mooney 
19404c87aefeSPatrick Mooney boolean_t
19414c87aefeSPatrick Mooney vmm_drv_release_reqd(vmm_hold_t *hold)
19424c87aefeSPatrick Mooney {
19434c87aefeSPatrick Mooney 	ASSERT(hold != NULL);
1944bf21cd93STycho Nightingale 
19454c87aefeSPatrick Mooney 	return (hold->vmh_release_req);
1946bf21cd93STycho Nightingale }
1947bf21cd93STycho Nightingale 
19484c87aefeSPatrick Mooney vmm_lease_t *
19494c87aefeSPatrick Mooney vmm_drv_lease_sign(vmm_hold_t *hold, boolean_t (*expiref)(void *), void *arg)
1950bf21cd93STycho Nightingale {
19514c87aefeSPatrick Mooney 	vmm_softc_t *sc = hold->vmh_sc;
19524c87aefeSPatrick Mooney 	vmm_lease_t *lease;
1953bf21cd93STycho Nightingale 
19544c87aefeSPatrick Mooney 	ASSERT3P(expiref, !=, NULL);
1955bf21cd93STycho Nightingale 
19564c87aefeSPatrick Mooney 	if (hold->vmh_release_req) {
19574c87aefeSPatrick Mooney 		return (NULL);
1958bf21cd93STycho Nightingale 	}
1959bf21cd93STycho Nightingale 
19604c87aefeSPatrick Mooney 	lease = kmem_alloc(sizeof (*lease), KM_SLEEP);
19614c87aefeSPatrick Mooney 	list_link_init(&lease->vml_node);
19624c87aefeSPatrick Mooney 	lease->vml_expire_func = expiref;
19634c87aefeSPatrick Mooney 	lease->vml_expire_arg = arg;
19644c87aefeSPatrick Mooney 	lease->vml_expired = B_FALSE;
19656703a0e8SPatrick Mooney 	lease->vml_break_deferred = B_FALSE;
19664c87aefeSPatrick Mooney 	lease->vml_hold = hold;
19674c87aefeSPatrick Mooney 	/* cache the VM pointer for one less pointer chase */
19684c87aefeSPatrick Mooney 	lease->vml_vm = sc->vmm_vm;
19690153d828SPatrick Mooney 	lease->vml_vmclient = vmspace_client_alloc(vm_get_vmspace(sc->vmm_vm));
19704c87aefeSPatrick Mooney 
19714c87aefeSPatrick Mooney 	mutex_enter(&sc->vmm_lease_lock);
19724c87aefeSPatrick Mooney 	while (sc->vmm_lease_blocker != 0) {
19734c87aefeSPatrick Mooney 		cv_wait(&sc->vmm_lease_cv, &sc->vmm_lease_lock);
1974bf21cd93STycho Nightingale 	}
19754c87aefeSPatrick Mooney 	list_insert_tail(&sc->vmm_lease_list, lease);
19764c87aefeSPatrick Mooney 	vmm_read_lock(sc);
19774c87aefeSPatrick Mooney 	mutex_exit(&sc->vmm_lease_lock);
1978bf21cd93STycho Nightingale 
19794c87aefeSPatrick Mooney 	return (lease);
19804c87aefeSPatrick Mooney }
1981bf21cd93STycho Nightingale 
19824c87aefeSPatrick Mooney static void
19834c87aefeSPatrick Mooney vmm_lease_break_locked(vmm_softc_t *sc, vmm_lease_t *lease)
19844c87aefeSPatrick Mooney {
19854c87aefeSPatrick Mooney 	ASSERT(MUTEX_HELD(&sc->vmm_lease_lock));
1986bf21cd93STycho Nightingale 
19874c87aefeSPatrick Mooney 	list_remove(&sc->vmm_lease_list, lease);
19884c87aefeSPatrick Mooney 	vmm_read_unlock(sc);
19890153d828SPatrick Mooney 	vmc_destroy(lease->vml_vmclient);
19904c87aefeSPatrick Mooney 	kmem_free(lease, sizeof (*lease));
19914c87aefeSPatrick Mooney }
19924c87aefeSPatrick Mooney 
19936703a0e8SPatrick Mooney static void
19946703a0e8SPatrick Mooney vmm_lease_block(vmm_softc_t *sc)
19956703a0e8SPatrick Mooney {
19966703a0e8SPatrick Mooney 	mutex_enter(&sc->vmm_lease_lock);
19976703a0e8SPatrick Mooney 	VERIFY3U(sc->vmm_lease_blocker, !=, UINT_MAX);
19986703a0e8SPatrick Mooney 	sc->vmm_lease_blocker++;
19996703a0e8SPatrick Mooney 	if (sc->vmm_lease_blocker == 1) {
20006703a0e8SPatrick Mooney 		list_t *list = &sc->vmm_lease_list;
20016703a0e8SPatrick Mooney 		vmm_lease_t *lease = list_head(list);
20026703a0e8SPatrick Mooney 
20036703a0e8SPatrick Mooney 		while (lease != NULL) {
20046703a0e8SPatrick Mooney 			void *arg = lease->vml_expire_arg;
20056703a0e8SPatrick Mooney 			boolean_t (*expiref)(void *) = lease->vml_expire_func;
20066703a0e8SPatrick Mooney 			boolean_t sync_break = B_FALSE;
20076703a0e8SPatrick Mooney 
20086703a0e8SPatrick Mooney 			/*
20096703a0e8SPatrick Mooney 			 * Since the lease expiration notification may
20106703a0e8SPatrick Mooney 			 * need to take locks which would deadlock with
20116703a0e8SPatrick Mooney 			 * vmm_lease_lock, drop it across the call.
20126703a0e8SPatrick Mooney 			 *
20136703a0e8SPatrick Mooney 			 * We are the only one allowed to manipulate
20146703a0e8SPatrick Mooney 			 * vmm_lease_list right now, so it is safe to
20156703a0e8SPatrick Mooney 			 * continue iterating through it after
20166703a0e8SPatrick Mooney 			 * reacquiring the lock.
20176703a0e8SPatrick Mooney 			 */
20186703a0e8SPatrick Mooney 			lease->vml_expired = B_TRUE;
20196703a0e8SPatrick Mooney 			mutex_exit(&sc->vmm_lease_lock);
20206703a0e8SPatrick Mooney 			sync_break = expiref(arg);
20216703a0e8SPatrick Mooney 			mutex_enter(&sc->vmm_lease_lock);
20226703a0e8SPatrick Mooney 
20236703a0e8SPatrick Mooney 			if (sync_break) {
20246703a0e8SPatrick Mooney 				vmm_lease_t *next;
20256703a0e8SPatrick Mooney 
20266703a0e8SPatrick Mooney 				/*
20276703a0e8SPatrick Mooney 				 * These leases which are synchronously broken
20286703a0e8SPatrick Mooney 				 * result in vmm_read_unlock() calls from a
20296703a0e8SPatrick Mooney 				 * different thread than the corresponding
20306703a0e8SPatrick Mooney 				 * vmm_read_lock().  This is acceptable, given
20316703a0e8SPatrick Mooney 				 * that the rwlock underpinning the whole
20326703a0e8SPatrick Mooney 				 * mechanism tolerates the behavior.  This
20336703a0e8SPatrick Mooney 				 * flexibility is _only_ afforded to VM read
20346703a0e8SPatrick Mooney 				 * lock (RW_READER) holders.
20356703a0e8SPatrick Mooney 				 */
20366703a0e8SPatrick Mooney 				next = list_next(list, lease);
20376703a0e8SPatrick Mooney 				vmm_lease_break_locked(sc, lease);
20386703a0e8SPatrick Mooney 				lease = next;
20396703a0e8SPatrick Mooney 			} else {
20406703a0e8SPatrick Mooney 				lease = list_next(list, lease);
20416703a0e8SPatrick Mooney 			}
20426703a0e8SPatrick Mooney 		}
20436703a0e8SPatrick Mooney 
20446703a0e8SPatrick Mooney 		/* Process leases which were not broken synchronously. */
20456703a0e8SPatrick Mooney 		while (!list_is_empty(list)) {
20466703a0e8SPatrick Mooney 			/*
20476703a0e8SPatrick Mooney 			 * Although the nested loops are quadratic, the number
20486703a0e8SPatrick Mooney 			 * of leases is small.
20496703a0e8SPatrick Mooney 			 */
20506703a0e8SPatrick Mooney 			lease = list_head(list);
20516703a0e8SPatrick Mooney 			while (lease != NULL) {
20526703a0e8SPatrick Mooney 				vmm_lease_t *next = list_next(list, lease);
20536703a0e8SPatrick Mooney 				if (lease->vml_break_deferred) {
20546703a0e8SPatrick Mooney 					vmm_lease_break_locked(sc, lease);
20556703a0e8SPatrick Mooney 				}
20566703a0e8SPatrick Mooney 				lease = next;
20576703a0e8SPatrick Mooney 			}
20586703a0e8SPatrick Mooney 			if (list_is_empty(list)) {
20596703a0e8SPatrick Mooney 				break;
20606703a0e8SPatrick Mooney 			}
20616703a0e8SPatrick Mooney 			cv_wait(&sc->vmm_lease_cv, &sc->vmm_lease_lock);
20626703a0e8SPatrick Mooney 		}
20636703a0e8SPatrick Mooney 		/* Wake anyone else waiting for the lease list to be empty  */
20646703a0e8SPatrick Mooney 		cv_broadcast(&sc->vmm_lease_cv);
20656703a0e8SPatrick Mooney 	} else {
20666703a0e8SPatrick Mooney 		list_t *list = &sc->vmm_lease_list;
20676703a0e8SPatrick Mooney 
20686703a0e8SPatrick Mooney 		/*
20696703a0e8SPatrick Mooney 		 * Some other thread beat us to the duty of lease cleanup.
20706703a0e8SPatrick Mooney 		 * Wait until that is complete.
20716703a0e8SPatrick Mooney 		 */
20726703a0e8SPatrick Mooney 		while (!list_is_empty(list)) {
20736703a0e8SPatrick Mooney 			cv_wait(&sc->vmm_lease_cv, &sc->vmm_lease_lock);
20746703a0e8SPatrick Mooney 		}
20756703a0e8SPatrick Mooney 	}
20766703a0e8SPatrick Mooney 	mutex_exit(&sc->vmm_lease_lock);
20776703a0e8SPatrick Mooney }
20786703a0e8SPatrick Mooney 
20796703a0e8SPatrick Mooney static void
20806703a0e8SPatrick Mooney vmm_lease_unblock(vmm_softc_t *sc)
20816703a0e8SPatrick Mooney {
20826703a0e8SPatrick Mooney 	mutex_enter(&sc->vmm_lease_lock);
20836703a0e8SPatrick Mooney 	VERIFY3U(sc->vmm_lease_blocker, !=, 0);
20846703a0e8SPatrick Mooney 	sc->vmm_lease_blocker--;
20856703a0e8SPatrick Mooney 	if (sc->vmm_lease_blocker == 0) {
20866703a0e8SPatrick Mooney 		cv_broadcast(&sc->vmm_lease_cv);
20876703a0e8SPatrick Mooney 	}
20886703a0e8SPatrick Mooney 	mutex_exit(&sc->vmm_lease_lock);
20896703a0e8SPatrick Mooney }
20906703a0e8SPatrick Mooney 
20914c87aefeSPatrick Mooney void
20924c87aefeSPatrick Mooney vmm_drv_lease_break(vmm_hold_t *hold, vmm_lease_t *lease)
20934c87aefeSPatrick Mooney {
20944c87aefeSPatrick Mooney 	vmm_softc_t *sc = hold->vmh_sc;
20954c87aefeSPatrick Mooney 
20964c87aefeSPatrick Mooney 	VERIFY3P(hold, ==, lease->vml_hold);
20976703a0e8SPatrick Mooney 	VERIFY(!lease->vml_break_deferred);
20984c87aefeSPatrick Mooney 
20994c87aefeSPatrick Mooney 	mutex_enter(&sc->vmm_lease_lock);
21006703a0e8SPatrick Mooney 	if (sc->vmm_lease_blocker == 0) {
21016703a0e8SPatrick Mooney 		vmm_lease_break_locked(sc, lease);
21026703a0e8SPatrick Mooney 	} else {
21036703a0e8SPatrick Mooney 		/*
21046703a0e8SPatrick Mooney 		 * Defer the lease-breaking to whichever thread is currently
21056703a0e8SPatrick Mooney 		 * cleaning up all leases as part of a vmm_lease_block() call.
21066703a0e8SPatrick Mooney 		 */
21076703a0e8SPatrick Mooney 		lease->vml_break_deferred = B_TRUE;
21086703a0e8SPatrick Mooney 		cv_broadcast(&sc->vmm_lease_cv);
21096703a0e8SPatrick Mooney 	}
21104c87aefeSPatrick Mooney 	mutex_exit(&sc->vmm_lease_lock);
21114c87aefeSPatrick Mooney }
21124c87aefeSPatrick Mooney 
21134c87aefeSPatrick Mooney boolean_t
21144c87aefeSPatrick Mooney vmm_drv_lease_expired(vmm_lease_t *lease)
21154c87aefeSPatrick Mooney {
21164c87aefeSPatrick Mooney 	return (lease->vml_expired);
21174c87aefeSPatrick Mooney }
21184c87aefeSPatrick Mooney 
2119db9aa506SPatrick Mooney vmm_page_t *
2120db9aa506SPatrick Mooney vmm_drv_page_hold(vmm_lease_t *lease, uintptr_t gpa, int prot)
21214c87aefeSPatrick Mooney {
21224c87aefeSPatrick Mooney 	ASSERT(lease != NULL);
21230153d828SPatrick Mooney 	ASSERT0(gpa & PAGEOFFSET);
21240153d828SPatrick Mooney 
2125db9aa506SPatrick Mooney 	return ((vmm_page_t *)vmc_hold(lease->vml_vmclient, gpa, prot));
2126db9aa506SPatrick Mooney }
2127db9aa506SPatrick Mooney 
2128db9aa506SPatrick Mooney void
2129db9aa506SPatrick Mooney vmm_drv_page_release(vmm_page_t *vmmp)
2130db9aa506SPatrick Mooney {
2131e0994bd2SPatrick Mooney 	(void) vmp_release((vm_page_t *)vmmp);
2132db9aa506SPatrick Mooney }
2133db9aa506SPatrick Mooney 
2134db9aa506SPatrick Mooney void
2135db9aa506SPatrick Mooney vmm_drv_page_release_chain(vmm_page_t *vmmp)
2136db9aa506SPatrick Mooney {
2137e0994bd2SPatrick Mooney 	(void) vmp_release_chain((vm_page_t *)vmmp);
2138db9aa506SPatrick Mooney }
2139db9aa506SPatrick Mooney 
2140db9aa506SPatrick Mooney const void *
2141db9aa506SPatrick Mooney vmm_drv_page_readable(const vmm_page_t *vmmp)
2142db9aa506SPatrick Mooney {
2143db9aa506SPatrick Mooney 	return (vmp_get_readable((const vm_page_t *)vmmp));
2144db9aa506SPatrick Mooney }
21454c87aefeSPatrick Mooney 
2146db9aa506SPatrick Mooney void *
2147db9aa506SPatrick Mooney vmm_drv_page_writable(const vmm_page_t *vmmp)
2148db9aa506SPatrick Mooney {
2149db9aa506SPatrick Mooney 	return (vmp_get_writable((const vm_page_t *)vmmp));
2150db9aa506SPatrick Mooney }
2151db9aa506SPatrick Mooney 
2152db9aa506SPatrick Mooney void
2153db9aa506SPatrick Mooney vmm_drv_page_chain(vmm_page_t *vmmp, vmm_page_t *to_chain)
2154db9aa506SPatrick Mooney {
2155db9aa506SPatrick Mooney 	vmp_chain((vm_page_t *)vmmp, (vm_page_t *)to_chain);
2156db9aa506SPatrick Mooney }
2157db9aa506SPatrick Mooney 
2158db9aa506SPatrick Mooney vmm_page_t *
2159db9aa506SPatrick Mooney vmm_drv_page_next(const vmm_page_t *vmmp)
2160db9aa506SPatrick Mooney {
2161db9aa506SPatrick Mooney 	return ((vmm_page_t *)vmp_next((vm_page_t *)vmmp));
21624c87aefeSPatrick Mooney }
21634c87aefeSPatrick Mooney 
21644c87aefeSPatrick Mooney int
21654c87aefeSPatrick Mooney vmm_drv_msi(vmm_lease_t *lease, uint64_t addr, uint64_t msg)
21664c87aefeSPatrick Mooney {
21674c87aefeSPatrick Mooney 	ASSERT(lease != NULL);
21684c87aefeSPatrick Mooney 
21694c87aefeSPatrick Mooney 	return (lapic_intr_msi(lease->vml_vm, addr, msg));
21704c87aefeSPatrick Mooney }
21714c87aefeSPatrick Mooney 
21724c87aefeSPatrick Mooney int
21730e1453c3SPatrick Mooney vmm_drv_ioport_hook(vmm_hold_t *hold, uint16_t ioport, vmm_drv_iop_cb_t func,
21740e1453c3SPatrick Mooney     void *arg, void **cookie)
21754c87aefeSPatrick Mooney {
21764c87aefeSPatrick Mooney 	vmm_softc_t *sc;
21774c87aefeSPatrick Mooney 	int err;
21784c87aefeSPatrick Mooney 
21794c87aefeSPatrick Mooney 	ASSERT(hold != NULL);
21804c87aefeSPatrick Mooney 	ASSERT(cookie != NULL);
21814c87aefeSPatrick Mooney 
21824c87aefeSPatrick Mooney 	sc = hold->vmh_sc;
21834c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
21844c87aefeSPatrick Mooney 	/* Confirm that hook installation is not blocked */
21854c87aefeSPatrick Mooney 	if ((sc->vmm_flags & VMM_BLOCK_HOOK) != 0) {
21864c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
21874c87aefeSPatrick Mooney 		return (EBUSY);
21884c87aefeSPatrick Mooney 	}
21894c87aefeSPatrick Mooney 	/*
21904c87aefeSPatrick Mooney 	 * Optimistically record an installed hook which will prevent a block
21914c87aefeSPatrick Mooney 	 * from being asserted while the mutex is dropped.
21924c87aefeSPatrick Mooney 	 */
21934c87aefeSPatrick Mooney 	hold->vmh_ioport_hook_cnt++;
21944c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
21954c87aefeSPatrick Mooney 
21964c87aefeSPatrick Mooney 	vmm_write_lock(sc);
21970e1453c3SPatrick Mooney 	err = vm_ioport_hook(sc->vmm_vm, ioport, (ioport_handler_t)func,
21980e1453c3SPatrick Mooney 	    arg, cookie);
21994c87aefeSPatrick Mooney 	vmm_write_unlock(sc);
22004c87aefeSPatrick Mooney 
22014c87aefeSPatrick Mooney 	if (err != 0) {
22024c87aefeSPatrick Mooney 		mutex_enter(&vmm_mtx);
22034c87aefeSPatrick Mooney 		/* Walk back optimism about the hook installation */
22044c87aefeSPatrick Mooney 		hold->vmh_ioport_hook_cnt--;
22054c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
2206bf21cd93STycho Nightingale 	}
22074c87aefeSPatrick Mooney 	return (err);
22084c87aefeSPatrick Mooney }
2209bf21cd93STycho Nightingale 
22104c87aefeSPatrick Mooney void
22114c87aefeSPatrick Mooney vmm_drv_ioport_unhook(vmm_hold_t *hold, void **cookie)
22124c87aefeSPatrick Mooney {
22134c87aefeSPatrick Mooney 	vmm_softc_t *sc;
2214bf21cd93STycho Nightingale 
22154c87aefeSPatrick Mooney 	ASSERT(hold != NULL);
22164c87aefeSPatrick Mooney 	ASSERT(cookie != NULL);
22174c87aefeSPatrick Mooney 	ASSERT(hold->vmh_ioport_hook_cnt != 0);
22184c87aefeSPatrick Mooney 
22194c87aefeSPatrick Mooney 	sc = hold->vmh_sc;
22204c87aefeSPatrick Mooney 	vmm_write_lock(sc);
22214c87aefeSPatrick Mooney 	vm_ioport_unhook(sc->vmm_vm, cookie);
22224c87aefeSPatrick Mooney 	vmm_write_unlock(sc);
22234c87aefeSPatrick Mooney 
22244c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
22254c87aefeSPatrick Mooney 	hold->vmh_ioport_hook_cnt--;
22264c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
2227bf21cd93STycho Nightingale }
2228bf21cd93STycho Nightingale 
22294c87aefeSPatrick Mooney static int
22304c87aefeSPatrick Mooney vmm_drv_purge(vmm_softc_t *sc)
2231bf21cd93STycho Nightingale {
22324c87aefeSPatrick Mooney 	ASSERT(MUTEX_HELD(&vmm_mtx));
2233bf21cd93STycho Nightingale 
22344c87aefeSPatrick Mooney 	if ((sc->vmm_flags & VMM_HELD) != 0) {
22354c87aefeSPatrick Mooney 		vmm_hold_t *hold;
22364c87aefeSPatrick Mooney 
22374c87aefeSPatrick Mooney 		sc->vmm_flags |= VMM_CLEANUP;
22384c87aefeSPatrick Mooney 		for (hold = list_head(&sc->vmm_holds); hold != NULL;
22394c87aefeSPatrick Mooney 		    hold = list_next(&sc->vmm_holds, hold)) {
22404c87aefeSPatrick Mooney 			hold->vmh_release_req = B_TRUE;
2241bf21cd93STycho Nightingale 		}
22424c87aefeSPatrick Mooney 		while ((sc->vmm_flags & VMM_HELD) != 0) {
22434c87aefeSPatrick Mooney 			if (cv_wait_sig(&sc->vmm_cv, &vmm_mtx) <= 0) {
22444c87aefeSPatrick Mooney 				return (EINTR);
22454c87aefeSPatrick Mooney 			}
22464c87aefeSPatrick Mooney 		}
22474c87aefeSPatrick Mooney 		sc->vmm_flags &= ~VMM_CLEANUP;
2248bf21cd93STycho Nightingale 	}
2249bf21cd93STycho Nightingale 
22504c87aefeSPatrick Mooney 	VERIFY(list_is_empty(&sc->vmm_holds));
22514c87aefeSPatrick Mooney 	sc->vmm_flags |= VMM_PURGED;
22524c87aefeSPatrick Mooney 	return (0);
2253bf21cd93STycho Nightingale }
2254bf21cd93STycho Nightingale 
22554c87aefeSPatrick Mooney static int
22564c87aefeSPatrick Mooney vmm_drv_block_hook(vmm_softc_t *sc, boolean_t enable_block)
2257bf21cd93STycho Nightingale {
22584c87aefeSPatrick Mooney 	int err = 0;
2259bf21cd93STycho Nightingale 
22604c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
22614c87aefeSPatrick Mooney 	if (!enable_block) {
22624c87aefeSPatrick Mooney 		VERIFY((sc->vmm_flags & VMM_BLOCK_HOOK) != 0);
2263bf21cd93STycho Nightingale 
22644c87aefeSPatrick Mooney 		sc->vmm_flags &= ~VMM_BLOCK_HOOK;
22654c87aefeSPatrick Mooney 		goto done;
2266bf21cd93STycho Nightingale 	}
2267bf21cd93STycho Nightingale 
22684c87aefeSPatrick Mooney 	/* If any holds have hooks installed, the block is a failure */
22694c87aefeSPatrick Mooney 	if (!list_is_empty(&sc->vmm_holds)) {
22704c87aefeSPatrick Mooney 		vmm_hold_t *hold;
22714c87aefeSPatrick Mooney 
22724c87aefeSPatrick Mooney 		for (hold = list_head(&sc->vmm_holds); hold != NULL;
22734c87aefeSPatrick Mooney 		    hold = list_next(&sc->vmm_holds, hold)) {
22744c87aefeSPatrick Mooney 			if (hold->vmh_ioport_hook_cnt != 0) {
22754c87aefeSPatrick Mooney 				err = EBUSY;
22764c87aefeSPatrick Mooney 				goto done;
22774c87aefeSPatrick Mooney 			}
22784c87aefeSPatrick Mooney 		}
22794c87aefeSPatrick Mooney 	}
22804c87aefeSPatrick Mooney 	sc->vmm_flags |= VMM_BLOCK_HOOK;
2281bf21cd93STycho Nightingale 
22824c87aefeSPatrick Mooney done:
22834c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
22844c87aefeSPatrick Mooney 	return (err);
2285bf21cd93STycho Nightingale }
2286bf21cd93STycho Nightingale 
22874c87aefeSPatrick Mooney static int
22888e3a263eSAndy Fiddaman vmm_do_vm_destroy_locked(vmm_softc_t *sc, boolean_t clean_zsd,
22898e3a263eSAndy Fiddaman     boolean_t *hma_release)
2290bf21cd93STycho Nightingale {
22914c87aefeSPatrick Mooney 	dev_info_t	*pdip = ddi_get_parent(vmmdev_dip);
22924c87aefeSPatrick Mooney 	minor_t		minor;
2293bf21cd93STycho Nightingale 
22944c87aefeSPatrick Mooney 	ASSERT(MUTEX_HELD(&vmm_mtx));
2295bf21cd93STycho Nightingale 
22968e3a263eSAndy Fiddaman 	*hma_release = B_FALSE;
22978e3a263eSAndy Fiddaman 
22984c87aefeSPatrick Mooney 	if (vmm_drv_purge(sc) != 0) {
22994c87aefeSPatrick Mooney 		return (EINTR);
2300bf21cd93STycho Nightingale 	}
2301bf21cd93STycho Nightingale 
2302b4100263SAndy Fiddaman 	if (clean_zsd) {
2303b4100263SAndy Fiddaman 		vmm_zsd_rem_vm(sc);
2304b4100263SAndy Fiddaman 	}
2305b4100263SAndy Fiddaman 
23064c87aefeSPatrick Mooney 	/* Clean up devmem entries */
23074c87aefeSPatrick Mooney 	vmmdev_devmem_purge(sc);
2308bf21cd93STycho Nightingale 
23094c87aefeSPatrick Mooney 	list_remove(&vmm_list, sc);
23104c87aefeSPatrick Mooney 	ddi_remove_minor_node(vmmdev_dip, sc->vmm_name);
23114c87aefeSPatrick Mooney 	minor = sc->vmm_minor;
23124c87aefeSPatrick Mooney 	zone_rele(sc->vmm_zone);
23134c87aefeSPatrick Mooney 	if (sc->vmm_is_open) {
23144c87aefeSPatrick Mooney 		list_insert_tail(&vmm_destroy_list, sc);
23154c87aefeSPatrick Mooney 		sc->vmm_flags |= VMM_DESTROY;
23164c87aefeSPatrick Mooney 	} else {
231759460b49SPatrick Mooney 		vmm_kstat_fini(sc);
23186884664dSPatrick Mooney 		vm_destroy(sc->vmm_vm);
23194c87aefeSPatrick Mooney 		ddi_soft_state_free(vmm_statep, minor);
23204c87aefeSPatrick Mooney 		id_free(vmm_minors, minor);
23218e3a263eSAndy Fiddaman 		*hma_release = B_TRUE;
23224c87aefeSPatrick Mooney 	}
23234c87aefeSPatrick Mooney 	(void) devfs_clean(pdip, NULL, DV_CLEAN_FORCE);
2324bf21cd93STycho Nightingale 
2325bf21cd93STycho Nightingale 	return (0);
2326bf21cd93STycho Nightingale }
2327bf21cd93STycho Nightingale 
2328bf21cd93STycho Nightingale int
23294c87aefeSPatrick Mooney vmm_do_vm_destroy(vmm_softc_t *sc, boolean_t clean_zsd)
2330bf21cd93STycho Nightingale {
23318e3a263eSAndy Fiddaman 	boolean_t	hma_release = B_FALSE;
23324c87aefeSPatrick Mooney 	int		err;
2333bf21cd93STycho Nightingale 
23344c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
23358e3a263eSAndy Fiddaman 	err = vmm_do_vm_destroy_locked(sc, clean_zsd, &hma_release);
23364c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
2337bf21cd93STycho Nightingale 
23388e3a263eSAndy Fiddaman 	if (hma_release)
23398e3a263eSAndy Fiddaman 		vmm_hma_release();
23408e3a263eSAndy Fiddaman 
23414c87aefeSPatrick Mooney 	return (err);
23424c87aefeSPatrick Mooney }
2343bf21cd93STycho Nightingale 
23444c87aefeSPatrick Mooney /* ARGSUSED */
23454c87aefeSPatrick Mooney static int
2346b57f5d3eSPatrick Mooney vmmdev_do_vm_destroy(const struct vm_destroy_req *req, cred_t *cr)
23474c87aefeSPatrick Mooney {
23488e3a263eSAndy Fiddaman 	boolean_t	hma_release = B_FALSE;
23494c87aefeSPatrick Mooney 	vmm_softc_t	*sc;
23504c87aefeSPatrick Mooney 	int		err;
23514c87aefeSPatrick Mooney 
23524c87aefeSPatrick Mooney 	if (crgetuid(cr) != 0)
23534c87aefeSPatrick Mooney 		return (EPERM);
23544c87aefeSPatrick Mooney 
23554c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
23564c87aefeSPatrick Mooney 
2357b57f5d3eSPatrick Mooney 	if ((sc = vmm_lookup(req->name)) == NULL) {
23584c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
23594c87aefeSPatrick Mooney 		return (ENOENT);
23604c87aefeSPatrick Mooney 	}
23614c87aefeSPatrick Mooney 	/*
23624c87aefeSPatrick Mooney 	 * We don't check this in vmm_lookup() since that function is also used
23634c87aefeSPatrick Mooney 	 * for validation during create and currently vmm names must be unique.
23644c87aefeSPatrick Mooney 	 */
23654c87aefeSPatrick Mooney 	if (!INGLOBALZONE(curproc) && sc->vmm_zone != curzone) {
23664c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
23674c87aefeSPatrick Mooney 		return (EPERM);
23684c87aefeSPatrick Mooney 	}
23698e3a263eSAndy Fiddaman 	err = vmm_do_vm_destroy_locked(sc, B_TRUE, &hma_release);
23708e3a263eSAndy Fiddaman 
23714c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
2372bf21cd93STycho Nightingale 
23738e3a263eSAndy Fiddaman 	if (hma_release)
23748e3a263eSAndy Fiddaman 		vmm_hma_release();
23758e3a263eSAndy Fiddaman 
23764c87aefeSPatrick Mooney 	return (err);
2377bf21cd93STycho Nightingale }
2378bf21cd93STycho Nightingale 
237959460b49SPatrick Mooney #define	VCPU_NAME_BUFLEN	32
238059460b49SPatrick Mooney 
238159460b49SPatrick Mooney static int
238259460b49SPatrick Mooney vmm_kstat_alloc(vmm_softc_t *sc, minor_t minor, const cred_t *cr)
238359460b49SPatrick Mooney {
238459460b49SPatrick Mooney 	zoneid_t zid = crgetzoneid(cr);
238559460b49SPatrick Mooney 	int instance = minor;
238659460b49SPatrick Mooney 	kstat_t *ksp;
238759460b49SPatrick Mooney 
238859460b49SPatrick Mooney 	ASSERT3P(sc->vmm_kstat_vm, ==, NULL);
238959460b49SPatrick Mooney 
239059460b49SPatrick Mooney 	ksp = kstat_create_zone(VMM_MODULE_NAME, instance, "vm",
239159460b49SPatrick Mooney 	    VMM_KSTAT_CLASS, KSTAT_TYPE_NAMED,
239259460b49SPatrick Mooney 	    sizeof (vmm_kstats_t) / sizeof (kstat_named_t), 0, zid);
239359460b49SPatrick Mooney 
239459460b49SPatrick Mooney 	if (ksp == NULL) {
239559460b49SPatrick Mooney 		return (-1);
239659460b49SPatrick Mooney 	}
239759460b49SPatrick Mooney 	sc->vmm_kstat_vm = ksp;
239859460b49SPatrick Mooney 
239959460b49SPatrick Mooney 	for (uint_t i = 0; i < VM_MAXCPU; i++) {
240059460b49SPatrick Mooney 		char namebuf[VCPU_NAME_BUFLEN];
240159460b49SPatrick Mooney 
240259460b49SPatrick Mooney 		ASSERT3P(sc->vmm_kstat_vcpu[i], ==, NULL);
240359460b49SPatrick Mooney 
240459460b49SPatrick Mooney 		(void) snprintf(namebuf, VCPU_NAME_BUFLEN, "vcpu%u", i);
240559460b49SPatrick Mooney 		ksp = kstat_create_zone(VMM_MODULE_NAME, instance, namebuf,
240659460b49SPatrick Mooney 		    VMM_KSTAT_CLASS, KSTAT_TYPE_NAMED,
240759460b49SPatrick Mooney 		    sizeof (vmm_vcpu_kstats_t) / sizeof (kstat_named_t),
240859460b49SPatrick Mooney 		    0, zid);
240959460b49SPatrick Mooney 		if (ksp == NULL) {
241059460b49SPatrick Mooney 			goto fail;
241159460b49SPatrick Mooney 		}
241259460b49SPatrick Mooney 
241359460b49SPatrick Mooney 		sc->vmm_kstat_vcpu[i] = ksp;
241459460b49SPatrick Mooney 	}
241559460b49SPatrick Mooney 
241659460b49SPatrick Mooney 	/*
241759460b49SPatrick Mooney 	 * If this instance is associated with a non-global zone, make its
241859460b49SPatrick Mooney 	 * kstats visible from the GZ.
241959460b49SPatrick Mooney 	 */
242059460b49SPatrick Mooney 	if (zid != GLOBAL_ZONEID) {
242159460b49SPatrick Mooney 		kstat_zone_add(sc->vmm_kstat_vm, GLOBAL_ZONEID);
242259460b49SPatrick Mooney 		for (uint_t i = 0; i < VM_MAXCPU; i++) {
242359460b49SPatrick Mooney 			kstat_zone_add(sc->vmm_kstat_vcpu[i], GLOBAL_ZONEID);
242459460b49SPatrick Mooney 		}
242559460b49SPatrick Mooney 	}
242659460b49SPatrick Mooney 
242759460b49SPatrick Mooney 	return (0);
242859460b49SPatrick Mooney 
242959460b49SPatrick Mooney fail:
243059460b49SPatrick Mooney 	for (uint_t i = 0; i < VM_MAXCPU; i++) {
243159460b49SPatrick Mooney 		if (sc->vmm_kstat_vcpu[i] != NULL) {
243259460b49SPatrick Mooney 			kstat_delete(sc->vmm_kstat_vcpu[i]);
243359460b49SPatrick Mooney 			sc->vmm_kstat_vcpu[i] = NULL;
243459460b49SPatrick Mooney 		} else {
243559460b49SPatrick Mooney 			break;
243659460b49SPatrick Mooney 		}
243759460b49SPatrick Mooney 	}
243859460b49SPatrick Mooney 	kstat_delete(sc->vmm_kstat_vm);
243959460b49SPatrick Mooney 	sc->vmm_kstat_vm = NULL;
244059460b49SPatrick Mooney 	return (-1);
244159460b49SPatrick Mooney }
244259460b49SPatrick Mooney 
244359460b49SPatrick Mooney static void
244459460b49SPatrick Mooney vmm_kstat_init(vmm_softc_t *sc)
244559460b49SPatrick Mooney {
244659460b49SPatrick Mooney 	kstat_t *ksp;
244759460b49SPatrick Mooney 
244859460b49SPatrick Mooney 	ASSERT3P(sc->vmm_vm, !=, NULL);
244959460b49SPatrick Mooney 	ASSERT3P(sc->vmm_kstat_vm, !=, NULL);
245059460b49SPatrick Mooney 
245159460b49SPatrick Mooney 	ksp = sc->vmm_kstat_vm;
245259460b49SPatrick Mooney 	vmm_kstats_t *vk = ksp->ks_data;
245359460b49SPatrick Mooney 	ksp->ks_private = sc->vmm_vm;
245459460b49SPatrick Mooney 	kstat_named_init(&vk->vk_name, "vm_name", KSTAT_DATA_STRING);
245559460b49SPatrick Mooney 	kstat_named_setstr(&vk->vk_name, sc->vmm_name);
245659460b49SPatrick Mooney 
245759460b49SPatrick Mooney 	for (uint_t i = 0; i < VM_MAXCPU; i++) {
245859460b49SPatrick Mooney 		ASSERT3P(sc->vmm_kstat_vcpu[i], !=, NULL);
245959460b49SPatrick Mooney 
246059460b49SPatrick Mooney 		ksp = sc->vmm_kstat_vcpu[i];
246159460b49SPatrick Mooney 		vmm_vcpu_kstats_t *vvk = ksp->ks_data;
246259460b49SPatrick Mooney 
246359460b49SPatrick Mooney 		kstat_named_init(&vvk->vvk_vcpu, "vcpu", KSTAT_DATA_UINT32);
246459460b49SPatrick Mooney 		vvk->vvk_vcpu.value.ui32 = i;
246559460b49SPatrick Mooney 		kstat_named_init(&vvk->vvk_time_init, "time_init",
246659460b49SPatrick Mooney 		    KSTAT_DATA_UINT64);
246759460b49SPatrick Mooney 		kstat_named_init(&vvk->vvk_time_run, "time_run",
246859460b49SPatrick Mooney 		    KSTAT_DATA_UINT64);
246959460b49SPatrick Mooney 		kstat_named_init(&vvk->vvk_time_idle, "time_idle",
247059460b49SPatrick Mooney 		    KSTAT_DATA_UINT64);
247159460b49SPatrick Mooney 		kstat_named_init(&vvk->vvk_time_emu_kern, "time_emu_kern",
247259460b49SPatrick Mooney 		    KSTAT_DATA_UINT64);
247359460b49SPatrick Mooney 		kstat_named_init(&vvk->vvk_time_emu_user, "time_emu_user",
247459460b49SPatrick Mooney 		    KSTAT_DATA_UINT64);
247559460b49SPatrick Mooney 		kstat_named_init(&vvk->vvk_time_sched, "time_sched",
247659460b49SPatrick Mooney 		    KSTAT_DATA_UINT64);
247759460b49SPatrick Mooney 		ksp->ks_private = sc->vmm_vm;
247859460b49SPatrick Mooney 		ksp->ks_update = vmm_kstat_update_vcpu;
247959460b49SPatrick Mooney 	}
248059460b49SPatrick Mooney 
248159460b49SPatrick Mooney 	kstat_install(sc->vmm_kstat_vm);
248259460b49SPatrick Mooney 	for (uint_t i = 0; i < VM_MAXCPU; i++) {
248359460b49SPatrick Mooney 		kstat_install(sc->vmm_kstat_vcpu[i]);
248459460b49SPatrick Mooney 	}
248559460b49SPatrick Mooney }
248659460b49SPatrick Mooney 
248759460b49SPatrick Mooney static void
248859460b49SPatrick Mooney vmm_kstat_fini(vmm_softc_t *sc)
248959460b49SPatrick Mooney {
249059460b49SPatrick Mooney 	ASSERT(sc->vmm_kstat_vm != NULL);
249159460b49SPatrick Mooney 
249259460b49SPatrick Mooney 	kstat_delete(sc->vmm_kstat_vm);
249359460b49SPatrick Mooney 	sc->vmm_kstat_vm = NULL;
249459460b49SPatrick Mooney 
249559460b49SPatrick Mooney 	for (uint_t i = 0; i < VM_MAXCPU; i++) {
249659460b49SPatrick Mooney 		ASSERT3P(sc->vmm_kstat_vcpu[i], !=, NULL);
249759460b49SPatrick Mooney 
249859460b49SPatrick Mooney 		kstat_delete(sc->vmm_kstat_vcpu[i]);
249959460b49SPatrick Mooney 		sc->vmm_kstat_vcpu[i] = NULL;
250059460b49SPatrick Mooney 	}
250159460b49SPatrick Mooney }
250259460b49SPatrick Mooney 
2503bf21cd93STycho Nightingale static int
2504bf21cd93STycho Nightingale vmm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
2505bf21cd93STycho Nightingale {
25064c87aefeSPatrick Mooney 	minor_t		minor;
25074c87aefeSPatrick Mooney 	vmm_softc_t	*sc;
2508bf21cd93STycho Nightingale 
25090153d828SPatrick Mooney 	/*
25100153d828SPatrick Mooney 	 * Forbid running bhyve in a 32-bit process until it has been tested and
25110153d828SPatrick Mooney 	 * verified to be safe.
25120153d828SPatrick Mooney 	 */
25130153d828SPatrick Mooney 	if (curproc->p_model != DATAMODEL_LP64) {
25140153d828SPatrick Mooney 		return (EFBIG);
25150153d828SPatrick Mooney 	}
25160153d828SPatrick Mooney 
2517bf21cd93STycho Nightingale 	minor = getminor(*devp);
2518bf21cd93STycho Nightingale 	if (minor == VMM_CTL_MINOR) {
2519bf21cd93STycho Nightingale 		/*
2520bf21cd93STycho Nightingale 		 * Master control device must be opened exclusively.
2521bf21cd93STycho Nightingale 		 */
2522bf21cd93STycho Nightingale 		if ((flag & FEXCL) != FEXCL || otyp != OTYP_CHR) {
2523bf21cd93STycho Nightingale 			return (EINVAL);
2524bf21cd93STycho Nightingale 		}
2525bf21cd93STycho Nightingale 
2526bf21cd93STycho Nightingale 		return (0);
2527bf21cd93STycho Nightingale 	}
2528bf21cd93STycho Nightingale 
25294c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
2530bf21cd93STycho Nightingale 	sc = ddi_get_soft_state(vmm_statep, minor);
2531bf21cd93STycho Nightingale 	if (sc == NULL) {
25324c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
2533bf21cd93STycho Nightingale 		return (ENXIO);
2534bf21cd93STycho Nightingale 	}
2535bf21cd93STycho Nightingale 
25364c87aefeSPatrick Mooney 	sc->vmm_is_open = B_TRUE;
25374c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
2538bf21cd93STycho Nightingale 
2539bf21cd93STycho Nightingale 	return (0);
2540bf21cd93STycho Nightingale }
2541bf21cd93STycho Nightingale 
2542bf21cd93STycho Nightingale static int
2543bf21cd93STycho Nightingale vmm_close(dev_t dev, int flag, int otyp, cred_t *credp)
2544bf21cd93STycho Nightingale {
25454c87aefeSPatrick Mooney 	minor_t		minor;
25464c87aefeSPatrick Mooney 	vmm_softc_t	*sc;
25478e3a263eSAndy Fiddaman 	boolean_t	hma_release = B_FALSE;
2548bf21cd93STycho Nightingale 
2549bf21cd93STycho Nightingale 	minor = getminor(dev);
2550bf21cd93STycho Nightingale 	if (minor == VMM_CTL_MINOR)
2551bf21cd93STycho Nightingale 		return (0);
2552bf21cd93STycho Nightingale 
25534c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
2554bf21cd93STycho Nightingale 	sc = ddi_get_soft_state(vmm_statep, minor);
2555bf21cd93STycho Nightingale 	if (sc == NULL) {
25564c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
2557bf21cd93STycho Nightingale 		return (ENXIO);
2558bf21cd93STycho Nightingale 	}
2559bf21cd93STycho Nightingale 
25604c87aefeSPatrick Mooney 	VERIFY(sc->vmm_is_open);
25614c87aefeSPatrick Mooney 	sc->vmm_is_open = B_FALSE;
25624c87aefeSPatrick Mooney 
25638e3a263eSAndy Fiddaman 	/*
25648e3a263eSAndy Fiddaman 	 * If this VM was destroyed while the vmm device was open, then
25658e3a263eSAndy Fiddaman 	 * clean it up now that it is closed.
25668e3a263eSAndy Fiddaman 	 */
25674c87aefeSPatrick Mooney 	if (sc->vmm_flags & VMM_DESTROY) {
25684c87aefeSPatrick Mooney 		list_remove(&vmm_destroy_list, sc);
25696884664dSPatrick Mooney 		vmm_kstat_fini(sc);
25704c87aefeSPatrick Mooney 		vm_destroy(sc->vmm_vm);
25714c87aefeSPatrick Mooney 		ddi_soft_state_free(vmm_statep, minor);
25724c87aefeSPatrick Mooney 		id_free(vmm_minors, minor);
25738e3a263eSAndy Fiddaman 		hma_release = B_TRUE;
25744c87aefeSPatrick Mooney 	}
25754c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
2576bf21cd93STycho Nightingale 
25778e3a263eSAndy Fiddaman 	if (hma_release)
25788e3a263eSAndy Fiddaman 		vmm_hma_release();
25798e3a263eSAndy Fiddaman 
2580bf21cd93STycho Nightingale 	return (0);
2581bf21cd93STycho Nightingale }
2582bf21cd93STycho Nightingale 
25834c87aefeSPatrick Mooney static int
25844c87aefeSPatrick Mooney vmm_is_supported(intptr_t arg)
25854c87aefeSPatrick Mooney {
25864c87aefeSPatrick Mooney 	int r;
25874c87aefeSPatrick Mooney 	const char *msg;
25884c87aefeSPatrick Mooney 
25894c87aefeSPatrick Mooney 	if (vmm_is_intel()) {
25904c87aefeSPatrick Mooney 		r = vmx_x86_supported(&msg);
2591154972afSPatrick Mooney 	} else if (vmm_is_svm()) {
25924c87aefeSPatrick Mooney 		/*
25934c87aefeSPatrick Mooney 		 * HMA already ensured that the features necessary for SVM
25944c87aefeSPatrick Mooney 		 * operation were present and online during vmm_attach().
25954c87aefeSPatrick Mooney 		 */
25964c87aefeSPatrick Mooney 		r = 0;
25974c87aefeSPatrick Mooney 	} else {
25984c87aefeSPatrick Mooney 		r = ENXIO;
25994c87aefeSPatrick Mooney 		msg = "Unsupported CPU vendor";
26004c87aefeSPatrick Mooney 	}
26014c87aefeSPatrick Mooney 
26024c87aefeSPatrick Mooney 	if (r != 0 && arg != (intptr_t)NULL) {
26034c87aefeSPatrick Mooney 		if (copyoutstr(msg, (char *)arg, strlen(msg) + 1, NULL) != 0)
26044c87aefeSPatrick Mooney 			return (EFAULT);
26054c87aefeSPatrick Mooney 	}
26064c87aefeSPatrick Mooney 	return (r);
26074c87aefeSPatrick Mooney }
26084c87aefeSPatrick Mooney 
2609b57f5d3eSPatrick Mooney static int
2610b57f5d3eSPatrick Mooney vmm_ctl_ioctl(int cmd, intptr_t arg, int md, cred_t *cr, int *rvalp)
2611b57f5d3eSPatrick Mooney {
2612b57f5d3eSPatrick Mooney 	void *argp = (void *)arg;
2613b57f5d3eSPatrick Mooney 
2614b57f5d3eSPatrick Mooney 	switch (cmd) {
2615b57f5d3eSPatrick Mooney 	case VMM_CREATE_VM: {
2616b57f5d3eSPatrick Mooney 		struct vm_create_req req;
2617b57f5d3eSPatrick Mooney 
2618b57f5d3eSPatrick Mooney 		if ((md & FWRITE) == 0) {
2619b57f5d3eSPatrick Mooney 			return (EPERM);
2620b57f5d3eSPatrick Mooney 		}
2621b57f5d3eSPatrick Mooney 		if (ddi_copyin(argp, &req, sizeof (req), md) != 0) {
2622b57f5d3eSPatrick Mooney 			return (EFAULT);
2623b57f5d3eSPatrick Mooney 		}
2624b57f5d3eSPatrick Mooney 		return (vmmdev_do_vm_create(&req, cr));
2625b57f5d3eSPatrick Mooney 	}
2626b57f5d3eSPatrick Mooney 	case VMM_DESTROY_VM: {
2627b57f5d3eSPatrick Mooney 		struct vm_destroy_req req;
2628b57f5d3eSPatrick Mooney 
2629b57f5d3eSPatrick Mooney 		if ((md & FWRITE) == 0) {
2630b57f5d3eSPatrick Mooney 			return (EPERM);
2631b57f5d3eSPatrick Mooney 		}
2632b57f5d3eSPatrick Mooney 		if (ddi_copyin(argp, &req, sizeof (req), md) != 0) {
2633b57f5d3eSPatrick Mooney 			return (EFAULT);
2634b57f5d3eSPatrick Mooney 		}
2635b57f5d3eSPatrick Mooney 		return (vmmdev_do_vm_destroy(&req, cr));
2636b57f5d3eSPatrick Mooney 	}
2637b57f5d3eSPatrick Mooney 	case VMM_VM_SUPPORTED:
2638b57f5d3eSPatrick Mooney 		return (vmm_is_supported(arg));
26393466010bSPatrick Mooney 	case VMM_INTERFACE_VERSION:
26403466010bSPatrick Mooney 		*rvalp = VMM_CURRENT_INTERFACE_VERSION;
26413466010bSPatrick Mooney 		return (0);
2642e760f150SPatrick Mooney 	case VMM_CHECK_IOMMU:
2643e760f150SPatrick Mooney 		if (!vmm_check_iommu()) {
2644e760f150SPatrick Mooney 			return (ENXIO);
2645e760f150SPatrick Mooney 		}
2646e760f150SPatrick Mooney 		return (0);
2647b57f5d3eSPatrick Mooney 	case VMM_RESV_QUERY:
2648b57f5d3eSPatrick Mooney 	case VMM_RESV_ADD:
2649b57f5d3eSPatrick Mooney 	case VMM_RESV_REMOVE:
2650b57f5d3eSPatrick Mooney 		return (vmmr_ioctl(cmd, arg, md, cr, rvalp));
2651b57f5d3eSPatrick Mooney 	default:
2652b57f5d3eSPatrick Mooney 		break;
2653b57f5d3eSPatrick Mooney 	}
2654b57f5d3eSPatrick Mooney 	/* No other actions are legal on ctl device */
2655b57f5d3eSPatrick Mooney 	return (ENOTTY);
2656b57f5d3eSPatrick Mooney }
2657b57f5d3eSPatrick Mooney 
2658bf21cd93STycho Nightingale static int
2659bf21cd93STycho Nightingale vmm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
2660bf21cd93STycho Nightingale     int *rvalp)
2661bf21cd93STycho Nightingale {
26624c87aefeSPatrick Mooney 	vmm_softc_t	*sc;
26634c87aefeSPatrick Mooney 	minor_t		minor;
2664bf21cd93STycho Nightingale 
26650153d828SPatrick Mooney 	/*
26660153d828SPatrick Mooney 	 * Forbid running bhyve in a 32-bit process until it has been tested and
26670153d828SPatrick Mooney 	 * verified to be safe.
26680153d828SPatrick Mooney 	 */
26690153d828SPatrick Mooney 	if (curproc->p_model != DATAMODEL_LP64) {
26700153d828SPatrick Mooney 		return (EFBIG);
26710153d828SPatrick Mooney 	}
26720153d828SPatrick Mooney 
2673e0c0d44eSPatrick Mooney 	/* The structs in bhyve ioctls assume a 64-bit datamodel */
2674e0c0d44eSPatrick Mooney 	if (ddi_model_convert_from(mode & FMODELS) != DDI_MODEL_NONE) {
2675e0c0d44eSPatrick Mooney 		return (ENOTSUP);
2676e0c0d44eSPatrick Mooney 	}
2677e0c0d44eSPatrick Mooney 
2678bf21cd93STycho Nightingale 	minor = getminor(dev);
2679bf21cd93STycho Nightingale 
2680bf21cd93STycho Nightingale 	if (minor == VMM_CTL_MINOR) {
2681b57f5d3eSPatrick Mooney 		return (vmm_ctl_ioctl(cmd, arg, mode, credp, rvalp));
2682bf21cd93STycho Nightingale 	}
2683bf21cd93STycho Nightingale 
2684bf21cd93STycho Nightingale 	sc = ddi_get_soft_state(vmm_statep, minor);
2685bf21cd93STycho Nightingale 	ASSERT(sc);
2686bf21cd93STycho Nightingale 
26874c87aefeSPatrick Mooney 	if (sc->vmm_flags & VMM_DESTROY)
26884c87aefeSPatrick Mooney 		return (ENXIO);
26894c87aefeSPatrick Mooney 
2690bf21cd93STycho Nightingale 	return (vmmdev_do_ioctl(sc, cmd, arg, mode, credp, rvalp));
2691bf21cd93STycho Nightingale }
2692bf21cd93STycho Nightingale 
2693bf21cd93STycho Nightingale static int
26944c87aefeSPatrick Mooney vmm_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
26954c87aefeSPatrick Mooney     unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp)
2696bf21cd93STycho Nightingale {
26974c87aefeSPatrick Mooney 	vmm_softc_t *sc;
26984c87aefeSPatrick Mooney 	const minor_t minor = getminor(dev);
26994c87aefeSPatrick Mooney 	int err;
27004c87aefeSPatrick Mooney 
27014c87aefeSPatrick Mooney 	if (minor == VMM_CTL_MINOR) {
27024c87aefeSPatrick Mooney 		return (ENODEV);
27034c87aefeSPatrick Mooney 	}
27044c87aefeSPatrick Mooney 	if (off < 0 || (off + len) <= 0) {
27054c87aefeSPatrick Mooney 		return (EINVAL);
27064c87aefeSPatrick Mooney 	}
27074c87aefeSPatrick Mooney 	if ((prot & PROT_USER) == 0) {
27084c87aefeSPatrick Mooney 		return (EACCES);
27094c87aefeSPatrick Mooney 	}
2710bf21cd93STycho Nightingale 
27114c87aefeSPatrick Mooney 	sc = ddi_get_soft_state(vmm_statep, minor);
2712bf21cd93STycho Nightingale 	ASSERT(sc);
2713bf21cd93STycho Nightingale 
27144c87aefeSPatrick Mooney 	if (sc->vmm_flags & VMM_DESTROY)
27154c87aefeSPatrick Mooney 		return (ENXIO);
2716bf21cd93STycho Nightingale 
27174c87aefeSPatrick Mooney 	/* Grab read lock on the VM to prevent any changes to the memory map */
27184c87aefeSPatrick Mooney 	vmm_read_lock(sc);
2719bf21cd93STycho Nightingale 
27204c87aefeSPatrick Mooney 	if (off >= VM_DEVMEM_START) {
27214c87aefeSPatrick Mooney 		int segid;
27220153d828SPatrick Mooney 		off_t segoff;
2723bf21cd93STycho Nightingale 
27244c87aefeSPatrick Mooney 		/* Mapping a devmem "device" */
27250153d828SPatrick Mooney 		if (!vmmdev_devmem_segid(sc, off, len, &segid, &segoff)) {
27264c87aefeSPatrick Mooney 			err = ENODEV;
27270153d828SPatrick Mooney 		} else {
27280153d828SPatrick Mooney 			err = vm_segmap_obj(sc->vmm_vm, segid, segoff, len, as,
27290153d828SPatrick Mooney 			    addrp, prot, maxprot, flags);
27304c87aefeSPatrick Mooney 		}
27314c87aefeSPatrick Mooney 	} else {
27324c87aefeSPatrick Mooney 		/* Mapping a part of the guest physical space */
27330153d828SPatrick Mooney 		err = vm_segmap_space(sc->vmm_vm, off, as, addrp, len, prot,
27340153d828SPatrick Mooney 		    maxprot, flags);
2735bf21cd93STycho Nightingale 	}
2736bf21cd93STycho Nightingale 
27374c87aefeSPatrick Mooney 	vmm_read_unlock(sc);
27384c87aefeSPatrick Mooney 	return (err);
2739bf21cd93STycho Nightingale }
2740bf21cd93STycho Nightingale 
27414c87aefeSPatrick Mooney static sdev_plugin_validate_t
27424c87aefeSPatrick Mooney vmm_sdev_validate(sdev_ctx_t ctx)
2743bf21cd93STycho Nightingale {
27444c87aefeSPatrick Mooney 	const char *name = sdev_ctx_name(ctx);
27454c87aefeSPatrick Mooney 	vmm_softc_t *sc;
27464c87aefeSPatrick Mooney 	sdev_plugin_validate_t ret;
27474c87aefeSPatrick Mooney 	minor_t minor;
27484c87aefeSPatrick Mooney 
27494c87aefeSPatrick Mooney 	if (sdev_ctx_vtype(ctx) != VCHR)
27504c87aefeSPatrick Mooney 		return (SDEV_VTOR_INVALID);
27514c87aefeSPatrick Mooney 
27524c87aefeSPatrick Mooney 	VERIFY3S(sdev_ctx_minor(ctx, &minor), ==, 0);
27534c87aefeSPatrick Mooney 
27544c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
27554c87aefeSPatrick Mooney 	if ((sc = vmm_lookup(name)) == NULL)
27564c87aefeSPatrick Mooney 		ret = SDEV_VTOR_INVALID;
27574c87aefeSPatrick Mooney 	else if (sc->vmm_minor != minor)
27584c87aefeSPatrick Mooney 		ret = SDEV_VTOR_STALE;
27594c87aefeSPatrick Mooney 	else
27604c87aefeSPatrick Mooney 		ret = SDEV_VTOR_VALID;
27614c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
27624c87aefeSPatrick Mooney 
27634c87aefeSPatrick Mooney 	return (ret);
2764bf21cd93STycho Nightingale }
2765bf21cd93STycho Nightingale 
2766bf21cd93STycho Nightingale static int
27674c87aefeSPatrick Mooney vmm_sdev_filldir(sdev_ctx_t ctx)
2768bf21cd93STycho Nightingale {
27694c87aefeSPatrick Mooney 	vmm_softc_t *sc;
27704c87aefeSPatrick Mooney 	int ret;
27714c87aefeSPatrick Mooney 
27724c87aefeSPatrick Mooney 	if (strcmp(sdev_ctx_path(ctx), VMM_SDEV_ROOT) != 0) {
27734c87aefeSPatrick Mooney 		cmn_err(CE_WARN, "%s: bad path '%s' != '%s'\n", __func__,
27744c87aefeSPatrick Mooney 		    sdev_ctx_path(ctx), VMM_SDEV_ROOT);
27754c87aefeSPatrick Mooney 		return (EINVAL);
27764c87aefeSPatrick Mooney 	}
27774c87aefeSPatrick Mooney 
27784c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
27794c87aefeSPatrick Mooney 	ASSERT(vmmdev_dip != NULL);
27804c87aefeSPatrick Mooney 	for (sc = list_head(&vmm_list); sc != NULL;
27814c87aefeSPatrick Mooney 	    sc = list_next(&vmm_list, sc)) {
27824c87aefeSPatrick Mooney 		if (INGLOBALZONE(curproc) || sc->vmm_zone == curzone) {
27834c87aefeSPatrick Mooney 			ret = sdev_plugin_mknod(ctx, sc->vmm_name,
27844c87aefeSPatrick Mooney 			    S_IFCHR | 0600,
27854c87aefeSPatrick Mooney 			    makedevice(ddi_driver_major(vmmdev_dip),
27864c87aefeSPatrick Mooney 			    sc->vmm_minor));
27874c87aefeSPatrick Mooney 		} else {
27884c87aefeSPatrick Mooney 			continue;
27894c87aefeSPatrick Mooney 		}
27904c87aefeSPatrick Mooney 		if (ret != 0 && ret != EEXIST)
27914c87aefeSPatrick Mooney 			goto out;
2792bf21cd93STycho Nightingale 	}
2793bf21cd93STycho Nightingale 
27944c87aefeSPatrick Mooney 	ret = 0;
27954c87aefeSPatrick Mooney 
27964c87aefeSPatrick Mooney out:
27974c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
27984c87aefeSPatrick Mooney 	return (ret);
27994c87aefeSPatrick Mooney }
28004c87aefeSPatrick Mooney 
28014c87aefeSPatrick Mooney /* ARGSUSED */
28024c87aefeSPatrick Mooney static void
28034c87aefeSPatrick Mooney vmm_sdev_inactive(sdev_ctx_t ctx)
28044c87aefeSPatrick Mooney {
2805bf21cd93STycho Nightingale }
2806bf21cd93STycho Nightingale 
28074c87aefeSPatrick Mooney static sdev_plugin_ops_t vmm_sdev_ops = {
28084c87aefeSPatrick Mooney 	.spo_version = SDEV_PLUGIN_VERSION,
28094c87aefeSPatrick Mooney 	.spo_flags = SDEV_PLUGIN_SUBDIR,
28104c87aefeSPatrick Mooney 	.spo_validate = vmm_sdev_validate,
28114c87aefeSPatrick Mooney 	.spo_filldir = vmm_sdev_filldir,
28124c87aefeSPatrick Mooney 	.spo_inactive = vmm_sdev_inactive
28134c87aefeSPatrick Mooney };
28144c87aefeSPatrick Mooney 
28154c87aefeSPatrick Mooney /* ARGSUSED */
2816bf21cd93STycho Nightingale static int
28174c87aefeSPatrick Mooney vmm_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2818bf21cd93STycho Nightingale {
28194c87aefeSPatrick Mooney 	int error;
28204c87aefeSPatrick Mooney 
2821bf21cd93STycho Nightingale 	switch (cmd) {
28224c87aefeSPatrick Mooney 	case DDI_INFO_DEVT2DEVINFO:
28234c87aefeSPatrick Mooney 		*result = (void *)vmmdev_dip;
28244c87aefeSPatrick Mooney 		error = DDI_SUCCESS;
28254c87aefeSPatrick Mooney 		break;
28264c87aefeSPatrick Mooney 	case DDI_INFO_DEVT2INSTANCE:
28274c87aefeSPatrick Mooney 		*result = (void *)0;
28284c87aefeSPatrick Mooney 		error = DDI_SUCCESS;
2829bf21cd93STycho Nightingale 		break;
2830bf21cd93STycho Nightingale 	default:
28314c87aefeSPatrick Mooney 		error = DDI_FAILURE;
28324c87aefeSPatrick Mooney 		break;
28334c87aefeSPatrick Mooney 	}
28344c87aefeSPatrick Mooney 	return (error);
28354c87aefeSPatrick Mooney }
28364c87aefeSPatrick Mooney 
28374c87aefeSPatrick Mooney static int
28384c87aefeSPatrick Mooney vmm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
28394c87aefeSPatrick Mooney {
28404c87aefeSPatrick Mooney 	sdev_plugin_hdl_t sph;
28414c87aefeSPatrick Mooney 	hma_reg_t *reg = NULL;
28424c87aefeSPatrick Mooney 	boolean_t vmm_loaded = B_FALSE;
28434c87aefeSPatrick Mooney 
28444c87aefeSPatrick Mooney 	if (cmd != DDI_ATTACH) {
2845bf21cd93STycho Nightingale 		return (DDI_FAILURE);
2846bf21cd93STycho Nightingale 	}
2847bf21cd93STycho Nightingale 
28484c87aefeSPatrick Mooney 	mutex_enter(&vmmdev_mtx);
28494c87aefeSPatrick Mooney 	/* Ensure we are not already attached. */
28504c87aefeSPatrick Mooney 	if (vmmdev_dip != NULL) {
28514c87aefeSPatrick Mooney 		mutex_exit(&vmmdev_mtx);
2852bf21cd93STycho Nightingale 		return (DDI_FAILURE);
2853bf21cd93STycho Nightingale 	}
2854bf21cd93STycho Nightingale 
28554c87aefeSPatrick Mooney 	vmm_sol_glue_init();
2856bf21cd93STycho Nightingale 
28578e3a263eSAndy Fiddaman 	/*
28588e3a263eSAndy Fiddaman 	 * Perform temporary HMA registration to determine if the system
28598e3a263eSAndy Fiddaman 	 * is capable.
28608e3a263eSAndy Fiddaman 	 */
28614c87aefeSPatrick Mooney 	if ((reg = hma_register(vmmdev_hvm_name)) == NULL) {
28624c87aefeSPatrick Mooney 		goto fail;
28634c87aefeSPatrick Mooney 	} else if (vmm_mod_load() != 0) {
28644c87aefeSPatrick Mooney 		goto fail;
28654c87aefeSPatrick Mooney 	}
28664c87aefeSPatrick Mooney 	vmm_loaded = B_TRUE;
28678e3a263eSAndy Fiddaman 	hma_unregister(reg);
28688e3a263eSAndy Fiddaman 	reg = NULL;
28694c87aefeSPatrick Mooney 
28704c87aefeSPatrick Mooney 	/* Create control node.  Other nodes will be created on demand. */
28714c87aefeSPatrick Mooney 	if (ddi_create_minor_node(dip, "ctl", S_IFCHR,
2872bf21cd93STycho Nightingale 	    VMM_CTL_MINOR, DDI_PSEUDO, 0) != 0) {
28734c87aefeSPatrick Mooney 		goto fail;
2874bf21cd93STycho Nightingale 	}
2875bf21cd93STycho Nightingale 
287659460b49SPatrick Mooney 	sph = sdev_plugin_register(VMM_MODULE_NAME, &vmm_sdev_ops, NULL);
287759460b49SPatrick Mooney 	if (sph == (sdev_plugin_hdl_t)NULL) {
28784c87aefeSPatrick Mooney 		ddi_remove_minor_node(dip, NULL);
28794c87aefeSPatrick Mooney 		goto fail;
28804c87aefeSPatrick Mooney 	}
2881bf21cd93STycho Nightingale 
28824c87aefeSPatrick Mooney 	ddi_report_dev(dip);
28834c87aefeSPatrick Mooney 	vmmdev_sdev_hdl = sph;
28844c87aefeSPatrick Mooney 	vmmdev_dip = dip;
28854c87aefeSPatrick Mooney 	mutex_exit(&vmmdev_mtx);
2886bf21cd93STycho Nightingale 	return (DDI_SUCCESS);
28874c87aefeSPatrick Mooney 
28884c87aefeSPatrick Mooney fail:
28894c87aefeSPatrick Mooney 	if (vmm_loaded) {
28904c87aefeSPatrick Mooney 		VERIFY0(vmm_mod_unload());
28914c87aefeSPatrick Mooney 	}
28924c87aefeSPatrick Mooney 	if (reg != NULL) {
28934c87aefeSPatrick Mooney 		hma_unregister(reg);
28944c87aefeSPatrick Mooney 	}
28954c87aefeSPatrick Mooney 	vmm_sol_glue_cleanup();
28964c87aefeSPatrick Mooney 	mutex_exit(&vmmdev_mtx);
28974c87aefeSPatrick Mooney 	return (DDI_FAILURE);
2898bf21cd93STycho Nightingale }
2899bf21cd93STycho Nightingale 
2900bf21cd93STycho Nightingale static int
2901bf21cd93STycho Nightingale vmm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2902bf21cd93STycho Nightingale {
29034c87aefeSPatrick Mooney 	if (cmd != DDI_DETACH) {
29044c87aefeSPatrick Mooney 		return (DDI_FAILURE);
29054c87aefeSPatrick Mooney 	}
29064c87aefeSPatrick Mooney 
2907eb9a1df2SHans Rosenfeld 	/*
2908eb9a1df2SHans Rosenfeld 	 * Ensure that all resources have been cleaned up.
2909eb9a1df2SHans Rosenfeld 	 *
2910eb9a1df2SHans Rosenfeld 	 * To prevent a deadlock with iommu_cleanup() we'll fail the detach if
2911eb9a1df2SHans Rosenfeld 	 * vmmdev_mtx is already held. We can't wait for vmmdev_mtx with our
2912eb9a1df2SHans Rosenfeld 	 * devinfo locked as iommu_cleanup() tries to recursively lock each
2913eb9a1df2SHans Rosenfeld 	 * devinfo, including our own, while holding vmmdev_mtx.
2914eb9a1df2SHans Rosenfeld 	 */
2915eb9a1df2SHans Rosenfeld 	if (mutex_tryenter(&vmmdev_mtx) == 0)
2916eb9a1df2SHans Rosenfeld 		return (DDI_FAILURE);
29174c87aefeSPatrick Mooney 
29184c87aefeSPatrick Mooney 	mutex_enter(&vmm_mtx);
29194c87aefeSPatrick Mooney 	if (!list_is_empty(&vmm_list) || !list_is_empty(&vmm_destroy_list)) {
29204c87aefeSPatrick Mooney 		mutex_exit(&vmm_mtx);
29214c87aefeSPatrick Mooney 		mutex_exit(&vmmdev_mtx);
2922bf21cd93STycho Nightingale 		return (DDI_FAILURE);
2923bf21cd93STycho Nightingale 	}
29244c87aefeSPatrick Mooney 	mutex_exit(&vmm_mtx);
2925bf21cd93STycho Nightingale 
2926b57f5d3eSPatrick Mooney 	if (!vmmr_is_empty()) {
2927b57f5d3eSPatrick Mooney 		mutex_exit(&vmmdev_mtx);
2928b57f5d3eSPatrick Mooney 		return (DDI_FAILURE);
2929b57f5d3eSPatrick Mooney 	}
2930b57f5d3eSPatrick Mooney 
29314c87aefeSPatrick Mooney 	VERIFY(vmmdev_sdev_hdl != (sdev_plugin_hdl_t)NULL);
29324c87aefeSPatrick Mooney 	if (sdev_plugin_unregister(vmmdev_sdev_hdl) != 0) {
29334c87aefeSPatrick Mooney 		mutex_exit(&vmmdev_mtx);
2934bf21cd93STycho Nightingale 		return (DDI_FAILURE);
2935bf21cd93STycho Nightingale 	}
29364c87aefeSPatrick Mooney 	vmmdev_sdev_hdl = (sdev_plugin_hdl_t)NULL;
2937bf21cd93STycho Nightingale 
29384c87aefeSPatrick Mooney 	/* Remove the control node. */
29394c87aefeSPatrick Mooney 	ddi_remove_minor_node(dip, "ctl");
29404c87aefeSPatrick Mooney 	vmmdev_dip = NULL;
29414c87aefeSPatrick Mooney 
29424c87aefeSPatrick Mooney 	VERIFY0(vmm_mod_unload());
29438e3a263eSAndy Fiddaman 	VERIFY3U(vmmdev_hma_reg, ==, NULL);
29444c87aefeSPatrick Mooney 	vmm_sol_glue_cleanup();
29454c87aefeSPatrick Mooney 
29464c87aefeSPatrick Mooney 	mutex_exit(&vmmdev_mtx);
2947bf21cd93STycho Nightingale 
2948bf21cd93STycho Nightingale 	return (DDI_SUCCESS);
2949bf21cd93STycho Nightingale }
2950bf21cd93STycho Nightingale 
2951bf21cd93STycho Nightingale static struct cb_ops vmm_cb_ops = {
2952bf21cd93STycho Nightingale 	vmm_open,
2953bf21cd93STycho Nightingale 	vmm_close,
2954bf21cd93STycho Nightingale 	nodev,		/* strategy */
2955bf21cd93STycho Nightingale 	nodev,		/* print */
2956bf21cd93STycho Nightingale 	nodev,		/* dump */
2957bf21cd93STycho Nightingale 	nodev,		/* read */
2958bf21cd93STycho Nightingale 	nodev,		/* write */
2959bf21cd93STycho Nightingale 	vmm_ioctl,
2960bf21cd93STycho Nightingale 	nodev,		/* devmap */
29614c87aefeSPatrick Mooney 	nodev,		/* mmap */
2962bf21cd93STycho Nightingale 	vmm_segmap,
2963bf21cd93STycho Nightingale 	nochpoll,	/* poll */
2964bf21cd93STycho Nightingale 	ddi_prop_op,
2965bf21cd93STycho Nightingale 	NULL,
2966bf21cd93STycho Nightingale 	D_NEW | D_MP | D_DEVMAP
2967bf21cd93STycho Nightingale };
2968bf21cd93STycho Nightingale 
2969bf21cd93STycho Nightingale static struct dev_ops vmm_ops = {
2970bf21cd93STycho Nightingale 	DEVO_REV,
2971bf21cd93STycho Nightingale 	0,
29724c87aefeSPatrick Mooney 	vmm_info,
2973bf21cd93STycho Nightingale 	nulldev,	/* identify */
29744c87aefeSPatrick Mooney 	nulldev,	/* probe */
2975bf21cd93STycho Nightingale 	vmm_attach,
2976bf21cd93STycho Nightingale 	vmm_detach,
2977bf21cd93STycho Nightingale 	nodev,		/* reset */
2978bf21cd93STycho Nightingale 	&vmm_cb_ops,
2979bf21cd93STycho Nightingale 	(struct bus_ops *)NULL
2980bf21cd93STycho Nightingale };
2981bf21cd93STycho Nightingale 
2982bf21cd93STycho Nightingale static struct modldrv modldrv = {
2983bf21cd93STycho Nightingale 	&mod_driverops,
29844c87aefeSPatrick Mooney 	"bhyve vmm",
2985bf21cd93STycho Nightingale 	&vmm_ops
2986bf21cd93STycho Nightingale };
2987bf21cd93STycho Nightingale 
2988bf21cd93STycho Nightingale static struct modlinkage modlinkage = {
2989bf21cd93STycho Nightingale 	MODREV_1,
2990bf21cd93STycho Nightingale 	&modldrv,
2991bf21cd93STycho Nightingale 	NULL
2992bf21cd93STycho Nightingale };
2993bf21cd93STycho Nightingale 
2994bf21cd93STycho Nightingale int
2995bf21cd93STycho Nightingale _init(void)
2996bf21cd93STycho Nightingale {
2997bf21cd93STycho Nightingale 	int	error;
2998bf21cd93STycho Nightingale 
29994c87aefeSPatrick Mooney 	sysinit();
3000bf21cd93STycho Nightingale 
30014c87aefeSPatrick Mooney 	mutex_init(&vmmdev_mtx, NULL, MUTEX_DRIVER, NULL);
30024c87aefeSPatrick Mooney 	mutex_init(&vmm_mtx, NULL, MUTEX_DRIVER, NULL);
30034c87aefeSPatrick Mooney 	list_create(&vmm_list, sizeof (vmm_softc_t),
30044c87aefeSPatrick Mooney 	    offsetof(vmm_softc_t, vmm_node));
30054c87aefeSPatrick Mooney 	list_create(&vmm_destroy_list, sizeof (vmm_softc_t),
30064c87aefeSPatrick Mooney 	    offsetof(vmm_softc_t, vmm_node));
30074c87aefeSPatrick Mooney 	vmm_minors = id_space_create("vmm_minors", VMM_CTL_MINOR + 1, MAXMIN32);
30084c87aefeSPatrick Mooney 
30094c87aefeSPatrick Mooney 	error = ddi_soft_state_init(&vmm_statep, sizeof (vmm_softc_t), 0);
3010bf21cd93STycho Nightingale 	if (error) {
3011bf21cd93STycho Nightingale 		return (error);
3012bf21cd93STycho Nightingale 	}
3013bf21cd93STycho Nightingale 
30144c87aefeSPatrick Mooney 	vmm_zsd_init();
3015b57f5d3eSPatrick Mooney 	vmmr_init();
30164c87aefeSPatrick Mooney 
3017bf21cd93STycho Nightingale 	error = mod_install(&modlinkage);
3018bf21cd93STycho Nightingale 	if (error) {
3019bf21cd93STycho Nightingale 		ddi_soft_state_fini(&vmm_statep);
30204c87aefeSPatrick Mooney 		vmm_zsd_fini();
3021b57f5d3eSPatrick Mooney 		vmmr_fini();
3022bf21cd93STycho Nightingale 	}
3023bf21cd93STycho Nightingale 
3024bf21cd93STycho Nightingale 	return (error);
3025bf21cd93STycho Nightingale }
3026bf21cd93STycho Nightingale 
3027bf21cd93STycho Nightingale int
3028bf21cd93STycho Nightingale _fini(void)
3029bf21cd93STycho Nightingale {
3030bf21cd93STycho Nightingale 	int	error;
3031bf21cd93STycho Nightingale 
3032bf21cd93STycho Nightingale 	error = mod_remove(&modlinkage);
3033bf21cd93STycho Nightingale 	if (error) {
3034bf21cd93STycho Nightingale 		return (error);
3035bf21cd93STycho Nightingale 	}
30364c87aefeSPatrick Mooney 
30374c87aefeSPatrick Mooney 	vmm_zsd_fini();
3038b57f5d3eSPatrick Mooney 	vmmr_fini();
30394c87aefeSPatrick Mooney 
3040bf21cd93STycho Nightingale 	ddi_soft_state_fini(&vmm_statep);
3041bf21cd93STycho Nightingale 
3042bf21cd93STycho Nightingale 	return (0);
3043bf21cd93STycho Nightingale }
3044bf21cd93STycho Nightingale 
3045bf21cd93STycho Nightingale int
3046bf21cd93STycho Nightingale _info(struct modinfo *modinfop)
3047bf21cd93STycho Nightingale {
3048bf21cd93STycho Nightingale 	return (mod_info(&modlinkage, modinfop));
3049bf21cd93STycho Nightingale }
3050