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> 33366f6083SPeter Grehan #include <sys/kernel.h> 34366f6083SPeter Grehan #include <sys/module.h> 35366f6083SPeter Grehan #include <sys/sysctl.h> 36366f6083SPeter Grehan #include <sys/malloc.h> 37366f6083SPeter Grehan #include <sys/pcpu.h> 38366f6083SPeter Grehan #include <sys/lock.h> 39366f6083SPeter Grehan #include <sys/mutex.h> 40366f6083SPeter Grehan #include <sys/proc.h> 41366f6083SPeter Grehan #include <sys/sched.h> 42366f6083SPeter Grehan #include <sys/smp.h> 43366f6083SPeter Grehan #include <sys/systm.h> 44366f6083SPeter Grehan 45366f6083SPeter Grehan #include <vm/vm.h> 46366f6083SPeter Grehan 47366f6083SPeter Grehan #include <machine/vm.h> 48366f6083SPeter Grehan #include <machine/pcb.h> 49*34a6b2d6SJohn Baldwin #include <x86/apicreg.h> 50366f6083SPeter Grehan 51366f6083SPeter Grehan #include <machine/vmm.h> 52366f6083SPeter Grehan #include "vmm_mem.h" 53366f6083SPeter Grehan #include "vmm_util.h" 54366f6083SPeter Grehan #include <machine/vmm_dev.h> 55366f6083SPeter Grehan #include "vlapic.h" 56366f6083SPeter Grehan #include "vmm_msr.h" 57366f6083SPeter Grehan #include "vmm_ipi.h" 58366f6083SPeter Grehan #include "vmm_stat.h" 59366f6083SPeter Grehan 60366f6083SPeter Grehan #include "io/ppt.h" 61366f6083SPeter Grehan #include "io/iommu.h" 62366f6083SPeter Grehan 63366f6083SPeter Grehan struct vlapic; 64366f6083SPeter Grehan 65366f6083SPeter Grehan struct vcpu { 66366f6083SPeter Grehan int flags; 67366f6083SPeter Grehan int pincpu; /* host cpuid this vcpu is bound to */ 68366f6083SPeter Grehan int hostcpu; /* host cpuid this vcpu last ran on */ 69366f6083SPeter Grehan uint64_t guest_msrs[VMM_MSR_NUM]; 70366f6083SPeter Grehan struct vlapic *vlapic; 71366f6083SPeter Grehan int vcpuid; 72366f6083SPeter Grehan struct savefpu savefpu; /* guest fpu state */ 73366f6083SPeter Grehan void *stats; 74366f6083SPeter Grehan }; 75366f6083SPeter Grehan #define VCPU_F_PINNED 0x0001 76366f6083SPeter Grehan #define VCPU_F_RUNNING 0x0002 77366f6083SPeter Grehan 78366f6083SPeter Grehan #define VCPU_PINCPU(vm, vcpuid) \ 79366f6083SPeter Grehan ((vm->vcpu[vcpuid].flags & VCPU_F_PINNED) ? vm->vcpu[vcpuid].pincpu : -1) 80366f6083SPeter Grehan 81366f6083SPeter Grehan #define VCPU_UNPIN(vm, vcpuid) (vm->vcpu[vcpuid].flags &= ~VCPU_F_PINNED) 82366f6083SPeter Grehan 83366f6083SPeter Grehan #define VCPU_PIN(vm, vcpuid, host_cpuid) \ 84366f6083SPeter Grehan do { \ 85366f6083SPeter Grehan vm->vcpu[vcpuid].flags |= VCPU_F_PINNED; \ 86366f6083SPeter Grehan vm->vcpu[vcpuid].pincpu = host_cpuid; \ 87366f6083SPeter Grehan } while(0) 88366f6083SPeter Grehan 89366f6083SPeter Grehan #define VM_MAX_MEMORY_SEGMENTS 2 90366f6083SPeter Grehan 91366f6083SPeter Grehan struct vm { 92366f6083SPeter Grehan void *cookie; /* processor-specific data */ 93366f6083SPeter Grehan void *iommu; /* iommu-specific data */ 94366f6083SPeter Grehan struct vcpu vcpu[VM_MAXCPU]; 95366f6083SPeter Grehan int num_mem_segs; 96366f6083SPeter Grehan struct vm_memory_segment mem_segs[VM_MAX_MEMORY_SEGMENTS]; 97366f6083SPeter Grehan char name[VM_MAX_NAMELEN]; 98366f6083SPeter Grehan 99366f6083SPeter Grehan /* 100366f6083SPeter Grehan * Mask of active vcpus. 101366f6083SPeter Grehan * An active vcpu is one that has been started implicitly (BSP) or 102366f6083SPeter Grehan * explicitly (AP) by sending it a startup ipi. 103366f6083SPeter Grehan */ 104366f6083SPeter Grehan cpumask_t active_cpus; 105366f6083SPeter Grehan }; 106366f6083SPeter Grehan 107366f6083SPeter Grehan static struct vmm_ops *ops; 108366f6083SPeter Grehan #define VMM_INIT() (ops != NULL ? (*ops->init)() : 0) 109366f6083SPeter Grehan #define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 110366f6083SPeter Grehan 111366f6083SPeter Grehan #define VMINIT(vm) (ops != NULL ? (*ops->vminit)(vm): NULL) 112366f6083SPeter Grehan #define VMRUN(vmi, vcpu, rip, vmexit) \ 113366f6083SPeter Grehan (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, vmexit) : ENXIO) 114366f6083SPeter Grehan #define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 115366f6083SPeter Grehan #define VMMMAP(vmi, gpa, hpa, len, attr, prot, spm) \ 116366f6083SPeter Grehan (ops != NULL ? (*ops->vmmmap)(vmi, gpa, hpa, len, attr, prot, spm) : ENXIO) 117366f6083SPeter Grehan #define VMGETREG(vmi, vcpu, num, retval) \ 118366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 119366f6083SPeter Grehan #define VMSETREG(vmi, vcpu, num, val) \ 120366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 121366f6083SPeter Grehan #define VMGETDESC(vmi, vcpu, num, desc) \ 122366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 123366f6083SPeter Grehan #define VMSETDESC(vmi, vcpu, num, desc) \ 124366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 125366f6083SPeter Grehan #define VMINJECT(vmi, vcpu, type, vec, ec, ecv) \ 126366f6083SPeter Grehan (ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO) 127366f6083SPeter Grehan #define VMNMI(vmi, vcpu) \ 128366f6083SPeter Grehan (ops != NULL ? (*ops->vmnmi)(vmi, vcpu) : ENXIO) 129366f6083SPeter Grehan #define VMGETCAP(vmi, vcpu, num, retval) \ 130366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 131366f6083SPeter Grehan #define VMSETCAP(vmi, vcpu, num, val) \ 132366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 133366f6083SPeter Grehan 134366f6083SPeter Grehan #define fxrstor(addr) __asm("fxrstor %0" : : "m" (*(addr))) 135366f6083SPeter Grehan #define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr))) 136366f6083SPeter Grehan #define fpu_start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ 137366f6083SPeter Grehan : : "n" (CR0_TS) : "ax") 138366f6083SPeter Grehan #define fpu_stop_emulating() __asm("clts") 139366f6083SPeter Grehan 140366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 141366f6083SPeter Grehan CTASSERT(VMM_MSR_NUM <= 64); /* msr_mask can keep track of up to 64 msrs */ 142366f6083SPeter Grehan 143366f6083SPeter Grehan /* statistics */ 144366f6083SPeter Grehan static VMM_STAT_DEFINE(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 145366f6083SPeter Grehan 146366f6083SPeter Grehan static void 147366f6083SPeter Grehan vcpu_cleanup(struct vcpu *vcpu) 148366f6083SPeter Grehan { 149366f6083SPeter Grehan vlapic_cleanup(vcpu->vlapic); 150366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 151366f6083SPeter Grehan } 152366f6083SPeter Grehan 153366f6083SPeter Grehan static void 154366f6083SPeter Grehan vcpu_init(struct vm *vm, uint32_t vcpu_id) 155366f6083SPeter Grehan { 156366f6083SPeter Grehan struct vcpu *vcpu; 157366f6083SPeter Grehan 158366f6083SPeter Grehan vcpu = &vm->vcpu[vcpu_id]; 159366f6083SPeter Grehan 160366f6083SPeter Grehan vcpu->hostcpu = -1; 161366f6083SPeter Grehan vcpu->vcpuid = vcpu_id; 162366f6083SPeter Grehan vcpu->vlapic = vlapic_init(vm, vcpu_id); 163*34a6b2d6SJohn Baldwin fpugetregs(curthread); 164*34a6b2d6SJohn Baldwin vcpu->savefpu = curthread->td_pcb->pcb_user_save; 165366f6083SPeter Grehan vcpu->stats = vmm_stat_alloc(); 166366f6083SPeter Grehan } 167366f6083SPeter Grehan 168366f6083SPeter Grehan static int 169366f6083SPeter Grehan vmm_init(void) 170366f6083SPeter Grehan { 171366f6083SPeter Grehan int error; 172366f6083SPeter Grehan 173366f6083SPeter Grehan vmm_ipi_init(); 174366f6083SPeter Grehan 175366f6083SPeter Grehan error = vmm_mem_init(); 176366f6083SPeter Grehan if (error) 177366f6083SPeter Grehan return (error); 178366f6083SPeter Grehan 179366f6083SPeter Grehan if (vmm_is_intel()) 180366f6083SPeter Grehan ops = &vmm_ops_intel; 181366f6083SPeter Grehan else if (vmm_is_amd()) 182366f6083SPeter Grehan ops = &vmm_ops_amd; 183366f6083SPeter Grehan else 184366f6083SPeter Grehan return (ENXIO); 185366f6083SPeter Grehan 186366f6083SPeter Grehan vmm_msr_init(); 187366f6083SPeter Grehan 188366f6083SPeter Grehan return (VMM_INIT()); 189366f6083SPeter Grehan } 190366f6083SPeter Grehan 191366f6083SPeter Grehan static int 192366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 193366f6083SPeter Grehan { 194366f6083SPeter Grehan int error; 195366f6083SPeter Grehan 196366f6083SPeter Grehan switch (what) { 197366f6083SPeter Grehan case MOD_LOAD: 198366f6083SPeter Grehan vmmdev_init(); 199366f6083SPeter Grehan iommu_init(); 200366f6083SPeter Grehan error = vmm_init(); 201366f6083SPeter Grehan break; 202366f6083SPeter Grehan case MOD_UNLOAD: 203366f6083SPeter Grehan vmmdev_cleanup(); 204366f6083SPeter Grehan iommu_cleanup(); 205366f6083SPeter Grehan vmm_ipi_cleanup(); 206366f6083SPeter Grehan error = VMM_CLEANUP(); 207366f6083SPeter Grehan break; 208366f6083SPeter Grehan default: 209366f6083SPeter Grehan error = 0; 210366f6083SPeter Grehan break; 211366f6083SPeter Grehan } 212366f6083SPeter Grehan return (error); 213366f6083SPeter Grehan } 214366f6083SPeter Grehan 215366f6083SPeter Grehan static moduledata_t vmm_kmod = { 216366f6083SPeter Grehan "vmm", 217366f6083SPeter Grehan vmm_handler, 218366f6083SPeter Grehan NULL 219366f6083SPeter Grehan }; 220366f6083SPeter Grehan 221366f6083SPeter Grehan /* 222366f6083SPeter Grehan * Execute the module load handler after the pci passthru driver has had 223366f6083SPeter Grehan * a chance to claim devices. We need this information at the time we do 224366f6083SPeter Grehan * iommu initialization. 225366f6083SPeter Grehan */ 226366f6083SPeter Grehan DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_CONFIGURE + 1, SI_ORDER_ANY); 227366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 228366f6083SPeter Grehan 229366f6083SPeter Grehan SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 230366f6083SPeter Grehan 231366f6083SPeter Grehan struct vm * 232366f6083SPeter Grehan vm_create(const char *name) 233366f6083SPeter Grehan { 234366f6083SPeter Grehan int i; 235366f6083SPeter Grehan struct vm *vm; 236366f6083SPeter Grehan vm_paddr_t maxaddr; 237366f6083SPeter Grehan 238366f6083SPeter Grehan const int BSP = 0; 239366f6083SPeter Grehan 240366f6083SPeter Grehan if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 241366f6083SPeter Grehan return (NULL); 242366f6083SPeter Grehan 243366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 244366f6083SPeter Grehan strcpy(vm->name, name); 245366f6083SPeter Grehan vm->cookie = VMINIT(vm); 246366f6083SPeter Grehan 247366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) { 248366f6083SPeter Grehan vcpu_init(vm, i); 249366f6083SPeter Grehan guest_msrs_init(vm, i); 250366f6083SPeter Grehan } 251366f6083SPeter Grehan 252366f6083SPeter Grehan maxaddr = vmm_mem_maxaddr(); 253366f6083SPeter Grehan vm->iommu = iommu_create_domain(maxaddr); 254366f6083SPeter Grehan vm_activate_cpu(vm, BSP); 255366f6083SPeter Grehan 256366f6083SPeter Grehan return (vm); 257366f6083SPeter Grehan } 258366f6083SPeter Grehan 259366f6083SPeter Grehan void 260366f6083SPeter Grehan vm_destroy(struct vm *vm) 261366f6083SPeter Grehan { 262366f6083SPeter Grehan int i; 263366f6083SPeter Grehan 264366f6083SPeter Grehan ppt_unassign_all(vm); 265366f6083SPeter Grehan 266366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) 267366f6083SPeter Grehan vmm_mem_free(vm->mem_segs[i].hpa, vm->mem_segs[i].len); 268366f6083SPeter Grehan 269366f6083SPeter Grehan for (i = 0; i < VM_MAXCPU; i++) 270366f6083SPeter Grehan vcpu_cleanup(&vm->vcpu[i]); 271366f6083SPeter Grehan 272366f6083SPeter Grehan iommu_destroy_domain(vm->iommu); 273366f6083SPeter Grehan 274366f6083SPeter Grehan VMCLEANUP(vm->cookie); 275366f6083SPeter Grehan 276366f6083SPeter Grehan free(vm, M_VM); 277366f6083SPeter Grehan } 278366f6083SPeter Grehan 279366f6083SPeter Grehan const char * 280366f6083SPeter Grehan vm_name(struct vm *vm) 281366f6083SPeter Grehan { 282366f6083SPeter Grehan return (vm->name); 283366f6083SPeter Grehan } 284366f6083SPeter Grehan 285366f6083SPeter Grehan int 286366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 287366f6083SPeter Grehan { 288366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 289366f6083SPeter Grehan 290366f6083SPeter Grehan return (VMMMAP(vm->cookie, gpa, hpa, len, VM_MEMATTR_UNCACHEABLE, 291366f6083SPeter Grehan VM_PROT_RW, spok)); 292366f6083SPeter Grehan } 293366f6083SPeter Grehan 294366f6083SPeter Grehan int 295366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 296366f6083SPeter Grehan { 297366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 298366f6083SPeter Grehan 299366f6083SPeter Grehan return (VMMMAP(vm->cookie, gpa, 0, len, VM_MEMATTR_UNCACHEABLE, 300366f6083SPeter Grehan VM_PROT_NONE, spok)); 301366f6083SPeter Grehan } 302366f6083SPeter Grehan 303366f6083SPeter Grehan int 304366f6083SPeter Grehan vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t *ret_hpa) 305366f6083SPeter Grehan { 306366f6083SPeter Grehan int error; 307366f6083SPeter Grehan vm_paddr_t hpa; 308366f6083SPeter Grehan 309366f6083SPeter Grehan const boolean_t spok = TRUE; /* superpage mappings are ok */ 310366f6083SPeter Grehan 311366f6083SPeter Grehan /* 312366f6083SPeter Grehan * find the hpa if already it was already vm_malloc'd. 313366f6083SPeter Grehan */ 314366f6083SPeter Grehan hpa = vm_gpa2hpa(vm, gpa, len); 315366f6083SPeter Grehan if (hpa != ((vm_paddr_t)-1)) 316366f6083SPeter Grehan goto out; 317366f6083SPeter Grehan 318366f6083SPeter Grehan if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS) 319366f6083SPeter Grehan return (E2BIG); 320366f6083SPeter Grehan 321366f6083SPeter Grehan hpa = vmm_mem_alloc(len); 322366f6083SPeter Grehan if (hpa == 0) 323366f6083SPeter Grehan return (ENOMEM); 324366f6083SPeter Grehan 325366f6083SPeter Grehan error = VMMMAP(vm->cookie, gpa, hpa, len, VM_MEMATTR_WRITE_BACK, 326366f6083SPeter Grehan VM_PROT_ALL, spok); 327366f6083SPeter Grehan if (error) { 328366f6083SPeter Grehan vmm_mem_free(hpa, len); 329366f6083SPeter Grehan return (error); 330366f6083SPeter Grehan } 331366f6083SPeter Grehan 332366f6083SPeter Grehan iommu_create_mapping(vm->iommu, gpa, hpa, len); 333366f6083SPeter Grehan 334366f6083SPeter Grehan vm->mem_segs[vm->num_mem_segs].gpa = gpa; 335366f6083SPeter Grehan vm->mem_segs[vm->num_mem_segs].hpa = hpa; 336366f6083SPeter Grehan vm->mem_segs[vm->num_mem_segs].len = len; 337366f6083SPeter Grehan vm->num_mem_segs++; 338366f6083SPeter Grehan out: 339366f6083SPeter Grehan *ret_hpa = hpa; 340366f6083SPeter Grehan return (0); 341366f6083SPeter Grehan } 342366f6083SPeter Grehan 343366f6083SPeter Grehan vm_paddr_t 344366f6083SPeter Grehan vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t len) 345366f6083SPeter Grehan { 346366f6083SPeter Grehan int i; 347366f6083SPeter Grehan vm_paddr_t gpabase, gpalimit, hpabase; 348366f6083SPeter Grehan 349366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) { 350366f6083SPeter Grehan hpabase = vm->mem_segs[i].hpa; 351366f6083SPeter Grehan gpabase = vm->mem_segs[i].gpa; 352366f6083SPeter Grehan gpalimit = gpabase + vm->mem_segs[i].len; 353366f6083SPeter Grehan if (gpa >= gpabase && gpa + len <= gpalimit) 354366f6083SPeter Grehan return ((gpa - gpabase) + hpabase); 355366f6083SPeter Grehan } 356366f6083SPeter Grehan return ((vm_paddr_t)-1); 357366f6083SPeter Grehan } 358366f6083SPeter Grehan 359366f6083SPeter Grehan int 360366f6083SPeter Grehan vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 361366f6083SPeter Grehan struct vm_memory_segment *seg) 362366f6083SPeter Grehan { 363366f6083SPeter Grehan int i; 364366f6083SPeter Grehan 365366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) { 366366f6083SPeter Grehan if (gpabase == vm->mem_segs[i].gpa) { 367366f6083SPeter Grehan *seg = vm->mem_segs[i]; 368366f6083SPeter Grehan return (0); 369366f6083SPeter Grehan } 370366f6083SPeter Grehan } 371366f6083SPeter Grehan return (-1); 372366f6083SPeter Grehan } 373366f6083SPeter Grehan 374366f6083SPeter Grehan int 375366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 376366f6083SPeter Grehan { 377366f6083SPeter Grehan 378366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 379366f6083SPeter Grehan return (EINVAL); 380366f6083SPeter Grehan 381366f6083SPeter Grehan if (reg >= VM_REG_LAST) 382366f6083SPeter Grehan return (EINVAL); 383366f6083SPeter Grehan 384366f6083SPeter Grehan return (VMGETREG(vm->cookie, vcpu, reg, retval)); 385366f6083SPeter Grehan } 386366f6083SPeter Grehan 387366f6083SPeter Grehan int 388366f6083SPeter Grehan vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val) 389366f6083SPeter Grehan { 390366f6083SPeter Grehan 391366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 392366f6083SPeter Grehan return (EINVAL); 393366f6083SPeter Grehan 394366f6083SPeter Grehan if (reg >= VM_REG_LAST) 395366f6083SPeter Grehan return (EINVAL); 396366f6083SPeter Grehan 397366f6083SPeter Grehan return (VMSETREG(vm->cookie, vcpu, reg, val)); 398366f6083SPeter Grehan } 399366f6083SPeter Grehan 400366f6083SPeter Grehan static boolean_t 401366f6083SPeter Grehan is_descriptor_table(int reg) 402366f6083SPeter Grehan { 403366f6083SPeter Grehan 404366f6083SPeter Grehan switch (reg) { 405366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 406366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 407366f6083SPeter Grehan return (TRUE); 408366f6083SPeter Grehan default: 409366f6083SPeter Grehan return (FALSE); 410366f6083SPeter Grehan } 411366f6083SPeter Grehan } 412366f6083SPeter Grehan 413366f6083SPeter Grehan static boolean_t 414366f6083SPeter Grehan is_segment_register(int reg) 415366f6083SPeter Grehan { 416366f6083SPeter Grehan 417366f6083SPeter Grehan switch (reg) { 418366f6083SPeter Grehan case VM_REG_GUEST_ES: 419366f6083SPeter Grehan case VM_REG_GUEST_CS: 420366f6083SPeter Grehan case VM_REG_GUEST_SS: 421366f6083SPeter Grehan case VM_REG_GUEST_DS: 422366f6083SPeter Grehan case VM_REG_GUEST_FS: 423366f6083SPeter Grehan case VM_REG_GUEST_GS: 424366f6083SPeter Grehan case VM_REG_GUEST_TR: 425366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 426366f6083SPeter Grehan return (TRUE); 427366f6083SPeter Grehan default: 428366f6083SPeter Grehan return (FALSE); 429366f6083SPeter Grehan } 430366f6083SPeter Grehan } 431366f6083SPeter Grehan 432366f6083SPeter Grehan int 433366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 434366f6083SPeter Grehan struct seg_desc *desc) 435366f6083SPeter Grehan { 436366f6083SPeter Grehan 437366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 438366f6083SPeter Grehan return (EINVAL); 439366f6083SPeter Grehan 440366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 441366f6083SPeter Grehan return (EINVAL); 442366f6083SPeter Grehan 443366f6083SPeter Grehan return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 444366f6083SPeter Grehan } 445366f6083SPeter Grehan 446366f6083SPeter Grehan int 447366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 448366f6083SPeter Grehan struct seg_desc *desc) 449366f6083SPeter Grehan { 450366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 451366f6083SPeter Grehan return (EINVAL); 452366f6083SPeter Grehan 453366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 454366f6083SPeter Grehan return (EINVAL); 455366f6083SPeter Grehan 456366f6083SPeter Grehan return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 457366f6083SPeter Grehan } 458366f6083SPeter Grehan 459366f6083SPeter Grehan int 460366f6083SPeter Grehan vm_get_pinning(struct vm *vm, int vcpuid, int *cpuid) 461366f6083SPeter Grehan { 462366f6083SPeter Grehan 463366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 464366f6083SPeter Grehan return (EINVAL); 465366f6083SPeter Grehan 466366f6083SPeter Grehan *cpuid = VCPU_PINCPU(vm, vcpuid); 467366f6083SPeter Grehan 468366f6083SPeter Grehan return (0); 469366f6083SPeter Grehan } 470366f6083SPeter Grehan 471366f6083SPeter Grehan int 472366f6083SPeter Grehan vm_set_pinning(struct vm *vm, int vcpuid, int host_cpuid) 473366f6083SPeter Grehan { 474366f6083SPeter Grehan struct thread *td; 475366f6083SPeter Grehan 476366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 477366f6083SPeter Grehan return (EINVAL); 478366f6083SPeter Grehan 479366f6083SPeter Grehan td = curthread; /* XXXSMP only safe when muxing vcpus */ 480366f6083SPeter Grehan 481366f6083SPeter Grehan /* unpin */ 482366f6083SPeter Grehan if (host_cpuid < 0) { 483366f6083SPeter Grehan VCPU_UNPIN(vm, vcpuid); 484366f6083SPeter Grehan thread_lock(td); 485366f6083SPeter Grehan sched_unbind(td); 486366f6083SPeter Grehan thread_unlock(td); 487366f6083SPeter Grehan return (0); 488366f6083SPeter Grehan } 489366f6083SPeter Grehan 490366f6083SPeter Grehan if (CPU_ABSENT(host_cpuid)) 491366f6083SPeter Grehan return (EINVAL); 492366f6083SPeter Grehan 493366f6083SPeter Grehan /* 494366f6083SPeter Grehan * XXX we should check that 'host_cpuid' has not already been pinned 495366f6083SPeter Grehan * by another vm. 496366f6083SPeter Grehan */ 497366f6083SPeter Grehan thread_lock(td); 498366f6083SPeter Grehan sched_bind(td, host_cpuid); 499366f6083SPeter Grehan thread_unlock(td); 500366f6083SPeter Grehan VCPU_PIN(vm, vcpuid, host_cpuid); 501366f6083SPeter Grehan 502366f6083SPeter Grehan return (0); 503366f6083SPeter Grehan } 504366f6083SPeter Grehan 505366f6083SPeter Grehan static void 506366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 507366f6083SPeter Grehan { 508366f6083SPeter Grehan register_t s; 509366f6083SPeter Grehan 510366f6083SPeter Grehan s = intr_disable(); 511366f6083SPeter Grehan fpu_stop_emulating(); 512366f6083SPeter Grehan fxrstor(&vcpu->savefpu); 513366f6083SPeter Grehan fpu_start_emulating(); 514366f6083SPeter Grehan intr_restore(s); 515366f6083SPeter Grehan } 516366f6083SPeter Grehan 517366f6083SPeter Grehan static void 518366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 519366f6083SPeter Grehan { 520366f6083SPeter Grehan register_t s; 521366f6083SPeter Grehan 522366f6083SPeter Grehan s = intr_disable(); 523366f6083SPeter Grehan fpu_stop_emulating(); 524366f6083SPeter Grehan fxsave(&vcpu->savefpu); 525366f6083SPeter Grehan fpu_start_emulating(); 526366f6083SPeter Grehan intr_restore(s); 527366f6083SPeter Grehan } 528366f6083SPeter Grehan 529366f6083SPeter Grehan int 530366f6083SPeter Grehan vm_run(struct vm *vm, struct vm_run *vmrun) 531366f6083SPeter Grehan { 532366f6083SPeter Grehan int error, vcpuid; 533366f6083SPeter Grehan struct vcpu *vcpu; 534366f6083SPeter Grehan struct pcb *pcb; 535366f6083SPeter Grehan uint64_t tscval; 536366f6083SPeter Grehan 537366f6083SPeter Grehan vcpuid = vmrun->cpuid; 538366f6083SPeter Grehan 539366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 540366f6083SPeter Grehan return (EINVAL); 541366f6083SPeter Grehan 542366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 543366f6083SPeter Grehan 544366f6083SPeter Grehan critical_enter(); 545366f6083SPeter Grehan 546366f6083SPeter Grehan tscval = rdtsc(); 547366f6083SPeter Grehan 548366f6083SPeter Grehan pcb = PCPU_GET(curpcb); 549*34a6b2d6SJohn Baldwin set_pcb_flags(pcb, PCB_FULL_IRET); 550366f6083SPeter Grehan 551366f6083SPeter Grehan vcpu->hostcpu = curcpu; 552366f6083SPeter Grehan 553366f6083SPeter Grehan fpuexit(curthread); 554366f6083SPeter Grehan restore_guest_msrs(vm, vcpuid); 555366f6083SPeter Grehan restore_guest_fpustate(vcpu); 556366f6083SPeter Grehan error = VMRUN(vm->cookie, vcpuid, vmrun->rip, &vmrun->vm_exit); 557366f6083SPeter Grehan save_guest_fpustate(vcpu); 558366f6083SPeter Grehan restore_host_msrs(vm, vcpuid); 559366f6083SPeter Grehan 560366f6083SPeter Grehan vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 561366f6083SPeter Grehan 562366f6083SPeter Grehan critical_exit(); 563366f6083SPeter Grehan 564366f6083SPeter Grehan return (error); 565366f6083SPeter Grehan } 566366f6083SPeter Grehan 567366f6083SPeter Grehan int 568366f6083SPeter Grehan vm_inject_event(struct vm *vm, int vcpuid, int type, 569366f6083SPeter Grehan int vector, uint32_t code, int code_valid) 570366f6083SPeter Grehan { 571366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 572366f6083SPeter Grehan return (EINVAL); 573366f6083SPeter Grehan 574366f6083SPeter Grehan if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0) 575366f6083SPeter Grehan return (EINVAL); 576366f6083SPeter Grehan 577366f6083SPeter Grehan if (vector < 0 || vector > 255) 578366f6083SPeter Grehan return (EINVAL); 579366f6083SPeter Grehan 580366f6083SPeter Grehan return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid)); 581366f6083SPeter Grehan } 582366f6083SPeter Grehan 583366f6083SPeter Grehan int 584366f6083SPeter Grehan vm_inject_nmi(struct vm *vm, int vcpu) 585366f6083SPeter Grehan { 586366f6083SPeter Grehan int error; 587366f6083SPeter Grehan 588366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 589366f6083SPeter Grehan return (EINVAL); 590366f6083SPeter Grehan 591366f6083SPeter Grehan error = VMNMI(vm->cookie, vcpu); 592366f6083SPeter Grehan vm_interrupt_hostcpu(vm, vcpu); 593366f6083SPeter Grehan return (error); 594366f6083SPeter Grehan } 595366f6083SPeter Grehan 596366f6083SPeter Grehan int 597366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 598366f6083SPeter Grehan { 599366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 600366f6083SPeter Grehan return (EINVAL); 601366f6083SPeter Grehan 602366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 603366f6083SPeter Grehan return (EINVAL); 604366f6083SPeter Grehan 605366f6083SPeter Grehan return (VMGETCAP(vm->cookie, vcpu, type, retval)); 606366f6083SPeter Grehan } 607366f6083SPeter Grehan 608366f6083SPeter Grehan int 609366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val) 610366f6083SPeter Grehan { 611366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 612366f6083SPeter Grehan return (EINVAL); 613366f6083SPeter Grehan 614366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 615366f6083SPeter Grehan return (EINVAL); 616366f6083SPeter Grehan 617366f6083SPeter Grehan return (VMSETCAP(vm->cookie, vcpu, type, val)); 618366f6083SPeter Grehan } 619366f6083SPeter Grehan 620366f6083SPeter Grehan uint64_t * 621366f6083SPeter Grehan vm_guest_msrs(struct vm *vm, int cpu) 622366f6083SPeter Grehan { 623366f6083SPeter Grehan return (vm->vcpu[cpu].guest_msrs); 624366f6083SPeter Grehan } 625366f6083SPeter Grehan 626366f6083SPeter Grehan struct vlapic * 627366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu) 628366f6083SPeter Grehan { 629366f6083SPeter Grehan return (vm->vcpu[cpu].vlapic); 630366f6083SPeter Grehan } 631366f6083SPeter Grehan 632366f6083SPeter Grehan boolean_t 633366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 634366f6083SPeter Grehan { 635366f6083SPeter Grehan int found, b, s, f, n; 636366f6083SPeter Grehan char *val, *cp, *cp2; 637366f6083SPeter Grehan 638366f6083SPeter Grehan /* 639366f6083SPeter Grehan * setenv pptdevs "1/2/3 4/5/6 7/8/9 10/11/12" 640366f6083SPeter Grehan */ 641366f6083SPeter Grehan found = 0; 642366f6083SPeter Grehan cp = val = getenv("pptdevs"); 643366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 644366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 645366f6083SPeter Grehan *cp2 = '\0'; 646366f6083SPeter Grehan 647366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 648366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 649366f6083SPeter Grehan found = 1; 650366f6083SPeter Grehan break; 651366f6083SPeter Grehan } 652366f6083SPeter Grehan 653366f6083SPeter Grehan if (cp2 != NULL) 654366f6083SPeter Grehan *cp2++ = ' '; 655366f6083SPeter Grehan 656366f6083SPeter Grehan cp = cp2; 657366f6083SPeter Grehan } 658366f6083SPeter Grehan freeenv(val); 659366f6083SPeter Grehan return (found); 660366f6083SPeter Grehan } 661366f6083SPeter Grehan 662366f6083SPeter Grehan void * 663366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 664366f6083SPeter Grehan { 665366f6083SPeter Grehan 666366f6083SPeter Grehan return (vm->iommu); 667366f6083SPeter Grehan } 668366f6083SPeter Grehan 669366f6083SPeter Grehan void 670366f6083SPeter Grehan vm_set_run_state(struct vm *vm, int vcpuid, int state) 671366f6083SPeter Grehan { 672366f6083SPeter Grehan struct vcpu *vcpu; 673366f6083SPeter Grehan 674366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 675366f6083SPeter Grehan panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 676366f6083SPeter Grehan 677366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 678366f6083SPeter Grehan 679366f6083SPeter Grehan if (state == VCPU_RUNNING) { 680366f6083SPeter Grehan if (vcpu->flags & VCPU_F_RUNNING) { 681366f6083SPeter Grehan panic("vm_set_run_state: %s[%d] is already running", 682366f6083SPeter Grehan vm_name(vm), vcpuid); 683366f6083SPeter Grehan } 684366f6083SPeter Grehan vcpu->flags |= VCPU_F_RUNNING; 685366f6083SPeter Grehan } else { 686366f6083SPeter Grehan if ((vcpu->flags & VCPU_F_RUNNING) == 0) { 687366f6083SPeter Grehan panic("vm_set_run_state: %s[%d] is already stopped", 688366f6083SPeter Grehan vm_name(vm), vcpuid); 689366f6083SPeter Grehan } 690366f6083SPeter Grehan vcpu->flags &= ~VCPU_F_RUNNING; 691366f6083SPeter Grehan } 692366f6083SPeter Grehan } 693366f6083SPeter Grehan 694366f6083SPeter Grehan int 695366f6083SPeter Grehan vm_get_run_state(struct vm *vm, int vcpuid, int *cpuptr) 696366f6083SPeter Grehan { 697366f6083SPeter Grehan int retval, hostcpu; 698366f6083SPeter Grehan struct vcpu *vcpu; 699366f6083SPeter Grehan 700366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 701366f6083SPeter Grehan panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 702366f6083SPeter Grehan 703366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 704366f6083SPeter Grehan if (vcpu->flags & VCPU_F_RUNNING) { 705366f6083SPeter Grehan retval = VCPU_RUNNING; 706366f6083SPeter Grehan hostcpu = vcpu->hostcpu; 707366f6083SPeter Grehan } else { 708366f6083SPeter Grehan retval = VCPU_STOPPED; 709366f6083SPeter Grehan hostcpu = -1; 710366f6083SPeter Grehan } 711366f6083SPeter Grehan 712366f6083SPeter Grehan if (cpuptr) 713366f6083SPeter Grehan *cpuptr = hostcpu; 714366f6083SPeter Grehan 715366f6083SPeter Grehan return (retval); 716366f6083SPeter Grehan } 717366f6083SPeter Grehan 718366f6083SPeter Grehan void 719366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid) 720366f6083SPeter Grehan { 721366f6083SPeter Grehan 722366f6083SPeter Grehan if (vcpuid >= 0 && vcpuid < VM_MAXCPU) 723366f6083SPeter Grehan vm->active_cpus |= vcpu_mask(vcpuid); 724366f6083SPeter Grehan } 725366f6083SPeter Grehan 726366f6083SPeter Grehan cpumask_t 727366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 728366f6083SPeter Grehan { 729366f6083SPeter Grehan 730366f6083SPeter Grehan return (vm->active_cpus); 731366f6083SPeter Grehan } 732366f6083SPeter Grehan 733366f6083SPeter Grehan void * 734366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid) 735366f6083SPeter Grehan { 736366f6083SPeter Grehan 737366f6083SPeter Grehan return (vm->vcpu[vcpuid].stats); 738366f6083SPeter Grehan } 739