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 29366f6083SPeter Grehan #include <sys/cdefs.h> 30483d953aSJohn Baldwin #include "opt_bhyve_snapshot.h" 31483d953aSJohn Baldwin 32366f6083SPeter Grehan #include <sys/param.h> 3338f1b189SPeter Grehan #include <sys/systm.h> 34366f6083SPeter Grehan #include <sys/kernel.h> 35366f6083SPeter Grehan #include <sys/module.h> 36366f6083SPeter Grehan #include <sys/sysctl.h> 37366f6083SPeter Grehan #include <sys/malloc.h> 38366f6083SPeter Grehan #include <sys/pcpu.h> 39366f6083SPeter Grehan #include <sys/lock.h> 40366f6083SPeter Grehan #include <sys/mutex.h> 41366f6083SPeter Grehan #include <sys/proc.h> 42318224bbSNeel Natu #include <sys/rwlock.h> 43366f6083SPeter Grehan #include <sys/sched.h> 44366f6083SPeter Grehan #include <sys/smp.h> 4567b69e76SJohn Baldwin #include <sys/sx.h> 46483d953aSJohn Baldwin #include <sys/vnode.h> 47366f6083SPeter Grehan 48366f6083SPeter Grehan #include <vm/vm.h> 493c48106aSKonstantin Belousov #include <vm/vm_param.h> 503c48106aSKonstantin Belousov #include <vm/vm_extern.h> 51318224bbSNeel Natu #include <vm/vm_object.h> 52318224bbSNeel Natu #include <vm/vm_page.h> 53318224bbSNeel Natu #include <vm/pmap.h> 54318224bbSNeel Natu #include <vm/vm_map.h> 55483d953aSJohn Baldwin #include <vm/vm_pager.h> 56483d953aSJohn Baldwin #include <vm/vm_kern.h> 57483d953aSJohn Baldwin #include <vm/vnode_pager.h> 58483d953aSJohn Baldwin #include <vm/swap_pager.h> 59483d953aSJohn Baldwin #include <vm/uma.h> 60366f6083SPeter Grehan 6163e62d39SJohn Baldwin #include <machine/cpu.h> 62366f6083SPeter Grehan #include <machine/pcb.h> 6375dd3366SNeel Natu #include <machine/smp.h> 64bd50262fSKonstantin Belousov #include <machine/md_var.h> 651c052192SNeel Natu #include <x86/psl.h> 6634a6b2d6SJohn Baldwin #include <x86/apicreg.h> 6715add60dSPeter Grehan #include <x86/ifunc.h> 68366f6083SPeter Grehan 69366f6083SPeter Grehan #include <machine/vmm.h> 70e813a873SNeel Natu #include <machine/vmm_instruction_emul.h> 71483d953aSJohn Baldwin #include <machine/vmm_snapshot.h> 72565bbb86SNeel Natu 73b9ef152bSMark Johnston #include <dev/vmm/vmm_dev.h> 743ccb0233SMark Johnston #include <dev/vmm/vmm_ktr.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 134318224bbSNeel Natu struct mem_seg { 1359b1aa8d6SNeel Natu size_t len; 1369b1aa8d6SNeel Natu bool sysmem; 1379b1aa8d6SNeel Natu struct vm_object *object; 1389b1aa8d6SNeel Natu }; 139e47fe318SCorvin Köhne #define VM_MAX_MEMSEGS 4 1409b1aa8d6SNeel Natu 1419b1aa8d6SNeel Natu struct mem_map { 142318224bbSNeel Natu vm_paddr_t gpa; 143318224bbSNeel Natu size_t len; 1449b1aa8d6SNeel Natu vm_ooffset_t segoff; 1459b1aa8d6SNeel Natu int segid; 1469b1aa8d6SNeel Natu int prot; 1479b1aa8d6SNeel Natu int flags; 148318224bbSNeel Natu }; 14900d3723fSConrad Meyer #define VM_MAX_MEMMAPS 8 150366f6083SPeter Grehan 151366f6083SPeter Grehan /* 1525fcf252fSNeel Natu * Initialization: 1535fcf252fSNeel Natu * (o) initialized the first time the VM is created 1545fcf252fSNeel Natu * (i) initialized when VM is created and when it is reinitialized 1555fcf252fSNeel Natu * (x) initialized before use 15667b69e76SJohn Baldwin * 15767b69e76SJohn Baldwin * Locking: 15867b69e76SJohn Baldwin * [m] mem_segs_lock 15967b69e76SJohn Baldwin * [r] rendezvous_mtx 16067b69e76SJohn Baldwin * [v] reads require one frozen vcpu, writes require freezing all vcpus 161366f6083SPeter Grehan */ 1625fcf252fSNeel Natu struct vm { 1635fcf252fSNeel Natu void *cookie; /* (i) cpu-specific data */ 1645fcf252fSNeel Natu void *iommu; /* (x) iommu-specific data */ 1655fcf252fSNeel Natu struct vhpet *vhpet; /* (i) virtual HPET */ 1665fcf252fSNeel Natu struct vioapic *vioapic; /* (i) virtual ioapic */ 1675fcf252fSNeel Natu struct vatpic *vatpic; /* (i) virtual atpic */ 1685fcf252fSNeel Natu struct vatpit *vatpit; /* (i) virtual atpit */ 169160ef77aSNeel Natu struct vpmtmr *vpmtmr; /* (i) virtual ACPI PM timer */ 1700dafa5cdSNeel Natu struct vrtc *vrtc; /* (o) virtual RTC */ 1715fcf252fSNeel Natu volatile cpuset_t active_cpus; /* (i) active vcpus */ 172fc276d92SJohn Baldwin volatile cpuset_t debug_cpus; /* (i) vcpus stopped for debug */ 173c0f35dbfSJohn Baldwin cpuset_t startup_cpus; /* (i) [r] waiting for startup */ 1745fcf252fSNeel Natu int suspend; /* (i) stop VM execution */ 17598568a00SJohn Baldwin bool dying; /* (o) is dying */ 1765fcf252fSNeel Natu volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */ 1775fcf252fSNeel Natu volatile cpuset_t halted_cpus; /* (x) cpus in a hard halt */ 17867b69e76SJohn Baldwin cpuset_t rendezvous_req_cpus; /* (x) [r] rendezvous requested */ 17967b69e76SJohn Baldwin cpuset_t rendezvous_done_cpus; /* (x) [r] rendezvous finished */ 18067b69e76SJohn Baldwin void *rendezvous_arg; /* (x) [r] rendezvous func/arg */ 1815b8a8cd1SNeel Natu vm_rendezvous_func_t rendezvous_func; 1825fcf252fSNeel Natu struct mtx rendezvous_mtx; /* (o) rendezvous lock */ 18367b69e76SJohn Baldwin struct mem_map mem_maps[VM_MAX_MEMMAPS]; /* (i) [m+v] guest address space */ 18467b69e76SJohn Baldwin struct mem_seg mem_segs[VM_MAX_MEMSEGS]; /* (o) [m+v] guest memory regions */ 1855fcf252fSNeel Natu struct vmspace *vmspace; /* (o) guest's address space */ 186df95cc76SKa Ho Ng char name[VM_MAX_NAMELEN+1]; /* (o) virtual machine name */ 187ee98f99dSJohn Baldwin struct vcpu **vcpu; /* (o) guest vcpus */ 18801d822d3SRodney W. Grimes /* The following describe the vm cpu topology */ 18901d822d3SRodney W. Grimes uint16_t sockets; /* (o) num of sockets */ 19001d822d3SRodney W. Grimes uint16_t cores; /* (o) num of cores/socket */ 19101d822d3SRodney W. Grimes uint16_t threads; /* (o) num of threads/core */ 19201d822d3SRodney W. Grimes uint16_t maxcpus; /* (o) max pluggable cpus */ 19367b69e76SJohn Baldwin struct sx mem_segs_lock; /* (o) */ 19498568a00SJohn Baldwin struct sx vcpus_init_lock; /* (o) */ 195366f6083SPeter Grehan }; 196366f6083SPeter Grehan 197950af9ffSJohn Baldwin #define VMM_CTR0(vcpu, format) \ 198950af9ffSJohn Baldwin VCPU_CTR0((vcpu)->vm, (vcpu)->vcpuid, format) 199950af9ffSJohn Baldwin 200950af9ffSJohn Baldwin #define VMM_CTR1(vcpu, format, p1) \ 201950af9ffSJohn Baldwin VCPU_CTR1((vcpu)->vm, (vcpu)->vcpuid, format, p1) 202950af9ffSJohn Baldwin 203950af9ffSJohn Baldwin #define VMM_CTR2(vcpu, format, p1, p2) \ 204950af9ffSJohn Baldwin VCPU_CTR2((vcpu)->vm, (vcpu)->vcpuid, format, p1, p2) 205950af9ffSJohn Baldwin 206950af9ffSJohn Baldwin #define VMM_CTR3(vcpu, format, p1, p2, p3) \ 207950af9ffSJohn Baldwin VCPU_CTR3((vcpu)->vm, (vcpu)->vcpuid, format, p1, p2, p3) 208950af9ffSJohn Baldwin 209950af9ffSJohn Baldwin #define VMM_CTR4(vcpu, format, p1, p2, p3, p4) \ 210950af9ffSJohn Baldwin VCPU_CTR4((vcpu)->vm, (vcpu)->vcpuid, format, p1, p2, p3, p4) 211950af9ffSJohn Baldwin 212d5408b1dSNeel Natu static int vmm_initialized; 213d5408b1dSNeel Natu 21415add60dSPeter Grehan static void vmmops_panic(void); 215366f6083SPeter Grehan 21615add60dSPeter Grehan static void 21715add60dSPeter Grehan vmmops_panic(void) 21815add60dSPeter Grehan { 21915add60dSPeter Grehan panic("vmm_ops func called when !vmm_is_intel() && !vmm_is_svm()"); 22015add60dSPeter Grehan } 22115add60dSPeter Grehan 22215add60dSPeter Grehan #define DEFINE_VMMOPS_IFUNC(ret_type, opname, args) \ 22315add60dSPeter Grehan DEFINE_IFUNC(static, ret_type, vmmops_##opname, args) \ 22415add60dSPeter Grehan { \ 22515add60dSPeter Grehan if (vmm_is_intel()) \ 22615add60dSPeter Grehan return (vmm_ops_intel.opname); \ 22715add60dSPeter Grehan else if (vmm_is_svm()) \ 22815add60dSPeter Grehan return (vmm_ops_amd.opname); \ 22915add60dSPeter Grehan else \ 23015add60dSPeter Grehan return ((ret_type (*)args)vmmops_panic); \ 23115add60dSPeter Grehan } 23215add60dSPeter Grehan 23315add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(int, modinit, (int ipinum)) 23415add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(int, modcleanup, (void)) 23515add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(void, modresume, (void)) 23615add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(void *, init, (struct vm *vm, struct pmap *pmap)) 237869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, run, (void *vcpui, register_t rip, struct pmap *pmap, 238869c8d19SJohn Baldwin struct vm_eventinfo *info)) 23915add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(void, cleanup, (void *vmi)) 240950af9ffSJohn Baldwin DEFINE_VMMOPS_IFUNC(void *, vcpu_init, (void *vmi, struct vcpu *vcpu, 241950af9ffSJohn Baldwin int vcpu_id)) 242869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(void, vcpu_cleanup, (void *vcpui)) 243869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, getreg, (void *vcpui, int num, uint64_t *retval)) 244869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, setreg, (void *vcpui, int num, uint64_t val)) 245869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, getdesc, (void *vcpui, int num, struct seg_desc *desc)) 246869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, setdesc, (void *vcpui, int num, struct seg_desc *desc)) 247869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, getcap, (void *vcpui, int num, int *retval)) 248869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, setcap, (void *vcpui, int num, int val)) 24915add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(struct vmspace *, vmspace_alloc, (vm_offset_t min, 25015add60dSPeter Grehan vm_offset_t max)) 25115add60dSPeter Grehan DEFINE_VMMOPS_IFUNC(void, vmspace_free, (struct vmspace *vmspace)) 252869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(struct vlapic *, vlapic_init, (void *vcpui)) 253869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(void, vlapic_cleanup, (struct vlapic *vlapic)) 254483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 255869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, vcpu_snapshot, (void *vcpui, 256869c8d19SJohn Baldwin struct vm_snapshot_meta *meta)) 257869c8d19SJohn Baldwin DEFINE_VMMOPS_IFUNC(int, restore_tsc, (void *vcpui, uint64_t now)) 258483d953aSJohn Baldwin #endif 259366f6083SPeter Grehan 2606ac73777STycho Nightingale SDT_PROVIDER_DEFINE(vmm); 2616ac73777STycho Nightingale 262366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm"); 263366f6083SPeter Grehan 264366f6083SPeter Grehan /* statistics */ 26561592433SNeel Natu static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 266366f6083SPeter Grehan 267b40598c5SPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 268b40598c5SPawel Biernacki NULL); 269add611fdSNeel Natu 270055fc2cbSNeel Natu /* 271055fc2cbSNeel Natu * Halt the guest if all vcpus are executing a HLT instruction with 272055fc2cbSNeel Natu * interrupts disabled. 273055fc2cbSNeel Natu */ 274055fc2cbSNeel Natu static int halt_detection_enabled = 1; 275055fc2cbSNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, halt_detection, CTLFLAG_RDTUN, 276055fc2cbSNeel Natu &halt_detection_enabled, 0, 277055fc2cbSNeel Natu "Halt VM if all vcpus execute HLT with interrupts disabled"); 278055fc2cbSNeel Natu 279978f3da1SAndriy Gapon static int vmm_ipinum; 280add611fdSNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, ipinum, CTLFLAG_RD, &vmm_ipinum, 0, 281add611fdSNeel Natu "IPI vector used for vcpu notifications"); 282add611fdSNeel Natu 283b0538143SNeel Natu static int trace_guest_exceptions; 284b0538143SNeel Natu SYSCTL_INT(_hw_vmm, OID_AUTO, trace_guest_exceptions, CTLFLAG_RDTUN, 285b0538143SNeel Natu &trace_guest_exceptions, 0, 286b0538143SNeel Natu "Trap into hypervisor on all guest exceptions and reflect them back"); 287b0538143SNeel Natu 2883ba952e1SCorvin Köhne static int trap_wbinvd; 2893ba952e1SCorvin Köhne SYSCTL_INT(_hw_vmm, OID_AUTO, trap_wbinvd, CTLFLAG_RDTUN, &trap_wbinvd, 0, 2903ba952e1SCorvin Köhne "WBINVD triggers a VM-exit"); 2913ba952e1SCorvin Köhne 292ee98f99dSJohn Baldwin u_int vm_maxcpu; 293ee98f99dSJohn Baldwin SYSCTL_UINT(_hw_vmm, OID_AUTO, maxcpu, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, 294ee98f99dSJohn Baldwin &vm_maxcpu, 0, "Maximum number of vCPUs"); 295ee98f99dSJohn Baldwin 2969b1aa8d6SNeel Natu static void vm_free_memmap(struct vm *vm, int ident); 2979b1aa8d6SNeel Natu static bool sysmem_mapping(struct vm *vm, struct mem_map *mm); 298248e6799SNeel Natu static void vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr); 299248e6799SNeel Natu 30093e81baaSMark Johnston /* global statistics */ 30193e81baaSMark Johnston VMM_STAT(VCPU_MIGRATIONS, "vcpu migration across host cpus"); 30293e81baaSMark Johnston VMM_STAT(VMEXIT_COUNT, "total number of vm exits"); 30393e81baaSMark Johnston VMM_STAT(VMEXIT_EXTINT, "vm exits due to external interrupt"); 30493e81baaSMark Johnston VMM_STAT(VMEXIT_HLT, "number of times hlt was intercepted"); 30593e81baaSMark Johnston VMM_STAT(VMEXIT_CR_ACCESS, "number of times %cr access was intercepted"); 30693e81baaSMark Johnston VMM_STAT(VMEXIT_RDMSR, "number of times rdmsr was intercepted"); 30793e81baaSMark Johnston VMM_STAT(VMEXIT_WRMSR, "number of times wrmsr was intercepted"); 30893e81baaSMark Johnston VMM_STAT(VMEXIT_MTRAP, "number of monitor trap exits"); 30993e81baaSMark Johnston VMM_STAT(VMEXIT_PAUSE, "number of times pause was intercepted"); 31093e81baaSMark Johnston VMM_STAT(VMEXIT_INTR_WINDOW, "vm exits due to interrupt window opening"); 31193e81baaSMark Johnston VMM_STAT(VMEXIT_NMI_WINDOW, "vm exits due to nmi window opening"); 31293e81baaSMark Johnston VMM_STAT(VMEXIT_INOUT, "number of times in/out was intercepted"); 31393e81baaSMark Johnston VMM_STAT(VMEXIT_CPUID, "number of times cpuid was intercepted"); 31493e81baaSMark Johnston VMM_STAT(VMEXIT_NESTED_FAULT, "vm exits due to nested page fault"); 31593e81baaSMark Johnston VMM_STAT(VMEXIT_INST_EMUL, "vm exits for instruction emulation"); 31693e81baaSMark Johnston VMM_STAT(VMEXIT_UNKNOWN, "number of vm exits for unknown reason"); 31793e81baaSMark Johnston VMM_STAT(VMEXIT_ASTPENDING, "number of times astpending at exit"); 31893e81baaSMark Johnston VMM_STAT(VMEXIT_REQIDLE, "number of times idle requested at exit"); 31993e81baaSMark Johnston VMM_STAT(VMEXIT_USERSPACE, "number of vm exits handled in userspace"); 32093e81baaSMark Johnston VMM_STAT(VMEXIT_RENDEZVOUS, "number of times rendezvous pending at exit"); 32193e81baaSMark Johnston VMM_STAT(VMEXIT_EXCEPTION, "number of vm exits due to exceptions"); 32293e81baaSMark Johnston 323ee98f99dSJohn Baldwin /* 324ee98f99dSJohn Baldwin * Upper limit on vm_maxcpu. Limited by use of uint16_t types for CPU 325ee98f99dSJohn Baldwin * counts as well as range of vpid values for VT-x and by the capacity 326ee98f99dSJohn Baldwin * of cpuset_t masks. The call to new_unrhdr() in vpid_init() in 327ee98f99dSJohn Baldwin * vmx.c requires 'vm_maxcpu + 1 <= 0xffff', hence the '- 1' below. 328ee98f99dSJohn Baldwin */ 329ee98f99dSJohn Baldwin #define VM_MAXCPU MIN(0xffff - 1, CPU_SETSIZE) 330ee98f99dSJohn Baldwin 331248e6799SNeel Natu #ifdef KTR 332248e6799SNeel Natu static const char * 333248e6799SNeel Natu vcpu_state2str(enum vcpu_state state) 334248e6799SNeel Natu { 335248e6799SNeel Natu 336248e6799SNeel Natu switch (state) { 337248e6799SNeel Natu case VCPU_IDLE: 338248e6799SNeel Natu return ("idle"); 339248e6799SNeel Natu case VCPU_FROZEN: 340248e6799SNeel Natu return ("frozen"); 341248e6799SNeel Natu case VCPU_RUNNING: 342248e6799SNeel Natu return ("running"); 343248e6799SNeel Natu case VCPU_SLEEPING: 344248e6799SNeel Natu return ("sleeping"); 345248e6799SNeel Natu default: 346248e6799SNeel Natu return ("unknown"); 347248e6799SNeel Natu } 348248e6799SNeel Natu } 349248e6799SNeel Natu #endif 350248e6799SNeel Natu 351366f6083SPeter Grehan static void 35298568a00SJohn Baldwin vcpu_cleanup(struct vcpu *vcpu, bool destroy) 353366f6083SPeter Grehan { 354869c8d19SJohn Baldwin vmmops_vlapic_cleanup(vcpu->vlapic); 355869c8d19SJohn Baldwin vmmops_vcpu_cleanup(vcpu->cookie); 3561aa51504SJohn Baldwin vcpu->cookie = NULL; 3575fcf252fSNeel Natu if (destroy) { 358366f6083SPeter Grehan vmm_stat_free(vcpu->stats); 35938f1b189SPeter Grehan fpu_save_area_free(vcpu->guestfpu); 36008ebb360SJohn Baldwin vcpu_lock_destroy(vcpu); 361af3b48e1SJohn Baldwin free(vcpu, M_VM); 362366f6083SPeter Grehan } 3635fcf252fSNeel Natu } 364366f6083SPeter Grehan 36598568a00SJohn Baldwin static struct vcpu * 36698568a00SJohn Baldwin vcpu_alloc(struct vm *vm, int vcpu_id) 367366f6083SPeter Grehan { 368366f6083SPeter Grehan struct vcpu *vcpu; 369366f6083SPeter Grehan 370a488c9c9SRodney W. Grimes KASSERT(vcpu_id >= 0 && vcpu_id < vm->maxcpus, 3715fcf252fSNeel Natu ("vcpu_init: invalid vcpu %d", vcpu_id)); 3725fcf252fSNeel Natu 37398568a00SJohn Baldwin vcpu = malloc(sizeof(*vcpu), M_VM, M_WAITOK | M_ZERO); 37475dd3366SNeel Natu vcpu_lock_init(vcpu); 3755fcf252fSNeel Natu vcpu->state = VCPU_IDLE; 37675dd3366SNeel Natu vcpu->hostcpu = NOCPU; 377950af9ffSJohn Baldwin vcpu->vcpuid = vcpu_id; 378950af9ffSJohn Baldwin vcpu->vm = vm; 3795fcf252fSNeel Natu vcpu->guestfpu = fpu_save_area_alloc(); 3805fcf252fSNeel Natu vcpu->stats = vmm_stat_alloc(); 381483d953aSJohn Baldwin vcpu->tsc_offset = 0; 38298568a00SJohn Baldwin return (vcpu); 3835fcf252fSNeel Natu } 3845fcf252fSNeel Natu 38598568a00SJohn Baldwin static void 38698568a00SJohn Baldwin vcpu_init(struct vcpu *vcpu) 38798568a00SJohn Baldwin { 38898568a00SJohn Baldwin vcpu->cookie = vmmops_vcpu_init(vcpu->vm->cookie, vcpu, vcpu->vcpuid); 389869c8d19SJohn Baldwin vcpu->vlapic = vmmops_vlapic_init(vcpu->cookie); 3903f0f4b15SJohn Baldwin vm_set_x2apic_state(vcpu, X2APIC_DISABLED); 391248e6799SNeel Natu vcpu->reqidle = 0; 392091d4532SNeel Natu vcpu->exitintinfo = 0; 3935fcf252fSNeel Natu vcpu->nmi_pending = 0; 3945fcf252fSNeel Natu vcpu->extint_pending = 0; 3955fcf252fSNeel Natu vcpu->exception_pending = 0; 396abb023fbSJohn Baldwin vcpu->guest_xcr0 = XFEATURE_ENABLED_X87; 39738f1b189SPeter Grehan fpu_save_area_reset(vcpu->guestfpu); 3985fcf252fSNeel Natu vmm_stat_init(vcpu->stats); 399366f6083SPeter Grehan } 400366f6083SPeter Grehan 401b0538143SNeel Natu int 40280cb5d84SJohn Baldwin vcpu_trace_exceptions(struct vcpu *vcpu) 403b0538143SNeel Natu { 404b0538143SNeel Natu 405b0538143SNeel Natu return (trace_guest_exceptions); 406b0538143SNeel Natu } 407b0538143SNeel Natu 4083ba952e1SCorvin Köhne int 40980cb5d84SJohn Baldwin vcpu_trap_wbinvd(struct vcpu *vcpu) 4103ba952e1SCorvin Köhne { 4113ba952e1SCorvin Köhne return (trap_wbinvd); 4123ba952e1SCorvin Köhne } 4133ba952e1SCorvin Köhne 41498ed632cSNeel Natu struct vm_exit * 41580cb5d84SJohn Baldwin vm_exitinfo(struct vcpu *vcpu) 41698ed632cSNeel Natu { 41798ed632cSNeel Natu return (&vcpu->exitinfo); 41898ed632cSNeel Natu } 41998ed632cSNeel Natu 420e17eca32SMark Johnston cpuset_t * 421e17eca32SMark Johnston vm_exitinfo_cpuset(struct vcpu *vcpu) 422e17eca32SMark Johnston { 423e17eca32SMark Johnston return (&vcpu->exitinfo_cpuset); 424e17eca32SMark Johnston } 425e17eca32SMark Johnston 426366f6083SPeter Grehan static int 427366f6083SPeter Grehan vmm_init(void) 428366f6083SPeter Grehan { 429366f6083SPeter Grehan int error; 430366f6083SPeter Grehan 43115add60dSPeter Grehan if (!vmm_is_hw_supported()) 43215add60dSPeter Grehan return (ENXIO); 43315add60dSPeter Grehan 434ee98f99dSJohn Baldwin vm_maxcpu = mp_ncpus; 435ee98f99dSJohn Baldwin TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu); 436ee98f99dSJohn Baldwin 437ee98f99dSJohn Baldwin if (vm_maxcpu > VM_MAXCPU) { 438ee98f99dSJohn Baldwin printf("vmm: vm_maxcpu clamped to %u\n", VM_MAXCPU); 439ee98f99dSJohn Baldwin vm_maxcpu = VM_MAXCPU; 440ee98f99dSJohn Baldwin } 441ee98f99dSJohn Baldwin if (vm_maxcpu == 0) 442ee98f99dSJohn Baldwin vm_maxcpu = 1; 443ee98f99dSJohn Baldwin 444b01c2033SNeel Natu vmm_host_state_init(); 445add611fdSNeel Natu 446bd50262fSKonstantin Belousov vmm_ipinum = lapic_ipi_alloc(pti ? &IDTVEC(justreturn1_pti) : 447bd50262fSKonstantin Belousov &IDTVEC(justreturn)); 44818a2b08eSNeel Natu if (vmm_ipinum < 0) 449add611fdSNeel Natu vmm_ipinum = IPI_AST; 450366f6083SPeter Grehan 451366f6083SPeter Grehan error = vmm_mem_init(); 452366f6083SPeter Grehan if (error) 453366f6083SPeter Grehan return (error); 454366f6083SPeter Grehan 45515add60dSPeter Grehan vmm_resume_p = vmmops_modresume; 456366f6083SPeter Grehan 45715add60dSPeter Grehan return (vmmops_modinit(vmm_ipinum)); 458366f6083SPeter Grehan } 459366f6083SPeter Grehan 460366f6083SPeter Grehan static int 461366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg) 462366f6083SPeter Grehan { 463366f6083SPeter Grehan int error; 464366f6083SPeter Grehan 465366f6083SPeter Grehan switch (what) { 466366f6083SPeter Grehan case MOD_LOAD: 46715add60dSPeter Grehan if (vmm_is_hw_supported()) { 468*a97f683fSMark Johnston error = vmmdev_init(); 469*a97f683fSMark Johnston if (error != 0) 470*a97f683fSMark Johnston break; 471366f6083SPeter Grehan error = vmm_init(); 472d5408b1dSNeel Natu if (error == 0) 473d5408b1dSNeel Natu vmm_initialized = 1; 47415add60dSPeter Grehan } else { 47515add60dSPeter Grehan error = ENXIO; 47615add60dSPeter Grehan } 477366f6083SPeter Grehan break; 478366f6083SPeter Grehan case MOD_UNLOAD: 47915add60dSPeter Grehan if (vmm_is_hw_supported()) { 480cdc5b9e7SNeel Natu error = vmmdev_cleanup(); 481cdc5b9e7SNeel Natu if (error == 0) { 48263e62d39SJohn Baldwin vmm_resume_p = NULL; 483366f6083SPeter Grehan iommu_cleanup(); 484add611fdSNeel Natu if (vmm_ipinum != IPI_AST) 48518a2b08eSNeel Natu lapic_ipi_free(vmm_ipinum); 48615add60dSPeter Grehan error = vmmops_modcleanup(); 48781ef6611SPeter Grehan /* 48881ef6611SPeter Grehan * Something bad happened - prevent new 48981ef6611SPeter Grehan * VMs from being created 49081ef6611SPeter Grehan */ 49181ef6611SPeter Grehan if (error) 492d5408b1dSNeel Natu vmm_initialized = 0; 49381ef6611SPeter Grehan } 49415add60dSPeter Grehan } else { 49515add60dSPeter Grehan error = 0; 49615add60dSPeter Grehan } 497366f6083SPeter Grehan break; 498366f6083SPeter Grehan default: 499366f6083SPeter Grehan error = 0; 500366f6083SPeter Grehan break; 501366f6083SPeter Grehan } 502366f6083SPeter Grehan return (error); 503366f6083SPeter Grehan } 504366f6083SPeter Grehan 505366f6083SPeter Grehan static moduledata_t vmm_kmod = { 506366f6083SPeter Grehan "vmm", 507366f6083SPeter Grehan vmm_handler, 508366f6083SPeter Grehan NULL 509366f6083SPeter Grehan }; 510366f6083SPeter Grehan 511366f6083SPeter Grehan /* 512e3f0800bSNeel Natu * vmm initialization has the following dependencies: 513e3f0800bSNeel Natu * 514e3f0800bSNeel Natu * - VT-x initialization requires smp_rendezvous() and therefore must happen 515e3f0800bSNeel Natu * after SMP is fully functional (after SI_SUB_SMP). 516366f6083SPeter Grehan */ 517e3f0800bSNeel Natu DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_SMP + 1, SI_ORDER_ANY); 518366f6083SPeter Grehan MODULE_VERSION(vmm, 1); 519366f6083SPeter Grehan 5205fcf252fSNeel Natu static void 5215fcf252fSNeel Natu vm_init(struct vm *vm, bool create) 5225fcf252fSNeel Natu { 52315add60dSPeter Grehan vm->cookie = vmmops_init(vm, vmspace_pmap(vm->vmspace)); 5245fcf252fSNeel Natu vm->iommu = NULL; 5255fcf252fSNeel Natu vm->vioapic = vioapic_init(vm); 5265fcf252fSNeel Natu vm->vhpet = vhpet_init(vm); 5275fcf252fSNeel Natu vm->vatpic = vatpic_init(vm); 5285fcf252fSNeel Natu vm->vatpit = vatpit_init(vm); 529160ef77aSNeel Natu vm->vpmtmr = vpmtmr_init(vm); 5300dafa5cdSNeel Natu if (create) 5310dafa5cdSNeel Natu vm->vrtc = vrtc_init(vm); 5325fcf252fSNeel Natu 5335fcf252fSNeel Natu CPU_ZERO(&vm->active_cpus); 534fc276d92SJohn Baldwin CPU_ZERO(&vm->debug_cpus); 535c0f35dbfSJohn Baldwin CPU_ZERO(&vm->startup_cpus); 5365fcf252fSNeel Natu 5375fcf252fSNeel Natu vm->suspend = 0; 5385fcf252fSNeel Natu CPU_ZERO(&vm->suspended_cpus); 5395fcf252fSNeel Natu 54098568a00SJohn Baldwin if (!create) { 54198568a00SJohn Baldwin for (int i = 0; i < vm->maxcpus; i++) { 54298568a00SJohn Baldwin if (vm->vcpu[i] != NULL) 54398568a00SJohn Baldwin vcpu_init(vm->vcpu[i]); 54498568a00SJohn Baldwin } 54598568a00SJohn Baldwin } 54698568a00SJohn Baldwin } 54798568a00SJohn Baldwin 54898568a00SJohn Baldwin void 54998568a00SJohn Baldwin vm_disable_vcpu_creation(struct vm *vm) 55098568a00SJohn Baldwin { 55198568a00SJohn Baldwin sx_xlock(&vm->vcpus_init_lock); 55298568a00SJohn Baldwin vm->dying = true; 55398568a00SJohn Baldwin sx_xunlock(&vm->vcpus_init_lock); 55498568a00SJohn Baldwin } 55598568a00SJohn Baldwin 55698568a00SJohn Baldwin struct vcpu * 55798568a00SJohn Baldwin vm_alloc_vcpu(struct vm *vm, int vcpuid) 55898568a00SJohn Baldwin { 55998568a00SJohn Baldwin struct vcpu *vcpu; 56098568a00SJohn Baldwin 56198568a00SJohn Baldwin if (vcpuid < 0 || vcpuid >= vm_get_maxcpus(vm)) 56298568a00SJohn Baldwin return (NULL); 56398568a00SJohn Baldwin 56472ae04c7SRuslan Bukin vcpu = (struct vcpu *) 56572ae04c7SRuslan Bukin atomic_load_acq_ptr((uintptr_t *)&vm->vcpu[vcpuid]); 56698568a00SJohn Baldwin if (__predict_true(vcpu != NULL)) 56798568a00SJohn Baldwin return (vcpu); 56898568a00SJohn Baldwin 56998568a00SJohn Baldwin sx_xlock(&vm->vcpus_init_lock); 57098568a00SJohn Baldwin vcpu = vm->vcpu[vcpuid]; 57198568a00SJohn Baldwin if (vcpu == NULL && !vm->dying) { 57298568a00SJohn Baldwin vcpu = vcpu_alloc(vm, vcpuid); 57398568a00SJohn Baldwin vcpu_init(vcpu); 57498568a00SJohn Baldwin 57598568a00SJohn Baldwin /* 57698568a00SJohn Baldwin * Ensure vCPU is fully created before updating pointer 57798568a00SJohn Baldwin * to permit unlocked reads above. 57898568a00SJohn Baldwin */ 57998568a00SJohn Baldwin atomic_store_rel_ptr((uintptr_t *)&vm->vcpu[vcpuid], 58098568a00SJohn Baldwin (uintptr_t)vcpu); 58198568a00SJohn Baldwin } 58298568a00SJohn Baldwin sx_xunlock(&vm->vcpus_init_lock); 58398568a00SJohn Baldwin return (vcpu); 58498568a00SJohn Baldwin } 58598568a00SJohn Baldwin 58698568a00SJohn Baldwin void 58798568a00SJohn Baldwin vm_slock_vcpus(struct vm *vm) 58898568a00SJohn Baldwin { 58998568a00SJohn Baldwin sx_slock(&vm->vcpus_init_lock); 59098568a00SJohn Baldwin } 59198568a00SJohn Baldwin 59298568a00SJohn Baldwin void 59398568a00SJohn Baldwin vm_unlock_vcpus(struct vm *vm) 59498568a00SJohn Baldwin { 59598568a00SJohn Baldwin sx_unlock(&vm->vcpus_init_lock); 5965fcf252fSNeel Natu } 5975fcf252fSNeel Natu 59801d822d3SRodney W. Grimes /* 59901d822d3SRodney W. Grimes * The default CPU topology is a single thread per package. 60001d822d3SRodney W. Grimes */ 60101d822d3SRodney W. Grimes u_int cores_per_package = 1; 60201d822d3SRodney W. Grimes u_int threads_per_core = 1; 60301d822d3SRodney W. Grimes 604d5408b1dSNeel Natu int 605d5408b1dSNeel Natu vm_create(const char *name, struct vm **retvm) 606366f6083SPeter Grehan { 607366f6083SPeter Grehan struct vm *vm; 608318224bbSNeel Natu struct vmspace *vmspace; 609366f6083SPeter Grehan 610d5408b1dSNeel Natu /* 611d5408b1dSNeel Natu * If vmm.ko could not be successfully initialized then don't attempt 612d5408b1dSNeel Natu * to create the virtual machine. 613d5408b1dSNeel Natu */ 614d5408b1dSNeel Natu if (!vmm_initialized) 615d5408b1dSNeel Natu return (ENXIO); 616d5408b1dSNeel Natu 617df95cc76SKa Ho Ng if (name == NULL || strnlen(name, VM_MAX_NAMELEN + 1) == 618df95cc76SKa Ho Ng VM_MAX_NAMELEN + 1) 619d5408b1dSNeel Natu return (EINVAL); 620366f6083SPeter Grehan 6213c48106aSKonstantin Belousov vmspace = vmmops_vmspace_alloc(0, VM_MAXUSER_ADDRESS_LA48); 622318224bbSNeel Natu if (vmspace == NULL) 623318224bbSNeel Natu return (ENOMEM); 624318224bbSNeel Natu 625366f6083SPeter Grehan vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 626366f6083SPeter Grehan strcpy(vm->name, name); 62788c4b8d1SNeel Natu vm->vmspace = vmspace; 6285b8a8cd1SNeel Natu mtx_init(&vm->rendezvous_mtx, "vm rendezvous lock", 0, MTX_DEF); 62967b69e76SJohn Baldwin sx_init(&vm->mem_segs_lock, "vm mem_segs"); 63098568a00SJohn Baldwin sx_init(&vm->vcpus_init_lock, "vm vcpus"); 631ee98f99dSJohn Baldwin vm->vcpu = malloc(sizeof(*vm->vcpu) * vm_maxcpu, M_VM, M_WAITOK | 632ee98f99dSJohn Baldwin M_ZERO); 633366f6083SPeter Grehan 63401d822d3SRodney W. Grimes vm->sockets = 1; 63501d822d3SRodney W. Grimes vm->cores = cores_per_package; /* XXX backwards compatibility */ 63601d822d3SRodney W. Grimes vm->threads = threads_per_core; /* XXX backwards compatibility */ 637ee98f99dSJohn Baldwin vm->maxcpus = vm_maxcpu; 63801d822d3SRodney W. Grimes 6395fcf252fSNeel Natu vm_init(vm, true); 640366f6083SPeter Grehan 641d5408b1dSNeel Natu *retvm = vm; 642d5408b1dSNeel Natu return (0); 643366f6083SPeter Grehan } 644366f6083SPeter Grehan 64501d822d3SRodney W. Grimes void 64601d822d3SRodney W. Grimes vm_get_topology(struct vm *vm, uint16_t *sockets, uint16_t *cores, 64701d822d3SRodney W. Grimes uint16_t *threads, uint16_t *maxcpus) 64801d822d3SRodney W. Grimes { 64901d822d3SRodney W. Grimes *sockets = vm->sockets; 65001d822d3SRodney W. Grimes *cores = vm->cores; 65101d822d3SRodney W. Grimes *threads = vm->threads; 65201d822d3SRodney W. Grimes *maxcpus = vm->maxcpus; 65301d822d3SRodney W. Grimes } 65401d822d3SRodney W. Grimes 655a488c9c9SRodney W. Grimes uint16_t 656a488c9c9SRodney W. Grimes vm_get_maxcpus(struct vm *vm) 657a488c9c9SRodney W. Grimes { 658a488c9c9SRodney W. Grimes return (vm->maxcpus); 659a488c9c9SRodney W. Grimes } 660a488c9c9SRodney W. Grimes 66101d822d3SRodney W. Grimes int 66201d822d3SRodney W. Grimes vm_set_topology(struct vm *vm, uint16_t sockets, uint16_t cores, 66398568a00SJohn Baldwin uint16_t threads, uint16_t maxcpus __unused) 66401d822d3SRodney W. Grimes { 66598568a00SJohn Baldwin /* Ignore maxcpus. */ 666a488c9c9SRodney W. Grimes if ((sockets * cores * threads) > vm->maxcpus) 66701d822d3SRodney W. Grimes return (EINVAL); 66801d822d3SRodney W. Grimes vm->sockets = sockets; 66901d822d3SRodney W. Grimes vm->cores = cores; 67001d822d3SRodney W. Grimes vm->threads = threads; 67101d822d3SRodney W. Grimes return(0); 67201d822d3SRodney W. Grimes } 67301d822d3SRodney W. Grimes 674f7d51510SNeel Natu static void 6755fcf252fSNeel Natu vm_cleanup(struct vm *vm, bool destroy) 676366f6083SPeter Grehan { 6779b1aa8d6SNeel Natu struct mem_map *mm; 678366f6083SPeter Grehan int i; 679366f6083SPeter Grehan 680c668e817SRobert Wing if (destroy) 681c668e817SRobert Wing vm_xlock_memsegs(vm); 682c668e817SRobert Wing 683366f6083SPeter Grehan ppt_unassign_all(vm); 684366f6083SPeter Grehan 685318224bbSNeel Natu if (vm->iommu != NULL) 686318224bbSNeel Natu iommu_destroy_domain(vm->iommu); 687318224bbSNeel Natu 6880dafa5cdSNeel Natu if (destroy) 6890dafa5cdSNeel Natu vrtc_cleanup(vm->vrtc); 6900dafa5cdSNeel Natu else 6910dafa5cdSNeel Natu vrtc_reset(vm->vrtc); 692160ef77aSNeel Natu vpmtmr_cleanup(vm->vpmtmr); 693e883c9bbSTycho Nightingale vatpit_cleanup(vm->vatpit); 69408e3ff32SNeel Natu vhpet_cleanup(vm->vhpet); 695762fd208STycho Nightingale vatpic_cleanup(vm->vatpic); 69608e3ff32SNeel Natu vioapic_cleanup(vm->vioapic); 69708e3ff32SNeel Natu 69898568a00SJohn Baldwin for (i = 0; i < vm->maxcpus; i++) { 69998568a00SJohn Baldwin if (vm->vcpu[i] != NULL) 70098568a00SJohn Baldwin vcpu_cleanup(vm->vcpu[i], destroy); 70198568a00SJohn Baldwin } 7025fcf252fSNeel Natu 70315add60dSPeter Grehan vmmops_cleanup(vm->cookie); 7045fcf252fSNeel Natu 7059b1aa8d6SNeel Natu /* 7069b1aa8d6SNeel Natu * System memory is removed from the guest address space only when 7079b1aa8d6SNeel Natu * the VM is destroyed. This is because the mapping remains the same 7089b1aa8d6SNeel Natu * across VM reset. 7099b1aa8d6SNeel Natu * 7109b1aa8d6SNeel Natu * Device memory can be relocated by the guest (e.g. using PCI BARs) 7119b1aa8d6SNeel Natu * so those mappings are removed on a VM reset. 7129b1aa8d6SNeel Natu */ 7139b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 7149b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 7159b1aa8d6SNeel Natu if (destroy || !sysmem_mapping(vm, mm)) 7169b1aa8d6SNeel Natu vm_free_memmap(vm, i); 7179b1aa8d6SNeel Natu } 718f7d51510SNeel Natu 7199b1aa8d6SNeel Natu if (destroy) { 7209b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMSEGS; i++) 7219b1aa8d6SNeel Natu vm_free_memseg(vm, i); 722c668e817SRobert Wing vm_unlock_memsegs(vm); 723366f6083SPeter Grehan 72415add60dSPeter Grehan vmmops_vmspace_free(vm->vmspace); 7255fcf252fSNeel Natu vm->vmspace = NULL; 72608ebb360SJohn Baldwin 727ee98f99dSJohn Baldwin free(vm->vcpu, M_VM); 72898568a00SJohn Baldwin sx_destroy(&vm->vcpus_init_lock); 72967b69e76SJohn Baldwin sx_destroy(&vm->mem_segs_lock); 73008ebb360SJohn Baldwin mtx_destroy(&vm->rendezvous_mtx); 7315fcf252fSNeel Natu } 7325fcf252fSNeel Natu } 733366f6083SPeter Grehan 7345fcf252fSNeel Natu void 7355fcf252fSNeel Natu vm_destroy(struct vm *vm) 7365fcf252fSNeel Natu { 7375fcf252fSNeel Natu vm_cleanup(vm, true); 738366f6083SPeter Grehan free(vm, M_VM); 739366f6083SPeter Grehan } 740366f6083SPeter Grehan 7415fcf252fSNeel Natu int 7425fcf252fSNeel Natu vm_reinit(struct vm *vm) 7435fcf252fSNeel Natu { 7445fcf252fSNeel Natu int error; 7455fcf252fSNeel Natu 7465fcf252fSNeel Natu /* 7475fcf252fSNeel Natu * A virtual machine can be reset only if all vcpus are suspended. 7485fcf252fSNeel Natu */ 7495fcf252fSNeel Natu if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 7505fcf252fSNeel Natu vm_cleanup(vm, false); 7515fcf252fSNeel Natu vm_init(vm, false); 7525fcf252fSNeel Natu error = 0; 7535fcf252fSNeel Natu } else { 7545fcf252fSNeel Natu error = EBUSY; 7555fcf252fSNeel Natu } 7565fcf252fSNeel Natu 7575fcf252fSNeel Natu return (error); 7585fcf252fSNeel Natu } 7595fcf252fSNeel Natu 760366f6083SPeter Grehan const char * 761366f6083SPeter Grehan vm_name(struct vm *vm) 762366f6083SPeter Grehan { 763366f6083SPeter Grehan return (vm->name); 764366f6083SPeter Grehan } 765366f6083SPeter Grehan 76667b69e76SJohn Baldwin void 76767b69e76SJohn Baldwin vm_slock_memsegs(struct vm *vm) 76867b69e76SJohn Baldwin { 76967b69e76SJohn Baldwin sx_slock(&vm->mem_segs_lock); 77067b69e76SJohn Baldwin } 77167b69e76SJohn Baldwin 77267b69e76SJohn Baldwin void 77367b69e76SJohn Baldwin vm_xlock_memsegs(struct vm *vm) 77467b69e76SJohn Baldwin { 77567b69e76SJohn Baldwin sx_xlock(&vm->mem_segs_lock); 77667b69e76SJohn Baldwin } 77767b69e76SJohn Baldwin 77867b69e76SJohn Baldwin void 77967b69e76SJohn Baldwin vm_unlock_memsegs(struct vm *vm) 78067b69e76SJohn Baldwin { 78167b69e76SJohn Baldwin sx_unlock(&vm->mem_segs_lock); 78267b69e76SJohn Baldwin } 78367b69e76SJohn Baldwin 784366f6083SPeter Grehan int 785366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 786366f6083SPeter Grehan { 787318224bbSNeel Natu vm_object_t obj; 788366f6083SPeter Grehan 789318224bbSNeel Natu if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa)) == NULL) 790318224bbSNeel Natu return (ENOMEM); 791318224bbSNeel Natu else 792318224bbSNeel Natu return (0); 793366f6083SPeter Grehan } 794366f6083SPeter Grehan 795366f6083SPeter Grehan int 796366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 797366f6083SPeter Grehan { 798366f6083SPeter Grehan 799318224bbSNeel Natu vmm_mmio_free(vm->vmspace, gpa, len); 800318224bbSNeel Natu return (0); 801366f6083SPeter Grehan } 802366f6083SPeter Grehan 8039b1aa8d6SNeel Natu /* 8049b1aa8d6SNeel Natu * Return 'true' if 'gpa' is allocated in the guest address space. 8059b1aa8d6SNeel Natu * 8069b1aa8d6SNeel Natu * This function is called in the context of a running vcpu which acts as 8079b1aa8d6SNeel Natu * an implicit lock on 'vm->mem_maps[]'. 8089b1aa8d6SNeel Natu */ 8099b1aa8d6SNeel Natu bool 81080cb5d84SJohn Baldwin vm_mem_allocated(struct vcpu *vcpu, vm_paddr_t gpa) 811366f6083SPeter Grehan { 81280cb5d84SJohn Baldwin struct vm *vm = vcpu->vm; 8139b1aa8d6SNeel Natu struct mem_map *mm; 814341f19c9SNeel Natu int i; 815341f19c9SNeel Natu 8169b1aa8d6SNeel Natu #ifdef INVARIANTS 8179b1aa8d6SNeel Natu int hostcpu, state; 81880cb5d84SJohn Baldwin state = vcpu_get_state(vcpu, &hostcpu); 8199b1aa8d6SNeel Natu KASSERT(state == VCPU_RUNNING && hostcpu == curcpu, 8209b1aa8d6SNeel Natu ("%s: invalid vcpu state %d/%d", __func__, state, hostcpu)); 8219b1aa8d6SNeel Natu #endif 8229b1aa8d6SNeel Natu 8239b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 8249b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 8259b1aa8d6SNeel Natu if (mm->len != 0 && gpa >= mm->gpa && gpa < mm->gpa + mm->len) 8269b1aa8d6SNeel Natu return (true); /* 'gpa' is sysmem or devmem */ 827341f19c9SNeel Natu } 828341f19c9SNeel Natu 829318224bbSNeel Natu if (ppt_is_mmio(vm, gpa)) 8309b1aa8d6SNeel Natu return (true); /* 'gpa' is pci passthru mmio */ 831318224bbSNeel Natu 8329b1aa8d6SNeel Natu return (false); 833341f19c9SNeel Natu } 834341f19c9SNeel Natu 835341f19c9SNeel Natu int 8369b1aa8d6SNeel Natu vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem) 837341f19c9SNeel Natu { 838318224bbSNeel Natu struct mem_seg *seg; 8399b1aa8d6SNeel Natu vm_object_t obj; 840366f6083SPeter Grehan 84167b69e76SJohn Baldwin sx_assert(&vm->mem_segs_lock, SX_XLOCKED); 84267b69e76SJohn Baldwin 8439b1aa8d6SNeel Natu if (ident < 0 || ident >= VM_MAX_MEMSEGS) 844341f19c9SNeel Natu return (EINVAL); 845341f19c9SNeel Natu 8469b1aa8d6SNeel Natu if (len == 0 || (len & PAGE_MASK)) 8479b1aa8d6SNeel Natu return (EINVAL); 848341f19c9SNeel Natu 8499b1aa8d6SNeel Natu seg = &vm->mem_segs[ident]; 8509b1aa8d6SNeel Natu if (seg->object != NULL) { 8519b1aa8d6SNeel Natu if (seg->len == len && seg->sysmem == sysmem) 8529b1aa8d6SNeel Natu return (EEXIST); 8539b1aa8d6SNeel Natu else 8549b1aa8d6SNeel Natu return (EINVAL); 855341f19c9SNeel Natu } 856341f19c9SNeel Natu 8576b389740SMark Johnston obj = vm_object_allocate(OBJT_SWAP, len >> PAGE_SHIFT); 8589b1aa8d6SNeel Natu if (obj == NULL) 859318224bbSNeel Natu return (ENOMEM); 860318224bbSNeel Natu 861318224bbSNeel Natu seg->len = len; 8629b1aa8d6SNeel Natu seg->object = obj; 8639b1aa8d6SNeel Natu seg->sysmem = sysmem; 864366f6083SPeter Grehan return (0); 865366f6083SPeter Grehan } 866366f6083SPeter Grehan 8679b1aa8d6SNeel Natu int 8689b1aa8d6SNeel Natu vm_get_memseg(struct vm *vm, int ident, size_t *len, bool *sysmem, 8699b1aa8d6SNeel Natu vm_object_t *objptr) 870477867a0SNeel Natu { 8719b1aa8d6SNeel Natu struct mem_seg *seg; 872477867a0SNeel Natu 87367b69e76SJohn Baldwin sx_assert(&vm->mem_segs_lock, SX_LOCKED); 87467b69e76SJohn Baldwin 8759b1aa8d6SNeel Natu if (ident < 0 || ident >= VM_MAX_MEMSEGS) 8769b1aa8d6SNeel Natu return (EINVAL); 8779b1aa8d6SNeel Natu 8789b1aa8d6SNeel Natu seg = &vm->mem_segs[ident]; 8799b1aa8d6SNeel Natu if (len) 8809b1aa8d6SNeel Natu *len = seg->len; 8819b1aa8d6SNeel Natu if (sysmem) 8829b1aa8d6SNeel Natu *sysmem = seg->sysmem; 8839b1aa8d6SNeel Natu if (objptr) 8849b1aa8d6SNeel Natu *objptr = seg->object; 8859b1aa8d6SNeel Natu return (0); 886477867a0SNeel Natu } 8879b1aa8d6SNeel Natu 8889b1aa8d6SNeel Natu void 8899b1aa8d6SNeel Natu vm_free_memseg(struct vm *vm, int ident) 8909b1aa8d6SNeel Natu { 8919b1aa8d6SNeel Natu struct mem_seg *seg; 8929b1aa8d6SNeel Natu 8939b1aa8d6SNeel Natu KASSERT(ident >= 0 && ident < VM_MAX_MEMSEGS, 8949b1aa8d6SNeel Natu ("%s: invalid memseg ident %d", __func__, ident)); 8959b1aa8d6SNeel Natu 8969b1aa8d6SNeel Natu seg = &vm->mem_segs[ident]; 8979b1aa8d6SNeel Natu if (seg->object != NULL) { 8989b1aa8d6SNeel Natu vm_object_deallocate(seg->object); 8999b1aa8d6SNeel Natu bzero(seg, sizeof(struct mem_seg)); 9009b1aa8d6SNeel Natu } 9019b1aa8d6SNeel Natu } 9029b1aa8d6SNeel Natu 9039b1aa8d6SNeel Natu int 9049b1aa8d6SNeel Natu vm_mmap_memseg(struct vm *vm, vm_paddr_t gpa, int segid, vm_ooffset_t first, 9059b1aa8d6SNeel Natu size_t len, int prot, int flags) 9069b1aa8d6SNeel Natu { 9079b1aa8d6SNeel Natu struct mem_seg *seg; 9089b1aa8d6SNeel Natu struct mem_map *m, *map; 9099b1aa8d6SNeel Natu vm_ooffset_t last; 9109b1aa8d6SNeel Natu int i, error; 9119b1aa8d6SNeel Natu 9129b1aa8d6SNeel Natu if (prot == 0 || (prot & ~(VM_PROT_ALL)) != 0) 9139b1aa8d6SNeel Natu return (EINVAL); 9149b1aa8d6SNeel Natu 9159b1aa8d6SNeel Natu if (flags & ~VM_MEMMAP_F_WIRED) 9169b1aa8d6SNeel Natu return (EINVAL); 9179b1aa8d6SNeel Natu 9189b1aa8d6SNeel Natu if (segid < 0 || segid >= VM_MAX_MEMSEGS) 9199b1aa8d6SNeel Natu return (EINVAL); 9209b1aa8d6SNeel Natu 9219b1aa8d6SNeel Natu seg = &vm->mem_segs[segid]; 9229b1aa8d6SNeel Natu if (seg->object == NULL) 9239b1aa8d6SNeel Natu return (EINVAL); 9249b1aa8d6SNeel Natu 9259b1aa8d6SNeel Natu last = first + len; 9269b1aa8d6SNeel Natu if (first < 0 || first >= last || last > seg->len) 9279b1aa8d6SNeel Natu return (EINVAL); 9289b1aa8d6SNeel Natu 9299b1aa8d6SNeel Natu if ((gpa | first | last) & PAGE_MASK) 9309b1aa8d6SNeel Natu return (EINVAL); 9319b1aa8d6SNeel Natu 9329b1aa8d6SNeel Natu map = NULL; 9339b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 9349b1aa8d6SNeel Natu m = &vm->mem_maps[i]; 9359b1aa8d6SNeel Natu if (m->len == 0) { 9369b1aa8d6SNeel Natu map = m; 9379b1aa8d6SNeel Natu break; 9389b1aa8d6SNeel Natu } 9399b1aa8d6SNeel Natu } 9409b1aa8d6SNeel Natu 9419b1aa8d6SNeel Natu if (map == NULL) 9429b1aa8d6SNeel Natu return (ENOSPC); 9439b1aa8d6SNeel Natu 9449b1aa8d6SNeel Natu error = vm_map_find(&vm->vmspace->vm_map, seg->object, first, &gpa, 9459b1aa8d6SNeel Natu len, 0, VMFS_NO_SPACE, prot, prot, 0); 9469b1aa8d6SNeel Natu if (error != KERN_SUCCESS) 9479b1aa8d6SNeel Natu return (EFAULT); 9489b1aa8d6SNeel Natu 9499b1aa8d6SNeel Natu vm_object_reference(seg->object); 9509b1aa8d6SNeel Natu 9519b1aa8d6SNeel Natu if (flags & VM_MEMMAP_F_WIRED) { 9529b1aa8d6SNeel Natu error = vm_map_wire(&vm->vmspace->vm_map, gpa, gpa + len, 9539b1aa8d6SNeel Natu VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 9549b1aa8d6SNeel Natu if (error != KERN_SUCCESS) { 9559b1aa8d6SNeel Natu vm_map_remove(&vm->vmspace->vm_map, gpa, gpa + len); 95654a3a114SMark Johnston return (error == KERN_RESOURCE_SHORTAGE ? ENOMEM : 95754a3a114SMark Johnston EFAULT); 9589b1aa8d6SNeel Natu } 9599b1aa8d6SNeel Natu } 9609b1aa8d6SNeel Natu 9619b1aa8d6SNeel Natu map->gpa = gpa; 9629b1aa8d6SNeel Natu map->len = len; 9639b1aa8d6SNeel Natu map->segoff = first; 9649b1aa8d6SNeel Natu map->segid = segid; 9659b1aa8d6SNeel Natu map->prot = prot; 9669b1aa8d6SNeel Natu map->flags = flags; 9679b1aa8d6SNeel Natu return (0); 9689b1aa8d6SNeel Natu } 9699b1aa8d6SNeel Natu 9709b1aa8d6SNeel Natu int 971f8a6ec2dSD Scott Phillips vm_munmap_memseg(struct vm *vm, vm_paddr_t gpa, size_t len) 972f8a6ec2dSD Scott Phillips { 973f8a6ec2dSD Scott Phillips struct mem_map *m; 974f8a6ec2dSD Scott Phillips int i; 975f8a6ec2dSD Scott Phillips 976f8a6ec2dSD Scott Phillips for (i = 0; i < VM_MAX_MEMMAPS; i++) { 977f8a6ec2dSD Scott Phillips m = &vm->mem_maps[i]; 978f8a6ec2dSD Scott Phillips if (m->gpa == gpa && m->len == len && 979f8a6ec2dSD Scott Phillips (m->flags & VM_MEMMAP_F_IOMMU) == 0) { 980f8a6ec2dSD Scott Phillips vm_free_memmap(vm, i); 981f8a6ec2dSD Scott Phillips return (0); 982f8a6ec2dSD Scott Phillips } 983f8a6ec2dSD Scott Phillips } 984f8a6ec2dSD Scott Phillips 985f8a6ec2dSD Scott Phillips return (EINVAL); 986f8a6ec2dSD Scott Phillips } 987f8a6ec2dSD Scott Phillips 988f8a6ec2dSD Scott Phillips int 9899b1aa8d6SNeel Natu vm_mmap_getnext(struct vm *vm, vm_paddr_t *gpa, int *segid, 9909b1aa8d6SNeel Natu vm_ooffset_t *segoff, size_t *len, int *prot, int *flags) 9919b1aa8d6SNeel Natu { 9929b1aa8d6SNeel Natu struct mem_map *mm, *mmnext; 9939b1aa8d6SNeel Natu int i; 9949b1aa8d6SNeel Natu 9959b1aa8d6SNeel Natu mmnext = NULL; 9969b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 9979b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 9989b1aa8d6SNeel Natu if (mm->len == 0 || mm->gpa < *gpa) 9999b1aa8d6SNeel Natu continue; 10009b1aa8d6SNeel Natu if (mmnext == NULL || mm->gpa < mmnext->gpa) 10019b1aa8d6SNeel Natu mmnext = mm; 10029b1aa8d6SNeel Natu } 10039b1aa8d6SNeel Natu 10049b1aa8d6SNeel Natu if (mmnext != NULL) { 10059b1aa8d6SNeel Natu *gpa = mmnext->gpa; 10069b1aa8d6SNeel Natu if (segid) 10079b1aa8d6SNeel Natu *segid = mmnext->segid; 10089b1aa8d6SNeel Natu if (segoff) 10099b1aa8d6SNeel Natu *segoff = mmnext->segoff; 10109b1aa8d6SNeel Natu if (len) 10119b1aa8d6SNeel Natu *len = mmnext->len; 10129b1aa8d6SNeel Natu if (prot) 10139b1aa8d6SNeel Natu *prot = mmnext->prot; 10149b1aa8d6SNeel Natu if (flags) 10159b1aa8d6SNeel Natu *flags = mmnext->flags; 10169b1aa8d6SNeel Natu return (0); 10179b1aa8d6SNeel Natu } else { 10189b1aa8d6SNeel Natu return (ENOENT); 10199b1aa8d6SNeel Natu } 1020477867a0SNeel Natu } 1021477867a0SNeel Natu 1022318224bbSNeel Natu static void 10239b1aa8d6SNeel Natu vm_free_memmap(struct vm *vm, int ident) 1024366f6083SPeter Grehan { 10259b1aa8d6SNeel Natu struct mem_map *mm; 102673505a10SRobert Wing int error __diagused; 10274db4fb2cSNeel Natu 10289b1aa8d6SNeel Natu mm = &vm->mem_maps[ident]; 10299b1aa8d6SNeel Natu if (mm->len) { 10309b1aa8d6SNeel Natu error = vm_map_remove(&vm->vmspace->vm_map, mm->gpa, 10319b1aa8d6SNeel Natu mm->gpa + mm->len); 10329b1aa8d6SNeel Natu KASSERT(error == KERN_SUCCESS, ("%s: vm_map_remove error %d", 10339b1aa8d6SNeel Natu __func__, error)); 10349b1aa8d6SNeel Natu bzero(mm, sizeof(struct mem_map)); 1035318224bbSNeel Natu } 1036318224bbSNeel Natu } 1037318224bbSNeel Natu 10389b1aa8d6SNeel Natu static __inline bool 10399b1aa8d6SNeel Natu sysmem_mapping(struct vm *vm, struct mem_map *mm) 1040318224bbSNeel Natu { 1041318224bbSNeel Natu 10429b1aa8d6SNeel Natu if (mm->len != 0 && vm->mem_segs[mm->segid].sysmem) 10439b1aa8d6SNeel Natu return (true); 10449b1aa8d6SNeel Natu else 10459b1aa8d6SNeel Natu return (false); 1046318224bbSNeel Natu } 1047318224bbSNeel Natu 1048147d12a7SAntoine Brodin vm_paddr_t 1049147d12a7SAntoine Brodin vmm_sysmem_maxaddr(struct vm *vm) 10509b1aa8d6SNeel Natu { 10519b1aa8d6SNeel Natu struct mem_map *mm; 10529b1aa8d6SNeel Natu vm_paddr_t maxaddr; 10539b1aa8d6SNeel Natu int i; 1054318224bbSNeel Natu 10559b1aa8d6SNeel Natu maxaddr = 0; 10569b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 10579b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 10589b1aa8d6SNeel Natu if (sysmem_mapping(vm, mm)) { 10599b1aa8d6SNeel Natu if (maxaddr < mm->gpa + mm->len) 10609b1aa8d6SNeel Natu maxaddr = mm->gpa + mm->len; 10619b1aa8d6SNeel Natu } 10629b1aa8d6SNeel Natu } 10639b1aa8d6SNeel Natu return (maxaddr); 1064318224bbSNeel Natu } 1065318224bbSNeel Natu 1066318224bbSNeel Natu static void 10673abc72f8SKonstantin Belousov vm_iommu_map(struct vm *vm) 1068318224bbSNeel Natu { 1069318224bbSNeel Natu vm_paddr_t gpa, hpa; 10709b1aa8d6SNeel Natu struct mem_map *mm; 10713abc72f8SKonstantin Belousov int i; 1072318224bbSNeel Natu 1073671a0049SKonstantin Belousov sx_assert(&vm->mem_segs_lock, SX_LOCKED); 1074671a0049SKonstantin Belousov 10759b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 10769b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 10779b1aa8d6SNeel Natu if (!sysmem_mapping(vm, mm)) 10789b1aa8d6SNeel Natu continue; 1079318224bbSNeel Natu 10809b1aa8d6SNeel Natu KASSERT((mm->flags & VM_MEMMAP_F_IOMMU) == 0, 10819b1aa8d6SNeel Natu ("iommu map found invalid memmap %#lx/%#lx/%#x", 10829b1aa8d6SNeel Natu mm->gpa, mm->len, mm->flags)); 10839b1aa8d6SNeel Natu if ((mm->flags & VM_MEMMAP_F_WIRED) == 0) 10849b1aa8d6SNeel Natu continue; 10859b1aa8d6SNeel Natu mm->flags |= VM_MEMMAP_F_IOMMU; 10863abc72f8SKonstantin Belousov 10873abc72f8SKonstantin Belousov for (gpa = mm->gpa; gpa < mm->gpa + mm->len; gpa += PAGE_SIZE) { 1088671a0049SKonstantin Belousov hpa = pmap_extract(vmspace_pmap(vm->vmspace), gpa); 10893abc72f8SKonstantin Belousov 1090671a0049SKonstantin Belousov /* 1091671a0049SKonstantin Belousov * All mappings in the vmm vmspace must be 1092671a0049SKonstantin Belousov * present since they are managed by vmm in this way. 1093671a0049SKonstantin Belousov * Because we are in pass-through mode, the 1094671a0049SKonstantin Belousov * mappings must also be wired. This implies 1095671a0049SKonstantin Belousov * that all pages must be mapped and wired, 1096671a0049SKonstantin Belousov * allowing to use pmap_extract() and avoiding the 1097671a0049SKonstantin Belousov * need to use vm_gpa_hold_global(). 1098671a0049SKonstantin Belousov * 1099671a0049SKonstantin Belousov * This could change if/when we start 1100671a0049SKonstantin Belousov * supporting page faults on IOMMU maps. 1101671a0049SKonstantin Belousov */ 1102671a0049SKonstantin Belousov KASSERT(vm_page_wired(PHYS_TO_VM_PAGE(hpa)), 1103671a0049SKonstantin Belousov ("vm_iommu_map: vm %p gpa %jx hpa %jx not wired", 1104671a0049SKonstantin Belousov vm, (uintmax_t)gpa, (uintmax_t)hpa)); 1105671a0049SKonstantin Belousov 11063abc72f8SKonstantin Belousov iommu_create_mapping(vm->iommu, gpa, hpa, PAGE_SIZE); 11073abc72f8SKonstantin Belousov } 11083abc72f8SKonstantin Belousov } 11093abc72f8SKonstantin Belousov 11103abc72f8SKonstantin Belousov iommu_invalidate_tlb(iommu_host_domain()); 11113abc72f8SKonstantin Belousov } 11123abc72f8SKonstantin Belousov 11133abc72f8SKonstantin Belousov static void 11143abc72f8SKonstantin Belousov vm_iommu_unmap(struct vm *vm) 11153abc72f8SKonstantin Belousov { 11163abc72f8SKonstantin Belousov vm_paddr_t gpa; 11173abc72f8SKonstantin Belousov struct mem_map *mm; 11183abc72f8SKonstantin Belousov int i; 11193abc72f8SKonstantin Belousov 1120671a0049SKonstantin Belousov sx_assert(&vm->mem_segs_lock, SX_LOCKED); 1121671a0049SKonstantin Belousov 11223abc72f8SKonstantin Belousov for (i = 0; i < VM_MAX_MEMMAPS; i++) { 11233abc72f8SKonstantin Belousov mm = &vm->mem_maps[i]; 11243abc72f8SKonstantin Belousov if (!sysmem_mapping(vm, mm)) 11253abc72f8SKonstantin Belousov continue; 11263abc72f8SKonstantin Belousov 11279b1aa8d6SNeel Natu if ((mm->flags & VM_MEMMAP_F_IOMMU) == 0) 11289b1aa8d6SNeel Natu continue; 11299b1aa8d6SNeel Natu mm->flags &= ~VM_MEMMAP_F_IOMMU; 11309b1aa8d6SNeel Natu KASSERT((mm->flags & VM_MEMMAP_F_WIRED) != 0, 11319b1aa8d6SNeel Natu ("iommu unmap found invalid memmap %#lx/%#lx/%#x", 11329b1aa8d6SNeel Natu mm->gpa, mm->len, mm->flags)); 11339b1aa8d6SNeel Natu 11343abc72f8SKonstantin Belousov for (gpa = mm->gpa; gpa < mm->gpa + mm->len; gpa += PAGE_SIZE) { 1135671a0049SKonstantin Belousov KASSERT(vm_page_wired(PHYS_TO_VM_PAGE(pmap_extract( 1136671a0049SKonstantin Belousov vmspace_pmap(vm->vmspace), gpa))), 1137671a0049SKonstantin Belousov ("vm_iommu_unmap: vm %p gpa %jx not wired", 1138671a0049SKonstantin Belousov vm, (uintmax_t)gpa)); 11393abc72f8SKonstantin Belousov iommu_remove_mapping(vm->iommu, gpa, PAGE_SIZE); 1140318224bbSNeel Natu } 1141318224bbSNeel Natu } 1142318224bbSNeel Natu 1143318224bbSNeel Natu /* 1144318224bbSNeel Natu * Invalidate the cached translations associated with the domain 1145318224bbSNeel Natu * from which pages were removed. 1146318224bbSNeel Natu */ 1147318224bbSNeel Natu iommu_invalidate_tlb(vm->iommu); 1148318224bbSNeel Natu } 1149318224bbSNeel Natu 1150318224bbSNeel Natu int 1151318224bbSNeel Natu vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func) 1152318224bbSNeel Natu { 1153318224bbSNeel Natu int error; 1154318224bbSNeel Natu 1155318224bbSNeel Natu error = ppt_unassign_device(vm, bus, slot, func); 1156318224bbSNeel Natu if (error) 1157318224bbSNeel Natu return (error); 1158318224bbSNeel Natu 11599b1aa8d6SNeel Natu if (ppt_assigned_devices(vm) == 0) 1160318224bbSNeel Natu vm_iommu_unmap(vm); 11619b1aa8d6SNeel Natu 1162318224bbSNeel Natu return (0); 1163318224bbSNeel Natu } 1164318224bbSNeel Natu 1165318224bbSNeel Natu int 1166318224bbSNeel Natu vm_assign_pptdev(struct vm *vm, int bus, int slot, int func) 1167318224bbSNeel Natu { 1168318224bbSNeel Natu int error; 1169318224bbSNeel Natu vm_paddr_t maxaddr; 1170318224bbSNeel Natu 11719b1aa8d6SNeel Natu /* Set up the IOMMU to do the 'gpa' to 'hpa' translation */ 117251f45d01SNeel Natu if (ppt_assigned_devices(vm) == 0) { 1173318224bbSNeel Natu KASSERT(vm->iommu == NULL, 1174318224bbSNeel Natu ("vm_assign_pptdev: iommu must be NULL")); 1175147d12a7SAntoine Brodin maxaddr = vmm_sysmem_maxaddr(vm); 1176318224bbSNeel Natu vm->iommu = iommu_create_domain(maxaddr); 1177ffe1b10dSJohn Baldwin if (vm->iommu == NULL) 1178ffe1b10dSJohn Baldwin return (ENXIO); 1179318224bbSNeel Natu vm_iommu_map(vm); 1180318224bbSNeel Natu } 1181318224bbSNeel Natu 1182318224bbSNeel Natu error = ppt_assign_device(vm, bus, slot, func); 1183318224bbSNeel Natu return (error); 1184318224bbSNeel Natu } 1185318224bbSNeel Natu 118628b561adSJohn Baldwin static void * 118728b561adSJohn Baldwin _vm_gpa_hold(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, 1188318224bbSNeel Natu void **cookie) 1189318224bbSNeel Natu { 11909b1aa8d6SNeel Natu int i, count, pageoff; 11919b1aa8d6SNeel Natu struct mem_map *mm; 1192318224bbSNeel Natu vm_page_t m; 119328b561adSJohn Baldwin 1194318224bbSNeel Natu pageoff = gpa & PAGE_MASK; 1195318224bbSNeel Natu if (len > PAGE_SIZE - pageoff) 1196318224bbSNeel Natu panic("vm_gpa_hold: invalid gpa/len: 0x%016lx/%lu", gpa, len); 1197318224bbSNeel Natu 11989b1aa8d6SNeel Natu count = 0; 11999b1aa8d6SNeel Natu for (i = 0; i < VM_MAX_MEMMAPS; i++) { 12009b1aa8d6SNeel Natu mm = &vm->mem_maps[i]; 120146567b4fSPeter Grehan if (gpa >= mm->gpa && gpa < mm->gpa + mm->len) { 1202318224bbSNeel Natu count = vm_fault_quick_hold_pages(&vm->vmspace->vm_map, 1203318224bbSNeel Natu trunc_page(gpa), PAGE_SIZE, reqprot, &m, 1); 12049b1aa8d6SNeel Natu break; 12059b1aa8d6SNeel Natu } 12069b1aa8d6SNeel Natu } 1207318224bbSNeel Natu 1208318224bbSNeel Natu if (count == 1) { 1209318224bbSNeel Natu *cookie = m; 1210318224bbSNeel Natu return ((void *)(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)) + pageoff)); 1211318224bbSNeel Natu } else { 1212318224bbSNeel Natu *cookie = NULL; 1213318224bbSNeel Natu return (NULL); 1214318224bbSNeel Natu } 1215318224bbSNeel Natu } 1216318224bbSNeel Natu 121728b561adSJohn Baldwin void * 1218d3956e46SJohn Baldwin vm_gpa_hold(struct vcpu *vcpu, vm_paddr_t gpa, size_t len, int reqprot, 121928b561adSJohn Baldwin void **cookie) 122028b561adSJohn Baldwin { 122128b561adSJohn Baldwin #ifdef INVARIANTS 122228b561adSJohn Baldwin /* 122328b561adSJohn Baldwin * The current vcpu should be frozen to ensure 'vm_memmap[]' 122428b561adSJohn Baldwin * stability. 122528b561adSJohn Baldwin */ 1226d3956e46SJohn Baldwin int state = vcpu_get_state(vcpu, NULL); 122728b561adSJohn Baldwin KASSERT(state == VCPU_FROZEN, ("%s: invalid vcpu state %d", 122828b561adSJohn Baldwin __func__, state)); 122928b561adSJohn Baldwin #endif 1230d3956e46SJohn Baldwin return (_vm_gpa_hold(vcpu->vm, gpa, len, reqprot, cookie)); 123128b561adSJohn Baldwin } 123228b561adSJohn Baldwin 123328b561adSJohn Baldwin void * 123428b561adSJohn Baldwin vm_gpa_hold_global(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, 123528b561adSJohn Baldwin void **cookie) 123628b561adSJohn Baldwin { 123767b69e76SJohn Baldwin sx_assert(&vm->mem_segs_lock, SX_LOCKED); 123828b561adSJohn Baldwin return (_vm_gpa_hold(vm, gpa, len, reqprot, cookie)); 123928b561adSJohn Baldwin } 124028b561adSJohn Baldwin 1241318224bbSNeel Natu void 1242318224bbSNeel Natu vm_gpa_release(void *cookie) 1243318224bbSNeel Natu { 1244318224bbSNeel Natu vm_page_t m = cookie; 1245318224bbSNeel Natu 1246eeacb3b0SMark Johnston vm_page_unwire(m, PQ_ACTIVE); 1247366f6083SPeter Grehan } 1248366f6083SPeter Grehan 1249366f6083SPeter Grehan int 1250d3956e46SJohn Baldwin vm_get_register(struct vcpu *vcpu, int reg, uint64_t *retval) 1251366f6083SPeter Grehan { 1252366f6083SPeter Grehan 1253366f6083SPeter Grehan if (reg >= VM_REG_LAST) 1254366f6083SPeter Grehan return (EINVAL); 1255366f6083SPeter Grehan 1256d3956e46SJohn Baldwin return (vmmops_getreg(vcpu->cookie, reg, retval)); 1257366f6083SPeter Grehan } 1258366f6083SPeter Grehan 1259366f6083SPeter Grehan int 1260d3956e46SJohn Baldwin vm_set_register(struct vcpu *vcpu, int reg, uint64_t val) 1261366f6083SPeter Grehan { 1262d087a399SNeel Natu int error; 1263366f6083SPeter Grehan 1264366f6083SPeter Grehan if (reg >= VM_REG_LAST) 1265366f6083SPeter Grehan return (EINVAL); 1266366f6083SPeter Grehan 1267869c8d19SJohn Baldwin error = vmmops_setreg(vcpu->cookie, reg, val); 1268d087a399SNeel Natu if (error || reg != VM_REG_GUEST_RIP) 1269d087a399SNeel Natu return (error); 1270d087a399SNeel Natu 1271d087a399SNeel Natu /* Set 'nextrip' to match the value of %rip */ 1272d3956e46SJohn Baldwin VMM_CTR1(vcpu, "Setting nextrip to %#lx", val); 1273d087a399SNeel Natu vcpu->nextrip = val; 1274d087a399SNeel Natu return (0); 1275366f6083SPeter Grehan } 1276366f6083SPeter Grehan 1277490d56c5SEd Maste static bool 1278366f6083SPeter Grehan is_descriptor_table(int reg) 1279366f6083SPeter Grehan { 1280366f6083SPeter Grehan 1281366f6083SPeter Grehan switch (reg) { 1282366f6083SPeter Grehan case VM_REG_GUEST_IDTR: 1283366f6083SPeter Grehan case VM_REG_GUEST_GDTR: 1284490d56c5SEd Maste return (true); 1285366f6083SPeter Grehan default: 1286490d56c5SEd Maste return (false); 1287366f6083SPeter Grehan } 1288366f6083SPeter Grehan } 1289366f6083SPeter Grehan 1290490d56c5SEd Maste static bool 1291366f6083SPeter Grehan is_segment_register(int reg) 1292366f6083SPeter Grehan { 1293366f6083SPeter Grehan 1294366f6083SPeter Grehan switch (reg) { 1295366f6083SPeter Grehan case VM_REG_GUEST_ES: 1296366f6083SPeter Grehan case VM_REG_GUEST_CS: 1297366f6083SPeter Grehan case VM_REG_GUEST_SS: 1298366f6083SPeter Grehan case VM_REG_GUEST_DS: 1299366f6083SPeter Grehan case VM_REG_GUEST_FS: 1300366f6083SPeter Grehan case VM_REG_GUEST_GS: 1301366f6083SPeter Grehan case VM_REG_GUEST_TR: 1302366f6083SPeter Grehan case VM_REG_GUEST_LDTR: 1303490d56c5SEd Maste return (true); 1304366f6083SPeter Grehan default: 1305490d56c5SEd Maste return (false); 1306366f6083SPeter Grehan } 1307366f6083SPeter Grehan } 1308366f6083SPeter Grehan 1309366f6083SPeter Grehan int 1310d3956e46SJohn Baldwin vm_get_seg_desc(struct vcpu *vcpu, int reg, struct seg_desc *desc) 1311366f6083SPeter Grehan { 1312366f6083SPeter Grehan 1313366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 1314366f6083SPeter Grehan return (EINVAL); 1315366f6083SPeter Grehan 1316d3956e46SJohn Baldwin return (vmmops_getdesc(vcpu->cookie, reg, desc)); 1317366f6083SPeter Grehan } 1318366f6083SPeter Grehan 1319366f6083SPeter Grehan int 13203f0f4b15SJohn Baldwin vm_set_seg_desc(struct vcpu *vcpu, int reg, struct seg_desc *desc) 1321366f6083SPeter Grehan { 1322366f6083SPeter Grehan 1323366f6083SPeter Grehan if (!is_segment_register(reg) && !is_descriptor_table(reg)) 1324366f6083SPeter Grehan return (EINVAL); 1325366f6083SPeter Grehan 13263f0f4b15SJohn Baldwin return (vmmops_setdesc(vcpu->cookie, reg, desc)); 1327366f6083SPeter Grehan } 1328366f6083SPeter Grehan 1329366f6083SPeter Grehan static void 1330366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu) 1331366f6083SPeter Grehan { 1332366f6083SPeter Grehan 133338f1b189SPeter Grehan /* flush host state to the pcb */ 133438f1b189SPeter Grehan fpuexit(curthread); 1335bd8572e0SNeel Natu 1336bd8572e0SNeel Natu /* restore guest FPU state */ 1337cc1cb9eaSJohn Baldwin fpu_enable(); 133838f1b189SPeter Grehan fpurestore(vcpu->guestfpu); 1339bd8572e0SNeel Natu 1340abb023fbSJohn Baldwin /* restore guest XCR0 if XSAVE is enabled in the host */ 1341abb023fbSJohn Baldwin if (rcr4() & CR4_XSAVE) 1342abb023fbSJohn Baldwin load_xcr(0, vcpu->guest_xcr0); 1343abb023fbSJohn Baldwin 1344bd8572e0SNeel Natu /* 1345cc1cb9eaSJohn Baldwin * The FPU is now "dirty" with the guest's state so disable 1346cc1cb9eaSJohn Baldwin * the FPU to trap any access by the host. 1347bd8572e0SNeel Natu */ 1348cc1cb9eaSJohn Baldwin fpu_disable(); 1349366f6083SPeter Grehan } 1350366f6083SPeter Grehan 1351366f6083SPeter Grehan static void 1352366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu) 1353366f6083SPeter Grehan { 1354366f6083SPeter Grehan 1355bd8572e0SNeel Natu if ((rcr0() & CR0_TS) == 0) 1356bd8572e0SNeel Natu panic("fpu emulation not enabled in host!"); 1357bd8572e0SNeel Natu 1358abb023fbSJohn Baldwin /* save guest XCR0 and restore host XCR0 */ 1359abb023fbSJohn Baldwin if (rcr4() & CR4_XSAVE) { 1360abb023fbSJohn Baldwin vcpu->guest_xcr0 = rxcr(0); 1361abb023fbSJohn Baldwin load_xcr(0, vmm_get_host_xcr0()); 1362abb023fbSJohn Baldwin } 1363abb023fbSJohn Baldwin 1364bd8572e0SNeel Natu /* save guest FPU state */ 1365cc1cb9eaSJohn Baldwin fpu_enable(); 136638f1b189SPeter Grehan fpusave(vcpu->guestfpu); 1367cc1cb9eaSJohn Baldwin fpu_disable(); 1368366f6083SPeter Grehan } 1369366f6083SPeter Grehan 137061592433SNeel Natu static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); 1371f76fc5d4SNeel Natu 1372318224bbSNeel Natu static int 13733f0f4b15SJohn Baldwin vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, 1374f80330a8SNeel Natu bool from_idle) 1375366f6083SPeter Grehan { 1376318224bbSNeel Natu int error; 1377366f6083SPeter Grehan 1378318224bbSNeel Natu vcpu_assert_locked(vcpu); 1379366f6083SPeter Grehan 1380f76fc5d4SNeel Natu /* 1381f80330a8SNeel Natu * State transitions from the vmmdev_ioctl() must always begin from 1382f80330a8SNeel Natu * the VCPU_IDLE state. This guarantees that there is only a single 1383f80330a8SNeel Natu * ioctl() operating on a vcpu at any point. 1384f80330a8SNeel Natu */ 1385f80330a8SNeel Natu if (from_idle) { 1386248e6799SNeel Natu while (vcpu->state != VCPU_IDLE) { 1387248e6799SNeel Natu vcpu->reqidle = 1; 1388248e6799SNeel Natu vcpu_notify_event_locked(vcpu, false); 13893f0f4b15SJohn Baldwin VMM_CTR1(vcpu, "vcpu state change from %s to " 1390248e6799SNeel Natu "idle requested", vcpu_state2str(vcpu->state)); 1391f80330a8SNeel Natu msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); 1392248e6799SNeel Natu } 1393f80330a8SNeel Natu } else { 1394f80330a8SNeel Natu KASSERT(vcpu->state != VCPU_IDLE, ("invalid transition from " 1395f80330a8SNeel Natu "vcpu idle state")); 1396f80330a8SNeel Natu } 1397f80330a8SNeel Natu 1398ef39d7e9SNeel Natu if (vcpu->state == VCPU_RUNNING) { 1399ef39d7e9SNeel Natu KASSERT(vcpu->hostcpu == curcpu, ("curcpu %d and hostcpu %d " 1400ef39d7e9SNeel Natu "mismatch for running vcpu", curcpu, vcpu->hostcpu)); 1401ef39d7e9SNeel Natu } else { 1402ef39d7e9SNeel Natu KASSERT(vcpu->hostcpu == NOCPU, ("Invalid hostcpu %d for a " 1403ef39d7e9SNeel Natu "vcpu that is not running", vcpu->hostcpu)); 1404ef39d7e9SNeel Natu } 1405ef39d7e9SNeel Natu 1406f80330a8SNeel Natu /* 1407318224bbSNeel Natu * The following state transitions are allowed: 1408318224bbSNeel Natu * IDLE -> FROZEN -> IDLE 1409318224bbSNeel Natu * FROZEN -> RUNNING -> FROZEN 1410318224bbSNeel Natu * FROZEN -> SLEEPING -> FROZEN 1411f76fc5d4SNeel Natu */ 1412318224bbSNeel Natu switch (vcpu->state) { 1413318224bbSNeel Natu case VCPU_IDLE: 1414318224bbSNeel Natu case VCPU_RUNNING: 1415318224bbSNeel Natu case VCPU_SLEEPING: 1416318224bbSNeel Natu error = (newstate != VCPU_FROZEN); 1417318224bbSNeel Natu break; 1418318224bbSNeel Natu case VCPU_FROZEN: 1419318224bbSNeel Natu error = (newstate == VCPU_FROZEN); 1420318224bbSNeel Natu break; 1421318224bbSNeel Natu default: 1422318224bbSNeel Natu error = 1; 1423318224bbSNeel Natu break; 1424318224bbSNeel Natu } 1425318224bbSNeel Natu 1426f80330a8SNeel Natu if (error) 1427f80330a8SNeel Natu return (EBUSY); 1428318224bbSNeel Natu 14293f0f4b15SJohn Baldwin VMM_CTR2(vcpu, "vcpu state changed from %s to %s", 1430248e6799SNeel Natu vcpu_state2str(vcpu->state), vcpu_state2str(newstate)); 1431248e6799SNeel Natu 1432f80330a8SNeel Natu vcpu->state = newstate; 1433ef39d7e9SNeel Natu if (newstate == VCPU_RUNNING) 1434ef39d7e9SNeel Natu vcpu->hostcpu = curcpu; 1435ef39d7e9SNeel Natu else 1436ef39d7e9SNeel Natu vcpu->hostcpu = NOCPU; 1437ef39d7e9SNeel Natu 1438f80330a8SNeel Natu if (newstate == VCPU_IDLE) 1439f80330a8SNeel Natu wakeup(&vcpu->state); 1440f80330a8SNeel Natu 1441f80330a8SNeel Natu return (0); 1442318224bbSNeel Natu } 1443318224bbSNeel Natu 1444318224bbSNeel Natu static void 14453f0f4b15SJohn Baldwin vcpu_require_state(struct vcpu *vcpu, enum vcpu_state newstate) 1446318224bbSNeel Natu { 1447318224bbSNeel Natu int error; 1448318224bbSNeel Natu 14493f0f4b15SJohn Baldwin if ((error = vcpu_set_state(vcpu, newstate, false)) != 0) 1450318224bbSNeel Natu panic("Error %d setting state to %d\n", error, newstate); 1451318224bbSNeel Natu } 1452318224bbSNeel Natu 1453318224bbSNeel Natu static void 14543f0f4b15SJohn Baldwin vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) 1455318224bbSNeel Natu { 1456318224bbSNeel Natu int error; 1457318224bbSNeel Natu 14583f0f4b15SJohn Baldwin if ((error = vcpu_set_state_locked(vcpu, newstate, false)) != 0) 1459318224bbSNeel Natu panic("Error %d setting state to %d", error, newstate); 1460318224bbSNeel Natu } 1461318224bbSNeel Natu 1462b837daddSKonstantin Belousov static int 1463d8be3d52SJohn Baldwin vm_handle_rendezvous(struct vcpu *vcpu) 14645b8a8cd1SNeel Natu { 1465d8be3d52SJohn Baldwin struct vm *vm = vcpu->vm; 1466b837daddSKonstantin Belousov struct thread *td; 1467d8be3d52SJohn Baldwin int error, vcpuid; 14685b8a8cd1SNeel Natu 1469b837daddSKonstantin Belousov error = 0; 1470d8be3d52SJohn Baldwin vcpuid = vcpu->vcpuid; 1471b837daddSKonstantin Belousov td = curthread; 14725b8a8cd1SNeel Natu mtx_lock(&vm->rendezvous_mtx); 14735b8a8cd1SNeel Natu while (vm->rendezvous_func != NULL) { 147422d822c6SNeel Natu /* 'rendezvous_req_cpus' must be a subset of 'active_cpus' */ 1475e2650af1SStefan Eßer CPU_AND(&vm->rendezvous_req_cpus, &vm->rendezvous_req_cpus, &vm->active_cpus); 147622d822c6SNeel Natu 1477949f0f47SJohn Baldwin if (CPU_ISSET(vcpuid, &vm->rendezvous_req_cpus) && 147822d822c6SNeel Natu !CPU_ISSET(vcpuid, &vm->rendezvous_done_cpus)) { 1479d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Calling rendezvous func"); 1480d8be3d52SJohn Baldwin (*vm->rendezvous_func)(vcpu, vm->rendezvous_arg); 14815b8a8cd1SNeel Natu CPU_SET(vcpuid, &vm->rendezvous_done_cpus); 14825b8a8cd1SNeel Natu } 14835b8a8cd1SNeel Natu if (CPU_CMP(&vm->rendezvous_req_cpus, 14845b8a8cd1SNeel Natu &vm->rendezvous_done_cpus) == 0) { 1485d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Rendezvous completed"); 1486892feec2SCorvin Köhne CPU_ZERO(&vm->rendezvous_req_cpus); 1487869dbab7SAndriy Gapon vm->rendezvous_func = NULL; 14885b8a8cd1SNeel Natu wakeup(&vm->rendezvous_func); 14895b8a8cd1SNeel Natu break; 14905b8a8cd1SNeel Natu } 1491d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Wait for rendezvous completion"); 14925b8a8cd1SNeel Natu mtx_sleep(&vm->rendezvous_func, &vm->rendezvous_mtx, 0, 1493b837daddSKonstantin Belousov "vmrndv", hz); 1494c6d31b83SKonstantin Belousov if (td_ast_pending(td, TDA_SUSPEND)) { 1495b837daddSKonstantin Belousov mtx_unlock(&vm->rendezvous_mtx); 1496b837daddSKonstantin Belousov error = thread_check_susp(td, true); 1497b837daddSKonstantin Belousov if (error != 0) 1498b837daddSKonstantin Belousov return (error); 1499b837daddSKonstantin Belousov mtx_lock(&vm->rendezvous_mtx); 1500b837daddSKonstantin Belousov } 15015b8a8cd1SNeel Natu } 15025b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 1503b837daddSKonstantin Belousov return (0); 15045b8a8cd1SNeel Natu } 15055b8a8cd1SNeel Natu 1506318224bbSNeel Natu /* 1507318224bbSNeel Natu * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run. 1508318224bbSNeel Natu */ 1509318224bbSNeel Natu static int 15103f0f4b15SJohn Baldwin vm_handle_hlt(struct vcpu *vcpu, bool intr_disabled, bool *retu) 1511318224bbSNeel Natu { 15123f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 1513c6a0cc2eSNeel Natu const char *wmesg; 1514b837daddSKonstantin Belousov struct thread *td; 15153f0f4b15SJohn Baldwin int error, t, vcpuid, vcpu_halted, vm_halted; 1516e50ce2aaSNeel Natu 15173f0f4b15SJohn Baldwin vcpuid = vcpu->vcpuid; 1518e50ce2aaSNeel Natu vcpu_halted = 0; 1519e50ce2aaSNeel Natu vm_halted = 0; 1520b837daddSKonstantin Belousov error = 0; 1521b837daddSKonstantin Belousov td = curthread; 1522318224bbSNeel Natu 15233f0f4b15SJohn Baldwin KASSERT(!CPU_ISSET(vcpuid, &vm->halted_cpus), ("vcpu already halted")); 15243f0f4b15SJohn Baldwin 1525f76fc5d4SNeel Natu vcpu_lock(vcpu); 1526c6a0cc2eSNeel Natu while (1) { 1527f76fc5d4SNeel Natu /* 1528f76fc5d4SNeel Natu * Do a final check for pending NMI or interrupts before 1529c6a0cc2eSNeel Natu * really putting this thread to sleep. Also check for 1530c6a0cc2eSNeel Natu * software events that would cause this vcpu to wakeup. 1531f76fc5d4SNeel Natu * 1532c6a0cc2eSNeel Natu * These interrupts/events could have happened after the 153315add60dSPeter Grehan * vcpu returned from vmmops_run() and before it acquired the 1534c6a0cc2eSNeel Natu * vcpu lock above. 1535f76fc5d4SNeel Natu */ 1536248e6799SNeel Natu if (vm->rendezvous_func != NULL || vm->suspend || vcpu->reqidle) 1537c6a0cc2eSNeel Natu break; 153880cb5d84SJohn Baldwin if (vm_nmi_pending(vcpu)) 1539c6a0cc2eSNeel Natu break; 1540c6a0cc2eSNeel Natu if (!intr_disabled) { 154180cb5d84SJohn Baldwin if (vm_extint_pending(vcpu) || 1542c6a0cc2eSNeel Natu vlapic_pending_intr(vcpu->vlapic, NULL)) { 1543c6a0cc2eSNeel Natu break; 1544c6a0cc2eSNeel Natu } 1545c6a0cc2eSNeel Natu } 1546c6a0cc2eSNeel Natu 1547f008d157SNeel Natu /* Don't go to sleep if the vcpu thread needs to yield */ 154880cb5d84SJohn Baldwin if (vcpu_should_yield(vcpu)) 1549f008d157SNeel Natu break; 1550f008d157SNeel Natu 155180cb5d84SJohn Baldwin if (vcpu_debugged(vcpu)) 1552fc276d92SJohn Baldwin break; 1553fc276d92SJohn Baldwin 1554e50ce2aaSNeel Natu /* 1555e50ce2aaSNeel Natu * Some Linux guests implement "halt" by having all vcpus 1556e50ce2aaSNeel Natu * execute HLT with interrupts disabled. 'halted_cpus' keeps 1557e50ce2aaSNeel Natu * track of the vcpus that have entered this state. When all 1558e50ce2aaSNeel Natu * vcpus enter the halted state the virtual machine is halted. 1559e50ce2aaSNeel Natu */ 1560e50ce2aaSNeel Natu if (intr_disabled) { 1561c6a0cc2eSNeel Natu wmesg = "vmhalt"; 15623f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "Halted"); 1563055fc2cbSNeel Natu if (!vcpu_halted && halt_detection_enabled) { 1564e50ce2aaSNeel Natu vcpu_halted = 1; 1565e50ce2aaSNeel Natu CPU_SET_ATOMIC(vcpuid, &vm->halted_cpus); 1566e50ce2aaSNeel Natu } 1567e50ce2aaSNeel Natu if (CPU_CMP(&vm->halted_cpus, &vm->active_cpus) == 0) { 1568e50ce2aaSNeel Natu vm_halted = 1; 1569e50ce2aaSNeel Natu break; 1570e50ce2aaSNeel Natu } 1571e50ce2aaSNeel Natu } else { 1572e50ce2aaSNeel Natu wmesg = "vmidle"; 1573e50ce2aaSNeel Natu } 1574c6a0cc2eSNeel Natu 1575f76fc5d4SNeel Natu t = ticks; 15763f0f4b15SJohn Baldwin vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 1577f008d157SNeel Natu /* 1578f008d157SNeel Natu * XXX msleep_spin() cannot be interrupted by signals so 1579f008d157SNeel Natu * wake up periodically to check pending signals. 1580f008d157SNeel Natu */ 1581f008d157SNeel Natu msleep_spin(vcpu, &vcpu->mtx, wmesg, hz); 15823f0f4b15SJohn Baldwin vcpu_require_state_locked(vcpu, VCPU_FROZEN); 15833dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VCPU_IDLE_TICKS, ticks - t); 1584c6d31b83SKonstantin Belousov if (td_ast_pending(td, TDA_SUSPEND)) { 1585b837daddSKonstantin Belousov vcpu_unlock(vcpu); 1586b837daddSKonstantin Belousov error = thread_check_susp(td, false); 15874d447b30SKonstantin Belousov if (error != 0) { 15884d447b30SKonstantin Belousov if (vcpu_halted) { 15894d447b30SKonstantin Belousov CPU_CLR_ATOMIC(vcpuid, 15904d447b30SKonstantin Belousov &vm->halted_cpus); 15914d447b30SKonstantin Belousov } 1592b837daddSKonstantin Belousov return (error); 15934d447b30SKonstantin Belousov } 1594b837daddSKonstantin Belousov vcpu_lock(vcpu); 1595b837daddSKonstantin Belousov } 1596f76fc5d4SNeel Natu } 1597e50ce2aaSNeel Natu 1598e50ce2aaSNeel Natu if (vcpu_halted) 1599e50ce2aaSNeel Natu CPU_CLR_ATOMIC(vcpuid, &vm->halted_cpus); 1600e50ce2aaSNeel Natu 1601f76fc5d4SNeel Natu vcpu_unlock(vcpu); 1602f76fc5d4SNeel Natu 1603e50ce2aaSNeel Natu if (vm_halted) 1604e50ce2aaSNeel Natu vm_suspend(vm, VM_SUSPEND_HALT); 1605e50ce2aaSNeel Natu 1606318224bbSNeel Natu return (0); 1607318224bbSNeel Natu } 1608318224bbSNeel Natu 1609318224bbSNeel Natu static int 16103f0f4b15SJohn Baldwin vm_handle_paging(struct vcpu *vcpu, bool *retu) 1611318224bbSNeel Natu { 16123f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 1613318224bbSNeel Natu int rv, ftype; 1614318224bbSNeel Natu struct vm_map *map; 1615318224bbSNeel Natu struct vm_exit *vme; 1616318224bbSNeel Natu 1617318224bbSNeel Natu vme = &vcpu->exitinfo; 1618318224bbSNeel Natu 1619d087a399SNeel Natu KASSERT(vme->inst_length == 0, ("%s: invalid inst_length %d", 1620d087a399SNeel Natu __func__, vme->inst_length)); 1621d087a399SNeel Natu 1622318224bbSNeel Natu ftype = vme->u.paging.fault_type; 1623318224bbSNeel Natu KASSERT(ftype == VM_PROT_READ || 1624318224bbSNeel Natu ftype == VM_PROT_WRITE || ftype == VM_PROT_EXECUTE, 1625318224bbSNeel Natu ("vm_handle_paging: invalid fault_type %d", ftype)); 1626318224bbSNeel Natu 1627318224bbSNeel Natu if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { 1628318224bbSNeel Natu rv = pmap_emulate_accessed_dirty(vmspace_pmap(vm->vmspace), 1629318224bbSNeel Natu vme->u.paging.gpa, ftype); 16309d8d8e3eSNeel Natu if (rv == 0) { 16313f0f4b15SJohn Baldwin VMM_CTR2(vcpu, "%s bit emulation for gpa %#lx", 16329d8d8e3eSNeel Natu ftype == VM_PROT_READ ? "accessed" : "dirty", 16339d8d8e3eSNeel Natu vme->u.paging.gpa); 1634318224bbSNeel Natu goto done; 1635318224bbSNeel Natu } 16369d8d8e3eSNeel Natu } 1637318224bbSNeel Natu 1638318224bbSNeel Natu map = &vm->vmspace->vm_map; 1639df08823dSKonstantin Belousov rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL, NULL); 1640318224bbSNeel Natu 16413f0f4b15SJohn Baldwin VMM_CTR3(vcpu, "vm_handle_paging rv = %d, gpa = %#lx, " 1642513c8d33SNeel Natu "ftype = %d", rv, vme->u.paging.gpa, ftype); 1643318224bbSNeel Natu 1644318224bbSNeel Natu if (rv != KERN_SUCCESS) 1645318224bbSNeel Natu return (EFAULT); 1646318224bbSNeel Natu done: 1647318224bbSNeel Natu return (0); 1648318224bbSNeel Natu } 1649318224bbSNeel Natu 1650318224bbSNeel Natu static int 16513f0f4b15SJohn Baldwin vm_handle_inst_emul(struct vcpu *vcpu, bool *retu) 1652318224bbSNeel Natu { 1653318224bbSNeel Natu struct vie *vie; 1654318224bbSNeel Natu struct vm_exit *vme; 1655e4f605eeSTycho Nightingale uint64_t gla, gpa, cs_base; 1656e813a873SNeel Natu struct vm_guest_paging *paging; 1657565bbb86SNeel Natu mem_region_read_t mread; 1658565bbb86SNeel Natu mem_region_write_t mwrite; 1659f7a9f178SNeel Natu enum vm_cpu_mode cpu_mode; 16601c73ea3eSNeel Natu int cs_d, error, fault; 1661318224bbSNeel Natu 1662318224bbSNeel Natu vme = &vcpu->exitinfo; 1663318224bbSNeel Natu 16641c73ea3eSNeel Natu KASSERT(vme->inst_length == 0, ("%s: invalid inst_length %d", 16651c73ea3eSNeel Natu __func__, vme->inst_length)); 16661c73ea3eSNeel Natu 1667318224bbSNeel Natu gla = vme->u.inst_emul.gla; 1668318224bbSNeel Natu gpa = vme->u.inst_emul.gpa; 1669e4f605eeSTycho Nightingale cs_base = vme->u.inst_emul.cs_base; 1670f7a9f178SNeel Natu cs_d = vme->u.inst_emul.cs_d; 1671318224bbSNeel Natu vie = &vme->u.inst_emul.vie; 1672e813a873SNeel Natu paging = &vme->u.inst_emul.paging; 1673f7a9f178SNeel Natu cpu_mode = paging->cpu_mode; 1674318224bbSNeel Natu 16753f0f4b15SJohn Baldwin VMM_CTR1(vcpu, "inst_emul fault accessing gpa %#lx", gpa); 16769d8d8e3eSNeel Natu 1677318224bbSNeel Natu /* Fetch, decode and emulate the faulting instruction */ 1678c2a875f9SNeel Natu if (vie->num_valid == 0) { 1679d3956e46SJohn Baldwin error = vmm_fetch_instruction(vcpu, paging, vme->rip + cs_base, 1680d3956e46SJohn Baldwin VIE_INST_SIZE, vie, &fault); 1681c2a875f9SNeel Natu } else { 1682c2a875f9SNeel Natu /* 1683c2a875f9SNeel Natu * The instruction bytes have already been copied into 'vie' 1684c2a875f9SNeel Natu */ 16859c4d5478SNeel Natu error = fault = 0; 1686c2a875f9SNeel Natu } 16879c4d5478SNeel Natu if (error || fault) 16889c4d5478SNeel Natu return (error); 1689318224bbSNeel Natu 1690d3956e46SJohn Baldwin if (vmm_decode_instruction(vcpu, gla, cpu_mode, cs_d, vie) != 0) { 16913f0f4b15SJohn Baldwin VMM_CTR1(vcpu, "Error decoding instruction at %#lx", 1692c07a0648SNeel Natu vme->rip + cs_base); 1693c07a0648SNeel Natu *retu = true; /* dump instruction bytes in userspace */ 1694c07a0648SNeel Natu return (0); 1695c07a0648SNeel Natu } 1696318224bbSNeel Natu 1697a0b78f09SPeter Grehan /* 16981c73ea3eSNeel Natu * Update 'nextrip' based on the length of the emulated instruction. 1699a0b78f09SPeter Grehan */ 1700a0b78f09SPeter Grehan vme->inst_length = vie->num_processed; 1701d087a399SNeel Natu vcpu->nextrip += vie->num_processed; 17023f0f4b15SJohn Baldwin VMM_CTR1(vcpu, "nextrip updated to %#lx after instruction decoding", 17033f0f4b15SJohn Baldwin vcpu->nextrip); 1704a0b78f09SPeter Grehan 170508e3ff32SNeel Natu /* return to userland unless this is an in-kernel emulated device */ 1706565bbb86SNeel Natu if (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE) { 1707565bbb86SNeel Natu mread = lapic_mmio_read; 1708565bbb86SNeel Natu mwrite = lapic_mmio_write; 1709565bbb86SNeel Natu } else if (gpa >= VIOAPIC_BASE && gpa < VIOAPIC_BASE + VIOAPIC_SIZE) { 1710565bbb86SNeel Natu mread = vioapic_mmio_read; 1711565bbb86SNeel Natu mwrite = vioapic_mmio_write; 171208e3ff32SNeel Natu } else if (gpa >= VHPET_BASE && gpa < VHPET_BASE + VHPET_SIZE) { 171308e3ff32SNeel Natu mread = vhpet_mmio_read; 171408e3ff32SNeel Natu mwrite = vhpet_mmio_write; 1715565bbb86SNeel Natu } else { 1716becd9849SNeel Natu *retu = true; 1717318224bbSNeel Natu return (0); 1718318224bbSNeel Natu } 1719318224bbSNeel Natu 1720d3956e46SJohn Baldwin error = vmm_emulate_instruction(vcpu, gpa, vie, paging, mread, mwrite, 1721d3956e46SJohn Baldwin retu); 1722318224bbSNeel Natu 1723318224bbSNeel Natu return (error); 1724318224bbSNeel Natu } 1725318224bbSNeel Natu 1726b15a09c0SNeel Natu static int 17273f0f4b15SJohn Baldwin vm_handle_suspend(struct vcpu *vcpu, bool *retu) 1728b15a09c0SNeel Natu { 17293f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 1730b837daddSKonstantin Belousov int error, i; 1731b837daddSKonstantin Belousov struct thread *td; 1732b15a09c0SNeel Natu 1733b837daddSKonstantin Belousov error = 0; 1734b837daddSKonstantin Belousov td = curthread; 1735b15a09c0SNeel Natu 17363f0f4b15SJohn Baldwin CPU_SET_ATOMIC(vcpu->vcpuid, &vm->suspended_cpus); 1737b15a09c0SNeel Natu 1738b15a09c0SNeel Natu /* 1739b15a09c0SNeel Natu * Wait until all 'active_cpus' have suspended themselves. 1740b15a09c0SNeel Natu * 1741b15a09c0SNeel Natu * Since a VM may be suspended at any time including when one or 1742b15a09c0SNeel Natu * more vcpus are doing a rendezvous we need to call the rendezvous 1743b15a09c0SNeel Natu * handler while we are waiting to prevent a deadlock. 1744b15a09c0SNeel Natu */ 1745b15a09c0SNeel Natu vcpu_lock(vcpu); 1746b837daddSKonstantin Belousov while (error == 0) { 1747b15a09c0SNeel Natu if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 17483f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "All vcpus suspended"); 1749b15a09c0SNeel Natu break; 1750b15a09c0SNeel Natu } 1751b15a09c0SNeel Natu 1752b15a09c0SNeel Natu if (vm->rendezvous_func == NULL) { 17533f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "Sleeping during suspend"); 17543f0f4b15SJohn Baldwin vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 1755b15a09c0SNeel Natu msleep_spin(vcpu, &vcpu->mtx, "vmsusp", hz); 17563f0f4b15SJohn Baldwin vcpu_require_state_locked(vcpu, VCPU_FROZEN); 1757c6d31b83SKonstantin Belousov if (td_ast_pending(td, TDA_SUSPEND)) { 1758b837daddSKonstantin Belousov vcpu_unlock(vcpu); 1759b837daddSKonstantin Belousov error = thread_check_susp(td, false); 1760b837daddSKonstantin Belousov vcpu_lock(vcpu); 1761b837daddSKonstantin Belousov } 1762b15a09c0SNeel Natu } else { 17633f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "Rendezvous during suspend"); 1764b15a09c0SNeel Natu vcpu_unlock(vcpu); 1765d8be3d52SJohn Baldwin error = vm_handle_rendezvous(vcpu); 1766b15a09c0SNeel Natu vcpu_lock(vcpu); 1767b15a09c0SNeel Natu } 1768b15a09c0SNeel Natu } 1769b15a09c0SNeel Natu vcpu_unlock(vcpu); 1770b15a09c0SNeel Natu 1771b15a09c0SNeel Natu /* 1772b15a09c0SNeel Natu * Wakeup the other sleeping vcpus and return to userspace. 1773b15a09c0SNeel Natu */ 1774a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 1775b15a09c0SNeel Natu if (CPU_ISSET(i, &vm->suspended_cpus)) { 17763f0f4b15SJohn Baldwin vcpu_notify_event(vm_vcpu(vm, i), false); 1777b15a09c0SNeel Natu } 1778b15a09c0SNeel Natu } 1779b15a09c0SNeel Natu 1780b15a09c0SNeel Natu *retu = true; 1781b837daddSKonstantin Belousov return (error); 1782b15a09c0SNeel Natu } 1783b15a09c0SNeel Natu 1784248e6799SNeel Natu static int 17853f0f4b15SJohn Baldwin vm_handle_reqidle(struct vcpu *vcpu, bool *retu) 1786248e6799SNeel Natu { 1787248e6799SNeel Natu vcpu_lock(vcpu); 1788248e6799SNeel Natu KASSERT(vcpu->reqidle, ("invalid vcpu reqidle %d", vcpu->reqidle)); 1789248e6799SNeel Natu vcpu->reqidle = 0; 1790248e6799SNeel Natu vcpu_unlock(vcpu); 1791248e6799SNeel Natu *retu = true; 1792248e6799SNeel Natu return (0); 1793248e6799SNeel Natu } 1794248e6799SNeel Natu 1795e3b4fe64SBojan Novković static int 1796e3b4fe64SBojan Novković vm_handle_db(struct vcpu *vcpu, struct vm_exit *vme, bool *retu) 1797e3b4fe64SBojan Novković { 1798e3b4fe64SBojan Novković int error, fault; 1799e3b4fe64SBojan Novković uint64_t rsp; 1800e3b4fe64SBojan Novković uint64_t rflags; 180151fda658SBojan Novković struct vm_copyinfo copyinfo[2]; 1802e3b4fe64SBojan Novković 1803e3b4fe64SBojan Novković *retu = true; 1804e3b4fe64SBojan Novković if (!vme->u.dbg.pushf_intercept || vme->u.dbg.tf_shadow_val != 0) { 1805e3b4fe64SBojan Novković return (0); 1806e3b4fe64SBojan Novković } 1807e3b4fe64SBojan Novković 1808e3b4fe64SBojan Novković vm_get_register(vcpu, VM_REG_GUEST_RSP, &rsp); 1809e3b4fe64SBojan Novković error = vm_copy_setup(vcpu, &vme->u.dbg.paging, rsp, sizeof(uint64_t), 181051fda658SBojan Novković VM_PROT_RW, copyinfo, nitems(copyinfo), &fault); 1811e3b4fe64SBojan Novković if (error != 0 || fault != 0) { 1812e3b4fe64SBojan Novković *retu = false; 1813e3b4fe64SBojan Novković return (EINVAL); 1814e3b4fe64SBojan Novković } 1815e3b4fe64SBojan Novković 1816e3b4fe64SBojan Novković /* Read pushed rflags value from top of stack. */ 181751fda658SBojan Novković vm_copyin(copyinfo, &rflags, sizeof(uint64_t)); 1818e3b4fe64SBojan Novković 1819e3b4fe64SBojan Novković /* Clear TF bit. */ 1820e3b4fe64SBojan Novković rflags &= ~(PSL_T); 1821e3b4fe64SBojan Novković 1822e3b4fe64SBojan Novković /* Write updated value back to memory. */ 182351fda658SBojan Novković vm_copyout(&rflags, copyinfo, sizeof(uint64_t)); 182451fda658SBojan Novković vm_copy_teardown(copyinfo, nitems(copyinfo)); 1825e3b4fe64SBojan Novković 1826e3b4fe64SBojan Novković return (0); 1827e3b4fe64SBojan Novković } 1828e3b4fe64SBojan Novković 1829b15a09c0SNeel Natu int 1830f0fdcfe2SNeel Natu vm_suspend(struct vm *vm, enum vm_suspend_how how) 1831b15a09c0SNeel Natu { 1832f0fdcfe2SNeel Natu int i; 1833b15a09c0SNeel Natu 1834f0fdcfe2SNeel Natu if (how <= VM_SUSPEND_NONE || how >= VM_SUSPEND_LAST) 1835f0fdcfe2SNeel Natu return (EINVAL); 1836f0fdcfe2SNeel Natu 1837f0fdcfe2SNeel Natu if (atomic_cmpset_int(&vm->suspend, 0, how) == 0) { 1838f0fdcfe2SNeel Natu VM_CTR2(vm, "virtual machine already suspended %d/%d", 1839f0fdcfe2SNeel Natu vm->suspend, how); 1840b15a09c0SNeel Natu return (EALREADY); 1841b15a09c0SNeel Natu } 1842f0fdcfe2SNeel Natu 1843f0fdcfe2SNeel Natu VM_CTR1(vm, "virtual machine successfully suspended %d", how); 1844f0fdcfe2SNeel Natu 1845f0fdcfe2SNeel Natu /* 1846f0fdcfe2SNeel Natu * Notify all active vcpus that they are now suspended. 1847f0fdcfe2SNeel Natu */ 1848a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 1849f0fdcfe2SNeel Natu if (CPU_ISSET(i, &vm->active_cpus)) 18503f0f4b15SJohn Baldwin vcpu_notify_event(vm_vcpu(vm, i), false); 1851f0fdcfe2SNeel Natu } 1852f0fdcfe2SNeel Natu 1853f0fdcfe2SNeel Natu return (0); 1854f0fdcfe2SNeel Natu } 1855f0fdcfe2SNeel Natu 1856f0fdcfe2SNeel Natu void 185780cb5d84SJohn Baldwin vm_exit_suspended(struct vcpu *vcpu, uint64_t rip) 1858f0fdcfe2SNeel Natu { 185980cb5d84SJohn Baldwin struct vm *vm = vcpu->vm; 1860f0fdcfe2SNeel Natu struct vm_exit *vmexit; 1861f0fdcfe2SNeel Natu 1862f0fdcfe2SNeel Natu KASSERT(vm->suspend > VM_SUSPEND_NONE && vm->suspend < VM_SUSPEND_LAST, 1863f0fdcfe2SNeel Natu ("vm_exit_suspended: invalid suspend type %d", vm->suspend)); 1864f0fdcfe2SNeel Natu 186580cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 1866f0fdcfe2SNeel Natu vmexit->rip = rip; 1867f0fdcfe2SNeel Natu vmexit->inst_length = 0; 1868f0fdcfe2SNeel Natu vmexit->exitcode = VM_EXITCODE_SUSPENDED; 1869f0fdcfe2SNeel Natu vmexit->u.suspended.how = vm->suspend; 1870b15a09c0SNeel Natu } 1871b15a09c0SNeel Natu 187240487465SNeel Natu void 187380cb5d84SJohn Baldwin vm_exit_debug(struct vcpu *vcpu, uint64_t rip) 1874fc276d92SJohn Baldwin { 1875fc276d92SJohn Baldwin struct vm_exit *vmexit; 1876fc276d92SJohn Baldwin 187780cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 1878fc276d92SJohn Baldwin vmexit->rip = rip; 1879fc276d92SJohn Baldwin vmexit->inst_length = 0; 1880fc276d92SJohn Baldwin vmexit->exitcode = VM_EXITCODE_DEBUG; 1881fc276d92SJohn Baldwin } 1882fc276d92SJohn Baldwin 1883fc276d92SJohn Baldwin void 188480cb5d84SJohn Baldwin vm_exit_rendezvous(struct vcpu *vcpu, uint64_t rip) 188540487465SNeel Natu { 188640487465SNeel Natu struct vm_exit *vmexit; 188740487465SNeel Natu 188880cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 188940487465SNeel Natu vmexit->rip = rip; 189040487465SNeel Natu vmexit->inst_length = 0; 189140487465SNeel Natu vmexit->exitcode = VM_EXITCODE_RENDEZVOUS; 189280cb5d84SJohn Baldwin vmm_stat_incr(vcpu, VMEXIT_RENDEZVOUS, 1); 189340487465SNeel Natu } 189440487465SNeel Natu 189540487465SNeel Natu void 189680cb5d84SJohn Baldwin vm_exit_reqidle(struct vcpu *vcpu, uint64_t rip) 1897248e6799SNeel Natu { 1898248e6799SNeel Natu struct vm_exit *vmexit; 1899248e6799SNeel Natu 190080cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 1901248e6799SNeel Natu vmexit->rip = rip; 1902248e6799SNeel Natu vmexit->inst_length = 0; 1903248e6799SNeel Natu vmexit->exitcode = VM_EXITCODE_REQIDLE; 190480cb5d84SJohn Baldwin vmm_stat_incr(vcpu, VMEXIT_REQIDLE, 1); 1905248e6799SNeel Natu } 1906248e6799SNeel Natu 1907248e6799SNeel Natu void 190880cb5d84SJohn Baldwin vm_exit_astpending(struct vcpu *vcpu, uint64_t rip) 190940487465SNeel Natu { 191040487465SNeel Natu struct vm_exit *vmexit; 191140487465SNeel Natu 191280cb5d84SJohn Baldwin vmexit = vm_exitinfo(vcpu); 191340487465SNeel Natu vmexit->rip = rip; 191440487465SNeel Natu vmexit->inst_length = 0; 191540487465SNeel Natu vmexit->exitcode = VM_EXITCODE_BOGUS; 191680cb5d84SJohn Baldwin vmm_stat_incr(vcpu, VMEXIT_ASTPENDING, 1); 191740487465SNeel Natu } 191840487465SNeel Natu 1919318224bbSNeel Natu int 1920e17eca32SMark Johnston vm_run(struct vcpu *vcpu) 1921318224bbSNeel Natu { 19223f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 1923248e6799SNeel Natu struct vm_eventinfo evinfo; 1924318224bbSNeel Natu int error, vcpuid; 1925318224bbSNeel Natu struct pcb *pcb; 1926d087a399SNeel Natu uint64_t tscval; 1927318224bbSNeel Natu struct vm_exit *vme; 1928becd9849SNeel Natu bool retu, intr_disabled; 1929318224bbSNeel Natu pmap_t pmap; 1930318224bbSNeel Natu 19313f0f4b15SJohn Baldwin vcpuid = vcpu->vcpuid; 1932318224bbSNeel Natu 193395ebc360SNeel Natu if (!CPU_ISSET(vcpuid, &vm->active_cpus)) 193495ebc360SNeel Natu return (EINVAL); 193595ebc360SNeel Natu 193695ebc360SNeel Natu if (CPU_ISSET(vcpuid, &vm->suspended_cpus)) 193795ebc360SNeel Natu return (EINVAL); 193895ebc360SNeel Natu 1939318224bbSNeel Natu pmap = vmspace_pmap(vm->vmspace); 1940318224bbSNeel Natu vme = &vcpu->exitinfo; 1941892feec2SCorvin Köhne evinfo.rptr = &vm->rendezvous_req_cpus; 1942248e6799SNeel Natu evinfo.sptr = &vm->suspend; 1943248e6799SNeel Natu evinfo.iptr = &vcpu->reqidle; 1944318224bbSNeel Natu restart: 1945318224bbSNeel Natu critical_enter(); 1946318224bbSNeel Natu 1947318224bbSNeel Natu KASSERT(!CPU_ISSET(curcpu, &pmap->pm_active), 1948318224bbSNeel Natu ("vm_run: absurd pm_active")); 1949318224bbSNeel Natu 1950318224bbSNeel Natu tscval = rdtsc(); 1951318224bbSNeel Natu 1952318224bbSNeel Natu pcb = PCPU_GET(curpcb); 1953318224bbSNeel Natu set_pcb_flags(pcb, PCB_FULL_IRET); 1954318224bbSNeel Natu 1955318224bbSNeel Natu restore_guest_fpustate(vcpu); 1956318224bbSNeel Natu 19573f0f4b15SJohn Baldwin vcpu_require_state(vcpu, VCPU_RUNNING); 1958869c8d19SJohn Baldwin error = vmmops_run(vcpu->cookie, vcpu->nextrip, pmap, &evinfo); 19593f0f4b15SJohn Baldwin vcpu_require_state(vcpu, VCPU_FROZEN); 1960318224bbSNeel Natu 1961318224bbSNeel Natu save_guest_fpustate(vcpu); 1962318224bbSNeel Natu 19633dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 1964318224bbSNeel Natu 1965318224bbSNeel Natu critical_exit(); 1966318224bbSNeel Natu 1967318224bbSNeel Natu if (error == 0) { 1968becd9849SNeel Natu retu = false; 1969d087a399SNeel Natu vcpu->nextrip = vme->rip + vme->inst_length; 1970318224bbSNeel Natu switch (vme->exitcode) { 1971248e6799SNeel Natu case VM_EXITCODE_REQIDLE: 19723f0f4b15SJohn Baldwin error = vm_handle_reqidle(vcpu, &retu); 1973248e6799SNeel Natu break; 1974b15a09c0SNeel Natu case VM_EXITCODE_SUSPENDED: 19753f0f4b15SJohn Baldwin error = vm_handle_suspend(vcpu, &retu); 1976b15a09c0SNeel Natu break; 197730b94db8SNeel Natu case VM_EXITCODE_IOAPIC_EOI: 1978e42c24d5SJohn Baldwin vioapic_process_eoi(vm, vme->u.ioapic_eoi.vector); 197930b94db8SNeel Natu break; 19805b8a8cd1SNeel Natu case VM_EXITCODE_RENDEZVOUS: 1981d8be3d52SJohn Baldwin error = vm_handle_rendezvous(vcpu); 19825b8a8cd1SNeel Natu break; 1983318224bbSNeel Natu case VM_EXITCODE_HLT: 1984becd9849SNeel Natu intr_disabled = ((vme->u.hlt.rflags & PSL_I) == 0); 19853f0f4b15SJohn Baldwin error = vm_handle_hlt(vcpu, intr_disabled, &retu); 1986318224bbSNeel Natu break; 1987318224bbSNeel Natu case VM_EXITCODE_PAGING: 19883f0f4b15SJohn Baldwin error = vm_handle_paging(vcpu, &retu); 1989318224bbSNeel Natu break; 1990318224bbSNeel Natu case VM_EXITCODE_INST_EMUL: 19913f0f4b15SJohn Baldwin error = vm_handle_inst_emul(vcpu, &retu); 1992318224bbSNeel Natu break; 1993d17b5104SNeel Natu case VM_EXITCODE_INOUT: 1994d17b5104SNeel Natu case VM_EXITCODE_INOUT_STR: 19953f0f4b15SJohn Baldwin error = vm_handle_inout(vcpu, vme, &retu); 1996d17b5104SNeel Natu break; 1997e3b4fe64SBojan Novković case VM_EXITCODE_DB: 1998e3b4fe64SBojan Novković error = vm_handle_db(vcpu, vme, &retu); 1999e3b4fe64SBojan Novković break; 200065145c7fSNeel Natu case VM_EXITCODE_MONITOR: 200165145c7fSNeel Natu case VM_EXITCODE_MWAIT: 200227d26457SAndrew Turner case VM_EXITCODE_VMINSN: 2003d3956e46SJohn Baldwin vm_inject_ud(vcpu); 200465145c7fSNeel Natu break; 2005318224bbSNeel Natu default: 2006becd9849SNeel Natu retu = true; /* handled in userland */ 2007318224bbSNeel Natu break; 2008318224bbSNeel Natu } 2009318224bbSNeel Natu } 2010318224bbSNeel Natu 20110bda8d3eSCorvin Köhne /* 20120bda8d3eSCorvin Köhne * VM_EXITCODE_INST_EMUL could access the apic which could transform the 20130bda8d3eSCorvin Köhne * exit code into VM_EXITCODE_IPI. 20140bda8d3eSCorvin Köhne */ 2015ba34de1bSMark Johnston if (error == 0 && vme->exitcode == VM_EXITCODE_IPI) 2016d8be3d52SJohn Baldwin error = vm_handle_ipi(vcpu, vme, &retu); 20170bda8d3eSCorvin Köhne 2018d087a399SNeel Natu if (error == 0 && retu == false) 2019f76fc5d4SNeel Natu goto restart; 2020f76fc5d4SNeel Natu 20213dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VMEXIT_USERSPACE, 1); 20223f0f4b15SJohn Baldwin VMM_CTR2(vcpu, "retu %d/%d", error, vme->exitcode); 2023248e6799SNeel Natu 2024366f6083SPeter Grehan return (error); 2025366f6083SPeter Grehan } 2026366f6083SPeter Grehan 2027366f6083SPeter Grehan int 2028d3956e46SJohn Baldwin vm_restart_instruction(struct vcpu *vcpu) 2029c9c75df4SNeel Natu { 2030d087a399SNeel Natu enum vcpu_state state; 2031d087a399SNeel Natu uint64_t rip; 203273505a10SRobert Wing int error __diagused; 2033c9c75df4SNeel Natu 2034d3956e46SJohn Baldwin state = vcpu_get_state(vcpu, NULL); 2035d087a399SNeel Natu if (state == VCPU_RUNNING) { 2036d087a399SNeel Natu /* 2037d087a399SNeel Natu * When a vcpu is "running" the next instruction is determined 2038d087a399SNeel Natu * by adding 'rip' and 'inst_length' in the vcpu's 'exitinfo'. 2039d087a399SNeel Natu * Thus setting 'inst_length' to zero will cause the current 2040d087a399SNeel Natu * instruction to be restarted. 2041d087a399SNeel Natu */ 2042c9c75df4SNeel Natu vcpu->exitinfo.inst_length = 0; 2043d3956e46SJohn Baldwin VMM_CTR1(vcpu, "restarting instruction at %#lx by " 2044d087a399SNeel Natu "setting inst_length to zero", vcpu->exitinfo.rip); 2045d087a399SNeel Natu } else if (state == VCPU_FROZEN) { 2046d087a399SNeel Natu /* 2047d087a399SNeel Natu * When a vcpu is "frozen" it is outside the critical section 204815add60dSPeter Grehan * around vmmops_run() and 'nextrip' points to the next 204915add60dSPeter Grehan * instruction. Thus instruction restart is achieved by setting 205015add60dSPeter Grehan * 'nextrip' to the vcpu's %rip. 2051d087a399SNeel Natu */ 2052d3956e46SJohn Baldwin error = vm_get_register(vcpu, VM_REG_GUEST_RIP, &rip); 2053d087a399SNeel Natu KASSERT(!error, ("%s: error %d getting rip", __func__, error)); 2054d3956e46SJohn Baldwin VMM_CTR2(vcpu, "restarting instruction by updating " 2055d087a399SNeel Natu "nextrip from %#lx to %#lx", vcpu->nextrip, rip); 2056d087a399SNeel Natu vcpu->nextrip = rip; 2057d087a399SNeel Natu } else { 2058d087a399SNeel Natu panic("%s: invalid state %d", __func__, state); 2059d087a399SNeel Natu } 2060c9c75df4SNeel Natu return (0); 2061c9c75df4SNeel Natu } 2062c9c75df4SNeel Natu 2063c9c75df4SNeel Natu int 206480cb5d84SJohn Baldwin vm_exit_intinfo(struct vcpu *vcpu, uint64_t info) 2065091d4532SNeel Natu { 2066091d4532SNeel Natu int type, vector; 2067091d4532SNeel Natu 2068091d4532SNeel Natu if (info & VM_INTINFO_VALID) { 2069091d4532SNeel Natu type = info & VM_INTINFO_TYPE; 2070091d4532SNeel Natu vector = info & 0xff; 2071091d4532SNeel Natu if (type == VM_INTINFO_NMI && vector != IDT_NMI) 2072091d4532SNeel Natu return (EINVAL); 2073091d4532SNeel Natu if (type == VM_INTINFO_HWEXCEPTION && vector >= 32) 2074091d4532SNeel Natu return (EINVAL); 2075091d4532SNeel Natu if (info & VM_INTINFO_RSVD) 2076091d4532SNeel Natu return (EINVAL); 2077091d4532SNeel Natu } else { 2078091d4532SNeel Natu info = 0; 2079091d4532SNeel Natu } 208080cb5d84SJohn Baldwin VMM_CTR2(vcpu, "%s: info1(%#lx)", __func__, info); 2081091d4532SNeel Natu vcpu->exitintinfo = info; 2082091d4532SNeel Natu return (0); 2083091d4532SNeel Natu } 2084091d4532SNeel Natu 2085091d4532SNeel Natu enum exc_class { 2086091d4532SNeel Natu EXC_BENIGN, 2087091d4532SNeel Natu EXC_CONTRIBUTORY, 2088091d4532SNeel Natu EXC_PAGEFAULT 2089091d4532SNeel Natu }; 2090091d4532SNeel Natu 2091091d4532SNeel Natu #define IDT_VE 20 /* Virtualization Exception (Intel specific) */ 2092091d4532SNeel Natu 2093091d4532SNeel Natu static enum exc_class 2094091d4532SNeel Natu exception_class(uint64_t info) 2095091d4532SNeel Natu { 2096091d4532SNeel Natu int type, vector; 2097091d4532SNeel Natu 2098091d4532SNeel Natu KASSERT(info & VM_INTINFO_VALID, ("intinfo must be valid: %#lx", info)); 2099091d4532SNeel Natu type = info & VM_INTINFO_TYPE; 2100091d4532SNeel Natu vector = info & 0xff; 2101091d4532SNeel Natu 2102091d4532SNeel Natu /* Table 6-4, "Interrupt and Exception Classes", Intel SDM, Vol 3 */ 2103091d4532SNeel Natu switch (type) { 2104091d4532SNeel Natu case VM_INTINFO_HWINTR: 2105091d4532SNeel Natu case VM_INTINFO_SWINTR: 2106091d4532SNeel Natu case VM_INTINFO_NMI: 2107091d4532SNeel Natu return (EXC_BENIGN); 2108091d4532SNeel Natu default: 2109091d4532SNeel Natu /* 2110091d4532SNeel Natu * Hardware exception. 2111091d4532SNeel Natu * 2112091d4532SNeel Natu * SVM and VT-x use identical type values to represent NMI, 2113091d4532SNeel Natu * hardware interrupt and software interrupt. 2114091d4532SNeel Natu * 2115091d4532SNeel Natu * SVM uses type '3' for all exceptions. VT-x uses type '3' 2116091d4532SNeel Natu * for exceptions except #BP and #OF. #BP and #OF use a type 2117091d4532SNeel Natu * value of '5' or '6'. Therefore we don't check for explicit 2118091d4532SNeel Natu * values of 'type' to classify 'intinfo' into a hardware 2119091d4532SNeel Natu * exception. 2120091d4532SNeel Natu */ 2121091d4532SNeel Natu break; 2122091d4532SNeel Natu } 2123091d4532SNeel Natu 2124091d4532SNeel Natu switch (vector) { 2125091d4532SNeel Natu case IDT_PF: 2126091d4532SNeel Natu case IDT_VE: 2127091d4532SNeel Natu return (EXC_PAGEFAULT); 2128091d4532SNeel Natu case IDT_DE: 2129091d4532SNeel Natu case IDT_TS: 2130091d4532SNeel Natu case IDT_NP: 2131091d4532SNeel Natu case IDT_SS: 2132091d4532SNeel Natu case IDT_GP: 2133091d4532SNeel Natu return (EXC_CONTRIBUTORY); 2134091d4532SNeel Natu default: 2135091d4532SNeel Natu return (EXC_BENIGN); 2136091d4532SNeel Natu } 2137091d4532SNeel Natu } 2138091d4532SNeel Natu 2139091d4532SNeel Natu static int 214080cb5d84SJohn Baldwin nested_fault(struct vcpu *vcpu, uint64_t info1, uint64_t info2, 2141091d4532SNeel Natu uint64_t *retinfo) 2142091d4532SNeel Natu { 2143091d4532SNeel Natu enum exc_class exc1, exc2; 2144091d4532SNeel Natu int type1, vector1; 2145091d4532SNeel Natu 2146091d4532SNeel Natu KASSERT(info1 & VM_INTINFO_VALID, ("info1 %#lx is not valid", info1)); 2147091d4532SNeel Natu KASSERT(info2 & VM_INTINFO_VALID, ("info2 %#lx is not valid", info2)); 2148091d4532SNeel Natu 2149091d4532SNeel Natu /* 2150091d4532SNeel Natu * If an exception occurs while attempting to call the double-fault 2151091d4532SNeel Natu * handler the processor enters shutdown mode (aka triple fault). 2152091d4532SNeel Natu */ 2153091d4532SNeel Natu type1 = info1 & VM_INTINFO_TYPE; 2154091d4532SNeel Natu vector1 = info1 & 0xff; 2155091d4532SNeel Natu if (type1 == VM_INTINFO_HWEXCEPTION && vector1 == IDT_DF) { 215680cb5d84SJohn Baldwin VMM_CTR2(vcpu, "triple fault: info1(%#lx), info2(%#lx)", 2157091d4532SNeel Natu info1, info2); 215880cb5d84SJohn Baldwin vm_suspend(vcpu->vm, VM_SUSPEND_TRIPLEFAULT); 2159091d4532SNeel Natu *retinfo = 0; 2160091d4532SNeel Natu return (0); 2161091d4532SNeel Natu } 2162091d4532SNeel Natu 2163091d4532SNeel Natu /* 2164091d4532SNeel Natu * Table 6-5 "Conditions for Generating a Double Fault", Intel SDM, Vol3 2165091d4532SNeel Natu */ 2166091d4532SNeel Natu exc1 = exception_class(info1); 2167091d4532SNeel Natu exc2 = exception_class(info2); 2168091d4532SNeel Natu if ((exc1 == EXC_CONTRIBUTORY && exc2 == EXC_CONTRIBUTORY) || 2169091d4532SNeel Natu (exc1 == EXC_PAGEFAULT && exc2 != EXC_BENIGN)) { 2170091d4532SNeel Natu /* Convert nested fault into a double fault. */ 2171091d4532SNeel Natu *retinfo = IDT_DF; 2172091d4532SNeel Natu *retinfo |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION; 2173091d4532SNeel Natu *retinfo |= VM_INTINFO_DEL_ERRCODE; 2174091d4532SNeel Natu } else { 2175091d4532SNeel Natu /* Handle exceptions serially */ 2176091d4532SNeel Natu *retinfo = info2; 2177091d4532SNeel Natu } 2178091d4532SNeel Natu return (1); 2179091d4532SNeel Natu } 2180091d4532SNeel Natu 2181091d4532SNeel Natu static uint64_t 2182091d4532SNeel Natu vcpu_exception_intinfo(struct vcpu *vcpu) 2183091d4532SNeel Natu { 2184091d4532SNeel Natu uint64_t info = 0; 2185091d4532SNeel Natu 2186091d4532SNeel Natu if (vcpu->exception_pending) { 2187c9c75df4SNeel Natu info = vcpu->exc_vector & 0xff; 2188091d4532SNeel Natu info |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION; 2189c9c75df4SNeel Natu if (vcpu->exc_errcode_valid) { 2190091d4532SNeel Natu info |= VM_INTINFO_DEL_ERRCODE; 2191c9c75df4SNeel Natu info |= (uint64_t)vcpu->exc_errcode << 32; 2192091d4532SNeel Natu } 2193091d4532SNeel Natu } 2194091d4532SNeel Natu return (info); 2195091d4532SNeel Natu } 2196091d4532SNeel Natu 2197091d4532SNeel Natu int 219880cb5d84SJohn Baldwin vm_entry_intinfo(struct vcpu *vcpu, uint64_t *retinfo) 2199091d4532SNeel Natu { 2200091d4532SNeel Natu uint64_t info1, info2; 2201091d4532SNeel Natu int valid; 2202091d4532SNeel Natu 2203091d4532SNeel Natu info1 = vcpu->exitintinfo; 2204091d4532SNeel Natu vcpu->exitintinfo = 0; 2205091d4532SNeel Natu 2206091d4532SNeel Natu info2 = 0; 2207091d4532SNeel Natu if (vcpu->exception_pending) { 2208091d4532SNeel Natu info2 = vcpu_exception_intinfo(vcpu); 2209091d4532SNeel Natu vcpu->exception_pending = 0; 221080cb5d84SJohn Baldwin VMM_CTR2(vcpu, "Exception %d delivered: %#lx", 2211c9c75df4SNeel Natu vcpu->exc_vector, info2); 2212091d4532SNeel Natu } 2213091d4532SNeel Natu 2214091d4532SNeel Natu if ((info1 & VM_INTINFO_VALID) && (info2 & VM_INTINFO_VALID)) { 221580cb5d84SJohn Baldwin valid = nested_fault(vcpu, info1, info2, retinfo); 2216091d4532SNeel Natu } else if (info1 & VM_INTINFO_VALID) { 2217091d4532SNeel Natu *retinfo = info1; 2218091d4532SNeel Natu valid = 1; 2219091d4532SNeel Natu } else if (info2 & VM_INTINFO_VALID) { 2220091d4532SNeel Natu *retinfo = info2; 2221091d4532SNeel Natu valid = 1; 2222091d4532SNeel Natu } else { 2223091d4532SNeel Natu valid = 0; 2224091d4532SNeel Natu } 2225091d4532SNeel Natu 2226091d4532SNeel Natu if (valid) { 2227d3956e46SJohn Baldwin VMM_CTR4(vcpu, "%s: info1(%#lx), info2(%#lx), " 2228091d4532SNeel Natu "retinfo(%#lx)", __func__, info1, info2, *retinfo); 2229091d4532SNeel Natu } 2230091d4532SNeel Natu 2231091d4532SNeel Natu return (valid); 2232091d4532SNeel Natu } 2233091d4532SNeel Natu 2234091d4532SNeel Natu int 22353f0f4b15SJohn Baldwin vm_get_intinfo(struct vcpu *vcpu, uint64_t *info1, uint64_t *info2) 2236091d4532SNeel Natu { 2237091d4532SNeel Natu *info1 = vcpu->exitintinfo; 2238091d4532SNeel Natu *info2 = vcpu_exception_intinfo(vcpu); 2239091d4532SNeel Natu return (0); 2240091d4532SNeel Natu } 2241091d4532SNeel Natu 2242091d4532SNeel Natu int 2243d3956e46SJohn Baldwin vm_inject_exception(struct vcpu *vcpu, int vector, int errcode_valid, 2244c9c75df4SNeel Natu uint32_t errcode, int restart_instruction) 2245366f6083SPeter Grehan { 224647b9935dSNeel Natu uint64_t regval; 224773505a10SRobert Wing int error __diagused; 2248dc506506SNeel Natu 2249c9c75df4SNeel Natu if (vector < 0 || vector >= 32) 2250366f6083SPeter Grehan return (EINVAL); 2251366f6083SPeter Grehan 2252091d4532SNeel Natu /* 2253091d4532SNeel Natu * A double fault exception should never be injected directly into 2254091d4532SNeel Natu * the guest. It is a derived exception that results from specific 2255091d4532SNeel Natu * combinations of nested faults. 2256091d4532SNeel Natu */ 2257c9c75df4SNeel Natu if (vector == IDT_DF) 2258091d4532SNeel Natu return (EINVAL); 2259091d4532SNeel Natu 2260dc506506SNeel Natu if (vcpu->exception_pending) { 2261d3956e46SJohn Baldwin VMM_CTR2(vcpu, "Unable to inject exception %d due to " 2262c9c75df4SNeel Natu "pending exception %d", vector, vcpu->exc_vector); 2263dc506506SNeel Natu return (EBUSY); 2264dc506506SNeel Natu } 2265dc506506SNeel Natu 226647b9935dSNeel Natu if (errcode_valid) { 226747b9935dSNeel Natu /* 226847b9935dSNeel Natu * Exceptions don't deliver an error code in real mode. 226947b9935dSNeel Natu */ 2270d3956e46SJohn Baldwin error = vm_get_register(vcpu, VM_REG_GUEST_CR0, ®val); 227147b9935dSNeel Natu KASSERT(!error, ("%s: error %d getting CR0", __func__, error)); 227247b9935dSNeel Natu if (!(regval & CR0_PE)) 227347b9935dSNeel Natu errcode_valid = 0; 227447b9935dSNeel Natu } 227547b9935dSNeel Natu 22762ce12423SNeel Natu /* 22772ce12423SNeel Natu * From section 26.6.1 "Interruptibility State" in Intel SDM: 22782ce12423SNeel Natu * 22792ce12423SNeel Natu * Event blocking by "STI" or "MOV SS" is cleared after guest executes 22802ce12423SNeel Natu * one instruction or incurs an exception. 22812ce12423SNeel Natu */ 2282d3956e46SJohn Baldwin error = vm_set_register(vcpu, VM_REG_GUEST_INTR_SHADOW, 0); 22832ce12423SNeel Natu KASSERT(error == 0, ("%s: error %d clearing interrupt shadow", 22842ce12423SNeel Natu __func__, error)); 22852ce12423SNeel Natu 2286c9c75df4SNeel Natu if (restart_instruction) 2287d3956e46SJohn Baldwin vm_restart_instruction(vcpu); 2288c9c75df4SNeel Natu 2289dc506506SNeel Natu vcpu->exception_pending = 1; 2290c9c75df4SNeel Natu vcpu->exc_vector = vector; 2291c9c75df4SNeel Natu vcpu->exc_errcode = errcode; 2292c9c75df4SNeel Natu vcpu->exc_errcode_valid = errcode_valid; 2293d3956e46SJohn Baldwin VMM_CTR1(vcpu, "Exception %d pending", vector); 2294dc506506SNeel Natu return (0); 2295dc506506SNeel Natu } 2296dc506506SNeel Natu 2297d37f2adbSNeel Natu void 2298d3956e46SJohn Baldwin vm_inject_fault(struct vcpu *vcpu, int vector, int errcode_valid, int errcode) 2299dc506506SNeel Natu { 230073505a10SRobert Wing int error __diagused, restart_instruction; 2301dc506506SNeel Natu 2302c9c75df4SNeel Natu restart_instruction = 1; 2303d37f2adbSNeel Natu 2304d3956e46SJohn Baldwin error = vm_inject_exception(vcpu, vector, errcode_valid, 2305c9c75df4SNeel Natu errcode, restart_instruction); 2306dc506506SNeel Natu KASSERT(error == 0, ("vm_inject_exception error %d", error)); 2307dc506506SNeel Natu } 2308dc506506SNeel Natu 2309dc506506SNeel Natu void 2310d3956e46SJohn Baldwin vm_inject_pf(struct vcpu *vcpu, int error_code, uint64_t cr2) 2311fd949af6SNeel Natu { 231273505a10SRobert Wing int error __diagused; 231337a723a5SNeel Natu 2314d3956e46SJohn Baldwin VMM_CTR2(vcpu, "Injecting page fault: error_code %#x, cr2 %#lx", 231537a723a5SNeel Natu error_code, cr2); 231637a723a5SNeel Natu 2317d3956e46SJohn Baldwin error = vm_set_register(vcpu, VM_REG_GUEST_CR2, cr2); 231837a723a5SNeel Natu KASSERT(error == 0, ("vm_set_register(cr2) error %d", error)); 2319fd949af6SNeel Natu 2320d3956e46SJohn Baldwin vm_inject_fault(vcpu, IDT_PF, 1, error_code); 2321366f6083SPeter Grehan } 2322366f6083SPeter Grehan 232361592433SNeel Natu static VMM_STAT(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); 2324366f6083SPeter Grehan 2325f352ff0cSNeel Natu int 23263f0f4b15SJohn Baldwin vm_inject_nmi(struct vcpu *vcpu) 2327f352ff0cSNeel Natu { 2328f352ff0cSNeel Natu 2329f352ff0cSNeel Natu vcpu->nmi_pending = 1; 23303f0f4b15SJohn Baldwin vcpu_notify_event(vcpu, false); 2331f352ff0cSNeel Natu return (0); 2332f352ff0cSNeel Natu } 2333f352ff0cSNeel Natu 2334f352ff0cSNeel Natu int 233580cb5d84SJohn Baldwin vm_nmi_pending(struct vcpu *vcpu) 2336f352ff0cSNeel Natu { 2337f352ff0cSNeel Natu return (vcpu->nmi_pending); 2338f352ff0cSNeel Natu } 2339f352ff0cSNeel Natu 2340f352ff0cSNeel Natu void 234180cb5d84SJohn Baldwin vm_nmi_clear(struct vcpu *vcpu) 2342f352ff0cSNeel Natu { 2343f352ff0cSNeel Natu if (vcpu->nmi_pending == 0) 2344f352ff0cSNeel Natu panic("vm_nmi_clear: inconsistent nmi_pending state"); 2345f352ff0cSNeel Natu 2346f352ff0cSNeel Natu vcpu->nmi_pending = 0; 23473dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VCPU_NMI_COUNT, 1); 2348366f6083SPeter Grehan } 2349366f6083SPeter Grehan 23500775fbb4STycho Nightingale static VMM_STAT(VCPU_EXTINT_COUNT, "number of ExtINTs delivered to vcpu"); 23510775fbb4STycho Nightingale 23520775fbb4STycho Nightingale int 23533f0f4b15SJohn Baldwin vm_inject_extint(struct vcpu *vcpu) 23540775fbb4STycho Nightingale { 23550775fbb4STycho Nightingale 23560775fbb4STycho Nightingale vcpu->extint_pending = 1; 23573f0f4b15SJohn Baldwin vcpu_notify_event(vcpu, false); 23580775fbb4STycho Nightingale return (0); 23590775fbb4STycho Nightingale } 23600775fbb4STycho Nightingale 23610775fbb4STycho Nightingale int 236280cb5d84SJohn Baldwin vm_extint_pending(struct vcpu *vcpu) 23630775fbb4STycho Nightingale { 23640775fbb4STycho Nightingale return (vcpu->extint_pending); 23650775fbb4STycho Nightingale } 23660775fbb4STycho Nightingale 23670775fbb4STycho Nightingale void 236880cb5d84SJohn Baldwin vm_extint_clear(struct vcpu *vcpu) 23690775fbb4STycho Nightingale { 23700775fbb4STycho Nightingale if (vcpu->extint_pending == 0) 23710775fbb4STycho Nightingale panic("vm_extint_clear: inconsistent extint_pending state"); 23720775fbb4STycho Nightingale 23730775fbb4STycho Nightingale vcpu->extint_pending = 0; 23743dc3d32aSJohn Baldwin vmm_stat_incr(vcpu, VCPU_EXTINT_COUNT, 1); 23750775fbb4STycho Nightingale } 23760775fbb4STycho Nightingale 2377366f6083SPeter Grehan int 23783f0f4b15SJohn Baldwin vm_get_capability(struct vcpu *vcpu, int type, int *retval) 2379366f6083SPeter Grehan { 2380366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 2381366f6083SPeter Grehan return (EINVAL); 2382366f6083SPeter Grehan 23833f0f4b15SJohn Baldwin return (vmmops_getcap(vcpu->cookie, type, retval)); 2384366f6083SPeter Grehan } 2385366f6083SPeter Grehan 2386366f6083SPeter Grehan int 23873f0f4b15SJohn Baldwin vm_set_capability(struct vcpu *vcpu, int type, int val) 2388366f6083SPeter Grehan { 2389366f6083SPeter Grehan if (type < 0 || type >= VM_CAP_MAX) 2390366f6083SPeter Grehan return (EINVAL); 2391366f6083SPeter Grehan 23923f0f4b15SJohn Baldwin return (vmmops_setcap(vcpu->cookie, type, val)); 2393366f6083SPeter Grehan } 2394366f6083SPeter Grehan 2395950af9ffSJohn Baldwin struct vm * 2396950af9ffSJohn Baldwin vcpu_vm(struct vcpu *vcpu) 2397950af9ffSJohn Baldwin { 2398950af9ffSJohn Baldwin return (vcpu->vm); 2399950af9ffSJohn Baldwin } 2400950af9ffSJohn Baldwin 2401950af9ffSJohn Baldwin int 2402950af9ffSJohn Baldwin vcpu_vcpuid(struct vcpu *vcpu) 2403950af9ffSJohn Baldwin { 2404950af9ffSJohn Baldwin return (vcpu->vcpuid); 2405950af9ffSJohn Baldwin } 2406950af9ffSJohn Baldwin 2407950af9ffSJohn Baldwin struct vcpu * 2408950af9ffSJohn Baldwin vm_vcpu(struct vm *vm, int vcpuid) 2409950af9ffSJohn Baldwin { 241098568a00SJohn Baldwin return (vm->vcpu[vcpuid]); 2411950af9ffSJohn Baldwin } 2412950af9ffSJohn Baldwin 2413366f6083SPeter Grehan struct vlapic * 2414d3956e46SJohn Baldwin vm_lapic(struct vcpu *vcpu) 2415366f6083SPeter Grehan { 2416d3956e46SJohn Baldwin return (vcpu->vlapic); 2417366f6083SPeter Grehan } 2418366f6083SPeter Grehan 2419565bbb86SNeel Natu struct vioapic * 2420565bbb86SNeel Natu vm_ioapic(struct vm *vm) 2421565bbb86SNeel Natu { 2422565bbb86SNeel Natu 2423565bbb86SNeel Natu return (vm->vioapic); 2424565bbb86SNeel Natu } 2425565bbb86SNeel Natu 242608e3ff32SNeel Natu struct vhpet * 242708e3ff32SNeel Natu vm_hpet(struct vm *vm) 242808e3ff32SNeel Natu { 242908e3ff32SNeel Natu 243008e3ff32SNeel Natu return (vm->vhpet); 243108e3ff32SNeel Natu } 243208e3ff32SNeel Natu 2433490d56c5SEd Maste bool 2434366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func) 2435366f6083SPeter Grehan { 2436490d56c5SEd Maste int b, f, i, n, s; 2437366f6083SPeter Grehan char *val, *cp, *cp2; 2438490d56c5SEd Maste bool found; 2439366f6083SPeter Grehan 2440366f6083SPeter Grehan /* 244107044a96SNeel Natu * XXX 244207044a96SNeel Natu * The length of an environment variable is limited to 128 bytes which 244307044a96SNeel Natu * puts an upper limit on the number of passthru devices that may be 244407044a96SNeel Natu * specified using a single environment variable. 244507044a96SNeel Natu * 244607044a96SNeel Natu * Work around this by scanning multiple environment variable 244707044a96SNeel Natu * names instead of a single one - yuck! 2448366f6083SPeter Grehan */ 244907044a96SNeel Natu const char *names[] = { "pptdevs", "pptdevs2", "pptdevs3", NULL }; 245007044a96SNeel Natu 245107044a96SNeel Natu /* set pptdevs="1/2/3 4/5/6 7/8/9 10/11/12" */ 2452490d56c5SEd Maste found = false; 245307044a96SNeel Natu for (i = 0; names[i] != NULL && !found; i++) { 24542be111bfSDavide Italiano cp = val = kern_getenv(names[i]); 2455366f6083SPeter Grehan while (cp != NULL && *cp != '\0') { 2456366f6083SPeter Grehan if ((cp2 = strchr(cp, ' ')) != NULL) 2457366f6083SPeter Grehan *cp2 = '\0'; 2458366f6083SPeter Grehan 2459366f6083SPeter Grehan n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 2460366f6083SPeter Grehan if (n == 3 && bus == b && slot == s && func == f) { 2461490d56c5SEd Maste found = true; 2462366f6083SPeter Grehan break; 2463366f6083SPeter Grehan } 2464366f6083SPeter Grehan 2465366f6083SPeter Grehan if (cp2 != NULL) 2466366f6083SPeter Grehan *cp2++ = ' '; 2467366f6083SPeter Grehan 2468366f6083SPeter Grehan cp = cp2; 2469366f6083SPeter Grehan } 2470366f6083SPeter Grehan freeenv(val); 247107044a96SNeel Natu } 2472366f6083SPeter Grehan return (found); 2473366f6083SPeter Grehan } 2474366f6083SPeter Grehan 2475366f6083SPeter Grehan void * 2476366f6083SPeter Grehan vm_iommu_domain(struct vm *vm) 2477366f6083SPeter Grehan { 2478366f6083SPeter Grehan 2479366f6083SPeter Grehan return (vm->iommu); 2480366f6083SPeter Grehan } 2481366f6083SPeter Grehan 248275dd3366SNeel Natu int 24833f0f4b15SJohn Baldwin vcpu_set_state(struct vcpu *vcpu, enum vcpu_state newstate, bool from_idle) 2484366f6083SPeter Grehan { 248575dd3366SNeel Natu int error; 2486366f6083SPeter Grehan 248775dd3366SNeel Natu vcpu_lock(vcpu); 24883f0f4b15SJohn Baldwin error = vcpu_set_state_locked(vcpu, newstate, from_idle); 248975dd3366SNeel Natu vcpu_unlock(vcpu); 249075dd3366SNeel Natu 249175dd3366SNeel Natu return (error); 249275dd3366SNeel Natu } 249375dd3366SNeel Natu 249475dd3366SNeel Natu enum vcpu_state 2495d3956e46SJohn Baldwin vcpu_get_state(struct vcpu *vcpu, int *hostcpu) 2496366f6083SPeter Grehan { 249775dd3366SNeel Natu enum vcpu_state state; 2498366f6083SPeter Grehan 249975dd3366SNeel Natu vcpu_lock(vcpu); 250075dd3366SNeel Natu state = vcpu->state; 2501d3c11f40SPeter Grehan if (hostcpu != NULL) 2502d3c11f40SPeter Grehan *hostcpu = vcpu->hostcpu; 250375dd3366SNeel Natu vcpu_unlock(vcpu); 2504366f6083SPeter Grehan 250575dd3366SNeel Natu return (state); 2506366f6083SPeter Grehan } 2507366f6083SPeter Grehan 250895ebc360SNeel Natu int 25093f0f4b15SJohn Baldwin vm_activate_cpu(struct vcpu *vcpu) 2510366f6083SPeter Grehan { 25113f0f4b15SJohn Baldwin struct vm *vm = vcpu->vm; 2512366f6083SPeter Grehan 25133f0f4b15SJohn Baldwin if (CPU_ISSET(vcpu->vcpuid, &vm->active_cpus)) 251495ebc360SNeel Natu return (EBUSY); 251522d822c6SNeel Natu 25163f0f4b15SJohn Baldwin VMM_CTR0(vcpu, "activated"); 25173f0f4b15SJohn Baldwin CPU_SET_ATOMIC(vcpu->vcpuid, &vm->active_cpus); 251895ebc360SNeel Natu return (0); 2519366f6083SPeter Grehan } 2520366f6083SPeter Grehan 2521fc276d92SJohn Baldwin int 25223f0f4b15SJohn Baldwin vm_suspend_cpu(struct vm *vm, struct vcpu *vcpu) 2523fc276d92SJohn Baldwin { 25243f0f4b15SJohn Baldwin if (vcpu == NULL) { 2525fc276d92SJohn Baldwin vm->debug_cpus = vm->active_cpus; 25263f0f4b15SJohn Baldwin for (int i = 0; i < vm->maxcpus; i++) { 2527fc276d92SJohn Baldwin if (CPU_ISSET(i, &vm->active_cpus)) 25283f0f4b15SJohn Baldwin vcpu_notify_event(vm_vcpu(vm, i), false); 2529fc276d92SJohn Baldwin } 2530fc276d92SJohn Baldwin } else { 25313f0f4b15SJohn Baldwin if (!CPU_ISSET(vcpu->vcpuid, &vm->active_cpus)) 2532fc276d92SJohn Baldwin return (EINVAL); 2533fc276d92SJohn Baldwin 25343f0f4b15SJohn Baldwin CPU_SET_ATOMIC(vcpu->vcpuid, &vm->debug_cpus); 25353f0f4b15SJohn Baldwin vcpu_notify_event(vcpu, false); 2536fc276d92SJohn Baldwin } 2537fc276d92SJohn Baldwin return (0); 2538fc276d92SJohn Baldwin } 2539fc276d92SJohn Baldwin 2540fc276d92SJohn Baldwin int 25413f0f4b15SJohn Baldwin vm_resume_cpu(struct vm *vm, struct vcpu *vcpu) 2542fc276d92SJohn Baldwin { 2543fc276d92SJohn Baldwin 25443f0f4b15SJohn Baldwin if (vcpu == NULL) { 2545fc276d92SJohn Baldwin CPU_ZERO(&vm->debug_cpus); 2546fc276d92SJohn Baldwin } else { 25473f0f4b15SJohn Baldwin if (!CPU_ISSET(vcpu->vcpuid, &vm->debug_cpus)) 2548fc276d92SJohn Baldwin return (EINVAL); 2549fc276d92SJohn Baldwin 25503f0f4b15SJohn Baldwin CPU_CLR_ATOMIC(vcpu->vcpuid, &vm->debug_cpus); 2551fc276d92SJohn Baldwin } 2552fc276d92SJohn Baldwin return (0); 2553fc276d92SJohn Baldwin } 2554fc276d92SJohn Baldwin 2555fc276d92SJohn Baldwin int 255680cb5d84SJohn Baldwin vcpu_debugged(struct vcpu *vcpu) 2557fc276d92SJohn Baldwin { 2558fc276d92SJohn Baldwin 255980cb5d84SJohn Baldwin return (CPU_ISSET(vcpu->vcpuid, &vcpu->vm->debug_cpus)); 2560fc276d92SJohn Baldwin } 2561fc276d92SJohn Baldwin 2562a5615c90SPeter Grehan cpuset_t 2563366f6083SPeter Grehan vm_active_cpus(struct vm *vm) 2564366f6083SPeter Grehan { 2565366f6083SPeter Grehan 2566366f6083SPeter Grehan return (vm->active_cpus); 2567366f6083SPeter Grehan } 2568366f6083SPeter Grehan 256995ebc360SNeel Natu cpuset_t 2570fc276d92SJohn Baldwin vm_debug_cpus(struct vm *vm) 2571fc276d92SJohn Baldwin { 2572fc276d92SJohn Baldwin 2573fc276d92SJohn Baldwin return (vm->debug_cpus); 2574fc276d92SJohn Baldwin } 2575fc276d92SJohn Baldwin 2576fc276d92SJohn Baldwin cpuset_t 257795ebc360SNeel Natu vm_suspended_cpus(struct vm *vm) 257895ebc360SNeel Natu { 257995ebc360SNeel Natu 258095ebc360SNeel Natu return (vm->suspended_cpus); 258195ebc360SNeel Natu } 258295ebc360SNeel Natu 2583c0f35dbfSJohn Baldwin /* 2584c0f35dbfSJohn Baldwin * Returns the subset of vCPUs in tostart that are awaiting startup. 2585c0f35dbfSJohn Baldwin * These vCPUs are also marked as no longer awaiting startup. 2586c0f35dbfSJohn Baldwin */ 2587c0f35dbfSJohn Baldwin cpuset_t 2588c0f35dbfSJohn Baldwin vm_start_cpus(struct vm *vm, const cpuset_t *tostart) 2589c0f35dbfSJohn Baldwin { 2590c0f35dbfSJohn Baldwin cpuset_t set; 2591c0f35dbfSJohn Baldwin 2592c0f35dbfSJohn Baldwin mtx_lock(&vm->rendezvous_mtx); 2593c0f35dbfSJohn Baldwin CPU_AND(&set, &vm->startup_cpus, tostart); 2594c0f35dbfSJohn Baldwin CPU_ANDNOT(&vm->startup_cpus, &vm->startup_cpus, &set); 2595c0f35dbfSJohn Baldwin mtx_unlock(&vm->rendezvous_mtx); 2596c0f35dbfSJohn Baldwin return (set); 2597c0f35dbfSJohn Baldwin } 2598c0f35dbfSJohn Baldwin 2599c0f35dbfSJohn Baldwin void 2600c0f35dbfSJohn Baldwin vm_await_start(struct vm *vm, const cpuset_t *waiting) 2601c0f35dbfSJohn Baldwin { 2602c0f35dbfSJohn Baldwin mtx_lock(&vm->rendezvous_mtx); 2603c0f35dbfSJohn Baldwin CPU_OR(&vm->startup_cpus, &vm->startup_cpus, waiting); 2604c0f35dbfSJohn Baldwin mtx_unlock(&vm->rendezvous_mtx); 2605c0f35dbfSJohn Baldwin } 2606c0f35dbfSJohn Baldwin 2607366f6083SPeter Grehan void * 26083dc3d32aSJohn Baldwin vcpu_stats(struct vcpu *vcpu) 2609366f6083SPeter Grehan { 2610366f6083SPeter Grehan 26113dc3d32aSJohn Baldwin return (vcpu->stats); 2612366f6083SPeter Grehan } 2613e9027382SNeel Natu 2614e9027382SNeel Natu int 26153f0f4b15SJohn Baldwin vm_get_x2apic_state(struct vcpu *vcpu, enum x2apic_state *state) 2616e9027382SNeel Natu { 26173f0f4b15SJohn Baldwin *state = vcpu->x2apic_state; 2618e9027382SNeel Natu 2619e9027382SNeel Natu return (0); 2620e9027382SNeel Natu } 2621e9027382SNeel Natu 2622e9027382SNeel Natu int 26233f0f4b15SJohn Baldwin vm_set_x2apic_state(struct vcpu *vcpu, enum x2apic_state state) 2624e9027382SNeel Natu { 26253f23d3caSNeel Natu if (state >= X2APIC_STATE_LAST) 2626e9027382SNeel Natu return (EINVAL); 2627e9027382SNeel Natu 2628d3956e46SJohn Baldwin vcpu->x2apic_state = state; 2629e9027382SNeel Natu 2630d3956e46SJohn Baldwin vlapic_set_x2apic_state(vcpu, state); 263173820fb0SNeel Natu 2632e9027382SNeel Natu return (0); 2633e9027382SNeel Natu } 263475dd3366SNeel Natu 263522821874SNeel Natu /* 263622821874SNeel Natu * This function is called to ensure that a vcpu "sees" a pending event 263722821874SNeel Natu * as soon as possible: 263822821874SNeel Natu * - If the vcpu thread is sleeping then it is woken up. 263922821874SNeel Natu * - If the vcpu is running on a different host_cpu then an IPI will be directed 264022821874SNeel Natu * to the host_cpu to cause the vcpu to trap into the hypervisor. 264122821874SNeel Natu */ 2642248e6799SNeel Natu static void 2643248e6799SNeel Natu vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr) 264475dd3366SNeel Natu { 264575dd3366SNeel Natu int hostcpu; 264675dd3366SNeel Natu 264775dd3366SNeel Natu hostcpu = vcpu->hostcpu; 2648ef39d7e9SNeel Natu if (vcpu->state == VCPU_RUNNING) { 2649ef39d7e9SNeel Natu KASSERT(hostcpu != NOCPU, ("vcpu running on invalid hostcpu")); 2650de5ea6b6SNeel Natu if (hostcpu != curcpu) { 2651ef39d7e9SNeel Natu if (lapic_intr) { 2652add611fdSNeel Natu vlapic_post_intr(vcpu->vlapic, hostcpu, 2653add611fdSNeel Natu vmm_ipinum); 2654ef39d7e9SNeel Natu } else { 265575dd3366SNeel Natu ipi_cpu(hostcpu, vmm_ipinum); 265675dd3366SNeel Natu } 2657ef39d7e9SNeel Natu } else { 2658ef39d7e9SNeel Natu /* 2659ef39d7e9SNeel Natu * If the 'vcpu' is running on 'curcpu' then it must 2660ef39d7e9SNeel Natu * be sending a notification to itself (e.g. SELF_IPI). 2661ef39d7e9SNeel Natu * The pending event will be picked up when the vcpu 2662ef39d7e9SNeel Natu * transitions back to guest context. 2663ef39d7e9SNeel Natu */ 2664ef39d7e9SNeel Natu } 2665ef39d7e9SNeel Natu } else { 2666ef39d7e9SNeel Natu KASSERT(hostcpu == NOCPU, ("vcpu state %d not consistent " 2667ef39d7e9SNeel Natu "with hostcpu %d", vcpu->state, hostcpu)); 2668366f6083SPeter Grehan if (vcpu->state == VCPU_SLEEPING) 2669366f6083SPeter Grehan wakeup_one(vcpu); 2670366f6083SPeter Grehan } 2671248e6799SNeel Natu } 2672248e6799SNeel Natu 2673248e6799SNeel Natu void 26743f0f4b15SJohn Baldwin vcpu_notify_event(struct vcpu *vcpu, bool lapic_intr) 2675248e6799SNeel Natu { 2676248e6799SNeel Natu vcpu_lock(vcpu); 2677248e6799SNeel Natu vcpu_notify_event_locked(vcpu, lapic_intr); 2678f76fc5d4SNeel Natu vcpu_unlock(vcpu); 2679f76fc5d4SNeel Natu } 2680318224bbSNeel Natu 2681318224bbSNeel Natu struct vmspace * 2682318224bbSNeel Natu vm_get_vmspace(struct vm *vm) 2683318224bbSNeel Natu { 2684318224bbSNeel Natu 2685318224bbSNeel Natu return (vm->vmspace); 2686318224bbSNeel Natu } 2687565bbb86SNeel Natu 2688565bbb86SNeel Natu int 2689565bbb86SNeel Natu vm_apicid2vcpuid(struct vm *vm, int apicid) 2690565bbb86SNeel Natu { 2691565bbb86SNeel Natu /* 2692565bbb86SNeel Natu * XXX apic id is assumed to be numerically identical to vcpu id 2693565bbb86SNeel Natu */ 2694565bbb86SNeel Natu return (apicid); 2695565bbb86SNeel Natu } 26965b8a8cd1SNeel Natu 2697b837daddSKonstantin Belousov int 2698d8be3d52SJohn Baldwin vm_smp_rendezvous(struct vcpu *vcpu, cpuset_t dest, 26995b8a8cd1SNeel Natu vm_rendezvous_func_t func, void *arg) 27005b8a8cd1SNeel Natu { 2701d8be3d52SJohn Baldwin struct vm *vm = vcpu->vm; 2702b837daddSKonstantin Belousov int error, i; 2703970955e4SNeel Natu 27045b8a8cd1SNeel Natu /* 27055b8a8cd1SNeel Natu * Enforce that this function is called without any locks 27065b8a8cd1SNeel Natu */ 27075b8a8cd1SNeel Natu WITNESS_WARN(WARN_PANIC, NULL, "vm_smp_rendezvous"); 27085b8a8cd1SNeel Natu 27095b8a8cd1SNeel Natu restart: 27105b8a8cd1SNeel Natu mtx_lock(&vm->rendezvous_mtx); 27115b8a8cd1SNeel Natu if (vm->rendezvous_func != NULL) { 27125b8a8cd1SNeel Natu /* 27135b8a8cd1SNeel Natu * If a rendezvous is already in progress then we need to 27143f0f4b15SJohn Baldwin * call the rendezvous handler in case this 'vcpu' is one 27155b8a8cd1SNeel Natu * of the targets of the rendezvous. 27165b8a8cd1SNeel Natu */ 2717d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Rendezvous already in progress"); 27185b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 2719d8be3d52SJohn Baldwin error = vm_handle_rendezvous(vcpu); 2720b837daddSKonstantin Belousov if (error != 0) 2721b837daddSKonstantin Belousov return (error); 27225b8a8cd1SNeel Natu goto restart; 27235b8a8cd1SNeel Natu } 27245b8a8cd1SNeel Natu KASSERT(vm->rendezvous_func == NULL, ("vm_smp_rendezvous: previous " 27255b8a8cd1SNeel Natu "rendezvous is still in progress")); 27265b8a8cd1SNeel Natu 2727d8be3d52SJohn Baldwin VMM_CTR0(vcpu, "Initiating rendezvous"); 27285b8a8cd1SNeel Natu vm->rendezvous_req_cpus = dest; 27295b8a8cd1SNeel Natu CPU_ZERO(&vm->rendezvous_done_cpus); 27305b8a8cd1SNeel Natu vm->rendezvous_arg = arg; 2731869dbab7SAndriy Gapon vm->rendezvous_func = func; 27325b8a8cd1SNeel Natu mtx_unlock(&vm->rendezvous_mtx); 27335b8a8cd1SNeel Natu 2734970955e4SNeel Natu /* 2735970955e4SNeel Natu * Wake up any sleeping vcpus and trigger a VM-exit in any running 2736970955e4SNeel Natu * vcpus so they handle the rendezvous as soon as possible. 2737970955e4SNeel Natu */ 2738a488c9c9SRodney W. Grimes for (i = 0; i < vm->maxcpus; i++) { 2739970955e4SNeel Natu if (CPU_ISSET(i, &dest)) 27403f0f4b15SJohn Baldwin vcpu_notify_event(vm_vcpu(vm, i), false); 2741970955e4SNeel Natu } 2742970955e4SNeel Natu 2743d8be3d52SJohn Baldwin return (vm_handle_rendezvous(vcpu)); 27445b8a8cd1SNeel Natu } 2745762fd208STycho Nightingale 2746762fd208STycho Nightingale struct vatpic * 2747762fd208STycho Nightingale vm_atpic(struct vm *vm) 2748762fd208STycho Nightingale { 2749762fd208STycho Nightingale return (vm->vatpic); 2750762fd208STycho Nightingale } 2751e883c9bbSTycho Nightingale 2752e883c9bbSTycho Nightingale struct vatpit * 2753e883c9bbSTycho Nightingale vm_atpit(struct vm *vm) 2754e883c9bbSTycho Nightingale { 2755e883c9bbSTycho Nightingale return (vm->vatpit); 2756e883c9bbSTycho Nightingale } 2757d17b5104SNeel Natu 2758160ef77aSNeel Natu struct vpmtmr * 2759160ef77aSNeel Natu vm_pmtmr(struct vm *vm) 2760160ef77aSNeel Natu { 2761160ef77aSNeel Natu 2762160ef77aSNeel Natu return (vm->vpmtmr); 2763160ef77aSNeel Natu } 2764160ef77aSNeel Natu 27650dafa5cdSNeel Natu struct vrtc * 27660dafa5cdSNeel Natu vm_rtc(struct vm *vm) 27670dafa5cdSNeel Natu { 27680dafa5cdSNeel Natu 27690dafa5cdSNeel Natu return (vm->vrtc); 27700dafa5cdSNeel Natu } 27710dafa5cdSNeel Natu 2772d17b5104SNeel Natu enum vm_reg_name 2773d17b5104SNeel Natu vm_segment_name(int seg) 2774d17b5104SNeel Natu { 2775d17b5104SNeel Natu static enum vm_reg_name seg_names[] = { 2776d17b5104SNeel Natu VM_REG_GUEST_ES, 2777d17b5104SNeel Natu VM_REG_GUEST_CS, 2778d17b5104SNeel Natu VM_REG_GUEST_SS, 2779d17b5104SNeel Natu VM_REG_GUEST_DS, 2780d17b5104SNeel Natu VM_REG_GUEST_FS, 2781d17b5104SNeel Natu VM_REG_GUEST_GS 2782d17b5104SNeel Natu }; 2783d17b5104SNeel Natu 2784d17b5104SNeel Natu KASSERT(seg >= 0 && seg < nitems(seg_names), 2785d17b5104SNeel Natu ("%s: invalid segment encoding %d", __func__, seg)); 2786d17b5104SNeel Natu return (seg_names[seg]); 2787d17b5104SNeel Natu } 2788cf1d80d8SPeter Grehan 2789d665d229SNeel Natu void 27902b4fe856SJohn Baldwin vm_copy_teardown(struct vm_copyinfo *copyinfo, int num_copyinfo) 2791d665d229SNeel Natu { 2792d665d229SNeel Natu int idx; 2793d665d229SNeel Natu 2794d665d229SNeel Natu for (idx = 0; idx < num_copyinfo; idx++) { 2795d665d229SNeel Natu if (copyinfo[idx].cookie != NULL) 2796d665d229SNeel Natu vm_gpa_release(copyinfo[idx].cookie); 2797d665d229SNeel Natu } 2798d665d229SNeel Natu bzero(copyinfo, num_copyinfo * sizeof(struct vm_copyinfo)); 2799d665d229SNeel Natu } 2800d665d229SNeel Natu 2801d665d229SNeel Natu int 2802d3956e46SJohn Baldwin vm_copy_setup(struct vcpu *vcpu, struct vm_guest_paging *paging, 2803d665d229SNeel Natu uint64_t gla, size_t len, int prot, struct vm_copyinfo *copyinfo, 28049c4d5478SNeel Natu int num_copyinfo, int *fault) 2805d665d229SNeel Natu { 2806d665d229SNeel Natu int error, idx, nused; 2807d665d229SNeel Natu size_t n, off, remaining; 2808d665d229SNeel Natu void *hva, *cookie; 2809d665d229SNeel Natu uint64_t gpa; 2810d665d229SNeel Natu 2811d665d229SNeel Natu bzero(copyinfo, sizeof(struct vm_copyinfo) * num_copyinfo); 2812d665d229SNeel Natu 2813d665d229SNeel Natu nused = 0; 2814d665d229SNeel Natu remaining = len; 2815d665d229SNeel Natu while (remaining > 0) { 2816d19fa9c1SPierre Pronchery if (nused >= num_copyinfo) 2817d19fa9c1SPierre Pronchery return (EFAULT); 2818d3956e46SJohn Baldwin error = vm_gla2gpa(vcpu, paging, gla, prot, &gpa, fault); 28199c4d5478SNeel Natu if (error || *fault) 2820d665d229SNeel Natu return (error); 2821d665d229SNeel Natu off = gpa & PAGE_MASK; 2822d665d229SNeel Natu n = min(remaining, PAGE_SIZE - off); 2823d665d229SNeel Natu copyinfo[nused].gpa = gpa; 2824d665d229SNeel Natu copyinfo[nused].len = n; 2825d665d229SNeel Natu remaining -= n; 2826d665d229SNeel Natu gla += n; 2827d665d229SNeel Natu nused++; 2828d665d229SNeel Natu } 2829d665d229SNeel Natu 2830d665d229SNeel Natu for (idx = 0; idx < nused; idx++) { 2831d3956e46SJohn Baldwin hva = vm_gpa_hold(vcpu, copyinfo[idx].gpa, 28329b1aa8d6SNeel Natu copyinfo[idx].len, prot, &cookie); 2833d665d229SNeel Natu if (hva == NULL) 2834d665d229SNeel Natu break; 2835d665d229SNeel Natu copyinfo[idx].hva = hva; 2836d665d229SNeel Natu copyinfo[idx].cookie = cookie; 2837d665d229SNeel Natu } 2838d665d229SNeel Natu 2839d665d229SNeel Natu if (idx != nused) { 28402b4fe856SJohn Baldwin vm_copy_teardown(copyinfo, num_copyinfo); 28419c4d5478SNeel Natu return (EFAULT); 2842d665d229SNeel Natu } else { 28439c4d5478SNeel Natu *fault = 0; 2844d665d229SNeel Natu return (0); 2845d665d229SNeel Natu } 2846d665d229SNeel Natu } 2847d665d229SNeel Natu 2848d665d229SNeel Natu void 28492b4fe856SJohn Baldwin vm_copyin(struct vm_copyinfo *copyinfo, void *kaddr, size_t len) 2850d665d229SNeel Natu { 2851d665d229SNeel Natu char *dst; 2852d665d229SNeel Natu int idx; 2853d665d229SNeel Natu 2854d665d229SNeel Natu dst = kaddr; 2855d665d229SNeel Natu idx = 0; 2856d665d229SNeel Natu while (len > 0) { 2857d665d229SNeel Natu bcopy(copyinfo[idx].hva, dst, copyinfo[idx].len); 2858d665d229SNeel Natu len -= copyinfo[idx].len; 2859d665d229SNeel Natu dst += copyinfo[idx].len; 2860d665d229SNeel Natu idx++; 2861d665d229SNeel Natu } 2862d665d229SNeel Natu } 2863d665d229SNeel Natu 2864d665d229SNeel Natu void 28652b4fe856SJohn Baldwin vm_copyout(const void *kaddr, struct vm_copyinfo *copyinfo, size_t len) 2866d665d229SNeel Natu { 2867d665d229SNeel Natu const char *src; 2868d665d229SNeel Natu int idx; 2869d665d229SNeel Natu 2870d665d229SNeel Natu src = kaddr; 2871d665d229SNeel Natu idx = 0; 2872d665d229SNeel Natu while (len > 0) { 2873d665d229SNeel Natu bcopy(src, copyinfo[idx].hva, copyinfo[idx].len); 2874d665d229SNeel Natu len -= copyinfo[idx].len; 2875d665d229SNeel Natu src += copyinfo[idx].len; 2876d665d229SNeel Natu idx++; 2877d665d229SNeel Natu } 2878d665d229SNeel Natu } 2879cf1d80d8SPeter Grehan 2880cf1d80d8SPeter Grehan /* 2881cf1d80d8SPeter Grehan * Return the amount of in-use and wired memory for the VM. Since 2882cf1d80d8SPeter Grehan * these are global stats, only return the values with for vCPU 0 2883cf1d80d8SPeter Grehan */ 2884cf1d80d8SPeter Grehan VMM_STAT_DECLARE(VMM_MEM_RESIDENT); 2885cf1d80d8SPeter Grehan VMM_STAT_DECLARE(VMM_MEM_WIRED); 2886cf1d80d8SPeter Grehan 2887cf1d80d8SPeter Grehan static void 28883f0f4b15SJohn Baldwin vm_get_rescnt(struct vcpu *vcpu, struct vmm_stat_type *stat) 2889cf1d80d8SPeter Grehan { 2890cf1d80d8SPeter Grehan 28913f0f4b15SJohn Baldwin if (vcpu->vcpuid == 0) { 28923f0f4b15SJohn Baldwin vmm_stat_set(vcpu, VMM_MEM_RESIDENT, PAGE_SIZE * 28933f0f4b15SJohn Baldwin vmspace_resident_count(vcpu->vm->vmspace)); 2894cf1d80d8SPeter Grehan } 2895cf1d80d8SPeter Grehan } 2896cf1d80d8SPeter Grehan 2897cf1d80d8SPeter Grehan static void 28983f0f4b15SJohn Baldwin vm_get_wiredcnt(struct vcpu *vcpu, struct vmm_stat_type *stat) 2899cf1d80d8SPeter Grehan { 2900cf1d80d8SPeter Grehan 29013f0f4b15SJohn Baldwin if (vcpu->vcpuid == 0) { 29023f0f4b15SJohn Baldwin vmm_stat_set(vcpu, VMM_MEM_WIRED, PAGE_SIZE * 29033f0f4b15SJohn Baldwin pmap_wired_count(vmspace_pmap(vcpu->vm->vmspace))); 2904cf1d80d8SPeter Grehan } 2905cf1d80d8SPeter Grehan } 2906cf1d80d8SPeter Grehan 2907cf1d80d8SPeter Grehan VMM_STAT_FUNC(VMM_MEM_RESIDENT, "Resident memory", vm_get_rescnt); 2908cf1d80d8SPeter Grehan VMM_STAT_FUNC(VMM_MEM_WIRED, "Wired memory", vm_get_wiredcnt); 2909483d953aSJohn Baldwin 2910483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 2911483d953aSJohn Baldwin static int 2912483d953aSJohn Baldwin vm_snapshot_vcpus(struct vm *vm, struct vm_snapshot_meta *meta) 2913483d953aSJohn Baldwin { 2914a7db532eSJohn Baldwin uint64_t tsc, now; 2915483d953aSJohn Baldwin int ret; 2916483d953aSJohn Baldwin struct vcpu *vcpu; 291735abc6c2SJohn Baldwin uint16_t i, maxcpus; 2918483d953aSJohn Baldwin 2919a7db532eSJohn Baldwin now = rdtsc(); 292035abc6c2SJohn Baldwin maxcpus = vm_get_maxcpus(vm); 292135abc6c2SJohn Baldwin for (i = 0; i < maxcpus; i++) { 292298568a00SJohn Baldwin vcpu = vm->vcpu[i]; 292398568a00SJohn Baldwin if (vcpu == NULL) 292498568a00SJohn Baldwin continue; 2925483d953aSJohn Baldwin 2926483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->x2apic_state, meta, ret, done); 2927483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exitintinfo, meta, ret, done); 2928483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_vector, meta, ret, done); 2929483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_errcode_valid, meta, ret, done); 2930483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_errcode, meta, ret, done); 2931483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->guest_xcr0, meta, ret, done); 2932483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->exitinfo, meta, ret, done); 2933483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vcpu->nextrip, meta, ret, done); 2934a7db532eSJohn Baldwin 2935a7db532eSJohn Baldwin /* 2936a7db532eSJohn Baldwin * Save the absolute TSC value by adding now to tsc_offset. 2937483d953aSJohn Baldwin * 2938483d953aSJohn Baldwin * It will be turned turned back into an actual offset when the 2939483d953aSJohn Baldwin * TSC restore function is called 2940483d953aSJohn Baldwin */ 2941a7db532eSJohn Baldwin tsc = now + vcpu->tsc_offset; 2942a7db532eSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(tsc, meta, ret, done); 2943281b496fSVitaliy Gusev if (meta->op == VM_SNAPSHOT_RESTORE) 2944281b496fSVitaliy Gusev vcpu->tsc_offset = tsc; 2945483d953aSJohn Baldwin } 2946483d953aSJohn Baldwin 2947483d953aSJohn Baldwin done: 2948483d953aSJohn Baldwin return (ret); 2949483d953aSJohn Baldwin } 2950483d953aSJohn Baldwin 2951483d953aSJohn Baldwin static int 2952483d953aSJohn Baldwin vm_snapshot_vm(struct vm *vm, struct vm_snapshot_meta *meta) 2953483d953aSJohn Baldwin { 2954483d953aSJohn Baldwin int ret; 2955483d953aSJohn Baldwin 2956483d953aSJohn Baldwin ret = vm_snapshot_vcpus(vm, meta); 2957a7db532eSJohn Baldwin if (ret != 0) 2958483d953aSJohn Baldwin goto done; 2959483d953aSJohn Baldwin 2960c0f35dbfSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(vm->startup_cpus, meta, ret, done); 2961483d953aSJohn Baldwin done: 2962483d953aSJohn Baldwin return (ret); 2963483d953aSJohn Baldwin } 2964483d953aSJohn Baldwin 2965483d953aSJohn Baldwin static int 29661aa51504SJohn Baldwin vm_snapshot_vcpu(struct vm *vm, struct vm_snapshot_meta *meta) 2967483d953aSJohn Baldwin { 296835abc6c2SJohn Baldwin int error; 29691aa51504SJohn Baldwin struct vcpu *vcpu; 297035abc6c2SJohn Baldwin uint16_t i, maxcpus; 2971483d953aSJohn Baldwin 2972483d953aSJohn Baldwin error = 0; 2973483d953aSJohn Baldwin 297435abc6c2SJohn Baldwin maxcpus = vm_get_maxcpus(vm); 297535abc6c2SJohn Baldwin for (i = 0; i < maxcpus; i++) { 297698568a00SJohn Baldwin vcpu = vm->vcpu[i]; 297798568a00SJohn Baldwin if (vcpu == NULL) 297898568a00SJohn Baldwin continue; 29791aa51504SJohn Baldwin 2980869c8d19SJohn Baldwin error = vmmops_vcpu_snapshot(vcpu->cookie, meta); 2981483d953aSJohn Baldwin if (error != 0) { 2982483d953aSJohn Baldwin printf("%s: failed to snapshot vmcs/vmcb data for " 2983483d953aSJohn Baldwin "vCPU: %d; error: %d\n", __func__, i, error); 2984483d953aSJohn Baldwin goto done; 2985483d953aSJohn Baldwin } 2986483d953aSJohn Baldwin } 2987483d953aSJohn Baldwin 2988483d953aSJohn Baldwin done: 2989483d953aSJohn Baldwin return (error); 2990483d953aSJohn Baldwin } 2991483d953aSJohn Baldwin 2992483d953aSJohn Baldwin /* 2993483d953aSJohn Baldwin * Save kernel-side structures to user-space for snapshotting. 2994483d953aSJohn Baldwin */ 2995483d953aSJohn Baldwin int 2996483d953aSJohn Baldwin vm_snapshot_req(struct vm *vm, struct vm_snapshot_meta *meta) 2997483d953aSJohn Baldwin { 2998483d953aSJohn Baldwin int ret = 0; 2999483d953aSJohn Baldwin 3000483d953aSJohn Baldwin switch (meta->dev_req) { 3001483d953aSJohn Baldwin case STRUCT_VMCX: 30021aa51504SJohn Baldwin ret = vm_snapshot_vcpu(vm, meta); 3003483d953aSJohn Baldwin break; 3004483d953aSJohn Baldwin case STRUCT_VM: 3005483d953aSJohn Baldwin ret = vm_snapshot_vm(vm, meta); 3006483d953aSJohn Baldwin break; 3007483d953aSJohn Baldwin case STRUCT_VIOAPIC: 3008483d953aSJohn Baldwin ret = vioapic_snapshot(vm_ioapic(vm), meta); 3009483d953aSJohn Baldwin break; 3010483d953aSJohn Baldwin case STRUCT_VLAPIC: 3011483d953aSJohn Baldwin ret = vlapic_snapshot(vm, meta); 3012483d953aSJohn Baldwin break; 3013483d953aSJohn Baldwin case STRUCT_VHPET: 3014483d953aSJohn Baldwin ret = vhpet_snapshot(vm_hpet(vm), meta); 3015483d953aSJohn Baldwin break; 3016483d953aSJohn Baldwin case STRUCT_VATPIC: 3017483d953aSJohn Baldwin ret = vatpic_snapshot(vm_atpic(vm), meta); 3018483d953aSJohn Baldwin break; 3019483d953aSJohn Baldwin case STRUCT_VATPIT: 3020483d953aSJohn Baldwin ret = vatpit_snapshot(vm_atpit(vm), meta); 3021483d953aSJohn Baldwin break; 3022483d953aSJohn Baldwin case STRUCT_VPMTMR: 3023483d953aSJohn Baldwin ret = vpmtmr_snapshot(vm_pmtmr(vm), meta); 3024483d953aSJohn Baldwin break; 3025483d953aSJohn Baldwin case STRUCT_VRTC: 3026483d953aSJohn Baldwin ret = vrtc_snapshot(vm_rtc(vm), meta); 3027483d953aSJohn Baldwin break; 3028483d953aSJohn Baldwin default: 3029483d953aSJohn Baldwin printf("%s: failed to find the requested type %#x\n", 3030483d953aSJohn Baldwin __func__, meta->dev_req); 3031483d953aSJohn Baldwin ret = (EINVAL); 3032483d953aSJohn Baldwin } 3033483d953aSJohn Baldwin return (ret); 3034483d953aSJohn Baldwin } 3035483d953aSJohn Baldwin 303680cb5d84SJohn Baldwin void 303780cb5d84SJohn Baldwin vm_set_tsc_offset(struct vcpu *vcpu, uint64_t offset) 3038483d953aSJohn Baldwin { 3039483d953aSJohn Baldwin vcpu->tsc_offset = offset; 3040483d953aSJohn Baldwin } 3041483d953aSJohn Baldwin 3042483d953aSJohn Baldwin int 3043483d953aSJohn Baldwin vm_restore_time(struct vm *vm) 3044483d953aSJohn Baldwin { 304535abc6c2SJohn Baldwin int error; 3046483d953aSJohn Baldwin uint64_t now; 3047483d953aSJohn Baldwin struct vcpu *vcpu; 304835abc6c2SJohn Baldwin uint16_t i, maxcpus; 3049483d953aSJohn Baldwin 3050483d953aSJohn Baldwin now = rdtsc(); 3051483d953aSJohn Baldwin 3052483d953aSJohn Baldwin error = vhpet_restore_time(vm_hpet(vm)); 3053483d953aSJohn Baldwin if (error) 3054483d953aSJohn Baldwin return (error); 3055483d953aSJohn Baldwin 305635abc6c2SJohn Baldwin maxcpus = vm_get_maxcpus(vm); 305735abc6c2SJohn Baldwin for (i = 0; i < maxcpus; i++) { 305898568a00SJohn Baldwin vcpu = vm->vcpu[i]; 305998568a00SJohn Baldwin if (vcpu == NULL) 306098568a00SJohn Baldwin continue; 3061483d953aSJohn Baldwin 3062869c8d19SJohn Baldwin error = vmmops_restore_tsc(vcpu->cookie, 30631aa51504SJohn Baldwin vcpu->tsc_offset - now); 3064483d953aSJohn Baldwin if (error) 3065483d953aSJohn Baldwin return (error); 3066483d953aSJohn Baldwin } 3067483d953aSJohn Baldwin 3068483d953aSJohn Baldwin return (0); 3069483d953aSJohn Baldwin } 3070483d953aSJohn Baldwin #endif 3071