1366f6083SPeter Grehan /*- 2366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 3366f6083SPeter Grehan * All rights reserved. 4366f6083SPeter Grehan * 5366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 6366f6083SPeter Grehan * modification, are permitted provided that the following conditions 7366f6083SPeter Grehan * are met: 8366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 9366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 10366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 12366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 13366f6083SPeter Grehan * 14366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24366f6083SPeter Grehan * SUCH DAMAGE. 25366f6083SPeter Grehan * 26366f6083SPeter Grehan * $FreeBSD$ 27366f6083SPeter Grehan */ 28366f6083SPeter Grehan 29366f6083SPeter Grehan #include <sys/cdefs.h> 30366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 31366f6083SPeter Grehan 32366f6083SPeter Grehan #include <sys/param.h> 3338f1b189SPeter Grehan #include <sys/systm.h> 34366f6083SPeter Grehan #include <sys/kernel.h> 35366f6083SPeter Grehan #include <sys/module.h> 36366f6083SPeter Grehan #include <sys/sysctl.h> 37366f6083SPeter Grehan #include <sys/malloc.h> 38366f6083SPeter Grehan #include <sys/pcpu.h> 39366f6083SPeter Grehan #include <sys/lock.h> 40366f6083SPeter Grehan #include <sys/mutex.h> 41366f6083SPeter Grehan #include <sys/proc.h> 42318224bbSNeel Natu #include <sys/rwlock.h> 43366f6083SPeter Grehan #include <sys/sched.h> 44366f6083SPeter Grehan #include <sys/smp.h> 45366f6083SPeter Grehan #include <sys/systm.h> 46366f6083SPeter Grehan 47366f6083SPeter Grehan #include <vm/vm.h> 48318224bbSNeel Natu #include <vm/vm_object.h> 49318224bbSNeel Natu #include <vm/vm_page.h> 50318224bbSNeel Natu #include <vm/pmap.h> 51318224bbSNeel Natu #include <vm/vm_map.h> 52318224bbSNeel Natu #include <vm/vm_extern.h> 53318224bbSNeel Natu #include <vm/vm_param.h> 54366f6083SPeter Grehan 55366f6083SPeter Grehan #include <machine/vm.h> 56366f6083SPeter Grehan #include <machine/pcb.h> 5775dd3366SNeel Natu #include <machine/smp.h> 58*1c052192SNeel Natu #include <x86/psl.h> 5934a6b2d6SJohn Baldwin #include <x86/apicreg.h> 60318224bbSNeel Natu #include <machine/vmparam.h> 61366f6083SPeter Grehan 62366f6083SPeter Grehan #include <machine/vmm.h> 63565bbb86SNeel Natu #include <machine/vmm_dev.h> 64565bbb86SNeel Natu 65318224bbSNeel Natu #include "vmm_ktr.h" 66b01c2033SNeel Natu #include "vmm_host.h" 67366f6083SPeter Grehan #include "vmm_mem.h" 68366f6083SPeter Grehan #include "vmm_util.h" 6908e3ff32SNeel Natu #include "vhpet.h" 70565bbb86SNeel Natu #include "vioapic.h" 71366f6083SPeter Grehan #include "vlapic.h" 72366f6083SPeter Grehan #include "vmm_msr.h" 73366f6083SPeter Grehan #include "vmm_ipi.h" 74366f6083SPeter Grehan #include "vmm_stat.h" 75f76fc5d4SNeel Natu #include "vmm_lapic.h" 76366f6083SPeter Grehan 77366f6083SPeter Grehan #include "io/ppt.h" 78366f6083SPeter Grehan #include "io/iommu.h" 79366f6083SPeter Grehan 80366f6083SPeter Grehan struct vlapic; 81366f6083SPeter Grehan 82366f6083SPeter Grehan struct vcpu { 83366f6083SPeter Grehan int flags; 8475dd3366SNeel Natu enum vcpu_state state; 8575dd3366SNeel Natu struct mtx mtx; 86366f6083SPeter Grehan int hostcpu; /* host cpuid this vcpu last ran on */ 87366f6083SPeter Grehan uint64_t guest_msrs[VMM_MSR_NUM]; 88366f6083SPeter Grehan struct vlapic *vlapic; 89366f6083SPeter Grehan int vcpuid; 9038f1b189SPeter Grehan struct savefpu *guestfpu; /* guest fpu state */ 91366f6083SPeter Grehan void *stats; 9298ed632cSNeel Natu struct vm_exit exitinfo; 93e9027382SNeel Natu enum x2apic_state x2apic_state; 94f352ff0cSNeel Natu int nmi_pending; 95366f6083SPeter Grehan }; 96366f6083SPeter Grehan 97f76fc5d4SNeel Natu #define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_SPIN) 98f76fc5d4SNeel Natu #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) 99f76fc5d4SNeel Natu #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) 100318224bbSNeel Natu #define vcpu_assert_locked(v) mtx_assert(&((v)->mtx), MA_OWNED) 10175dd3366SNeel Natu 102318224bbSNeel Natu struct mem_seg { 103318224bbSNeel Natu vm_paddr_t gpa; 104318224bbSNeel Natu size_t len; 105318224bbSNeel Natu boolean_t wired; 106318224bbSNeel Natu vm_object_t object; 107318224bbSNeel Natu }; 108366f6083SPeter Grehan #define VM_MAX_MEMORY_SEGMENTS 2 109366f6083SPeter Grehan 110366f6083SPeter Grehan struct vm { 111366f6083SPeter Grehan void *cookie; /* processor-specific data */ 112366f6083SPeter Grehan void *iommu; /* iommu-specific data */ 11308e3ff32SNeel Natu struct vhpet *vhpet; /* virtual HPET */ 114565bbb86SNeel Natu struct vioapic *vioapic; /* virtual ioapic */ 115318224bbSNeel Natu struct vmspace *vmspace; /* guest's address space */ 116366f6083SPeter Grehan struct vcpu vcpu[VM_MAXCPU]; 117366f6083SPeter Grehan int num_mem_segs; 118318224bbSNeel Natu struct mem_seg mem_segs[VM_MAX_MEMORY_SEGMENTS]; 119366f6083SPeter Grehan char name[VM_MAX_NAMELEN]; 120366f6083SPeter Grehan 121366f6083SPeter Grehan /* 122a5615c90SPeter Grehan * Set of active vcpus. 123366f6083SPeter Grehan * An active vcpu is one that has been started implicitly (BSP) or 124366f6083SPeter Grehan * explicitly (AP) by sending it a startup ipi. 125366f6083SPeter Grehan */ 126a5615c90SPeter Grehan cpuset_t active_cpus; 127366f6083SPeter Grehan }; 128366f6083SPeter Grehan 129d5408b1dSNeel Natu static int vmm_initialized; 130d5408b1dSNeel Natu 131366f6083SPeter Grehan static struct vmm_ops *ops; 132366f6083SPeter Grehan #define VMM_INIT() (ops != NULL ? (*ops->init)() : 0) 133366f6083SPeter Grehan #define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 134366f6083SPeter Grehan 135318224bbSNeel Natu #define VMINIT(vm, pmap) (ops != NULL ? (*ops->vminit)(vm, pmap): NULL) 136318224bbSNeel Natu #define VMRUN(vmi, vcpu, rip, pmap) \ 137318224bbSNeel Natu (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, pmap) : ENXIO) 138366f6083SPeter Grehan #define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 139318224bbSNeel Natu #define VMSPACE_ALLOC(min, max) \ 140318224bbSNeel Natu (ops != NULL ? (*ops->vmspace_alloc)(min, max) : NULL) 141318224bbSNeel Natu #define VMSPACE_FREE(vmspace) \ 142318224bbSNeel Natu (ops != NULL ? (*ops->vmspace_free)(vmspace) : ENXIO) 143366f6083SPeter Grehan #define VMGETREG(vmi, vcpu, num, retval) \ 144366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 145366f6083SPeter Grehan #define VMSETREG(vmi, vcpu, num, val) \ 146366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 147366f6083SPeter Grehan #define VMGETDESC(vmi, vcpu, num, desc) \ 148366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 149366f6083SPeter Grehan #define VMSETDESC(vmi, vcpu, num, desc) \ 150366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 151366f6083SPeter Grehan #define VMINJECT(vmi, vcpu, type, vec, ec, ecv) \ 152366f6083SPeter Grehan (ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO) 153366f6083SPeter Grehan #define VMGETCAP(vmi, vcpu, num, retval) \ 154366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 155366f6083SPeter Grehan #define VMSETCAP(vmi, vcpu, num, val) \ 156366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 157366f6083SPeter Grehan 158014a52f3SNeel Natu #define fpu_start_emulating() load_cr0(rcr0() | CR0_TS) 159014a52f3SNeel Natu #define fpu_stop_emulating() clts() 160366f6083SPeter Grehan 161366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 162366f6083SPeter Grehan CTASSERT(VMM_MSR_NUM <= 64); /* msr_mask can keep track of up to 64 msrs */ 163366f6083SPeter Grehan 164366f6083SPeter Grehan /* statistics */ 16561592433SNeel Natu static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 166366f6083SPeter Grehan 167366f6083SPeter Grehan static void 168366f6083SPeter Grehan vcpu_cleanup(struct vcpu *vcpu) 169366f6083SPeter Grehan { 170366f6083SPeter Grehan vlapic_cleanup(vcpu->vlapic); 171366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 17238f1b189SPeter Grehan fpu_save_area_free(vcpu->guestfpu); 173366f6083SPeter Grehan } 174366f6083SPeter Grehan 175366f6083SPeter Grehan static void 176366f6083SPeter Grehan vcpu_init(struct vm *vm, uint32_t vcpu_id) 177366f6083SPeter Grehan { 178366f6083SPeter Grehan struct vcpu *vcpu; 179366f6083SPeter Grehan 180366f6083SPeter Grehan vcpu = &vm->vcpu[vcpu_id]; 181366f6083SPeter Grehan 18275dd3366SNeel Natu vcpu_lock_init(vcpu); 18375dd3366SNeel Natu vcpu->hostcpu = NOCPU; 184366f6083SPeter Grehan vcpu->vcpuid = vcpu_id; 185366f6083SPeter Grehan vcpu->vlapic = vlapic_init(vm, vcpu_id); 18673820fb0SNeel Natu vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED); 18738f1b189SPeter Grehan vcpu->guestfpu = fpu_save_area_alloc(); 18838f1b189SPeter Grehan fpu_save_area_reset(vcpu->guestfpu); 189366f6083SPeter Grehan vcpu->stats = vmm_stat_alloc(); 190366f6083SPeter Grehan } 191366f6083SPeter Grehan 19298ed632cSNeel Natu struct vm_exit * 19398ed632cSNeel Natu vm_exitinfo(struct vm *vm, int cpuid) 19498ed632cSNeel Natu { 19598ed632cSNeel Natu struct vcpu *vcpu; 19698ed632cSNeel Natu 19798ed632cSNeel Natu if (cpuid < 0 || cpuid >= VM_MAXCPU) 19898ed632cSNeel Natu panic("vm_exitinfo: invalid cpuid %d", cpuid); 19998ed632cSNeel Natu 20098ed632cSNeel Natu vcpu = &vm->vcpu[cpuid]; 20198ed632cSNeel Natu 20298ed632cSNeel Natu return (&vcpu->exitinfo); 20398ed632cSNeel Natu } 20498ed632cSNeel Natu 205366f6083SPeter Grehan static int 206366f6083SPeter Grehan vmm_init(void) 207366f6083SPeter Grehan { 208366f6083SPeter Grehan int error; 209366f6083SPeter Grehan 210b01c2033SNeel Natu vmm_host_state_init(); 211366f6083SPeter Grehan vmm_ipi_init(); 212366f6083SPeter Grehan 213366f6083SPeter Grehan error = vmm_mem_init(); 214366f6083SPeter Grehan if (error) 215366f6083SPeter Grehan return (error); 216366f6083SPeter Grehan 217366f6083SPeter Grehan if (vmm_is_intel()) 218366f6083SPeter Grehan ops = &vmm_ops_intel; 219366f6083SPeter Grehan else if (vmm_is_amd()) 220366f6083SPeter Grehan ops = &vmm_ops_amd; 221366f6083SPeter Grehan else 222366f6083SPeter Grehan return (ENXIO); 223366f6083SPeter Grehan 224366f6083SPeter Grehan vmm_msr_init(); 225366f6083SPeter Grehan 226366f6083SPeter Grehan return (VMM_INIT()); 227366f6083SPeter Grehan } 228366f6083SPeter Grehan 229366f6083SPeter Grehan static int 230366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 231366f6083SPeter Grehan { 232366f6083SPeter Grehan int error; 233366f6083SPeter Grehan 234366f6083SPeter Grehan switch (what) { 235366f6083SPeter Grehan case MOD_LOAD: 236366f6083SPeter Grehan vmmdev_init(); 237366f6083SPeter Grehan iommu_init(); 238366f6083SPeter Grehan error = vmm_init(); 239d5408b1dSNeel Natu if (error == 0) 240d5408b1dSNeel Natu vmm_initialized = 1; 241366f6083SPeter Grehan break; 242366f6083SPeter Grehan case MOD_UNLOAD: 243cdc5b9e7SNeel Natu error = vmmdev_cleanup(); 244cdc5b9e7SNeel Natu if (error == 0) { 245366f6083SPeter Grehan iommu_cleanup(); 246366f6083SPeter Grehan vmm_ipi_cleanup(); 247366f6083SPeter Grehan error = VMM_CLEANUP(); 24881ef6611SPeter Grehan /* 24981ef6611SPeter Grehan * Something bad happened - prevent new 25081ef6611SPeter Grehan * VMs from being created 25181ef6611SPeter Grehan */ 25281ef6611SPeter Grehan if (error) 253d5408b1dSNeel Natu vmm_initialized = 0; 25481ef6611SPeter Grehan } 255366f6083SPeter Grehan break; 256366f6083SPeter Grehan default: 257366f6083SPeter Grehan error = 0; 258366f6083SPeter Grehan break; 259366f6083SPeter Grehan } 260366f6083SPeter Grehan return (error); 261366f6083SPeter Grehan } 262366f6083SPeter Grehan 263366f6083SPeter Grehan static moduledata_t vmm_kmod = { 264366f6083SPeter Grehan "vmm", 265366f6083SPeter Grehan vmm_handler, 266366f6083SPeter Grehan NULL 267366f6083SPeter Grehan }; 268366f6083SPeter Grehan 269366f6083SPeter Grehan /* 270e3f0800bSNeel Natu * vmm initialization has the following dependencies: 271e3f0800bSNeel Natu * 272e3f0800bSNeel Natu * - iommu initialization must happen after the pci passthru driver has had 273e3f0800bSNeel Natu * a chance to attach to any passthru devices (after SI_SUB_CONFIGURE). 274e3f0800bSNeel Natu * 275e3f0800bSNeel Natu * - VT-x initialization requires smp_rendezvous() and therefore must happen 276e3f0800bSNeel Natu * after SMP is fully functional (after SI_SUB_SMP). 277366f6083SPeter Grehan */ 278e3f0800bSNeel Natu DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_SMP + 1, SI_ORDER_ANY); 279366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 280366f6083SPeter Grehan 281366f6083SPeter Grehan SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 282366f6083SPeter Grehan 283d5408b1dSNeel Natu int 284d5408b1dSNeel Natu vm_create(const char *name, struct vm **retvm) 285366f6083SPeter Grehan { 286366f6083SPeter Grehan int i; 287366f6083SPeter Grehan struct vm *vm; 288318224bbSNeel Natu struct vmspace *vmspace; 289366f6083SPeter Grehan 290366f6083SPeter Grehan const int BSP = 0; 291366f6083SPeter Grehan 292d5408b1dSNeel Natu /* 293d5408b1dSNeel Natu * If vmm.ko could not be successfully initialized then don't attempt 294d5408b1dSNeel Natu * to create the virtual machine. 295d5408b1dSNeel Natu */ 296d5408b1dSNeel Natu if (!vmm_initialized) 297d5408b1dSNeel Natu return (ENXIO); 298d5408b1dSNeel Natu 299366f6083SPeter Grehan if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 300d5408b1dSNeel Natu return (EINVAL); 301366f6083SPeter Grehan 302318224bbSNeel Natu vmspace = VMSPACE_ALLOC(VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS); 303318224bbSNeel Natu if (vmspace == NULL) 304318224bbSNeel Natu return (ENOMEM); 305318224bbSNeel Natu 306366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 307366f6083SPeter Grehan strcpy(vm->name, name); 308318224bbSNeel Natu vm->cookie = VMINIT(vm, vmspace_pmap(vmspace)); 309565bbb86SNeel Natu vm->vioapic = vioapic_init(vm); 31008e3ff32SNeel Natu vm->vhpet = vhpet_init(vm); 311366f6083SPeter Grehan 312366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) { 313366f6083SPeter Grehan vcpu_init(vm, i); 314366f6083SPeter Grehan guest_msrs_init(vm, i); 315366f6083SPeter Grehan } 316366f6083SPeter Grehan 317366f6083SPeter Grehan vm_activate_cpu(vm, BSP); 318318224bbSNeel Natu vm->vmspace = vmspace; 319366f6083SPeter Grehan 320d5408b1dSNeel Natu *retvm = vm; 321d5408b1dSNeel Natu return (0); 322366f6083SPeter Grehan } 323366f6083SPeter Grehan 324f7d51510SNeel Natu static void 325318224bbSNeel Natu vm_free_mem_seg(struct vm *vm, struct mem_seg *seg) 326f7d51510SNeel Natu { 3277ce04d0aSNeel Natu 328318224bbSNeel Natu if (seg->object != NULL) 329318224bbSNeel Natu vmm_mem_free(vm->vmspace, seg->gpa, seg->len); 330f7d51510SNeel Natu 331318224bbSNeel Natu bzero(seg, sizeof(*seg)); 332f7d51510SNeel Natu } 333f7d51510SNeel Natu 334366f6083SPeter Grehan void 335366f6083SPeter Grehan vm_destroy(struct vm *vm) 336366f6083SPeter Grehan { 337366f6083SPeter Grehan int i; 338366f6083SPeter Grehan 339366f6083SPeter Grehan ppt_unassign_all(vm); 340366f6083SPeter Grehan 341318224bbSNeel Natu if (vm->iommu != NULL) 342318224bbSNeel Natu iommu_destroy_domain(vm->iommu); 343318224bbSNeel Natu 34408e3ff32SNeel Natu vhpet_cleanup(vm->vhpet); 34508e3ff32SNeel Natu vioapic_cleanup(vm->vioapic); 34608e3ff32SNeel Natu 347366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) 348f7d51510SNeel Natu vm_free_mem_seg(vm, &vm->mem_segs[i]); 349f7d51510SNeel Natu 350f7d51510SNeel Natu vm->num_mem_segs = 0; 351366f6083SPeter Grehan 352366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) 353366f6083SPeter Grehan vcpu_cleanup(&vm->vcpu[i]); 354366f6083SPeter Grehan 355318224bbSNeel Natu VMSPACE_FREE(vm->vmspace); 356366f6083SPeter Grehan 357366f6083SPeter Grehan VMCLEANUP(vm->cookie); 358366f6083SPeter Grehan 359366f6083SPeter Grehan free(vm, M_VM); 360366f6083SPeter Grehan } 361366f6083SPeter Grehan 362366f6083SPeter Grehan const char * 363366f6083SPeter Grehan vm_name(struct vm *vm) 364366f6083SPeter Grehan { 365366f6083SPeter Grehan return (vm->name); 366366f6083SPeter Grehan } 367366f6083SPeter Grehan 368366f6083SPeter Grehan int 369366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 370366f6083SPeter Grehan { 371318224bbSNeel Natu vm_object_t obj; 372366f6083SPeter Grehan 373318224bbSNeel Natu if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa)) == NULL) 374318224bbSNeel Natu return (ENOMEM); 375318224bbSNeel Natu else 376318224bbSNeel Natu return (0); 377366f6083SPeter Grehan } 378366f6083SPeter Grehan 379366f6083SPeter Grehan int 380366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 381366f6083SPeter Grehan { 382366f6083SPeter Grehan 383318224bbSNeel Natu vmm_mmio_free(vm->vmspace, gpa, len); 384318224bbSNeel Natu return (0); 385366f6083SPeter Grehan } 386366f6083SPeter Grehan 387318224bbSNeel Natu boolean_t 388318224bbSNeel Natu vm_mem_allocated(struct vm *vm, vm_paddr_t gpa) 389366f6083SPeter Grehan { 390341f19c9SNeel Natu int i; 391341f19c9SNeel Natu vm_paddr_t gpabase, gpalimit; 392341f19c9SNeel Natu 393341f19c9SNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 394341f19c9SNeel Natu gpabase = vm->mem_segs[i].gpa; 395341f19c9SNeel Natu gpalimit = gpabase + vm->mem_segs[i].len; 396341f19c9SNeel Natu if (gpa >= gpabase && gpa < gpalimit) 397318224bbSNeel Natu return (TRUE); /* 'gpa' is regular memory */ 398341f19c9SNeel Natu } 399341f19c9SNeel Natu 400318224bbSNeel Natu if (ppt_is_mmio(vm, gpa)) 401318224bbSNeel Natu return (TRUE); /* 'gpa' is pci passthru mmio */ 402318224bbSNeel Natu 403318224bbSNeel Natu return (FALSE); 404341f19c9SNeel Natu } 405341f19c9SNeel Natu 406341f19c9SNeel Natu int 407341f19c9SNeel Natu vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len) 408341f19c9SNeel Natu { 409318224bbSNeel Natu int available, allocated; 410318224bbSNeel Natu struct mem_seg *seg; 411318224bbSNeel Natu vm_object_t object; 412318224bbSNeel Natu vm_paddr_t g; 413366f6083SPeter Grehan 414341f19c9SNeel Natu if ((gpa & PAGE_MASK) || (len & PAGE_MASK) || len == 0) 415341f19c9SNeel Natu return (EINVAL); 416341f19c9SNeel Natu 417341f19c9SNeel Natu available = allocated = 0; 418341f19c9SNeel Natu g = gpa; 419341f19c9SNeel Natu while (g < gpa + len) { 420318224bbSNeel Natu if (vm_mem_allocated(vm, g)) 421341f19c9SNeel Natu allocated++; 422318224bbSNeel Natu else 423318224bbSNeel Natu available++; 424341f19c9SNeel Natu 425341f19c9SNeel Natu g += PAGE_SIZE; 426341f19c9SNeel Natu } 427341f19c9SNeel Natu 428366f6083SPeter Grehan /* 429341f19c9SNeel Natu * If there are some allocated and some available pages in the address 430341f19c9SNeel Natu * range then it is an error. 431366f6083SPeter Grehan */ 432341f19c9SNeel Natu if (allocated && available) 433341f19c9SNeel Natu return (EINVAL); 434341f19c9SNeel Natu 435341f19c9SNeel Natu /* 436341f19c9SNeel Natu * If the entire address range being requested has already been 437341f19c9SNeel Natu * allocated then there isn't anything more to do. 438341f19c9SNeel Natu */ 439341f19c9SNeel Natu if (allocated && available == 0) 440341f19c9SNeel Natu return (0); 441366f6083SPeter Grehan 442366f6083SPeter Grehan if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS) 443366f6083SPeter Grehan return (E2BIG); 444366f6083SPeter Grehan 445f7d51510SNeel Natu seg = &vm->mem_segs[vm->num_mem_segs]; 446366f6083SPeter Grehan 447318224bbSNeel Natu if ((object = vmm_mem_alloc(vm->vmspace, gpa, len)) == NULL) 448318224bbSNeel Natu return (ENOMEM); 449318224bbSNeel Natu 450f7d51510SNeel Natu seg->gpa = gpa; 451318224bbSNeel Natu seg->len = len; 452318224bbSNeel Natu seg->object = object; 453318224bbSNeel Natu seg->wired = FALSE; 4547ce04d0aSNeel Natu 455366f6083SPeter Grehan vm->num_mem_segs++; 456341f19c9SNeel Natu 457366f6083SPeter Grehan return (0); 458366f6083SPeter Grehan } 459366f6083SPeter Grehan 460318224bbSNeel Natu static void 461318224bbSNeel Natu vm_gpa_unwire(struct vm *vm) 462366f6083SPeter Grehan { 463318224bbSNeel Natu int i, rv; 464318224bbSNeel Natu struct mem_seg *seg; 4654db4fb2cSNeel Natu 466318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 467318224bbSNeel Natu seg = &vm->mem_segs[i]; 468318224bbSNeel Natu if (!seg->wired) 469318224bbSNeel Natu continue; 470366f6083SPeter Grehan 471318224bbSNeel Natu rv = vm_map_unwire(&vm->vmspace->vm_map, 472318224bbSNeel Natu seg->gpa, seg->gpa + seg->len, 473318224bbSNeel Natu VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 474318224bbSNeel Natu KASSERT(rv == KERN_SUCCESS, ("vm(%s) memory segment " 475318224bbSNeel Natu "%#lx/%ld could not be unwired: %d", 476318224bbSNeel Natu vm_name(vm), seg->gpa, seg->len, rv)); 477318224bbSNeel Natu 478318224bbSNeel Natu seg->wired = FALSE; 479318224bbSNeel Natu } 480318224bbSNeel Natu } 481318224bbSNeel Natu 482318224bbSNeel Natu static int 483318224bbSNeel Natu vm_gpa_wire(struct vm *vm) 484318224bbSNeel Natu { 485318224bbSNeel Natu int i, rv; 486318224bbSNeel Natu struct mem_seg *seg; 487318224bbSNeel Natu 488318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 489318224bbSNeel Natu seg = &vm->mem_segs[i]; 490318224bbSNeel Natu if (seg->wired) 491318224bbSNeel Natu continue; 492318224bbSNeel Natu 493318224bbSNeel Natu /* XXX rlimits? */ 494318224bbSNeel Natu rv = vm_map_wire(&vm->vmspace->vm_map, 495318224bbSNeel Natu seg->gpa, seg->gpa + seg->len, 496318224bbSNeel Natu VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 497318224bbSNeel Natu if (rv != KERN_SUCCESS) 498318224bbSNeel Natu break; 499318224bbSNeel Natu 500318224bbSNeel Natu seg->wired = TRUE; 501318224bbSNeel Natu } 502318224bbSNeel Natu 503318224bbSNeel Natu if (i < vm->num_mem_segs) { 504318224bbSNeel Natu /* 505318224bbSNeel Natu * Undo the wiring before returning an error. 506318224bbSNeel Natu */ 507318224bbSNeel Natu vm_gpa_unwire(vm); 508318224bbSNeel Natu return (EAGAIN); 509318224bbSNeel Natu } 510318224bbSNeel Natu 511318224bbSNeel Natu return (0); 512318224bbSNeel Natu } 513318224bbSNeel Natu 514318224bbSNeel Natu static void 515318224bbSNeel Natu vm_iommu_modify(struct vm *vm, boolean_t map) 516318224bbSNeel Natu { 517318224bbSNeel Natu int i, sz; 518318224bbSNeel Natu vm_paddr_t gpa, hpa; 519318224bbSNeel Natu struct mem_seg *seg; 520318224bbSNeel Natu void *vp, *cookie, *host_domain; 521318224bbSNeel Natu 522318224bbSNeel Natu sz = PAGE_SIZE; 523318224bbSNeel Natu host_domain = iommu_host_domain(); 524318224bbSNeel Natu 525318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 526318224bbSNeel Natu seg = &vm->mem_segs[i]; 527318224bbSNeel Natu KASSERT(seg->wired, ("vm(%s) memory segment %#lx/%ld not wired", 528318224bbSNeel Natu vm_name(vm), seg->gpa, seg->len)); 529318224bbSNeel Natu 530318224bbSNeel Natu gpa = seg->gpa; 531318224bbSNeel Natu while (gpa < seg->gpa + seg->len) { 532318224bbSNeel Natu vp = vm_gpa_hold(vm, gpa, PAGE_SIZE, VM_PROT_WRITE, 533318224bbSNeel Natu &cookie); 534318224bbSNeel Natu KASSERT(vp != NULL, ("vm(%s) could not map gpa %#lx", 535318224bbSNeel Natu vm_name(vm), gpa)); 536318224bbSNeel Natu 537318224bbSNeel Natu vm_gpa_release(cookie); 538318224bbSNeel Natu 539318224bbSNeel Natu hpa = DMAP_TO_PHYS((uintptr_t)vp); 540318224bbSNeel Natu if (map) { 541318224bbSNeel Natu iommu_create_mapping(vm->iommu, gpa, hpa, sz); 542318224bbSNeel Natu iommu_remove_mapping(host_domain, hpa, sz); 543318224bbSNeel Natu } else { 544318224bbSNeel Natu iommu_remove_mapping(vm->iommu, gpa, sz); 545318224bbSNeel Natu iommu_create_mapping(host_domain, hpa, hpa, sz); 546318224bbSNeel Natu } 547318224bbSNeel Natu 548318224bbSNeel Natu gpa += PAGE_SIZE; 549318224bbSNeel Natu } 550318224bbSNeel Natu } 551318224bbSNeel Natu 552318224bbSNeel Natu /* 553318224bbSNeel Natu * Invalidate the cached translations associated with the domain 554318224bbSNeel Natu * from which pages were removed. 555318224bbSNeel Natu */ 556318224bbSNeel Natu if (map) 557318224bbSNeel Natu iommu_invalidate_tlb(host_domain); 558318224bbSNeel Natu else 559318224bbSNeel Natu iommu_invalidate_tlb(vm->iommu); 560318224bbSNeel Natu } 561318224bbSNeel Natu 562318224bbSNeel Natu #define vm_iommu_unmap(vm) vm_iommu_modify((vm), FALSE) 563318224bbSNeel Natu #define vm_iommu_map(vm) vm_iommu_modify((vm), TRUE) 564318224bbSNeel Natu 565318224bbSNeel Natu int 566318224bbSNeel Natu vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func) 567318224bbSNeel Natu { 568318224bbSNeel Natu int error; 569318224bbSNeel Natu 570318224bbSNeel Natu error = ppt_unassign_device(vm, bus, slot, func); 571318224bbSNeel Natu if (error) 572318224bbSNeel Natu return (error); 573318224bbSNeel Natu 574318224bbSNeel Natu if (ppt_num_devices(vm) == 0) { 575318224bbSNeel Natu vm_iommu_unmap(vm); 576318224bbSNeel Natu vm_gpa_unwire(vm); 577318224bbSNeel Natu } 578318224bbSNeel Natu return (0); 579318224bbSNeel Natu } 580318224bbSNeel Natu 581318224bbSNeel Natu int 582318224bbSNeel Natu vm_assign_pptdev(struct vm *vm, int bus, int slot, int func) 583318224bbSNeel Natu { 584318224bbSNeel Natu int error; 585318224bbSNeel Natu vm_paddr_t maxaddr; 586318224bbSNeel Natu 587318224bbSNeel Natu /* 588318224bbSNeel Natu * Virtual machines with pci passthru devices get special treatment: 589318224bbSNeel Natu * - the guest physical memory is wired 590318224bbSNeel Natu * - the iommu is programmed to do the 'gpa' to 'hpa' translation 591318224bbSNeel Natu * 592318224bbSNeel Natu * We need to do this before the first pci passthru device is attached. 593318224bbSNeel Natu */ 594318224bbSNeel Natu if (ppt_num_devices(vm) == 0) { 595318224bbSNeel Natu KASSERT(vm->iommu == NULL, 596318224bbSNeel Natu ("vm_assign_pptdev: iommu must be NULL")); 597318224bbSNeel Natu maxaddr = vmm_mem_maxaddr(); 598318224bbSNeel Natu vm->iommu = iommu_create_domain(maxaddr); 599318224bbSNeel Natu 600318224bbSNeel Natu error = vm_gpa_wire(vm); 601318224bbSNeel Natu if (error) 602318224bbSNeel Natu return (error); 603318224bbSNeel Natu 604318224bbSNeel Natu vm_iommu_map(vm); 605318224bbSNeel Natu } 606318224bbSNeel Natu 607318224bbSNeel Natu error = ppt_assign_device(vm, bus, slot, func); 608318224bbSNeel Natu return (error); 609318224bbSNeel Natu } 610318224bbSNeel Natu 611318224bbSNeel Natu void * 612318224bbSNeel Natu vm_gpa_hold(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, 613318224bbSNeel Natu void **cookie) 614318224bbSNeel Natu { 615318224bbSNeel Natu int count, pageoff; 616318224bbSNeel Natu vm_page_t m; 617318224bbSNeel Natu 618318224bbSNeel Natu pageoff = gpa & PAGE_MASK; 619318224bbSNeel Natu if (len > PAGE_SIZE - pageoff) 620318224bbSNeel Natu panic("vm_gpa_hold: invalid gpa/len: 0x%016lx/%lu", gpa, len); 621318224bbSNeel Natu 622318224bbSNeel Natu count = vm_fault_quick_hold_pages(&vm->vmspace->vm_map, 623318224bbSNeel Natu trunc_page(gpa), PAGE_SIZE, reqprot, &m, 1); 624318224bbSNeel Natu 625318224bbSNeel Natu if (count == 1) { 626318224bbSNeel Natu *cookie = m; 627318224bbSNeel Natu return ((void *)(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)) + pageoff)); 628318224bbSNeel Natu } else { 629318224bbSNeel Natu *cookie = NULL; 630318224bbSNeel Natu return (NULL); 631318224bbSNeel Natu } 632318224bbSNeel Natu } 633318224bbSNeel Natu 634318224bbSNeel Natu void 635318224bbSNeel Natu vm_gpa_release(void *cookie) 636318224bbSNeel Natu { 637318224bbSNeel Natu vm_page_t m = cookie; 638318224bbSNeel Natu 639318224bbSNeel Natu vm_page_lock(m); 640318224bbSNeel Natu vm_page_unhold(m); 641318224bbSNeel Natu vm_page_unlock(m); 642366f6083SPeter Grehan } 643366f6083SPeter Grehan 644366f6083SPeter Grehan int 645366f6083SPeter Grehan vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 646366f6083SPeter Grehan struct vm_memory_segment *seg) 647366f6083SPeter Grehan { 648366f6083SPeter Grehan int i; 649366f6083SPeter Grehan 650366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) { 651366f6083SPeter Grehan if (gpabase == vm->mem_segs[i].gpa) { 652318224bbSNeel Natu seg->gpa = vm->mem_segs[i].gpa; 653318224bbSNeel Natu seg->len = vm->mem_segs[i].len; 654318224bbSNeel Natu seg->wired = vm->mem_segs[i].wired; 655366f6083SPeter Grehan return (0); 656366f6083SPeter Grehan } 657366f6083SPeter Grehan } 658366f6083SPeter Grehan return (-1); 659366f6083SPeter Grehan } 660366f6083SPeter Grehan 661366f6083SPeter Grehan int 662318224bbSNeel Natu vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len, 663318224bbSNeel Natu vm_offset_t *offset, struct vm_object **object) 664318224bbSNeel Natu { 665318224bbSNeel Natu int i; 666318224bbSNeel Natu size_t seg_len; 667318224bbSNeel Natu vm_paddr_t seg_gpa; 668318224bbSNeel Natu vm_object_t seg_obj; 669318224bbSNeel Natu 670318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 671318224bbSNeel Natu if ((seg_obj = vm->mem_segs[i].object) == NULL) 672318224bbSNeel Natu continue; 673318224bbSNeel Natu 674318224bbSNeel Natu seg_gpa = vm->mem_segs[i].gpa; 675318224bbSNeel Natu seg_len = vm->mem_segs[i].len; 676318224bbSNeel Natu 677318224bbSNeel Natu if (gpa >= seg_gpa && gpa < seg_gpa + seg_len) { 678318224bbSNeel Natu *offset = gpa - seg_gpa; 679318224bbSNeel Natu *object = seg_obj; 680318224bbSNeel Natu vm_object_reference(seg_obj); 681318224bbSNeel Natu return (0); 682318224bbSNeel Natu } 683318224bbSNeel Natu } 684318224bbSNeel Natu 685318224bbSNeel Natu return (EINVAL); 686318224bbSNeel Natu } 687318224bbSNeel Natu 688318224bbSNeel Natu int 689366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 690366f6083SPeter Grehan { 691366f6083SPeter Grehan 692366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 693366f6083SPeter Grehan return (EINVAL); 694366f6083SPeter Grehan 695366f6083SPeter Grehan if (reg >= VM_REG_LAST) 696366f6083SPeter Grehan return (EINVAL); 697366f6083SPeter Grehan 698366f6083SPeter Grehan return (VMGETREG(vm->cookie, vcpu, reg, retval)); 699366f6083SPeter Grehan } 700366f6083SPeter Grehan 701366f6083SPeter Grehan int 702366f6083SPeter Grehan vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val) 703366f6083SPeter Grehan { 704366f6083SPeter Grehan 705366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 706366f6083SPeter Grehan return (EINVAL); 707366f6083SPeter Grehan 708366f6083SPeter Grehan if (reg >= VM_REG_LAST) 709366f6083SPeter Grehan return (EINVAL); 710366f6083SPeter Grehan 711366f6083SPeter Grehan return (VMSETREG(vm->cookie, vcpu, reg, val)); 712366f6083SPeter Grehan } 713366f6083SPeter Grehan 714366f6083SPeter Grehan static boolean_t 715366f6083SPeter Grehan is_descriptor_table(int reg) 716366f6083SPeter Grehan { 717366f6083SPeter Grehan 718366f6083SPeter Grehan switch (reg) { 719366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 720366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 721366f6083SPeter Grehan return (TRUE); 722366f6083SPeter Grehan default: 723366f6083SPeter Grehan return (FALSE); 724366f6083SPeter Grehan } 725366f6083SPeter Grehan } 726366f6083SPeter Grehan 727366f6083SPeter Grehan static boolean_t 728366f6083SPeter Grehan is_segment_register(int reg) 729366f6083SPeter Grehan { 730366f6083SPeter Grehan 731366f6083SPeter Grehan switch (reg) { 732366f6083SPeter Grehan case VM_REG_GUEST_ES: 733366f6083SPeter Grehan case VM_REG_GUEST_CS: 734366f6083SPeter Grehan case VM_REG_GUEST_SS: 735366f6083SPeter Grehan case VM_REG_GUEST_DS: 736366f6083SPeter Grehan case VM_REG_GUEST_FS: 737366f6083SPeter Grehan case VM_REG_GUEST_GS: 738366f6083SPeter Grehan case VM_REG_GUEST_TR: 739366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 740366f6083SPeter Grehan return (TRUE); 741366f6083SPeter Grehan default: 742366f6083SPeter Grehan return (FALSE); 743366f6083SPeter Grehan } 744366f6083SPeter Grehan } 745366f6083SPeter Grehan 746366f6083SPeter Grehan int 747366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 748366f6083SPeter Grehan struct seg_desc *desc) 749366f6083SPeter Grehan { 750366f6083SPeter Grehan 751366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 752366f6083SPeter Grehan return (EINVAL); 753366f6083SPeter Grehan 754366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 755366f6083SPeter Grehan return (EINVAL); 756366f6083SPeter Grehan 757366f6083SPeter Grehan return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 758366f6083SPeter Grehan } 759366f6083SPeter Grehan 760366f6083SPeter Grehan int 761366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 762366f6083SPeter Grehan struct seg_desc *desc) 763366f6083SPeter Grehan { 764366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 765366f6083SPeter Grehan return (EINVAL); 766366f6083SPeter Grehan 767366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 768366f6083SPeter Grehan return (EINVAL); 769366f6083SPeter Grehan 770366f6083SPeter Grehan return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 771366f6083SPeter Grehan } 772366f6083SPeter Grehan 773366f6083SPeter Grehan static void 774366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 775366f6083SPeter Grehan { 776366f6083SPeter Grehan 77738f1b189SPeter Grehan /* flush host state to the pcb */ 77838f1b189SPeter Grehan fpuexit(curthread); 779bd8572e0SNeel Natu 780bd8572e0SNeel Natu /* restore guest FPU state */ 781366f6083SPeter Grehan fpu_stop_emulating(); 78238f1b189SPeter Grehan fpurestore(vcpu->guestfpu); 783bd8572e0SNeel Natu 784bd8572e0SNeel Natu /* 785bd8572e0SNeel Natu * The FPU is now "dirty" with the guest's state so turn on emulation 786bd8572e0SNeel Natu * to trap any access to the FPU by the host. 787bd8572e0SNeel Natu */ 788bd8572e0SNeel Natu fpu_start_emulating(); 789366f6083SPeter Grehan } 790366f6083SPeter Grehan 791366f6083SPeter Grehan static void 792366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 793366f6083SPeter Grehan { 794366f6083SPeter Grehan 795bd8572e0SNeel Natu if ((rcr0() & CR0_TS) == 0) 796bd8572e0SNeel Natu panic("fpu emulation not enabled in host!"); 797bd8572e0SNeel Natu 798bd8572e0SNeel Natu /* save guest FPU state */ 799bd8572e0SNeel Natu fpu_stop_emulating(); 80038f1b189SPeter Grehan fpusave(vcpu->guestfpu); 801366f6083SPeter Grehan fpu_start_emulating(); 802366f6083SPeter Grehan } 803366f6083SPeter Grehan 80461592433SNeel Natu static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); 805f76fc5d4SNeel Natu 806318224bbSNeel Natu static int 807318224bbSNeel Natu vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) 808366f6083SPeter Grehan { 809318224bbSNeel Natu int error; 810366f6083SPeter Grehan 811318224bbSNeel Natu vcpu_assert_locked(vcpu); 812366f6083SPeter Grehan 813f76fc5d4SNeel Natu /* 814318224bbSNeel Natu * The following state transitions are allowed: 815318224bbSNeel Natu * IDLE -> FROZEN -> IDLE 816318224bbSNeel Natu * FROZEN -> RUNNING -> FROZEN 817318224bbSNeel Natu * FROZEN -> SLEEPING -> FROZEN 818f76fc5d4SNeel Natu */ 819318224bbSNeel Natu switch (vcpu->state) { 820318224bbSNeel Natu case VCPU_IDLE: 821318224bbSNeel Natu case VCPU_RUNNING: 822318224bbSNeel Natu case VCPU_SLEEPING: 823318224bbSNeel Natu error = (newstate != VCPU_FROZEN); 824318224bbSNeel Natu break; 825318224bbSNeel Natu case VCPU_FROZEN: 826318224bbSNeel Natu error = (newstate == VCPU_FROZEN); 827318224bbSNeel Natu break; 828318224bbSNeel Natu default: 829318224bbSNeel Natu error = 1; 830318224bbSNeel Natu break; 831318224bbSNeel Natu } 832318224bbSNeel Natu 833318224bbSNeel Natu if (error == 0) 834318224bbSNeel Natu vcpu->state = newstate; 835318224bbSNeel Natu else 836318224bbSNeel Natu error = EBUSY; 837318224bbSNeel Natu 838318224bbSNeel Natu return (error); 839318224bbSNeel Natu } 840318224bbSNeel Natu 841318224bbSNeel Natu static void 842318224bbSNeel Natu vcpu_require_state(struct vm *vm, int vcpuid, enum vcpu_state newstate) 843318224bbSNeel Natu { 844318224bbSNeel Natu int error; 845318224bbSNeel Natu 846318224bbSNeel Natu if ((error = vcpu_set_state(vm, vcpuid, newstate)) != 0) 847318224bbSNeel Natu panic("Error %d setting state to %d\n", error, newstate); 848318224bbSNeel Natu } 849318224bbSNeel Natu 850318224bbSNeel Natu static void 851318224bbSNeel Natu vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) 852318224bbSNeel Natu { 853318224bbSNeel Natu int error; 854318224bbSNeel Natu 855318224bbSNeel Natu if ((error = vcpu_set_state_locked(vcpu, newstate)) != 0) 856318224bbSNeel Natu panic("Error %d setting state to %d", error, newstate); 857318224bbSNeel Natu } 858318224bbSNeel Natu 859318224bbSNeel Natu /* 860318224bbSNeel Natu * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run. 861318224bbSNeel Natu */ 862318224bbSNeel Natu static int 863*1c052192SNeel Natu vm_handle_hlt(struct vm *vm, int vcpuid, boolean_t intr_disabled, 864*1c052192SNeel Natu boolean_t *retu) 865318224bbSNeel Natu { 866*1c052192SNeel Natu struct vm_exit *vmexit; 867318224bbSNeel Natu struct vcpu *vcpu; 868318224bbSNeel Natu int sleepticks, t; 869318224bbSNeel Natu 870318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 871318224bbSNeel Natu 872f76fc5d4SNeel Natu vcpu_lock(vcpu); 873f76fc5d4SNeel Natu 874f76fc5d4SNeel Natu /* 875f76fc5d4SNeel Natu * Figure out the number of host ticks until the next apic 876f76fc5d4SNeel Natu * timer interrupt in the guest. 877f76fc5d4SNeel Natu */ 878f76fc5d4SNeel Natu sleepticks = lapic_timer_tick(vm, vcpuid); 879f76fc5d4SNeel Natu 880f76fc5d4SNeel Natu /* 881f76fc5d4SNeel Natu * If the guest local apic timer is disabled then sleep for 882f76fc5d4SNeel Natu * a long time but not forever. 883f76fc5d4SNeel Natu */ 884f76fc5d4SNeel Natu if (sleepticks < 0) 885f76fc5d4SNeel Natu sleepticks = hz; 886f76fc5d4SNeel Natu 887f76fc5d4SNeel Natu /* 888f76fc5d4SNeel Natu * Do a final check for pending NMI or interrupts before 889f76fc5d4SNeel Natu * really putting this thread to sleep. 890f76fc5d4SNeel Natu * 891f76fc5d4SNeel Natu * These interrupts could have happened any time after we 892f76fc5d4SNeel Natu * returned from VMRUN() and before we grabbed the vcpu lock. 893f76fc5d4SNeel Natu */ 894*1c052192SNeel Natu if (!vm_nmi_pending(vm, vcpuid) && 895*1c052192SNeel Natu (intr_disabled || vlapic_pending_intr(vcpu->vlapic) < 0)) { 896f76fc5d4SNeel Natu if (sleepticks <= 0) 897f76fc5d4SNeel Natu panic("invalid sleepticks %d", sleepticks); 898f76fc5d4SNeel Natu t = ticks; 899318224bbSNeel Natu vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 900*1c052192SNeel Natu if (vlapic_enabled(vcpu->vlapic)) { 901f76fc5d4SNeel Natu msleep_spin(vcpu, &vcpu->mtx, "vmidle", sleepticks); 902*1c052192SNeel Natu } else { 903*1c052192SNeel Natu /* 904*1c052192SNeel Natu * Spindown the vcpu if the apic is disabled and it 905*1c052192SNeel Natu * had entered the halted state. 906*1c052192SNeel Natu */ 907*1c052192SNeel Natu *retu = TRUE; 908*1c052192SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 909*1c052192SNeel Natu vmexit->exitcode = VM_EXITCODE_SPINDOWN_CPU; 910*1c052192SNeel Natu VCPU_CTR0(vm, vcpuid, "spinning down cpu"); 911*1c052192SNeel Natu } 912318224bbSNeel Natu vcpu_require_state_locked(vcpu, VCPU_FROZEN); 913f76fc5d4SNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t); 914f76fc5d4SNeel Natu } 915f76fc5d4SNeel Natu vcpu_unlock(vcpu); 916f76fc5d4SNeel Natu 917318224bbSNeel Natu return (0); 918318224bbSNeel Natu } 919318224bbSNeel Natu 920318224bbSNeel Natu static int 921318224bbSNeel Natu vm_handle_paging(struct vm *vm, int vcpuid, boolean_t *retu) 922318224bbSNeel Natu { 923318224bbSNeel Natu int rv, ftype; 924318224bbSNeel Natu struct vm_map *map; 925318224bbSNeel Natu struct vcpu *vcpu; 926318224bbSNeel Natu struct vm_exit *vme; 927318224bbSNeel Natu 928318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 929318224bbSNeel Natu vme = &vcpu->exitinfo; 930318224bbSNeel Natu 931318224bbSNeel Natu ftype = vme->u.paging.fault_type; 932318224bbSNeel Natu KASSERT(ftype == VM_PROT_READ || 933318224bbSNeel Natu ftype == VM_PROT_WRITE || ftype == VM_PROT_EXECUTE, 934318224bbSNeel Natu ("vm_handle_paging: invalid fault_type %d", ftype)); 935318224bbSNeel Natu 936318224bbSNeel Natu if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { 937318224bbSNeel Natu rv = pmap_emulate_accessed_dirty(vmspace_pmap(vm->vmspace), 938318224bbSNeel Natu vme->u.paging.gpa, ftype); 939318224bbSNeel Natu if (rv == 0) 940318224bbSNeel Natu goto done; 941318224bbSNeel Natu } 942318224bbSNeel Natu 943318224bbSNeel Natu map = &vm->vmspace->vm_map; 944318224bbSNeel Natu rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL); 945318224bbSNeel Natu 946513c8d33SNeel Natu VCPU_CTR3(vm, vcpuid, "vm_handle_paging rv = %d, gpa = %#lx, " 947513c8d33SNeel Natu "ftype = %d", rv, vme->u.paging.gpa, ftype); 948318224bbSNeel Natu 949318224bbSNeel Natu if (rv != KERN_SUCCESS) 950318224bbSNeel Natu return (EFAULT); 951318224bbSNeel Natu done: 952318224bbSNeel Natu /* restart execution at the faulting instruction */ 953318224bbSNeel Natu vme->inst_length = 0; 954318224bbSNeel Natu 955318224bbSNeel Natu return (0); 956318224bbSNeel Natu } 957318224bbSNeel Natu 958318224bbSNeel Natu static int 959318224bbSNeel Natu vm_handle_inst_emul(struct vm *vm, int vcpuid, boolean_t *retu) 960318224bbSNeel Natu { 961318224bbSNeel Natu struct vie *vie; 962318224bbSNeel Natu struct vcpu *vcpu; 963318224bbSNeel Natu struct vm_exit *vme; 964318224bbSNeel Natu int error, inst_length; 965318224bbSNeel Natu uint64_t rip, gla, gpa, cr3; 966565bbb86SNeel Natu mem_region_read_t mread; 967565bbb86SNeel Natu mem_region_write_t mwrite; 968318224bbSNeel Natu 969318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 970318224bbSNeel Natu vme = &vcpu->exitinfo; 971318224bbSNeel Natu 972318224bbSNeel Natu rip = vme->rip; 973318224bbSNeel Natu inst_length = vme->inst_length; 974318224bbSNeel Natu 975318224bbSNeel Natu gla = vme->u.inst_emul.gla; 976318224bbSNeel Natu gpa = vme->u.inst_emul.gpa; 977318224bbSNeel Natu cr3 = vme->u.inst_emul.cr3; 978318224bbSNeel Natu vie = &vme->u.inst_emul.vie; 979318224bbSNeel Natu 980318224bbSNeel Natu vie_init(vie); 981318224bbSNeel Natu 982318224bbSNeel Natu /* Fetch, decode and emulate the faulting instruction */ 983318224bbSNeel Natu if (vmm_fetch_instruction(vm, vcpuid, rip, inst_length, cr3, vie) != 0) 984318224bbSNeel Natu return (EFAULT); 985318224bbSNeel Natu 986318224bbSNeel Natu if (vmm_decode_instruction(vm, vcpuid, gla, vie) != 0) 987318224bbSNeel Natu return (EFAULT); 988318224bbSNeel Natu 98908e3ff32SNeel Natu /* return to userland unless this is an in-kernel emulated device */ 990565bbb86SNeel Natu if (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE) { 991565bbb86SNeel Natu mread = lapic_mmio_read; 992565bbb86SNeel Natu mwrite = lapic_mmio_write; 993565bbb86SNeel Natu } else if (gpa >= VIOAPIC_BASE && gpa < VIOAPIC_BASE + VIOAPIC_SIZE) { 994565bbb86SNeel Natu mread = vioapic_mmio_read; 995565bbb86SNeel Natu mwrite = vioapic_mmio_write; 99608e3ff32SNeel Natu } else if (gpa >= VHPET_BASE && gpa < VHPET_BASE + VHPET_SIZE) { 99708e3ff32SNeel Natu mread = vhpet_mmio_read; 99808e3ff32SNeel Natu mwrite = vhpet_mmio_write; 999565bbb86SNeel Natu } else { 1000318224bbSNeel Natu *retu = TRUE; 1001318224bbSNeel Natu return (0); 1002318224bbSNeel Natu } 1003318224bbSNeel Natu 1004565bbb86SNeel Natu error = vmm_emulate_instruction(vm, vcpuid, gpa, vie, mread, mwrite, 0); 1005318224bbSNeel Natu 1006318224bbSNeel Natu /* return to userland to spin up the AP */ 1007318224bbSNeel Natu if (error == 0 && vme->exitcode == VM_EXITCODE_SPINUP_AP) 1008318224bbSNeel Natu *retu = TRUE; 1009318224bbSNeel Natu 1010318224bbSNeel Natu return (error); 1011318224bbSNeel Natu } 1012318224bbSNeel Natu 1013318224bbSNeel Natu int 1014318224bbSNeel Natu vm_run(struct vm *vm, struct vm_run *vmrun) 1015318224bbSNeel Natu { 1016318224bbSNeel Natu int error, vcpuid; 1017318224bbSNeel Natu struct vcpu *vcpu; 1018318224bbSNeel Natu struct pcb *pcb; 1019318224bbSNeel Natu uint64_t tscval, rip; 1020318224bbSNeel Natu struct vm_exit *vme; 1021*1c052192SNeel Natu boolean_t retu, intr_disabled; 1022318224bbSNeel Natu pmap_t pmap; 1023318224bbSNeel Natu 1024318224bbSNeel Natu vcpuid = vmrun->cpuid; 1025318224bbSNeel Natu 1026318224bbSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1027318224bbSNeel Natu return (EINVAL); 1028318224bbSNeel Natu 1029318224bbSNeel Natu pmap = vmspace_pmap(vm->vmspace); 1030318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1031318224bbSNeel Natu vme = &vcpu->exitinfo; 1032318224bbSNeel Natu rip = vmrun->rip; 1033318224bbSNeel Natu restart: 1034318224bbSNeel Natu critical_enter(); 1035318224bbSNeel Natu 1036318224bbSNeel Natu KASSERT(!CPU_ISSET(curcpu, &pmap->pm_active), 1037318224bbSNeel Natu ("vm_run: absurd pm_active")); 1038318224bbSNeel Natu 1039318224bbSNeel Natu tscval = rdtsc(); 1040318224bbSNeel Natu 1041318224bbSNeel Natu pcb = PCPU_GET(curpcb); 1042318224bbSNeel Natu set_pcb_flags(pcb, PCB_FULL_IRET); 1043318224bbSNeel Natu 1044318224bbSNeel Natu restore_guest_msrs(vm, vcpuid); 1045318224bbSNeel Natu restore_guest_fpustate(vcpu); 1046318224bbSNeel Natu 1047318224bbSNeel Natu vcpu_require_state(vm, vcpuid, VCPU_RUNNING); 1048318224bbSNeel Natu vcpu->hostcpu = curcpu; 1049318224bbSNeel Natu error = VMRUN(vm->cookie, vcpuid, rip, pmap); 1050318224bbSNeel Natu vcpu->hostcpu = NOCPU; 1051318224bbSNeel Natu vcpu_require_state(vm, vcpuid, VCPU_FROZEN); 1052318224bbSNeel Natu 1053318224bbSNeel Natu save_guest_fpustate(vcpu); 1054318224bbSNeel Natu restore_host_msrs(vm, vcpuid); 1055318224bbSNeel Natu 1056318224bbSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 1057318224bbSNeel Natu 1058318224bbSNeel Natu critical_exit(); 1059318224bbSNeel Natu 1060318224bbSNeel Natu if (error == 0) { 1061318224bbSNeel Natu retu = FALSE; 1062318224bbSNeel Natu switch (vme->exitcode) { 1063318224bbSNeel Natu case VM_EXITCODE_HLT: 1064*1c052192SNeel Natu if ((vme->u.hlt.rflags & PSL_I) == 0) 1065*1c052192SNeel Natu intr_disabled = TRUE; 1066*1c052192SNeel Natu else 1067*1c052192SNeel Natu intr_disabled = FALSE; 1068*1c052192SNeel Natu error = vm_handle_hlt(vm, vcpuid, intr_disabled, &retu); 1069318224bbSNeel Natu break; 1070318224bbSNeel Natu case VM_EXITCODE_PAGING: 1071318224bbSNeel Natu error = vm_handle_paging(vm, vcpuid, &retu); 1072318224bbSNeel Natu break; 1073318224bbSNeel Natu case VM_EXITCODE_INST_EMUL: 1074318224bbSNeel Natu error = vm_handle_inst_emul(vm, vcpuid, &retu); 1075318224bbSNeel Natu break; 1076318224bbSNeel Natu default: 1077318224bbSNeel Natu retu = TRUE; /* handled in userland */ 1078318224bbSNeel Natu break; 1079318224bbSNeel Natu } 1080318224bbSNeel Natu } 1081318224bbSNeel Natu 1082318224bbSNeel Natu if (error == 0 && retu == FALSE) { 1083f76fc5d4SNeel Natu rip = vme->rip + vme->inst_length; 1084f76fc5d4SNeel Natu goto restart; 1085f76fc5d4SNeel Natu } 1086f76fc5d4SNeel Natu 1087318224bbSNeel Natu /* copy the exit information */ 1088318224bbSNeel Natu bcopy(vme, &vmrun->vm_exit, sizeof(struct vm_exit)); 1089366f6083SPeter Grehan return (error); 1090366f6083SPeter Grehan } 1091366f6083SPeter Grehan 1092366f6083SPeter Grehan int 1093366f6083SPeter Grehan vm_inject_event(struct vm *vm, int vcpuid, int type, 1094366f6083SPeter Grehan int vector, uint32_t code, int code_valid) 1095366f6083SPeter Grehan { 1096366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1097366f6083SPeter Grehan return (EINVAL); 1098366f6083SPeter Grehan 1099366f6083SPeter Grehan if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0) 1100366f6083SPeter Grehan return (EINVAL); 1101366f6083SPeter Grehan 1102366f6083SPeter Grehan if (vector < 0 || vector > 255) 1103366f6083SPeter Grehan return (EINVAL); 1104366f6083SPeter Grehan 1105366f6083SPeter Grehan return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid)); 1106366f6083SPeter Grehan } 1107366f6083SPeter Grehan 110861592433SNeel Natu static VMM_STAT(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); 1109366f6083SPeter Grehan 1110f352ff0cSNeel Natu int 1111f352ff0cSNeel Natu vm_inject_nmi(struct vm *vm, int vcpuid) 1112f352ff0cSNeel Natu { 1113f352ff0cSNeel Natu struct vcpu *vcpu; 1114f352ff0cSNeel Natu 1115f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1116366f6083SPeter Grehan return (EINVAL); 1117366f6083SPeter Grehan 1118f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1119f352ff0cSNeel Natu 1120f352ff0cSNeel Natu vcpu->nmi_pending = 1; 112122821874SNeel Natu vcpu_notify_event(vm, vcpuid); 1122f352ff0cSNeel Natu return (0); 1123f352ff0cSNeel Natu } 1124f352ff0cSNeel Natu 1125f352ff0cSNeel Natu int 1126f352ff0cSNeel Natu vm_nmi_pending(struct vm *vm, int vcpuid) 1127f352ff0cSNeel Natu { 1128f352ff0cSNeel Natu struct vcpu *vcpu; 1129f352ff0cSNeel Natu 1130f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1131f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 1132f352ff0cSNeel Natu 1133f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1134f352ff0cSNeel Natu 1135f352ff0cSNeel Natu return (vcpu->nmi_pending); 1136f352ff0cSNeel Natu } 1137f352ff0cSNeel Natu 1138f352ff0cSNeel Natu void 1139f352ff0cSNeel Natu vm_nmi_clear(struct vm *vm, int vcpuid) 1140f352ff0cSNeel Natu { 1141f352ff0cSNeel Natu struct vcpu *vcpu; 1142f352ff0cSNeel Natu 1143f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1144f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 1145f352ff0cSNeel Natu 1146f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1147f352ff0cSNeel Natu 1148f352ff0cSNeel Natu if (vcpu->nmi_pending == 0) 1149f352ff0cSNeel Natu panic("vm_nmi_clear: inconsistent nmi_pending state"); 1150f352ff0cSNeel Natu 1151f352ff0cSNeel Natu vcpu->nmi_pending = 0; 1152f352ff0cSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1); 1153366f6083SPeter Grehan } 1154366f6083SPeter Grehan 1155366f6083SPeter Grehan int 1156366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 1157366f6083SPeter Grehan { 1158366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 1159366f6083SPeter Grehan return (EINVAL); 1160366f6083SPeter Grehan 1161366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 1162366f6083SPeter Grehan return (EINVAL); 1163366f6083SPeter Grehan 1164366f6083SPeter Grehan return (VMGETCAP(vm->cookie, vcpu, type, retval)); 1165366f6083SPeter Grehan } 1166366f6083SPeter Grehan 1167366f6083SPeter Grehan int 1168366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val) 1169366f6083SPeter Grehan { 1170366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 1171366f6083SPeter Grehan return (EINVAL); 1172366f6083SPeter Grehan 1173366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 1174366f6083SPeter Grehan return (EINVAL); 1175366f6083SPeter Grehan 1176366f6083SPeter Grehan return (VMSETCAP(vm->cookie, vcpu, type, val)); 1177366f6083SPeter Grehan } 1178366f6083SPeter Grehan 1179366f6083SPeter Grehan uint64_t * 1180366f6083SPeter Grehan vm_guest_msrs(struct vm *vm, int cpu) 1181366f6083SPeter Grehan { 1182366f6083SPeter Grehan return (vm->vcpu[cpu].guest_msrs); 1183366f6083SPeter Grehan } 1184366f6083SPeter Grehan 1185366f6083SPeter Grehan struct vlapic * 1186366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu) 1187366f6083SPeter Grehan { 1188366f6083SPeter Grehan return (vm->vcpu[cpu].vlapic); 1189366f6083SPeter Grehan } 1190366f6083SPeter Grehan 1191565bbb86SNeel Natu struct vioapic * 1192565bbb86SNeel Natu vm_ioapic(struct vm *vm) 1193565bbb86SNeel Natu { 1194565bbb86SNeel Natu 1195565bbb86SNeel Natu return (vm->vioapic); 1196565bbb86SNeel Natu } 1197565bbb86SNeel Natu 119808e3ff32SNeel Natu struct vhpet * 119908e3ff32SNeel Natu vm_hpet(struct vm *vm) 120008e3ff32SNeel Natu { 120108e3ff32SNeel Natu 120208e3ff32SNeel Natu return (vm->vhpet); 120308e3ff32SNeel Natu } 120408e3ff32SNeel Natu 1205366f6083SPeter Grehan boolean_t 1206366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 1207366f6083SPeter Grehan { 120807044a96SNeel Natu int found, i, n; 120907044a96SNeel Natu int b, s, f; 1210366f6083SPeter Grehan char *val, *cp, *cp2; 1211366f6083SPeter Grehan 1212366f6083SPeter Grehan /* 121307044a96SNeel Natu * XXX 121407044a96SNeel Natu * The length of an environment variable is limited to 128 bytes which 121507044a96SNeel Natu * puts an upper limit on the number of passthru devices that may be 121607044a96SNeel Natu * specified using a single environment variable. 121707044a96SNeel Natu * 121807044a96SNeel Natu * Work around this by scanning multiple environment variable 121907044a96SNeel Natu * names instead of a single one - yuck! 1220366f6083SPeter Grehan */ 122107044a96SNeel Natu const char *names[] = { "pptdevs", "pptdevs2", "pptdevs3", NULL }; 122207044a96SNeel Natu 122307044a96SNeel Natu /* set pptdevs="1/2/3 4/5/6 7/8/9 10/11/12" */ 1224366f6083SPeter Grehan found = 0; 122507044a96SNeel Natu for (i = 0; names[i] != NULL && !found; i++) { 122607044a96SNeel Natu cp = val = getenv(names[i]); 1227366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 1228366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 1229366f6083SPeter Grehan *cp2 = '\0'; 1230366f6083SPeter Grehan 1231366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 1232366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 1233366f6083SPeter Grehan found = 1; 1234366f6083SPeter Grehan break; 1235366f6083SPeter Grehan } 1236366f6083SPeter Grehan 1237366f6083SPeter Grehan if (cp2 != NULL) 1238366f6083SPeter Grehan *cp2++ = ' '; 1239366f6083SPeter Grehan 1240366f6083SPeter Grehan cp = cp2; 1241366f6083SPeter Grehan } 1242366f6083SPeter Grehan freeenv(val); 124307044a96SNeel Natu } 1244366f6083SPeter Grehan return (found); 1245366f6083SPeter Grehan } 1246366f6083SPeter Grehan 1247366f6083SPeter Grehan void * 1248366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 1249366f6083SPeter Grehan { 1250366f6083SPeter Grehan 1251366f6083SPeter Grehan return (vm->iommu); 1252366f6083SPeter Grehan } 1253366f6083SPeter Grehan 125475dd3366SNeel Natu int 1255318224bbSNeel Natu vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state newstate) 1256366f6083SPeter Grehan { 125775dd3366SNeel Natu int error; 1258366f6083SPeter Grehan struct vcpu *vcpu; 1259366f6083SPeter Grehan 1260366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1261366f6083SPeter Grehan panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 1262366f6083SPeter Grehan 1263366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 1264366f6083SPeter Grehan 126575dd3366SNeel Natu vcpu_lock(vcpu); 1266318224bbSNeel Natu error = vcpu_set_state_locked(vcpu, newstate); 126775dd3366SNeel Natu vcpu_unlock(vcpu); 126875dd3366SNeel Natu 126975dd3366SNeel Natu return (error); 127075dd3366SNeel Natu } 127175dd3366SNeel Natu 127275dd3366SNeel Natu enum vcpu_state 1273d3c11f40SPeter Grehan vcpu_get_state(struct vm *vm, int vcpuid, int *hostcpu) 1274366f6083SPeter Grehan { 1275366f6083SPeter Grehan struct vcpu *vcpu; 127675dd3366SNeel Natu enum vcpu_state state; 1277366f6083SPeter Grehan 1278366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1279366f6083SPeter Grehan panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 1280366f6083SPeter Grehan 1281366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 1282366f6083SPeter Grehan 128375dd3366SNeel Natu vcpu_lock(vcpu); 128475dd3366SNeel Natu state = vcpu->state; 1285d3c11f40SPeter Grehan if (hostcpu != NULL) 1286d3c11f40SPeter Grehan *hostcpu = vcpu->hostcpu; 128775dd3366SNeel Natu vcpu_unlock(vcpu); 1288366f6083SPeter Grehan 128975dd3366SNeel Natu return (state); 1290366f6083SPeter Grehan } 1291366f6083SPeter Grehan 1292366f6083SPeter Grehan void 1293366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid) 1294366f6083SPeter Grehan { 1295366f6083SPeter Grehan 1296366f6083SPeter Grehan if (vcpuid >= 0 && vcpuid < VM_MAXCPU) 1297a5615c90SPeter Grehan CPU_SET(vcpuid, &vm->active_cpus); 1298366f6083SPeter Grehan } 1299366f6083SPeter Grehan 1300a5615c90SPeter Grehan cpuset_t 1301366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 1302366f6083SPeter Grehan { 1303366f6083SPeter Grehan 1304366f6083SPeter Grehan return (vm->active_cpus); 1305366f6083SPeter Grehan } 1306366f6083SPeter Grehan 1307366f6083SPeter Grehan void * 1308366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid) 1309366f6083SPeter Grehan { 1310366f6083SPeter Grehan 1311366f6083SPeter Grehan return (vm->vcpu[vcpuid].stats); 1312366f6083SPeter Grehan } 1313e9027382SNeel Natu 1314e9027382SNeel Natu int 1315e9027382SNeel Natu vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) 1316e9027382SNeel Natu { 1317e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1318e9027382SNeel Natu return (EINVAL); 1319e9027382SNeel Natu 1320e9027382SNeel Natu *state = vm->vcpu[vcpuid].x2apic_state; 1321e9027382SNeel Natu 1322e9027382SNeel Natu return (0); 1323e9027382SNeel Natu } 1324e9027382SNeel Natu 1325e9027382SNeel Natu int 1326e9027382SNeel Natu vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 1327e9027382SNeel Natu { 1328e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1329e9027382SNeel Natu return (EINVAL); 1330e9027382SNeel Natu 13313f23d3caSNeel Natu if (state >= X2APIC_STATE_LAST) 1332e9027382SNeel Natu return (EINVAL); 1333e9027382SNeel Natu 1334e9027382SNeel Natu vm->vcpu[vcpuid].x2apic_state = state; 1335e9027382SNeel Natu 133673820fb0SNeel Natu vlapic_set_x2apic_state(vm, vcpuid, state); 133773820fb0SNeel Natu 1338e9027382SNeel Natu return (0); 1339e9027382SNeel Natu } 134075dd3366SNeel Natu 134122821874SNeel Natu /* 134222821874SNeel Natu * This function is called to ensure that a vcpu "sees" a pending event 134322821874SNeel Natu * as soon as possible: 134422821874SNeel Natu * - If the vcpu thread is sleeping then it is woken up. 134522821874SNeel Natu * - If the vcpu is running on a different host_cpu then an IPI will be directed 134622821874SNeel Natu * to the host_cpu to cause the vcpu to trap into the hypervisor. 134722821874SNeel Natu */ 134875dd3366SNeel Natu void 134922821874SNeel Natu vcpu_notify_event(struct vm *vm, int vcpuid) 135075dd3366SNeel Natu { 135175dd3366SNeel Natu int hostcpu; 135275dd3366SNeel Natu struct vcpu *vcpu; 135375dd3366SNeel Natu 135475dd3366SNeel Natu vcpu = &vm->vcpu[vcpuid]; 135575dd3366SNeel Natu 1356f76fc5d4SNeel Natu vcpu_lock(vcpu); 135775dd3366SNeel Natu hostcpu = vcpu->hostcpu; 1358f76fc5d4SNeel Natu if (hostcpu == NOCPU) { 1359318224bbSNeel Natu if (vcpu->state == VCPU_SLEEPING) 1360f76fc5d4SNeel Natu wakeup_one(vcpu); 1361f76fc5d4SNeel Natu } else { 1362f76fc5d4SNeel Natu if (vcpu->state != VCPU_RUNNING) 1363f76fc5d4SNeel Natu panic("invalid vcpu state %d", vcpu->state); 1364f76fc5d4SNeel Natu if (hostcpu != curcpu) 136575dd3366SNeel Natu ipi_cpu(hostcpu, vmm_ipinum); 136675dd3366SNeel Natu } 1367f76fc5d4SNeel Natu vcpu_unlock(vcpu); 1368f76fc5d4SNeel Natu } 1369318224bbSNeel Natu 1370318224bbSNeel Natu struct vmspace * 1371318224bbSNeel Natu vm_get_vmspace(struct vm *vm) 1372318224bbSNeel Natu { 1373318224bbSNeel Natu 1374318224bbSNeel Natu return (vm->vmspace); 1375318224bbSNeel Natu } 1376565bbb86SNeel Natu 1377565bbb86SNeel Natu int 1378565bbb86SNeel Natu vm_apicid2vcpuid(struct vm *vm, int apicid) 1379565bbb86SNeel Natu { 1380565bbb86SNeel Natu /* 1381565bbb86SNeel Natu * XXX apic id is assumed to be numerically identical to vcpu id 1382565bbb86SNeel Natu */ 1383565bbb86SNeel Natu return (apicid); 1384565bbb86SNeel Natu } 1385