vmm_dev.c revision 284899
1106159Sjulian/*- 2106159Sjulian * Copyright (c) 2011 NetApp, Inc. 3139823Simp * All rights reserved. 4139823Simp * 5139823Simp * Redistribution and use in source and binary forms, with or without 6106159Sjulian * modification, are permitted provided that the following conditions 7106159Sjulian * are met: 8106159Sjulian * 1. Redistributions of source code must retain the above copyright 9106159Sjulian * notice, this list of conditions and the following disclaimer. 10106159Sjulian * 2. Redistributions in binary form must reproduce the above copyright 11106159Sjulian * notice, this list of conditions and the following disclaimer in the 12106159Sjulian * documentation and/or other materials provided with the distribution. 13106159Sjulian * 14106159Sjulian * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15106159Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16106159Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17106159Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18106159Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19106159Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20106159Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21106159Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22106159Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23106159Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24106159Sjulian * SUCH DAMAGE. 25106159Sjulian * 26106159Sjulian * $FreeBSD: stable/10/sys/amd64/vmm/vmm_dev.c 284899 2015-06-28 01:21:55Z neel $ 27106159Sjulian */ 28106159Sjulian 29106159Sjulian#include <sys/cdefs.h> 30106159Sjulian__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/vmm_dev.c 284899 2015-06-28 01:21:55Z neel $"); 31106159Sjulian 32106159Sjulian#include <sys/param.h> 33106159Sjulian#include <sys/kernel.h> 34106159Sjulian#include <sys/queue.h> 35106159Sjulian#include <sys/lock.h> 36106159Sjulian#include <sys/mutex.h> 37106159Sjulian#include <sys/malloc.h> 38106159Sjulian#include <sys/conf.h> 39139823Simp#include <sys/sysctl.h> 40106159Sjulian#include <sys/libkern.h> 41106159Sjulian#include <sys/ioccom.h> 42106159Sjulian#include <sys/mman.h> 43106159Sjulian#include <sys/uio.h> 44106159Sjulian 45106159Sjulian#include <vm/vm.h> 46106159Sjulian#include <vm/pmap.h> 47106159Sjulian#include <vm/vm_map.h> 48106159Sjulian 49106159Sjulian#include <machine/vmparam.h> 50106159Sjulian#include <machine/vmm.h> 51106159Sjulian#include <machine/vmm_instruction_emul.h> 52106159Sjulian#include <machine/vmm_dev.h> 53106159Sjulian 54106159Sjulian#include "vmm_lapic.h" 55106159Sjulian#include "vmm_stat.h" 56106159Sjulian#include "vmm_mem.h" 57106159Sjulian#include "io/ppt.h" 58106159Sjulian#include "io/vatpic.h" 59106159Sjulian#include "io/vioapic.h" 60106159Sjulian#include "io/vhpet.h" 61106159Sjulian#include "io/vrtc.h" 62106159Sjulian 63106159Sjulianstruct vmmdev_softc { 64106159Sjulian struct vm *vm; /* vm instance cookie */ 65106159Sjulian struct cdev *cdev; 66106159Sjulian SLIST_ENTRY(vmmdev_softc) link; 67106159Sjulian int flags; 68106159Sjulian}; 69106159Sjulian#define VSC_LINKED 0x01 70106159Sjulian 71106159Sjulianstatic SLIST_HEAD(, vmmdev_softc) head; 72106159Sjulian 73106159Sjulianstatic struct mtx vmmdev_mtx; 74106159Sjulian 75106159Sjulianstatic MALLOC_DEFINE(M_VMMDEV, "vmmdev", "vmmdev"); 76106159Sjulian 77106159SjulianSYSCTL_DECL(_hw_vmm); 78106159Sjulian 79106159Sjulianstatic struct vmmdev_softc * 80106159Sjulianvmmdev_lookup(const char *name) 81106159Sjulian{ 82106159Sjulian struct vmmdev_softc *sc; 83106159Sjulian 84106159Sjulian#ifdef notyet /* XXX kernel is not compiled with invariants */ 85106159Sjulian mtx_assert(&vmmdev_mtx, MA_OWNED); 86106159Sjulian#endif 87106159Sjulian 88106159Sjulian SLIST_FOREACH(sc, &head, link) { 89106159Sjulian if (strcmp(name, vm_name(sc->vm)) == 0) 90106159Sjulian break; 91106159Sjulian } 92106159Sjulian 93106159Sjulian return (sc); 94106159Sjulian} 95106159Sjulian 96106159Sjulianstatic struct vmmdev_softc * 97106159Sjulianvmmdev_lookup2(struct cdev *cdev) 98106159Sjulian{ 99106159Sjulian 100106159Sjulian return (cdev->si_drv1); 101106159Sjulian} 102106159Sjulian 103106159Sjulianstatic int 104106159Sjulianvmmdev_rw(struct cdev *cdev, struct uio *uio, int flags) 105152315Sru{ 106106159Sjulian int error, off, c, prot; 107106159Sjulian vm_paddr_t gpa; 108106159Sjulian void *hpa, *cookie; 109106159Sjulian struct vmmdev_softc *sc; 110191148Skmacy 111106159Sjulian static char zerobuf[PAGE_SIZE]; 112106159Sjulian 113106159Sjulian error = 0; 114106159Sjulian sc = vmmdev_lookup2(cdev); 115106159Sjulian if (sc == NULL) 116106159Sjulian error = ENXIO; 117106159Sjulian 118106159Sjulian prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ); 119106159Sjulian while (uio->uio_resid > 0 && error == 0) { 120106159Sjulian gpa = uio->uio_offset; 121106159Sjulian off = gpa & PAGE_MASK; 122106159Sjulian c = min(uio->uio_resid, PAGE_SIZE - off); 123106159Sjulian 124106159Sjulian /* 125106159Sjulian * The VM has a hole in its physical memory map. If we want to 126106159Sjulian * use 'dd' to inspect memory beyond the hole we need to 127106159Sjulian * provide bogus data for memory that lies in the hole. 128106159Sjulian * 129106159Sjulian * Since this device does not support lseek(2), dd(1) will 130130808Swpaul * read(2) blocks of data to simulate the lseek(2). 131130808Swpaul */ 132130808Swpaul hpa = vm_gpa_hold(sc->vm, gpa, c, prot, &cookie); 133130808Swpaul if (hpa == NULL) { 134130808Swpaul if (uio->uio_rw == UIO_READ) 135130815Swpaul error = uiomove(zerobuf, c, uio); 136130815Swpaul else 137130808Swpaul error = EFAULT; 138152243Sru } else { 139106159Sjulian error = uiomove(hpa, c, uio); 140106159Sjulian vm_gpa_release(cookie); 141106159Sjulian } 142106159Sjulian } 143106159Sjulian return (error); 144106159Sjulian} 145106159Sjulian 146106159Sjulianstatic int 147106159Sjulianvmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, 148130815Swpaul struct thread *td) 149130815Swpaul{ 150106159Sjulian int error, vcpu, state_changed, size; 151106159Sjulian cpuset_t *cpuset; 152106159Sjulian struct vmmdev_softc *sc; 153169677Sdwmalone struct vm_memory_segment *seg; 154106159Sjulian struct vm_register *vmreg; 155106159Sjulian struct vm_seg_desc *vmsegdesc; 156106159Sjulian struct vm_run *vmrun; 157169677Sdwmalone struct vm_exception *vmexc; 158169677Sdwmalone struct vm_lapic_irq *vmirq; 159169677Sdwmalone struct vm_lapic_msi *vmmsi; 160169677Sdwmalone struct vm_ioapic_irq *ioapic_irq; 161169677Sdwmalone struct vm_isa_irq *isa_irq; 162106159Sjulian struct vm_isa_irq_trigger *isa_irq_trigger; 163106159Sjulian struct vm_capability *vmcap; 164106159Sjulian struct vm_pptdev *pptdev; 165106159Sjulian struct vm_pptdev_mmio *pptmmio; 166130815Swpaul struct vm_pptdev_msi *pptmsi; 167130815Swpaul struct vm_pptdev_msix *pptmsix; 168249925Sglebius struct vm_nmi *vmnmi; 169191148Skmacy struct vm_stats *vmstats; 170106159Sjulian struct vm_stat_desc *statdesc; 171106159Sjulian struct vm_x2apic *x2apic; 172106159Sjulian struct vm_gpa_pte *gpapte; 173106159Sjulian struct vm_suspend *vmsuspend; 174106159Sjulian struct vm_gla2gpa *gg; 175106159Sjulian struct vm_activate_cpu *vac; 176106159Sjulian struct vm_cpuset *vm_cpuset; 177106159Sjulian struct vm_intinfo *vmii; 178147256Sbrooks struct vm_rtc_time *rtctime; 179106159Sjulian struct vm_rtc_data *rtcdata; 180106159Sjulian 181106159Sjulian sc = vmmdev_lookup2(cdev); 182106159Sjulian if (sc == NULL) 183106159Sjulian return (ENXIO); 184106159Sjulian 185106159Sjulian error = 0; 186106159Sjulian vcpu = -1; 187106159Sjulian state_changed = 0; 188106159Sjulian 189106159Sjulian /* 190111565Swpaul * Some VMM ioctls can operate only on vcpus that are not running. 191106159Sjulian */ 192106159Sjulian switch (cmd) { 193106159Sjulian case VM_RUN: 194106159Sjulian case VM_GET_REGISTER: 195106159Sjulian case VM_SET_REGISTER: 196106159Sjulian case VM_GET_SEGMENT_DESCRIPTOR: 197106159Sjulian case VM_SET_SEGMENT_DESCRIPTOR: 198106159Sjulian case VM_INJECT_EXCEPTION: 199106159Sjulian case VM_GET_CAPABILITY: 200106159Sjulian case VM_SET_CAPABILITY: 201249925Sglebius case VM_PPTDEV_MSI: 202106159Sjulian case VM_PPTDEV_MSIX: 203106159Sjulian case VM_SET_X2APIC_STATE: 204106159Sjulian case VM_GLA2GPA: 205169677Sdwmalone case VM_ACTIVATE_CPU: 206106159Sjulian case VM_SET_INTINFO: 207106159Sjulian case VM_GET_INTINFO: 208106159Sjulian case VM_RESTART_INSTRUCTION: 209106159Sjulian /* 210106159Sjulian * XXX fragile, handle with care 211106159Sjulian * Assumes that the first field of the ioctl data is the vcpu. 212141341Sru */ 213106159Sjulian vcpu = *(int *)data; 214106159Sjulian if (vcpu < 0 || vcpu >= VM_MAXCPU) { 215106159Sjulian error = EINVAL; 216106159Sjulian goto done; 217106159Sjulian } 218106159Sjulian 219106159Sjulian error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true); 220106159Sjulian if (error) 221106159Sjulian goto done; 222106159Sjulian 223106159Sjulian state_changed = 1; 224106159Sjulian break; 225106159Sjulian 226106159Sjulian case VM_MAP_PPTDEV_MMIO: 227106159Sjulian case VM_BIND_PPTDEV: 228106159Sjulian case VM_UNBIND_PPTDEV: 229106159Sjulian case VM_MAP_MEMORY: 230106159Sjulian case VM_REINIT: 231106159Sjulian /* 232106159Sjulian * ioctls that operate on the entire virtual machine must 233106159Sjulian * prevent all vcpus from running. 234106159Sjulian */ 235106159Sjulian error = 0; 236106159Sjulian for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) { 237106159Sjulian error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true); 238106159Sjulian if (error) 239106159Sjulian break; 240106159Sjulian } 241106159Sjulian 242106159Sjulian if (error) { 243106159Sjulian while (--vcpu >= 0) 244106159Sjulian vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 245106159Sjulian goto done; 246106159Sjulian } 247106159Sjulian 248106159Sjulian state_changed = 2; 249106159Sjulian break; 250106159Sjulian 251106159Sjulian default: 252129823Sjulian break; 253129823Sjulian } 254141341Sru 255129823Sjulian switch(cmd) { 256129823Sjulian case VM_RUN: 257129823Sjulian vmrun = (struct vm_run *)data; 258129823Sjulian error = vm_run(sc->vm, vmrun); 259106159Sjulian break; 260106159Sjulian case VM_SUSPEND: 261106159Sjulian vmsuspend = (struct vm_suspend *)data; 262106159Sjulian error = vm_suspend(sc->vm, vmsuspend->how); 263106159Sjulian break; 264106159Sjulian case VM_REINIT: 265106159Sjulian error = vm_reinit(sc->vm); 266106159Sjulian break; 267106159Sjulian case VM_STAT_DESC: { 268106159Sjulian statdesc = (struct vm_stat_desc *)data; 269106159Sjulian error = vmm_stat_desc_copy(statdesc->index, 270132161Srwatson statdesc->desc, sizeof(statdesc->desc)); 271132161Srwatson break; 272106159Sjulian } 273106159Sjulian case VM_STATS: { 274106159Sjulian CTASSERT(MAX_VM_STATS >= MAX_VMM_STAT_ELEMS); 275106159Sjulian vmstats = (struct vm_stats *)data; 276131575Sstefanf getmicrotime(&vmstats->tv); 277106159Sjulian error = vmm_stat_copy(sc->vm, vmstats->cpuid, 278106159Sjulian &vmstats->num_entries, vmstats->statbuf); 279106159Sjulian break; 280106159Sjulian } 281132161Srwatson case VM_PPTDEV_MSI: 282106159Sjulian pptmsi = (struct vm_pptdev_msi *)data; 283106159Sjulian error = ppt_setup_msi(sc->vm, pptmsi->vcpu, 284106159Sjulian pptmsi->bus, pptmsi->slot, pptmsi->func, 285106159Sjulian pptmsi->addr, pptmsi->msg, 286106159Sjulian pptmsi->numvec); 287106159Sjulian break; 288184205Sdes case VM_PPTDEV_MSIX: 289106159Sjulian pptmsix = (struct vm_pptdev_msix *)data; 290132161Srwatson error = ppt_setup_msix(sc->vm, pptmsix->vcpu, 291132161Srwatson pptmsix->bus, pptmsix->slot, 292106159Sjulian pptmsix->func, pptmsix->idx, 293132161Srwatson pptmsix->addr, pptmsix->msg, 294106159Sjulian pptmsix->vector_control); 295106159Sjulian break; 296106159Sjulian case VM_MAP_PPTDEV_MMIO: 297106159Sjulian pptmmio = (struct vm_pptdev_mmio *)data; 298106159Sjulian error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot, 299184205Sdes pptmmio->func, pptmmio->gpa, pptmmio->len, 300106159Sjulian pptmmio->hpa); 301106159Sjulian break; 302106159Sjulian case VM_BIND_PPTDEV: 303106159Sjulian pptdev = (struct vm_pptdev *)data; 304106159Sjulian error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot, 305148915Sobrien pptdev->func); 306106159Sjulian break; 307106159Sjulian case VM_UNBIND_PPTDEV: 308106159Sjulian pptdev = (struct vm_pptdev *)data; 309132161Srwatson error = vm_unassign_pptdev(sc->vm, pptdev->bus, pptdev->slot, 310106159Sjulian pptdev->func); 311106159Sjulian break; 312106159Sjulian case VM_INJECT_EXCEPTION: 313106159Sjulian vmexc = (struct vm_exception *)data; 314106159Sjulian error = vm_inject_exception(sc->vm, vmexc->cpuid, 315106159Sjulian vmexc->vector, vmexc->error_code_valid, vmexc->error_code, 316131575Sstefanf vmexc->restart_instruction); 317106159Sjulian break; 318106159Sjulian case VM_INJECT_NMI: 319106159Sjulian vmnmi = (struct vm_nmi *)data; 320106159Sjulian error = vm_inject_nmi(sc->vm, vmnmi->cpuid); 321106159Sjulian break; 322106159Sjulian case VM_LAPIC_IRQ: 323132161Srwatson vmirq = (struct vm_lapic_irq *)data; 324106159Sjulian error = lapic_intr_edge(sc->vm, vmirq->cpuid, vmirq->vector); 325148915Sobrien break; 326106159Sjulian case VM_LAPIC_LOCAL_IRQ: 327148915Sobrien vmirq = (struct vm_lapic_irq *)data; 328106159Sjulian error = lapic_set_local_intr(sc->vm, vmirq->cpuid, 329106159Sjulian vmirq->vector); 330106159Sjulian break; 331106159Sjulian case VM_LAPIC_MSI: 332106159Sjulian vmmsi = (struct vm_lapic_msi *)data; 333106159Sjulian error = lapic_intr_msi(sc->vm, vmmsi->addr, vmmsi->msg); 334106159Sjulian break; 335106159Sjulian case VM_IOAPIC_ASSERT_IRQ: 336106159Sjulian ioapic_irq = (struct vm_ioapic_irq *)data; 337184205Sdes error = vioapic_assert_irq(sc->vm, ioapic_irq->irq); 338106159Sjulian break; 339106159Sjulian case VM_IOAPIC_DEASSERT_IRQ: 340106159Sjulian ioapic_irq = (struct vm_ioapic_irq *)data; 341132161Srwatson error = vioapic_deassert_irq(sc->vm, ioapic_irq->irq); 342106159Sjulian break; 343106159Sjulian case VM_IOAPIC_PULSE_IRQ: 344106159Sjulian ioapic_irq = (struct vm_ioapic_irq *)data; 345106159Sjulian error = vioapic_pulse_irq(sc->vm, ioapic_irq->irq); 346106159Sjulian break; 347106159Sjulian case VM_IOAPIC_PINCOUNT: 348106159Sjulian *(int *)data = vioapic_pincount(sc->vm); 349106159Sjulian break; 350106159Sjulian case VM_ISA_ASSERT_IRQ: 351106159Sjulian isa_irq = (struct vm_isa_irq *)data; 352106159Sjulian error = vatpic_assert_irq(sc->vm, isa_irq->atpic_irq); 353106159Sjulian if (error == 0 && isa_irq->ioapic_irq != -1) 354106159Sjulian error = vioapic_assert_irq(sc->vm, 355106159Sjulian isa_irq->ioapic_irq); 356106159Sjulian break; 357106159Sjulian case VM_ISA_DEASSERT_IRQ: 358106159Sjulian isa_irq = (struct vm_isa_irq *)data; 359147256Sbrooks error = vatpic_deassert_irq(sc->vm, isa_irq->atpic_irq); 360106159Sjulian if (error == 0 && isa_irq->ioapic_irq != -1) 361152031Sru error = vioapic_deassert_irq(sc->vm, 362152031Sru isa_irq->ioapic_irq); 363152031Sru break; 364152031Sru case VM_ISA_PULSE_IRQ: 365152031Sru isa_irq = (struct vm_isa_irq *)data; 366152031Sru error = vatpic_pulse_irq(sc->vm, isa_irq->atpic_irq); 367152031Sru if (error == 0 && isa_irq->ioapic_irq != -1) 368106159Sjulian error = vioapic_pulse_irq(sc->vm, isa_irq->ioapic_irq); 369106159Sjulian break; 370106159Sjulian case VM_ISA_SET_IRQ_TRIGGER: 371106159Sjulian isa_irq_trigger = (struct vm_isa_irq_trigger *)data; 372106159Sjulian error = vatpic_set_irq_trigger(sc->vm, 373106159Sjulian isa_irq_trigger->atpic_irq, isa_irq_trigger->trigger); 374106159Sjulian break; 375106159Sjulian case VM_MAP_MEMORY: 376106159Sjulian seg = (struct vm_memory_segment *)data; 377106159Sjulian error = vm_malloc(sc->vm, seg->gpa, seg->len); 378106159Sjulian break; 379106159Sjulian case VM_GET_MEMORY_SEG: 380106159Sjulian seg = (struct vm_memory_segment *)data; 381106159Sjulian seg->len = 0; 382106159Sjulian (void)vm_gpabase2memseg(sc->vm, seg->gpa, seg); 383106159Sjulian error = 0; 384106159Sjulian break; 385106159Sjulian case VM_GET_REGISTER: 386106159Sjulian vmreg = (struct vm_register *)data; 387106159Sjulian error = vm_get_register(sc->vm, vmreg->cpuid, vmreg->regnum, 388106159Sjulian &vmreg->regval); 389106159Sjulian break; 390106159Sjulian case VM_SET_REGISTER: 391106159Sjulian vmreg = (struct vm_register *)data; 392130815Swpaul error = vm_set_register(sc->vm, vmreg->cpuid, vmreg->regnum, 393130815Swpaul vmreg->regval); 394130815Swpaul break; 395130815Swpaul case VM_SET_SEGMENT_DESCRIPTOR: 396130815Swpaul vmsegdesc = (struct vm_seg_desc *)data; 397130815Swpaul error = vm_set_seg_desc(sc->vm, vmsegdesc->cpuid, 398130815Swpaul vmsegdesc->regnum, 399130815Swpaul &vmsegdesc->desc); 400130815Swpaul break; 401130815Swpaul case VM_GET_SEGMENT_DESCRIPTOR: 402130815Swpaul vmsegdesc = (struct vm_seg_desc *)data; 403130815Swpaul error = vm_get_seg_desc(sc->vm, vmsegdesc->cpuid, 404130815Swpaul vmsegdesc->regnum, 405130815Swpaul &vmsegdesc->desc); 406106159Sjulian break; 407184214Sdes case VM_GET_CAPABILITY: 408106159Sjulian vmcap = (struct vm_capability *)data; 409106159Sjulian error = vm_get_capability(sc->vm, vmcap->cpuid, 410106159Sjulian vmcap->captype, 411130808Swpaul &vmcap->capval); 412152243Sru break; 413130808Swpaul case VM_SET_CAPABILITY: 414130808Swpaul vmcap = (struct vm_capability *)data; 415106159Sjulian error = vm_set_capability(sc->vm, vmcap->cpuid, 416106159Sjulian vmcap->captype, 417106159Sjulian vmcap->capval); 418106159Sjulian break; 419106159Sjulian case VM_SET_X2APIC_STATE: 420152032Sru x2apic = (struct vm_x2apic *)data; 421152315Sru error = vm_set_x2apic_state(sc->vm, 422106159Sjulian x2apic->cpuid, x2apic->state); 423106159Sjulian break; 424106159Sjulian case VM_GET_X2APIC_STATE: 425106159Sjulian x2apic = (struct vm_x2apic *)data; 426106159Sjulian error = vm_get_x2apic_state(sc->vm, 427169677Sdwmalone x2apic->cpuid, &x2apic->state); 428169677Sdwmalone break; 429169677Sdwmalone case VM_GET_GPA_PMAP: 430106159Sjulian gpapte = (struct vm_gpa_pte *)data; 431152315Sru pmap_get_mapping(vmspace_pmap(vm_get_vmspace(sc->vm)), 432106159Sjulian gpapte->gpa, gpapte->pte, &gpapte->ptenum); 433106159Sjulian error = 0; 434106159Sjulian break; 435152315Sru case VM_GET_HPET_CAPABILITIES: 436202588Sthompsa error = vhpet_getcap((struct vm_hpet_cap *)data); 437106159Sjulian break; 438111565Swpaul case VM_GLA2GPA: { 439111565Swpaul CTASSERT(PROT_READ == VM_PROT_READ); 440111565Swpaul CTASSERT(PROT_WRITE == VM_PROT_WRITE); 441111565Swpaul CTASSERT(PROT_EXEC == VM_PROT_EXECUTE); 442111565Swpaul gg = (struct vm_gla2gpa *)data; 443111565Swpaul error = vm_gla2gpa(sc->vm, gg->vcpuid, &gg->paging, gg->gla, 444130815Swpaul gg->prot, &gg->gpa); 445130815Swpaul KASSERT(error == 0 || error == 1 || error == -1, 446130815Swpaul ("%s: vm_gla2gpa unknown error %d", __func__, error)); 447130815Swpaul if (error >= 0) { 448106159Sjulian /* 449106159Sjulian * error = 0: the translation was successful 450152031Sru * error = 1: a fault was injected into the guest 451106159Sjulian */ 452106159Sjulian gg->fault = error; 453169677Sdwmalone error = 0; 454169677Sdwmalone } else { 455169677Sdwmalone error = EFAULT; 456106159Sjulian } 457106159Sjulian break; 458106159Sjulian } 459106159Sjulian case VM_ACTIVATE_CPU: 460106159Sjulian vac = (struct vm_activate_cpu *)data; 461106159Sjulian error = vm_activate_cpu(sc->vm, vac->vcpuid); 462106159Sjulian break; 463106159Sjulian case VM_GET_CPUS: 464106159Sjulian error = 0; 465106159Sjulian vm_cpuset = (struct vm_cpuset *)data; 466106159Sjulian size = vm_cpuset->cpusetsize; 467106159Sjulian if (size < sizeof(cpuset_t) || size > CPU_MAXSIZE / NBBY) { 468106159Sjulian error = ERANGE; 469106159Sjulian break; 470147256Sbrooks } 471106159Sjulian cpuset = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 472152031Sru if (vm_cpuset->which == VM_ACTIVE_CPUS) 473152031Sru *cpuset = vm_active_cpus(sc->vm); 474152031Sru else if (vm_cpuset->which == VM_SUSPENDED_CPUS) 475152031Sru *cpuset = vm_suspended_cpus(sc->vm); 476152031Sru else 477152031Sru error = EINVAL; 478152031Sru if (error == 0) 479106159Sjulian error = copyout(cpuset, vm_cpuset->cpus, size); 480106159Sjulian free(cpuset, M_TEMP); 481106159Sjulian break; 482106159Sjulian case VM_SET_INTINFO: 483106159Sjulian vmii = (struct vm_intinfo *)data; 484106159Sjulian error = vm_exit_intinfo(sc->vm, vmii->vcpuid, vmii->info1); 485106159Sjulian break; 486106159Sjulian case VM_GET_INTINFO: 487106159Sjulian vmii = (struct vm_intinfo *)data; 488106159Sjulian error = vm_get_intinfo(sc->vm, vmii->vcpuid, &vmii->info1, 489106159Sjulian &vmii->info2); 490106159Sjulian break; 491106159Sjulian case VM_RTC_WRITE: 492106159Sjulian rtcdata = (struct vm_rtc_data *)data; 493106159Sjulian error = vrtc_nvram_write(sc->vm, rtcdata->offset, 494106159Sjulian rtcdata->value); 495106159Sjulian break; 496106159Sjulian case VM_RTC_READ: 497106159Sjulian rtcdata = (struct vm_rtc_data *)data; 498106159Sjulian error = vrtc_nvram_read(sc->vm, rtcdata->offset, 499106159Sjulian &rtcdata->value); 500106159Sjulian break; 501106159Sjulian case VM_RTC_SETTIME: 502106159Sjulian rtctime = (struct vm_rtc_time *)data; 503152032Sru error = vrtc_set_time(sc->vm, rtctime->secs); 504106159Sjulian break; 505111565Swpaul case VM_RTC_GETTIME: 506111565Swpaul error = 0; 507111565Swpaul rtctime = (struct vm_rtc_time *)data; 508130808Swpaul rtctime->secs = vrtc_get_time(sc->vm); 509130808Swpaul break; 510152243Sru case VM_RESTART_INSTRUCTION: 511130808Swpaul error = vm_restart_instruction(sc->vm, vcpu); 512130808Swpaul break; 513106159Sjulian default: 514106159Sjulian error = ENOTTY; 515184205Sdes break; 516106159Sjulian } 517106159Sjulian 518130815Swpaul if (state_changed == 1) { 519130815Swpaul vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 520130815Swpaul } else if (state_changed == 2) { 521106159Sjulian for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) 522106159Sjulian vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); 523106159Sjulian } 524169677Sdwmalone 525169677Sdwmalonedone: 526169677Sdwmalone /* Make sure that no handler returns a bogus value like ERESTART */ 527169677Sdwmalone KASSERT(error >= 0, ("vmmdev_ioctl: invalid error return %d", error)); 528169677Sdwmalone return (error); 529169677Sdwmalone} 530169677Sdwmalone 531169677Sdwmalonestatic int 532169677Sdwmalonevmmdev_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, 533169677Sdwmalone vm_size_t size, struct vm_object **object, int nprot) 534169677Sdwmalone{ 535169677Sdwmalone int error; 536169677Sdwmalone struct vmmdev_softc *sc; 537169677Sdwmalone 538169677Sdwmalone sc = vmmdev_lookup2(cdev); 539169677Sdwmalone if (sc != NULL && (nprot & PROT_EXEC) == 0) 540169677Sdwmalone error = vm_get_memobj(sc->vm, *offset, size, offset, object); 541169677Sdwmalone else 542169677Sdwmalone error = EINVAL; 543169677Sdwmalone 544169677Sdwmalone return (error); 545169677Sdwmalone} 546169677Sdwmalone 547169677Sdwmalonestatic void 548169677Sdwmalonevmmdev_destroy(void *arg) 549169677Sdwmalone{ 550169677Sdwmalone 551169677Sdwmalone struct vmmdev_softc *sc = arg; 552169677Sdwmalone 553169677Sdwmalone if (sc->cdev != NULL) 554169677Sdwmalone destroy_dev(sc->cdev); 555169677Sdwmalone 556169677Sdwmalone if (sc->vm != NULL) 557169677Sdwmalone vm_destroy(sc->vm); 558169677Sdwmalone 559169677Sdwmalone if ((sc->flags & VSC_LINKED) != 0) { 560169677Sdwmalone mtx_lock(&vmmdev_mtx); 561169677Sdwmalone SLIST_REMOVE(&head, sc, vmmdev_softc, link); 562169677Sdwmalone mtx_unlock(&vmmdev_mtx); 563169677Sdwmalone } 564169677Sdwmalone 565169677Sdwmalone free(sc, M_VMMDEV); 566169677Sdwmalone} 567169677Sdwmalone 568169677Sdwmalonestatic int 569169677Sdwmalonesysctl_vmm_destroy(SYSCTL_HANDLER_ARGS) 570169677Sdwmalone{ 571169677Sdwmalone int error; 572169677Sdwmalone char buf[VM_MAX_NAMELEN]; 573169677Sdwmalone struct vmmdev_softc *sc; 574169677Sdwmalone struct cdev *cdev; 575169677Sdwmalone 576169677Sdwmalone strlcpy(buf, "beavis", sizeof(buf)); 577169677Sdwmalone error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 578169677Sdwmalone if (error != 0 || req->newptr == NULL) 579169677Sdwmalone return (error); 580169677Sdwmalone 581169677Sdwmalone mtx_lock(&vmmdev_mtx); 582169677Sdwmalone sc = vmmdev_lookup(buf); 583169677Sdwmalone if (sc == NULL || sc->cdev == NULL) { 584169677Sdwmalone mtx_unlock(&vmmdev_mtx); 585106159Sjulian return (EINVAL); 586106159Sjulian } 587169677Sdwmalone 588106159Sjulian /* 589106159Sjulian * The 'cdev' will be destroyed asynchronously when 'si_threadcount' 590106159Sjulian * goes down to 0 so we should not do it again in the callback. 591106159Sjulian */ 592106159Sjulian cdev = sc->cdev; 593106159Sjulian sc->cdev = NULL; 594106159Sjulian mtx_unlock(&vmmdev_mtx); 595106159Sjulian 596106159Sjulian /* 597106159Sjulian * Schedule the 'cdev' to be destroyed: 598106159Sjulian * 599106159Sjulian * - any new operations on this 'cdev' will return an error (ENXIO). 600106159Sjulian * 601106159Sjulian * - when the 'si_threadcount' dwindles down to zero the 'cdev' will 602106159Sjulian * be destroyed and the callback will be invoked in a taskqueue 603106159Sjulian * context. 604106159Sjulian */ 605106159Sjulian destroy_dev_sched_cb(cdev, vmmdev_destroy, sc); 606106159Sjulian 607106159Sjulian return (0); 608106159Sjulian} 609106159SjulianSYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW, 610106159Sjulian NULL, 0, sysctl_vmm_destroy, "A", NULL); 611106159Sjulian 612106159Sjulianstatic struct cdevsw vmmdevsw = { 613106159Sjulian .d_name = "vmmdev", 614106159Sjulian .d_version = D_VERSION, 615106159Sjulian .d_ioctl = vmmdev_ioctl, 616106159Sjulian .d_mmap_single = vmmdev_mmap_single, 617106159Sjulian .d_read = vmmdev_rw, 618149462Semax .d_write = vmmdev_rw, 619149462Semax}; 620106159Sjulian 621106159Sjulianstatic int 622152031Srusysctl_vmm_create(SYSCTL_HANDLER_ARGS) 623106159Sjulian{ 624106159Sjulian int error; 625106159Sjulian struct vm *vm; 626106159Sjulian struct cdev *cdev; 627106159Sjulian struct vmmdev_softc *sc, *sc2; 628106159Sjulian char buf[VM_MAX_NAMELEN]; 629106159Sjulian 630106159Sjulian strlcpy(buf, "beavis", sizeof(buf)); 631106159Sjulian error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 632106159Sjulian if (error != 0 || req->newptr == NULL) 633106159Sjulian return (error); 634106159Sjulian 635106159Sjulian mtx_lock(&vmmdev_mtx); 636106159Sjulian sc = vmmdev_lookup(buf); 637106159Sjulian mtx_unlock(&vmmdev_mtx); 638106159Sjulian if (sc != NULL) 639152030Sru return (EEXIST); 640152030Sru 641152030Sru error = vm_create(buf, &vm); 642106159Sjulian if (error != 0) 643106159Sjulian return (error); 644106159Sjulian 645106159Sjulian sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO); 646106159Sjulian sc->vm = vm; 647106159Sjulian 648106159Sjulian /* 649106159Sjulian * Lookup the name again just in case somebody sneaked in when we 650106159Sjulian * dropped the lock. 651106159Sjulian */ 652106159Sjulian mtx_lock(&vmmdev_mtx); 653106159Sjulian sc2 = vmmdev_lookup(buf); 654106159Sjulian if (sc2 == NULL) { 655106159Sjulian SLIST_INSERT_HEAD(&head, sc, link); 656106159Sjulian sc->flags |= VSC_LINKED; 657106159Sjulian } 658106159Sjulian mtx_unlock(&vmmdev_mtx); 659106159Sjulian 660106159Sjulian if (sc2 != NULL) { 661106159Sjulian vmmdev_destroy(sc); 662106159Sjulian return (EEXIST); 663106159Sjulian } 664106159Sjulian 665106159Sjulian error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, NULL, 666152030Sru UID_ROOT, GID_WHEEL, 0600, "vmm/%s", buf); 667152030Sru if (error != 0) { 668106159Sjulian vmmdev_destroy(sc); 669106159Sjulian return (error); 670106159Sjulian } 671106159Sjulian 672106159Sjulian mtx_lock(&vmmdev_mtx); 673106159Sjulian sc->cdev = cdev; 674106159Sjulian sc->cdev->si_drv1 = sc; 675106159Sjulian mtx_unlock(&vmmdev_mtx); 676106159Sjulian 677106159Sjulian return (0); 678106159Sjulian} 679106159SjulianSYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW, 680106159Sjulian NULL, 0, sysctl_vmm_create, "A", NULL); 681106159Sjulian 682106159Sjulianvoid 683106159Sjulianvmmdev_init(void) 684106159Sjulian{ 685106159Sjulian mtx_init(&vmmdev_mtx, "vmm device mutex", NULL, MTX_DEF); 686106159Sjulian} 687106159Sjulian 688106159Sjulianint 689106159Sjulianvmmdev_cleanup(void) 690121816Sbrooks{ 691106159Sjulian int error; 692106159Sjulian 693106159Sjulian if (SLIST_EMPTY(&head)) 694130815Swpaul error = 0; 695106159Sjulian else 696106159Sjulian error = EBUSY; 697106159Sjulian 698106159Sjulian return (error); 699121816Sbrooks} 700106159Sjulian