vmm_dev.c revision 284899
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 284899 2015-06-28 01:21:55Z neel $ 27221828Sgrehan */ 28221828Sgrehan 29221828Sgrehan#include <sys/cdefs.h> 30221828Sgrehan__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/vmm_dev.c 284899 2015-06-28 01:21:55Z neel $"); 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" 61284894Sneel#include "io/vrtc.h" 62221828Sgrehan 63221828Sgrehanstruct vmmdev_softc { 64221828Sgrehan struct vm *vm; /* vm instance cookie */ 65221828Sgrehan struct cdev *cdev; 66221828Sgrehan SLIST_ENTRY(vmmdev_softc) link; 67256651Sneel int flags; 68221828Sgrehan}; 69256651Sneel#define VSC_LINKED 0x01 70256651Sneel 71221828Sgrehanstatic SLIST_HEAD(, vmmdev_softc) head; 72221828Sgrehan 73221828Sgrehanstatic struct mtx vmmdev_mtx; 74221828Sgrehan 75221828Sgrehanstatic MALLOC_DEFINE(M_VMMDEV, "vmmdev", "vmmdev"); 76221828Sgrehan 77221828SgrehanSYSCTL_DECL(_hw_vmm); 78221828Sgrehan 79221828Sgrehanstatic struct vmmdev_softc * 80221828Sgrehanvmmdev_lookup(const char *name) 81221828Sgrehan{ 82221828Sgrehan struct vmmdev_softc *sc; 83221828Sgrehan 84221828Sgrehan#ifdef notyet /* XXX kernel is not compiled with invariants */ 85221828Sgrehan mtx_assert(&vmmdev_mtx, MA_OWNED); 86221828Sgrehan#endif 87221828Sgrehan 88221828Sgrehan SLIST_FOREACH(sc, &head, link) { 89221828Sgrehan if (strcmp(name, vm_name(sc->vm)) == 0) 90221828Sgrehan break; 91221828Sgrehan } 92221828Sgrehan 93221828Sgrehan return (sc); 94221828Sgrehan} 95221828Sgrehan 96221828Sgrehanstatic struct vmmdev_softc * 97221828Sgrehanvmmdev_lookup2(struct cdev *cdev) 98221828Sgrehan{ 99221828Sgrehan 100241454Sneel return (cdev->si_drv1); 101221828Sgrehan} 102221828Sgrehan 103221828Sgrehanstatic int 104221828Sgrehanvmmdev_rw(struct cdev *cdev, struct uio *uio, int flags) 105221828Sgrehan{ 106256072Sneel int error, off, c, prot; 107256072Sneel vm_paddr_t gpa; 108256072Sneel void *hpa, *cookie; 109221828Sgrehan struct vmmdev_softc *sc; 110221828Sgrehan 111221828Sgrehan static char zerobuf[PAGE_SIZE]; 112221828Sgrehan 113221828Sgrehan error = 0; 114221828Sgrehan sc = vmmdev_lookup2(cdev); 115241454Sneel if (sc == NULL) 116241454Sneel error = ENXIO; 117221828Sgrehan 118256072Sneel prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ); 119221828Sgrehan while (uio->uio_resid > 0 && error == 0) { 120221828Sgrehan gpa = uio->uio_offset; 121221828Sgrehan off = gpa & PAGE_MASK; 122221828Sgrehan c = min(uio->uio_resid, PAGE_SIZE - off); 123221828Sgrehan 124221828Sgrehan /* 125221828Sgrehan * The VM has a hole in its physical memory map. If we want to 126221828Sgrehan * use 'dd' to inspect memory beyond the hole we need to 127221828Sgrehan * provide bogus data for memory that lies in the hole. 128221828Sgrehan * 129221828Sgrehan * Since this device does not support lseek(2), dd(1) will 130221828Sgrehan * read(2) blocks of data to simulate the lseek(2). 131221828Sgrehan */ 132256072Sneel hpa = vm_gpa_hold(sc->vm, gpa, c, prot, &cookie); 133256072Sneel if (hpa == NULL) { 134221828Sgrehan if (uio->uio_rw == UIO_READ) 135221828Sgrehan error = uiomove(zerobuf, c, uio); 136221828Sgrehan else 137221828Sgrehan error = EFAULT; 138256072Sneel } else { 139256072Sneel error = uiomove(hpa, c, uio); 140256072Sneel vm_gpa_release(cookie); 141256072Sneel } 142221828Sgrehan } 143221828Sgrehan return (error); 144221828Sgrehan} 145221828Sgrehan 146221828Sgrehanstatic int 147221828Sgrehanvmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, 148221828Sgrehan struct thread *td) 149221828Sgrehan{ 150270070Sgrehan int error, vcpu, state_changed, size; 151270070Sgrehan cpuset_t *cpuset; 152221828Sgrehan struct vmmdev_softc *sc; 153221828Sgrehan struct vm_memory_segment *seg; 154221828Sgrehan struct vm_register *vmreg; 155261088Sjhb struct vm_seg_desc *vmsegdesc; 156221828Sgrehan struct vm_run *vmrun; 157267427Sjhb struct vm_exception *vmexc; 158221828Sgrehan struct vm_lapic_irq *vmirq; 159262350Sjhb struct vm_lapic_msi *vmmsi; 160261088Sjhb struct vm_ioapic_irq *ioapic_irq; 161268891Sjhb struct vm_isa_irq *isa_irq; 162268972Sjhb struct vm_isa_irq_trigger *isa_irq_trigger; 163221828Sgrehan struct vm_capability *vmcap; 164221828Sgrehan struct vm_pptdev *pptdev; 165221828Sgrehan struct vm_pptdev_mmio *pptmmio; 166221828Sgrehan struct vm_pptdev_msi *pptmsi; 167234761Sgrehan struct vm_pptdev_msix *pptmsix; 168221828Sgrehan struct vm_nmi *vmnmi; 169221828Sgrehan struct vm_stats *vmstats; 170221828Sgrehan struct vm_stat_desc *statdesc; 171240922Sneel struct vm_x2apic *x2apic; 172256072Sneel struct vm_gpa_pte *gpapte; 173268935Sjhb struct vm_suspend *vmsuspend; 174268976Sjhb struct vm_gla2gpa *gg; 175270070Sgrehan struct vm_activate_cpu *vac; 176270070Sgrehan struct vm_cpuset *vm_cpuset; 177270159Sgrehan struct vm_intinfo *vmii; 178284894Sneel struct vm_rtc_time *rtctime; 179284894Sneel struct vm_rtc_data *rtcdata; 180221828Sgrehan 181221828Sgrehan sc = vmmdev_lookup2(cdev); 182241489Sneel if (sc == NULL) 183221828Sgrehan return (ENXIO); 184221828Sgrehan 185268891Sjhb error = 0; 186241489Sneel vcpu = -1; 187241489Sneel state_changed = 0; 188241489Sneel 189221828Sgrehan /* 190221828Sgrehan * Some VMM ioctls can operate only on vcpus that are not running. 191221828Sgrehan */ 192221828Sgrehan switch (cmd) { 193221828Sgrehan case VM_RUN: 194221828Sgrehan case VM_GET_REGISTER: 195221828Sgrehan case VM_SET_REGISTER: 196221828Sgrehan case VM_GET_SEGMENT_DESCRIPTOR: 197221828Sgrehan case VM_SET_SEGMENT_DESCRIPTOR: 198267427Sjhb case VM_INJECT_EXCEPTION: 199221828Sgrehan case VM_GET_CAPABILITY: 200221828Sgrehan case VM_SET_CAPABILITY: 201221828Sgrehan case VM_PPTDEV_MSI: 202241489Sneel case VM_PPTDEV_MSIX: 203240922Sneel case VM_SET_X2APIC_STATE: 204268976Sjhb case VM_GLA2GPA: 205270070Sgrehan case VM_ACTIVATE_CPU: 206270159Sgrehan case VM_SET_INTINFO: 207270159Sgrehan case VM_GET_INTINFO: 208284894Sneel case VM_RESTART_INSTRUCTION: 209221828Sgrehan /* 210221828Sgrehan * XXX fragile, handle with care 211221828Sgrehan * Assumes that the first field of the ioctl data is the vcpu. 212221828Sgrehan */ 213221828Sgrehan vcpu = *(int *)data; 214221828Sgrehan if (vcpu < 0 || vcpu >= VM_MAXCPU) { 215221828Sgrehan error = EINVAL; 216221828Sgrehan goto done; 217221828Sgrehan } 218221828Sgrehan 219266393Sjhb error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true); 220241489Sneel if (error) 221221828Sgrehan goto done; 222241489Sneel 223241489Sneel state_changed = 1; 224241489Sneel break; 225241489Sneel 226241489Sneel case VM_MAP_PPTDEV_MMIO: 227241489Sneel case VM_BIND_PPTDEV: 228241489Sneel case VM_UNBIND_PPTDEV: 229241489Sneel case VM_MAP_MEMORY: 230270071Sgrehan case VM_REINIT: 231241489Sneel /* 232241489Sneel * ioctls that operate on the entire virtual machine must 233241489Sneel * prevent all vcpus from running. 234241489Sneel */ 235241489Sneel error = 0; 236241489Sneel for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) { 237266393Sjhb error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true); 238241489Sneel if (error) 239241489Sneel break; 240221828Sgrehan } 241241489Sneel 242241489Sneel if (error) { 243241489Sneel while (--vcpu >= 0) 244266393Sjhb vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 245241489Sneel goto done; 246241489Sneel } 247241489Sneel 248241489Sneel state_changed = 2; 249221828Sgrehan break; 250241489Sneel 251221828Sgrehan default: 252221828Sgrehan break; 253221828Sgrehan } 254221828Sgrehan 255221828Sgrehan switch(cmd) { 256221828Sgrehan case VM_RUN: 257221828Sgrehan vmrun = (struct vm_run *)data; 258221828Sgrehan error = vm_run(sc->vm, vmrun); 259221828Sgrehan break; 260268935Sjhb case VM_SUSPEND: 261268935Sjhb vmsuspend = (struct vm_suspend *)data; 262268935Sjhb error = vm_suspend(sc->vm, vmsuspend->how); 263268935Sjhb break; 264270071Sgrehan case VM_REINIT: 265270071Sgrehan error = vm_reinit(sc->vm); 266270071Sgrehan break; 267221828Sgrehan case VM_STAT_DESC: { 268221828Sgrehan statdesc = (struct vm_stat_desc *)data; 269250427Sneel error = vmm_stat_desc_copy(statdesc->index, 270250427Sneel statdesc->desc, sizeof(statdesc->desc)); 271221828Sgrehan break; 272221828Sgrehan } 273221828Sgrehan case VM_STATS: { 274250427Sneel CTASSERT(MAX_VM_STATS >= MAX_VMM_STAT_ELEMS); 275221828Sgrehan vmstats = (struct vm_stats *)data; 276221828Sgrehan getmicrotime(&vmstats->tv); 277221828Sgrehan error = vmm_stat_copy(sc->vm, vmstats->cpuid, 278221828Sgrehan &vmstats->num_entries, vmstats->statbuf); 279221828Sgrehan break; 280221828Sgrehan } 281221828Sgrehan case VM_PPTDEV_MSI: 282221828Sgrehan pptmsi = (struct vm_pptdev_msi *)data; 283221828Sgrehan error = ppt_setup_msi(sc->vm, pptmsi->vcpu, 284221828Sgrehan pptmsi->bus, pptmsi->slot, pptmsi->func, 285262350Sjhb pptmsi->addr, pptmsi->msg, 286221828Sgrehan pptmsi->numvec); 287221828Sgrehan break; 288234761Sgrehan case VM_PPTDEV_MSIX: 289234761Sgrehan pptmsix = (struct vm_pptdev_msix *)data; 290234761Sgrehan error = ppt_setup_msix(sc->vm, pptmsix->vcpu, 291234761Sgrehan pptmsix->bus, pptmsix->slot, 292234761Sgrehan pptmsix->func, pptmsix->idx, 293262350Sjhb pptmsix->addr, pptmsix->msg, 294262350Sjhb pptmsix->vector_control); 295234761Sgrehan break; 296221828Sgrehan case VM_MAP_PPTDEV_MMIO: 297221828Sgrehan pptmmio = (struct vm_pptdev_mmio *)data; 298221828Sgrehan error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot, 299221828Sgrehan pptmmio->func, pptmmio->gpa, pptmmio->len, 300221828Sgrehan pptmmio->hpa); 301221828Sgrehan break; 302221828Sgrehan case VM_BIND_PPTDEV: 303221828Sgrehan pptdev = (struct vm_pptdev *)data; 304256072Sneel error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot, 305256072Sneel pptdev->func); 306221828Sgrehan break; 307221828Sgrehan case VM_UNBIND_PPTDEV: 308221828Sgrehan pptdev = (struct vm_pptdev *)data; 309256072Sneel error = vm_unassign_pptdev(sc->vm, pptdev->bus, pptdev->slot, 310256072Sneel pptdev->func); 311221828Sgrehan break; 312267427Sjhb case VM_INJECT_EXCEPTION: 313267427Sjhb vmexc = (struct vm_exception *)data; 314284894Sneel error = vm_inject_exception(sc->vm, vmexc->cpuid, 315284894Sneel vmexc->vector, vmexc->error_code_valid, vmexc->error_code, 316284894Sneel vmexc->restart_instruction); 317221828Sgrehan break; 318221828Sgrehan case VM_INJECT_NMI: 319221828Sgrehan vmnmi = (struct vm_nmi *)data; 320221828Sgrehan error = vm_inject_nmi(sc->vm, vmnmi->cpuid); 321221828Sgrehan break; 322221828Sgrehan case VM_LAPIC_IRQ: 323221828Sgrehan vmirq = (struct vm_lapic_irq *)data; 324261088Sjhb error = lapic_intr_edge(sc->vm, vmirq->cpuid, vmirq->vector); 325221828Sgrehan break; 326262350Sjhb case VM_LAPIC_LOCAL_IRQ: 327262350Sjhb vmirq = (struct vm_lapic_irq *)data; 328262350Sjhb error = lapic_set_local_intr(sc->vm, vmirq->cpuid, 329262350Sjhb vmirq->vector); 330262350Sjhb break; 331262350Sjhb case VM_LAPIC_MSI: 332262350Sjhb vmmsi = (struct vm_lapic_msi *)data; 333262350Sjhb error = lapic_intr_msi(sc->vm, vmmsi->addr, vmmsi->msg); 334262350Sjhb break; 335261088Sjhb case VM_IOAPIC_ASSERT_IRQ: 336261088Sjhb ioapic_irq = (struct vm_ioapic_irq *)data; 337261088Sjhb error = vioapic_assert_irq(sc->vm, ioapic_irq->irq); 338261088Sjhb break; 339261088Sjhb case VM_IOAPIC_DEASSERT_IRQ: 340261088Sjhb ioapic_irq = (struct vm_ioapic_irq *)data; 341261088Sjhb error = vioapic_deassert_irq(sc->vm, ioapic_irq->irq); 342261088Sjhb break; 343261088Sjhb case VM_IOAPIC_PULSE_IRQ: 344261088Sjhb ioapic_irq = (struct vm_ioapic_irq *)data; 345261088Sjhb error = vioapic_pulse_irq(sc->vm, ioapic_irq->irq); 346261088Sjhb break; 347267393Sjhb case VM_IOAPIC_PINCOUNT: 348267393Sjhb *(int *)data = vioapic_pincount(sc->vm); 349267393Sjhb break; 350268891Sjhb case VM_ISA_ASSERT_IRQ: 351268891Sjhb isa_irq = (struct vm_isa_irq *)data; 352268891Sjhb error = vatpic_assert_irq(sc->vm, isa_irq->atpic_irq); 353268891Sjhb if (error == 0 && isa_irq->ioapic_irq != -1) 354268891Sjhb error = vioapic_assert_irq(sc->vm, 355268891Sjhb isa_irq->ioapic_irq); 356268891Sjhb break; 357268891Sjhb case VM_ISA_DEASSERT_IRQ: 358268891Sjhb isa_irq = (struct vm_isa_irq *)data; 359268891Sjhb error = vatpic_deassert_irq(sc->vm, isa_irq->atpic_irq); 360268891Sjhb if (error == 0 && isa_irq->ioapic_irq != -1) 361268891Sjhb error = vioapic_deassert_irq(sc->vm, 362268891Sjhb isa_irq->ioapic_irq); 363268891Sjhb break; 364268891Sjhb case VM_ISA_PULSE_IRQ: 365268891Sjhb isa_irq = (struct vm_isa_irq *)data; 366268891Sjhb error = vatpic_pulse_irq(sc->vm, isa_irq->atpic_irq); 367268891Sjhb if (error == 0 && isa_irq->ioapic_irq != -1) 368268891Sjhb error = vioapic_pulse_irq(sc->vm, isa_irq->ioapic_irq); 369268891Sjhb break; 370268972Sjhb case VM_ISA_SET_IRQ_TRIGGER: 371268972Sjhb isa_irq_trigger = (struct vm_isa_irq_trigger *)data; 372268972Sjhb error = vatpic_set_irq_trigger(sc->vm, 373268972Sjhb isa_irq_trigger->atpic_irq, isa_irq_trigger->trigger); 374268972Sjhb break; 375221828Sgrehan case VM_MAP_MEMORY: 376221828Sgrehan seg = (struct vm_memory_segment *)data; 377241041Sneel error = vm_malloc(sc->vm, seg->gpa, seg->len); 378221828Sgrehan break; 379221828Sgrehan case VM_GET_MEMORY_SEG: 380221828Sgrehan seg = (struct vm_memory_segment *)data; 381241178Sneel seg->len = 0; 382221828Sgrehan (void)vm_gpabase2memseg(sc->vm, seg->gpa, seg); 383221828Sgrehan error = 0; 384221828Sgrehan break; 385221828Sgrehan case VM_GET_REGISTER: 386221828Sgrehan vmreg = (struct vm_register *)data; 387221828Sgrehan error = vm_get_register(sc->vm, vmreg->cpuid, vmreg->regnum, 388221828Sgrehan &vmreg->regval); 389221828Sgrehan break; 390221828Sgrehan case VM_SET_REGISTER: 391221828Sgrehan vmreg = (struct vm_register *)data; 392221828Sgrehan error = vm_set_register(sc->vm, vmreg->cpuid, vmreg->regnum, 393221828Sgrehan vmreg->regval); 394221828Sgrehan break; 395221828Sgrehan case VM_SET_SEGMENT_DESCRIPTOR: 396221828Sgrehan vmsegdesc = (struct vm_seg_desc *)data; 397221828Sgrehan error = vm_set_seg_desc(sc->vm, vmsegdesc->cpuid, 398221828Sgrehan vmsegdesc->regnum, 399221828Sgrehan &vmsegdesc->desc); 400221828Sgrehan break; 401221828Sgrehan case VM_GET_SEGMENT_DESCRIPTOR: 402221828Sgrehan vmsegdesc = (struct vm_seg_desc *)data; 403221828Sgrehan error = vm_get_seg_desc(sc->vm, vmsegdesc->cpuid, 404221828Sgrehan vmsegdesc->regnum, 405221828Sgrehan &vmsegdesc->desc); 406221828Sgrehan break; 407221828Sgrehan case VM_GET_CAPABILITY: 408221828Sgrehan vmcap = (struct vm_capability *)data; 409221828Sgrehan error = vm_get_capability(sc->vm, vmcap->cpuid, 410221828Sgrehan vmcap->captype, 411221828Sgrehan &vmcap->capval); 412221828Sgrehan break; 413221828Sgrehan case VM_SET_CAPABILITY: 414221828Sgrehan vmcap = (struct vm_capability *)data; 415221828Sgrehan error = vm_set_capability(sc->vm, vmcap->cpuid, 416221828Sgrehan vmcap->captype, 417221828Sgrehan vmcap->capval); 418221828Sgrehan break; 419240922Sneel case VM_SET_X2APIC_STATE: 420240922Sneel x2apic = (struct vm_x2apic *)data; 421240922Sneel error = vm_set_x2apic_state(sc->vm, 422240922Sneel x2apic->cpuid, x2apic->state); 423240922Sneel break; 424240922Sneel case VM_GET_X2APIC_STATE: 425240922Sneel x2apic = (struct vm_x2apic *)data; 426240922Sneel error = vm_get_x2apic_state(sc->vm, 427240922Sneel x2apic->cpuid, &x2apic->state); 428240922Sneel break; 429256072Sneel case VM_GET_GPA_PMAP: 430256072Sneel gpapte = (struct vm_gpa_pte *)data; 431256072Sneel pmap_get_mapping(vmspace_pmap(vm_get_vmspace(sc->vm)), 432256072Sneel gpapte->gpa, gpapte->pte, &gpapte->ptenum); 433256072Sneel error = 0; 434256072Sneel break; 435261088Sjhb case VM_GET_HPET_CAPABILITIES: 436261088Sjhb error = vhpet_getcap((struct vm_hpet_cap *)data); 437261088Sjhb break; 438268976Sjhb case VM_GLA2GPA: { 439268976Sjhb CTASSERT(PROT_READ == VM_PROT_READ); 440268976Sjhb CTASSERT(PROT_WRITE == VM_PROT_WRITE); 441268976Sjhb CTASSERT(PROT_EXEC == VM_PROT_EXECUTE); 442268976Sjhb gg = (struct vm_gla2gpa *)data; 443284899Sneel error = vm_gla2gpa(sc->vm, gg->vcpuid, &gg->paging, gg->gla, 444268976Sjhb gg->prot, &gg->gpa); 445268976Sjhb KASSERT(error == 0 || error == 1 || error == -1, 446284899Sneel ("%s: vm_gla2gpa unknown error %d", __func__, error)); 447268976Sjhb if (error >= 0) { 448268976Sjhb /* 449268976Sjhb * error = 0: the translation was successful 450268976Sjhb * error = 1: a fault was injected into the guest 451268976Sjhb */ 452268976Sjhb gg->fault = error; 453268976Sjhb error = 0; 454268976Sjhb } else { 455268976Sjhb error = EFAULT; 456268976Sjhb } 457268976Sjhb break; 458268976Sjhb } 459270070Sgrehan case VM_ACTIVATE_CPU: 460270070Sgrehan vac = (struct vm_activate_cpu *)data; 461270070Sgrehan error = vm_activate_cpu(sc->vm, vac->vcpuid); 462270070Sgrehan break; 463270070Sgrehan case VM_GET_CPUS: 464270070Sgrehan error = 0; 465270070Sgrehan vm_cpuset = (struct vm_cpuset *)data; 466270070Sgrehan size = vm_cpuset->cpusetsize; 467270070Sgrehan if (size < sizeof(cpuset_t) || size > CPU_MAXSIZE / NBBY) { 468270070Sgrehan error = ERANGE; 469270070Sgrehan break; 470270070Sgrehan } 471270070Sgrehan cpuset = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 472270070Sgrehan if (vm_cpuset->which == VM_ACTIVE_CPUS) 473270070Sgrehan *cpuset = vm_active_cpus(sc->vm); 474270070Sgrehan else if (vm_cpuset->which == VM_SUSPENDED_CPUS) 475270070Sgrehan *cpuset = vm_suspended_cpus(sc->vm); 476270070Sgrehan else 477270070Sgrehan error = EINVAL; 478270070Sgrehan if (error == 0) 479270070Sgrehan error = copyout(cpuset, vm_cpuset->cpus, size); 480270070Sgrehan free(cpuset, M_TEMP); 481270070Sgrehan break; 482270159Sgrehan case VM_SET_INTINFO: 483270159Sgrehan vmii = (struct vm_intinfo *)data; 484270159Sgrehan error = vm_exit_intinfo(sc->vm, vmii->vcpuid, vmii->info1); 485270159Sgrehan break; 486270159Sgrehan case VM_GET_INTINFO: 487270159Sgrehan vmii = (struct vm_intinfo *)data; 488270159Sgrehan error = vm_get_intinfo(sc->vm, vmii->vcpuid, &vmii->info1, 489270159Sgrehan &vmii->info2); 490270159Sgrehan break; 491284894Sneel case VM_RTC_WRITE: 492284894Sneel rtcdata = (struct vm_rtc_data *)data; 493284894Sneel error = vrtc_nvram_write(sc->vm, rtcdata->offset, 494284894Sneel rtcdata->value); 495284894Sneel break; 496284894Sneel case VM_RTC_READ: 497284894Sneel rtcdata = (struct vm_rtc_data *)data; 498284894Sneel error = vrtc_nvram_read(sc->vm, rtcdata->offset, 499284894Sneel &rtcdata->value); 500284894Sneel break; 501284894Sneel case VM_RTC_SETTIME: 502284894Sneel rtctime = (struct vm_rtc_time *)data; 503284894Sneel error = vrtc_set_time(sc->vm, rtctime->secs); 504284894Sneel break; 505284894Sneel case VM_RTC_GETTIME: 506284894Sneel error = 0; 507284894Sneel rtctime = (struct vm_rtc_time *)data; 508284894Sneel rtctime->secs = vrtc_get_time(sc->vm); 509284894Sneel break; 510284894Sneel case VM_RESTART_INSTRUCTION: 511284894Sneel error = vm_restart_instruction(sc->vm, vcpu); 512284894Sneel break; 513221828Sgrehan default: 514221828Sgrehan error = ENOTTY; 515221828Sgrehan break; 516221828Sgrehan } 517241489Sneel 518241489Sneel if (state_changed == 1) { 519266393Sjhb vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 520241489Sneel } else if (state_changed == 2) { 521241489Sneel for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) 522266393Sjhb vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 523241489Sneel } 524241489Sneel 525221828Sgrehandone: 526256072Sneel /* Make sure that no handler returns a bogus value like ERESTART */ 527256072Sneel KASSERT(error >= 0, ("vmmdev_ioctl: invalid error return %d", error)); 528221828Sgrehan return (error); 529221828Sgrehan} 530221828Sgrehan 531221828Sgrehanstatic int 532256072Sneelvmmdev_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, 533256072Sneel vm_size_t size, struct vm_object **object, int nprot) 534221828Sgrehan{ 535221828Sgrehan int error; 536221828Sgrehan struct vmmdev_softc *sc; 537221828Sgrehan 538221828Sgrehan sc = vmmdev_lookup2(cdev); 539256072Sneel if (sc != NULL && (nprot & PROT_EXEC) == 0) 540256072Sneel error = vm_get_memobj(sc->vm, *offset, size, offset, object); 541256072Sneel else 542256072Sneel error = EINVAL; 543221828Sgrehan 544221828Sgrehan return (error); 545221828Sgrehan} 546221828Sgrehan 547221828Sgrehanstatic void 548256651Sneelvmmdev_destroy(void *arg) 549221828Sgrehan{ 550221828Sgrehan 551256651Sneel struct vmmdev_softc *sc = arg; 552256651Sneel 553256651Sneel if (sc->cdev != NULL) 554241454Sneel destroy_dev(sc->cdev); 555241454Sneel 556256651Sneel if (sc->vm != NULL) 557241454Sneel vm_destroy(sc->vm); 558241454Sneel 559256651Sneel if ((sc->flags & VSC_LINKED) != 0) { 560241454Sneel mtx_lock(&vmmdev_mtx); 561241454Sneel SLIST_REMOVE(&head, sc, vmmdev_softc, link); 562241454Sneel mtx_unlock(&vmmdev_mtx); 563241454Sneel } 564241454Sneel 565221828Sgrehan free(sc, M_VMMDEV); 566221828Sgrehan} 567221828Sgrehan 568221828Sgrehanstatic int 569221828Sgrehansysctl_vmm_destroy(SYSCTL_HANDLER_ARGS) 570221828Sgrehan{ 571221828Sgrehan int error; 572221828Sgrehan char buf[VM_MAX_NAMELEN]; 573221828Sgrehan struct vmmdev_softc *sc; 574256651Sneel struct cdev *cdev; 575221828Sgrehan 576221828Sgrehan strlcpy(buf, "beavis", sizeof(buf)); 577221828Sgrehan error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 578221828Sgrehan if (error != 0 || req->newptr == NULL) 579221828Sgrehan return (error); 580221828Sgrehan 581221828Sgrehan mtx_lock(&vmmdev_mtx); 582221828Sgrehan sc = vmmdev_lookup(buf); 583256651Sneel if (sc == NULL || sc->cdev == NULL) { 584221828Sgrehan mtx_unlock(&vmmdev_mtx); 585221828Sgrehan return (EINVAL); 586221828Sgrehan } 587241454Sneel 588256651Sneel /* 589256651Sneel * The 'cdev' will be destroyed asynchronously when 'si_threadcount' 590256651Sneel * goes down to 0 so we should not do it again in the callback. 591256651Sneel */ 592256651Sneel cdev = sc->cdev; 593256651Sneel sc->cdev = NULL; 594221828Sgrehan mtx_unlock(&vmmdev_mtx); 595241454Sneel 596256651Sneel /* 597256651Sneel * Schedule the 'cdev' to be destroyed: 598256651Sneel * 599256651Sneel * - any new operations on this 'cdev' will return an error (ENXIO). 600256651Sneel * 601256651Sneel * - when the 'si_threadcount' dwindles down to zero the 'cdev' will 602256651Sneel * be destroyed and the callback will be invoked in a taskqueue 603256651Sneel * context. 604256651Sneel */ 605256651Sneel destroy_dev_sched_cb(cdev, vmmdev_destroy, sc); 606241454Sneel 607221828Sgrehan return (0); 608221828Sgrehan} 609221828SgrehanSYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW, 610221828Sgrehan NULL, 0, sysctl_vmm_destroy, "A", NULL); 611221828Sgrehan 612221828Sgrehanstatic struct cdevsw vmmdevsw = { 613221828Sgrehan .d_name = "vmmdev", 614221828Sgrehan .d_version = D_VERSION, 615221828Sgrehan .d_ioctl = vmmdev_ioctl, 616256072Sneel .d_mmap_single = vmmdev_mmap_single, 617221828Sgrehan .d_read = vmmdev_rw, 618221828Sgrehan .d_write = vmmdev_rw, 619221828Sgrehan}; 620221828Sgrehan 621221828Sgrehanstatic int 622221828Sgrehansysctl_vmm_create(SYSCTL_HANDLER_ARGS) 623221828Sgrehan{ 624221828Sgrehan int error; 625221828Sgrehan struct vm *vm; 626256651Sneel struct cdev *cdev; 627241454Sneel struct vmmdev_softc *sc, *sc2; 628221828Sgrehan char buf[VM_MAX_NAMELEN]; 629221828Sgrehan 630221828Sgrehan strlcpy(buf, "beavis", sizeof(buf)); 631221828Sgrehan error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 632221828Sgrehan if (error != 0 || req->newptr == NULL) 633221828Sgrehan return (error); 634221828Sgrehan 635221828Sgrehan mtx_lock(&vmmdev_mtx); 636221828Sgrehan sc = vmmdev_lookup(buf); 637241454Sneel mtx_unlock(&vmmdev_mtx); 638241454Sneel if (sc != NULL) 639221828Sgrehan return (EEXIST); 640221828Sgrehan 641249396Sneel error = vm_create(buf, &vm); 642249396Sneel if (error != 0) 643249396Sneel return (error); 644221828Sgrehan 645221828Sgrehan sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO); 646221828Sgrehan sc->vm = vm; 647241454Sneel 648241454Sneel /* 649241454Sneel * Lookup the name again just in case somebody sneaked in when we 650241454Sneel * dropped the lock. 651241454Sneel */ 652241454Sneel mtx_lock(&vmmdev_mtx); 653241454Sneel sc2 = vmmdev_lookup(buf); 654256651Sneel if (sc2 == NULL) { 655241454Sneel SLIST_INSERT_HEAD(&head, sc, link); 656256651Sneel sc->flags |= VSC_LINKED; 657256651Sneel } 658241454Sneel mtx_unlock(&vmmdev_mtx); 659241454Sneel 660241454Sneel if (sc2 != NULL) { 661256651Sneel vmmdev_destroy(sc); 662241454Sneel return (EEXIST); 663241454Sneel } 664241454Sneel 665256651Sneel error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, NULL, 666249435Sneel UID_ROOT, GID_WHEEL, 0600, "vmm/%s", buf); 667249435Sneel if (error != 0) { 668256651Sneel vmmdev_destroy(sc); 669249435Sneel return (error); 670249435Sneel } 671256651Sneel 672256651Sneel mtx_lock(&vmmdev_mtx); 673256651Sneel sc->cdev = cdev; 674221828Sgrehan sc->cdev->si_drv1 = sc; 675256651Sneel mtx_unlock(&vmmdev_mtx); 676221828Sgrehan 677221828Sgrehan return (0); 678221828Sgrehan} 679221828SgrehanSYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW, 680221828Sgrehan NULL, 0, sysctl_vmm_create, "A", NULL); 681221828Sgrehan 682221828Sgrehanvoid 683221828Sgrehanvmmdev_init(void) 684221828Sgrehan{ 685221828Sgrehan mtx_init(&vmmdev_mtx, "vmm device mutex", NULL, MTX_DEF); 686221828Sgrehan} 687221828Sgrehan 688241454Sneelint 689221828Sgrehanvmmdev_cleanup(void) 690221828Sgrehan{ 691241454Sneel int error; 692221828Sgrehan 693241454Sneel if (SLIST_EMPTY(&head)) 694241454Sneel error = 0; 695241454Sneel else 696241454Sneel error = EBUSY; 697221828Sgrehan 698241454Sneel return (error); 699221828Sgrehan} 700