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 ®vals[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