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> 5834a6b2d6SJohn Baldwin #include <x86/apicreg.h> 59318224bbSNeel Natu #include <machine/vmparam.h> 60366f6083SPeter Grehan 61366f6083SPeter Grehan #include <machine/vmm.h> 62318224bbSNeel Natu #include "vmm_ktr.h" 63b01c2033SNeel Natu #include "vmm_host.h" 64366f6083SPeter Grehan #include "vmm_mem.h" 65366f6083SPeter Grehan #include "vmm_util.h" 66366f6083SPeter Grehan #include <machine/vmm_dev.h> 67366f6083SPeter Grehan #include "vlapic.h" 68366f6083SPeter Grehan #include "vmm_msr.h" 69366f6083SPeter Grehan #include "vmm_ipi.h" 70366f6083SPeter Grehan #include "vmm_stat.h" 71f76fc5d4SNeel Natu #include "vmm_lapic.h" 72366f6083SPeter Grehan 73366f6083SPeter Grehan #include "io/ppt.h" 74366f6083SPeter Grehan #include "io/iommu.h" 75366f6083SPeter Grehan 76366f6083SPeter Grehan struct vlapic; 77366f6083SPeter Grehan 78366f6083SPeter Grehan struct vcpu { 79366f6083SPeter Grehan int flags; 8075dd3366SNeel Natu enum vcpu_state state; 8175dd3366SNeel Natu struct mtx mtx; 82366f6083SPeter Grehan int hostcpu; /* host cpuid this vcpu last ran on */ 83366f6083SPeter Grehan uint64_t guest_msrs[VMM_MSR_NUM]; 84366f6083SPeter Grehan struct vlapic *vlapic; 85366f6083SPeter Grehan int vcpuid; 8638f1b189SPeter Grehan struct savefpu *guestfpu; /* guest fpu state */ 87366f6083SPeter Grehan void *stats; 8898ed632cSNeel Natu struct vm_exit exitinfo; 89e9027382SNeel Natu enum x2apic_state x2apic_state; 90f352ff0cSNeel Natu int nmi_pending; 91366f6083SPeter Grehan }; 92366f6083SPeter Grehan 93f76fc5d4SNeel Natu #define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_SPIN) 94f76fc5d4SNeel Natu #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) 95f76fc5d4SNeel Natu #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) 96318224bbSNeel Natu #define vcpu_assert_locked(v) mtx_assert(&((v)->mtx), MA_OWNED) 9775dd3366SNeel Natu 98318224bbSNeel Natu struct mem_seg { 99318224bbSNeel Natu vm_paddr_t gpa; 100318224bbSNeel Natu size_t len; 101318224bbSNeel Natu boolean_t wired; 102318224bbSNeel Natu vm_object_t object; 103318224bbSNeel Natu }; 104366f6083SPeter Grehan #define VM_MAX_MEMORY_SEGMENTS 2 105366f6083SPeter Grehan 106366f6083SPeter Grehan struct vm { 107366f6083SPeter Grehan void *cookie; /* processor-specific data */ 108366f6083SPeter Grehan void *iommu; /* iommu-specific data */ 109318224bbSNeel Natu struct vmspace *vmspace; /* guest's address space */ 110366f6083SPeter Grehan struct vcpu vcpu[VM_MAXCPU]; 111366f6083SPeter Grehan int num_mem_segs; 112318224bbSNeel Natu struct mem_seg mem_segs[VM_MAX_MEMORY_SEGMENTS]; 113366f6083SPeter Grehan char name[VM_MAX_NAMELEN]; 114366f6083SPeter Grehan 115366f6083SPeter Grehan /* 116a5615c90SPeter Grehan * Set of active vcpus. 117366f6083SPeter Grehan * An active vcpu is one that has been started implicitly (BSP) or 118366f6083SPeter Grehan * explicitly (AP) by sending it a startup ipi. 119366f6083SPeter Grehan */ 120a5615c90SPeter Grehan cpuset_t active_cpus; 121366f6083SPeter Grehan }; 122366f6083SPeter Grehan 123d5408b1dSNeel Natu static int vmm_initialized; 124d5408b1dSNeel Natu 125366f6083SPeter Grehan static struct vmm_ops *ops; 126366f6083SPeter Grehan #define VMM_INIT() (ops != NULL ? (*ops->init)() : 0) 127366f6083SPeter Grehan #define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 128366f6083SPeter Grehan 129318224bbSNeel Natu #define VMINIT(vm, pmap) (ops != NULL ? (*ops->vminit)(vm, pmap): NULL) 130318224bbSNeel Natu #define VMRUN(vmi, vcpu, rip, pmap) \ 131318224bbSNeel Natu (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, pmap) : ENXIO) 132366f6083SPeter Grehan #define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 133318224bbSNeel Natu #define VMSPACE_ALLOC(min, max) \ 134318224bbSNeel Natu (ops != NULL ? (*ops->vmspace_alloc)(min, max) : NULL) 135318224bbSNeel Natu #define VMSPACE_FREE(vmspace) \ 136318224bbSNeel Natu (ops != NULL ? (*ops->vmspace_free)(vmspace) : ENXIO) 137366f6083SPeter Grehan #define VMGETREG(vmi, vcpu, num, retval) \ 138366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 139366f6083SPeter Grehan #define VMSETREG(vmi, vcpu, num, val) \ 140366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 141366f6083SPeter Grehan #define VMGETDESC(vmi, vcpu, num, desc) \ 142366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 143366f6083SPeter Grehan #define VMSETDESC(vmi, vcpu, num, desc) \ 144366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 145366f6083SPeter Grehan #define VMINJECT(vmi, vcpu, type, vec, ec, ecv) \ 146366f6083SPeter Grehan (ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO) 147366f6083SPeter Grehan #define VMGETCAP(vmi, vcpu, num, retval) \ 148366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 149366f6083SPeter Grehan #define VMSETCAP(vmi, vcpu, num, val) \ 150366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 151366f6083SPeter Grehan 152014a52f3SNeel Natu #define fpu_start_emulating() load_cr0(rcr0() | CR0_TS) 153014a52f3SNeel Natu #define fpu_stop_emulating() clts() 154366f6083SPeter Grehan 155366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 156366f6083SPeter Grehan CTASSERT(VMM_MSR_NUM <= 64); /* msr_mask can keep track of up to 64 msrs */ 157366f6083SPeter Grehan 158366f6083SPeter Grehan /* statistics */ 15961592433SNeel Natu static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 160366f6083SPeter Grehan 161366f6083SPeter Grehan static void 162366f6083SPeter Grehan vcpu_cleanup(struct vcpu *vcpu) 163366f6083SPeter Grehan { 164366f6083SPeter Grehan vlapic_cleanup(vcpu->vlapic); 165366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 16638f1b189SPeter Grehan fpu_save_area_free(vcpu->guestfpu); 167366f6083SPeter Grehan } 168366f6083SPeter Grehan 169366f6083SPeter Grehan static void 170366f6083SPeter Grehan vcpu_init(struct vm *vm, uint32_t vcpu_id) 171366f6083SPeter Grehan { 172366f6083SPeter Grehan struct vcpu *vcpu; 173366f6083SPeter Grehan 174366f6083SPeter Grehan vcpu = &vm->vcpu[vcpu_id]; 175366f6083SPeter Grehan 17675dd3366SNeel Natu vcpu_lock_init(vcpu); 17775dd3366SNeel Natu vcpu->hostcpu = NOCPU; 178366f6083SPeter Grehan vcpu->vcpuid = vcpu_id; 179366f6083SPeter Grehan vcpu->vlapic = vlapic_init(vm, vcpu_id); 18073820fb0SNeel Natu vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED); 18138f1b189SPeter Grehan vcpu->guestfpu = fpu_save_area_alloc(); 18238f1b189SPeter Grehan fpu_save_area_reset(vcpu->guestfpu); 183366f6083SPeter Grehan vcpu->stats = vmm_stat_alloc(); 184366f6083SPeter Grehan } 185366f6083SPeter Grehan 18698ed632cSNeel Natu struct vm_exit * 18798ed632cSNeel Natu vm_exitinfo(struct vm *vm, int cpuid) 18898ed632cSNeel Natu { 18998ed632cSNeel Natu struct vcpu *vcpu; 19098ed632cSNeel Natu 19198ed632cSNeel Natu if (cpuid < 0 || cpuid >= VM_MAXCPU) 19298ed632cSNeel Natu panic("vm_exitinfo: invalid cpuid %d", cpuid); 19398ed632cSNeel Natu 19498ed632cSNeel Natu vcpu = &vm->vcpu[cpuid]; 19598ed632cSNeel Natu 19698ed632cSNeel Natu return (&vcpu->exitinfo); 19798ed632cSNeel Natu } 19898ed632cSNeel Natu 199366f6083SPeter Grehan static int 200366f6083SPeter Grehan vmm_init(void) 201366f6083SPeter Grehan { 202366f6083SPeter Grehan int error; 203366f6083SPeter Grehan 204b01c2033SNeel Natu vmm_host_state_init(); 205366f6083SPeter Grehan vmm_ipi_init(); 206366f6083SPeter Grehan 207366f6083SPeter Grehan error = vmm_mem_init(); 208366f6083SPeter Grehan if (error) 209366f6083SPeter Grehan return (error); 210366f6083SPeter Grehan 211366f6083SPeter Grehan if (vmm_is_intel()) 212366f6083SPeter Grehan ops = &vmm_ops_intel; 213366f6083SPeter Grehan else if (vmm_is_amd()) 214366f6083SPeter Grehan ops = &vmm_ops_amd; 215366f6083SPeter Grehan else 216366f6083SPeter Grehan return (ENXIO); 217366f6083SPeter Grehan 218366f6083SPeter Grehan vmm_msr_init(); 219366f6083SPeter Grehan 220366f6083SPeter Grehan return (VMM_INIT()); 221366f6083SPeter Grehan } 222366f6083SPeter Grehan 223366f6083SPeter Grehan static int 224366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 225366f6083SPeter Grehan { 226366f6083SPeter Grehan int error; 227366f6083SPeter Grehan 228366f6083SPeter Grehan switch (what) { 229366f6083SPeter Grehan case MOD_LOAD: 230366f6083SPeter Grehan vmmdev_init(); 231366f6083SPeter Grehan iommu_init(); 232366f6083SPeter Grehan error = vmm_init(); 233d5408b1dSNeel Natu if (error == 0) 234d5408b1dSNeel Natu vmm_initialized = 1; 235366f6083SPeter Grehan break; 236366f6083SPeter Grehan case MOD_UNLOAD: 237cdc5b9e7SNeel Natu error = vmmdev_cleanup(); 238cdc5b9e7SNeel Natu if (error == 0) { 239366f6083SPeter Grehan iommu_cleanup(); 240366f6083SPeter Grehan vmm_ipi_cleanup(); 241366f6083SPeter Grehan error = VMM_CLEANUP(); 24281ef6611SPeter Grehan /* 24381ef6611SPeter Grehan * Something bad happened - prevent new 24481ef6611SPeter Grehan * VMs from being created 24581ef6611SPeter Grehan */ 24681ef6611SPeter Grehan if (error) 247d5408b1dSNeel Natu vmm_initialized = 0; 24881ef6611SPeter Grehan } 249366f6083SPeter Grehan break; 250366f6083SPeter Grehan default: 251366f6083SPeter Grehan error = 0; 252366f6083SPeter Grehan break; 253366f6083SPeter Grehan } 254366f6083SPeter Grehan return (error); 255366f6083SPeter Grehan } 256366f6083SPeter Grehan 257366f6083SPeter Grehan static moduledata_t vmm_kmod = { 258366f6083SPeter Grehan "vmm", 259366f6083SPeter Grehan vmm_handler, 260366f6083SPeter Grehan NULL 261366f6083SPeter Grehan }; 262366f6083SPeter Grehan 263366f6083SPeter Grehan /* 264e3f0800bSNeel Natu * vmm initialization has the following dependencies: 265e3f0800bSNeel Natu * 266e3f0800bSNeel Natu * - iommu initialization must happen after the pci passthru driver has had 267e3f0800bSNeel Natu * a chance to attach to any passthru devices (after SI_SUB_CONFIGURE). 268e3f0800bSNeel Natu * 269e3f0800bSNeel Natu * - VT-x initialization requires smp_rendezvous() and therefore must happen 270e3f0800bSNeel Natu * after SMP is fully functional (after SI_SUB_SMP). 271366f6083SPeter Grehan */ 272e3f0800bSNeel Natu DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_SMP + 1, SI_ORDER_ANY); 273366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 274366f6083SPeter Grehan 275366f6083SPeter Grehan SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 276366f6083SPeter Grehan 277d5408b1dSNeel Natu int 278d5408b1dSNeel Natu vm_create(const char *name, struct vm **retvm) 279366f6083SPeter Grehan { 280366f6083SPeter Grehan int i; 281366f6083SPeter Grehan struct vm *vm; 282318224bbSNeel Natu struct vmspace *vmspace; 283366f6083SPeter Grehan 284366f6083SPeter Grehan const int BSP = 0; 285366f6083SPeter Grehan 286d5408b1dSNeel Natu /* 287d5408b1dSNeel Natu * If vmm.ko could not be successfully initialized then don't attempt 288d5408b1dSNeel Natu * to create the virtual machine. 289d5408b1dSNeel Natu */ 290d5408b1dSNeel Natu if (!vmm_initialized) 291d5408b1dSNeel Natu return (ENXIO); 292d5408b1dSNeel Natu 293366f6083SPeter Grehan if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 294d5408b1dSNeel Natu return (EINVAL); 295366f6083SPeter Grehan 296318224bbSNeel Natu vmspace = VMSPACE_ALLOC(VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS); 297318224bbSNeel Natu if (vmspace == NULL) 298318224bbSNeel Natu return (ENOMEM); 299318224bbSNeel Natu 300366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 301366f6083SPeter Grehan strcpy(vm->name, name); 302318224bbSNeel Natu vm->cookie = VMINIT(vm, vmspace_pmap(vmspace)); 303366f6083SPeter Grehan 304366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) { 305366f6083SPeter Grehan vcpu_init(vm, i); 306366f6083SPeter Grehan guest_msrs_init(vm, i); 307366f6083SPeter Grehan } 308366f6083SPeter Grehan 309366f6083SPeter Grehan vm_activate_cpu(vm, BSP); 310318224bbSNeel Natu vm->vmspace = vmspace; 311366f6083SPeter Grehan 312d5408b1dSNeel Natu *retvm = vm; 313d5408b1dSNeel Natu return (0); 314366f6083SPeter Grehan } 315366f6083SPeter Grehan 316f7d51510SNeel Natu static void 317318224bbSNeel Natu vm_free_mem_seg(struct vm *vm, struct mem_seg *seg) 318f7d51510SNeel Natu { 3197ce04d0aSNeel Natu 320318224bbSNeel Natu if (seg->object != NULL) 321318224bbSNeel Natu vmm_mem_free(vm->vmspace, seg->gpa, seg->len); 322f7d51510SNeel Natu 323318224bbSNeel Natu bzero(seg, sizeof(*seg)); 324f7d51510SNeel Natu } 325f7d51510SNeel Natu 326366f6083SPeter Grehan void 327366f6083SPeter Grehan vm_destroy(struct vm *vm) 328366f6083SPeter Grehan { 329366f6083SPeter Grehan int i; 330366f6083SPeter Grehan 331366f6083SPeter Grehan ppt_unassign_all(vm); 332366f6083SPeter Grehan 333318224bbSNeel Natu if (vm->iommu != NULL) 334318224bbSNeel Natu iommu_destroy_domain(vm->iommu); 335318224bbSNeel Natu 336366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) 337f7d51510SNeel Natu vm_free_mem_seg(vm, &vm->mem_segs[i]); 338f7d51510SNeel Natu 339f7d51510SNeel Natu vm->num_mem_segs = 0; 340366f6083SPeter Grehan 341366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) 342366f6083SPeter Grehan vcpu_cleanup(&vm->vcpu[i]); 343366f6083SPeter Grehan 344318224bbSNeel Natu VMSPACE_FREE(vm->vmspace); 345366f6083SPeter Grehan 346366f6083SPeter Grehan VMCLEANUP(vm->cookie); 347366f6083SPeter Grehan 348366f6083SPeter Grehan free(vm, M_VM); 349366f6083SPeter Grehan } 350366f6083SPeter Grehan 351366f6083SPeter Grehan const char * 352366f6083SPeter Grehan vm_name(struct vm *vm) 353366f6083SPeter Grehan { 354366f6083SPeter Grehan return (vm->name); 355366f6083SPeter Grehan } 356366f6083SPeter Grehan 357366f6083SPeter Grehan int 358366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 359366f6083SPeter Grehan { 360318224bbSNeel Natu vm_object_t obj; 361366f6083SPeter Grehan 362318224bbSNeel Natu if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa)) == NULL) 363318224bbSNeel Natu return (ENOMEM); 364318224bbSNeel Natu else 365318224bbSNeel Natu return (0); 366366f6083SPeter Grehan } 367366f6083SPeter Grehan 368366f6083SPeter Grehan int 369366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 370366f6083SPeter Grehan { 371366f6083SPeter Grehan 372318224bbSNeel Natu vmm_mmio_free(vm->vmspace, gpa, len); 373318224bbSNeel Natu return (0); 374366f6083SPeter Grehan } 375366f6083SPeter Grehan 376318224bbSNeel Natu boolean_t 377318224bbSNeel Natu vm_mem_allocated(struct vm *vm, vm_paddr_t gpa) 378366f6083SPeter Grehan { 379341f19c9SNeel Natu int i; 380341f19c9SNeel Natu vm_paddr_t gpabase, gpalimit; 381341f19c9SNeel Natu 382341f19c9SNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 383341f19c9SNeel Natu gpabase = vm->mem_segs[i].gpa; 384341f19c9SNeel Natu gpalimit = gpabase + vm->mem_segs[i].len; 385341f19c9SNeel Natu if (gpa >= gpabase && gpa < gpalimit) 386318224bbSNeel Natu return (TRUE); /* 'gpa' is regular memory */ 387341f19c9SNeel Natu } 388341f19c9SNeel Natu 389318224bbSNeel Natu if (ppt_is_mmio(vm, gpa)) 390318224bbSNeel Natu return (TRUE); /* 'gpa' is pci passthru mmio */ 391318224bbSNeel Natu 392318224bbSNeel Natu return (FALSE); 393341f19c9SNeel Natu } 394341f19c9SNeel Natu 395341f19c9SNeel Natu int 396341f19c9SNeel Natu vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len) 397341f19c9SNeel Natu { 398318224bbSNeel Natu int available, allocated; 399318224bbSNeel Natu struct mem_seg *seg; 400318224bbSNeel Natu vm_object_t object; 401318224bbSNeel Natu vm_paddr_t g; 402366f6083SPeter Grehan 403341f19c9SNeel Natu if ((gpa & PAGE_MASK) || (len & PAGE_MASK) || len == 0) 404341f19c9SNeel Natu return (EINVAL); 405341f19c9SNeel Natu 406341f19c9SNeel Natu available = allocated = 0; 407341f19c9SNeel Natu g = gpa; 408341f19c9SNeel Natu while (g < gpa + len) { 409318224bbSNeel Natu if (vm_mem_allocated(vm, g)) 410341f19c9SNeel Natu allocated++; 411318224bbSNeel Natu else 412318224bbSNeel Natu available++; 413341f19c9SNeel Natu 414341f19c9SNeel Natu g += PAGE_SIZE; 415341f19c9SNeel Natu } 416341f19c9SNeel Natu 417366f6083SPeter Grehan /* 418341f19c9SNeel Natu * If there are some allocated and some available pages in the address 419341f19c9SNeel Natu * range then it is an error. 420366f6083SPeter Grehan */ 421341f19c9SNeel Natu if (allocated && available) 422341f19c9SNeel Natu return (EINVAL); 423341f19c9SNeel Natu 424341f19c9SNeel Natu /* 425341f19c9SNeel Natu * If the entire address range being requested has already been 426341f19c9SNeel Natu * allocated then there isn't anything more to do. 427341f19c9SNeel Natu */ 428341f19c9SNeel Natu if (allocated && available == 0) 429341f19c9SNeel Natu return (0); 430366f6083SPeter Grehan 431366f6083SPeter Grehan if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS) 432366f6083SPeter Grehan return (E2BIG); 433366f6083SPeter Grehan 434f7d51510SNeel Natu seg = &vm->mem_segs[vm->num_mem_segs]; 435366f6083SPeter Grehan 436318224bbSNeel Natu if ((object = vmm_mem_alloc(vm->vmspace, gpa, len)) == NULL) 437318224bbSNeel Natu return (ENOMEM); 438318224bbSNeel Natu 439f7d51510SNeel Natu seg->gpa = gpa; 440318224bbSNeel Natu seg->len = len; 441318224bbSNeel Natu seg->object = object; 442318224bbSNeel Natu seg->wired = FALSE; 4437ce04d0aSNeel Natu 444366f6083SPeter Grehan vm->num_mem_segs++; 445341f19c9SNeel Natu 446366f6083SPeter Grehan return (0); 447366f6083SPeter Grehan } 448366f6083SPeter Grehan 449318224bbSNeel Natu static void 450318224bbSNeel Natu vm_gpa_unwire(struct vm *vm) 451366f6083SPeter Grehan { 452318224bbSNeel Natu int i, rv; 453318224bbSNeel Natu struct mem_seg *seg; 4544db4fb2cSNeel Natu 455318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 456318224bbSNeel Natu seg = &vm->mem_segs[i]; 457318224bbSNeel Natu if (!seg->wired) 458318224bbSNeel Natu continue; 459366f6083SPeter Grehan 460318224bbSNeel Natu rv = vm_map_unwire(&vm->vmspace->vm_map, 461318224bbSNeel Natu seg->gpa, seg->gpa + seg->len, 462318224bbSNeel Natu VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 463318224bbSNeel Natu KASSERT(rv == KERN_SUCCESS, ("vm(%s) memory segment " 464318224bbSNeel Natu "%#lx/%ld could not be unwired: %d", 465318224bbSNeel Natu vm_name(vm), seg->gpa, seg->len, rv)); 466318224bbSNeel Natu 467318224bbSNeel Natu seg->wired = FALSE; 468318224bbSNeel Natu } 469318224bbSNeel Natu } 470318224bbSNeel Natu 471318224bbSNeel Natu static int 472318224bbSNeel Natu vm_gpa_wire(struct vm *vm) 473318224bbSNeel Natu { 474318224bbSNeel Natu int i, rv; 475318224bbSNeel Natu struct mem_seg *seg; 476318224bbSNeel Natu 477318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 478318224bbSNeel Natu seg = &vm->mem_segs[i]; 479318224bbSNeel Natu if (seg->wired) 480318224bbSNeel Natu continue; 481318224bbSNeel Natu 482318224bbSNeel Natu /* XXX rlimits? */ 483318224bbSNeel Natu rv = vm_map_wire(&vm->vmspace->vm_map, 484318224bbSNeel Natu seg->gpa, seg->gpa + seg->len, 485318224bbSNeel Natu VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 486318224bbSNeel Natu if (rv != KERN_SUCCESS) 487318224bbSNeel Natu break; 488318224bbSNeel Natu 489318224bbSNeel Natu seg->wired = TRUE; 490318224bbSNeel Natu } 491318224bbSNeel Natu 492318224bbSNeel Natu if (i < vm->num_mem_segs) { 493318224bbSNeel Natu /* 494318224bbSNeel Natu * Undo the wiring before returning an error. 495318224bbSNeel Natu */ 496318224bbSNeel Natu vm_gpa_unwire(vm); 497318224bbSNeel Natu return (EAGAIN); 498318224bbSNeel Natu } 499318224bbSNeel Natu 500318224bbSNeel Natu return (0); 501318224bbSNeel Natu } 502318224bbSNeel Natu 503318224bbSNeel Natu static void 504318224bbSNeel Natu vm_iommu_modify(struct vm *vm, boolean_t map) 505318224bbSNeel Natu { 506318224bbSNeel Natu int i, sz; 507318224bbSNeel Natu vm_paddr_t gpa, hpa; 508318224bbSNeel Natu struct mem_seg *seg; 509318224bbSNeel Natu void *vp, *cookie, *host_domain; 510318224bbSNeel Natu 511318224bbSNeel Natu sz = PAGE_SIZE; 512318224bbSNeel Natu host_domain = iommu_host_domain(); 513318224bbSNeel Natu 514318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 515318224bbSNeel Natu seg = &vm->mem_segs[i]; 516318224bbSNeel Natu KASSERT(seg->wired, ("vm(%s) memory segment %#lx/%ld not wired", 517318224bbSNeel Natu vm_name(vm), seg->gpa, seg->len)); 518318224bbSNeel Natu 519318224bbSNeel Natu gpa = seg->gpa; 520318224bbSNeel Natu while (gpa < seg->gpa + seg->len) { 521318224bbSNeel Natu vp = vm_gpa_hold(vm, gpa, PAGE_SIZE, VM_PROT_WRITE, 522318224bbSNeel Natu &cookie); 523318224bbSNeel Natu KASSERT(vp != NULL, ("vm(%s) could not map gpa %#lx", 524318224bbSNeel Natu vm_name(vm), gpa)); 525318224bbSNeel Natu 526318224bbSNeel Natu vm_gpa_release(cookie); 527318224bbSNeel Natu 528318224bbSNeel Natu hpa = DMAP_TO_PHYS((uintptr_t)vp); 529318224bbSNeel Natu if (map) { 530318224bbSNeel Natu iommu_create_mapping(vm->iommu, gpa, hpa, sz); 531318224bbSNeel Natu iommu_remove_mapping(host_domain, hpa, sz); 532318224bbSNeel Natu } else { 533318224bbSNeel Natu iommu_remove_mapping(vm->iommu, gpa, sz); 534318224bbSNeel Natu iommu_create_mapping(host_domain, hpa, hpa, sz); 535318224bbSNeel Natu } 536318224bbSNeel Natu 537318224bbSNeel Natu gpa += PAGE_SIZE; 538318224bbSNeel Natu } 539318224bbSNeel Natu } 540318224bbSNeel Natu 541318224bbSNeel Natu /* 542318224bbSNeel Natu * Invalidate the cached translations associated with the domain 543318224bbSNeel Natu * from which pages were removed. 544318224bbSNeel Natu */ 545318224bbSNeel Natu if (map) 546318224bbSNeel Natu iommu_invalidate_tlb(host_domain); 547318224bbSNeel Natu else 548318224bbSNeel Natu iommu_invalidate_tlb(vm->iommu); 549318224bbSNeel Natu } 550318224bbSNeel Natu 551318224bbSNeel Natu #define vm_iommu_unmap(vm) vm_iommu_modify((vm), FALSE) 552318224bbSNeel Natu #define vm_iommu_map(vm) vm_iommu_modify((vm), TRUE) 553318224bbSNeel Natu 554318224bbSNeel Natu int 555318224bbSNeel Natu vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func) 556318224bbSNeel Natu { 557318224bbSNeel Natu int error; 558318224bbSNeel Natu 559318224bbSNeel Natu error = ppt_unassign_device(vm, bus, slot, func); 560318224bbSNeel Natu if (error) 561318224bbSNeel Natu return (error); 562318224bbSNeel Natu 563318224bbSNeel Natu if (ppt_num_devices(vm) == 0) { 564318224bbSNeel Natu vm_iommu_unmap(vm); 565318224bbSNeel Natu vm_gpa_unwire(vm); 566318224bbSNeel Natu } 567318224bbSNeel Natu return (0); 568318224bbSNeel Natu } 569318224bbSNeel Natu 570318224bbSNeel Natu int 571318224bbSNeel Natu vm_assign_pptdev(struct vm *vm, int bus, int slot, int func) 572318224bbSNeel Natu { 573318224bbSNeel Natu int error; 574318224bbSNeel Natu vm_paddr_t maxaddr; 575318224bbSNeel Natu 576318224bbSNeel Natu /* 577318224bbSNeel Natu * Virtual machines with pci passthru devices get special treatment: 578318224bbSNeel Natu * - the guest physical memory is wired 579318224bbSNeel Natu * - the iommu is programmed to do the 'gpa' to 'hpa' translation 580318224bbSNeel Natu * 581318224bbSNeel Natu * We need to do this before the first pci passthru device is attached. 582318224bbSNeel Natu */ 583318224bbSNeel Natu if (ppt_num_devices(vm) == 0) { 584318224bbSNeel Natu KASSERT(vm->iommu == NULL, 585318224bbSNeel Natu ("vm_assign_pptdev: iommu must be NULL")); 586318224bbSNeel Natu maxaddr = vmm_mem_maxaddr(); 587318224bbSNeel Natu vm->iommu = iommu_create_domain(maxaddr); 588318224bbSNeel Natu 589318224bbSNeel Natu error = vm_gpa_wire(vm); 590318224bbSNeel Natu if (error) 591318224bbSNeel Natu return (error); 592318224bbSNeel Natu 593318224bbSNeel Natu vm_iommu_map(vm); 594318224bbSNeel Natu } 595318224bbSNeel Natu 596318224bbSNeel Natu error = ppt_assign_device(vm, bus, slot, func); 597318224bbSNeel Natu return (error); 598318224bbSNeel Natu } 599318224bbSNeel Natu 600318224bbSNeel Natu void * 601318224bbSNeel Natu vm_gpa_hold(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, 602318224bbSNeel Natu void **cookie) 603318224bbSNeel Natu { 604318224bbSNeel Natu int count, pageoff; 605318224bbSNeel Natu vm_page_t m; 606318224bbSNeel Natu 607318224bbSNeel Natu pageoff = gpa & PAGE_MASK; 608318224bbSNeel Natu if (len > PAGE_SIZE - pageoff) 609318224bbSNeel Natu panic("vm_gpa_hold: invalid gpa/len: 0x%016lx/%lu", gpa, len); 610318224bbSNeel Natu 611318224bbSNeel Natu count = vm_fault_quick_hold_pages(&vm->vmspace->vm_map, 612318224bbSNeel Natu trunc_page(gpa), PAGE_SIZE, reqprot, &m, 1); 613318224bbSNeel Natu 614318224bbSNeel Natu if (count == 1) { 615318224bbSNeel Natu *cookie = m; 616318224bbSNeel Natu return ((void *)(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)) + pageoff)); 617318224bbSNeel Natu } else { 618318224bbSNeel Natu *cookie = NULL; 619318224bbSNeel Natu return (NULL); 620318224bbSNeel Natu } 621318224bbSNeel Natu } 622318224bbSNeel Natu 623318224bbSNeel Natu void 624318224bbSNeel Natu vm_gpa_release(void *cookie) 625318224bbSNeel Natu { 626318224bbSNeel Natu vm_page_t m = cookie; 627318224bbSNeel Natu 628318224bbSNeel Natu vm_page_lock(m); 629318224bbSNeel Natu vm_page_unhold(m); 630318224bbSNeel Natu vm_page_unlock(m); 631366f6083SPeter Grehan } 632366f6083SPeter Grehan 633366f6083SPeter Grehan int 634366f6083SPeter Grehan vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 635366f6083SPeter Grehan struct vm_memory_segment *seg) 636366f6083SPeter Grehan { 637366f6083SPeter Grehan int i; 638366f6083SPeter Grehan 639366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) { 640366f6083SPeter Grehan if (gpabase == vm->mem_segs[i].gpa) { 641318224bbSNeel Natu seg->gpa = vm->mem_segs[i].gpa; 642318224bbSNeel Natu seg->len = vm->mem_segs[i].len; 643318224bbSNeel Natu seg->wired = vm->mem_segs[i].wired; 644366f6083SPeter Grehan return (0); 645366f6083SPeter Grehan } 646366f6083SPeter Grehan } 647366f6083SPeter Grehan return (-1); 648366f6083SPeter Grehan } 649366f6083SPeter Grehan 650366f6083SPeter Grehan int 651318224bbSNeel Natu vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len, 652318224bbSNeel Natu vm_offset_t *offset, struct vm_object **object) 653318224bbSNeel Natu { 654318224bbSNeel Natu int i; 655318224bbSNeel Natu size_t seg_len; 656318224bbSNeel Natu vm_paddr_t seg_gpa; 657318224bbSNeel Natu vm_object_t seg_obj; 658318224bbSNeel Natu 659318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 660318224bbSNeel Natu if ((seg_obj = vm->mem_segs[i].object) == NULL) 661318224bbSNeel Natu continue; 662318224bbSNeel Natu 663318224bbSNeel Natu seg_gpa = vm->mem_segs[i].gpa; 664318224bbSNeel Natu seg_len = vm->mem_segs[i].len; 665318224bbSNeel Natu 666318224bbSNeel Natu if (gpa >= seg_gpa && gpa < seg_gpa + seg_len) { 667318224bbSNeel Natu *offset = gpa - seg_gpa; 668318224bbSNeel Natu *object = seg_obj; 669318224bbSNeel Natu vm_object_reference(seg_obj); 670318224bbSNeel Natu return (0); 671318224bbSNeel Natu } 672318224bbSNeel Natu } 673318224bbSNeel Natu 674318224bbSNeel Natu return (EINVAL); 675318224bbSNeel Natu } 676318224bbSNeel Natu 677318224bbSNeel Natu int 678366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 679366f6083SPeter Grehan { 680366f6083SPeter Grehan 681366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 682366f6083SPeter Grehan return (EINVAL); 683366f6083SPeter Grehan 684366f6083SPeter Grehan if (reg >= VM_REG_LAST) 685366f6083SPeter Grehan return (EINVAL); 686366f6083SPeter Grehan 687366f6083SPeter Grehan return (VMGETREG(vm->cookie, vcpu, reg, retval)); 688366f6083SPeter Grehan } 689366f6083SPeter Grehan 690366f6083SPeter Grehan int 691366f6083SPeter Grehan vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val) 692366f6083SPeter Grehan { 693366f6083SPeter Grehan 694366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 695366f6083SPeter Grehan return (EINVAL); 696366f6083SPeter Grehan 697366f6083SPeter Grehan if (reg >= VM_REG_LAST) 698366f6083SPeter Grehan return (EINVAL); 699366f6083SPeter Grehan 700366f6083SPeter Grehan return (VMSETREG(vm->cookie, vcpu, reg, val)); 701366f6083SPeter Grehan } 702366f6083SPeter Grehan 703366f6083SPeter Grehan static boolean_t 704366f6083SPeter Grehan is_descriptor_table(int reg) 705366f6083SPeter Grehan { 706366f6083SPeter Grehan 707366f6083SPeter Grehan switch (reg) { 708366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 709366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 710366f6083SPeter Grehan return (TRUE); 711366f6083SPeter Grehan default: 712366f6083SPeter Grehan return (FALSE); 713366f6083SPeter Grehan } 714366f6083SPeter Grehan } 715366f6083SPeter Grehan 716366f6083SPeter Grehan static boolean_t 717366f6083SPeter Grehan is_segment_register(int reg) 718366f6083SPeter Grehan { 719366f6083SPeter Grehan 720366f6083SPeter Grehan switch (reg) { 721366f6083SPeter Grehan case VM_REG_GUEST_ES: 722366f6083SPeter Grehan case VM_REG_GUEST_CS: 723366f6083SPeter Grehan case VM_REG_GUEST_SS: 724366f6083SPeter Grehan case VM_REG_GUEST_DS: 725366f6083SPeter Grehan case VM_REG_GUEST_FS: 726366f6083SPeter Grehan case VM_REG_GUEST_GS: 727366f6083SPeter Grehan case VM_REG_GUEST_TR: 728366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 729366f6083SPeter Grehan return (TRUE); 730366f6083SPeter Grehan default: 731366f6083SPeter Grehan return (FALSE); 732366f6083SPeter Grehan } 733366f6083SPeter Grehan } 734366f6083SPeter Grehan 735366f6083SPeter Grehan int 736366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 737366f6083SPeter Grehan struct seg_desc *desc) 738366f6083SPeter Grehan { 739366f6083SPeter Grehan 740366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 741366f6083SPeter Grehan return (EINVAL); 742366f6083SPeter Grehan 743366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 744366f6083SPeter Grehan return (EINVAL); 745366f6083SPeter Grehan 746366f6083SPeter Grehan return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 747366f6083SPeter Grehan } 748366f6083SPeter Grehan 749366f6083SPeter Grehan int 750366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 751366f6083SPeter Grehan struct seg_desc *desc) 752366f6083SPeter Grehan { 753366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 754366f6083SPeter Grehan return (EINVAL); 755366f6083SPeter Grehan 756366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 757366f6083SPeter Grehan return (EINVAL); 758366f6083SPeter Grehan 759366f6083SPeter Grehan return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 760366f6083SPeter Grehan } 761366f6083SPeter Grehan 762366f6083SPeter Grehan static void 763366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 764366f6083SPeter Grehan { 765366f6083SPeter Grehan 76638f1b189SPeter Grehan /* flush host state to the pcb */ 76738f1b189SPeter Grehan fpuexit(curthread); 768bd8572e0SNeel Natu 769bd8572e0SNeel Natu /* restore guest FPU state */ 770366f6083SPeter Grehan fpu_stop_emulating(); 77138f1b189SPeter Grehan fpurestore(vcpu->guestfpu); 772bd8572e0SNeel Natu 773bd8572e0SNeel Natu /* 774bd8572e0SNeel Natu * The FPU is now "dirty" with the guest's state so turn on emulation 775bd8572e0SNeel Natu * to trap any access to the FPU by the host. 776bd8572e0SNeel Natu */ 777bd8572e0SNeel Natu fpu_start_emulating(); 778366f6083SPeter Grehan } 779366f6083SPeter Grehan 780366f6083SPeter Grehan static void 781366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 782366f6083SPeter Grehan { 783366f6083SPeter Grehan 784bd8572e0SNeel Natu if ((rcr0() & CR0_TS) == 0) 785bd8572e0SNeel Natu panic("fpu emulation not enabled in host!"); 786bd8572e0SNeel Natu 787bd8572e0SNeel Natu /* save guest FPU state */ 788bd8572e0SNeel Natu fpu_stop_emulating(); 78938f1b189SPeter Grehan fpusave(vcpu->guestfpu); 790366f6083SPeter Grehan fpu_start_emulating(); 791366f6083SPeter Grehan } 792366f6083SPeter Grehan 79361592433SNeel Natu static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); 794f76fc5d4SNeel Natu 795318224bbSNeel Natu static int 796318224bbSNeel Natu vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) 797366f6083SPeter Grehan { 798318224bbSNeel Natu int error; 799366f6083SPeter Grehan 800318224bbSNeel Natu vcpu_assert_locked(vcpu); 801366f6083SPeter Grehan 802f76fc5d4SNeel Natu /* 803318224bbSNeel Natu * The following state transitions are allowed: 804318224bbSNeel Natu * IDLE -> FROZEN -> IDLE 805318224bbSNeel Natu * FROZEN -> RUNNING -> FROZEN 806318224bbSNeel Natu * FROZEN -> SLEEPING -> FROZEN 807f76fc5d4SNeel Natu */ 808318224bbSNeel Natu switch (vcpu->state) { 809318224bbSNeel Natu case VCPU_IDLE: 810318224bbSNeel Natu case VCPU_RUNNING: 811318224bbSNeel Natu case VCPU_SLEEPING: 812318224bbSNeel Natu error = (newstate != VCPU_FROZEN); 813318224bbSNeel Natu break; 814318224bbSNeel Natu case VCPU_FROZEN: 815318224bbSNeel Natu error = (newstate == VCPU_FROZEN); 816318224bbSNeel Natu break; 817318224bbSNeel Natu default: 818318224bbSNeel Natu error = 1; 819318224bbSNeel Natu break; 820318224bbSNeel Natu } 821318224bbSNeel Natu 822318224bbSNeel Natu if (error == 0) 823318224bbSNeel Natu vcpu->state = newstate; 824318224bbSNeel Natu else 825318224bbSNeel Natu error = EBUSY; 826318224bbSNeel Natu 827318224bbSNeel Natu return (error); 828318224bbSNeel Natu } 829318224bbSNeel Natu 830318224bbSNeel Natu static void 831318224bbSNeel Natu vcpu_require_state(struct vm *vm, int vcpuid, enum vcpu_state newstate) 832318224bbSNeel Natu { 833318224bbSNeel Natu int error; 834318224bbSNeel Natu 835318224bbSNeel Natu if ((error = vcpu_set_state(vm, vcpuid, newstate)) != 0) 836318224bbSNeel Natu panic("Error %d setting state to %d\n", error, newstate); 837318224bbSNeel Natu } 838318224bbSNeel Natu 839318224bbSNeel Natu static void 840318224bbSNeel Natu vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) 841318224bbSNeel Natu { 842318224bbSNeel Natu int error; 843318224bbSNeel Natu 844318224bbSNeel Natu if ((error = vcpu_set_state_locked(vcpu, newstate)) != 0) 845318224bbSNeel Natu panic("Error %d setting state to %d", error, newstate); 846318224bbSNeel Natu } 847318224bbSNeel Natu 848318224bbSNeel Natu /* 849318224bbSNeel Natu * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run. 850318224bbSNeel Natu */ 851318224bbSNeel Natu static int 852318224bbSNeel Natu vm_handle_hlt(struct vm *vm, int vcpuid, boolean_t *retu) 853318224bbSNeel Natu { 854318224bbSNeel Natu struct vcpu *vcpu; 855318224bbSNeel Natu int sleepticks, t; 856318224bbSNeel Natu 857318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 858318224bbSNeel Natu 859f76fc5d4SNeel Natu vcpu_lock(vcpu); 860f76fc5d4SNeel Natu 861f76fc5d4SNeel Natu /* 862f76fc5d4SNeel Natu * Figure out the number of host ticks until the next apic 863f76fc5d4SNeel Natu * timer interrupt in the guest. 864f76fc5d4SNeel Natu */ 865f76fc5d4SNeel Natu sleepticks = lapic_timer_tick(vm, vcpuid); 866f76fc5d4SNeel Natu 867f76fc5d4SNeel Natu /* 868f76fc5d4SNeel Natu * If the guest local apic timer is disabled then sleep for 869f76fc5d4SNeel Natu * a long time but not forever. 870f76fc5d4SNeel Natu */ 871f76fc5d4SNeel Natu if (sleepticks < 0) 872f76fc5d4SNeel Natu sleepticks = hz; 873f76fc5d4SNeel Natu 874f76fc5d4SNeel Natu /* 875f76fc5d4SNeel Natu * Do a final check for pending NMI or interrupts before 876f76fc5d4SNeel Natu * really putting this thread to sleep. 877f76fc5d4SNeel Natu * 878f76fc5d4SNeel Natu * These interrupts could have happened any time after we 879f76fc5d4SNeel Natu * returned from VMRUN() and before we grabbed the vcpu lock. 880f76fc5d4SNeel Natu */ 881318224bbSNeel Natu if (!vm_nmi_pending(vm, vcpuid) && lapic_pending_intr(vm, vcpuid) < 0) { 882f76fc5d4SNeel Natu if (sleepticks <= 0) 883f76fc5d4SNeel Natu panic("invalid sleepticks %d", sleepticks); 884f76fc5d4SNeel Natu t = ticks; 885318224bbSNeel Natu vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 886f76fc5d4SNeel Natu msleep_spin(vcpu, &vcpu->mtx, "vmidle", sleepticks); 887318224bbSNeel Natu vcpu_require_state_locked(vcpu, VCPU_FROZEN); 888f76fc5d4SNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t); 889f76fc5d4SNeel Natu } 890f76fc5d4SNeel Natu vcpu_unlock(vcpu); 891f76fc5d4SNeel Natu 892318224bbSNeel Natu return (0); 893318224bbSNeel Natu } 894318224bbSNeel Natu 895318224bbSNeel Natu static int 896318224bbSNeel Natu vm_handle_paging(struct vm *vm, int vcpuid, boolean_t *retu) 897318224bbSNeel Natu { 898318224bbSNeel Natu int rv, ftype; 899318224bbSNeel Natu struct vm_map *map; 900318224bbSNeel Natu struct vcpu *vcpu; 901318224bbSNeel Natu struct vm_exit *vme; 902318224bbSNeel Natu 903318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 904318224bbSNeel Natu vme = &vcpu->exitinfo; 905318224bbSNeel Natu 906318224bbSNeel Natu ftype = vme->u.paging.fault_type; 907318224bbSNeel Natu KASSERT(ftype == VM_PROT_READ || 908318224bbSNeel Natu ftype == VM_PROT_WRITE || ftype == VM_PROT_EXECUTE, 909318224bbSNeel Natu ("vm_handle_paging: invalid fault_type %d", ftype)); 910318224bbSNeel Natu 911318224bbSNeel Natu if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { 912318224bbSNeel Natu rv = pmap_emulate_accessed_dirty(vmspace_pmap(vm->vmspace), 913318224bbSNeel Natu vme->u.paging.gpa, ftype); 914318224bbSNeel Natu if (rv == 0) 915318224bbSNeel Natu goto done; 916318224bbSNeel Natu } 917318224bbSNeel Natu 918318224bbSNeel Natu map = &vm->vmspace->vm_map; 919318224bbSNeel Natu rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL); 920318224bbSNeel Natu 921*513c8d33SNeel Natu VCPU_CTR3(vm, vcpuid, "vm_handle_paging rv = %d, gpa = %#lx, " 922*513c8d33SNeel Natu "ftype = %d", rv, vme->u.paging.gpa, ftype); 923318224bbSNeel Natu 924318224bbSNeel Natu if (rv != KERN_SUCCESS) 925318224bbSNeel Natu return (EFAULT); 926318224bbSNeel Natu done: 927318224bbSNeel Natu /* restart execution at the faulting instruction */ 928318224bbSNeel Natu vme->inst_length = 0; 929318224bbSNeel Natu 930318224bbSNeel Natu return (0); 931318224bbSNeel Natu } 932318224bbSNeel Natu 933318224bbSNeel Natu static int 934318224bbSNeel Natu vm_handle_inst_emul(struct vm *vm, int vcpuid, boolean_t *retu) 935318224bbSNeel Natu { 936318224bbSNeel Natu struct vie *vie; 937318224bbSNeel Natu struct vcpu *vcpu; 938318224bbSNeel Natu struct vm_exit *vme; 939318224bbSNeel Natu int error, inst_length; 940318224bbSNeel Natu uint64_t rip, gla, gpa, cr3; 941318224bbSNeel Natu 942318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 943318224bbSNeel Natu vme = &vcpu->exitinfo; 944318224bbSNeel Natu 945318224bbSNeel Natu rip = vme->rip; 946318224bbSNeel Natu inst_length = vme->inst_length; 947318224bbSNeel Natu 948318224bbSNeel Natu gla = vme->u.inst_emul.gla; 949318224bbSNeel Natu gpa = vme->u.inst_emul.gpa; 950318224bbSNeel Natu cr3 = vme->u.inst_emul.cr3; 951318224bbSNeel Natu vie = &vme->u.inst_emul.vie; 952318224bbSNeel Natu 953318224bbSNeel Natu vie_init(vie); 954318224bbSNeel Natu 955318224bbSNeel Natu /* Fetch, decode and emulate the faulting instruction */ 956318224bbSNeel Natu if (vmm_fetch_instruction(vm, vcpuid, rip, inst_length, cr3, vie) != 0) 957318224bbSNeel Natu return (EFAULT); 958318224bbSNeel Natu 959318224bbSNeel Natu if (vmm_decode_instruction(vm, vcpuid, gla, vie) != 0) 960318224bbSNeel Natu return (EFAULT); 961318224bbSNeel Natu 962318224bbSNeel Natu /* return to userland unless this is a local apic access */ 963318224bbSNeel Natu if (gpa < DEFAULT_APIC_BASE || gpa >= DEFAULT_APIC_BASE + PAGE_SIZE) { 964318224bbSNeel Natu *retu = TRUE; 965318224bbSNeel Natu return (0); 966318224bbSNeel Natu } 967318224bbSNeel Natu 968318224bbSNeel Natu error = vmm_emulate_instruction(vm, vcpuid, gpa, vie, 969318224bbSNeel Natu lapic_mmio_read, lapic_mmio_write, 0); 970318224bbSNeel Natu 971318224bbSNeel Natu /* return to userland to spin up the AP */ 972318224bbSNeel Natu if (error == 0 && vme->exitcode == VM_EXITCODE_SPINUP_AP) 973318224bbSNeel Natu *retu = TRUE; 974318224bbSNeel Natu 975318224bbSNeel Natu return (error); 976318224bbSNeel Natu } 977318224bbSNeel Natu 978318224bbSNeel Natu int 979318224bbSNeel Natu vm_run(struct vm *vm, struct vm_run *vmrun) 980318224bbSNeel Natu { 981318224bbSNeel Natu int error, vcpuid; 982318224bbSNeel Natu struct vcpu *vcpu; 983318224bbSNeel Natu struct pcb *pcb; 984318224bbSNeel Natu uint64_t tscval, rip; 985318224bbSNeel Natu struct vm_exit *vme; 986318224bbSNeel Natu boolean_t retu; 987318224bbSNeel Natu pmap_t pmap; 988318224bbSNeel Natu 989318224bbSNeel Natu vcpuid = vmrun->cpuid; 990318224bbSNeel Natu 991318224bbSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 992318224bbSNeel Natu return (EINVAL); 993318224bbSNeel Natu 994318224bbSNeel Natu pmap = vmspace_pmap(vm->vmspace); 995318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 996318224bbSNeel Natu vme = &vcpu->exitinfo; 997318224bbSNeel Natu rip = vmrun->rip; 998318224bbSNeel Natu restart: 999318224bbSNeel Natu critical_enter(); 1000318224bbSNeel Natu 1001318224bbSNeel Natu KASSERT(!CPU_ISSET(curcpu, &pmap->pm_active), 1002318224bbSNeel Natu ("vm_run: absurd pm_active")); 1003318224bbSNeel Natu 1004318224bbSNeel Natu tscval = rdtsc(); 1005318224bbSNeel Natu 1006318224bbSNeel Natu pcb = PCPU_GET(curpcb); 1007318224bbSNeel Natu set_pcb_flags(pcb, PCB_FULL_IRET); 1008318224bbSNeel Natu 1009318224bbSNeel Natu restore_guest_msrs(vm, vcpuid); 1010318224bbSNeel Natu restore_guest_fpustate(vcpu); 1011318224bbSNeel Natu 1012318224bbSNeel Natu vcpu_require_state(vm, vcpuid, VCPU_RUNNING); 1013318224bbSNeel Natu vcpu->hostcpu = curcpu; 1014318224bbSNeel Natu error = VMRUN(vm->cookie, vcpuid, rip, pmap); 1015318224bbSNeel Natu vcpu->hostcpu = NOCPU; 1016318224bbSNeel Natu vcpu_require_state(vm, vcpuid, VCPU_FROZEN); 1017318224bbSNeel Natu 1018318224bbSNeel Natu save_guest_fpustate(vcpu); 1019318224bbSNeel Natu restore_host_msrs(vm, vcpuid); 1020318224bbSNeel Natu 1021318224bbSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 1022318224bbSNeel Natu 1023318224bbSNeel Natu critical_exit(); 1024318224bbSNeel Natu 1025318224bbSNeel Natu if (error == 0) { 1026318224bbSNeel Natu retu = FALSE; 1027318224bbSNeel Natu switch (vme->exitcode) { 1028318224bbSNeel Natu case VM_EXITCODE_HLT: 1029318224bbSNeel Natu error = vm_handle_hlt(vm, vcpuid, &retu); 1030318224bbSNeel Natu break; 1031318224bbSNeel Natu case VM_EXITCODE_PAGING: 1032318224bbSNeel Natu error = vm_handle_paging(vm, vcpuid, &retu); 1033318224bbSNeel Natu break; 1034318224bbSNeel Natu case VM_EXITCODE_INST_EMUL: 1035318224bbSNeel Natu error = vm_handle_inst_emul(vm, vcpuid, &retu); 1036318224bbSNeel Natu break; 1037318224bbSNeel Natu default: 1038318224bbSNeel Natu retu = TRUE; /* handled in userland */ 1039318224bbSNeel Natu break; 1040318224bbSNeel Natu } 1041318224bbSNeel Natu } 1042318224bbSNeel Natu 1043318224bbSNeel Natu if (error == 0 && retu == FALSE) { 1044f76fc5d4SNeel Natu rip = vme->rip + vme->inst_length; 1045f76fc5d4SNeel Natu goto restart; 1046f76fc5d4SNeel Natu } 1047f76fc5d4SNeel Natu 1048318224bbSNeel Natu /* copy the exit information */ 1049318224bbSNeel Natu bcopy(vme, &vmrun->vm_exit, sizeof(struct vm_exit)); 1050366f6083SPeter Grehan return (error); 1051366f6083SPeter Grehan } 1052366f6083SPeter Grehan 1053366f6083SPeter Grehan int 1054366f6083SPeter Grehan vm_inject_event(struct vm *vm, int vcpuid, int type, 1055366f6083SPeter Grehan int vector, uint32_t code, int code_valid) 1056366f6083SPeter Grehan { 1057366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1058366f6083SPeter Grehan return (EINVAL); 1059366f6083SPeter Grehan 1060366f6083SPeter Grehan if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0) 1061366f6083SPeter Grehan return (EINVAL); 1062366f6083SPeter Grehan 1063366f6083SPeter Grehan if (vector < 0 || vector > 255) 1064366f6083SPeter Grehan return (EINVAL); 1065366f6083SPeter Grehan 1066366f6083SPeter Grehan return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid)); 1067366f6083SPeter Grehan } 1068366f6083SPeter Grehan 106961592433SNeel Natu static VMM_STAT(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); 1070366f6083SPeter Grehan 1071f352ff0cSNeel Natu int 1072f352ff0cSNeel Natu vm_inject_nmi(struct vm *vm, int vcpuid) 1073f352ff0cSNeel Natu { 1074f352ff0cSNeel Natu struct vcpu *vcpu; 1075f352ff0cSNeel Natu 1076f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1077366f6083SPeter Grehan return (EINVAL); 1078366f6083SPeter Grehan 1079f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1080f352ff0cSNeel Natu 1081f352ff0cSNeel Natu vcpu->nmi_pending = 1; 1082f352ff0cSNeel Natu vm_interrupt_hostcpu(vm, vcpuid); 1083f352ff0cSNeel Natu return (0); 1084f352ff0cSNeel Natu } 1085f352ff0cSNeel Natu 1086f352ff0cSNeel Natu int 1087f352ff0cSNeel Natu vm_nmi_pending(struct vm *vm, int vcpuid) 1088f352ff0cSNeel Natu { 1089f352ff0cSNeel Natu struct vcpu *vcpu; 1090f352ff0cSNeel Natu 1091f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1092f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 1093f352ff0cSNeel Natu 1094f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1095f352ff0cSNeel Natu 1096f352ff0cSNeel Natu return (vcpu->nmi_pending); 1097f352ff0cSNeel Natu } 1098f352ff0cSNeel Natu 1099f352ff0cSNeel Natu void 1100f352ff0cSNeel Natu vm_nmi_clear(struct vm *vm, int vcpuid) 1101f352ff0cSNeel Natu { 1102f352ff0cSNeel Natu struct vcpu *vcpu; 1103f352ff0cSNeel Natu 1104f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1105f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 1106f352ff0cSNeel Natu 1107f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1108f352ff0cSNeel Natu 1109f352ff0cSNeel Natu if (vcpu->nmi_pending == 0) 1110f352ff0cSNeel Natu panic("vm_nmi_clear: inconsistent nmi_pending state"); 1111f352ff0cSNeel Natu 1112f352ff0cSNeel Natu vcpu->nmi_pending = 0; 1113f352ff0cSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1); 1114366f6083SPeter Grehan } 1115366f6083SPeter Grehan 1116366f6083SPeter Grehan int 1117366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 1118366f6083SPeter Grehan { 1119366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 1120366f6083SPeter Grehan return (EINVAL); 1121366f6083SPeter Grehan 1122366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 1123366f6083SPeter Grehan return (EINVAL); 1124366f6083SPeter Grehan 1125366f6083SPeter Grehan return (VMGETCAP(vm->cookie, vcpu, type, retval)); 1126366f6083SPeter Grehan } 1127366f6083SPeter Grehan 1128366f6083SPeter Grehan int 1129366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val) 1130366f6083SPeter Grehan { 1131366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 1132366f6083SPeter Grehan return (EINVAL); 1133366f6083SPeter Grehan 1134366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 1135366f6083SPeter Grehan return (EINVAL); 1136366f6083SPeter Grehan 1137366f6083SPeter Grehan return (VMSETCAP(vm->cookie, vcpu, type, val)); 1138366f6083SPeter Grehan } 1139366f6083SPeter Grehan 1140366f6083SPeter Grehan uint64_t * 1141366f6083SPeter Grehan vm_guest_msrs(struct vm *vm, int cpu) 1142366f6083SPeter Grehan { 1143366f6083SPeter Grehan return (vm->vcpu[cpu].guest_msrs); 1144366f6083SPeter Grehan } 1145366f6083SPeter Grehan 1146366f6083SPeter Grehan struct vlapic * 1147366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu) 1148366f6083SPeter Grehan { 1149366f6083SPeter Grehan return (vm->vcpu[cpu].vlapic); 1150366f6083SPeter Grehan } 1151366f6083SPeter Grehan 1152366f6083SPeter Grehan boolean_t 1153366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 1154366f6083SPeter Grehan { 115507044a96SNeel Natu int found, i, n; 115607044a96SNeel Natu int b, s, f; 1157366f6083SPeter Grehan char *val, *cp, *cp2; 1158366f6083SPeter Grehan 1159366f6083SPeter Grehan /* 116007044a96SNeel Natu * XXX 116107044a96SNeel Natu * The length of an environment variable is limited to 128 bytes which 116207044a96SNeel Natu * puts an upper limit on the number of passthru devices that may be 116307044a96SNeel Natu * specified using a single environment variable. 116407044a96SNeel Natu * 116507044a96SNeel Natu * Work around this by scanning multiple environment variable 116607044a96SNeel Natu * names instead of a single one - yuck! 1167366f6083SPeter Grehan */ 116807044a96SNeel Natu const char *names[] = { "pptdevs", "pptdevs2", "pptdevs3", NULL }; 116907044a96SNeel Natu 117007044a96SNeel Natu /* set pptdevs="1/2/3 4/5/6 7/8/9 10/11/12" */ 1171366f6083SPeter Grehan found = 0; 117207044a96SNeel Natu for (i = 0; names[i] != NULL && !found; i++) { 117307044a96SNeel Natu cp = val = getenv(names[i]); 1174366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 1175366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 1176366f6083SPeter Grehan *cp2 = '\0'; 1177366f6083SPeter Grehan 1178366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 1179366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 1180366f6083SPeter Grehan found = 1; 1181366f6083SPeter Grehan break; 1182366f6083SPeter Grehan } 1183366f6083SPeter Grehan 1184366f6083SPeter Grehan if (cp2 != NULL) 1185366f6083SPeter Grehan *cp2++ = ' '; 1186366f6083SPeter Grehan 1187366f6083SPeter Grehan cp = cp2; 1188366f6083SPeter Grehan } 1189366f6083SPeter Grehan freeenv(val); 119007044a96SNeel Natu } 1191366f6083SPeter Grehan return (found); 1192366f6083SPeter Grehan } 1193366f6083SPeter Grehan 1194366f6083SPeter Grehan void * 1195366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 1196366f6083SPeter Grehan { 1197366f6083SPeter Grehan 1198366f6083SPeter Grehan return (vm->iommu); 1199366f6083SPeter Grehan } 1200366f6083SPeter Grehan 120175dd3366SNeel Natu int 1202318224bbSNeel Natu vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state newstate) 1203366f6083SPeter Grehan { 120475dd3366SNeel Natu int error; 1205366f6083SPeter Grehan struct vcpu *vcpu; 1206366f6083SPeter Grehan 1207366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1208366f6083SPeter Grehan panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 1209366f6083SPeter Grehan 1210366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 1211366f6083SPeter Grehan 121275dd3366SNeel Natu vcpu_lock(vcpu); 1213318224bbSNeel Natu error = vcpu_set_state_locked(vcpu, newstate); 121475dd3366SNeel Natu vcpu_unlock(vcpu); 121575dd3366SNeel Natu 121675dd3366SNeel Natu return (error); 121775dd3366SNeel Natu } 121875dd3366SNeel Natu 121975dd3366SNeel Natu enum vcpu_state 1220d3c11f40SPeter Grehan vcpu_get_state(struct vm *vm, int vcpuid, int *hostcpu) 1221366f6083SPeter Grehan { 1222366f6083SPeter Grehan struct vcpu *vcpu; 122375dd3366SNeel Natu enum vcpu_state state; 1224366f6083SPeter Grehan 1225366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1226366f6083SPeter Grehan panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 1227366f6083SPeter Grehan 1228366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 1229366f6083SPeter Grehan 123075dd3366SNeel Natu vcpu_lock(vcpu); 123175dd3366SNeel Natu state = vcpu->state; 1232d3c11f40SPeter Grehan if (hostcpu != NULL) 1233d3c11f40SPeter Grehan *hostcpu = vcpu->hostcpu; 123475dd3366SNeel Natu vcpu_unlock(vcpu); 1235366f6083SPeter Grehan 123675dd3366SNeel Natu return (state); 1237366f6083SPeter Grehan } 1238366f6083SPeter Grehan 1239366f6083SPeter Grehan void 1240366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid) 1241366f6083SPeter Grehan { 1242366f6083SPeter Grehan 1243366f6083SPeter Grehan if (vcpuid >= 0 && vcpuid < VM_MAXCPU) 1244a5615c90SPeter Grehan CPU_SET(vcpuid, &vm->active_cpus); 1245366f6083SPeter Grehan } 1246366f6083SPeter Grehan 1247a5615c90SPeter Grehan cpuset_t 1248366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 1249366f6083SPeter Grehan { 1250366f6083SPeter Grehan 1251366f6083SPeter Grehan return (vm->active_cpus); 1252366f6083SPeter Grehan } 1253366f6083SPeter Grehan 1254366f6083SPeter Grehan void * 1255366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid) 1256366f6083SPeter Grehan { 1257366f6083SPeter Grehan 1258366f6083SPeter Grehan return (vm->vcpu[vcpuid].stats); 1259366f6083SPeter Grehan } 1260e9027382SNeel Natu 1261e9027382SNeel Natu int 1262e9027382SNeel Natu vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) 1263e9027382SNeel Natu { 1264e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1265e9027382SNeel Natu return (EINVAL); 1266e9027382SNeel Natu 1267e9027382SNeel Natu *state = vm->vcpu[vcpuid].x2apic_state; 1268e9027382SNeel Natu 1269e9027382SNeel Natu return (0); 1270e9027382SNeel Natu } 1271e9027382SNeel Natu 1272e9027382SNeel Natu int 1273e9027382SNeel Natu vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 1274e9027382SNeel Natu { 1275e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1276e9027382SNeel Natu return (EINVAL); 1277e9027382SNeel Natu 12783f23d3caSNeel Natu if (state >= X2APIC_STATE_LAST) 1279e9027382SNeel Natu return (EINVAL); 1280e9027382SNeel Natu 1281e9027382SNeel Natu vm->vcpu[vcpuid].x2apic_state = state; 1282e9027382SNeel Natu 128373820fb0SNeel Natu vlapic_set_x2apic_state(vm, vcpuid, state); 128473820fb0SNeel Natu 1285e9027382SNeel Natu return (0); 1286e9027382SNeel Natu } 128775dd3366SNeel Natu 128875dd3366SNeel Natu void 128975dd3366SNeel Natu vm_interrupt_hostcpu(struct vm *vm, int vcpuid) 129075dd3366SNeel Natu { 129175dd3366SNeel Natu int hostcpu; 129275dd3366SNeel Natu struct vcpu *vcpu; 129375dd3366SNeel Natu 129475dd3366SNeel Natu vcpu = &vm->vcpu[vcpuid]; 129575dd3366SNeel Natu 1296f76fc5d4SNeel Natu vcpu_lock(vcpu); 129775dd3366SNeel Natu hostcpu = vcpu->hostcpu; 1298f76fc5d4SNeel Natu if (hostcpu == NOCPU) { 1299318224bbSNeel Natu if (vcpu->state == VCPU_SLEEPING) 1300f76fc5d4SNeel Natu wakeup_one(vcpu); 1301f76fc5d4SNeel Natu } else { 1302f76fc5d4SNeel Natu if (vcpu->state != VCPU_RUNNING) 1303f76fc5d4SNeel Natu panic("invalid vcpu state %d", vcpu->state); 1304f76fc5d4SNeel Natu if (hostcpu != curcpu) 130575dd3366SNeel Natu ipi_cpu(hostcpu, vmm_ipinum); 130675dd3366SNeel Natu } 1307f76fc5d4SNeel Natu vcpu_unlock(vcpu); 1308f76fc5d4SNeel Natu } 1309318224bbSNeel Natu 1310318224bbSNeel Natu struct vmspace * 1311318224bbSNeel Natu vm_get_vmspace(struct vm *vm) 1312318224bbSNeel Natu { 1313318224bbSNeel Natu 1314318224bbSNeel Natu return (vm->vmspace); 1315318224bbSNeel Natu } 1316