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> 42366f6083SPeter Grehan #include <sys/sched.h> 43366f6083SPeter Grehan #include <sys/smp.h> 44366f6083SPeter Grehan #include <sys/systm.h> 45366f6083SPeter Grehan 46366f6083SPeter Grehan #include <vm/vm.h> 47366f6083SPeter Grehan 48366f6083SPeter Grehan #include <machine/vm.h> 49366f6083SPeter Grehan #include <machine/pcb.h> 5075dd3366SNeel Natu #include <machine/smp.h> 5134a6b2d6SJohn Baldwin #include <x86/apicreg.h> 52366f6083SPeter Grehan 53366f6083SPeter Grehan #include <machine/vmm.h> 54b01c2033SNeel Natu #include "vmm_host.h" 55366f6083SPeter Grehan #include "vmm_mem.h" 56366f6083SPeter Grehan #include "vmm_util.h" 57366f6083SPeter Grehan #include <machine/vmm_dev.h> 58366f6083SPeter Grehan #include "vlapic.h" 59366f6083SPeter Grehan #include "vmm_msr.h" 60366f6083SPeter Grehan #include "vmm_ipi.h" 61366f6083SPeter Grehan #include "vmm_stat.h" 62f76fc5d4SNeel Natu #include "vmm_lapic.h" 63366f6083SPeter Grehan 64366f6083SPeter Grehan #include "io/ppt.h" 65366f6083SPeter Grehan #include "io/iommu.h" 66366f6083SPeter Grehan 67366f6083SPeter Grehan struct vlapic; 68366f6083SPeter Grehan 69366f6083SPeter Grehan struct vcpu { 70366f6083SPeter Grehan int flags; 7175dd3366SNeel Natu enum vcpu_state state; 7275dd3366SNeel Natu struct mtx mtx; 73366f6083SPeter Grehan int hostcpu; /* host cpuid this vcpu last ran on */ 74366f6083SPeter Grehan uint64_t guest_msrs[VMM_MSR_NUM]; 75366f6083SPeter Grehan struct vlapic *vlapic; 76366f6083SPeter Grehan int vcpuid; 7738f1b189SPeter Grehan struct savefpu *guestfpu; /* guest fpu state */ 78366f6083SPeter Grehan void *stats; 7998ed632cSNeel Natu struct vm_exit exitinfo; 80e9027382SNeel Natu enum x2apic_state x2apic_state; 81f352ff0cSNeel Natu int nmi_pending; 82366f6083SPeter Grehan }; 83366f6083SPeter Grehan 84f76fc5d4SNeel Natu #define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_SPIN) 85f76fc5d4SNeel Natu #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) 86f76fc5d4SNeel Natu #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) 8775dd3366SNeel Natu 88366f6083SPeter Grehan #define VM_MAX_MEMORY_SEGMENTS 2 89366f6083SPeter Grehan 90366f6083SPeter Grehan struct vm { 91366f6083SPeter Grehan void *cookie; /* processor-specific data */ 92366f6083SPeter Grehan void *iommu; /* iommu-specific data */ 93366f6083SPeter Grehan struct vcpu vcpu[VM_MAXCPU]; 94366f6083SPeter Grehan int num_mem_segs; 95366f6083SPeter Grehan struct vm_memory_segment mem_segs[VM_MAX_MEMORY_SEGMENTS]; 96366f6083SPeter Grehan char name[VM_MAX_NAMELEN]; 97366f6083SPeter Grehan 98366f6083SPeter Grehan /* 99a5615c90SPeter Grehan * Set of active vcpus. 100366f6083SPeter Grehan * An active vcpu is one that has been started implicitly (BSP) or 101366f6083SPeter Grehan * explicitly (AP) by sending it a startup ipi. 102366f6083SPeter Grehan */ 103a5615c90SPeter Grehan cpuset_t active_cpus; 104366f6083SPeter Grehan }; 105366f6083SPeter Grehan 106366f6083SPeter Grehan static struct vmm_ops *ops; 107366f6083SPeter Grehan #define VMM_INIT() (ops != NULL ? (*ops->init)() : 0) 108366f6083SPeter Grehan #define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 109366f6083SPeter Grehan 110366f6083SPeter Grehan #define VMINIT(vm) (ops != NULL ? (*ops->vminit)(vm): NULL) 11198ed632cSNeel Natu #define VMRUN(vmi, vcpu, rip) \ 11298ed632cSNeel Natu (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip) : ENXIO) 113366f6083SPeter Grehan #define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 114bda273f2SNeel Natu #define VMMMAP_SET(vmi, gpa, hpa, len, attr, prot, spm) \ 115bda273f2SNeel Natu (ops != NULL ? \ 116bda273f2SNeel Natu (*ops->vmmmap_set)(vmi, gpa, hpa, len, attr, prot, spm) : \ 117bda273f2SNeel Natu ENXIO) 118bda273f2SNeel Natu #define VMMMAP_GET(vmi, gpa) \ 119bda273f2SNeel Natu (ops != NULL ? (*ops->vmmmap_get)(vmi, gpa) : ENXIO) 120366f6083SPeter Grehan #define VMGETREG(vmi, vcpu, num, retval) \ 121366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 122366f6083SPeter Grehan #define VMSETREG(vmi, vcpu, num, val) \ 123366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 124366f6083SPeter Grehan #define VMGETDESC(vmi, vcpu, num, desc) \ 125366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 126366f6083SPeter Grehan #define VMSETDESC(vmi, vcpu, num, desc) \ 127366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 128366f6083SPeter Grehan #define VMINJECT(vmi, vcpu, type, vec, ec, ecv) \ 129366f6083SPeter Grehan (ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO) 130366f6083SPeter Grehan #define VMGETCAP(vmi, vcpu, num, retval) \ 131366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 132366f6083SPeter Grehan #define VMSETCAP(vmi, vcpu, num, val) \ 133366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 134366f6083SPeter Grehan 135014a52f3SNeel Natu #define fpu_start_emulating() load_cr0(rcr0() | CR0_TS) 136014a52f3SNeel Natu #define fpu_stop_emulating() clts() 137366f6083SPeter Grehan 138366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 139366f6083SPeter Grehan CTASSERT(VMM_MSR_NUM <= 64); /* msr_mask can keep track of up to 64 msrs */ 140366f6083SPeter Grehan 141366f6083SPeter Grehan /* statistics */ 142*61592433SNeel Natu static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 143366f6083SPeter Grehan 144366f6083SPeter Grehan static void 145366f6083SPeter Grehan vcpu_cleanup(struct vcpu *vcpu) 146366f6083SPeter Grehan { 147366f6083SPeter Grehan vlapic_cleanup(vcpu->vlapic); 148366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 14938f1b189SPeter Grehan fpu_save_area_free(vcpu->guestfpu); 150366f6083SPeter Grehan } 151366f6083SPeter Grehan 152366f6083SPeter Grehan static void 153366f6083SPeter Grehan vcpu_init(struct vm *vm, uint32_t vcpu_id) 154366f6083SPeter Grehan { 155366f6083SPeter Grehan struct vcpu *vcpu; 156366f6083SPeter Grehan 157366f6083SPeter Grehan vcpu = &vm->vcpu[vcpu_id]; 158366f6083SPeter Grehan 15975dd3366SNeel Natu vcpu_lock_init(vcpu); 16075dd3366SNeel Natu vcpu->hostcpu = NOCPU; 161366f6083SPeter Grehan vcpu->vcpuid = vcpu_id; 162366f6083SPeter Grehan vcpu->vlapic = vlapic_init(vm, vcpu_id); 16373820fb0SNeel Natu vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED); 16438f1b189SPeter Grehan vcpu->guestfpu = fpu_save_area_alloc(); 16538f1b189SPeter Grehan fpu_save_area_reset(vcpu->guestfpu); 166366f6083SPeter Grehan vcpu->stats = vmm_stat_alloc(); 167366f6083SPeter Grehan } 168366f6083SPeter Grehan 16998ed632cSNeel Natu struct vm_exit * 17098ed632cSNeel Natu vm_exitinfo(struct vm *vm, int cpuid) 17198ed632cSNeel Natu { 17298ed632cSNeel Natu struct vcpu *vcpu; 17398ed632cSNeel Natu 17498ed632cSNeel Natu if (cpuid < 0 || cpuid >= VM_MAXCPU) 17598ed632cSNeel Natu panic("vm_exitinfo: invalid cpuid %d", cpuid); 17698ed632cSNeel Natu 17798ed632cSNeel Natu vcpu = &vm->vcpu[cpuid]; 17898ed632cSNeel Natu 17998ed632cSNeel Natu return (&vcpu->exitinfo); 18098ed632cSNeel Natu } 18198ed632cSNeel Natu 182366f6083SPeter Grehan static int 183366f6083SPeter Grehan vmm_init(void) 184366f6083SPeter Grehan { 185366f6083SPeter Grehan int error; 186366f6083SPeter Grehan 187b01c2033SNeel Natu vmm_host_state_init(); 188366f6083SPeter Grehan vmm_ipi_init(); 189366f6083SPeter Grehan 190366f6083SPeter Grehan error = vmm_mem_init(); 191366f6083SPeter Grehan if (error) 192366f6083SPeter Grehan return (error); 193366f6083SPeter Grehan 194366f6083SPeter Grehan if (vmm_is_intel()) 195366f6083SPeter Grehan ops = &vmm_ops_intel; 196366f6083SPeter Grehan else if (vmm_is_amd()) 197366f6083SPeter Grehan ops = &vmm_ops_amd; 198366f6083SPeter Grehan else 199366f6083SPeter Grehan return (ENXIO); 200366f6083SPeter Grehan 201366f6083SPeter Grehan vmm_msr_init(); 202366f6083SPeter Grehan 203366f6083SPeter Grehan return (VMM_INIT()); 204366f6083SPeter Grehan } 205366f6083SPeter Grehan 206366f6083SPeter Grehan static int 207366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 208366f6083SPeter Grehan { 209366f6083SPeter Grehan int error; 210366f6083SPeter Grehan 211366f6083SPeter Grehan switch (what) { 212366f6083SPeter Grehan case MOD_LOAD: 213366f6083SPeter Grehan vmmdev_init(); 214366f6083SPeter Grehan iommu_init(); 215366f6083SPeter Grehan error = vmm_init(); 216366f6083SPeter Grehan break; 217366f6083SPeter Grehan case MOD_UNLOAD: 218cdc5b9e7SNeel Natu error = vmmdev_cleanup(); 219cdc5b9e7SNeel Natu if (error == 0) { 220366f6083SPeter Grehan iommu_cleanup(); 221366f6083SPeter Grehan vmm_ipi_cleanup(); 222366f6083SPeter Grehan error = VMM_CLEANUP(); 223cdc5b9e7SNeel Natu } 224366f6083SPeter Grehan break; 225366f6083SPeter Grehan default: 226366f6083SPeter Grehan error = 0; 227366f6083SPeter Grehan break; 228366f6083SPeter Grehan } 229366f6083SPeter Grehan return (error); 230366f6083SPeter Grehan } 231366f6083SPeter Grehan 232366f6083SPeter Grehan static moduledata_t vmm_kmod = { 233366f6083SPeter Grehan "vmm", 234366f6083SPeter Grehan vmm_handler, 235366f6083SPeter Grehan NULL 236366f6083SPeter Grehan }; 237366f6083SPeter Grehan 238366f6083SPeter Grehan /* 239e3f0800bSNeel Natu * vmm initialization has the following dependencies: 240e3f0800bSNeel Natu * 241e3f0800bSNeel Natu * - iommu initialization must happen after the pci passthru driver has had 242e3f0800bSNeel Natu * a chance to attach to any passthru devices (after SI_SUB_CONFIGURE). 243e3f0800bSNeel Natu * 244e3f0800bSNeel Natu * - VT-x initialization requires smp_rendezvous() and therefore must happen 245e3f0800bSNeel Natu * after SMP is fully functional (after SI_SUB_SMP). 246366f6083SPeter Grehan */ 247e3f0800bSNeel Natu DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_SMP + 1, SI_ORDER_ANY); 248366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 249366f6083SPeter Grehan 250366f6083SPeter Grehan SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 251366f6083SPeter Grehan 252366f6083SPeter Grehan struct vm * 253366f6083SPeter Grehan vm_create(const char *name) 254366f6083SPeter Grehan { 255366f6083SPeter Grehan int i; 256366f6083SPeter Grehan struct vm *vm; 257366f6083SPeter Grehan vm_paddr_t maxaddr; 258366f6083SPeter Grehan 259366f6083SPeter Grehan const int BSP = 0; 260366f6083SPeter Grehan 261366f6083SPeter Grehan if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 262366f6083SPeter Grehan return (NULL); 263366f6083SPeter Grehan 264366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 265366f6083SPeter Grehan strcpy(vm->name, name); 266366f6083SPeter Grehan vm->cookie = VMINIT(vm); 267366f6083SPeter Grehan 268366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) { 269366f6083SPeter Grehan vcpu_init(vm, i); 270366f6083SPeter Grehan guest_msrs_init(vm, i); 271366f6083SPeter Grehan } 272366f6083SPeter Grehan 273366f6083SPeter Grehan maxaddr = vmm_mem_maxaddr(); 274366f6083SPeter Grehan vm->iommu = iommu_create_domain(maxaddr); 275366f6083SPeter Grehan vm_activate_cpu(vm, BSP); 276366f6083SPeter Grehan 277366f6083SPeter Grehan return (vm); 278366f6083SPeter Grehan } 279366f6083SPeter Grehan 280f7d51510SNeel Natu static void 281f7d51510SNeel Natu vm_free_mem_seg(struct vm *vm, struct vm_memory_segment *seg) 282f7d51510SNeel Natu { 283f7d51510SNeel Natu size_t len; 284f7d51510SNeel Natu vm_paddr_t hpa; 2857ce04d0aSNeel Natu void *host_domain; 2867ce04d0aSNeel Natu 2877ce04d0aSNeel Natu host_domain = iommu_host_domain(); 288f7d51510SNeel Natu 289f7d51510SNeel Natu len = 0; 290f7d51510SNeel Natu while (len < seg->len) { 291f7d51510SNeel Natu hpa = vm_gpa2hpa(vm, seg->gpa + len, PAGE_SIZE); 292f7d51510SNeel Natu if (hpa == (vm_paddr_t)-1) { 293f7d51510SNeel Natu panic("vm_free_mem_segs: cannot free hpa " 294f7d51510SNeel Natu "associated with gpa 0x%016lx", seg->gpa + len); 295f7d51510SNeel Natu } 296f7d51510SNeel Natu 2977ce04d0aSNeel Natu /* 2987ce04d0aSNeel Natu * Remove the 'gpa' to 'hpa' mapping in VMs domain. 2997ce04d0aSNeel Natu * And resurrect the 1:1 mapping for 'hpa' in 'host_domain'. 3007ce04d0aSNeel Natu */ 3017ce04d0aSNeel Natu iommu_remove_mapping(vm->iommu, seg->gpa + len, PAGE_SIZE); 3027ce04d0aSNeel Natu iommu_create_mapping(host_domain, hpa, hpa, PAGE_SIZE); 3037ce04d0aSNeel Natu 304f7d51510SNeel Natu vmm_mem_free(hpa, PAGE_SIZE); 305f7d51510SNeel Natu 306f7d51510SNeel Natu len += PAGE_SIZE; 307f7d51510SNeel Natu } 308f7d51510SNeel Natu 3097ce04d0aSNeel Natu /* 3107ce04d0aSNeel Natu * Invalidate cached translations associated with 'vm->iommu' since 3117ce04d0aSNeel Natu * we have now moved some pages from it. 3127ce04d0aSNeel Natu */ 3137ce04d0aSNeel Natu iommu_invalidate_tlb(vm->iommu); 3147ce04d0aSNeel Natu 315f7d51510SNeel Natu bzero(seg, sizeof(struct vm_memory_segment)); 316f7d51510SNeel Natu } 317f7d51510SNeel Natu 318366f6083SPeter Grehan void 319366f6083SPeter Grehan vm_destroy(struct vm *vm) 320366f6083SPeter Grehan { 321366f6083SPeter Grehan int i; 322366f6083SPeter Grehan 323366f6083SPeter Grehan ppt_unassign_all(vm); 324366f6083SPeter Grehan 325366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) 326f7d51510SNeel Natu vm_free_mem_seg(vm, &vm->mem_segs[i]); 327f7d51510SNeel Natu 328f7d51510SNeel Natu vm->num_mem_segs = 0; 329366f6083SPeter Grehan 330366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) 331366f6083SPeter Grehan vcpu_cleanup(&vm->vcpu[i]); 332366f6083SPeter Grehan 333366f6083SPeter Grehan iommu_destroy_domain(vm->iommu); 334366f6083SPeter Grehan 335366f6083SPeter Grehan VMCLEANUP(vm->cookie); 336366f6083SPeter Grehan 337366f6083SPeter Grehan free(vm, M_VM); 338366f6083SPeter Grehan } 339366f6083SPeter Grehan 340366f6083SPeter Grehan const char * 341366f6083SPeter Grehan vm_name(struct vm *vm) 342366f6083SPeter Grehan { 343366f6083SPeter Grehan return (vm->name); 344366f6083SPeter Grehan } 345366f6083SPeter Grehan 346366f6083SPeter Grehan int 347366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 348366f6083SPeter Grehan { 349366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 350366f6083SPeter Grehan 351bda273f2SNeel Natu return (VMMMAP_SET(vm->cookie, gpa, hpa, len, VM_MEMATTR_UNCACHEABLE, 352366f6083SPeter Grehan VM_PROT_RW, spok)); 353366f6083SPeter Grehan } 354366f6083SPeter Grehan 355366f6083SPeter Grehan int 356366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 357366f6083SPeter Grehan { 358366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 359366f6083SPeter Grehan 360bda273f2SNeel Natu return (VMMMAP_SET(vm->cookie, gpa, 0, len, 0, 361366f6083SPeter Grehan VM_PROT_NONE, spok)); 362366f6083SPeter Grehan } 363366f6083SPeter Grehan 364341f19c9SNeel Natu /* 365341f19c9SNeel Natu * Returns TRUE if 'gpa' is available for allocation and FALSE otherwise 366341f19c9SNeel Natu */ 367341f19c9SNeel Natu static boolean_t 368341f19c9SNeel Natu vm_gpa_available(struct vm *vm, vm_paddr_t gpa) 369366f6083SPeter Grehan { 370341f19c9SNeel Natu int i; 371341f19c9SNeel Natu vm_paddr_t gpabase, gpalimit; 372341f19c9SNeel Natu 373341f19c9SNeel Natu if (gpa & PAGE_MASK) 374341f19c9SNeel Natu panic("vm_gpa_available: gpa (0x%016lx) not page aligned", gpa); 375341f19c9SNeel Natu 376341f19c9SNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 377341f19c9SNeel Natu gpabase = vm->mem_segs[i].gpa; 378341f19c9SNeel Natu gpalimit = gpabase + vm->mem_segs[i].len; 379341f19c9SNeel Natu if (gpa >= gpabase && gpa < gpalimit) 380341f19c9SNeel Natu return (FALSE); 381341f19c9SNeel Natu } 382341f19c9SNeel Natu 383341f19c9SNeel Natu return (TRUE); 384341f19c9SNeel Natu } 385341f19c9SNeel Natu 386341f19c9SNeel Natu int 387341f19c9SNeel Natu vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len) 388341f19c9SNeel Natu { 389341f19c9SNeel Natu int error, available, allocated; 390f7d51510SNeel Natu struct vm_memory_segment *seg; 391341f19c9SNeel Natu vm_paddr_t g, hpa; 3927ce04d0aSNeel Natu void *host_domain; 393366f6083SPeter Grehan 394366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 395366f6083SPeter Grehan 396341f19c9SNeel Natu if ((gpa & PAGE_MASK) || (len & PAGE_MASK) || len == 0) 397341f19c9SNeel Natu return (EINVAL); 398341f19c9SNeel Natu 399341f19c9SNeel Natu available = allocated = 0; 400341f19c9SNeel Natu g = gpa; 401341f19c9SNeel Natu while (g < gpa + len) { 402341f19c9SNeel Natu if (vm_gpa_available(vm, g)) 403341f19c9SNeel Natu available++; 404341f19c9SNeel Natu else 405341f19c9SNeel Natu allocated++; 406341f19c9SNeel Natu 407341f19c9SNeel Natu g += PAGE_SIZE; 408341f19c9SNeel Natu } 409341f19c9SNeel Natu 410366f6083SPeter Grehan /* 411341f19c9SNeel Natu * If there are some allocated and some available pages in the address 412341f19c9SNeel Natu * range then it is an error. 413366f6083SPeter Grehan */ 414341f19c9SNeel Natu if (allocated && available) 415341f19c9SNeel Natu return (EINVAL); 416341f19c9SNeel Natu 417341f19c9SNeel Natu /* 418341f19c9SNeel Natu * If the entire address range being requested has already been 419341f19c9SNeel Natu * allocated then there isn't anything more to do. 420341f19c9SNeel Natu */ 421341f19c9SNeel Natu if (allocated && available == 0) 422341f19c9SNeel Natu return (0); 423366f6083SPeter Grehan 424366f6083SPeter Grehan if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS) 425366f6083SPeter Grehan return (E2BIG); 426366f6083SPeter Grehan 4277ce04d0aSNeel Natu host_domain = iommu_host_domain(); 4287ce04d0aSNeel Natu 429f7d51510SNeel Natu seg = &vm->mem_segs[vm->num_mem_segs]; 430366f6083SPeter Grehan 4317ce04d0aSNeel Natu error = 0; 432f7d51510SNeel Natu seg->gpa = gpa; 433f7d51510SNeel Natu seg->len = 0; 434f7d51510SNeel Natu while (seg->len < len) { 435f7d51510SNeel Natu hpa = vmm_mem_alloc(PAGE_SIZE); 436f7d51510SNeel Natu if (hpa == 0) { 437f7d51510SNeel Natu error = ENOMEM; 438f7d51510SNeel Natu break; 439f7d51510SNeel Natu } 440f7d51510SNeel Natu 441f7d51510SNeel Natu error = VMMMAP_SET(vm->cookie, gpa + seg->len, hpa, PAGE_SIZE, 442f7d51510SNeel Natu VM_MEMATTR_WRITE_BACK, VM_PROT_ALL, spok); 443f7d51510SNeel Natu if (error) 444f7d51510SNeel Natu break; 445f7d51510SNeel Natu 4467ce04d0aSNeel Natu /* 4477ce04d0aSNeel Natu * Remove the 1:1 mapping for 'hpa' from the 'host_domain'. 4487ce04d0aSNeel Natu * Add mapping for 'gpa + seg->len' to 'hpa' in the VMs domain. 4497ce04d0aSNeel Natu */ 4507ce04d0aSNeel Natu iommu_remove_mapping(host_domain, hpa, PAGE_SIZE); 451f7d51510SNeel Natu iommu_create_mapping(vm->iommu, gpa + seg->len, hpa, PAGE_SIZE); 452f7d51510SNeel Natu 453f7d51510SNeel Natu seg->len += PAGE_SIZE; 454f7d51510SNeel Natu } 455f7d51510SNeel Natu 4567ce04d0aSNeel Natu if (error) { 457f7d51510SNeel Natu vm_free_mem_seg(vm, seg); 458366f6083SPeter Grehan return (error); 459366f6083SPeter Grehan } 460366f6083SPeter Grehan 4617ce04d0aSNeel Natu /* 4627ce04d0aSNeel Natu * Invalidate cached translations associated with 'host_domain' since 4637ce04d0aSNeel Natu * we have now moved some pages from it. 4647ce04d0aSNeel Natu */ 4657ce04d0aSNeel Natu iommu_invalidate_tlb(host_domain); 4667ce04d0aSNeel Natu 467366f6083SPeter Grehan vm->num_mem_segs++; 468341f19c9SNeel Natu 469366f6083SPeter Grehan return (0); 470366f6083SPeter Grehan } 471366f6083SPeter Grehan 472366f6083SPeter Grehan vm_paddr_t 473366f6083SPeter Grehan vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t len) 474366f6083SPeter Grehan { 4754db4fb2cSNeel Natu vm_paddr_t nextpage; 4764db4fb2cSNeel Natu 4774db4fb2cSNeel Natu nextpage = rounddown(gpa + PAGE_SIZE, PAGE_SIZE); 4784db4fb2cSNeel Natu if (len > nextpage - gpa) 4794db4fb2cSNeel Natu panic("vm_gpa2hpa: invalid gpa/len: 0x%016lx/%lu", gpa, len); 480366f6083SPeter Grehan 481bda273f2SNeel Natu return (VMMMAP_GET(vm->cookie, gpa)); 482366f6083SPeter Grehan } 483366f6083SPeter Grehan 484366f6083SPeter Grehan int 485366f6083SPeter Grehan vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 486366f6083SPeter Grehan struct vm_memory_segment *seg) 487366f6083SPeter Grehan { 488366f6083SPeter Grehan int i; 489366f6083SPeter Grehan 490366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) { 491366f6083SPeter Grehan if (gpabase == vm->mem_segs[i].gpa) { 492366f6083SPeter Grehan *seg = vm->mem_segs[i]; 493366f6083SPeter Grehan return (0); 494366f6083SPeter Grehan } 495366f6083SPeter Grehan } 496366f6083SPeter Grehan return (-1); 497366f6083SPeter Grehan } 498366f6083SPeter Grehan 499366f6083SPeter Grehan int 500366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 501366f6083SPeter Grehan { 502366f6083SPeter Grehan 503366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 504366f6083SPeter Grehan return (EINVAL); 505366f6083SPeter Grehan 506366f6083SPeter Grehan if (reg >= VM_REG_LAST) 507366f6083SPeter Grehan return (EINVAL); 508366f6083SPeter Grehan 509366f6083SPeter Grehan return (VMGETREG(vm->cookie, vcpu, reg, retval)); 510366f6083SPeter Grehan } 511366f6083SPeter Grehan 512366f6083SPeter Grehan int 513366f6083SPeter Grehan vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val) 514366f6083SPeter Grehan { 515366f6083SPeter Grehan 516366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 517366f6083SPeter Grehan return (EINVAL); 518366f6083SPeter Grehan 519366f6083SPeter Grehan if (reg >= VM_REG_LAST) 520366f6083SPeter Grehan return (EINVAL); 521366f6083SPeter Grehan 522366f6083SPeter Grehan return (VMSETREG(vm->cookie, vcpu, reg, val)); 523366f6083SPeter Grehan } 524366f6083SPeter Grehan 525366f6083SPeter Grehan static boolean_t 526366f6083SPeter Grehan is_descriptor_table(int reg) 527366f6083SPeter Grehan { 528366f6083SPeter Grehan 529366f6083SPeter Grehan switch (reg) { 530366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 531366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 532366f6083SPeter Grehan return (TRUE); 533366f6083SPeter Grehan default: 534366f6083SPeter Grehan return (FALSE); 535366f6083SPeter Grehan } 536366f6083SPeter Grehan } 537366f6083SPeter Grehan 538366f6083SPeter Grehan static boolean_t 539366f6083SPeter Grehan is_segment_register(int reg) 540366f6083SPeter Grehan { 541366f6083SPeter Grehan 542366f6083SPeter Grehan switch (reg) { 543366f6083SPeter Grehan case VM_REG_GUEST_ES: 544366f6083SPeter Grehan case VM_REG_GUEST_CS: 545366f6083SPeter Grehan case VM_REG_GUEST_SS: 546366f6083SPeter Grehan case VM_REG_GUEST_DS: 547366f6083SPeter Grehan case VM_REG_GUEST_FS: 548366f6083SPeter Grehan case VM_REG_GUEST_GS: 549366f6083SPeter Grehan case VM_REG_GUEST_TR: 550366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 551366f6083SPeter Grehan return (TRUE); 552366f6083SPeter Grehan default: 553366f6083SPeter Grehan return (FALSE); 554366f6083SPeter Grehan } 555366f6083SPeter Grehan } 556366f6083SPeter Grehan 557366f6083SPeter Grehan int 558366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 559366f6083SPeter Grehan struct seg_desc *desc) 560366f6083SPeter Grehan { 561366f6083SPeter Grehan 562366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 563366f6083SPeter Grehan return (EINVAL); 564366f6083SPeter Grehan 565366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 566366f6083SPeter Grehan return (EINVAL); 567366f6083SPeter Grehan 568366f6083SPeter Grehan return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 569366f6083SPeter Grehan } 570366f6083SPeter Grehan 571366f6083SPeter Grehan int 572366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 573366f6083SPeter Grehan struct seg_desc *desc) 574366f6083SPeter Grehan { 575366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 576366f6083SPeter Grehan return (EINVAL); 577366f6083SPeter Grehan 578366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 579366f6083SPeter Grehan return (EINVAL); 580366f6083SPeter Grehan 581366f6083SPeter Grehan return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 582366f6083SPeter Grehan } 583366f6083SPeter Grehan 584366f6083SPeter Grehan static void 585366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 586366f6083SPeter Grehan { 587366f6083SPeter Grehan 58838f1b189SPeter Grehan /* flush host state to the pcb */ 58938f1b189SPeter Grehan fpuexit(curthread); 590bd8572e0SNeel Natu 591bd8572e0SNeel Natu /* restore guest FPU state */ 592366f6083SPeter Grehan fpu_stop_emulating(); 59338f1b189SPeter Grehan fpurestore(vcpu->guestfpu); 594bd8572e0SNeel Natu 595bd8572e0SNeel Natu /* 596bd8572e0SNeel Natu * The FPU is now "dirty" with the guest's state so turn on emulation 597bd8572e0SNeel Natu * to trap any access to the FPU by the host. 598bd8572e0SNeel Natu */ 599bd8572e0SNeel Natu fpu_start_emulating(); 600366f6083SPeter Grehan } 601366f6083SPeter Grehan 602366f6083SPeter Grehan static void 603366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 604366f6083SPeter Grehan { 605366f6083SPeter Grehan 606bd8572e0SNeel Natu if ((rcr0() & CR0_TS) == 0) 607bd8572e0SNeel Natu panic("fpu emulation not enabled in host!"); 608bd8572e0SNeel Natu 609bd8572e0SNeel Natu /* save guest FPU state */ 610bd8572e0SNeel Natu fpu_stop_emulating(); 61138f1b189SPeter Grehan fpusave(vcpu->guestfpu); 612366f6083SPeter Grehan fpu_start_emulating(); 613366f6083SPeter Grehan } 614366f6083SPeter Grehan 615*61592433SNeel Natu static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); 616f76fc5d4SNeel Natu 617366f6083SPeter Grehan int 618366f6083SPeter Grehan vm_run(struct vm *vm, struct vm_run *vmrun) 619366f6083SPeter Grehan { 620f76fc5d4SNeel Natu int error, vcpuid, sleepticks, t; 621366f6083SPeter Grehan struct vcpu *vcpu; 622366f6083SPeter Grehan struct pcb *pcb; 623f76fc5d4SNeel Natu uint64_t tscval, rip; 624f76fc5d4SNeel Natu struct vm_exit *vme; 625366f6083SPeter Grehan 626366f6083SPeter Grehan vcpuid = vmrun->cpuid; 627366f6083SPeter Grehan 628366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 629366f6083SPeter Grehan return (EINVAL); 630366f6083SPeter Grehan 631366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 632f76fc5d4SNeel Natu vme = &vmrun->vm_exit; 633f76fc5d4SNeel Natu rip = vmrun->rip; 634f76fc5d4SNeel Natu restart: 635366f6083SPeter Grehan critical_enter(); 636366f6083SPeter Grehan 637366f6083SPeter Grehan tscval = rdtsc(); 638366f6083SPeter Grehan 639366f6083SPeter Grehan pcb = PCPU_GET(curpcb); 64034a6b2d6SJohn Baldwin set_pcb_flags(pcb, PCB_FULL_IRET); 641366f6083SPeter Grehan 642366f6083SPeter Grehan restore_guest_msrs(vm, vcpuid); 643366f6083SPeter Grehan restore_guest_fpustate(vcpu); 64475dd3366SNeel Natu 64575dd3366SNeel Natu vcpu->hostcpu = curcpu; 646f76fc5d4SNeel Natu error = VMRUN(vm->cookie, vcpuid, rip); 64775dd3366SNeel Natu vcpu->hostcpu = NOCPU; 64875dd3366SNeel Natu 649366f6083SPeter Grehan save_guest_fpustate(vcpu); 650366f6083SPeter Grehan restore_host_msrs(vm, vcpuid); 651366f6083SPeter Grehan 652366f6083SPeter Grehan vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 653366f6083SPeter Grehan 65498ed632cSNeel Natu /* copy the exit information */ 655f76fc5d4SNeel Natu bcopy(&vcpu->exitinfo, vme, sizeof(struct vm_exit)); 65698ed632cSNeel Natu 657366f6083SPeter Grehan critical_exit(); 658366f6083SPeter Grehan 659f76fc5d4SNeel Natu /* 660f76fc5d4SNeel Natu * Oblige the guest's desire to 'hlt' by sleeping until the vcpu 661f76fc5d4SNeel Natu * is ready to run. 662f76fc5d4SNeel Natu */ 663f76fc5d4SNeel Natu if (error == 0 && vme->exitcode == VM_EXITCODE_HLT) { 664f76fc5d4SNeel Natu vcpu_lock(vcpu); 665f76fc5d4SNeel Natu 666f76fc5d4SNeel Natu /* 667f76fc5d4SNeel Natu * Figure out the number of host ticks until the next apic 668f76fc5d4SNeel Natu * timer interrupt in the guest. 669f76fc5d4SNeel Natu */ 670f76fc5d4SNeel Natu sleepticks = lapic_timer_tick(vm, vcpuid); 671f76fc5d4SNeel Natu 672f76fc5d4SNeel Natu /* 673f76fc5d4SNeel Natu * If the guest local apic timer is disabled then sleep for 674f76fc5d4SNeel Natu * a long time but not forever. 675f76fc5d4SNeel Natu */ 676f76fc5d4SNeel Natu if (sleepticks < 0) 677f76fc5d4SNeel Natu sleepticks = hz; 678f76fc5d4SNeel Natu 679f76fc5d4SNeel Natu /* 680f76fc5d4SNeel Natu * Do a final check for pending NMI or interrupts before 681f76fc5d4SNeel Natu * really putting this thread to sleep. 682f76fc5d4SNeel Natu * 683f76fc5d4SNeel Natu * These interrupts could have happened any time after we 684f76fc5d4SNeel Natu * returned from VMRUN() and before we grabbed the vcpu lock. 685f76fc5d4SNeel Natu */ 686f76fc5d4SNeel Natu if (!vm_nmi_pending(vm, vcpuid) && 687f76fc5d4SNeel Natu lapic_pending_intr(vm, vcpuid) < 0) { 688f76fc5d4SNeel Natu if (sleepticks <= 0) 689f76fc5d4SNeel Natu panic("invalid sleepticks %d", sleepticks); 690f76fc5d4SNeel Natu t = ticks; 691f76fc5d4SNeel Natu msleep_spin(vcpu, &vcpu->mtx, "vmidle", sleepticks); 692f76fc5d4SNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t); 693f76fc5d4SNeel Natu } 694f76fc5d4SNeel Natu 695f76fc5d4SNeel Natu vcpu_unlock(vcpu); 696f76fc5d4SNeel Natu 697f76fc5d4SNeel Natu rip = vme->rip + vme->inst_length; 698f76fc5d4SNeel Natu goto restart; 699f76fc5d4SNeel Natu } 700f76fc5d4SNeel Natu 701366f6083SPeter Grehan return (error); 702366f6083SPeter Grehan } 703366f6083SPeter Grehan 704366f6083SPeter Grehan int 705366f6083SPeter Grehan vm_inject_event(struct vm *vm, int vcpuid, int type, 706366f6083SPeter Grehan int vector, uint32_t code, int code_valid) 707366f6083SPeter Grehan { 708366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 709366f6083SPeter Grehan return (EINVAL); 710366f6083SPeter Grehan 711366f6083SPeter Grehan if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0) 712366f6083SPeter Grehan return (EINVAL); 713366f6083SPeter Grehan 714366f6083SPeter Grehan if (vector < 0 || vector > 255) 715366f6083SPeter Grehan return (EINVAL); 716366f6083SPeter Grehan 717366f6083SPeter Grehan return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid)); 718366f6083SPeter Grehan } 719366f6083SPeter Grehan 720*61592433SNeel Natu static VMM_STAT(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); 721366f6083SPeter Grehan 722f352ff0cSNeel Natu int 723f352ff0cSNeel Natu vm_inject_nmi(struct vm *vm, int vcpuid) 724f352ff0cSNeel Natu { 725f352ff0cSNeel Natu struct vcpu *vcpu; 726f352ff0cSNeel Natu 727f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 728366f6083SPeter Grehan return (EINVAL); 729366f6083SPeter Grehan 730f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 731f352ff0cSNeel Natu 732f352ff0cSNeel Natu vcpu->nmi_pending = 1; 733f352ff0cSNeel Natu vm_interrupt_hostcpu(vm, vcpuid); 734f352ff0cSNeel Natu return (0); 735f352ff0cSNeel Natu } 736f352ff0cSNeel Natu 737f352ff0cSNeel Natu int 738f352ff0cSNeel Natu vm_nmi_pending(struct vm *vm, int vcpuid) 739f352ff0cSNeel Natu { 740f352ff0cSNeel Natu struct vcpu *vcpu; 741f352ff0cSNeel Natu 742f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 743f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 744f352ff0cSNeel Natu 745f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 746f352ff0cSNeel Natu 747f352ff0cSNeel Natu return (vcpu->nmi_pending); 748f352ff0cSNeel Natu } 749f352ff0cSNeel Natu 750f352ff0cSNeel Natu void 751f352ff0cSNeel Natu vm_nmi_clear(struct vm *vm, int vcpuid) 752f352ff0cSNeel Natu { 753f352ff0cSNeel Natu struct vcpu *vcpu; 754f352ff0cSNeel Natu 755f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 756f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 757f352ff0cSNeel Natu 758f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 759f352ff0cSNeel Natu 760f352ff0cSNeel Natu if (vcpu->nmi_pending == 0) 761f352ff0cSNeel Natu panic("vm_nmi_clear: inconsistent nmi_pending state"); 762f352ff0cSNeel Natu 763f352ff0cSNeel Natu vcpu->nmi_pending = 0; 764f352ff0cSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1); 765366f6083SPeter Grehan } 766366f6083SPeter Grehan 767366f6083SPeter Grehan int 768366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 769366f6083SPeter Grehan { 770366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 771366f6083SPeter Grehan return (EINVAL); 772366f6083SPeter Grehan 773366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 774366f6083SPeter Grehan return (EINVAL); 775366f6083SPeter Grehan 776366f6083SPeter Grehan return (VMGETCAP(vm->cookie, vcpu, type, retval)); 777366f6083SPeter Grehan } 778366f6083SPeter Grehan 779366f6083SPeter Grehan int 780366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val) 781366f6083SPeter Grehan { 782366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 783366f6083SPeter Grehan return (EINVAL); 784366f6083SPeter Grehan 785366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 786366f6083SPeter Grehan return (EINVAL); 787366f6083SPeter Grehan 788366f6083SPeter Grehan return (VMSETCAP(vm->cookie, vcpu, type, val)); 789366f6083SPeter Grehan } 790366f6083SPeter Grehan 791366f6083SPeter Grehan uint64_t * 792366f6083SPeter Grehan vm_guest_msrs(struct vm *vm, int cpu) 793366f6083SPeter Grehan { 794366f6083SPeter Grehan return (vm->vcpu[cpu].guest_msrs); 795366f6083SPeter Grehan } 796366f6083SPeter Grehan 797366f6083SPeter Grehan struct vlapic * 798366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu) 799366f6083SPeter Grehan { 800366f6083SPeter Grehan return (vm->vcpu[cpu].vlapic); 801366f6083SPeter Grehan } 802366f6083SPeter Grehan 803366f6083SPeter Grehan boolean_t 804366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 805366f6083SPeter Grehan { 80607044a96SNeel Natu int found, i, n; 80707044a96SNeel Natu int b, s, f; 808366f6083SPeter Grehan char *val, *cp, *cp2; 809366f6083SPeter Grehan 810366f6083SPeter Grehan /* 81107044a96SNeel Natu * XXX 81207044a96SNeel Natu * The length of an environment variable is limited to 128 bytes which 81307044a96SNeel Natu * puts an upper limit on the number of passthru devices that may be 81407044a96SNeel Natu * specified using a single environment variable. 81507044a96SNeel Natu * 81607044a96SNeel Natu * Work around this by scanning multiple environment variable 81707044a96SNeel Natu * names instead of a single one - yuck! 818366f6083SPeter Grehan */ 81907044a96SNeel Natu const char *names[] = { "pptdevs", "pptdevs2", "pptdevs3", NULL }; 82007044a96SNeel Natu 82107044a96SNeel Natu /* set pptdevs="1/2/3 4/5/6 7/8/9 10/11/12" */ 822366f6083SPeter Grehan found = 0; 82307044a96SNeel Natu for (i = 0; names[i] != NULL && !found; i++) { 82407044a96SNeel Natu cp = val = getenv(names[i]); 825366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 826366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 827366f6083SPeter Grehan *cp2 = '\0'; 828366f6083SPeter Grehan 829366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 830366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 831366f6083SPeter Grehan found = 1; 832366f6083SPeter Grehan break; 833366f6083SPeter Grehan } 834366f6083SPeter Grehan 835366f6083SPeter Grehan if (cp2 != NULL) 836366f6083SPeter Grehan *cp2++ = ' '; 837366f6083SPeter Grehan 838366f6083SPeter Grehan cp = cp2; 839366f6083SPeter Grehan } 840366f6083SPeter Grehan freeenv(val); 84107044a96SNeel Natu } 842366f6083SPeter Grehan return (found); 843366f6083SPeter Grehan } 844366f6083SPeter Grehan 845366f6083SPeter Grehan void * 846366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 847366f6083SPeter Grehan { 848366f6083SPeter Grehan 849366f6083SPeter Grehan return (vm->iommu); 850366f6083SPeter Grehan } 851366f6083SPeter Grehan 85275dd3366SNeel Natu int 85375dd3366SNeel Natu vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state state) 854366f6083SPeter Grehan { 85575dd3366SNeel Natu int error; 856366f6083SPeter Grehan struct vcpu *vcpu; 857366f6083SPeter Grehan 858366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 859366f6083SPeter Grehan panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 860366f6083SPeter Grehan 861366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 862366f6083SPeter Grehan 86375dd3366SNeel Natu vcpu_lock(vcpu); 86475dd3366SNeel Natu 86575dd3366SNeel Natu /* 86675dd3366SNeel Natu * The following state transitions are allowed: 86775dd3366SNeel Natu * IDLE -> RUNNING -> IDLE 86875dd3366SNeel Natu * IDLE -> CANNOT_RUN -> IDLE 86975dd3366SNeel Natu */ 87075dd3366SNeel Natu if ((vcpu->state == VCPU_IDLE && state != VCPU_IDLE) || 87175dd3366SNeel Natu (vcpu->state != VCPU_IDLE && state == VCPU_IDLE)) { 87275dd3366SNeel Natu error = 0; 87375dd3366SNeel Natu vcpu->state = state; 874366f6083SPeter Grehan } else { 87575dd3366SNeel Natu error = EBUSY; 876366f6083SPeter Grehan } 877366f6083SPeter Grehan 87875dd3366SNeel Natu vcpu_unlock(vcpu); 87975dd3366SNeel Natu 88075dd3366SNeel Natu return (error); 88175dd3366SNeel Natu } 88275dd3366SNeel Natu 88375dd3366SNeel Natu enum vcpu_state 88475dd3366SNeel Natu vcpu_get_state(struct vm *vm, int vcpuid) 885366f6083SPeter Grehan { 886366f6083SPeter Grehan struct vcpu *vcpu; 88775dd3366SNeel Natu enum vcpu_state state; 888366f6083SPeter Grehan 889366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 890366f6083SPeter Grehan panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 891366f6083SPeter Grehan 892366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 893366f6083SPeter Grehan 89475dd3366SNeel Natu vcpu_lock(vcpu); 89575dd3366SNeel Natu state = vcpu->state; 89675dd3366SNeel Natu vcpu_unlock(vcpu); 897366f6083SPeter Grehan 89875dd3366SNeel Natu return (state); 899366f6083SPeter Grehan } 900366f6083SPeter Grehan 901366f6083SPeter Grehan void 902366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid) 903366f6083SPeter Grehan { 904366f6083SPeter Grehan 905366f6083SPeter Grehan if (vcpuid >= 0 && vcpuid < VM_MAXCPU) 906a5615c90SPeter Grehan CPU_SET(vcpuid, &vm->active_cpus); 907366f6083SPeter Grehan } 908366f6083SPeter Grehan 909a5615c90SPeter Grehan cpuset_t 910366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 911366f6083SPeter Grehan { 912366f6083SPeter Grehan 913366f6083SPeter Grehan return (vm->active_cpus); 914366f6083SPeter Grehan } 915366f6083SPeter Grehan 916366f6083SPeter Grehan void * 917366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid) 918366f6083SPeter Grehan { 919366f6083SPeter Grehan 920366f6083SPeter Grehan return (vm->vcpu[vcpuid].stats); 921366f6083SPeter Grehan } 922e9027382SNeel Natu 923e9027382SNeel Natu int 924e9027382SNeel Natu vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) 925e9027382SNeel Natu { 926e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 927e9027382SNeel Natu return (EINVAL); 928e9027382SNeel Natu 929e9027382SNeel Natu *state = vm->vcpu[vcpuid].x2apic_state; 930e9027382SNeel Natu 931e9027382SNeel Natu return (0); 932e9027382SNeel Natu } 933e9027382SNeel Natu 934e9027382SNeel Natu int 935e9027382SNeel Natu vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 936e9027382SNeel Natu { 937e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 938e9027382SNeel Natu return (EINVAL); 939e9027382SNeel Natu 940e9027382SNeel Natu if (state < 0 || state >= X2APIC_STATE_LAST) 941e9027382SNeel Natu return (EINVAL); 942e9027382SNeel Natu 943e9027382SNeel Natu vm->vcpu[vcpuid].x2apic_state = state; 944e9027382SNeel Natu 94573820fb0SNeel Natu vlapic_set_x2apic_state(vm, vcpuid, state); 94673820fb0SNeel Natu 947e9027382SNeel Natu return (0); 948e9027382SNeel Natu } 94975dd3366SNeel Natu 95075dd3366SNeel Natu void 95175dd3366SNeel Natu vm_interrupt_hostcpu(struct vm *vm, int vcpuid) 95275dd3366SNeel Natu { 95375dd3366SNeel Natu int hostcpu; 95475dd3366SNeel Natu struct vcpu *vcpu; 95575dd3366SNeel Natu 95675dd3366SNeel Natu vcpu = &vm->vcpu[vcpuid]; 95775dd3366SNeel Natu 958f76fc5d4SNeel Natu vcpu_lock(vcpu); 95975dd3366SNeel Natu hostcpu = vcpu->hostcpu; 960f76fc5d4SNeel Natu if (hostcpu == NOCPU) { 961f76fc5d4SNeel Natu /* 962f76fc5d4SNeel Natu * If the vcpu is 'RUNNING' but without a valid 'hostcpu' then 963f76fc5d4SNeel Natu * the host thread must be sleeping waiting for an event to 964f76fc5d4SNeel Natu * kick the vcpu out of 'hlt'. 965f76fc5d4SNeel Natu * 966f76fc5d4SNeel Natu * XXX this is racy because the condition exists right before 967f76fc5d4SNeel Natu * and after calling VMRUN() in vm_run(). The wakeup() is 968f76fc5d4SNeel Natu * benign in this case. 969f76fc5d4SNeel Natu */ 970f76fc5d4SNeel Natu if (vcpu->state == VCPU_RUNNING) 971f76fc5d4SNeel Natu wakeup_one(vcpu); 972f76fc5d4SNeel Natu } else { 973f76fc5d4SNeel Natu if (vcpu->state != VCPU_RUNNING) 974f76fc5d4SNeel Natu panic("invalid vcpu state %d", vcpu->state); 975f76fc5d4SNeel Natu if (hostcpu != curcpu) 97675dd3366SNeel Natu ipi_cpu(hostcpu, vmm_ipinum); 97775dd3366SNeel Natu } 978f76fc5d4SNeel Natu vcpu_unlock(vcpu); 979f76fc5d4SNeel Natu } 980