1366f6083SPeter Grehan /*- 2366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 3366f6083SPeter Grehan * All rights reserved. 4366f6083SPeter Grehan * 5366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 6366f6083SPeter Grehan * modification, are permitted provided that the following conditions 7366f6083SPeter Grehan * are met: 8366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 9366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 10366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 12366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 13366f6083SPeter Grehan * 14366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24366f6083SPeter Grehan * SUCH DAMAGE. 25366f6083SPeter Grehan * 26366f6083SPeter Grehan * $FreeBSD$ 27366f6083SPeter Grehan */ 28366f6083SPeter Grehan 29366f6083SPeter Grehan #include <sys/cdefs.h> 30366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 31366f6083SPeter Grehan 32366f6083SPeter Grehan #include <sys/param.h> 3338f1b189SPeter Grehan #include <sys/systm.h> 34366f6083SPeter Grehan #include <sys/kernel.h> 35366f6083SPeter Grehan #include <sys/module.h> 36366f6083SPeter Grehan #include <sys/sysctl.h> 37366f6083SPeter Grehan #include <sys/malloc.h> 38366f6083SPeter Grehan #include <sys/pcpu.h> 39366f6083SPeter Grehan #include <sys/lock.h> 40366f6083SPeter Grehan #include <sys/mutex.h> 41366f6083SPeter Grehan #include <sys/proc.h> 42318224bbSNeel Natu #include <sys/rwlock.h> 43366f6083SPeter Grehan #include <sys/sched.h> 44366f6083SPeter Grehan #include <sys/smp.h> 45366f6083SPeter Grehan #include <sys/systm.h> 46366f6083SPeter Grehan 47366f6083SPeter Grehan #include <vm/vm.h> 48318224bbSNeel Natu #include <vm/vm_object.h> 49318224bbSNeel Natu #include <vm/vm_page.h> 50318224bbSNeel Natu #include <vm/pmap.h> 51318224bbSNeel Natu #include <vm/vm_map.h> 52318224bbSNeel Natu #include <vm/vm_extern.h> 53318224bbSNeel Natu #include <vm/vm_param.h> 54366f6083SPeter Grehan 5563e62d39SJohn Baldwin #include <machine/cpu.h> 56366f6083SPeter Grehan #include <machine/vm.h> 57366f6083SPeter Grehan #include <machine/pcb.h> 5875dd3366SNeel Natu #include <machine/smp.h> 591c052192SNeel Natu #include <x86/psl.h> 6034a6b2d6SJohn Baldwin #include <x86/apicreg.h> 61318224bbSNeel Natu #include <machine/vmparam.h> 62366f6083SPeter Grehan 63366f6083SPeter Grehan #include <machine/vmm.h> 64565bbb86SNeel Natu #include <machine/vmm_dev.h> 65e813a873SNeel Natu #include <machine/vmm_instruction_emul.h> 66565bbb86SNeel Natu 67d17b5104SNeel Natu #include "vmm_ioport.h" 68318224bbSNeel Natu #include "vmm_ktr.h" 69b01c2033SNeel Natu #include "vmm_host.h" 70366f6083SPeter Grehan #include "vmm_mem.h" 71366f6083SPeter Grehan #include "vmm_util.h" 72762fd208STycho Nightingale #include "vatpic.h" 73e883c9bbSTycho Nightingale #include "vatpit.h" 7408e3ff32SNeel Natu #include "vhpet.h" 75565bbb86SNeel Natu #include "vioapic.h" 76366f6083SPeter Grehan #include "vlapic.h" 77366f6083SPeter Grehan #include "vmm_msr.h" 78366f6083SPeter Grehan #include "vmm_ipi.h" 79366f6083SPeter Grehan #include "vmm_stat.h" 80f76fc5d4SNeel Natu #include "vmm_lapic.h" 81366f6083SPeter Grehan 82366f6083SPeter Grehan #include "io/ppt.h" 83366f6083SPeter Grehan #include "io/iommu.h" 84366f6083SPeter Grehan 85366f6083SPeter Grehan struct vlapic; 86366f6083SPeter Grehan 875fcf252fSNeel Natu /* 885fcf252fSNeel Natu * Initialization: 895fcf252fSNeel Natu * (a) allocated when vcpu is created 905fcf252fSNeel Natu * (i) initialized when vcpu is created and when it is reinitialized 915fcf252fSNeel Natu * (o) initialized the first time the vcpu is created 925fcf252fSNeel Natu * (x) initialized before use 935fcf252fSNeel Natu */ 94366f6083SPeter Grehan struct vcpu { 955fcf252fSNeel Natu struct mtx mtx; /* (o) protects 'state' and 'hostcpu' */ 965fcf252fSNeel Natu enum vcpu_state state; /* (o) vcpu state */ 975fcf252fSNeel Natu int hostcpu; /* (o) vcpu's host cpu */ 985fcf252fSNeel Natu struct vlapic *vlapic; /* (i) APIC device model */ 995fcf252fSNeel Natu enum x2apic_state x2apic_state; /* (i) APIC mode */ 1005fcf252fSNeel Natu int nmi_pending; /* (i) NMI pending */ 1015fcf252fSNeel Natu int extint_pending; /* (i) INTR pending */ 1025fcf252fSNeel Natu struct vm_exception exception; /* (x) exception collateral */ 1035fcf252fSNeel Natu int exception_pending; /* (i) exception pending */ 1045fcf252fSNeel Natu struct savefpu *guestfpu; /* (a,i) guest fpu state */ 1055fcf252fSNeel Natu uint64_t guest_xcr0; /* (i) guest %xcr0 register */ 1065fcf252fSNeel Natu void *stats; /* (a,i) statistics */ 1075fcf252fSNeel Natu uint64_t guest_msrs[VMM_MSR_NUM]; /* (i) emulated MSRs */ 1085fcf252fSNeel Natu struct vm_exit exitinfo; /* (x) exit reason and collateral */ 109366f6083SPeter Grehan }; 110366f6083SPeter Grehan 1115fcf252fSNeel Natu #define vcpu_lock_initialized(v) mtx_initialized(&((v)->mtx)) 112f76fc5d4SNeel Natu #define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_SPIN) 113f76fc5d4SNeel Natu #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) 114f76fc5d4SNeel Natu #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) 115318224bbSNeel Natu #define vcpu_assert_locked(v) mtx_assert(&((v)->mtx), MA_OWNED) 11675dd3366SNeel Natu 117318224bbSNeel Natu struct mem_seg { 118318224bbSNeel Natu vm_paddr_t gpa; 119318224bbSNeel Natu size_t len; 120318224bbSNeel Natu boolean_t wired; 121318224bbSNeel Natu vm_object_t object; 122318224bbSNeel Natu }; 123366f6083SPeter Grehan #define VM_MAX_MEMORY_SEGMENTS 2 124366f6083SPeter Grehan 125366f6083SPeter Grehan /* 1265fcf252fSNeel Natu * Initialization: 1275fcf252fSNeel Natu * (o) initialized the first time the VM is created 1285fcf252fSNeel Natu * (i) initialized when VM is created and when it is reinitialized 1295fcf252fSNeel Natu * (x) initialized before use 130366f6083SPeter Grehan */ 1315fcf252fSNeel Natu struct vm { 1325fcf252fSNeel Natu void *cookie; /* (i) cpu-specific data */ 1335fcf252fSNeel Natu void *iommu; /* (x) iommu-specific data */ 1345fcf252fSNeel Natu struct vhpet *vhpet; /* (i) virtual HPET */ 1355fcf252fSNeel Natu struct vioapic *vioapic; /* (i) virtual ioapic */ 1365fcf252fSNeel Natu struct vatpic *vatpic; /* (i) virtual atpic */ 1375fcf252fSNeel Natu struct vatpit *vatpit; /* (i) virtual atpit */ 1385fcf252fSNeel Natu volatile cpuset_t active_cpus; /* (i) active vcpus */ 1395fcf252fSNeel Natu int suspend; /* (i) stop VM execution */ 1405fcf252fSNeel Natu volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */ 1415fcf252fSNeel Natu volatile cpuset_t halted_cpus; /* (x) cpus in a hard halt */ 1425fcf252fSNeel Natu cpuset_t rendezvous_req_cpus; /* (x) rendezvous requested */ 1435fcf252fSNeel Natu cpuset_t rendezvous_done_cpus; /* (x) rendezvous finished */ 1445fcf252fSNeel Natu void *rendezvous_arg; /* (x) rendezvous func/arg */ 1455b8a8cd1SNeel Natu vm_rendezvous_func_t rendezvous_func; 1465fcf252fSNeel Natu struct mtx rendezvous_mtx; /* (o) rendezvous lock */ 1475fcf252fSNeel Natu int num_mem_segs; /* (o) guest memory segments */ 1485fcf252fSNeel Natu struct mem_seg mem_segs[VM_MAX_MEMORY_SEGMENTS]; 1495fcf252fSNeel Natu struct vmspace *vmspace; /* (o) guest's address space */ 1505fcf252fSNeel Natu char name[VM_MAX_NAMELEN]; /* (o) virtual machine name */ 1515fcf252fSNeel Natu struct vcpu vcpu[VM_MAXCPU]; /* (i) guest vcpus */ 152366f6083SPeter Grehan }; 153366f6083SPeter Grehan 154d5408b1dSNeel Natu static int vmm_initialized; 155d5408b1dSNeel Natu 156366f6083SPeter Grehan static struct vmm_ops *ops; 157add611fdSNeel Natu #define VMM_INIT(num) (ops != NULL ? (*ops->init)(num) : 0) 158366f6083SPeter Grehan #define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 15963e62d39SJohn Baldwin #define VMM_RESUME() (ops != NULL ? (*ops->resume)() : 0) 160366f6083SPeter Grehan 161318224bbSNeel Natu #define VMINIT(vm, pmap) (ops != NULL ? (*ops->vminit)(vm, pmap): NULL) 162b15a09c0SNeel Natu #define VMRUN(vmi, vcpu, rip, pmap, rptr, sptr) \ 163b15a09c0SNeel Natu (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, pmap, rptr, sptr) : ENXIO) 164366f6083SPeter Grehan #define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 165318224bbSNeel Natu #define VMSPACE_ALLOC(min, max) \ 166318224bbSNeel Natu (ops != NULL ? (*ops->vmspace_alloc)(min, max) : NULL) 167318224bbSNeel Natu #define VMSPACE_FREE(vmspace) \ 168318224bbSNeel Natu (ops != NULL ? (*ops->vmspace_free)(vmspace) : ENXIO) 169366f6083SPeter Grehan #define VMGETREG(vmi, vcpu, num, retval) \ 170366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 171366f6083SPeter Grehan #define VMSETREG(vmi, vcpu, num, val) \ 172366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 173366f6083SPeter Grehan #define VMGETDESC(vmi, vcpu, num, desc) \ 174366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 175366f6083SPeter Grehan #define VMSETDESC(vmi, vcpu, num, desc) \ 176366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 177366f6083SPeter Grehan #define VMGETCAP(vmi, vcpu, num, retval) \ 178366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 179366f6083SPeter Grehan #define VMSETCAP(vmi, vcpu, num, val) \ 180366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 181de5ea6b6SNeel Natu #define VLAPIC_INIT(vmi, vcpu) \ 182de5ea6b6SNeel Natu (ops != NULL ? (*ops->vlapic_init)(vmi, vcpu) : NULL) 183de5ea6b6SNeel Natu #define VLAPIC_CLEANUP(vmi, vlapic) \ 184de5ea6b6SNeel Natu (ops != NULL ? (*ops->vlapic_cleanup)(vmi, vlapic) : NULL) 185366f6083SPeter Grehan 186014a52f3SNeel Natu #define fpu_start_emulating() load_cr0(rcr0() | CR0_TS) 187014a52f3SNeel Natu #define fpu_stop_emulating() clts() 188366f6083SPeter Grehan 189366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 190366f6083SPeter Grehan CTASSERT(VMM_MSR_NUM <= 64); /* msr_mask can keep track of up to 64 msrs */ 191366f6083SPeter Grehan 192366f6083SPeter Grehan /* statistics */ 19361592433SNeel Natu static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 194366f6083SPeter Grehan 195add611fdSNeel Natu SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 196add611fdSNeel Natu 197055fc2cbSNeel Natu /* 198055fc2cbSNeel Natu * Halt the guest if all vcpus are executing a HLT instruction with 199055fc2cbSNeel Natu * interrupts disabled. 200055fc2cbSNeel Natu */ 201055fc2cbSNeel Natu static int halt_detection_enabled = 1; 202055fc2cbSNeel Natu TUNABLE_INT("hw.vmm.halt_detection", &halt_detection_enabled); 203055fc2cbSNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, halt_detection, CTLFLAG_RDTUN, 204055fc2cbSNeel Natu &halt_detection_enabled, 0, 205055fc2cbSNeel Natu "Halt VM if all vcpus execute HLT with interrupts disabled"); 206055fc2cbSNeel Natu 207add611fdSNeel Natu static int vmm_ipinum; 208add611fdSNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, ipinum, CTLFLAG_RD, &vmm_ipinum, 0, 209add611fdSNeel Natu "IPI vector used for vcpu notifications"); 210add611fdSNeel Natu 211366f6083SPeter Grehan static void 2125fcf252fSNeel Natu vcpu_cleanup(struct vm *vm, int i, bool destroy) 213366f6083SPeter Grehan { 214de5ea6b6SNeel Natu struct vcpu *vcpu = &vm->vcpu[i]; 215de5ea6b6SNeel Natu 216de5ea6b6SNeel Natu VLAPIC_CLEANUP(vm->cookie, vcpu->vlapic); 2175fcf252fSNeel Natu if (destroy) { 218366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 21938f1b189SPeter Grehan fpu_save_area_free(vcpu->guestfpu); 220366f6083SPeter Grehan } 2215fcf252fSNeel Natu } 222366f6083SPeter Grehan 223366f6083SPeter Grehan static void 2245fcf252fSNeel Natu vcpu_init(struct vm *vm, int vcpu_id, bool create) 225366f6083SPeter Grehan { 226366f6083SPeter Grehan struct vcpu *vcpu; 227366f6083SPeter Grehan 2285fcf252fSNeel Natu KASSERT(vcpu_id >= 0 && vcpu_id < VM_MAXCPU, 2295fcf252fSNeel Natu ("vcpu_init: invalid vcpu %d", vcpu_id)); 2305fcf252fSNeel Natu 231366f6083SPeter Grehan vcpu = &vm->vcpu[vcpu_id]; 232366f6083SPeter Grehan 2335fcf252fSNeel Natu if (create) { 2345fcf252fSNeel Natu KASSERT(!vcpu_lock_initialized(vcpu), ("vcpu %d already " 2355fcf252fSNeel Natu "initialized", vcpu_id)); 23675dd3366SNeel Natu vcpu_lock_init(vcpu); 2375fcf252fSNeel Natu vcpu->state = VCPU_IDLE; 23875dd3366SNeel Natu vcpu->hostcpu = NOCPU; 2395fcf252fSNeel Natu vcpu->guestfpu = fpu_save_area_alloc(); 2405fcf252fSNeel Natu vcpu->stats = vmm_stat_alloc(); 2415fcf252fSNeel Natu } 2425fcf252fSNeel Natu 243de5ea6b6SNeel Natu vcpu->vlapic = VLAPIC_INIT(vm->cookie, vcpu_id); 24452e5c8a2SNeel Natu vm_set_x2apic_state(vm, vcpu_id, X2APIC_DISABLED); 2455fcf252fSNeel Natu vcpu->nmi_pending = 0; 2465fcf252fSNeel Natu vcpu->extint_pending = 0; 2475fcf252fSNeel Natu vcpu->exception_pending = 0; 248abb023fbSJohn Baldwin vcpu->guest_xcr0 = XFEATURE_ENABLED_X87; 24938f1b189SPeter Grehan fpu_save_area_reset(vcpu->guestfpu); 2505fcf252fSNeel Natu vmm_stat_init(vcpu->stats); 2515fcf252fSNeel Natu guest_msrs_init(vm, vcpu_id); 252366f6083SPeter Grehan } 253366f6083SPeter Grehan 25498ed632cSNeel Natu struct vm_exit * 25598ed632cSNeel Natu vm_exitinfo(struct vm *vm, int cpuid) 25698ed632cSNeel Natu { 25798ed632cSNeel Natu struct vcpu *vcpu; 25898ed632cSNeel Natu 25998ed632cSNeel Natu if (cpuid < 0 || cpuid >= VM_MAXCPU) 26098ed632cSNeel Natu panic("vm_exitinfo: invalid cpuid %d", cpuid); 26198ed632cSNeel Natu 26298ed632cSNeel Natu vcpu = &vm->vcpu[cpuid]; 26398ed632cSNeel Natu 26498ed632cSNeel Natu return (&vcpu->exitinfo); 26598ed632cSNeel Natu } 26698ed632cSNeel Natu 26763e62d39SJohn Baldwin static void 26863e62d39SJohn Baldwin vmm_resume(void) 26963e62d39SJohn Baldwin { 27063e62d39SJohn Baldwin VMM_RESUME(); 27163e62d39SJohn Baldwin } 27263e62d39SJohn Baldwin 273366f6083SPeter Grehan static int 274366f6083SPeter Grehan vmm_init(void) 275366f6083SPeter Grehan { 276366f6083SPeter Grehan int error; 277366f6083SPeter Grehan 278b01c2033SNeel Natu vmm_host_state_init(); 279add611fdSNeel Natu 280add611fdSNeel Natu vmm_ipinum = vmm_ipi_alloc(); 281add611fdSNeel Natu if (vmm_ipinum == 0) 282add611fdSNeel Natu vmm_ipinum = IPI_AST; 283366f6083SPeter Grehan 284366f6083SPeter Grehan error = vmm_mem_init(); 285366f6083SPeter Grehan if (error) 286366f6083SPeter Grehan return (error); 287366f6083SPeter Grehan 288366f6083SPeter Grehan if (vmm_is_intel()) 289366f6083SPeter Grehan ops = &vmm_ops_intel; 290366f6083SPeter Grehan else if (vmm_is_amd()) 291366f6083SPeter Grehan ops = &vmm_ops_amd; 292366f6083SPeter Grehan else 293366f6083SPeter Grehan return (ENXIO); 294366f6083SPeter Grehan 295366f6083SPeter Grehan vmm_msr_init(); 29663e62d39SJohn Baldwin vmm_resume_p = vmm_resume; 297366f6083SPeter Grehan 298add611fdSNeel Natu return (VMM_INIT(vmm_ipinum)); 299366f6083SPeter Grehan } 300366f6083SPeter Grehan 301366f6083SPeter Grehan static int 302366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 303366f6083SPeter Grehan { 304366f6083SPeter Grehan int error; 305366f6083SPeter Grehan 306366f6083SPeter Grehan switch (what) { 307366f6083SPeter Grehan case MOD_LOAD: 308366f6083SPeter Grehan vmmdev_init(); 30951f45d01SNeel Natu if (ppt_avail_devices() > 0) 310366f6083SPeter Grehan iommu_init(); 311366f6083SPeter Grehan error = vmm_init(); 312d5408b1dSNeel Natu if (error == 0) 313d5408b1dSNeel Natu vmm_initialized = 1; 314366f6083SPeter Grehan break; 315366f6083SPeter Grehan case MOD_UNLOAD: 316cdc5b9e7SNeel Natu error = vmmdev_cleanup(); 317cdc5b9e7SNeel Natu if (error == 0) { 31863e62d39SJohn Baldwin vmm_resume_p = NULL; 319366f6083SPeter Grehan iommu_cleanup(); 320add611fdSNeel Natu if (vmm_ipinum != IPI_AST) 321add611fdSNeel Natu vmm_ipi_free(vmm_ipinum); 322366f6083SPeter Grehan error = VMM_CLEANUP(); 32381ef6611SPeter Grehan /* 32481ef6611SPeter Grehan * Something bad happened - prevent new 32581ef6611SPeter Grehan * VMs from being created 32681ef6611SPeter Grehan */ 32781ef6611SPeter Grehan if (error) 328d5408b1dSNeel Natu vmm_initialized = 0; 32981ef6611SPeter Grehan } 330366f6083SPeter Grehan break; 331366f6083SPeter Grehan default: 332366f6083SPeter Grehan error = 0; 333366f6083SPeter Grehan break; 334366f6083SPeter Grehan } 335366f6083SPeter Grehan return (error); 336366f6083SPeter Grehan } 337366f6083SPeter Grehan 338366f6083SPeter Grehan static moduledata_t vmm_kmod = { 339366f6083SPeter Grehan "vmm", 340366f6083SPeter Grehan vmm_handler, 341366f6083SPeter Grehan NULL 342366f6083SPeter Grehan }; 343366f6083SPeter Grehan 344366f6083SPeter Grehan /* 345e3f0800bSNeel Natu * vmm initialization has the following dependencies: 346e3f0800bSNeel Natu * 347e3f0800bSNeel Natu * - iommu initialization must happen after the pci passthru driver has had 348e3f0800bSNeel Natu * a chance to attach to any passthru devices (after SI_SUB_CONFIGURE). 349e3f0800bSNeel Natu * 350e3f0800bSNeel Natu * - VT-x initialization requires smp_rendezvous() and therefore must happen 351e3f0800bSNeel Natu * after SMP is fully functional (after SI_SUB_SMP). 352366f6083SPeter Grehan */ 353e3f0800bSNeel Natu DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_SMP + 1, SI_ORDER_ANY); 354366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 355366f6083SPeter Grehan 3565fcf252fSNeel Natu static void 3575fcf252fSNeel Natu vm_init(struct vm *vm, bool create) 3585fcf252fSNeel Natu { 3595fcf252fSNeel Natu int i; 3605fcf252fSNeel Natu 3615fcf252fSNeel Natu vm->cookie = VMINIT(vm, vmspace_pmap(vm->vmspace)); 3625fcf252fSNeel Natu vm->iommu = NULL; 3635fcf252fSNeel Natu vm->vioapic = vioapic_init(vm); 3645fcf252fSNeel Natu vm->vhpet = vhpet_init(vm); 3655fcf252fSNeel Natu vm->vatpic = vatpic_init(vm); 3665fcf252fSNeel Natu vm->vatpit = vatpit_init(vm); 3675fcf252fSNeel Natu 3685fcf252fSNeel Natu CPU_ZERO(&vm->active_cpus); 3695fcf252fSNeel Natu 3705fcf252fSNeel Natu vm->suspend = 0; 3715fcf252fSNeel Natu CPU_ZERO(&vm->suspended_cpus); 3725fcf252fSNeel Natu 3735fcf252fSNeel Natu for (i = 0; i < VM_MAXCPU; i++) 3745fcf252fSNeel Natu vcpu_init(vm, i, create); 3755fcf252fSNeel Natu } 3765fcf252fSNeel Natu 377d5408b1dSNeel Natu int 378d5408b1dSNeel Natu vm_create(const char *name, struct vm **retvm) 379366f6083SPeter Grehan { 380366f6083SPeter Grehan struct vm *vm; 381318224bbSNeel Natu struct vmspace *vmspace; 382366f6083SPeter Grehan 383d5408b1dSNeel Natu /* 384d5408b1dSNeel Natu * If vmm.ko could not be successfully initialized then don't attempt 385d5408b1dSNeel Natu * to create the virtual machine. 386d5408b1dSNeel Natu */ 387d5408b1dSNeel Natu if (!vmm_initialized) 388d5408b1dSNeel Natu return (ENXIO); 389d5408b1dSNeel Natu 390366f6083SPeter Grehan if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 391d5408b1dSNeel Natu return (EINVAL); 392366f6083SPeter Grehan 393318224bbSNeel Natu vmspace = VMSPACE_ALLOC(VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS); 394318224bbSNeel Natu if (vmspace == NULL) 395318224bbSNeel Natu return (ENOMEM); 396318224bbSNeel Natu 397366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 398366f6083SPeter Grehan strcpy(vm->name, name); 3995fcf252fSNeel Natu vm->num_mem_segs = 0; 40088c4b8d1SNeel Natu vm->vmspace = vmspace; 4015b8a8cd1SNeel Natu mtx_init(&vm->rendezvous_mtx, "vm rendezvous lock", 0, MTX_DEF); 402366f6083SPeter Grehan 4035fcf252fSNeel Natu vm_init(vm, true); 404366f6083SPeter Grehan 405d5408b1dSNeel Natu *retvm = vm; 406d5408b1dSNeel Natu return (0); 407366f6083SPeter Grehan } 408366f6083SPeter Grehan 409f7d51510SNeel Natu static void 410318224bbSNeel Natu vm_free_mem_seg(struct vm *vm, struct mem_seg *seg) 411f7d51510SNeel Natu { 4127ce04d0aSNeel Natu 413318224bbSNeel Natu if (seg->object != NULL) 414318224bbSNeel Natu vmm_mem_free(vm->vmspace, seg->gpa, seg->len); 415f7d51510SNeel Natu 416318224bbSNeel Natu bzero(seg, sizeof(*seg)); 417f7d51510SNeel Natu } 418f7d51510SNeel Natu 4195fcf252fSNeel Natu static void 4205fcf252fSNeel Natu vm_cleanup(struct vm *vm, bool destroy) 421366f6083SPeter Grehan { 422366f6083SPeter Grehan int i; 423366f6083SPeter Grehan 424366f6083SPeter Grehan ppt_unassign_all(vm); 425366f6083SPeter Grehan 426318224bbSNeel Natu if (vm->iommu != NULL) 427318224bbSNeel Natu iommu_destroy_domain(vm->iommu); 428318224bbSNeel Natu 429e883c9bbSTycho Nightingale vatpit_cleanup(vm->vatpit); 43008e3ff32SNeel Natu vhpet_cleanup(vm->vhpet); 431762fd208STycho Nightingale vatpic_cleanup(vm->vatpic); 43208e3ff32SNeel Natu vioapic_cleanup(vm->vioapic); 43308e3ff32SNeel Natu 4345fcf252fSNeel Natu for (i = 0; i < VM_MAXCPU; i++) 4355fcf252fSNeel Natu vcpu_cleanup(vm, i, destroy); 4365fcf252fSNeel Natu 4375fcf252fSNeel Natu VMCLEANUP(vm->cookie); 4385fcf252fSNeel Natu 4395fcf252fSNeel Natu if (destroy) { 440366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) 441f7d51510SNeel Natu vm_free_mem_seg(vm, &vm->mem_segs[i]); 442f7d51510SNeel Natu 443f7d51510SNeel Natu vm->num_mem_segs = 0; 444366f6083SPeter Grehan 445318224bbSNeel Natu VMSPACE_FREE(vm->vmspace); 4465fcf252fSNeel Natu vm->vmspace = NULL; 4475fcf252fSNeel Natu } 4485fcf252fSNeel Natu } 449366f6083SPeter Grehan 4505fcf252fSNeel Natu void 4515fcf252fSNeel Natu vm_destroy(struct vm *vm) 4525fcf252fSNeel Natu { 4535fcf252fSNeel Natu vm_cleanup(vm, true); 454366f6083SPeter Grehan free(vm, M_VM); 455366f6083SPeter Grehan } 456366f6083SPeter Grehan 4575fcf252fSNeel Natu int 4585fcf252fSNeel Natu vm_reinit(struct vm *vm) 4595fcf252fSNeel Natu { 4605fcf252fSNeel Natu int error; 4615fcf252fSNeel Natu 4625fcf252fSNeel Natu /* 4635fcf252fSNeel Natu * A virtual machine can be reset only if all vcpus are suspended. 4645fcf252fSNeel Natu */ 4655fcf252fSNeel Natu if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 4665fcf252fSNeel Natu vm_cleanup(vm, false); 4675fcf252fSNeel Natu vm_init(vm, false); 4685fcf252fSNeel Natu error = 0; 4695fcf252fSNeel Natu } else { 4705fcf252fSNeel Natu error = EBUSY; 4715fcf252fSNeel Natu } 4725fcf252fSNeel Natu 4735fcf252fSNeel Natu return (error); 4745fcf252fSNeel Natu } 4755fcf252fSNeel Natu 476366f6083SPeter Grehan const char * 477366f6083SPeter Grehan vm_name(struct vm *vm) 478366f6083SPeter Grehan { 479366f6083SPeter Grehan return (vm->name); 480366f6083SPeter Grehan } 481366f6083SPeter Grehan 482366f6083SPeter Grehan int 483366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 484366f6083SPeter Grehan { 485318224bbSNeel Natu vm_object_t obj; 486366f6083SPeter Grehan 487318224bbSNeel Natu if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa)) == NULL) 488318224bbSNeel Natu return (ENOMEM); 489318224bbSNeel Natu else 490318224bbSNeel Natu return (0); 491366f6083SPeter Grehan } 492366f6083SPeter Grehan 493366f6083SPeter Grehan int 494366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 495366f6083SPeter Grehan { 496366f6083SPeter Grehan 497318224bbSNeel Natu vmm_mmio_free(vm->vmspace, gpa, len); 498318224bbSNeel Natu return (0); 499366f6083SPeter Grehan } 500366f6083SPeter Grehan 501318224bbSNeel Natu boolean_t 502318224bbSNeel Natu vm_mem_allocated(struct vm *vm, vm_paddr_t gpa) 503366f6083SPeter Grehan { 504341f19c9SNeel Natu int i; 505341f19c9SNeel Natu vm_paddr_t gpabase, gpalimit; 506341f19c9SNeel Natu 507341f19c9SNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 508341f19c9SNeel Natu gpabase = vm->mem_segs[i].gpa; 509341f19c9SNeel Natu gpalimit = gpabase + vm->mem_segs[i].len; 510341f19c9SNeel Natu if (gpa >= gpabase && gpa < gpalimit) 511318224bbSNeel Natu return (TRUE); /* 'gpa' is regular memory */ 512341f19c9SNeel Natu } 513341f19c9SNeel Natu 514318224bbSNeel Natu if (ppt_is_mmio(vm, gpa)) 515318224bbSNeel Natu return (TRUE); /* 'gpa' is pci passthru mmio */ 516318224bbSNeel Natu 517318224bbSNeel Natu return (FALSE); 518341f19c9SNeel Natu } 519341f19c9SNeel Natu 520341f19c9SNeel Natu int 521341f19c9SNeel Natu vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len) 522341f19c9SNeel Natu { 523318224bbSNeel Natu int available, allocated; 524318224bbSNeel Natu struct mem_seg *seg; 525318224bbSNeel Natu vm_object_t object; 526318224bbSNeel Natu vm_paddr_t g; 527366f6083SPeter Grehan 528341f19c9SNeel Natu if ((gpa & PAGE_MASK) || (len & PAGE_MASK) || len == 0) 529341f19c9SNeel Natu return (EINVAL); 530341f19c9SNeel Natu 531341f19c9SNeel Natu available = allocated = 0; 532341f19c9SNeel Natu g = gpa; 533341f19c9SNeel Natu while (g < gpa + len) { 534318224bbSNeel Natu if (vm_mem_allocated(vm, g)) 535341f19c9SNeel Natu allocated++; 536318224bbSNeel Natu else 537318224bbSNeel Natu available++; 538341f19c9SNeel Natu 539341f19c9SNeel Natu g += PAGE_SIZE; 540341f19c9SNeel Natu } 541341f19c9SNeel Natu 542366f6083SPeter Grehan /* 543341f19c9SNeel Natu * If there are some allocated and some available pages in the address 544341f19c9SNeel Natu * range then it is an error. 545366f6083SPeter Grehan */ 546341f19c9SNeel Natu if (allocated && available) 547341f19c9SNeel Natu return (EINVAL); 548341f19c9SNeel Natu 549341f19c9SNeel Natu /* 550341f19c9SNeel Natu * If the entire address range being requested has already been 551341f19c9SNeel Natu * allocated then there isn't anything more to do. 552341f19c9SNeel Natu */ 553341f19c9SNeel Natu if (allocated && available == 0) 554341f19c9SNeel Natu return (0); 555366f6083SPeter Grehan 556366f6083SPeter Grehan if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS) 557366f6083SPeter Grehan return (E2BIG); 558366f6083SPeter Grehan 559f7d51510SNeel Natu seg = &vm->mem_segs[vm->num_mem_segs]; 560366f6083SPeter Grehan 561318224bbSNeel Natu if ((object = vmm_mem_alloc(vm->vmspace, gpa, len)) == NULL) 562318224bbSNeel Natu return (ENOMEM); 563318224bbSNeel Natu 564f7d51510SNeel Natu seg->gpa = gpa; 565318224bbSNeel Natu seg->len = len; 566318224bbSNeel Natu seg->object = object; 567318224bbSNeel Natu seg->wired = FALSE; 5687ce04d0aSNeel Natu 569366f6083SPeter Grehan vm->num_mem_segs++; 570341f19c9SNeel Natu 571366f6083SPeter Grehan return (0); 572366f6083SPeter Grehan } 573366f6083SPeter Grehan 574318224bbSNeel Natu static void 575318224bbSNeel Natu vm_gpa_unwire(struct vm *vm) 576366f6083SPeter Grehan { 577318224bbSNeel Natu int i, rv; 578318224bbSNeel Natu struct mem_seg *seg; 5794db4fb2cSNeel Natu 580318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 581318224bbSNeel Natu seg = &vm->mem_segs[i]; 582318224bbSNeel Natu if (!seg->wired) 583318224bbSNeel Natu continue; 584366f6083SPeter Grehan 585318224bbSNeel Natu rv = vm_map_unwire(&vm->vmspace->vm_map, 586318224bbSNeel Natu seg->gpa, seg->gpa + seg->len, 587318224bbSNeel Natu VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 588318224bbSNeel Natu KASSERT(rv == KERN_SUCCESS, ("vm(%s) memory segment " 589318224bbSNeel Natu "%#lx/%ld could not be unwired: %d", 590318224bbSNeel Natu vm_name(vm), seg->gpa, seg->len, rv)); 591318224bbSNeel Natu 592318224bbSNeel Natu seg->wired = FALSE; 593318224bbSNeel Natu } 594318224bbSNeel Natu } 595318224bbSNeel Natu 596318224bbSNeel Natu static int 597318224bbSNeel Natu vm_gpa_wire(struct vm *vm) 598318224bbSNeel Natu { 599318224bbSNeel Natu int i, rv; 600318224bbSNeel Natu struct mem_seg *seg; 601318224bbSNeel Natu 602318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 603318224bbSNeel Natu seg = &vm->mem_segs[i]; 604318224bbSNeel Natu if (seg->wired) 605318224bbSNeel Natu continue; 606318224bbSNeel Natu 607318224bbSNeel Natu /* XXX rlimits? */ 608318224bbSNeel Natu rv = vm_map_wire(&vm->vmspace->vm_map, 609318224bbSNeel Natu seg->gpa, seg->gpa + seg->len, 610318224bbSNeel Natu VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 611318224bbSNeel Natu if (rv != KERN_SUCCESS) 612318224bbSNeel Natu break; 613318224bbSNeel Natu 614318224bbSNeel Natu seg->wired = TRUE; 615318224bbSNeel Natu } 616318224bbSNeel Natu 617318224bbSNeel Natu if (i < vm->num_mem_segs) { 618318224bbSNeel Natu /* 619318224bbSNeel Natu * Undo the wiring before returning an error. 620318224bbSNeel Natu */ 621318224bbSNeel Natu vm_gpa_unwire(vm); 622318224bbSNeel Natu return (EAGAIN); 623318224bbSNeel Natu } 624318224bbSNeel Natu 625318224bbSNeel Natu return (0); 626318224bbSNeel Natu } 627318224bbSNeel Natu 628318224bbSNeel Natu static void 629318224bbSNeel Natu vm_iommu_modify(struct vm *vm, boolean_t map) 630318224bbSNeel Natu { 631318224bbSNeel Natu int i, sz; 632318224bbSNeel Natu vm_paddr_t gpa, hpa; 633318224bbSNeel Natu struct mem_seg *seg; 634318224bbSNeel Natu void *vp, *cookie, *host_domain; 635318224bbSNeel Natu 636318224bbSNeel Natu sz = PAGE_SIZE; 637318224bbSNeel Natu host_domain = iommu_host_domain(); 638318224bbSNeel Natu 639318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 640318224bbSNeel Natu seg = &vm->mem_segs[i]; 641318224bbSNeel Natu KASSERT(seg->wired, ("vm(%s) memory segment %#lx/%ld not wired", 642318224bbSNeel Natu vm_name(vm), seg->gpa, seg->len)); 643318224bbSNeel Natu 644318224bbSNeel Natu gpa = seg->gpa; 645318224bbSNeel Natu while (gpa < seg->gpa + seg->len) { 646318224bbSNeel Natu vp = vm_gpa_hold(vm, gpa, PAGE_SIZE, VM_PROT_WRITE, 647318224bbSNeel Natu &cookie); 648318224bbSNeel Natu KASSERT(vp != NULL, ("vm(%s) could not map gpa %#lx", 649318224bbSNeel Natu vm_name(vm), gpa)); 650318224bbSNeel Natu 651318224bbSNeel Natu vm_gpa_release(cookie); 652318224bbSNeel Natu 653318224bbSNeel Natu hpa = DMAP_TO_PHYS((uintptr_t)vp); 654318224bbSNeel Natu if (map) { 655318224bbSNeel Natu iommu_create_mapping(vm->iommu, gpa, hpa, sz); 656318224bbSNeel Natu iommu_remove_mapping(host_domain, hpa, sz); 657318224bbSNeel Natu } else { 658318224bbSNeel Natu iommu_remove_mapping(vm->iommu, gpa, sz); 659318224bbSNeel Natu iommu_create_mapping(host_domain, hpa, hpa, sz); 660318224bbSNeel Natu } 661318224bbSNeel Natu 662318224bbSNeel Natu gpa += PAGE_SIZE; 663318224bbSNeel Natu } 664318224bbSNeel Natu } 665318224bbSNeel Natu 666318224bbSNeel Natu /* 667318224bbSNeel Natu * Invalidate the cached translations associated with the domain 668318224bbSNeel Natu * from which pages were removed. 669318224bbSNeel Natu */ 670318224bbSNeel Natu if (map) 671318224bbSNeel Natu iommu_invalidate_tlb(host_domain); 672318224bbSNeel Natu else 673318224bbSNeel Natu iommu_invalidate_tlb(vm->iommu); 674318224bbSNeel Natu } 675318224bbSNeel Natu 676318224bbSNeel Natu #define vm_iommu_unmap(vm) vm_iommu_modify((vm), FALSE) 677318224bbSNeel Natu #define vm_iommu_map(vm) vm_iommu_modify((vm), TRUE) 678318224bbSNeel Natu 679318224bbSNeel Natu int 680318224bbSNeel Natu vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func) 681318224bbSNeel Natu { 682318224bbSNeel Natu int error; 683318224bbSNeel Natu 684318224bbSNeel Natu error = ppt_unassign_device(vm, bus, slot, func); 685318224bbSNeel Natu if (error) 686318224bbSNeel Natu return (error); 687318224bbSNeel Natu 68851f45d01SNeel Natu if (ppt_assigned_devices(vm) == 0) { 689318224bbSNeel Natu vm_iommu_unmap(vm); 690318224bbSNeel Natu vm_gpa_unwire(vm); 691318224bbSNeel Natu } 692318224bbSNeel Natu return (0); 693318224bbSNeel Natu } 694318224bbSNeel Natu 695318224bbSNeel Natu int 696318224bbSNeel Natu vm_assign_pptdev(struct vm *vm, int bus, int slot, int func) 697318224bbSNeel Natu { 698318224bbSNeel Natu int error; 699318224bbSNeel Natu vm_paddr_t maxaddr; 700318224bbSNeel Natu 701318224bbSNeel Natu /* 702318224bbSNeel Natu * Virtual machines with pci passthru devices get special treatment: 703318224bbSNeel Natu * - the guest physical memory is wired 704318224bbSNeel Natu * - the iommu is programmed to do the 'gpa' to 'hpa' translation 705318224bbSNeel Natu * 706318224bbSNeel Natu * We need to do this before the first pci passthru device is attached. 707318224bbSNeel Natu */ 70851f45d01SNeel Natu if (ppt_assigned_devices(vm) == 0) { 709318224bbSNeel Natu KASSERT(vm->iommu == NULL, 710318224bbSNeel Natu ("vm_assign_pptdev: iommu must be NULL")); 711318224bbSNeel Natu maxaddr = vmm_mem_maxaddr(); 712318224bbSNeel Natu vm->iommu = iommu_create_domain(maxaddr); 713318224bbSNeel Natu 714318224bbSNeel Natu error = vm_gpa_wire(vm); 715318224bbSNeel Natu if (error) 716318224bbSNeel Natu return (error); 717318224bbSNeel Natu 718318224bbSNeel Natu vm_iommu_map(vm); 719318224bbSNeel Natu } 720318224bbSNeel Natu 721318224bbSNeel Natu error = ppt_assign_device(vm, bus, slot, func); 722318224bbSNeel Natu return (error); 723318224bbSNeel Natu } 724318224bbSNeel Natu 725318224bbSNeel Natu void * 726318224bbSNeel Natu vm_gpa_hold(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, 727318224bbSNeel Natu void **cookie) 728318224bbSNeel Natu { 729318224bbSNeel Natu int count, pageoff; 730318224bbSNeel Natu vm_page_t m; 731318224bbSNeel Natu 732318224bbSNeel Natu pageoff = gpa & PAGE_MASK; 733318224bbSNeel Natu if (len > PAGE_SIZE - pageoff) 734318224bbSNeel Natu panic("vm_gpa_hold: invalid gpa/len: 0x%016lx/%lu", gpa, len); 735318224bbSNeel Natu 736318224bbSNeel Natu count = vm_fault_quick_hold_pages(&vm->vmspace->vm_map, 737318224bbSNeel Natu trunc_page(gpa), PAGE_SIZE, reqprot, &m, 1); 738318224bbSNeel Natu 739318224bbSNeel Natu if (count == 1) { 740318224bbSNeel Natu *cookie = m; 741318224bbSNeel Natu return ((void *)(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)) + pageoff)); 742318224bbSNeel Natu } else { 743318224bbSNeel Natu *cookie = NULL; 744318224bbSNeel Natu return (NULL); 745318224bbSNeel Natu } 746318224bbSNeel Natu } 747318224bbSNeel Natu 748318224bbSNeel Natu void 749318224bbSNeel Natu vm_gpa_release(void *cookie) 750318224bbSNeel Natu { 751318224bbSNeel Natu vm_page_t m = cookie; 752318224bbSNeel Natu 753318224bbSNeel Natu vm_page_lock(m); 754318224bbSNeel Natu vm_page_unhold(m); 755318224bbSNeel Natu vm_page_unlock(m); 756366f6083SPeter Grehan } 757366f6083SPeter Grehan 758366f6083SPeter Grehan int 759366f6083SPeter Grehan vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 760366f6083SPeter Grehan struct vm_memory_segment *seg) 761366f6083SPeter Grehan { 762366f6083SPeter Grehan int i; 763366f6083SPeter Grehan 764366f6083SPeter Grehan for (i = 0; i < vm->num_mem_segs; i++) { 765366f6083SPeter Grehan if (gpabase == vm->mem_segs[i].gpa) { 766318224bbSNeel Natu seg->gpa = vm->mem_segs[i].gpa; 767318224bbSNeel Natu seg->len = vm->mem_segs[i].len; 768318224bbSNeel Natu seg->wired = vm->mem_segs[i].wired; 769366f6083SPeter Grehan return (0); 770366f6083SPeter Grehan } 771366f6083SPeter Grehan } 772366f6083SPeter Grehan return (-1); 773366f6083SPeter Grehan } 774366f6083SPeter Grehan 775366f6083SPeter Grehan int 776318224bbSNeel Natu vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len, 777318224bbSNeel Natu vm_offset_t *offset, struct vm_object **object) 778318224bbSNeel Natu { 779318224bbSNeel Natu int i; 780318224bbSNeel Natu size_t seg_len; 781318224bbSNeel Natu vm_paddr_t seg_gpa; 782318224bbSNeel Natu vm_object_t seg_obj; 783318224bbSNeel Natu 784318224bbSNeel Natu for (i = 0; i < vm->num_mem_segs; i++) { 785318224bbSNeel Natu if ((seg_obj = vm->mem_segs[i].object) == NULL) 786318224bbSNeel Natu continue; 787318224bbSNeel Natu 788318224bbSNeel Natu seg_gpa = vm->mem_segs[i].gpa; 789318224bbSNeel Natu seg_len = vm->mem_segs[i].len; 790318224bbSNeel Natu 791318224bbSNeel Natu if (gpa >= seg_gpa && gpa < seg_gpa + seg_len) { 792318224bbSNeel Natu *offset = gpa - seg_gpa; 793318224bbSNeel Natu *object = seg_obj; 794318224bbSNeel Natu vm_object_reference(seg_obj); 795318224bbSNeel Natu return (0); 796318224bbSNeel Natu } 797318224bbSNeel Natu } 798318224bbSNeel Natu 799318224bbSNeel Natu return (EINVAL); 800318224bbSNeel Natu } 801318224bbSNeel Natu 802318224bbSNeel Natu int 803366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 804366f6083SPeter Grehan { 805366f6083SPeter Grehan 806366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 807366f6083SPeter Grehan return (EINVAL); 808366f6083SPeter Grehan 809366f6083SPeter Grehan if (reg >= VM_REG_LAST) 810366f6083SPeter Grehan return (EINVAL); 811366f6083SPeter Grehan 812366f6083SPeter Grehan return (VMGETREG(vm->cookie, vcpu, reg, retval)); 813366f6083SPeter Grehan } 814366f6083SPeter Grehan 815366f6083SPeter Grehan int 816366f6083SPeter Grehan vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val) 817366f6083SPeter Grehan { 818366f6083SPeter Grehan 819366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 820366f6083SPeter Grehan return (EINVAL); 821366f6083SPeter Grehan 822366f6083SPeter Grehan if (reg >= VM_REG_LAST) 823366f6083SPeter Grehan return (EINVAL); 824366f6083SPeter Grehan 825366f6083SPeter Grehan return (VMSETREG(vm->cookie, vcpu, reg, val)); 826366f6083SPeter Grehan } 827366f6083SPeter Grehan 828366f6083SPeter Grehan static boolean_t 829366f6083SPeter Grehan is_descriptor_table(int reg) 830366f6083SPeter Grehan { 831366f6083SPeter Grehan 832366f6083SPeter Grehan switch (reg) { 833366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 834366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 835366f6083SPeter Grehan return (TRUE); 836366f6083SPeter Grehan default: 837366f6083SPeter Grehan return (FALSE); 838366f6083SPeter Grehan } 839366f6083SPeter Grehan } 840366f6083SPeter Grehan 841366f6083SPeter Grehan static boolean_t 842366f6083SPeter Grehan is_segment_register(int reg) 843366f6083SPeter Grehan { 844366f6083SPeter Grehan 845366f6083SPeter Grehan switch (reg) { 846366f6083SPeter Grehan case VM_REG_GUEST_ES: 847366f6083SPeter Grehan case VM_REG_GUEST_CS: 848366f6083SPeter Grehan case VM_REG_GUEST_SS: 849366f6083SPeter Grehan case VM_REG_GUEST_DS: 850366f6083SPeter Grehan case VM_REG_GUEST_FS: 851366f6083SPeter Grehan case VM_REG_GUEST_GS: 852366f6083SPeter Grehan case VM_REG_GUEST_TR: 853366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 854366f6083SPeter Grehan return (TRUE); 855366f6083SPeter Grehan default: 856366f6083SPeter Grehan return (FALSE); 857366f6083SPeter Grehan } 858366f6083SPeter Grehan } 859366f6083SPeter Grehan 860366f6083SPeter Grehan int 861366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 862366f6083SPeter Grehan struct seg_desc *desc) 863366f6083SPeter Grehan { 864366f6083SPeter Grehan 865366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 866366f6083SPeter Grehan return (EINVAL); 867366f6083SPeter Grehan 868366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 869366f6083SPeter Grehan return (EINVAL); 870366f6083SPeter Grehan 871366f6083SPeter Grehan return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 872366f6083SPeter Grehan } 873366f6083SPeter Grehan 874366f6083SPeter Grehan int 875366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 876366f6083SPeter Grehan struct seg_desc *desc) 877366f6083SPeter Grehan { 878366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 879366f6083SPeter Grehan return (EINVAL); 880366f6083SPeter Grehan 881366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 882366f6083SPeter Grehan return (EINVAL); 883366f6083SPeter Grehan 884366f6083SPeter Grehan return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 885366f6083SPeter Grehan } 886366f6083SPeter Grehan 887366f6083SPeter Grehan static void 888366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 889366f6083SPeter Grehan { 890366f6083SPeter Grehan 89138f1b189SPeter Grehan /* flush host state to the pcb */ 89238f1b189SPeter Grehan fpuexit(curthread); 893bd8572e0SNeel Natu 894bd8572e0SNeel Natu /* restore guest FPU state */ 895366f6083SPeter Grehan fpu_stop_emulating(); 89638f1b189SPeter Grehan fpurestore(vcpu->guestfpu); 897bd8572e0SNeel Natu 898abb023fbSJohn Baldwin /* restore guest XCR0 if XSAVE is enabled in the host */ 899abb023fbSJohn Baldwin if (rcr4() & CR4_XSAVE) 900abb023fbSJohn Baldwin load_xcr(0, vcpu->guest_xcr0); 901abb023fbSJohn Baldwin 902bd8572e0SNeel Natu /* 903bd8572e0SNeel Natu * The FPU is now "dirty" with the guest's state so turn on emulation 904bd8572e0SNeel Natu * to trap any access to the FPU by the host. 905bd8572e0SNeel Natu */ 906bd8572e0SNeel Natu fpu_start_emulating(); 907366f6083SPeter Grehan } 908366f6083SPeter Grehan 909366f6083SPeter Grehan static void 910366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 911366f6083SPeter Grehan { 912366f6083SPeter Grehan 913bd8572e0SNeel Natu if ((rcr0() & CR0_TS) == 0) 914bd8572e0SNeel Natu panic("fpu emulation not enabled in host!"); 915bd8572e0SNeel Natu 916abb023fbSJohn Baldwin /* save guest XCR0 and restore host XCR0 */ 917abb023fbSJohn Baldwin if (rcr4() & CR4_XSAVE) { 918abb023fbSJohn Baldwin vcpu->guest_xcr0 = rxcr(0); 919abb023fbSJohn Baldwin load_xcr(0, vmm_get_host_xcr0()); 920abb023fbSJohn Baldwin } 921abb023fbSJohn Baldwin 922bd8572e0SNeel Natu /* save guest FPU state */ 923bd8572e0SNeel Natu fpu_stop_emulating(); 92438f1b189SPeter Grehan fpusave(vcpu->guestfpu); 925366f6083SPeter Grehan fpu_start_emulating(); 926366f6083SPeter Grehan } 927366f6083SPeter Grehan 92861592433SNeel Natu static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); 929f76fc5d4SNeel Natu 930318224bbSNeel Natu static int 931f80330a8SNeel Natu vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, 932f80330a8SNeel Natu bool from_idle) 933366f6083SPeter Grehan { 934318224bbSNeel Natu int error; 935366f6083SPeter Grehan 936318224bbSNeel Natu vcpu_assert_locked(vcpu); 937366f6083SPeter Grehan 938f76fc5d4SNeel Natu /* 939f80330a8SNeel Natu * State transitions from the vmmdev_ioctl() must always begin from 940f80330a8SNeel Natu * the VCPU_IDLE state. This guarantees that there is only a single 941f80330a8SNeel Natu * ioctl() operating on a vcpu at any point. 942f80330a8SNeel Natu */ 943f80330a8SNeel Natu if (from_idle) { 944f80330a8SNeel Natu while (vcpu->state != VCPU_IDLE) 945f80330a8SNeel Natu msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); 946f80330a8SNeel Natu } else { 947f80330a8SNeel Natu KASSERT(vcpu->state != VCPU_IDLE, ("invalid transition from " 948f80330a8SNeel Natu "vcpu idle state")); 949f80330a8SNeel Natu } 950f80330a8SNeel Natu 951ef39d7e9SNeel Natu if (vcpu->state == VCPU_RUNNING) { 952ef39d7e9SNeel Natu KASSERT(vcpu->hostcpu == curcpu, ("curcpu %d and hostcpu %d " 953ef39d7e9SNeel Natu "mismatch for running vcpu", curcpu, vcpu->hostcpu)); 954ef39d7e9SNeel Natu } else { 955ef39d7e9SNeel Natu KASSERT(vcpu->hostcpu == NOCPU, ("Invalid hostcpu %d for a " 956ef39d7e9SNeel Natu "vcpu that is not running", vcpu->hostcpu)); 957ef39d7e9SNeel Natu } 958ef39d7e9SNeel Natu 959f80330a8SNeel Natu /* 960318224bbSNeel Natu * The following state transitions are allowed: 961318224bbSNeel Natu * IDLE -> FROZEN -> IDLE 962318224bbSNeel Natu * FROZEN -> RUNNING -> FROZEN 963318224bbSNeel Natu * FROZEN -> SLEEPING -> FROZEN 964f76fc5d4SNeel Natu */ 965318224bbSNeel Natu switch (vcpu->state) { 966318224bbSNeel Natu case VCPU_IDLE: 967318224bbSNeel Natu case VCPU_RUNNING: 968318224bbSNeel Natu case VCPU_SLEEPING: 969318224bbSNeel Natu error = (newstate != VCPU_FROZEN); 970318224bbSNeel Natu break; 971318224bbSNeel Natu case VCPU_FROZEN: 972318224bbSNeel Natu error = (newstate == VCPU_FROZEN); 973318224bbSNeel Natu break; 974318224bbSNeel Natu default: 975318224bbSNeel Natu error = 1; 976318224bbSNeel Natu break; 977318224bbSNeel Natu } 978318224bbSNeel Natu 979f80330a8SNeel Natu if (error) 980f80330a8SNeel Natu return (EBUSY); 981318224bbSNeel Natu 982f80330a8SNeel Natu vcpu->state = newstate; 983ef39d7e9SNeel Natu if (newstate == VCPU_RUNNING) 984ef39d7e9SNeel Natu vcpu->hostcpu = curcpu; 985ef39d7e9SNeel Natu else 986ef39d7e9SNeel Natu vcpu->hostcpu = NOCPU; 987ef39d7e9SNeel Natu 988f80330a8SNeel Natu if (newstate == VCPU_IDLE) 989f80330a8SNeel Natu wakeup(&vcpu->state); 990f80330a8SNeel Natu 991f80330a8SNeel Natu return (0); 992318224bbSNeel Natu } 993318224bbSNeel Natu 994318224bbSNeel Natu static void 995318224bbSNeel Natu vcpu_require_state(struct vm *vm, int vcpuid, enum vcpu_state newstate) 996318224bbSNeel Natu { 997318224bbSNeel Natu int error; 998318224bbSNeel Natu 999f80330a8SNeel Natu if ((error = vcpu_set_state(vm, vcpuid, newstate, false)) != 0) 1000318224bbSNeel Natu panic("Error %d setting state to %d\n", error, newstate); 1001318224bbSNeel Natu } 1002318224bbSNeel Natu 1003318224bbSNeel Natu static void 1004318224bbSNeel Natu vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) 1005318224bbSNeel Natu { 1006318224bbSNeel Natu int error; 1007318224bbSNeel Natu 1008f80330a8SNeel Natu if ((error = vcpu_set_state_locked(vcpu, newstate, false)) != 0) 1009318224bbSNeel Natu panic("Error %d setting state to %d", error, newstate); 1010318224bbSNeel Natu } 1011318224bbSNeel Natu 10125b8a8cd1SNeel Natu static void 10135b8a8cd1SNeel Natu vm_set_rendezvous_func(struct vm *vm, vm_rendezvous_func_t func) 10145b8a8cd1SNeel Natu { 10155b8a8cd1SNeel Natu 10165b8a8cd1SNeel Natu KASSERT(mtx_owned(&vm->rendezvous_mtx), ("rendezvous_mtx not locked")); 10175b8a8cd1SNeel Natu 10185b8a8cd1SNeel Natu /* 10195b8a8cd1SNeel Natu * Update 'rendezvous_func' and execute a write memory barrier to 10205b8a8cd1SNeel Natu * ensure that it is visible across all host cpus. This is not needed 10215b8a8cd1SNeel Natu * for correctness but it does ensure that all the vcpus will notice 10225b8a8cd1SNeel Natu * that the rendezvous is requested immediately. 10235b8a8cd1SNeel Natu */ 10245b8a8cd1SNeel Natu vm->rendezvous_func = func; 10255b8a8cd1SNeel Natu wmb(); 10265b8a8cd1SNeel Natu } 10275b8a8cd1SNeel Natu 10285b8a8cd1SNeel Natu #define RENDEZVOUS_CTR0(vm, vcpuid, fmt) \ 10295b8a8cd1SNeel Natu do { \ 10305b8a8cd1SNeel Natu if (vcpuid >= 0) \ 10315b8a8cd1SNeel Natu VCPU_CTR0(vm, vcpuid, fmt); \ 10325b8a8cd1SNeel Natu else \ 10335b8a8cd1SNeel Natu VM_CTR0(vm, fmt); \ 10345b8a8cd1SNeel Natu } while (0) 10355b8a8cd1SNeel Natu 10365b8a8cd1SNeel Natu static void 10375b8a8cd1SNeel Natu vm_handle_rendezvous(struct vm *vm, int vcpuid) 10385b8a8cd1SNeel Natu { 10395b8a8cd1SNeel Natu 10405b8a8cd1SNeel Natu KASSERT(vcpuid == -1 || (vcpuid >= 0 && vcpuid < VM_MAXCPU), 10415b8a8cd1SNeel Natu ("vm_handle_rendezvous: invalid vcpuid %d", vcpuid)); 10425b8a8cd1SNeel Natu 10435b8a8cd1SNeel Natu mtx_lock(&vm->rendezvous_mtx); 10445b8a8cd1SNeel Natu while (vm->rendezvous_func != NULL) { 104522d822c6SNeel Natu /* 'rendezvous_req_cpus' must be a subset of 'active_cpus' */ 104622d822c6SNeel Natu CPU_AND(&vm->rendezvous_req_cpus, &vm->active_cpus); 104722d822c6SNeel Natu 10485b8a8cd1SNeel Natu if (vcpuid != -1 && 104922d822c6SNeel Natu CPU_ISSET(vcpuid, &vm->rendezvous_req_cpus) && 105022d822c6SNeel Natu !CPU_ISSET(vcpuid, &vm->rendezvous_done_cpus)) { 10515b8a8cd1SNeel Natu VCPU_CTR0(vm, vcpuid, "Calling rendezvous func"); 10525b8a8cd1SNeel Natu (*vm->rendezvous_func)(vm, vcpuid, vm->rendezvous_arg); 10535b8a8cd1SNeel Natu CPU_SET(vcpuid, &vm->rendezvous_done_cpus); 10545b8a8cd1SNeel Natu } 10555b8a8cd1SNeel Natu if (CPU_CMP(&vm->rendezvous_req_cpus, 10565b8a8cd1SNeel Natu &vm->rendezvous_done_cpus) == 0) { 10575b8a8cd1SNeel Natu VCPU_CTR0(vm, vcpuid, "Rendezvous completed"); 10585b8a8cd1SNeel Natu vm_set_rendezvous_func(vm, NULL); 10595b8a8cd1SNeel Natu wakeup(&vm->rendezvous_func); 10605b8a8cd1SNeel Natu break; 10615b8a8cd1SNeel Natu } 10625b8a8cd1SNeel Natu RENDEZVOUS_CTR0(vm, vcpuid, "Wait for rendezvous completion"); 10635b8a8cd1SNeel Natu mtx_sleep(&vm->rendezvous_func, &vm->rendezvous_mtx, 0, 10645b8a8cd1SNeel Natu "vmrndv", 0); 10655b8a8cd1SNeel Natu } 10665b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 10675b8a8cd1SNeel Natu } 10685b8a8cd1SNeel Natu 1069318224bbSNeel Natu /* 1070318224bbSNeel Natu * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run. 1071318224bbSNeel Natu */ 1072318224bbSNeel Natu static int 1073becd9849SNeel Natu vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu) 1074318224bbSNeel Natu { 1075318224bbSNeel Natu struct vcpu *vcpu; 1076c6a0cc2eSNeel Natu const char *wmesg; 1077e50ce2aaSNeel Natu int t, vcpu_halted, vm_halted; 1078e50ce2aaSNeel Natu 1079e50ce2aaSNeel Natu KASSERT(!CPU_ISSET(vcpuid, &vm->halted_cpus), ("vcpu already halted")); 1080318224bbSNeel Natu 1081318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1082e50ce2aaSNeel Natu vcpu_halted = 0; 1083e50ce2aaSNeel Natu vm_halted = 0; 1084318224bbSNeel Natu 1085f76fc5d4SNeel Natu vcpu_lock(vcpu); 1086c6a0cc2eSNeel Natu while (1) { 1087f76fc5d4SNeel Natu /* 1088f76fc5d4SNeel Natu * Do a final check for pending NMI or interrupts before 1089c6a0cc2eSNeel Natu * really putting this thread to sleep. Also check for 1090c6a0cc2eSNeel Natu * software events that would cause this vcpu to wakeup. 1091f76fc5d4SNeel Natu * 1092c6a0cc2eSNeel Natu * These interrupts/events could have happened after the 1093c6a0cc2eSNeel Natu * vcpu returned from VMRUN() and before it acquired the 1094c6a0cc2eSNeel Natu * vcpu lock above. 1095f76fc5d4SNeel Natu */ 1096c6a0cc2eSNeel Natu if (vm->rendezvous_func != NULL || vm->suspend) 1097c6a0cc2eSNeel Natu break; 1098c6a0cc2eSNeel Natu if (vm_nmi_pending(vm, vcpuid)) 1099c6a0cc2eSNeel Natu break; 1100c6a0cc2eSNeel Natu if (!intr_disabled) { 1101c6a0cc2eSNeel Natu if (vm_extint_pending(vm, vcpuid) || 1102c6a0cc2eSNeel Natu vlapic_pending_intr(vcpu->vlapic, NULL)) { 1103c6a0cc2eSNeel Natu break; 1104c6a0cc2eSNeel Natu } 1105c6a0cc2eSNeel Natu } 1106c6a0cc2eSNeel Natu 1107e50ce2aaSNeel Natu /* 1108e50ce2aaSNeel Natu * Some Linux guests implement "halt" by having all vcpus 1109e50ce2aaSNeel Natu * execute HLT with interrupts disabled. 'halted_cpus' keeps 1110e50ce2aaSNeel Natu * track of the vcpus that have entered this state. When all 1111e50ce2aaSNeel Natu * vcpus enter the halted state the virtual machine is halted. 1112e50ce2aaSNeel Natu */ 1113e50ce2aaSNeel Natu if (intr_disabled) { 1114c6a0cc2eSNeel Natu wmesg = "vmhalt"; 1115e50ce2aaSNeel Natu VCPU_CTR0(vm, vcpuid, "Halted"); 1116055fc2cbSNeel Natu if (!vcpu_halted && halt_detection_enabled) { 1117e50ce2aaSNeel Natu vcpu_halted = 1; 1118e50ce2aaSNeel Natu CPU_SET_ATOMIC(vcpuid, &vm->halted_cpus); 1119e50ce2aaSNeel Natu } 1120e50ce2aaSNeel Natu if (CPU_CMP(&vm->halted_cpus, &vm->active_cpus) == 0) { 1121e50ce2aaSNeel Natu vm_halted = 1; 1122e50ce2aaSNeel Natu break; 1123e50ce2aaSNeel Natu } 1124e50ce2aaSNeel Natu } else { 1125e50ce2aaSNeel Natu wmesg = "vmidle"; 1126e50ce2aaSNeel Natu } 1127c6a0cc2eSNeel Natu 1128f76fc5d4SNeel Natu t = ticks; 1129318224bbSNeel Natu vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 1130c6a0cc2eSNeel Natu msleep_spin(vcpu, &vcpu->mtx, wmesg, 0); 113122d822c6SNeel Natu vcpu_require_state_locked(vcpu, VCPU_FROZEN); 113222d822c6SNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t); 113322d822c6SNeel Natu } 1134e50ce2aaSNeel Natu 1135e50ce2aaSNeel Natu if (vcpu_halted) 1136e50ce2aaSNeel Natu CPU_CLR_ATOMIC(vcpuid, &vm->halted_cpus); 1137e50ce2aaSNeel Natu 113822d822c6SNeel Natu vcpu_unlock(vcpu); 113922d822c6SNeel Natu 1140e50ce2aaSNeel Natu if (vm_halted) 1141e50ce2aaSNeel Natu vm_suspend(vm, VM_SUSPEND_HALT); 1142e50ce2aaSNeel Natu 1143318224bbSNeel Natu return (0); 1144318224bbSNeel Natu } 1145318224bbSNeel Natu 1146318224bbSNeel Natu static int 1147becd9849SNeel Natu vm_handle_paging(struct vm *vm, int vcpuid, bool *retu) 1148318224bbSNeel Natu { 1149318224bbSNeel Natu int rv, ftype; 1150318224bbSNeel Natu struct vm_map *map; 1151318224bbSNeel Natu struct vcpu *vcpu; 1152318224bbSNeel Natu struct vm_exit *vme; 1153318224bbSNeel Natu 1154318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1155318224bbSNeel Natu vme = &vcpu->exitinfo; 1156318224bbSNeel Natu 1157318224bbSNeel Natu ftype = vme->u.paging.fault_type; 1158318224bbSNeel Natu KASSERT(ftype == VM_PROT_READ || 1159318224bbSNeel Natu ftype == VM_PROT_WRITE || ftype == VM_PROT_EXECUTE, 1160318224bbSNeel Natu ("vm_handle_paging: invalid fault_type %d", ftype)); 1161318224bbSNeel Natu 1162318224bbSNeel Natu if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { 1163318224bbSNeel Natu rv = pmap_emulate_accessed_dirty(vmspace_pmap(vm->vmspace), 1164318224bbSNeel Natu vme->u.paging.gpa, ftype); 1165318224bbSNeel Natu if (rv == 0) 1166318224bbSNeel Natu goto done; 1167318224bbSNeel Natu } 1168318224bbSNeel Natu 1169318224bbSNeel Natu map = &vm->vmspace->vm_map; 1170318224bbSNeel Natu rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL); 1171318224bbSNeel Natu 1172513c8d33SNeel Natu VCPU_CTR3(vm, vcpuid, "vm_handle_paging rv = %d, gpa = %#lx, " 1173513c8d33SNeel Natu "ftype = %d", rv, vme->u.paging.gpa, ftype); 1174318224bbSNeel Natu 1175318224bbSNeel Natu if (rv != KERN_SUCCESS) 1176318224bbSNeel Natu return (EFAULT); 1177318224bbSNeel Natu done: 1178318224bbSNeel Natu /* restart execution at the faulting instruction */ 1179318224bbSNeel Natu vme->inst_length = 0; 1180318224bbSNeel Natu 1181318224bbSNeel Natu return (0); 1182318224bbSNeel Natu } 1183318224bbSNeel Natu 1184318224bbSNeel Natu static int 1185becd9849SNeel Natu vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu) 1186318224bbSNeel Natu { 1187318224bbSNeel Natu struct vie *vie; 1188318224bbSNeel Natu struct vcpu *vcpu; 1189318224bbSNeel Natu struct vm_exit *vme; 1190e813a873SNeel Natu uint64_t gla, gpa; 1191e813a873SNeel Natu struct vm_guest_paging *paging; 1192565bbb86SNeel Natu mem_region_read_t mread; 1193565bbb86SNeel Natu mem_region_write_t mwrite; 1194e813a873SNeel Natu int error; 1195318224bbSNeel Natu 1196318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1197318224bbSNeel Natu vme = &vcpu->exitinfo; 1198318224bbSNeel Natu 1199318224bbSNeel Natu gla = vme->u.inst_emul.gla; 1200318224bbSNeel Natu gpa = vme->u.inst_emul.gpa; 1201318224bbSNeel Natu vie = &vme->u.inst_emul.vie; 1202e813a873SNeel Natu paging = &vme->u.inst_emul.paging; 1203318224bbSNeel Natu 1204318224bbSNeel Natu vie_init(vie); 1205318224bbSNeel Natu 1206318224bbSNeel Natu /* Fetch, decode and emulate the faulting instruction */ 1207e813a873SNeel Natu error = vmm_fetch_instruction(vm, vcpuid, paging, vme->rip, 1208e813a873SNeel Natu vme->inst_length, vie); 1209fd949af6SNeel Natu if (error == 1) 1210fd949af6SNeel Natu return (0); /* Resume guest to handle page fault */ 1211fd949af6SNeel Natu else if (error == -1) 1212318224bbSNeel Natu return (EFAULT); 1213fd949af6SNeel Natu else if (error != 0) 1214fd949af6SNeel Natu panic("%s: vmm_fetch_instruction error %d", __func__, error); 1215318224bbSNeel Natu 1216e813a873SNeel Natu if (vmm_decode_instruction(vm, vcpuid, gla, paging->cpu_mode, vie) != 0) 1217318224bbSNeel Natu return (EFAULT); 1218318224bbSNeel Natu 121908e3ff32SNeel Natu /* return to userland unless this is an in-kernel emulated device */ 1220565bbb86SNeel Natu if (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE) { 1221565bbb86SNeel Natu mread = lapic_mmio_read; 1222565bbb86SNeel Natu mwrite = lapic_mmio_write; 1223565bbb86SNeel Natu } else if (gpa >= VIOAPIC_BASE && gpa < VIOAPIC_BASE + VIOAPIC_SIZE) { 1224565bbb86SNeel Natu mread = vioapic_mmio_read; 1225565bbb86SNeel Natu mwrite = vioapic_mmio_write; 122608e3ff32SNeel Natu } else if (gpa >= VHPET_BASE && gpa < VHPET_BASE + VHPET_SIZE) { 122708e3ff32SNeel Natu mread = vhpet_mmio_read; 122808e3ff32SNeel Natu mwrite = vhpet_mmio_write; 1229565bbb86SNeel Natu } else { 1230becd9849SNeel Natu *retu = true; 1231318224bbSNeel Natu return (0); 1232318224bbSNeel Natu } 1233318224bbSNeel Natu 1234becd9849SNeel Natu error = vmm_emulate_instruction(vm, vcpuid, gpa, vie, mread, mwrite, 1235becd9849SNeel Natu retu); 1236318224bbSNeel Natu 1237318224bbSNeel Natu return (error); 1238318224bbSNeel Natu } 1239318224bbSNeel Natu 1240b15a09c0SNeel Natu static int 1241b15a09c0SNeel Natu vm_handle_suspend(struct vm *vm, int vcpuid, bool *retu) 1242b15a09c0SNeel Natu { 1243b15a09c0SNeel Natu int i, done; 1244b15a09c0SNeel Natu struct vcpu *vcpu; 1245b15a09c0SNeel Natu 1246b15a09c0SNeel Natu done = 0; 1247b15a09c0SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1248b15a09c0SNeel Natu 1249b15a09c0SNeel Natu CPU_SET_ATOMIC(vcpuid, &vm->suspended_cpus); 1250b15a09c0SNeel Natu 1251b15a09c0SNeel Natu /* 1252b15a09c0SNeel Natu * Wait until all 'active_cpus' have suspended themselves. 1253b15a09c0SNeel Natu * 1254b15a09c0SNeel Natu * Since a VM may be suspended at any time including when one or 1255b15a09c0SNeel Natu * more vcpus are doing a rendezvous we need to call the rendezvous 1256b15a09c0SNeel Natu * handler while we are waiting to prevent a deadlock. 1257b15a09c0SNeel Natu */ 1258b15a09c0SNeel Natu vcpu_lock(vcpu); 1259b15a09c0SNeel Natu while (1) { 1260b15a09c0SNeel Natu if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 1261b15a09c0SNeel Natu VCPU_CTR0(vm, vcpuid, "All vcpus suspended"); 1262b15a09c0SNeel Natu break; 1263b15a09c0SNeel Natu } 1264b15a09c0SNeel Natu 1265b15a09c0SNeel Natu if (vm->rendezvous_func == NULL) { 1266b15a09c0SNeel Natu VCPU_CTR0(vm, vcpuid, "Sleeping during suspend"); 1267b15a09c0SNeel Natu vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 1268b15a09c0SNeel Natu msleep_spin(vcpu, &vcpu->mtx, "vmsusp", hz); 1269b15a09c0SNeel Natu vcpu_require_state_locked(vcpu, VCPU_FROZEN); 1270b15a09c0SNeel Natu } else { 1271b15a09c0SNeel Natu VCPU_CTR0(vm, vcpuid, "Rendezvous during suspend"); 1272b15a09c0SNeel Natu vcpu_unlock(vcpu); 1273b15a09c0SNeel Natu vm_handle_rendezvous(vm, vcpuid); 1274b15a09c0SNeel Natu vcpu_lock(vcpu); 1275b15a09c0SNeel Natu } 1276b15a09c0SNeel Natu } 1277b15a09c0SNeel Natu vcpu_unlock(vcpu); 1278b15a09c0SNeel Natu 1279b15a09c0SNeel Natu /* 1280b15a09c0SNeel Natu * Wakeup the other sleeping vcpus and return to userspace. 1281b15a09c0SNeel Natu */ 1282b15a09c0SNeel Natu for (i = 0; i < VM_MAXCPU; i++) { 1283b15a09c0SNeel Natu if (CPU_ISSET(i, &vm->suspended_cpus)) { 1284b15a09c0SNeel Natu vcpu_notify_event(vm, i, false); 1285b15a09c0SNeel Natu } 1286b15a09c0SNeel Natu } 1287b15a09c0SNeel Natu 1288b15a09c0SNeel Natu *retu = true; 1289b15a09c0SNeel Natu return (0); 1290b15a09c0SNeel Natu } 1291b15a09c0SNeel Natu 1292b15a09c0SNeel Natu int 1293f0fdcfe2SNeel Natu vm_suspend(struct vm *vm, enum vm_suspend_how how) 1294b15a09c0SNeel Natu { 1295f0fdcfe2SNeel Natu int i; 1296b15a09c0SNeel Natu 1297f0fdcfe2SNeel Natu if (how <= VM_SUSPEND_NONE || how >= VM_SUSPEND_LAST) 1298f0fdcfe2SNeel Natu return (EINVAL); 1299f0fdcfe2SNeel Natu 1300f0fdcfe2SNeel Natu if (atomic_cmpset_int(&vm->suspend, 0, how) == 0) { 1301f0fdcfe2SNeel Natu VM_CTR2(vm, "virtual machine already suspended %d/%d", 1302f0fdcfe2SNeel Natu vm->suspend, how); 1303b15a09c0SNeel Natu return (EALREADY); 1304b15a09c0SNeel Natu } 1305f0fdcfe2SNeel Natu 1306f0fdcfe2SNeel Natu VM_CTR1(vm, "virtual machine successfully suspended %d", how); 1307f0fdcfe2SNeel Natu 1308f0fdcfe2SNeel Natu /* 1309f0fdcfe2SNeel Natu * Notify all active vcpus that they are now suspended. 1310f0fdcfe2SNeel Natu */ 1311f0fdcfe2SNeel Natu for (i = 0; i < VM_MAXCPU; i++) { 1312f0fdcfe2SNeel Natu if (CPU_ISSET(i, &vm->active_cpus)) 1313f0fdcfe2SNeel Natu vcpu_notify_event(vm, i, false); 1314f0fdcfe2SNeel Natu } 1315f0fdcfe2SNeel Natu 1316f0fdcfe2SNeel Natu return (0); 1317f0fdcfe2SNeel Natu } 1318f0fdcfe2SNeel Natu 1319f0fdcfe2SNeel Natu void 1320f0fdcfe2SNeel Natu vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip) 1321f0fdcfe2SNeel Natu { 1322f0fdcfe2SNeel Natu struct vm_exit *vmexit; 1323f0fdcfe2SNeel Natu 1324f0fdcfe2SNeel Natu KASSERT(vm->suspend > VM_SUSPEND_NONE && vm->suspend < VM_SUSPEND_LAST, 1325f0fdcfe2SNeel Natu ("vm_exit_suspended: invalid suspend type %d", vm->suspend)); 1326f0fdcfe2SNeel Natu 1327f0fdcfe2SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 1328f0fdcfe2SNeel Natu vmexit->rip = rip; 1329f0fdcfe2SNeel Natu vmexit->inst_length = 0; 1330f0fdcfe2SNeel Natu vmexit->exitcode = VM_EXITCODE_SUSPENDED; 1331f0fdcfe2SNeel Natu vmexit->u.suspended.how = vm->suspend; 1332b15a09c0SNeel Natu } 1333b15a09c0SNeel Natu 133440487465SNeel Natu void 133540487465SNeel Natu vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip) 133640487465SNeel Natu { 133740487465SNeel Natu struct vm_exit *vmexit; 133840487465SNeel Natu 133940487465SNeel Natu KASSERT(vm->rendezvous_func != NULL, ("rendezvous not in progress")); 134040487465SNeel Natu 134140487465SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 134240487465SNeel Natu vmexit->rip = rip; 134340487465SNeel Natu vmexit->inst_length = 0; 134440487465SNeel Natu vmexit->exitcode = VM_EXITCODE_RENDEZVOUS; 134540487465SNeel Natu vmm_stat_incr(vm, vcpuid, VMEXIT_RENDEZVOUS, 1); 134640487465SNeel Natu } 134740487465SNeel Natu 134840487465SNeel Natu void 134940487465SNeel Natu vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip) 135040487465SNeel Natu { 135140487465SNeel Natu struct vm_exit *vmexit; 135240487465SNeel Natu 135340487465SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 135440487465SNeel Natu vmexit->rip = rip; 135540487465SNeel Natu vmexit->inst_length = 0; 135640487465SNeel Natu vmexit->exitcode = VM_EXITCODE_BOGUS; 135740487465SNeel Natu vmm_stat_incr(vm, vcpuid, VMEXIT_ASTPENDING, 1); 135840487465SNeel Natu } 135940487465SNeel Natu 1360318224bbSNeel Natu int 1361318224bbSNeel Natu vm_run(struct vm *vm, struct vm_run *vmrun) 1362318224bbSNeel Natu { 1363318224bbSNeel Natu int error, vcpuid; 1364318224bbSNeel Natu struct vcpu *vcpu; 1365318224bbSNeel Natu struct pcb *pcb; 1366318224bbSNeel Natu uint64_t tscval, rip; 1367318224bbSNeel Natu struct vm_exit *vme; 1368becd9849SNeel Natu bool retu, intr_disabled; 1369318224bbSNeel Natu pmap_t pmap; 1370b15a09c0SNeel Natu void *rptr, *sptr; 1371318224bbSNeel Natu 1372318224bbSNeel Natu vcpuid = vmrun->cpuid; 1373318224bbSNeel Natu 1374318224bbSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1375318224bbSNeel Natu return (EINVAL); 1376318224bbSNeel Natu 137795ebc360SNeel Natu if (!CPU_ISSET(vcpuid, &vm->active_cpus)) 137895ebc360SNeel Natu return (EINVAL); 137995ebc360SNeel Natu 138095ebc360SNeel Natu if (CPU_ISSET(vcpuid, &vm->suspended_cpus)) 138195ebc360SNeel Natu return (EINVAL); 138295ebc360SNeel Natu 1383b15a09c0SNeel Natu rptr = &vm->rendezvous_func; 1384b15a09c0SNeel Natu sptr = &vm->suspend; 1385318224bbSNeel Natu pmap = vmspace_pmap(vm->vmspace); 1386318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1387318224bbSNeel Natu vme = &vcpu->exitinfo; 1388318224bbSNeel Natu rip = vmrun->rip; 1389318224bbSNeel Natu restart: 1390318224bbSNeel Natu critical_enter(); 1391318224bbSNeel Natu 1392318224bbSNeel Natu KASSERT(!CPU_ISSET(curcpu, &pmap->pm_active), 1393318224bbSNeel Natu ("vm_run: absurd pm_active")); 1394318224bbSNeel Natu 1395318224bbSNeel Natu tscval = rdtsc(); 1396318224bbSNeel Natu 1397318224bbSNeel Natu pcb = PCPU_GET(curpcb); 1398318224bbSNeel Natu set_pcb_flags(pcb, PCB_FULL_IRET); 1399318224bbSNeel Natu 1400318224bbSNeel Natu restore_guest_msrs(vm, vcpuid); 1401318224bbSNeel Natu restore_guest_fpustate(vcpu); 1402318224bbSNeel Natu 1403318224bbSNeel Natu vcpu_require_state(vm, vcpuid, VCPU_RUNNING); 1404b15a09c0SNeel Natu error = VMRUN(vm->cookie, vcpuid, rip, pmap, rptr, sptr); 1405318224bbSNeel Natu vcpu_require_state(vm, vcpuid, VCPU_FROZEN); 1406318224bbSNeel Natu 1407318224bbSNeel Natu save_guest_fpustate(vcpu); 1408318224bbSNeel Natu restore_host_msrs(vm, vcpuid); 1409318224bbSNeel Natu 1410318224bbSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 1411318224bbSNeel Natu 1412318224bbSNeel Natu critical_exit(); 1413318224bbSNeel Natu 1414318224bbSNeel Natu if (error == 0) { 1415becd9849SNeel Natu retu = false; 1416318224bbSNeel Natu switch (vme->exitcode) { 1417b15a09c0SNeel Natu case VM_EXITCODE_SUSPENDED: 1418b15a09c0SNeel Natu error = vm_handle_suspend(vm, vcpuid, &retu); 1419b15a09c0SNeel Natu break; 142030b94db8SNeel Natu case VM_EXITCODE_IOAPIC_EOI: 142130b94db8SNeel Natu vioapic_process_eoi(vm, vcpuid, 142230b94db8SNeel Natu vme->u.ioapic_eoi.vector); 142330b94db8SNeel Natu break; 14245b8a8cd1SNeel Natu case VM_EXITCODE_RENDEZVOUS: 14255b8a8cd1SNeel Natu vm_handle_rendezvous(vm, vcpuid); 14265b8a8cd1SNeel Natu error = 0; 14275b8a8cd1SNeel Natu break; 1428318224bbSNeel Natu case VM_EXITCODE_HLT: 1429becd9849SNeel Natu intr_disabled = ((vme->u.hlt.rflags & PSL_I) == 0); 14301c052192SNeel Natu error = vm_handle_hlt(vm, vcpuid, intr_disabled, &retu); 1431318224bbSNeel Natu break; 1432318224bbSNeel Natu case VM_EXITCODE_PAGING: 1433318224bbSNeel Natu error = vm_handle_paging(vm, vcpuid, &retu); 1434318224bbSNeel Natu break; 1435318224bbSNeel Natu case VM_EXITCODE_INST_EMUL: 1436318224bbSNeel Natu error = vm_handle_inst_emul(vm, vcpuid, &retu); 1437318224bbSNeel Natu break; 1438d17b5104SNeel Natu case VM_EXITCODE_INOUT: 1439d17b5104SNeel Natu case VM_EXITCODE_INOUT_STR: 1440d17b5104SNeel Natu error = vm_handle_inout(vm, vcpuid, vme, &retu); 1441d17b5104SNeel Natu break; 1442318224bbSNeel Natu default: 1443becd9849SNeel Natu retu = true; /* handled in userland */ 1444318224bbSNeel Natu break; 1445318224bbSNeel Natu } 1446318224bbSNeel Natu } 1447318224bbSNeel Natu 1448becd9849SNeel Natu if (error == 0 && retu == false) { 1449f76fc5d4SNeel Natu rip = vme->rip + vme->inst_length; 1450f76fc5d4SNeel Natu goto restart; 1451f76fc5d4SNeel Natu } 1452f76fc5d4SNeel Natu 1453318224bbSNeel Natu /* copy the exit information */ 1454318224bbSNeel Natu bcopy(vme, &vmrun->vm_exit, sizeof(struct vm_exit)); 1455366f6083SPeter Grehan return (error); 1456366f6083SPeter Grehan } 1457366f6083SPeter Grehan 1458366f6083SPeter Grehan int 1459dc506506SNeel Natu vm_inject_exception(struct vm *vm, int vcpuid, struct vm_exception *exception) 1460366f6083SPeter Grehan { 1461dc506506SNeel Natu struct vcpu *vcpu; 1462dc506506SNeel Natu 1463366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1464366f6083SPeter Grehan return (EINVAL); 1465366f6083SPeter Grehan 1466dc506506SNeel Natu if (exception->vector < 0 || exception->vector >= 32) 1467366f6083SPeter Grehan return (EINVAL); 1468366f6083SPeter Grehan 1469dc506506SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1470366f6083SPeter Grehan 1471dc506506SNeel Natu if (vcpu->exception_pending) { 1472dc506506SNeel Natu VCPU_CTR2(vm, vcpuid, "Unable to inject exception %d due to " 1473dc506506SNeel Natu "pending exception %d", exception->vector, 1474dc506506SNeel Natu vcpu->exception.vector); 1475dc506506SNeel Natu return (EBUSY); 1476dc506506SNeel Natu } 1477dc506506SNeel Natu 1478dc506506SNeel Natu vcpu->exception_pending = 1; 1479dc506506SNeel Natu vcpu->exception = *exception; 1480dc506506SNeel Natu VCPU_CTR1(vm, vcpuid, "Exception %d pending", exception->vector); 1481dc506506SNeel Natu return (0); 1482dc506506SNeel Natu } 1483dc506506SNeel Natu 1484dc506506SNeel Natu int 1485dc506506SNeel Natu vm_exception_pending(struct vm *vm, int vcpuid, struct vm_exception *exception) 1486dc506506SNeel Natu { 1487dc506506SNeel Natu struct vcpu *vcpu; 1488dc506506SNeel Natu int pending; 1489dc506506SNeel Natu 1490dc506506SNeel Natu KASSERT(vcpuid >= 0 && vcpuid < VM_MAXCPU, ("invalid vcpu %d", vcpuid)); 1491dc506506SNeel Natu 1492dc506506SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1493dc506506SNeel Natu pending = vcpu->exception_pending; 1494dc506506SNeel Natu if (pending) { 1495dc506506SNeel Natu vcpu->exception_pending = 0; 1496dc506506SNeel Natu *exception = vcpu->exception; 1497dc506506SNeel Natu VCPU_CTR1(vm, vcpuid, "Exception %d delivered", 1498dc506506SNeel Natu exception->vector); 1499dc506506SNeel Natu } 1500dc506506SNeel Natu return (pending); 1501dc506506SNeel Natu } 1502dc506506SNeel Natu 1503dc506506SNeel Natu static void 1504dc506506SNeel Natu vm_inject_fault(struct vm *vm, int vcpuid, struct vm_exception *exception) 1505dc506506SNeel Natu { 1506dc506506SNeel Natu struct vm_exit *vmexit; 1507dc506506SNeel Natu int error; 1508dc506506SNeel Natu 1509dc506506SNeel Natu error = vm_inject_exception(vm, vcpuid, exception); 1510dc506506SNeel Natu KASSERT(error == 0, ("vm_inject_exception error %d", error)); 1511dc506506SNeel Natu 1512dc506506SNeel Natu /* 1513dc506506SNeel Natu * A fault-like exception allows the instruction to be restarted 1514dc506506SNeel Natu * after the exception handler returns. 1515dc506506SNeel Natu * 1516dc506506SNeel Natu * By setting the inst_length to 0 we ensure that the instruction 1517dc506506SNeel Natu * pointer remains at the faulting instruction. 1518dc506506SNeel Natu */ 1519dc506506SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 1520dc506506SNeel Natu vmexit->inst_length = 0; 1521dc506506SNeel Natu } 1522dc506506SNeel Natu 1523dc506506SNeel Natu void 152437a723a5SNeel Natu vm_inject_pf(struct vm *vm, int vcpuid, int error_code, uint64_t cr2) 1525fd949af6SNeel Natu { 1526fd949af6SNeel Natu struct vm_exception pf = { 1527fd949af6SNeel Natu .vector = IDT_PF, 1528fd949af6SNeel Natu .error_code_valid = 1, 1529fd949af6SNeel Natu .error_code = error_code 1530fd949af6SNeel Natu }; 153137a723a5SNeel Natu int error; 153237a723a5SNeel Natu 153337a723a5SNeel Natu VCPU_CTR2(vm, vcpuid, "Injecting page fault: error_code %#x, cr2 %#lx", 153437a723a5SNeel Natu error_code, cr2); 153537a723a5SNeel Natu 153637a723a5SNeel Natu error = vm_set_register(vm, vcpuid, VM_REG_GUEST_CR2, cr2); 153737a723a5SNeel Natu KASSERT(error == 0, ("vm_set_register(cr2) error %d", error)); 1538fd949af6SNeel Natu 1539fd949af6SNeel Natu vm_inject_fault(vm, vcpuid, &pf); 1540fd949af6SNeel Natu } 1541fd949af6SNeel Natu 1542fd949af6SNeel Natu void 1543dc506506SNeel Natu vm_inject_gp(struct vm *vm, int vcpuid) 1544dc506506SNeel Natu { 1545dc506506SNeel Natu struct vm_exception gpf = { 1546dc506506SNeel Natu .vector = IDT_GP, 1547dc506506SNeel Natu .error_code_valid = 1, 1548dc506506SNeel Natu .error_code = 0 1549dc506506SNeel Natu }; 1550dc506506SNeel Natu 1551dc506506SNeel Natu vm_inject_fault(vm, vcpuid, &gpf); 1552dc506506SNeel Natu } 1553dc506506SNeel Natu 1554dc506506SNeel Natu void 1555dc506506SNeel Natu vm_inject_ud(struct vm *vm, int vcpuid) 1556dc506506SNeel Natu { 1557dc506506SNeel Natu struct vm_exception udf = { 1558dc506506SNeel Natu .vector = IDT_UD, 1559dc506506SNeel Natu .error_code_valid = 0 1560dc506506SNeel Natu }; 1561dc506506SNeel Natu 1562dc506506SNeel Natu vm_inject_fault(vm, vcpuid, &udf); 1563366f6083SPeter Grehan } 1564366f6083SPeter Grehan 156561592433SNeel Natu static VMM_STAT(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); 1566366f6083SPeter Grehan 1567f352ff0cSNeel Natu int 1568f352ff0cSNeel Natu vm_inject_nmi(struct vm *vm, int vcpuid) 1569f352ff0cSNeel Natu { 1570f352ff0cSNeel Natu struct vcpu *vcpu; 1571f352ff0cSNeel Natu 1572f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1573366f6083SPeter Grehan return (EINVAL); 1574366f6083SPeter Grehan 1575f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1576f352ff0cSNeel Natu 1577f352ff0cSNeel Natu vcpu->nmi_pending = 1; 1578de5ea6b6SNeel Natu vcpu_notify_event(vm, vcpuid, false); 1579f352ff0cSNeel Natu return (0); 1580f352ff0cSNeel Natu } 1581f352ff0cSNeel Natu 1582f352ff0cSNeel Natu int 1583f352ff0cSNeel Natu vm_nmi_pending(struct vm *vm, int vcpuid) 1584f352ff0cSNeel Natu { 1585f352ff0cSNeel Natu struct vcpu *vcpu; 1586f352ff0cSNeel Natu 1587f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1588f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 1589f352ff0cSNeel Natu 1590f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1591f352ff0cSNeel Natu 1592f352ff0cSNeel Natu return (vcpu->nmi_pending); 1593f352ff0cSNeel Natu } 1594f352ff0cSNeel Natu 1595f352ff0cSNeel Natu void 1596f352ff0cSNeel Natu vm_nmi_clear(struct vm *vm, int vcpuid) 1597f352ff0cSNeel Natu { 1598f352ff0cSNeel Natu struct vcpu *vcpu; 1599f352ff0cSNeel Natu 1600f352ff0cSNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1601f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 1602f352ff0cSNeel Natu 1603f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1604f352ff0cSNeel Natu 1605f352ff0cSNeel Natu if (vcpu->nmi_pending == 0) 1606f352ff0cSNeel Natu panic("vm_nmi_clear: inconsistent nmi_pending state"); 1607f352ff0cSNeel Natu 1608f352ff0cSNeel Natu vcpu->nmi_pending = 0; 1609f352ff0cSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1); 1610366f6083SPeter Grehan } 1611366f6083SPeter Grehan 16120775fbb4STycho Nightingale static VMM_STAT(VCPU_EXTINT_COUNT, "number of ExtINTs delivered to vcpu"); 16130775fbb4STycho Nightingale 16140775fbb4STycho Nightingale int 16150775fbb4STycho Nightingale vm_inject_extint(struct vm *vm, int vcpuid) 16160775fbb4STycho Nightingale { 16170775fbb4STycho Nightingale struct vcpu *vcpu; 16180775fbb4STycho Nightingale 16190775fbb4STycho Nightingale if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 16200775fbb4STycho Nightingale return (EINVAL); 16210775fbb4STycho Nightingale 16220775fbb4STycho Nightingale vcpu = &vm->vcpu[vcpuid]; 16230775fbb4STycho Nightingale 16240775fbb4STycho Nightingale vcpu->extint_pending = 1; 16250775fbb4STycho Nightingale vcpu_notify_event(vm, vcpuid, false); 16260775fbb4STycho Nightingale return (0); 16270775fbb4STycho Nightingale } 16280775fbb4STycho Nightingale 16290775fbb4STycho Nightingale int 16300775fbb4STycho Nightingale vm_extint_pending(struct vm *vm, int vcpuid) 16310775fbb4STycho Nightingale { 16320775fbb4STycho Nightingale struct vcpu *vcpu; 16330775fbb4STycho Nightingale 16340775fbb4STycho Nightingale if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 16350775fbb4STycho Nightingale panic("vm_extint_pending: invalid vcpuid %d", vcpuid); 16360775fbb4STycho Nightingale 16370775fbb4STycho Nightingale vcpu = &vm->vcpu[vcpuid]; 16380775fbb4STycho Nightingale 16390775fbb4STycho Nightingale return (vcpu->extint_pending); 16400775fbb4STycho Nightingale } 16410775fbb4STycho Nightingale 16420775fbb4STycho Nightingale void 16430775fbb4STycho Nightingale vm_extint_clear(struct vm *vm, int vcpuid) 16440775fbb4STycho Nightingale { 16450775fbb4STycho Nightingale struct vcpu *vcpu; 16460775fbb4STycho Nightingale 16470775fbb4STycho Nightingale if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 16480775fbb4STycho Nightingale panic("vm_extint_pending: invalid vcpuid %d", vcpuid); 16490775fbb4STycho Nightingale 16500775fbb4STycho Nightingale vcpu = &vm->vcpu[vcpuid]; 16510775fbb4STycho Nightingale 16520775fbb4STycho Nightingale if (vcpu->extint_pending == 0) 16530775fbb4STycho Nightingale panic("vm_extint_clear: inconsistent extint_pending state"); 16540775fbb4STycho Nightingale 16550775fbb4STycho Nightingale vcpu->extint_pending = 0; 16560775fbb4STycho Nightingale vmm_stat_incr(vm, vcpuid, VCPU_EXTINT_COUNT, 1); 16570775fbb4STycho Nightingale } 16580775fbb4STycho Nightingale 1659366f6083SPeter Grehan int 1660366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 1661366f6083SPeter Grehan { 1662366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 1663366f6083SPeter Grehan return (EINVAL); 1664366f6083SPeter Grehan 1665366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 1666366f6083SPeter Grehan return (EINVAL); 1667366f6083SPeter Grehan 1668366f6083SPeter Grehan return (VMGETCAP(vm->cookie, vcpu, type, retval)); 1669366f6083SPeter Grehan } 1670366f6083SPeter Grehan 1671366f6083SPeter Grehan int 1672366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val) 1673366f6083SPeter Grehan { 1674366f6083SPeter Grehan if (vcpu < 0 || vcpu >= VM_MAXCPU) 1675366f6083SPeter Grehan return (EINVAL); 1676366f6083SPeter Grehan 1677366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 1678366f6083SPeter Grehan return (EINVAL); 1679366f6083SPeter Grehan 1680366f6083SPeter Grehan return (VMSETCAP(vm->cookie, vcpu, type, val)); 1681366f6083SPeter Grehan } 1682366f6083SPeter Grehan 1683366f6083SPeter Grehan uint64_t * 1684366f6083SPeter Grehan vm_guest_msrs(struct vm *vm, int cpu) 1685366f6083SPeter Grehan { 1686366f6083SPeter Grehan return (vm->vcpu[cpu].guest_msrs); 1687366f6083SPeter Grehan } 1688366f6083SPeter Grehan 1689366f6083SPeter Grehan struct vlapic * 1690366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu) 1691366f6083SPeter Grehan { 1692366f6083SPeter Grehan return (vm->vcpu[cpu].vlapic); 1693366f6083SPeter Grehan } 1694366f6083SPeter Grehan 1695565bbb86SNeel Natu struct vioapic * 1696565bbb86SNeel Natu vm_ioapic(struct vm *vm) 1697565bbb86SNeel Natu { 1698565bbb86SNeel Natu 1699565bbb86SNeel Natu return (vm->vioapic); 1700565bbb86SNeel Natu } 1701565bbb86SNeel Natu 170208e3ff32SNeel Natu struct vhpet * 170308e3ff32SNeel Natu vm_hpet(struct vm *vm) 170408e3ff32SNeel Natu { 170508e3ff32SNeel Natu 170608e3ff32SNeel Natu return (vm->vhpet); 170708e3ff32SNeel Natu } 170808e3ff32SNeel Natu 1709366f6083SPeter Grehan boolean_t 1710366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 1711366f6083SPeter Grehan { 171207044a96SNeel Natu int found, i, n; 171307044a96SNeel Natu int b, s, f; 1714366f6083SPeter Grehan char *val, *cp, *cp2; 1715366f6083SPeter Grehan 1716366f6083SPeter Grehan /* 171707044a96SNeel Natu * XXX 171807044a96SNeel Natu * The length of an environment variable is limited to 128 bytes which 171907044a96SNeel Natu * puts an upper limit on the number of passthru devices that may be 172007044a96SNeel Natu * specified using a single environment variable. 172107044a96SNeel Natu * 172207044a96SNeel Natu * Work around this by scanning multiple environment variable 172307044a96SNeel Natu * names instead of a single one - yuck! 1724366f6083SPeter Grehan */ 172507044a96SNeel Natu const char *names[] = { "pptdevs", "pptdevs2", "pptdevs3", NULL }; 172607044a96SNeel Natu 172707044a96SNeel Natu /* set pptdevs="1/2/3 4/5/6 7/8/9 10/11/12" */ 1728366f6083SPeter Grehan found = 0; 172907044a96SNeel Natu for (i = 0; names[i] != NULL && !found; i++) { 173007044a96SNeel Natu cp = val = getenv(names[i]); 1731366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 1732366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 1733366f6083SPeter Grehan *cp2 = '\0'; 1734366f6083SPeter Grehan 1735366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 1736366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 1737366f6083SPeter Grehan found = 1; 1738366f6083SPeter Grehan break; 1739366f6083SPeter Grehan } 1740366f6083SPeter Grehan 1741366f6083SPeter Grehan if (cp2 != NULL) 1742366f6083SPeter Grehan *cp2++ = ' '; 1743366f6083SPeter Grehan 1744366f6083SPeter Grehan cp = cp2; 1745366f6083SPeter Grehan } 1746366f6083SPeter Grehan freeenv(val); 174707044a96SNeel Natu } 1748366f6083SPeter Grehan return (found); 1749366f6083SPeter Grehan } 1750366f6083SPeter Grehan 1751366f6083SPeter Grehan void * 1752366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 1753366f6083SPeter Grehan { 1754366f6083SPeter Grehan 1755366f6083SPeter Grehan return (vm->iommu); 1756366f6083SPeter Grehan } 1757366f6083SPeter Grehan 175875dd3366SNeel Natu int 1759f80330a8SNeel Natu vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state newstate, 1760f80330a8SNeel Natu bool from_idle) 1761366f6083SPeter Grehan { 176275dd3366SNeel Natu int error; 1763366f6083SPeter Grehan struct vcpu *vcpu; 1764366f6083SPeter Grehan 1765366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1766366f6083SPeter Grehan panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 1767366f6083SPeter Grehan 1768366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 1769366f6083SPeter Grehan 177075dd3366SNeel Natu vcpu_lock(vcpu); 1771f80330a8SNeel Natu error = vcpu_set_state_locked(vcpu, newstate, from_idle); 177275dd3366SNeel Natu vcpu_unlock(vcpu); 177375dd3366SNeel Natu 177475dd3366SNeel Natu return (error); 177575dd3366SNeel Natu } 177675dd3366SNeel Natu 177775dd3366SNeel Natu enum vcpu_state 1778d3c11f40SPeter Grehan vcpu_get_state(struct vm *vm, int vcpuid, int *hostcpu) 1779366f6083SPeter Grehan { 1780366f6083SPeter Grehan struct vcpu *vcpu; 178175dd3366SNeel Natu enum vcpu_state state; 1782366f6083SPeter Grehan 1783366f6083SPeter Grehan if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1784366f6083SPeter Grehan panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 1785366f6083SPeter Grehan 1786366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 1787366f6083SPeter Grehan 178875dd3366SNeel Natu vcpu_lock(vcpu); 178975dd3366SNeel Natu state = vcpu->state; 1790d3c11f40SPeter Grehan if (hostcpu != NULL) 1791d3c11f40SPeter Grehan *hostcpu = vcpu->hostcpu; 179275dd3366SNeel Natu vcpu_unlock(vcpu); 1793366f6083SPeter Grehan 179475dd3366SNeel Natu return (state); 1795366f6083SPeter Grehan } 1796366f6083SPeter Grehan 179795ebc360SNeel Natu int 1798366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid) 1799366f6083SPeter Grehan { 1800366f6083SPeter Grehan 180195ebc360SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 180295ebc360SNeel Natu return (EINVAL); 180395ebc360SNeel Natu 180495ebc360SNeel Natu if (CPU_ISSET(vcpuid, &vm->active_cpus)) 180595ebc360SNeel Natu return (EBUSY); 180622d822c6SNeel Natu 180722d822c6SNeel Natu VCPU_CTR0(vm, vcpuid, "activated"); 180822d822c6SNeel Natu CPU_SET_ATOMIC(vcpuid, &vm->active_cpus); 180995ebc360SNeel Natu return (0); 1810366f6083SPeter Grehan } 1811366f6083SPeter Grehan 1812a5615c90SPeter Grehan cpuset_t 1813366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 1814366f6083SPeter Grehan { 1815366f6083SPeter Grehan 1816366f6083SPeter Grehan return (vm->active_cpus); 1817366f6083SPeter Grehan } 1818366f6083SPeter Grehan 181995ebc360SNeel Natu cpuset_t 182095ebc360SNeel Natu vm_suspended_cpus(struct vm *vm) 182195ebc360SNeel Natu { 182295ebc360SNeel Natu 182395ebc360SNeel Natu return (vm->suspended_cpus); 182495ebc360SNeel Natu } 182595ebc360SNeel Natu 1826366f6083SPeter Grehan void * 1827366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid) 1828366f6083SPeter Grehan { 1829366f6083SPeter Grehan 1830366f6083SPeter Grehan return (vm->vcpu[vcpuid].stats); 1831366f6083SPeter Grehan } 1832e9027382SNeel Natu 1833e9027382SNeel Natu int 1834e9027382SNeel Natu vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) 1835e9027382SNeel Natu { 1836e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1837e9027382SNeel Natu return (EINVAL); 1838e9027382SNeel Natu 1839e9027382SNeel Natu *state = vm->vcpu[vcpuid].x2apic_state; 1840e9027382SNeel Natu 1841e9027382SNeel Natu return (0); 1842e9027382SNeel Natu } 1843e9027382SNeel Natu 1844e9027382SNeel Natu int 1845e9027382SNeel Natu vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 1846e9027382SNeel Natu { 1847e9027382SNeel Natu if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 1848e9027382SNeel Natu return (EINVAL); 1849e9027382SNeel Natu 18503f23d3caSNeel Natu if (state >= X2APIC_STATE_LAST) 1851e9027382SNeel Natu return (EINVAL); 1852e9027382SNeel Natu 1853e9027382SNeel Natu vm->vcpu[vcpuid].x2apic_state = state; 1854e9027382SNeel Natu 185573820fb0SNeel Natu vlapic_set_x2apic_state(vm, vcpuid, state); 185673820fb0SNeel Natu 1857e9027382SNeel Natu return (0); 1858e9027382SNeel Natu } 185975dd3366SNeel Natu 186022821874SNeel Natu /* 186122821874SNeel Natu * This function is called to ensure that a vcpu "sees" a pending event 186222821874SNeel Natu * as soon as possible: 186322821874SNeel Natu * - If the vcpu thread is sleeping then it is woken up. 186422821874SNeel Natu * - If the vcpu is running on a different host_cpu then an IPI will be directed 186522821874SNeel Natu * to the host_cpu to cause the vcpu to trap into the hypervisor. 186622821874SNeel Natu */ 186775dd3366SNeel Natu void 1868de5ea6b6SNeel Natu vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr) 186975dd3366SNeel Natu { 187075dd3366SNeel Natu int hostcpu; 187175dd3366SNeel Natu struct vcpu *vcpu; 187275dd3366SNeel Natu 187375dd3366SNeel Natu vcpu = &vm->vcpu[vcpuid]; 187475dd3366SNeel Natu 1875f76fc5d4SNeel Natu vcpu_lock(vcpu); 187675dd3366SNeel Natu hostcpu = vcpu->hostcpu; 1877ef39d7e9SNeel Natu if (vcpu->state == VCPU_RUNNING) { 1878ef39d7e9SNeel Natu KASSERT(hostcpu != NOCPU, ("vcpu running on invalid hostcpu")); 1879de5ea6b6SNeel Natu if (hostcpu != curcpu) { 1880ef39d7e9SNeel Natu if (lapic_intr) { 1881add611fdSNeel Natu vlapic_post_intr(vcpu->vlapic, hostcpu, 1882add611fdSNeel Natu vmm_ipinum); 1883ef39d7e9SNeel Natu } else { 188475dd3366SNeel Natu ipi_cpu(hostcpu, vmm_ipinum); 188575dd3366SNeel Natu } 1886ef39d7e9SNeel Natu } else { 1887ef39d7e9SNeel Natu /* 1888ef39d7e9SNeel Natu * If the 'vcpu' is running on 'curcpu' then it must 1889ef39d7e9SNeel Natu * be sending a notification to itself (e.g. SELF_IPI). 1890ef39d7e9SNeel Natu * The pending event will be picked up when the vcpu 1891ef39d7e9SNeel Natu * transitions back to guest context. 1892ef39d7e9SNeel Natu */ 1893ef39d7e9SNeel Natu } 1894ef39d7e9SNeel Natu } else { 1895ef39d7e9SNeel Natu KASSERT(hostcpu == NOCPU, ("vcpu state %d not consistent " 1896ef39d7e9SNeel Natu "with hostcpu %d", vcpu->state, hostcpu)); 1897ef39d7e9SNeel Natu if (vcpu->state == VCPU_SLEEPING) 1898ef39d7e9SNeel Natu wakeup_one(vcpu); 1899de5ea6b6SNeel Natu } 1900f76fc5d4SNeel Natu vcpu_unlock(vcpu); 1901f76fc5d4SNeel Natu } 1902318224bbSNeel Natu 1903318224bbSNeel Natu struct vmspace * 1904318224bbSNeel Natu vm_get_vmspace(struct vm *vm) 1905318224bbSNeel Natu { 1906318224bbSNeel Natu 1907318224bbSNeel Natu return (vm->vmspace); 1908318224bbSNeel Natu } 1909565bbb86SNeel Natu 1910565bbb86SNeel Natu int 1911565bbb86SNeel Natu vm_apicid2vcpuid(struct vm *vm, int apicid) 1912565bbb86SNeel Natu { 1913565bbb86SNeel Natu /* 1914565bbb86SNeel Natu * XXX apic id is assumed to be numerically identical to vcpu id 1915565bbb86SNeel Natu */ 1916565bbb86SNeel Natu return (apicid); 1917565bbb86SNeel Natu } 19185b8a8cd1SNeel Natu 19195b8a8cd1SNeel Natu void 19205b8a8cd1SNeel Natu vm_smp_rendezvous(struct vm *vm, int vcpuid, cpuset_t dest, 19215b8a8cd1SNeel Natu vm_rendezvous_func_t func, void *arg) 19225b8a8cd1SNeel Natu { 1923970955e4SNeel Natu int i; 1924970955e4SNeel Natu 19255b8a8cd1SNeel Natu /* 19265b8a8cd1SNeel Natu * Enforce that this function is called without any locks 19275b8a8cd1SNeel Natu */ 19285b8a8cd1SNeel Natu WITNESS_WARN(WARN_PANIC, NULL, "vm_smp_rendezvous"); 19295b8a8cd1SNeel Natu KASSERT(vcpuid == -1 || (vcpuid >= 0 && vcpuid < VM_MAXCPU), 19305b8a8cd1SNeel Natu ("vm_smp_rendezvous: invalid vcpuid %d", vcpuid)); 19315b8a8cd1SNeel Natu 19325b8a8cd1SNeel Natu restart: 19335b8a8cd1SNeel Natu mtx_lock(&vm->rendezvous_mtx); 19345b8a8cd1SNeel Natu if (vm->rendezvous_func != NULL) { 19355b8a8cd1SNeel Natu /* 19365b8a8cd1SNeel Natu * If a rendezvous is already in progress then we need to 19375b8a8cd1SNeel Natu * call the rendezvous handler in case this 'vcpuid' is one 19385b8a8cd1SNeel Natu * of the targets of the rendezvous. 19395b8a8cd1SNeel Natu */ 19405b8a8cd1SNeel Natu RENDEZVOUS_CTR0(vm, vcpuid, "Rendezvous already in progress"); 19415b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 19425b8a8cd1SNeel Natu vm_handle_rendezvous(vm, vcpuid); 19435b8a8cd1SNeel Natu goto restart; 19445b8a8cd1SNeel Natu } 19455b8a8cd1SNeel Natu KASSERT(vm->rendezvous_func == NULL, ("vm_smp_rendezvous: previous " 19465b8a8cd1SNeel Natu "rendezvous is still in progress")); 19475b8a8cd1SNeel Natu 19485b8a8cd1SNeel Natu RENDEZVOUS_CTR0(vm, vcpuid, "Initiating rendezvous"); 19495b8a8cd1SNeel Natu vm->rendezvous_req_cpus = dest; 19505b8a8cd1SNeel Natu CPU_ZERO(&vm->rendezvous_done_cpus); 19515b8a8cd1SNeel Natu vm->rendezvous_arg = arg; 19525b8a8cd1SNeel Natu vm_set_rendezvous_func(vm, func); 19535b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 19545b8a8cd1SNeel Natu 1955970955e4SNeel Natu /* 1956970955e4SNeel Natu * Wake up any sleeping vcpus and trigger a VM-exit in any running 1957970955e4SNeel Natu * vcpus so they handle the rendezvous as soon as possible. 1958970955e4SNeel Natu */ 1959970955e4SNeel Natu for (i = 0; i < VM_MAXCPU; i++) { 1960970955e4SNeel Natu if (CPU_ISSET(i, &dest)) 1961970955e4SNeel Natu vcpu_notify_event(vm, i, false); 1962970955e4SNeel Natu } 1963970955e4SNeel Natu 19645b8a8cd1SNeel Natu vm_handle_rendezvous(vm, vcpuid); 19655b8a8cd1SNeel Natu } 1966762fd208STycho Nightingale 1967762fd208STycho Nightingale struct vatpic * 1968762fd208STycho Nightingale vm_atpic(struct vm *vm) 1969762fd208STycho Nightingale { 1970762fd208STycho Nightingale return (vm->vatpic); 1971762fd208STycho Nightingale } 1972e883c9bbSTycho Nightingale 1973e883c9bbSTycho Nightingale struct vatpit * 1974e883c9bbSTycho Nightingale vm_atpit(struct vm *vm) 1975e883c9bbSTycho Nightingale { 1976e883c9bbSTycho Nightingale return (vm->vatpit); 1977e883c9bbSTycho Nightingale } 1978d17b5104SNeel Natu 1979d17b5104SNeel Natu enum vm_reg_name 1980d17b5104SNeel Natu vm_segment_name(int seg) 1981d17b5104SNeel Natu { 1982d17b5104SNeel Natu static enum vm_reg_name seg_names[] = { 1983d17b5104SNeel Natu VM_REG_GUEST_ES, 1984d17b5104SNeel Natu VM_REG_GUEST_CS, 1985d17b5104SNeel Natu VM_REG_GUEST_SS, 1986d17b5104SNeel Natu VM_REG_GUEST_DS, 1987d17b5104SNeel Natu VM_REG_GUEST_FS, 1988d17b5104SNeel Natu VM_REG_GUEST_GS 1989d17b5104SNeel Natu }; 1990d17b5104SNeel Natu 1991d17b5104SNeel Natu KASSERT(seg >= 0 && seg < nitems(seg_names), 1992d17b5104SNeel Natu ("%s: invalid segment encoding %d", __func__, seg)); 1993d17b5104SNeel Natu return (seg_names[seg]); 1994d17b5104SNeel Natu } 1995*cf1d80d8SPeter Grehan 1996*cf1d80d8SPeter Grehan 1997*cf1d80d8SPeter Grehan /* 1998*cf1d80d8SPeter Grehan * Return the amount of in-use and wired memory for the VM. Since 1999*cf1d80d8SPeter Grehan * these are global stats, only return the values with for vCPU 0 2000*cf1d80d8SPeter Grehan */ 2001*cf1d80d8SPeter Grehan VMM_STAT_DECLARE(VMM_MEM_RESIDENT); 2002*cf1d80d8SPeter Grehan VMM_STAT_DECLARE(VMM_MEM_WIRED); 2003*cf1d80d8SPeter Grehan 2004*cf1d80d8SPeter Grehan static void 2005*cf1d80d8SPeter Grehan vm_get_rescnt(struct vm *vm, int vcpu, struct vmm_stat_type *stat) 2006*cf1d80d8SPeter Grehan { 2007*cf1d80d8SPeter Grehan 2008*cf1d80d8SPeter Grehan if (vcpu == 0) { 2009*cf1d80d8SPeter Grehan vmm_stat_set(vm, vcpu, VMM_MEM_RESIDENT, 2010*cf1d80d8SPeter Grehan PAGE_SIZE * vmspace_resident_count(vm->vmspace)); 2011*cf1d80d8SPeter Grehan } 2012*cf1d80d8SPeter Grehan } 2013*cf1d80d8SPeter Grehan 2014*cf1d80d8SPeter Grehan static void 2015*cf1d80d8SPeter Grehan vm_get_wiredcnt(struct vm *vm, int vcpu, struct vmm_stat_type *stat) 2016*cf1d80d8SPeter Grehan { 2017*cf1d80d8SPeter Grehan 2018*cf1d80d8SPeter Grehan if (vcpu == 0) { 2019*cf1d80d8SPeter Grehan vmm_stat_set(vm, vcpu, VMM_MEM_WIRED, 2020*cf1d80d8SPeter Grehan PAGE_SIZE * pmap_wired_count(vmspace_pmap(vm->vmspace))); 2021*cf1d80d8SPeter Grehan } 2022*cf1d80d8SPeter Grehan } 2023*cf1d80d8SPeter Grehan 2024*cf1d80d8SPeter Grehan VMM_STAT_FUNC(VMM_MEM_RESIDENT, "Resident memory", vm_get_rescnt); 2025*cf1d80d8SPeter Grehan VMM_STAT_FUNC(VMM_MEM_WIRED, "Wired memory", vm_get_wiredcnt); 2026