vmm_dev.c revision 234761
1221828Sgrehan/*- 2221828Sgrehan * Copyright (c) 2011 NetApp, Inc. 3221828Sgrehan * All rights reserved. 4221828Sgrehan * 5221828Sgrehan * Redistribution and use in source and binary forms, with or without 6221828Sgrehan * modification, are permitted provided that the following conditions 7221828Sgrehan * are met: 8221828Sgrehan * 1. Redistributions of source code must retain the above copyright 9221828Sgrehan * notice, this list of conditions and the following disclaimer. 10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11221828Sgrehan * notice, this list of conditions and the following disclaimer in the 12221828Sgrehan * documentation and/or other materials provided with the distribution. 13221828Sgrehan * 14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17221828Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24221828Sgrehan * SUCH DAMAGE. 25221828Sgrehan * 26221828Sgrehan * $FreeBSD$ 27221828Sgrehan */ 28221828Sgrehan 29221828Sgrehan#include <sys/cdefs.h> 30221828Sgrehan__FBSDID("$FreeBSD$"); 31221828Sgrehan 32221828Sgrehan#include <sys/param.h> 33221828Sgrehan#include <sys/kernel.h> 34221828Sgrehan#include <sys/queue.h> 35221828Sgrehan#include <sys/lock.h> 36221828Sgrehan#include <sys/mutex.h> 37221828Sgrehan#include <sys/malloc.h> 38221828Sgrehan#include <sys/conf.h> 39221828Sgrehan#include <sys/sysctl.h> 40221828Sgrehan#include <sys/libkern.h> 41221828Sgrehan#include <sys/ioccom.h> 42221828Sgrehan#include <sys/mman.h> 43221828Sgrehan#include <sys/uio.h> 44221828Sgrehan 45221828Sgrehan#include <vm/vm.h> 46221828Sgrehan#include <vm/pmap.h> 47221828Sgrehan 48221828Sgrehan#include <machine/pmap.h> 49221828Sgrehan#include <machine/vmparam.h> 50221828Sgrehan 51221828Sgrehan#include <machine/vmm.h> 52221828Sgrehan#include "vmm_lapic.h" 53221828Sgrehan#include "vmm_stat.h" 54221828Sgrehan#include "io/ppt.h" 55221828Sgrehan#include <machine/vmm_dev.h> 56221828Sgrehan 57221828Sgrehanstruct vmmdev_softc { 58221828Sgrehan struct vm *vm; /* vm instance cookie */ 59221828Sgrehan struct cdev *cdev; 60221828Sgrehan SLIST_ENTRY(vmmdev_softc) link; 61221828Sgrehan}; 62221828Sgrehanstatic SLIST_HEAD(, vmmdev_softc) head; 63221828Sgrehan 64221828Sgrehanstatic struct mtx vmmdev_mtx; 65221828Sgrehan 66221828Sgrehanstatic MALLOC_DEFINE(M_VMMDEV, "vmmdev", "vmmdev"); 67221828Sgrehan 68221828SgrehanSYSCTL_DECL(_hw_vmm); 69221828Sgrehan 70221828Sgrehanstatic struct vmmdev_softc * 71221828Sgrehanvmmdev_lookup(const char *name) 72221828Sgrehan{ 73221828Sgrehan struct vmmdev_softc *sc; 74221828Sgrehan 75221828Sgrehan#ifdef notyet /* XXX kernel is not compiled with invariants */ 76221828Sgrehan mtx_assert(&vmmdev_mtx, MA_OWNED); 77221828Sgrehan#endif 78221828Sgrehan 79221828Sgrehan SLIST_FOREACH(sc, &head, link) { 80221828Sgrehan if (strcmp(name, vm_name(sc->vm)) == 0) 81221828Sgrehan break; 82221828Sgrehan } 83221828Sgrehan 84221828Sgrehan return (sc); 85221828Sgrehan} 86221828Sgrehan 87221828Sgrehanstatic struct vmmdev_softc * 88221828Sgrehanvmmdev_lookup2(struct cdev *cdev) 89221828Sgrehan{ 90221828Sgrehan struct vmmdev_softc *sc; 91221828Sgrehan 92221828Sgrehan#ifdef notyet /* XXX kernel is not compiled with invariants */ 93221828Sgrehan mtx_assert(&vmmdev_mtx, MA_OWNED); 94221828Sgrehan#endif 95221828Sgrehan 96221828Sgrehan SLIST_FOREACH(sc, &head, link) { 97221828Sgrehan if (sc->cdev == cdev) 98221828Sgrehan break; 99221828Sgrehan } 100221828Sgrehan 101221828Sgrehan return (sc); 102221828Sgrehan} 103221828Sgrehan 104221828Sgrehanstatic int 105221828Sgrehanvmmdev_rw(struct cdev *cdev, struct uio *uio, int flags) 106221828Sgrehan{ 107221828Sgrehan int error, off, c; 108221828Sgrehan vm_paddr_t hpa, gpa; 109221828Sgrehan struct vmmdev_softc *sc; 110221828Sgrehan 111221828Sgrehan static char zerobuf[PAGE_SIZE]; 112221828Sgrehan 113221828Sgrehan error = 0; 114221828Sgrehan mtx_lock(&vmmdev_mtx); 115221828Sgrehan sc = vmmdev_lookup2(cdev); 116221828Sgrehan 117221828Sgrehan while (uio->uio_resid > 0 && error == 0) { 118221828Sgrehan gpa = uio->uio_offset; 119221828Sgrehan off = gpa & PAGE_MASK; 120221828Sgrehan c = min(uio->uio_resid, PAGE_SIZE - off); 121221828Sgrehan 122221828Sgrehan /* 123221828Sgrehan * The VM has a hole in its physical memory map. If we want to 124221828Sgrehan * use 'dd' to inspect memory beyond the hole we need to 125221828Sgrehan * provide bogus data for memory that lies in the hole. 126221828Sgrehan * 127221828Sgrehan * Since this device does not support lseek(2), dd(1) will 128221828Sgrehan * read(2) blocks of data to simulate the lseek(2). 129221828Sgrehan */ 130221828Sgrehan hpa = vm_gpa2hpa(sc->vm, gpa, c); 131221828Sgrehan if (hpa == (vm_paddr_t)-1) { 132221828Sgrehan if (uio->uio_rw == UIO_READ) 133221828Sgrehan error = uiomove(zerobuf, c, uio); 134221828Sgrehan else 135221828Sgrehan error = EFAULT; 136221828Sgrehan } else 137221828Sgrehan error = uiomove((void *)PHYS_TO_DMAP(hpa), c, uio); 138221828Sgrehan } 139221828Sgrehan 140221828Sgrehan mtx_unlock(&vmmdev_mtx); 141221828Sgrehan return (error); 142221828Sgrehan} 143221828Sgrehan 144221828Sgrehanstatic int 145221828Sgrehanvmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, 146221828Sgrehan struct thread *td) 147221828Sgrehan{ 148221828Sgrehan int error, vcpu; 149221828Sgrehan struct vmmdev_softc *sc; 150221828Sgrehan struct vm_memory_segment *seg; 151221828Sgrehan struct vm_register *vmreg; 152221828Sgrehan struct vm_seg_desc* vmsegdesc; 153221828Sgrehan struct vm_pin *vmpin; 154221828Sgrehan struct vm_run *vmrun; 155221828Sgrehan struct vm_event *vmevent; 156221828Sgrehan struct vm_lapic_irq *vmirq; 157221828Sgrehan struct vm_capability *vmcap; 158221828Sgrehan struct vm_pptdev *pptdev; 159221828Sgrehan struct vm_pptdev_mmio *pptmmio; 160221828Sgrehan struct vm_pptdev_msi *pptmsi; 161234761Sgrehan struct vm_pptdev_msix *pptmsix; 162221828Sgrehan struct vm_nmi *vmnmi; 163221828Sgrehan struct vm_stats *vmstats; 164221828Sgrehan struct vm_stat_desc *statdesc; 165221828Sgrehan 166221828Sgrehan mtx_lock(&vmmdev_mtx); 167221828Sgrehan sc = vmmdev_lookup2(cdev); 168221828Sgrehan if (sc == NULL) { 169221828Sgrehan mtx_unlock(&vmmdev_mtx); 170221828Sgrehan return (ENXIO); 171221828Sgrehan } 172221828Sgrehan 173221828Sgrehan /* 174221828Sgrehan * Some VMM ioctls can operate only on vcpus that are not running. 175221828Sgrehan */ 176221828Sgrehan switch (cmd) { 177221828Sgrehan case VM_RUN: 178221828Sgrehan case VM_SET_PINNING: 179221828Sgrehan case VM_GET_REGISTER: 180221828Sgrehan case VM_SET_REGISTER: 181221828Sgrehan case VM_GET_SEGMENT_DESCRIPTOR: 182221828Sgrehan case VM_SET_SEGMENT_DESCRIPTOR: 183221828Sgrehan case VM_INJECT_EVENT: 184221828Sgrehan case VM_GET_CAPABILITY: 185221828Sgrehan case VM_SET_CAPABILITY: 186221828Sgrehan case VM_PPTDEV_MSI: 187221828Sgrehan /* 188221828Sgrehan * XXX fragile, handle with care 189221828Sgrehan * Assumes that the first field of the ioctl data is the vcpu. 190221828Sgrehan */ 191221828Sgrehan vcpu = *(int *)data; 192221828Sgrehan if (vcpu < 0 || vcpu >= VM_MAXCPU) { 193221828Sgrehan error = EINVAL; 194221828Sgrehan goto done; 195221828Sgrehan } 196221828Sgrehan 197221828Sgrehan if (vcpu_is_running(sc->vm, vcpu, NULL)) { 198221828Sgrehan error = EBUSY; 199221828Sgrehan goto done; 200221828Sgrehan } 201221828Sgrehan break; 202221828Sgrehan default: 203221828Sgrehan break; 204221828Sgrehan } 205221828Sgrehan 206221828Sgrehan switch(cmd) { 207221828Sgrehan case VM_RUN: 208221828Sgrehan vmrun = (struct vm_run *)data; 209221828Sgrehan 210221828Sgrehan vm_set_run_state(sc->vm, vmrun->cpuid, VCPU_RUNNING); 211221828Sgrehan mtx_unlock(&vmmdev_mtx); 212221828Sgrehan 213221828Sgrehan error = vm_run(sc->vm, vmrun); 214221828Sgrehan 215221828Sgrehan mtx_lock(&vmmdev_mtx); 216221828Sgrehan vm_set_run_state(sc->vm, vmrun->cpuid, VCPU_STOPPED); 217221828Sgrehan break; 218221828Sgrehan case VM_STAT_DESC: { 219221828Sgrehan const char *desc; 220221828Sgrehan statdesc = (struct vm_stat_desc *)data; 221221828Sgrehan desc = vmm_stat_desc(statdesc->index); 222221828Sgrehan if (desc != NULL) { 223221828Sgrehan error = 0; 224221828Sgrehan strlcpy(statdesc->desc, desc, sizeof(statdesc->desc)); 225221828Sgrehan } else 226221828Sgrehan error = EINVAL; 227221828Sgrehan break; 228221828Sgrehan } 229221828Sgrehan case VM_STATS: { 230221828Sgrehan CTASSERT(MAX_VM_STATS >= MAX_VMM_STAT_TYPES); 231221828Sgrehan vmstats = (struct vm_stats *)data; 232221828Sgrehan getmicrotime(&vmstats->tv); 233221828Sgrehan error = vmm_stat_copy(sc->vm, vmstats->cpuid, 234221828Sgrehan &vmstats->num_entries, vmstats->statbuf); 235221828Sgrehan break; 236221828Sgrehan } 237221828Sgrehan case VM_PPTDEV_MSI: 238221828Sgrehan pptmsi = (struct vm_pptdev_msi *)data; 239221828Sgrehan error = ppt_setup_msi(sc->vm, pptmsi->vcpu, 240221828Sgrehan pptmsi->bus, pptmsi->slot, pptmsi->func, 241221828Sgrehan pptmsi->destcpu, pptmsi->vector, 242221828Sgrehan pptmsi->numvec); 243221828Sgrehan break; 244234761Sgrehan case VM_PPTDEV_MSIX: 245234761Sgrehan pptmsix = (struct vm_pptdev_msix *)data; 246234761Sgrehan error = ppt_setup_msix(sc->vm, pptmsix->vcpu, 247234761Sgrehan pptmsix->bus, pptmsix->slot, 248234761Sgrehan pptmsix->func, pptmsix->idx, 249234761Sgrehan pptmsix->msg, pptmsix->vector_control, 250234761Sgrehan pptmsix->addr); 251234761Sgrehan break; 252221828Sgrehan case VM_MAP_PPTDEV_MMIO: 253221828Sgrehan pptmmio = (struct vm_pptdev_mmio *)data; 254221828Sgrehan error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot, 255221828Sgrehan pptmmio->func, pptmmio->gpa, pptmmio->len, 256221828Sgrehan pptmmio->hpa); 257221828Sgrehan break; 258221828Sgrehan case VM_BIND_PPTDEV: 259221828Sgrehan pptdev = (struct vm_pptdev *)data; 260221828Sgrehan error = ppt_assign_device(sc->vm, pptdev->bus, pptdev->slot, 261221828Sgrehan pptdev->func); 262221828Sgrehan break; 263221828Sgrehan case VM_UNBIND_PPTDEV: 264221828Sgrehan pptdev = (struct vm_pptdev *)data; 265221828Sgrehan error = ppt_unassign_device(sc->vm, pptdev->bus, pptdev->slot, 266221828Sgrehan pptdev->func); 267221828Sgrehan break; 268221828Sgrehan case VM_INJECT_EVENT: 269221828Sgrehan vmevent = (struct vm_event *)data; 270221828Sgrehan error = vm_inject_event(sc->vm, vmevent->cpuid, vmevent->type, 271221828Sgrehan vmevent->vector, 272221828Sgrehan vmevent->error_code, 273221828Sgrehan vmevent->error_code_valid); 274221828Sgrehan break; 275221828Sgrehan case VM_INJECT_NMI: 276221828Sgrehan vmnmi = (struct vm_nmi *)data; 277221828Sgrehan error = vm_inject_nmi(sc->vm, vmnmi->cpuid); 278221828Sgrehan break; 279221828Sgrehan case VM_LAPIC_IRQ: 280221828Sgrehan vmirq = (struct vm_lapic_irq *)data; 281221828Sgrehan error = lapic_set_intr(sc->vm, vmirq->cpuid, vmirq->vector); 282221828Sgrehan break; 283221828Sgrehan case VM_SET_PINNING: 284221828Sgrehan vmpin = (struct vm_pin *)data; 285221828Sgrehan error = vm_set_pinning(sc->vm, vmpin->vm_cpuid, 286221828Sgrehan vmpin->host_cpuid); 287221828Sgrehan break; 288221828Sgrehan case VM_GET_PINNING: 289221828Sgrehan vmpin = (struct vm_pin *)data; 290221828Sgrehan error = vm_get_pinning(sc->vm, vmpin->vm_cpuid, 291221828Sgrehan &vmpin->host_cpuid); 292221828Sgrehan break; 293221828Sgrehan case VM_MAP_MEMORY: 294221828Sgrehan seg = (struct vm_memory_segment *)data; 295221828Sgrehan error = vm_malloc(sc->vm, seg->gpa, seg->len, &seg->hpa); 296221828Sgrehan break; 297221828Sgrehan case VM_GET_MEMORY_SEG: 298221828Sgrehan seg = (struct vm_memory_segment *)data; 299221828Sgrehan seg->hpa = seg->len = 0; 300221828Sgrehan (void)vm_gpabase2memseg(sc->vm, seg->gpa, seg); 301221828Sgrehan error = 0; 302221828Sgrehan break; 303221828Sgrehan case VM_GET_REGISTER: 304221828Sgrehan vmreg = (struct vm_register *)data; 305221828Sgrehan error = vm_get_register(sc->vm, vmreg->cpuid, vmreg->regnum, 306221828Sgrehan &vmreg->regval); 307221828Sgrehan break; 308221828Sgrehan case VM_SET_REGISTER: 309221828Sgrehan vmreg = (struct vm_register *)data; 310221828Sgrehan error = vm_set_register(sc->vm, vmreg->cpuid, vmreg->regnum, 311221828Sgrehan vmreg->regval); 312221828Sgrehan break; 313221828Sgrehan case VM_SET_SEGMENT_DESCRIPTOR: 314221828Sgrehan vmsegdesc = (struct vm_seg_desc *)data; 315221828Sgrehan error = vm_set_seg_desc(sc->vm, vmsegdesc->cpuid, 316221828Sgrehan vmsegdesc->regnum, 317221828Sgrehan &vmsegdesc->desc); 318221828Sgrehan break; 319221828Sgrehan case VM_GET_SEGMENT_DESCRIPTOR: 320221828Sgrehan vmsegdesc = (struct vm_seg_desc *)data; 321221828Sgrehan error = vm_get_seg_desc(sc->vm, vmsegdesc->cpuid, 322221828Sgrehan vmsegdesc->regnum, 323221828Sgrehan &vmsegdesc->desc); 324221828Sgrehan break; 325221828Sgrehan case VM_GET_CAPABILITY: 326221828Sgrehan vmcap = (struct vm_capability *)data; 327221828Sgrehan error = vm_get_capability(sc->vm, vmcap->cpuid, 328221828Sgrehan vmcap->captype, 329221828Sgrehan &vmcap->capval); 330221828Sgrehan break; 331221828Sgrehan case VM_SET_CAPABILITY: 332221828Sgrehan vmcap = (struct vm_capability *)data; 333221828Sgrehan error = vm_set_capability(sc->vm, vmcap->cpuid, 334221828Sgrehan vmcap->captype, 335221828Sgrehan vmcap->capval); 336221828Sgrehan break; 337221828Sgrehan default: 338221828Sgrehan error = ENOTTY; 339221828Sgrehan break; 340221828Sgrehan } 341221828Sgrehandone: 342221828Sgrehan mtx_unlock(&vmmdev_mtx); 343221828Sgrehan 344221828Sgrehan return (error); 345221828Sgrehan} 346221828Sgrehan 347221828Sgrehanstatic int 348221914Sjhbvmmdev_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr, 349221914Sjhb int nprot, vm_memattr_t *memattr) 350221828Sgrehan{ 351221828Sgrehan int error; 352221828Sgrehan struct vmmdev_softc *sc; 353221828Sgrehan 354221828Sgrehan error = -1; 355221828Sgrehan mtx_lock(&vmmdev_mtx); 356221828Sgrehan 357221828Sgrehan sc = vmmdev_lookup2(cdev); 358221828Sgrehan if (sc != NULL && (nprot & PROT_EXEC) == 0) { 359221828Sgrehan *paddr = vm_gpa2hpa(sc->vm, (vm_paddr_t)offset, PAGE_SIZE); 360221828Sgrehan if (*paddr != (vm_paddr_t)-1) 361221828Sgrehan error = 0; 362221828Sgrehan } 363221828Sgrehan 364221828Sgrehan mtx_unlock(&vmmdev_mtx); 365221828Sgrehan 366221828Sgrehan return (error); 367221828Sgrehan} 368221828Sgrehan 369221828Sgrehanstatic void 370221828Sgrehanvmmdev_destroy(struct vmmdev_softc *sc) 371221828Sgrehan{ 372221828Sgrehan 373221828Sgrehan#ifdef notyet /* XXX kernel is not compiled with invariants */ 374221828Sgrehan mtx_assert(&vmmdev_mtx, MA_OWNED); 375221828Sgrehan#endif 376221828Sgrehan 377221828Sgrehan /* 378221828Sgrehan * XXX must stop virtual machine instances that may be still 379221828Sgrehan * running and cleanup their state. 380221828Sgrehan */ 381221828Sgrehan SLIST_REMOVE(&head, sc, vmmdev_softc, link); 382221828Sgrehan destroy_dev(sc->cdev); 383221828Sgrehan vm_destroy(sc->vm); 384221828Sgrehan free(sc, M_VMMDEV); 385221828Sgrehan} 386221828Sgrehan 387221828Sgrehanstatic int 388221828Sgrehansysctl_vmm_destroy(SYSCTL_HANDLER_ARGS) 389221828Sgrehan{ 390221828Sgrehan int error; 391221828Sgrehan char buf[VM_MAX_NAMELEN]; 392221828Sgrehan struct vmmdev_softc *sc; 393221828Sgrehan 394221828Sgrehan strlcpy(buf, "beavis", sizeof(buf)); 395221828Sgrehan error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 396221828Sgrehan if (error != 0 || req->newptr == NULL) 397221828Sgrehan return (error); 398221828Sgrehan 399221828Sgrehan mtx_lock(&vmmdev_mtx); 400221828Sgrehan sc = vmmdev_lookup(buf); 401221828Sgrehan if (sc == NULL) { 402221828Sgrehan mtx_unlock(&vmmdev_mtx); 403221828Sgrehan return (EINVAL); 404221828Sgrehan } 405221828Sgrehan vmmdev_destroy(sc); 406221828Sgrehan mtx_unlock(&vmmdev_mtx); 407221828Sgrehan return (0); 408221828Sgrehan} 409221828SgrehanSYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW, 410221828Sgrehan NULL, 0, sysctl_vmm_destroy, "A", NULL); 411221828Sgrehan 412221828Sgrehanstatic struct cdevsw vmmdevsw = { 413221828Sgrehan .d_name = "vmmdev", 414221828Sgrehan .d_version = D_VERSION, 415221828Sgrehan .d_ioctl = vmmdev_ioctl, 416221828Sgrehan .d_mmap = vmmdev_mmap, 417221828Sgrehan .d_read = vmmdev_rw, 418221828Sgrehan .d_write = vmmdev_rw, 419221828Sgrehan}; 420221828Sgrehan 421221828Sgrehanstatic int 422221828Sgrehansysctl_vmm_create(SYSCTL_HANDLER_ARGS) 423221828Sgrehan{ 424221828Sgrehan int error; 425221828Sgrehan struct vm *vm; 426221828Sgrehan struct vmmdev_softc *sc; 427221828Sgrehan char buf[VM_MAX_NAMELEN]; 428221828Sgrehan 429221828Sgrehan strlcpy(buf, "beavis", sizeof(buf)); 430221828Sgrehan error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 431221828Sgrehan if (error != 0 || req->newptr == NULL) 432221828Sgrehan return (error); 433221828Sgrehan 434221828Sgrehan mtx_lock(&vmmdev_mtx); 435221828Sgrehan 436221828Sgrehan sc = vmmdev_lookup(buf); 437221828Sgrehan if (sc != NULL) { 438221828Sgrehan mtx_unlock(&vmmdev_mtx); 439221828Sgrehan return (EEXIST); 440221828Sgrehan } 441221828Sgrehan 442221828Sgrehan vm = vm_create(buf); 443221828Sgrehan if (vm == NULL) { 444221828Sgrehan mtx_unlock(&vmmdev_mtx); 445221828Sgrehan return (EINVAL); 446221828Sgrehan } 447221828Sgrehan 448221828Sgrehan sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO); 449221828Sgrehan sc->vm = vm; 450221828Sgrehan sc->cdev = make_dev(&vmmdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 451221828Sgrehan "vmm/%s", buf); 452221828Sgrehan sc->cdev->si_drv1 = sc; 453221828Sgrehan SLIST_INSERT_HEAD(&head, sc, link); 454221828Sgrehan 455221828Sgrehan mtx_unlock(&vmmdev_mtx); 456221828Sgrehan return (0); 457221828Sgrehan} 458221828SgrehanSYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW, 459221828Sgrehan NULL, 0, sysctl_vmm_create, "A", NULL); 460221828Sgrehan 461221828Sgrehanvoid 462221828Sgrehanvmmdev_init(void) 463221828Sgrehan{ 464221828Sgrehan mtx_init(&vmmdev_mtx, "vmm device mutex", NULL, MTX_DEF); 465221828Sgrehan} 466221828Sgrehan 467221828Sgrehanvoid 468221828Sgrehanvmmdev_cleanup(void) 469221828Sgrehan{ 470221828Sgrehan struct vmmdev_softc *sc, *sc2; 471221828Sgrehan 472221828Sgrehan mtx_lock(&vmmdev_mtx); 473221828Sgrehan 474221828Sgrehan SLIST_FOREACH_SAFE(sc, &head, link, sc2) 475221828Sgrehan vmmdev_destroy(sc); 476221828Sgrehan 477221828Sgrehan mtx_unlock(&vmmdev_mtx); 478221828Sgrehan} 479