17c8c0b82SPatrick Mooney /*
27c8c0b82SPatrick Mooney * This file and its contents are supplied under the terms of the
37c8c0b82SPatrick Mooney * Common Development and Distribution License ("CDDL"), version 1.0.
47c8c0b82SPatrick Mooney * You may only use this file in accordance with the terms of version
57c8c0b82SPatrick Mooney * 1.0 of the CDDL.
67c8c0b82SPatrick Mooney *
77c8c0b82SPatrick Mooney * A full copy of the text of the CDDL should have accompanied this
87c8c0b82SPatrick Mooney * source. A copy of the CDDL is also available via the Internet at
97c8c0b82SPatrick Mooney * http://www.illumos.org/license/CDDL.
107c8c0b82SPatrick Mooney */
117c8c0b82SPatrick Mooney /* This file is dual-licensed; see usr/src/contrib/bhyve/LICENSE */
127c8c0b82SPatrick Mooney
137c8c0b82SPatrick Mooney /*
147c8c0b82SPatrick Mooney * Copyright 2015 Pluribus Networks Inc.
157c8c0b82SPatrick Mooney * Copyright 2019 Joyent, Inc.
167c8c0b82SPatrick Mooney * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
176bba8b59SPatrick Mooney * Copyright 2023 Oxide Computer Company
187c8c0b82SPatrick Mooney */
197c8c0b82SPatrick Mooney
207c8c0b82SPatrick Mooney #include <sys/types.h>
217c8c0b82SPatrick Mooney #include <sys/conf.h>
227c8c0b82SPatrick Mooney #include <sys/cpuvar.h>
237c8c0b82SPatrick Mooney #include <sys/ioccom.h>
247c8c0b82SPatrick Mooney #include <sys/stat.h>
257c8c0b82SPatrick Mooney #include <sys/vmsystm.h>
267c8c0b82SPatrick Mooney #include <sys/ddi.h>
277c8c0b82SPatrick Mooney #include <sys/mkdev.h>
287c8c0b82SPatrick Mooney #include <sys/sunddi.h>
297c8c0b82SPatrick Mooney #include <sys/fs/dv_node.h>
307c8c0b82SPatrick Mooney #include <sys/cpuset.h>
317c8c0b82SPatrick Mooney #include <sys/id_space.h>
327c8c0b82SPatrick Mooney #include <sys/fs/sdev_plugin.h>
337c8c0b82SPatrick Mooney #include <sys/smt.h>
347c8c0b82SPatrick Mooney #include <sys/kstat.h>
357c8c0b82SPatrick Mooney
367c8c0b82SPatrick Mooney #include <sys/kernel.h>
377c8c0b82SPatrick Mooney #include <sys/hma.h>
387c8c0b82SPatrick Mooney #include <sys/x86_archext.h>
397c8c0b82SPatrick Mooney #include <x86/apicreg.h>
407c8c0b82SPatrick Mooney
417c8c0b82SPatrick Mooney #include <sys/vmm.h>
427c8c0b82SPatrick Mooney #include <sys/vmm_kernel.h>
437c8c0b82SPatrick Mooney #include <sys/vmm_instruction_emul.h>
447c8c0b82SPatrick Mooney #include <sys/vmm_dev.h>
457c8c0b82SPatrick Mooney #include <sys/vmm_impl.h>
467c8c0b82SPatrick Mooney #include <sys/vmm_drv.h>
477c8c0b82SPatrick Mooney #include <sys/vmm_vm.h>
487c8c0b82SPatrick Mooney #include <sys/vmm_reservoir.h>
497c8c0b82SPatrick Mooney
507c8c0b82SPatrick Mooney #include <vm/seg_dev.h>
517c8c0b82SPatrick Mooney
527c8c0b82SPatrick Mooney #include "io/ppt.h"
537c8c0b82SPatrick Mooney #include "io/vatpic.h"
547c8c0b82SPatrick Mooney #include "io/vioapic.h"
557c8c0b82SPatrick Mooney #include "io/vrtc.h"
567c8c0b82SPatrick Mooney #include "io/vhpet.h"
577c8c0b82SPatrick Mooney #include "io/vpmtmr.h"
587c8c0b82SPatrick Mooney #include "vmm_lapic.h"
597c8c0b82SPatrick Mooney #include "vmm_stat.h"
607c8c0b82SPatrick Mooney #include "vmm_util.h"
617c8c0b82SPatrick Mooney
627c8c0b82SPatrick Mooney /*
637c8c0b82SPatrick Mooney * Locking details:
647c8c0b82SPatrick Mooney *
657c8c0b82SPatrick Mooney * Driver-wide data (vmmdev_*) , including HMA and sdev registration, is
667c8c0b82SPatrick Mooney * protected by vmmdev_mtx. The list of vmm_softc_t instances and related data
677c8c0b82SPatrick Mooney * (vmm_*) are protected by vmm_mtx. Actions requiring both locks must acquire
687c8c0b82SPatrick Mooney * vmmdev_mtx before vmm_mtx. The sdev plugin functions must not attempt to
697c8c0b82SPatrick Mooney * acquire vmmdev_mtx, as they could deadlock with plugin unregistration.
707c8c0b82SPatrick Mooney */
717c8c0b82SPatrick Mooney
727c8c0b82SPatrick Mooney static kmutex_t vmmdev_mtx;
737c8c0b82SPatrick Mooney static dev_info_t *vmmdev_dip;
747c8c0b82SPatrick Mooney static hma_reg_t *vmmdev_hma_reg;
757c8c0b82SPatrick Mooney static uint_t vmmdev_hma_ref;
767c8c0b82SPatrick Mooney static sdev_plugin_hdl_t vmmdev_sdev_hdl;
777c8c0b82SPatrick Mooney
787c8c0b82SPatrick Mooney static kmutex_t vmm_mtx;
797c8c0b82SPatrick Mooney static list_t vmm_list;
807c8c0b82SPatrick Mooney static id_space_t *vmm_minors;
817c8c0b82SPatrick Mooney static void *vmm_statep;
827c8c0b82SPatrick Mooney
831ab0d30fSPatrick Mooney /*
841ab0d30fSPatrick Mooney * Until device emulation in bhyve had been adequately scrutinized and tested,
851ab0d30fSPatrick Mooney * there was (justified) concern that unusual or corrupt device state payloads
861ab0d30fSPatrick Mooney * could crash the host when loaded via the vmm-data interface.
871ab0d30fSPatrick Mooney *
881ab0d30fSPatrick Mooney * Now that those concerns have been mitigated, this protection is loosened to
891ab0d30fSPatrick Mooney * default-allow, but the switch is left in place, in case there is a need to
901ab0d30fSPatrick Mooney * once again clamp down on vmm-data writes.
911ab0d30fSPatrick Mooney */
921ab0d30fSPatrick Mooney int vmm_allow_state_writes = 1;
93d515dd77SPatrick Mooney
947c8c0b82SPatrick Mooney static const char *vmmdev_hvm_name = "bhyve";
957c8c0b82SPatrick Mooney
967c8c0b82SPatrick Mooney /* For sdev plugin (/dev) */
977c8c0b82SPatrick Mooney #define VMM_SDEV_ROOT "/dev/vmm"
987c8c0b82SPatrick Mooney
997c8c0b82SPatrick Mooney /* From uts/intel/io/vmm/intel/vmx.c */
1007c8c0b82SPatrick Mooney extern int vmx_x86_supported(const char **);
1017c8c0b82SPatrick Mooney
1027c8c0b82SPatrick Mooney /* Holds and hooks from drivers external to vmm */
1037c8c0b82SPatrick Mooney struct vmm_hold {
1047c8c0b82SPatrick Mooney list_node_t vmh_node;
1057c8c0b82SPatrick Mooney vmm_softc_t *vmh_sc;
1067c8c0b82SPatrick Mooney boolean_t vmh_release_req;
1077c8c0b82SPatrick Mooney uint_t vmh_ioport_hook_cnt;
1087c8c0b82SPatrick Mooney };
1097c8c0b82SPatrick Mooney
1107c8c0b82SPatrick Mooney struct vmm_lease {
1117c8c0b82SPatrick Mooney list_node_t vml_node;
1127c8c0b82SPatrick Mooney struct vm *vml_vm;
1137c8c0b82SPatrick Mooney vm_client_t *vml_vmclient;
1147c8c0b82SPatrick Mooney boolean_t vml_expired;
1157c8c0b82SPatrick Mooney boolean_t vml_break_deferred;
1167c8c0b82SPatrick Mooney boolean_t (*vml_expire_func)(void *);
1177c8c0b82SPatrick Mooney void *vml_expire_arg;
1187c8c0b82SPatrick Mooney struct vmm_hold *vml_hold;
1197c8c0b82SPatrick Mooney };
1207c8c0b82SPatrick Mooney
121aa39f6d0SPatrick Mooney /* Options for vmm_destroy_locked */
122aa39f6d0SPatrick Mooney typedef enum vmm_destroy_opts {
123aa39f6d0SPatrick Mooney VDO_DEFAULT = 0,
124aa39f6d0SPatrick Mooney /*
12542640e49SPatrick Mooney * Indicate that zone-specific-data associated with this VM not be
126aa39f6d0SPatrick Mooney * cleaned up as part of the destroy. Skipping ZSD clean-up is
127aa39f6d0SPatrick Mooney * necessary when VM is being destroyed as part of zone destruction,
128aa39f6d0SPatrick Mooney * when said ZSD is already being cleaned up.
129aa39f6d0SPatrick Mooney */
130aa39f6d0SPatrick Mooney VDO_NO_CLEAN_ZSD = (1 << 0),
131aa39f6d0SPatrick Mooney /*
13242640e49SPatrick Mooney * Attempt to wait for VM destruction to complete. This is opt-in,
13342640e49SPatrick Mooney * since there are many normal conditions which could lead to
13442640e49SPatrick Mooney * destruction being stalled pending other clean-up.
135aa39f6d0SPatrick Mooney */
13642640e49SPatrick Mooney VDO_ATTEMPT_WAIT = (1 << 1),
137aa39f6d0SPatrick Mooney } vmm_destroy_opts_t;
138aa39f6d0SPatrick Mooney
13942640e49SPatrick Mooney static void vmm_hma_release(void);
14042640e49SPatrick Mooney static int vmm_destroy_locked(vmm_softc_t *, vmm_destroy_opts_t, bool *);
1417c8c0b82SPatrick Mooney static int vmm_drv_block_hook(vmm_softc_t *, boolean_t);
1427c8c0b82SPatrick Mooney static void vmm_lease_block(vmm_softc_t *);
1437c8c0b82SPatrick Mooney static void vmm_lease_unblock(vmm_softc_t *);
1447c8c0b82SPatrick Mooney static int vmm_kstat_alloc(vmm_softc_t *, minor_t, const cred_t *);
1457c8c0b82SPatrick Mooney static void vmm_kstat_init(vmm_softc_t *);
1467c8c0b82SPatrick Mooney static void vmm_kstat_fini(vmm_softc_t *);
1477c8c0b82SPatrick Mooney
1487c8c0b82SPatrick Mooney /*
1497c8c0b82SPatrick Mooney * The 'devmem' hack:
1507c8c0b82SPatrick Mooney *
1517c8c0b82SPatrick Mooney * On native FreeBSD, bhyve consumers are allowed to create 'devmem' segments
1527c8c0b82SPatrick Mooney * in the vm which appear with their own name related to the vm under /dev.
1537c8c0b82SPatrick Mooney * Since this would be a hassle from an sdev perspective and would require a
1547c8c0b82SPatrick Mooney * new cdev interface (or complicate the existing one), we choose to implement
1557c8c0b82SPatrick Mooney * this in a different manner. Direct access to the underlying vm memory
1567c8c0b82SPatrick Mooney * segments is exposed by placing them in a range of offsets beyond the normal
1577c8c0b82SPatrick Mooney * guest memory space. Userspace can query the appropriate offset to mmap()
1587c8c0b82SPatrick Mooney * for a given segment-id with the VM_DEVMEM_GETOFFSET ioctl.
1597c8c0b82SPatrick Mooney */
1607c8c0b82SPatrick Mooney
1617c8c0b82SPatrick Mooney static vmm_devmem_entry_t *
vmmdev_devmem_find(vmm_softc_t * sc,int segid)1627c8c0b82SPatrick Mooney vmmdev_devmem_find(vmm_softc_t *sc, int segid)
1637c8c0b82SPatrick Mooney {
1647c8c0b82SPatrick Mooney vmm_devmem_entry_t *ent = NULL;
1657c8c0b82SPatrick Mooney list_t *dl = &sc->vmm_devmem_list;
1667c8c0b82SPatrick Mooney
1677c8c0b82SPatrick Mooney for (ent = list_head(dl); ent != NULL; ent = list_next(dl, ent)) {
1687c8c0b82SPatrick Mooney if (ent->vde_segid == segid) {
1697c8c0b82SPatrick Mooney return (ent);
1707c8c0b82SPatrick Mooney }
1717c8c0b82SPatrick Mooney }
1727c8c0b82SPatrick Mooney return (NULL);
1737c8c0b82SPatrick Mooney }
1747c8c0b82SPatrick Mooney
1757c8c0b82SPatrick Mooney static int
vmmdev_get_memseg(vmm_softc_t * sc,struct vm_memseg * mseg)1767c8c0b82SPatrick Mooney vmmdev_get_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
1777c8c0b82SPatrick Mooney {
1787c8c0b82SPatrick Mooney int error;
1797c8c0b82SPatrick Mooney bool sysmem;
1807c8c0b82SPatrick Mooney
1817c8c0b82SPatrick Mooney error = vm_get_memseg(sc->vmm_vm, mseg->segid, &mseg->len, &sysmem,
1827c8c0b82SPatrick Mooney NULL);
1837c8c0b82SPatrick Mooney if (error || mseg->len == 0)
1847c8c0b82SPatrick Mooney return (error);
1857c8c0b82SPatrick Mooney
1867c8c0b82SPatrick Mooney if (!sysmem) {
1877c8c0b82SPatrick Mooney vmm_devmem_entry_t *de;
1887c8c0b82SPatrick Mooney
1897c8c0b82SPatrick Mooney de = vmmdev_devmem_find(sc, mseg->segid);
1907c8c0b82SPatrick Mooney if (de != NULL) {
1917c8c0b82SPatrick Mooney (void) strlcpy(mseg->name, de->vde_name,
1927c8c0b82SPatrick Mooney sizeof (mseg->name));
1937c8c0b82SPatrick Mooney }
1947c8c0b82SPatrick Mooney } else {
1957c8c0b82SPatrick Mooney bzero(mseg->name, sizeof (mseg->name));
1967c8c0b82SPatrick Mooney }
1977c8c0b82SPatrick Mooney
1987c8c0b82SPatrick Mooney return (error);
1997c8c0b82SPatrick Mooney }
2007c8c0b82SPatrick Mooney
2017c8c0b82SPatrick Mooney static int
vmmdev_devmem_create(vmm_softc_t * sc,struct vm_memseg * mseg,const char * name)2027c8c0b82SPatrick Mooney vmmdev_devmem_create(vmm_softc_t *sc, struct vm_memseg *mseg, const char *name)
2037c8c0b82SPatrick Mooney {
2047c8c0b82SPatrick Mooney off_t map_offset;
2057c8c0b82SPatrick Mooney vmm_devmem_entry_t *entry;
2067c8c0b82SPatrick Mooney
2077c8c0b82SPatrick Mooney if (list_is_empty(&sc->vmm_devmem_list)) {
2087c8c0b82SPatrick Mooney map_offset = VM_DEVMEM_START;
2097c8c0b82SPatrick Mooney } else {
2107c8c0b82SPatrick Mooney entry = list_tail(&sc->vmm_devmem_list);
2117c8c0b82SPatrick Mooney map_offset = entry->vde_off + entry->vde_len;
2127c8c0b82SPatrick Mooney if (map_offset < entry->vde_off) {
2137c8c0b82SPatrick Mooney /* Do not tolerate overflow */
2147c8c0b82SPatrick Mooney return (ERANGE);
2157c8c0b82SPatrick Mooney }
2167c8c0b82SPatrick Mooney /*
2177c8c0b82SPatrick Mooney * XXXJOY: We could choose to search the list for duplicate
2187c8c0b82SPatrick Mooney * names and toss an error. Since we're using the offset
2197c8c0b82SPatrick Mooney * method for now, it does not make much of a difference.
2207c8c0b82SPatrick Mooney */
2217c8c0b82SPatrick Mooney }
2227c8c0b82SPatrick Mooney
2237c8c0b82SPatrick Mooney entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
2247c8c0b82SPatrick Mooney entry->vde_segid = mseg->segid;
2257c8c0b82SPatrick Mooney entry->vde_len = mseg->len;
2267c8c0b82SPatrick Mooney entry->vde_off = map_offset;
2277c8c0b82SPatrick Mooney (void) strlcpy(entry->vde_name, name, sizeof (entry->vde_name));
2287c8c0b82SPatrick Mooney list_insert_tail(&sc->vmm_devmem_list, entry);
2297c8c0b82SPatrick Mooney
2307c8c0b82SPatrick Mooney return (0);
2317c8c0b82SPatrick Mooney }
2327c8c0b82SPatrick Mooney
2337c8c0b82SPatrick Mooney static boolean_t
vmmdev_devmem_segid(vmm_softc_t * sc,off_t off,off_t len,int * segidp,off_t * map_offp)2347c8c0b82SPatrick Mooney vmmdev_devmem_segid(vmm_softc_t *sc, off_t off, off_t len, int *segidp,
2357c8c0b82SPatrick Mooney off_t *map_offp)
2367c8c0b82SPatrick Mooney {
2377c8c0b82SPatrick Mooney list_t *dl = &sc->vmm_devmem_list;
2387c8c0b82SPatrick Mooney vmm_devmem_entry_t *de = NULL;
2397c8c0b82SPatrick Mooney const off_t map_end = off + len;
2407c8c0b82SPatrick Mooney
2417c8c0b82SPatrick Mooney VERIFY(off >= VM_DEVMEM_START);
2427c8c0b82SPatrick Mooney
2437c8c0b82SPatrick Mooney if (map_end < off) {
2447c8c0b82SPatrick Mooney /* No match on overflow */
2457c8c0b82SPatrick Mooney return (B_FALSE);
2467c8c0b82SPatrick Mooney }
2477c8c0b82SPatrick Mooney
2487c8c0b82SPatrick Mooney for (de = list_head(dl); de != NULL; de = list_next(dl, de)) {
2497c8c0b82SPatrick Mooney const off_t item_end = de->vde_off + de->vde_len;
2507c8c0b82SPatrick Mooney
2517c8c0b82SPatrick Mooney if (de->vde_off <= off && item_end >= map_end) {
2527c8c0b82SPatrick Mooney *segidp = de->vde_segid;
2537c8c0b82SPatrick Mooney *map_offp = off - de->vde_off;
2547c8c0b82SPatrick Mooney return (B_TRUE);
2557c8c0b82SPatrick Mooney }
2567c8c0b82SPatrick Mooney }
2577c8c0b82SPatrick Mooney return (B_FALSE);
2587c8c0b82SPatrick Mooney }
2597c8c0b82SPatrick Mooney
26042640e49SPatrick Mooney /*
26142640e49SPatrick Mooney * When an instance is being destroyed, the devmem list of named memory objects
26242640e49SPatrick Mooney * can be torn down, as no new mappings are allowed.
26342640e49SPatrick Mooney */
2647c8c0b82SPatrick Mooney static void
vmmdev_devmem_purge(vmm_softc_t * sc)2657c8c0b82SPatrick Mooney vmmdev_devmem_purge(vmm_softc_t *sc)
2667c8c0b82SPatrick Mooney {
2677c8c0b82SPatrick Mooney vmm_devmem_entry_t *entry;
2687c8c0b82SPatrick Mooney
2697c8c0b82SPatrick Mooney while ((entry = list_remove_head(&sc->vmm_devmem_list)) != NULL) {
2707c8c0b82SPatrick Mooney kmem_free(entry, sizeof (*entry));
2717c8c0b82SPatrick Mooney }
2727c8c0b82SPatrick Mooney }
2737c8c0b82SPatrick Mooney
2747c8c0b82SPatrick Mooney static int
vmmdev_alloc_memseg(vmm_softc_t * sc,struct vm_memseg * mseg)2757c8c0b82SPatrick Mooney vmmdev_alloc_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
2767c8c0b82SPatrick Mooney {
2777c8c0b82SPatrick Mooney int error;
2787c8c0b82SPatrick Mooney bool sysmem = true;
2797c8c0b82SPatrick Mooney
2807c8c0b82SPatrick Mooney if (VM_MEMSEG_NAME(mseg)) {
2817c8c0b82SPatrick Mooney sysmem = false;
2827c8c0b82SPatrick Mooney }
2837c8c0b82SPatrick Mooney error = vm_alloc_memseg(sc->vmm_vm, mseg->segid, mseg->len, sysmem);
2847c8c0b82SPatrick Mooney
2857c8c0b82SPatrick Mooney if (error == 0) {
2867c8c0b82SPatrick Mooney /*
2877c8c0b82SPatrick Mooney * Rather than create a whole fresh device from which userspace
2887c8c0b82SPatrick Mooney * can mmap this segment, instead make it available at an
2897c8c0b82SPatrick Mooney * offset above where the main guest memory resides.
2907c8c0b82SPatrick Mooney */
2917c8c0b82SPatrick Mooney error = vmmdev_devmem_create(sc, mseg, mseg->name);
2927c8c0b82SPatrick Mooney if (error != 0) {
2937c8c0b82SPatrick Mooney vm_free_memseg(sc->vmm_vm, mseg->segid);
2947c8c0b82SPatrick Mooney }
2957c8c0b82SPatrick Mooney }
2967c8c0b82SPatrick Mooney return (error);
2977c8c0b82SPatrick Mooney }
2987c8c0b82SPatrick Mooney
2997c8c0b82SPatrick Mooney /*
3007c8c0b82SPatrick Mooney * Resource Locking and Exclusion
3017c8c0b82SPatrick Mooney *
3027c8c0b82SPatrick Mooney * Much of bhyve depends on key portions of VM state, such as the guest memory
3037c8c0b82SPatrick Mooney * map, to remain unchanged while the guest is running. As ported from
3047c8c0b82SPatrick Mooney * FreeBSD, the initial strategy for this resource exclusion hinged on gating
3057c8c0b82SPatrick Mooney * access to the instance vCPUs. Threads acting on a single vCPU, like those
3067c8c0b82SPatrick Mooney * performing the work of actually running the guest in VMX/SVM, would lock
3077c8c0b82SPatrick Mooney * only that vCPU during ioctl() entry. For ioctls which would change VM-wide
3087c8c0b82SPatrick Mooney * state, all of the vCPUs would be first locked, ensuring that the
3097c8c0b82SPatrick Mooney * operation(s) could complete without any other threads stumbling into
3107c8c0b82SPatrick Mooney * intermediate states.
3117c8c0b82SPatrick Mooney *
3127c8c0b82SPatrick Mooney * This approach is largely effective for bhyve. Common operations, such as
3137c8c0b82SPatrick Mooney * running the vCPUs, steer clear of lock contention. The model begins to
3147c8c0b82SPatrick Mooney * break down for operations which do not occur in the context of a specific
3157c8c0b82SPatrick Mooney * vCPU. LAPIC MSI delivery, for example, may be initiated from a worker
3167c8c0b82SPatrick Mooney * thread in the bhyve process. In order to properly protect those vCPU-less
3177c8c0b82SPatrick Mooney * operations from encountering invalid states, additional locking is required.
3187c8c0b82SPatrick Mooney * This was solved by forcing those operations to lock the VM_MAXCPU-1 vCPU.
3197c8c0b82SPatrick Mooney * It does mean that class of operations will be serialized on locking the
3207c8c0b82SPatrick Mooney * specific vCPU and that instances sized at VM_MAXCPU will potentially see
3217c8c0b82SPatrick Mooney * undue contention on the VM_MAXCPU-1 vCPU.
3227c8c0b82SPatrick Mooney *
3237c8c0b82SPatrick Mooney * In order to address the shortcomings of this model, the concept of a
3247c8c0b82SPatrick Mooney * read/write lock has been added to bhyve. Operations which change
3257c8c0b82SPatrick Mooney * fundamental aspects of a VM (such as the memory map) must acquire the write
3267c8c0b82SPatrick Mooney * lock, which also implies locking all of the vCPUs and waiting for all read
3277c8c0b82SPatrick Mooney * lock holders to release. While it increases the cost and waiting time for
3287c8c0b82SPatrick Mooney * those few operations, it allows most hot-path operations on the VM (which
3297c8c0b82SPatrick Mooney * depend on its configuration remaining stable) to occur with minimal locking.
3307c8c0b82SPatrick Mooney *
3317c8c0b82SPatrick Mooney * Consumers of the Driver API (see below) are a special case when it comes to
3327c8c0b82SPatrick Mooney * this locking, since they may hold a read lock via the drv_lease mechanism
3337c8c0b82SPatrick Mooney * for an extended period of time. Rather than forcing those consumers to
3347c8c0b82SPatrick Mooney * continuously poll for a write lock attempt, the lease system forces them to
3357c8c0b82SPatrick Mooney * provide a release callback to trigger their clean-up (and potential later
3367c8c0b82SPatrick Mooney * reacquisition) of the read lock.
3377c8c0b82SPatrick Mooney */
3387c8c0b82SPatrick Mooney
3397c8c0b82SPatrick Mooney static void
vcpu_lock_one(vmm_softc_t * sc,int vcpu)3407c8c0b82SPatrick Mooney vcpu_lock_one(vmm_softc_t *sc, int vcpu)
3417c8c0b82SPatrick Mooney {
3427c8c0b82SPatrick Mooney ASSERT(vcpu >= 0 && vcpu < VM_MAXCPU);
3437c8c0b82SPatrick Mooney
3447c8c0b82SPatrick Mooney /*
3457c8c0b82SPatrick Mooney * Since this state transition is utilizing from_idle=true, it should
3467c8c0b82SPatrick Mooney * not fail, but rather block until it can be successful.
3477c8c0b82SPatrick Mooney */
3487c8c0b82SPatrick Mooney VERIFY0(vcpu_set_state(sc->vmm_vm, vcpu, VCPU_FROZEN, true));
3497c8c0b82SPatrick Mooney }
3507c8c0b82SPatrick Mooney
3517c8c0b82SPatrick Mooney static void
vcpu_unlock_one(vmm_softc_t * sc,int vcpu)3527c8c0b82SPatrick Mooney vcpu_unlock_one(vmm_softc_t *sc, int vcpu)
3537c8c0b82SPatrick Mooney {
3547c8c0b82SPatrick Mooney ASSERT(vcpu >= 0 && vcpu < VM_MAXCPU);
3557c8c0b82SPatrick Mooney
3567c8c0b82SPatrick Mooney VERIFY3U(vcpu_get_state(sc->vmm_vm, vcpu, NULL), ==, VCPU_FROZEN);
357e0994bd2SPatrick Mooney VERIFY0(vcpu_set_state(sc->vmm_vm, vcpu, VCPU_IDLE, false));
3587c8c0b82SPatrick Mooney }
3597c8c0b82SPatrick Mooney
3607c8c0b82SPatrick Mooney static void
vmm_read_lock(vmm_softc_t * sc)3617c8c0b82SPatrick Mooney vmm_read_lock(vmm_softc_t *sc)
3627c8c0b82SPatrick Mooney {
3637c8c0b82SPatrick Mooney rw_enter(&sc->vmm_rwlock, RW_READER);
3647c8c0b82SPatrick Mooney }
3657c8c0b82SPatrick Mooney
3667c8c0b82SPatrick Mooney static void
vmm_read_unlock(vmm_softc_t * sc)3677c8c0b82SPatrick Mooney vmm_read_unlock(vmm_softc_t *sc)
3687c8c0b82SPatrick Mooney {
3697c8c0b82SPatrick Mooney rw_exit(&sc->vmm_rwlock);
3707c8c0b82SPatrick Mooney }
3717c8c0b82SPatrick Mooney
3727c8c0b82SPatrick Mooney static void
vmm_write_lock(vmm_softc_t * sc)3737c8c0b82SPatrick Mooney vmm_write_lock(vmm_softc_t *sc)
3747c8c0b82SPatrick Mooney {
3757c8c0b82SPatrick Mooney int maxcpus;
3767c8c0b82SPatrick Mooney
3777c8c0b82SPatrick Mooney /* First lock all the vCPUs */
3787c8c0b82SPatrick Mooney maxcpus = vm_get_maxcpus(sc->vmm_vm);
3797c8c0b82SPatrick Mooney for (int vcpu = 0; vcpu < maxcpus; vcpu++) {
3807c8c0b82SPatrick Mooney vcpu_lock_one(sc, vcpu);
3817c8c0b82SPatrick Mooney }
3827c8c0b82SPatrick Mooney
3837c8c0b82SPatrick Mooney /*
3847c8c0b82SPatrick Mooney * Block vmm_drv leases from being acquired or held while the VM write
3857c8c0b82SPatrick Mooney * lock is held.
3867c8c0b82SPatrick Mooney */
3877c8c0b82SPatrick Mooney vmm_lease_block(sc);
3887c8c0b82SPatrick Mooney
3897c8c0b82SPatrick Mooney rw_enter(&sc->vmm_rwlock, RW_WRITER);
3907c8c0b82SPatrick Mooney /*
3917c8c0b82SPatrick Mooney * For now, the 'maxcpus' value for an instance is fixed at the
3927c8c0b82SPatrick Mooney * compile-time constant of VM_MAXCPU at creation. If this changes in
3937c8c0b82SPatrick Mooney * the future, allowing for dynamic vCPU resource sizing, acquisition
3947c8c0b82SPatrick Mooney * of the write lock will need to be wary of such changes.
3957c8c0b82SPatrick Mooney */
3967c8c0b82SPatrick Mooney VERIFY(maxcpus == vm_get_maxcpus(sc->vmm_vm));
3977c8c0b82SPatrick Mooney }
3987c8c0b82SPatrick Mooney
3997c8c0b82SPatrick Mooney static void
vmm_write_unlock(vmm_softc_t * sc)4007c8c0b82SPatrick Mooney vmm_write_unlock(vmm_softc_t *sc)
4017c8c0b82SPatrick Mooney {
4027c8c0b82SPatrick Mooney int maxcpus;
4037c8c0b82SPatrick Mooney
4047c8c0b82SPatrick Mooney /* Allow vmm_drv leases to be acquired once write lock is dropped */
4057c8c0b82SPatrick Mooney vmm_lease_unblock(sc);
4067c8c0b82SPatrick Mooney
4077c8c0b82SPatrick Mooney /*
4087c8c0b82SPatrick Mooney * The VM write lock _must_ be released from the same thread it was
4097c8c0b82SPatrick Mooney * acquired in, unlike the read lock.
4107c8c0b82SPatrick Mooney */
4117c8c0b82SPatrick Mooney VERIFY(rw_write_held(&sc->vmm_rwlock));
4127c8c0b82SPatrick Mooney rw_exit(&sc->vmm_rwlock);
4137c8c0b82SPatrick Mooney
4147c8c0b82SPatrick Mooney /* Unlock all the vCPUs */
4157c8c0b82SPatrick Mooney maxcpus = vm_get_maxcpus(sc->vmm_vm);
4167c8c0b82SPatrick Mooney for (int vcpu = 0; vcpu < maxcpus; vcpu++) {
4177c8c0b82SPatrick Mooney vcpu_unlock_one(sc, vcpu);
4187c8c0b82SPatrick Mooney }
4197c8c0b82SPatrick Mooney }
4207c8c0b82SPatrick Mooney
4217c8c0b82SPatrick Mooney static int
vmmdev_do_ioctl(vmm_softc_t * sc,int cmd,intptr_t arg,int md,cred_t * credp,int * rvalp)4227c8c0b82SPatrick Mooney vmmdev_do_ioctl(vmm_softc_t *sc, int cmd, intptr_t arg, int md,
4237c8c0b82SPatrick Mooney cred_t *credp, int *rvalp)
4247c8c0b82SPatrick Mooney {
4257c8c0b82SPatrick Mooney int error = 0, vcpu = -1;
4267c8c0b82SPatrick Mooney void *datap = (void *)arg;
4277c8c0b82SPatrick Mooney enum vm_lock_type {
4287c8c0b82SPatrick Mooney LOCK_NONE = 0,
4297c8c0b82SPatrick Mooney LOCK_VCPU,
4307c8c0b82SPatrick Mooney LOCK_READ_HOLD,
4317c8c0b82SPatrick Mooney LOCK_WRITE_HOLD
4327c8c0b82SPatrick Mooney } lock_type = LOCK_NONE;
4337c8c0b82SPatrick Mooney
4347c8c0b82SPatrick Mooney /* Acquire any exclusion resources needed for the operation. */
4357c8c0b82SPatrick Mooney switch (cmd) {
4367c8c0b82SPatrick Mooney case VM_RUN:
4377c8c0b82SPatrick Mooney case VM_GET_REGISTER:
4387c8c0b82SPatrick Mooney case VM_SET_REGISTER:
4397c8c0b82SPatrick Mooney case VM_GET_SEGMENT_DESCRIPTOR:
4407c8c0b82SPatrick Mooney case VM_SET_SEGMENT_DESCRIPTOR:
4417c8c0b82SPatrick Mooney case VM_GET_REGISTER_SET:
4427c8c0b82SPatrick Mooney case VM_SET_REGISTER_SET:
4437c8c0b82SPatrick Mooney case VM_INJECT_EXCEPTION:
4447c8c0b82SPatrick Mooney case VM_GET_CAPABILITY:
4457c8c0b82SPatrick Mooney case VM_SET_CAPABILITY:
4467c8c0b82SPatrick Mooney case VM_PPTDEV_MSI:
4477c8c0b82SPatrick Mooney case VM_PPTDEV_MSIX:
4487c8c0b82SPatrick Mooney case VM_SET_X2APIC_STATE:
4497c8c0b82SPatrick Mooney case VM_GLA2GPA:
4507c8c0b82SPatrick Mooney case VM_GLA2GPA_NOFAULT:
4517c8c0b82SPatrick Mooney case VM_ACTIVATE_CPU:
4527c8c0b82SPatrick Mooney case VM_SET_INTINFO:
4537c8c0b82SPatrick Mooney case VM_GET_INTINFO:
4547c8c0b82SPatrick Mooney case VM_RESTART_INSTRUCTION:
4557c8c0b82SPatrick Mooney case VM_SET_KERNEMU_DEV:
4567c8c0b82SPatrick Mooney case VM_GET_KERNEMU_DEV:
4577c8c0b82SPatrick Mooney case VM_RESET_CPU:
4587c8c0b82SPatrick Mooney case VM_GET_RUN_STATE:
4597c8c0b82SPatrick Mooney case VM_SET_RUN_STATE:
4607c8c0b82SPatrick Mooney case VM_GET_FPU:
4617c8c0b82SPatrick Mooney case VM_SET_FPU:
462578d9a56SPatrick Mooney case VM_GET_CPUID:
463578d9a56SPatrick Mooney case VM_SET_CPUID:
464578d9a56SPatrick Mooney case VM_LEGACY_CPUID:
4657c8c0b82SPatrick Mooney /*
4667c8c0b82SPatrick Mooney * Copy in the ID of the vCPU chosen for this operation.
4677c8c0b82SPatrick Mooney * Since a nefarious caller could update their struct between
4687c8c0b82SPatrick Mooney * this locking and when the rest of the ioctl data is copied
4697c8c0b82SPatrick Mooney * in, it is _critical_ that this local 'vcpu' variable be used
4707c8c0b82SPatrick Mooney * rather than the in-struct one when performing the ioctl.
4717c8c0b82SPatrick Mooney */
4727c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vcpu, sizeof (vcpu), md)) {
4737c8c0b82SPatrick Mooney return (EFAULT);
4747c8c0b82SPatrick Mooney }
4752cef7ad9SPatrick Mooney if (vcpu < 0 || vcpu >= vm_get_maxcpus(sc->vmm_vm)) {
4767c8c0b82SPatrick Mooney return (EINVAL);
4777c8c0b82SPatrick Mooney }
4787c8c0b82SPatrick Mooney vcpu_lock_one(sc, vcpu);
4797c8c0b82SPatrick Mooney lock_type = LOCK_VCPU;
4807c8c0b82SPatrick Mooney break;
4817c8c0b82SPatrick Mooney
4827c8c0b82SPatrick Mooney case VM_REINIT:
4837c8c0b82SPatrick Mooney case VM_BIND_PPTDEV:
4847c8c0b82SPatrick Mooney case VM_UNBIND_PPTDEV:
4857c8c0b82SPatrick Mooney case VM_MAP_PPTDEV_MMIO:
4867c8c0b82SPatrick Mooney case VM_UNMAP_PPTDEV_MMIO:
4877c8c0b82SPatrick Mooney case VM_ALLOC_MEMSEG:
4887c8c0b82SPatrick Mooney case VM_MMAP_MEMSEG:
4897c8c0b82SPatrick Mooney case VM_MUNMAP_MEMSEG:
4907c8c0b82SPatrick Mooney case VM_WRLOCK_CYCLE:
4917c8c0b82SPatrick Mooney case VM_PMTMR_LOCATE:
4922cac0506SPatrick Mooney case VM_PAUSE:
4932cac0506SPatrick Mooney case VM_RESUME:
4947c8c0b82SPatrick Mooney vmm_write_lock(sc);
4957c8c0b82SPatrick Mooney lock_type = LOCK_WRITE_HOLD;
4967c8c0b82SPatrick Mooney break;
4977c8c0b82SPatrick Mooney
4987c8c0b82SPatrick Mooney case VM_GET_MEMSEG:
4997c8c0b82SPatrick Mooney case VM_MMAP_GETNEXT:
5007c8c0b82SPatrick Mooney case VM_LAPIC_IRQ:
5017c8c0b82SPatrick Mooney case VM_INJECT_NMI:
5027c8c0b82SPatrick Mooney case VM_IOAPIC_ASSERT_IRQ:
5037c8c0b82SPatrick Mooney case VM_IOAPIC_DEASSERT_IRQ:
5047c8c0b82SPatrick Mooney case VM_IOAPIC_PULSE_IRQ:
5057c8c0b82SPatrick Mooney case VM_LAPIC_MSI:
5067c8c0b82SPatrick Mooney case VM_LAPIC_LOCAL_IRQ:
5077c8c0b82SPatrick Mooney case VM_GET_X2APIC_STATE:
5087c8c0b82SPatrick Mooney case VM_RTC_READ:
5097c8c0b82SPatrick Mooney case VM_RTC_WRITE:
5107c8c0b82SPatrick Mooney case VM_RTC_SETTIME:
5117c8c0b82SPatrick Mooney case VM_RTC_GETTIME:
5127c8c0b82SPatrick Mooney case VM_PPTDEV_DISABLE_MSIX:
5137c8c0b82SPatrick Mooney case VM_DEVMEM_GETOFFSET:
5147c8c0b82SPatrick Mooney case VM_TRACK_DIRTY_PAGES:
515b9b43e84SPatrick Mooney case VM_NPT_OPERATION:
5167c8c0b82SPatrick Mooney vmm_read_lock(sc);
5177c8c0b82SPatrick Mooney lock_type = LOCK_READ_HOLD;
5187c8c0b82SPatrick Mooney break;
5197c8c0b82SPatrick Mooney
520d515dd77SPatrick Mooney case VM_DATA_READ:
521d515dd77SPatrick Mooney case VM_DATA_WRITE:
522d515dd77SPatrick Mooney if (ddi_copyin(datap, &vcpu, sizeof (vcpu), md)) {
523d515dd77SPatrick Mooney return (EFAULT);
524d515dd77SPatrick Mooney }
525d515dd77SPatrick Mooney if (vcpu == -1) {
526d515dd77SPatrick Mooney /* Access data for VM-wide devices */
527d515dd77SPatrick Mooney vmm_write_lock(sc);
528d515dd77SPatrick Mooney lock_type = LOCK_WRITE_HOLD;
529d515dd77SPatrick Mooney } else if (vcpu >= 0 && vcpu < vm_get_maxcpus(sc->vmm_vm)) {
530d515dd77SPatrick Mooney /* Access data associated with a specific vCPU */
531d515dd77SPatrick Mooney vcpu_lock_one(sc, vcpu);
532d515dd77SPatrick Mooney lock_type = LOCK_VCPU;
533d515dd77SPatrick Mooney } else {
534d515dd77SPatrick Mooney return (EINVAL);
535d515dd77SPatrick Mooney }
536d515dd77SPatrick Mooney break;
537d515dd77SPatrick Mooney
5387c8c0b82SPatrick Mooney case VM_GET_GPA_PMAP:
5397c8c0b82SPatrick Mooney case VM_IOAPIC_PINCOUNT:
5407c8c0b82SPatrick Mooney case VM_SUSPEND:
5417c8c0b82SPatrick Mooney case VM_DESC_FPU_AREA:
542aa39f6d0SPatrick Mooney case VM_SET_AUTODESTRUCT:
54342640e49SPatrick Mooney case VM_DESTROY_SELF:
54442640e49SPatrick Mooney case VM_DESTROY_PENDING:
54572473353SPatrick Mooney case VM_VCPU_BARRIER:
5467c8c0b82SPatrick Mooney default:
5477c8c0b82SPatrick Mooney break;
5487c8c0b82SPatrick Mooney }
5497c8c0b82SPatrick Mooney
5507c8c0b82SPatrick Mooney /* Execute the primary logic for the ioctl. */
5517c8c0b82SPatrick Mooney switch (cmd) {
5527c8c0b82SPatrick Mooney case VM_RUN: {
5537c8c0b82SPatrick Mooney struct vm_entry entry;
5547c8c0b82SPatrick Mooney
5557c8c0b82SPatrick Mooney if (ddi_copyin(datap, &entry, sizeof (entry), md)) {
5567c8c0b82SPatrick Mooney error = EFAULT;
5577c8c0b82SPatrick Mooney break;
5587c8c0b82SPatrick Mooney }
5597c8c0b82SPatrick Mooney
5607c8c0b82SPatrick Mooney if (!(curthread->t_schedflag & TS_VCPU))
5617c8c0b82SPatrick Mooney smt_mark_as_vcpu();
5627c8c0b82SPatrick Mooney
5637c8c0b82SPatrick Mooney error = vm_run(sc->vmm_vm, vcpu, &entry);
5647c8c0b82SPatrick Mooney
5657c8c0b82SPatrick Mooney /*
5667c8c0b82SPatrick Mooney * Unexpected states in vm_run() are expressed through positive
5677c8c0b82SPatrick Mooney * errno-oriented return values. VM states which expect further
5687c8c0b82SPatrick Mooney * processing in userspace (necessary context via exitinfo) are
5697c8c0b82SPatrick Mooney * expressed through negative return values. For the time being
5707c8c0b82SPatrick Mooney * a return value of 0 is not expected from vm_run().
5717c8c0b82SPatrick Mooney */
5727c8c0b82SPatrick Mooney ASSERT(error != 0);
5737c8c0b82SPatrick Mooney if (error < 0) {
5747c8c0b82SPatrick Mooney const struct vm_exit *vme;
5757c8c0b82SPatrick Mooney void *outp = entry.exit_data;
5767c8c0b82SPatrick Mooney
5777c8c0b82SPatrick Mooney error = 0;
5787c8c0b82SPatrick Mooney vme = vm_exitinfo(sc->vmm_vm, vcpu);
5797c8c0b82SPatrick Mooney if (ddi_copyout(vme, outp, sizeof (*vme), md)) {
5807c8c0b82SPatrick Mooney error = EFAULT;
5817c8c0b82SPatrick Mooney }
5827c8c0b82SPatrick Mooney }
5837c8c0b82SPatrick Mooney break;
5847c8c0b82SPatrick Mooney }
5857c8c0b82SPatrick Mooney case VM_SUSPEND: {
5867c8c0b82SPatrick Mooney struct vm_suspend vmsuspend;
5877c8c0b82SPatrick Mooney
5887c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmsuspend, sizeof (vmsuspend), md)) {
5897c8c0b82SPatrick Mooney error = EFAULT;
5907c8c0b82SPatrick Mooney break;
5917c8c0b82SPatrick Mooney }
59272473353SPatrick Mooney error = vm_suspend(sc->vmm_vm, vmsuspend.how, vmsuspend.source);
5937c8c0b82SPatrick Mooney break;
5947c8c0b82SPatrick Mooney }
5957c8c0b82SPatrick Mooney case VM_REINIT: {
5967c8c0b82SPatrick Mooney struct vm_reinit reinit;
5977c8c0b82SPatrick Mooney
5987c8c0b82SPatrick Mooney if (ddi_copyin(datap, &reinit, sizeof (reinit), md)) {
5997c8c0b82SPatrick Mooney error = EFAULT;
6007c8c0b82SPatrick Mooney break;
6017c8c0b82SPatrick Mooney }
6027c8c0b82SPatrick Mooney if ((error = vmm_drv_block_hook(sc, B_TRUE)) != 0) {
6037c8c0b82SPatrick Mooney /*
6047c8c0b82SPatrick Mooney * The VM instance should be free of driver-attached
6057c8c0b82SPatrick Mooney * hooks during the reinitialization process.
6067c8c0b82SPatrick Mooney */
6077c8c0b82SPatrick Mooney break;
6087c8c0b82SPatrick Mooney }
6097c8c0b82SPatrick Mooney error = vm_reinit(sc->vmm_vm, reinit.flags);
6107c8c0b82SPatrick Mooney (void) vmm_drv_block_hook(sc, B_FALSE);
6117c8c0b82SPatrick Mooney break;
6127c8c0b82SPatrick Mooney }
6137c8c0b82SPatrick Mooney case VM_STAT_DESC: {
6147c8c0b82SPatrick Mooney struct vm_stat_desc statdesc;
6157c8c0b82SPatrick Mooney
6167c8c0b82SPatrick Mooney if (ddi_copyin(datap, &statdesc, sizeof (statdesc), md)) {
6177c8c0b82SPatrick Mooney error = EFAULT;
6187c8c0b82SPatrick Mooney break;
6197c8c0b82SPatrick Mooney }
6207c8c0b82SPatrick Mooney error = vmm_stat_desc_copy(statdesc.index, statdesc.desc,
6217c8c0b82SPatrick Mooney sizeof (statdesc.desc));
6227c8c0b82SPatrick Mooney if (error == 0 &&
6237c8c0b82SPatrick Mooney ddi_copyout(&statdesc, datap, sizeof (statdesc), md)) {
6247c8c0b82SPatrick Mooney error = EFAULT;
6257c8c0b82SPatrick Mooney break;
6267c8c0b82SPatrick Mooney }
6277c8c0b82SPatrick Mooney break;
6287c8c0b82SPatrick Mooney }
6297c8c0b82SPatrick Mooney case VM_STATS_IOC: {
6307c8c0b82SPatrick Mooney struct vm_stats vmstats;
6317c8c0b82SPatrick Mooney
6327c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmstats, sizeof (vmstats), md)) {
6337c8c0b82SPatrick Mooney error = EFAULT;
6347c8c0b82SPatrick Mooney break;
6357c8c0b82SPatrick Mooney }
6367c8c0b82SPatrick Mooney hrt2tv(gethrtime(), &vmstats.tv);
637d7b72f7bSAndy Fiddaman error = vmm_stat_copy(sc->vmm_vm, vmstats.cpuid, vmstats.index,
638d7b72f7bSAndy Fiddaman nitems(vmstats.statbuf),
6397c8c0b82SPatrick Mooney &vmstats.num_entries, vmstats.statbuf);
6407c8c0b82SPatrick Mooney if (error == 0 &&
6417c8c0b82SPatrick Mooney ddi_copyout(&vmstats, datap, sizeof (vmstats), md)) {
6427c8c0b82SPatrick Mooney error = EFAULT;
6437c8c0b82SPatrick Mooney break;
6447c8c0b82SPatrick Mooney }
6457c8c0b82SPatrick Mooney break;
6467c8c0b82SPatrick Mooney }
6477c8c0b82SPatrick Mooney
6487c8c0b82SPatrick Mooney case VM_PPTDEV_MSI: {
6497c8c0b82SPatrick Mooney struct vm_pptdev_msi pptmsi;
6507c8c0b82SPatrick Mooney
6517c8c0b82SPatrick Mooney if (ddi_copyin(datap, &pptmsi, sizeof (pptmsi), md)) {
6527c8c0b82SPatrick Mooney error = EFAULT;
6537c8c0b82SPatrick Mooney break;
6547c8c0b82SPatrick Mooney }
6557c8c0b82SPatrick Mooney error = ppt_setup_msi(sc->vmm_vm, pptmsi.vcpu, pptmsi.pptfd,
6567c8c0b82SPatrick Mooney pptmsi.addr, pptmsi.msg, pptmsi.numvec);
6577c8c0b82SPatrick Mooney break;
6587c8c0b82SPatrick Mooney }
6597c8c0b82SPatrick Mooney case VM_PPTDEV_MSIX: {
6607c8c0b82SPatrick Mooney struct vm_pptdev_msix pptmsix;
6617c8c0b82SPatrick Mooney
6627c8c0b82SPatrick Mooney if (ddi_copyin(datap, &pptmsix, sizeof (pptmsix), md)) {
6637c8c0b82SPatrick Mooney error = EFAULT;
6647c8c0b82SPatrick Mooney break;
6657c8c0b82SPatrick Mooney }
6667c8c0b82SPatrick Mooney error = ppt_setup_msix(sc->vmm_vm, pptmsix.vcpu, pptmsix.pptfd,
6677c8c0b82SPatrick Mooney pptmsix.idx, pptmsix.addr, pptmsix.msg,
6687c8c0b82SPatrick Mooney pptmsix.vector_control);
6697c8c0b82SPatrick Mooney break;
6707c8c0b82SPatrick Mooney }
6717c8c0b82SPatrick Mooney case VM_PPTDEV_DISABLE_MSIX: {
6727c8c0b82SPatrick Mooney struct vm_pptdev pptdev;
6737c8c0b82SPatrick Mooney
6747c8c0b82SPatrick Mooney if (ddi_copyin(datap, &pptdev, sizeof (pptdev), md)) {
6757c8c0b82SPatrick Mooney error = EFAULT;
6767c8c0b82SPatrick Mooney break;
6777c8c0b82SPatrick Mooney }
6787c8c0b82SPatrick Mooney error = ppt_disable_msix(sc->vmm_vm, pptdev.pptfd);
6797c8c0b82SPatrick Mooney break;
6807c8c0b82SPatrick Mooney }
6817c8c0b82SPatrick Mooney case VM_MAP_PPTDEV_MMIO: {
6827c8c0b82SPatrick Mooney struct vm_pptdev_mmio pptmmio;
6837c8c0b82SPatrick Mooney
6847c8c0b82SPatrick Mooney if (ddi_copyin(datap, &pptmmio, sizeof (pptmmio), md)) {
6857c8c0b82SPatrick Mooney error = EFAULT;
6867c8c0b82SPatrick Mooney break;
6877c8c0b82SPatrick Mooney }
6887c8c0b82SPatrick Mooney error = ppt_map_mmio(sc->vmm_vm, pptmmio.pptfd, pptmmio.gpa,
6897c8c0b82SPatrick Mooney pptmmio.len, pptmmio.hpa);
6907c8c0b82SPatrick Mooney break;
6917c8c0b82SPatrick Mooney }
6927c8c0b82SPatrick Mooney case VM_UNMAP_PPTDEV_MMIO: {
6937c8c0b82SPatrick Mooney struct vm_pptdev_mmio pptmmio;
6947c8c0b82SPatrick Mooney
6957c8c0b82SPatrick Mooney if (ddi_copyin(datap, &pptmmio, sizeof (pptmmio), md)) {
6967c8c0b82SPatrick Mooney error = EFAULT;
6977c8c0b82SPatrick Mooney break;
6987c8c0b82SPatrick Mooney }
6997c8c0b82SPatrick Mooney error = ppt_unmap_mmio(sc->vmm_vm, pptmmio.pptfd, pptmmio.gpa,
7007c8c0b82SPatrick Mooney pptmmio.len);
7017c8c0b82SPatrick Mooney break;
7027c8c0b82SPatrick Mooney }
7037c8c0b82SPatrick Mooney case VM_BIND_PPTDEV: {
7047c8c0b82SPatrick Mooney struct vm_pptdev pptdev;
7057c8c0b82SPatrick Mooney
7067c8c0b82SPatrick Mooney if (ddi_copyin(datap, &pptdev, sizeof (pptdev), md)) {
7077c8c0b82SPatrick Mooney error = EFAULT;
7087c8c0b82SPatrick Mooney break;
7097c8c0b82SPatrick Mooney }
7107c8c0b82SPatrick Mooney error = vm_assign_pptdev(sc->vmm_vm, pptdev.pptfd);
7117c8c0b82SPatrick Mooney break;
7127c8c0b82SPatrick Mooney }
7137c8c0b82SPatrick Mooney case VM_UNBIND_PPTDEV: {
7147c8c0b82SPatrick Mooney struct vm_pptdev pptdev;
7157c8c0b82SPatrick Mooney
7167c8c0b82SPatrick Mooney if (ddi_copyin(datap, &pptdev, sizeof (pptdev), md)) {
7177c8c0b82SPatrick Mooney error = EFAULT;
7187c8c0b82SPatrick Mooney break;
7197c8c0b82SPatrick Mooney }
7207c8c0b82SPatrick Mooney error = vm_unassign_pptdev(sc->vmm_vm, pptdev.pptfd);
7217c8c0b82SPatrick Mooney break;
7227c8c0b82SPatrick Mooney }
7237c8c0b82SPatrick Mooney case VM_GET_PPTDEV_LIMITS: {
7247c8c0b82SPatrick Mooney struct vm_pptdev_limits pptlimits;
7257c8c0b82SPatrick Mooney
7267c8c0b82SPatrick Mooney if (ddi_copyin(datap, &pptlimits, sizeof (pptlimits), md)) {
7277c8c0b82SPatrick Mooney error = EFAULT;
7287c8c0b82SPatrick Mooney break;
7297c8c0b82SPatrick Mooney }
7307c8c0b82SPatrick Mooney error = ppt_get_limits(sc->vmm_vm, pptlimits.pptfd,
7317c8c0b82SPatrick Mooney &pptlimits.msi_limit, &pptlimits.msix_limit);
7327c8c0b82SPatrick Mooney if (error == 0 &&
7337c8c0b82SPatrick Mooney ddi_copyout(&pptlimits, datap, sizeof (pptlimits), md)) {
7347c8c0b82SPatrick Mooney error = EFAULT;
7357c8c0b82SPatrick Mooney break;
7367c8c0b82SPatrick Mooney }
7377c8c0b82SPatrick Mooney break;
7387c8c0b82SPatrick Mooney }
7397c8c0b82SPatrick Mooney case VM_INJECT_EXCEPTION: {
7407c8c0b82SPatrick Mooney struct vm_exception vmexc;
7417c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmexc, sizeof (vmexc), md)) {
7427c8c0b82SPatrick Mooney error = EFAULT;
7437c8c0b82SPatrick Mooney break;
7447c8c0b82SPatrick Mooney }
7457c8c0b82SPatrick Mooney error = vm_inject_exception(sc->vmm_vm, vcpu, vmexc.vector,
7463d097f7dSPatrick Mooney vmexc.error_code_valid != 0, vmexc.error_code,
7473d097f7dSPatrick Mooney vmexc.restart_instruction != 0);
7487c8c0b82SPatrick Mooney break;
7497c8c0b82SPatrick Mooney }
7507c8c0b82SPatrick Mooney case VM_INJECT_NMI: {
7517c8c0b82SPatrick Mooney struct vm_nmi vmnmi;
7527c8c0b82SPatrick Mooney
7537c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmnmi, sizeof (vmnmi), md)) {
7547c8c0b82SPatrick Mooney error = EFAULT;
7557c8c0b82SPatrick Mooney break;
7567c8c0b82SPatrick Mooney }
7577c8c0b82SPatrick Mooney error = vm_inject_nmi(sc->vmm_vm, vmnmi.cpuid);
7587c8c0b82SPatrick Mooney break;
7597c8c0b82SPatrick Mooney }
7607c8c0b82SPatrick Mooney case VM_LAPIC_IRQ: {
7617c8c0b82SPatrick Mooney struct vm_lapic_irq vmirq;
7627c8c0b82SPatrick Mooney
7637c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmirq, sizeof (vmirq), md)) {
7647c8c0b82SPatrick Mooney error = EFAULT;
7657c8c0b82SPatrick Mooney break;
7667c8c0b82SPatrick Mooney }
7677c8c0b82SPatrick Mooney error = lapic_intr_edge(sc->vmm_vm, vmirq.cpuid, vmirq.vector);
7687c8c0b82SPatrick Mooney break;
7697c8c0b82SPatrick Mooney }
7707c8c0b82SPatrick Mooney case VM_LAPIC_LOCAL_IRQ: {
7717c8c0b82SPatrick Mooney struct vm_lapic_irq vmirq;
7727c8c0b82SPatrick Mooney
7737c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmirq, sizeof (vmirq), md)) {
7747c8c0b82SPatrick Mooney error = EFAULT;
7757c8c0b82SPatrick Mooney break;
7767c8c0b82SPatrick Mooney }
7777c8c0b82SPatrick Mooney error = lapic_set_local_intr(sc->vmm_vm, vmirq.cpuid,
7787c8c0b82SPatrick Mooney vmirq.vector);
7797c8c0b82SPatrick Mooney break;
7807c8c0b82SPatrick Mooney }
7817c8c0b82SPatrick Mooney case VM_LAPIC_MSI: {
7827c8c0b82SPatrick Mooney struct vm_lapic_msi vmmsi;
7837c8c0b82SPatrick Mooney
7847c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmmsi, sizeof (vmmsi), md)) {
7857c8c0b82SPatrick Mooney error = EFAULT;
7867c8c0b82SPatrick Mooney break;
7877c8c0b82SPatrick Mooney }
7887c8c0b82SPatrick Mooney error = lapic_intr_msi(sc->vmm_vm, vmmsi.addr, vmmsi.msg);
7897c8c0b82SPatrick Mooney break;
7907c8c0b82SPatrick Mooney }
7917c8c0b82SPatrick Mooney
7927c8c0b82SPatrick Mooney case VM_IOAPIC_ASSERT_IRQ: {
7937c8c0b82SPatrick Mooney struct vm_ioapic_irq ioapic_irq;
7947c8c0b82SPatrick Mooney
7957c8c0b82SPatrick Mooney if (ddi_copyin(datap, &ioapic_irq, sizeof (ioapic_irq), md)) {
7967c8c0b82SPatrick Mooney error = EFAULT;
7977c8c0b82SPatrick Mooney break;
7987c8c0b82SPatrick Mooney }
7997c8c0b82SPatrick Mooney error = vioapic_assert_irq(sc->vmm_vm, ioapic_irq.irq);
8007c8c0b82SPatrick Mooney break;
8017c8c0b82SPatrick Mooney }
8027c8c0b82SPatrick Mooney case VM_IOAPIC_DEASSERT_IRQ: {
8037c8c0b82SPatrick Mooney struct vm_ioapic_irq ioapic_irq;
8047c8c0b82SPatrick Mooney
8057c8c0b82SPatrick Mooney if (ddi_copyin(datap, &ioapic_irq, sizeof (ioapic_irq), md)) {
8067c8c0b82SPatrick Mooney error = EFAULT;
8077c8c0b82SPatrick Mooney break;
8087c8c0b82SPatrick Mooney }
8097c8c0b82SPatrick Mooney error = vioapic_deassert_irq(sc->vmm_vm, ioapic_irq.irq);
8107c8c0b82SPatrick Mooney break;
8117c8c0b82SPatrick Mooney }
8127c8c0b82SPatrick Mooney case VM_IOAPIC_PULSE_IRQ: {
8137c8c0b82SPatrick Mooney struct vm_ioapic_irq ioapic_irq;
8147c8c0b82SPatrick Mooney
8157c8c0b82SPatrick Mooney if (ddi_copyin(datap, &ioapic_irq, sizeof (ioapic_irq), md)) {
8167c8c0b82SPatrick Mooney error = EFAULT;
8177c8c0b82SPatrick Mooney break;
8187c8c0b82SPatrick Mooney }
8197c8c0b82SPatrick Mooney error = vioapic_pulse_irq(sc->vmm_vm, ioapic_irq.irq);
8207c8c0b82SPatrick Mooney break;
8217c8c0b82SPatrick Mooney }
8227c8c0b82SPatrick Mooney case VM_IOAPIC_PINCOUNT: {
8237c8c0b82SPatrick Mooney int pincount;
8247c8c0b82SPatrick Mooney
8257c8c0b82SPatrick Mooney pincount = vioapic_pincount(sc->vmm_vm);
8267c8c0b82SPatrick Mooney if (ddi_copyout(&pincount, datap, sizeof (int), md)) {
8277c8c0b82SPatrick Mooney error = EFAULT;
8287c8c0b82SPatrick Mooney break;
8297c8c0b82SPatrick Mooney }
8307c8c0b82SPatrick Mooney break;
8317c8c0b82SPatrick Mooney }
8327c8c0b82SPatrick Mooney case VM_DESC_FPU_AREA: {
8337c8c0b82SPatrick Mooney struct vm_fpu_desc desc;
8347c8c0b82SPatrick Mooney void *buf = NULL;
8357c8c0b82SPatrick Mooney
8367c8c0b82SPatrick Mooney if (ddi_copyin(datap, &desc, sizeof (desc), md)) {
8377c8c0b82SPatrick Mooney error = EFAULT;
8387c8c0b82SPatrick Mooney break;
8397c8c0b82SPatrick Mooney }
8407c8c0b82SPatrick Mooney if (desc.vfd_num_entries > 64) {
8417c8c0b82SPatrick Mooney error = EINVAL;
8427c8c0b82SPatrick Mooney break;
8437c8c0b82SPatrick Mooney }
8447c8c0b82SPatrick Mooney const size_t buf_sz = sizeof (struct vm_fpu_desc_entry) *
8457c8c0b82SPatrick Mooney desc.vfd_num_entries;
8467c8c0b82SPatrick Mooney if (buf_sz != 0) {
8477c8c0b82SPatrick Mooney buf = kmem_zalloc(buf_sz, KM_SLEEP);
8487c8c0b82SPatrick Mooney }
8497c8c0b82SPatrick Mooney
8507c8c0b82SPatrick Mooney /*
8517c8c0b82SPatrick Mooney * For now, we are depending on vm_fpu_desc_entry and
8527c8c0b82SPatrick Mooney * hma_xsave_state_desc_t having the same format.
8537c8c0b82SPatrick Mooney */
8547c8c0b82SPatrick Mooney CTASSERT(sizeof (struct vm_fpu_desc_entry) ==
8557c8c0b82SPatrick Mooney sizeof (hma_xsave_state_desc_t));
8567c8c0b82SPatrick Mooney
8577c8c0b82SPatrick Mooney size_t req_size;
8587c8c0b82SPatrick Mooney const uint_t max_entries = hma_fpu_describe_xsave_state(
8597c8c0b82SPatrick Mooney (hma_xsave_state_desc_t *)buf,
8607c8c0b82SPatrick Mooney desc.vfd_num_entries,
8617c8c0b82SPatrick Mooney &req_size);
8627c8c0b82SPatrick Mooney
8637c8c0b82SPatrick Mooney desc.vfd_req_size = req_size;
8647c8c0b82SPatrick Mooney desc.vfd_num_entries = max_entries;
8657c8c0b82SPatrick Mooney if (buf_sz != 0) {
8667c8c0b82SPatrick Mooney if (ddi_copyout(buf, desc.vfd_entry_data, buf_sz, md)) {
8677c8c0b82SPatrick Mooney error = EFAULT;
8687c8c0b82SPatrick Mooney }
8697c8c0b82SPatrick Mooney kmem_free(buf, buf_sz);
8707c8c0b82SPatrick Mooney }
8717c8c0b82SPatrick Mooney
8727c8c0b82SPatrick Mooney if (error == 0) {
8737c8c0b82SPatrick Mooney if (ddi_copyout(&desc, datap, sizeof (desc), md)) {
8747c8c0b82SPatrick Mooney error = EFAULT;
8757c8c0b82SPatrick Mooney }
8767c8c0b82SPatrick Mooney }
8777c8c0b82SPatrick Mooney break;
8787c8c0b82SPatrick Mooney }
879aa39f6d0SPatrick Mooney case VM_SET_AUTODESTRUCT: {
880aa39f6d0SPatrick Mooney /*
881aa39f6d0SPatrick Mooney * Since this has to do with controlling the lifetime of the
882aa39f6d0SPatrick Mooney * greater vmm_softc_t, the flag is protected by vmm_mtx, rather
883aa39f6d0SPatrick Mooney * than the vcpu-centric or rwlock exclusion mechanisms.
884aa39f6d0SPatrick Mooney */
885aa39f6d0SPatrick Mooney mutex_enter(&vmm_mtx);
88642640e49SPatrick Mooney if (arg != 0) {
88742640e49SPatrick Mooney sc->vmm_flags |= VMM_AUTODESTROY;
88842640e49SPatrick Mooney } else {
88942640e49SPatrick Mooney sc->vmm_flags &= ~VMM_AUTODESTROY;
89042640e49SPatrick Mooney }
891aa39f6d0SPatrick Mooney mutex_exit(&vmm_mtx);
892aa39f6d0SPatrick Mooney break;
893aa39f6d0SPatrick Mooney }
89442640e49SPatrick Mooney case VM_DESTROY_SELF: {
89542640e49SPatrick Mooney bool hma_release = false;
89642640e49SPatrick Mooney
89742640e49SPatrick Mooney /*
89842640e49SPatrick Mooney * Just like VMM_DESTROY_VM, but on the instance file descriptor
89942640e49SPatrick Mooney * itself, rather than having to perform a racy name lookup as
90042640e49SPatrick Mooney * part of the destroy process.
90142640e49SPatrick Mooney *
90242640e49SPatrick Mooney * Since vmm_destroy_locked() performs vCPU lock acquisition in
90342640e49SPatrick Mooney * order to kick the vCPUs out of guest context as part of any
90442640e49SPatrick Mooney * destruction, we do not need to worry about it ourself using
90542640e49SPatrick Mooney * the `lock_type` logic here.
90642640e49SPatrick Mooney */
90742640e49SPatrick Mooney mutex_enter(&vmm_mtx);
90842640e49SPatrick Mooney VERIFY0(vmm_destroy_locked(sc, VDO_DEFAULT, &hma_release));
90942640e49SPatrick Mooney mutex_exit(&vmm_mtx);
91042640e49SPatrick Mooney if (hma_release) {
91142640e49SPatrick Mooney vmm_hma_release();
91242640e49SPatrick Mooney }
91342640e49SPatrick Mooney break;
91442640e49SPatrick Mooney }
91542640e49SPatrick Mooney case VM_DESTROY_PENDING: {
91642640e49SPatrick Mooney /*
91742640e49SPatrick Mooney * If we have made it this far, then destruction of the instance
91842640e49SPatrick Mooney * has not been initiated.
91942640e49SPatrick Mooney */
92042640e49SPatrick Mooney *rvalp = 0;
92142640e49SPatrick Mooney break;
92242640e49SPatrick Mooney }
9237c8c0b82SPatrick Mooney
9247c8c0b82SPatrick Mooney case VM_ISA_ASSERT_IRQ: {
9257c8c0b82SPatrick Mooney struct vm_isa_irq isa_irq;
9267c8c0b82SPatrick Mooney
9277c8c0b82SPatrick Mooney if (ddi_copyin(datap, &isa_irq, sizeof (isa_irq), md)) {
9287c8c0b82SPatrick Mooney error = EFAULT;
9297c8c0b82SPatrick Mooney break;
9307c8c0b82SPatrick Mooney }
9317c8c0b82SPatrick Mooney error = vatpic_assert_irq(sc->vmm_vm, isa_irq.atpic_irq);
9327c8c0b82SPatrick Mooney if (error == 0 && isa_irq.ioapic_irq != -1) {
9337c8c0b82SPatrick Mooney error = vioapic_assert_irq(sc->vmm_vm,
9347c8c0b82SPatrick Mooney isa_irq.ioapic_irq);
9357c8c0b82SPatrick Mooney }
9367c8c0b82SPatrick Mooney break;
9377c8c0b82SPatrick Mooney }
9387c8c0b82SPatrick Mooney case VM_ISA_DEASSERT_IRQ: {
9397c8c0b82SPatrick Mooney struct vm_isa_irq isa_irq;
9407c8c0b82SPatrick Mooney
9417c8c0b82SPatrick Mooney if (ddi_copyin(datap, &isa_irq, sizeof (isa_irq), md)) {
9427c8c0b82SPatrick Mooney error = EFAULT;
9437c8c0b82SPatrick Mooney break;
9447c8c0b82SPatrick Mooney }
9457c8c0b82SPatrick Mooney error = vatpic_deassert_irq(sc->vmm_vm, isa_irq.atpic_irq);
9467c8c0b82SPatrick Mooney if (error == 0 && isa_irq.ioapic_irq != -1) {
9477c8c0b82SPatrick Mooney error = vioapic_deassert_irq(sc->vmm_vm,
9487c8c0b82SPatrick Mooney isa_irq.ioapic_irq);
9497c8c0b82SPatrick Mooney }
9507c8c0b82SPatrick Mooney break;
9517c8c0b82SPatrick Mooney }
9527c8c0b82SPatrick Mooney case VM_ISA_PULSE_IRQ: {
9537c8c0b82SPatrick Mooney struct vm_isa_irq isa_irq;
9547c8c0b82SPatrick Mooney
9557c8c0b82SPatrick Mooney if (ddi_copyin(datap, &isa_irq, sizeof (isa_irq), md)) {
9567c8c0b82SPatrick Mooney error = EFAULT;
9577c8c0b82SPatrick Mooney break;
9587c8c0b82SPatrick Mooney }
9597c8c0b82SPatrick Mooney error = vatpic_pulse_irq(sc->vmm_vm, isa_irq.atpic_irq);
9607c8c0b82SPatrick Mooney if (error == 0 && isa_irq.ioapic_irq != -1) {
9617c8c0b82SPatrick Mooney error = vioapic_pulse_irq(sc->vmm_vm,
9627c8c0b82SPatrick Mooney isa_irq.ioapic_irq);
9637c8c0b82SPatrick Mooney }
9647c8c0b82SPatrick Mooney break;
9657c8c0b82SPatrick Mooney }
9667c8c0b82SPatrick Mooney case VM_ISA_SET_IRQ_TRIGGER: {
9677c8c0b82SPatrick Mooney struct vm_isa_irq_trigger isa_irq_trigger;
9687c8c0b82SPatrick Mooney
9697c8c0b82SPatrick Mooney if (ddi_copyin(datap, &isa_irq_trigger,
9707c8c0b82SPatrick Mooney sizeof (isa_irq_trigger), md)) {
9717c8c0b82SPatrick Mooney error = EFAULT;
9727c8c0b82SPatrick Mooney break;
9737c8c0b82SPatrick Mooney }
9747c8c0b82SPatrick Mooney error = vatpic_set_irq_trigger(sc->vmm_vm,
9757c8c0b82SPatrick Mooney isa_irq_trigger.atpic_irq, isa_irq_trigger.trigger);
9767c8c0b82SPatrick Mooney break;
9777c8c0b82SPatrick Mooney }
9787c8c0b82SPatrick Mooney
9797c8c0b82SPatrick Mooney case VM_MMAP_GETNEXT: {
9807c8c0b82SPatrick Mooney struct vm_memmap mm;
9817c8c0b82SPatrick Mooney
9827c8c0b82SPatrick Mooney if (ddi_copyin(datap, &mm, sizeof (mm), md)) {
9837c8c0b82SPatrick Mooney error = EFAULT;
9847c8c0b82SPatrick Mooney break;
9857c8c0b82SPatrick Mooney }
9867c8c0b82SPatrick Mooney error = vm_mmap_getnext(sc->vmm_vm, &mm.gpa, &mm.segid,
9877c8c0b82SPatrick Mooney &mm.segoff, &mm.len, &mm.prot, &mm.flags);
9887c8c0b82SPatrick Mooney if (error == 0 && ddi_copyout(&mm, datap, sizeof (mm), md)) {
9897c8c0b82SPatrick Mooney error = EFAULT;
9907c8c0b82SPatrick Mooney break;
9917c8c0b82SPatrick Mooney }
9927c8c0b82SPatrick Mooney break;
9937c8c0b82SPatrick Mooney }
9947c8c0b82SPatrick Mooney case VM_MMAP_MEMSEG: {
9957c8c0b82SPatrick Mooney struct vm_memmap mm;
9967c8c0b82SPatrick Mooney
9977c8c0b82SPatrick Mooney if (ddi_copyin(datap, &mm, sizeof (mm), md)) {
9987c8c0b82SPatrick Mooney error = EFAULT;
9997c8c0b82SPatrick Mooney break;
10007c8c0b82SPatrick Mooney }
10017c8c0b82SPatrick Mooney error = vm_mmap_memseg(sc->vmm_vm, mm.gpa, mm.segid, mm.segoff,
10027c8c0b82SPatrick Mooney mm.len, mm.prot, mm.flags);
10037c8c0b82SPatrick Mooney break;
10047c8c0b82SPatrick Mooney }
10057c8c0b82SPatrick Mooney case VM_MUNMAP_MEMSEG: {
10067c8c0b82SPatrick Mooney struct vm_munmap mu;
10077c8c0b82SPatrick Mooney
10087c8c0b82SPatrick Mooney if (ddi_copyin(datap, &mu, sizeof (mu), md)) {
10097c8c0b82SPatrick Mooney error = EFAULT;
10107c8c0b82SPatrick Mooney break;
10117c8c0b82SPatrick Mooney }
10127c8c0b82SPatrick Mooney error = vm_munmap_memseg(sc->vmm_vm, mu.gpa, mu.len);
10137c8c0b82SPatrick Mooney break;
10147c8c0b82SPatrick Mooney }
10157c8c0b82SPatrick Mooney case VM_ALLOC_MEMSEG: {
10167c8c0b82SPatrick Mooney struct vm_memseg vmseg;
10177c8c0b82SPatrick Mooney
10187c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmseg, sizeof (vmseg), md)) {
10197c8c0b82SPatrick Mooney error = EFAULT;
10207c8c0b82SPatrick Mooney break;
10217c8c0b82SPatrick Mooney }
10227c8c0b82SPatrick Mooney error = vmmdev_alloc_memseg(sc, &vmseg);
10237c8c0b82SPatrick Mooney break;
10247c8c0b82SPatrick Mooney }
10257c8c0b82SPatrick Mooney case VM_GET_MEMSEG: {
10267c8c0b82SPatrick Mooney struct vm_memseg vmseg;
10277c8c0b82SPatrick Mooney
10287c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmseg, sizeof (vmseg), md)) {
10297c8c0b82SPatrick Mooney error = EFAULT;
10307c8c0b82SPatrick Mooney break;
10317c8c0b82SPatrick Mooney }
10327c8c0b82SPatrick Mooney error = vmmdev_get_memseg(sc, &vmseg);
10337c8c0b82SPatrick Mooney if (error == 0 &&
10347c8c0b82SPatrick Mooney ddi_copyout(&vmseg, datap, sizeof (vmseg), md)) {
10357c8c0b82SPatrick Mooney error = EFAULT;
10367c8c0b82SPatrick Mooney break;
10377c8c0b82SPatrick Mooney }
10387c8c0b82SPatrick Mooney break;
10397c8c0b82SPatrick Mooney }
10407c8c0b82SPatrick Mooney case VM_GET_REGISTER: {
10417c8c0b82SPatrick Mooney struct vm_register vmreg;
10427c8c0b82SPatrick Mooney
10437c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmreg, sizeof (vmreg), md)) {
10447c8c0b82SPatrick Mooney error = EFAULT;
10457c8c0b82SPatrick Mooney break;
10467c8c0b82SPatrick Mooney }
10477c8c0b82SPatrick Mooney error = vm_get_register(sc->vmm_vm, vcpu, vmreg.regnum,
10487c8c0b82SPatrick Mooney &vmreg.regval);
10497c8c0b82SPatrick Mooney if (error == 0 &&
10507c8c0b82SPatrick Mooney ddi_copyout(&vmreg, datap, sizeof (vmreg), md)) {
10517c8c0b82SPatrick Mooney error = EFAULT;
10527c8c0b82SPatrick Mooney break;
10537c8c0b82SPatrick Mooney }
10547c8c0b82SPatrick Mooney break;
10557c8c0b82SPatrick Mooney }
10567c8c0b82SPatrick Mooney case VM_SET_REGISTER: {
10577c8c0b82SPatrick Mooney struct vm_register vmreg;
10587c8c0b82SPatrick Mooney
10597c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmreg, sizeof (vmreg), md)) {
10607c8c0b82SPatrick Mooney error = EFAULT;
10617c8c0b82SPatrick Mooney break;
10627c8c0b82SPatrick Mooney }
10637c8c0b82SPatrick Mooney error = vm_set_register(sc->vmm_vm, vcpu, vmreg.regnum,
10647c8c0b82SPatrick Mooney vmreg.regval);
10657c8c0b82SPatrick Mooney break;
10667c8c0b82SPatrick Mooney }
10677c8c0b82SPatrick Mooney case VM_SET_SEGMENT_DESCRIPTOR: {
10687c8c0b82SPatrick Mooney struct vm_seg_desc vmsegd;
10697c8c0b82SPatrick Mooney
10707c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmsegd, sizeof (vmsegd), md)) {
10717c8c0b82SPatrick Mooney error = EFAULT;
10727c8c0b82SPatrick Mooney break;
10737c8c0b82SPatrick Mooney }
10747c8c0b82SPatrick Mooney error = vm_set_seg_desc(sc->vmm_vm, vcpu, vmsegd.regnum,
10757c8c0b82SPatrick Mooney &vmsegd.desc);
10767c8c0b82SPatrick Mooney break;
10777c8c0b82SPatrick Mooney }
10787c8c0b82SPatrick Mooney case VM_GET_SEGMENT_DESCRIPTOR: {
10797c8c0b82SPatrick Mooney struct vm_seg_desc vmsegd;
10807c8c0b82SPatrick Mooney
10817c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmsegd, sizeof (vmsegd), md)) {
10827c8c0b82SPatrick Mooney error = EFAULT;
10837c8c0b82SPatrick Mooney break;
10847c8c0b82SPatrick Mooney }
10857c8c0b82SPatrick Mooney error = vm_get_seg_desc(sc->vmm_vm, vcpu, vmsegd.regnum,
10867c8c0b82SPatrick Mooney &vmsegd.desc);
10877c8c0b82SPatrick Mooney if (error == 0 &&
10887c8c0b82SPatrick Mooney ddi_copyout(&vmsegd, datap, sizeof (vmsegd), md)) {
10897c8c0b82SPatrick Mooney error = EFAULT;
10907c8c0b82SPatrick Mooney break;
10917c8c0b82SPatrick Mooney }
10927c8c0b82SPatrick Mooney break;
10937c8c0b82SPatrick Mooney }
10947c8c0b82SPatrick Mooney case VM_GET_REGISTER_SET: {
10957c8c0b82SPatrick Mooney struct vm_register_set vrs;
10967c8c0b82SPatrick Mooney int regnums[VM_REG_LAST];
10977c8c0b82SPatrick Mooney uint64_t regvals[VM_REG_LAST];
10987c8c0b82SPatrick Mooney
10997c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vrs, sizeof (vrs), md)) {
11007c8c0b82SPatrick Mooney error = EFAULT;
11017c8c0b82SPatrick Mooney break;
11027c8c0b82SPatrick Mooney }
11037c8c0b82SPatrick Mooney if (vrs.count > VM_REG_LAST || vrs.count == 0) {
11047c8c0b82SPatrick Mooney error = EINVAL;
11057c8c0b82SPatrick Mooney break;
11067c8c0b82SPatrick Mooney }
11077c8c0b82SPatrick Mooney if (ddi_copyin(vrs.regnums, regnums,
11087c8c0b82SPatrick Mooney sizeof (int) * vrs.count, md)) {
11097c8c0b82SPatrick Mooney error = EFAULT;
11107c8c0b82SPatrick Mooney break;
11117c8c0b82SPatrick Mooney }
11127c8c0b82SPatrick Mooney
11137c8c0b82SPatrick Mooney error = 0;
11147c8c0b82SPatrick Mooney for (uint_t i = 0; i < vrs.count && error == 0; i++) {
11157c8c0b82SPatrick Mooney if (regnums[i] < 0) {
11167c8c0b82SPatrick Mooney error = EINVAL;
11177c8c0b82SPatrick Mooney break;
11187c8c0b82SPatrick Mooney }
11197c8c0b82SPatrick Mooney error = vm_get_register(sc->vmm_vm, vcpu, regnums[i],
11207c8c0b82SPatrick Mooney ®vals[i]);
11217c8c0b82SPatrick Mooney }
11227c8c0b82SPatrick Mooney if (error == 0 && ddi_copyout(regvals, vrs.regvals,
11237c8c0b82SPatrick Mooney sizeof (uint64_t) * vrs.count, md)) {
11247c8c0b82SPatrick Mooney error = EFAULT;
11257c8c0b82SPatrick Mooney }
11267c8c0b82SPatrick Mooney break;
11277c8c0b82SPatrick Mooney }
11287c8c0b82SPatrick Mooney case VM_SET_REGISTER_SET: {
11297c8c0b82SPatrick Mooney struct vm_register_set vrs;
11307c8c0b82SPatrick Mooney int regnums[VM_REG_LAST];
11317c8c0b82SPatrick Mooney uint64_t regvals[VM_REG_LAST];
11327c8c0b82SPatrick Mooney
11337c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vrs, sizeof (vrs), md)) {
11347c8c0b82SPatrick Mooney error = EFAULT;
11357c8c0b82SPatrick Mooney break;
11367c8c0b82SPatrick Mooney }
11377c8c0b82SPatrick Mooney if (vrs.count > VM_REG_LAST || vrs.count == 0) {
11387c8c0b82SPatrick Mooney error = EINVAL;
11397c8c0b82SPatrick Mooney break;
11407c8c0b82SPatrick Mooney }
11417c8c0b82SPatrick Mooney if (ddi_copyin(vrs.regnums, regnums,
11427c8c0b82SPatrick Mooney sizeof (int) * vrs.count, md)) {
11437c8c0b82SPatrick Mooney error = EFAULT;
11447c8c0b82SPatrick Mooney break;
11457c8c0b82SPatrick Mooney }
11467c8c0b82SPatrick Mooney if (ddi_copyin(vrs.regvals, regvals,
11477c8c0b82SPatrick Mooney sizeof (uint64_t) * vrs.count, md)) {
11487c8c0b82SPatrick Mooney error = EFAULT;
11497c8c0b82SPatrick Mooney break;
11507c8c0b82SPatrick Mooney }
11517c8c0b82SPatrick Mooney
11527c8c0b82SPatrick Mooney error = 0;
11537c8c0b82SPatrick Mooney for (uint_t i = 0; i < vrs.count && error == 0; i++) {
11547c8c0b82SPatrick Mooney /*
11557c8c0b82SPatrick Mooney * Setting registers in a set is not atomic, since a
11567c8c0b82SPatrick Mooney * failure in the middle of the set will cause a
11577c8c0b82SPatrick Mooney * bail-out and inconsistent register state. Callers
11587c8c0b82SPatrick Mooney * should be wary of this.
11597c8c0b82SPatrick Mooney */
11607c8c0b82SPatrick Mooney if (regnums[i] < 0) {
11617c8c0b82SPatrick Mooney error = EINVAL;
11627c8c0b82SPatrick Mooney break;
11637c8c0b82SPatrick Mooney }
11647c8c0b82SPatrick Mooney error = vm_set_register(sc->vmm_vm, vcpu, regnums[i],
11657c8c0b82SPatrick Mooney regvals[i]);
11667c8c0b82SPatrick Mooney }
11677c8c0b82SPatrick Mooney break;
11687c8c0b82SPatrick Mooney }
11697c8c0b82SPatrick Mooney case VM_RESET_CPU: {
11707c8c0b82SPatrick Mooney struct vm_vcpu_reset vvr;
11717c8c0b82SPatrick Mooney
11727c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vvr, sizeof (vvr), md)) {
11737c8c0b82SPatrick Mooney error = EFAULT;
11747c8c0b82SPatrick Mooney break;
11757c8c0b82SPatrick Mooney }
11767c8c0b82SPatrick Mooney if (vvr.kind != VRK_RESET && vvr.kind != VRK_INIT) {
11777c8c0b82SPatrick Mooney error = EINVAL;
11787c8c0b82SPatrick Mooney }
11797c8c0b82SPatrick Mooney
11807c8c0b82SPatrick Mooney error = vcpu_arch_reset(sc->vmm_vm, vcpu, vvr.kind == VRK_INIT);
11817c8c0b82SPatrick Mooney break;
11827c8c0b82SPatrick Mooney }
11837c8c0b82SPatrick Mooney case VM_GET_RUN_STATE: {
11847c8c0b82SPatrick Mooney struct vm_run_state vrs;
11857c8c0b82SPatrick Mooney
11867c8c0b82SPatrick Mooney bzero(&vrs, sizeof (vrs));
11877c8c0b82SPatrick Mooney error = vm_get_run_state(sc->vmm_vm, vcpu, &vrs.state,
11887c8c0b82SPatrick Mooney &vrs.sipi_vector);
11897c8c0b82SPatrick Mooney if (error == 0) {
11907c8c0b82SPatrick Mooney if (ddi_copyout(&vrs, datap, sizeof (vrs), md)) {
11917c8c0b82SPatrick Mooney error = EFAULT;
11927c8c0b82SPatrick Mooney break;
11937c8c0b82SPatrick Mooney }
11947c8c0b82SPatrick Mooney }
11957c8c0b82SPatrick Mooney break;
11967c8c0b82SPatrick Mooney }
11977c8c0b82SPatrick Mooney case VM_SET_RUN_STATE: {
11987c8c0b82SPatrick Mooney struct vm_run_state vrs;
11997c8c0b82SPatrick Mooney
12007c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vrs, sizeof (vrs), md)) {
12017c8c0b82SPatrick Mooney error = EFAULT;
12027c8c0b82SPatrick Mooney break;
12037c8c0b82SPatrick Mooney }
12047c8c0b82SPatrick Mooney error = vm_set_run_state(sc->vmm_vm, vcpu, vrs.state,
12057c8c0b82SPatrick Mooney vrs.sipi_vector);
12067c8c0b82SPatrick Mooney break;
12077c8c0b82SPatrick Mooney }
12087c8c0b82SPatrick Mooney case VM_GET_FPU: {
12097c8c0b82SPatrick Mooney struct vm_fpu_state req;
12107c8c0b82SPatrick Mooney const size_t max_len = (PAGESIZE * 2);
12117c8c0b82SPatrick Mooney void *kbuf;
12127c8c0b82SPatrick Mooney
12137c8c0b82SPatrick Mooney if (ddi_copyin(datap, &req, sizeof (req), md)) {
12147c8c0b82SPatrick Mooney error = EFAULT;
12157c8c0b82SPatrick Mooney break;
12167c8c0b82SPatrick Mooney }
12177c8c0b82SPatrick Mooney if (req.len > max_len || req.len == 0) {
12187c8c0b82SPatrick Mooney error = EINVAL;
12197c8c0b82SPatrick Mooney break;
12207c8c0b82SPatrick Mooney }
12217c8c0b82SPatrick Mooney kbuf = kmem_zalloc(req.len, KM_SLEEP);
12227c8c0b82SPatrick Mooney error = vm_get_fpu(sc->vmm_vm, vcpu, kbuf, req.len);
12237c8c0b82SPatrick Mooney if (error == 0) {
12247c8c0b82SPatrick Mooney if (ddi_copyout(kbuf, req.buf, req.len, md)) {
12257c8c0b82SPatrick Mooney error = EFAULT;
12267c8c0b82SPatrick Mooney }
12277c8c0b82SPatrick Mooney }
12287c8c0b82SPatrick Mooney kmem_free(kbuf, req.len);
12297c8c0b82SPatrick Mooney break;
12307c8c0b82SPatrick Mooney }
12317c8c0b82SPatrick Mooney case VM_SET_FPU: {
12327c8c0b82SPatrick Mooney struct vm_fpu_state req;
12337c8c0b82SPatrick Mooney const size_t max_len = (PAGESIZE * 2);
12347c8c0b82SPatrick Mooney void *kbuf;
12357c8c0b82SPatrick Mooney
12367c8c0b82SPatrick Mooney if (ddi_copyin(datap, &req, sizeof (req), md)) {
12377c8c0b82SPatrick Mooney error = EFAULT;
12387c8c0b82SPatrick Mooney break;
12397c8c0b82SPatrick Mooney }
12407c8c0b82SPatrick Mooney if (req.len > max_len || req.len == 0) {
12417c8c0b82SPatrick Mooney error = EINVAL;
12427c8c0b82SPatrick Mooney break;
12437c8c0b82SPatrick Mooney }
12447c8c0b82SPatrick Mooney kbuf = kmem_alloc(req.len, KM_SLEEP);
12457c8c0b82SPatrick Mooney if (ddi_copyin(req.buf, kbuf, req.len, md)) {
12467c8c0b82SPatrick Mooney error = EFAULT;
12477c8c0b82SPatrick Mooney } else {
12487c8c0b82SPatrick Mooney error = vm_set_fpu(sc->vmm_vm, vcpu, kbuf, req.len);
12497c8c0b82SPatrick Mooney }
12507c8c0b82SPatrick Mooney kmem_free(kbuf, req.len);
12517c8c0b82SPatrick Mooney break;
12527c8c0b82SPatrick Mooney }
1253578d9a56SPatrick Mooney case VM_GET_CPUID: {
1254578d9a56SPatrick Mooney struct vm_vcpu_cpuid_config cfg;
1255578d9a56SPatrick Mooney struct vcpu_cpuid_entry *entries = NULL;
1256578d9a56SPatrick Mooney
1257578d9a56SPatrick Mooney if (ddi_copyin(datap, &cfg, sizeof (cfg), md)) {
1258578d9a56SPatrick Mooney error = EFAULT;
1259578d9a56SPatrick Mooney break;
1260578d9a56SPatrick Mooney }
1261578d9a56SPatrick Mooney if (cfg.vvcc_nent > VMM_MAX_CPUID_ENTRIES) {
1262578d9a56SPatrick Mooney error = EINVAL;
1263578d9a56SPatrick Mooney break;
1264578d9a56SPatrick Mooney }
1265578d9a56SPatrick Mooney
1266578d9a56SPatrick Mooney const size_t entries_size =
1267578d9a56SPatrick Mooney cfg.vvcc_nent * sizeof (struct vcpu_cpuid_entry);
1268578d9a56SPatrick Mooney if (entries_size != 0) {
1269578d9a56SPatrick Mooney entries = kmem_zalloc(entries_size, KM_SLEEP);
1270578d9a56SPatrick Mooney }
1271578d9a56SPatrick Mooney
1272578d9a56SPatrick Mooney vcpu_cpuid_config_t vm_cfg = {
1273578d9a56SPatrick Mooney .vcc_nent = cfg.vvcc_nent,
1274578d9a56SPatrick Mooney .vcc_entries = entries,
1275578d9a56SPatrick Mooney };
1276578d9a56SPatrick Mooney error = vm_get_cpuid(sc->vmm_vm, vcpu, &vm_cfg);
1277578d9a56SPatrick Mooney
1278578d9a56SPatrick Mooney /*
1279578d9a56SPatrick Mooney * Only attempt to copy out the resultant entries if we were
1280578d9a56SPatrick Mooney * able to query them from the instance. The flags and number
1281578d9a56SPatrick Mooney * of entries are emitted regardless.
1282578d9a56SPatrick Mooney */
1283578d9a56SPatrick Mooney cfg.vvcc_flags = vm_cfg.vcc_flags;
1284578d9a56SPatrick Mooney cfg.vvcc_nent = vm_cfg.vcc_nent;
1285578d9a56SPatrick Mooney if (entries != NULL) {
1286578d9a56SPatrick Mooney if (error == 0 && ddi_copyout(entries, cfg.vvcc_entries,
1287578d9a56SPatrick Mooney entries_size, md) != 0) {
1288578d9a56SPatrick Mooney error = EFAULT;
1289578d9a56SPatrick Mooney }
1290578d9a56SPatrick Mooney
1291578d9a56SPatrick Mooney kmem_free(entries, entries_size);
1292578d9a56SPatrick Mooney }
1293578d9a56SPatrick Mooney
1294578d9a56SPatrick Mooney if (ddi_copyout(&cfg, datap, sizeof (cfg), md) != 0) {
1295578d9a56SPatrick Mooney error = EFAULT;
1296578d9a56SPatrick Mooney }
1297578d9a56SPatrick Mooney break;
1298578d9a56SPatrick Mooney }
1299578d9a56SPatrick Mooney case VM_SET_CPUID: {
1300578d9a56SPatrick Mooney struct vm_vcpu_cpuid_config cfg;
1301578d9a56SPatrick Mooney struct vcpu_cpuid_entry *entries = NULL;
1302578d9a56SPatrick Mooney size_t entries_size = 0;
1303578d9a56SPatrick Mooney
1304578d9a56SPatrick Mooney if (ddi_copyin(datap, &cfg, sizeof (cfg), md)) {
1305578d9a56SPatrick Mooney error = EFAULT;
1306578d9a56SPatrick Mooney break;
1307578d9a56SPatrick Mooney }
1308578d9a56SPatrick Mooney if (cfg.vvcc_nent > VMM_MAX_CPUID_ENTRIES) {
1309578d9a56SPatrick Mooney error = EFBIG;
1310578d9a56SPatrick Mooney break;
1311578d9a56SPatrick Mooney }
1312578d9a56SPatrick Mooney if ((cfg.vvcc_flags & VCC_FLAG_LEGACY_HANDLING) != 0) {
1313578d9a56SPatrick Mooney /*
1314578d9a56SPatrick Mooney * If we are being instructed to use "legacy" handling,
1315578d9a56SPatrick Mooney * then no entries should be provided, since the static
1316578d9a56SPatrick Mooney * in-kernel masking will be used.
1317578d9a56SPatrick Mooney */
1318578d9a56SPatrick Mooney if (cfg.vvcc_nent != 0) {
1319578d9a56SPatrick Mooney error = EINVAL;
1320578d9a56SPatrick Mooney break;
1321578d9a56SPatrick Mooney }
1322578d9a56SPatrick Mooney } else if (cfg.vvcc_nent != 0) {
1323578d9a56SPatrick Mooney entries_size =
1324578d9a56SPatrick Mooney cfg.vvcc_nent * sizeof (struct vcpu_cpuid_entry);
1325578d9a56SPatrick Mooney entries = kmem_alloc(entries_size, KM_SLEEP);
1326578d9a56SPatrick Mooney
1327578d9a56SPatrick Mooney if (ddi_copyin(cfg.vvcc_entries, entries, entries_size,
1328578d9a56SPatrick Mooney md) != 0) {
1329578d9a56SPatrick Mooney error = EFAULT;
1330578d9a56SPatrick Mooney kmem_free(entries, entries_size);
1331578d9a56SPatrick Mooney break;
1332578d9a56SPatrick Mooney }
1333578d9a56SPatrick Mooney }
1334578d9a56SPatrick Mooney
1335578d9a56SPatrick Mooney vcpu_cpuid_config_t vm_cfg = {
1336578d9a56SPatrick Mooney .vcc_flags = cfg.vvcc_flags,
1337578d9a56SPatrick Mooney .vcc_nent = cfg.vvcc_nent,
1338578d9a56SPatrick Mooney .vcc_entries = entries,
1339578d9a56SPatrick Mooney };
1340578d9a56SPatrick Mooney error = vm_set_cpuid(sc->vmm_vm, vcpu, &vm_cfg);
1341578d9a56SPatrick Mooney
1342578d9a56SPatrick Mooney if (entries != NULL) {
1343578d9a56SPatrick Mooney kmem_free(entries, entries_size);
1344578d9a56SPatrick Mooney }
1345578d9a56SPatrick Mooney break;
1346578d9a56SPatrick Mooney }
1347578d9a56SPatrick Mooney case VM_LEGACY_CPUID: {
1348578d9a56SPatrick Mooney struct vm_legacy_cpuid vlc;
1349578d9a56SPatrick Mooney if (ddi_copyin(datap, &vlc, sizeof (vlc), md)) {
1350578d9a56SPatrick Mooney error = EFAULT;
1351578d9a56SPatrick Mooney break;
1352578d9a56SPatrick Mooney }
1353578d9a56SPatrick Mooney vlc.vlc_vcpuid = vcpu;
1354578d9a56SPatrick Mooney
1355578d9a56SPatrick Mooney legacy_emulate_cpuid(sc->vmm_vm, vcpu, &vlc.vlc_eax,
1356578d9a56SPatrick Mooney &vlc.vlc_ebx, &vlc.vlc_ecx, &vlc.vlc_edx);
1357578d9a56SPatrick Mooney
1358578d9a56SPatrick Mooney if (ddi_copyout(&vlc, datap, sizeof (vlc), md)) {
1359578d9a56SPatrick Mooney error = EFAULT;
1360578d9a56SPatrick Mooney break;
1361578d9a56SPatrick Mooney }
1362578d9a56SPatrick Mooney break;
1363578d9a56SPatrick Mooney }
13647c8c0b82SPatrick Mooney
13657c8c0b82SPatrick Mooney case VM_SET_KERNEMU_DEV:
13667c8c0b82SPatrick Mooney case VM_GET_KERNEMU_DEV: {
13677c8c0b82SPatrick Mooney struct vm_readwrite_kernemu_device kemu;
13687c8c0b82SPatrick Mooney size_t size = 0;
13697c8c0b82SPatrick Mooney
13707c8c0b82SPatrick Mooney if (ddi_copyin(datap, &kemu, sizeof (kemu), md)) {
13717c8c0b82SPatrick Mooney error = EFAULT;
13727c8c0b82SPatrick Mooney break;
13737c8c0b82SPatrick Mooney }
13747c8c0b82SPatrick Mooney
13757c8c0b82SPatrick Mooney if (kemu.access_width > 3) {
13767c8c0b82SPatrick Mooney error = EINVAL;
13777c8c0b82SPatrick Mooney break;
13787c8c0b82SPatrick Mooney }
13797c8c0b82SPatrick Mooney size = (1 << kemu.access_width);
13807c8c0b82SPatrick Mooney ASSERT(size >= 1 && size <= 8);
13817c8c0b82SPatrick Mooney
13827c8c0b82SPatrick Mooney if (cmd == VM_SET_KERNEMU_DEV) {
13837c8c0b82SPatrick Mooney error = vm_service_mmio_write(sc->vmm_vm, vcpu,
13847c8c0b82SPatrick Mooney kemu.gpa, kemu.value, size);
13857c8c0b82SPatrick Mooney } else {
13867c8c0b82SPatrick Mooney error = vm_service_mmio_read(sc->vmm_vm, vcpu,
13877c8c0b82SPatrick Mooney kemu.gpa, &kemu.value, size);
13887c8c0b82SPatrick Mooney }
13897c8c0b82SPatrick Mooney
13907c8c0b82SPatrick Mooney if (error == 0) {
13917c8c0b82SPatrick Mooney if (ddi_copyout(&kemu, datap, sizeof (kemu), md)) {
13927c8c0b82SPatrick Mooney error = EFAULT;
13937c8c0b82SPatrick Mooney break;
13947c8c0b82SPatrick Mooney }
13957c8c0b82SPatrick Mooney }
13967c8c0b82SPatrick Mooney break;
13977c8c0b82SPatrick Mooney }
13987c8c0b82SPatrick Mooney
13997c8c0b82SPatrick Mooney case VM_GET_CAPABILITY: {
14007c8c0b82SPatrick Mooney struct vm_capability vmcap;
14017c8c0b82SPatrick Mooney
14027c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmcap, sizeof (vmcap), md)) {
14037c8c0b82SPatrick Mooney error = EFAULT;
14047c8c0b82SPatrick Mooney break;
14057c8c0b82SPatrick Mooney }
14067c8c0b82SPatrick Mooney error = vm_get_capability(sc->vmm_vm, vcpu, vmcap.captype,
14077c8c0b82SPatrick Mooney &vmcap.capval);
14087c8c0b82SPatrick Mooney if (error == 0 &&
14097c8c0b82SPatrick Mooney ddi_copyout(&vmcap, datap, sizeof (vmcap), md)) {
14107c8c0b82SPatrick Mooney error = EFAULT;
14117c8c0b82SPatrick Mooney break;
14127c8c0b82SPatrick Mooney }
14137c8c0b82SPatrick Mooney break;
14147c8c0b82SPatrick Mooney }
14157c8c0b82SPatrick Mooney case VM_SET_CAPABILITY: {
14167c8c0b82SPatrick Mooney struct vm_capability vmcap;
14177c8c0b82SPatrick Mooney
14187c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmcap, sizeof (vmcap), md)) {
14197c8c0b82SPatrick Mooney error = EFAULT;
14207c8c0b82SPatrick Mooney break;
14217c8c0b82SPatrick Mooney }
14227c8c0b82SPatrick Mooney error = vm_set_capability(sc->vmm_vm, vcpu, vmcap.captype,
14237c8c0b82SPatrick Mooney vmcap.capval);
14247c8c0b82SPatrick Mooney break;
14257c8c0b82SPatrick Mooney }
14267c8c0b82SPatrick Mooney case VM_SET_X2APIC_STATE: {
14277c8c0b82SPatrick Mooney struct vm_x2apic x2apic;
14287c8c0b82SPatrick Mooney
14297c8c0b82SPatrick Mooney if (ddi_copyin(datap, &x2apic, sizeof (x2apic), md)) {
14307c8c0b82SPatrick Mooney error = EFAULT;
14317c8c0b82SPatrick Mooney break;
14327c8c0b82SPatrick Mooney }
14337c8c0b82SPatrick Mooney error = vm_set_x2apic_state(sc->vmm_vm, vcpu, x2apic.state);
14347c8c0b82SPatrick Mooney break;
14357c8c0b82SPatrick Mooney }
14367c8c0b82SPatrick Mooney case VM_GET_X2APIC_STATE: {
14377c8c0b82SPatrick Mooney struct vm_x2apic x2apic;
14387c8c0b82SPatrick Mooney
14397c8c0b82SPatrick Mooney if (ddi_copyin(datap, &x2apic, sizeof (x2apic), md)) {
14407c8c0b82SPatrick Mooney error = EFAULT;
14417c8c0b82SPatrick Mooney break;
14427c8c0b82SPatrick Mooney }
14437c8c0b82SPatrick Mooney error = vm_get_x2apic_state(sc->vmm_vm, x2apic.cpuid,
14447c8c0b82SPatrick Mooney &x2apic.state);
14457c8c0b82SPatrick Mooney if (error == 0 &&
14467c8c0b82SPatrick Mooney ddi_copyout(&x2apic, datap, sizeof (x2apic), md)) {
14477c8c0b82SPatrick Mooney error = EFAULT;
14487c8c0b82SPatrick Mooney break;
14497c8c0b82SPatrick Mooney }
14507c8c0b82SPatrick Mooney break;
14517c8c0b82SPatrick Mooney }
14527c8c0b82SPatrick Mooney case VM_GET_GPA_PMAP: {
14537c8c0b82SPatrick Mooney /*
14547c8c0b82SPatrick Mooney * Until there is a necessity to leak EPT/RVI PTE values to
14557c8c0b82SPatrick Mooney * userspace, this will remain unimplemented
14567c8c0b82SPatrick Mooney */
14577c8c0b82SPatrick Mooney error = EINVAL;
14587c8c0b82SPatrick Mooney break;
14597c8c0b82SPatrick Mooney }
14607c8c0b82SPatrick Mooney case VM_GET_HPET_CAPABILITIES: {
14617c8c0b82SPatrick Mooney struct vm_hpet_cap hpetcap;
14627c8c0b82SPatrick Mooney
14637c8c0b82SPatrick Mooney error = vhpet_getcap(&hpetcap);
14647c8c0b82SPatrick Mooney if (error == 0 &&
14657c8c0b82SPatrick Mooney ddi_copyout(&hpetcap, datap, sizeof (hpetcap), md)) {
14667c8c0b82SPatrick Mooney error = EFAULT;
14677c8c0b82SPatrick Mooney break;
14687c8c0b82SPatrick Mooney }
14697c8c0b82SPatrick Mooney break;
14707c8c0b82SPatrick Mooney }
14717c8c0b82SPatrick Mooney case VM_GLA2GPA: {
14727c8c0b82SPatrick Mooney struct vm_gla2gpa gg;
14737c8c0b82SPatrick Mooney
14747c8c0b82SPatrick Mooney if (ddi_copyin(datap, &gg, sizeof (gg), md)) {
14757c8c0b82SPatrick Mooney error = EFAULT;
14767c8c0b82SPatrick Mooney break;
14777c8c0b82SPatrick Mooney }
14787c8c0b82SPatrick Mooney gg.vcpuid = vcpu;
14797c8c0b82SPatrick Mooney error = vm_gla2gpa(sc->vmm_vm, vcpu, &gg.paging, gg.gla,
14807c8c0b82SPatrick Mooney gg.prot, &gg.gpa, &gg.fault);
14817c8c0b82SPatrick Mooney if (error == 0 && ddi_copyout(&gg, datap, sizeof (gg), md)) {
14827c8c0b82SPatrick Mooney error = EFAULT;
14837c8c0b82SPatrick Mooney break;
14847c8c0b82SPatrick Mooney }
14857c8c0b82SPatrick Mooney break;
14867c8c0b82SPatrick Mooney }
14877c8c0b82SPatrick Mooney case VM_GLA2GPA_NOFAULT: {
14887c8c0b82SPatrick Mooney struct vm_gla2gpa gg;
14897c8c0b82SPatrick Mooney
14907c8c0b82SPatrick Mooney if (ddi_copyin(datap, &gg, sizeof (gg), md)) {
14917c8c0b82SPatrick Mooney error = EFAULT;
14927c8c0b82SPatrick Mooney break;
14937c8c0b82SPatrick Mooney }
14947c8c0b82SPatrick Mooney gg.vcpuid = vcpu;
14957c8c0b82SPatrick Mooney error = vm_gla2gpa_nofault(sc->vmm_vm, vcpu, &gg.paging,
14967c8c0b82SPatrick Mooney gg.gla, gg.prot, &gg.gpa, &gg.fault);
14977c8c0b82SPatrick Mooney if (error == 0 && ddi_copyout(&gg, datap, sizeof (gg), md)) {
14987c8c0b82SPatrick Mooney error = EFAULT;
14997c8c0b82SPatrick Mooney break;
15007c8c0b82SPatrick Mooney }
15017c8c0b82SPatrick Mooney break;
15027c8c0b82SPatrick Mooney }
15037c8c0b82SPatrick Mooney
15047c8c0b82SPatrick Mooney case VM_ACTIVATE_CPU:
15057c8c0b82SPatrick Mooney error = vm_activate_cpu(sc->vmm_vm, vcpu);
15067c8c0b82SPatrick Mooney break;
15077c8c0b82SPatrick Mooney
15087c8c0b82SPatrick Mooney case VM_SUSPEND_CPU:
15097c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vcpu, sizeof (vcpu), md)) {
15107c8c0b82SPatrick Mooney error = EFAULT;
15117c8c0b82SPatrick Mooney } else {
15127c8c0b82SPatrick Mooney error = vm_suspend_cpu(sc->vmm_vm, vcpu);
15137c8c0b82SPatrick Mooney }
15147c8c0b82SPatrick Mooney break;
15157c8c0b82SPatrick Mooney
15167c8c0b82SPatrick Mooney case VM_RESUME_CPU:
15177c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vcpu, sizeof (vcpu), md)) {
15187c8c0b82SPatrick Mooney error = EFAULT;
15197c8c0b82SPatrick Mooney } else {
15207c8c0b82SPatrick Mooney error = vm_resume_cpu(sc->vmm_vm, vcpu);
15217c8c0b82SPatrick Mooney }
15227c8c0b82SPatrick Mooney break;
15237c8c0b82SPatrick Mooney
152472473353SPatrick Mooney case VM_VCPU_BARRIER:
152572473353SPatrick Mooney vcpu = arg;
152672473353SPatrick Mooney error = vm_vcpu_barrier(sc->vmm_vm, vcpu);
152772473353SPatrick Mooney break;
152872473353SPatrick Mooney
15297c8c0b82SPatrick Mooney case VM_GET_CPUS: {
15307c8c0b82SPatrick Mooney struct vm_cpuset vm_cpuset;
15317c8c0b82SPatrick Mooney cpuset_t tempset;
15327c8c0b82SPatrick Mooney void *srcp = &tempset;
15337c8c0b82SPatrick Mooney int size;
15347c8c0b82SPatrick Mooney
15357c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vm_cpuset, sizeof (vm_cpuset), md)) {
15367c8c0b82SPatrick Mooney error = EFAULT;
15377c8c0b82SPatrick Mooney break;
15387c8c0b82SPatrick Mooney }
15397c8c0b82SPatrick Mooney
15407c8c0b82SPatrick Mooney /* Be more generous about sizing since our cpuset_t is large. */
15417c8c0b82SPatrick Mooney size = vm_cpuset.cpusetsize;
15427c8c0b82SPatrick Mooney if (size <= 0 || size > sizeof (cpuset_t)) {
15437c8c0b82SPatrick Mooney error = ERANGE;
15447c8c0b82SPatrick Mooney }
15457c8c0b82SPatrick Mooney /*
15467c8c0b82SPatrick Mooney * If they want a ulong_t or less, make sure they receive the
15477c8c0b82SPatrick Mooney * low bits with all the useful information.
15487c8c0b82SPatrick Mooney */
15497c8c0b82SPatrick Mooney if (size <= sizeof (tempset.cpub[0])) {
15507c8c0b82SPatrick Mooney srcp = &tempset.cpub[0];
15517c8c0b82SPatrick Mooney }
15527c8c0b82SPatrick Mooney
15537c8c0b82SPatrick Mooney if (vm_cpuset.which == VM_ACTIVE_CPUS) {
15547c8c0b82SPatrick Mooney tempset = vm_active_cpus(sc->vmm_vm);
15557c8c0b82SPatrick Mooney } else if (vm_cpuset.which == VM_DEBUG_CPUS) {
15567c8c0b82SPatrick Mooney tempset = vm_debug_cpus(sc->vmm_vm);
15577c8c0b82SPatrick Mooney } else {
15587c8c0b82SPatrick Mooney error = EINVAL;
15597c8c0b82SPatrick Mooney }
15607c8c0b82SPatrick Mooney
15617c8c0b82SPatrick Mooney ASSERT(size > 0 && size <= sizeof (tempset));
15627c8c0b82SPatrick Mooney if (error == 0 &&
15637c8c0b82SPatrick Mooney ddi_copyout(srcp, vm_cpuset.cpus, size, md)) {
15647c8c0b82SPatrick Mooney error = EFAULT;
15657c8c0b82SPatrick Mooney break;
15667c8c0b82SPatrick Mooney }
15677c8c0b82SPatrick Mooney break;
15687c8c0b82SPatrick Mooney }
15697c8c0b82SPatrick Mooney case VM_SET_INTINFO: {
15707c8c0b82SPatrick Mooney struct vm_intinfo vmii;
15717c8c0b82SPatrick Mooney
15727c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vmii, sizeof (vmii), md)) {
15737c8c0b82SPatrick Mooney error = EFAULT;
15747c8c0b82SPatrick Mooney break;
15757c8c0b82SPatrick Mooney }
15767c8c0b82SPatrick Mooney error = vm_exit_intinfo(sc->vmm_vm, vcpu, vmii.info1);
15777c8c0b82SPatrick Mooney break;
15787c8c0b82SPatrick Mooney }
15797c8c0b82SPatrick Mooney case VM_GET_INTINFO: {
15807c8c0b82SPatrick Mooney struct vm_intinfo vmii;
15817c8c0b82SPatrick Mooney
15827c8c0b82SPatrick Mooney vmii.vcpuid = vcpu;
15837c8c0b82SPatrick Mooney error = vm_get_intinfo(sc->vmm_vm, vcpu, &vmii.info1,
15847c8c0b82SPatrick Mooney &vmii.info2);
15857c8c0b82SPatrick Mooney if (error == 0 &&
15867c8c0b82SPatrick Mooney ddi_copyout(&vmii, datap, sizeof (vmii), md)) {
15877c8c0b82SPatrick Mooney error = EFAULT;
15887c8c0b82SPatrick Mooney break;
15897c8c0b82SPatrick Mooney }
15907c8c0b82SPatrick Mooney break;
15917c8c0b82SPatrick Mooney }
15927c8c0b82SPatrick Mooney case VM_RTC_WRITE: {
15937c8c0b82SPatrick Mooney struct vm_rtc_data rtcdata;
15947c8c0b82SPatrick Mooney
15957c8c0b82SPatrick Mooney if (ddi_copyin(datap, &rtcdata, sizeof (rtcdata), md)) {
15967c8c0b82SPatrick Mooney error = EFAULT;
15977c8c0b82SPatrick Mooney break;
15987c8c0b82SPatrick Mooney }
15997c8c0b82SPatrick Mooney error = vrtc_nvram_write(sc->vmm_vm, rtcdata.offset,
16007c8c0b82SPatrick Mooney rtcdata.value);
16017c8c0b82SPatrick Mooney break;
16027c8c0b82SPatrick Mooney }
16037c8c0b82SPatrick Mooney case VM_RTC_READ: {
16047c8c0b82SPatrick Mooney struct vm_rtc_data rtcdata;
16057c8c0b82SPatrick Mooney
16067c8c0b82SPatrick Mooney if (ddi_copyin(datap, &rtcdata, sizeof (rtcdata), md)) {
16077c8c0b82SPatrick Mooney error = EFAULT;
16087c8c0b82SPatrick Mooney break;
16097c8c0b82SPatrick Mooney }
16107c8c0b82SPatrick Mooney error = vrtc_nvram_read(sc->vmm_vm, rtcdata.offset,
16117c8c0b82SPatrick Mooney &rtcdata.value);
16127c8c0b82SPatrick Mooney if (error == 0 &&
16137c8c0b82SPatrick Mooney ddi_copyout(&rtcdata, datap, sizeof (rtcdata), md)) {
16147c8c0b82SPatrick Mooney error = EFAULT;
16157c8c0b82SPatrick Mooney break;
16167c8c0b82SPatrick Mooney }
16177c8c0b82SPatrick Mooney break;
16187c8c0b82SPatrick Mooney }
16197c8c0b82SPatrick Mooney case VM_RTC_SETTIME: {
1620a1d41cf9SPatrick Mooney timespec_t ts;
16217c8c0b82SPatrick Mooney
1622a1d41cf9SPatrick Mooney if (ddi_copyin(datap, &ts, sizeof (ts), md)) {
16237c8c0b82SPatrick Mooney error = EFAULT;
16247c8c0b82SPatrick Mooney break;
16257c8c0b82SPatrick Mooney }
1626a1d41cf9SPatrick Mooney error = vrtc_set_time(sc->vmm_vm, &ts);
16277c8c0b82SPatrick Mooney break;
16287c8c0b82SPatrick Mooney }
16297c8c0b82SPatrick Mooney case VM_RTC_GETTIME: {
1630a1d41cf9SPatrick Mooney timespec_t ts;
16317c8c0b82SPatrick Mooney
1632a1d41cf9SPatrick Mooney vrtc_get_time(sc->vmm_vm, &ts);
1633a1d41cf9SPatrick Mooney if (ddi_copyout(&ts, datap, sizeof (ts), md)) {
16347c8c0b82SPatrick Mooney error = EFAULT;
16357c8c0b82SPatrick Mooney break;
16367c8c0b82SPatrick Mooney }
16377c8c0b82SPatrick Mooney break;
16387c8c0b82SPatrick Mooney }
16397c8c0b82SPatrick Mooney
16407c8c0b82SPatrick Mooney case VM_PMTMR_LOCATE: {
16417c8c0b82SPatrick Mooney uint16_t port = arg;
16427c8c0b82SPatrick Mooney error = vpmtmr_set_location(sc->vmm_vm, port);
16437c8c0b82SPatrick Mooney break;
16447c8c0b82SPatrick Mooney }
16457c8c0b82SPatrick Mooney
16467c8c0b82SPatrick Mooney case VM_RESTART_INSTRUCTION:
16477c8c0b82SPatrick Mooney error = vm_restart_instruction(sc->vmm_vm, vcpu);
16487c8c0b82SPatrick Mooney break;
16497c8c0b82SPatrick Mooney
16507c8c0b82SPatrick Mooney case VM_SET_TOPOLOGY: {
16517c8c0b82SPatrick Mooney struct vm_cpu_topology topo;
16527c8c0b82SPatrick Mooney
16537c8c0b82SPatrick Mooney if (ddi_copyin(datap, &topo, sizeof (topo), md) != 0) {
16547c8c0b82SPatrick Mooney error = EFAULT;
16557c8c0b82SPatrick Mooney break;
16567c8c0b82SPatrick Mooney }
16577c8c0b82SPatrick Mooney error = vm_set_topology(sc->vmm_vm, topo.sockets, topo.cores,
16587c8c0b82SPatrick Mooney topo.threads, topo.maxcpus);
16597c8c0b82SPatrick Mooney break;
16607c8c0b82SPatrick Mooney }
16617c8c0b82SPatrick Mooney case VM_GET_TOPOLOGY: {
16627c8c0b82SPatrick Mooney struct vm_cpu_topology topo;
16637c8c0b82SPatrick Mooney
16647c8c0b82SPatrick Mooney vm_get_topology(sc->vmm_vm, &topo.sockets, &topo.cores,
16657c8c0b82SPatrick Mooney &topo.threads, &topo.maxcpus);
16667c8c0b82SPatrick Mooney if (ddi_copyout(&topo, datap, sizeof (topo), md) != 0) {
16677c8c0b82SPatrick Mooney error = EFAULT;
16687c8c0b82SPatrick Mooney break;
16697c8c0b82SPatrick Mooney }
16707c8c0b82SPatrick Mooney break;
16717c8c0b82SPatrick Mooney }
16727c8c0b82SPatrick Mooney case VM_DEVMEM_GETOFFSET: {
16737c8c0b82SPatrick Mooney struct vm_devmem_offset vdo;
16747c8c0b82SPatrick Mooney vmm_devmem_entry_t *de;
16757c8c0b82SPatrick Mooney
16767c8c0b82SPatrick Mooney if (ddi_copyin(datap, &vdo, sizeof (vdo), md) != 0) {
16777c8c0b82SPatrick Mooney error = EFAULT;
16787c8c0b82SPatrick Mooney break;
16797c8c0b82SPatrick Mooney }
16807c8c0b82SPatrick Mooney
16817c8c0b82SPatrick Mooney de = vmmdev_devmem_find(sc, vdo.segid);
16827c8c0b82SPatrick Mooney if (de != NULL) {
16837c8c0b82SPatrick Mooney vdo.offset = de->vde_off;
16847c8c0b82SPatrick Mooney if (ddi_copyout(&vdo, datap, sizeof (vdo), md) != 0) {
16857c8c0b82SPatrick Mooney error = EFAULT;
16867c8c0b82SPatrick Mooney }
16877c8c0b82SPatrick Mooney } else {
16887c8c0b82SPatrick Mooney error = ENOENT;
16897c8c0b82SPatrick Mooney }
16907c8c0b82SPatrick Mooney break;
16917c8c0b82SPatrick Mooney }
16927c8c0b82SPatrick Mooney case VM_TRACK_DIRTY_PAGES: {
16937c8c0b82SPatrick Mooney const size_t max_track_region_len = 8 * PAGESIZE * 8 * PAGESIZE;
16947c8c0b82SPatrick Mooney struct vmm_dirty_tracker tracker;
16957c8c0b82SPatrick Mooney uint8_t *bitmap;
16967c8c0b82SPatrick Mooney size_t len;
16977c8c0b82SPatrick Mooney
16987c8c0b82SPatrick Mooney if (ddi_copyin(datap, &tracker, sizeof (tracker), md) != 0) {
16997c8c0b82SPatrick Mooney error = EFAULT;
17007c8c0b82SPatrick Mooney break;
17017c8c0b82SPatrick Mooney }
17027c8c0b82SPatrick Mooney if ((tracker.vdt_start_gpa & PAGEOFFSET) != 0) {
17037c8c0b82SPatrick Mooney error = EINVAL;
17047c8c0b82SPatrick Mooney break;
17057c8c0b82SPatrick Mooney }
17067c8c0b82SPatrick Mooney if (tracker.vdt_len == 0) {
17077c8c0b82SPatrick Mooney break;
17087c8c0b82SPatrick Mooney }
17097c8c0b82SPatrick Mooney if ((tracker.vdt_len & PAGEOFFSET) != 0) {
17107c8c0b82SPatrick Mooney error = EINVAL;
17117c8c0b82SPatrick Mooney break;
17127c8c0b82SPatrick Mooney }
17137c8c0b82SPatrick Mooney if (tracker.vdt_len > max_track_region_len) {
17147c8c0b82SPatrick Mooney error = EINVAL;
17157c8c0b82SPatrick Mooney break;
17167c8c0b82SPatrick Mooney }
17177c8c0b82SPatrick Mooney len = roundup(tracker.vdt_len / PAGESIZE, 8) / 8;
17187c8c0b82SPatrick Mooney bitmap = kmem_zalloc(len, KM_SLEEP);
17194ac713daSLuqman Aden error = vm_track_dirty_pages(sc->vmm_vm, tracker.vdt_start_gpa,
17207c8c0b82SPatrick Mooney tracker.vdt_len, bitmap);
17214ac713daSLuqman Aden if (error == 0 &&
17224ac713daSLuqman Aden ddi_copyout(bitmap, tracker.vdt_pfns, len, md) != 0) {
17237c8c0b82SPatrick Mooney error = EFAULT;
17247c8c0b82SPatrick Mooney }
17257c8c0b82SPatrick Mooney kmem_free(bitmap, len);
17267c8c0b82SPatrick Mooney
17277c8c0b82SPatrick Mooney break;
17287c8c0b82SPatrick Mooney }
1729b9b43e84SPatrick Mooney case VM_NPT_OPERATION: {
1730b9b43e84SPatrick Mooney struct vm_npt_operation vno;
1731b9b43e84SPatrick Mooney uint8_t *bitmap = NULL;
1732b9b43e84SPatrick Mooney uint64_t bitmap_size = 0;
1733b9b43e84SPatrick Mooney
1734b9b43e84SPatrick Mooney if (ddi_copyin(datap, &vno, sizeof (vno), md) != 0) {
1735b9b43e84SPatrick Mooney error = EFAULT;
1736b9b43e84SPatrick Mooney break;
1737b9b43e84SPatrick Mooney }
1738b9b43e84SPatrick Mooney if ((vno.vno_gpa & PAGEOFFSET) != 0 ||
1739b9b43e84SPatrick Mooney (vno.vno_len & PAGEOFFSET) != 0) {
1740b9b43e84SPatrick Mooney error = EINVAL;
1741b9b43e84SPatrick Mooney break;
1742b9b43e84SPatrick Mooney }
1743b9b43e84SPatrick Mooney if ((UINT64_MAX - vno.vno_len) < vno.vno_gpa) {
1744b9b43e84SPatrick Mooney error = EOVERFLOW;
1745b9b43e84SPatrick Mooney break;
1746b9b43e84SPatrick Mooney }
1747b9b43e84SPatrick Mooney
1748b9b43e84SPatrick Mooney /*
1749b9b43e84SPatrick Mooney * Allocate a bitmap for the operation if it is specified as
1750b9b43e84SPatrick Mooney * part of the input or output.
1751b9b43e84SPatrick Mooney */
1752b9b43e84SPatrick Mooney if ((vno.vno_operation &
1753b9b43e84SPatrick Mooney (VNO_FLAG_BITMAP_IN | VNO_FLAG_BITMAP_OUT)) != 0) {
1754b9b43e84SPatrick Mooney /*
1755b9b43e84SPatrick Mooney * Operations expecting data to be copied in or out
1756b9b43e84SPatrick Mooney * should not have zero length.
1757b9b43e84SPatrick Mooney */
1758b9b43e84SPatrick Mooney if (vno.vno_len == 0) {
1759b9b43e84SPatrick Mooney error = EINVAL;
1760b9b43e84SPatrick Mooney break;
1761b9b43e84SPatrick Mooney }
1762b9b43e84SPatrick Mooney
1763b9b43e84SPatrick Mooney /*
1764b9b43e84SPatrick Mooney * Maximum bitmap size of 8 pages results in 1 GiB of
1765b9b43e84SPatrick Mooney * coverage.
1766b9b43e84SPatrick Mooney */
1767b9b43e84SPatrick Mooney const uint64_t max_bitmap_size = 8 * PAGESIZE;
1768b9b43e84SPatrick Mooney
1769b9b43e84SPatrick Mooney bitmap_size = roundup(vno.vno_len / PAGESIZE, 8) / 8;
1770b9b43e84SPatrick Mooney if (bitmap_size > max_bitmap_size) {
1771b9b43e84SPatrick Mooney error = E2BIG;
1772b9b43e84SPatrick Mooney break;
1773b9b43e84SPatrick Mooney }
1774b9b43e84SPatrick Mooney bitmap = kmem_zalloc(bitmap_size, KM_SLEEP);
1775b9b43e84SPatrick Mooney }
1776b9b43e84SPatrick Mooney
1777b9b43e84SPatrick Mooney if ((vno.vno_operation & VNO_FLAG_BITMAP_IN) != 0) {
1778b9b43e84SPatrick Mooney ASSERT(bitmap != NULL);
1779b9b43e84SPatrick Mooney if (ddi_copyin(vno.vno_bitmap, bitmap, bitmap_size,
1780b9b43e84SPatrick Mooney md) != 0) {
1781b9b43e84SPatrick Mooney error = EFAULT;
1782b9b43e84SPatrick Mooney }
1783b9b43e84SPatrick Mooney }
1784b9b43e84SPatrick Mooney
1785b9b43e84SPatrick Mooney if (error == 0) {
1786b9b43e84SPatrick Mooney error = vm_npt_do_operation(sc->vmm_vm, vno.vno_gpa,
1787b9b43e84SPatrick Mooney vno.vno_len, vno.vno_operation, bitmap, rvalp);
1788b9b43e84SPatrick Mooney }
1789b9b43e84SPatrick Mooney
1790b9b43e84SPatrick Mooney if ((vno.vno_operation & VNO_FLAG_BITMAP_OUT) != 0 &&
1791b9b43e84SPatrick Mooney error == 0) {
1792b9b43e84SPatrick Mooney ASSERT(bitmap != NULL);
1793b9b43e84SPatrick Mooney if (ddi_copyout(bitmap, vno.vno_bitmap, bitmap_size,
1794b9b43e84SPatrick Mooney md) != 0) {
1795b9b43e84SPatrick Mooney error = EFAULT;
1796b9b43e84SPatrick Mooney }
1797b9b43e84SPatrick Mooney }
1798b9b43e84SPatrick Mooney
1799b9b43e84SPatrick Mooney if (bitmap != NULL) {
1800b9b43e84SPatrick Mooney kmem_free(bitmap, bitmap_size);
1801b9b43e84SPatrick Mooney }
1802b9b43e84SPatrick Mooney
1803b9b43e84SPatrick Mooney break;
1804b9b43e84SPatrick Mooney }
18057c8c0b82SPatrick Mooney case VM_WRLOCK_CYCLE: {
18067c8c0b82SPatrick Mooney /*
18077c8c0b82SPatrick Mooney * Present a test mechanism to acquire/release the write lock
18087c8c0b82SPatrick Mooney * on the VM without any other effects.
18097c8c0b82SPatrick Mooney */
18107c8c0b82SPatrick Mooney break;
18117c8c0b82SPatrick Mooney }
1812d515dd77SPatrick Mooney case VM_DATA_READ: {
1813d515dd77SPatrick Mooney struct vm_data_xfer vdx;
1814d515dd77SPatrick Mooney
1815d515dd77SPatrick Mooney if (ddi_copyin(datap, &vdx, sizeof (vdx), md) != 0) {
1816d515dd77SPatrick Mooney error = EFAULT;
1817d515dd77SPatrick Mooney break;
1818d515dd77SPatrick Mooney }
1819d515dd77SPatrick Mooney if ((vdx.vdx_flags & ~VDX_FLAGS_VALID) != 0) {
1820d515dd77SPatrick Mooney error = EINVAL;
1821d515dd77SPatrick Mooney break;
1822d515dd77SPatrick Mooney }
1823d515dd77SPatrick Mooney if (vdx.vdx_len > VM_DATA_XFER_LIMIT) {
1824d515dd77SPatrick Mooney error = EFBIG;
1825d515dd77SPatrick Mooney break;
1826d515dd77SPatrick Mooney }
1827d515dd77SPatrick Mooney
1828d515dd77SPatrick Mooney const size_t len = vdx.vdx_len;
182954cf5b63SPatrick Mooney void *buf = NULL;
183054cf5b63SPatrick Mooney if (len != 0) {
1831ad4335f7SPatrick Mooney const void *udata = vdx.vdx_data;
1832ad4335f7SPatrick Mooney
183354cf5b63SPatrick Mooney buf = kmem_alloc(len, KM_SLEEP);
1834ad4335f7SPatrick Mooney if ((vdx.vdx_flags & VDX_FLAG_READ_COPYIN) == 0) {
1835ad4335f7SPatrick Mooney bzero(buf, len);
1836ad4335f7SPatrick Mooney } else if (ddi_copyin(udata, buf, len, md) != 0) {
1837d515dd77SPatrick Mooney kmem_free(buf, len);
1838d515dd77SPatrick Mooney error = EFAULT;
1839d515dd77SPatrick Mooney break;
1840d515dd77SPatrick Mooney }
184154cf5b63SPatrick Mooney }
1842d515dd77SPatrick Mooney
184354cf5b63SPatrick Mooney vdx.vdx_result_len = 0;
1844d515dd77SPatrick Mooney vmm_data_req_t req = {
1845d515dd77SPatrick Mooney .vdr_class = vdx.vdx_class,
1846d515dd77SPatrick Mooney .vdr_version = vdx.vdx_version,
1847d515dd77SPatrick Mooney .vdr_flags = vdx.vdx_flags,
184854cf5b63SPatrick Mooney .vdr_len = len,
1849d515dd77SPatrick Mooney .vdr_data = buf,
185054cf5b63SPatrick Mooney .vdr_result_len = &vdx.vdx_result_len,
1851*4bd36be4SPatrick Mooney .vdr_vcpuid = vdx.vdx_vcpuid,
1852d515dd77SPatrick Mooney };
1853*4bd36be4SPatrick Mooney error = vmm_data_read(sc->vmm_vm, &req);
1854d515dd77SPatrick Mooney
185554cf5b63SPatrick Mooney if (error == 0 && buf != NULL) {
1856d515dd77SPatrick Mooney if (ddi_copyout(buf, vdx.vdx_data, len, md) != 0) {
1857d515dd77SPatrick Mooney error = EFAULT;
1858d515dd77SPatrick Mooney }
1859d515dd77SPatrick Mooney }
186054cf5b63SPatrick Mooney
186154cf5b63SPatrick Mooney /*
186254cf5b63SPatrick Mooney * Copy out the transfer request so that the value of
186354cf5b63SPatrick Mooney * vdx_result_len can be made available, regardless of any
186454cf5b63SPatrick Mooney * error(s) which may have occurred.
186554cf5b63SPatrick Mooney */
186654cf5b63SPatrick Mooney if (ddi_copyout(&vdx, datap, sizeof (vdx), md) != 0) {
186754cf5b63SPatrick Mooney error = (error != 0) ? error : EFAULT;
186854cf5b63SPatrick Mooney }
186954cf5b63SPatrick Mooney
187054cf5b63SPatrick Mooney if (buf != NULL) {
1871d515dd77SPatrick Mooney kmem_free(buf, len);
187254cf5b63SPatrick Mooney }
1873d515dd77SPatrick Mooney break;
1874d515dd77SPatrick Mooney }
1875d515dd77SPatrick Mooney case VM_DATA_WRITE: {
1876d515dd77SPatrick Mooney struct vm_data_xfer vdx;
1877d515dd77SPatrick Mooney
1878d515dd77SPatrick Mooney if (ddi_copyin(datap, &vdx, sizeof (vdx), md) != 0) {
1879d515dd77SPatrick Mooney error = EFAULT;
1880d515dd77SPatrick Mooney break;
1881d515dd77SPatrick Mooney }
1882d515dd77SPatrick Mooney if ((vdx.vdx_flags & ~VDX_FLAGS_VALID) != 0) {
1883d515dd77SPatrick Mooney error = EINVAL;
1884d515dd77SPatrick Mooney break;
1885d515dd77SPatrick Mooney }
1886d515dd77SPatrick Mooney if (vdx.vdx_len > VM_DATA_XFER_LIMIT) {
1887d515dd77SPatrick Mooney error = EFBIG;
1888d515dd77SPatrick Mooney break;
1889d515dd77SPatrick Mooney }
1890d515dd77SPatrick Mooney
1891d515dd77SPatrick Mooney const size_t len = vdx.vdx_len;
189254cf5b63SPatrick Mooney void *buf = NULL;
189354cf5b63SPatrick Mooney if (len != 0) {
189454cf5b63SPatrick Mooney buf = kmem_alloc(len, KM_SLEEP);
1895d515dd77SPatrick Mooney if (ddi_copyin(vdx.vdx_data, buf, len, md) != 0) {
1896d515dd77SPatrick Mooney kmem_free(buf, len);
1897d515dd77SPatrick Mooney error = EFAULT;
1898d515dd77SPatrick Mooney break;
1899d515dd77SPatrick Mooney }
190054cf5b63SPatrick Mooney }
1901d515dd77SPatrick Mooney
190254cf5b63SPatrick Mooney vdx.vdx_result_len = 0;
1903d515dd77SPatrick Mooney vmm_data_req_t req = {
1904d515dd77SPatrick Mooney .vdr_class = vdx.vdx_class,
1905d515dd77SPatrick Mooney .vdr_version = vdx.vdx_version,
1906d515dd77SPatrick Mooney .vdr_flags = vdx.vdx_flags,
190754cf5b63SPatrick Mooney .vdr_len = len,
1908d515dd77SPatrick Mooney .vdr_data = buf,
190954cf5b63SPatrick Mooney .vdr_result_len = &vdx.vdx_result_len,
1910*4bd36be4SPatrick Mooney .vdr_vcpuid = vdx.vdx_vcpuid,
1911d515dd77SPatrick Mooney };
19121ab0d30fSPatrick Mooney if (vmm_allow_state_writes != 0) {
1913*4bd36be4SPatrick Mooney error = vmm_data_write(sc->vmm_vm, &req);
19141ab0d30fSPatrick Mooney } else {
19151ab0d30fSPatrick Mooney /*
19161ab0d30fSPatrick Mooney * Reject the write if somone has thrown the switch back
19171ab0d30fSPatrick Mooney * into the "disallow" position.
19181ab0d30fSPatrick Mooney */
19191ab0d30fSPatrick Mooney error = EPERM;
1920d515dd77SPatrick Mooney }
1921d515dd77SPatrick Mooney
192254cf5b63SPatrick Mooney if (error == 0 && buf != NULL &&
1923d515dd77SPatrick Mooney (vdx.vdx_flags & VDX_FLAG_WRITE_COPYOUT) != 0) {
1924d515dd77SPatrick Mooney if (ddi_copyout(buf, vdx.vdx_data, len, md) != 0) {
1925d515dd77SPatrick Mooney error = EFAULT;
1926d515dd77SPatrick Mooney }
1927d515dd77SPatrick Mooney }
192854cf5b63SPatrick Mooney
192954cf5b63SPatrick Mooney /*
193054cf5b63SPatrick Mooney * Copy out the transfer request so that the value of
193154cf5b63SPatrick Mooney * vdx_result_len can be made available, regardless of any
193254cf5b63SPatrick Mooney * error(s) which may have occurred.
193354cf5b63SPatrick Mooney */
193454cf5b63SPatrick Mooney if (ddi_copyout(&vdx, datap, sizeof (vdx), md) != 0) {
193554cf5b63SPatrick Mooney error = (error != 0) ? error : EFAULT;
193654cf5b63SPatrick Mooney }
193754cf5b63SPatrick Mooney
193854cf5b63SPatrick Mooney if (buf != NULL) {
1939d515dd77SPatrick Mooney kmem_free(buf, len);
194054cf5b63SPatrick Mooney }
1941d515dd77SPatrick Mooney break;
1942d515dd77SPatrick Mooney }
19437c8c0b82SPatrick Mooney
19442cac0506SPatrick Mooney case VM_PAUSE: {
19452cac0506SPatrick Mooney error = vm_pause_instance(sc->vmm_vm);
19462cac0506SPatrick Mooney break;
19472cac0506SPatrick Mooney }
19482cac0506SPatrick Mooney case VM_RESUME: {
19492cac0506SPatrick Mooney error = vm_resume_instance(sc->vmm_vm);
19502cac0506SPatrick Mooney break;
19512cac0506SPatrick Mooney }
19522cac0506SPatrick Mooney
19537c8c0b82SPatrick Mooney default:
19547c8c0b82SPatrick Mooney error = ENOTTY;
19557c8c0b82SPatrick Mooney break;
19567c8c0b82SPatrick Mooney }
19577c8c0b82SPatrick Mooney
19587c8c0b82SPatrick Mooney /* Release exclusion resources */
19597c8c0b82SPatrick Mooney switch (lock_type) {
19607c8c0b82SPatrick Mooney case LOCK_NONE:
19617c8c0b82SPatrick Mooney break;
19627c8c0b82SPatrick Mooney case LOCK_VCPU:
19637c8c0b82SPatrick Mooney vcpu_unlock_one(sc, vcpu);
19647c8c0b82SPatrick Mooney break;
19657c8c0b82SPatrick Mooney case LOCK_READ_HOLD:
19667c8c0b82SPatrick Mooney vmm_read_unlock(sc);
19677c8c0b82SPatrick Mooney break;
19687c8c0b82SPatrick Mooney case LOCK_WRITE_HOLD:
19697c8c0b82SPatrick Mooney vmm_write_unlock(sc);
19707c8c0b82SPatrick Mooney break;
19717c8c0b82SPatrick Mooney default:
19727c8c0b82SPatrick Mooney panic("unexpected lock type");
19737c8c0b82SPatrick Mooney break;
19747c8c0b82SPatrick Mooney }
19757c8c0b82SPatrick Mooney
19767c8c0b82SPatrick Mooney return (error);
19777c8c0b82SPatrick Mooney }
19787c8c0b82SPatrick Mooney
19797c8c0b82SPatrick Mooney static vmm_softc_t *
vmm_lookup(const char * name)19807c8c0b82SPatrick Mooney vmm_lookup(const char *name)
19817c8c0b82SPatrick Mooney {
19827c8c0b82SPatrick Mooney list_t *vml = &vmm_list;
19837c8c0b82SPatrick Mooney vmm_softc_t *sc;
19847c8c0b82SPatrick Mooney
19857c8c0b82SPatrick Mooney ASSERT(MUTEX_HELD(&vmm_mtx));
19867c8c0b82SPatrick Mooney
19877c8c0b82SPatrick Mooney for (sc = list_head(vml); sc != NULL; sc = list_next(vml, sc)) {
19887c8c0b82SPatrick Mooney if (strcmp(sc->vmm_name, name) == 0) {
19897c8c0b82SPatrick Mooney break;
19907c8c0b82SPatrick Mooney }
19917c8c0b82SPatrick Mooney }
19927c8c0b82SPatrick Mooney
19937c8c0b82SPatrick Mooney return (sc);
19947c8c0b82SPatrick Mooney }
19957c8c0b82SPatrick Mooney
19967c8c0b82SPatrick Mooney /*
19977c8c0b82SPatrick Mooney * Acquire an HMA registration if not already held.
19987c8c0b82SPatrick Mooney */
19997c8c0b82SPatrick Mooney static boolean_t
vmm_hma_acquire(void)20007c8c0b82SPatrick Mooney vmm_hma_acquire(void)
20017c8c0b82SPatrick Mooney {
20027c8c0b82SPatrick Mooney ASSERT(MUTEX_NOT_HELD(&vmm_mtx));
20037c8c0b82SPatrick Mooney
20047c8c0b82SPatrick Mooney mutex_enter(&vmmdev_mtx);
20057c8c0b82SPatrick Mooney
20067c8c0b82SPatrick Mooney if (vmmdev_hma_reg == NULL) {
20077c8c0b82SPatrick Mooney VERIFY3U(vmmdev_hma_ref, ==, 0);
20087c8c0b82SPatrick Mooney vmmdev_hma_reg = hma_register(vmmdev_hvm_name);
20097c8c0b82SPatrick Mooney if (vmmdev_hma_reg == NULL) {
20107c8c0b82SPatrick Mooney cmn_err(CE_WARN, "%s HMA registration failed.",
20117c8c0b82SPatrick Mooney vmmdev_hvm_name);
20127c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
20137c8c0b82SPatrick Mooney return (B_FALSE);
20147c8c0b82SPatrick Mooney }
20157c8c0b82SPatrick Mooney }
20167c8c0b82SPatrick Mooney
20177c8c0b82SPatrick Mooney vmmdev_hma_ref++;
20187c8c0b82SPatrick Mooney
20197c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
20207c8c0b82SPatrick Mooney
20217c8c0b82SPatrick Mooney return (B_TRUE);
20227c8c0b82SPatrick Mooney }
20237c8c0b82SPatrick Mooney
20247c8c0b82SPatrick Mooney /*
20257c8c0b82SPatrick Mooney * Release the HMA registration if held and there are no remaining VMs.
20267c8c0b82SPatrick Mooney */
20277c8c0b82SPatrick Mooney static void
vmm_hma_release(void)20287c8c0b82SPatrick Mooney vmm_hma_release(void)
20297c8c0b82SPatrick Mooney {
20307c8c0b82SPatrick Mooney ASSERT(MUTEX_NOT_HELD(&vmm_mtx));
20317c8c0b82SPatrick Mooney
20327c8c0b82SPatrick Mooney mutex_enter(&vmmdev_mtx);
20337c8c0b82SPatrick Mooney
20347c8c0b82SPatrick Mooney VERIFY3U(vmmdev_hma_ref, !=, 0);
20357c8c0b82SPatrick Mooney
20367c8c0b82SPatrick Mooney vmmdev_hma_ref--;
20377c8c0b82SPatrick Mooney
20387c8c0b82SPatrick Mooney if (vmmdev_hma_ref == 0) {
20397c8c0b82SPatrick Mooney VERIFY(vmmdev_hma_reg != NULL);
20407c8c0b82SPatrick Mooney hma_unregister(vmmdev_hma_reg);
20417c8c0b82SPatrick Mooney vmmdev_hma_reg = NULL;
20427c8c0b82SPatrick Mooney }
20437c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
20447c8c0b82SPatrick Mooney }
20457c8c0b82SPatrick Mooney
20467c8c0b82SPatrick Mooney static int
vmmdev_do_vm_create(const struct vm_create_req * req,cred_t * cr)20477c8c0b82SPatrick Mooney vmmdev_do_vm_create(const struct vm_create_req *req, cred_t *cr)
20487c8c0b82SPatrick Mooney {
20497c8c0b82SPatrick Mooney vmm_softc_t *sc = NULL;
20507c8c0b82SPatrick Mooney minor_t minor;
20517c8c0b82SPatrick Mooney int error = ENOMEM;
20527c8c0b82SPatrick Mooney size_t len;
20537c8c0b82SPatrick Mooney const char *name = req->name;
20547c8c0b82SPatrick Mooney
20557c8c0b82SPatrick Mooney len = strnlen(name, VM_MAX_NAMELEN);
20567c8c0b82SPatrick Mooney if (len == 0) {
20577c8c0b82SPatrick Mooney return (EINVAL);
20587c8c0b82SPatrick Mooney }
20597c8c0b82SPatrick Mooney if (len >= VM_MAX_NAMELEN) {
20607c8c0b82SPatrick Mooney return (ENAMETOOLONG);
20617c8c0b82SPatrick Mooney }
20627c8c0b82SPatrick Mooney if (strchr(name, '/') != NULL) {
20637c8c0b82SPatrick Mooney return (EINVAL);
20647c8c0b82SPatrick Mooney }
20657c8c0b82SPatrick Mooney
20667c8c0b82SPatrick Mooney if (!vmm_hma_acquire())
20677c8c0b82SPatrick Mooney return (ENXIO);
20687c8c0b82SPatrick Mooney
20697c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
20707c8c0b82SPatrick Mooney
20717c8c0b82SPatrick Mooney /* Look for duplicate names */
20727c8c0b82SPatrick Mooney if (vmm_lookup(name) != NULL) {
20737c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
20747c8c0b82SPatrick Mooney vmm_hma_release();
20757c8c0b82SPatrick Mooney return (EEXIST);
20767c8c0b82SPatrick Mooney }
20777c8c0b82SPatrick Mooney
20787c8c0b82SPatrick Mooney /* Allow only one instance per non-global zone. */
20797c8c0b82SPatrick Mooney if (!INGLOBALZONE(curproc)) {
20807c8c0b82SPatrick Mooney for (sc = list_head(&vmm_list); sc != NULL;
20817c8c0b82SPatrick Mooney sc = list_next(&vmm_list, sc)) {
20827c8c0b82SPatrick Mooney if (sc->vmm_zone == curzone) {
20837c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
20847c8c0b82SPatrick Mooney vmm_hma_release();
20857c8c0b82SPatrick Mooney return (EINVAL);
20867c8c0b82SPatrick Mooney }
20877c8c0b82SPatrick Mooney }
20887c8c0b82SPatrick Mooney }
20897c8c0b82SPatrick Mooney
20907c8c0b82SPatrick Mooney minor = id_alloc(vmm_minors);
20917c8c0b82SPatrick Mooney if (ddi_soft_state_zalloc(vmm_statep, minor) != DDI_SUCCESS) {
20927c8c0b82SPatrick Mooney goto fail;
20937c8c0b82SPatrick Mooney } else if ((sc = ddi_get_soft_state(vmm_statep, minor)) == NULL) {
20947c8c0b82SPatrick Mooney ddi_soft_state_free(vmm_statep, minor);
20957c8c0b82SPatrick Mooney goto fail;
20967c8c0b82SPatrick Mooney } else if (ddi_create_minor_node(vmmdev_dip, name, S_IFCHR, minor,
20977c8c0b82SPatrick Mooney DDI_PSEUDO, 0) != DDI_SUCCESS) {
20987c8c0b82SPatrick Mooney goto fail;
20997c8c0b82SPatrick Mooney }
21007c8c0b82SPatrick Mooney
21017c8c0b82SPatrick Mooney if (vmm_kstat_alloc(sc, minor, cr) != 0) {
21027c8c0b82SPatrick Mooney goto fail;
21037c8c0b82SPatrick Mooney }
21047c8c0b82SPatrick Mooney
2105d4f59ae5SPatrick Mooney error = vm_create(req->flags, &sc->vmm_vm);
21067c8c0b82SPatrick Mooney if (error == 0) {
21077c8c0b82SPatrick Mooney /* Complete VM intialization and report success. */
21087c8c0b82SPatrick Mooney (void) strlcpy(sc->vmm_name, name, sizeof (sc->vmm_name));
21097c8c0b82SPatrick Mooney sc->vmm_minor = minor;
21107c8c0b82SPatrick Mooney list_create(&sc->vmm_devmem_list, sizeof (vmm_devmem_entry_t),
21117c8c0b82SPatrick Mooney offsetof(vmm_devmem_entry_t, vde_node));
21127c8c0b82SPatrick Mooney
21137c8c0b82SPatrick Mooney list_create(&sc->vmm_holds, sizeof (vmm_hold_t),
21147c8c0b82SPatrick Mooney offsetof(vmm_hold_t, vmh_node));
21157c8c0b82SPatrick Mooney cv_init(&sc->vmm_cv, NULL, CV_DEFAULT, NULL);
21167c8c0b82SPatrick Mooney
21177c8c0b82SPatrick Mooney mutex_init(&sc->vmm_lease_lock, NULL, MUTEX_DEFAULT, NULL);
21187c8c0b82SPatrick Mooney list_create(&sc->vmm_lease_list, sizeof (vmm_lease_t),
21197c8c0b82SPatrick Mooney offsetof(vmm_lease_t, vml_node));
21207c8c0b82SPatrick Mooney cv_init(&sc->vmm_lease_cv, NULL, CV_DEFAULT, NULL);
21217c8c0b82SPatrick Mooney rw_init(&sc->vmm_rwlock, NULL, RW_DEFAULT, NULL);
21227c8c0b82SPatrick Mooney
21237c8c0b82SPatrick Mooney sc->vmm_zone = crgetzone(cr);
21247c8c0b82SPatrick Mooney zone_hold(sc->vmm_zone);
21257c8c0b82SPatrick Mooney vmm_zsd_add_vm(sc);
21267c8c0b82SPatrick Mooney vmm_kstat_init(sc);
21277c8c0b82SPatrick Mooney
21287c8c0b82SPatrick Mooney list_insert_tail(&vmm_list, sc);
21297c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
21307c8c0b82SPatrick Mooney return (0);
21317c8c0b82SPatrick Mooney }
21327c8c0b82SPatrick Mooney
21337c8c0b82SPatrick Mooney vmm_kstat_fini(sc);
21347c8c0b82SPatrick Mooney ddi_remove_minor_node(vmmdev_dip, name);
21357c8c0b82SPatrick Mooney fail:
21367c8c0b82SPatrick Mooney id_free(vmm_minors, minor);
21377c8c0b82SPatrick Mooney if (sc != NULL) {
21387c8c0b82SPatrick Mooney ddi_soft_state_free(vmm_statep, minor);
21397c8c0b82SPatrick Mooney }
21407c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
21417c8c0b82SPatrick Mooney vmm_hma_release();
21427c8c0b82SPatrick Mooney
21437c8c0b82SPatrick Mooney return (error);
21447c8c0b82SPatrick Mooney }
21457c8c0b82SPatrick Mooney
21467c8c0b82SPatrick Mooney /*
21477c8c0b82SPatrick Mooney * Bhyve 'Driver' Interface
21487c8c0b82SPatrick Mooney *
21497c8c0b82SPatrick Mooney * While many devices are emulated in the bhyve userspace process, there are
21507c8c0b82SPatrick Mooney * others with performance constraints which require that they run mostly or
21517c8c0b82SPatrick Mooney * entirely in-kernel. For those not integrated directly into bhyve, an API is
21527c8c0b82SPatrick Mooney * needed so they can query/manipulate the portions of VM state needed to
21537c8c0b82SPatrick Mooney * fulfill their purpose.
21547c8c0b82SPatrick Mooney *
21557c8c0b82SPatrick Mooney * This includes:
21567c8c0b82SPatrick Mooney * - Translating guest-physical addresses to host-virtual pointers
21577c8c0b82SPatrick Mooney * - Injecting MSIs
21587c8c0b82SPatrick Mooney * - Hooking IO port addresses
21597c8c0b82SPatrick Mooney *
21607c8c0b82SPatrick Mooney * The vmm_drv interface exists to provide that functionality to its consumers.
21617c8c0b82SPatrick Mooney * (At this time, 'viona' is the only user)
21627c8c0b82SPatrick Mooney */
21637c8c0b82SPatrick Mooney int
vmm_drv_hold(file_t * fp,cred_t * cr,vmm_hold_t ** holdp)21647c8c0b82SPatrick Mooney vmm_drv_hold(file_t *fp, cred_t *cr, vmm_hold_t **holdp)
21657c8c0b82SPatrick Mooney {
21667c8c0b82SPatrick Mooney vnode_t *vp = fp->f_vnode;
21677c8c0b82SPatrick Mooney const dev_t dev = vp->v_rdev;
21687c8c0b82SPatrick Mooney vmm_softc_t *sc;
21697c8c0b82SPatrick Mooney vmm_hold_t *hold;
21707c8c0b82SPatrick Mooney int err = 0;
21717c8c0b82SPatrick Mooney
21727c8c0b82SPatrick Mooney if (vp->v_type != VCHR) {
21737c8c0b82SPatrick Mooney return (ENXIO);
21747c8c0b82SPatrick Mooney }
21757c8c0b82SPatrick Mooney const major_t major = getmajor(dev);
21767c8c0b82SPatrick Mooney const minor_t minor = getminor(dev);
21777c8c0b82SPatrick Mooney
21787c8c0b82SPatrick Mooney mutex_enter(&vmmdev_mtx);
21797c8c0b82SPatrick Mooney if (vmmdev_dip == NULL || major != ddi_driver_major(vmmdev_dip)) {
21807c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
21817c8c0b82SPatrick Mooney return (ENOENT);
21827c8c0b82SPatrick Mooney }
21837c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
21847c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
21857c8c0b82SPatrick Mooney
21867c8c0b82SPatrick Mooney if ((sc = ddi_get_soft_state(vmm_statep, minor)) == NULL) {
21877c8c0b82SPatrick Mooney err = ENOENT;
21887c8c0b82SPatrick Mooney goto out;
21897c8c0b82SPatrick Mooney }
21907c8c0b82SPatrick Mooney /* XXXJOY: check cred permissions against instance */
21917c8c0b82SPatrick Mooney
219242640e49SPatrick Mooney if ((sc->vmm_flags & VMM_DESTROY) != 0) {
21937c8c0b82SPatrick Mooney err = EBUSY;
21947c8c0b82SPatrick Mooney goto out;
21957c8c0b82SPatrick Mooney }
21967c8c0b82SPatrick Mooney
21977c8c0b82SPatrick Mooney hold = kmem_zalloc(sizeof (*hold), KM_SLEEP);
21987c8c0b82SPatrick Mooney hold->vmh_sc = sc;
21997c8c0b82SPatrick Mooney hold->vmh_release_req = B_FALSE;
22007c8c0b82SPatrick Mooney
22017c8c0b82SPatrick Mooney list_insert_tail(&sc->vmm_holds, hold);
22027c8c0b82SPatrick Mooney sc->vmm_flags |= VMM_HELD;
22037c8c0b82SPatrick Mooney *holdp = hold;
22047c8c0b82SPatrick Mooney
22057c8c0b82SPatrick Mooney out:
22067c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
22077c8c0b82SPatrick Mooney return (err);
22087c8c0b82SPatrick Mooney }
22097c8c0b82SPatrick Mooney
22107c8c0b82SPatrick Mooney void
vmm_drv_rele(vmm_hold_t * hold)22117c8c0b82SPatrick Mooney vmm_drv_rele(vmm_hold_t *hold)
22127c8c0b82SPatrick Mooney {
22137c8c0b82SPatrick Mooney vmm_softc_t *sc;
221442640e49SPatrick Mooney bool hma_release = false;
22157c8c0b82SPatrick Mooney
22167c8c0b82SPatrick Mooney ASSERT(hold != NULL);
22177c8c0b82SPatrick Mooney ASSERT(hold->vmh_sc != NULL);
22187c8c0b82SPatrick Mooney VERIFY(hold->vmh_ioport_hook_cnt == 0);
22197c8c0b82SPatrick Mooney
22207c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
22217c8c0b82SPatrick Mooney sc = hold->vmh_sc;
22227c8c0b82SPatrick Mooney list_remove(&sc->vmm_holds, hold);
222342640e49SPatrick Mooney kmem_free(hold, sizeof (*hold));
222442640e49SPatrick Mooney
22257c8c0b82SPatrick Mooney if (list_is_empty(&sc->vmm_holds)) {
22267c8c0b82SPatrick Mooney sc->vmm_flags &= ~VMM_HELD;
2227aa39f6d0SPatrick Mooney
2228aa39f6d0SPatrick Mooney /*
222942640e49SPatrick Mooney * Since outstanding holds would prevent instance destruction
223042640e49SPatrick Mooney * from completing, attempt to finish it now if it was already
223142640e49SPatrick Mooney * set in motion.
2232aa39f6d0SPatrick Mooney */
223342640e49SPatrick Mooney if ((sc->vmm_flags & VMM_DESTROY) != 0) {
223442640e49SPatrick Mooney VERIFY0(vmm_destroy_locked(sc, VDO_DEFAULT,
223542640e49SPatrick Mooney &hma_release));
2236aa39f6d0SPatrick Mooney }
22377c8c0b82SPatrick Mooney }
22387c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
2239aa39f6d0SPatrick Mooney
2240aa39f6d0SPatrick Mooney if (hma_release) {
2241aa39f6d0SPatrick Mooney vmm_hma_release();
2242aa39f6d0SPatrick Mooney }
22437c8c0b82SPatrick Mooney }
22447c8c0b82SPatrick Mooney
22457c8c0b82SPatrick Mooney boolean_t
vmm_drv_release_reqd(vmm_hold_t * hold)22467c8c0b82SPatrick Mooney vmm_drv_release_reqd(vmm_hold_t *hold)
22477c8c0b82SPatrick Mooney {
22487c8c0b82SPatrick Mooney ASSERT(hold != NULL);
22497c8c0b82SPatrick Mooney
22507c8c0b82SPatrick Mooney return (hold->vmh_release_req);
22517c8c0b82SPatrick Mooney }
22527c8c0b82SPatrick Mooney
22537c8c0b82SPatrick Mooney vmm_lease_t *
vmm_drv_lease_sign(vmm_hold_t * hold,boolean_t (* expiref)(void *),void * arg)22547c8c0b82SPatrick Mooney vmm_drv_lease_sign(vmm_hold_t *hold, boolean_t (*expiref)(void *), void *arg)
22557c8c0b82SPatrick Mooney {
22567c8c0b82SPatrick Mooney vmm_softc_t *sc = hold->vmh_sc;
22577c8c0b82SPatrick Mooney vmm_lease_t *lease;
22587c8c0b82SPatrick Mooney
22597c8c0b82SPatrick Mooney ASSERT3P(expiref, !=, NULL);
22607c8c0b82SPatrick Mooney
22617c8c0b82SPatrick Mooney if (hold->vmh_release_req) {
22627c8c0b82SPatrick Mooney return (NULL);
22637c8c0b82SPatrick Mooney }
22647c8c0b82SPatrick Mooney
22657c8c0b82SPatrick Mooney lease = kmem_alloc(sizeof (*lease), KM_SLEEP);
22667c8c0b82SPatrick Mooney list_link_init(&lease->vml_node);
22677c8c0b82SPatrick Mooney lease->vml_expire_func = expiref;
22687c8c0b82SPatrick Mooney lease->vml_expire_arg = arg;
22697c8c0b82SPatrick Mooney lease->vml_expired = B_FALSE;
22707c8c0b82SPatrick Mooney lease->vml_break_deferred = B_FALSE;
22717c8c0b82SPatrick Mooney lease->vml_hold = hold;
22727c8c0b82SPatrick Mooney /* cache the VM pointer for one less pointer chase */
22737c8c0b82SPatrick Mooney lease->vml_vm = sc->vmm_vm;
22747c8c0b82SPatrick Mooney lease->vml_vmclient = vmspace_client_alloc(vm_get_vmspace(sc->vmm_vm));
22757c8c0b82SPatrick Mooney
22767c8c0b82SPatrick Mooney mutex_enter(&sc->vmm_lease_lock);
22777c8c0b82SPatrick Mooney while (sc->vmm_lease_blocker != 0) {
22787c8c0b82SPatrick Mooney cv_wait(&sc->vmm_lease_cv, &sc->vmm_lease_lock);
22797c8c0b82SPatrick Mooney }
22807c8c0b82SPatrick Mooney list_insert_tail(&sc->vmm_lease_list, lease);
22817c8c0b82SPatrick Mooney vmm_read_lock(sc);
22827c8c0b82SPatrick Mooney mutex_exit(&sc->vmm_lease_lock);
22837c8c0b82SPatrick Mooney
22847c8c0b82SPatrick Mooney return (lease);
22857c8c0b82SPatrick Mooney }
22867c8c0b82SPatrick Mooney
22877c8c0b82SPatrick Mooney static void
vmm_lease_break_locked(vmm_softc_t * sc,vmm_lease_t * lease)22887c8c0b82SPatrick Mooney vmm_lease_break_locked(vmm_softc_t *sc, vmm_lease_t *lease)
22897c8c0b82SPatrick Mooney {
22907c8c0b82SPatrick Mooney ASSERT(MUTEX_HELD(&sc->vmm_lease_lock));
22917c8c0b82SPatrick Mooney
22927c8c0b82SPatrick Mooney list_remove(&sc->vmm_lease_list, lease);
22937c8c0b82SPatrick Mooney vmm_read_unlock(sc);
22947c8c0b82SPatrick Mooney vmc_destroy(lease->vml_vmclient);
22957c8c0b82SPatrick Mooney kmem_free(lease, sizeof (*lease));
22967c8c0b82SPatrick Mooney }
22977c8c0b82SPatrick Mooney
22987c8c0b82SPatrick Mooney static void
vmm_lease_block(vmm_softc_t * sc)22997c8c0b82SPatrick Mooney vmm_lease_block(vmm_softc_t *sc)
23007c8c0b82SPatrick Mooney {
23017c8c0b82SPatrick Mooney mutex_enter(&sc->vmm_lease_lock);
23027c8c0b82SPatrick Mooney VERIFY3U(sc->vmm_lease_blocker, !=, UINT_MAX);
23037c8c0b82SPatrick Mooney sc->vmm_lease_blocker++;
23047c8c0b82SPatrick Mooney if (sc->vmm_lease_blocker == 1) {
23057c8c0b82SPatrick Mooney list_t *list = &sc->vmm_lease_list;
23067c8c0b82SPatrick Mooney vmm_lease_t *lease = list_head(list);
23077c8c0b82SPatrick Mooney
23087c8c0b82SPatrick Mooney while (lease != NULL) {
23097c8c0b82SPatrick Mooney void *arg = lease->vml_expire_arg;
23107c8c0b82SPatrick Mooney boolean_t (*expiref)(void *) = lease->vml_expire_func;
23117c8c0b82SPatrick Mooney boolean_t sync_break = B_FALSE;
23127c8c0b82SPatrick Mooney
23137c8c0b82SPatrick Mooney /*
23147c8c0b82SPatrick Mooney * Since the lease expiration notification may
23157c8c0b82SPatrick Mooney * need to take locks which would deadlock with
23167c8c0b82SPatrick Mooney * vmm_lease_lock, drop it across the call.
23177c8c0b82SPatrick Mooney *
23187c8c0b82SPatrick Mooney * We are the only one allowed to manipulate
23197c8c0b82SPatrick Mooney * vmm_lease_list right now, so it is safe to
23207c8c0b82SPatrick Mooney * continue iterating through it after
23217c8c0b82SPatrick Mooney * reacquiring the lock.
23227c8c0b82SPatrick Mooney */
23237c8c0b82SPatrick Mooney lease->vml_expired = B_TRUE;
23247c8c0b82SPatrick Mooney mutex_exit(&sc->vmm_lease_lock);
23257c8c0b82SPatrick Mooney sync_break = expiref(arg);
23267c8c0b82SPatrick Mooney mutex_enter(&sc->vmm_lease_lock);
23277c8c0b82SPatrick Mooney
23287c8c0b82SPatrick Mooney if (sync_break) {
23297c8c0b82SPatrick Mooney vmm_lease_t *next;
23307c8c0b82SPatrick Mooney
23317c8c0b82SPatrick Mooney /*
23327c8c0b82SPatrick Mooney * These leases which are synchronously broken
23337c8c0b82SPatrick Mooney * result in vmm_read_unlock() calls from a
23347c8c0b82SPatrick Mooney * different thread than the corresponding
23357c8c0b82SPatrick Mooney * vmm_read_lock(). This is acceptable, given
23367c8c0b82SPatrick Mooney * that the rwlock underpinning the whole
23377c8c0b82SPatrick Mooney * mechanism tolerates the behavior. This
23387c8c0b82SPatrick Mooney * flexibility is _only_ afforded to VM read
23397c8c0b82SPatrick Mooney * lock (RW_READER) holders.
23407c8c0b82SPatrick Mooney */
23417c8c0b82SPatrick Mooney next = list_next(list, lease);
23427c8c0b82SPatrick Mooney vmm_lease_break_locked(sc, lease);
23437c8c0b82SPatrick Mooney lease = next;
23447c8c0b82SPatrick Mooney } else {
23457c8c0b82SPatrick Mooney lease = list_next(list, lease);
23467c8c0b82SPatrick Mooney }
23477c8c0b82SPatrick Mooney }
23487c8c0b82SPatrick Mooney
23497c8c0b82SPatrick Mooney /* Process leases which were not broken synchronously. */
23507c8c0b82SPatrick Mooney while (!list_is_empty(list)) {
23517c8c0b82SPatrick Mooney /*
23527c8c0b82SPatrick Mooney * Although the nested loops are quadratic, the number
23537c8c0b82SPatrick Mooney * of leases is small.
23547c8c0b82SPatrick Mooney */
23557c8c0b82SPatrick Mooney lease = list_head(list);
23567c8c0b82SPatrick Mooney while (lease != NULL) {
23577c8c0b82SPatrick Mooney vmm_lease_t *next = list_next(list, lease);
23587c8c0b82SPatrick Mooney if (lease->vml_break_deferred) {
23597c8c0b82SPatrick Mooney vmm_lease_break_locked(sc, lease);
23607c8c0b82SPatrick Mooney }
23617c8c0b82SPatrick Mooney lease = next;
23627c8c0b82SPatrick Mooney }
23637c8c0b82SPatrick Mooney if (list_is_empty(list)) {
23647c8c0b82SPatrick Mooney break;
23657c8c0b82SPatrick Mooney }
23667c8c0b82SPatrick Mooney cv_wait(&sc->vmm_lease_cv, &sc->vmm_lease_lock);
23677c8c0b82SPatrick Mooney }
23687c8c0b82SPatrick Mooney /* Wake anyone else waiting for the lease list to be empty */
23697c8c0b82SPatrick Mooney cv_broadcast(&sc->vmm_lease_cv);
23707c8c0b82SPatrick Mooney } else {
23717c8c0b82SPatrick Mooney list_t *list = &sc->vmm_lease_list;
23727c8c0b82SPatrick Mooney
23737c8c0b82SPatrick Mooney /*
23747c8c0b82SPatrick Mooney * Some other thread beat us to the duty of lease cleanup.
23757c8c0b82SPatrick Mooney * Wait until that is complete.
23767c8c0b82SPatrick Mooney */
23777c8c0b82SPatrick Mooney while (!list_is_empty(list)) {
23787c8c0b82SPatrick Mooney cv_wait(&sc->vmm_lease_cv, &sc->vmm_lease_lock);
23797c8c0b82SPatrick Mooney }
23807c8c0b82SPatrick Mooney }
23817c8c0b82SPatrick Mooney mutex_exit(&sc->vmm_lease_lock);
23827c8c0b82SPatrick Mooney }
23837c8c0b82SPatrick Mooney
23847c8c0b82SPatrick Mooney static void
vmm_lease_unblock(vmm_softc_t * sc)23857c8c0b82SPatrick Mooney vmm_lease_unblock(vmm_softc_t *sc)
23867c8c0b82SPatrick Mooney {
23877c8c0b82SPatrick Mooney mutex_enter(&sc->vmm_lease_lock);
23887c8c0b82SPatrick Mooney VERIFY3U(sc->vmm_lease_blocker, !=, 0);
23897c8c0b82SPatrick Mooney sc->vmm_lease_blocker--;
23907c8c0b82SPatrick Mooney if (sc->vmm_lease_blocker == 0) {
23917c8c0b82SPatrick Mooney cv_broadcast(&sc->vmm_lease_cv);
23927c8c0b82SPatrick Mooney }
23937c8c0b82SPatrick Mooney mutex_exit(&sc->vmm_lease_lock);
23947c8c0b82SPatrick Mooney }
23957c8c0b82SPatrick Mooney
23967c8c0b82SPatrick Mooney void
vmm_drv_lease_break(vmm_hold_t * hold,vmm_lease_t * lease)23977c8c0b82SPatrick Mooney vmm_drv_lease_break(vmm_hold_t *hold, vmm_lease_t *lease)
23987c8c0b82SPatrick Mooney {
23997c8c0b82SPatrick Mooney vmm_softc_t *sc = hold->vmh_sc;
24007c8c0b82SPatrick Mooney
24017c8c0b82SPatrick Mooney VERIFY3P(hold, ==, lease->vml_hold);
24027c8c0b82SPatrick Mooney VERIFY(!lease->vml_break_deferred);
24037c8c0b82SPatrick Mooney
24047c8c0b82SPatrick Mooney mutex_enter(&sc->vmm_lease_lock);
24057c8c0b82SPatrick Mooney if (sc->vmm_lease_blocker == 0) {
24067c8c0b82SPatrick Mooney vmm_lease_break_locked(sc, lease);
24077c8c0b82SPatrick Mooney } else {
24087c8c0b82SPatrick Mooney /*
24097c8c0b82SPatrick Mooney * Defer the lease-breaking to whichever thread is currently
24107c8c0b82SPatrick Mooney * cleaning up all leases as part of a vmm_lease_block() call.
24117c8c0b82SPatrick Mooney */
24127c8c0b82SPatrick Mooney lease->vml_break_deferred = B_TRUE;
24137c8c0b82SPatrick Mooney cv_broadcast(&sc->vmm_lease_cv);
24147c8c0b82SPatrick Mooney }
24157c8c0b82SPatrick Mooney mutex_exit(&sc->vmm_lease_lock);
24167c8c0b82SPatrick Mooney }
24177c8c0b82SPatrick Mooney
24187c8c0b82SPatrick Mooney boolean_t
vmm_drv_lease_expired(vmm_lease_t * lease)24197c8c0b82SPatrick Mooney vmm_drv_lease_expired(vmm_lease_t *lease)
24207c8c0b82SPatrick Mooney {
24217c8c0b82SPatrick Mooney return (lease->vml_expired);
24227c8c0b82SPatrick Mooney }
24237c8c0b82SPatrick Mooney
24247c8c0b82SPatrick Mooney vmm_page_t *
vmm_drv_page_hold(vmm_lease_t * lease,uintptr_t gpa,int prot)24257c8c0b82SPatrick Mooney vmm_drv_page_hold(vmm_lease_t *lease, uintptr_t gpa, int prot)
24267c8c0b82SPatrick Mooney {
24277c8c0b82SPatrick Mooney ASSERT(lease != NULL);
24287c8c0b82SPatrick Mooney ASSERT0(gpa & PAGEOFFSET);
24297c8c0b82SPatrick Mooney
24307c8c0b82SPatrick Mooney return ((vmm_page_t *)vmc_hold(lease->vml_vmclient, gpa, prot));
24317c8c0b82SPatrick Mooney }
24327c8c0b82SPatrick Mooney
2433f2357d97SPatrick Mooney
2434f2357d97SPatrick Mooney /* Ensure that flags mirrored by vmm_drv interface properly match up */
2435f2357d97SPatrick Mooney CTASSERT(VMPF_DEFER_DIRTY == VPF_DEFER_DIRTY);
2436f2357d97SPatrick Mooney
2437f2357d97SPatrick Mooney vmm_page_t *
vmm_drv_page_hold_ext(vmm_lease_t * lease,uintptr_t gpa,int prot,int flags)2438f2357d97SPatrick Mooney vmm_drv_page_hold_ext(vmm_lease_t *lease, uintptr_t gpa, int prot, int flags)
2439f2357d97SPatrick Mooney {
2440f2357d97SPatrick Mooney ASSERT(lease != NULL);
2441f2357d97SPatrick Mooney ASSERT0(gpa & PAGEOFFSET);
2442f2357d97SPatrick Mooney
2443f2357d97SPatrick Mooney vmm_page_t *page =
2444f2357d97SPatrick Mooney (vmm_page_t *)vmc_hold_ext(lease->vml_vmclient, gpa, prot, flags);
2445f2357d97SPatrick Mooney return (page);
2446f2357d97SPatrick Mooney }
2447f2357d97SPatrick Mooney
24487c8c0b82SPatrick Mooney void
vmm_drv_page_release(vmm_page_t * vmmp)24497c8c0b82SPatrick Mooney vmm_drv_page_release(vmm_page_t *vmmp)
24507c8c0b82SPatrick Mooney {
2451e0994bd2SPatrick Mooney (void) vmp_release((vm_page_t *)vmmp);
24527c8c0b82SPatrick Mooney }
24537c8c0b82SPatrick Mooney
24547c8c0b82SPatrick Mooney void
vmm_drv_page_release_chain(vmm_page_t * vmmp)24557c8c0b82SPatrick Mooney vmm_drv_page_release_chain(vmm_page_t *vmmp)
24567c8c0b82SPatrick Mooney {
2457e0994bd2SPatrick Mooney (void) vmp_release_chain((vm_page_t *)vmmp);
24587c8c0b82SPatrick Mooney }
24597c8c0b82SPatrick Mooney
24607c8c0b82SPatrick Mooney const void *
vmm_drv_page_readable(const vmm_page_t * vmmp)24617c8c0b82SPatrick Mooney vmm_drv_page_readable(const vmm_page_t *vmmp)
24627c8c0b82SPatrick Mooney {
24637c8c0b82SPatrick Mooney return (vmp_get_readable((const vm_page_t *)vmmp));
24647c8c0b82SPatrick Mooney }
24657c8c0b82SPatrick Mooney
24667c8c0b82SPatrick Mooney void *
vmm_drv_page_writable(const vmm_page_t * vmmp)24677c8c0b82SPatrick Mooney vmm_drv_page_writable(const vmm_page_t *vmmp)
24687c8c0b82SPatrick Mooney {
24697c8c0b82SPatrick Mooney return (vmp_get_writable((const vm_page_t *)vmmp));
24707c8c0b82SPatrick Mooney }
24717c8c0b82SPatrick Mooney
24727c8c0b82SPatrick Mooney void
vmm_drv_page_mark_dirty(vmm_page_t * vmmp)2473f2357d97SPatrick Mooney vmm_drv_page_mark_dirty(vmm_page_t *vmmp)
2474f2357d97SPatrick Mooney {
2475f2357d97SPatrick Mooney return (vmp_mark_dirty((vm_page_t *)vmmp));
2476f2357d97SPatrick Mooney }
2477f2357d97SPatrick Mooney
2478f2357d97SPatrick Mooney void
vmm_drv_page_chain(vmm_page_t * vmmp,vmm_page_t * to_chain)24797c8c0b82SPatrick Mooney vmm_drv_page_chain(vmm_page_t *vmmp, vmm_page_t *to_chain)
24807c8c0b82SPatrick Mooney {
24817c8c0b82SPatrick Mooney vmp_chain((vm_page_t *)vmmp, (vm_page_t *)to_chain);
24827c8c0b82SPatrick Mooney }
24837c8c0b82SPatrick Mooney
24847c8c0b82SPatrick Mooney vmm_page_t *
vmm_drv_page_next(const vmm_page_t * vmmp)24857c8c0b82SPatrick Mooney vmm_drv_page_next(const vmm_page_t *vmmp)
24867c8c0b82SPatrick Mooney {
24877c8c0b82SPatrick Mooney return ((vmm_page_t *)vmp_next((vm_page_t *)vmmp));
24887c8c0b82SPatrick Mooney }
24897c8c0b82SPatrick Mooney
24907c8c0b82SPatrick Mooney int
vmm_drv_msi(vmm_lease_t * lease,uint64_t addr,uint64_t msg)24917c8c0b82SPatrick Mooney vmm_drv_msi(vmm_lease_t *lease, uint64_t addr, uint64_t msg)
24927c8c0b82SPatrick Mooney {
24937c8c0b82SPatrick Mooney ASSERT(lease != NULL);
24947c8c0b82SPatrick Mooney
24957c8c0b82SPatrick Mooney return (lapic_intr_msi(lease->vml_vm, addr, msg));
24967c8c0b82SPatrick Mooney }
24977c8c0b82SPatrick Mooney
24987c8c0b82SPatrick Mooney int
vmm_drv_ioport_hook(vmm_hold_t * hold,uint16_t ioport,vmm_drv_iop_cb_t func,void * arg,void ** cookie)24997c8c0b82SPatrick Mooney vmm_drv_ioport_hook(vmm_hold_t *hold, uint16_t ioport, vmm_drv_iop_cb_t func,
25007c8c0b82SPatrick Mooney void *arg, void **cookie)
25017c8c0b82SPatrick Mooney {
25027c8c0b82SPatrick Mooney vmm_softc_t *sc;
25037c8c0b82SPatrick Mooney int err;
25047c8c0b82SPatrick Mooney
25057c8c0b82SPatrick Mooney ASSERT(hold != NULL);
25067c8c0b82SPatrick Mooney ASSERT(cookie != NULL);
25077c8c0b82SPatrick Mooney
25087c8c0b82SPatrick Mooney sc = hold->vmh_sc;
25097c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
25107c8c0b82SPatrick Mooney /* Confirm that hook installation is not blocked */
25117c8c0b82SPatrick Mooney if ((sc->vmm_flags & VMM_BLOCK_HOOK) != 0) {
25127c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
25137c8c0b82SPatrick Mooney return (EBUSY);
25147c8c0b82SPatrick Mooney }
25157c8c0b82SPatrick Mooney /*
25167c8c0b82SPatrick Mooney * Optimistically record an installed hook which will prevent a block
25177c8c0b82SPatrick Mooney * from being asserted while the mutex is dropped.
25187c8c0b82SPatrick Mooney */
25197c8c0b82SPatrick Mooney hold->vmh_ioport_hook_cnt++;
25207c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
25217c8c0b82SPatrick Mooney
25227c8c0b82SPatrick Mooney vmm_write_lock(sc);
25237c8c0b82SPatrick Mooney err = vm_ioport_hook(sc->vmm_vm, ioport, (ioport_handler_t)func,
25247c8c0b82SPatrick Mooney arg, cookie);
25257c8c0b82SPatrick Mooney vmm_write_unlock(sc);
25267c8c0b82SPatrick Mooney
25277c8c0b82SPatrick Mooney if (err != 0) {
25287c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
25297c8c0b82SPatrick Mooney /* Walk back optimism about the hook installation */
25307c8c0b82SPatrick Mooney hold->vmh_ioport_hook_cnt--;
25317c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
25327c8c0b82SPatrick Mooney }
25337c8c0b82SPatrick Mooney return (err);
25347c8c0b82SPatrick Mooney }
25357c8c0b82SPatrick Mooney
25367c8c0b82SPatrick Mooney void
vmm_drv_ioport_unhook(vmm_hold_t * hold,void ** cookie)25377c8c0b82SPatrick Mooney vmm_drv_ioport_unhook(vmm_hold_t *hold, void **cookie)
25387c8c0b82SPatrick Mooney {
25397c8c0b82SPatrick Mooney vmm_softc_t *sc;
25407c8c0b82SPatrick Mooney
25417c8c0b82SPatrick Mooney ASSERT(hold != NULL);
25427c8c0b82SPatrick Mooney ASSERT(cookie != NULL);
25437c8c0b82SPatrick Mooney ASSERT(hold->vmh_ioport_hook_cnt != 0);
25447c8c0b82SPatrick Mooney
25457c8c0b82SPatrick Mooney sc = hold->vmh_sc;
25467c8c0b82SPatrick Mooney vmm_write_lock(sc);
25477c8c0b82SPatrick Mooney vm_ioport_unhook(sc->vmm_vm, cookie);
25487c8c0b82SPatrick Mooney vmm_write_unlock(sc);
25497c8c0b82SPatrick Mooney
25507c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
25517c8c0b82SPatrick Mooney hold->vmh_ioport_hook_cnt--;
25527c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
25537c8c0b82SPatrick Mooney }
25547c8c0b82SPatrick Mooney
255542640e49SPatrick Mooney static void
vmm_drv_purge(vmm_softc_t * sc)255642640e49SPatrick Mooney vmm_drv_purge(vmm_softc_t *sc)
25577c8c0b82SPatrick Mooney {
25587c8c0b82SPatrick Mooney ASSERT(MUTEX_HELD(&vmm_mtx));
25597c8c0b82SPatrick Mooney
25607c8c0b82SPatrick Mooney if ((sc->vmm_flags & VMM_HELD) != 0) {
25617c8c0b82SPatrick Mooney vmm_hold_t *hold;
25627c8c0b82SPatrick Mooney
25637c8c0b82SPatrick Mooney for (hold = list_head(&sc->vmm_holds); hold != NULL;
25647c8c0b82SPatrick Mooney hold = list_next(&sc->vmm_holds, hold)) {
25657c8c0b82SPatrick Mooney hold->vmh_release_req = B_TRUE;
25667c8c0b82SPatrick Mooney }
2567a26f9c14SPatrick Mooney
2568a26f9c14SPatrick Mooney /*
2569a26f9c14SPatrick Mooney * Require that all leases on the instance be broken, now that
2570a26f9c14SPatrick Mooney * all associated holds have been marked as needing release.
2571a26f9c14SPatrick Mooney *
2572a26f9c14SPatrick Mooney * Dropping vmm_mtx is not strictly necessary, but if any of the
2573a26f9c14SPatrick Mooney * lessees are slow to respond, it would be nice to leave it
2574a26f9c14SPatrick Mooney * available for other parties.
2575a26f9c14SPatrick Mooney */
2576a26f9c14SPatrick Mooney mutex_exit(&vmm_mtx);
2577a26f9c14SPatrick Mooney vmm_lease_block(sc);
2578a26f9c14SPatrick Mooney vmm_lease_unblock(sc);
2579a26f9c14SPatrick Mooney mutex_enter(&vmm_mtx);
25807c8c0b82SPatrick Mooney }
25817c8c0b82SPatrick Mooney }
25827c8c0b82SPatrick Mooney
25837c8c0b82SPatrick Mooney static int
vmm_drv_block_hook(vmm_softc_t * sc,boolean_t enable_block)25847c8c0b82SPatrick Mooney vmm_drv_block_hook(vmm_softc_t *sc, boolean_t enable_block)
25857c8c0b82SPatrick Mooney {
25867c8c0b82SPatrick Mooney int err = 0;
25877c8c0b82SPatrick Mooney
25887c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
25897c8c0b82SPatrick Mooney if (!enable_block) {
25907c8c0b82SPatrick Mooney VERIFY((sc->vmm_flags & VMM_BLOCK_HOOK) != 0);
25917c8c0b82SPatrick Mooney
25927c8c0b82SPatrick Mooney sc->vmm_flags &= ~VMM_BLOCK_HOOK;
25937c8c0b82SPatrick Mooney goto done;
25947c8c0b82SPatrick Mooney }
25957c8c0b82SPatrick Mooney
25967c8c0b82SPatrick Mooney /* If any holds have hooks installed, the block is a failure */
25977c8c0b82SPatrick Mooney if (!list_is_empty(&sc->vmm_holds)) {
25987c8c0b82SPatrick Mooney vmm_hold_t *hold;
25997c8c0b82SPatrick Mooney
26007c8c0b82SPatrick Mooney for (hold = list_head(&sc->vmm_holds); hold != NULL;
26017c8c0b82SPatrick Mooney hold = list_next(&sc->vmm_holds, hold)) {
26027c8c0b82SPatrick Mooney if (hold->vmh_ioport_hook_cnt != 0) {
26037c8c0b82SPatrick Mooney err = EBUSY;
26047c8c0b82SPatrick Mooney goto done;
26057c8c0b82SPatrick Mooney }
26067c8c0b82SPatrick Mooney }
26077c8c0b82SPatrick Mooney }
26087c8c0b82SPatrick Mooney sc->vmm_flags |= VMM_BLOCK_HOOK;
26097c8c0b82SPatrick Mooney
26107c8c0b82SPatrick Mooney done:
26117c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
26127c8c0b82SPatrick Mooney return (err);
26137c8c0b82SPatrick Mooney }
26147c8c0b82SPatrick Mooney
261542640e49SPatrick Mooney
261642640e49SPatrick Mooney static void
vmm_destroy_begin(vmm_softc_t * sc,vmm_destroy_opts_t opts)261742640e49SPatrick Mooney vmm_destroy_begin(vmm_softc_t *sc, vmm_destroy_opts_t opts)
26187c8c0b82SPatrick Mooney {
26197c8c0b82SPatrick Mooney ASSERT(MUTEX_HELD(&vmm_mtx));
262042640e49SPatrick Mooney ASSERT0(sc->vmm_flags & VMM_DESTROY);
26217c8c0b82SPatrick Mooney
262242640e49SPatrick Mooney sc->vmm_flags |= VMM_DESTROY;
26237c8c0b82SPatrick Mooney
262442640e49SPatrick Mooney /*
262542640e49SPatrick Mooney * Lock and unlock all of the vCPUs to ensure that they are kicked out
262642640e49SPatrick Mooney * of guest context, being unable to return now that the instance is
262742640e49SPatrick Mooney * marked for destruction.
262842640e49SPatrick Mooney */
262942640e49SPatrick Mooney const int maxcpus = vm_get_maxcpus(sc->vmm_vm);
263042640e49SPatrick Mooney for (int vcpu = 0; vcpu < maxcpus; vcpu++) {
263142640e49SPatrick Mooney vcpu_lock_one(sc, vcpu);
263242640e49SPatrick Mooney vcpu_unlock_one(sc, vcpu);
26337c8c0b82SPatrick Mooney }
26347c8c0b82SPatrick Mooney
263542640e49SPatrick Mooney vmmdev_devmem_purge(sc);
2636aa39f6d0SPatrick Mooney if ((opts & VDO_NO_CLEAN_ZSD) == 0) {
263742640e49SPatrick Mooney /*
263842640e49SPatrick Mooney * The ZSD should be cleaned up now, unless destruction of the
263942640e49SPatrick Mooney * instance was initated by destruction of the containing zone,
264042640e49SPatrick Mooney * in which case the ZSD has already been removed.
264142640e49SPatrick Mooney */
26427c8c0b82SPatrick Mooney vmm_zsd_rem_vm(sc);
26437c8c0b82SPatrick Mooney }
264442640e49SPatrick Mooney zone_rele(sc->vmm_zone);
26457c8c0b82SPatrick Mooney
264642640e49SPatrick Mooney vmm_drv_purge(sc);
264742640e49SPatrick Mooney }
264842640e49SPatrick Mooney
264942640e49SPatrick Mooney static bool
vmm_destroy_ready(vmm_softc_t * sc)265042640e49SPatrick Mooney vmm_destroy_ready(vmm_softc_t *sc)
265142640e49SPatrick Mooney {
265242640e49SPatrick Mooney ASSERT(MUTEX_HELD(&vmm_mtx));
265342640e49SPatrick Mooney
265442640e49SPatrick Mooney if ((sc->vmm_flags & (VMM_HELD | VMM_IS_OPEN)) == 0) {
265542640e49SPatrick Mooney VERIFY(list_is_empty(&sc->vmm_holds));
265642640e49SPatrick Mooney return (true);
265742640e49SPatrick Mooney }
265842640e49SPatrick Mooney
265942640e49SPatrick Mooney return (false);
266042640e49SPatrick Mooney }
266142640e49SPatrick Mooney
266242640e49SPatrick Mooney static void
vmm_destroy_finish(vmm_softc_t * sc)266342640e49SPatrick Mooney vmm_destroy_finish(vmm_softc_t *sc)
266442640e49SPatrick Mooney {
266542640e49SPatrick Mooney ASSERT(MUTEX_HELD(&vmm_mtx));
266642640e49SPatrick Mooney ASSERT(vmm_destroy_ready(sc));
26677c8c0b82SPatrick Mooney
26687c8c0b82SPatrick Mooney list_remove(&vmm_list, sc);
26697c8c0b82SPatrick Mooney vmm_kstat_fini(sc);
26707c8c0b82SPatrick Mooney vm_destroy(sc->vmm_vm);
267142640e49SPatrick Mooney ddi_remove_minor_node(vmmdev_dip, sc->vmm_name);
267242640e49SPatrick Mooney (void) devfs_clean(ddi_get_parent(vmmdev_dip), NULL, DV_CLEAN_FORCE);
267342640e49SPatrick Mooney
267442640e49SPatrick Mooney const minor_t minor = sc->vmm_minor;
26757c8c0b82SPatrick Mooney ddi_soft_state_free(vmm_statep, minor);
26767c8c0b82SPatrick Mooney id_free(vmm_minors, minor);
26777c8c0b82SPatrick Mooney }
26787c8c0b82SPatrick Mooney
267942640e49SPatrick Mooney /*
268042640e49SPatrick Mooney * Initiate or attempt to finish destruction of a VMM instance.
268142640e49SPatrick Mooney *
268242640e49SPatrick Mooney * This is called from several contexts:
268342640e49SPatrick Mooney * - An explicit destroy ioctl is made
268442640e49SPatrick Mooney * - A vmm_drv consumer releases its hold (being the last on the instance)
268542640e49SPatrick Mooney * - The vmm device is closed, and auto-destruct is enabled
268642640e49SPatrick Mooney */
268742640e49SPatrick Mooney static int
vmm_destroy_locked(vmm_softc_t * sc,vmm_destroy_opts_t opts,bool * hma_release)268842640e49SPatrick Mooney vmm_destroy_locked(vmm_softc_t *sc, vmm_destroy_opts_t opts,
268942640e49SPatrick Mooney bool *hma_release)
269042640e49SPatrick Mooney {
269142640e49SPatrick Mooney ASSERT(MUTEX_HELD(&vmm_mtx));
269242640e49SPatrick Mooney
269342640e49SPatrick Mooney *hma_release = false;
269442640e49SPatrick Mooney
269542640e49SPatrick Mooney /*
269642640e49SPatrick Mooney * When instance destruction begins, it is so marked such that any
269742640e49SPatrick Mooney * further requests to operate the instance will fail.
269842640e49SPatrick Mooney */
269942640e49SPatrick Mooney if ((sc->vmm_flags & VMM_DESTROY) == 0) {
270042640e49SPatrick Mooney vmm_destroy_begin(sc, opts);
270142640e49SPatrick Mooney }
270242640e49SPatrick Mooney
270342640e49SPatrick Mooney if (vmm_destroy_ready(sc)) {
270442640e49SPatrick Mooney
270542640e49SPatrick Mooney /*
270642640e49SPatrick Mooney * Notify anyone waiting for the destruction to finish. They
270742640e49SPatrick Mooney * must be clear before we can safely tear down the softc.
270842640e49SPatrick Mooney */
270942640e49SPatrick Mooney if (sc->vmm_destroy_waiters != 0) {
271042640e49SPatrick Mooney cv_broadcast(&sc->vmm_cv);
271142640e49SPatrick Mooney while (sc->vmm_destroy_waiters != 0) {
271242640e49SPatrick Mooney cv_wait(&sc->vmm_cv, &vmm_mtx);
271342640e49SPatrick Mooney }
271442640e49SPatrick Mooney }
271542640e49SPatrick Mooney
271642640e49SPatrick Mooney /*
271742640e49SPatrick Mooney * Finish destruction of instance. After this point, the softc
271842640e49SPatrick Mooney * is freed and cannot be accessed again.
271942640e49SPatrick Mooney *
272042640e49SPatrick Mooney * With destruction complete, the HMA hold can be released
272142640e49SPatrick Mooney */
272242640e49SPatrick Mooney vmm_destroy_finish(sc);
272342640e49SPatrick Mooney *hma_release = true;
272442640e49SPatrick Mooney return (0);
272542640e49SPatrick Mooney } else if ((opts & VDO_ATTEMPT_WAIT) != 0) {
272642640e49SPatrick Mooney int err = 0;
272742640e49SPatrick Mooney
272842640e49SPatrick Mooney sc->vmm_destroy_waiters++;
272942640e49SPatrick Mooney while (!vmm_destroy_ready(sc) && err == 0) {
273042640e49SPatrick Mooney if (cv_wait_sig(&sc->vmm_cv, &vmm_mtx) <= 0) {
273142640e49SPatrick Mooney err = EINTR;
273242640e49SPatrick Mooney }
273342640e49SPatrick Mooney }
273442640e49SPatrick Mooney sc->vmm_destroy_waiters--;
273542640e49SPatrick Mooney
273642640e49SPatrick Mooney if (sc->vmm_destroy_waiters == 0) {
273742640e49SPatrick Mooney /*
273842640e49SPatrick Mooney * If we were the last waiter, it could be that VM
273942640e49SPatrick Mooney * destruction is waiting on _us_ to proceed with the
274042640e49SPatrick Mooney * final clean-up.
274142640e49SPatrick Mooney */
274242640e49SPatrick Mooney cv_signal(&sc->vmm_cv);
274342640e49SPatrick Mooney }
274442640e49SPatrick Mooney return (err);
274542640e49SPatrick Mooney } else {
274642640e49SPatrick Mooney /*
274742640e49SPatrick Mooney * Since the instance is not ready for destruction, and the
274842640e49SPatrick Mooney * caller did not ask to wait, consider it a success for now.
274942640e49SPatrick Mooney */
27507c8c0b82SPatrick Mooney return (0);
27517c8c0b82SPatrick Mooney }
275242640e49SPatrick Mooney }
27537c8c0b82SPatrick Mooney
275442640e49SPatrick Mooney void
vmm_zone_vm_destroy(vmm_softc_t * sc)2755aa39f6d0SPatrick Mooney vmm_zone_vm_destroy(vmm_softc_t *sc)
27567c8c0b82SPatrick Mooney {
275742640e49SPatrick Mooney bool hma_release = false;
27587c8c0b82SPatrick Mooney int err;
27597c8c0b82SPatrick Mooney
27607c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
2761aa39f6d0SPatrick Mooney err = vmm_destroy_locked(sc, VDO_NO_CLEAN_ZSD, &hma_release);
27627c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
27637c8c0b82SPatrick Mooney
276442640e49SPatrick Mooney VERIFY0(err);
27657c8c0b82SPatrick Mooney
276642640e49SPatrick Mooney if (hma_release) {
276742640e49SPatrick Mooney vmm_hma_release();
276842640e49SPatrick Mooney }
27697c8c0b82SPatrick Mooney }
27707c8c0b82SPatrick Mooney
27717c8c0b82SPatrick Mooney static int
vmmdev_do_vm_destroy(const struct vm_destroy_req * req,cred_t * cr)27727c8c0b82SPatrick Mooney vmmdev_do_vm_destroy(const struct vm_destroy_req *req, cred_t *cr)
27737c8c0b82SPatrick Mooney {
27747c8c0b82SPatrick Mooney vmm_softc_t *sc;
277542640e49SPatrick Mooney bool hma_release = false;
27767c8c0b82SPatrick Mooney int err;
27777c8c0b82SPatrick Mooney
277842640e49SPatrick Mooney if (crgetuid(cr) != 0) {
27797c8c0b82SPatrick Mooney return (EPERM);
278042640e49SPatrick Mooney }
27817c8c0b82SPatrick Mooney
27827c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
278342640e49SPatrick Mooney sc = vmm_lookup(req->name);
278442640e49SPatrick Mooney if (sc == NULL) {
27857c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
27867c8c0b82SPatrick Mooney return (ENOENT);
27877c8c0b82SPatrick Mooney }
27887c8c0b82SPatrick Mooney /*
27897c8c0b82SPatrick Mooney * We don't check this in vmm_lookup() since that function is also used
27907c8c0b82SPatrick Mooney * for validation during create and currently vmm names must be unique.
27917c8c0b82SPatrick Mooney */
27927c8c0b82SPatrick Mooney if (!INGLOBALZONE(curproc) && sc->vmm_zone != curzone) {
27937c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
27947c8c0b82SPatrick Mooney return (EPERM);
27957c8c0b82SPatrick Mooney }
27967c8c0b82SPatrick Mooney
279742640e49SPatrick Mooney err = vmm_destroy_locked(sc, VDO_ATTEMPT_WAIT, &hma_release);
27987c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
27997c8c0b82SPatrick Mooney
280042640e49SPatrick Mooney if (hma_release) {
28017c8c0b82SPatrick Mooney vmm_hma_release();
280242640e49SPatrick Mooney }
28037c8c0b82SPatrick Mooney
28047c8c0b82SPatrick Mooney return (err);
28057c8c0b82SPatrick Mooney }
28067c8c0b82SPatrick Mooney
28077c8c0b82SPatrick Mooney #define VCPU_NAME_BUFLEN 32
28087c8c0b82SPatrick Mooney
28097c8c0b82SPatrick Mooney static int
vmm_kstat_alloc(vmm_softc_t * sc,minor_t minor,const cred_t * cr)28107c8c0b82SPatrick Mooney vmm_kstat_alloc(vmm_softc_t *sc, minor_t minor, const cred_t *cr)
28117c8c0b82SPatrick Mooney {
28127c8c0b82SPatrick Mooney zoneid_t zid = crgetzoneid(cr);
28137c8c0b82SPatrick Mooney int instance = minor;
28147c8c0b82SPatrick Mooney kstat_t *ksp;
28157c8c0b82SPatrick Mooney
28167c8c0b82SPatrick Mooney ASSERT3P(sc->vmm_kstat_vm, ==, NULL);
28177c8c0b82SPatrick Mooney
28187c8c0b82SPatrick Mooney ksp = kstat_create_zone(VMM_MODULE_NAME, instance, "vm",
28197c8c0b82SPatrick Mooney VMM_KSTAT_CLASS, KSTAT_TYPE_NAMED,
28207c8c0b82SPatrick Mooney sizeof (vmm_kstats_t) / sizeof (kstat_named_t), 0, zid);
28217c8c0b82SPatrick Mooney
28227c8c0b82SPatrick Mooney if (ksp == NULL) {
28237c8c0b82SPatrick Mooney return (-1);
28247c8c0b82SPatrick Mooney }
28257c8c0b82SPatrick Mooney sc->vmm_kstat_vm = ksp;
28267c8c0b82SPatrick Mooney
28277c8c0b82SPatrick Mooney for (uint_t i = 0; i < VM_MAXCPU; i++) {
28287c8c0b82SPatrick Mooney char namebuf[VCPU_NAME_BUFLEN];
28297c8c0b82SPatrick Mooney
28307c8c0b82SPatrick Mooney ASSERT3P(sc->vmm_kstat_vcpu[i], ==, NULL);
28317c8c0b82SPatrick Mooney
28327c8c0b82SPatrick Mooney (void) snprintf(namebuf, VCPU_NAME_BUFLEN, "vcpu%u", i);
28337c8c0b82SPatrick Mooney ksp = kstat_create_zone(VMM_MODULE_NAME, instance, namebuf,
28347c8c0b82SPatrick Mooney VMM_KSTAT_CLASS, KSTAT_TYPE_NAMED,
28357c8c0b82SPatrick Mooney sizeof (vmm_vcpu_kstats_t) / sizeof (kstat_named_t),
28367c8c0b82SPatrick Mooney 0, zid);
28377c8c0b82SPatrick Mooney if (ksp == NULL) {
28387c8c0b82SPatrick Mooney goto fail;
28397c8c0b82SPatrick Mooney }
28407c8c0b82SPatrick Mooney
28417c8c0b82SPatrick Mooney sc->vmm_kstat_vcpu[i] = ksp;
28427c8c0b82SPatrick Mooney }
28437c8c0b82SPatrick Mooney
28447c8c0b82SPatrick Mooney /*
28457c8c0b82SPatrick Mooney * If this instance is associated with a non-global zone, make its
28467c8c0b82SPatrick Mooney * kstats visible from the GZ.
28477c8c0b82SPatrick Mooney */
28487c8c0b82SPatrick Mooney if (zid != GLOBAL_ZONEID) {
28497c8c0b82SPatrick Mooney kstat_zone_add(sc->vmm_kstat_vm, GLOBAL_ZONEID);
28507c8c0b82SPatrick Mooney for (uint_t i = 0; i < VM_MAXCPU; i++) {
28517c8c0b82SPatrick Mooney kstat_zone_add(sc->vmm_kstat_vcpu[i], GLOBAL_ZONEID);
28527c8c0b82SPatrick Mooney }
28537c8c0b82SPatrick Mooney }
28547c8c0b82SPatrick Mooney
28557c8c0b82SPatrick Mooney return (0);
28567c8c0b82SPatrick Mooney
28577c8c0b82SPatrick Mooney fail:
28587c8c0b82SPatrick Mooney for (uint_t i = 0; i < VM_MAXCPU; i++) {
28597c8c0b82SPatrick Mooney if (sc->vmm_kstat_vcpu[i] != NULL) {
28607c8c0b82SPatrick Mooney kstat_delete(sc->vmm_kstat_vcpu[i]);
28617c8c0b82SPatrick Mooney sc->vmm_kstat_vcpu[i] = NULL;
28627c8c0b82SPatrick Mooney } else {
28637c8c0b82SPatrick Mooney break;
28647c8c0b82SPatrick Mooney }
28657c8c0b82SPatrick Mooney }
28667c8c0b82SPatrick Mooney kstat_delete(sc->vmm_kstat_vm);
28677c8c0b82SPatrick Mooney sc->vmm_kstat_vm = NULL;
28687c8c0b82SPatrick Mooney return (-1);
28697c8c0b82SPatrick Mooney }
28707c8c0b82SPatrick Mooney
28717c8c0b82SPatrick Mooney static void
vmm_kstat_init(vmm_softc_t * sc)28727c8c0b82SPatrick Mooney vmm_kstat_init(vmm_softc_t *sc)
28737c8c0b82SPatrick Mooney {
28747c8c0b82SPatrick Mooney kstat_t *ksp;
28757c8c0b82SPatrick Mooney
28767c8c0b82SPatrick Mooney ASSERT3P(sc->vmm_vm, !=, NULL);
28777c8c0b82SPatrick Mooney ASSERT3P(sc->vmm_kstat_vm, !=, NULL);
28787c8c0b82SPatrick Mooney
28797c8c0b82SPatrick Mooney ksp = sc->vmm_kstat_vm;
28807c8c0b82SPatrick Mooney vmm_kstats_t *vk = ksp->ks_data;
28817c8c0b82SPatrick Mooney ksp->ks_private = sc->vmm_vm;
28827c8c0b82SPatrick Mooney kstat_named_init(&vk->vk_name, "vm_name", KSTAT_DATA_STRING);
28837c8c0b82SPatrick Mooney kstat_named_setstr(&vk->vk_name, sc->vmm_name);
28847c8c0b82SPatrick Mooney
28857c8c0b82SPatrick Mooney for (uint_t i = 0; i < VM_MAXCPU; i++) {
28867c8c0b82SPatrick Mooney ASSERT3P(sc->vmm_kstat_vcpu[i], !=, NULL);
28877c8c0b82SPatrick Mooney
28887c8c0b82SPatrick Mooney ksp = sc->vmm_kstat_vcpu[i];
28897c8c0b82SPatrick Mooney vmm_vcpu_kstats_t *vvk = ksp->ks_data;
28907c8c0b82SPatrick Mooney
28917c8c0b82SPatrick Mooney kstat_named_init(&vvk->vvk_vcpu, "vcpu", KSTAT_DATA_UINT32);
28927c8c0b82SPatrick Mooney vvk->vvk_vcpu.value.ui32 = i;
28937c8c0b82SPatrick Mooney kstat_named_init(&vvk->vvk_time_init, "time_init",
28947c8c0b82SPatrick Mooney KSTAT_DATA_UINT64);
28957c8c0b82SPatrick Mooney kstat_named_init(&vvk->vvk_time_run, "time_run",
28967c8c0b82SPatrick Mooney KSTAT_DATA_UINT64);
28977c8c0b82SPatrick Mooney kstat_named_init(&vvk->vvk_time_idle, "time_idle",
28987c8c0b82SPatrick Mooney KSTAT_DATA_UINT64);
28997c8c0b82SPatrick Mooney kstat_named_init(&vvk->vvk_time_emu_kern, "time_emu_kern",
29007c8c0b82SPatrick Mooney KSTAT_DATA_UINT64);
29017c8c0b82SPatrick Mooney kstat_named_init(&vvk->vvk_time_emu_user, "time_emu_user",
29027c8c0b82SPatrick Mooney KSTAT_DATA_UINT64);
29037c8c0b82SPatrick Mooney kstat_named_init(&vvk->vvk_time_sched, "time_sched",
29047c8c0b82SPatrick Mooney KSTAT_DATA_UINT64);
29057c8c0b82SPatrick Mooney ksp->ks_private = sc->vmm_vm;
29067c8c0b82SPatrick Mooney ksp->ks_update = vmm_kstat_update_vcpu;
29077c8c0b82SPatrick Mooney }
29087c8c0b82SPatrick Mooney
29097c8c0b82SPatrick Mooney kstat_install(sc->vmm_kstat_vm);
29107c8c0b82SPatrick Mooney for (uint_t i = 0; i < VM_MAXCPU; i++) {
29117c8c0b82SPatrick Mooney kstat_install(sc->vmm_kstat_vcpu[i]);
29127c8c0b82SPatrick Mooney }
29137c8c0b82SPatrick Mooney }
29147c8c0b82SPatrick Mooney
29157c8c0b82SPatrick Mooney static void
vmm_kstat_fini(vmm_softc_t * sc)29167c8c0b82SPatrick Mooney vmm_kstat_fini(vmm_softc_t *sc)
29177c8c0b82SPatrick Mooney {
29187c8c0b82SPatrick Mooney ASSERT(sc->vmm_kstat_vm != NULL);
29197c8c0b82SPatrick Mooney
29207c8c0b82SPatrick Mooney kstat_delete(sc->vmm_kstat_vm);
29217c8c0b82SPatrick Mooney sc->vmm_kstat_vm = NULL;
29227c8c0b82SPatrick Mooney
29237c8c0b82SPatrick Mooney for (uint_t i = 0; i < VM_MAXCPU; i++) {
29247c8c0b82SPatrick Mooney ASSERT3P(sc->vmm_kstat_vcpu[i], !=, NULL);
29257c8c0b82SPatrick Mooney
29267c8c0b82SPatrick Mooney kstat_delete(sc->vmm_kstat_vcpu[i]);
29277c8c0b82SPatrick Mooney sc->vmm_kstat_vcpu[i] = NULL;
29287c8c0b82SPatrick Mooney }
29297c8c0b82SPatrick Mooney }
29307c8c0b82SPatrick Mooney
29317c8c0b82SPatrick Mooney static int
vmm_open(dev_t * devp,int flag,int otyp,cred_t * credp)29327c8c0b82SPatrick Mooney vmm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
29337c8c0b82SPatrick Mooney {
29347c8c0b82SPatrick Mooney minor_t minor;
29357c8c0b82SPatrick Mooney vmm_softc_t *sc;
29367c8c0b82SPatrick Mooney
29377c8c0b82SPatrick Mooney /*
29387c8c0b82SPatrick Mooney * Forbid running bhyve in a 32-bit process until it has been tested and
29397c8c0b82SPatrick Mooney * verified to be safe.
29407c8c0b82SPatrick Mooney */
29417c8c0b82SPatrick Mooney if (curproc->p_model != DATAMODEL_LP64) {
29427c8c0b82SPatrick Mooney return (EFBIG);
29437c8c0b82SPatrick Mooney }
29447c8c0b82SPatrick Mooney
29457c8c0b82SPatrick Mooney minor = getminor(*devp);
29467c8c0b82SPatrick Mooney if (minor == VMM_CTL_MINOR) {
29477c8c0b82SPatrick Mooney /*
29487c8c0b82SPatrick Mooney * Master control device must be opened exclusively.
29497c8c0b82SPatrick Mooney */
29507c8c0b82SPatrick Mooney if ((flag & FEXCL) != FEXCL || otyp != OTYP_CHR) {
29517c8c0b82SPatrick Mooney return (EINVAL);
29527c8c0b82SPatrick Mooney }
29537c8c0b82SPatrick Mooney
29547c8c0b82SPatrick Mooney return (0);
29557c8c0b82SPatrick Mooney }
29567c8c0b82SPatrick Mooney
29577c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
29587c8c0b82SPatrick Mooney sc = ddi_get_soft_state(vmm_statep, minor);
29597c8c0b82SPatrick Mooney if (sc == NULL) {
29607c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
29617c8c0b82SPatrick Mooney return (ENXIO);
29627c8c0b82SPatrick Mooney }
29637c8c0b82SPatrick Mooney
296442640e49SPatrick Mooney sc->vmm_flags |= VMM_IS_OPEN;
29657c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
29667c8c0b82SPatrick Mooney
29677c8c0b82SPatrick Mooney return (0);
29687c8c0b82SPatrick Mooney }
29697c8c0b82SPatrick Mooney
29707c8c0b82SPatrick Mooney static int
vmm_close(dev_t dev,int flag,int otyp,cred_t * credp)29717c8c0b82SPatrick Mooney vmm_close(dev_t dev, int flag, int otyp, cred_t *credp)
29727c8c0b82SPatrick Mooney {
297342640e49SPatrick Mooney const minor_t minor = getminor(dev);
29747c8c0b82SPatrick Mooney vmm_softc_t *sc;
297542640e49SPatrick Mooney bool hma_release = false;
29767c8c0b82SPatrick Mooney
297742640e49SPatrick Mooney if (minor == VMM_CTL_MINOR) {
29787c8c0b82SPatrick Mooney return (0);
297942640e49SPatrick Mooney }
29807c8c0b82SPatrick Mooney
29817c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
29827c8c0b82SPatrick Mooney sc = ddi_get_soft_state(vmm_statep, minor);
29837c8c0b82SPatrick Mooney if (sc == NULL) {
29847c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
29857c8c0b82SPatrick Mooney return (ENXIO);
29867c8c0b82SPatrick Mooney }
29877c8c0b82SPatrick Mooney
298842640e49SPatrick Mooney VERIFY3U(sc->vmm_flags & VMM_IS_OPEN, !=, 0);
298942640e49SPatrick Mooney sc->vmm_flags &= ~VMM_IS_OPEN;
29907c8c0b82SPatrick Mooney
29917c8c0b82SPatrick Mooney /*
299242640e49SPatrick Mooney * If instance was marked for auto-destruction begin that now. Instance
299342640e49SPatrick Mooney * destruction may have been initated already, so try to make progress
299442640e49SPatrick Mooney * in that case, since closure of the device is one of its requirements.
29957c8c0b82SPatrick Mooney */
299642640e49SPatrick Mooney if ((sc->vmm_flags & VMM_DESTROY) != 0 ||
299742640e49SPatrick Mooney (sc->vmm_flags & VMM_AUTODESTROY) != 0) {
299842640e49SPatrick Mooney VERIFY0(vmm_destroy_locked(sc, VDO_DEFAULT, &hma_release));
29997c8c0b82SPatrick Mooney }
30007c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
30017c8c0b82SPatrick Mooney
300242640e49SPatrick Mooney if (hma_release) {
30037c8c0b82SPatrick Mooney vmm_hma_release();
300442640e49SPatrick Mooney }
30057c8c0b82SPatrick Mooney
30067c8c0b82SPatrick Mooney return (0);
30077c8c0b82SPatrick Mooney }
30087c8c0b82SPatrick Mooney
30097c8c0b82SPatrick Mooney static int
vmm_is_supported(intptr_t arg)30107c8c0b82SPatrick Mooney vmm_is_supported(intptr_t arg)
30117c8c0b82SPatrick Mooney {
30127c8c0b82SPatrick Mooney int r;
30137c8c0b82SPatrick Mooney const char *msg;
30147c8c0b82SPatrick Mooney
30157c8c0b82SPatrick Mooney if (vmm_is_intel()) {
30167c8c0b82SPatrick Mooney r = vmx_x86_supported(&msg);
30177c8c0b82SPatrick Mooney } else if (vmm_is_svm()) {
30187c8c0b82SPatrick Mooney /*
30197c8c0b82SPatrick Mooney * HMA already ensured that the features necessary for SVM
30207c8c0b82SPatrick Mooney * operation were present and online during vmm_attach().
30217c8c0b82SPatrick Mooney */
30227c8c0b82SPatrick Mooney r = 0;
30237c8c0b82SPatrick Mooney } else {
30247c8c0b82SPatrick Mooney r = ENXIO;
30257c8c0b82SPatrick Mooney msg = "Unsupported CPU vendor";
30267c8c0b82SPatrick Mooney }
30277c8c0b82SPatrick Mooney
30287c8c0b82SPatrick Mooney if (r != 0 && arg != (intptr_t)NULL) {
30297c8c0b82SPatrick Mooney if (copyoutstr(msg, (char *)arg, strlen(msg) + 1, NULL) != 0)
30307c8c0b82SPatrick Mooney return (EFAULT);
30317c8c0b82SPatrick Mooney }
30327c8c0b82SPatrick Mooney return (r);
30337c8c0b82SPatrick Mooney }
30347c8c0b82SPatrick Mooney
30357c8c0b82SPatrick Mooney static int
vmm_ctl_ioctl(int cmd,intptr_t arg,int md,cred_t * cr,int * rvalp)30367c8c0b82SPatrick Mooney vmm_ctl_ioctl(int cmd, intptr_t arg, int md, cred_t *cr, int *rvalp)
30377c8c0b82SPatrick Mooney {
30387c8c0b82SPatrick Mooney void *argp = (void *)arg;
30397c8c0b82SPatrick Mooney
30407c8c0b82SPatrick Mooney switch (cmd) {
30417c8c0b82SPatrick Mooney case VMM_CREATE_VM: {
30427c8c0b82SPatrick Mooney struct vm_create_req req;
30437c8c0b82SPatrick Mooney
30447c8c0b82SPatrick Mooney if ((md & FWRITE) == 0) {
30457c8c0b82SPatrick Mooney return (EPERM);
30467c8c0b82SPatrick Mooney }
30477c8c0b82SPatrick Mooney if (ddi_copyin(argp, &req, sizeof (req), md) != 0) {
30487c8c0b82SPatrick Mooney return (EFAULT);
30497c8c0b82SPatrick Mooney }
30507c8c0b82SPatrick Mooney return (vmmdev_do_vm_create(&req, cr));
30517c8c0b82SPatrick Mooney }
30527c8c0b82SPatrick Mooney case VMM_DESTROY_VM: {
30537c8c0b82SPatrick Mooney struct vm_destroy_req req;
30547c8c0b82SPatrick Mooney
30557c8c0b82SPatrick Mooney if ((md & FWRITE) == 0) {
30567c8c0b82SPatrick Mooney return (EPERM);
30577c8c0b82SPatrick Mooney }
30587c8c0b82SPatrick Mooney if (ddi_copyin(argp, &req, sizeof (req), md) != 0) {
30597c8c0b82SPatrick Mooney return (EFAULT);
30607c8c0b82SPatrick Mooney }
30617c8c0b82SPatrick Mooney return (vmmdev_do_vm_destroy(&req, cr));
30627c8c0b82SPatrick Mooney }
30637c8c0b82SPatrick Mooney case VMM_VM_SUPPORTED:
30647c8c0b82SPatrick Mooney return (vmm_is_supported(arg));
3065e760f150SPatrick Mooney case VMM_CHECK_IOMMU:
3066e760f150SPatrick Mooney if (!vmm_check_iommu()) {
3067e760f150SPatrick Mooney return (ENXIO);
3068e760f150SPatrick Mooney }
3069e760f150SPatrick Mooney return (0);
30707c8c0b82SPatrick Mooney case VMM_RESV_QUERY:
30716bba8b59SPatrick Mooney case VMM_RESV_SET_TARGET:
30727c8c0b82SPatrick Mooney return (vmmr_ioctl(cmd, arg, md, cr, rvalp));
30737c8c0b82SPatrick Mooney default:
30747c8c0b82SPatrick Mooney break;
30757c8c0b82SPatrick Mooney }
30767c8c0b82SPatrick Mooney /* No other actions are legal on ctl device */
30777c8c0b82SPatrick Mooney return (ENOTTY);
30787c8c0b82SPatrick Mooney }
30797c8c0b82SPatrick Mooney
30807c8c0b82SPatrick Mooney static int
vmm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)30817c8c0b82SPatrick Mooney vmm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
30827c8c0b82SPatrick Mooney int *rvalp)
30837c8c0b82SPatrick Mooney {
30847c8c0b82SPatrick Mooney vmm_softc_t *sc;
30857c8c0b82SPatrick Mooney minor_t minor;
30867c8c0b82SPatrick Mooney
30877c8c0b82SPatrick Mooney /*
30887c8c0b82SPatrick Mooney * Forbid running bhyve in a 32-bit process until it has been tested and
30897c8c0b82SPatrick Mooney * verified to be safe.
30907c8c0b82SPatrick Mooney */
30917c8c0b82SPatrick Mooney if (curproc->p_model != DATAMODEL_LP64) {
30927c8c0b82SPatrick Mooney return (EFBIG);
30937c8c0b82SPatrick Mooney }
30947c8c0b82SPatrick Mooney
30957c8c0b82SPatrick Mooney /* The structs in bhyve ioctls assume a 64-bit datamodel */
30967c8c0b82SPatrick Mooney if (ddi_model_convert_from(mode & FMODELS) != DDI_MODEL_NONE) {
30977c8c0b82SPatrick Mooney return (ENOTSUP);
30987c8c0b82SPatrick Mooney }
30997c8c0b82SPatrick Mooney
310017e9e0aeSPatrick Mooney /*
310117e9e0aeSPatrick Mooney * Regardless of minor (vmmctl or instance), we respond to queries of
310217e9e0aeSPatrick Mooney * the interface version.
310317e9e0aeSPatrick Mooney */
310417e9e0aeSPatrick Mooney if (cmd == VMM_INTERFACE_VERSION) {
310517e9e0aeSPatrick Mooney *rvalp = VMM_CURRENT_INTERFACE_VERSION;
310617e9e0aeSPatrick Mooney return (0);
310717e9e0aeSPatrick Mooney }
310817e9e0aeSPatrick Mooney
31097c8c0b82SPatrick Mooney minor = getminor(dev);
31107c8c0b82SPatrick Mooney
31117c8c0b82SPatrick Mooney if (minor == VMM_CTL_MINOR) {
31127c8c0b82SPatrick Mooney return (vmm_ctl_ioctl(cmd, arg, mode, credp, rvalp));
31137c8c0b82SPatrick Mooney }
31147c8c0b82SPatrick Mooney
31157c8c0b82SPatrick Mooney sc = ddi_get_soft_state(vmm_statep, minor);
311642640e49SPatrick Mooney ASSERT(sc != NULL);
31177c8c0b82SPatrick Mooney
311842640e49SPatrick Mooney /*
311942640e49SPatrick Mooney * Turn away any ioctls against an instance when it is being destroyed.
312042640e49SPatrick Mooney * (Except for the ioctl inquiring about that destroy-in-progress.)
312142640e49SPatrick Mooney */
312242640e49SPatrick Mooney if ((sc->vmm_flags & VMM_DESTROY) != 0) {
312342640e49SPatrick Mooney if (cmd == VM_DESTROY_PENDING) {
312442640e49SPatrick Mooney *rvalp = 1;
312542640e49SPatrick Mooney return (0);
312642640e49SPatrick Mooney }
31277c8c0b82SPatrick Mooney return (ENXIO);
312842640e49SPatrick Mooney }
31297c8c0b82SPatrick Mooney
31307c8c0b82SPatrick Mooney return (vmmdev_do_ioctl(sc, cmd, arg, mode, credp, rvalp));
31317c8c0b82SPatrick Mooney }
31327c8c0b82SPatrick Mooney
31337c8c0b82SPatrick Mooney static int
vmm_segmap(dev_t dev,off_t off,struct as * as,caddr_t * addrp,off_t len,unsigned int prot,unsigned int maxprot,unsigned int flags,cred_t * credp)31347c8c0b82SPatrick Mooney vmm_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
31357c8c0b82SPatrick Mooney unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp)
31367c8c0b82SPatrick Mooney {
31377c8c0b82SPatrick Mooney vmm_softc_t *sc;
31387c8c0b82SPatrick Mooney const minor_t minor = getminor(dev);
31397c8c0b82SPatrick Mooney int err;
31407c8c0b82SPatrick Mooney
31417c8c0b82SPatrick Mooney if (minor == VMM_CTL_MINOR) {
31427c8c0b82SPatrick Mooney return (ENODEV);
31437c8c0b82SPatrick Mooney }
31447c8c0b82SPatrick Mooney if (off < 0 || (off + len) <= 0) {
31457c8c0b82SPatrick Mooney return (EINVAL);
31467c8c0b82SPatrick Mooney }
31477c8c0b82SPatrick Mooney if ((prot & PROT_USER) == 0) {
31487c8c0b82SPatrick Mooney return (EACCES);
31497c8c0b82SPatrick Mooney }
31507c8c0b82SPatrick Mooney
31517c8c0b82SPatrick Mooney sc = ddi_get_soft_state(vmm_statep, minor);
31527c8c0b82SPatrick Mooney ASSERT(sc);
31537c8c0b82SPatrick Mooney
31547c8c0b82SPatrick Mooney if (sc->vmm_flags & VMM_DESTROY)
31557c8c0b82SPatrick Mooney return (ENXIO);
31567c8c0b82SPatrick Mooney
31577c8c0b82SPatrick Mooney /* Grab read lock on the VM to prevent any changes to the memory map */
31587c8c0b82SPatrick Mooney vmm_read_lock(sc);
31597c8c0b82SPatrick Mooney
31607c8c0b82SPatrick Mooney if (off >= VM_DEVMEM_START) {
31617c8c0b82SPatrick Mooney int segid;
31627c8c0b82SPatrick Mooney off_t segoff;
31637c8c0b82SPatrick Mooney
31647c8c0b82SPatrick Mooney /* Mapping a devmem "device" */
31657c8c0b82SPatrick Mooney if (!vmmdev_devmem_segid(sc, off, len, &segid, &segoff)) {
31667c8c0b82SPatrick Mooney err = ENODEV;
31677c8c0b82SPatrick Mooney } else {
31687c8c0b82SPatrick Mooney err = vm_segmap_obj(sc->vmm_vm, segid, segoff, len, as,
31697c8c0b82SPatrick Mooney addrp, prot, maxprot, flags);
31707c8c0b82SPatrick Mooney }
31717c8c0b82SPatrick Mooney } else {
31727c8c0b82SPatrick Mooney /* Mapping a part of the guest physical space */
31737c8c0b82SPatrick Mooney err = vm_segmap_space(sc->vmm_vm, off, as, addrp, len, prot,
31747c8c0b82SPatrick Mooney maxprot, flags);
31757c8c0b82SPatrick Mooney }
31767c8c0b82SPatrick Mooney
31777c8c0b82SPatrick Mooney vmm_read_unlock(sc);
31787c8c0b82SPatrick Mooney return (err);
31797c8c0b82SPatrick Mooney }
31807c8c0b82SPatrick Mooney
31817c8c0b82SPatrick Mooney static sdev_plugin_validate_t
vmm_sdev_validate(sdev_ctx_t ctx)31827c8c0b82SPatrick Mooney vmm_sdev_validate(sdev_ctx_t ctx)
31837c8c0b82SPatrick Mooney {
31847c8c0b82SPatrick Mooney const char *name = sdev_ctx_name(ctx);
31857c8c0b82SPatrick Mooney vmm_softc_t *sc;
31867c8c0b82SPatrick Mooney sdev_plugin_validate_t ret;
31877c8c0b82SPatrick Mooney minor_t minor;
31887c8c0b82SPatrick Mooney
31897c8c0b82SPatrick Mooney if (sdev_ctx_vtype(ctx) != VCHR)
31907c8c0b82SPatrick Mooney return (SDEV_VTOR_INVALID);
31917c8c0b82SPatrick Mooney
31927c8c0b82SPatrick Mooney VERIFY3S(sdev_ctx_minor(ctx, &minor), ==, 0);
31937c8c0b82SPatrick Mooney
31947c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
31957c8c0b82SPatrick Mooney if ((sc = vmm_lookup(name)) == NULL)
31967c8c0b82SPatrick Mooney ret = SDEV_VTOR_INVALID;
31977c8c0b82SPatrick Mooney else if (sc->vmm_minor != minor)
31987c8c0b82SPatrick Mooney ret = SDEV_VTOR_STALE;
31997c8c0b82SPatrick Mooney else
32007c8c0b82SPatrick Mooney ret = SDEV_VTOR_VALID;
32017c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
32027c8c0b82SPatrick Mooney
32037c8c0b82SPatrick Mooney return (ret);
32047c8c0b82SPatrick Mooney }
32057c8c0b82SPatrick Mooney
32067c8c0b82SPatrick Mooney static int
vmm_sdev_filldir(sdev_ctx_t ctx)32077c8c0b82SPatrick Mooney vmm_sdev_filldir(sdev_ctx_t ctx)
32087c8c0b82SPatrick Mooney {
32097c8c0b82SPatrick Mooney vmm_softc_t *sc;
32107c8c0b82SPatrick Mooney int ret;
32117c8c0b82SPatrick Mooney
32127c8c0b82SPatrick Mooney if (strcmp(sdev_ctx_path(ctx), VMM_SDEV_ROOT) != 0) {
32137c8c0b82SPatrick Mooney cmn_err(CE_WARN, "%s: bad path '%s' != '%s'\n", __func__,
32147c8c0b82SPatrick Mooney sdev_ctx_path(ctx), VMM_SDEV_ROOT);
32157c8c0b82SPatrick Mooney return (EINVAL);
32167c8c0b82SPatrick Mooney }
32177c8c0b82SPatrick Mooney
32187c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
32197c8c0b82SPatrick Mooney ASSERT(vmmdev_dip != NULL);
32207c8c0b82SPatrick Mooney for (sc = list_head(&vmm_list); sc != NULL;
32217c8c0b82SPatrick Mooney sc = list_next(&vmm_list, sc)) {
32227c8c0b82SPatrick Mooney if (INGLOBALZONE(curproc) || sc->vmm_zone == curzone) {
32237c8c0b82SPatrick Mooney ret = sdev_plugin_mknod(ctx, sc->vmm_name,
32247c8c0b82SPatrick Mooney S_IFCHR | 0600,
32257c8c0b82SPatrick Mooney makedevice(ddi_driver_major(vmmdev_dip),
32267c8c0b82SPatrick Mooney sc->vmm_minor));
32277c8c0b82SPatrick Mooney } else {
32287c8c0b82SPatrick Mooney continue;
32297c8c0b82SPatrick Mooney }
32307c8c0b82SPatrick Mooney if (ret != 0 && ret != EEXIST)
32317c8c0b82SPatrick Mooney goto out;
32327c8c0b82SPatrick Mooney }
32337c8c0b82SPatrick Mooney
32347c8c0b82SPatrick Mooney ret = 0;
32357c8c0b82SPatrick Mooney
32367c8c0b82SPatrick Mooney out:
32377c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
32387c8c0b82SPatrick Mooney return (ret);
32397c8c0b82SPatrick Mooney }
32407c8c0b82SPatrick Mooney
32417c8c0b82SPatrick Mooney /* ARGSUSED */
32427c8c0b82SPatrick Mooney static void
vmm_sdev_inactive(sdev_ctx_t ctx)32437c8c0b82SPatrick Mooney vmm_sdev_inactive(sdev_ctx_t ctx)
32447c8c0b82SPatrick Mooney {
32457c8c0b82SPatrick Mooney }
32467c8c0b82SPatrick Mooney
32477c8c0b82SPatrick Mooney static sdev_plugin_ops_t vmm_sdev_ops = {
32487c8c0b82SPatrick Mooney .spo_version = SDEV_PLUGIN_VERSION,
32497c8c0b82SPatrick Mooney .spo_flags = SDEV_PLUGIN_SUBDIR,
32507c8c0b82SPatrick Mooney .spo_validate = vmm_sdev_validate,
32517c8c0b82SPatrick Mooney .spo_filldir = vmm_sdev_filldir,
32527c8c0b82SPatrick Mooney .spo_inactive = vmm_sdev_inactive
32537c8c0b82SPatrick Mooney };
32547c8c0b82SPatrick Mooney
32557c8c0b82SPatrick Mooney /* ARGSUSED */
32567c8c0b82SPatrick Mooney static int
vmm_info(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)32577c8c0b82SPatrick Mooney vmm_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
32587c8c0b82SPatrick Mooney {
32597c8c0b82SPatrick Mooney int error;
32607c8c0b82SPatrick Mooney
32617c8c0b82SPatrick Mooney switch (cmd) {
32627c8c0b82SPatrick Mooney case DDI_INFO_DEVT2DEVINFO:
32637c8c0b82SPatrick Mooney *result = (void *)vmmdev_dip;
32647c8c0b82SPatrick Mooney error = DDI_SUCCESS;
32657c8c0b82SPatrick Mooney break;
32667c8c0b82SPatrick Mooney case DDI_INFO_DEVT2INSTANCE:
32677c8c0b82SPatrick Mooney *result = (void *)0;
32687c8c0b82SPatrick Mooney error = DDI_SUCCESS;
32697c8c0b82SPatrick Mooney break;
32707c8c0b82SPatrick Mooney default:
32717c8c0b82SPatrick Mooney error = DDI_FAILURE;
32727c8c0b82SPatrick Mooney break;
32737c8c0b82SPatrick Mooney }
32747c8c0b82SPatrick Mooney return (error);
32757c8c0b82SPatrick Mooney }
32767c8c0b82SPatrick Mooney
32777c8c0b82SPatrick Mooney static int
vmm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)32787c8c0b82SPatrick Mooney vmm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
32797c8c0b82SPatrick Mooney {
32807c8c0b82SPatrick Mooney sdev_plugin_hdl_t sph;
32817c8c0b82SPatrick Mooney hma_reg_t *reg = NULL;
32827c8c0b82SPatrick Mooney boolean_t vmm_loaded = B_FALSE;
32837c8c0b82SPatrick Mooney
32847c8c0b82SPatrick Mooney if (cmd != DDI_ATTACH) {
32857c8c0b82SPatrick Mooney return (DDI_FAILURE);
32867c8c0b82SPatrick Mooney }
32877c8c0b82SPatrick Mooney
32887c8c0b82SPatrick Mooney mutex_enter(&vmmdev_mtx);
32897c8c0b82SPatrick Mooney /* Ensure we are not already attached. */
32907c8c0b82SPatrick Mooney if (vmmdev_dip != NULL) {
32917c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
32927c8c0b82SPatrick Mooney return (DDI_FAILURE);
32937c8c0b82SPatrick Mooney }
32947c8c0b82SPatrick Mooney
32957c8c0b82SPatrick Mooney vmm_sol_glue_init();
32967c8c0b82SPatrick Mooney
32977c8c0b82SPatrick Mooney /*
32987c8c0b82SPatrick Mooney * Perform temporary HMA registration to determine if the system
32997c8c0b82SPatrick Mooney * is capable.
33007c8c0b82SPatrick Mooney */
33017c8c0b82SPatrick Mooney if ((reg = hma_register(vmmdev_hvm_name)) == NULL) {
33027c8c0b82SPatrick Mooney goto fail;
33037c8c0b82SPatrick Mooney } else if (vmm_mod_load() != 0) {
33047c8c0b82SPatrick Mooney goto fail;
33057c8c0b82SPatrick Mooney }
33067c8c0b82SPatrick Mooney vmm_loaded = B_TRUE;
33077c8c0b82SPatrick Mooney hma_unregister(reg);
33087c8c0b82SPatrick Mooney reg = NULL;
33097c8c0b82SPatrick Mooney
33107c8c0b82SPatrick Mooney /* Create control node. Other nodes will be created on demand. */
33117c8c0b82SPatrick Mooney if (ddi_create_minor_node(dip, "ctl", S_IFCHR,
33127c8c0b82SPatrick Mooney VMM_CTL_MINOR, DDI_PSEUDO, 0) != 0) {
33137c8c0b82SPatrick Mooney goto fail;
33147c8c0b82SPatrick Mooney }
33157c8c0b82SPatrick Mooney
33167c8c0b82SPatrick Mooney sph = sdev_plugin_register(VMM_MODULE_NAME, &vmm_sdev_ops, NULL);
33177c8c0b82SPatrick Mooney if (sph == (sdev_plugin_hdl_t)NULL) {
33187c8c0b82SPatrick Mooney ddi_remove_minor_node(dip, NULL);
33197c8c0b82SPatrick Mooney goto fail;
33207c8c0b82SPatrick Mooney }
33217c8c0b82SPatrick Mooney
33227c8c0b82SPatrick Mooney ddi_report_dev(dip);
33237c8c0b82SPatrick Mooney vmmdev_sdev_hdl = sph;
33247c8c0b82SPatrick Mooney vmmdev_dip = dip;
33257c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
33267c8c0b82SPatrick Mooney return (DDI_SUCCESS);
33277c8c0b82SPatrick Mooney
33287c8c0b82SPatrick Mooney fail:
33297c8c0b82SPatrick Mooney if (vmm_loaded) {
33307c8c0b82SPatrick Mooney VERIFY0(vmm_mod_unload());
33317c8c0b82SPatrick Mooney }
33327c8c0b82SPatrick Mooney if (reg != NULL) {
33337c8c0b82SPatrick Mooney hma_unregister(reg);
33347c8c0b82SPatrick Mooney }
33357c8c0b82SPatrick Mooney vmm_sol_glue_cleanup();
33367c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
33377c8c0b82SPatrick Mooney return (DDI_FAILURE);
33387c8c0b82SPatrick Mooney }
33397c8c0b82SPatrick Mooney
33407c8c0b82SPatrick Mooney static int
vmm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)33417c8c0b82SPatrick Mooney vmm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
33427c8c0b82SPatrick Mooney {
33437c8c0b82SPatrick Mooney if (cmd != DDI_DETACH) {
33447c8c0b82SPatrick Mooney return (DDI_FAILURE);
33457c8c0b82SPatrick Mooney }
33467c8c0b82SPatrick Mooney
33477c8c0b82SPatrick Mooney /*
33487c8c0b82SPatrick Mooney * Ensure that all resources have been cleaned up.
33497c8c0b82SPatrick Mooney *
33507c8c0b82SPatrick Mooney * To prevent a deadlock with iommu_cleanup() we'll fail the detach if
33517c8c0b82SPatrick Mooney * vmmdev_mtx is already held. We can't wait for vmmdev_mtx with our
33527c8c0b82SPatrick Mooney * devinfo locked as iommu_cleanup() tries to recursively lock each
33537c8c0b82SPatrick Mooney * devinfo, including our own, while holding vmmdev_mtx.
33547c8c0b82SPatrick Mooney */
33557c8c0b82SPatrick Mooney if (mutex_tryenter(&vmmdev_mtx) == 0)
33567c8c0b82SPatrick Mooney return (DDI_FAILURE);
33577c8c0b82SPatrick Mooney
33587c8c0b82SPatrick Mooney mutex_enter(&vmm_mtx);
335942640e49SPatrick Mooney if (!list_is_empty(&vmm_list)) {
33607c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
33617c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
33627c8c0b82SPatrick Mooney return (DDI_FAILURE);
33637c8c0b82SPatrick Mooney }
33647c8c0b82SPatrick Mooney mutex_exit(&vmm_mtx);
33657c8c0b82SPatrick Mooney
33667c8c0b82SPatrick Mooney if (!vmmr_is_empty()) {
33677c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
33687c8c0b82SPatrick Mooney return (DDI_FAILURE);
33697c8c0b82SPatrick Mooney }
33707c8c0b82SPatrick Mooney
33717c8c0b82SPatrick Mooney VERIFY(vmmdev_sdev_hdl != (sdev_plugin_hdl_t)NULL);
33727c8c0b82SPatrick Mooney if (sdev_plugin_unregister(vmmdev_sdev_hdl) != 0) {
33737c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
33747c8c0b82SPatrick Mooney return (DDI_FAILURE);
33757c8c0b82SPatrick Mooney }
33767c8c0b82SPatrick Mooney vmmdev_sdev_hdl = (sdev_plugin_hdl_t)NULL;
33777c8c0b82SPatrick Mooney
33787c8c0b82SPatrick Mooney /* Remove the control node. */
33797c8c0b82SPatrick Mooney ddi_remove_minor_node(dip, "ctl");
33807c8c0b82SPatrick Mooney vmmdev_dip = NULL;
33817c8c0b82SPatrick Mooney
33827c8c0b82SPatrick Mooney VERIFY0(vmm_mod_unload());
33837c8c0b82SPatrick Mooney VERIFY3U(vmmdev_hma_reg, ==, NULL);
33847c8c0b82SPatrick Mooney vmm_sol_glue_cleanup();
33857c8c0b82SPatrick Mooney
33867c8c0b82SPatrick Mooney mutex_exit(&vmmdev_mtx);
33877c8c0b82SPatrick Mooney
33887c8c0b82SPatrick Mooney return (DDI_SUCCESS);
33897c8c0b82SPatrick Mooney }
33907c8c0b82SPatrick Mooney
33917c8c0b82SPatrick Mooney static struct cb_ops vmm_cb_ops = {
33927c8c0b82SPatrick Mooney vmm_open,
33937c8c0b82SPatrick Mooney vmm_close,
33947c8c0b82SPatrick Mooney nodev, /* strategy */
33957c8c0b82SPatrick Mooney nodev, /* print */
33967c8c0b82SPatrick Mooney nodev, /* dump */
33977c8c0b82SPatrick Mooney nodev, /* read */
33987c8c0b82SPatrick Mooney nodev, /* write */
33997c8c0b82SPatrick Mooney vmm_ioctl,
34007c8c0b82SPatrick Mooney nodev, /* devmap */
34017c8c0b82SPatrick Mooney nodev, /* mmap */
34027c8c0b82SPatrick Mooney vmm_segmap,
34037c8c0b82SPatrick Mooney nochpoll, /* poll */
34047c8c0b82SPatrick Mooney ddi_prop_op,
34057c8c0b82SPatrick Mooney NULL,
34067c8c0b82SPatrick Mooney D_NEW | D_MP | D_DEVMAP
34077c8c0b82SPatrick Mooney };
34087c8c0b82SPatrick Mooney
34097c8c0b82SPatrick Mooney static struct dev_ops vmm_ops = {
34107c8c0b82SPatrick Mooney DEVO_REV,
34117c8c0b82SPatrick Mooney 0,
34127c8c0b82SPatrick Mooney vmm_info,
34137c8c0b82SPatrick Mooney nulldev, /* identify */
34147c8c0b82SPatrick Mooney nulldev, /* probe */
34157c8c0b82SPatrick Mooney vmm_attach,
34167c8c0b82SPatrick Mooney vmm_detach,
34177c8c0b82SPatrick Mooney nodev, /* reset */
34187c8c0b82SPatrick Mooney &vmm_cb_ops,
34197c8c0b82SPatrick Mooney (struct bus_ops *)NULL
34207c8c0b82SPatrick Mooney };
34217c8c0b82SPatrick Mooney
34227c8c0b82SPatrick Mooney static struct modldrv modldrv = {
34237c8c0b82SPatrick Mooney &mod_driverops,
34247c8c0b82SPatrick Mooney "bhyve vmm",
34257c8c0b82SPatrick Mooney &vmm_ops
34267c8c0b82SPatrick Mooney };
34277c8c0b82SPatrick Mooney
34287c8c0b82SPatrick Mooney static struct modlinkage modlinkage = {
34297c8c0b82SPatrick Mooney MODREV_1,
34307c8c0b82SPatrick Mooney &modldrv,
34317c8c0b82SPatrick Mooney NULL
34327c8c0b82SPatrick Mooney };
34337c8c0b82SPatrick Mooney
34347c8c0b82SPatrick Mooney int
_init(void)34357c8c0b82SPatrick Mooney _init(void)
34367c8c0b82SPatrick Mooney {
34377c8c0b82SPatrick Mooney int error;
34387c8c0b82SPatrick Mooney
34397c8c0b82SPatrick Mooney sysinit();
34407c8c0b82SPatrick Mooney
34417c8c0b82SPatrick Mooney mutex_init(&vmmdev_mtx, NULL, MUTEX_DRIVER, NULL);
34427c8c0b82SPatrick Mooney mutex_init(&vmm_mtx, NULL, MUTEX_DRIVER, NULL);
34437c8c0b82SPatrick Mooney list_create(&vmm_list, sizeof (vmm_softc_t),
34447c8c0b82SPatrick Mooney offsetof(vmm_softc_t, vmm_node));
34457c8c0b82SPatrick Mooney vmm_minors = id_space_create("vmm_minors", VMM_CTL_MINOR + 1, MAXMIN32);
34467c8c0b82SPatrick Mooney
34477c8c0b82SPatrick Mooney error = ddi_soft_state_init(&vmm_statep, sizeof (vmm_softc_t), 0);
34487c8c0b82SPatrick Mooney if (error) {
34497c8c0b82SPatrick Mooney return (error);
34507c8c0b82SPatrick Mooney }
34517c8c0b82SPatrick Mooney
34526bba8b59SPatrick Mooney error = vmmr_init();
34536bba8b59SPatrick Mooney if (error) {
34546bba8b59SPatrick Mooney ddi_soft_state_fini(&vmm_statep);
34556bba8b59SPatrick Mooney return (error);
34566bba8b59SPatrick Mooney }
34576bba8b59SPatrick Mooney
34587c8c0b82SPatrick Mooney vmm_zsd_init();
34597c8c0b82SPatrick Mooney
34607c8c0b82SPatrick Mooney error = mod_install(&modlinkage);
34617c8c0b82SPatrick Mooney if (error) {
34627c8c0b82SPatrick Mooney ddi_soft_state_fini(&vmm_statep);
34637c8c0b82SPatrick Mooney vmm_zsd_fini();
34647c8c0b82SPatrick Mooney vmmr_fini();
34657c8c0b82SPatrick Mooney }
34667c8c0b82SPatrick Mooney
34677c8c0b82SPatrick Mooney return (error);
34687c8c0b82SPatrick Mooney }
34697c8c0b82SPatrick Mooney
34707c8c0b82SPatrick Mooney int
_fini(void)34717c8c0b82SPatrick Mooney _fini(void)
34727c8c0b82SPatrick Mooney {
34737c8c0b82SPatrick Mooney int error;
34747c8c0b82SPatrick Mooney
34757c8c0b82SPatrick Mooney error = mod_remove(&modlinkage);
34767c8c0b82SPatrick Mooney if (error) {
34777c8c0b82SPatrick Mooney return (error);
34787c8c0b82SPatrick Mooney }
34797c8c0b82SPatrick Mooney
34807c8c0b82SPatrick Mooney vmm_zsd_fini();
34817c8c0b82SPatrick Mooney vmmr_fini();
34827c8c0b82SPatrick Mooney
34837c8c0b82SPatrick Mooney ddi_soft_state_fini(&vmm_statep);
34847c8c0b82SPatrick Mooney
34857c8c0b82SPatrick Mooney return (0);
34867c8c0b82SPatrick Mooney }
34877c8c0b82SPatrick Mooney
34887c8c0b82SPatrick Mooney int
_info(struct modinfo * modinfop)34897c8c0b82SPatrick Mooney _info(struct modinfo *modinfop)
34907c8c0b82SPatrick Mooney {
34917c8c0b82SPatrick Mooney return (mod_info(&modlinkage, modinfop));
34927c8c0b82SPatrick Mooney }
3493