vmm_dev.c revision 270159
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: stable/10/sys/amd64/vmm/vmm_dev.c 270159 2014-08-19 01:20:24Z grehan $ 27221828Sgrehan */ 28221828Sgrehan 29221828Sgrehan#include <sys/cdefs.h> 30221828Sgrehan__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/vmm_dev.c 270159 2014-08-19 01:20:24Z grehan $"); 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> 47256072Sneel#include <vm/vm_map.h> 48221828Sgrehan 49221828Sgrehan#include <machine/vmparam.h> 50261088Sjhb#include <machine/vmm.h> 51268976Sjhb#include <machine/vmm_instruction_emul.h> 52261088Sjhb#include <machine/vmm_dev.h> 53221828Sgrehan 54221828Sgrehan#include "vmm_lapic.h" 55221828Sgrehan#include "vmm_stat.h" 56239700Sgrehan#include "vmm_mem.h" 57221828Sgrehan#include "io/ppt.h" 58268891Sjhb#include "io/vatpic.h" 59261088Sjhb#include "io/vioapic.h" 60261088Sjhb#include "io/vhpet.h" 61221828Sgrehan 62221828Sgrehanstruct vmmdev_softc { 63221828Sgrehan struct vm *vm; /* vm instance cookie */ 64221828Sgrehan struct cdev *cdev; 65221828Sgrehan SLIST_ENTRY(vmmdev_softc) link; 66256651Sneel int flags; 67221828Sgrehan}; 68256651Sneel#define VSC_LINKED 0x01 69256651Sneel 70221828Sgrehanstatic SLIST_HEAD(, vmmdev_softc) head; 71221828Sgrehan 72221828Sgrehanstatic struct mtx vmmdev_mtx; 73221828Sgrehan 74221828Sgrehanstatic MALLOC_DEFINE(M_VMMDEV, "vmmdev", "vmmdev"); 75221828Sgrehan 76221828SgrehanSYSCTL_DECL(_hw_vmm); 77221828Sgrehan 78221828Sgrehanstatic struct vmmdev_softc * 79221828Sgrehanvmmdev_lookup(const char *name) 80221828Sgrehan{ 81221828Sgrehan struct vmmdev_softc *sc; 82221828Sgrehan 83221828Sgrehan#ifdef notyet /* XXX kernel is not compiled with invariants */ 84221828Sgrehan mtx_assert(&vmmdev_mtx, MA_OWNED); 85221828Sgrehan#endif 86221828Sgrehan 87221828Sgrehan SLIST_FOREACH(sc, &head, link) { 88221828Sgrehan if (strcmp(name, vm_name(sc->vm)) == 0) 89221828Sgrehan break; 90221828Sgrehan } 91221828Sgrehan 92221828Sgrehan return (sc); 93221828Sgrehan} 94221828Sgrehan 95221828Sgrehanstatic struct vmmdev_softc * 96221828Sgrehanvmmdev_lookup2(struct cdev *cdev) 97221828Sgrehan{ 98221828Sgrehan 99241454Sneel return (cdev->si_drv1); 100221828Sgrehan} 101221828Sgrehan 102221828Sgrehanstatic int 103221828Sgrehanvmmdev_rw(struct cdev *cdev, struct uio *uio, int flags) 104221828Sgrehan{ 105256072Sneel int error, off, c, prot; 106256072Sneel vm_paddr_t gpa; 107256072Sneel void *hpa, *cookie; 108221828Sgrehan struct vmmdev_softc *sc; 109221828Sgrehan 110221828Sgrehan static char zerobuf[PAGE_SIZE]; 111221828Sgrehan 112221828Sgrehan error = 0; 113221828Sgrehan sc = vmmdev_lookup2(cdev); 114241454Sneel if (sc == NULL) 115241454Sneel error = ENXIO; 116221828Sgrehan 117256072Sneel prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ); 118221828Sgrehan while (uio->uio_resid > 0 && error == 0) { 119221828Sgrehan gpa = uio->uio_offset; 120221828Sgrehan off = gpa & PAGE_MASK; 121221828Sgrehan c = min(uio->uio_resid, PAGE_SIZE - off); 122221828Sgrehan 123221828Sgrehan /* 124221828Sgrehan * The VM has a hole in its physical memory map. If we want to 125221828Sgrehan * use 'dd' to inspect memory beyond the hole we need to 126221828Sgrehan * provide bogus data for memory that lies in the hole. 127221828Sgrehan * 128221828Sgrehan * Since this device does not support lseek(2), dd(1) will 129221828Sgrehan * read(2) blocks of data to simulate the lseek(2). 130221828Sgrehan */ 131256072Sneel hpa = vm_gpa_hold(sc->vm, gpa, c, prot, &cookie); 132256072Sneel if (hpa == NULL) { 133221828Sgrehan if (uio->uio_rw == UIO_READ) 134221828Sgrehan error = uiomove(zerobuf, c, uio); 135221828Sgrehan else 136221828Sgrehan error = EFAULT; 137256072Sneel } else { 138256072Sneel error = uiomove(hpa, c, uio); 139256072Sneel vm_gpa_release(cookie); 140256072Sneel } 141221828Sgrehan } 142221828Sgrehan return (error); 143221828Sgrehan} 144221828Sgrehan 145221828Sgrehanstatic int 146221828Sgrehanvmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, 147221828Sgrehan struct thread *td) 148221828Sgrehan{ 149270070Sgrehan int error, vcpu, state_changed, size; 150270070Sgrehan cpuset_t *cpuset; 151221828Sgrehan struct vmmdev_softc *sc; 152221828Sgrehan struct vm_memory_segment *seg; 153221828Sgrehan struct vm_register *vmreg; 154261088Sjhb struct vm_seg_desc *vmsegdesc; 155221828Sgrehan struct vm_run *vmrun; 156267427Sjhb struct vm_exception *vmexc; 157221828Sgrehan struct vm_lapic_irq *vmirq; 158262350Sjhb struct vm_lapic_msi *vmmsi; 159261088Sjhb struct vm_ioapic_irq *ioapic_irq; 160268891Sjhb struct vm_isa_irq *isa_irq; 161268972Sjhb struct vm_isa_irq_trigger *isa_irq_trigger; 162221828Sgrehan struct vm_capability *vmcap; 163221828Sgrehan struct vm_pptdev *pptdev; 164221828Sgrehan struct vm_pptdev_mmio *pptmmio; 165221828Sgrehan struct vm_pptdev_msi *pptmsi; 166234761Sgrehan struct vm_pptdev_msix *pptmsix; 167221828Sgrehan struct vm_nmi *vmnmi; 168221828Sgrehan struct vm_stats *vmstats; 169221828Sgrehan struct vm_stat_desc *statdesc; 170240922Sneel struct vm_x2apic *x2apic; 171256072Sneel struct vm_gpa_pte *gpapte; 172268935Sjhb struct vm_suspend *vmsuspend; 173268976Sjhb struct vm_gla2gpa *gg; 174270070Sgrehan struct vm_activate_cpu *vac; 175270070Sgrehan struct vm_cpuset *vm_cpuset; 176270159Sgrehan struct vm_intinfo *vmii; 177221828Sgrehan 178221828Sgrehan sc = vmmdev_lookup2(cdev); 179241489Sneel if (sc == NULL) 180221828Sgrehan return (ENXIO); 181221828Sgrehan 182268891Sjhb error = 0; 183241489Sneel vcpu = -1; 184241489Sneel state_changed = 0; 185241489Sneel 186221828Sgrehan /* 187221828Sgrehan * Some VMM ioctls can operate only on vcpus that are not running. 188221828Sgrehan */ 189221828Sgrehan switch (cmd) { 190221828Sgrehan case VM_RUN: 191221828Sgrehan case VM_GET_REGISTER: 192221828Sgrehan case VM_SET_REGISTER: 193221828Sgrehan case VM_GET_SEGMENT_DESCRIPTOR: 194221828Sgrehan case VM_SET_SEGMENT_DESCRIPTOR: 195267427Sjhb case VM_INJECT_EXCEPTION: 196221828Sgrehan case VM_GET_CAPABILITY: 197221828Sgrehan case VM_SET_CAPABILITY: 198221828Sgrehan case VM_PPTDEV_MSI: 199241489Sneel case VM_PPTDEV_MSIX: 200240922Sneel case VM_SET_X2APIC_STATE: 201268976Sjhb case VM_GLA2GPA: 202270070Sgrehan case VM_ACTIVATE_CPU: 203270159Sgrehan case VM_SET_INTINFO: 204270159Sgrehan case VM_GET_INTINFO: 205221828Sgrehan /* 206221828Sgrehan * XXX fragile, handle with care 207221828Sgrehan * Assumes that the first field of the ioctl data is the vcpu. 208221828Sgrehan */ 209221828Sgrehan vcpu = *(int *)data; 210221828Sgrehan if (vcpu < 0 || vcpu >= VM_MAXCPU) { 211221828Sgrehan error = EINVAL; 212221828Sgrehan goto done; 213221828Sgrehan } 214221828Sgrehan 215266393Sjhb error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true); 216241489Sneel if (error) 217221828Sgrehan goto done; 218241489Sneel 219241489Sneel state_changed = 1; 220241489Sneel break; 221241489Sneel 222241489Sneel case VM_MAP_PPTDEV_MMIO: 223241489Sneel case VM_BIND_PPTDEV: 224241489Sneel case VM_UNBIND_PPTDEV: 225241489Sneel case VM_MAP_MEMORY: 226270071Sgrehan case VM_REINIT: 227241489Sneel /* 228241489Sneel * ioctls that operate on the entire virtual machine must 229241489Sneel * prevent all vcpus from running. 230241489Sneel */ 231241489Sneel error = 0; 232241489Sneel for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) { 233266393Sjhb error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true); 234241489Sneel if (error) 235241489Sneel break; 236221828Sgrehan } 237241489Sneel 238241489Sneel if (error) { 239241489Sneel while (--vcpu >= 0) 240266393Sjhb vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 241241489Sneel goto done; 242241489Sneel } 243241489Sneel 244241489Sneel state_changed = 2; 245221828Sgrehan break; 246241489Sneel 247221828Sgrehan default: 248221828Sgrehan break; 249221828Sgrehan } 250221828Sgrehan 251221828Sgrehan switch(cmd) { 252221828Sgrehan case VM_RUN: 253221828Sgrehan vmrun = (struct vm_run *)data; 254221828Sgrehan error = vm_run(sc->vm, vmrun); 255221828Sgrehan break; 256268935Sjhb case VM_SUSPEND: 257268935Sjhb vmsuspend = (struct vm_suspend *)data; 258268935Sjhb error = vm_suspend(sc->vm, vmsuspend->how); 259268935Sjhb break; 260270071Sgrehan case VM_REINIT: 261270071Sgrehan error = vm_reinit(sc->vm); 262270071Sgrehan break; 263221828Sgrehan case VM_STAT_DESC: { 264221828Sgrehan statdesc = (struct vm_stat_desc *)data; 265250427Sneel error = vmm_stat_desc_copy(statdesc->index, 266250427Sneel statdesc->desc, sizeof(statdesc->desc)); 267221828Sgrehan break; 268221828Sgrehan } 269221828Sgrehan case VM_STATS: { 270250427Sneel CTASSERT(MAX_VM_STATS >= MAX_VMM_STAT_ELEMS); 271221828Sgrehan vmstats = (struct vm_stats *)data; 272221828Sgrehan getmicrotime(&vmstats->tv); 273221828Sgrehan error = vmm_stat_copy(sc->vm, vmstats->cpuid, 274221828Sgrehan &vmstats->num_entries, vmstats->statbuf); 275221828Sgrehan break; 276221828Sgrehan } 277221828Sgrehan case VM_PPTDEV_MSI: 278221828Sgrehan pptmsi = (struct vm_pptdev_msi *)data; 279221828Sgrehan error = ppt_setup_msi(sc->vm, pptmsi->vcpu, 280221828Sgrehan pptmsi->bus, pptmsi->slot, pptmsi->func, 281262350Sjhb pptmsi->addr, pptmsi->msg, 282221828Sgrehan pptmsi->numvec); 283221828Sgrehan break; 284234761Sgrehan case VM_PPTDEV_MSIX: 285234761Sgrehan pptmsix = (struct vm_pptdev_msix *)data; 286234761Sgrehan error = ppt_setup_msix(sc->vm, pptmsix->vcpu, 287234761Sgrehan pptmsix->bus, pptmsix->slot, 288234761Sgrehan pptmsix->func, pptmsix->idx, 289262350Sjhb pptmsix->addr, pptmsix->msg, 290262350Sjhb pptmsix->vector_control); 291234761Sgrehan break; 292221828Sgrehan case VM_MAP_PPTDEV_MMIO: 293221828Sgrehan pptmmio = (struct vm_pptdev_mmio *)data; 294221828Sgrehan error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot, 295221828Sgrehan pptmmio->func, pptmmio->gpa, pptmmio->len, 296221828Sgrehan pptmmio->hpa); 297221828Sgrehan break; 298221828Sgrehan case VM_BIND_PPTDEV: 299221828Sgrehan pptdev = (struct vm_pptdev *)data; 300256072Sneel error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot, 301256072Sneel pptdev->func); 302221828Sgrehan break; 303221828Sgrehan case VM_UNBIND_PPTDEV: 304221828Sgrehan pptdev = (struct vm_pptdev *)data; 305256072Sneel error = vm_unassign_pptdev(sc->vm, pptdev->bus, pptdev->slot, 306256072Sneel pptdev->func); 307221828Sgrehan break; 308267427Sjhb case VM_INJECT_EXCEPTION: 309267427Sjhb vmexc = (struct vm_exception *)data; 310267427Sjhb error = vm_inject_exception(sc->vm, vmexc->cpuid, vmexc); 311221828Sgrehan break; 312221828Sgrehan case VM_INJECT_NMI: 313221828Sgrehan vmnmi = (struct vm_nmi *)data; 314221828Sgrehan error = vm_inject_nmi(sc->vm, vmnmi->cpuid); 315221828Sgrehan break; 316221828Sgrehan case VM_LAPIC_IRQ: 317221828Sgrehan vmirq = (struct vm_lapic_irq *)data; 318261088Sjhb error = lapic_intr_edge(sc->vm, vmirq->cpuid, vmirq->vector); 319221828Sgrehan break; 320262350Sjhb case VM_LAPIC_LOCAL_IRQ: 321262350Sjhb vmirq = (struct vm_lapic_irq *)data; 322262350Sjhb error = lapic_set_local_intr(sc->vm, vmirq->cpuid, 323262350Sjhb vmirq->vector); 324262350Sjhb break; 325262350Sjhb case VM_LAPIC_MSI: 326262350Sjhb vmmsi = (struct vm_lapic_msi *)data; 327262350Sjhb error = lapic_intr_msi(sc->vm, vmmsi->addr, vmmsi->msg); 328262350Sjhb break; 329261088Sjhb case VM_IOAPIC_ASSERT_IRQ: 330261088Sjhb ioapic_irq = (struct vm_ioapic_irq *)data; 331261088Sjhb error = vioapic_assert_irq(sc->vm, ioapic_irq->irq); 332261088Sjhb break; 333261088Sjhb case VM_IOAPIC_DEASSERT_IRQ: 334261088Sjhb ioapic_irq = (struct vm_ioapic_irq *)data; 335261088Sjhb error = vioapic_deassert_irq(sc->vm, ioapic_irq->irq); 336261088Sjhb break; 337261088Sjhb case VM_IOAPIC_PULSE_IRQ: 338261088Sjhb ioapic_irq = (struct vm_ioapic_irq *)data; 339261088Sjhb error = vioapic_pulse_irq(sc->vm, ioapic_irq->irq); 340261088Sjhb break; 341267393Sjhb case VM_IOAPIC_PINCOUNT: 342267393Sjhb *(int *)data = vioapic_pincount(sc->vm); 343267393Sjhb break; 344268891Sjhb case VM_ISA_ASSERT_IRQ: 345268891Sjhb isa_irq = (struct vm_isa_irq *)data; 346268891Sjhb error = vatpic_assert_irq(sc->vm, isa_irq->atpic_irq); 347268891Sjhb if (error == 0 && isa_irq->ioapic_irq != -1) 348268891Sjhb error = vioapic_assert_irq(sc->vm, 349268891Sjhb isa_irq->ioapic_irq); 350268891Sjhb break; 351268891Sjhb case VM_ISA_DEASSERT_IRQ: 352268891Sjhb isa_irq = (struct vm_isa_irq *)data; 353268891Sjhb error = vatpic_deassert_irq(sc->vm, isa_irq->atpic_irq); 354268891Sjhb if (error == 0 && isa_irq->ioapic_irq != -1) 355268891Sjhb error = vioapic_deassert_irq(sc->vm, 356268891Sjhb isa_irq->ioapic_irq); 357268891Sjhb break; 358268891Sjhb case VM_ISA_PULSE_IRQ: 359268891Sjhb isa_irq = (struct vm_isa_irq *)data; 360268891Sjhb error = vatpic_pulse_irq(sc->vm, isa_irq->atpic_irq); 361268891Sjhb if (error == 0 && isa_irq->ioapic_irq != -1) 362268891Sjhb error = vioapic_pulse_irq(sc->vm, isa_irq->ioapic_irq); 363268891Sjhb break; 364268972Sjhb case VM_ISA_SET_IRQ_TRIGGER: 365268972Sjhb isa_irq_trigger = (struct vm_isa_irq_trigger *)data; 366268972Sjhb error = vatpic_set_irq_trigger(sc->vm, 367268972Sjhb isa_irq_trigger->atpic_irq, isa_irq_trigger->trigger); 368268972Sjhb break; 369221828Sgrehan case VM_MAP_MEMORY: 370221828Sgrehan seg = (struct vm_memory_segment *)data; 371241041Sneel error = vm_malloc(sc->vm, seg->gpa, seg->len); 372221828Sgrehan break; 373221828Sgrehan case VM_GET_MEMORY_SEG: 374221828Sgrehan seg = (struct vm_memory_segment *)data; 375241178Sneel seg->len = 0; 376221828Sgrehan (void)vm_gpabase2memseg(sc->vm, seg->gpa, seg); 377221828Sgrehan error = 0; 378221828Sgrehan break; 379221828Sgrehan case VM_GET_REGISTER: 380221828Sgrehan vmreg = (struct vm_register *)data; 381221828Sgrehan error = vm_get_register(sc->vm, vmreg->cpuid, vmreg->regnum, 382221828Sgrehan &vmreg->regval); 383221828Sgrehan break; 384221828Sgrehan case VM_SET_REGISTER: 385221828Sgrehan vmreg = (struct vm_register *)data; 386221828Sgrehan error = vm_set_register(sc->vm, vmreg->cpuid, vmreg->regnum, 387221828Sgrehan vmreg->regval); 388221828Sgrehan break; 389221828Sgrehan case VM_SET_SEGMENT_DESCRIPTOR: 390221828Sgrehan vmsegdesc = (struct vm_seg_desc *)data; 391221828Sgrehan error = vm_set_seg_desc(sc->vm, vmsegdesc->cpuid, 392221828Sgrehan vmsegdesc->regnum, 393221828Sgrehan &vmsegdesc->desc); 394221828Sgrehan break; 395221828Sgrehan case VM_GET_SEGMENT_DESCRIPTOR: 396221828Sgrehan vmsegdesc = (struct vm_seg_desc *)data; 397221828Sgrehan error = vm_get_seg_desc(sc->vm, vmsegdesc->cpuid, 398221828Sgrehan vmsegdesc->regnum, 399221828Sgrehan &vmsegdesc->desc); 400221828Sgrehan break; 401221828Sgrehan case VM_GET_CAPABILITY: 402221828Sgrehan vmcap = (struct vm_capability *)data; 403221828Sgrehan error = vm_get_capability(sc->vm, vmcap->cpuid, 404221828Sgrehan vmcap->captype, 405221828Sgrehan &vmcap->capval); 406221828Sgrehan break; 407221828Sgrehan case VM_SET_CAPABILITY: 408221828Sgrehan vmcap = (struct vm_capability *)data; 409221828Sgrehan error = vm_set_capability(sc->vm, vmcap->cpuid, 410221828Sgrehan vmcap->captype, 411221828Sgrehan vmcap->capval); 412221828Sgrehan break; 413240922Sneel case VM_SET_X2APIC_STATE: 414240922Sneel x2apic = (struct vm_x2apic *)data; 415240922Sneel error = vm_set_x2apic_state(sc->vm, 416240922Sneel x2apic->cpuid, x2apic->state); 417240922Sneel break; 418240922Sneel case VM_GET_X2APIC_STATE: 419240922Sneel x2apic = (struct vm_x2apic *)data; 420240922Sneel error = vm_get_x2apic_state(sc->vm, 421240922Sneel x2apic->cpuid, &x2apic->state); 422240922Sneel break; 423256072Sneel case VM_GET_GPA_PMAP: 424256072Sneel gpapte = (struct vm_gpa_pte *)data; 425256072Sneel pmap_get_mapping(vmspace_pmap(vm_get_vmspace(sc->vm)), 426256072Sneel gpapte->gpa, gpapte->pte, &gpapte->ptenum); 427256072Sneel error = 0; 428256072Sneel break; 429261088Sjhb case VM_GET_HPET_CAPABILITIES: 430261088Sjhb error = vhpet_getcap((struct vm_hpet_cap *)data); 431261088Sjhb break; 432268976Sjhb case VM_GLA2GPA: { 433268976Sjhb CTASSERT(PROT_READ == VM_PROT_READ); 434268976Sjhb CTASSERT(PROT_WRITE == VM_PROT_WRITE); 435268976Sjhb CTASSERT(PROT_EXEC == VM_PROT_EXECUTE); 436268976Sjhb gg = (struct vm_gla2gpa *)data; 437268976Sjhb error = vmm_gla2gpa(sc->vm, gg->vcpuid, &gg->paging, gg->gla, 438268976Sjhb gg->prot, &gg->gpa); 439268976Sjhb KASSERT(error == 0 || error == 1 || error == -1, 440268976Sjhb ("%s: vmm_gla2gpa unknown error %d", __func__, error)); 441268976Sjhb if (error >= 0) { 442268976Sjhb /* 443268976Sjhb * error = 0: the translation was successful 444268976Sjhb * error = 1: a fault was injected into the guest 445268976Sjhb */ 446268976Sjhb gg->fault = error; 447268976Sjhb error = 0; 448268976Sjhb } else { 449268976Sjhb error = EFAULT; 450268976Sjhb } 451268976Sjhb break; 452268976Sjhb } 453270070Sgrehan case VM_ACTIVATE_CPU: 454270070Sgrehan vac = (struct vm_activate_cpu *)data; 455270070Sgrehan error = vm_activate_cpu(sc->vm, vac->vcpuid); 456270070Sgrehan break; 457270070Sgrehan case VM_GET_CPUS: 458270070Sgrehan error = 0; 459270070Sgrehan vm_cpuset = (struct vm_cpuset *)data; 460270070Sgrehan size = vm_cpuset->cpusetsize; 461270070Sgrehan if (size < sizeof(cpuset_t) || size > CPU_MAXSIZE / NBBY) { 462270070Sgrehan error = ERANGE; 463270070Sgrehan break; 464270070Sgrehan } 465270070Sgrehan cpuset = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 466270070Sgrehan if (vm_cpuset->which == VM_ACTIVE_CPUS) 467270070Sgrehan *cpuset = vm_active_cpus(sc->vm); 468270070Sgrehan else if (vm_cpuset->which == VM_SUSPENDED_CPUS) 469270070Sgrehan *cpuset = vm_suspended_cpus(sc->vm); 470270070Sgrehan else 471270070Sgrehan error = EINVAL; 472270070Sgrehan if (error == 0) 473270070Sgrehan error = copyout(cpuset, vm_cpuset->cpus, size); 474270070Sgrehan free(cpuset, M_TEMP); 475270070Sgrehan break; 476270159Sgrehan case VM_SET_INTINFO: 477270159Sgrehan vmii = (struct vm_intinfo *)data; 478270159Sgrehan error = vm_exit_intinfo(sc->vm, vmii->vcpuid, vmii->info1); 479270159Sgrehan break; 480270159Sgrehan case VM_GET_INTINFO: 481270159Sgrehan vmii = (struct vm_intinfo *)data; 482270159Sgrehan error = vm_get_intinfo(sc->vm, vmii->vcpuid, &vmii->info1, 483270159Sgrehan &vmii->info2); 484270159Sgrehan break; 485221828Sgrehan default: 486221828Sgrehan error = ENOTTY; 487221828Sgrehan break; 488221828Sgrehan } 489241489Sneel 490241489Sneel if (state_changed == 1) { 491266393Sjhb vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 492241489Sneel } else if (state_changed == 2) { 493241489Sneel for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) 494266393Sjhb vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 495241489Sneel } 496241489Sneel 497221828Sgrehandone: 498256072Sneel /* Make sure that no handler returns a bogus value like ERESTART */ 499256072Sneel KASSERT(error >= 0, ("vmmdev_ioctl: invalid error return %d", error)); 500221828Sgrehan return (error); 501221828Sgrehan} 502221828Sgrehan 503221828Sgrehanstatic int 504256072Sneelvmmdev_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, 505256072Sneel vm_size_t size, struct vm_object **object, int nprot) 506221828Sgrehan{ 507221828Sgrehan int error; 508221828Sgrehan struct vmmdev_softc *sc; 509221828Sgrehan 510221828Sgrehan sc = vmmdev_lookup2(cdev); 511256072Sneel if (sc != NULL && (nprot & PROT_EXEC) == 0) 512256072Sneel error = vm_get_memobj(sc->vm, *offset, size, offset, object); 513256072Sneel else 514256072Sneel error = EINVAL; 515221828Sgrehan 516221828Sgrehan return (error); 517221828Sgrehan} 518221828Sgrehan 519221828Sgrehanstatic void 520256651Sneelvmmdev_destroy(void *arg) 521221828Sgrehan{ 522221828Sgrehan 523256651Sneel struct vmmdev_softc *sc = arg; 524256651Sneel 525256651Sneel if (sc->cdev != NULL) 526241454Sneel destroy_dev(sc->cdev); 527241454Sneel 528256651Sneel if (sc->vm != NULL) 529241454Sneel vm_destroy(sc->vm); 530241454Sneel 531256651Sneel if ((sc->flags & VSC_LINKED) != 0) { 532241454Sneel mtx_lock(&vmmdev_mtx); 533241454Sneel SLIST_REMOVE(&head, sc, vmmdev_softc, link); 534241454Sneel mtx_unlock(&vmmdev_mtx); 535241454Sneel } 536241454Sneel 537221828Sgrehan free(sc, M_VMMDEV); 538221828Sgrehan} 539221828Sgrehan 540221828Sgrehanstatic int 541221828Sgrehansysctl_vmm_destroy(SYSCTL_HANDLER_ARGS) 542221828Sgrehan{ 543221828Sgrehan int error; 544221828Sgrehan char buf[VM_MAX_NAMELEN]; 545221828Sgrehan struct vmmdev_softc *sc; 546256651Sneel struct cdev *cdev; 547221828Sgrehan 548221828Sgrehan strlcpy(buf, "beavis", sizeof(buf)); 549221828Sgrehan error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 550221828Sgrehan if (error != 0 || req->newptr == NULL) 551221828Sgrehan return (error); 552221828Sgrehan 553221828Sgrehan mtx_lock(&vmmdev_mtx); 554221828Sgrehan sc = vmmdev_lookup(buf); 555256651Sneel if (sc == NULL || sc->cdev == NULL) { 556221828Sgrehan mtx_unlock(&vmmdev_mtx); 557221828Sgrehan return (EINVAL); 558221828Sgrehan } 559241454Sneel 560256651Sneel /* 561256651Sneel * The 'cdev' will be destroyed asynchronously when 'si_threadcount' 562256651Sneel * goes down to 0 so we should not do it again in the callback. 563256651Sneel */ 564256651Sneel cdev = sc->cdev; 565256651Sneel sc->cdev = NULL; 566221828Sgrehan mtx_unlock(&vmmdev_mtx); 567241454Sneel 568256651Sneel /* 569256651Sneel * Schedule the 'cdev' to be destroyed: 570256651Sneel * 571256651Sneel * - any new operations on this 'cdev' will return an error (ENXIO). 572256651Sneel * 573256651Sneel * - when the 'si_threadcount' dwindles down to zero the 'cdev' will 574256651Sneel * be destroyed and the callback will be invoked in a taskqueue 575256651Sneel * context. 576256651Sneel */ 577256651Sneel destroy_dev_sched_cb(cdev, vmmdev_destroy, sc); 578241454Sneel 579221828Sgrehan return (0); 580221828Sgrehan} 581221828SgrehanSYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW, 582221828Sgrehan NULL, 0, sysctl_vmm_destroy, "A", NULL); 583221828Sgrehan 584221828Sgrehanstatic struct cdevsw vmmdevsw = { 585221828Sgrehan .d_name = "vmmdev", 586221828Sgrehan .d_version = D_VERSION, 587221828Sgrehan .d_ioctl = vmmdev_ioctl, 588256072Sneel .d_mmap_single = vmmdev_mmap_single, 589221828Sgrehan .d_read = vmmdev_rw, 590221828Sgrehan .d_write = vmmdev_rw, 591221828Sgrehan}; 592221828Sgrehan 593221828Sgrehanstatic int 594221828Sgrehansysctl_vmm_create(SYSCTL_HANDLER_ARGS) 595221828Sgrehan{ 596221828Sgrehan int error; 597221828Sgrehan struct vm *vm; 598256651Sneel struct cdev *cdev; 599241454Sneel struct vmmdev_softc *sc, *sc2; 600221828Sgrehan char buf[VM_MAX_NAMELEN]; 601221828Sgrehan 602221828Sgrehan strlcpy(buf, "beavis", sizeof(buf)); 603221828Sgrehan error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 604221828Sgrehan if (error != 0 || req->newptr == NULL) 605221828Sgrehan return (error); 606221828Sgrehan 607221828Sgrehan mtx_lock(&vmmdev_mtx); 608221828Sgrehan sc = vmmdev_lookup(buf); 609241454Sneel mtx_unlock(&vmmdev_mtx); 610241454Sneel if (sc != NULL) 611221828Sgrehan return (EEXIST); 612221828Sgrehan 613249396Sneel error = vm_create(buf, &vm); 614249396Sneel if (error != 0) 615249396Sneel return (error); 616221828Sgrehan 617221828Sgrehan sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO); 618221828Sgrehan sc->vm = vm; 619241454Sneel 620241454Sneel /* 621241454Sneel * Lookup the name again just in case somebody sneaked in when we 622241454Sneel * dropped the lock. 623241454Sneel */ 624241454Sneel mtx_lock(&vmmdev_mtx); 625241454Sneel sc2 = vmmdev_lookup(buf); 626256651Sneel if (sc2 == NULL) { 627241454Sneel SLIST_INSERT_HEAD(&head, sc, link); 628256651Sneel sc->flags |= VSC_LINKED; 629256651Sneel } 630241454Sneel mtx_unlock(&vmmdev_mtx); 631241454Sneel 632241454Sneel if (sc2 != NULL) { 633256651Sneel vmmdev_destroy(sc); 634241454Sneel return (EEXIST); 635241454Sneel } 636241454Sneel 637256651Sneel error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, NULL, 638249435Sneel UID_ROOT, GID_WHEEL, 0600, "vmm/%s", buf); 639249435Sneel if (error != 0) { 640256651Sneel vmmdev_destroy(sc); 641249435Sneel return (error); 642249435Sneel } 643256651Sneel 644256651Sneel mtx_lock(&vmmdev_mtx); 645256651Sneel sc->cdev = cdev; 646221828Sgrehan sc->cdev->si_drv1 = sc; 647256651Sneel mtx_unlock(&vmmdev_mtx); 648221828Sgrehan 649221828Sgrehan return (0); 650221828Sgrehan} 651221828SgrehanSYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW, 652221828Sgrehan NULL, 0, sysctl_vmm_create, "A", NULL); 653221828Sgrehan 654221828Sgrehanvoid 655221828Sgrehanvmmdev_init(void) 656221828Sgrehan{ 657221828Sgrehan mtx_init(&vmmdev_mtx, "vmm device mutex", NULL, MTX_DEF); 658221828Sgrehan} 659221828Sgrehan 660241454Sneelint 661221828Sgrehanvmmdev_cleanup(void) 662221828Sgrehan{ 663241454Sneel int error; 664221828Sgrehan 665241454Sneel if (SLIST_EMPTY(&head)) 666241454Sneel error = 0; 667241454Sneel else 668241454Sneel error = EBUSY; 669221828Sgrehan 670241454Sneel return (error); 671221828Sgrehan} 672