1366f6083SPeter Grehan /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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 29483d953aSJohn Baldwin #include "opt_bhyve_snapshot.h" 30483d953aSJohn Baldwin 31366f6083SPeter Grehan #include <sys/param.h> 3238f1b189SPeter Grehan #include <sys/systm.h> 33366f6083SPeter Grehan #include <sys/kernel.h> 34366f6083SPeter Grehan #include <sys/module.h> 35366f6083SPeter Grehan #include <sys/sysctl.h> 36366f6083SPeter Grehan #include <sys/malloc.h> 37366f6083SPeter Grehan #include <sys/pcpu.h> 38366f6083SPeter Grehan #include <sys/lock.h> 39366f6083SPeter Grehan #include <sys/mutex.h> 40366f6083SPeter Grehan #include <sys/proc.h> 41318224bbSNeel Natu #include <sys/rwlock.h> 42366f6083SPeter Grehan #include <sys/sched.h> 43366f6083SPeter Grehan #include <sys/smp.h> 4467b69e76SJohn Baldwin #include <sys/sx.h> 45483d953aSJohn Baldwin #include <sys/vnode.h> 46366f6083SPeter Grehan 47366f6083SPeter Grehan #include <vm/vm.h> 483c48106aSKonstantin Belousov #include <vm/vm_param.h> 493c48106aSKonstantin Belousov #include <vm/vm_extern.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> 54483d953aSJohn Baldwin #include <vm/vm_pager.h> 55483d953aSJohn Baldwin #include <vm/vm_kern.h> 56483d953aSJohn Baldwin #include <vm/vnode_pager.h> 57483d953aSJohn Baldwin #include <vm/swap_pager.h> 58483d953aSJohn Baldwin #include <vm/uma.h> 59366f6083SPeter Grehan 6063e62d39SJohn Baldwin #include <machine/cpu.h> 61366f6083SPeter Grehan #include <machine/pcb.h> 6275dd3366SNeel Natu #include <machine/smp.h> 63bd50262fSKonstantin Belousov #include <machine/md_var.h> 641c052192SNeel Natu #include <x86/psl.h> 6534a6b2d6SJohn Baldwin #include <x86/apicreg.h> 6615add60dSPeter Grehan #include <x86/ifunc.h> 67366f6083SPeter Grehan 68366f6083SPeter Grehan #include <machine/vmm.h> 69e813a873SNeel Natu #include <machine/vmm_instruction_emul.h> 70483d953aSJohn Baldwin #include <machine/vmm_snapshot.h> 71565bbb86SNeel Natu 72b9ef152bSMark Johnston #include <dev/vmm/vmm_dev.h> 733ccb0233SMark Johnston #include <dev/vmm/vmm_ktr.h> 74*c76c2a19SMark Johnston #include <dev/vmm/vmm_mem.h> 753ccb0233SMark Johnston 76d17b5104SNeel Natu #include "vmm_ioport.h" 77b01c2033SNeel Natu #include "vmm_host.h" 78366f6083SPeter Grehan #include "vmm_mem.h" 79366f6083SPeter Grehan #include "vmm_util.h" 80762fd208STycho Nightingale #include "vatpic.h" 81e883c9bbSTycho Nightingale #include "vatpit.h" 8208e3ff32SNeel Natu #include "vhpet.h" 83565bbb86SNeel Natu #include "vioapic.h" 84366f6083SPeter Grehan #include "vlapic.h" 85160ef77aSNeel Natu #include "vpmtmr.h" 860dafa5cdSNeel Natu #include "vrtc.h" 87366f6083SPeter Grehan #include "vmm_stat.h" 88f76fc5d4SNeel Natu #include "vmm_lapic.h" 89366f6083SPeter Grehan 90366f6083SPeter Grehan #include "io/ppt.h" 91366f6083SPeter Grehan #include "io/iommu.h" 92366f6083SPeter Grehan 93366f6083SPeter Grehan struct vlapic; 94366f6083SPeter Grehan 955fcf252fSNeel Natu /* 965fcf252fSNeel Natu * Initialization: 975fcf252fSNeel Natu * (a) allocated when vcpu is created 985fcf252fSNeel Natu * (i) initialized when vcpu is created and when it is reinitialized 995fcf252fSNeel Natu * (o) initialized the first time the vcpu is created 1005fcf252fSNeel Natu * (x) initialized before use 1015fcf252fSNeel Natu */ 102366f6083SPeter Grehan struct vcpu { 1035fcf252fSNeel Natu struct mtx mtx; /* (o) protects 'state' and 'hostcpu' */ 1045fcf252fSNeel Natu enum vcpu_state state; /* (o) vcpu state */ 105950af9ffSJohn Baldwin int vcpuid; /* (o) */ 1065fcf252fSNeel Natu int hostcpu; /* (o) vcpu's host cpu */ 107248e6799SNeel Natu int reqidle; /* (i) request vcpu to idle */ 108950af9ffSJohn Baldwin struct vm *vm; /* (o) */ 1091aa51504SJohn Baldwin void *cookie; /* (i) cpu-specific data */ 1105fcf252fSNeel Natu struct vlapic *vlapic; /* (i) APIC device model */ 1115fcf252fSNeel Natu enum x2apic_state x2apic_state; /* (i) APIC mode */ 112091d4532SNeel Natu uint64_t exitintinfo; /* (i) events pending at VM exit */ 1135fcf252fSNeel Natu int nmi_pending; /* (i) NMI pending */ 1145fcf252fSNeel Natu int extint_pending; /* (i) INTR pending */ 1155fcf252fSNeel Natu int exception_pending; /* (i) exception pending */ 116c9c75df4SNeel Natu int exc_vector; /* (x) exception collateral */ 117c9c75df4SNeel Natu int exc_errcode_valid; 118c9c75df4SNeel Natu uint32_t exc_errcode; 1195fcf252fSNeel Natu struct savefpu *guestfpu; /* (a,i) guest fpu state */ 1205fcf252fSNeel Natu uint64_t guest_xcr0; /* (i) guest %xcr0 register */ 1215fcf252fSNeel Natu void *stats; /* (a,i) statistics */ 1225fcf252fSNeel Natu struct vm_exit exitinfo; /* (x) exit reason and collateral */ 123e17eca32SMark Johnston cpuset_t exitinfo_cpuset; /* (x) storage for vmexit handlers */ 124d087a399SNeel Natu uint64_t nextrip; /* (x) next instruction to execute */ 125483d953aSJohn Baldwin uint64_t tsc_offset; /* (o) TSC offsetting */ 126366f6083SPeter Grehan }; 127366f6083SPeter Grehan 128f76fc5d4SNeel Natu #define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_SPIN) 12908ebb360SJohn Baldwin #define vcpu_lock_destroy(v) mtx_destroy(&((v)->mtx)) 130f76fc5d4SNeel Natu #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) 131f76fc5d4SNeel Natu #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) 132318224bbSNeel Natu #define vcpu_assert_locked(v) mtx_assert(&((v)->mtx), MA_OWNED) 13375dd3366SNeel Natu 134366f6083SPeter Grehan /* 1355fcf252fSNeel Natu * Initialization: 1365fcf252fSNeel Natu * (o) initialized the first time the VM is created 1375fcf252fSNeel Natu * (i) initialized when VM is created and when it is reinitialized 1385fcf252fSNeel Natu * (x) initialized before use 13967b69e76SJohn Baldwin * 14067b69e76SJohn Baldwin * Locking: 14167b69e76SJohn Baldwin * [m] mem_segs_lock 14267b69e76SJohn Baldwin * [r] rendezvous_mtx 14367b69e76SJohn Baldwin * [v] reads require one frozen vcpu, writes require freezing all vcpus 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 */ 156c0f35dbfSJohn Baldwin cpuset_t startup_cpus; /* (i) [r] waiting for startup */ 1575fcf252fSNeel Natu int suspend; /* (i) stop VM execution */ 15898568a00SJohn Baldwin bool dying; /* (o) is dying */ 1595fcf252fSNeel Natu volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */ 1605fcf252fSNeel Natu volatile cpuset_t halted_cpus; /* (x) cpus in a hard halt */ 16167b69e76SJohn Baldwin cpuset_t rendezvous_req_cpus; /* (x) [r] rendezvous requested */ 16267b69e76SJohn Baldwin cpuset_t rendezvous_done_cpus; /* (x) [r] rendezvous finished */ 16367b69e76SJohn Baldwin void *rendezvous_arg; /* (x) [r] rendezvous func/arg */ 1645b8a8cd1SNeel Natu vm_rendezvous_func_t rendezvous_func; 1655fcf252fSNeel Natu struct mtx rendezvous_mtx; /* (o) rendezvous lock */ 1665fcf252fSNeel Natu struct vmspace *vmspace; /* (o) guest's address space */ 167*c76c2a19SMark Johnston struct vm_mem mem; /* (i) [m+v] guest memory */ 168df95cc76SKa Ho Ng char name[VM_MAX_NAMELEN+1]; /* (o) virtual machine name */ 169ee98f99dSJohn Baldwin struct vcpu **vcpu; /* (o) guest vcpus */ 17001d822d3SRodney W. Grimes /* The following describe the vm cpu topology */ 17101d822d3SRodney W. Grimes uint16_t sockets; /* (o) num of sockets */ 17201d822d3SRodney W. Grimes uint16_t cores; /* (o) num of cores/socket */ 17301d822d3SRodney W. Grimes uint16_t threads; /* (o) num of threads/core */ 17401d822d3SRodney W. Grimes uint16_t maxcpus; /* (o) max pluggable cpus */ 17598568a00SJohn Baldwin struct sx vcpus_init_lock; /* (o) */ 176366f6083SPeter Grehan }; 177366f6083SPeter Grehan 178950af9ffSJohn Baldwin #define VMM_CTR0(vcpu, format) \ 179950af9ffSJohn Baldwin VCPU_CTR0((vcpu)->vm, (vcpu)->vcpuid, format) 180950af9ffSJohn Baldwin 181950af9ffSJohn Baldwin #define VMM_CTR1(vcpu, format, p1) \ 182950af9ffSJohn Baldwin VCPU_CTR1((vcpu)->vm, (vcpu)->vcpuid, format, p1) 183950af9ffSJohn Baldwin 184950af9ffSJohn Baldwin #define VMM_CTR2(vcpu, format, p1, p2) \ 185950af9ffSJohn Baldwin VCPU_CTR2((vcpu)->vm, (vcpu)->vcpuid, format, p1, p2) 186950af9ffSJohn Baldwin 187950af9ffSJohn Baldwin #define VMM_CTR3(vcpu, format, p1, p2, p3) \ 188950af9ffSJohn Baldwin VCPU_CTR3((vcpu)->vm, (vcpu)->vcpuid, format, p1, p2, p3) 189950af9ffSJohn Baldwin 190950af9ffSJohn Baldwin #define VMM_CTR4(vcpu, format, p1, p2, p3, p4) \ 191950af9ffSJohn Baldwin VCPU_CTR4((vcpu)->vm, (vcpu)->vcpuid, format, p1, p2, p3, p4) 192950af9ffSJohn Baldwin 193d5408b1dSNeel Natu static int vmm_initialized; 194d5408b1dSNeel Natu 19515add60dSPeter Grehan static void vmmops_panic(void); 196366f6083SPeter Grehan 19715add60dSPeter Grehan static void 19815add60dSPeter Grehan vmmops_panic(void) 19915add60dSPeter Grehan { 20015add60dSPeter Grehan panic("vmm_ops func called when !vmm_is_intel() && !vmm_is_svm()"); 20115add60dSPeter Grehan } 20215add60dSPeter Grehan 20315add60dSPeter Grehan #define DEFINE_VMMOPS_IFUNC(ret_type, opname, args) \ 20415add60dSPeter Grehan DEFINE_IFUNC(static, ret_type, vmmops_##opname, args) \ 20515add60dSPeter Grehan { \ 20615add60dSPeter Grehan if (vmm_is_intel()) \ 20715add60dSPeter Grehan return (vmm_ops_intel.opname); \ 20815add60dSPeter Grehan else if (vmm_is_svm()) \ 20915add60dSPeter Grehan return (vmm_ops_amd.opname); \ 21015add60dSPeter Grehan else \ 21115add60dSPeter Grehan return ((ret_type (*)args)vmmops_panic); \ 21215add60dSPeter Grehan } 21315add60dSPeter Grehan 21415add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(int, modinit, (int ipinum)) 21515add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(int, modcleanup, (void)) 2160b32ef71SJoshua Rogers DEFINE_VMMOPS_IFUNC(void, modsuspend, (void)) 21715add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(void, modresume, (void)) 21815add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(void *, init, (struct vm *vm, struct pmap *pmap)) 219869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, run, (void *vcpui, register_t rip, struct pmap *pmap, 220869c8d19SJohn Baldwin struct vm_eventinfo *info)) 22115add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(void, cleanup, (void *vmi)) 222950af9ffSJohn Baldwin DEFINE_VMMOPS_IFUNC(void *, vcpu_init, (void *vmi, struct vcpu *vcpu, 223950af9ffSJohn Baldwin int vcpu_id)) 224869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(void, vcpu_cleanup, (void *vcpui)) 225869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, getreg, (void *vcpui, int num, uint64_t *retval)) 226869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, setreg, (void *vcpui, int num, uint64_t val)) 227869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, getdesc, (void *vcpui, int num, struct seg_desc *desc)) 228869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, setdesc, (void *vcpui, int num, struct seg_desc *desc)) 229869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, getcap, (void *vcpui, int num, int *retval)) 230869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, setcap, (void *vcpui, int num, int val)) 23115add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(struct vmspace *, vmspace_alloc, (vm_offset_t min, 23215add60dSPeter Grehan vm_offset_t max)) 23315add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(void, vmspace_free, (struct vmspace *vmspace)) 234869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(struct vlapic *, vlapic_init, (void *vcpui)) 235869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(void, vlapic_cleanup, (struct vlapic *vlapic)) 236483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 237869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, vcpu_snapshot, (void *vcpui, 238869c8d19SJohn Baldwin struct vm_snapshot_meta *meta)) 239869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, restore_tsc, (void *vcpui, uint64_t now)) 240483d953aSJohn Baldwin #endif 241366f6083SPeter Grehan 2426ac73777STycho Nightingale SDT_PROVIDER_DEFINE(vmm); 2436ac73777STycho Nightingale 244366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 245366f6083SPeter Grehan 246366f6083SPeter Grehan /* statistics */ 24761592433SNeel Natu static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 248366f6083SPeter Grehan 249b40598c5SPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 250b40598c5SPawel Biernacki NULL); 251add611fdSNeel Natu 252055fc2cbSNeel Natu /* 253055fc2cbSNeel Natu * Halt the guest if all vcpus are executing a HLT instruction with 254055fc2cbSNeel Natu * interrupts disabled. 255055fc2cbSNeel Natu */ 256055fc2cbSNeel Natu static int halt_detection_enabled = 1; 257055fc2cbSNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, halt_detection, CTLFLAG_RDTUN, 258055fc2cbSNeel Natu &halt_detection_enabled, 0, 259055fc2cbSNeel Natu "Halt VM if all vcpus execute HLT with interrupts disabled"); 260055fc2cbSNeel Natu 261978f3da1SAndriy Gapon static int vmm_ipinum; 262add611fdSNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, ipinum, CTLFLAG_RD, &vmm_ipinum, 0, 263add611fdSNeel Natu "IPI vector used for vcpu notifications"); 264add611fdSNeel Natu 265b0538143SNeel Natu static int trace_guest_exceptions; 266b0538143SNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, trace_guest_exceptions, CTLFLAG_RDTUN, 267b0538143SNeel Natu &trace_guest_exceptions, 0, 268b0538143SNeel Natu "Trap into hypervisor on all guest exceptions and reflect them back"); 269b0538143SNeel Natu 2703ba952e1SCorvin Köhne static int trap_wbinvd; 2713ba952e1SCorvin Köhne SYSCTL_INT(_hw_vmm, OID_AUTO, trap_wbinvd, CTLFLAG_RDTUN, &trap_wbinvd, 0, 2723ba952e1SCorvin Köhne "WBINVD triggers a VM-exit"); 2733ba952e1SCorvin Köhne 274ee98f99dSJohn Baldwin u_int vm_maxcpu; 275ee98f99dSJohn Baldwin SYSCTL_UINT(_hw_vmm, OID_AUTO, maxcpu, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, 276ee98f99dSJohn Baldwin &vm_maxcpu, 0, "Maximum number of vCPUs"); 277ee98f99dSJohn Baldwin 278248e6799SNeel Natu static void vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr); 279248e6799SNeel Natu 28093e81baaSMark Johnston /* global statistics */ 28193e81baaSMark Johnston VMM_STAT(VCPU_MIGRATIONS, "vcpu migration across host cpus"); 28293e81baaSMark Johnston VMM_STAT(VMEXIT_COUNT, "total number of vm exits"); 28393e81baaSMark Johnston VMM_STAT(VMEXIT_EXTINT, "vm exits due to external interrupt"); 28493e81baaSMark Johnston VMM_STAT(VMEXIT_HLT, "number of times hlt was intercepted"); 28593e81baaSMark Johnston VMM_STAT(VMEXIT_CR_ACCESS, "number of times %cr access was intercepted"); 28693e81baaSMark Johnston VMM_STAT(VMEXIT_RDMSR, "number of times rdmsr was intercepted"); 28793e81baaSMark Johnston VMM_STAT(VMEXIT_WRMSR, "number of times wrmsr was intercepted"); 28893e81baaSMark Johnston VMM_STAT(VMEXIT_MTRAP, "number of monitor trap exits"); 28993e81baaSMark Johnston VMM_STAT(VMEXIT_PAUSE, "number of times pause was intercepted"); 29093e81baaSMark Johnston VMM_STAT(VMEXIT_INTR_WINDOW, "vm exits due to interrupt window opening"); 29193e81baaSMark Johnston VMM_STAT(VMEXIT_NMI_WINDOW, "vm exits due to nmi window opening"); 29293e81baaSMark Johnston VMM_STAT(VMEXIT_INOUT, "number of times in/out was intercepted"); 29393e81baaSMark Johnston VMM_STAT(VMEXIT_CPUID, "number of times cpuid was intercepted"); 29493e81baaSMark Johnston VMM_STAT(VMEXIT_NESTED_FAULT, "vm exits due to nested page fault"); 29593e81baaSMark Johnston VMM_STAT(VMEXIT_INST_EMUL, "vm exits for instruction emulation"); 29693e81baaSMark Johnston VMM_STAT(VMEXIT_UNKNOWN, "number of vm exits for unknown reason"); 29793e81baaSMark Johnston VMM_STAT(VMEXIT_ASTPENDING, "number of times astpending at exit"); 29893e81baaSMark Johnston VMM_STAT(VMEXIT_REQIDLE, "number of times idle requested at exit"); 29993e81baaSMark Johnston VMM_STAT(VMEXIT_USERSPACE, "number of vm exits handled in userspace"); 30093e81baaSMark Johnston VMM_STAT(VMEXIT_RENDEZVOUS, "number of times rendezvous pending at exit"); 30193e81baaSMark Johnston VMM_STAT(VMEXIT_EXCEPTION, "number of vm exits due to exceptions"); 30293e81baaSMark Johnston 303ee98f99dSJohn Baldwin /* 304ee98f99dSJohn Baldwin * Upper limit on vm_maxcpu. Limited by use of uint16_t types for CPU 305ee98f99dSJohn Baldwin * counts as well as range of vpid values for VT-x and by the capacity 306ee98f99dSJohn Baldwin * of cpuset_t masks. The call to new_unrhdr() in vpid_init() in 307ee98f99dSJohn Baldwin * vmx.c requires 'vm_maxcpu + 1 <= 0xffff', hence the '- 1' below. 308ee98f99dSJohn Baldwin */ 309ee98f99dSJohn Baldwin #define VM_MAXCPU MIN(0xffff - 1, CPU_SETSIZE) 310ee98f99dSJohn Baldwin 311248e6799SNeel Natu #ifdef KTR 312248e6799SNeel Natu static const char * 313248e6799SNeel Natu vcpu_state2str(enum vcpu_state state) 314248e6799SNeel Natu { 315248e6799SNeel Natu 316248e6799SNeel Natu switch (state) { 317248e6799SNeel Natu case VCPU_IDLE: 318248e6799SNeel Natu return ("idle"); 319248e6799SNeel Natu case VCPU_FROZEN: 320248e6799SNeel Natu return ("frozen"); 321248e6799SNeel Natu case VCPU_RUNNING: 322248e6799SNeel Natu return ("running"); 323248e6799SNeel Natu case VCPU_SLEEPING: 324248e6799SNeel Natu return ("sleeping"); 325248e6799SNeel Natu default: 326248e6799SNeel Natu return ("unknown"); 327248e6799SNeel Natu } 328248e6799SNeel Natu } 329248e6799SNeel Natu #endif 330248e6799SNeel Natu 331366f6083SPeter Grehan static void 33298568a00SJohn Baldwin vcpu_cleanup(struct vcpu *vcpu, bool destroy) 333366f6083SPeter Grehan { 334869c8d19SJohn Baldwin vmmops_vlapic_cleanup(vcpu->vlapic); 335869c8d19SJohn Baldwin vmmops_vcpu_cleanup(vcpu->cookie); 3361aa51504SJohn Baldwin vcpu->cookie = NULL; 3375fcf252fSNeel Natu if (destroy) { 338366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 33938f1b189SPeter Grehan fpu_save_area_free(vcpu->guestfpu); 34008ebb360SJohn Baldwin vcpu_lock_destroy(vcpu); 341af3b48e1SJohn Baldwin free(vcpu, M_VM); 342366f6083SPeter Grehan } 3435fcf252fSNeel Natu } 344366f6083SPeter Grehan 34598568a00SJohn Baldwin static struct vcpu * 34698568a00SJohn Baldwin vcpu_alloc(struct vm *vm, int vcpu_id) 347366f6083SPeter Grehan { 348366f6083SPeter Grehan struct vcpu *vcpu; 349366f6083SPeter Grehan 350a488c9c9SRodney W. Grimes KASSERT(vcpu_id >= 0 && vcpu_id < vm->maxcpus, 3515fcf252fSNeel Natu ("vcpu_init: invalid vcpu %d", vcpu_id)); 3525fcf252fSNeel Natu 35398568a00SJohn Baldwin vcpu = malloc(sizeof(*vcpu), M_VM, M_WAITOK | M_ZERO); 35475dd3366SNeel Natu vcpu_lock_init(vcpu); 3555fcf252fSNeel Natu vcpu->state = VCPU_IDLE; 35675dd3366SNeel Natu vcpu->hostcpu = NOCPU; 357950af9ffSJohn Baldwin vcpu->vcpuid = vcpu_id; 358950af9ffSJohn Baldwin vcpu->vm = vm; 3595fcf252fSNeel Natu vcpu->guestfpu = fpu_save_area_alloc(); 3605fcf252fSNeel Natu vcpu->stats = vmm_stat_alloc(); 361483d953aSJohn Baldwin vcpu->tsc_offset = 0; 36298568a00SJohn Baldwin return (vcpu); 3635fcf252fSNeel Natu } 3645fcf252fSNeel Natu 36598568a00SJohn Baldwin static void 36698568a00SJohn Baldwin vcpu_init(struct vcpu *vcpu) 36798568a00SJohn Baldwin { 36898568a00SJohn Baldwin vcpu->cookie = vmmops_vcpu_init(vcpu->vm->cookie, vcpu, vcpu->vcpuid); 369869c8d19SJohn Baldwin vcpu->vlapic = vmmops_vlapic_init(vcpu->cookie); 3703f0f4b15SJohn Baldwin vm_set_x2apic_state(vcpu, X2APIC_DISABLED); 371248e6799SNeel Natu vcpu->reqidle = 0; 372091d4532SNeel Natu vcpu->exitintinfo = 0; 3735fcf252fSNeel Natu vcpu->nmi_pending = 0; 3745fcf252fSNeel Natu vcpu->extint_pending = 0; 3755fcf252fSNeel Natu vcpu->exception_pending = 0; 376abb023fbSJohn Baldwin vcpu->guest_xcr0 = XFEATURE_ENABLED_X87; 37738f1b189SPeter Grehan fpu_save_area_reset(vcpu->guestfpu); 3785fcf252fSNeel Natu vmm_stat_init(vcpu->stats); 379366f6083SPeter Grehan } 380366f6083SPeter Grehan 381b0538143SNeel Natu int 38280cb5d84SJohn Baldwin vcpu_trace_exceptions(struct vcpu *vcpu) 383b0538143SNeel Natu { 384b0538143SNeel Natu 385b0538143SNeel Natu return (trace_guest_exceptions); 386b0538143SNeel Natu } 387b0538143SNeel Natu 3883ba952e1SCorvin Köhne int 38980cb5d84SJohn Baldwin vcpu_trap_wbinvd(struct vcpu *vcpu) 3903ba952e1SCorvin Köhne { 3913ba952e1SCorvin Köhne return (trap_wbinvd); 3923ba952e1SCorvin Köhne } 3933ba952e1SCorvin Köhne 39498ed632cSNeel Natu struct vm_exit * 39580cb5d84SJohn Baldwin vm_exitinfo(struct vcpu *vcpu) 39698ed632cSNeel Natu { 39798ed632cSNeel Natu return (&vcpu->exitinfo); 39898ed632cSNeel Natu } 39998ed632cSNeel Natu 400e17eca32SMark Johnston cpuset_t * 401e17eca32SMark Johnston vm_exitinfo_cpuset(struct vcpu *vcpu) 402e17eca32SMark Johnston { 403e17eca32SMark Johnston return (&vcpu->exitinfo_cpuset); 404e17eca32SMark Johnston } 405e17eca32SMark Johnston 406366f6083SPeter Grehan static int 407366f6083SPeter Grehan vmm_init(void) 408366f6083SPeter Grehan { 40915add60dSPeter Grehan if (!vmm_is_hw_supported()) 41015add60dSPeter Grehan return (ENXIO); 41115add60dSPeter Grehan 412ee98f99dSJohn Baldwin vm_maxcpu = mp_ncpus; 413ee98f99dSJohn Baldwin TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu); 414ee98f99dSJohn Baldwin 415ee98f99dSJohn Baldwin if (vm_maxcpu > VM_MAXCPU) { 416ee98f99dSJohn Baldwin printf("vmm: vm_maxcpu clamped to %u\n", VM_MAXCPU); 417ee98f99dSJohn Baldwin vm_maxcpu = VM_MAXCPU; 418ee98f99dSJohn Baldwin } 419ee98f99dSJohn Baldwin if (vm_maxcpu == 0) 420ee98f99dSJohn Baldwin vm_maxcpu = 1; 421ee98f99dSJohn Baldwin 422b01c2033SNeel Natu vmm_host_state_init(); 423add611fdSNeel Natu 424bd50262fSKonstantin Belousov vmm_ipinum = lapic_ipi_alloc(pti ? &IDTVEC(justreturn1_pti) : 425bd50262fSKonstantin Belousov &IDTVEC(justreturn)); 42618a2b08eSNeel Natu if (vmm_ipinum < 0) 427add611fdSNeel Natu vmm_ipinum = IPI_AST; 428366f6083SPeter Grehan 4290b32ef71SJoshua Rogers vmm_suspend_p = vmmops_modsuspend; 43015add60dSPeter Grehan vmm_resume_p = vmmops_modresume; 431366f6083SPeter Grehan 43215add60dSPeter Grehan return (vmmops_modinit(vmm_ipinum)); 433366f6083SPeter Grehan } 434366f6083SPeter Grehan 435366f6083SPeter Grehan static int 436366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 437366f6083SPeter Grehan { 438366f6083SPeter Grehan int error; 439366f6083SPeter Grehan 440366f6083SPeter Grehan switch (what) { 441366f6083SPeter Grehan case MOD_LOAD: 44215add60dSPeter Grehan if (vmm_is_hw_supported()) { 443a97f683fSMark Johnston error = vmmdev_init(); 444a97f683fSMark Johnston if (error != 0) 445a97f683fSMark Johnston break; 446366f6083SPeter Grehan error = vmm_init(); 447d5408b1dSNeel Natu if (error == 0) 448d5408b1dSNeel Natu vmm_initialized = 1; 4494a46ece6SMark Johnston else 4504a46ece6SMark Johnston (void)vmmdev_cleanup(); 45115add60dSPeter Grehan } else { 45215add60dSPeter Grehan error = ENXIO; 45315add60dSPeter Grehan } 454366f6083SPeter Grehan break; 455366f6083SPeter Grehan case MOD_UNLOAD: 45615add60dSPeter Grehan if (vmm_is_hw_supported()) { 457cdc5b9e7SNeel Natu error = vmmdev_cleanup(); 458cdc5b9e7SNeel Natu if (error == 0) { 4590b32ef71SJoshua Rogers vmm_suspend_p = NULL; 46063e62d39SJohn Baldwin vmm_resume_p = NULL; 461366f6083SPeter Grehan iommu_cleanup(); 462add611fdSNeel Natu if (vmm_ipinum != IPI_AST) 46318a2b08eSNeel Natu lapic_ipi_free(vmm_ipinum); 46415add60dSPeter Grehan error = vmmops_modcleanup(); 46581ef6611SPeter Grehan /* 46681ef6611SPeter Grehan * Something bad happened - prevent new 46781ef6611SPeter Grehan * VMs from being created 46881ef6611SPeter Grehan */ 46981ef6611SPeter Grehan if (error) 470d5408b1dSNeel Natu vmm_initialized = 0; 47181ef6611SPeter Grehan } 47215add60dSPeter Grehan } else { 47315add60dSPeter Grehan error = 0; 47415add60dSPeter Grehan } 475366f6083SPeter Grehan break; 476366f6083SPeter Grehan default: 477366f6083SPeter Grehan error = 0; 478366f6083SPeter Grehan break; 479366f6083SPeter Grehan } 480366f6083SPeter Grehan return (error); 481366f6083SPeter Grehan } 482366f6083SPeter Grehan 483366f6083SPeter Grehan static moduledata_t vmm_kmod = { 484366f6083SPeter Grehan "vmm", 485366f6083SPeter Grehan vmm_handler, 486366f6083SPeter Grehan NULL 487366f6083SPeter Grehan }; 488366f6083SPeter Grehan 489366f6083SPeter Grehan /* 490e3f0800bSNeel Natu * vmm initialization has the following dependencies: 491e3f0800bSNeel Natu * 492e3f0800bSNeel Natu * - VT-x initialization requires smp_rendezvous() and therefore must happen 493e3f0800bSNeel Natu * after SMP is fully functional (after SI_SUB_SMP). 494d7023078SMark Johnston * - vmm device initialization requires an initialized devfs. 495366f6083SPeter Grehan */ 496d7023078SMark Johnston DECLARE_MODULE(vmm, vmm_kmod, MAX(SI_SUB_SMP, SI_SUB_DEVFS) + 1, SI_ORDER_ANY); 497366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 498366f6083SPeter Grehan 4995fcf252fSNeel Natu static void 5005fcf252fSNeel Natu vm_init(struct vm *vm, bool create) 5015fcf252fSNeel Natu { 50215add60dSPeter Grehan vm->cookie = vmmops_init(vm, vmspace_pmap(vm->vmspace)); 5035fcf252fSNeel Natu vm->iommu = NULL; 5045fcf252fSNeel Natu vm->vioapic = vioapic_init(vm); 5055fcf252fSNeel Natu vm->vhpet = vhpet_init(vm); 5065fcf252fSNeel Natu vm->vatpic = vatpic_init(vm); 5075fcf252fSNeel Natu vm->vatpit = vatpit_init(vm); 508160ef77aSNeel Natu vm->vpmtmr = vpmtmr_init(vm); 5090dafa5cdSNeel Natu if (create) 5100dafa5cdSNeel Natu vm->vrtc = vrtc_init(vm); 5115fcf252fSNeel Natu 5125fcf252fSNeel Natu CPU_ZERO(&vm->active_cpus); 513fc276d92SJohn Baldwin CPU_ZERO(&vm->debug_cpus); 514c0f35dbfSJohn Baldwin CPU_ZERO(&vm->startup_cpus); 5155fcf252fSNeel Natu 5165fcf252fSNeel Natu vm->suspend = 0; 5175fcf252fSNeel Natu CPU_ZERO(&vm->suspended_cpus); 5185fcf252fSNeel Natu 51998568a00SJohn Baldwin if (!create) { 52098568a00SJohn Baldwin for (int i = 0; i < vm->maxcpus; i++) { 52198568a00SJohn Baldwin if (vm->vcpu[i] != NULL) 52298568a00SJohn Baldwin vcpu_init(vm->vcpu[i]); 52398568a00SJohn Baldwin } 52498568a00SJohn Baldwin } 52598568a00SJohn Baldwin } 52698568a00SJohn Baldwin 52798568a00SJohn Baldwin void 52898568a00SJohn Baldwin vm_disable_vcpu_creation(struct vm *vm) 52998568a00SJohn Baldwin { 53098568a00SJohn Baldwin sx_xlock(&vm->vcpus_init_lock); 53198568a00SJohn Baldwin vm->dying = true; 53298568a00SJohn Baldwin sx_xunlock(&vm->vcpus_init_lock); 53398568a00SJohn Baldwin } 53498568a00SJohn Baldwin 53598568a00SJohn Baldwin struct vcpu * 53698568a00SJohn Baldwin vm_alloc_vcpu(struct vm *vm, int vcpuid) 53798568a00SJohn Baldwin { 53898568a00SJohn Baldwin struct vcpu *vcpu; 53998568a00SJohn Baldwin 54098568a00SJohn Baldwin if (vcpuid < 0 || vcpuid >= vm_get_maxcpus(vm)) 54198568a00SJohn Baldwin return (NULL); 54298568a00SJohn Baldwin 54372ae04c7SRuslan Bukin vcpu = (struct vcpu *) 54472ae04c7SRuslan Bukin atomic_load_acq_ptr((uintptr_t *)&vm->vcpu[vcpuid]); 54598568a00SJohn Baldwin if (__predict_true(vcpu != NULL)) 54698568a00SJohn Baldwin return (vcpu); 54798568a00SJohn Baldwin 54898568a00SJohn Baldwin sx_xlock(&vm->vcpus_init_lock); 54998568a00SJohn Baldwin vcpu = vm->vcpu[vcpuid]; 55098568a00SJohn Baldwin if (vcpu == NULL && !vm->dying) { 55198568a00SJohn Baldwin vcpu = vcpu_alloc(vm, vcpuid); 55298568a00SJohn Baldwin vcpu_init(vcpu); 55398568a00SJohn Baldwin 55498568a00SJohn Baldwin /* 55598568a00SJohn Baldwin * Ensure vCPU is fully created before updating pointer 55698568a00SJohn Baldwin * to permit unlocked reads above. 55798568a00SJohn Baldwin */ 55898568a00SJohn Baldwin atomic_store_rel_ptr((uintptr_t *)&vm->vcpu[vcpuid], 55998568a00SJohn Baldwin (uintptr_t)vcpu); 56098568a00SJohn Baldwin } 56198568a00SJohn Baldwin sx_xunlock(&vm->vcpus_init_lock); 56298568a00SJohn Baldwin return (vcpu); 56398568a00SJohn Baldwin } 56498568a00SJohn Baldwin 56598568a00SJohn Baldwin void 56698568a00SJohn Baldwin vm_slock_vcpus(struct vm *vm) 56798568a00SJohn Baldwin { 56898568a00SJohn Baldwin sx_slock(&vm->vcpus_init_lock); 56998568a00SJohn Baldwin } 57098568a00SJohn Baldwin 57198568a00SJohn Baldwin void 57298568a00SJohn Baldwin vm_unlock_vcpus(struct vm *vm) 57398568a00SJohn Baldwin { 57498568a00SJohn Baldwin sx_unlock(&vm->vcpus_init_lock); 5755fcf252fSNeel Natu } 5765fcf252fSNeel Natu 57701d822d3SRodney W. Grimes /* 57801d822d3SRodney W. Grimes * The default CPU topology is a single thread per package. 57901d822d3SRodney W. Grimes */ 58001d822d3SRodney W. Grimes u_int cores_per_package = 1; 58101d822d3SRodney W. Grimes u_int threads_per_core = 1; 58201d822d3SRodney W. Grimes 583d5408b1dSNeel Natu int 584d5408b1dSNeel Natu vm_create(const char *name, struct vm **retvm) 585366f6083SPeter Grehan { 586366f6083SPeter Grehan struct vm *vm; 587318224bbSNeel Natu struct vmspace *vmspace; 588366f6083SPeter Grehan 589d5408b1dSNeel Natu /* 590d5408b1dSNeel Natu * If vmm.ko could not be successfully initialized then don't attempt 591d5408b1dSNeel Natu * to create the virtual machine. 592d5408b1dSNeel Natu */ 593d5408b1dSNeel Natu if (!vmm_initialized) 594d5408b1dSNeel Natu return (ENXIO); 595d5408b1dSNeel Natu 596df95cc76SKa Ho Ng if (name == NULL || strnlen(name, VM_MAX_NAMELEN + 1) == 597df95cc76SKa Ho Ng VM_MAX_NAMELEN + 1) 598d5408b1dSNeel Natu return (EINVAL); 599366f6083SPeter Grehan 6003c48106aSKonstantin Belousov vmspace = vmmops_vmspace_alloc(0, VM_MAXUSER_ADDRESS_LA48); 601318224bbSNeel Natu if (vmspace == NULL) 602318224bbSNeel Natu return (ENOMEM); 603318224bbSNeel Natu 604366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 605366f6083SPeter Grehan strcpy(vm->name, name); 60688c4b8d1SNeel Natu vm->vmspace = vmspace; 607*c76c2a19SMark Johnston vm_mem_init(&vm->mem); 6085b8a8cd1SNeel Natu mtx_init(&vm->rendezvous_mtx, "vm rendezvous lock", 0, MTX_DEF); 60998568a00SJohn Baldwin sx_init(&vm->vcpus_init_lock, "vm vcpus"); 610ee98f99dSJohn Baldwin vm->vcpu = malloc(sizeof(*vm->vcpu) * vm_maxcpu, M_VM, M_WAITOK | 611ee98f99dSJohn Baldwin M_ZERO); 612366f6083SPeter Grehan 61301d822d3SRodney W. Grimes vm->sockets = 1; 61401d822d3SRodney W. Grimes vm->cores = cores_per_package; /* XXX backwards compatibility */ 61501d822d3SRodney W. Grimes vm->threads = threads_per_core; /* XXX backwards compatibility */ 616ee98f99dSJohn Baldwin vm->maxcpus = vm_maxcpu; 61701d822d3SRodney W. Grimes 6185fcf252fSNeel Natu vm_init(vm, true); 619366f6083SPeter Grehan 620d5408b1dSNeel Natu *retvm = vm; 621d5408b1dSNeel Natu return (0); 622366f6083SPeter Grehan } 623366f6083SPeter Grehan 62401d822d3SRodney W. Grimes void 62501d822d3SRodney W. Grimes vm_get_topology(struct vm *vm, uint16_t *sockets, uint16_t *cores, 62601d822d3SRodney W. Grimes uint16_t *threads, uint16_t *maxcpus) 62701d822d3SRodney W. Grimes { 62801d822d3SRodney W. Grimes *sockets = vm->sockets; 62901d822d3SRodney W. Grimes *cores = vm->cores; 63001d822d3SRodney W. Grimes *threads = vm->threads; 63101d822d3SRodney W. Grimes *maxcpus = vm->maxcpus; 63201d822d3SRodney W. Grimes } 63301d822d3SRodney W. Grimes 634a488c9c9SRodney W. Grimes uint16_t 635a488c9c9SRodney W. Grimes vm_get_maxcpus(struct vm *vm) 636a488c9c9SRodney W. Grimes { 637a488c9c9SRodney W. Grimes return (vm->maxcpus); 638a488c9c9SRodney W. Grimes } 639a488c9c9SRodney W. Grimes 64001d822d3SRodney W. Grimes int 64101d822d3SRodney W. Grimes vm_set_topology(struct vm *vm, uint16_t sockets, uint16_t cores, 64298568a00SJohn Baldwin uint16_t threads, uint16_t maxcpus __unused) 64301d822d3SRodney W. Grimes { 64498568a00SJohn Baldwin /* Ignore maxcpus. */ 645a488c9c9SRodney W. Grimes if ((sockets * cores * threads) > vm->maxcpus) 64601d822d3SRodney W. Grimes return (EINVAL); 64701d822d3SRodney W. Grimes vm->sockets = sockets; 64801d822d3SRodney W. Grimes vm->cores = cores; 64901d822d3SRodney W. Grimes vm->threads = threads; 65001d822d3SRodney W. Grimes return(0); 65101d822d3SRodney W. Grimes } 65201d822d3SRodney W. Grimes 653f7d51510SNeel Natu static void 6545fcf252fSNeel Natu vm_cleanup(struct vm *vm, bool destroy) 655366f6083SPeter Grehan { 656c668e817SRobert Wing if (destroy) 657c668e817SRobert Wing vm_xlock_memsegs(vm); 658*c76c2a19SMark Johnston else 659*c76c2a19SMark Johnston vm_assert_memseg_xlocked(vm); 660c668e817SRobert Wing 661366f6083SPeter Grehan ppt_unassign_all(vm); 662366f6083SPeter Grehan 663318224bbSNeel Natu if (vm->iommu != NULL) 664318224bbSNeel Natu iommu_destroy_domain(vm->iommu); 665318224bbSNeel Natu 6660dafa5cdSNeel Natu if (destroy) 6670dafa5cdSNeel Natu vrtc_cleanup(vm->vrtc); 6680dafa5cdSNeel Natu else 6690dafa5cdSNeel Natu vrtc_reset(vm->vrtc); 670160ef77aSNeel Natu vpmtmr_cleanup(vm->vpmtmr); 671e883c9bbSTycho Nightingale vatpit_cleanup(vm->vatpit); 67208e3ff32SNeel Natu vhpet_cleanup(vm->vhpet); 673762fd208STycho Nightingale vatpic_cleanup(vm->vatpic); 67408e3ff32SNeel Natu vioapic_cleanup(vm->vioapic); 67508e3ff32SNeel Natu 676*c76c2a19SMark Johnston for (int i = 0; i < vm->maxcpus; i++) { 67798568a00SJohn Baldwin if (vm->vcpu[i] != NULL) 67898568a00SJohn Baldwin vcpu_cleanup(vm->vcpu[i], destroy); 67998568a00SJohn Baldwin } 6805fcf252fSNeel Natu 68115add60dSPeter Grehan vmmops_cleanup(vm->cookie); 6825fcf252fSNeel Natu 683*c76c2a19SMark Johnston vm_mem_cleanup(vm); 684f7d51510SNeel Natu 6859b1aa8d6SNeel Natu if (destroy) { 686*c76c2a19SMark Johnston vm_mem_destroy(vm); 687366f6083SPeter Grehan 68815add60dSPeter Grehan vmmops_vmspace_free(vm->vmspace); 6895fcf252fSNeel Natu vm->vmspace = NULL; 69008ebb360SJohn Baldwin 691ee98f99dSJohn Baldwin free(vm->vcpu, M_VM); 69298568a00SJohn Baldwin sx_destroy(&vm->vcpus_init_lock); 69308ebb360SJohn Baldwin mtx_destroy(&vm->rendezvous_mtx); 6945fcf252fSNeel Natu } 6955fcf252fSNeel Natu } 696366f6083SPeter Grehan 6975fcf252fSNeel Natu void 6985fcf252fSNeel Natu vm_destroy(struct vm *vm) 6995fcf252fSNeel Natu { 7005fcf252fSNeel Natu vm_cleanup(vm, true); 701366f6083SPeter Grehan free(vm, M_VM); 702366f6083SPeter Grehan } 703366f6083SPeter Grehan 7045fcf252fSNeel Natu int 7055fcf252fSNeel Natu vm_reinit(struct vm *vm) 7065fcf252fSNeel Natu { 7075fcf252fSNeel Natu int error; 7085fcf252fSNeel Natu 7095fcf252fSNeel Natu /* 7105fcf252fSNeel Natu * A virtual machine can be reset only if all vcpus are suspended. 7115fcf252fSNeel Natu */ 7125fcf252fSNeel Natu if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 7135fcf252fSNeel Natu vm_cleanup(vm, false); 7145fcf252fSNeel Natu vm_init(vm, false); 7155fcf252fSNeel Natu error = 0; 7165fcf252fSNeel Natu } else { 7175fcf252fSNeel Natu error = EBUSY; 7185fcf252fSNeel Natu } 7195fcf252fSNeel Natu 7205fcf252fSNeel Natu return (error); 7215fcf252fSNeel Natu } 7225fcf252fSNeel Natu 723366f6083SPeter Grehan const char * 724366f6083SPeter Grehan vm_name(struct vm *vm) 725366f6083SPeter Grehan { 726366f6083SPeter Grehan return (vm->name); 727366f6083SPeter Grehan } 728366f6083SPeter Grehan 729366f6083SPeter Grehan int 730366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 731366f6083SPeter Grehan { 732318224bbSNeel Natu vm_object_t obj; 733366f6083SPeter Grehan 734318224bbSNeel Natu if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa)) == NULL) 735318224bbSNeel Natu return (ENOMEM); 736318224bbSNeel Natu else 737318224bbSNeel Natu return (0); 738366f6083SPeter Grehan } 739366f6083SPeter Grehan 740366f6083SPeter Grehan int 741366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 742366f6083SPeter Grehan { 743366f6083SPeter Grehan 744318224bbSNeel Natu vmm_mmio_free(vm->vmspace, gpa, len); 745318224bbSNeel Natu return (0); 746366f6083SPeter Grehan } 747366f6083SPeter Grehan 748318224bbSNeel Natu static void 7493abc72f8SKonstantin Belousov vm_iommu_map(struct vm *vm) 750318224bbSNeel Natu { 751318224bbSNeel Natu vm_paddr_t gpa, hpa; 752*c76c2a19SMark Johnston struct vm_mem_map *mm; 7533abc72f8SKonstantin Belousov int i; 754318224bbSNeel Natu 755*c76c2a19SMark Johnston sx_assert(&vm->mem.mem_segs_lock, SX_LOCKED); 756671a0049SKonstantin Belousov 7579b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 758*c76c2a19SMark Johnston if (!vm_memseg_sysmem(vm, i)) 7599b1aa8d6SNeel Natu continue; 760318224bbSNeel Natu 761*c76c2a19SMark Johnston mm = &vm->mem.mem_maps[i]; 7629b1aa8d6SNeel Natu KASSERT((mm->flags & VM_MEMMAP_F_IOMMU) == 0, 7639b1aa8d6SNeel Natu ("iommu map found invalid memmap %#lx/%#lx/%#x", 7649b1aa8d6SNeel Natu mm->gpa, mm->len, mm->flags)); 7659b1aa8d6SNeel Natu if ((mm->flags & VM_MEMMAP_F_WIRED) == 0) 7669b1aa8d6SNeel Natu continue; 7679b1aa8d6SNeel Natu mm->flags |= VM_MEMMAP_F_IOMMU; 7683abc72f8SKonstantin Belousov 7693abc72f8SKonstantin Belousov for (gpa = mm->gpa; gpa < mm->gpa + mm->len; gpa += PAGE_SIZE) { 770671a0049SKonstantin Belousov hpa = pmap_extract(vmspace_pmap(vm->vmspace), gpa); 7713abc72f8SKonstantin Belousov 772671a0049SKonstantin Belousov /* 773671a0049SKonstantin Belousov * All mappings in the vmm vmspace must be 774671a0049SKonstantin Belousov * present since they are managed by vmm in this way. 775671a0049SKonstantin Belousov * Because we are in pass-through mode, the 776671a0049SKonstantin Belousov * mappings must also be wired. This implies 777671a0049SKonstantin Belousov * that all pages must be mapped and wired, 778671a0049SKonstantin Belousov * allowing to use pmap_extract() and avoiding the 779671a0049SKonstantin Belousov * need to use vm_gpa_hold_global(). 780671a0049SKonstantin Belousov * 781671a0049SKonstantin Belousov * This could change if/when we start 782671a0049SKonstantin Belousov * supporting page faults on IOMMU maps. 783671a0049SKonstantin Belousov */ 784671a0049SKonstantin Belousov KASSERT(vm_page_wired(PHYS_TO_VM_PAGE(hpa)), 785671a0049SKonstantin Belousov ("vm_iommu_map: vm %p gpa %jx hpa %jx not wired", 786671a0049SKonstantin Belousov vm, (uintmax_t)gpa, (uintmax_t)hpa)); 787671a0049SKonstantin Belousov 7883abc72f8SKonstantin Belousov iommu_create_mapping(vm->iommu, gpa, hpa, PAGE_SIZE); 7893abc72f8SKonstantin Belousov } 7903abc72f8SKonstantin Belousov } 7913abc72f8SKonstantin Belousov 7923abc72f8SKonstantin Belousov iommu_invalidate_tlb(iommu_host_domain()); 7933abc72f8SKonstantin Belousov } 7943abc72f8SKonstantin Belousov 7953abc72f8SKonstantin Belousov static void 7963abc72f8SKonstantin Belousov vm_iommu_unmap(struct vm *vm) 7973abc72f8SKonstantin Belousov { 7983abc72f8SKonstantin Belousov vm_paddr_t gpa; 799*c76c2a19SMark Johnston struct vm_mem_map *mm; 8003abc72f8SKonstantin Belousov int i; 8013abc72f8SKonstantin Belousov 802*c76c2a19SMark Johnston sx_assert(&vm->mem.mem_segs_lock, SX_LOCKED); 803671a0049SKonstantin Belousov 8043abc72f8SKonstantin Belousov for (i = 0; i < VM_MAX_MEMMAPS; i++) { 805*c76c2a19SMark Johnston if (!vm_memseg_sysmem(vm, i)) 8063abc72f8SKonstantin Belousov continue; 8073abc72f8SKonstantin Belousov 808*c76c2a19SMark Johnston mm = &vm->mem.mem_maps[i]; 8099b1aa8d6SNeel Natu if ((mm->flags & VM_MEMMAP_F_IOMMU) == 0) 8109b1aa8d6SNeel Natu continue; 8119b1aa8d6SNeel Natu mm->flags &= ~VM_MEMMAP_F_IOMMU; 8129b1aa8d6SNeel Natu KASSERT((mm->flags & VM_MEMMAP_F_WIRED) != 0, 8139b1aa8d6SNeel Natu ("iommu unmap found invalid memmap %#lx/%#lx/%#x", 8149b1aa8d6SNeel Natu mm->gpa, mm->len, mm->flags)); 8159b1aa8d6SNeel Natu 8163abc72f8SKonstantin Belousov for (gpa = mm->gpa; gpa < mm->gpa + mm->len; gpa += PAGE_SIZE) { 817671a0049SKonstantin Belousov KASSERT(vm_page_wired(PHYS_TO_VM_PAGE(pmap_extract( 818671a0049SKonstantin Belousov vmspace_pmap(vm->vmspace), gpa))), 819671a0049SKonstantin Belousov ("vm_iommu_unmap: vm %p gpa %jx not wired", 820671a0049SKonstantin Belousov vm, (uintmax_t)gpa)); 8213abc72f8SKonstantin Belousov iommu_remove_mapping(vm->iommu, gpa, PAGE_SIZE); 822318224bbSNeel Natu } 823318224bbSNeel Natu } 824318224bbSNeel Natu 825318224bbSNeel Natu /* 826318224bbSNeel Natu * Invalidate the cached translations associated with the domain 827318224bbSNeel Natu * from which pages were removed. 828318224bbSNeel Natu */ 829318224bbSNeel Natu iommu_invalidate_tlb(vm->iommu); 830318224bbSNeel Natu } 831318224bbSNeel Natu 832318224bbSNeel Natu int 833318224bbSNeel Natu vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func) 834318224bbSNeel Natu { 835318224bbSNeel Natu int error; 836318224bbSNeel Natu 837318224bbSNeel Natu error = ppt_unassign_device(vm, bus, slot, func); 838318224bbSNeel Natu if (error) 839318224bbSNeel Natu return (error); 840318224bbSNeel Natu 8419b1aa8d6SNeel Natu if (ppt_assigned_devices(vm) == 0) 842318224bbSNeel Natu vm_iommu_unmap(vm); 8439b1aa8d6SNeel Natu 844318224bbSNeel Natu return (0); 845318224bbSNeel Natu } 846318224bbSNeel Natu 847318224bbSNeel Natu int 848318224bbSNeel Natu vm_assign_pptdev(struct vm *vm, int bus, int slot, int func) 849318224bbSNeel Natu { 850318224bbSNeel Natu int error; 851318224bbSNeel Natu vm_paddr_t maxaddr; 852318224bbSNeel Natu 8539b1aa8d6SNeel Natu /* Set up the IOMMU to do the 'gpa' to 'hpa' translation */ 85451f45d01SNeel Natu if (ppt_assigned_devices(vm) == 0) { 855318224bbSNeel Natu KASSERT(vm->iommu == NULL, 856318224bbSNeel Natu ("vm_assign_pptdev: iommu must be NULL")); 857147d12a7SAntoine Brodin maxaddr = vmm_sysmem_maxaddr(vm); 858318224bbSNeel Natu vm->iommu = iommu_create_domain(maxaddr); 859ffe1b10dSJohn Baldwin if (vm->iommu == NULL) 860ffe1b10dSJohn Baldwin return (ENXIO); 861318224bbSNeel Natu vm_iommu_map(vm); 862318224bbSNeel Natu } 863318224bbSNeel Natu 864318224bbSNeel Natu error = ppt_assign_device(vm, bus, slot, func); 865318224bbSNeel Natu return (error); 866318224bbSNeel Natu } 867318224bbSNeel Natu 868366f6083SPeter Grehan int 869d3956e46SJohn Baldwin vm_get_register(struct vcpu *vcpu, int reg, uint64_t *retval) 870366f6083SPeter Grehan { 871366f6083SPeter Grehan 872366f6083SPeter Grehan if (reg >= VM_REG_LAST) 873366f6083SPeter Grehan return (EINVAL); 874366f6083SPeter Grehan 875d3956e46SJohn Baldwin return (vmmops_getreg(vcpu->cookie, reg, retval)); 876366f6083SPeter Grehan } 877366f6083SPeter Grehan 878366f6083SPeter Grehan int 879d3956e46SJohn Baldwin vm_set_register(struct vcpu *vcpu, int reg, uint64_t val) 880366f6083SPeter Grehan { 881d087a399SNeel Natu int error; 882366f6083SPeter Grehan 883366f6083SPeter Grehan if (reg >= VM_REG_LAST) 884366f6083SPeter Grehan return (EINVAL); 885366f6083SPeter Grehan 886869c8d19SJohn Baldwin error = vmmops_setreg(vcpu->cookie, reg, val); 887d087a399SNeel Natu if (error || reg != VM_REG_GUEST_RIP) 888d087a399SNeel Natu return (error); 889d087a399SNeel Natu 890d087a399SNeel Natu /* Set 'nextrip' to match the value of %rip */ 891d3956e46SJohn Baldwin VMM_CTR1(vcpu, "Setting nextrip to %#lx", val); 892d087a399SNeel Natu vcpu->nextrip = val; 893d087a399SNeel Natu return (0); 894366f6083SPeter Grehan } 895366f6083SPeter Grehan 896490d56c5SEd Maste static bool 897366f6083SPeter Grehan is_descriptor_table(int reg) 898366f6083SPeter Grehan { 899366f6083SPeter Grehan 900366f6083SPeter Grehan switch (reg) { 901366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 902366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 903490d56c5SEd Maste return (true); 904366f6083SPeter Grehan default: 905490d56c5SEd Maste return (false); 906366f6083SPeter Grehan } 907366f6083SPeter Grehan } 908366f6083SPeter Grehan 909490d56c5SEd Maste static bool 910366f6083SPeter Grehan is_segment_register(int reg) 911366f6083SPeter Grehan { 912366f6083SPeter Grehan 913366f6083SPeter Grehan switch (reg) { 914366f6083SPeter Grehan case VM_REG_GUEST_ES: 915366f6083SPeter Grehan case VM_REG_GUEST_CS: 916366f6083SPeter Grehan case VM_REG_GUEST_SS: 917366f6083SPeter Grehan case VM_REG_GUEST_DS: 918366f6083SPeter Grehan case VM_REG_GUEST_FS: 919366f6083SPeter Grehan case VM_REG_GUEST_GS: 920366f6083SPeter Grehan case VM_REG_GUEST_TR: 921366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 922490d56c5SEd Maste return (true); 923366f6083SPeter Grehan default: 924490d56c5SEd Maste return (false); 925366f6083SPeter Grehan } 926366f6083SPeter Grehan } 927366f6083SPeter Grehan 928366f6083SPeter Grehan int 929d3956e46SJohn Baldwin vm_get_seg_desc(struct vcpu *vcpu, int reg, struct seg_desc *desc) 930366f6083SPeter Grehan { 931366f6083SPeter Grehan 932366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 933366f6083SPeter Grehan return (EINVAL); 934366f6083SPeter Grehan 935d3956e46SJohn Baldwin return (vmmops_getdesc(vcpu->cookie, reg, desc)); 936366f6083SPeter Grehan } 937366f6083SPeter Grehan 938366f6083SPeter Grehan int 9393f0f4b15SJohn Baldwin vm_set_seg_desc(struct vcpu *vcpu, int reg, struct seg_desc *desc) 940366f6083SPeter Grehan { 941366f6083SPeter Grehan 942366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 943366f6083SPeter Grehan return (EINVAL); 944366f6083SPeter Grehan 9453f0f4b15SJohn Baldwin return (vmmops_setdesc(vcpu->cookie, reg, desc)); 946366f6083SPeter Grehan } 947366f6083SPeter Grehan 948366f6083SPeter Grehan static void 949366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 950366f6083SPeter Grehan { 951366f6083SPeter Grehan 95238f1b189SPeter Grehan /* flush host state to the pcb */ 95338f1b189SPeter Grehan fpuexit(curthread); 954bd8572e0SNeel Natu 955bd8572e0SNeel Natu /* restore guest FPU state */ 956cc1cb9eaSJohn Baldwin fpu_enable(); 95738f1b189SPeter Grehan fpurestore(vcpu->guestfpu); 958bd8572e0SNeel Natu 959abb023fbSJohn Baldwin /* restore guest XCR0 if XSAVE is enabled in the host */ 960abb023fbSJohn Baldwin if (rcr4() & CR4_XSAVE) 961abb023fbSJohn Baldwin load_xcr(0, vcpu->guest_xcr0); 962abb023fbSJohn Baldwin 963bd8572e0SNeel Natu /* 964cc1cb9eaSJohn Baldwin * The FPU is now "dirty" with the guest's state so disable 965cc1cb9eaSJohn Baldwin * the FPU to trap any access by the host. 966bd8572e0SNeel Natu */ 967cc1cb9eaSJohn Baldwin fpu_disable(); 968366f6083SPeter Grehan } 969366f6083SPeter Grehan 970366f6083SPeter Grehan static void 971366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 972366f6083SPeter Grehan { 973366f6083SPeter Grehan 974bd8572e0SNeel Natu if ((rcr0() & CR0_TS) == 0) 975bd8572e0SNeel Natu panic("fpu emulation not enabled in host!"); 976bd8572e0SNeel Natu 977abb023fbSJohn Baldwin /* save guest XCR0 and restore host XCR0 */ 978abb023fbSJohn Baldwin if (rcr4() & CR4_XSAVE) { 979abb023fbSJohn Baldwin vcpu->guest_xcr0 = rxcr(0); 980abb023fbSJohn Baldwin load_xcr(0, vmm_get_host_xcr0()); 981abb023fbSJohn Baldwin } 982abb023fbSJohn Baldwin 983bd8572e0SNeel Natu /* save guest FPU state */ 984cc1cb9eaSJohn Baldwin fpu_enable(); 98538f1b189SPeter Grehan fpusave(vcpu->guestfpu); 986cc1cb9eaSJohn Baldwin fpu_disable(); 987366f6083SPeter Grehan } 988366f6083SPeter Grehan 98961592433SNeel Natu static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); 990f76fc5d4SNeel Natu 991318224bbSNeel Natu static int 9923f0f4b15SJohn Baldwin vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, 993f80330a8SNeel Natu bool from_idle) 994366f6083SPeter Grehan { 995318224bbSNeel Natu int error; 996366f6083SPeter Grehan 997318224bbSNeel Natu vcpu_assert_locked(vcpu); 998366f6083SPeter Grehan 999f76fc5d4SNeel Natu /* 1000f80330a8SNeel Natu * State transitions from the vmmdev_ioctl() must always begin from 1001f80330a8SNeel Natu * the VCPU_IDLE state. This guarantees that there is only a single 1002f80330a8SNeel Natu * ioctl() operating on a vcpu at any point. 1003f80330a8SNeel Natu */ 1004f80330a8SNeel Natu if (from_idle) { 1005248e6799SNeel Natu while (vcpu->state != VCPU_IDLE) { 1006248e6799SNeel Natu vcpu->reqidle = 1; 1007248e6799SNeel Natu vcpu_notify_event_locked(vcpu, false); 10083f0f4b15SJohn Baldwin VMM_CTR1(vcpu, "vcpu state change from %s to " 1009248e6799SNeel Natu "idle requested", vcpu_state2str(vcpu->state)); 1010f80330a8SNeel Natu msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); 1011248e6799SNeel Natu } 1012f80330a8SNeel Natu } else { 1013f80330a8SNeel Natu KASSERT(vcpu->state != VCPU_IDLE, ("invalid transition from " 1014f80330a8SNeel Natu "vcpu idle state")); 1015f80330a8SNeel Natu } 1016f80330a8SNeel Natu 1017ef39d7e9SNeel Natu if (vcpu->state == VCPU_RUNNING) { 1018ef39d7e9SNeel Natu KASSERT(vcpu->hostcpu == curcpu, ("curcpu %d and hostcpu %d " 1019ef39d7e9SNeel Natu "mismatch for running vcpu", curcpu, vcpu->hostcpu)); 1020ef39d7e9SNeel Natu } else { 1021ef39d7e9SNeel Natu KASSERT(vcpu->hostcpu == NOCPU, ("Invalid hostcpu %d for a " 1022ef39d7e9SNeel Natu "vcpu that is not running", vcpu->hostcpu)); 1023ef39d7e9SNeel Natu } 1024ef39d7e9SNeel Natu 1025f80330a8SNeel Natu /* 1026318224bbSNeel Natu * The following state transitions are allowed: 1027318224bbSNeel Natu * IDLE -> FROZEN -> IDLE 1028318224bbSNeel Natu * FROZEN -> RUNNING -> FROZEN 1029318224bbSNeel Natu * FROZEN -> SLEEPING -> FROZEN 1030f76fc5d4SNeel Natu */ 1031318224bbSNeel Natu switch (vcpu->state) { 1032318224bbSNeel Natu case VCPU_IDLE: 1033318224bbSNeel Natu case VCPU_RUNNING: 1034318224bbSNeel Natu case VCPU_SLEEPING: 1035318224bbSNeel Natu error = (newstate != VCPU_FROZEN); 1036318224bbSNeel Natu break; 1037318224bbSNeel Natu case VCPU_FROZEN: 1038318224bbSNeel Natu error = (newstate == VCPU_FROZEN); 1039318224bbSNeel Natu break; 1040318224bbSNeel Natu default: 1041318224bbSNeel Natu error = 1; 1042318224bbSNeel Natu break; 1043318224bbSNeel Natu } 1044318224bbSNeel Natu 1045f80330a8SNeel Natu if (error) 1046f80330a8SNeel Natu return (EBUSY); 1047318224bbSNeel Natu 10483f0f4b15SJohn Baldwin VMM_CTR2(vcpu, "vcpu state changed from %s to %s", 1049248e6799SNeel Natu vcpu_state2str(vcpu->state), vcpu_state2str(newstate)); 1050248e6799SNeel Natu 1051f80330a8SNeel Natu vcpu->state = newstate; 1052ef39d7e9SNeel Natu if (newstate == VCPU_RUNNING) 1053ef39d7e9SNeel Natu vcpu->hostcpu = curcpu; 1054ef39d7e9SNeel Natu else 1055ef39d7e9SNeel Natu vcpu->hostcpu = NOCPU; 1056ef39d7e9SNeel Natu 1057f80330a8SNeel Natu if (newstate == VCPU_IDLE) 1058f80330a8SNeel Natu wakeup(&vcpu->state); 1059f80330a8SNeel Natu 1060f80330a8SNeel Natu return (0); 1061318224bbSNeel Natu } 1062318224bbSNeel Natu 1063318224bbSNeel Natu static void 10643f0f4b15SJohn Baldwin vcpu_require_state(struct vcpu *vcpu, enum vcpu_state newstate) 1065318224bbSNeel Natu { 1066318224bbSNeel Natu int error; 1067318224bbSNeel Natu 10683f0f4b15SJohn Baldwin if ((error = vcpu_set_state(vcpu, newstate, false)) != 0) 1069318224bbSNeel Natu panic("Error %d setting state to %d\n", error, newstate); 1070318224bbSNeel Natu } 1071318224bbSNeel Natu 1072318224bbSNeel Natu static void 10733f0f4b15SJohn Baldwin vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) 1074318224bbSNeel Natu { 1075318224bbSNeel Natu int error; 1076318224bbSNeel Natu 10773f0f4b15SJohn Baldwin if ((error = vcpu_set_state_locked(vcpu, newstate, false)) != 0) 1078318224bbSNeel Natu panic("Error %d setting state to %d", error, newstate); 1079318224bbSNeel Natu } 1080318224bbSNeel Natu 1081b837daddSKonstantin Belousov static int 1082d8be3d52SJohn Baldwin vm_handle_rendezvous(struct vcpu *vcpu) 10835b8a8cd1SNeel Natu { 1084d8be3d52SJohn Baldwin struct vm *vm = vcpu->vm; 1085b837daddSKonstantin Belousov struct thread *td; 1086d8be3d52SJohn Baldwin int error, vcpuid; 10875b8a8cd1SNeel Natu 1088b837daddSKonstantin Belousov error = 0; 1089d8be3d52SJohn Baldwin vcpuid = vcpu->vcpuid; 1090b837daddSKonstantin Belousov td = curthread; 10915b8a8cd1SNeel Natu mtx_lock(&vm->rendezvous_mtx); 10925b8a8cd1SNeel Natu while (vm->rendezvous_func != NULL) { 109322d822c6SNeel Natu /* 'rendezvous_req_cpus' must be a subset of 'active_cpus' */ 1094e2650af1SStefan Eßer CPU_AND(&vm->rendezvous_req_cpus, &vm->rendezvous_req_cpus, &vm->active_cpus); 109522d822c6SNeel Natu 1096949f0f47SJohn Baldwin if (CPU_ISSET(vcpuid, &vm->rendezvous_req_cpus) && 109722d822c6SNeel Natu !CPU_ISSET(vcpuid, &vm->rendezvous_done_cpus)) { 1098d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Calling rendezvous func"); 1099d8be3d52SJohn Baldwin (*vm->rendezvous_func)(vcpu, vm->rendezvous_arg); 11005b8a8cd1SNeel Natu CPU_SET(vcpuid, &vm->rendezvous_done_cpus); 11015b8a8cd1SNeel Natu } 11025b8a8cd1SNeel Natu if (CPU_CMP(&vm->rendezvous_req_cpus, 11035b8a8cd1SNeel Natu &vm->rendezvous_done_cpus) == 0) { 1104d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Rendezvous completed"); 1105892feec2SCorvin Köhne CPU_ZERO(&vm->rendezvous_req_cpus); 1106869dbab7SAndriy Gapon vm->rendezvous_func = NULL; 11075b8a8cd1SNeel Natu wakeup(&vm->rendezvous_func); 11085b8a8cd1SNeel Natu break; 11095b8a8cd1SNeel Natu } 1110d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Wait for rendezvous completion"); 11115b8a8cd1SNeel Natu mtx_sleep(&vm->rendezvous_func, &vm->rendezvous_mtx, 0, 1112b837daddSKonstantin Belousov "vmrndv", hz); 1113c6d31b83SKonstantin Belousov if (td_ast_pending(td, TDA_SUSPEND)) { 1114b837daddSKonstantin Belousov mtx_unlock(&vm->rendezvous_mtx); 1115b837daddSKonstantin Belousov error = thread_check_susp(td, true); 1116b837daddSKonstantin Belousov if (error != 0) 1117b837daddSKonstantin Belousov return (error); 1118b837daddSKonstantin Belousov mtx_lock(&vm->rendezvous_mtx); 1119b837daddSKonstantin Belousov } 11205b8a8cd1SNeel Natu } 11215b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 1122b837daddSKonstantin Belousov return (0); 11235b8a8cd1SNeel Natu } 11245b8a8cd1SNeel Natu 1125318224bbSNeel Natu /* 1126318224bbSNeel Natu * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run. 1127318224bbSNeel Natu */ 1128318224bbSNeel Natu static int 11293f0f4b15SJohn Baldwin vm_handle_hlt(struct vcpu *vcpu, bool intr_disabled, bool *retu) 1130318224bbSNeel Natu { 11313f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 1132c6a0cc2eSNeel Natu const char *wmesg; 1133b837daddSKonstantin Belousov struct thread *td; 11343f0f4b15SJohn Baldwin int error, t, vcpuid, vcpu_halted, vm_halted; 1135e50ce2aaSNeel Natu 11363f0f4b15SJohn Baldwin vcpuid = vcpu->vcpuid; 1137e50ce2aaSNeel Natu vcpu_halted = 0; 1138e50ce2aaSNeel Natu vm_halted = 0; 1139b837daddSKonstantin Belousov error = 0; 1140b837daddSKonstantin Belousov td = curthread; 1141318224bbSNeel Natu 11423f0f4b15SJohn Baldwin KASSERT(!CPU_ISSET(vcpuid, &vm->halted_cpus), ("vcpu already halted")); 11433f0f4b15SJohn Baldwin 1144f76fc5d4SNeel Natu vcpu_lock(vcpu); 1145c6a0cc2eSNeel Natu while (1) { 1146f76fc5d4SNeel Natu /* 1147f76fc5d4SNeel Natu * Do a final check for pending NMI or interrupts before 1148c6a0cc2eSNeel Natu * really putting this thread to sleep. Also check for 1149c6a0cc2eSNeel Natu * software events that would cause this vcpu to wakeup. 1150f76fc5d4SNeel Natu * 1151c6a0cc2eSNeel Natu * These interrupts/events could have happened after the 115215add60dSPeter Grehan * vcpu returned from vmmops_run() and before it acquired the 1153c6a0cc2eSNeel Natu * vcpu lock above. 1154f76fc5d4SNeel Natu */ 1155248e6799SNeel Natu if (vm->rendezvous_func != NULL || vm->suspend || vcpu->reqidle) 1156c6a0cc2eSNeel Natu break; 115780cb5d84SJohn Baldwin if (vm_nmi_pending(vcpu)) 1158c6a0cc2eSNeel Natu break; 1159c6a0cc2eSNeel Natu if (!intr_disabled) { 116080cb5d84SJohn Baldwin if (vm_extint_pending(vcpu) || 1161c6a0cc2eSNeel Natu vlapic_pending_intr(vcpu->vlapic, NULL)) { 1162c6a0cc2eSNeel Natu break; 1163c6a0cc2eSNeel Natu } 1164c6a0cc2eSNeel Natu } 1165c6a0cc2eSNeel Natu 1166f008d157SNeel Natu /* Don't go to sleep if the vcpu thread needs to yield */ 116780cb5d84SJohn Baldwin if (vcpu_should_yield(vcpu)) 1168f008d157SNeel Natu break; 1169f008d157SNeel Natu 117080cb5d84SJohn Baldwin if (vcpu_debugged(vcpu)) 1171fc276d92SJohn Baldwin break; 1172fc276d92SJohn Baldwin 1173e50ce2aaSNeel Natu /* 1174e50ce2aaSNeel Natu * Some Linux guests implement "halt" by having all vcpus 1175e50ce2aaSNeel Natu * execute HLT with interrupts disabled. 'halted_cpus' keeps 1176e50ce2aaSNeel Natu * track of the vcpus that have entered this state. When all 1177e50ce2aaSNeel Natu * vcpus enter the halted state the virtual machine is halted. 1178e50ce2aaSNeel Natu */ 1179e50ce2aaSNeel Natu if (intr_disabled) { 1180c6a0cc2eSNeel Natu wmesg = "vmhalt"; 11813f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "Halted"); 1182055fc2cbSNeel Natu if (!vcpu_halted && halt_detection_enabled) { 1183e50ce2aaSNeel Natu vcpu_halted = 1; 1184e50ce2aaSNeel Natu CPU_SET_ATOMIC(vcpuid, &vm->halted_cpus); 1185e50ce2aaSNeel Natu } 1186e50ce2aaSNeel Natu if (CPU_CMP(&vm->halted_cpus, &vm->active_cpus) == 0) { 1187e50ce2aaSNeel Natu vm_halted = 1; 1188e50ce2aaSNeel Natu break; 1189e50ce2aaSNeel Natu } 1190e50ce2aaSNeel Natu } else { 1191e50ce2aaSNeel Natu wmesg = "vmidle"; 1192e50ce2aaSNeel Natu } 1193c6a0cc2eSNeel Natu 1194f76fc5d4SNeel Natu t = ticks; 11953f0f4b15SJohn Baldwin vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 1196f008d157SNeel Natu /* 1197f008d157SNeel Natu * XXX msleep_spin() cannot be interrupted by signals so 1198f008d157SNeel Natu * wake up periodically to check pending signals. 1199f008d157SNeel Natu */ 1200f008d157SNeel Natu msleep_spin(vcpu, &vcpu->mtx, wmesg, hz); 12013f0f4b15SJohn Baldwin vcpu_require_state_locked(vcpu, VCPU_FROZEN); 12023dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VCPU_IDLE_TICKS, ticks - t); 1203c6d31b83SKonstantin Belousov if (td_ast_pending(td, TDA_SUSPEND)) { 1204b837daddSKonstantin Belousov vcpu_unlock(vcpu); 1205b837daddSKonstantin Belousov error = thread_check_susp(td, false); 12064d447b30SKonstantin Belousov if (error != 0) { 12074d447b30SKonstantin Belousov if (vcpu_halted) { 12084d447b30SKonstantin Belousov CPU_CLR_ATOMIC(vcpuid, 12094d447b30SKonstantin Belousov &vm->halted_cpus); 12104d447b30SKonstantin Belousov } 1211b837daddSKonstantin Belousov return (error); 12124d447b30SKonstantin Belousov } 1213b837daddSKonstantin Belousov vcpu_lock(vcpu); 1214b837daddSKonstantin Belousov } 1215f76fc5d4SNeel Natu } 1216e50ce2aaSNeel Natu 1217e50ce2aaSNeel Natu if (vcpu_halted) 1218e50ce2aaSNeel Natu CPU_CLR_ATOMIC(vcpuid, &vm->halted_cpus); 1219e50ce2aaSNeel Natu 1220f76fc5d4SNeel Natu vcpu_unlock(vcpu); 1221f76fc5d4SNeel Natu 1222e50ce2aaSNeel Natu if (vm_halted) 1223e50ce2aaSNeel Natu vm_suspend(vm, VM_SUSPEND_HALT); 1224e50ce2aaSNeel Natu 1225318224bbSNeel Natu return (0); 1226318224bbSNeel Natu } 1227318224bbSNeel Natu 1228318224bbSNeel Natu static int 12293f0f4b15SJohn Baldwin vm_handle_paging(struct vcpu *vcpu, bool *retu) 1230318224bbSNeel Natu { 12313f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 1232318224bbSNeel Natu int rv, ftype; 1233318224bbSNeel Natu struct vm_map *map; 1234318224bbSNeel Natu struct vm_exit *vme; 1235318224bbSNeel Natu 1236318224bbSNeel Natu vme = &vcpu->exitinfo; 1237318224bbSNeel Natu 1238d087a399SNeel Natu KASSERT(vme->inst_length == 0, ("%s: invalid inst_length %d", 1239d087a399SNeel Natu __func__, vme->inst_length)); 1240d087a399SNeel Natu 1241318224bbSNeel Natu ftype = vme->u.paging.fault_type; 1242318224bbSNeel Natu KASSERT(ftype == VM_PROT_READ || 1243318224bbSNeel Natu ftype == VM_PROT_WRITE || ftype == VM_PROT_EXECUTE, 1244318224bbSNeel Natu ("vm_handle_paging: invalid fault_type %d", ftype)); 1245318224bbSNeel Natu 1246318224bbSNeel Natu if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { 1247318224bbSNeel Natu rv = pmap_emulate_accessed_dirty(vmspace_pmap(vm->vmspace), 1248318224bbSNeel Natu vme->u.paging.gpa, ftype); 12499d8d8e3eSNeel Natu if (rv == 0) { 12503f0f4b15SJohn Baldwin VMM_CTR2(vcpu, "%s bit emulation for gpa %#lx", 12519d8d8e3eSNeel Natu ftype == VM_PROT_READ ? "accessed" : "dirty", 12529d8d8e3eSNeel Natu vme->u.paging.gpa); 1253318224bbSNeel Natu goto done; 1254318224bbSNeel Natu } 12559d8d8e3eSNeel Natu } 1256318224bbSNeel Natu 1257318224bbSNeel Natu map = &vm->vmspace->vm_map; 1258df08823dSKonstantin Belousov rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL, NULL); 1259318224bbSNeel Natu 12603f0f4b15SJohn Baldwin VMM_CTR3(vcpu, "vm_handle_paging rv = %d, gpa = %#lx, " 1261513c8d33SNeel Natu "ftype = %d", rv, vme->u.paging.gpa, ftype); 1262318224bbSNeel Natu 1263318224bbSNeel Natu if (rv != KERN_SUCCESS) 1264318224bbSNeel Natu return (EFAULT); 1265318224bbSNeel Natu done: 1266318224bbSNeel Natu return (0); 1267318224bbSNeel Natu } 1268318224bbSNeel Natu 1269318224bbSNeel Natu static int 12703f0f4b15SJohn Baldwin vm_handle_inst_emul(struct vcpu *vcpu, bool *retu) 1271318224bbSNeel Natu { 1272318224bbSNeel Natu struct vie *vie; 1273318224bbSNeel Natu struct vm_exit *vme; 1274e4f605eeSTycho Nightingale uint64_t gla, gpa, cs_base; 1275e813a873SNeel Natu struct vm_guest_paging *paging; 1276565bbb86SNeel Natu mem_region_read_t mread; 1277565bbb86SNeel Natu mem_region_write_t mwrite; 1278f7a9f178SNeel Natu enum vm_cpu_mode cpu_mode; 12791c73ea3eSNeel Natu int cs_d, error, fault; 1280318224bbSNeel Natu 1281318224bbSNeel Natu vme = &vcpu->exitinfo; 1282318224bbSNeel Natu 12831c73ea3eSNeel Natu KASSERT(vme->inst_length == 0, ("%s: invalid inst_length %d", 12841c73ea3eSNeel Natu __func__, vme->inst_length)); 12851c73ea3eSNeel Natu 1286318224bbSNeel Natu gla = vme->u.inst_emul.gla; 1287318224bbSNeel Natu gpa = vme->u.inst_emul.gpa; 1288e4f605eeSTycho Nightingale cs_base = vme->u.inst_emul.cs_base; 1289f7a9f178SNeel Natu cs_d = vme->u.inst_emul.cs_d; 1290318224bbSNeel Natu vie = &vme->u.inst_emul.vie; 1291e813a873SNeel Natu paging = &vme->u.inst_emul.paging; 1292f7a9f178SNeel Natu cpu_mode = paging->cpu_mode; 1293318224bbSNeel Natu 12943f0f4b15SJohn Baldwin VMM_CTR1(vcpu, "inst_emul fault accessing gpa %#lx", gpa); 12959d8d8e3eSNeel Natu 1296318224bbSNeel Natu /* Fetch, decode and emulate the faulting instruction */ 1297c2a875f9SNeel Natu if (vie->num_valid == 0) { 1298d3956e46SJohn Baldwin error = vmm_fetch_instruction(vcpu, paging, vme->rip + cs_base, 1299d3956e46SJohn Baldwin VIE_INST_SIZE, vie, &fault); 1300c2a875f9SNeel Natu } else { 1301c2a875f9SNeel Natu /* 1302c2a875f9SNeel Natu * The instruction bytes have already been copied into 'vie' 1303c2a875f9SNeel Natu */ 13049c4d5478SNeel Natu error = fault = 0; 1305c2a875f9SNeel Natu } 13069c4d5478SNeel Natu if (error || fault) 13079c4d5478SNeel Natu return (error); 1308318224bbSNeel Natu 1309d3956e46SJohn Baldwin if (vmm_decode_instruction(vcpu, gla, cpu_mode, cs_d, vie) != 0) { 13103f0f4b15SJohn Baldwin VMM_CTR1(vcpu, "Error decoding instruction at %#lx", 1311c07a0648SNeel Natu vme->rip + cs_base); 1312c07a0648SNeel Natu *retu = true; /* dump instruction bytes in userspace */ 1313c07a0648SNeel Natu return (0); 1314c07a0648SNeel Natu } 1315318224bbSNeel Natu 1316a0b78f09SPeter Grehan /* 13171c73ea3eSNeel Natu * Update 'nextrip' based on the length of the emulated instruction. 1318a0b78f09SPeter Grehan */ 1319a0b78f09SPeter Grehan vme->inst_length = vie->num_processed; 1320d087a399SNeel Natu vcpu->nextrip += vie->num_processed; 13213f0f4b15SJohn Baldwin VMM_CTR1(vcpu, "nextrip updated to %#lx after instruction decoding", 13223f0f4b15SJohn Baldwin vcpu->nextrip); 1323a0b78f09SPeter Grehan 132408e3ff32SNeel Natu /* return to userland unless this is an in-kernel emulated device */ 1325565bbb86SNeel Natu if (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE) { 1326565bbb86SNeel Natu mread = lapic_mmio_read; 1327565bbb86SNeel Natu mwrite = lapic_mmio_write; 1328565bbb86SNeel Natu } else if (gpa >= VIOAPIC_BASE && gpa < VIOAPIC_BASE + VIOAPIC_SIZE) { 1329565bbb86SNeel Natu mread = vioapic_mmio_read; 1330565bbb86SNeel Natu mwrite = vioapic_mmio_write; 133108e3ff32SNeel Natu } else if (gpa >= VHPET_BASE && gpa < VHPET_BASE + VHPET_SIZE) { 133208e3ff32SNeel Natu mread = vhpet_mmio_read; 133308e3ff32SNeel Natu mwrite = vhpet_mmio_write; 1334565bbb86SNeel Natu } else { 1335becd9849SNeel Natu *retu = true; 1336318224bbSNeel Natu return (0); 1337318224bbSNeel Natu } 1338318224bbSNeel Natu 1339d3956e46SJohn Baldwin error = vmm_emulate_instruction(vcpu, gpa, vie, paging, mread, mwrite, 1340d3956e46SJohn Baldwin retu); 1341318224bbSNeel Natu 1342318224bbSNeel Natu return (error); 1343318224bbSNeel Natu } 1344318224bbSNeel Natu 1345b15a09c0SNeel Natu static int 13463f0f4b15SJohn Baldwin vm_handle_suspend(struct vcpu *vcpu, bool *retu) 1347b15a09c0SNeel Natu { 13483f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 1349b837daddSKonstantin Belousov int error, i; 1350b837daddSKonstantin Belousov struct thread *td; 1351b15a09c0SNeel Natu 1352b837daddSKonstantin Belousov error = 0; 1353b837daddSKonstantin Belousov td = curthread; 1354b15a09c0SNeel Natu 13553f0f4b15SJohn Baldwin CPU_SET_ATOMIC(vcpu->vcpuid, &vm->suspended_cpus); 1356b15a09c0SNeel Natu 1357b15a09c0SNeel Natu /* 1358b15a09c0SNeel Natu * Wait until all 'active_cpus' have suspended themselves. 1359b15a09c0SNeel Natu * 1360b15a09c0SNeel Natu * Since a VM may be suspended at any time including when one or 1361b15a09c0SNeel Natu * more vcpus are doing a rendezvous we need to call the rendezvous 1362b15a09c0SNeel Natu * handler while we are waiting to prevent a deadlock. 1363b15a09c0SNeel Natu */ 1364b15a09c0SNeel Natu vcpu_lock(vcpu); 1365b837daddSKonstantin Belousov while (error == 0) { 1366b15a09c0SNeel Natu if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 13673f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "All vcpus suspended"); 1368b15a09c0SNeel Natu break; 1369b15a09c0SNeel Natu } 1370b15a09c0SNeel Natu 1371b15a09c0SNeel Natu if (vm->rendezvous_func == NULL) { 13723f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "Sleeping during suspend"); 13733f0f4b15SJohn Baldwin vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 1374b15a09c0SNeel Natu msleep_spin(vcpu, &vcpu->mtx, "vmsusp", hz); 13753f0f4b15SJohn Baldwin vcpu_require_state_locked(vcpu, VCPU_FROZEN); 1376c6d31b83SKonstantin Belousov if (td_ast_pending(td, TDA_SUSPEND)) { 1377b837daddSKonstantin Belousov vcpu_unlock(vcpu); 1378b837daddSKonstantin Belousov error = thread_check_susp(td, false); 1379b837daddSKonstantin Belousov vcpu_lock(vcpu); 1380b837daddSKonstantin Belousov } 1381b15a09c0SNeel Natu } else { 13823f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "Rendezvous during suspend"); 1383b15a09c0SNeel Natu vcpu_unlock(vcpu); 1384d8be3d52SJohn Baldwin error = vm_handle_rendezvous(vcpu); 1385b15a09c0SNeel Natu vcpu_lock(vcpu); 1386b15a09c0SNeel Natu } 1387b15a09c0SNeel Natu } 1388b15a09c0SNeel Natu vcpu_unlock(vcpu); 1389b15a09c0SNeel Natu 1390b15a09c0SNeel Natu /* 1391b15a09c0SNeel Natu * Wakeup the other sleeping vcpus and return to userspace. 1392b15a09c0SNeel Natu */ 1393a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 1394b15a09c0SNeel Natu if (CPU_ISSET(i, &vm->suspended_cpus)) { 13953f0f4b15SJohn Baldwin vcpu_notify_event(vm_vcpu(vm, i), false); 1396b15a09c0SNeel Natu } 1397b15a09c0SNeel Natu } 1398b15a09c0SNeel Natu 1399b15a09c0SNeel Natu *retu = true; 1400b837daddSKonstantin Belousov return (error); 1401b15a09c0SNeel Natu } 1402b15a09c0SNeel Natu 1403248e6799SNeel Natu static int 14043f0f4b15SJohn Baldwin vm_handle_reqidle(struct vcpu *vcpu, bool *retu) 1405248e6799SNeel Natu { 1406248e6799SNeel Natu vcpu_lock(vcpu); 1407248e6799SNeel Natu KASSERT(vcpu->reqidle, ("invalid vcpu reqidle %d", vcpu->reqidle)); 1408248e6799SNeel Natu vcpu->reqidle = 0; 1409248e6799SNeel Natu vcpu_unlock(vcpu); 1410248e6799SNeel Natu *retu = true; 1411248e6799SNeel Natu return (0); 1412248e6799SNeel Natu } 1413248e6799SNeel Natu 1414e3b4fe64SBojan Novković static int 1415e3b4fe64SBojan Novković vm_handle_db(struct vcpu *vcpu, struct vm_exit *vme, bool *retu) 1416e3b4fe64SBojan Novković { 1417e3b4fe64SBojan Novković int error, fault; 1418e3b4fe64SBojan Novković uint64_t rsp; 1419e3b4fe64SBojan Novković uint64_t rflags; 142051fda658SBojan Novković struct vm_copyinfo copyinfo[2]; 1421e3b4fe64SBojan Novković 1422e3b4fe64SBojan Novković *retu = true; 1423e3b4fe64SBojan Novković if (!vme->u.dbg.pushf_intercept || vme->u.dbg.tf_shadow_val != 0) { 1424e3b4fe64SBojan Novković return (0); 1425e3b4fe64SBojan Novković } 1426e3b4fe64SBojan Novković 1427e3b4fe64SBojan Novković vm_get_register(vcpu, VM_REG_GUEST_RSP, &rsp); 1428e3b4fe64SBojan Novković error = vm_copy_setup(vcpu, &vme->u.dbg.paging, rsp, sizeof(uint64_t), 142951fda658SBojan Novković VM_PROT_RW, copyinfo, nitems(copyinfo), &fault); 1430e3b4fe64SBojan Novković if (error != 0 || fault != 0) { 1431e3b4fe64SBojan Novković *retu = false; 1432e3b4fe64SBojan Novković return (EINVAL); 1433e3b4fe64SBojan Novković } 1434e3b4fe64SBojan Novković 1435e3b4fe64SBojan Novković /* Read pushed rflags value from top of stack. */ 143651fda658SBojan Novković vm_copyin(copyinfo, &rflags, sizeof(uint64_t)); 1437e3b4fe64SBojan Novković 1438e3b4fe64SBojan Novković /* Clear TF bit. */ 1439e3b4fe64SBojan Novković rflags &= ~(PSL_T); 1440e3b4fe64SBojan Novković 1441e3b4fe64SBojan Novković /* Write updated value back to memory. */ 144251fda658SBojan Novković vm_copyout(&rflags, copyinfo, sizeof(uint64_t)); 144351fda658SBojan Novković vm_copy_teardown(copyinfo, nitems(copyinfo)); 1444e3b4fe64SBojan Novković 1445e3b4fe64SBojan Novković return (0); 1446e3b4fe64SBojan Novković } 1447e3b4fe64SBojan Novković 1448b15a09c0SNeel Natu int 1449f0fdcfe2SNeel Natu vm_suspend(struct vm *vm, enum vm_suspend_how how) 1450b15a09c0SNeel Natu { 1451f0fdcfe2SNeel Natu int i; 1452b15a09c0SNeel Natu 1453f0fdcfe2SNeel Natu if (how <= VM_SUSPEND_NONE || how >= VM_SUSPEND_LAST) 1454f0fdcfe2SNeel Natu return (EINVAL); 1455f0fdcfe2SNeel Natu 1456f0fdcfe2SNeel Natu if (atomic_cmpset_int(&vm->suspend, 0, how) == 0) { 1457f0fdcfe2SNeel Natu VM_CTR2(vm, "virtual machine already suspended %d/%d", 1458f0fdcfe2SNeel Natu vm->suspend, how); 1459b15a09c0SNeel Natu return (EALREADY); 1460b15a09c0SNeel Natu } 1461f0fdcfe2SNeel Natu 1462f0fdcfe2SNeel Natu VM_CTR1(vm, "virtual machine successfully suspended %d", how); 1463f0fdcfe2SNeel Natu 1464f0fdcfe2SNeel Natu /* 1465f0fdcfe2SNeel Natu * Notify all active vcpus that they are now suspended. 1466f0fdcfe2SNeel Natu */ 1467a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 1468f0fdcfe2SNeel Natu if (CPU_ISSET(i, &vm->active_cpus)) 14693f0f4b15SJohn Baldwin vcpu_notify_event(vm_vcpu(vm, i), false); 1470f0fdcfe2SNeel Natu } 1471f0fdcfe2SNeel Natu 1472f0fdcfe2SNeel Natu return (0); 1473f0fdcfe2SNeel Natu } 1474f0fdcfe2SNeel Natu 1475f0fdcfe2SNeel Natu void 147680cb5d84SJohn Baldwin vm_exit_suspended(struct vcpu *vcpu, uint64_t rip) 1477f0fdcfe2SNeel Natu { 147880cb5d84SJohn Baldwin struct vm *vm = vcpu->vm; 1479f0fdcfe2SNeel Natu struct vm_exit *vmexit; 1480f0fdcfe2SNeel Natu 1481f0fdcfe2SNeel Natu KASSERT(vm->suspend > VM_SUSPEND_NONE && vm->suspend < VM_SUSPEND_LAST, 1482f0fdcfe2SNeel Natu ("vm_exit_suspended: invalid suspend type %d", vm->suspend)); 1483f0fdcfe2SNeel Natu 148480cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 1485f0fdcfe2SNeel Natu vmexit->rip = rip; 1486f0fdcfe2SNeel Natu vmexit->inst_length = 0; 1487f0fdcfe2SNeel Natu vmexit->exitcode = VM_EXITCODE_SUSPENDED; 1488f0fdcfe2SNeel Natu vmexit->u.suspended.how = vm->suspend; 1489b15a09c0SNeel Natu } 1490b15a09c0SNeel Natu 149140487465SNeel Natu void 149280cb5d84SJohn Baldwin vm_exit_debug(struct vcpu *vcpu, uint64_t rip) 1493fc276d92SJohn Baldwin { 1494fc276d92SJohn Baldwin struct vm_exit *vmexit; 1495fc276d92SJohn Baldwin 149680cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 1497fc276d92SJohn Baldwin vmexit->rip = rip; 1498fc276d92SJohn Baldwin vmexit->inst_length = 0; 1499fc276d92SJohn Baldwin vmexit->exitcode = VM_EXITCODE_DEBUG; 1500fc276d92SJohn Baldwin } 1501fc276d92SJohn Baldwin 1502fc276d92SJohn Baldwin void 150380cb5d84SJohn Baldwin vm_exit_rendezvous(struct vcpu *vcpu, uint64_t rip) 150440487465SNeel Natu { 150540487465SNeel Natu struct vm_exit *vmexit; 150640487465SNeel Natu 150780cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 150840487465SNeel Natu vmexit->rip = rip; 150940487465SNeel Natu vmexit->inst_length = 0; 151040487465SNeel Natu vmexit->exitcode = VM_EXITCODE_RENDEZVOUS; 151180cb5d84SJohn Baldwin vmm_stat_incr(vcpu, VMEXIT_RENDEZVOUS, 1); 151240487465SNeel Natu } 151340487465SNeel Natu 151440487465SNeel Natu void 151580cb5d84SJohn Baldwin vm_exit_reqidle(struct vcpu *vcpu, uint64_t rip) 1516248e6799SNeel Natu { 1517248e6799SNeel Natu struct vm_exit *vmexit; 1518248e6799SNeel Natu 151980cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 1520248e6799SNeel Natu vmexit->rip = rip; 1521248e6799SNeel Natu vmexit->inst_length = 0; 1522248e6799SNeel Natu vmexit->exitcode = VM_EXITCODE_REQIDLE; 152380cb5d84SJohn Baldwin vmm_stat_incr(vcpu, VMEXIT_REQIDLE, 1); 1524248e6799SNeel Natu } 1525248e6799SNeel Natu 1526248e6799SNeel Natu void 152780cb5d84SJohn Baldwin vm_exit_astpending(struct vcpu *vcpu, uint64_t rip) 152840487465SNeel Natu { 152940487465SNeel Natu struct vm_exit *vmexit; 153040487465SNeel Natu 153180cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 153240487465SNeel Natu vmexit->rip = rip; 153340487465SNeel Natu vmexit->inst_length = 0; 153440487465SNeel Natu vmexit->exitcode = VM_EXITCODE_BOGUS; 153580cb5d84SJohn Baldwin vmm_stat_incr(vcpu, VMEXIT_ASTPENDING, 1); 153640487465SNeel Natu } 153740487465SNeel Natu 1538318224bbSNeel Natu int 1539e17eca32SMark Johnston vm_run(struct vcpu *vcpu) 1540318224bbSNeel Natu { 15413f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 1542248e6799SNeel Natu struct vm_eventinfo evinfo; 1543318224bbSNeel Natu int error, vcpuid; 1544318224bbSNeel Natu struct pcb *pcb; 1545d087a399SNeel Natu uint64_t tscval; 1546318224bbSNeel Natu struct vm_exit *vme; 1547becd9849SNeel Natu bool retu, intr_disabled; 1548318224bbSNeel Natu pmap_t pmap; 1549318224bbSNeel Natu 15503f0f4b15SJohn Baldwin vcpuid = vcpu->vcpuid; 1551318224bbSNeel Natu 155295ebc360SNeel Natu if (!CPU_ISSET(vcpuid, &vm->active_cpus)) 155395ebc360SNeel Natu return (EINVAL); 155495ebc360SNeel Natu 155595ebc360SNeel Natu if (CPU_ISSET(vcpuid, &vm->suspended_cpus)) 155695ebc360SNeel Natu return (EINVAL); 155795ebc360SNeel Natu 1558318224bbSNeel Natu pmap = vmspace_pmap(vm->vmspace); 1559318224bbSNeel Natu vme = &vcpu->exitinfo; 1560892feec2SCorvin Köhne evinfo.rptr = &vm->rendezvous_req_cpus; 1561248e6799SNeel Natu evinfo.sptr = &vm->suspend; 1562248e6799SNeel Natu evinfo.iptr = &vcpu->reqidle; 1563318224bbSNeel Natu restart: 1564318224bbSNeel Natu critical_enter(); 1565318224bbSNeel Natu 1566318224bbSNeel Natu KASSERT(!CPU_ISSET(curcpu, &pmap->pm_active), 1567318224bbSNeel Natu ("vm_run: absurd pm_active")); 1568318224bbSNeel Natu 1569318224bbSNeel Natu tscval = rdtsc(); 1570318224bbSNeel Natu 1571318224bbSNeel Natu pcb = PCPU_GET(curpcb); 1572318224bbSNeel Natu set_pcb_flags(pcb, PCB_FULL_IRET); 1573318224bbSNeel Natu 1574318224bbSNeel Natu restore_guest_fpustate(vcpu); 1575318224bbSNeel Natu 15763f0f4b15SJohn Baldwin vcpu_require_state(vcpu, VCPU_RUNNING); 1577869c8d19SJohn Baldwin error = vmmops_run(vcpu->cookie, vcpu->nextrip, pmap, &evinfo); 15783f0f4b15SJohn Baldwin vcpu_require_state(vcpu, VCPU_FROZEN); 1579318224bbSNeel Natu 1580318224bbSNeel Natu save_guest_fpustate(vcpu); 1581318224bbSNeel Natu 15823dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 1583318224bbSNeel Natu 1584318224bbSNeel Natu critical_exit(); 1585318224bbSNeel Natu 1586318224bbSNeel Natu if (error == 0) { 1587becd9849SNeel Natu retu = false; 1588d087a399SNeel Natu vcpu->nextrip = vme->rip + vme->inst_length; 1589318224bbSNeel Natu switch (vme->exitcode) { 1590248e6799SNeel Natu case VM_EXITCODE_REQIDLE: 15913f0f4b15SJohn Baldwin error = vm_handle_reqidle(vcpu, &retu); 1592248e6799SNeel Natu break; 1593b15a09c0SNeel Natu case VM_EXITCODE_SUSPENDED: 15943f0f4b15SJohn Baldwin error = vm_handle_suspend(vcpu, &retu); 1595b15a09c0SNeel Natu break; 159630b94db8SNeel Natu case VM_EXITCODE_IOAPIC_EOI: 1597e42c24d5SJohn Baldwin vioapic_process_eoi(vm, vme->u.ioapic_eoi.vector); 159830b94db8SNeel Natu break; 15995b8a8cd1SNeel Natu case VM_EXITCODE_RENDEZVOUS: 1600d8be3d52SJohn Baldwin error = vm_handle_rendezvous(vcpu); 16015b8a8cd1SNeel Natu break; 1602318224bbSNeel Natu case VM_EXITCODE_HLT: 1603becd9849SNeel Natu intr_disabled = ((vme->u.hlt.rflags & PSL_I) == 0); 16043f0f4b15SJohn Baldwin error = vm_handle_hlt(vcpu, intr_disabled, &retu); 1605318224bbSNeel Natu break; 1606318224bbSNeel Natu case VM_EXITCODE_PAGING: 16073f0f4b15SJohn Baldwin error = vm_handle_paging(vcpu, &retu); 1608318224bbSNeel Natu break; 1609318224bbSNeel Natu case VM_EXITCODE_INST_EMUL: 16103f0f4b15SJohn Baldwin error = vm_handle_inst_emul(vcpu, &retu); 1611318224bbSNeel Natu break; 1612d17b5104SNeel Natu case VM_EXITCODE_INOUT: 1613d17b5104SNeel Natu case VM_EXITCODE_INOUT_STR: 16143f0f4b15SJohn Baldwin error = vm_handle_inout(vcpu, vme, &retu); 1615d17b5104SNeel Natu break; 1616e3b4fe64SBojan Novković case VM_EXITCODE_DB: 1617e3b4fe64SBojan Novković error = vm_handle_db(vcpu, vme, &retu); 1618e3b4fe64SBojan Novković break; 161965145c7fSNeel Natu case VM_EXITCODE_MONITOR: 162065145c7fSNeel Natu case VM_EXITCODE_MWAIT: 162127d26457SAndrew Turner case VM_EXITCODE_VMINSN: 1622d3956e46SJohn Baldwin vm_inject_ud(vcpu); 162365145c7fSNeel Natu break; 1624318224bbSNeel Natu default: 1625becd9849SNeel Natu retu = true; /* handled in userland */ 1626318224bbSNeel Natu break; 1627318224bbSNeel Natu } 1628318224bbSNeel Natu } 1629318224bbSNeel Natu 16300bda8d3eSCorvin Köhne /* 16310bda8d3eSCorvin Köhne * VM_EXITCODE_INST_EMUL could access the apic which could transform the 16320bda8d3eSCorvin Köhne * exit code into VM_EXITCODE_IPI. 16330bda8d3eSCorvin Köhne */ 1634ba34de1bSMark Johnston if (error == 0 && vme->exitcode == VM_EXITCODE_IPI) 1635d8be3d52SJohn Baldwin error = vm_handle_ipi(vcpu, vme, &retu); 16360bda8d3eSCorvin Köhne 1637d087a399SNeel Natu if (error == 0 && retu == false) 1638f76fc5d4SNeel Natu goto restart; 1639f76fc5d4SNeel Natu 16403dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VMEXIT_USERSPACE, 1); 16413f0f4b15SJohn Baldwin VMM_CTR2(vcpu, "retu %d/%d", error, vme->exitcode); 1642248e6799SNeel Natu 1643366f6083SPeter Grehan return (error); 1644366f6083SPeter Grehan } 1645366f6083SPeter Grehan 1646366f6083SPeter Grehan int 1647d3956e46SJohn Baldwin vm_restart_instruction(struct vcpu *vcpu) 1648c9c75df4SNeel Natu { 1649d087a399SNeel Natu enum vcpu_state state; 1650d087a399SNeel Natu uint64_t rip; 165173505a10SRobert Wing int error __diagused; 1652c9c75df4SNeel Natu 1653d3956e46SJohn Baldwin state = vcpu_get_state(vcpu, NULL); 1654d087a399SNeel Natu if (state == VCPU_RUNNING) { 1655d087a399SNeel Natu /* 1656d087a399SNeel Natu * When a vcpu is "running" the next instruction is determined 1657d087a399SNeel Natu * by adding 'rip' and 'inst_length' in the vcpu's 'exitinfo'. 1658d087a399SNeel Natu * Thus setting 'inst_length' to zero will cause the current 1659d087a399SNeel Natu * instruction to be restarted. 1660d087a399SNeel Natu */ 1661c9c75df4SNeel Natu vcpu->exitinfo.inst_length = 0; 1662d3956e46SJohn Baldwin VMM_CTR1(vcpu, "restarting instruction at %#lx by " 1663d087a399SNeel Natu "setting inst_length to zero", vcpu->exitinfo.rip); 1664d087a399SNeel Natu } else if (state == VCPU_FROZEN) { 1665d087a399SNeel Natu /* 1666d087a399SNeel Natu * When a vcpu is "frozen" it is outside the critical section 166715add60dSPeter Grehan * around vmmops_run() and 'nextrip' points to the next 166815add60dSPeter Grehan * instruction. Thus instruction restart is achieved by setting 166915add60dSPeter Grehan * 'nextrip' to the vcpu's %rip. 1670d087a399SNeel Natu */ 1671d3956e46SJohn Baldwin error = vm_get_register(vcpu, VM_REG_GUEST_RIP, &rip); 1672d087a399SNeel Natu KASSERT(!error, ("%s: error %d getting rip", __func__, error)); 1673d3956e46SJohn Baldwin VMM_CTR2(vcpu, "restarting instruction by updating " 1674d087a399SNeel Natu "nextrip from %#lx to %#lx", vcpu->nextrip, rip); 1675d087a399SNeel Natu vcpu->nextrip = rip; 1676d087a399SNeel Natu } else { 1677d087a399SNeel Natu panic("%s: invalid state %d", __func__, state); 1678d087a399SNeel Natu } 1679c9c75df4SNeel Natu return (0); 1680c9c75df4SNeel Natu } 1681c9c75df4SNeel Natu 1682c9c75df4SNeel Natu int 168380cb5d84SJohn Baldwin vm_exit_intinfo(struct vcpu *vcpu, uint64_t info) 1684091d4532SNeel Natu { 1685091d4532SNeel Natu int type, vector; 1686091d4532SNeel Natu 1687091d4532SNeel Natu if (info & VM_INTINFO_VALID) { 1688091d4532SNeel Natu type = info & VM_INTINFO_TYPE; 1689091d4532SNeel Natu vector = info & 0xff; 1690091d4532SNeel Natu if (type == VM_INTINFO_NMI && vector != IDT_NMI) 1691091d4532SNeel Natu return (EINVAL); 1692091d4532SNeel Natu if (type == VM_INTINFO_HWEXCEPTION && vector >= 32) 1693091d4532SNeel Natu return (EINVAL); 1694091d4532SNeel Natu if (info & VM_INTINFO_RSVD) 1695091d4532SNeel Natu return (EINVAL); 1696091d4532SNeel Natu } else { 1697091d4532SNeel Natu info = 0; 1698091d4532SNeel Natu } 169980cb5d84SJohn Baldwin VMM_CTR2(vcpu, "%s: info1(%#lx)", __func__, info); 1700091d4532SNeel Natu vcpu->exitintinfo = info; 1701091d4532SNeel Natu return (0); 1702091d4532SNeel Natu } 1703091d4532SNeel Natu 1704091d4532SNeel Natu enum exc_class { 1705091d4532SNeel Natu EXC_BENIGN, 1706091d4532SNeel Natu EXC_CONTRIBUTORY, 1707091d4532SNeel Natu EXC_PAGEFAULT 1708091d4532SNeel Natu }; 1709091d4532SNeel Natu 1710091d4532SNeel Natu #define IDT_VE 20 /* Virtualization Exception (Intel specific) */ 1711091d4532SNeel Natu 1712091d4532SNeel Natu static enum exc_class 1713091d4532SNeel Natu exception_class(uint64_t info) 1714091d4532SNeel Natu { 1715091d4532SNeel Natu int type, vector; 1716091d4532SNeel Natu 1717091d4532SNeel Natu KASSERT(info & VM_INTINFO_VALID, ("intinfo must be valid: %#lx", info)); 1718091d4532SNeel Natu type = info & VM_INTINFO_TYPE; 1719091d4532SNeel Natu vector = info & 0xff; 1720091d4532SNeel Natu 1721091d4532SNeel Natu /* Table 6-4, "Interrupt and Exception Classes", Intel SDM, Vol 3 */ 1722091d4532SNeel Natu switch (type) { 1723091d4532SNeel Natu case VM_INTINFO_HWINTR: 1724091d4532SNeel Natu case VM_INTINFO_SWINTR: 1725091d4532SNeel Natu case VM_INTINFO_NMI: 1726091d4532SNeel Natu return (EXC_BENIGN); 1727091d4532SNeel Natu default: 1728091d4532SNeel Natu /* 1729091d4532SNeel Natu * Hardware exception. 1730091d4532SNeel Natu * 1731091d4532SNeel Natu * SVM and VT-x use identical type values to represent NMI, 1732091d4532SNeel Natu * hardware interrupt and software interrupt. 1733091d4532SNeel Natu * 1734091d4532SNeel Natu * SVM uses type '3' for all exceptions. VT-x uses type '3' 1735091d4532SNeel Natu * for exceptions except #BP and #OF. #BP and #OF use a type 1736091d4532SNeel Natu * value of '5' or '6'. Therefore we don't check for explicit 1737091d4532SNeel Natu * values of 'type' to classify 'intinfo' into a hardware 1738091d4532SNeel Natu * exception. 1739091d4532SNeel Natu */ 1740091d4532SNeel Natu break; 1741091d4532SNeel Natu } 1742091d4532SNeel Natu 1743091d4532SNeel Natu switch (vector) { 1744091d4532SNeel Natu case IDT_PF: 1745091d4532SNeel Natu case IDT_VE: 1746091d4532SNeel Natu return (EXC_PAGEFAULT); 1747091d4532SNeel Natu case IDT_DE: 1748091d4532SNeel Natu case IDT_TS: 1749091d4532SNeel Natu case IDT_NP: 1750091d4532SNeel Natu case IDT_SS: 1751091d4532SNeel Natu case IDT_GP: 1752091d4532SNeel Natu return (EXC_CONTRIBUTORY); 1753091d4532SNeel Natu default: 1754091d4532SNeel Natu return (EXC_BENIGN); 1755091d4532SNeel Natu } 1756091d4532SNeel Natu } 1757091d4532SNeel Natu 1758091d4532SNeel Natu static int 175980cb5d84SJohn Baldwin nested_fault(struct vcpu *vcpu, uint64_t info1, uint64_t info2, 1760091d4532SNeel Natu uint64_t *retinfo) 1761091d4532SNeel Natu { 1762091d4532SNeel Natu enum exc_class exc1, exc2; 1763091d4532SNeel Natu int type1, vector1; 1764091d4532SNeel Natu 1765091d4532SNeel Natu KASSERT(info1 & VM_INTINFO_VALID, ("info1 %#lx is not valid", info1)); 1766091d4532SNeel Natu KASSERT(info2 & VM_INTINFO_VALID, ("info2 %#lx is not valid", info2)); 1767091d4532SNeel Natu 1768091d4532SNeel Natu /* 1769091d4532SNeel Natu * If an exception occurs while attempting to call the double-fault 1770091d4532SNeel Natu * handler the processor enters shutdown mode (aka triple fault). 1771091d4532SNeel Natu */ 1772091d4532SNeel Natu type1 = info1 & VM_INTINFO_TYPE; 1773091d4532SNeel Natu vector1 = info1 & 0xff; 1774091d4532SNeel Natu if (type1 == VM_INTINFO_HWEXCEPTION && vector1 == IDT_DF) { 177580cb5d84SJohn Baldwin VMM_CTR2(vcpu, "triple fault: info1(%#lx), info2(%#lx)", 1776091d4532SNeel Natu info1, info2); 177780cb5d84SJohn Baldwin vm_suspend(vcpu->vm, VM_SUSPEND_TRIPLEFAULT); 1778091d4532SNeel Natu *retinfo = 0; 1779091d4532SNeel Natu return (0); 1780091d4532SNeel Natu } 1781091d4532SNeel Natu 1782091d4532SNeel Natu /* 1783091d4532SNeel Natu * Table 6-5 "Conditions for Generating a Double Fault", Intel SDM, Vol3 1784091d4532SNeel Natu */ 1785091d4532SNeel Natu exc1 = exception_class(info1); 1786091d4532SNeel Natu exc2 = exception_class(info2); 1787091d4532SNeel Natu if ((exc1 == EXC_CONTRIBUTORY && exc2 == EXC_CONTRIBUTORY) || 1788091d4532SNeel Natu (exc1 == EXC_PAGEFAULT && exc2 != EXC_BENIGN)) { 1789091d4532SNeel Natu /* Convert nested fault into a double fault. */ 1790091d4532SNeel Natu *retinfo = IDT_DF; 1791091d4532SNeel Natu *retinfo |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION; 1792091d4532SNeel Natu *retinfo |= VM_INTINFO_DEL_ERRCODE; 1793091d4532SNeel Natu } else { 1794091d4532SNeel Natu /* Handle exceptions serially */ 1795091d4532SNeel Natu *retinfo = info2; 1796091d4532SNeel Natu } 1797091d4532SNeel Natu return (1); 1798091d4532SNeel Natu } 1799091d4532SNeel Natu 1800091d4532SNeel Natu static uint64_t 1801091d4532SNeel Natu vcpu_exception_intinfo(struct vcpu *vcpu) 1802091d4532SNeel Natu { 1803091d4532SNeel Natu uint64_t info = 0; 1804091d4532SNeel Natu 1805091d4532SNeel Natu if (vcpu->exception_pending) { 1806c9c75df4SNeel Natu info = vcpu->exc_vector & 0xff; 1807091d4532SNeel Natu info |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION; 1808c9c75df4SNeel Natu if (vcpu->exc_errcode_valid) { 1809091d4532SNeel Natu info |= VM_INTINFO_DEL_ERRCODE; 1810c9c75df4SNeel Natu info |= (uint64_t)vcpu->exc_errcode << 32; 1811091d4532SNeel Natu } 1812091d4532SNeel Natu } 1813091d4532SNeel Natu return (info); 1814091d4532SNeel Natu } 1815091d4532SNeel Natu 1816091d4532SNeel Natu int 181780cb5d84SJohn Baldwin vm_entry_intinfo(struct vcpu *vcpu, uint64_t *retinfo) 1818091d4532SNeel Natu { 1819091d4532SNeel Natu uint64_t info1, info2; 1820091d4532SNeel Natu int valid; 1821091d4532SNeel Natu 1822091d4532SNeel Natu info1 = vcpu->exitintinfo; 1823091d4532SNeel Natu vcpu->exitintinfo = 0; 1824091d4532SNeel Natu 1825091d4532SNeel Natu info2 = 0; 1826091d4532SNeel Natu if (vcpu->exception_pending) { 1827091d4532SNeel Natu info2 = vcpu_exception_intinfo(vcpu); 1828091d4532SNeel Natu vcpu->exception_pending = 0; 182980cb5d84SJohn Baldwin VMM_CTR2(vcpu, "Exception %d delivered: %#lx", 1830c9c75df4SNeel Natu vcpu->exc_vector, info2); 1831091d4532SNeel Natu } 1832091d4532SNeel Natu 1833091d4532SNeel Natu if ((info1 & VM_INTINFO_VALID) && (info2 & VM_INTINFO_VALID)) { 183480cb5d84SJohn Baldwin valid = nested_fault(vcpu, info1, info2, retinfo); 1835091d4532SNeel Natu } else if (info1 & VM_INTINFO_VALID) { 1836091d4532SNeel Natu *retinfo = info1; 1837091d4532SNeel Natu valid = 1; 1838091d4532SNeel Natu } else if (info2 & VM_INTINFO_VALID) { 1839091d4532SNeel Natu *retinfo = info2; 1840091d4532SNeel Natu valid = 1; 1841091d4532SNeel Natu } else { 1842091d4532SNeel Natu valid = 0; 1843091d4532SNeel Natu } 1844091d4532SNeel Natu 1845091d4532SNeel Natu if (valid) { 1846d3956e46SJohn Baldwin VMM_CTR4(vcpu, "%s: info1(%#lx), info2(%#lx), " 1847091d4532SNeel Natu "retinfo(%#lx)", __func__, info1, info2, *retinfo); 1848091d4532SNeel Natu } 1849091d4532SNeel Natu 1850091d4532SNeel Natu return (valid); 1851091d4532SNeel Natu } 1852091d4532SNeel Natu 1853091d4532SNeel Natu int 18543f0f4b15SJohn Baldwin vm_get_intinfo(struct vcpu *vcpu, uint64_t *info1, uint64_t *info2) 1855091d4532SNeel Natu { 1856091d4532SNeel Natu *info1 = vcpu->exitintinfo; 1857091d4532SNeel Natu *info2 = vcpu_exception_intinfo(vcpu); 1858091d4532SNeel Natu return (0); 1859091d4532SNeel Natu } 1860091d4532SNeel Natu 1861091d4532SNeel Natu int 1862d3956e46SJohn Baldwin vm_inject_exception(struct vcpu *vcpu, int vector, int errcode_valid, 1863c9c75df4SNeel Natu uint32_t errcode, int restart_instruction) 1864366f6083SPeter Grehan { 186547b9935dSNeel Natu uint64_t regval; 186673505a10SRobert Wing int error __diagused; 1867dc506506SNeel Natu 1868c9c75df4SNeel Natu if (vector < 0 || vector >= 32) 1869366f6083SPeter Grehan return (EINVAL); 1870366f6083SPeter Grehan 1871091d4532SNeel Natu /* 1872091d4532SNeel Natu * A double fault exception should never be injected directly into 1873091d4532SNeel Natu * the guest. It is a derived exception that results from specific 1874091d4532SNeel Natu * combinations of nested faults. 1875091d4532SNeel Natu */ 1876c9c75df4SNeel Natu if (vector == IDT_DF) 1877091d4532SNeel Natu return (EINVAL); 1878091d4532SNeel Natu 1879dc506506SNeel Natu if (vcpu->exception_pending) { 1880d3956e46SJohn Baldwin VMM_CTR2(vcpu, "Unable to inject exception %d due to " 1881c9c75df4SNeel Natu "pending exception %d", vector, vcpu->exc_vector); 1882dc506506SNeel Natu return (EBUSY); 1883dc506506SNeel Natu } 1884dc506506SNeel Natu 188547b9935dSNeel Natu if (errcode_valid) { 188647b9935dSNeel Natu /* 188747b9935dSNeel Natu * Exceptions don't deliver an error code in real mode. 188847b9935dSNeel Natu */ 1889d3956e46SJohn Baldwin error = vm_get_register(vcpu, VM_REG_GUEST_CR0, ®val); 189047b9935dSNeel Natu KASSERT(!error, ("%s: error %d getting CR0", __func__, error)); 189147b9935dSNeel Natu if (!(regval & CR0_PE)) 189247b9935dSNeel Natu errcode_valid = 0; 189347b9935dSNeel Natu } 189447b9935dSNeel Natu 18952ce12423SNeel Natu /* 18962ce12423SNeel Natu * From section 26.6.1 "Interruptibility State" in Intel SDM: 18972ce12423SNeel Natu * 18982ce12423SNeel Natu * Event blocking by "STI" or "MOV SS" is cleared after guest executes 18992ce12423SNeel Natu * one instruction or incurs an exception. 19002ce12423SNeel Natu */ 1901d3956e46SJohn Baldwin error = vm_set_register(vcpu, VM_REG_GUEST_INTR_SHADOW, 0); 19022ce12423SNeel Natu KASSERT(error == 0, ("%s: error %d clearing interrupt shadow", 19032ce12423SNeel Natu __func__, error)); 19042ce12423SNeel Natu 1905c9c75df4SNeel Natu if (restart_instruction) 1906d3956e46SJohn Baldwin vm_restart_instruction(vcpu); 1907c9c75df4SNeel Natu 1908dc506506SNeel Natu vcpu->exception_pending = 1; 1909c9c75df4SNeel Natu vcpu->exc_vector = vector; 1910c9c75df4SNeel Natu vcpu->exc_errcode = errcode; 1911c9c75df4SNeel Natu vcpu->exc_errcode_valid = errcode_valid; 1912d3956e46SJohn Baldwin VMM_CTR1(vcpu, "Exception %d pending", vector); 1913dc506506SNeel Natu return (0); 1914dc506506SNeel Natu } 1915dc506506SNeel Natu 1916d37f2adbSNeel Natu void 1917d3956e46SJohn Baldwin vm_inject_fault(struct vcpu *vcpu, int vector, int errcode_valid, int errcode) 1918dc506506SNeel Natu { 191973505a10SRobert Wing int error __diagused, restart_instruction; 1920dc506506SNeel Natu 1921c9c75df4SNeel Natu restart_instruction = 1; 1922d37f2adbSNeel Natu 1923d3956e46SJohn Baldwin error = vm_inject_exception(vcpu, vector, errcode_valid, 1924c9c75df4SNeel Natu errcode, restart_instruction); 1925dc506506SNeel Natu KASSERT(error == 0, ("vm_inject_exception error %d", error)); 1926dc506506SNeel Natu } 1927dc506506SNeel Natu 1928dc506506SNeel Natu void 1929d3956e46SJohn Baldwin vm_inject_pf(struct vcpu *vcpu, int error_code, uint64_t cr2) 1930fd949af6SNeel Natu { 193173505a10SRobert Wing int error __diagused; 193237a723a5SNeel Natu 1933d3956e46SJohn Baldwin VMM_CTR2(vcpu, "Injecting page fault: error_code %#x, cr2 %#lx", 193437a723a5SNeel Natu error_code, cr2); 193537a723a5SNeel Natu 1936d3956e46SJohn Baldwin error = vm_set_register(vcpu, VM_REG_GUEST_CR2, cr2); 193737a723a5SNeel Natu KASSERT(error == 0, ("vm_set_register(cr2) error %d", error)); 1938fd949af6SNeel Natu 1939d3956e46SJohn Baldwin vm_inject_fault(vcpu, IDT_PF, 1, error_code); 1940366f6083SPeter Grehan } 1941366f6083SPeter Grehan 194261592433SNeel Natu static VMM_STAT(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); 1943366f6083SPeter Grehan 1944f352ff0cSNeel Natu int 19453f0f4b15SJohn Baldwin vm_inject_nmi(struct vcpu *vcpu) 1946f352ff0cSNeel Natu { 1947f352ff0cSNeel Natu 1948f352ff0cSNeel Natu vcpu->nmi_pending = 1; 19493f0f4b15SJohn Baldwin vcpu_notify_event(vcpu, false); 1950f352ff0cSNeel Natu return (0); 1951f352ff0cSNeel Natu } 1952f352ff0cSNeel Natu 1953f352ff0cSNeel Natu int 195480cb5d84SJohn Baldwin vm_nmi_pending(struct vcpu *vcpu) 1955f352ff0cSNeel Natu { 1956f352ff0cSNeel Natu return (vcpu->nmi_pending); 1957f352ff0cSNeel Natu } 1958f352ff0cSNeel Natu 1959f352ff0cSNeel Natu void 196080cb5d84SJohn Baldwin vm_nmi_clear(struct vcpu *vcpu) 1961f352ff0cSNeel Natu { 1962f352ff0cSNeel Natu if (vcpu->nmi_pending == 0) 1963f352ff0cSNeel Natu panic("vm_nmi_clear: inconsistent nmi_pending state"); 1964f352ff0cSNeel Natu 1965f352ff0cSNeel Natu vcpu->nmi_pending = 0; 19663dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VCPU_NMI_COUNT, 1); 1967366f6083SPeter Grehan } 1968366f6083SPeter Grehan 19690775fbb4STycho Nightingale static VMM_STAT(VCPU_EXTINT_COUNT, "number of ExtINTs delivered to vcpu"); 19700775fbb4STycho Nightingale 19710775fbb4STycho Nightingale int 19723f0f4b15SJohn Baldwin vm_inject_extint(struct vcpu *vcpu) 19730775fbb4STycho Nightingale { 19740775fbb4STycho Nightingale 19750775fbb4STycho Nightingale vcpu->extint_pending = 1; 19763f0f4b15SJohn Baldwin vcpu_notify_event(vcpu, false); 19770775fbb4STycho Nightingale return (0); 19780775fbb4STycho Nightingale } 19790775fbb4STycho Nightingale 19800775fbb4STycho Nightingale int 198180cb5d84SJohn Baldwin vm_extint_pending(struct vcpu *vcpu) 19820775fbb4STycho Nightingale { 19830775fbb4STycho Nightingale return (vcpu->extint_pending); 19840775fbb4STycho Nightingale } 19850775fbb4STycho Nightingale 19860775fbb4STycho Nightingale void 198780cb5d84SJohn Baldwin vm_extint_clear(struct vcpu *vcpu) 19880775fbb4STycho Nightingale { 19890775fbb4STycho Nightingale if (vcpu->extint_pending == 0) 19900775fbb4STycho Nightingale panic("vm_extint_clear: inconsistent extint_pending state"); 19910775fbb4STycho Nightingale 19920775fbb4STycho Nightingale vcpu->extint_pending = 0; 19933dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VCPU_EXTINT_COUNT, 1); 19940775fbb4STycho Nightingale } 19950775fbb4STycho Nightingale 1996366f6083SPeter Grehan int 19973f0f4b15SJohn Baldwin vm_get_capability(struct vcpu *vcpu, int type, int *retval) 1998366f6083SPeter Grehan { 1999366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 2000366f6083SPeter Grehan return (EINVAL); 2001366f6083SPeter Grehan 20023f0f4b15SJohn Baldwin return (vmmops_getcap(vcpu->cookie, type, retval)); 2003366f6083SPeter Grehan } 2004366f6083SPeter Grehan 2005366f6083SPeter Grehan int 20063f0f4b15SJohn Baldwin vm_set_capability(struct vcpu *vcpu, int type, int val) 2007366f6083SPeter Grehan { 2008366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 2009366f6083SPeter Grehan return (EINVAL); 2010366f6083SPeter Grehan 20113f0f4b15SJohn Baldwin return (vmmops_setcap(vcpu->cookie, type, val)); 2012366f6083SPeter Grehan } 2013366f6083SPeter Grehan 2014950af9ffSJohn Baldwin struct vm * 2015950af9ffSJohn Baldwin vcpu_vm(struct vcpu *vcpu) 2016950af9ffSJohn Baldwin { 2017950af9ffSJohn Baldwin return (vcpu->vm); 2018950af9ffSJohn Baldwin } 2019950af9ffSJohn Baldwin 2020950af9ffSJohn Baldwin int 2021950af9ffSJohn Baldwin vcpu_vcpuid(struct vcpu *vcpu) 2022950af9ffSJohn Baldwin { 2023950af9ffSJohn Baldwin return (vcpu->vcpuid); 2024950af9ffSJohn Baldwin } 2025950af9ffSJohn Baldwin 2026950af9ffSJohn Baldwin struct vcpu * 2027950af9ffSJohn Baldwin vm_vcpu(struct vm *vm, int vcpuid) 2028950af9ffSJohn Baldwin { 202998568a00SJohn Baldwin return (vm->vcpu[vcpuid]); 2030950af9ffSJohn Baldwin } 2031950af9ffSJohn Baldwin 2032366f6083SPeter Grehan struct vlapic * 2033d3956e46SJohn Baldwin vm_lapic(struct vcpu *vcpu) 2034366f6083SPeter Grehan { 2035d3956e46SJohn Baldwin return (vcpu->vlapic); 2036366f6083SPeter Grehan } 2037366f6083SPeter Grehan 2038565bbb86SNeel Natu struct vioapic * 2039565bbb86SNeel Natu vm_ioapic(struct vm *vm) 2040565bbb86SNeel Natu { 2041565bbb86SNeel Natu 2042565bbb86SNeel Natu return (vm->vioapic); 2043565bbb86SNeel Natu } 2044565bbb86SNeel Natu 204508e3ff32SNeel Natu struct vhpet * 204608e3ff32SNeel Natu vm_hpet(struct vm *vm) 204708e3ff32SNeel Natu { 204808e3ff32SNeel Natu 204908e3ff32SNeel Natu return (vm->vhpet); 205008e3ff32SNeel Natu } 205108e3ff32SNeel Natu 2052490d56c5SEd Maste bool 2053366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 2054366f6083SPeter Grehan { 2055490d56c5SEd Maste int b, f, i, n, s; 2056366f6083SPeter Grehan char *val, *cp, *cp2; 2057490d56c5SEd Maste bool found; 2058366f6083SPeter Grehan 2059366f6083SPeter Grehan /* 206007044a96SNeel Natu * XXX 206107044a96SNeel Natu * The length of an environment variable is limited to 128 bytes which 206207044a96SNeel Natu * puts an upper limit on the number of passthru devices that may be 206307044a96SNeel Natu * specified using a single environment variable. 206407044a96SNeel Natu * 206507044a96SNeel Natu * Work around this by scanning multiple environment variable 206607044a96SNeel Natu * names instead of a single one - yuck! 2067366f6083SPeter Grehan */ 206807044a96SNeel Natu const char *names[] = { "pptdevs", "pptdevs2", "pptdevs3", NULL }; 206907044a96SNeel Natu 207007044a96SNeel Natu /* set pptdevs="1/2/3 4/5/6 7/8/9 10/11/12" */ 2071490d56c5SEd Maste found = false; 207207044a96SNeel Natu for (i = 0; names[i] != NULL && !found; i++) { 20732be111bfSDavide Italiano cp = val = kern_getenv(names[i]); 2074366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 2075366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 2076366f6083SPeter Grehan *cp2 = '\0'; 2077366f6083SPeter Grehan 2078366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 2079366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 2080490d56c5SEd Maste found = true; 2081366f6083SPeter Grehan break; 2082366f6083SPeter Grehan } 2083366f6083SPeter Grehan 2084366f6083SPeter Grehan if (cp2 != NULL) 2085366f6083SPeter Grehan *cp2++ = ' '; 2086366f6083SPeter Grehan 2087366f6083SPeter Grehan cp = cp2; 2088366f6083SPeter Grehan } 2089366f6083SPeter Grehan freeenv(val); 209007044a96SNeel Natu } 2091366f6083SPeter Grehan return (found); 2092366f6083SPeter Grehan } 2093366f6083SPeter Grehan 2094366f6083SPeter Grehan void * 2095366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 2096366f6083SPeter Grehan { 2097366f6083SPeter Grehan 2098366f6083SPeter Grehan return (vm->iommu); 2099366f6083SPeter Grehan } 2100366f6083SPeter Grehan 210175dd3366SNeel Natu int 21023f0f4b15SJohn Baldwin vcpu_set_state(struct vcpu *vcpu, enum vcpu_state newstate, bool from_idle) 2103366f6083SPeter Grehan { 210475dd3366SNeel Natu int error; 2105366f6083SPeter Grehan 210675dd3366SNeel Natu vcpu_lock(vcpu); 21073f0f4b15SJohn Baldwin error = vcpu_set_state_locked(vcpu, newstate, from_idle); 210875dd3366SNeel Natu vcpu_unlock(vcpu); 210975dd3366SNeel Natu 211075dd3366SNeel Natu return (error); 211175dd3366SNeel Natu } 211275dd3366SNeel Natu 211375dd3366SNeel Natu enum vcpu_state 2114d3956e46SJohn Baldwin vcpu_get_state(struct vcpu *vcpu, int *hostcpu) 2115366f6083SPeter Grehan { 211675dd3366SNeel Natu enum vcpu_state state; 2117366f6083SPeter Grehan 211875dd3366SNeel Natu vcpu_lock(vcpu); 211975dd3366SNeel Natu state = vcpu->state; 2120d3c11f40SPeter Grehan if (hostcpu != NULL) 2121d3c11f40SPeter Grehan *hostcpu = vcpu->hostcpu; 212275dd3366SNeel Natu vcpu_unlock(vcpu); 2123366f6083SPeter Grehan 212475dd3366SNeel Natu return (state); 2125366f6083SPeter Grehan } 2126366f6083SPeter Grehan 212795ebc360SNeel Natu int 21283f0f4b15SJohn Baldwin vm_activate_cpu(struct vcpu *vcpu) 2129366f6083SPeter Grehan { 21303f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 2131366f6083SPeter Grehan 21323f0f4b15SJohn Baldwin if (CPU_ISSET(vcpu->vcpuid, &vm->active_cpus)) 213395ebc360SNeel Natu return (EBUSY); 213422d822c6SNeel Natu 21353f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "activated"); 21363f0f4b15SJohn Baldwin CPU_SET_ATOMIC(vcpu->vcpuid, &vm->active_cpus); 213795ebc360SNeel Natu return (0); 2138366f6083SPeter Grehan } 2139366f6083SPeter Grehan 2140fc276d92SJohn Baldwin int 21413f0f4b15SJohn Baldwin vm_suspend_cpu(struct vm *vm, struct vcpu *vcpu) 2142fc276d92SJohn Baldwin { 21433f0f4b15SJohn Baldwin if (vcpu == NULL) { 2144fc276d92SJohn Baldwin vm->debug_cpus = vm->active_cpus; 21453f0f4b15SJohn Baldwin for (int i = 0; i < vm->maxcpus; i++) { 2146fc276d92SJohn Baldwin if (CPU_ISSET(i, &vm->active_cpus)) 21473f0f4b15SJohn Baldwin vcpu_notify_event(vm_vcpu(vm, i), false); 2148fc276d92SJohn Baldwin } 2149fc276d92SJohn Baldwin } else { 21503f0f4b15SJohn Baldwin if (!CPU_ISSET(vcpu->vcpuid, &vm->active_cpus)) 2151fc276d92SJohn Baldwin return (EINVAL); 2152fc276d92SJohn Baldwin 21533f0f4b15SJohn Baldwin CPU_SET_ATOMIC(vcpu->vcpuid, &vm->debug_cpus); 21543f0f4b15SJohn Baldwin vcpu_notify_event(vcpu, false); 2155fc276d92SJohn Baldwin } 2156fc276d92SJohn Baldwin return (0); 2157fc276d92SJohn Baldwin } 2158fc276d92SJohn Baldwin 2159fc276d92SJohn Baldwin int 21603f0f4b15SJohn Baldwin vm_resume_cpu(struct vm *vm, struct vcpu *vcpu) 2161fc276d92SJohn Baldwin { 2162fc276d92SJohn Baldwin 21633f0f4b15SJohn Baldwin if (vcpu == NULL) { 2164fc276d92SJohn Baldwin CPU_ZERO(&vm->debug_cpus); 2165fc276d92SJohn Baldwin } else { 21663f0f4b15SJohn Baldwin if (!CPU_ISSET(vcpu->vcpuid, &vm->debug_cpus)) 2167fc276d92SJohn Baldwin return (EINVAL); 2168fc276d92SJohn Baldwin 21693f0f4b15SJohn Baldwin CPU_CLR_ATOMIC(vcpu->vcpuid, &vm->debug_cpus); 2170fc276d92SJohn Baldwin } 2171fc276d92SJohn Baldwin return (0); 2172fc276d92SJohn Baldwin } 2173fc276d92SJohn Baldwin 2174fc276d92SJohn Baldwin int 217580cb5d84SJohn Baldwin vcpu_debugged(struct vcpu *vcpu) 2176fc276d92SJohn Baldwin { 2177fc276d92SJohn Baldwin 217880cb5d84SJohn Baldwin return (CPU_ISSET(vcpu->vcpuid, &vcpu->vm->debug_cpus)); 2179fc276d92SJohn Baldwin } 2180fc276d92SJohn Baldwin 2181a5615c90SPeter Grehan cpuset_t 2182366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 2183366f6083SPeter Grehan { 2184366f6083SPeter Grehan 2185366f6083SPeter Grehan return (vm->active_cpus); 2186366f6083SPeter Grehan } 2187366f6083SPeter Grehan 218895ebc360SNeel Natu cpuset_t 2189fc276d92SJohn Baldwin vm_debug_cpus(struct vm *vm) 2190fc276d92SJohn Baldwin { 2191fc276d92SJohn Baldwin 2192fc276d92SJohn Baldwin return (vm->debug_cpus); 2193fc276d92SJohn Baldwin } 2194fc276d92SJohn Baldwin 2195fc276d92SJohn Baldwin cpuset_t 219695ebc360SNeel Natu vm_suspended_cpus(struct vm *vm) 219795ebc360SNeel Natu { 219895ebc360SNeel Natu 219995ebc360SNeel Natu return (vm->suspended_cpus); 220095ebc360SNeel Natu } 220195ebc360SNeel Natu 2202c0f35dbfSJohn Baldwin /* 2203c0f35dbfSJohn Baldwin * Returns the subset of vCPUs in tostart that are awaiting startup. 2204c0f35dbfSJohn Baldwin * These vCPUs are also marked as no longer awaiting startup. 2205c0f35dbfSJohn Baldwin */ 2206c0f35dbfSJohn Baldwin cpuset_t 2207c0f35dbfSJohn Baldwin vm_start_cpus(struct vm *vm, const cpuset_t *tostart) 2208c0f35dbfSJohn Baldwin { 2209c0f35dbfSJohn Baldwin cpuset_t set; 2210c0f35dbfSJohn Baldwin 2211c0f35dbfSJohn Baldwin mtx_lock(&vm->rendezvous_mtx); 2212c0f35dbfSJohn Baldwin CPU_AND(&set, &vm->startup_cpus, tostart); 2213c0f35dbfSJohn Baldwin CPU_ANDNOT(&vm->startup_cpus, &vm->startup_cpus, &set); 2214c0f35dbfSJohn Baldwin mtx_unlock(&vm->rendezvous_mtx); 2215c0f35dbfSJohn Baldwin return (set); 2216c0f35dbfSJohn Baldwin } 2217c0f35dbfSJohn Baldwin 2218c0f35dbfSJohn Baldwin void 2219c0f35dbfSJohn Baldwin vm_await_start(struct vm *vm, const cpuset_t *waiting) 2220c0f35dbfSJohn Baldwin { 2221c0f35dbfSJohn Baldwin mtx_lock(&vm->rendezvous_mtx); 2222c0f35dbfSJohn Baldwin CPU_OR(&vm->startup_cpus, &vm->startup_cpus, waiting); 2223c0f35dbfSJohn Baldwin mtx_unlock(&vm->rendezvous_mtx); 2224c0f35dbfSJohn Baldwin } 2225c0f35dbfSJohn Baldwin 2226366f6083SPeter Grehan void * 22273dc3d32aSJohn Baldwin vcpu_stats(struct vcpu *vcpu) 2228366f6083SPeter Grehan { 2229366f6083SPeter Grehan 22303dc3d32aSJohn Baldwin return (vcpu->stats); 2231366f6083SPeter Grehan } 2232e9027382SNeel Natu 2233e9027382SNeel Natu int 22343f0f4b15SJohn Baldwin vm_get_x2apic_state(struct vcpu *vcpu, enum x2apic_state *state) 2235e9027382SNeel Natu { 22363f0f4b15SJohn Baldwin *state = vcpu->x2apic_state; 2237e9027382SNeel Natu 2238e9027382SNeel Natu return (0); 2239e9027382SNeel Natu } 2240e9027382SNeel Natu 2241e9027382SNeel Natu int 22423f0f4b15SJohn Baldwin vm_set_x2apic_state(struct vcpu *vcpu, enum x2apic_state state) 2243e9027382SNeel Natu { 22443f23d3caSNeel Natu if (state >= X2APIC_STATE_LAST) 2245e9027382SNeel Natu return (EINVAL); 2246e9027382SNeel Natu 2247d3956e46SJohn Baldwin vcpu->x2apic_state = state; 2248e9027382SNeel Natu 2249d3956e46SJohn Baldwin vlapic_set_x2apic_state(vcpu, state); 225073820fb0SNeel Natu 2251e9027382SNeel Natu return (0); 2252e9027382SNeel Natu } 225375dd3366SNeel Natu 225422821874SNeel Natu /* 225522821874SNeel Natu * This function is called to ensure that a vcpu "sees" a pending event 225622821874SNeel Natu * as soon as possible: 225722821874SNeel Natu * - If the vcpu thread is sleeping then it is woken up. 225822821874SNeel Natu * - If the vcpu is running on a different host_cpu then an IPI will be directed 225922821874SNeel Natu * to the host_cpu to cause the vcpu to trap into the hypervisor. 226022821874SNeel Natu */ 2261248e6799SNeel Natu static void 2262248e6799SNeel Natu vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr) 226375dd3366SNeel Natu { 226475dd3366SNeel Natu int hostcpu; 226575dd3366SNeel Natu 226675dd3366SNeel Natu hostcpu = vcpu->hostcpu; 2267ef39d7e9SNeel Natu if (vcpu->state == VCPU_RUNNING) { 2268ef39d7e9SNeel Natu KASSERT(hostcpu != NOCPU, ("vcpu running on invalid hostcpu")); 2269de5ea6b6SNeel Natu if (hostcpu != curcpu) { 2270ef39d7e9SNeel Natu if (lapic_intr) { 2271add611fdSNeel Natu vlapic_post_intr(vcpu->vlapic, hostcpu, 2272add611fdSNeel Natu vmm_ipinum); 2273ef39d7e9SNeel Natu } else { 227475dd3366SNeel Natu ipi_cpu(hostcpu, vmm_ipinum); 227575dd3366SNeel Natu } 2276ef39d7e9SNeel Natu } else { 2277ef39d7e9SNeel Natu /* 2278ef39d7e9SNeel Natu * If the 'vcpu' is running on 'curcpu' then it must 2279ef39d7e9SNeel Natu * be sending a notification to itself (e.g. SELF_IPI). 2280ef39d7e9SNeel Natu * The pending event will be picked up when the vcpu 2281ef39d7e9SNeel Natu * transitions back to guest context. 2282ef39d7e9SNeel Natu */ 2283ef39d7e9SNeel Natu } 2284ef39d7e9SNeel Natu } else { 2285ef39d7e9SNeel Natu KASSERT(hostcpu == NOCPU, ("vcpu state %d not consistent " 2286ef39d7e9SNeel Natu "with hostcpu %d", vcpu->state, hostcpu)); 2287366f6083SPeter Grehan if (vcpu->state == VCPU_SLEEPING) 2288366f6083SPeter Grehan wakeup_one(vcpu); 2289366f6083SPeter Grehan } 2290248e6799SNeel Natu } 2291248e6799SNeel Natu 2292248e6799SNeel Natu void 22933f0f4b15SJohn Baldwin vcpu_notify_event(struct vcpu *vcpu, bool lapic_intr) 2294248e6799SNeel Natu { 2295248e6799SNeel Natu vcpu_lock(vcpu); 2296248e6799SNeel Natu vcpu_notify_event_locked(vcpu, lapic_intr); 2297f76fc5d4SNeel Natu vcpu_unlock(vcpu); 2298f76fc5d4SNeel Natu } 2299318224bbSNeel Natu 2300318224bbSNeel Natu struct vmspace * 2301c945c9ddSMark Johnston vm_vmspace(struct vm *vm) 2302318224bbSNeel Natu { 2303318224bbSNeel Natu return (vm->vmspace); 2304318224bbSNeel Natu } 2305565bbb86SNeel Natu 2306*c76c2a19SMark Johnston struct vm_mem * 2307*c76c2a19SMark Johnston vm_mem(struct vm *vm) 2308*c76c2a19SMark Johnston { 2309*c76c2a19SMark Johnston return (&vm->mem); 2310*c76c2a19SMark Johnston } 2311*c76c2a19SMark Johnston 2312565bbb86SNeel Natu int 2313565bbb86SNeel Natu vm_apicid2vcpuid(struct vm *vm, int apicid) 2314565bbb86SNeel Natu { 2315565bbb86SNeel Natu /* 2316565bbb86SNeel Natu * XXX apic id is assumed to be numerically identical to vcpu id 2317565bbb86SNeel Natu */ 2318565bbb86SNeel Natu return (apicid); 2319565bbb86SNeel Natu } 23205b8a8cd1SNeel Natu 2321b837daddSKonstantin Belousov int 2322d8be3d52SJohn Baldwin vm_smp_rendezvous(struct vcpu *vcpu, cpuset_t dest, 23235b8a8cd1SNeel Natu vm_rendezvous_func_t func, void *arg) 23245b8a8cd1SNeel Natu { 2325d8be3d52SJohn Baldwin struct vm *vm = vcpu->vm; 2326b837daddSKonstantin Belousov int error, i; 2327970955e4SNeel Natu 23285b8a8cd1SNeel Natu /* 23295b8a8cd1SNeel Natu * Enforce that this function is called without any locks 23305b8a8cd1SNeel Natu */ 23315b8a8cd1SNeel Natu WITNESS_WARN(WARN_PANIC, NULL, "vm_smp_rendezvous"); 23325b8a8cd1SNeel Natu 23335b8a8cd1SNeel Natu restart: 23345b8a8cd1SNeel Natu mtx_lock(&vm->rendezvous_mtx); 23355b8a8cd1SNeel Natu if (vm->rendezvous_func != NULL) { 23365b8a8cd1SNeel Natu /* 23375b8a8cd1SNeel Natu * If a rendezvous is already in progress then we need to 23383f0f4b15SJohn Baldwin * call the rendezvous handler in case this 'vcpu' is one 23395b8a8cd1SNeel Natu * of the targets of the rendezvous. 23405b8a8cd1SNeel Natu */ 2341d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Rendezvous already in progress"); 23425b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 2343d8be3d52SJohn Baldwin error = vm_handle_rendezvous(vcpu); 2344b837daddSKonstantin Belousov if (error != 0) 2345b837daddSKonstantin Belousov return (error); 23465b8a8cd1SNeel Natu goto restart; 23475b8a8cd1SNeel Natu } 23485b8a8cd1SNeel Natu KASSERT(vm->rendezvous_func == NULL, ("vm_smp_rendezvous: previous " 23495b8a8cd1SNeel Natu "rendezvous is still in progress")); 23505b8a8cd1SNeel Natu 2351d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Initiating rendezvous"); 23525b8a8cd1SNeel Natu vm->rendezvous_req_cpus = dest; 23535b8a8cd1SNeel Natu CPU_ZERO(&vm->rendezvous_done_cpus); 23545b8a8cd1SNeel Natu vm->rendezvous_arg = arg; 2355869dbab7SAndriy Gapon vm->rendezvous_func = func; 23565b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 23575b8a8cd1SNeel Natu 2358970955e4SNeel Natu /* 2359970955e4SNeel Natu * Wake up any sleeping vcpus and trigger a VM-exit in any running 2360970955e4SNeel Natu * vcpus so they handle the rendezvous as soon as possible. 2361970955e4SNeel Natu */ 2362a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 2363970955e4SNeel Natu if (CPU_ISSET(i, &dest)) 23643f0f4b15SJohn Baldwin vcpu_notify_event(vm_vcpu(vm, i), false); 2365970955e4SNeel Natu } 2366970955e4SNeel Natu 2367d8be3d52SJohn Baldwin return (vm_handle_rendezvous(vcpu)); 23685b8a8cd1SNeel Natu } 2369762fd208STycho Nightingale 2370762fd208STycho Nightingale struct vatpic * 2371762fd208STycho Nightingale vm_atpic(struct vm *vm) 2372762fd208STycho Nightingale { 2373762fd208STycho Nightingale return (vm->vatpic); 2374762fd208STycho Nightingale } 2375e883c9bbSTycho Nightingale 2376e883c9bbSTycho Nightingale struct vatpit * 2377e883c9bbSTycho Nightingale vm_atpit(struct vm *vm) 2378e883c9bbSTycho Nightingale { 2379e883c9bbSTycho Nightingale return (vm->vatpit); 2380e883c9bbSTycho Nightingale } 2381d17b5104SNeel Natu 2382160ef77aSNeel Natu struct vpmtmr * 2383160ef77aSNeel Natu vm_pmtmr(struct vm *vm) 2384160ef77aSNeel Natu { 2385160ef77aSNeel Natu 2386160ef77aSNeel Natu return (vm->vpmtmr); 2387160ef77aSNeel Natu } 2388160ef77aSNeel Natu 23890dafa5cdSNeel Natu struct vrtc * 23900dafa5cdSNeel Natu vm_rtc(struct vm *vm) 23910dafa5cdSNeel Natu { 23920dafa5cdSNeel Natu 23930dafa5cdSNeel Natu return (vm->vrtc); 23940dafa5cdSNeel Natu } 23950dafa5cdSNeel Natu 2396d17b5104SNeel Natu enum vm_reg_name 2397d17b5104SNeel Natu vm_segment_name(int seg) 2398d17b5104SNeel Natu { 2399d17b5104SNeel Natu static enum vm_reg_name seg_names[] = { 2400d17b5104SNeel Natu VM_REG_GUEST_ES, 2401d17b5104SNeel Natu VM_REG_GUEST_CS, 2402d17b5104SNeel Natu VM_REG_GUEST_SS, 2403d17b5104SNeel Natu VM_REG_GUEST_DS, 2404d17b5104SNeel Natu VM_REG_GUEST_FS, 2405d17b5104SNeel Natu VM_REG_GUEST_GS 2406d17b5104SNeel Natu }; 2407d17b5104SNeel Natu 2408d17b5104SNeel Natu KASSERT(seg >= 0 && seg < nitems(seg_names), 2409d17b5104SNeel Natu ("%s: invalid segment encoding %d", __func__, seg)); 2410d17b5104SNeel Natu return (seg_names[seg]); 2411d17b5104SNeel Natu } 2412cf1d80d8SPeter Grehan 2413d665d229SNeel Natu void 24142b4fe856SJohn Baldwin vm_copy_teardown(struct vm_copyinfo *copyinfo, int num_copyinfo) 2415d665d229SNeel Natu { 2416d665d229SNeel Natu int idx; 2417d665d229SNeel Natu 2418d665d229SNeel Natu for (idx = 0; idx < num_copyinfo; idx++) { 2419d665d229SNeel Natu if (copyinfo[idx].cookie != NULL) 2420d665d229SNeel Natu vm_gpa_release(copyinfo[idx].cookie); 2421d665d229SNeel Natu } 2422d665d229SNeel Natu bzero(copyinfo, num_copyinfo * sizeof(struct vm_copyinfo)); 2423d665d229SNeel Natu } 2424d665d229SNeel Natu 2425d665d229SNeel Natu int 2426d3956e46SJohn Baldwin vm_copy_setup(struct vcpu *vcpu, struct vm_guest_paging *paging, 2427d665d229SNeel Natu uint64_t gla, size_t len, int prot, struct vm_copyinfo *copyinfo, 24289c4d5478SNeel Natu int num_copyinfo, int *fault) 2429d665d229SNeel Natu { 2430d665d229SNeel Natu int error, idx, nused; 2431d665d229SNeel Natu size_t n, off, remaining; 2432d665d229SNeel Natu void *hva, *cookie; 2433d665d229SNeel Natu uint64_t gpa; 2434d665d229SNeel Natu 2435d665d229SNeel Natu bzero(copyinfo, sizeof(struct vm_copyinfo) * num_copyinfo); 2436d665d229SNeel Natu 2437d665d229SNeel Natu nused = 0; 2438d665d229SNeel Natu remaining = len; 2439d665d229SNeel Natu while (remaining > 0) { 2440d19fa9c1SPierre Pronchery if (nused >= num_copyinfo) 2441d19fa9c1SPierre Pronchery return (EFAULT); 2442d3956e46SJohn Baldwin error = vm_gla2gpa(vcpu, paging, gla, prot, &gpa, fault); 24439c4d5478SNeel Natu if (error || *fault) 2444d665d229SNeel Natu return (error); 2445d665d229SNeel Natu off = gpa & PAGE_MASK; 2446d665d229SNeel Natu n = min(remaining, PAGE_SIZE - off); 2447d665d229SNeel Natu copyinfo[nused].gpa = gpa; 2448d665d229SNeel Natu copyinfo[nused].len = n; 2449d665d229SNeel Natu remaining -= n; 2450d665d229SNeel Natu gla += n; 2451d665d229SNeel Natu nused++; 2452d665d229SNeel Natu } 2453d665d229SNeel Natu 2454d665d229SNeel Natu for (idx = 0; idx < nused; idx++) { 2455d3956e46SJohn Baldwin hva = vm_gpa_hold(vcpu, copyinfo[idx].gpa, 24569b1aa8d6SNeel Natu copyinfo[idx].len, prot, &cookie); 2457d665d229SNeel Natu if (hva == NULL) 2458d665d229SNeel Natu break; 2459d665d229SNeel Natu copyinfo[idx].hva = hva; 2460d665d229SNeel Natu copyinfo[idx].cookie = cookie; 2461d665d229SNeel Natu } 2462d665d229SNeel Natu 2463d665d229SNeel Natu if (idx != nused) { 24642b4fe856SJohn Baldwin vm_copy_teardown(copyinfo, num_copyinfo); 24659c4d5478SNeel Natu return (EFAULT); 2466d665d229SNeel Natu } else { 24679c4d5478SNeel Natu *fault = 0; 2468d665d229SNeel Natu return (0); 2469d665d229SNeel Natu } 2470d665d229SNeel Natu } 2471d665d229SNeel Natu 2472d665d229SNeel Natu void 24732b4fe856SJohn Baldwin vm_copyin(struct vm_copyinfo *copyinfo, void *kaddr, size_t len) 2474d665d229SNeel Natu { 2475d665d229SNeel Natu char *dst; 2476d665d229SNeel Natu int idx; 2477d665d229SNeel Natu 2478d665d229SNeel Natu dst = kaddr; 2479d665d229SNeel Natu idx = 0; 2480d665d229SNeel Natu while (len > 0) { 2481d665d229SNeel Natu bcopy(copyinfo[idx].hva, dst, copyinfo[idx].len); 2482d665d229SNeel Natu len -= copyinfo[idx].len; 2483d665d229SNeel Natu dst += copyinfo[idx].len; 2484d665d229SNeel Natu idx++; 2485d665d229SNeel Natu } 2486d665d229SNeel Natu } 2487d665d229SNeel Natu 2488d665d229SNeel Natu void 24892b4fe856SJohn Baldwin vm_copyout(const void *kaddr, struct vm_copyinfo *copyinfo, size_t len) 2490d665d229SNeel Natu { 2491d665d229SNeel Natu const char *src; 2492d665d229SNeel Natu int idx; 2493d665d229SNeel Natu 2494d665d229SNeel Natu src = kaddr; 2495d665d229SNeel Natu idx = 0; 2496d665d229SNeel Natu while (len > 0) { 2497d665d229SNeel Natu bcopy(src, copyinfo[idx].hva, copyinfo[idx].len); 2498d665d229SNeel Natu len -= copyinfo[idx].len; 2499d665d229SNeel Natu src += copyinfo[idx].len; 2500d665d229SNeel Natu idx++; 2501d665d229SNeel Natu } 2502d665d229SNeel Natu } 2503cf1d80d8SPeter Grehan 2504cf1d80d8SPeter Grehan /* 2505cf1d80d8SPeter Grehan * Return the amount of in-use and wired memory for the VM. Since 2506cf1d80d8SPeter Grehan * these are global stats, only return the values with for vCPU 0 2507cf1d80d8SPeter Grehan */ 2508cf1d80d8SPeter Grehan VMM_STAT_DECLARE(VMM_MEM_RESIDENT); 2509cf1d80d8SPeter Grehan VMM_STAT_DECLARE(VMM_MEM_WIRED); 2510cf1d80d8SPeter Grehan 2511cf1d80d8SPeter Grehan static void 25123f0f4b15SJohn Baldwin vm_get_rescnt(struct vcpu *vcpu, struct vmm_stat_type *stat) 2513cf1d80d8SPeter Grehan { 2514cf1d80d8SPeter Grehan 25153f0f4b15SJohn Baldwin if (vcpu->vcpuid == 0) { 25163f0f4b15SJohn Baldwin vmm_stat_set(vcpu, VMM_MEM_RESIDENT, PAGE_SIZE * 25173f0f4b15SJohn Baldwin vmspace_resident_count(vcpu->vm->vmspace)); 2518cf1d80d8SPeter Grehan } 2519cf1d80d8SPeter Grehan } 2520cf1d80d8SPeter Grehan 2521cf1d80d8SPeter Grehan static void 25223f0f4b15SJohn Baldwin vm_get_wiredcnt(struct vcpu *vcpu, struct vmm_stat_type *stat) 2523cf1d80d8SPeter Grehan { 2524cf1d80d8SPeter Grehan 25253f0f4b15SJohn Baldwin if (vcpu->vcpuid == 0) { 25263f0f4b15SJohn Baldwin vmm_stat_set(vcpu, VMM_MEM_WIRED, PAGE_SIZE * 25273f0f4b15SJohn Baldwin pmap_wired_count(vmspace_pmap(vcpu->vm->vmspace))); 2528cf1d80d8SPeter Grehan } 2529cf1d80d8SPeter Grehan } 2530cf1d80d8SPeter Grehan 2531cf1d80d8SPeter Grehan VMM_STAT_FUNC(VMM_MEM_RESIDENT, "Resident memory", vm_get_rescnt); 2532cf1d80d8SPeter Grehan VMM_STAT_FUNC(VMM_MEM_WIRED, "Wired memory", vm_get_wiredcnt); 2533483d953aSJohn Baldwin 2534483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 2535483d953aSJohn Baldwin static int 2536483d953aSJohn Baldwin vm_snapshot_vcpus(struct vm *vm, struct vm_snapshot_meta *meta) 2537483d953aSJohn Baldwin { 2538a7db532eSJohn Baldwin uint64_t tsc, now; 2539483d953aSJohn Baldwin int ret; 2540483d953aSJohn Baldwin struct vcpu *vcpu; 254135abc6c2SJohn Baldwin uint16_t i, maxcpus; 2542483d953aSJohn Baldwin 2543a7db532eSJohn Baldwin now = rdtsc(); 254435abc6c2SJohn Baldwin maxcpus = vm_get_maxcpus(vm); 254535abc6c2SJohn Baldwin for (i = 0; i < maxcpus; i++) { 254698568a00SJohn Baldwin vcpu = vm->vcpu[i]; 254798568a00SJohn Baldwin if (vcpu == NULL) 254898568a00SJohn Baldwin continue; 2549483d953aSJohn Baldwin 2550483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->x2apic_state, meta, ret, done); 2551483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exitintinfo, meta, ret, done); 2552483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_vector, meta, ret, done); 2553483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_errcode_valid, meta, ret, done); 2554483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_errcode, meta, ret, done); 2555483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->guest_xcr0, meta, ret, done); 2556483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exitinfo, meta, ret, done); 2557483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->nextrip, meta, ret, done); 2558a7db532eSJohn Baldwin 2559a7db532eSJohn Baldwin /* 2560a7db532eSJohn Baldwin * Save the absolute TSC value by adding now to tsc_offset. 2561483d953aSJohn Baldwin * 2562483d953aSJohn Baldwin * It will be turned turned back into an actual offset when the 2563483d953aSJohn Baldwin * TSC restore function is called 2564483d953aSJohn Baldwin */ 2565a7db532eSJohn Baldwin tsc = now + vcpu->tsc_offset; 2566a7db532eSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(tsc, meta, ret, done); 2567281b496fSVitaliy Gusev if (meta->op == VM_SNAPSHOT_RESTORE) 2568281b496fSVitaliy Gusev vcpu->tsc_offset = tsc; 2569483d953aSJohn Baldwin } 2570483d953aSJohn Baldwin 2571483d953aSJohn Baldwin done: 2572483d953aSJohn Baldwin return (ret); 2573483d953aSJohn Baldwin } 2574483d953aSJohn Baldwin 2575483d953aSJohn Baldwin static int 2576483d953aSJohn Baldwin vm_snapshot_vm(struct vm *vm, struct vm_snapshot_meta *meta) 2577483d953aSJohn Baldwin { 2578483d953aSJohn Baldwin int ret; 2579483d953aSJohn Baldwin 2580483d953aSJohn Baldwin ret = vm_snapshot_vcpus(vm, meta); 2581a7db532eSJohn Baldwin if (ret != 0) 2582483d953aSJohn Baldwin goto done; 2583483d953aSJohn Baldwin 2584c0f35dbfSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vm->startup_cpus, meta, ret, done); 2585483d953aSJohn Baldwin done: 2586483d953aSJohn Baldwin return (ret); 2587483d953aSJohn Baldwin } 2588483d953aSJohn Baldwin 2589483d953aSJohn Baldwin static int 25901aa51504SJohn Baldwin vm_snapshot_vcpu(struct vm *vm, struct vm_snapshot_meta *meta) 2591483d953aSJohn Baldwin { 259235abc6c2SJohn Baldwin int error; 25931aa51504SJohn Baldwin struct vcpu *vcpu; 259435abc6c2SJohn Baldwin uint16_t i, maxcpus; 2595483d953aSJohn Baldwin 2596483d953aSJohn Baldwin error = 0; 2597483d953aSJohn Baldwin 259835abc6c2SJohn Baldwin maxcpus = vm_get_maxcpus(vm); 259935abc6c2SJohn Baldwin for (i = 0; i < maxcpus; i++) { 260098568a00SJohn Baldwin vcpu = vm->vcpu[i]; 260198568a00SJohn Baldwin if (vcpu == NULL) 260298568a00SJohn Baldwin continue; 26031aa51504SJohn Baldwin 2604869c8d19SJohn Baldwin error = vmmops_vcpu_snapshot(vcpu->cookie, meta); 2605483d953aSJohn Baldwin if (error != 0) { 2606483d953aSJohn Baldwin printf("%s: failed to snapshot vmcs/vmcb data for " 2607483d953aSJohn Baldwin "vCPU: %d; error: %d\n", __func__, i, error); 2608483d953aSJohn Baldwin goto done; 2609483d953aSJohn Baldwin } 2610483d953aSJohn Baldwin } 2611483d953aSJohn Baldwin 2612483d953aSJohn Baldwin done: 2613483d953aSJohn Baldwin return (error); 2614483d953aSJohn Baldwin } 2615483d953aSJohn Baldwin 2616483d953aSJohn Baldwin /* 2617483d953aSJohn Baldwin * Save kernel-side structures to user-space for snapshotting. 2618483d953aSJohn Baldwin */ 2619483d953aSJohn Baldwin int 2620483d953aSJohn Baldwin vm_snapshot_req(struct vm *vm, struct vm_snapshot_meta *meta) 2621483d953aSJohn Baldwin { 2622483d953aSJohn Baldwin int ret = 0; 2623483d953aSJohn Baldwin 2624483d953aSJohn Baldwin switch (meta->dev_req) { 2625483d953aSJohn Baldwin case STRUCT_VMCX: 26261aa51504SJohn Baldwin ret = vm_snapshot_vcpu(vm, meta); 2627483d953aSJohn Baldwin break; 2628483d953aSJohn Baldwin case STRUCT_VM: 2629483d953aSJohn Baldwin ret = vm_snapshot_vm(vm, meta); 2630483d953aSJohn Baldwin break; 2631483d953aSJohn Baldwin case STRUCT_VIOAPIC: 2632483d953aSJohn Baldwin ret = vioapic_snapshot(vm_ioapic(vm), meta); 2633483d953aSJohn Baldwin break; 2634483d953aSJohn Baldwin case STRUCT_VLAPIC: 2635483d953aSJohn Baldwin ret = vlapic_snapshot(vm, meta); 2636483d953aSJohn Baldwin break; 2637483d953aSJohn Baldwin case STRUCT_VHPET: 2638483d953aSJohn Baldwin ret = vhpet_snapshot(vm_hpet(vm), meta); 2639483d953aSJohn Baldwin break; 2640483d953aSJohn Baldwin case STRUCT_VATPIC: 2641483d953aSJohn Baldwin ret = vatpic_snapshot(vm_atpic(vm), meta); 2642483d953aSJohn Baldwin break; 2643483d953aSJohn Baldwin case STRUCT_VATPIT: 2644483d953aSJohn Baldwin ret = vatpit_snapshot(vm_atpit(vm), meta); 2645483d953aSJohn Baldwin break; 2646483d953aSJohn Baldwin case STRUCT_VPMTMR: 2647483d953aSJohn Baldwin ret = vpmtmr_snapshot(vm_pmtmr(vm), meta); 2648483d953aSJohn Baldwin break; 2649483d953aSJohn Baldwin case STRUCT_VRTC: 2650483d953aSJohn Baldwin ret = vrtc_snapshot(vm_rtc(vm), meta); 2651483d953aSJohn Baldwin break; 2652483d953aSJohn Baldwin default: 2653483d953aSJohn Baldwin printf("%s: failed to find the requested type %#x\n", 2654483d953aSJohn Baldwin __func__, meta->dev_req); 2655483d953aSJohn Baldwin ret = (EINVAL); 2656483d953aSJohn Baldwin } 2657483d953aSJohn Baldwin return (ret); 2658483d953aSJohn Baldwin } 2659483d953aSJohn Baldwin 266080cb5d84SJohn Baldwin void 266180cb5d84SJohn Baldwin vm_set_tsc_offset(struct vcpu *vcpu, uint64_t offset) 2662483d953aSJohn Baldwin { 2663483d953aSJohn Baldwin vcpu->tsc_offset = offset; 2664483d953aSJohn Baldwin } 2665483d953aSJohn Baldwin 2666483d953aSJohn Baldwin int 2667483d953aSJohn Baldwin vm_restore_time(struct vm *vm) 2668483d953aSJohn Baldwin { 266935abc6c2SJohn Baldwin int error; 2670483d953aSJohn Baldwin uint64_t now; 2671483d953aSJohn Baldwin struct vcpu *vcpu; 267235abc6c2SJohn Baldwin uint16_t i, maxcpus; 2673483d953aSJohn Baldwin 2674483d953aSJohn Baldwin now = rdtsc(); 2675483d953aSJohn Baldwin 2676483d953aSJohn Baldwin error = vhpet_restore_time(vm_hpet(vm)); 2677483d953aSJohn Baldwin if (error) 2678483d953aSJohn Baldwin return (error); 2679483d953aSJohn Baldwin 268035abc6c2SJohn Baldwin maxcpus = vm_get_maxcpus(vm); 268135abc6c2SJohn Baldwin for (i = 0; i < maxcpus; i++) { 268298568a00SJohn Baldwin vcpu = vm->vcpu[i]; 268398568a00SJohn Baldwin if (vcpu == NULL) 268498568a00SJohn Baldwin continue; 2685483d953aSJohn Baldwin 2686869c8d19SJohn Baldwin error = vmmops_restore_tsc(vcpu->cookie, 26871aa51504SJohn Baldwin vcpu->tsc_offset - now); 2688483d953aSJohn Baldwin if (error) 2689483d953aSJohn Baldwin return (error); 2690483d953aSJohn Baldwin } 2691483d953aSJohn Baldwin 2692483d953aSJohn Baldwin return (0); 2693483d953aSJohn Baldwin } 2694483d953aSJohn Baldwin #endif 2695