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> 5034a6b2d6SJohn Baldwin #include <x86/apicreg.h> 51366f6083SPeter Grehan 52366f6083SPeter Grehan #include <machine/vmm.h> 53366f6083SPeter Grehan #include "vmm_mem.h" 54366f6083SPeter Grehan #include "vmm_util.h" 55366f6083SPeter Grehan #include <machine/vmm_dev.h> 56366f6083SPeter Grehan #include "vlapic.h" 57366f6083SPeter Grehan #include "vmm_msr.h" 58366f6083SPeter Grehan #include "vmm_ipi.h" 59366f6083SPeter Grehan #include "vmm_stat.h" 60366f6083SPeter Grehan 61366f6083SPeter Grehan #include "io/ppt.h" 62366f6083SPeter Grehan #include "io/iommu.h" 63366f6083SPeter Grehan 64366f6083SPeter Grehan struct vlapic; 65366f6083SPeter Grehan 66366f6083SPeter Grehan struct vcpu { 67366f6083SPeter Grehan int flags; 68366f6083SPeter Grehan int pincpu; /* host cpuid this vcpu is bound to */ 69366f6083SPeter Grehan int hostcpu; /* host cpuid this vcpu last ran on */ 70366f6083SPeter Grehan uint64_t guest_msrs[VMM_MSR_NUM]; 71366f6083SPeter Grehan struct vlapic *vlapic; 72366f6083SPeter Grehan int vcpuid; 7338f1b189SPeter Grehan struct savefpu *guestfpu; /* guest fpu state */ 74366f6083SPeter Grehan void *stats; 7598ed632cSNeel Natu struct vm_exit exitinfo; 76e9027382SNeel Natu enum x2apic_state x2apic_state; 77366f6083SPeter Grehan }; 78366f6083SPeter Grehan #define VCPU_F_PINNED 0x0001 79366f6083SPeter Grehan #define VCPU_F_RUNNING 0x0002 80366f6083SPeter Grehan 81366f6083SPeter Grehan #define VCPU_PINCPU(vm, vcpuid) \ 82366f6083SPeter Grehan ((vm->vcpu[vcpuid].flags & VCPU_F_PINNED) ? vm->vcpu[vcpuid].pincpu : -1) 83366f6083SPeter Grehan 84366f6083SPeter Grehan #define VCPU_UNPIN(vm, vcpuid) (vm->vcpu[vcpuid].flags &= ~VCPU_F_PINNED) 85366f6083SPeter Grehan 86366f6083SPeter Grehan #define VCPU_PIN(vm, vcpuid, host_cpuid) \ 87366f6083SPeter Grehan do { \ 88366f6083SPeter Grehan vm->vcpu[vcpuid].flags |= VCPU_F_PINNED; \ 89366f6083SPeter Grehan vm->vcpu[vcpuid].pincpu = host_cpuid; \ 90366f6083SPeter Grehan } while(0) 91366f6083SPeter Grehan 92366f6083SPeter Grehan #define VM_MAX_MEMORY_SEGMENTS 2 93366f6083SPeter Grehan 94366f6083SPeter Grehan struct vm { 95366f6083SPeter Grehan void *cookie; /* processor-specific data */ 96366f6083SPeter Grehan void *iommu; /* iommu-specific data */ 97366f6083SPeter Grehan struct vcpu vcpu[VM_MAXCPU]; 98366f6083SPeter Grehan int num_mem_segs; 99366f6083SPeter Grehan struct vm_memory_segment mem_segs[VM_MAX_MEMORY_SEGMENTS]; 100366f6083SPeter Grehan char name[VM_MAX_NAMELEN]; 101366f6083SPeter Grehan 102366f6083SPeter Grehan /* 103a5615c90SPeter Grehan * Set of active vcpus. 104366f6083SPeter Grehan * An active vcpu is one that has been started implicitly (BSP) or 105366f6083SPeter Grehan * explicitly (AP) by sending it a startup ipi. 106366f6083SPeter Grehan */ 107a5615c90SPeter Grehan cpuset_t active_cpus; 108366f6083SPeter Grehan }; 109366f6083SPeter Grehan 110366f6083SPeter Grehan static struct vmm_ops *ops; 111366f6083SPeter Grehan #define VMM_INIT() (ops != NULL ? (*ops->init)() : 0) 112366f6083SPeter Grehan #define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 113366f6083SPeter Grehan 114366f6083SPeter Grehan #define VMINIT(vm) (ops != NULL ? (*ops->vminit)(vm): NULL) 11598ed632cSNeel Natu #define VMRUN(vmi, vcpu, rip) \ 11698ed632cSNeel Natu (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip) : ENXIO) 117366f6083SPeter Grehan #define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 118bda273f2SNeel Natu #define VMMMAP_SET(vmi, gpa, hpa, len, attr, prot, spm) \ 119bda273f2SNeel Natu (ops != NULL ? \ 120bda273f2SNeel Natu (*ops->vmmmap_set)(vmi, gpa, hpa, len, attr, prot, spm) : \ 121bda273f2SNeel Natu ENXIO) 122bda273f2SNeel Natu #define VMMMAP_GET(vmi, gpa) \ 123bda273f2SNeel Natu (ops != NULL ? (*ops->vmmmap_get)(vmi, gpa) : ENXIO) 124366f6083SPeter Grehan #define VMGETREG(vmi, vcpu, num, retval) \ 125366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 126366f6083SPeter Grehan #define VMSETREG(vmi, vcpu, num, val) \ 127366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 128366f6083SPeter Grehan #define VMGETDESC(vmi, vcpu, num, desc) \ 129366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 130366f6083SPeter Grehan #define VMSETDESC(vmi, vcpu, num, desc) \ 131366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 132366f6083SPeter Grehan #define VMINJECT(vmi, vcpu, type, vec, ec, ecv) \ 133366f6083SPeter Grehan (ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO) 134366f6083SPeter Grehan #define VMNMI(vmi, vcpu) \ 135366f6083SPeter Grehan (ops != NULL ? (*ops->vmnmi)(vmi, vcpu) : ENXIO) 136366f6083SPeter Grehan #define VMGETCAP(vmi, vcpu, num, retval) \ 137366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 138366f6083SPeter Grehan #define VMSETCAP(vmi, vcpu, num, val) \ 139366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 140366f6083SPeter Grehan 14138f1b189SPeter Grehan #define fpu_start_emulating() start_emulating() 14238f1b189SPeter Grehan #define fpu_stop_emulating() stop_emulating() 143366f6083SPeter Grehan 144366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 145366f6083SPeter Grehan CTASSERT(VMM_MSR_NUM <= 64); /* msr_mask can keep track of up to 64 msrs */ 146366f6083SPeter Grehan 147366f6083SPeter Grehan /* statistics */ 148366f6083SPeter Grehan static VMM_STAT_DEFINE(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 149366f6083SPeter Grehan 150366f6083SPeter Grehan static void 151366f6083SPeter Grehan vcpu_cleanup(struct vcpu *vcpu) 152366f6083SPeter Grehan { 153366f6083SPeter Grehan vlapic_cleanup(vcpu->vlapic); 154366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 15538f1b189SPeter Grehan fpu_save_area_free(vcpu->guestfpu); 156366f6083SPeter Grehan } 157366f6083SPeter Grehan 158366f6083SPeter Grehan static void 159366f6083SPeter Grehan vcpu_init(struct vm *vm, uint32_t vcpu_id) 160366f6083SPeter Grehan { 161366f6083SPeter Grehan struct vcpu *vcpu; 162366f6083SPeter Grehan 163366f6083SPeter Grehan vcpu = &vm->vcpu[vcpu_id]; 164366f6083SPeter Grehan 165366f6083SPeter Grehan vcpu->hostcpu = -1; 166366f6083SPeter Grehan vcpu->vcpuid = vcpu_id; 167366f6083SPeter Grehan vcpu->vlapic = vlapic_init(vm, vcpu_id); 16873820fb0SNeel Natu vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED); 16938f1b189SPeter Grehan vcpu->guestfpu = fpu_save_area_alloc(); 17038f1b189SPeter Grehan fpu_save_area_reset(vcpu->guestfpu); 171366f6083SPeter Grehan vcpu->stats = vmm_stat_alloc(); 172366f6083SPeter Grehan } 173366f6083SPeter Grehan 17498ed632cSNeel Natu struct vm_exit * 17598ed632cSNeel Natu vm_exitinfo(struct vm *vm, int cpuid) 17698ed632cSNeel Natu { 17798ed632cSNeel Natu struct vcpu *vcpu; 17898ed632cSNeel Natu 17998ed632cSNeel Natu if (cpuid < 0 || cpuid >= VM_MAXCPU) 18098ed632cSNeel Natu panic("vm_exitinfo: invalid cpuid %d", cpuid); 18198ed632cSNeel Natu 18298ed632cSNeel Natu vcpu = &vm->vcpu[cpuid]; 18398ed632cSNeel Natu 18498ed632cSNeel Natu return (&vcpu->exitinfo); 18598ed632cSNeel Natu } 18698ed632cSNeel Natu 187366f6083SPeter Grehan static int 188366f6083SPeter Grehan vmm_init(void) 189366f6083SPeter Grehan { 190366f6083SPeter Grehan int error; 191366f6083SPeter Grehan 192366f6083SPeter Grehan vmm_ipi_init(); 193366f6083SPeter Grehan 194366f6083SPeter Grehan error = vmm_mem_init(); 195366f6083SPeter Grehan if (error) 196366f6083SPeter Grehan return (error); 197366f6083SPeter Grehan 198366f6083SPeter Grehan if (vmm_is_intel()) 199366f6083SPeter Grehan ops = &vmm_ops_intel; 200366f6083SPeter Grehan else if (vmm_is_amd()) 201366f6083SPeter Grehan ops = &vmm_ops_amd; 202366f6083SPeter Grehan else 203366f6083SPeter Grehan return (ENXIO); 204366f6083SPeter Grehan 205366f6083SPeter Grehan vmm_msr_init(); 206366f6083SPeter Grehan 207366f6083SPeter Grehan return (VMM_INIT()); 208366f6083SPeter Grehan } 209366f6083SPeter Grehan 210366f6083SPeter Grehan static int 211366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 212366f6083SPeter Grehan { 213366f6083SPeter Grehan int error; 214366f6083SPeter Grehan 215366f6083SPeter Grehan switch (what) { 216366f6083SPeter Grehan case MOD_LOAD: 217366f6083SPeter Grehan vmmdev_init(); 218366f6083SPeter Grehan iommu_init(); 219366f6083SPeter Grehan error = vmm_init(); 220366f6083SPeter Grehan break; 221366f6083SPeter Grehan case MOD_UNLOAD: 222366f6083SPeter Grehan vmmdev_cleanup(); 223366f6083SPeter Grehan iommu_cleanup(); 224366f6083SPeter Grehan vmm_ipi_cleanup(); 225366f6083SPeter Grehan error = VMM_CLEANUP(); 226366f6083SPeter Grehan break; 227366f6083SPeter Grehan default: 228366f6083SPeter Grehan error = 0; 229366f6083SPeter Grehan break; 230366f6083SPeter Grehan } 231366f6083SPeter Grehan return (error); 232366f6083SPeter Grehan } 233366f6083SPeter Grehan 234366f6083SPeter Grehan static moduledata_t vmm_kmod = { 235366f6083SPeter Grehan "vmm", 236366f6083SPeter Grehan vmm_handler, 237366f6083SPeter Grehan NULL 238366f6083SPeter Grehan }; 239366f6083SPeter Grehan 240366f6083SPeter Grehan /* 241366f6083SPeter Grehan * Execute the module load handler after the pci passthru driver has had 242366f6083SPeter Grehan * a chance to claim devices. We need this information at the time we do 243366f6083SPeter Grehan * iommu initialization. 244366f6083SPeter Grehan */ 245366f6083SPeter Grehan DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_CONFIGURE + 1, SI_ORDER_ANY); 246366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 247366f6083SPeter Grehan 248366f6083SPeter Grehan SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 249366f6083SPeter Grehan 250366f6083SPeter Grehan struct vm * 251366f6083SPeter Grehan vm_create(const char *name) 252366f6083SPeter Grehan { 253366f6083SPeter Grehan int i; 254366f6083SPeter Grehan struct vm *vm; 255366f6083SPeter Grehan vm_paddr_t maxaddr; 256366f6083SPeter Grehan 257366f6083SPeter Grehan const int BSP = 0; 258366f6083SPeter Grehan 259366f6083SPeter Grehan if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 260366f6083SPeter Grehan return (NULL); 261366f6083SPeter Grehan 262366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 263366f6083SPeter Grehan strcpy(vm->name, name); 264366f6083SPeter Grehan vm->cookie = VMINIT(vm); 265366f6083SPeter Grehan 266366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) { 267366f6083SPeter Grehan vcpu_init(vm, i); 268366f6083SPeter Grehan guest_msrs_init(vm, i); 269366f6083SPeter Grehan } 270366f6083SPeter Grehan 271366f6083SPeter Grehan maxaddr = vmm_mem_maxaddr(); 272366f6083SPeter Grehan vm->iommu = iommu_create_domain(maxaddr); 273366f6083SPeter Grehan vm_activate_cpu(vm, BSP); 274366f6083SPeter Grehan 275366f6083SPeter Grehan return (vm); 276366f6083SPeter Grehan } 277366f6083SPeter Grehan 278f7d51510SNeel Natu static void 279f7d51510SNeel Natu vm_free_mem_seg(struct vm *vm, struct vm_memory_segment *seg) 280f7d51510SNeel Natu { 281f7d51510SNeel Natu size_t len; 282f7d51510SNeel Natu vm_paddr_t hpa; 2837ce04d0aSNeel Natu void *host_domain; 2847ce04d0aSNeel Natu 2857ce04d0aSNeel Natu host_domain = iommu_host_domain(); 286f7d51510SNeel Natu 287f7d51510SNeel Natu len = 0; 288f7d51510SNeel Natu while (len < seg->len) { 289f7d51510SNeel Natu hpa = vm_gpa2hpa(vm, seg->gpa + len, PAGE_SIZE); 290f7d51510SNeel Natu if (hpa == (vm_paddr_t)-1) { 291f7d51510SNeel Natu panic("vm_free_mem_segs: cannot free hpa " 292f7d51510SNeel Natu "associated with gpa 0x%016lx", seg->gpa + len); 293f7d51510SNeel Natu } 294f7d51510SNeel Natu 2957ce04d0aSNeel Natu /* 2967ce04d0aSNeel Natu * Remove the 'gpa' to 'hpa' mapping in VMs domain. 2977ce04d0aSNeel Natu * And resurrect the 1:1 mapping for 'hpa' in 'host_domain'. 2987ce04d0aSNeel Natu */ 2997ce04d0aSNeel Natu iommu_remove_mapping(vm->iommu, seg->gpa + len, PAGE_SIZE); 3007ce04d0aSNeel Natu iommu_create_mapping(host_domain, hpa, hpa, PAGE_SIZE); 3017ce04d0aSNeel Natu 302f7d51510SNeel Natu vmm_mem_free(hpa, PAGE_SIZE); 303f7d51510SNeel Natu 304f7d51510SNeel Natu len += PAGE_SIZE; 305f7d51510SNeel Natu } 306f7d51510SNeel Natu 3077ce04d0aSNeel Natu /* 3087ce04d0aSNeel Natu * Invalidate cached translations associated with 'vm->iommu' since 3097ce04d0aSNeel Natu * we have now moved some pages from it. 3107ce04d0aSNeel Natu */ 3117ce04d0aSNeel Natu iommu_invalidate_tlb(vm->iommu); 3127ce04d0aSNeel Natu 313f7d51510SNeel Natu bzero(seg, sizeof(struct vm_memory_segment)); 314f7d51510SNeel Natu } 315f7d51510SNeel Natu 316366f6083SPeter Grehan void 317366f6083SPeter Grehan vm_destroy(struct vm *vm) 318366f6083SPeter Grehan { 319366f6083SPeter Grehan int i; 320366f6083SPeter Grehan 321366f6083SPeter Grehan ppt_unassign_all(vm); 322366f6083SPeter Grehan 323366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) 324f7d51510SNeel Natu vm_free_mem_seg(vm, &vm->mem_segs[i]); 325f7d51510SNeel Natu 326f7d51510SNeel Natu vm->num_mem_segs = 0; 327366f6083SPeter Grehan 328366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) 329366f6083SPeter Grehan vcpu_cleanup(&vm->vcpu[i]); 330366f6083SPeter Grehan 331366f6083SPeter Grehan iommu_destroy_domain(vm->iommu); 332366f6083SPeter Grehan 333366f6083SPeter Grehan VMCLEANUP(vm->cookie); 334366f6083SPeter Grehan 335366f6083SPeter Grehan free(vm, M_VM); 336366f6083SPeter Grehan } 337366f6083SPeter Grehan 338366f6083SPeter Grehan const char * 339366f6083SPeter Grehan vm_name(struct vm *vm) 340366f6083SPeter Grehan { 341366f6083SPeter Grehan return (vm->name); 342366f6083SPeter Grehan } 343366f6083SPeter Grehan 344366f6083SPeter Grehan int 345366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 346366f6083SPeter Grehan { 347366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 348366f6083SPeter Grehan 349bda273f2SNeel Natu return (VMMMAP_SET(vm->cookie, gpa, hpa, len, VM_MEMATTR_UNCACHEABLE, 350366f6083SPeter Grehan VM_PROT_RW, spok)); 351366f6083SPeter Grehan } 352366f6083SPeter Grehan 353366f6083SPeter Grehan int 354366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 355366f6083SPeter Grehan { 356366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 357366f6083SPeter Grehan 358bda273f2SNeel Natu return (VMMMAP_SET(vm->cookie, gpa, 0, len, 0, 359366f6083SPeter Grehan VM_PROT_NONE, spok)); 360366f6083SPeter Grehan } 361366f6083SPeter Grehan 362341f19c9SNeel Natu /* 363341f19c9SNeel Natu * Returns TRUE if 'gpa' is available for allocation and FALSE otherwise 364341f19c9SNeel Natu */ 365341f19c9SNeel Natu static boolean_t 366341f19c9SNeel Natu vm_gpa_available(struct vm *vm, vm_paddr_t gpa) 367366f6083SPeter Grehan { 368341f19c9SNeel Natu int i; 369341f19c9SNeel Natu vm_paddr_t gpabase, gpalimit; 370341f19c9SNeel Natu 371341f19c9SNeel Natu if (gpa & PAGE_MASK) 372341f19c9SNeel Natu panic("vm_gpa_available: gpa (0x%016lx) not page aligned", gpa); 373341f19c9SNeel Natu 374341f19c9SNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 375341f19c9SNeel Natu gpabase = vm->mem_segs[i].gpa; 376341f19c9SNeel Natu gpalimit = gpabase + vm->mem_segs[i].len; 377341f19c9SNeel Natu if (gpa >= gpabase && gpa < gpalimit) 378341f19c9SNeel Natu return (FALSE); 379341f19c9SNeel Natu } 380341f19c9SNeel Natu 381341f19c9SNeel Natu return (TRUE); 382341f19c9SNeel Natu } 383341f19c9SNeel Natu 384341f19c9SNeel Natu int 385341f19c9SNeel Natu vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len) 386341f19c9SNeel Natu { 387341f19c9SNeel Natu int error, available, allocated; 388f7d51510SNeel Natu struct vm_memory_segment *seg; 389341f19c9SNeel Natu vm_paddr_t g, hpa; 3907ce04d0aSNeel Natu void *host_domain; 391366f6083SPeter Grehan 392366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 393366f6083SPeter Grehan 394341f19c9SNeel Natu if ((gpa & PAGE_MASK) || (len & PAGE_MASK) || len == 0) 395341f19c9SNeel Natu return (EINVAL); 396341f19c9SNeel Natu 397341f19c9SNeel Natu available = allocated = 0; 398341f19c9SNeel Natu g = gpa; 399341f19c9SNeel Natu while (g < gpa + len) { 400341f19c9SNeel Natu if (vm_gpa_available(vm, g)) 401341f19c9SNeel Natu available++; 402341f19c9SNeel Natu else 403341f19c9SNeel Natu allocated++; 404341f19c9SNeel Natu 405341f19c9SNeel Natu g += PAGE_SIZE; 406341f19c9SNeel Natu } 407341f19c9SNeel Natu 408366f6083SPeter Grehan /* 409341f19c9SNeel Natu * If there are some allocated and some available pages in the address 410341f19c9SNeel Natu * range then it is an error. 411366f6083SPeter Grehan */ 412341f19c9SNeel Natu if (allocated && available) 413341f19c9SNeel Natu return (EINVAL); 414341f19c9SNeel Natu 415341f19c9SNeel Natu /* 416341f19c9SNeel Natu * If the entire address range being requested has already been 417341f19c9SNeel Natu * allocated then there isn't anything more to do. 418341f19c9SNeel Natu */ 419341f19c9SNeel Natu if (allocated && available == 0) 420341f19c9SNeel Natu return (0); 421366f6083SPeter Grehan 422366f6083SPeter Grehan if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS) 423366f6083SPeter Grehan return (E2BIG); 424366f6083SPeter Grehan 4257ce04d0aSNeel Natu host_domain = iommu_host_domain(); 4267ce04d0aSNeel Natu 427f7d51510SNeel Natu seg = &vm->mem_segs[vm->num_mem_segs]; 428366f6083SPeter Grehan 4297ce04d0aSNeel Natu error = 0; 430f7d51510SNeel Natu seg->gpa = gpa; 431f7d51510SNeel Natu seg->len = 0; 432f7d51510SNeel Natu while (seg->len < len) { 433f7d51510SNeel Natu hpa = vmm_mem_alloc(PAGE_SIZE); 434f7d51510SNeel Natu if (hpa == 0) { 435f7d51510SNeel Natu error = ENOMEM; 436f7d51510SNeel Natu break; 437f7d51510SNeel Natu } 438f7d51510SNeel Natu 439f7d51510SNeel Natu error = VMMMAP_SET(vm->cookie, gpa + seg->len, hpa, PAGE_SIZE, 440f7d51510SNeel Natu VM_MEMATTR_WRITE_BACK, VM_PROT_ALL, spok); 441f7d51510SNeel Natu if (error) 442f7d51510SNeel Natu break; 443f7d51510SNeel Natu 4447ce04d0aSNeel Natu /* 4457ce04d0aSNeel Natu * Remove the 1:1 mapping for 'hpa' from the 'host_domain'. 4467ce04d0aSNeel Natu * Add mapping for 'gpa + seg->len' to 'hpa' in the VMs domain. 4477ce04d0aSNeel Natu */ 4487ce04d0aSNeel Natu iommu_remove_mapping(host_domain, hpa, PAGE_SIZE); 449f7d51510SNeel Natu iommu_create_mapping(vm->iommu, gpa + seg->len, hpa, PAGE_SIZE); 450f7d51510SNeel Natu 451f7d51510SNeel Natu seg->len += PAGE_SIZE; 452f7d51510SNeel Natu } 453f7d51510SNeel Natu 4547ce04d0aSNeel Natu if (error) { 455f7d51510SNeel Natu vm_free_mem_seg(vm, seg); 456366f6083SPeter Grehan return (error); 457366f6083SPeter Grehan } 458366f6083SPeter Grehan 4597ce04d0aSNeel Natu /* 4607ce04d0aSNeel Natu * Invalidate cached translations associated with 'host_domain' since 4617ce04d0aSNeel Natu * we have now moved some pages from it. 4627ce04d0aSNeel Natu */ 4637ce04d0aSNeel Natu iommu_invalidate_tlb(host_domain); 4647ce04d0aSNeel Natu 465366f6083SPeter Grehan vm->num_mem_segs++; 466341f19c9SNeel Natu 467366f6083SPeter Grehan return (0); 468366f6083SPeter Grehan } 469366f6083SPeter Grehan 470366f6083SPeter Grehan vm_paddr_t 471366f6083SPeter Grehan vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t len) 472366f6083SPeter Grehan { 4734db4fb2cSNeel Natu vm_paddr_t nextpage; 4744db4fb2cSNeel Natu 4754db4fb2cSNeel Natu nextpage = rounddown(gpa + PAGE_SIZE, PAGE_SIZE); 4764db4fb2cSNeel Natu if (len > nextpage - gpa) 4774db4fb2cSNeel Natu panic("vm_gpa2hpa: invalid gpa/len: 0x%016lx/%lu", gpa, len); 478366f6083SPeter Grehan 479bda273f2SNeel Natu return (VMMMAP_GET(vm->cookie, gpa)); 480366f6083SPeter Grehan } 481366f6083SPeter Grehan 482366f6083SPeter Grehan int 483366f6083SPeter Grehan vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 484366f6083SPeter Grehan struct vm_memory_segment *seg) 485366f6083SPeter Grehan { 486366f6083SPeter Grehan int i; 487366f6083SPeter Grehan 488366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) { 489366f6083SPeter Grehan if (gpabase == vm->mem_segs[i].gpa) { 490366f6083SPeter Grehan *seg = vm->mem_segs[i]; 491366f6083SPeter Grehan return (0); 492366f6083SPeter Grehan } 493366f6083SPeter Grehan } 494366f6083SPeter Grehan return (-1); 495366f6083SPeter Grehan } 496366f6083SPeter Grehan 497366f6083SPeter Grehan int 498366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 499366f6083SPeter Grehan { 500366f6083SPeter Grehan 501366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 502366f6083SPeter Grehan return (EINVAL); 503366f6083SPeter Grehan 504366f6083SPeter Grehan if (reg >= VM_REG_LAST) 505366f6083SPeter Grehan return (EINVAL); 506366f6083SPeter Grehan 507366f6083SPeter Grehan return (VMGETREG(vm->cookie, vcpu, reg, retval)); 508366f6083SPeter Grehan } 509366f6083SPeter Grehan 510366f6083SPeter Grehan int 511366f6083SPeter Grehan vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val) 512366f6083SPeter Grehan { 513366f6083SPeter Grehan 514366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 515366f6083SPeter Grehan return (EINVAL); 516366f6083SPeter Grehan 517366f6083SPeter Grehan if (reg >= VM_REG_LAST) 518366f6083SPeter Grehan return (EINVAL); 519366f6083SPeter Grehan 520366f6083SPeter Grehan return (VMSETREG(vm->cookie, vcpu, reg, val)); 521366f6083SPeter Grehan } 522366f6083SPeter Grehan 523366f6083SPeter Grehan static boolean_t 524366f6083SPeter Grehan is_descriptor_table(int reg) 525366f6083SPeter Grehan { 526366f6083SPeter Grehan 527366f6083SPeter Grehan switch (reg) { 528366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 529366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 530366f6083SPeter Grehan return (TRUE); 531366f6083SPeter Grehan default: 532366f6083SPeter Grehan return (FALSE); 533366f6083SPeter Grehan } 534366f6083SPeter Grehan } 535366f6083SPeter Grehan 536366f6083SPeter Grehan static boolean_t 537366f6083SPeter Grehan is_segment_register(int reg) 538366f6083SPeter Grehan { 539366f6083SPeter Grehan 540366f6083SPeter Grehan switch (reg) { 541366f6083SPeter Grehan case VM_REG_GUEST_ES: 542366f6083SPeter Grehan case VM_REG_GUEST_CS: 543366f6083SPeter Grehan case VM_REG_GUEST_SS: 544366f6083SPeter Grehan case VM_REG_GUEST_DS: 545366f6083SPeter Grehan case VM_REG_GUEST_FS: 546366f6083SPeter Grehan case VM_REG_GUEST_GS: 547366f6083SPeter Grehan case VM_REG_GUEST_TR: 548366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 549366f6083SPeter Grehan return (TRUE); 550366f6083SPeter Grehan default: 551366f6083SPeter Grehan return (FALSE); 552366f6083SPeter Grehan } 553366f6083SPeter Grehan } 554366f6083SPeter Grehan 555366f6083SPeter Grehan int 556366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 557366f6083SPeter Grehan struct seg_desc *desc) 558366f6083SPeter Grehan { 559366f6083SPeter Grehan 560366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 561366f6083SPeter Grehan return (EINVAL); 562366f6083SPeter Grehan 563366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 564366f6083SPeter Grehan return (EINVAL); 565366f6083SPeter Grehan 566366f6083SPeter Grehan return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 567366f6083SPeter Grehan } 568366f6083SPeter Grehan 569366f6083SPeter Grehan int 570366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 571366f6083SPeter Grehan struct seg_desc *desc) 572366f6083SPeter Grehan { 573366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 574366f6083SPeter Grehan return (EINVAL); 575366f6083SPeter Grehan 576366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 577366f6083SPeter Grehan return (EINVAL); 578366f6083SPeter Grehan 579366f6083SPeter Grehan return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 580366f6083SPeter Grehan } 581366f6083SPeter Grehan 582366f6083SPeter Grehan int 583366f6083SPeter Grehan vm_get_pinning(struct vm *vm, int vcpuid, int *cpuid) 584366f6083SPeter Grehan { 585366f6083SPeter Grehan 586366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 587366f6083SPeter Grehan return (EINVAL); 588366f6083SPeter Grehan 589366f6083SPeter Grehan *cpuid = VCPU_PINCPU(vm, vcpuid); 590366f6083SPeter Grehan 591366f6083SPeter Grehan return (0); 592366f6083SPeter Grehan } 593366f6083SPeter Grehan 594366f6083SPeter Grehan int 595366f6083SPeter Grehan vm_set_pinning(struct vm *vm, int vcpuid, int host_cpuid) 596366f6083SPeter Grehan { 597366f6083SPeter Grehan struct thread *td; 598366f6083SPeter Grehan 599366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 600366f6083SPeter Grehan return (EINVAL); 601366f6083SPeter Grehan 602366f6083SPeter Grehan td = curthread; /* XXXSMP only safe when muxing vcpus */ 603366f6083SPeter Grehan 604366f6083SPeter Grehan /* unpin */ 605366f6083SPeter Grehan if (host_cpuid < 0) { 606366f6083SPeter Grehan VCPU_UNPIN(vm, vcpuid); 607366f6083SPeter Grehan thread_lock(td); 608366f6083SPeter Grehan sched_unbind(td); 609366f6083SPeter Grehan thread_unlock(td); 610366f6083SPeter Grehan return (0); 611366f6083SPeter Grehan } 612366f6083SPeter Grehan 613366f6083SPeter Grehan if (CPU_ABSENT(host_cpuid)) 614366f6083SPeter Grehan return (EINVAL); 615366f6083SPeter Grehan 616366f6083SPeter Grehan /* 617366f6083SPeter Grehan * XXX we should check that 'host_cpuid' has not already been pinned 618366f6083SPeter Grehan * by another vm. 619366f6083SPeter Grehan */ 620366f6083SPeter Grehan thread_lock(td); 621366f6083SPeter Grehan sched_bind(td, host_cpuid); 622366f6083SPeter Grehan thread_unlock(td); 623366f6083SPeter Grehan VCPU_PIN(vm, vcpuid, host_cpuid); 624366f6083SPeter Grehan 625366f6083SPeter Grehan return (0); 626366f6083SPeter Grehan } 627366f6083SPeter Grehan 628366f6083SPeter Grehan static void 629366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 630366f6083SPeter Grehan { 631366f6083SPeter Grehan 63238f1b189SPeter Grehan /* flush host state to the pcb */ 63338f1b189SPeter Grehan fpuexit(curthread); 634366f6083SPeter Grehan fpu_stop_emulating(); 63538f1b189SPeter Grehan fpurestore(vcpu->guestfpu); 636366f6083SPeter Grehan } 637366f6083SPeter Grehan 638366f6083SPeter Grehan static void 639366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 640366f6083SPeter Grehan { 641366f6083SPeter Grehan 64238f1b189SPeter Grehan fpusave(vcpu->guestfpu); 643366f6083SPeter Grehan fpu_start_emulating(); 644366f6083SPeter Grehan } 645366f6083SPeter Grehan 646366f6083SPeter Grehan int 647366f6083SPeter Grehan vm_run(struct vm *vm, struct vm_run *vmrun) 648366f6083SPeter Grehan { 649366f6083SPeter Grehan int error, vcpuid; 650366f6083SPeter Grehan struct vcpu *vcpu; 651366f6083SPeter Grehan struct pcb *pcb; 652366f6083SPeter Grehan uint64_t tscval; 653366f6083SPeter Grehan 654366f6083SPeter Grehan vcpuid = vmrun->cpuid; 655366f6083SPeter Grehan 656366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 657366f6083SPeter Grehan return (EINVAL); 658366f6083SPeter Grehan 659366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 660366f6083SPeter Grehan 661366f6083SPeter Grehan critical_enter(); 662366f6083SPeter Grehan 663366f6083SPeter Grehan tscval = rdtsc(); 664366f6083SPeter Grehan 665366f6083SPeter Grehan pcb = PCPU_GET(curpcb); 66634a6b2d6SJohn Baldwin set_pcb_flags(pcb, PCB_FULL_IRET); 667366f6083SPeter Grehan 668366f6083SPeter Grehan vcpu->hostcpu = curcpu; 669366f6083SPeter Grehan 670366f6083SPeter Grehan restore_guest_msrs(vm, vcpuid); 671366f6083SPeter Grehan restore_guest_fpustate(vcpu); 67298ed632cSNeel Natu error = VMRUN(vm->cookie, vcpuid, vmrun->rip); 673366f6083SPeter Grehan save_guest_fpustate(vcpu); 674366f6083SPeter Grehan restore_host_msrs(vm, vcpuid); 675366f6083SPeter Grehan 676366f6083SPeter Grehan vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 677366f6083SPeter Grehan 67898ed632cSNeel Natu /* copy the exit information */ 67998ed632cSNeel Natu bcopy(&vcpu->exitinfo, &vmrun->vm_exit, sizeof(struct vm_exit)); 68098ed632cSNeel Natu 681366f6083SPeter Grehan critical_exit(); 682366f6083SPeter Grehan 683366f6083SPeter Grehan return (error); 684366f6083SPeter Grehan } 685366f6083SPeter Grehan 686366f6083SPeter Grehan int 687366f6083SPeter Grehan vm_inject_event(struct vm *vm, int vcpuid, int type, 688366f6083SPeter Grehan int vector, uint32_t code, int code_valid) 689366f6083SPeter Grehan { 690366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 691366f6083SPeter Grehan return (EINVAL); 692366f6083SPeter Grehan 693366f6083SPeter Grehan if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0) 694366f6083SPeter Grehan return (EINVAL); 695366f6083SPeter Grehan 696366f6083SPeter Grehan if (vector < 0 || vector > 255) 697366f6083SPeter Grehan return (EINVAL); 698366f6083SPeter Grehan 699366f6083SPeter Grehan return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid)); 700366f6083SPeter Grehan } 701366f6083SPeter Grehan 702366f6083SPeter Grehan int 703366f6083SPeter Grehan vm_inject_nmi(struct vm *vm, int vcpu) 704366f6083SPeter Grehan { 705366f6083SPeter Grehan int error; 706366f6083SPeter Grehan 707366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 708366f6083SPeter Grehan return (EINVAL); 709366f6083SPeter Grehan 710366f6083SPeter Grehan error = VMNMI(vm->cookie, vcpu); 711366f6083SPeter Grehan vm_interrupt_hostcpu(vm, vcpu); 712366f6083SPeter Grehan return (error); 713366f6083SPeter Grehan } 714366f6083SPeter Grehan 715366f6083SPeter Grehan int 716366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 717366f6083SPeter Grehan { 718366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 719366f6083SPeter Grehan return (EINVAL); 720366f6083SPeter Grehan 721366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 722366f6083SPeter Grehan return (EINVAL); 723366f6083SPeter Grehan 724366f6083SPeter Grehan return (VMGETCAP(vm->cookie, vcpu, type, retval)); 725366f6083SPeter Grehan } 726366f6083SPeter Grehan 727366f6083SPeter Grehan int 728366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val) 729366f6083SPeter Grehan { 730366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 731366f6083SPeter Grehan return (EINVAL); 732366f6083SPeter Grehan 733366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 734366f6083SPeter Grehan return (EINVAL); 735366f6083SPeter Grehan 736366f6083SPeter Grehan return (VMSETCAP(vm->cookie, vcpu, type, val)); 737366f6083SPeter Grehan } 738366f6083SPeter Grehan 739366f6083SPeter Grehan uint64_t * 740366f6083SPeter Grehan vm_guest_msrs(struct vm *vm, int cpu) 741366f6083SPeter Grehan { 742366f6083SPeter Grehan return (vm->vcpu[cpu].guest_msrs); 743366f6083SPeter Grehan } 744366f6083SPeter Grehan 745366f6083SPeter Grehan struct vlapic * 746366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu) 747366f6083SPeter Grehan { 748366f6083SPeter Grehan return (vm->vcpu[cpu].vlapic); 749366f6083SPeter Grehan } 750366f6083SPeter Grehan 751366f6083SPeter Grehan boolean_t 752366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 753366f6083SPeter Grehan { 754366f6083SPeter Grehan int found, b, s, f, n; 755366f6083SPeter Grehan char *val, *cp, *cp2; 756366f6083SPeter Grehan 757366f6083SPeter Grehan /* 758366f6083SPeter Grehan * setenv pptdevs "1/2/3 4/5/6 7/8/9 10/11/12" 759366f6083SPeter Grehan */ 760366f6083SPeter Grehan found = 0; 761366f6083SPeter Grehan cp = val = getenv("pptdevs"); 762366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 763366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 764366f6083SPeter Grehan *cp2 = '\0'; 765366f6083SPeter Grehan 766366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 767366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 768366f6083SPeter Grehan found = 1; 769366f6083SPeter Grehan break; 770366f6083SPeter Grehan } 771366f6083SPeter Grehan 772366f6083SPeter Grehan if (cp2 != NULL) 773366f6083SPeter Grehan *cp2++ = ' '; 774366f6083SPeter Grehan 775366f6083SPeter Grehan cp = cp2; 776366f6083SPeter Grehan } 777366f6083SPeter Grehan freeenv(val); 778366f6083SPeter Grehan return (found); 779366f6083SPeter Grehan } 780366f6083SPeter Grehan 781366f6083SPeter Grehan void * 782366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 783366f6083SPeter Grehan { 784366f6083SPeter Grehan 785366f6083SPeter Grehan return (vm->iommu); 786366f6083SPeter Grehan } 787366f6083SPeter Grehan 788366f6083SPeter Grehan void 789366f6083SPeter Grehan vm_set_run_state(struct vm *vm, int vcpuid, int state) 790366f6083SPeter Grehan { 791366f6083SPeter Grehan struct vcpu *vcpu; 792366f6083SPeter Grehan 793366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 794366f6083SPeter Grehan panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 795366f6083SPeter Grehan 796366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 797366f6083SPeter Grehan 798366f6083SPeter Grehan if (state == VCPU_RUNNING) { 799366f6083SPeter Grehan if (vcpu->flags & VCPU_F_RUNNING) { 800366f6083SPeter Grehan panic("vm_set_run_state: %s[%d] is already running", 801366f6083SPeter Grehan vm_name(vm), vcpuid); 802366f6083SPeter Grehan } 803366f6083SPeter Grehan vcpu->flags |= VCPU_F_RUNNING; 804366f6083SPeter Grehan } else { 805366f6083SPeter Grehan if ((vcpu->flags & VCPU_F_RUNNING) == 0) { 806366f6083SPeter Grehan panic("vm_set_run_state: %s[%d] is already stopped", 807366f6083SPeter Grehan vm_name(vm), vcpuid); 808366f6083SPeter Grehan } 809366f6083SPeter Grehan vcpu->flags &= ~VCPU_F_RUNNING; 810366f6083SPeter Grehan } 811366f6083SPeter Grehan } 812366f6083SPeter Grehan 813366f6083SPeter Grehan int 814366f6083SPeter Grehan vm_get_run_state(struct vm *vm, int vcpuid, int *cpuptr) 815366f6083SPeter Grehan { 816366f6083SPeter Grehan int retval, hostcpu; 817366f6083SPeter Grehan struct vcpu *vcpu; 818366f6083SPeter Grehan 819366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 820366f6083SPeter Grehan panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 821366f6083SPeter Grehan 822366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 823366f6083SPeter Grehan if (vcpu->flags & VCPU_F_RUNNING) { 824366f6083SPeter Grehan retval = VCPU_RUNNING; 825366f6083SPeter Grehan hostcpu = vcpu->hostcpu; 826366f6083SPeter Grehan } else { 827366f6083SPeter Grehan retval = VCPU_STOPPED; 828366f6083SPeter Grehan hostcpu = -1; 829366f6083SPeter Grehan } 830366f6083SPeter Grehan 831366f6083SPeter Grehan if (cpuptr) 832366f6083SPeter Grehan *cpuptr = hostcpu; 833366f6083SPeter Grehan 834366f6083SPeter Grehan return (retval); 835366f6083SPeter Grehan } 836366f6083SPeter Grehan 837366f6083SPeter Grehan void 838366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid) 839366f6083SPeter Grehan { 840366f6083SPeter Grehan 841366f6083SPeter Grehan if (vcpuid >= 0 && vcpuid < VM_MAXCPU) 842a5615c90SPeter Grehan CPU_SET(vcpuid, &vm->active_cpus); 843366f6083SPeter Grehan } 844366f6083SPeter Grehan 845a5615c90SPeter Grehan cpuset_t 846366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 847366f6083SPeter Grehan { 848366f6083SPeter Grehan 849366f6083SPeter Grehan return (vm->active_cpus); 850366f6083SPeter Grehan } 851366f6083SPeter Grehan 852366f6083SPeter Grehan void * 853366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid) 854366f6083SPeter Grehan { 855366f6083SPeter Grehan 856366f6083SPeter Grehan return (vm->vcpu[vcpuid].stats); 857366f6083SPeter Grehan } 858e9027382SNeel Natu 859e9027382SNeel Natu int 860e9027382SNeel Natu vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) 861e9027382SNeel Natu { 862e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 863e9027382SNeel Natu return (EINVAL); 864e9027382SNeel Natu 865e9027382SNeel Natu *state = vm->vcpu[vcpuid].x2apic_state; 866e9027382SNeel Natu 867e9027382SNeel Natu return (0); 868e9027382SNeel Natu } 869e9027382SNeel Natu 870e9027382SNeel Natu int 871e9027382SNeel Natu vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 872e9027382SNeel Natu { 873e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 874e9027382SNeel Natu return (EINVAL); 875e9027382SNeel Natu 876e9027382SNeel Natu if (state < 0 || state >= X2APIC_STATE_LAST) 877e9027382SNeel Natu return (EINVAL); 878e9027382SNeel Natu 879e9027382SNeel Natu vm->vcpu[vcpuid].x2apic_state = state; 880e9027382SNeel Natu 88173820fb0SNeel Natu vlapic_set_x2apic_state(vm, vcpuid, state); 88273820fb0SNeel Natu 883e9027382SNeel Natu return (0); 884e9027382SNeel Natu } 885