1366f6083SPeter Grehan /*- 2c49761ddSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3c49761ddSPedro F. Giffuni * 4366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 5366f6083SPeter Grehan * All rights reserved. 6366f6083SPeter Grehan * 7366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 8366f6083SPeter Grehan * modification, are permitted provided that the following conditions 9366f6083SPeter Grehan * are met: 10366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 12366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 13366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 14366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 15366f6083SPeter Grehan * 16366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26366f6083SPeter Grehan * SUCH DAMAGE. 27366f6083SPeter Grehan * 28366f6083SPeter Grehan * $FreeBSD$ 29366f6083SPeter Grehan */ 30366f6083SPeter Grehan 31366f6083SPeter Grehan #include <sys/cdefs.h> 32366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 33366f6083SPeter Grehan 34366f6083SPeter Grehan #include <sys/param.h> 3538f1b189SPeter Grehan #include <sys/systm.h> 36366f6083SPeter Grehan #include <sys/kernel.h> 37366f6083SPeter Grehan #include <sys/module.h> 38366f6083SPeter Grehan #include <sys/sysctl.h> 39366f6083SPeter Grehan #include <sys/malloc.h> 40366f6083SPeter Grehan #include <sys/pcpu.h> 41366f6083SPeter Grehan #include <sys/lock.h> 42366f6083SPeter Grehan #include <sys/mutex.h> 43366f6083SPeter Grehan #include <sys/proc.h> 44318224bbSNeel Natu #include <sys/rwlock.h> 45366f6083SPeter Grehan #include <sys/sched.h> 46366f6083SPeter Grehan #include <sys/smp.h> 47366f6083SPeter Grehan #include <sys/systm.h> 48366f6083SPeter Grehan 49366f6083SPeter Grehan #include <vm/vm.h> 50318224bbSNeel Natu #include <vm/vm_object.h> 51318224bbSNeel Natu #include <vm/vm_page.h> 52318224bbSNeel Natu #include <vm/pmap.h> 53318224bbSNeel Natu #include <vm/vm_map.h> 54318224bbSNeel Natu #include <vm/vm_extern.h> 55318224bbSNeel Natu #include <vm/vm_param.h> 56366f6083SPeter Grehan 5763e62d39SJohn Baldwin #include <machine/cpu.h> 58366f6083SPeter Grehan #include <machine/pcb.h> 5975dd3366SNeel Natu #include <machine/smp.h> 60bd50262fSKonstantin Belousov #include <machine/md_var.h> 611c052192SNeel Natu #include <x86/psl.h> 6234a6b2d6SJohn Baldwin #include <x86/apicreg.h> 63366f6083SPeter Grehan 64366f6083SPeter Grehan #include <machine/vmm.h> 65565bbb86SNeel Natu #include <machine/vmm_dev.h> 66e813a873SNeel Natu #include <machine/vmm_instruction_emul.h> 67565bbb86SNeel Natu 68d17b5104SNeel Natu #include "vmm_ioport.h" 69318224bbSNeel Natu #include "vmm_ktr.h" 70b01c2033SNeel Natu #include "vmm_host.h" 71366f6083SPeter Grehan #include "vmm_mem.h" 72366f6083SPeter Grehan #include "vmm_util.h" 73762fd208STycho Nightingale #include "vatpic.h" 74e883c9bbSTycho Nightingale #include "vatpit.h" 7508e3ff32SNeel Natu #include "vhpet.h" 76565bbb86SNeel Natu #include "vioapic.h" 77366f6083SPeter Grehan #include "vlapic.h" 78160ef77aSNeel Natu #include "vpmtmr.h" 790dafa5cdSNeel Natu #include "vrtc.h" 80366f6083SPeter Grehan #include "vmm_stat.h" 81f76fc5d4SNeel Natu #include "vmm_lapic.h" 82366f6083SPeter Grehan 83366f6083SPeter Grehan #include "io/ppt.h" 84366f6083SPeter Grehan #include "io/iommu.h" 85366f6083SPeter Grehan 86366f6083SPeter Grehan struct vlapic; 87366f6083SPeter Grehan 885fcf252fSNeel Natu /* 895fcf252fSNeel Natu * Initialization: 905fcf252fSNeel Natu * (a) allocated when vcpu is created 915fcf252fSNeel Natu * (i) initialized when vcpu is created and when it is reinitialized 925fcf252fSNeel Natu * (o) initialized the first time the vcpu is created 935fcf252fSNeel Natu * (x) initialized before use 945fcf252fSNeel Natu */ 95366f6083SPeter Grehan struct vcpu { 965fcf252fSNeel Natu struct mtx mtx; /* (o) protects 'state' and 'hostcpu' */ 975fcf252fSNeel Natu enum vcpu_state state; /* (o) vcpu state */ 985fcf252fSNeel Natu int hostcpu; /* (o) vcpu's host cpu */ 99248e6799SNeel Natu int reqidle; /* (i) request vcpu to idle */ 1005fcf252fSNeel Natu struct vlapic *vlapic; /* (i) APIC device model */ 1015fcf252fSNeel Natu enum x2apic_state x2apic_state; /* (i) APIC mode */ 102091d4532SNeel Natu uint64_t exitintinfo; /* (i) events pending at VM exit */ 1035fcf252fSNeel Natu int nmi_pending; /* (i) NMI pending */ 1045fcf252fSNeel Natu int extint_pending; /* (i) INTR pending */ 1055fcf252fSNeel Natu int exception_pending; /* (i) exception pending */ 106c9c75df4SNeel Natu int exc_vector; /* (x) exception collateral */ 107c9c75df4SNeel Natu int exc_errcode_valid; 108c9c75df4SNeel Natu uint32_t exc_errcode; 1095fcf252fSNeel Natu struct savefpu *guestfpu; /* (a,i) guest fpu state */ 1105fcf252fSNeel Natu uint64_t guest_xcr0; /* (i) guest %xcr0 register */ 1115fcf252fSNeel Natu void *stats; /* (a,i) statistics */ 1125fcf252fSNeel Natu struct vm_exit exitinfo; /* (x) exit reason and collateral */ 113d087a399SNeel Natu uint64_t nextrip; /* (x) next instruction to execute */ 114366f6083SPeter Grehan }; 115366f6083SPeter Grehan 1165fcf252fSNeel Natu #define vcpu_lock_initialized(v) mtx_initialized(&((v)->mtx)) 117f76fc5d4SNeel Natu #define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_SPIN) 118f76fc5d4SNeel Natu #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) 119f76fc5d4SNeel Natu #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) 120318224bbSNeel Natu #define vcpu_assert_locked(v) mtx_assert(&((v)->mtx), MA_OWNED) 12175dd3366SNeel Natu 122318224bbSNeel Natu struct mem_seg { 1239b1aa8d6SNeel Natu size_t len; 1249b1aa8d6SNeel Natu bool sysmem; 1259b1aa8d6SNeel Natu struct vm_object *object; 1269b1aa8d6SNeel Natu }; 1276bcf245eSMarcel Moolenaar #define VM_MAX_MEMSEGS 3 1289b1aa8d6SNeel Natu 1299b1aa8d6SNeel Natu struct mem_map { 130318224bbSNeel Natu vm_paddr_t gpa; 131318224bbSNeel Natu size_t len; 1329b1aa8d6SNeel Natu vm_ooffset_t segoff; 1339b1aa8d6SNeel Natu int segid; 1349b1aa8d6SNeel Natu int prot; 1359b1aa8d6SNeel Natu int flags; 136318224bbSNeel Natu }; 1379b1aa8d6SNeel Natu #define VM_MAX_MEMMAPS 4 138366f6083SPeter Grehan 139366f6083SPeter Grehan /* 1405fcf252fSNeel Natu * Initialization: 1415fcf252fSNeel Natu * (o) initialized the first time the VM is created 1425fcf252fSNeel Natu * (i) initialized when VM is created and when it is reinitialized 1435fcf252fSNeel Natu * (x) initialized before use 144366f6083SPeter Grehan */ 1455fcf252fSNeel Natu struct vm { 1465fcf252fSNeel Natu void *cookie; /* (i) cpu-specific data */ 1475fcf252fSNeel Natu void *iommu; /* (x) iommu-specific data */ 1485fcf252fSNeel Natu struct vhpet *vhpet; /* (i) virtual HPET */ 1495fcf252fSNeel Natu struct vioapic *vioapic; /* (i) virtual ioapic */ 1505fcf252fSNeel Natu struct vatpic *vatpic; /* (i) virtual atpic */ 1515fcf252fSNeel Natu struct vatpit *vatpit; /* (i) virtual atpit */ 152160ef77aSNeel Natu struct vpmtmr *vpmtmr; /* (i) virtual ACPI PM timer */ 1530dafa5cdSNeel Natu struct vrtc *vrtc; /* (o) virtual RTC */ 1545fcf252fSNeel Natu volatile cpuset_t active_cpus; /* (i) active vcpus */ 155fc276d92SJohn Baldwin volatile cpuset_t debug_cpus; /* (i) vcpus stopped for debug */ 1565fcf252fSNeel Natu int suspend; /* (i) stop VM execution */ 1575fcf252fSNeel Natu volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */ 1585fcf252fSNeel Natu volatile cpuset_t halted_cpus; /* (x) cpus in a hard halt */ 1595fcf252fSNeel Natu cpuset_t rendezvous_req_cpus; /* (x) rendezvous requested */ 1605fcf252fSNeel Natu cpuset_t rendezvous_done_cpus; /* (x) rendezvous finished */ 1615fcf252fSNeel Natu void *rendezvous_arg; /* (x) rendezvous func/arg */ 1625b8a8cd1SNeel Natu vm_rendezvous_func_t rendezvous_func; 1635fcf252fSNeel Natu struct mtx rendezvous_mtx; /* (o) rendezvous lock */ 1649b1aa8d6SNeel Natu struct mem_map mem_maps[VM_MAX_MEMMAPS]; /* (i) guest address space */ 1659b1aa8d6SNeel Natu struct mem_seg mem_segs[VM_MAX_MEMSEGS]; /* (o) guest memory regions */ 1665fcf252fSNeel Natu struct vmspace *vmspace; /* (o) guest's address space */ 1675fcf252fSNeel Natu char name[VM_MAX_NAMELEN]; /* (o) virtual machine name */ 1685fcf252fSNeel Natu struct vcpu vcpu[VM_MAXCPU]; /* (i) guest vcpus */ 16901d822d3SRodney W. Grimes /* The following describe the vm cpu topology */ 17001d822d3SRodney W. Grimes uint16_t sockets; /* (o) num of sockets */ 17101d822d3SRodney W. Grimes uint16_t cores; /* (o) num of cores/socket */ 17201d822d3SRodney W. Grimes uint16_t threads; /* (o) num of threads/core */ 17301d822d3SRodney W. Grimes uint16_t maxcpus; /* (o) max pluggable cpus */ 174366f6083SPeter Grehan }; 175366f6083SPeter Grehan 176d5408b1dSNeel Natu static int vmm_initialized; 177d5408b1dSNeel Natu 178366f6083SPeter Grehan static struct vmm_ops *ops; 179add611fdSNeel Natu #define VMM_INIT(num) (ops != NULL ? (*ops->init)(num) : 0) 180366f6083SPeter Grehan #define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 18163e62d39SJohn Baldwin #define VMM_RESUME() (ops != NULL ? (*ops->resume)() : 0) 182366f6083SPeter Grehan 183318224bbSNeel Natu #define VMINIT(vm, pmap) (ops != NULL ? (*ops->vminit)(vm, pmap): NULL) 184248e6799SNeel Natu #define VMRUN(vmi, vcpu, rip, pmap, evinfo) \ 185248e6799SNeel Natu (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, pmap, evinfo) : ENXIO) 186366f6083SPeter Grehan #define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 187318224bbSNeel Natu #define VMSPACE_ALLOC(min, max) \ 188318224bbSNeel Natu (ops != NULL ? (*ops->vmspace_alloc)(min, max) : NULL) 189318224bbSNeel Natu #define VMSPACE_FREE(vmspace) \ 190318224bbSNeel Natu (ops != NULL ? (*ops->vmspace_free)(vmspace) : ENXIO) 191366f6083SPeter Grehan #define VMGETREG(vmi, vcpu, num, retval) \ 192366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 193366f6083SPeter Grehan #define VMSETREG(vmi, vcpu, num, val) \ 194366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 195366f6083SPeter Grehan #define VMGETDESC(vmi, vcpu, num, desc) \ 196366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 197366f6083SPeter Grehan #define VMSETDESC(vmi, vcpu, num, desc) \ 198366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 199366f6083SPeter Grehan #define VMGETCAP(vmi, vcpu, num, retval) \ 200366f6083SPeter Grehan (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 201366f6083SPeter Grehan #define VMSETCAP(vmi, vcpu, num, val) \ 202366f6083SPeter Grehan (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 203de5ea6b6SNeel Natu #define VLAPIC_INIT(vmi, vcpu) \ 204de5ea6b6SNeel Natu (ops != NULL ? (*ops->vlapic_init)(vmi, vcpu) : NULL) 205de5ea6b6SNeel Natu #define VLAPIC_CLEANUP(vmi, vlapic) \ 206de5ea6b6SNeel Natu (ops != NULL ? (*ops->vlapic_cleanup)(vmi, vlapic) : NULL) 207366f6083SPeter Grehan 208014a52f3SNeel Natu #define fpu_start_emulating() load_cr0(rcr0() | CR0_TS) 209014a52f3SNeel Natu #define fpu_stop_emulating() clts() 210366f6083SPeter Grehan 2116ac73777STycho Nightingale SDT_PROVIDER_DEFINE(vmm); 2126ac73777STycho Nightingale 213366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 214366f6083SPeter Grehan 215366f6083SPeter Grehan /* statistics */ 21661592433SNeel Natu static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 217366f6083SPeter Grehan 218*b40598c5SPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 219*b40598c5SPawel Biernacki NULL); 220add611fdSNeel Natu 221055fc2cbSNeel Natu /* 222055fc2cbSNeel Natu * Halt the guest if all vcpus are executing a HLT instruction with 223055fc2cbSNeel Natu * interrupts disabled. 224055fc2cbSNeel Natu */ 225055fc2cbSNeel Natu static int halt_detection_enabled = 1; 226055fc2cbSNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, halt_detection, CTLFLAG_RDTUN, 227055fc2cbSNeel Natu &halt_detection_enabled, 0, 228055fc2cbSNeel Natu "Halt VM if all vcpus execute HLT with interrupts disabled"); 229055fc2cbSNeel Natu 230978f3da1SAndriy Gapon static int vmm_ipinum; 231add611fdSNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, ipinum, CTLFLAG_RD, &vmm_ipinum, 0, 232add611fdSNeel Natu "IPI vector used for vcpu notifications"); 233add611fdSNeel Natu 234b0538143SNeel Natu static int trace_guest_exceptions; 235b0538143SNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, trace_guest_exceptions, CTLFLAG_RDTUN, 236b0538143SNeel Natu &trace_guest_exceptions, 0, 237b0538143SNeel Natu "Trap into hypervisor on all guest exceptions and reflect them back"); 238b0538143SNeel Natu 2399b1aa8d6SNeel Natu static void vm_free_memmap(struct vm *vm, int ident); 2409b1aa8d6SNeel Natu static bool sysmem_mapping(struct vm *vm, struct mem_map *mm); 241248e6799SNeel Natu static void vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr); 242248e6799SNeel Natu 243248e6799SNeel Natu #ifdef KTR 244248e6799SNeel Natu static const char * 245248e6799SNeel Natu vcpu_state2str(enum vcpu_state state) 246248e6799SNeel Natu { 247248e6799SNeel Natu 248248e6799SNeel Natu switch (state) { 249248e6799SNeel Natu case VCPU_IDLE: 250248e6799SNeel Natu return ("idle"); 251248e6799SNeel Natu case VCPU_FROZEN: 252248e6799SNeel Natu return ("frozen"); 253248e6799SNeel Natu case VCPU_RUNNING: 254248e6799SNeel Natu return ("running"); 255248e6799SNeel Natu case VCPU_SLEEPING: 256248e6799SNeel Natu return ("sleeping"); 257248e6799SNeel Natu default: 258248e6799SNeel Natu return ("unknown"); 259248e6799SNeel Natu } 260248e6799SNeel Natu } 261248e6799SNeel Natu #endif 262248e6799SNeel Natu 263366f6083SPeter Grehan static void 2645fcf252fSNeel Natu vcpu_cleanup(struct vm *vm, int i, bool destroy) 265366f6083SPeter Grehan { 266de5ea6b6SNeel Natu struct vcpu *vcpu = &vm->vcpu[i]; 267de5ea6b6SNeel Natu 268de5ea6b6SNeel Natu VLAPIC_CLEANUP(vm->cookie, vcpu->vlapic); 2695fcf252fSNeel Natu if (destroy) { 270366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 27138f1b189SPeter Grehan fpu_save_area_free(vcpu->guestfpu); 272366f6083SPeter Grehan } 2735fcf252fSNeel Natu } 274366f6083SPeter Grehan 275366f6083SPeter Grehan static void 2765fcf252fSNeel Natu vcpu_init(struct vm *vm, int vcpu_id, bool create) 277366f6083SPeter Grehan { 278366f6083SPeter Grehan struct vcpu *vcpu; 279366f6083SPeter Grehan 280a488c9c9SRodney W. Grimes KASSERT(vcpu_id >= 0 && vcpu_id < vm->maxcpus, 2815fcf252fSNeel Natu ("vcpu_init: invalid vcpu %d", vcpu_id)); 2825fcf252fSNeel Natu 283366f6083SPeter Grehan vcpu = &vm->vcpu[vcpu_id]; 284366f6083SPeter Grehan 2855fcf252fSNeel Natu if (create) { 2865fcf252fSNeel Natu KASSERT(!vcpu_lock_initialized(vcpu), ("vcpu %d already " 2875fcf252fSNeel Natu "initialized", vcpu_id)); 28875dd3366SNeel Natu vcpu_lock_init(vcpu); 2895fcf252fSNeel Natu vcpu->state = VCPU_IDLE; 29075dd3366SNeel Natu vcpu->hostcpu = NOCPU; 2915fcf252fSNeel Natu vcpu->guestfpu = fpu_save_area_alloc(); 2925fcf252fSNeel Natu vcpu->stats = vmm_stat_alloc(); 2935fcf252fSNeel Natu } 2945fcf252fSNeel Natu 295de5ea6b6SNeel Natu vcpu->vlapic = VLAPIC_INIT(vm->cookie, vcpu_id); 29652e5c8a2SNeel Natu vm_set_x2apic_state(vm, vcpu_id, X2APIC_DISABLED); 297248e6799SNeel Natu vcpu->reqidle = 0; 298091d4532SNeel Natu vcpu->exitintinfo = 0; 2995fcf252fSNeel Natu vcpu->nmi_pending = 0; 3005fcf252fSNeel Natu vcpu->extint_pending = 0; 3015fcf252fSNeel Natu vcpu->exception_pending = 0; 302abb023fbSJohn Baldwin vcpu->guest_xcr0 = XFEATURE_ENABLED_X87; 30338f1b189SPeter Grehan fpu_save_area_reset(vcpu->guestfpu); 3045fcf252fSNeel Natu vmm_stat_init(vcpu->stats); 305366f6083SPeter Grehan } 306366f6083SPeter Grehan 307b0538143SNeel Natu int 308b0538143SNeel Natu vcpu_trace_exceptions(struct vm *vm, int vcpuid) 309b0538143SNeel Natu { 310b0538143SNeel Natu 311b0538143SNeel Natu return (trace_guest_exceptions); 312b0538143SNeel Natu } 313b0538143SNeel Natu 31498ed632cSNeel Natu struct vm_exit * 31598ed632cSNeel Natu vm_exitinfo(struct vm *vm, int cpuid) 31698ed632cSNeel Natu { 31798ed632cSNeel Natu struct vcpu *vcpu; 31898ed632cSNeel Natu 319a488c9c9SRodney W. Grimes if (cpuid < 0 || cpuid >= vm->maxcpus) 32098ed632cSNeel Natu panic("vm_exitinfo: invalid cpuid %d", cpuid); 32198ed632cSNeel Natu 32298ed632cSNeel Natu vcpu = &vm->vcpu[cpuid]; 32398ed632cSNeel Natu 32498ed632cSNeel Natu return (&vcpu->exitinfo); 32598ed632cSNeel Natu } 32698ed632cSNeel Natu 32763e62d39SJohn Baldwin static void 32863e62d39SJohn Baldwin vmm_resume(void) 32963e62d39SJohn Baldwin { 33063e62d39SJohn Baldwin VMM_RESUME(); 33163e62d39SJohn Baldwin } 33263e62d39SJohn Baldwin 333366f6083SPeter Grehan static int 334366f6083SPeter Grehan vmm_init(void) 335366f6083SPeter Grehan { 336366f6083SPeter Grehan int error; 337366f6083SPeter Grehan 338b01c2033SNeel Natu vmm_host_state_init(); 339add611fdSNeel Natu 340bd50262fSKonstantin Belousov vmm_ipinum = lapic_ipi_alloc(pti ? &IDTVEC(justreturn1_pti) : 341bd50262fSKonstantin Belousov &IDTVEC(justreturn)); 34218a2b08eSNeel Natu if (vmm_ipinum < 0) 343add611fdSNeel Natu vmm_ipinum = IPI_AST; 344366f6083SPeter Grehan 345366f6083SPeter Grehan error = vmm_mem_init(); 346366f6083SPeter Grehan if (error) 347366f6083SPeter Grehan return (error); 348366f6083SPeter Grehan 349366f6083SPeter Grehan if (vmm_is_intel()) 350366f6083SPeter Grehan ops = &vmm_ops_intel; 351caab5042SKonstantin Belousov else if (vmm_is_svm()) 352366f6083SPeter Grehan ops = &vmm_ops_amd; 353366f6083SPeter Grehan else 354366f6083SPeter Grehan return (ENXIO); 355366f6083SPeter Grehan 35663e62d39SJohn Baldwin vmm_resume_p = vmm_resume; 357366f6083SPeter Grehan 358add611fdSNeel Natu return (VMM_INIT(vmm_ipinum)); 359366f6083SPeter Grehan } 360366f6083SPeter Grehan 361366f6083SPeter Grehan static int 362366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 363366f6083SPeter Grehan { 364366f6083SPeter Grehan int error; 365366f6083SPeter Grehan 366366f6083SPeter Grehan switch (what) { 367366f6083SPeter Grehan case MOD_LOAD: 368366f6083SPeter Grehan vmmdev_init(); 369366f6083SPeter Grehan error = vmm_init(); 370d5408b1dSNeel Natu if (error == 0) 371d5408b1dSNeel Natu vmm_initialized = 1; 372366f6083SPeter Grehan break; 373366f6083SPeter Grehan case MOD_UNLOAD: 374cdc5b9e7SNeel Natu error = vmmdev_cleanup(); 375cdc5b9e7SNeel Natu if (error == 0) { 37663e62d39SJohn Baldwin vmm_resume_p = NULL; 377366f6083SPeter Grehan iommu_cleanup(); 378add611fdSNeel Natu if (vmm_ipinum != IPI_AST) 37918a2b08eSNeel Natu lapic_ipi_free(vmm_ipinum); 380366f6083SPeter Grehan error = VMM_CLEANUP(); 38181ef6611SPeter Grehan /* 38281ef6611SPeter Grehan * Something bad happened - prevent new 38381ef6611SPeter Grehan * VMs from being created 38481ef6611SPeter Grehan */ 38581ef6611SPeter Grehan if (error) 386d5408b1dSNeel Natu vmm_initialized = 0; 38781ef6611SPeter Grehan } 388366f6083SPeter Grehan break; 389366f6083SPeter Grehan default: 390366f6083SPeter Grehan error = 0; 391366f6083SPeter Grehan break; 392366f6083SPeter Grehan } 393366f6083SPeter Grehan return (error); 394366f6083SPeter Grehan } 395366f6083SPeter Grehan 396366f6083SPeter Grehan static moduledata_t vmm_kmod = { 397366f6083SPeter Grehan "vmm", 398366f6083SPeter Grehan vmm_handler, 399366f6083SPeter Grehan NULL 400366f6083SPeter Grehan }; 401366f6083SPeter Grehan 402366f6083SPeter Grehan /* 403e3f0800bSNeel Natu * vmm initialization has the following dependencies: 404e3f0800bSNeel Natu * 405e3f0800bSNeel Natu * - VT-x initialization requires smp_rendezvous() and therefore must happen 406e3f0800bSNeel Natu * after SMP is fully functional (after SI_SUB_SMP). 407366f6083SPeter Grehan */ 408e3f0800bSNeel Natu DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_SMP + 1, SI_ORDER_ANY); 409366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 410366f6083SPeter Grehan 4115fcf252fSNeel Natu static void 4125fcf252fSNeel Natu vm_init(struct vm *vm, bool create) 4135fcf252fSNeel Natu { 4145fcf252fSNeel Natu int i; 4155fcf252fSNeel Natu 4165fcf252fSNeel Natu vm->cookie = VMINIT(vm, vmspace_pmap(vm->vmspace)); 4175fcf252fSNeel Natu vm->iommu = NULL; 4185fcf252fSNeel Natu vm->vioapic = vioapic_init(vm); 4195fcf252fSNeel Natu vm->vhpet = vhpet_init(vm); 4205fcf252fSNeel Natu vm->vatpic = vatpic_init(vm); 4215fcf252fSNeel Natu vm->vatpit = vatpit_init(vm); 422160ef77aSNeel Natu vm->vpmtmr = vpmtmr_init(vm); 4230dafa5cdSNeel Natu if (create) 4240dafa5cdSNeel Natu vm->vrtc = vrtc_init(vm); 4255fcf252fSNeel Natu 4265fcf252fSNeel Natu CPU_ZERO(&vm->active_cpus); 427fc276d92SJohn Baldwin CPU_ZERO(&vm->debug_cpus); 4285fcf252fSNeel Natu 4295fcf252fSNeel Natu vm->suspend = 0; 4305fcf252fSNeel Natu CPU_ZERO(&vm->suspended_cpus); 4315fcf252fSNeel Natu 432a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) 4335fcf252fSNeel Natu vcpu_init(vm, i, create); 4345fcf252fSNeel Natu } 4355fcf252fSNeel Natu 43601d822d3SRodney W. Grimes /* 43701d822d3SRodney W. Grimes * The default CPU topology is a single thread per package. 43801d822d3SRodney W. Grimes */ 43901d822d3SRodney W. Grimes u_int cores_per_package = 1; 44001d822d3SRodney W. Grimes u_int threads_per_core = 1; 44101d822d3SRodney W. Grimes 442d5408b1dSNeel Natu int 443d5408b1dSNeel Natu vm_create(const char *name, struct vm **retvm) 444366f6083SPeter Grehan { 445366f6083SPeter Grehan struct vm *vm; 446318224bbSNeel Natu struct vmspace *vmspace; 447366f6083SPeter Grehan 448d5408b1dSNeel Natu /* 449d5408b1dSNeel Natu * If vmm.ko could not be successfully initialized then don't attempt 450d5408b1dSNeel Natu * to create the virtual machine. 451d5408b1dSNeel Natu */ 452d5408b1dSNeel Natu if (!vmm_initialized) 453d5408b1dSNeel Natu return (ENXIO); 454d5408b1dSNeel Natu 455366f6083SPeter Grehan if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 456d5408b1dSNeel Natu return (EINVAL); 457366f6083SPeter Grehan 458526c8885SPeter Grehan vmspace = VMSPACE_ALLOC(0, VM_MAXUSER_ADDRESS); 459318224bbSNeel Natu if (vmspace == NULL) 460318224bbSNeel Natu return (ENOMEM); 461318224bbSNeel Natu 462366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 463366f6083SPeter Grehan strcpy(vm->name, name); 46488c4b8d1SNeel Natu vm->vmspace = vmspace; 4655b8a8cd1SNeel Natu mtx_init(&vm->rendezvous_mtx, "vm rendezvous lock", 0, MTX_DEF); 466366f6083SPeter Grehan 46701d822d3SRodney W. Grimes vm->sockets = 1; 46801d822d3SRodney W. Grimes vm->cores = cores_per_package; /* XXX backwards compatibility */ 46901d822d3SRodney W. Grimes vm->threads = threads_per_core; /* XXX backwards compatibility */ 470a488c9c9SRodney W. Grimes vm->maxcpus = VM_MAXCPU; /* XXX temp to keep code working */ 47101d822d3SRodney W. Grimes 4725fcf252fSNeel Natu vm_init(vm, true); 473366f6083SPeter Grehan 474d5408b1dSNeel Natu *retvm = vm; 475d5408b1dSNeel Natu return (0); 476366f6083SPeter Grehan } 477366f6083SPeter Grehan 47801d822d3SRodney W. Grimes void 47901d822d3SRodney W. Grimes vm_get_topology(struct vm *vm, uint16_t *sockets, uint16_t *cores, 48001d822d3SRodney W. Grimes uint16_t *threads, uint16_t *maxcpus) 48101d822d3SRodney W. Grimes { 48201d822d3SRodney W. Grimes *sockets = vm->sockets; 48301d822d3SRodney W. Grimes *cores = vm->cores; 48401d822d3SRodney W. Grimes *threads = vm->threads; 48501d822d3SRodney W. Grimes *maxcpus = vm->maxcpus; 48601d822d3SRodney W. Grimes } 48701d822d3SRodney W. Grimes 488a488c9c9SRodney W. Grimes uint16_t 489a488c9c9SRodney W. Grimes vm_get_maxcpus(struct vm *vm) 490a488c9c9SRodney W. Grimes { 491a488c9c9SRodney W. Grimes return (vm->maxcpus); 492a488c9c9SRodney W. Grimes } 493a488c9c9SRodney W. Grimes 49401d822d3SRodney W. Grimes int 49501d822d3SRodney W. Grimes vm_set_topology(struct vm *vm, uint16_t sockets, uint16_t cores, 49601d822d3SRodney W. Grimes uint16_t threads, uint16_t maxcpus) 49701d822d3SRodney W. Grimes { 49801d822d3SRodney W. Grimes if (maxcpus != 0) 49901d822d3SRodney W. Grimes return (EINVAL); /* XXX remove when supported */ 500a488c9c9SRodney W. Grimes if ((sockets * cores * threads) > vm->maxcpus) 50101d822d3SRodney W. Grimes return (EINVAL); 50201d822d3SRodney W. Grimes /* XXX need to check sockets * cores * threads == vCPU, how? */ 50301d822d3SRodney W. Grimes vm->sockets = sockets; 50401d822d3SRodney W. Grimes vm->cores = cores; 50501d822d3SRodney W. Grimes vm->threads = threads; 506a488c9c9SRodney W. Grimes vm->maxcpus = VM_MAXCPU; /* XXX temp to keep code working */ 50701d822d3SRodney W. Grimes return(0); 50801d822d3SRodney W. Grimes } 50901d822d3SRodney W. Grimes 510f7d51510SNeel Natu static void 5115fcf252fSNeel Natu vm_cleanup(struct vm *vm, bool destroy) 512366f6083SPeter Grehan { 5139b1aa8d6SNeel Natu struct mem_map *mm; 514366f6083SPeter Grehan int i; 515366f6083SPeter Grehan 516366f6083SPeter Grehan ppt_unassign_all(vm); 517366f6083SPeter Grehan 518318224bbSNeel Natu if (vm->iommu != NULL) 519318224bbSNeel Natu iommu_destroy_domain(vm->iommu); 520318224bbSNeel Natu 5210dafa5cdSNeel Natu if (destroy) 5220dafa5cdSNeel Natu vrtc_cleanup(vm->vrtc); 5230dafa5cdSNeel Natu else 5240dafa5cdSNeel Natu vrtc_reset(vm->vrtc); 525160ef77aSNeel Natu vpmtmr_cleanup(vm->vpmtmr); 526e883c9bbSTycho Nightingale vatpit_cleanup(vm->vatpit); 52708e3ff32SNeel Natu vhpet_cleanup(vm->vhpet); 528762fd208STycho Nightingale vatpic_cleanup(vm->vatpic); 52908e3ff32SNeel Natu vioapic_cleanup(vm->vioapic); 53008e3ff32SNeel Natu 531a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) 5325fcf252fSNeel Natu vcpu_cleanup(vm, i, destroy); 5335fcf252fSNeel Natu 5345fcf252fSNeel Natu VMCLEANUP(vm->cookie); 5355fcf252fSNeel Natu 5369b1aa8d6SNeel Natu /* 5379b1aa8d6SNeel Natu * System memory is removed from the guest address space only when 5389b1aa8d6SNeel Natu * the VM is destroyed. This is because the mapping remains the same 5399b1aa8d6SNeel Natu * across VM reset. 5409b1aa8d6SNeel Natu * 5419b1aa8d6SNeel Natu * Device memory can be relocated by the guest (e.g. using PCI BARs) 5429b1aa8d6SNeel Natu * so those mappings are removed on a VM reset. 5439b1aa8d6SNeel Natu */ 5449b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 5459b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 5469b1aa8d6SNeel Natu if (destroy || !sysmem_mapping(vm, mm)) 5479b1aa8d6SNeel Natu vm_free_memmap(vm, i); 5489b1aa8d6SNeel Natu } 549f7d51510SNeel Natu 5509b1aa8d6SNeel Natu if (destroy) { 5519b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMSEGS; i++) 5529b1aa8d6SNeel Natu vm_free_memseg(vm, i); 553366f6083SPeter Grehan 554318224bbSNeel Natu VMSPACE_FREE(vm->vmspace); 5555fcf252fSNeel Natu vm->vmspace = NULL; 5565fcf252fSNeel Natu } 5575fcf252fSNeel Natu } 558366f6083SPeter Grehan 5595fcf252fSNeel Natu void 5605fcf252fSNeel Natu vm_destroy(struct vm *vm) 5615fcf252fSNeel Natu { 5625fcf252fSNeel Natu vm_cleanup(vm, true); 563366f6083SPeter Grehan free(vm, M_VM); 564366f6083SPeter Grehan } 565366f6083SPeter Grehan 5665fcf252fSNeel Natu int 5675fcf252fSNeel Natu vm_reinit(struct vm *vm) 5685fcf252fSNeel Natu { 5695fcf252fSNeel Natu int error; 5705fcf252fSNeel Natu 5715fcf252fSNeel Natu /* 5725fcf252fSNeel Natu * A virtual machine can be reset only if all vcpus are suspended. 5735fcf252fSNeel Natu */ 5745fcf252fSNeel Natu if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 5755fcf252fSNeel Natu vm_cleanup(vm, false); 5765fcf252fSNeel Natu vm_init(vm, false); 5775fcf252fSNeel Natu error = 0; 5785fcf252fSNeel Natu } else { 5795fcf252fSNeel Natu error = EBUSY; 5805fcf252fSNeel Natu } 5815fcf252fSNeel Natu 5825fcf252fSNeel Natu return (error); 5835fcf252fSNeel Natu } 5845fcf252fSNeel Natu 585366f6083SPeter Grehan const char * 586366f6083SPeter Grehan vm_name(struct vm *vm) 587366f6083SPeter Grehan { 588366f6083SPeter Grehan return (vm->name); 589366f6083SPeter Grehan } 590366f6083SPeter Grehan 591366f6083SPeter Grehan int 592366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 593366f6083SPeter Grehan { 594318224bbSNeel Natu vm_object_t obj; 595366f6083SPeter Grehan 596318224bbSNeel Natu if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa)) == NULL) 597318224bbSNeel Natu return (ENOMEM); 598318224bbSNeel Natu else 599318224bbSNeel Natu return (0); 600366f6083SPeter Grehan } 601366f6083SPeter Grehan 602366f6083SPeter Grehan int 603366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 604366f6083SPeter Grehan { 605366f6083SPeter Grehan 606318224bbSNeel Natu vmm_mmio_free(vm->vmspace, gpa, len); 607318224bbSNeel Natu return (0); 608366f6083SPeter Grehan } 609366f6083SPeter Grehan 6109b1aa8d6SNeel Natu /* 6119b1aa8d6SNeel Natu * Return 'true' if 'gpa' is allocated in the guest address space. 6129b1aa8d6SNeel Natu * 6139b1aa8d6SNeel Natu * This function is called in the context of a running vcpu which acts as 6149b1aa8d6SNeel Natu * an implicit lock on 'vm->mem_maps[]'. 6159b1aa8d6SNeel Natu */ 6169b1aa8d6SNeel Natu bool 6179b1aa8d6SNeel Natu vm_mem_allocated(struct vm *vm, int vcpuid, vm_paddr_t gpa) 618366f6083SPeter Grehan { 6199b1aa8d6SNeel Natu struct mem_map *mm; 620341f19c9SNeel Natu int i; 621341f19c9SNeel Natu 6229b1aa8d6SNeel Natu #ifdef INVARIANTS 6239b1aa8d6SNeel Natu int hostcpu, state; 6249b1aa8d6SNeel Natu state = vcpu_get_state(vm, vcpuid, &hostcpu); 6259b1aa8d6SNeel Natu KASSERT(state == VCPU_RUNNING && hostcpu == curcpu, 6269b1aa8d6SNeel Natu ("%s: invalid vcpu state %d/%d", __func__, state, hostcpu)); 6279b1aa8d6SNeel Natu #endif 6289b1aa8d6SNeel Natu 6299b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 6309b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 6319b1aa8d6SNeel Natu if (mm->len != 0 && gpa >= mm->gpa && gpa < mm->gpa + mm->len) 6329b1aa8d6SNeel Natu return (true); /* 'gpa' is sysmem or devmem */ 633341f19c9SNeel Natu } 634341f19c9SNeel Natu 635318224bbSNeel Natu if (ppt_is_mmio(vm, gpa)) 6369b1aa8d6SNeel Natu return (true); /* 'gpa' is pci passthru mmio */ 637318224bbSNeel Natu 6389b1aa8d6SNeel Natu return (false); 639341f19c9SNeel Natu } 640341f19c9SNeel Natu 641341f19c9SNeel Natu int 6429b1aa8d6SNeel Natu vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem) 643341f19c9SNeel Natu { 644318224bbSNeel Natu struct mem_seg *seg; 6459b1aa8d6SNeel Natu vm_object_t obj; 646366f6083SPeter Grehan 6479b1aa8d6SNeel Natu if (ident < 0 || ident >= VM_MAX_MEMSEGS) 648341f19c9SNeel Natu return (EINVAL); 649341f19c9SNeel Natu 6509b1aa8d6SNeel Natu if (len == 0 || (len & PAGE_MASK)) 6519b1aa8d6SNeel Natu return (EINVAL); 652341f19c9SNeel Natu 6539b1aa8d6SNeel Natu seg = &vm->mem_segs[ident]; 6549b1aa8d6SNeel Natu if (seg->object != NULL) { 6559b1aa8d6SNeel Natu if (seg->len == len && seg->sysmem == sysmem) 6569b1aa8d6SNeel Natu return (EEXIST); 6579b1aa8d6SNeel Natu else 6589b1aa8d6SNeel Natu return (EINVAL); 659341f19c9SNeel Natu } 660341f19c9SNeel Natu 6619b1aa8d6SNeel Natu obj = vm_object_allocate(OBJT_DEFAULT, len >> PAGE_SHIFT); 6629b1aa8d6SNeel Natu if (obj == NULL) 663318224bbSNeel Natu return (ENOMEM); 664318224bbSNeel Natu 665318224bbSNeel Natu seg->len = len; 6669b1aa8d6SNeel Natu seg->object = obj; 6679b1aa8d6SNeel Natu seg->sysmem = sysmem; 668366f6083SPeter Grehan return (0); 669366f6083SPeter Grehan } 670366f6083SPeter Grehan 6719b1aa8d6SNeel Natu int 6729b1aa8d6SNeel Natu vm_get_memseg(struct vm *vm, int ident, size_t *len, bool *sysmem, 6739b1aa8d6SNeel Natu vm_object_t *objptr) 674477867a0SNeel Natu { 6759b1aa8d6SNeel Natu struct mem_seg *seg; 676477867a0SNeel Natu 6779b1aa8d6SNeel Natu if (ident < 0 || ident >= VM_MAX_MEMSEGS) 6789b1aa8d6SNeel Natu return (EINVAL); 6799b1aa8d6SNeel Natu 6809b1aa8d6SNeel Natu seg = &vm->mem_segs[ident]; 6819b1aa8d6SNeel Natu if (len) 6829b1aa8d6SNeel Natu *len = seg->len; 6839b1aa8d6SNeel Natu if (sysmem) 6849b1aa8d6SNeel Natu *sysmem = seg->sysmem; 6859b1aa8d6SNeel Natu if (objptr) 6869b1aa8d6SNeel Natu *objptr = seg->object; 6879b1aa8d6SNeel Natu return (0); 688477867a0SNeel Natu } 6899b1aa8d6SNeel Natu 6909b1aa8d6SNeel Natu void 6919b1aa8d6SNeel Natu vm_free_memseg(struct vm *vm, int ident) 6929b1aa8d6SNeel Natu { 6939b1aa8d6SNeel Natu struct mem_seg *seg; 6949b1aa8d6SNeel Natu 6959b1aa8d6SNeel Natu KASSERT(ident >= 0 && ident < VM_MAX_MEMSEGS, 6969b1aa8d6SNeel Natu ("%s: invalid memseg ident %d", __func__, ident)); 6979b1aa8d6SNeel Natu 6989b1aa8d6SNeel Natu seg = &vm->mem_segs[ident]; 6999b1aa8d6SNeel Natu if (seg->object != NULL) { 7009b1aa8d6SNeel Natu vm_object_deallocate(seg->object); 7019b1aa8d6SNeel Natu bzero(seg, sizeof(struct mem_seg)); 7029b1aa8d6SNeel Natu } 7039b1aa8d6SNeel Natu } 7049b1aa8d6SNeel Natu 7059b1aa8d6SNeel Natu int 7069b1aa8d6SNeel Natu vm_mmap_memseg(struct vm *vm, vm_paddr_t gpa, int segid, vm_ooffset_t first, 7079b1aa8d6SNeel Natu size_t len, int prot, int flags) 7089b1aa8d6SNeel Natu { 7099b1aa8d6SNeel Natu struct mem_seg *seg; 7109b1aa8d6SNeel Natu struct mem_map *m, *map; 7119b1aa8d6SNeel Natu vm_ooffset_t last; 7129b1aa8d6SNeel Natu int i, error; 7139b1aa8d6SNeel Natu 7149b1aa8d6SNeel Natu if (prot == 0 || (prot & ~(VM_PROT_ALL)) != 0) 7159b1aa8d6SNeel Natu return (EINVAL); 7169b1aa8d6SNeel Natu 7179b1aa8d6SNeel Natu if (flags & ~VM_MEMMAP_F_WIRED) 7189b1aa8d6SNeel Natu return (EINVAL); 7199b1aa8d6SNeel Natu 7209b1aa8d6SNeel Natu if (segid < 0 || segid >= VM_MAX_MEMSEGS) 7219b1aa8d6SNeel Natu return (EINVAL); 7229b1aa8d6SNeel Natu 7239b1aa8d6SNeel Natu seg = &vm->mem_segs[segid]; 7249b1aa8d6SNeel Natu if (seg->object == NULL) 7259b1aa8d6SNeel Natu return (EINVAL); 7269b1aa8d6SNeel Natu 7279b1aa8d6SNeel Natu last = first + len; 7289b1aa8d6SNeel Natu if (first < 0 || first >= last || last > seg->len) 7299b1aa8d6SNeel Natu return (EINVAL); 7309b1aa8d6SNeel Natu 7319b1aa8d6SNeel Natu if ((gpa | first | last) & PAGE_MASK) 7329b1aa8d6SNeel Natu return (EINVAL); 7339b1aa8d6SNeel Natu 7349b1aa8d6SNeel Natu map = NULL; 7359b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 7369b1aa8d6SNeel Natu m = &vm->mem_maps[i]; 7379b1aa8d6SNeel Natu if (m->len == 0) { 7389b1aa8d6SNeel Natu map = m; 7399b1aa8d6SNeel Natu break; 7409b1aa8d6SNeel Natu } 7419b1aa8d6SNeel Natu } 7429b1aa8d6SNeel Natu 7439b1aa8d6SNeel Natu if (map == NULL) 7449b1aa8d6SNeel Natu return (ENOSPC); 7459b1aa8d6SNeel Natu 7469b1aa8d6SNeel Natu error = vm_map_find(&vm->vmspace->vm_map, seg->object, first, &gpa, 7479b1aa8d6SNeel Natu len, 0, VMFS_NO_SPACE, prot, prot, 0); 7489b1aa8d6SNeel Natu if (error != KERN_SUCCESS) 7499b1aa8d6SNeel Natu return (EFAULT); 7509b1aa8d6SNeel Natu 7519b1aa8d6SNeel Natu vm_object_reference(seg->object); 7529b1aa8d6SNeel Natu 7539b1aa8d6SNeel Natu if (flags & VM_MEMMAP_F_WIRED) { 7549b1aa8d6SNeel Natu error = vm_map_wire(&vm->vmspace->vm_map, gpa, gpa + len, 7559b1aa8d6SNeel Natu VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 7569b1aa8d6SNeel Natu if (error != KERN_SUCCESS) { 7579b1aa8d6SNeel Natu vm_map_remove(&vm->vmspace->vm_map, gpa, gpa + len); 75854a3a114SMark Johnston return (error == KERN_RESOURCE_SHORTAGE ? ENOMEM : 75954a3a114SMark Johnston EFAULT); 7609b1aa8d6SNeel Natu } 7619b1aa8d6SNeel Natu } 7629b1aa8d6SNeel Natu 7639b1aa8d6SNeel Natu map->gpa = gpa; 7649b1aa8d6SNeel Natu map->len = len; 7659b1aa8d6SNeel Natu map->segoff = first; 7669b1aa8d6SNeel Natu map->segid = segid; 7679b1aa8d6SNeel Natu map->prot = prot; 7689b1aa8d6SNeel Natu map->flags = flags; 7699b1aa8d6SNeel Natu return (0); 7709b1aa8d6SNeel Natu } 7719b1aa8d6SNeel Natu 7729b1aa8d6SNeel Natu int 7739b1aa8d6SNeel Natu vm_mmap_getnext(struct vm *vm, vm_paddr_t *gpa, int *segid, 7749b1aa8d6SNeel Natu vm_ooffset_t *segoff, size_t *len, int *prot, int *flags) 7759b1aa8d6SNeel Natu { 7769b1aa8d6SNeel Natu struct mem_map *mm, *mmnext; 7779b1aa8d6SNeel Natu int i; 7789b1aa8d6SNeel Natu 7799b1aa8d6SNeel Natu mmnext = NULL; 7809b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 7819b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 7829b1aa8d6SNeel Natu if (mm->len == 0 || mm->gpa < *gpa) 7839b1aa8d6SNeel Natu continue; 7849b1aa8d6SNeel Natu if (mmnext == NULL || mm->gpa < mmnext->gpa) 7859b1aa8d6SNeel Natu mmnext = mm; 7869b1aa8d6SNeel Natu } 7879b1aa8d6SNeel Natu 7889b1aa8d6SNeel Natu if (mmnext != NULL) { 7899b1aa8d6SNeel Natu *gpa = mmnext->gpa; 7909b1aa8d6SNeel Natu if (segid) 7919b1aa8d6SNeel Natu *segid = mmnext->segid; 7929b1aa8d6SNeel Natu if (segoff) 7939b1aa8d6SNeel Natu *segoff = mmnext->segoff; 7949b1aa8d6SNeel Natu if (len) 7959b1aa8d6SNeel Natu *len = mmnext->len; 7969b1aa8d6SNeel Natu if (prot) 7979b1aa8d6SNeel Natu *prot = mmnext->prot; 7989b1aa8d6SNeel Natu if (flags) 7999b1aa8d6SNeel Natu *flags = mmnext->flags; 8009b1aa8d6SNeel Natu return (0); 8019b1aa8d6SNeel Natu } else { 8029b1aa8d6SNeel Natu return (ENOENT); 8039b1aa8d6SNeel Natu } 804477867a0SNeel Natu } 805477867a0SNeel Natu 806318224bbSNeel Natu static void 8079b1aa8d6SNeel Natu vm_free_memmap(struct vm *vm, int ident) 808366f6083SPeter Grehan { 8099b1aa8d6SNeel Natu struct mem_map *mm; 8109b1aa8d6SNeel Natu int error; 8114db4fb2cSNeel Natu 8129b1aa8d6SNeel Natu mm = &vm->mem_maps[ident]; 8139b1aa8d6SNeel Natu if (mm->len) { 8149b1aa8d6SNeel Natu error = vm_map_remove(&vm->vmspace->vm_map, mm->gpa, 8159b1aa8d6SNeel Natu mm->gpa + mm->len); 8169b1aa8d6SNeel Natu KASSERT(error == KERN_SUCCESS, ("%s: vm_map_remove error %d", 8179b1aa8d6SNeel Natu __func__, error)); 8189b1aa8d6SNeel Natu bzero(mm, sizeof(struct mem_map)); 819318224bbSNeel Natu } 820318224bbSNeel Natu } 821318224bbSNeel Natu 8229b1aa8d6SNeel Natu static __inline bool 8239b1aa8d6SNeel Natu sysmem_mapping(struct vm *vm, struct mem_map *mm) 824318224bbSNeel Natu { 825318224bbSNeel Natu 8269b1aa8d6SNeel Natu if (mm->len != 0 && vm->mem_segs[mm->segid].sysmem) 8279b1aa8d6SNeel Natu return (true); 8289b1aa8d6SNeel Natu else 8299b1aa8d6SNeel Natu return (false); 830318224bbSNeel Natu } 831318224bbSNeel Natu 832147d12a7SAntoine Brodin vm_paddr_t 833147d12a7SAntoine Brodin vmm_sysmem_maxaddr(struct vm *vm) 8349b1aa8d6SNeel Natu { 8359b1aa8d6SNeel Natu struct mem_map *mm; 8369b1aa8d6SNeel Natu vm_paddr_t maxaddr; 8379b1aa8d6SNeel Natu int i; 838318224bbSNeel Natu 8399b1aa8d6SNeel Natu maxaddr = 0; 8409b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 8419b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 8429b1aa8d6SNeel Natu if (sysmem_mapping(vm, mm)) { 8439b1aa8d6SNeel Natu if (maxaddr < mm->gpa + mm->len) 8449b1aa8d6SNeel Natu maxaddr = mm->gpa + mm->len; 8459b1aa8d6SNeel Natu } 8469b1aa8d6SNeel Natu } 8479b1aa8d6SNeel Natu return (maxaddr); 848318224bbSNeel Natu } 849318224bbSNeel Natu 850318224bbSNeel Natu static void 851490d56c5SEd Maste vm_iommu_modify(struct vm *vm, bool map) 852318224bbSNeel Natu { 853318224bbSNeel Natu int i, sz; 854318224bbSNeel Natu vm_paddr_t gpa, hpa; 8559b1aa8d6SNeel Natu struct mem_map *mm; 856318224bbSNeel Natu void *vp, *cookie, *host_domain; 857318224bbSNeel Natu 858318224bbSNeel Natu sz = PAGE_SIZE; 859318224bbSNeel Natu host_domain = iommu_host_domain(); 860318224bbSNeel Natu 8619b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 8629b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 8639b1aa8d6SNeel Natu if (!sysmem_mapping(vm, mm)) 8649b1aa8d6SNeel Natu continue; 865318224bbSNeel Natu 8669b1aa8d6SNeel Natu if (map) { 8679b1aa8d6SNeel Natu KASSERT((mm->flags & VM_MEMMAP_F_IOMMU) == 0, 8689b1aa8d6SNeel Natu ("iommu map found invalid memmap %#lx/%#lx/%#x", 8699b1aa8d6SNeel Natu mm->gpa, mm->len, mm->flags)); 8709b1aa8d6SNeel Natu if ((mm->flags & VM_MEMMAP_F_WIRED) == 0) 8719b1aa8d6SNeel Natu continue; 8729b1aa8d6SNeel Natu mm->flags |= VM_MEMMAP_F_IOMMU; 8739b1aa8d6SNeel Natu } else { 8749b1aa8d6SNeel Natu if ((mm->flags & VM_MEMMAP_F_IOMMU) == 0) 8759b1aa8d6SNeel Natu continue; 8769b1aa8d6SNeel Natu mm->flags &= ~VM_MEMMAP_F_IOMMU; 8779b1aa8d6SNeel Natu KASSERT((mm->flags & VM_MEMMAP_F_WIRED) != 0, 8789b1aa8d6SNeel Natu ("iommu unmap found invalid memmap %#lx/%#lx/%#x", 8799b1aa8d6SNeel Natu mm->gpa, mm->len, mm->flags)); 8809b1aa8d6SNeel Natu } 8819b1aa8d6SNeel Natu 8829b1aa8d6SNeel Natu gpa = mm->gpa; 8839b1aa8d6SNeel Natu while (gpa < mm->gpa + mm->len) { 8849b1aa8d6SNeel Natu vp = vm_gpa_hold(vm, -1, gpa, PAGE_SIZE, VM_PROT_WRITE, 885318224bbSNeel Natu &cookie); 886318224bbSNeel Natu KASSERT(vp != NULL, ("vm(%s) could not map gpa %#lx", 887318224bbSNeel Natu vm_name(vm), gpa)); 888318224bbSNeel Natu 889318224bbSNeel Natu vm_gpa_release(cookie); 890318224bbSNeel Natu 891318224bbSNeel Natu hpa = DMAP_TO_PHYS((uintptr_t)vp); 892318224bbSNeel Natu if (map) { 893318224bbSNeel Natu iommu_create_mapping(vm->iommu, gpa, hpa, sz); 894318224bbSNeel Natu iommu_remove_mapping(host_domain, hpa, sz); 895318224bbSNeel Natu } else { 896318224bbSNeel Natu iommu_remove_mapping(vm->iommu, gpa, sz); 897318224bbSNeel Natu iommu_create_mapping(host_domain, hpa, hpa, sz); 898318224bbSNeel Natu } 899318224bbSNeel Natu 900318224bbSNeel Natu gpa += PAGE_SIZE; 901318224bbSNeel Natu } 902318224bbSNeel Natu } 903318224bbSNeel Natu 904318224bbSNeel Natu /* 905318224bbSNeel Natu * Invalidate the cached translations associated with the domain 906318224bbSNeel Natu * from which pages were removed. 907318224bbSNeel Natu */ 908318224bbSNeel Natu if (map) 909318224bbSNeel Natu iommu_invalidate_tlb(host_domain); 910318224bbSNeel Natu else 911318224bbSNeel Natu iommu_invalidate_tlb(vm->iommu); 912318224bbSNeel Natu } 913318224bbSNeel Natu 914490d56c5SEd Maste #define vm_iommu_unmap(vm) vm_iommu_modify((vm), false) 915490d56c5SEd Maste #define vm_iommu_map(vm) vm_iommu_modify((vm), true) 916318224bbSNeel Natu 917318224bbSNeel Natu int 918318224bbSNeel Natu vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func) 919318224bbSNeel Natu { 920318224bbSNeel Natu int error; 921318224bbSNeel Natu 922318224bbSNeel Natu error = ppt_unassign_device(vm, bus, slot, func); 923318224bbSNeel Natu if (error) 924318224bbSNeel Natu return (error); 925318224bbSNeel Natu 9269b1aa8d6SNeel Natu if (ppt_assigned_devices(vm) == 0) 927318224bbSNeel Natu vm_iommu_unmap(vm); 9289b1aa8d6SNeel Natu 929318224bbSNeel Natu return (0); 930318224bbSNeel Natu } 931318224bbSNeel Natu 932318224bbSNeel Natu int 933318224bbSNeel Natu vm_assign_pptdev(struct vm *vm, int bus, int slot, int func) 934318224bbSNeel Natu { 935318224bbSNeel Natu int error; 936318224bbSNeel Natu vm_paddr_t maxaddr; 937318224bbSNeel Natu 9389b1aa8d6SNeel Natu /* Set up the IOMMU to do the 'gpa' to 'hpa' translation */ 93951f45d01SNeel Natu if (ppt_assigned_devices(vm) == 0) { 940318224bbSNeel Natu KASSERT(vm->iommu == NULL, 941318224bbSNeel Natu ("vm_assign_pptdev: iommu must be NULL")); 942147d12a7SAntoine Brodin maxaddr = vmm_sysmem_maxaddr(vm); 943318224bbSNeel Natu vm->iommu = iommu_create_domain(maxaddr); 944ffe1b10dSJohn Baldwin if (vm->iommu == NULL) 945ffe1b10dSJohn Baldwin return (ENXIO); 946318224bbSNeel Natu vm_iommu_map(vm); 947318224bbSNeel Natu } 948318224bbSNeel Natu 949318224bbSNeel Natu error = ppt_assign_device(vm, bus, slot, func); 950318224bbSNeel Natu return (error); 951318224bbSNeel Natu } 952318224bbSNeel Natu 953318224bbSNeel Natu void * 9549b1aa8d6SNeel Natu vm_gpa_hold(struct vm *vm, int vcpuid, vm_paddr_t gpa, size_t len, int reqprot, 955318224bbSNeel Natu void **cookie) 956318224bbSNeel Natu { 9579b1aa8d6SNeel Natu int i, count, pageoff; 9589b1aa8d6SNeel Natu struct mem_map *mm; 959318224bbSNeel Natu vm_page_t m; 9609b1aa8d6SNeel Natu #ifdef INVARIANTS 9619b1aa8d6SNeel Natu /* 9629b1aa8d6SNeel Natu * All vcpus are frozen by ioctls that modify the memory map 9639b1aa8d6SNeel Natu * (e.g. VM_MMAP_MEMSEG). Therefore 'vm->memmap[]' stability is 9649b1aa8d6SNeel Natu * guaranteed if at least one vcpu is in the VCPU_FROZEN state. 9659b1aa8d6SNeel Natu */ 9669b1aa8d6SNeel Natu int state; 967a488c9c9SRodney W. Grimes KASSERT(vcpuid >= -1 && vcpuid < vm->maxcpus, ("%s: invalid vcpuid %d", 9689b1aa8d6SNeel Natu __func__, vcpuid)); 969a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 9709b1aa8d6SNeel Natu if (vcpuid != -1 && vcpuid != i) 9719b1aa8d6SNeel Natu continue; 9729b1aa8d6SNeel Natu state = vcpu_get_state(vm, i, NULL); 9739b1aa8d6SNeel Natu KASSERT(state == VCPU_FROZEN, ("%s: invalid vcpu state %d", 9749b1aa8d6SNeel Natu __func__, state)); 9759b1aa8d6SNeel Natu } 9769b1aa8d6SNeel Natu #endif 977318224bbSNeel Natu pageoff = gpa & PAGE_MASK; 978318224bbSNeel Natu if (len > PAGE_SIZE - pageoff) 979318224bbSNeel Natu panic("vm_gpa_hold: invalid gpa/len: 0x%016lx/%lu", gpa, len); 980318224bbSNeel Natu 9819b1aa8d6SNeel Natu count = 0; 9829b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 9839b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 9849b1aa8d6SNeel Natu if (sysmem_mapping(vm, mm) && gpa >= mm->gpa && 9859b1aa8d6SNeel Natu gpa < mm->gpa + mm->len) { 986318224bbSNeel Natu count = vm_fault_quick_hold_pages(&vm->vmspace->vm_map, 987318224bbSNeel Natu trunc_page(gpa), PAGE_SIZE, reqprot, &m, 1); 9889b1aa8d6SNeel Natu break; 9899b1aa8d6SNeel Natu } 9909b1aa8d6SNeel Natu } 991318224bbSNeel Natu 992318224bbSNeel Natu if (count == 1) { 993318224bbSNeel Natu *cookie = m; 994318224bbSNeel Natu return ((void *)(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)) + pageoff)); 995318224bbSNeel Natu } else { 996318224bbSNeel Natu *cookie = NULL; 997318224bbSNeel Natu return (NULL); 998318224bbSNeel Natu } 999318224bbSNeel Natu } 1000318224bbSNeel Natu 1001318224bbSNeel Natu void 1002318224bbSNeel Natu vm_gpa_release(void *cookie) 1003318224bbSNeel Natu { 1004318224bbSNeel Natu vm_page_t m = cookie; 1005318224bbSNeel Natu 1006eeacb3b0SMark Johnston vm_page_unwire(m, PQ_ACTIVE); 1007366f6083SPeter Grehan } 1008366f6083SPeter Grehan 1009366f6083SPeter Grehan int 1010366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 1011366f6083SPeter Grehan { 1012366f6083SPeter Grehan 1013a488c9c9SRodney W. Grimes if (vcpu < 0 || vcpu >= vm->maxcpus) 1014366f6083SPeter Grehan return (EINVAL); 1015366f6083SPeter Grehan 1016366f6083SPeter Grehan if (reg >= VM_REG_LAST) 1017366f6083SPeter Grehan return (EINVAL); 1018366f6083SPeter Grehan 1019366f6083SPeter Grehan return (VMGETREG(vm->cookie, vcpu, reg, retval)); 1020366f6083SPeter Grehan } 1021366f6083SPeter Grehan 1022366f6083SPeter Grehan int 1023d087a399SNeel Natu vm_set_register(struct vm *vm, int vcpuid, int reg, uint64_t val) 1024366f6083SPeter Grehan { 1025d087a399SNeel Natu struct vcpu *vcpu; 1026d087a399SNeel Natu int error; 1027366f6083SPeter Grehan 1028a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 1029366f6083SPeter Grehan return (EINVAL); 1030366f6083SPeter Grehan 1031366f6083SPeter Grehan if (reg >= VM_REG_LAST) 1032366f6083SPeter Grehan return (EINVAL); 1033366f6083SPeter Grehan 1034d087a399SNeel Natu error = VMSETREG(vm->cookie, vcpuid, reg, val); 1035d087a399SNeel Natu if (error || reg != VM_REG_GUEST_RIP) 1036d087a399SNeel Natu return (error); 1037d087a399SNeel Natu 1038d087a399SNeel Natu /* Set 'nextrip' to match the value of %rip */ 1039d087a399SNeel Natu VCPU_CTR1(vm, vcpuid, "Setting nextrip to %#lx", val); 1040d087a399SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1041d087a399SNeel Natu vcpu->nextrip = val; 1042d087a399SNeel Natu return (0); 1043366f6083SPeter Grehan } 1044366f6083SPeter Grehan 1045490d56c5SEd Maste static bool 1046366f6083SPeter Grehan is_descriptor_table(int reg) 1047366f6083SPeter Grehan { 1048366f6083SPeter Grehan 1049366f6083SPeter Grehan switch (reg) { 1050366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 1051366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 1052490d56c5SEd Maste return (true); 1053366f6083SPeter Grehan default: 1054490d56c5SEd Maste return (false); 1055366f6083SPeter Grehan } 1056366f6083SPeter Grehan } 1057366f6083SPeter Grehan 1058490d56c5SEd Maste static bool 1059366f6083SPeter Grehan is_segment_register(int reg) 1060366f6083SPeter Grehan { 1061366f6083SPeter Grehan 1062366f6083SPeter Grehan switch (reg) { 1063366f6083SPeter Grehan case VM_REG_GUEST_ES: 1064366f6083SPeter Grehan case VM_REG_GUEST_CS: 1065366f6083SPeter Grehan case VM_REG_GUEST_SS: 1066366f6083SPeter Grehan case VM_REG_GUEST_DS: 1067366f6083SPeter Grehan case VM_REG_GUEST_FS: 1068366f6083SPeter Grehan case VM_REG_GUEST_GS: 1069366f6083SPeter Grehan case VM_REG_GUEST_TR: 1070366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 1071490d56c5SEd Maste return (true); 1072366f6083SPeter Grehan default: 1073490d56c5SEd Maste return (false); 1074366f6083SPeter Grehan } 1075366f6083SPeter Grehan } 1076366f6083SPeter Grehan 1077366f6083SPeter Grehan int 1078366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 1079366f6083SPeter Grehan struct seg_desc *desc) 1080366f6083SPeter Grehan { 1081366f6083SPeter Grehan 1082a488c9c9SRodney W. Grimes if (vcpu < 0 || vcpu >= vm->maxcpus) 1083366f6083SPeter Grehan return (EINVAL); 1084366f6083SPeter Grehan 1085366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 1086366f6083SPeter Grehan return (EINVAL); 1087366f6083SPeter Grehan 1088366f6083SPeter Grehan return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 1089366f6083SPeter Grehan } 1090366f6083SPeter Grehan 1091366f6083SPeter Grehan int 1092366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 1093366f6083SPeter Grehan struct seg_desc *desc) 1094366f6083SPeter Grehan { 1095a488c9c9SRodney W. Grimes if (vcpu < 0 || vcpu >= vm->maxcpus) 1096366f6083SPeter Grehan return (EINVAL); 1097366f6083SPeter Grehan 1098366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 1099366f6083SPeter Grehan return (EINVAL); 1100366f6083SPeter Grehan 1101366f6083SPeter Grehan return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 1102366f6083SPeter Grehan } 1103366f6083SPeter Grehan 1104366f6083SPeter Grehan static void 1105366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 1106366f6083SPeter Grehan { 1107366f6083SPeter Grehan 110838f1b189SPeter Grehan /* flush host state to the pcb */ 110938f1b189SPeter Grehan fpuexit(curthread); 1110bd8572e0SNeel Natu 1111bd8572e0SNeel Natu /* restore guest FPU state */ 1112366f6083SPeter Grehan fpu_stop_emulating(); 111338f1b189SPeter Grehan fpurestore(vcpu->guestfpu); 1114bd8572e0SNeel Natu 1115abb023fbSJohn Baldwin /* restore guest XCR0 if XSAVE is enabled in the host */ 1116abb023fbSJohn Baldwin if (rcr4() & CR4_XSAVE) 1117abb023fbSJohn Baldwin load_xcr(0, vcpu->guest_xcr0); 1118abb023fbSJohn Baldwin 1119bd8572e0SNeel Natu /* 1120bd8572e0SNeel Natu * The FPU is now "dirty" with the guest's state so turn on emulation 1121bd8572e0SNeel Natu * to trap any access to the FPU by the host. 1122bd8572e0SNeel Natu */ 1123bd8572e0SNeel Natu fpu_start_emulating(); 1124366f6083SPeter Grehan } 1125366f6083SPeter Grehan 1126366f6083SPeter Grehan static void 1127366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 1128366f6083SPeter Grehan { 1129366f6083SPeter Grehan 1130bd8572e0SNeel Natu if ((rcr0() & CR0_TS) == 0) 1131bd8572e0SNeel Natu panic("fpu emulation not enabled in host!"); 1132bd8572e0SNeel Natu 1133abb023fbSJohn Baldwin /* save guest XCR0 and restore host XCR0 */ 1134abb023fbSJohn Baldwin if (rcr4() & CR4_XSAVE) { 1135abb023fbSJohn Baldwin vcpu->guest_xcr0 = rxcr(0); 1136abb023fbSJohn Baldwin load_xcr(0, vmm_get_host_xcr0()); 1137abb023fbSJohn Baldwin } 1138abb023fbSJohn Baldwin 1139bd8572e0SNeel Natu /* save guest FPU state */ 1140bd8572e0SNeel Natu fpu_stop_emulating(); 114138f1b189SPeter Grehan fpusave(vcpu->guestfpu); 1142366f6083SPeter Grehan fpu_start_emulating(); 1143366f6083SPeter Grehan } 1144366f6083SPeter Grehan 114561592433SNeel Natu static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); 1146f76fc5d4SNeel Natu 1147318224bbSNeel Natu static int 1148248e6799SNeel Natu vcpu_set_state_locked(struct vm *vm, int vcpuid, enum vcpu_state newstate, 1149f80330a8SNeel Natu bool from_idle) 1150366f6083SPeter Grehan { 1151248e6799SNeel Natu struct vcpu *vcpu; 1152318224bbSNeel Natu int error; 1153366f6083SPeter Grehan 1154248e6799SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1155318224bbSNeel Natu vcpu_assert_locked(vcpu); 1156366f6083SPeter Grehan 1157f76fc5d4SNeel Natu /* 1158f80330a8SNeel Natu * State transitions from the vmmdev_ioctl() must always begin from 1159f80330a8SNeel Natu * the VCPU_IDLE state. This guarantees that there is only a single 1160f80330a8SNeel Natu * ioctl() operating on a vcpu at any point. 1161f80330a8SNeel Natu */ 1162f80330a8SNeel Natu if (from_idle) { 1163248e6799SNeel Natu while (vcpu->state != VCPU_IDLE) { 1164248e6799SNeel Natu vcpu->reqidle = 1; 1165248e6799SNeel Natu vcpu_notify_event_locked(vcpu, false); 1166248e6799SNeel Natu VCPU_CTR1(vm, vcpuid, "vcpu state change from %s to " 1167248e6799SNeel Natu "idle requested", vcpu_state2str(vcpu->state)); 1168f80330a8SNeel Natu msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); 1169248e6799SNeel Natu } 1170f80330a8SNeel Natu } else { 1171f80330a8SNeel Natu KASSERT(vcpu->state != VCPU_IDLE, ("invalid transition from " 1172f80330a8SNeel Natu "vcpu idle state")); 1173f80330a8SNeel Natu } 1174f80330a8SNeel Natu 1175ef39d7e9SNeel Natu if (vcpu->state == VCPU_RUNNING) { 1176ef39d7e9SNeel Natu KASSERT(vcpu->hostcpu == curcpu, ("curcpu %d and hostcpu %d " 1177ef39d7e9SNeel Natu "mismatch for running vcpu", curcpu, vcpu->hostcpu)); 1178ef39d7e9SNeel Natu } else { 1179ef39d7e9SNeel Natu KASSERT(vcpu->hostcpu == NOCPU, ("Invalid hostcpu %d for a " 1180ef39d7e9SNeel Natu "vcpu that is not running", vcpu->hostcpu)); 1181ef39d7e9SNeel Natu } 1182ef39d7e9SNeel Natu 1183f80330a8SNeel Natu /* 1184318224bbSNeel Natu * The following state transitions are allowed: 1185318224bbSNeel Natu * IDLE -> FROZEN -> IDLE 1186318224bbSNeel Natu * FROZEN -> RUNNING -> FROZEN 1187318224bbSNeel Natu * FROZEN -> SLEEPING -> FROZEN 1188f76fc5d4SNeel Natu */ 1189318224bbSNeel Natu switch (vcpu->state) { 1190318224bbSNeel Natu case VCPU_IDLE: 1191318224bbSNeel Natu case VCPU_RUNNING: 1192318224bbSNeel Natu case VCPU_SLEEPING: 1193318224bbSNeel Natu error = (newstate != VCPU_FROZEN); 1194318224bbSNeel Natu break; 1195318224bbSNeel Natu case VCPU_FROZEN: 1196318224bbSNeel Natu error = (newstate == VCPU_FROZEN); 1197318224bbSNeel Natu break; 1198318224bbSNeel Natu default: 1199318224bbSNeel Natu error = 1; 1200318224bbSNeel Natu break; 1201318224bbSNeel Natu } 1202318224bbSNeel Natu 1203f80330a8SNeel Natu if (error) 1204f80330a8SNeel Natu return (EBUSY); 1205318224bbSNeel Natu 1206248e6799SNeel Natu VCPU_CTR2(vm, vcpuid, "vcpu state changed from %s to %s", 1207248e6799SNeel Natu vcpu_state2str(vcpu->state), vcpu_state2str(newstate)); 1208248e6799SNeel Natu 1209f80330a8SNeel Natu vcpu->state = newstate; 1210ef39d7e9SNeel Natu if (newstate == VCPU_RUNNING) 1211ef39d7e9SNeel Natu vcpu->hostcpu = curcpu; 1212ef39d7e9SNeel Natu else 1213ef39d7e9SNeel Natu vcpu->hostcpu = NOCPU; 1214ef39d7e9SNeel Natu 1215f80330a8SNeel Natu if (newstate == VCPU_IDLE) 1216f80330a8SNeel Natu wakeup(&vcpu->state); 1217f80330a8SNeel Natu 1218f80330a8SNeel Natu return (0); 1219318224bbSNeel Natu } 1220318224bbSNeel Natu 1221318224bbSNeel Natu static void 1222318224bbSNeel Natu vcpu_require_state(struct vm *vm, int vcpuid, enum vcpu_state newstate) 1223318224bbSNeel Natu { 1224318224bbSNeel Natu int error; 1225318224bbSNeel Natu 1226f80330a8SNeel Natu if ((error = vcpu_set_state(vm, vcpuid, newstate, false)) != 0) 1227318224bbSNeel Natu panic("Error %d setting state to %d\n", error, newstate); 1228318224bbSNeel Natu } 1229318224bbSNeel Natu 1230318224bbSNeel Natu static void 1231248e6799SNeel Natu vcpu_require_state_locked(struct vm *vm, int vcpuid, enum vcpu_state newstate) 1232318224bbSNeel Natu { 1233318224bbSNeel Natu int error; 1234318224bbSNeel Natu 1235248e6799SNeel Natu if ((error = vcpu_set_state_locked(vm, vcpuid, newstate, false)) != 0) 1236318224bbSNeel Natu panic("Error %d setting state to %d", error, newstate); 1237318224bbSNeel Natu } 1238318224bbSNeel Natu 12395b8a8cd1SNeel Natu #define RENDEZVOUS_CTR0(vm, vcpuid, fmt) \ 12405b8a8cd1SNeel Natu do { \ 12415b8a8cd1SNeel Natu if (vcpuid >= 0) \ 12425b8a8cd1SNeel Natu VCPU_CTR0(vm, vcpuid, fmt); \ 12435b8a8cd1SNeel Natu else \ 12445b8a8cd1SNeel Natu VM_CTR0(vm, fmt); \ 12455b8a8cd1SNeel Natu } while (0) 12465b8a8cd1SNeel Natu 1247b837daddSKonstantin Belousov static int 12485b8a8cd1SNeel Natu vm_handle_rendezvous(struct vm *vm, int vcpuid) 12495b8a8cd1SNeel Natu { 1250b837daddSKonstantin Belousov struct thread *td; 1251b837daddSKonstantin Belousov int error; 12525b8a8cd1SNeel Natu 1253a488c9c9SRodney W. Grimes KASSERT(vcpuid == -1 || (vcpuid >= 0 && vcpuid < vm->maxcpus), 12545b8a8cd1SNeel Natu ("vm_handle_rendezvous: invalid vcpuid %d", vcpuid)); 12555b8a8cd1SNeel Natu 1256b837daddSKonstantin Belousov error = 0; 1257b837daddSKonstantin Belousov td = curthread; 12585b8a8cd1SNeel Natu mtx_lock(&vm->rendezvous_mtx); 12595b8a8cd1SNeel Natu while (vm->rendezvous_func != NULL) { 126022d822c6SNeel Natu /* 'rendezvous_req_cpus' must be a subset of 'active_cpus' */ 126122d822c6SNeel Natu CPU_AND(&vm->rendezvous_req_cpus, &vm->active_cpus); 126222d822c6SNeel Natu 12635b8a8cd1SNeel Natu if (vcpuid != -1 && 126422d822c6SNeel Natu CPU_ISSET(vcpuid, &vm->rendezvous_req_cpus) && 126522d822c6SNeel Natu !CPU_ISSET(vcpuid, &vm->rendezvous_done_cpus)) { 12665b8a8cd1SNeel Natu VCPU_CTR0(vm, vcpuid, "Calling rendezvous func"); 12675b8a8cd1SNeel Natu (*vm->rendezvous_func)(vm, vcpuid, vm->rendezvous_arg); 12685b8a8cd1SNeel Natu CPU_SET(vcpuid, &vm->rendezvous_done_cpus); 12695b8a8cd1SNeel Natu } 12705b8a8cd1SNeel Natu if (CPU_CMP(&vm->rendezvous_req_cpus, 12715b8a8cd1SNeel Natu &vm->rendezvous_done_cpus) == 0) { 12725b8a8cd1SNeel Natu VCPU_CTR0(vm, vcpuid, "Rendezvous completed"); 1273869dbab7SAndriy Gapon vm->rendezvous_func = NULL; 12745b8a8cd1SNeel Natu wakeup(&vm->rendezvous_func); 12755b8a8cd1SNeel Natu break; 12765b8a8cd1SNeel Natu } 12775b8a8cd1SNeel Natu RENDEZVOUS_CTR0(vm, vcpuid, "Wait for rendezvous completion"); 12785b8a8cd1SNeel Natu mtx_sleep(&vm->rendezvous_func, &vm->rendezvous_mtx, 0, 1279b837daddSKonstantin Belousov "vmrndv", hz); 1280b837daddSKonstantin Belousov if ((td->td_flags & TDF_NEEDSUSPCHK) != 0) { 1281b837daddSKonstantin Belousov mtx_unlock(&vm->rendezvous_mtx); 1282b837daddSKonstantin Belousov error = thread_check_susp(td, true); 1283b837daddSKonstantin Belousov if (error != 0) 1284b837daddSKonstantin Belousov return (error); 1285b837daddSKonstantin Belousov mtx_lock(&vm->rendezvous_mtx); 1286b837daddSKonstantin Belousov } 12875b8a8cd1SNeel Natu } 12885b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 1289b837daddSKonstantin Belousov return (0); 12905b8a8cd1SNeel Natu } 12915b8a8cd1SNeel Natu 1292318224bbSNeel Natu /* 1293318224bbSNeel Natu * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run. 1294318224bbSNeel Natu */ 1295318224bbSNeel Natu static int 1296becd9849SNeel Natu vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu) 1297318224bbSNeel Natu { 1298318224bbSNeel Natu struct vcpu *vcpu; 1299c6a0cc2eSNeel Natu const char *wmesg; 1300b837daddSKonstantin Belousov struct thread *td; 1301b837daddSKonstantin Belousov int error, t, vcpu_halted, vm_halted; 1302e50ce2aaSNeel Natu 1303e50ce2aaSNeel Natu KASSERT(!CPU_ISSET(vcpuid, &vm->halted_cpus), ("vcpu already halted")); 1304318224bbSNeel Natu 1305318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1306e50ce2aaSNeel Natu vcpu_halted = 0; 1307e50ce2aaSNeel Natu vm_halted = 0; 1308b837daddSKonstantin Belousov error = 0; 1309b837daddSKonstantin Belousov td = curthread; 1310318224bbSNeel Natu 1311f76fc5d4SNeel Natu vcpu_lock(vcpu); 1312c6a0cc2eSNeel Natu while (1) { 1313f76fc5d4SNeel Natu /* 1314f76fc5d4SNeel Natu * Do a final check for pending NMI or interrupts before 1315c6a0cc2eSNeel Natu * really putting this thread to sleep. Also check for 1316c6a0cc2eSNeel Natu * software events that would cause this vcpu to wakeup. 1317f76fc5d4SNeel Natu * 1318c6a0cc2eSNeel Natu * These interrupts/events could have happened after the 1319c6a0cc2eSNeel Natu * vcpu returned from VMRUN() and before it acquired the 1320c6a0cc2eSNeel Natu * vcpu lock above. 1321f76fc5d4SNeel Natu */ 1322248e6799SNeel Natu if (vm->rendezvous_func != NULL || vm->suspend || vcpu->reqidle) 1323c6a0cc2eSNeel Natu break; 1324c6a0cc2eSNeel Natu if (vm_nmi_pending(vm, vcpuid)) 1325c6a0cc2eSNeel Natu break; 1326c6a0cc2eSNeel Natu if (!intr_disabled) { 1327c6a0cc2eSNeel Natu if (vm_extint_pending(vm, vcpuid) || 1328c6a0cc2eSNeel Natu vlapic_pending_intr(vcpu->vlapic, NULL)) { 1329c6a0cc2eSNeel Natu break; 1330c6a0cc2eSNeel Natu } 1331c6a0cc2eSNeel Natu } 1332c6a0cc2eSNeel Natu 1333f008d157SNeel Natu /* Don't go to sleep if the vcpu thread needs to yield */ 1334f008d157SNeel Natu if (vcpu_should_yield(vm, vcpuid)) 1335f008d157SNeel Natu break; 1336f008d157SNeel Natu 1337fc276d92SJohn Baldwin if (vcpu_debugged(vm, vcpuid)) 1338fc276d92SJohn Baldwin break; 1339fc276d92SJohn Baldwin 1340e50ce2aaSNeel Natu /* 1341e50ce2aaSNeel Natu * Some Linux guests implement "halt" by having all vcpus 1342e50ce2aaSNeel Natu * execute HLT with interrupts disabled. 'halted_cpus' keeps 1343e50ce2aaSNeel Natu * track of the vcpus that have entered this state. When all 1344e50ce2aaSNeel Natu * vcpus enter the halted state the virtual machine is halted. 1345e50ce2aaSNeel Natu */ 1346e50ce2aaSNeel Natu if (intr_disabled) { 1347c6a0cc2eSNeel Natu wmesg = "vmhalt"; 1348e50ce2aaSNeel Natu VCPU_CTR0(vm, vcpuid, "Halted"); 1349055fc2cbSNeel Natu if (!vcpu_halted && halt_detection_enabled) { 1350e50ce2aaSNeel Natu vcpu_halted = 1; 1351e50ce2aaSNeel Natu CPU_SET_ATOMIC(vcpuid, &vm->halted_cpus); 1352e50ce2aaSNeel Natu } 1353e50ce2aaSNeel Natu if (CPU_CMP(&vm->halted_cpus, &vm->active_cpus) == 0) { 1354e50ce2aaSNeel Natu vm_halted = 1; 1355e50ce2aaSNeel Natu break; 1356e50ce2aaSNeel Natu } 1357e50ce2aaSNeel Natu } else { 1358e50ce2aaSNeel Natu wmesg = "vmidle"; 1359e50ce2aaSNeel Natu } 1360c6a0cc2eSNeel Natu 1361f76fc5d4SNeel Natu t = ticks; 1362248e6799SNeel Natu vcpu_require_state_locked(vm, vcpuid, VCPU_SLEEPING); 1363f008d157SNeel Natu /* 1364f008d157SNeel Natu * XXX msleep_spin() cannot be interrupted by signals so 1365f008d157SNeel Natu * wake up periodically to check pending signals. 1366f008d157SNeel Natu */ 1367f008d157SNeel Natu msleep_spin(vcpu, &vcpu->mtx, wmesg, hz); 1368248e6799SNeel Natu vcpu_require_state_locked(vm, vcpuid, VCPU_FROZEN); 1369f76fc5d4SNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t); 1370b837daddSKonstantin Belousov if ((td->td_flags & TDF_NEEDSUSPCHK) != 0) { 1371b837daddSKonstantin Belousov vcpu_unlock(vcpu); 1372b837daddSKonstantin Belousov error = thread_check_susp(td, false); 1373b837daddSKonstantin Belousov if (error != 0) 1374b837daddSKonstantin Belousov return (error); 1375b837daddSKonstantin Belousov vcpu_lock(vcpu); 1376b837daddSKonstantin Belousov } 1377f76fc5d4SNeel Natu } 1378e50ce2aaSNeel Natu 1379e50ce2aaSNeel Natu if (vcpu_halted) 1380e50ce2aaSNeel Natu CPU_CLR_ATOMIC(vcpuid, &vm->halted_cpus); 1381e50ce2aaSNeel Natu 1382f76fc5d4SNeel Natu vcpu_unlock(vcpu); 1383f76fc5d4SNeel Natu 1384e50ce2aaSNeel Natu if (vm_halted) 1385e50ce2aaSNeel Natu vm_suspend(vm, VM_SUSPEND_HALT); 1386e50ce2aaSNeel Natu 1387318224bbSNeel Natu return (0); 1388318224bbSNeel Natu } 1389318224bbSNeel Natu 1390318224bbSNeel Natu static int 1391becd9849SNeel Natu vm_handle_paging(struct vm *vm, int vcpuid, bool *retu) 1392318224bbSNeel Natu { 1393318224bbSNeel Natu int rv, ftype; 1394318224bbSNeel Natu struct vm_map *map; 1395318224bbSNeel Natu struct vcpu *vcpu; 1396318224bbSNeel Natu struct vm_exit *vme; 1397318224bbSNeel Natu 1398318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1399318224bbSNeel Natu vme = &vcpu->exitinfo; 1400318224bbSNeel Natu 1401d087a399SNeel Natu KASSERT(vme->inst_length == 0, ("%s: invalid inst_length %d", 1402d087a399SNeel Natu __func__, vme->inst_length)); 1403d087a399SNeel Natu 1404318224bbSNeel Natu ftype = vme->u.paging.fault_type; 1405318224bbSNeel Natu KASSERT(ftype == VM_PROT_READ || 1406318224bbSNeel Natu ftype == VM_PROT_WRITE || ftype == VM_PROT_EXECUTE, 1407318224bbSNeel Natu ("vm_handle_paging: invalid fault_type %d", ftype)); 1408318224bbSNeel Natu 1409318224bbSNeel Natu if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { 1410318224bbSNeel Natu rv = pmap_emulate_accessed_dirty(vmspace_pmap(vm->vmspace), 1411318224bbSNeel Natu vme->u.paging.gpa, ftype); 14129d8d8e3eSNeel Natu if (rv == 0) { 14139d8d8e3eSNeel Natu VCPU_CTR2(vm, vcpuid, "%s bit emulation for gpa %#lx", 14149d8d8e3eSNeel Natu ftype == VM_PROT_READ ? "accessed" : "dirty", 14159d8d8e3eSNeel Natu vme->u.paging.gpa); 1416318224bbSNeel Natu goto done; 1417318224bbSNeel Natu } 14189d8d8e3eSNeel Natu } 1419318224bbSNeel Natu 1420318224bbSNeel Natu map = &vm->vmspace->vm_map; 1421df08823dSKonstantin Belousov rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL, NULL); 1422318224bbSNeel Natu 1423513c8d33SNeel Natu VCPU_CTR3(vm, vcpuid, "vm_handle_paging rv = %d, gpa = %#lx, " 1424513c8d33SNeel Natu "ftype = %d", rv, vme->u.paging.gpa, ftype); 1425318224bbSNeel Natu 1426318224bbSNeel Natu if (rv != KERN_SUCCESS) 1427318224bbSNeel Natu return (EFAULT); 1428318224bbSNeel Natu done: 1429318224bbSNeel Natu return (0); 1430318224bbSNeel Natu } 1431318224bbSNeel Natu 1432318224bbSNeel Natu static int 1433becd9849SNeel Natu vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu) 1434318224bbSNeel Natu { 1435318224bbSNeel Natu struct vie *vie; 1436318224bbSNeel Natu struct vcpu *vcpu; 1437318224bbSNeel Natu struct vm_exit *vme; 1438e4f605eeSTycho Nightingale uint64_t gla, gpa, cs_base; 1439e813a873SNeel Natu struct vm_guest_paging *paging; 1440565bbb86SNeel Natu mem_region_read_t mread; 1441565bbb86SNeel Natu mem_region_write_t mwrite; 1442f7a9f178SNeel Natu enum vm_cpu_mode cpu_mode; 14431c73ea3eSNeel Natu int cs_d, error, fault; 1444318224bbSNeel Natu 1445318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1446318224bbSNeel Natu vme = &vcpu->exitinfo; 1447318224bbSNeel Natu 14481c73ea3eSNeel Natu KASSERT(vme->inst_length == 0, ("%s: invalid inst_length %d", 14491c73ea3eSNeel Natu __func__, vme->inst_length)); 14501c73ea3eSNeel Natu 1451318224bbSNeel Natu gla = vme->u.inst_emul.gla; 1452318224bbSNeel Natu gpa = vme->u.inst_emul.gpa; 1453e4f605eeSTycho Nightingale cs_base = vme->u.inst_emul.cs_base; 1454f7a9f178SNeel Natu cs_d = vme->u.inst_emul.cs_d; 1455318224bbSNeel Natu vie = &vme->u.inst_emul.vie; 1456e813a873SNeel Natu paging = &vme->u.inst_emul.paging; 1457f7a9f178SNeel Natu cpu_mode = paging->cpu_mode; 1458318224bbSNeel Natu 14599d8d8e3eSNeel Natu VCPU_CTR1(vm, vcpuid, "inst_emul fault accessing gpa %#lx", gpa); 14609d8d8e3eSNeel Natu 1461318224bbSNeel Natu /* Fetch, decode and emulate the faulting instruction */ 1462c2a875f9SNeel Natu if (vie->num_valid == 0) { 1463e4f605eeSTycho Nightingale error = vmm_fetch_instruction(vm, vcpuid, paging, vme->rip + 14641c73ea3eSNeel Natu cs_base, VIE_INST_SIZE, vie, &fault); 1465c2a875f9SNeel Natu } else { 1466c2a875f9SNeel Natu /* 1467c2a875f9SNeel Natu * The instruction bytes have already been copied into 'vie' 1468c2a875f9SNeel Natu */ 14699c4d5478SNeel Natu error = fault = 0; 1470c2a875f9SNeel Natu } 14719c4d5478SNeel Natu if (error || fault) 14729c4d5478SNeel Natu return (error); 1473318224bbSNeel Natu 1474c07a0648SNeel Natu if (vmm_decode_instruction(vm, vcpuid, gla, cpu_mode, cs_d, vie) != 0) { 1475c07a0648SNeel Natu VCPU_CTR1(vm, vcpuid, "Error decoding instruction at %#lx", 1476c07a0648SNeel Natu vme->rip + cs_base); 1477c07a0648SNeel Natu *retu = true; /* dump instruction bytes in userspace */ 1478c07a0648SNeel Natu return (0); 1479c07a0648SNeel Natu } 1480318224bbSNeel Natu 1481a0b78f09SPeter Grehan /* 14821c73ea3eSNeel Natu * Update 'nextrip' based on the length of the emulated instruction. 1483a0b78f09SPeter Grehan */ 1484a0b78f09SPeter Grehan vme->inst_length = vie->num_processed; 1485d087a399SNeel Natu vcpu->nextrip += vie->num_processed; 14861c73ea3eSNeel Natu VCPU_CTR1(vm, vcpuid, "nextrip updated to %#lx after instruction " 14871c73ea3eSNeel Natu "decoding", vcpu->nextrip); 1488a0b78f09SPeter Grehan 148908e3ff32SNeel Natu /* return to userland unless this is an in-kernel emulated device */ 1490565bbb86SNeel Natu if (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE) { 1491565bbb86SNeel Natu mread = lapic_mmio_read; 1492565bbb86SNeel Natu mwrite = lapic_mmio_write; 1493565bbb86SNeel Natu } else if (gpa >= VIOAPIC_BASE && gpa < VIOAPIC_BASE + VIOAPIC_SIZE) { 1494565bbb86SNeel Natu mread = vioapic_mmio_read; 1495565bbb86SNeel Natu mwrite = vioapic_mmio_write; 149608e3ff32SNeel Natu } else if (gpa >= VHPET_BASE && gpa < VHPET_BASE + VHPET_SIZE) { 149708e3ff32SNeel Natu mread = vhpet_mmio_read; 149808e3ff32SNeel Natu mwrite = vhpet_mmio_write; 1499565bbb86SNeel Natu } else { 1500becd9849SNeel Natu *retu = true; 1501318224bbSNeel Natu return (0); 1502318224bbSNeel Natu } 1503318224bbSNeel Natu 1504d665d229SNeel Natu error = vmm_emulate_instruction(vm, vcpuid, gpa, vie, paging, 1505d665d229SNeel Natu mread, mwrite, retu); 1506318224bbSNeel Natu 1507318224bbSNeel Natu return (error); 1508318224bbSNeel Natu } 1509318224bbSNeel Natu 1510b15a09c0SNeel Natu static int 1511b15a09c0SNeel Natu vm_handle_suspend(struct vm *vm, int vcpuid, bool *retu) 1512b15a09c0SNeel Natu { 1513b837daddSKonstantin Belousov int error, i; 1514b15a09c0SNeel Natu struct vcpu *vcpu; 1515b837daddSKonstantin Belousov struct thread *td; 1516b15a09c0SNeel Natu 1517b837daddSKonstantin Belousov error = 0; 1518b15a09c0SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1519b837daddSKonstantin Belousov td = curthread; 1520b15a09c0SNeel Natu 1521b15a09c0SNeel Natu CPU_SET_ATOMIC(vcpuid, &vm->suspended_cpus); 1522b15a09c0SNeel Natu 1523b15a09c0SNeel Natu /* 1524b15a09c0SNeel Natu * Wait until all 'active_cpus' have suspended themselves. 1525b15a09c0SNeel Natu * 1526b15a09c0SNeel Natu * Since a VM may be suspended at any time including when one or 1527b15a09c0SNeel Natu * more vcpus are doing a rendezvous we need to call the rendezvous 1528b15a09c0SNeel Natu * handler while we are waiting to prevent a deadlock. 1529b15a09c0SNeel Natu */ 1530b15a09c0SNeel Natu vcpu_lock(vcpu); 1531b837daddSKonstantin Belousov while (error == 0) { 1532b15a09c0SNeel Natu if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 1533b15a09c0SNeel Natu VCPU_CTR0(vm, vcpuid, "All vcpus suspended"); 1534b15a09c0SNeel Natu break; 1535b15a09c0SNeel Natu } 1536b15a09c0SNeel Natu 1537b15a09c0SNeel Natu if (vm->rendezvous_func == NULL) { 1538b15a09c0SNeel Natu VCPU_CTR0(vm, vcpuid, "Sleeping during suspend"); 1539248e6799SNeel Natu vcpu_require_state_locked(vm, vcpuid, VCPU_SLEEPING); 1540b15a09c0SNeel Natu msleep_spin(vcpu, &vcpu->mtx, "vmsusp", hz); 1541248e6799SNeel Natu vcpu_require_state_locked(vm, vcpuid, VCPU_FROZEN); 1542b837daddSKonstantin Belousov if ((td->td_flags & TDF_NEEDSUSPCHK) != 0) { 1543b837daddSKonstantin Belousov vcpu_unlock(vcpu); 1544b837daddSKonstantin Belousov error = thread_check_susp(td, false); 1545b837daddSKonstantin Belousov vcpu_lock(vcpu); 1546b837daddSKonstantin Belousov } 1547b15a09c0SNeel Natu } else { 1548b15a09c0SNeel Natu VCPU_CTR0(vm, vcpuid, "Rendezvous during suspend"); 1549b15a09c0SNeel Natu vcpu_unlock(vcpu); 1550b837daddSKonstantin Belousov error = vm_handle_rendezvous(vm, vcpuid); 1551b15a09c0SNeel Natu vcpu_lock(vcpu); 1552b15a09c0SNeel Natu } 1553b15a09c0SNeel Natu } 1554b15a09c0SNeel Natu vcpu_unlock(vcpu); 1555b15a09c0SNeel Natu 1556b15a09c0SNeel Natu /* 1557b15a09c0SNeel Natu * Wakeup the other sleeping vcpus and return to userspace. 1558b15a09c0SNeel Natu */ 1559a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 1560b15a09c0SNeel Natu if (CPU_ISSET(i, &vm->suspended_cpus)) { 1561b15a09c0SNeel Natu vcpu_notify_event(vm, i, false); 1562b15a09c0SNeel Natu } 1563b15a09c0SNeel Natu } 1564b15a09c0SNeel Natu 1565b15a09c0SNeel Natu *retu = true; 1566b837daddSKonstantin Belousov return (error); 1567b15a09c0SNeel Natu } 1568b15a09c0SNeel Natu 1569248e6799SNeel Natu static int 1570248e6799SNeel Natu vm_handle_reqidle(struct vm *vm, int vcpuid, bool *retu) 1571248e6799SNeel Natu { 1572248e6799SNeel Natu struct vcpu *vcpu = &vm->vcpu[vcpuid]; 1573248e6799SNeel Natu 1574248e6799SNeel Natu vcpu_lock(vcpu); 1575248e6799SNeel Natu KASSERT(vcpu->reqidle, ("invalid vcpu reqidle %d", vcpu->reqidle)); 1576248e6799SNeel Natu vcpu->reqidle = 0; 1577248e6799SNeel Natu vcpu_unlock(vcpu); 1578248e6799SNeel Natu *retu = true; 1579248e6799SNeel Natu return (0); 1580248e6799SNeel Natu } 1581248e6799SNeel Natu 1582b15a09c0SNeel Natu int 1583f0fdcfe2SNeel Natu vm_suspend(struct vm *vm, enum vm_suspend_how how) 1584b15a09c0SNeel Natu { 1585f0fdcfe2SNeel Natu int i; 1586b15a09c0SNeel Natu 1587f0fdcfe2SNeel Natu if (how <= VM_SUSPEND_NONE || how >= VM_SUSPEND_LAST) 1588f0fdcfe2SNeel Natu return (EINVAL); 1589f0fdcfe2SNeel Natu 1590f0fdcfe2SNeel Natu if (atomic_cmpset_int(&vm->suspend, 0, how) == 0) { 1591f0fdcfe2SNeel Natu VM_CTR2(vm, "virtual machine already suspended %d/%d", 1592f0fdcfe2SNeel Natu vm->suspend, how); 1593b15a09c0SNeel Natu return (EALREADY); 1594b15a09c0SNeel Natu } 1595f0fdcfe2SNeel Natu 1596f0fdcfe2SNeel Natu VM_CTR1(vm, "virtual machine successfully suspended %d", how); 1597f0fdcfe2SNeel Natu 1598f0fdcfe2SNeel Natu /* 1599f0fdcfe2SNeel Natu * Notify all active vcpus that they are now suspended. 1600f0fdcfe2SNeel Natu */ 1601a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 1602f0fdcfe2SNeel Natu if (CPU_ISSET(i, &vm->active_cpus)) 1603f0fdcfe2SNeel Natu vcpu_notify_event(vm, i, false); 1604f0fdcfe2SNeel Natu } 1605f0fdcfe2SNeel Natu 1606f0fdcfe2SNeel Natu return (0); 1607f0fdcfe2SNeel Natu } 1608f0fdcfe2SNeel Natu 1609f0fdcfe2SNeel Natu void 1610f0fdcfe2SNeel Natu vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip) 1611f0fdcfe2SNeel Natu { 1612f0fdcfe2SNeel Natu struct vm_exit *vmexit; 1613f0fdcfe2SNeel Natu 1614f0fdcfe2SNeel Natu KASSERT(vm->suspend > VM_SUSPEND_NONE && vm->suspend < VM_SUSPEND_LAST, 1615f0fdcfe2SNeel Natu ("vm_exit_suspended: invalid suspend type %d", vm->suspend)); 1616f0fdcfe2SNeel Natu 1617f0fdcfe2SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 1618f0fdcfe2SNeel Natu vmexit->rip = rip; 1619f0fdcfe2SNeel Natu vmexit->inst_length = 0; 1620f0fdcfe2SNeel Natu vmexit->exitcode = VM_EXITCODE_SUSPENDED; 1621f0fdcfe2SNeel Natu vmexit->u.suspended.how = vm->suspend; 1622b15a09c0SNeel Natu } 1623b15a09c0SNeel Natu 162440487465SNeel Natu void 1625fc276d92SJohn Baldwin vm_exit_debug(struct vm *vm, int vcpuid, uint64_t rip) 1626fc276d92SJohn Baldwin { 1627fc276d92SJohn Baldwin struct vm_exit *vmexit; 1628fc276d92SJohn Baldwin 1629fc276d92SJohn Baldwin vmexit = vm_exitinfo(vm, vcpuid); 1630fc276d92SJohn Baldwin vmexit->rip = rip; 1631fc276d92SJohn Baldwin vmexit->inst_length = 0; 1632fc276d92SJohn Baldwin vmexit->exitcode = VM_EXITCODE_DEBUG; 1633fc276d92SJohn Baldwin } 1634fc276d92SJohn Baldwin 1635fc276d92SJohn Baldwin void 163640487465SNeel Natu vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip) 163740487465SNeel Natu { 163840487465SNeel Natu struct vm_exit *vmexit; 163940487465SNeel Natu 164040487465SNeel Natu KASSERT(vm->rendezvous_func != NULL, ("rendezvous not in progress")); 164140487465SNeel Natu 164240487465SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 164340487465SNeel Natu vmexit->rip = rip; 164440487465SNeel Natu vmexit->inst_length = 0; 164540487465SNeel Natu vmexit->exitcode = VM_EXITCODE_RENDEZVOUS; 164640487465SNeel Natu vmm_stat_incr(vm, vcpuid, VMEXIT_RENDEZVOUS, 1); 164740487465SNeel Natu } 164840487465SNeel Natu 164940487465SNeel Natu void 1650248e6799SNeel Natu vm_exit_reqidle(struct vm *vm, int vcpuid, uint64_t rip) 1651248e6799SNeel Natu { 1652248e6799SNeel Natu struct vm_exit *vmexit; 1653248e6799SNeel Natu 1654248e6799SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 1655248e6799SNeel Natu vmexit->rip = rip; 1656248e6799SNeel Natu vmexit->inst_length = 0; 1657248e6799SNeel Natu vmexit->exitcode = VM_EXITCODE_REQIDLE; 1658248e6799SNeel Natu vmm_stat_incr(vm, vcpuid, VMEXIT_REQIDLE, 1); 1659248e6799SNeel Natu } 1660248e6799SNeel Natu 1661248e6799SNeel Natu void 166240487465SNeel Natu vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip) 166340487465SNeel Natu { 166440487465SNeel Natu struct vm_exit *vmexit; 166540487465SNeel Natu 166640487465SNeel Natu vmexit = vm_exitinfo(vm, vcpuid); 166740487465SNeel Natu vmexit->rip = rip; 166840487465SNeel Natu vmexit->inst_length = 0; 166940487465SNeel Natu vmexit->exitcode = VM_EXITCODE_BOGUS; 167040487465SNeel Natu vmm_stat_incr(vm, vcpuid, VMEXIT_ASTPENDING, 1); 167140487465SNeel Natu } 167240487465SNeel Natu 1673318224bbSNeel Natu int 1674318224bbSNeel Natu vm_run(struct vm *vm, struct vm_run *vmrun) 1675318224bbSNeel Natu { 1676248e6799SNeel Natu struct vm_eventinfo evinfo; 1677318224bbSNeel Natu int error, vcpuid; 1678318224bbSNeel Natu struct vcpu *vcpu; 1679318224bbSNeel Natu struct pcb *pcb; 1680d087a399SNeel Natu uint64_t tscval; 1681318224bbSNeel Natu struct vm_exit *vme; 1682becd9849SNeel Natu bool retu, intr_disabled; 1683318224bbSNeel Natu pmap_t pmap; 1684318224bbSNeel Natu 1685318224bbSNeel Natu vcpuid = vmrun->cpuid; 1686318224bbSNeel Natu 1687a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 1688318224bbSNeel Natu return (EINVAL); 1689318224bbSNeel Natu 169095ebc360SNeel Natu if (!CPU_ISSET(vcpuid, &vm->active_cpus)) 169195ebc360SNeel Natu return (EINVAL); 169295ebc360SNeel Natu 169395ebc360SNeel Natu if (CPU_ISSET(vcpuid, &vm->suspended_cpus)) 169495ebc360SNeel Natu return (EINVAL); 169595ebc360SNeel Natu 1696318224bbSNeel Natu pmap = vmspace_pmap(vm->vmspace); 1697318224bbSNeel Natu vcpu = &vm->vcpu[vcpuid]; 1698318224bbSNeel Natu vme = &vcpu->exitinfo; 1699248e6799SNeel Natu evinfo.rptr = &vm->rendezvous_func; 1700248e6799SNeel Natu evinfo.sptr = &vm->suspend; 1701248e6799SNeel Natu evinfo.iptr = &vcpu->reqidle; 1702318224bbSNeel Natu restart: 1703318224bbSNeel Natu critical_enter(); 1704318224bbSNeel Natu 1705318224bbSNeel Natu KASSERT(!CPU_ISSET(curcpu, &pmap->pm_active), 1706318224bbSNeel Natu ("vm_run: absurd pm_active")); 1707318224bbSNeel Natu 1708318224bbSNeel Natu tscval = rdtsc(); 1709318224bbSNeel Natu 1710318224bbSNeel Natu pcb = PCPU_GET(curpcb); 1711318224bbSNeel Natu set_pcb_flags(pcb, PCB_FULL_IRET); 1712318224bbSNeel Natu 1713318224bbSNeel Natu restore_guest_fpustate(vcpu); 1714318224bbSNeel Natu 1715318224bbSNeel Natu vcpu_require_state(vm, vcpuid, VCPU_RUNNING); 1716248e6799SNeel Natu error = VMRUN(vm->cookie, vcpuid, vcpu->nextrip, pmap, &evinfo); 1717318224bbSNeel Natu vcpu_require_state(vm, vcpuid, VCPU_FROZEN); 1718318224bbSNeel Natu 1719318224bbSNeel Natu save_guest_fpustate(vcpu); 1720318224bbSNeel Natu 1721318224bbSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 1722318224bbSNeel Natu 1723318224bbSNeel Natu critical_exit(); 1724318224bbSNeel Natu 1725318224bbSNeel Natu if (error == 0) { 1726becd9849SNeel Natu retu = false; 1727d087a399SNeel Natu vcpu->nextrip = vme->rip + vme->inst_length; 1728318224bbSNeel Natu switch (vme->exitcode) { 1729248e6799SNeel Natu case VM_EXITCODE_REQIDLE: 1730248e6799SNeel Natu error = vm_handle_reqidle(vm, vcpuid, &retu); 1731248e6799SNeel Natu break; 1732b15a09c0SNeel Natu case VM_EXITCODE_SUSPENDED: 1733b15a09c0SNeel Natu error = vm_handle_suspend(vm, vcpuid, &retu); 1734b15a09c0SNeel Natu break; 173530b94db8SNeel Natu case VM_EXITCODE_IOAPIC_EOI: 173630b94db8SNeel Natu vioapic_process_eoi(vm, vcpuid, 173730b94db8SNeel Natu vme->u.ioapic_eoi.vector); 173830b94db8SNeel Natu break; 17395b8a8cd1SNeel Natu case VM_EXITCODE_RENDEZVOUS: 1740b837daddSKonstantin Belousov error = vm_handle_rendezvous(vm, vcpuid); 17415b8a8cd1SNeel Natu break; 1742318224bbSNeel Natu case VM_EXITCODE_HLT: 1743becd9849SNeel Natu intr_disabled = ((vme->u.hlt.rflags & PSL_I) == 0); 17441c052192SNeel Natu error = vm_handle_hlt(vm, vcpuid, intr_disabled, &retu); 1745318224bbSNeel Natu break; 1746318224bbSNeel Natu case VM_EXITCODE_PAGING: 1747318224bbSNeel Natu error = vm_handle_paging(vm, vcpuid, &retu); 1748318224bbSNeel Natu break; 1749318224bbSNeel Natu case VM_EXITCODE_INST_EMUL: 1750318224bbSNeel Natu error = vm_handle_inst_emul(vm, vcpuid, &retu); 1751318224bbSNeel Natu break; 1752d17b5104SNeel Natu case VM_EXITCODE_INOUT: 1753d17b5104SNeel Natu case VM_EXITCODE_INOUT_STR: 1754d17b5104SNeel Natu error = vm_handle_inout(vm, vcpuid, vme, &retu); 1755d17b5104SNeel Natu break; 175665145c7fSNeel Natu case VM_EXITCODE_MONITOR: 175765145c7fSNeel Natu case VM_EXITCODE_MWAIT: 175827d26457SAndrew Turner case VM_EXITCODE_VMINSN: 175965145c7fSNeel Natu vm_inject_ud(vm, vcpuid); 176065145c7fSNeel Natu break; 1761318224bbSNeel Natu default: 1762becd9849SNeel Natu retu = true; /* handled in userland */ 1763318224bbSNeel Natu break; 1764318224bbSNeel Natu } 1765318224bbSNeel Natu } 1766318224bbSNeel Natu 1767d087a399SNeel Natu if (error == 0 && retu == false) 1768f76fc5d4SNeel Natu goto restart; 1769f76fc5d4SNeel Natu 1770248e6799SNeel Natu VCPU_CTR2(vm, vcpuid, "retu %d/%d", error, vme->exitcode); 1771248e6799SNeel Natu 1772318224bbSNeel Natu /* copy the exit information */ 1773318224bbSNeel Natu bcopy(vme, &vmrun->vm_exit, sizeof(struct vm_exit)); 1774366f6083SPeter Grehan return (error); 1775366f6083SPeter Grehan } 1776366f6083SPeter Grehan 1777366f6083SPeter Grehan int 1778c9c75df4SNeel Natu vm_restart_instruction(void *arg, int vcpuid) 1779c9c75df4SNeel Natu { 1780d087a399SNeel Natu struct vm *vm; 1781c9c75df4SNeel Natu struct vcpu *vcpu; 1782d087a399SNeel Natu enum vcpu_state state; 1783d087a399SNeel Natu uint64_t rip; 1784d087a399SNeel Natu int error; 1785c9c75df4SNeel Natu 1786d087a399SNeel Natu vm = arg; 1787a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 1788c9c75df4SNeel Natu return (EINVAL); 1789c9c75df4SNeel Natu 1790c9c75df4SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1791d087a399SNeel Natu state = vcpu_get_state(vm, vcpuid, NULL); 1792d087a399SNeel Natu if (state == VCPU_RUNNING) { 1793d087a399SNeel Natu /* 1794d087a399SNeel Natu * When a vcpu is "running" the next instruction is determined 1795d087a399SNeel Natu * by adding 'rip' and 'inst_length' in the vcpu's 'exitinfo'. 1796d087a399SNeel Natu * Thus setting 'inst_length' to zero will cause the current 1797d087a399SNeel Natu * instruction to be restarted. 1798d087a399SNeel Natu */ 1799c9c75df4SNeel Natu vcpu->exitinfo.inst_length = 0; 1800d087a399SNeel Natu VCPU_CTR1(vm, vcpuid, "restarting instruction at %#lx by " 1801d087a399SNeel Natu "setting inst_length to zero", vcpu->exitinfo.rip); 1802d087a399SNeel Natu } else if (state == VCPU_FROZEN) { 1803d087a399SNeel Natu /* 1804d087a399SNeel Natu * When a vcpu is "frozen" it is outside the critical section 1805d087a399SNeel Natu * around VMRUN() and 'nextrip' points to the next instruction. 1806d087a399SNeel Natu * Thus instruction restart is achieved by setting 'nextrip' 1807d087a399SNeel Natu * to the vcpu's %rip. 1808d087a399SNeel Natu */ 1809d087a399SNeel Natu error = vm_get_register(vm, vcpuid, VM_REG_GUEST_RIP, &rip); 1810d087a399SNeel Natu KASSERT(!error, ("%s: error %d getting rip", __func__, error)); 1811d087a399SNeel Natu VCPU_CTR2(vm, vcpuid, "restarting instruction by updating " 1812d087a399SNeel Natu "nextrip from %#lx to %#lx", vcpu->nextrip, rip); 1813d087a399SNeel Natu vcpu->nextrip = rip; 1814d087a399SNeel Natu } else { 1815d087a399SNeel Natu panic("%s: invalid state %d", __func__, state); 1816d087a399SNeel Natu } 1817c9c75df4SNeel Natu return (0); 1818c9c75df4SNeel Natu } 1819c9c75df4SNeel Natu 1820c9c75df4SNeel Natu int 1821091d4532SNeel Natu vm_exit_intinfo(struct vm *vm, int vcpuid, uint64_t info) 1822091d4532SNeel Natu { 1823091d4532SNeel Natu struct vcpu *vcpu; 1824091d4532SNeel Natu int type, vector; 1825091d4532SNeel Natu 1826a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 1827091d4532SNeel Natu return (EINVAL); 1828091d4532SNeel Natu 1829091d4532SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1830091d4532SNeel Natu 1831091d4532SNeel Natu if (info & VM_INTINFO_VALID) { 1832091d4532SNeel Natu type = info & VM_INTINFO_TYPE; 1833091d4532SNeel Natu vector = info & 0xff; 1834091d4532SNeel Natu if (type == VM_INTINFO_NMI && vector != IDT_NMI) 1835091d4532SNeel Natu return (EINVAL); 1836091d4532SNeel Natu if (type == VM_INTINFO_HWEXCEPTION && vector >= 32) 1837091d4532SNeel Natu return (EINVAL); 1838091d4532SNeel Natu if (info & VM_INTINFO_RSVD) 1839091d4532SNeel Natu return (EINVAL); 1840091d4532SNeel Natu } else { 1841091d4532SNeel Natu info = 0; 1842091d4532SNeel Natu } 1843091d4532SNeel Natu VCPU_CTR2(vm, vcpuid, "%s: info1(%#lx)", __func__, info); 1844091d4532SNeel Natu vcpu->exitintinfo = info; 1845091d4532SNeel Natu return (0); 1846091d4532SNeel Natu } 1847091d4532SNeel Natu 1848091d4532SNeel Natu enum exc_class { 1849091d4532SNeel Natu EXC_BENIGN, 1850091d4532SNeel Natu EXC_CONTRIBUTORY, 1851091d4532SNeel Natu EXC_PAGEFAULT 1852091d4532SNeel Natu }; 1853091d4532SNeel Natu 1854091d4532SNeel Natu #define IDT_VE 20 /* Virtualization Exception (Intel specific) */ 1855091d4532SNeel Natu 1856091d4532SNeel Natu static enum exc_class 1857091d4532SNeel Natu exception_class(uint64_t info) 1858091d4532SNeel Natu { 1859091d4532SNeel Natu int type, vector; 1860091d4532SNeel Natu 1861091d4532SNeel Natu KASSERT(info & VM_INTINFO_VALID, ("intinfo must be valid: %#lx", info)); 1862091d4532SNeel Natu type = info & VM_INTINFO_TYPE; 1863091d4532SNeel Natu vector = info & 0xff; 1864091d4532SNeel Natu 1865091d4532SNeel Natu /* Table 6-4, "Interrupt and Exception Classes", Intel SDM, Vol 3 */ 1866091d4532SNeel Natu switch (type) { 1867091d4532SNeel Natu case VM_INTINFO_HWINTR: 1868091d4532SNeel Natu case VM_INTINFO_SWINTR: 1869091d4532SNeel Natu case VM_INTINFO_NMI: 1870091d4532SNeel Natu return (EXC_BENIGN); 1871091d4532SNeel Natu default: 1872091d4532SNeel Natu /* 1873091d4532SNeel Natu * Hardware exception. 1874091d4532SNeel Natu * 1875091d4532SNeel Natu * SVM and VT-x use identical type values to represent NMI, 1876091d4532SNeel Natu * hardware interrupt and software interrupt. 1877091d4532SNeel Natu * 1878091d4532SNeel Natu * SVM uses type '3' for all exceptions. VT-x uses type '3' 1879091d4532SNeel Natu * for exceptions except #BP and #OF. #BP and #OF use a type 1880091d4532SNeel Natu * value of '5' or '6'. Therefore we don't check for explicit 1881091d4532SNeel Natu * values of 'type' to classify 'intinfo' into a hardware 1882091d4532SNeel Natu * exception. 1883091d4532SNeel Natu */ 1884091d4532SNeel Natu break; 1885091d4532SNeel Natu } 1886091d4532SNeel Natu 1887091d4532SNeel Natu switch (vector) { 1888091d4532SNeel Natu case IDT_PF: 1889091d4532SNeel Natu case IDT_VE: 1890091d4532SNeel Natu return (EXC_PAGEFAULT); 1891091d4532SNeel Natu case IDT_DE: 1892091d4532SNeel Natu case IDT_TS: 1893091d4532SNeel Natu case IDT_NP: 1894091d4532SNeel Natu case IDT_SS: 1895091d4532SNeel Natu case IDT_GP: 1896091d4532SNeel Natu return (EXC_CONTRIBUTORY); 1897091d4532SNeel Natu default: 1898091d4532SNeel Natu return (EXC_BENIGN); 1899091d4532SNeel Natu } 1900091d4532SNeel Natu } 1901091d4532SNeel Natu 1902091d4532SNeel Natu static int 1903091d4532SNeel Natu nested_fault(struct vm *vm, int vcpuid, uint64_t info1, uint64_t info2, 1904091d4532SNeel Natu uint64_t *retinfo) 1905091d4532SNeel Natu { 1906091d4532SNeel Natu enum exc_class exc1, exc2; 1907091d4532SNeel Natu int type1, vector1; 1908091d4532SNeel Natu 1909091d4532SNeel Natu KASSERT(info1 & VM_INTINFO_VALID, ("info1 %#lx is not valid", info1)); 1910091d4532SNeel Natu KASSERT(info2 & VM_INTINFO_VALID, ("info2 %#lx is not valid", info2)); 1911091d4532SNeel Natu 1912091d4532SNeel Natu /* 1913091d4532SNeel Natu * If an exception occurs while attempting to call the double-fault 1914091d4532SNeel Natu * handler the processor enters shutdown mode (aka triple fault). 1915091d4532SNeel Natu */ 1916091d4532SNeel Natu type1 = info1 & VM_INTINFO_TYPE; 1917091d4532SNeel Natu vector1 = info1 & 0xff; 1918091d4532SNeel Natu if (type1 == VM_INTINFO_HWEXCEPTION && vector1 == IDT_DF) { 1919091d4532SNeel Natu VCPU_CTR2(vm, vcpuid, "triple fault: info1(%#lx), info2(%#lx)", 1920091d4532SNeel Natu info1, info2); 1921091d4532SNeel Natu vm_suspend(vm, VM_SUSPEND_TRIPLEFAULT); 1922091d4532SNeel Natu *retinfo = 0; 1923091d4532SNeel Natu return (0); 1924091d4532SNeel Natu } 1925091d4532SNeel Natu 1926091d4532SNeel Natu /* 1927091d4532SNeel Natu * Table 6-5 "Conditions for Generating a Double Fault", Intel SDM, Vol3 1928091d4532SNeel Natu */ 1929091d4532SNeel Natu exc1 = exception_class(info1); 1930091d4532SNeel Natu exc2 = exception_class(info2); 1931091d4532SNeel Natu if ((exc1 == EXC_CONTRIBUTORY && exc2 == EXC_CONTRIBUTORY) || 1932091d4532SNeel Natu (exc1 == EXC_PAGEFAULT && exc2 != EXC_BENIGN)) { 1933091d4532SNeel Natu /* Convert nested fault into a double fault. */ 1934091d4532SNeel Natu *retinfo = IDT_DF; 1935091d4532SNeel Natu *retinfo |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION; 1936091d4532SNeel Natu *retinfo |= VM_INTINFO_DEL_ERRCODE; 1937091d4532SNeel Natu } else { 1938091d4532SNeel Natu /* Handle exceptions serially */ 1939091d4532SNeel Natu *retinfo = info2; 1940091d4532SNeel Natu } 1941091d4532SNeel Natu return (1); 1942091d4532SNeel Natu } 1943091d4532SNeel Natu 1944091d4532SNeel Natu static uint64_t 1945091d4532SNeel Natu vcpu_exception_intinfo(struct vcpu *vcpu) 1946091d4532SNeel Natu { 1947091d4532SNeel Natu uint64_t info = 0; 1948091d4532SNeel Natu 1949091d4532SNeel Natu if (vcpu->exception_pending) { 1950c9c75df4SNeel Natu info = vcpu->exc_vector & 0xff; 1951091d4532SNeel Natu info |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION; 1952c9c75df4SNeel Natu if (vcpu->exc_errcode_valid) { 1953091d4532SNeel Natu info |= VM_INTINFO_DEL_ERRCODE; 1954c9c75df4SNeel Natu info |= (uint64_t)vcpu->exc_errcode << 32; 1955091d4532SNeel Natu } 1956091d4532SNeel Natu } 1957091d4532SNeel Natu return (info); 1958091d4532SNeel Natu } 1959091d4532SNeel Natu 1960091d4532SNeel Natu int 1961091d4532SNeel Natu vm_entry_intinfo(struct vm *vm, int vcpuid, uint64_t *retinfo) 1962091d4532SNeel Natu { 1963091d4532SNeel Natu struct vcpu *vcpu; 1964091d4532SNeel Natu uint64_t info1, info2; 1965091d4532SNeel Natu int valid; 1966091d4532SNeel Natu 1967a488c9c9SRodney W. Grimes KASSERT(vcpuid >= 0 && 1968a488c9c9SRodney W. Grimes vcpuid < vm->maxcpus, ("invalid vcpu %d", vcpuid)); 1969091d4532SNeel Natu 1970091d4532SNeel Natu vcpu = &vm->vcpu[vcpuid]; 1971091d4532SNeel Natu 1972091d4532SNeel Natu info1 = vcpu->exitintinfo; 1973091d4532SNeel Natu vcpu->exitintinfo = 0; 1974091d4532SNeel Natu 1975091d4532SNeel Natu info2 = 0; 1976091d4532SNeel Natu if (vcpu->exception_pending) { 1977091d4532SNeel Natu info2 = vcpu_exception_intinfo(vcpu); 1978091d4532SNeel Natu vcpu->exception_pending = 0; 1979091d4532SNeel Natu VCPU_CTR2(vm, vcpuid, "Exception %d delivered: %#lx", 1980c9c75df4SNeel Natu vcpu->exc_vector, info2); 1981091d4532SNeel Natu } 1982091d4532SNeel Natu 1983091d4532SNeel Natu if ((info1 & VM_INTINFO_VALID) && (info2 & VM_INTINFO_VALID)) { 1984091d4532SNeel Natu valid = nested_fault(vm, vcpuid, info1, info2, retinfo); 1985091d4532SNeel Natu } else if (info1 & VM_INTINFO_VALID) { 1986091d4532SNeel Natu *retinfo = info1; 1987091d4532SNeel Natu valid = 1; 1988091d4532SNeel Natu } else if (info2 & VM_INTINFO_VALID) { 1989091d4532SNeel Natu *retinfo = info2; 1990091d4532SNeel Natu valid = 1; 1991091d4532SNeel Natu } else { 1992091d4532SNeel Natu valid = 0; 1993091d4532SNeel Natu } 1994091d4532SNeel Natu 1995091d4532SNeel Natu if (valid) { 1996091d4532SNeel Natu VCPU_CTR4(vm, vcpuid, "%s: info1(%#lx), info2(%#lx), " 1997091d4532SNeel Natu "retinfo(%#lx)", __func__, info1, info2, *retinfo); 1998091d4532SNeel Natu } 1999091d4532SNeel Natu 2000091d4532SNeel Natu return (valid); 2001091d4532SNeel Natu } 2002091d4532SNeel Natu 2003091d4532SNeel Natu int 2004091d4532SNeel Natu vm_get_intinfo(struct vm *vm, int vcpuid, uint64_t *info1, uint64_t *info2) 2005091d4532SNeel Natu { 2006091d4532SNeel Natu struct vcpu *vcpu; 2007091d4532SNeel Natu 2008a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2009091d4532SNeel Natu return (EINVAL); 2010091d4532SNeel Natu 2011091d4532SNeel Natu vcpu = &vm->vcpu[vcpuid]; 2012091d4532SNeel Natu *info1 = vcpu->exitintinfo; 2013091d4532SNeel Natu *info2 = vcpu_exception_intinfo(vcpu); 2014091d4532SNeel Natu return (0); 2015091d4532SNeel Natu } 2016091d4532SNeel Natu 2017091d4532SNeel Natu int 2018c9c75df4SNeel Natu vm_inject_exception(struct vm *vm, int vcpuid, int vector, int errcode_valid, 2019c9c75df4SNeel Natu uint32_t errcode, int restart_instruction) 2020366f6083SPeter Grehan { 2021dc506506SNeel Natu struct vcpu *vcpu; 202247b9935dSNeel Natu uint64_t regval; 20232ce12423SNeel Natu int error; 2024dc506506SNeel Natu 2025a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2026366f6083SPeter Grehan return (EINVAL); 2027366f6083SPeter Grehan 2028c9c75df4SNeel Natu if (vector < 0 || vector >= 32) 2029366f6083SPeter Grehan return (EINVAL); 2030366f6083SPeter Grehan 2031091d4532SNeel Natu /* 2032091d4532SNeel Natu * A double fault exception should never be injected directly into 2033091d4532SNeel Natu * the guest. It is a derived exception that results from specific 2034091d4532SNeel Natu * combinations of nested faults. 2035091d4532SNeel Natu */ 2036c9c75df4SNeel Natu if (vector == IDT_DF) 2037091d4532SNeel Natu return (EINVAL); 2038091d4532SNeel Natu 2039dc506506SNeel Natu vcpu = &vm->vcpu[vcpuid]; 2040366f6083SPeter Grehan 2041dc506506SNeel Natu if (vcpu->exception_pending) { 2042dc506506SNeel Natu VCPU_CTR2(vm, vcpuid, "Unable to inject exception %d due to " 2043c9c75df4SNeel Natu "pending exception %d", vector, vcpu->exc_vector); 2044dc506506SNeel Natu return (EBUSY); 2045dc506506SNeel Natu } 2046dc506506SNeel Natu 204747b9935dSNeel Natu if (errcode_valid) { 204847b9935dSNeel Natu /* 204947b9935dSNeel Natu * Exceptions don't deliver an error code in real mode. 205047b9935dSNeel Natu */ 205147b9935dSNeel Natu error = vm_get_register(vm, vcpuid, VM_REG_GUEST_CR0, ®val); 205247b9935dSNeel Natu KASSERT(!error, ("%s: error %d getting CR0", __func__, error)); 205347b9935dSNeel Natu if (!(regval & CR0_PE)) 205447b9935dSNeel Natu errcode_valid = 0; 205547b9935dSNeel Natu } 205647b9935dSNeel Natu 20572ce12423SNeel Natu /* 20582ce12423SNeel Natu * From section 26.6.1 "Interruptibility State" in Intel SDM: 20592ce12423SNeel Natu * 20602ce12423SNeel Natu * Event blocking by "STI" or "MOV SS" is cleared after guest executes 20612ce12423SNeel Natu * one instruction or incurs an exception. 20622ce12423SNeel Natu */ 20632ce12423SNeel Natu error = vm_set_register(vm, vcpuid, VM_REG_GUEST_INTR_SHADOW, 0); 20642ce12423SNeel Natu KASSERT(error == 0, ("%s: error %d clearing interrupt shadow", 20652ce12423SNeel Natu __func__, error)); 20662ce12423SNeel Natu 2067c9c75df4SNeel Natu if (restart_instruction) 2068c9c75df4SNeel Natu vm_restart_instruction(vm, vcpuid); 2069c9c75df4SNeel Natu 2070dc506506SNeel Natu vcpu->exception_pending = 1; 2071c9c75df4SNeel Natu vcpu->exc_vector = vector; 2072c9c75df4SNeel Natu vcpu->exc_errcode = errcode; 2073c9c75df4SNeel Natu vcpu->exc_errcode_valid = errcode_valid; 2074c9c75df4SNeel Natu VCPU_CTR1(vm, vcpuid, "Exception %d pending", vector); 2075dc506506SNeel Natu return (0); 2076dc506506SNeel Natu } 2077dc506506SNeel Natu 2078d37f2adbSNeel Natu void 2079d37f2adbSNeel Natu vm_inject_fault(void *vmarg, int vcpuid, int vector, int errcode_valid, 2080d37f2adbSNeel Natu int errcode) 2081dc506506SNeel Natu { 2082d37f2adbSNeel Natu struct vm *vm; 2083c9c75df4SNeel Natu int error, restart_instruction; 2084dc506506SNeel Natu 2085d37f2adbSNeel Natu vm = vmarg; 2086c9c75df4SNeel Natu restart_instruction = 1; 2087d37f2adbSNeel Natu 2088c9c75df4SNeel Natu error = vm_inject_exception(vm, vcpuid, vector, errcode_valid, 2089c9c75df4SNeel Natu errcode, restart_instruction); 2090dc506506SNeel Natu KASSERT(error == 0, ("vm_inject_exception error %d", error)); 2091dc506506SNeel Natu } 2092dc506506SNeel Natu 2093dc506506SNeel Natu void 2094d37f2adbSNeel Natu vm_inject_pf(void *vmarg, int vcpuid, int error_code, uint64_t cr2) 2095fd949af6SNeel Natu { 2096d37f2adbSNeel Natu struct vm *vm; 209737a723a5SNeel Natu int error; 209837a723a5SNeel Natu 2099d37f2adbSNeel Natu vm = vmarg; 210037a723a5SNeel Natu VCPU_CTR2(vm, vcpuid, "Injecting page fault: error_code %#x, cr2 %#lx", 210137a723a5SNeel Natu error_code, cr2); 210237a723a5SNeel Natu 210337a723a5SNeel Natu error = vm_set_register(vm, vcpuid, VM_REG_GUEST_CR2, cr2); 210437a723a5SNeel Natu KASSERT(error == 0, ("vm_set_register(cr2) error %d", error)); 2105fd949af6SNeel Natu 2106d37f2adbSNeel Natu vm_inject_fault(vm, vcpuid, IDT_PF, 1, error_code); 2107366f6083SPeter Grehan } 2108366f6083SPeter Grehan 210961592433SNeel Natu static VMM_STAT(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); 2110366f6083SPeter Grehan 2111f352ff0cSNeel Natu int 2112f352ff0cSNeel Natu vm_inject_nmi(struct vm *vm, int vcpuid) 2113f352ff0cSNeel Natu { 2114f352ff0cSNeel Natu struct vcpu *vcpu; 2115f352ff0cSNeel Natu 2116a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2117366f6083SPeter Grehan return (EINVAL); 2118366f6083SPeter Grehan 2119f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 2120f352ff0cSNeel Natu 2121f352ff0cSNeel Natu vcpu->nmi_pending = 1; 2122de5ea6b6SNeel Natu vcpu_notify_event(vm, vcpuid, false); 2123f352ff0cSNeel Natu return (0); 2124f352ff0cSNeel Natu } 2125f352ff0cSNeel Natu 2126f352ff0cSNeel Natu int 2127f352ff0cSNeel Natu vm_nmi_pending(struct vm *vm, int vcpuid) 2128f352ff0cSNeel Natu { 2129f352ff0cSNeel Natu struct vcpu *vcpu; 2130f352ff0cSNeel Natu 2131a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2132f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 2133f352ff0cSNeel Natu 2134f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 2135f352ff0cSNeel Natu 2136f352ff0cSNeel Natu return (vcpu->nmi_pending); 2137f352ff0cSNeel Natu } 2138f352ff0cSNeel Natu 2139f352ff0cSNeel Natu void 2140f352ff0cSNeel Natu vm_nmi_clear(struct vm *vm, int vcpuid) 2141f352ff0cSNeel Natu { 2142f352ff0cSNeel Natu struct vcpu *vcpu; 2143f352ff0cSNeel Natu 2144a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2145f352ff0cSNeel Natu panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 2146f352ff0cSNeel Natu 2147f352ff0cSNeel Natu vcpu = &vm->vcpu[vcpuid]; 2148f352ff0cSNeel Natu 2149f352ff0cSNeel Natu if (vcpu->nmi_pending == 0) 2150f352ff0cSNeel Natu panic("vm_nmi_clear: inconsistent nmi_pending state"); 2151f352ff0cSNeel Natu 2152f352ff0cSNeel Natu vcpu->nmi_pending = 0; 2153f352ff0cSNeel Natu vmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1); 2154366f6083SPeter Grehan } 2155366f6083SPeter Grehan 21560775fbb4STycho Nightingale static VMM_STAT(VCPU_EXTINT_COUNT, "number of ExtINTs delivered to vcpu"); 21570775fbb4STycho Nightingale 21580775fbb4STycho Nightingale int 21590775fbb4STycho Nightingale vm_inject_extint(struct vm *vm, int vcpuid) 21600775fbb4STycho Nightingale { 21610775fbb4STycho Nightingale struct vcpu *vcpu; 21620775fbb4STycho Nightingale 2163a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 21640775fbb4STycho Nightingale return (EINVAL); 21650775fbb4STycho Nightingale 21660775fbb4STycho Nightingale vcpu = &vm->vcpu[vcpuid]; 21670775fbb4STycho Nightingale 21680775fbb4STycho Nightingale vcpu->extint_pending = 1; 21690775fbb4STycho Nightingale vcpu_notify_event(vm, vcpuid, false); 21700775fbb4STycho Nightingale return (0); 21710775fbb4STycho Nightingale } 21720775fbb4STycho Nightingale 21730775fbb4STycho Nightingale int 21740775fbb4STycho Nightingale vm_extint_pending(struct vm *vm, int vcpuid) 21750775fbb4STycho Nightingale { 21760775fbb4STycho Nightingale struct vcpu *vcpu; 21770775fbb4STycho Nightingale 2178a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 21790775fbb4STycho Nightingale panic("vm_extint_pending: invalid vcpuid %d", vcpuid); 21800775fbb4STycho Nightingale 21810775fbb4STycho Nightingale vcpu = &vm->vcpu[vcpuid]; 21820775fbb4STycho Nightingale 21830775fbb4STycho Nightingale return (vcpu->extint_pending); 21840775fbb4STycho Nightingale } 21850775fbb4STycho Nightingale 21860775fbb4STycho Nightingale void 21870775fbb4STycho Nightingale vm_extint_clear(struct vm *vm, int vcpuid) 21880775fbb4STycho Nightingale { 21890775fbb4STycho Nightingale struct vcpu *vcpu; 21900775fbb4STycho Nightingale 2191a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 21920775fbb4STycho Nightingale panic("vm_extint_pending: invalid vcpuid %d", vcpuid); 21930775fbb4STycho Nightingale 21940775fbb4STycho Nightingale vcpu = &vm->vcpu[vcpuid]; 21950775fbb4STycho Nightingale 21960775fbb4STycho Nightingale if (vcpu->extint_pending == 0) 21970775fbb4STycho Nightingale panic("vm_extint_clear: inconsistent extint_pending state"); 21980775fbb4STycho Nightingale 21990775fbb4STycho Nightingale vcpu->extint_pending = 0; 22000775fbb4STycho Nightingale vmm_stat_incr(vm, vcpuid, VCPU_EXTINT_COUNT, 1); 22010775fbb4STycho Nightingale } 22020775fbb4STycho Nightingale 2203366f6083SPeter Grehan int 2204366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 2205366f6083SPeter Grehan { 2206a488c9c9SRodney W. Grimes if (vcpu < 0 || vcpu >= vm->maxcpus) 2207366f6083SPeter Grehan return (EINVAL); 2208366f6083SPeter Grehan 2209366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 2210366f6083SPeter Grehan return (EINVAL); 2211366f6083SPeter Grehan 2212366f6083SPeter Grehan return (VMGETCAP(vm->cookie, vcpu, type, retval)); 2213366f6083SPeter Grehan } 2214366f6083SPeter Grehan 2215366f6083SPeter Grehan int 2216366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val) 2217366f6083SPeter Grehan { 2218a488c9c9SRodney W. Grimes if (vcpu < 0 || vcpu >= vm->maxcpus) 2219366f6083SPeter Grehan return (EINVAL); 2220366f6083SPeter Grehan 2221366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 2222366f6083SPeter Grehan return (EINVAL); 2223366f6083SPeter Grehan 2224366f6083SPeter Grehan return (VMSETCAP(vm->cookie, vcpu, type, val)); 2225366f6083SPeter Grehan } 2226366f6083SPeter Grehan 2227366f6083SPeter Grehan struct vlapic * 2228366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu) 2229366f6083SPeter Grehan { 2230366f6083SPeter Grehan return (vm->vcpu[cpu].vlapic); 2231366f6083SPeter Grehan } 2232366f6083SPeter Grehan 2233565bbb86SNeel Natu struct vioapic * 2234565bbb86SNeel Natu vm_ioapic(struct vm *vm) 2235565bbb86SNeel Natu { 2236565bbb86SNeel Natu 2237565bbb86SNeel Natu return (vm->vioapic); 2238565bbb86SNeel Natu } 2239565bbb86SNeel Natu 224008e3ff32SNeel Natu struct vhpet * 224108e3ff32SNeel Natu vm_hpet(struct vm *vm) 224208e3ff32SNeel Natu { 224308e3ff32SNeel Natu 224408e3ff32SNeel Natu return (vm->vhpet); 224508e3ff32SNeel Natu } 224608e3ff32SNeel Natu 2247490d56c5SEd Maste bool 2248366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 2249366f6083SPeter Grehan { 2250490d56c5SEd Maste int b, f, i, n, s; 2251366f6083SPeter Grehan char *val, *cp, *cp2; 2252490d56c5SEd Maste bool found; 2253366f6083SPeter Grehan 2254366f6083SPeter Grehan /* 225507044a96SNeel Natu * XXX 225607044a96SNeel Natu * The length of an environment variable is limited to 128 bytes which 225707044a96SNeel Natu * puts an upper limit on the number of passthru devices that may be 225807044a96SNeel Natu * specified using a single environment variable. 225907044a96SNeel Natu * 226007044a96SNeel Natu * Work around this by scanning multiple environment variable 226107044a96SNeel Natu * names instead of a single one - yuck! 2262366f6083SPeter Grehan */ 226307044a96SNeel Natu const char *names[] = { "pptdevs", "pptdevs2", "pptdevs3", NULL }; 226407044a96SNeel Natu 226507044a96SNeel Natu /* set pptdevs="1/2/3 4/5/6 7/8/9 10/11/12" */ 2266490d56c5SEd Maste found = false; 226707044a96SNeel Natu for (i = 0; names[i] != NULL && !found; i++) { 22682be111bfSDavide Italiano cp = val = kern_getenv(names[i]); 2269366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 2270366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 2271366f6083SPeter Grehan *cp2 = '\0'; 2272366f6083SPeter Grehan 2273366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 2274366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 2275490d56c5SEd Maste found = true; 2276366f6083SPeter Grehan break; 2277366f6083SPeter Grehan } 2278366f6083SPeter Grehan 2279366f6083SPeter Grehan if (cp2 != NULL) 2280366f6083SPeter Grehan *cp2++ = ' '; 2281366f6083SPeter Grehan 2282366f6083SPeter Grehan cp = cp2; 2283366f6083SPeter Grehan } 2284366f6083SPeter Grehan freeenv(val); 228507044a96SNeel Natu } 2286366f6083SPeter Grehan return (found); 2287366f6083SPeter Grehan } 2288366f6083SPeter Grehan 2289366f6083SPeter Grehan void * 2290366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 2291366f6083SPeter Grehan { 2292366f6083SPeter Grehan 2293366f6083SPeter Grehan return (vm->iommu); 2294366f6083SPeter Grehan } 2295366f6083SPeter Grehan 229675dd3366SNeel Natu int 2297f80330a8SNeel Natu vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state newstate, 2298f80330a8SNeel Natu bool from_idle) 2299366f6083SPeter Grehan { 230075dd3366SNeel Natu int error; 2301366f6083SPeter Grehan struct vcpu *vcpu; 2302366f6083SPeter Grehan 2303a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2304366f6083SPeter Grehan panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 2305366f6083SPeter Grehan 2306366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 2307366f6083SPeter Grehan 230875dd3366SNeel Natu vcpu_lock(vcpu); 2309248e6799SNeel Natu error = vcpu_set_state_locked(vm, vcpuid, newstate, from_idle); 231075dd3366SNeel Natu vcpu_unlock(vcpu); 231175dd3366SNeel Natu 231275dd3366SNeel Natu return (error); 231375dd3366SNeel Natu } 231475dd3366SNeel Natu 231575dd3366SNeel Natu enum vcpu_state 2316d3c11f40SPeter Grehan vcpu_get_state(struct vm *vm, int vcpuid, int *hostcpu) 2317366f6083SPeter Grehan { 2318366f6083SPeter Grehan struct vcpu *vcpu; 231975dd3366SNeel Natu enum vcpu_state state; 2320366f6083SPeter Grehan 2321a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2322366f6083SPeter Grehan panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 2323366f6083SPeter Grehan 2324366f6083SPeter Grehan vcpu = &vm->vcpu[vcpuid]; 2325366f6083SPeter Grehan 232675dd3366SNeel Natu vcpu_lock(vcpu); 232775dd3366SNeel Natu state = vcpu->state; 2328d3c11f40SPeter Grehan if (hostcpu != NULL) 2329d3c11f40SPeter Grehan *hostcpu = vcpu->hostcpu; 233075dd3366SNeel Natu vcpu_unlock(vcpu); 2331366f6083SPeter Grehan 233275dd3366SNeel Natu return (state); 2333366f6083SPeter Grehan } 2334366f6083SPeter Grehan 233595ebc360SNeel Natu int 2336366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid) 2337366f6083SPeter Grehan { 2338366f6083SPeter Grehan 2339a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 234095ebc360SNeel Natu return (EINVAL); 234195ebc360SNeel Natu 234295ebc360SNeel Natu if (CPU_ISSET(vcpuid, &vm->active_cpus)) 234395ebc360SNeel Natu return (EBUSY); 234422d822c6SNeel Natu 234522d822c6SNeel Natu VCPU_CTR0(vm, vcpuid, "activated"); 234622d822c6SNeel Natu CPU_SET_ATOMIC(vcpuid, &vm->active_cpus); 234795ebc360SNeel Natu return (0); 2348366f6083SPeter Grehan } 2349366f6083SPeter Grehan 2350fc276d92SJohn Baldwin int 2351fc276d92SJohn Baldwin vm_suspend_cpu(struct vm *vm, int vcpuid) 2352fc276d92SJohn Baldwin { 2353fc276d92SJohn Baldwin int i; 2354fc276d92SJohn Baldwin 2355a488c9c9SRodney W. Grimes if (vcpuid < -1 || vcpuid >= vm->maxcpus) 2356fc276d92SJohn Baldwin return (EINVAL); 2357fc276d92SJohn Baldwin 2358fc276d92SJohn Baldwin if (vcpuid == -1) { 2359fc276d92SJohn Baldwin vm->debug_cpus = vm->active_cpus; 2360a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 2361fc276d92SJohn Baldwin if (CPU_ISSET(i, &vm->active_cpus)) 2362fc276d92SJohn Baldwin vcpu_notify_event(vm, i, false); 2363fc276d92SJohn Baldwin } 2364fc276d92SJohn Baldwin } else { 2365fc276d92SJohn Baldwin if (!CPU_ISSET(vcpuid, &vm->active_cpus)) 2366fc276d92SJohn Baldwin return (EINVAL); 2367fc276d92SJohn Baldwin 2368fc276d92SJohn Baldwin CPU_SET_ATOMIC(vcpuid, &vm->debug_cpus); 2369fc276d92SJohn Baldwin vcpu_notify_event(vm, vcpuid, false); 2370fc276d92SJohn Baldwin } 2371fc276d92SJohn Baldwin return (0); 2372fc276d92SJohn Baldwin } 2373fc276d92SJohn Baldwin 2374fc276d92SJohn Baldwin int 2375fc276d92SJohn Baldwin vm_resume_cpu(struct vm *vm, int vcpuid) 2376fc276d92SJohn Baldwin { 2377fc276d92SJohn Baldwin 2378a488c9c9SRodney W. Grimes if (vcpuid < -1 || vcpuid >= vm->maxcpus) 2379fc276d92SJohn Baldwin return (EINVAL); 2380fc276d92SJohn Baldwin 2381fc276d92SJohn Baldwin if (vcpuid == -1) { 2382fc276d92SJohn Baldwin CPU_ZERO(&vm->debug_cpus); 2383fc276d92SJohn Baldwin } else { 2384fc276d92SJohn Baldwin if (!CPU_ISSET(vcpuid, &vm->debug_cpus)) 2385fc276d92SJohn Baldwin return (EINVAL); 2386fc276d92SJohn Baldwin 2387fc276d92SJohn Baldwin CPU_CLR_ATOMIC(vcpuid, &vm->debug_cpus); 2388fc276d92SJohn Baldwin } 2389fc276d92SJohn Baldwin return (0); 2390fc276d92SJohn Baldwin } 2391fc276d92SJohn Baldwin 2392fc276d92SJohn Baldwin int 2393fc276d92SJohn Baldwin vcpu_debugged(struct vm *vm, int vcpuid) 2394fc276d92SJohn Baldwin { 2395fc276d92SJohn Baldwin 2396fc276d92SJohn Baldwin return (CPU_ISSET(vcpuid, &vm->debug_cpus)); 2397fc276d92SJohn Baldwin } 2398fc276d92SJohn Baldwin 2399a5615c90SPeter Grehan cpuset_t 2400366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 2401366f6083SPeter Grehan { 2402366f6083SPeter Grehan 2403366f6083SPeter Grehan return (vm->active_cpus); 2404366f6083SPeter Grehan } 2405366f6083SPeter Grehan 240695ebc360SNeel Natu cpuset_t 2407fc276d92SJohn Baldwin vm_debug_cpus(struct vm *vm) 2408fc276d92SJohn Baldwin { 2409fc276d92SJohn Baldwin 2410fc276d92SJohn Baldwin return (vm->debug_cpus); 2411fc276d92SJohn Baldwin } 2412fc276d92SJohn Baldwin 2413fc276d92SJohn Baldwin cpuset_t 241495ebc360SNeel Natu vm_suspended_cpus(struct vm *vm) 241595ebc360SNeel Natu { 241695ebc360SNeel Natu 241795ebc360SNeel Natu return (vm->suspended_cpus); 241895ebc360SNeel Natu } 241995ebc360SNeel Natu 2420366f6083SPeter Grehan void * 2421366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid) 2422366f6083SPeter Grehan { 2423366f6083SPeter Grehan 2424366f6083SPeter Grehan return (vm->vcpu[vcpuid].stats); 2425366f6083SPeter Grehan } 2426e9027382SNeel Natu 2427e9027382SNeel Natu int 2428e9027382SNeel Natu vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) 2429e9027382SNeel Natu { 2430a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2431e9027382SNeel Natu return (EINVAL); 2432e9027382SNeel Natu 2433e9027382SNeel Natu *state = vm->vcpu[vcpuid].x2apic_state; 2434e9027382SNeel Natu 2435e9027382SNeel Natu return (0); 2436e9027382SNeel Natu } 2437e9027382SNeel Natu 2438e9027382SNeel Natu int 2439e9027382SNeel Natu vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 2440e9027382SNeel Natu { 2441a488c9c9SRodney W. Grimes if (vcpuid < 0 || vcpuid >= vm->maxcpus) 2442e9027382SNeel Natu return (EINVAL); 2443e9027382SNeel Natu 24443f23d3caSNeel Natu if (state >= X2APIC_STATE_LAST) 2445e9027382SNeel Natu return (EINVAL); 2446e9027382SNeel Natu 2447e9027382SNeel Natu vm->vcpu[vcpuid].x2apic_state = state; 2448e9027382SNeel Natu 244973820fb0SNeel Natu vlapic_set_x2apic_state(vm, vcpuid, state); 245073820fb0SNeel Natu 2451e9027382SNeel Natu return (0); 2452e9027382SNeel Natu } 245375dd3366SNeel Natu 245422821874SNeel Natu /* 245522821874SNeel Natu * This function is called to ensure that a vcpu "sees" a pending event 245622821874SNeel Natu * as soon as possible: 245722821874SNeel Natu * - If the vcpu thread is sleeping then it is woken up. 245822821874SNeel Natu * - If the vcpu is running on a different host_cpu then an IPI will be directed 245922821874SNeel Natu * to the host_cpu to cause the vcpu to trap into the hypervisor. 246022821874SNeel Natu */ 2461248e6799SNeel Natu static void 2462248e6799SNeel Natu vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr) 246375dd3366SNeel Natu { 246475dd3366SNeel Natu int hostcpu; 246575dd3366SNeel Natu 246675dd3366SNeel Natu hostcpu = vcpu->hostcpu; 2467ef39d7e9SNeel Natu if (vcpu->state == VCPU_RUNNING) { 2468ef39d7e9SNeel Natu KASSERT(hostcpu != NOCPU, ("vcpu running on invalid hostcpu")); 2469de5ea6b6SNeel Natu if (hostcpu != curcpu) { 2470ef39d7e9SNeel Natu if (lapic_intr) { 2471add611fdSNeel Natu vlapic_post_intr(vcpu->vlapic, hostcpu, 2472add611fdSNeel Natu vmm_ipinum); 2473ef39d7e9SNeel Natu } else { 247475dd3366SNeel Natu ipi_cpu(hostcpu, vmm_ipinum); 247575dd3366SNeel Natu } 2476ef39d7e9SNeel Natu } else { 2477ef39d7e9SNeel Natu /* 2478ef39d7e9SNeel Natu * If the 'vcpu' is running on 'curcpu' then it must 2479ef39d7e9SNeel Natu * be sending a notification to itself (e.g. SELF_IPI). 2480ef39d7e9SNeel Natu * The pending event will be picked up when the vcpu 2481ef39d7e9SNeel Natu * transitions back to guest context. 2482ef39d7e9SNeel Natu */ 2483ef39d7e9SNeel Natu } 2484ef39d7e9SNeel Natu } else { 2485ef39d7e9SNeel Natu KASSERT(hostcpu == NOCPU, ("vcpu state %d not consistent " 2486ef39d7e9SNeel Natu "with hostcpu %d", vcpu->state, hostcpu)); 2487366f6083SPeter Grehan if (vcpu->state == VCPU_SLEEPING) 2488366f6083SPeter Grehan wakeup_one(vcpu); 2489366f6083SPeter Grehan } 2490248e6799SNeel Natu } 2491248e6799SNeel Natu 2492248e6799SNeel Natu void 2493248e6799SNeel Natu vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr) 2494248e6799SNeel Natu { 2495248e6799SNeel Natu struct vcpu *vcpu = &vm->vcpu[vcpuid]; 2496248e6799SNeel Natu 2497248e6799SNeel Natu vcpu_lock(vcpu); 2498248e6799SNeel Natu vcpu_notify_event_locked(vcpu, lapic_intr); 2499f76fc5d4SNeel Natu vcpu_unlock(vcpu); 2500f76fc5d4SNeel Natu } 2501318224bbSNeel Natu 2502318224bbSNeel Natu struct vmspace * 2503318224bbSNeel Natu vm_get_vmspace(struct vm *vm) 2504318224bbSNeel Natu { 2505318224bbSNeel Natu 2506318224bbSNeel Natu return (vm->vmspace); 2507318224bbSNeel Natu } 2508565bbb86SNeel Natu 2509565bbb86SNeel Natu int 2510565bbb86SNeel Natu vm_apicid2vcpuid(struct vm *vm, int apicid) 2511565bbb86SNeel Natu { 2512565bbb86SNeel Natu /* 2513565bbb86SNeel Natu * XXX apic id is assumed to be numerically identical to vcpu id 2514565bbb86SNeel Natu */ 2515565bbb86SNeel Natu return (apicid); 2516565bbb86SNeel Natu } 25175b8a8cd1SNeel Natu 2518b837daddSKonstantin Belousov int 25195b8a8cd1SNeel Natu vm_smp_rendezvous(struct vm *vm, int vcpuid, cpuset_t dest, 25205b8a8cd1SNeel Natu vm_rendezvous_func_t func, void *arg) 25215b8a8cd1SNeel Natu { 2522b837daddSKonstantin Belousov int error, i; 2523970955e4SNeel Natu 25245b8a8cd1SNeel Natu /* 25255b8a8cd1SNeel Natu * Enforce that this function is called without any locks 25265b8a8cd1SNeel Natu */ 25275b8a8cd1SNeel Natu WITNESS_WARN(WARN_PANIC, NULL, "vm_smp_rendezvous"); 2528a488c9c9SRodney W. Grimes KASSERT(vcpuid == -1 || (vcpuid >= 0 && vcpuid < vm->maxcpus), 25295b8a8cd1SNeel Natu ("vm_smp_rendezvous: invalid vcpuid %d", vcpuid)); 25305b8a8cd1SNeel Natu 25315b8a8cd1SNeel Natu restart: 25325b8a8cd1SNeel Natu mtx_lock(&vm->rendezvous_mtx); 25335b8a8cd1SNeel Natu if (vm->rendezvous_func != NULL) { 25345b8a8cd1SNeel Natu /* 25355b8a8cd1SNeel Natu * If a rendezvous is already in progress then we need to 25365b8a8cd1SNeel Natu * call the rendezvous handler in case this 'vcpuid' is one 25375b8a8cd1SNeel Natu * of the targets of the rendezvous. 25385b8a8cd1SNeel Natu */ 25395b8a8cd1SNeel Natu RENDEZVOUS_CTR0(vm, vcpuid, "Rendezvous already in progress"); 25405b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 2541b837daddSKonstantin Belousov error = vm_handle_rendezvous(vm, vcpuid); 2542b837daddSKonstantin Belousov if (error != 0) 2543b837daddSKonstantin Belousov return (error); 25445b8a8cd1SNeel Natu goto restart; 25455b8a8cd1SNeel Natu } 25465b8a8cd1SNeel Natu KASSERT(vm->rendezvous_func == NULL, ("vm_smp_rendezvous: previous " 25475b8a8cd1SNeel Natu "rendezvous is still in progress")); 25485b8a8cd1SNeel Natu 25495b8a8cd1SNeel Natu RENDEZVOUS_CTR0(vm, vcpuid, "Initiating rendezvous"); 25505b8a8cd1SNeel Natu vm->rendezvous_req_cpus = dest; 25515b8a8cd1SNeel Natu CPU_ZERO(&vm->rendezvous_done_cpus); 25525b8a8cd1SNeel Natu vm->rendezvous_arg = arg; 2553869dbab7SAndriy Gapon vm->rendezvous_func = func; 25545b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 25555b8a8cd1SNeel Natu 2556970955e4SNeel Natu /* 2557970955e4SNeel Natu * Wake up any sleeping vcpus and trigger a VM-exit in any running 2558970955e4SNeel Natu * vcpus so they handle the rendezvous as soon as possible. 2559970955e4SNeel Natu */ 2560a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 2561970955e4SNeel Natu if (CPU_ISSET(i, &dest)) 2562970955e4SNeel Natu vcpu_notify_event(vm, i, false); 2563970955e4SNeel Natu } 2564970955e4SNeel Natu 2565b837daddSKonstantin Belousov return (vm_handle_rendezvous(vm, vcpuid)); 25665b8a8cd1SNeel Natu } 2567762fd208STycho Nightingale 2568762fd208STycho Nightingale struct vatpic * 2569762fd208STycho Nightingale vm_atpic(struct vm *vm) 2570762fd208STycho Nightingale { 2571762fd208STycho Nightingale return (vm->vatpic); 2572762fd208STycho Nightingale } 2573e883c9bbSTycho Nightingale 2574e883c9bbSTycho Nightingale struct vatpit * 2575e883c9bbSTycho Nightingale vm_atpit(struct vm *vm) 2576e883c9bbSTycho Nightingale { 2577e883c9bbSTycho Nightingale return (vm->vatpit); 2578e883c9bbSTycho Nightingale } 2579d17b5104SNeel Natu 2580160ef77aSNeel Natu struct vpmtmr * 2581160ef77aSNeel Natu vm_pmtmr(struct vm *vm) 2582160ef77aSNeel Natu { 2583160ef77aSNeel Natu 2584160ef77aSNeel Natu return (vm->vpmtmr); 2585160ef77aSNeel Natu } 2586160ef77aSNeel Natu 25870dafa5cdSNeel Natu struct vrtc * 25880dafa5cdSNeel Natu vm_rtc(struct vm *vm) 25890dafa5cdSNeel Natu { 25900dafa5cdSNeel Natu 25910dafa5cdSNeel Natu return (vm->vrtc); 25920dafa5cdSNeel Natu } 25930dafa5cdSNeel Natu 2594d17b5104SNeel Natu enum vm_reg_name 2595d17b5104SNeel Natu vm_segment_name(int seg) 2596d17b5104SNeel Natu { 2597d17b5104SNeel Natu static enum vm_reg_name seg_names[] = { 2598d17b5104SNeel Natu VM_REG_GUEST_ES, 2599d17b5104SNeel Natu VM_REG_GUEST_CS, 2600d17b5104SNeel Natu VM_REG_GUEST_SS, 2601d17b5104SNeel Natu VM_REG_GUEST_DS, 2602d17b5104SNeel Natu VM_REG_GUEST_FS, 2603d17b5104SNeel Natu VM_REG_GUEST_GS 2604d17b5104SNeel Natu }; 2605d17b5104SNeel Natu 2606d17b5104SNeel Natu KASSERT(seg >= 0 && seg < nitems(seg_names), 2607d17b5104SNeel Natu ("%s: invalid segment encoding %d", __func__, seg)); 2608d17b5104SNeel Natu return (seg_names[seg]); 2609d17b5104SNeel Natu } 2610cf1d80d8SPeter Grehan 2611d665d229SNeel Natu void 2612d665d229SNeel Natu vm_copy_teardown(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo, 2613d665d229SNeel Natu int num_copyinfo) 2614d665d229SNeel Natu { 2615d665d229SNeel Natu int idx; 2616d665d229SNeel Natu 2617d665d229SNeel Natu for (idx = 0; idx < num_copyinfo; idx++) { 2618d665d229SNeel Natu if (copyinfo[idx].cookie != NULL) 2619d665d229SNeel Natu vm_gpa_release(copyinfo[idx].cookie); 2620d665d229SNeel Natu } 2621d665d229SNeel Natu bzero(copyinfo, num_copyinfo * sizeof(struct vm_copyinfo)); 2622d665d229SNeel Natu } 2623d665d229SNeel Natu 2624d665d229SNeel Natu int 2625d665d229SNeel Natu vm_copy_setup(struct vm *vm, int vcpuid, struct vm_guest_paging *paging, 2626d665d229SNeel Natu uint64_t gla, size_t len, int prot, struct vm_copyinfo *copyinfo, 26279c4d5478SNeel Natu int num_copyinfo, int *fault) 2628d665d229SNeel Natu { 2629d665d229SNeel Natu int error, idx, nused; 2630d665d229SNeel Natu size_t n, off, remaining; 2631d665d229SNeel Natu void *hva, *cookie; 2632d665d229SNeel Natu uint64_t gpa; 2633d665d229SNeel Natu 2634d665d229SNeel Natu bzero(copyinfo, sizeof(struct vm_copyinfo) * num_copyinfo); 2635d665d229SNeel Natu 2636d665d229SNeel Natu nused = 0; 2637d665d229SNeel Natu remaining = len; 2638d665d229SNeel Natu while (remaining > 0) { 2639d665d229SNeel Natu KASSERT(nused < num_copyinfo, ("insufficient vm_copyinfo")); 26409c4d5478SNeel Natu error = vm_gla2gpa(vm, vcpuid, paging, gla, prot, &gpa, fault); 26419c4d5478SNeel Natu if (error || *fault) 2642d665d229SNeel Natu return (error); 2643d665d229SNeel Natu off = gpa & PAGE_MASK; 2644d665d229SNeel Natu n = min(remaining, PAGE_SIZE - off); 2645d665d229SNeel Natu copyinfo[nused].gpa = gpa; 2646d665d229SNeel Natu copyinfo[nused].len = n; 2647d665d229SNeel Natu remaining -= n; 2648d665d229SNeel Natu gla += n; 2649d665d229SNeel Natu nused++; 2650d665d229SNeel Natu } 2651d665d229SNeel Natu 2652d665d229SNeel Natu for (idx = 0; idx < nused; idx++) { 26539b1aa8d6SNeel Natu hva = vm_gpa_hold(vm, vcpuid, copyinfo[idx].gpa, 26549b1aa8d6SNeel Natu copyinfo[idx].len, prot, &cookie); 2655d665d229SNeel Natu if (hva == NULL) 2656d665d229SNeel Natu break; 2657d665d229SNeel Natu copyinfo[idx].hva = hva; 2658d665d229SNeel Natu copyinfo[idx].cookie = cookie; 2659d665d229SNeel Natu } 2660d665d229SNeel Natu 2661d665d229SNeel Natu if (idx != nused) { 2662d665d229SNeel Natu vm_copy_teardown(vm, vcpuid, copyinfo, num_copyinfo); 26639c4d5478SNeel Natu return (EFAULT); 2664d665d229SNeel Natu } else { 26659c4d5478SNeel Natu *fault = 0; 2666d665d229SNeel Natu return (0); 2667d665d229SNeel Natu } 2668d665d229SNeel Natu } 2669d665d229SNeel Natu 2670d665d229SNeel Natu void 2671d665d229SNeel Natu vm_copyin(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo, void *kaddr, 2672d665d229SNeel Natu size_t len) 2673d665d229SNeel Natu { 2674d665d229SNeel Natu char *dst; 2675d665d229SNeel Natu int idx; 2676d665d229SNeel Natu 2677d665d229SNeel Natu dst = kaddr; 2678d665d229SNeel Natu idx = 0; 2679d665d229SNeel Natu while (len > 0) { 2680d665d229SNeel Natu bcopy(copyinfo[idx].hva, dst, copyinfo[idx].len); 2681d665d229SNeel Natu len -= copyinfo[idx].len; 2682d665d229SNeel Natu dst += copyinfo[idx].len; 2683d665d229SNeel Natu idx++; 2684d665d229SNeel Natu } 2685d665d229SNeel Natu } 2686d665d229SNeel Natu 2687d665d229SNeel Natu void 2688d665d229SNeel Natu vm_copyout(struct vm *vm, int vcpuid, const void *kaddr, 2689d665d229SNeel Natu struct vm_copyinfo *copyinfo, size_t len) 2690d665d229SNeel Natu { 2691d665d229SNeel Natu const char *src; 2692d665d229SNeel Natu int idx; 2693d665d229SNeel Natu 2694d665d229SNeel Natu src = kaddr; 2695d665d229SNeel Natu idx = 0; 2696d665d229SNeel Natu while (len > 0) { 2697d665d229SNeel Natu bcopy(src, copyinfo[idx].hva, copyinfo[idx].len); 2698d665d229SNeel Natu len -= copyinfo[idx].len; 2699d665d229SNeel Natu src += copyinfo[idx].len; 2700d665d229SNeel Natu idx++; 2701d665d229SNeel Natu } 2702d665d229SNeel Natu } 2703cf1d80d8SPeter Grehan 2704cf1d80d8SPeter Grehan /* 2705cf1d80d8SPeter Grehan * Return the amount of in-use and wired memory for the VM. Since 2706cf1d80d8SPeter Grehan * these are global stats, only return the values with for vCPU 0 2707cf1d80d8SPeter Grehan */ 2708cf1d80d8SPeter Grehan VMM_STAT_DECLARE(VMM_MEM_RESIDENT); 2709cf1d80d8SPeter Grehan VMM_STAT_DECLARE(VMM_MEM_WIRED); 2710cf1d80d8SPeter Grehan 2711cf1d80d8SPeter Grehan static void 2712cf1d80d8SPeter Grehan vm_get_rescnt(struct vm *vm, int vcpu, struct vmm_stat_type *stat) 2713cf1d80d8SPeter Grehan { 2714cf1d80d8SPeter Grehan 2715cf1d80d8SPeter Grehan if (vcpu == 0) { 2716cf1d80d8SPeter Grehan vmm_stat_set(vm, vcpu, VMM_MEM_RESIDENT, 2717cf1d80d8SPeter Grehan PAGE_SIZE * vmspace_resident_count(vm->vmspace)); 2718cf1d80d8SPeter Grehan } 2719cf1d80d8SPeter Grehan } 2720cf1d80d8SPeter Grehan 2721cf1d80d8SPeter Grehan static void 2722cf1d80d8SPeter Grehan vm_get_wiredcnt(struct vm *vm, int vcpu, struct vmm_stat_type *stat) 2723cf1d80d8SPeter Grehan { 2724cf1d80d8SPeter Grehan 2725cf1d80d8SPeter Grehan if (vcpu == 0) { 2726cf1d80d8SPeter Grehan vmm_stat_set(vm, vcpu, VMM_MEM_WIRED, 2727cf1d80d8SPeter Grehan PAGE_SIZE * pmap_wired_count(vmspace_pmap(vm->vmspace))); 2728cf1d80d8SPeter Grehan } 2729cf1d80d8SPeter Grehan } 2730cf1d80d8SPeter Grehan 2731cf1d80d8SPeter Grehan VMM_STAT_FUNC(VMM_MEM_RESIDENT, "Resident memory", vm_get_rescnt); 2732cf1d80d8SPeter Grehan VMM_STAT_FUNC(VMM_MEM_WIRED, "Wired memory", vm_get_wiredcnt); 2733