The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/amd64/vmm/vmm_dev.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2011 NetApp, Inc.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: releng/10.1/sys/amd64/vmm/vmm_dev.c 270159 2014-08-19 01:20:24Z grehan $
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/10.1/sys/amd64/vmm/vmm_dev.c 270159 2014-08-19 01:20:24Z grehan $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/kernel.h>
   34 #include <sys/queue.h>
   35 #include <sys/lock.h>
   36 #include <sys/mutex.h>
   37 #include <sys/malloc.h>
   38 #include <sys/conf.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/libkern.h>
   41 #include <sys/ioccom.h>
   42 #include <sys/mman.h>
   43 #include <sys/uio.h>
   44 
   45 #include <vm/vm.h>
   46 #include <vm/pmap.h>
   47 #include <vm/vm_map.h>
   48 
   49 #include <machine/vmparam.h>
   50 #include <machine/vmm.h>
   51 #include <machine/vmm_instruction_emul.h>
   52 #include <machine/vmm_dev.h>
   53 
   54 #include "vmm_lapic.h"
   55 #include "vmm_stat.h"
   56 #include "vmm_mem.h"
   57 #include "io/ppt.h"
   58 #include "io/vatpic.h"
   59 #include "io/vioapic.h"
   60 #include "io/vhpet.h"
   61 
   62 struct vmmdev_softc {
   63         struct vm       *vm;            /* vm instance cookie */
   64         struct cdev     *cdev;
   65         SLIST_ENTRY(vmmdev_softc) link;
   66         int             flags;
   67 };
   68 #define VSC_LINKED              0x01
   69 
   70 static SLIST_HEAD(, vmmdev_softc) head;
   71 
   72 static struct mtx vmmdev_mtx;
   73 
   74 static MALLOC_DEFINE(M_VMMDEV, "vmmdev", "vmmdev");
   75 
   76 SYSCTL_DECL(_hw_vmm);
   77 
   78 static struct vmmdev_softc *
   79 vmmdev_lookup(const char *name)
   80 {
   81         struct vmmdev_softc *sc;
   82 
   83 #ifdef notyet   /* XXX kernel is not compiled with invariants */
   84         mtx_assert(&vmmdev_mtx, MA_OWNED);
   85 #endif
   86 
   87         SLIST_FOREACH(sc, &head, link) {
   88                 if (strcmp(name, vm_name(sc->vm)) == 0)
   89                         break;
   90         }
   91 
   92         return (sc);
   93 }
   94 
   95 static struct vmmdev_softc *
   96 vmmdev_lookup2(struct cdev *cdev)
   97 {
   98 
   99         return (cdev->si_drv1);
  100 }
  101 
  102 static int
  103 vmmdev_rw(struct cdev *cdev, struct uio *uio, int flags)
  104 {
  105         int error, off, c, prot;
  106         vm_paddr_t gpa;
  107         void *hpa, *cookie;
  108         struct vmmdev_softc *sc;
  109 
  110         static char zerobuf[PAGE_SIZE];
  111 
  112         error = 0;
  113         sc = vmmdev_lookup2(cdev);
  114         if (sc == NULL)
  115                 error = ENXIO;
  116 
  117         prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ);
  118         while (uio->uio_resid > 0 && error == 0) {
  119                 gpa = uio->uio_offset;
  120                 off = gpa & PAGE_MASK;
  121                 c = min(uio->uio_resid, PAGE_SIZE - off);
  122 
  123                 /*
  124                  * The VM has a hole in its physical memory map. If we want to
  125                  * use 'dd' to inspect memory beyond the hole we need to
  126                  * provide bogus data for memory that lies in the hole.
  127                  *
  128                  * Since this device does not support lseek(2), dd(1) will
  129                  * read(2) blocks of data to simulate the lseek(2).
  130                  */
  131                 hpa = vm_gpa_hold(sc->vm, gpa, c, prot, &cookie);
  132                 if (hpa == NULL) {
  133                         if (uio->uio_rw == UIO_READ)
  134                                 error = uiomove(zerobuf, c, uio);
  135                         else
  136                                 error = EFAULT;
  137                 } else {
  138                         error = uiomove(hpa, c, uio);
  139                         vm_gpa_release(cookie);
  140                 }
  141         }
  142         return (error);
  143 }
  144 
  145 static int
  146 vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
  147              struct thread *td)
  148 {
  149         int error, vcpu, state_changed, size;
  150         cpuset_t *cpuset;
  151         struct vmmdev_softc *sc;
  152         struct vm_memory_segment *seg;
  153         struct vm_register *vmreg;
  154         struct vm_seg_desc *vmsegdesc;
  155         struct vm_run *vmrun;
  156         struct vm_exception *vmexc;
  157         struct vm_lapic_irq *vmirq;
  158         struct vm_lapic_msi *vmmsi;
  159         struct vm_ioapic_irq *ioapic_irq;
  160         struct vm_isa_irq *isa_irq;
  161         struct vm_isa_irq_trigger *isa_irq_trigger;
  162         struct vm_capability *vmcap;
  163         struct vm_pptdev *pptdev;
  164         struct vm_pptdev_mmio *pptmmio;
  165         struct vm_pptdev_msi *pptmsi;
  166         struct vm_pptdev_msix *pptmsix;
  167         struct vm_nmi *vmnmi;
  168         struct vm_stats *vmstats;
  169         struct vm_stat_desc *statdesc;
  170         struct vm_x2apic *x2apic;
  171         struct vm_gpa_pte *gpapte;
  172         struct vm_suspend *vmsuspend;
  173         struct vm_gla2gpa *gg;
  174         struct vm_activate_cpu *vac;
  175         struct vm_cpuset *vm_cpuset;
  176         struct vm_intinfo *vmii;
  177 
  178         sc = vmmdev_lookup2(cdev);
  179         if (sc == NULL)
  180                 return (ENXIO);
  181 
  182         error = 0;
  183         vcpu = -1;
  184         state_changed = 0;
  185 
  186         /*
  187          * Some VMM ioctls can operate only on vcpus that are not running.
  188          */
  189         switch (cmd) {
  190         case VM_RUN:
  191         case VM_GET_REGISTER:
  192         case VM_SET_REGISTER:
  193         case VM_GET_SEGMENT_DESCRIPTOR:
  194         case VM_SET_SEGMENT_DESCRIPTOR:
  195         case VM_INJECT_EXCEPTION:
  196         case VM_GET_CAPABILITY:
  197         case VM_SET_CAPABILITY:
  198         case VM_PPTDEV_MSI:
  199         case VM_PPTDEV_MSIX:
  200         case VM_SET_X2APIC_STATE:
  201         case VM_GLA2GPA:
  202         case VM_ACTIVATE_CPU:
  203         case VM_SET_INTINFO:
  204         case VM_GET_INTINFO:
  205                 /*
  206                  * XXX fragile, handle with care
  207                  * Assumes that the first field of the ioctl data is the vcpu.
  208                  */
  209                 vcpu = *(int *)data;
  210                 if (vcpu < 0 || vcpu >= VM_MAXCPU) {
  211                         error = EINVAL;
  212                         goto done;
  213                 }
  214 
  215                 error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true);
  216                 if (error)
  217                         goto done;
  218 
  219                 state_changed = 1;
  220                 break;
  221 
  222         case VM_MAP_PPTDEV_MMIO:
  223         case VM_BIND_PPTDEV:
  224         case VM_UNBIND_PPTDEV:
  225         case VM_MAP_MEMORY:
  226         case VM_REINIT:
  227                 /*
  228                  * ioctls that operate on the entire virtual machine must
  229                  * prevent all vcpus from running.
  230                  */
  231                 error = 0;
  232                 for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) {
  233                         error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true);
  234                         if (error)
  235                                 break;
  236                 }
  237 
  238                 if (error) {
  239                         while (--vcpu >= 0)
  240                                 vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false);
  241                         goto done;
  242                 }
  243 
  244                 state_changed = 2;
  245                 break;
  246 
  247         default:
  248                 break;
  249         }
  250 
  251         switch(cmd) {
  252         case VM_RUN:
  253                 vmrun = (struct vm_run *)data;
  254                 error = vm_run(sc->vm, vmrun);
  255                 break;
  256         case VM_SUSPEND:
  257                 vmsuspend = (struct vm_suspend *)data;
  258                 error = vm_suspend(sc->vm, vmsuspend->how);
  259                 break;
  260         case VM_REINIT:
  261                 error = vm_reinit(sc->vm);
  262                 break;
  263         case VM_STAT_DESC: {
  264                 statdesc = (struct vm_stat_desc *)data;
  265                 error = vmm_stat_desc_copy(statdesc->index,
  266                                         statdesc->desc, sizeof(statdesc->desc));
  267                 break;
  268         }
  269         case VM_STATS: {
  270                 CTASSERT(MAX_VM_STATS >= MAX_VMM_STAT_ELEMS);
  271                 vmstats = (struct vm_stats *)data;
  272                 getmicrotime(&vmstats->tv);
  273                 error = vmm_stat_copy(sc->vm, vmstats->cpuid,
  274                                       &vmstats->num_entries, vmstats->statbuf);
  275                 break;
  276         }
  277         case VM_PPTDEV_MSI:
  278                 pptmsi = (struct vm_pptdev_msi *)data;
  279                 error = ppt_setup_msi(sc->vm, pptmsi->vcpu,
  280                                       pptmsi->bus, pptmsi->slot, pptmsi->func,
  281                                       pptmsi->addr, pptmsi->msg,
  282                                       pptmsi->numvec);
  283                 break;
  284         case VM_PPTDEV_MSIX:
  285                 pptmsix = (struct vm_pptdev_msix *)data;
  286                 error = ppt_setup_msix(sc->vm, pptmsix->vcpu,
  287                                        pptmsix->bus, pptmsix->slot, 
  288                                        pptmsix->func, pptmsix->idx,
  289                                        pptmsix->addr, pptmsix->msg,
  290                                        pptmsix->vector_control);
  291                 break;
  292         case VM_MAP_PPTDEV_MMIO:
  293                 pptmmio = (struct vm_pptdev_mmio *)data;
  294                 error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot,
  295                                      pptmmio->func, pptmmio->gpa, pptmmio->len,
  296                                      pptmmio->hpa);
  297                 break;
  298         case VM_BIND_PPTDEV:
  299                 pptdev = (struct vm_pptdev *)data;
  300                 error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
  301                                          pptdev->func);
  302                 break;
  303         case VM_UNBIND_PPTDEV:
  304                 pptdev = (struct vm_pptdev *)data;
  305                 error = vm_unassign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
  306                                            pptdev->func);
  307                 break;
  308         case VM_INJECT_EXCEPTION:
  309                 vmexc = (struct vm_exception *)data;
  310                 error = vm_inject_exception(sc->vm, vmexc->cpuid, vmexc);
  311                 break;
  312         case VM_INJECT_NMI:
  313                 vmnmi = (struct vm_nmi *)data;
  314                 error = vm_inject_nmi(sc->vm, vmnmi->cpuid);
  315                 break;
  316         case VM_LAPIC_IRQ:
  317                 vmirq = (struct vm_lapic_irq *)data;
  318                 error = lapic_intr_edge(sc->vm, vmirq->cpuid, vmirq->vector);
  319                 break;
  320         case VM_LAPIC_LOCAL_IRQ:
  321                 vmirq = (struct vm_lapic_irq *)data;
  322                 error = lapic_set_local_intr(sc->vm, vmirq->cpuid,
  323                     vmirq->vector);
  324                 break;
  325         case VM_LAPIC_MSI:
  326                 vmmsi = (struct vm_lapic_msi *)data;
  327                 error = lapic_intr_msi(sc->vm, vmmsi->addr, vmmsi->msg);
  328                 break;
  329         case VM_IOAPIC_ASSERT_IRQ:
  330                 ioapic_irq = (struct vm_ioapic_irq *)data;
  331                 error = vioapic_assert_irq(sc->vm, ioapic_irq->irq);
  332                 break;
  333         case VM_IOAPIC_DEASSERT_IRQ:
  334                 ioapic_irq = (struct vm_ioapic_irq *)data;
  335                 error = vioapic_deassert_irq(sc->vm, ioapic_irq->irq);
  336                 break;
  337         case VM_IOAPIC_PULSE_IRQ:
  338                 ioapic_irq = (struct vm_ioapic_irq *)data;
  339                 error = vioapic_pulse_irq(sc->vm, ioapic_irq->irq);
  340                 break;
  341         case VM_IOAPIC_PINCOUNT:
  342                 *(int *)data = vioapic_pincount(sc->vm);
  343                 break;
  344         case VM_ISA_ASSERT_IRQ:
  345                 isa_irq = (struct vm_isa_irq *)data;
  346                 error = vatpic_assert_irq(sc->vm, isa_irq->atpic_irq);
  347                 if (error == 0 && isa_irq->ioapic_irq != -1)
  348                         error = vioapic_assert_irq(sc->vm,
  349                             isa_irq->ioapic_irq);
  350                 break;
  351         case VM_ISA_DEASSERT_IRQ:
  352                 isa_irq = (struct vm_isa_irq *)data;
  353                 error = vatpic_deassert_irq(sc->vm, isa_irq->atpic_irq);
  354                 if (error == 0 && isa_irq->ioapic_irq != -1)
  355                         error = vioapic_deassert_irq(sc->vm,
  356                             isa_irq->ioapic_irq);
  357                 break;
  358         case VM_ISA_PULSE_IRQ:
  359                 isa_irq = (struct vm_isa_irq *)data;
  360                 error = vatpic_pulse_irq(sc->vm, isa_irq->atpic_irq);
  361                 if (error == 0 && isa_irq->ioapic_irq != -1)
  362                         error = vioapic_pulse_irq(sc->vm, isa_irq->ioapic_irq);
  363                 break;
  364         case VM_ISA_SET_IRQ_TRIGGER:
  365                 isa_irq_trigger = (struct vm_isa_irq_trigger *)data;
  366                 error = vatpic_set_irq_trigger(sc->vm,
  367                     isa_irq_trigger->atpic_irq, isa_irq_trigger->trigger);
  368                 break;
  369         case VM_MAP_MEMORY:
  370                 seg = (struct vm_memory_segment *)data;
  371                 error = vm_malloc(sc->vm, seg->gpa, seg->len);
  372                 break;
  373         case VM_GET_MEMORY_SEG:
  374                 seg = (struct vm_memory_segment *)data;
  375                 seg->len = 0;
  376                 (void)vm_gpabase2memseg(sc->vm, seg->gpa, seg);
  377                 error = 0;
  378                 break;
  379         case VM_GET_REGISTER:
  380                 vmreg = (struct vm_register *)data;
  381                 error = vm_get_register(sc->vm, vmreg->cpuid, vmreg->regnum,
  382                                         &vmreg->regval);
  383                 break;
  384         case VM_SET_REGISTER:
  385                 vmreg = (struct vm_register *)data;
  386                 error = vm_set_register(sc->vm, vmreg->cpuid, vmreg->regnum,
  387                                         vmreg->regval);
  388                 break;
  389         case VM_SET_SEGMENT_DESCRIPTOR:
  390                 vmsegdesc = (struct vm_seg_desc *)data;
  391                 error = vm_set_seg_desc(sc->vm, vmsegdesc->cpuid,
  392                                         vmsegdesc->regnum,
  393                                         &vmsegdesc->desc);
  394                 break;
  395         case VM_GET_SEGMENT_DESCRIPTOR:
  396                 vmsegdesc = (struct vm_seg_desc *)data;
  397                 error = vm_get_seg_desc(sc->vm, vmsegdesc->cpuid,
  398                                         vmsegdesc->regnum,
  399                                         &vmsegdesc->desc);
  400                 break;
  401         case VM_GET_CAPABILITY:
  402                 vmcap = (struct vm_capability *)data;
  403                 error = vm_get_capability(sc->vm, vmcap->cpuid,
  404                                           vmcap->captype,
  405                                           &vmcap->capval);
  406                 break;
  407         case VM_SET_CAPABILITY:
  408                 vmcap = (struct vm_capability *)data;
  409                 error = vm_set_capability(sc->vm, vmcap->cpuid,
  410                                           vmcap->captype,
  411                                           vmcap->capval);
  412                 break;
  413         case VM_SET_X2APIC_STATE:
  414                 x2apic = (struct vm_x2apic *)data;
  415                 error = vm_set_x2apic_state(sc->vm,
  416                                             x2apic->cpuid, x2apic->state);
  417                 break;
  418         case VM_GET_X2APIC_STATE:
  419                 x2apic = (struct vm_x2apic *)data;
  420                 error = vm_get_x2apic_state(sc->vm,
  421                                             x2apic->cpuid, &x2apic->state);
  422                 break;
  423         case VM_GET_GPA_PMAP:
  424                 gpapte = (struct vm_gpa_pte *)data;
  425                 pmap_get_mapping(vmspace_pmap(vm_get_vmspace(sc->vm)),
  426                                  gpapte->gpa, gpapte->pte, &gpapte->ptenum);
  427                 error = 0;
  428                 break;
  429         case VM_GET_HPET_CAPABILITIES:
  430                 error = vhpet_getcap((struct vm_hpet_cap *)data);
  431                 break;
  432         case VM_GLA2GPA: {
  433                 CTASSERT(PROT_READ == VM_PROT_READ);
  434                 CTASSERT(PROT_WRITE == VM_PROT_WRITE);
  435                 CTASSERT(PROT_EXEC == VM_PROT_EXECUTE);
  436                 gg = (struct vm_gla2gpa *)data;
  437                 error = vmm_gla2gpa(sc->vm, gg->vcpuid, &gg->paging, gg->gla,
  438                     gg->prot, &gg->gpa);
  439                 KASSERT(error == 0 || error == 1 || error == -1,
  440                     ("%s: vmm_gla2gpa unknown error %d", __func__, error));
  441                 if (error >= 0) {
  442                         /*
  443                          * error = 0: the translation was successful
  444                          * error = 1: a fault was injected into the guest
  445                          */
  446                         gg->fault = error;
  447                         error = 0;
  448                 } else {
  449                         error = EFAULT;
  450                 }
  451                 break;
  452         }
  453         case VM_ACTIVATE_CPU:
  454                 vac = (struct vm_activate_cpu *)data;
  455                 error = vm_activate_cpu(sc->vm, vac->vcpuid);
  456                 break;
  457         case VM_GET_CPUS:
  458                 error = 0;
  459                 vm_cpuset = (struct vm_cpuset *)data;
  460                 size = vm_cpuset->cpusetsize;
  461                 if (size < sizeof(cpuset_t) || size > CPU_MAXSIZE / NBBY) {
  462                         error = ERANGE;
  463                         break;
  464                 }
  465                 cpuset = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
  466                 if (vm_cpuset->which == VM_ACTIVE_CPUS)
  467                         *cpuset = vm_active_cpus(sc->vm);
  468                 else if (vm_cpuset->which == VM_SUSPENDED_CPUS)
  469                         *cpuset = vm_suspended_cpus(sc->vm);
  470                 else
  471                         error = EINVAL;
  472                 if (error == 0)
  473                         error = copyout(cpuset, vm_cpuset->cpus, size);
  474                 free(cpuset, M_TEMP);
  475                 break;
  476         case VM_SET_INTINFO:
  477                 vmii = (struct vm_intinfo *)data;
  478                 error = vm_exit_intinfo(sc->vm, vmii->vcpuid, vmii->info1);
  479                 break;
  480         case VM_GET_INTINFO:
  481                 vmii = (struct vm_intinfo *)data;
  482                 error = vm_get_intinfo(sc->vm, vmii->vcpuid, &vmii->info1,
  483                     &vmii->info2);
  484                 break;
  485         default:
  486                 error = ENOTTY;
  487                 break;
  488         }
  489 
  490         if (state_changed == 1) {
  491                 vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false);
  492         } else if (state_changed == 2) {
  493                 for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++)
  494                         vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false);
  495         }
  496 
  497 done:
  498         /* Make sure that no handler returns a bogus value like ERESTART */
  499         KASSERT(error >= 0, ("vmmdev_ioctl: invalid error return %d", error));
  500         return (error);
  501 }
  502 
  503 static int
  504 vmmdev_mmap_single(struct cdev *cdev, vm_ooffset_t *offset,
  505                    vm_size_t size, struct vm_object **object, int nprot)
  506 {
  507         int error;
  508         struct vmmdev_softc *sc;
  509 
  510         sc = vmmdev_lookup2(cdev);
  511         if (sc != NULL && (nprot & PROT_EXEC) == 0)
  512                 error = vm_get_memobj(sc->vm, *offset, size, offset, object);
  513         else
  514                 error = EINVAL;
  515 
  516         return (error);
  517 }
  518 
  519 static void
  520 vmmdev_destroy(void *arg)
  521 {
  522 
  523         struct vmmdev_softc *sc = arg;
  524 
  525         if (sc->cdev != NULL)
  526                 destroy_dev(sc->cdev);
  527 
  528         if (sc->vm != NULL)
  529                 vm_destroy(sc->vm);
  530 
  531         if ((sc->flags & VSC_LINKED) != 0) {
  532                 mtx_lock(&vmmdev_mtx);
  533                 SLIST_REMOVE(&head, sc, vmmdev_softc, link);
  534                 mtx_unlock(&vmmdev_mtx);
  535         }
  536 
  537         free(sc, M_VMMDEV);
  538 }
  539 
  540 static int
  541 sysctl_vmm_destroy(SYSCTL_HANDLER_ARGS)
  542 {
  543         int error;
  544         char buf[VM_MAX_NAMELEN];
  545         struct vmmdev_softc *sc;
  546         struct cdev *cdev;
  547 
  548         strlcpy(buf, "beavis", sizeof(buf));
  549         error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
  550         if (error != 0 || req->newptr == NULL)
  551                 return (error);
  552 
  553         mtx_lock(&vmmdev_mtx);
  554         sc = vmmdev_lookup(buf);
  555         if (sc == NULL || sc->cdev == NULL) {
  556                 mtx_unlock(&vmmdev_mtx);
  557                 return (EINVAL);
  558         }
  559 
  560         /*
  561          * The 'cdev' will be destroyed asynchronously when 'si_threadcount'
  562          * goes down to 0 so we should not do it again in the callback.
  563          */
  564         cdev = sc->cdev;
  565         sc->cdev = NULL;                
  566         mtx_unlock(&vmmdev_mtx);
  567 
  568         /*
  569          * Schedule the 'cdev' to be destroyed:
  570          *
  571          * - any new operations on this 'cdev' will return an error (ENXIO).
  572          *
  573          * - when the 'si_threadcount' dwindles down to zero the 'cdev' will
  574          *   be destroyed and the callback will be invoked in a taskqueue
  575          *   context.
  576          */
  577         destroy_dev_sched_cb(cdev, vmmdev_destroy, sc);
  578 
  579         return (0);
  580 }
  581 SYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW,
  582             NULL, 0, sysctl_vmm_destroy, "A", NULL);
  583 
  584 static struct cdevsw vmmdevsw = {
  585         .d_name         = "vmmdev",
  586         .d_version      = D_VERSION,
  587         .d_ioctl        = vmmdev_ioctl,
  588         .d_mmap_single  = vmmdev_mmap_single,
  589         .d_read         = vmmdev_rw,
  590         .d_write        = vmmdev_rw,
  591 };
  592 
  593 static int
  594 sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
  595 {
  596         int error;
  597         struct vm *vm;
  598         struct cdev *cdev;
  599         struct vmmdev_softc *sc, *sc2;
  600         char buf[VM_MAX_NAMELEN];
  601 
  602         strlcpy(buf, "beavis", sizeof(buf));
  603         error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
  604         if (error != 0 || req->newptr == NULL)
  605                 return (error);
  606 
  607         mtx_lock(&vmmdev_mtx);
  608         sc = vmmdev_lookup(buf);
  609         mtx_unlock(&vmmdev_mtx);
  610         if (sc != NULL)
  611                 return (EEXIST);
  612 
  613         error = vm_create(buf, &vm);
  614         if (error != 0)
  615                 return (error);
  616 
  617         sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO);
  618         sc->vm = vm;
  619 
  620         /*
  621          * Lookup the name again just in case somebody sneaked in when we
  622          * dropped the lock.
  623          */
  624         mtx_lock(&vmmdev_mtx);
  625         sc2 = vmmdev_lookup(buf);
  626         if (sc2 == NULL) {
  627                 SLIST_INSERT_HEAD(&head, sc, link);
  628                 sc->flags |= VSC_LINKED;
  629         }
  630         mtx_unlock(&vmmdev_mtx);
  631 
  632         if (sc2 != NULL) {
  633                 vmmdev_destroy(sc);
  634                 return (EEXIST);
  635         }
  636 
  637         error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, NULL,
  638                            UID_ROOT, GID_WHEEL, 0600, "vmm/%s", buf);
  639         if (error != 0) {
  640                 vmmdev_destroy(sc);
  641                 return (error);
  642         }
  643 
  644         mtx_lock(&vmmdev_mtx);
  645         sc->cdev = cdev;
  646         sc->cdev->si_drv1 = sc;
  647         mtx_unlock(&vmmdev_mtx);
  648 
  649         return (0);
  650 }
  651 SYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW,
  652             NULL, 0, sysctl_vmm_create, "A", NULL);
  653 
  654 void
  655 vmmdev_init(void)
  656 {
  657         mtx_init(&vmmdev_mtx, "vmm device mutex", NULL, MTX_DEF);
  658 }
  659 
  660 int
  661 vmmdev_cleanup(void)
  662 {
  663         int error;
  664 
  665         if (SLIST_EMPTY(&head))
  666                 error = 0;
  667         else
  668                 error = EBUSY;
  669 
  670         return (error);
  671 }

Cache object: 50de94d9a0927a3f6a4ab03453f9fe21


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.