1*47e07394SAndrew Turner /*- 2*47e07394SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause 3*47e07394SAndrew Turner * 4*47e07394SAndrew Turner * Copyright (C) 2015 Mihai Carabas <mihai.carabas@gmail.com> 5*47e07394SAndrew Turner * All rights reserved. 6*47e07394SAndrew Turner * 7*47e07394SAndrew Turner * Redistribution and use in source and binary forms, with or without 8*47e07394SAndrew Turner * modification, are permitted provided that the following conditions 9*47e07394SAndrew Turner * are met: 10*47e07394SAndrew Turner * 1. Redistributions of source code must retain the above copyright 11*47e07394SAndrew Turner * notice, this list of conditions and the following disclaimer. 12*47e07394SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 13*47e07394SAndrew Turner * notice, this list of conditions and the following disclaimer in the 14*47e07394SAndrew Turner * documentation and/or other materials provided with the distribution. 15*47e07394SAndrew Turner * 16*47e07394SAndrew Turner * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*47e07394SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*47e07394SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*47e07394SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 20*47e07394SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*47e07394SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*47e07394SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*47e07394SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*47e07394SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*47e07394SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*47e07394SAndrew Turner * SUCH DAMAGE. 27*47e07394SAndrew Turner */ 28*47e07394SAndrew Turner 29*47e07394SAndrew Turner #include <sys/param.h> 30*47e07394SAndrew Turner #include <sys/systm.h> 31*47e07394SAndrew Turner #include <sys/cpuset.h> 32*47e07394SAndrew Turner #include <sys/kernel.h> 33*47e07394SAndrew Turner #include <sys/linker.h> 34*47e07394SAndrew Turner #include <sys/lock.h> 35*47e07394SAndrew Turner #include <sys/malloc.h> 36*47e07394SAndrew Turner #include <sys/module.h> 37*47e07394SAndrew Turner #include <sys/mutex.h> 38*47e07394SAndrew Turner #include <sys/pcpu.h> 39*47e07394SAndrew Turner #include <sys/proc.h> 40*47e07394SAndrew Turner #include <sys/queue.h> 41*47e07394SAndrew Turner #include <sys/rwlock.h> 42*47e07394SAndrew Turner #include <sys/sched.h> 43*47e07394SAndrew Turner #include <sys/smp.h> 44*47e07394SAndrew Turner #include <sys/sysctl.h> 45*47e07394SAndrew Turner 46*47e07394SAndrew Turner #include <vm/vm.h> 47*47e07394SAndrew Turner #include <vm/vm_object.h> 48*47e07394SAndrew Turner #include <vm/vm_page.h> 49*47e07394SAndrew Turner #include <vm/pmap.h> 50*47e07394SAndrew Turner #include <vm/vm_map.h> 51*47e07394SAndrew Turner #include <vm/vm_extern.h> 52*47e07394SAndrew Turner #include <vm/vm_param.h> 53*47e07394SAndrew Turner 54*47e07394SAndrew Turner #include <machine/armreg.h> 55*47e07394SAndrew Turner #include <machine/cpu.h> 56*47e07394SAndrew Turner #include <machine/fpu.h> 57*47e07394SAndrew Turner #include <machine/machdep.h> 58*47e07394SAndrew Turner #include <machine/pcb.h> 59*47e07394SAndrew Turner #include <machine/smp.h> 60*47e07394SAndrew Turner #include <machine/vm.h> 61*47e07394SAndrew Turner #include <machine/vmparam.h> 62*47e07394SAndrew Turner #include <machine/vmm.h> 63*47e07394SAndrew Turner #include <machine/vmm_dev.h> 64*47e07394SAndrew Turner #include <machine/vmm_instruction_emul.h> 65*47e07394SAndrew Turner 66*47e07394SAndrew Turner #include <dev/pci/pcireg.h> 67*47e07394SAndrew Turner 68*47e07394SAndrew Turner #include "vmm_ktr.h" 69*47e07394SAndrew Turner #include "vmm_stat.h" 70*47e07394SAndrew Turner #include "arm64.h" 71*47e07394SAndrew Turner #include "mmu.h" 72*47e07394SAndrew Turner 73*47e07394SAndrew Turner #include "io/vgic.h" 74*47e07394SAndrew Turner #include "io/vtimer.h" 75*47e07394SAndrew Turner 76*47e07394SAndrew Turner struct vcpu { 77*47e07394SAndrew Turner int flags; 78*47e07394SAndrew Turner enum vcpu_state state; 79*47e07394SAndrew Turner struct mtx mtx; 80*47e07394SAndrew Turner int hostcpu; /* host cpuid this vcpu last ran on */ 81*47e07394SAndrew Turner int vcpuid; 82*47e07394SAndrew Turner void *stats; 83*47e07394SAndrew Turner struct vm_exit exitinfo; 84*47e07394SAndrew Turner uint64_t nextpc; /* (x) next instruction to execute */ 85*47e07394SAndrew Turner struct vm *vm; /* (o) */ 86*47e07394SAndrew Turner void *cookie; /* (i) cpu-specific data */ 87*47e07394SAndrew Turner struct vfpstate *guestfpu; /* (a,i) guest fpu state */ 88*47e07394SAndrew Turner }; 89*47e07394SAndrew Turner 90*47e07394SAndrew Turner #define vcpu_lock_initialized(v) mtx_initialized(&((v)->mtx)) 91*47e07394SAndrew Turner #define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_SPIN) 92*47e07394SAndrew Turner #define vcpu_lock_destroy(v) mtx_destroy(&((v)->mtx)) 93*47e07394SAndrew Turner #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) 94*47e07394SAndrew Turner #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) 95*47e07394SAndrew Turner #define vcpu_assert_locked(v) mtx_assert(&((v)->mtx), MA_OWNED) 96*47e07394SAndrew Turner 97*47e07394SAndrew Turner struct mem_seg { 98*47e07394SAndrew Turner uint64_t gpa; 99*47e07394SAndrew Turner size_t len; 100*47e07394SAndrew Turner bool wired; 101*47e07394SAndrew Turner bool sysmem; 102*47e07394SAndrew Turner vm_object_t object; 103*47e07394SAndrew Turner }; 104*47e07394SAndrew Turner #define VM_MAX_MEMSEGS 3 105*47e07394SAndrew Turner 106*47e07394SAndrew Turner struct mem_map { 107*47e07394SAndrew Turner vm_paddr_t gpa; 108*47e07394SAndrew Turner size_t len; 109*47e07394SAndrew Turner vm_ooffset_t segoff; 110*47e07394SAndrew Turner int segid; 111*47e07394SAndrew Turner int prot; 112*47e07394SAndrew Turner int flags; 113*47e07394SAndrew Turner }; 114*47e07394SAndrew Turner #define VM_MAX_MEMMAPS 4 115*47e07394SAndrew Turner 116*47e07394SAndrew Turner struct vmm_mmio_region { 117*47e07394SAndrew Turner uint64_t start; 118*47e07394SAndrew Turner uint64_t end; 119*47e07394SAndrew Turner mem_region_read_t read; 120*47e07394SAndrew Turner mem_region_write_t write; 121*47e07394SAndrew Turner }; 122*47e07394SAndrew Turner #define VM_MAX_MMIO_REGIONS 4 123*47e07394SAndrew Turner 124*47e07394SAndrew Turner struct vmm_special_reg { 125*47e07394SAndrew Turner uint32_t esr_iss; 126*47e07394SAndrew Turner uint32_t esr_mask; 127*47e07394SAndrew Turner reg_read_t reg_read; 128*47e07394SAndrew Turner reg_write_t reg_write; 129*47e07394SAndrew Turner void *arg; 130*47e07394SAndrew Turner }; 131*47e07394SAndrew Turner #define VM_MAX_SPECIAL_REGS 16 132*47e07394SAndrew Turner 133*47e07394SAndrew Turner /* 134*47e07394SAndrew Turner * Initialization: 135*47e07394SAndrew Turner * (o) initialized the first time the VM is created 136*47e07394SAndrew Turner * (i) initialized when VM is created and when it is reinitialized 137*47e07394SAndrew Turner * (x) initialized before use 138*47e07394SAndrew Turner */ 139*47e07394SAndrew Turner struct vm { 140*47e07394SAndrew Turner void *cookie; /* (i) cpu-specific data */ 141*47e07394SAndrew Turner volatile cpuset_t active_cpus; /* (i) active vcpus */ 142*47e07394SAndrew Turner volatile cpuset_t debug_cpus; /* (i) vcpus stopped for debug */ 143*47e07394SAndrew Turner int suspend; /* (i) stop VM execution */ 144*47e07394SAndrew Turner volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */ 145*47e07394SAndrew Turner volatile cpuset_t halted_cpus; /* (x) cpus in a hard halt */ 146*47e07394SAndrew Turner struct mem_map mem_maps[VM_MAX_MEMMAPS]; /* (i) guest address space */ 147*47e07394SAndrew Turner struct mem_seg mem_segs[VM_MAX_MEMSEGS]; /* (o) guest memory regions */ 148*47e07394SAndrew Turner struct vmspace *vmspace; /* (o) guest's address space */ 149*47e07394SAndrew Turner char name[VM_MAX_NAMELEN]; /* (o) virtual machine name */ 150*47e07394SAndrew Turner struct vcpu **vcpu; /* (i) guest vcpus */ 151*47e07394SAndrew Turner struct vmm_mmio_region mmio_region[VM_MAX_MMIO_REGIONS]; 152*47e07394SAndrew Turner /* (o) guest MMIO regions */ 153*47e07394SAndrew Turner struct vmm_special_reg special_reg[VM_MAX_SPECIAL_REGS]; 154*47e07394SAndrew Turner /* The following describe the vm cpu topology */ 155*47e07394SAndrew Turner uint16_t sockets; /* (o) num of sockets */ 156*47e07394SAndrew Turner uint16_t cores; /* (o) num of cores/socket */ 157*47e07394SAndrew Turner uint16_t threads; /* (o) num of threads/core */ 158*47e07394SAndrew Turner uint16_t maxcpus; /* (o) max pluggable cpus */ 159*47e07394SAndrew Turner struct sx mem_segs_lock; /* (o) */ 160*47e07394SAndrew Turner struct sx vcpus_init_lock; /* (o) */ 161*47e07394SAndrew Turner }; 162*47e07394SAndrew Turner 163*47e07394SAndrew Turner static bool vmm_initialized = false; 164*47e07394SAndrew Turner 165*47e07394SAndrew Turner static int vm_handle_wfi(struct vcpu *vcpu, 166*47e07394SAndrew Turner struct vm_exit *vme, bool *retu); 167*47e07394SAndrew Turner 168*47e07394SAndrew Turner static MALLOC_DEFINE(M_VMM, "vmm", "vmm"); 169*47e07394SAndrew Turner 170*47e07394SAndrew Turner /* statistics */ 171*47e07394SAndrew Turner static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 172*47e07394SAndrew Turner 173*47e07394SAndrew Turner SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 174*47e07394SAndrew Turner 175*47e07394SAndrew Turner static int vmm_ipinum; 176*47e07394SAndrew Turner SYSCTL_INT(_hw_vmm, OID_AUTO, ipinum, CTLFLAG_RD, &vmm_ipinum, 0, 177*47e07394SAndrew Turner "IPI vector used for vcpu notifications"); 178*47e07394SAndrew Turner 179*47e07394SAndrew Turner struct vmm_regs { 180*47e07394SAndrew Turner uint64_t id_aa64afr0; 181*47e07394SAndrew Turner uint64_t id_aa64afr1; 182*47e07394SAndrew Turner uint64_t id_aa64dfr0; 183*47e07394SAndrew Turner uint64_t id_aa64dfr1; 184*47e07394SAndrew Turner uint64_t id_aa64isar0; 185*47e07394SAndrew Turner uint64_t id_aa64isar1; 186*47e07394SAndrew Turner uint64_t id_aa64isar2; 187*47e07394SAndrew Turner uint64_t id_aa64mmfr0; 188*47e07394SAndrew Turner uint64_t id_aa64mmfr1; 189*47e07394SAndrew Turner uint64_t id_aa64mmfr2; 190*47e07394SAndrew Turner uint64_t id_aa64pfr0; 191*47e07394SAndrew Turner uint64_t id_aa64pfr1; 192*47e07394SAndrew Turner }; 193*47e07394SAndrew Turner 194*47e07394SAndrew Turner static const struct vmm_regs vmm_arch_regs_masks = { 195*47e07394SAndrew Turner .id_aa64dfr0 = 196*47e07394SAndrew Turner ID_AA64DFR0_CTX_CMPs_MASK | 197*47e07394SAndrew Turner ID_AA64DFR0_WRPs_MASK | 198*47e07394SAndrew Turner ID_AA64DFR0_BRPs_MASK | 199*47e07394SAndrew Turner ID_AA64DFR0_PMUVer_3 | 200*47e07394SAndrew Turner ID_AA64DFR0_DebugVer_8, 201*47e07394SAndrew Turner .id_aa64isar0 = 202*47e07394SAndrew Turner ID_AA64ISAR0_TLB_TLBIOSR | 203*47e07394SAndrew Turner ID_AA64ISAR0_SHA3_IMPL | 204*47e07394SAndrew Turner ID_AA64ISAR0_RDM_IMPL | 205*47e07394SAndrew Turner ID_AA64ISAR0_Atomic_IMPL | 206*47e07394SAndrew Turner ID_AA64ISAR0_CRC32_BASE | 207*47e07394SAndrew Turner ID_AA64ISAR0_SHA2_512 | 208*47e07394SAndrew Turner ID_AA64ISAR0_SHA1_BASE | 209*47e07394SAndrew Turner ID_AA64ISAR0_AES_PMULL, 210*47e07394SAndrew Turner .id_aa64mmfr0 = 211*47e07394SAndrew Turner ID_AA64MMFR0_TGran4_IMPL | 212*47e07394SAndrew Turner ID_AA64MMFR0_TGran64_IMPL | 213*47e07394SAndrew Turner ID_AA64MMFR0_TGran16_IMPL | 214*47e07394SAndrew Turner ID_AA64MMFR0_ASIDBits_16 | 215*47e07394SAndrew Turner ID_AA64MMFR0_PARange_4P, 216*47e07394SAndrew Turner .id_aa64mmfr1 = 217*47e07394SAndrew Turner ID_AA64MMFR1_SpecSEI_IMPL | 218*47e07394SAndrew Turner ID_AA64MMFR1_PAN_ATS1E1 | 219*47e07394SAndrew Turner ID_AA64MMFR1_HAFDBS_AF, 220*47e07394SAndrew Turner .id_aa64pfr0 = 221*47e07394SAndrew Turner ID_AA64PFR0_GIC_CPUIF_NONE | 222*47e07394SAndrew Turner ID_AA64PFR0_AdvSIMD_HP | 223*47e07394SAndrew Turner ID_AA64PFR0_FP_HP | 224*47e07394SAndrew Turner ID_AA64PFR0_EL3_64 | 225*47e07394SAndrew Turner ID_AA64PFR0_EL2_64 | 226*47e07394SAndrew Turner ID_AA64PFR0_EL1_64 | 227*47e07394SAndrew Turner ID_AA64PFR0_EL0_64, 228*47e07394SAndrew Turner }; 229*47e07394SAndrew Turner 230*47e07394SAndrew Turner /* Host registers masked by vmm_arch_regs_masks. */ 231*47e07394SAndrew Turner static struct vmm_regs vmm_arch_regs; 232*47e07394SAndrew Turner 233*47e07394SAndrew Turner u_int vm_maxcpu; 234*47e07394SAndrew Turner SYSCTL_UINT(_hw_vmm, OID_AUTO, maxcpu, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, 235*47e07394SAndrew Turner &vm_maxcpu, 0, "Maximum number of vCPUs"); 236*47e07394SAndrew Turner 237*47e07394SAndrew Turner static void vm_free_memmap(struct vm *vm, int ident); 238*47e07394SAndrew Turner static bool sysmem_mapping(struct vm *vm, struct mem_map *mm); 239*47e07394SAndrew Turner static void vcpu_notify_event_locked(struct vcpu *vcpu); 240*47e07394SAndrew Turner 241*47e07394SAndrew Turner /* 242*47e07394SAndrew Turner * Upper limit on vm_maxcpu. We could increase this to 28 bits, but this 243*47e07394SAndrew Turner * is a safe value for now. 244*47e07394SAndrew Turner */ 245*47e07394SAndrew Turner #define VM_MAXCPU MIN(0xffff - 1, CPU_SETSIZE) 246*47e07394SAndrew Turner 247*47e07394SAndrew Turner static int 248*47e07394SAndrew Turner vmm_regs_init(struct vmm_regs *regs, const struct vmm_regs *masks) 249*47e07394SAndrew Turner { 250*47e07394SAndrew Turner #define _FETCH_KERN_REG(reg, field) do { \ 251*47e07394SAndrew Turner regs->field = vmm_arch_regs_masks.field; \ 252*47e07394SAndrew Turner if (!get_kernel_reg_masked(reg, ®s->field, masks->field)) \ 253*47e07394SAndrew Turner regs->field = 0; \ 254*47e07394SAndrew Turner } while (0) 255*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64AFR0_EL1, id_aa64afr0); 256*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64AFR1_EL1, id_aa64afr1); 257*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64DFR0_EL1, id_aa64dfr0); 258*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64DFR1_EL1, id_aa64dfr1); 259*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64ISAR0_EL1, id_aa64isar0); 260*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64ISAR1_EL1, id_aa64isar1); 261*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64ISAR2_EL1, id_aa64isar2); 262*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64MMFR0_EL1, id_aa64mmfr0); 263*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64MMFR1_EL1, id_aa64mmfr1); 264*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64MMFR2_EL1, id_aa64mmfr2); 265*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64PFR0_EL1, id_aa64pfr0); 266*47e07394SAndrew Turner _FETCH_KERN_REG(ID_AA64PFR1_EL1, id_aa64pfr1); 267*47e07394SAndrew Turner #undef _FETCH_KERN_REG 268*47e07394SAndrew Turner return (0); 269*47e07394SAndrew Turner } 270*47e07394SAndrew Turner 271*47e07394SAndrew Turner static void 272*47e07394SAndrew Turner vcpu_cleanup(struct vcpu *vcpu, bool destroy) 273*47e07394SAndrew Turner { 274*47e07394SAndrew Turner vmmops_vcpu_cleanup(vcpu->cookie); 275*47e07394SAndrew Turner vcpu->cookie = NULL; 276*47e07394SAndrew Turner if (destroy) { 277*47e07394SAndrew Turner vmm_stat_free(vcpu->stats); 278*47e07394SAndrew Turner fpu_save_area_free(vcpu->guestfpu); 279*47e07394SAndrew Turner vcpu_lock_destroy(vcpu); 280*47e07394SAndrew Turner } 281*47e07394SAndrew Turner } 282*47e07394SAndrew Turner 283*47e07394SAndrew Turner static struct vcpu * 284*47e07394SAndrew Turner vcpu_alloc(struct vm *vm, int vcpu_id) 285*47e07394SAndrew Turner { 286*47e07394SAndrew Turner struct vcpu *vcpu; 287*47e07394SAndrew Turner 288*47e07394SAndrew Turner KASSERT(vcpu_id >= 0 && vcpu_id < vm->maxcpus, 289*47e07394SAndrew Turner ("vcpu_alloc: invalid vcpu %d", vcpu_id)); 290*47e07394SAndrew Turner 291*47e07394SAndrew Turner vcpu = malloc(sizeof(*vcpu), M_VMM, M_WAITOK | M_ZERO); 292*47e07394SAndrew Turner vcpu_lock_init(vcpu); 293*47e07394SAndrew Turner vcpu->state = VCPU_IDLE; 294*47e07394SAndrew Turner vcpu->hostcpu = NOCPU; 295*47e07394SAndrew Turner vcpu->vcpuid = vcpu_id; 296*47e07394SAndrew Turner vcpu->vm = vm; 297*47e07394SAndrew Turner vcpu->guestfpu = fpu_save_area_alloc(); 298*47e07394SAndrew Turner vcpu->stats = vmm_stat_alloc(); 299*47e07394SAndrew Turner return (vcpu); 300*47e07394SAndrew Turner } 301*47e07394SAndrew Turner 302*47e07394SAndrew Turner static void 303*47e07394SAndrew Turner vcpu_init(struct vcpu *vcpu) 304*47e07394SAndrew Turner { 305*47e07394SAndrew Turner vcpu->cookie = vmmops_vcpu_init(vcpu->vm->cookie, vcpu, vcpu->vcpuid); 306*47e07394SAndrew Turner MPASS(vcpu->cookie != NULL); 307*47e07394SAndrew Turner fpu_save_area_reset(vcpu->guestfpu); 308*47e07394SAndrew Turner vmm_stat_init(vcpu->stats); 309*47e07394SAndrew Turner } 310*47e07394SAndrew Turner 311*47e07394SAndrew Turner struct vm_exit * 312*47e07394SAndrew Turner vm_exitinfo(struct vcpu *vcpu) 313*47e07394SAndrew Turner { 314*47e07394SAndrew Turner return (&vcpu->exitinfo); 315*47e07394SAndrew Turner } 316*47e07394SAndrew Turner 317*47e07394SAndrew Turner static int 318*47e07394SAndrew Turner vmm_init(void) 319*47e07394SAndrew Turner { 320*47e07394SAndrew Turner int error; 321*47e07394SAndrew Turner 322*47e07394SAndrew Turner vm_maxcpu = mp_ncpus; 323*47e07394SAndrew Turner TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu); 324*47e07394SAndrew Turner 325*47e07394SAndrew Turner if (vm_maxcpu > VM_MAXCPU) { 326*47e07394SAndrew Turner printf("vmm: vm_maxcpu clamped to %u\n", VM_MAXCPU); 327*47e07394SAndrew Turner vm_maxcpu = VM_MAXCPU; 328*47e07394SAndrew Turner } 329*47e07394SAndrew Turner if (vm_maxcpu == 0) 330*47e07394SAndrew Turner vm_maxcpu = 1; 331*47e07394SAndrew Turner 332*47e07394SAndrew Turner error = vmm_regs_init(&vmm_arch_regs, &vmm_arch_regs_masks); 333*47e07394SAndrew Turner if (error != 0) 334*47e07394SAndrew Turner return (error); 335*47e07394SAndrew Turner 336*47e07394SAndrew Turner return (vmmops_modinit(0)); 337*47e07394SAndrew Turner } 338*47e07394SAndrew Turner 339*47e07394SAndrew Turner static int 340*47e07394SAndrew Turner vmm_handler(module_t mod, int what, void *arg) 341*47e07394SAndrew Turner { 342*47e07394SAndrew Turner int error; 343*47e07394SAndrew Turner 344*47e07394SAndrew Turner switch (what) { 345*47e07394SAndrew Turner case MOD_LOAD: 346*47e07394SAndrew Turner /* TODO: if (vmm_is_hw_supported()) { */ 347*47e07394SAndrew Turner vmmdev_init(); 348*47e07394SAndrew Turner error = vmm_init(); 349*47e07394SAndrew Turner if (error == 0) 350*47e07394SAndrew Turner vmm_initialized = true; 351*47e07394SAndrew Turner break; 352*47e07394SAndrew Turner case MOD_UNLOAD: 353*47e07394SAndrew Turner /* TODO: if (vmm_is_hw_supported()) { */ 354*47e07394SAndrew Turner error = vmmdev_cleanup(); 355*47e07394SAndrew Turner if (error == 0 && vmm_initialized) { 356*47e07394SAndrew Turner error = vmmops_modcleanup(); 357*47e07394SAndrew Turner if (error) 358*47e07394SAndrew Turner vmm_initialized = false; 359*47e07394SAndrew Turner } 360*47e07394SAndrew Turner break; 361*47e07394SAndrew Turner default: 362*47e07394SAndrew Turner error = 0; 363*47e07394SAndrew Turner break; 364*47e07394SAndrew Turner } 365*47e07394SAndrew Turner return (error); 366*47e07394SAndrew Turner } 367*47e07394SAndrew Turner 368*47e07394SAndrew Turner static moduledata_t vmm_kmod = { 369*47e07394SAndrew Turner "vmm", 370*47e07394SAndrew Turner vmm_handler, 371*47e07394SAndrew Turner NULL 372*47e07394SAndrew Turner }; 373*47e07394SAndrew Turner 374*47e07394SAndrew Turner /* 375*47e07394SAndrew Turner * vmm initialization has the following dependencies: 376*47e07394SAndrew Turner * 377*47e07394SAndrew Turner * - HYP initialization requires smp_rendezvous() and therefore must happen 378*47e07394SAndrew Turner * after SMP is fully functional (after SI_SUB_SMP). 379*47e07394SAndrew Turner */ 380*47e07394SAndrew Turner DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_SMP + 1, SI_ORDER_ANY); 381*47e07394SAndrew Turner MODULE_VERSION(vmm, 1); 382*47e07394SAndrew Turner 383*47e07394SAndrew Turner static void 384*47e07394SAndrew Turner vm_init(struct vm *vm, bool create) 385*47e07394SAndrew Turner { 386*47e07394SAndrew Turner int i; 387*47e07394SAndrew Turner 388*47e07394SAndrew Turner vm->cookie = vmmops_init(vm, vmspace_pmap(vm->vmspace)); 389*47e07394SAndrew Turner MPASS(vm->cookie != NULL); 390*47e07394SAndrew Turner 391*47e07394SAndrew Turner CPU_ZERO(&vm->active_cpus); 392*47e07394SAndrew Turner CPU_ZERO(&vm->debug_cpus); 393*47e07394SAndrew Turner 394*47e07394SAndrew Turner vm->suspend = 0; 395*47e07394SAndrew Turner CPU_ZERO(&vm->suspended_cpus); 396*47e07394SAndrew Turner 397*47e07394SAndrew Turner memset(vm->mmio_region, 0, sizeof(vm->mmio_region)); 398*47e07394SAndrew Turner memset(vm->special_reg, 0, sizeof(vm->special_reg)); 399*47e07394SAndrew Turner 400*47e07394SAndrew Turner if (!create) { 401*47e07394SAndrew Turner for (i = 0; i < vm->maxcpus; i++) { 402*47e07394SAndrew Turner if (vm->vcpu[i] != NULL) 403*47e07394SAndrew Turner vcpu_init(vm->vcpu[i]); 404*47e07394SAndrew Turner } 405*47e07394SAndrew Turner } 406*47e07394SAndrew Turner } 407*47e07394SAndrew Turner 408*47e07394SAndrew Turner struct vcpu * 409*47e07394SAndrew Turner vm_alloc_vcpu(struct vm *vm, int vcpuid) 410*47e07394SAndrew Turner { 411*47e07394SAndrew Turner struct vcpu *vcpu; 412*47e07394SAndrew Turner 413*47e07394SAndrew Turner if (vcpuid < 0 || vcpuid >= vm_get_maxcpus(vm)) 414*47e07394SAndrew Turner return (NULL); 415*47e07394SAndrew Turner 416*47e07394SAndrew Turner /* Some interrupt controllers may have a CPU limit */ 417*47e07394SAndrew Turner if (vcpuid >= vgic_max_cpu_count(vm->cookie)) 418*47e07394SAndrew Turner return (NULL); 419*47e07394SAndrew Turner 420*47e07394SAndrew Turner vcpu = atomic_load_ptr(&vm->vcpu[vcpuid]); 421*47e07394SAndrew Turner if (__predict_true(vcpu != NULL)) 422*47e07394SAndrew Turner return (vcpu); 423*47e07394SAndrew Turner 424*47e07394SAndrew Turner sx_xlock(&vm->vcpus_init_lock); 425*47e07394SAndrew Turner vcpu = vm->vcpu[vcpuid]; 426*47e07394SAndrew Turner if (vcpu == NULL/* && !vm->dying*/) { 427*47e07394SAndrew Turner vcpu = vcpu_alloc(vm, vcpuid); 428*47e07394SAndrew Turner vcpu_init(vcpu); 429*47e07394SAndrew Turner 430*47e07394SAndrew Turner /* 431*47e07394SAndrew Turner * Ensure vCPU is fully created before updating pointer 432*47e07394SAndrew Turner * to permit unlocked reads above. 433*47e07394SAndrew Turner */ 434*47e07394SAndrew Turner atomic_store_rel_ptr((uintptr_t *)&vm->vcpu[vcpuid], 435*47e07394SAndrew Turner (uintptr_t)vcpu); 436*47e07394SAndrew Turner } 437*47e07394SAndrew Turner sx_xunlock(&vm->vcpus_init_lock); 438*47e07394SAndrew Turner return (vcpu); 439*47e07394SAndrew Turner } 440*47e07394SAndrew Turner 441*47e07394SAndrew Turner void 442*47e07394SAndrew Turner vm_slock_vcpus(struct vm *vm) 443*47e07394SAndrew Turner { 444*47e07394SAndrew Turner sx_slock(&vm->vcpus_init_lock); 445*47e07394SAndrew Turner } 446*47e07394SAndrew Turner 447*47e07394SAndrew Turner void 448*47e07394SAndrew Turner vm_unlock_vcpus(struct vm *vm) 449*47e07394SAndrew Turner { 450*47e07394SAndrew Turner sx_unlock(&vm->vcpus_init_lock); 451*47e07394SAndrew Turner } 452*47e07394SAndrew Turner 453*47e07394SAndrew Turner int 454*47e07394SAndrew Turner vm_create(const char *name, struct vm **retvm) 455*47e07394SAndrew Turner { 456*47e07394SAndrew Turner struct vm *vm; 457*47e07394SAndrew Turner struct vmspace *vmspace; 458*47e07394SAndrew Turner 459*47e07394SAndrew Turner /* 460*47e07394SAndrew Turner * If vmm.ko could not be successfully initialized then don't attempt 461*47e07394SAndrew Turner * to create the virtual machine. 462*47e07394SAndrew Turner */ 463*47e07394SAndrew Turner if (!vmm_initialized) 464*47e07394SAndrew Turner return (ENXIO); 465*47e07394SAndrew Turner 466*47e07394SAndrew Turner if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 467*47e07394SAndrew Turner return (EINVAL); 468*47e07394SAndrew Turner 469*47e07394SAndrew Turner vmspace = vmmops_vmspace_alloc(0, 1ul << 39); 470*47e07394SAndrew Turner if (vmspace == NULL) 471*47e07394SAndrew Turner return (ENOMEM); 472*47e07394SAndrew Turner 473*47e07394SAndrew Turner vm = malloc(sizeof(struct vm), M_VMM, M_WAITOK | M_ZERO); 474*47e07394SAndrew Turner strcpy(vm->name, name); 475*47e07394SAndrew Turner vm->vmspace = vmspace; 476*47e07394SAndrew Turner sx_init(&vm->mem_segs_lock, "vm mem_segs"); 477*47e07394SAndrew Turner sx_init(&vm->vcpus_init_lock, "vm vcpus"); 478*47e07394SAndrew Turner 479*47e07394SAndrew Turner vm->sockets = 1; 480*47e07394SAndrew Turner vm->cores = 1; /* XXX backwards compatibility */ 481*47e07394SAndrew Turner vm->threads = 1; /* XXX backwards compatibility */ 482*47e07394SAndrew Turner vm->maxcpus = vm_maxcpu; 483*47e07394SAndrew Turner 484*47e07394SAndrew Turner vm->vcpu = malloc(sizeof(*vm->vcpu) * vm->maxcpus, M_VMM, 485*47e07394SAndrew Turner M_WAITOK | M_ZERO); 486*47e07394SAndrew Turner 487*47e07394SAndrew Turner vm_init(vm, true); 488*47e07394SAndrew Turner 489*47e07394SAndrew Turner *retvm = vm; 490*47e07394SAndrew Turner return (0); 491*47e07394SAndrew Turner } 492*47e07394SAndrew Turner 493*47e07394SAndrew Turner void 494*47e07394SAndrew Turner vm_get_topology(struct vm *vm, uint16_t *sockets, uint16_t *cores, 495*47e07394SAndrew Turner uint16_t *threads, uint16_t *maxcpus) 496*47e07394SAndrew Turner { 497*47e07394SAndrew Turner *sockets = vm->sockets; 498*47e07394SAndrew Turner *cores = vm->cores; 499*47e07394SAndrew Turner *threads = vm->threads; 500*47e07394SAndrew Turner *maxcpus = vm->maxcpus; 501*47e07394SAndrew Turner } 502*47e07394SAndrew Turner 503*47e07394SAndrew Turner uint16_t 504*47e07394SAndrew Turner vm_get_maxcpus(struct vm *vm) 505*47e07394SAndrew Turner { 506*47e07394SAndrew Turner return (vm->maxcpus); 507*47e07394SAndrew Turner } 508*47e07394SAndrew Turner 509*47e07394SAndrew Turner int 510*47e07394SAndrew Turner vm_set_topology(struct vm *vm, uint16_t sockets, uint16_t cores, 511*47e07394SAndrew Turner uint16_t threads, uint16_t maxcpus) 512*47e07394SAndrew Turner { 513*47e07394SAndrew Turner /* Ignore maxcpus. */ 514*47e07394SAndrew Turner if ((sockets * cores * threads) > vm->maxcpus) 515*47e07394SAndrew Turner return (EINVAL); 516*47e07394SAndrew Turner vm->sockets = sockets; 517*47e07394SAndrew Turner vm->cores = cores; 518*47e07394SAndrew Turner vm->threads = threads; 519*47e07394SAndrew Turner return(0); 520*47e07394SAndrew Turner } 521*47e07394SAndrew Turner 522*47e07394SAndrew Turner static void 523*47e07394SAndrew Turner vm_cleanup(struct vm *vm, bool destroy) 524*47e07394SAndrew Turner { 525*47e07394SAndrew Turner struct mem_map *mm; 526*47e07394SAndrew Turner pmap_t pmap __diagused; 527*47e07394SAndrew Turner int i; 528*47e07394SAndrew Turner 529*47e07394SAndrew Turner if (destroy) { 530*47e07394SAndrew Turner pmap = vmspace_pmap(vm->vmspace); 531*47e07394SAndrew Turner sched_pin(); 532*47e07394SAndrew Turner PCPU_SET(curvmpmap, NULL); 533*47e07394SAndrew Turner sched_unpin(); 534*47e07394SAndrew Turner CPU_FOREACH(i) { 535*47e07394SAndrew Turner MPASS(cpuid_to_pcpu[i]->pc_curvmpmap != pmap); 536*47e07394SAndrew Turner } 537*47e07394SAndrew Turner } 538*47e07394SAndrew Turner 539*47e07394SAndrew Turner vgic_detach_from_vm(vm->cookie); 540*47e07394SAndrew Turner 541*47e07394SAndrew Turner for (i = 0; i < vm->maxcpus; i++) { 542*47e07394SAndrew Turner if (vm->vcpu[i] != NULL) 543*47e07394SAndrew Turner vcpu_cleanup(vm->vcpu[i], destroy); 544*47e07394SAndrew Turner } 545*47e07394SAndrew Turner 546*47e07394SAndrew Turner vmmops_cleanup(vm->cookie); 547*47e07394SAndrew Turner 548*47e07394SAndrew Turner /* 549*47e07394SAndrew Turner * System memory is removed from the guest address space only when 550*47e07394SAndrew Turner * the VM is destroyed. This is because the mapping remains the same 551*47e07394SAndrew Turner * across VM reset. 552*47e07394SAndrew Turner * 553*47e07394SAndrew Turner * Device memory can be relocated by the guest (e.g. using PCI BARs) 554*47e07394SAndrew Turner * so those mappings are removed on a VM reset. 555*47e07394SAndrew Turner */ 556*47e07394SAndrew Turner if (!destroy) { 557*47e07394SAndrew Turner for (i = 0; i < VM_MAX_MEMMAPS; i++) { 558*47e07394SAndrew Turner mm = &vm->mem_maps[i]; 559*47e07394SAndrew Turner if (destroy || !sysmem_mapping(vm, mm)) 560*47e07394SAndrew Turner vm_free_memmap(vm, i); 561*47e07394SAndrew Turner } 562*47e07394SAndrew Turner } 563*47e07394SAndrew Turner 564*47e07394SAndrew Turner if (destroy) { 565*47e07394SAndrew Turner for (i = 0; i < VM_MAX_MEMSEGS; i++) 566*47e07394SAndrew Turner vm_free_memseg(vm, i); 567*47e07394SAndrew Turner 568*47e07394SAndrew Turner vmmops_vmspace_free(vm->vmspace); 569*47e07394SAndrew Turner vm->vmspace = NULL; 570*47e07394SAndrew Turner 571*47e07394SAndrew Turner for (i = 0; i < vm->maxcpus; i++) 572*47e07394SAndrew Turner free(vm->vcpu[i], M_VMM); 573*47e07394SAndrew Turner free(vm->vcpu, M_VMM); 574*47e07394SAndrew Turner sx_destroy(&vm->vcpus_init_lock); 575*47e07394SAndrew Turner sx_destroy(&vm->mem_segs_lock); 576*47e07394SAndrew Turner } 577*47e07394SAndrew Turner } 578*47e07394SAndrew Turner 579*47e07394SAndrew Turner void 580*47e07394SAndrew Turner vm_destroy(struct vm *vm) 581*47e07394SAndrew Turner { 582*47e07394SAndrew Turner vm_cleanup(vm, true); 583*47e07394SAndrew Turner free(vm, M_VMM); 584*47e07394SAndrew Turner } 585*47e07394SAndrew Turner 586*47e07394SAndrew Turner int 587*47e07394SAndrew Turner vm_reinit(struct vm *vm) 588*47e07394SAndrew Turner { 589*47e07394SAndrew Turner int error; 590*47e07394SAndrew Turner 591*47e07394SAndrew Turner /* 592*47e07394SAndrew Turner * A virtual machine can be reset only if all vcpus are suspended. 593*47e07394SAndrew Turner */ 594*47e07394SAndrew Turner if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) { 595*47e07394SAndrew Turner vm_cleanup(vm, false); 596*47e07394SAndrew Turner vm_init(vm, false); 597*47e07394SAndrew Turner error = 0; 598*47e07394SAndrew Turner } else { 599*47e07394SAndrew Turner error = EBUSY; 600*47e07394SAndrew Turner } 601*47e07394SAndrew Turner 602*47e07394SAndrew Turner return (error); 603*47e07394SAndrew Turner } 604*47e07394SAndrew Turner 605*47e07394SAndrew Turner const char * 606*47e07394SAndrew Turner vm_name(struct vm *vm) 607*47e07394SAndrew Turner { 608*47e07394SAndrew Turner return (vm->name); 609*47e07394SAndrew Turner } 610*47e07394SAndrew Turner 611*47e07394SAndrew Turner void 612*47e07394SAndrew Turner vm_slock_memsegs(struct vm *vm) 613*47e07394SAndrew Turner { 614*47e07394SAndrew Turner sx_slock(&vm->mem_segs_lock); 615*47e07394SAndrew Turner } 616*47e07394SAndrew Turner 617*47e07394SAndrew Turner void 618*47e07394SAndrew Turner vm_xlock_memsegs(struct vm *vm) 619*47e07394SAndrew Turner { 620*47e07394SAndrew Turner sx_xlock(&vm->mem_segs_lock); 621*47e07394SAndrew Turner } 622*47e07394SAndrew Turner 623*47e07394SAndrew Turner void 624*47e07394SAndrew Turner vm_unlock_memsegs(struct vm *vm) 625*47e07394SAndrew Turner { 626*47e07394SAndrew Turner sx_unlock(&vm->mem_segs_lock); 627*47e07394SAndrew Turner } 628*47e07394SAndrew Turner 629*47e07394SAndrew Turner /* 630*47e07394SAndrew Turner * Return 'true' if 'gpa' is allocated in the guest address space. 631*47e07394SAndrew Turner * 632*47e07394SAndrew Turner * This function is called in the context of a running vcpu which acts as 633*47e07394SAndrew Turner * an implicit lock on 'vm->mem_maps[]'. 634*47e07394SAndrew Turner */ 635*47e07394SAndrew Turner bool 636*47e07394SAndrew Turner vm_mem_allocated(struct vcpu *vcpu, vm_paddr_t gpa) 637*47e07394SAndrew Turner { 638*47e07394SAndrew Turner struct vm *vm = vcpu->vm; 639*47e07394SAndrew Turner struct mem_map *mm; 640*47e07394SAndrew Turner int i; 641*47e07394SAndrew Turner 642*47e07394SAndrew Turner #ifdef INVARIANTS 643*47e07394SAndrew Turner int hostcpu, state; 644*47e07394SAndrew Turner state = vcpu_get_state(vcpu, &hostcpu); 645*47e07394SAndrew Turner KASSERT(state == VCPU_RUNNING && hostcpu == curcpu, 646*47e07394SAndrew Turner ("%s: invalid vcpu state %d/%d", __func__, state, hostcpu)); 647*47e07394SAndrew Turner #endif 648*47e07394SAndrew Turner 649*47e07394SAndrew Turner for (i = 0; i < VM_MAX_MEMMAPS; i++) { 650*47e07394SAndrew Turner mm = &vm->mem_maps[i]; 651*47e07394SAndrew Turner if (mm->len != 0 && gpa >= mm->gpa && gpa < mm->gpa + mm->len) 652*47e07394SAndrew Turner return (true); /* 'gpa' is sysmem or devmem */ 653*47e07394SAndrew Turner } 654*47e07394SAndrew Turner 655*47e07394SAndrew Turner return (false); 656*47e07394SAndrew Turner } 657*47e07394SAndrew Turner 658*47e07394SAndrew Turner int 659*47e07394SAndrew Turner vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem) 660*47e07394SAndrew Turner { 661*47e07394SAndrew Turner struct mem_seg *seg; 662*47e07394SAndrew Turner vm_object_t obj; 663*47e07394SAndrew Turner 664*47e07394SAndrew Turner sx_assert(&vm->mem_segs_lock, SX_XLOCKED); 665*47e07394SAndrew Turner 666*47e07394SAndrew Turner if (ident < 0 || ident >= VM_MAX_MEMSEGS) 667*47e07394SAndrew Turner return (EINVAL); 668*47e07394SAndrew Turner 669*47e07394SAndrew Turner if (len == 0 || (len & PAGE_MASK)) 670*47e07394SAndrew Turner return (EINVAL); 671*47e07394SAndrew Turner 672*47e07394SAndrew Turner seg = &vm->mem_segs[ident]; 673*47e07394SAndrew Turner if (seg->object != NULL) { 674*47e07394SAndrew Turner if (seg->len == len && seg->sysmem == sysmem) 675*47e07394SAndrew Turner return (EEXIST); 676*47e07394SAndrew Turner else 677*47e07394SAndrew Turner return (EINVAL); 678*47e07394SAndrew Turner } 679*47e07394SAndrew Turner 680*47e07394SAndrew Turner obj = vm_object_allocate(OBJT_DEFAULT, len >> PAGE_SHIFT); 681*47e07394SAndrew Turner if (obj == NULL) 682*47e07394SAndrew Turner return (ENOMEM); 683*47e07394SAndrew Turner 684*47e07394SAndrew Turner seg->len = len; 685*47e07394SAndrew Turner seg->object = obj; 686*47e07394SAndrew Turner seg->sysmem = sysmem; 687*47e07394SAndrew Turner return (0); 688*47e07394SAndrew Turner } 689*47e07394SAndrew Turner 690*47e07394SAndrew Turner int 691*47e07394SAndrew Turner vm_get_memseg(struct vm *vm, int ident, size_t *len, bool *sysmem, 692*47e07394SAndrew Turner vm_object_t *objptr) 693*47e07394SAndrew Turner { 694*47e07394SAndrew Turner struct mem_seg *seg; 695*47e07394SAndrew Turner 696*47e07394SAndrew Turner sx_assert(&vm->mem_segs_lock, SX_LOCKED); 697*47e07394SAndrew Turner 698*47e07394SAndrew Turner if (ident < 0 || ident >= VM_MAX_MEMSEGS) 699*47e07394SAndrew Turner return (EINVAL); 700*47e07394SAndrew Turner 701*47e07394SAndrew Turner seg = &vm->mem_segs[ident]; 702*47e07394SAndrew Turner if (len) 703*47e07394SAndrew Turner *len = seg->len; 704*47e07394SAndrew Turner if (sysmem) 705*47e07394SAndrew Turner *sysmem = seg->sysmem; 706*47e07394SAndrew Turner if (objptr) 707*47e07394SAndrew Turner *objptr = seg->object; 708*47e07394SAndrew Turner return (0); 709*47e07394SAndrew Turner } 710*47e07394SAndrew Turner 711*47e07394SAndrew Turner void 712*47e07394SAndrew Turner vm_free_memseg(struct vm *vm, int ident) 713*47e07394SAndrew Turner { 714*47e07394SAndrew Turner struct mem_seg *seg; 715*47e07394SAndrew Turner 716*47e07394SAndrew Turner KASSERT(ident >= 0 && ident < VM_MAX_MEMSEGS, 717*47e07394SAndrew Turner ("%s: invalid memseg ident %d", __func__, ident)); 718*47e07394SAndrew Turner 719*47e07394SAndrew Turner seg = &vm->mem_segs[ident]; 720*47e07394SAndrew Turner if (seg->object != NULL) { 721*47e07394SAndrew Turner vm_object_deallocate(seg->object); 722*47e07394SAndrew Turner bzero(seg, sizeof(struct mem_seg)); 723*47e07394SAndrew Turner } 724*47e07394SAndrew Turner } 725*47e07394SAndrew Turner 726*47e07394SAndrew Turner int 727*47e07394SAndrew Turner vm_mmap_memseg(struct vm *vm, vm_paddr_t gpa, int segid, vm_ooffset_t first, 728*47e07394SAndrew Turner size_t len, int prot, int flags) 729*47e07394SAndrew Turner { 730*47e07394SAndrew Turner struct mem_seg *seg; 731*47e07394SAndrew Turner struct mem_map *m, *map; 732*47e07394SAndrew Turner vm_ooffset_t last; 733*47e07394SAndrew Turner int i, error; 734*47e07394SAndrew Turner 735*47e07394SAndrew Turner if (prot == 0 || (prot & ~(VM_PROT_ALL)) != 0) 736*47e07394SAndrew Turner return (EINVAL); 737*47e07394SAndrew Turner 738*47e07394SAndrew Turner if (flags & ~VM_MEMMAP_F_WIRED) 739*47e07394SAndrew Turner return (EINVAL); 740*47e07394SAndrew Turner 741*47e07394SAndrew Turner if (segid < 0 || segid >= VM_MAX_MEMSEGS) 742*47e07394SAndrew Turner return (EINVAL); 743*47e07394SAndrew Turner 744*47e07394SAndrew Turner seg = &vm->mem_segs[segid]; 745*47e07394SAndrew Turner if (seg->object == NULL) 746*47e07394SAndrew Turner return (EINVAL); 747*47e07394SAndrew Turner 748*47e07394SAndrew Turner last = first + len; 749*47e07394SAndrew Turner if (first < 0 || first >= last || last > seg->len) 750*47e07394SAndrew Turner return (EINVAL); 751*47e07394SAndrew Turner 752*47e07394SAndrew Turner if ((gpa | first | last) & PAGE_MASK) 753*47e07394SAndrew Turner return (EINVAL); 754*47e07394SAndrew Turner 755*47e07394SAndrew Turner map = NULL; 756*47e07394SAndrew Turner for (i = 0; i < VM_MAX_MEMMAPS; i++) { 757*47e07394SAndrew Turner m = &vm->mem_maps[i]; 758*47e07394SAndrew Turner if (m->len == 0) { 759*47e07394SAndrew Turner map = m; 760*47e07394SAndrew Turner break; 761*47e07394SAndrew Turner } 762*47e07394SAndrew Turner } 763*47e07394SAndrew Turner 764*47e07394SAndrew Turner if (map == NULL) 765*47e07394SAndrew Turner return (ENOSPC); 766*47e07394SAndrew Turner 767*47e07394SAndrew Turner error = vm_map_find(&vm->vmspace->vm_map, seg->object, first, &gpa, 768*47e07394SAndrew Turner len, 0, VMFS_NO_SPACE, prot, prot, 0); 769*47e07394SAndrew Turner if (error != KERN_SUCCESS) 770*47e07394SAndrew Turner return (EFAULT); 771*47e07394SAndrew Turner 772*47e07394SAndrew Turner vm_object_reference(seg->object); 773*47e07394SAndrew Turner 774*47e07394SAndrew Turner if (flags & VM_MEMMAP_F_WIRED) { 775*47e07394SAndrew Turner error = vm_map_wire(&vm->vmspace->vm_map, gpa, gpa + len, 776*47e07394SAndrew Turner VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 777*47e07394SAndrew Turner if (error != KERN_SUCCESS) { 778*47e07394SAndrew Turner vm_map_remove(&vm->vmspace->vm_map, gpa, gpa + len); 779*47e07394SAndrew Turner return (error == KERN_RESOURCE_SHORTAGE ? ENOMEM : 780*47e07394SAndrew Turner EFAULT); 781*47e07394SAndrew Turner } 782*47e07394SAndrew Turner } 783*47e07394SAndrew Turner 784*47e07394SAndrew Turner map->gpa = gpa; 785*47e07394SAndrew Turner map->len = len; 786*47e07394SAndrew Turner map->segoff = first; 787*47e07394SAndrew Turner map->segid = segid; 788*47e07394SAndrew Turner map->prot = prot; 789*47e07394SAndrew Turner map->flags = flags; 790*47e07394SAndrew Turner return (0); 791*47e07394SAndrew Turner } 792*47e07394SAndrew Turner 793*47e07394SAndrew Turner int 794*47e07394SAndrew Turner vm_munmap_memseg(struct vm *vm, vm_paddr_t gpa, size_t len) 795*47e07394SAndrew Turner { 796*47e07394SAndrew Turner struct mem_map *m; 797*47e07394SAndrew Turner int i; 798*47e07394SAndrew Turner 799*47e07394SAndrew Turner for (i = 0; i < VM_MAX_MEMMAPS; i++) { 800*47e07394SAndrew Turner m = &vm->mem_maps[i]; 801*47e07394SAndrew Turner if (m->gpa == gpa && m->len == len) { 802*47e07394SAndrew Turner vm_free_memmap(vm, i); 803*47e07394SAndrew Turner return (0); 804*47e07394SAndrew Turner } 805*47e07394SAndrew Turner } 806*47e07394SAndrew Turner 807*47e07394SAndrew Turner return (EINVAL); 808*47e07394SAndrew Turner } 809*47e07394SAndrew Turner 810*47e07394SAndrew Turner int 811*47e07394SAndrew Turner vm_mmap_getnext(struct vm *vm, vm_paddr_t *gpa, int *segid, 812*47e07394SAndrew Turner vm_ooffset_t *segoff, size_t *len, int *prot, int *flags) 813*47e07394SAndrew Turner { 814*47e07394SAndrew Turner struct mem_map *mm, *mmnext; 815*47e07394SAndrew Turner int i; 816*47e07394SAndrew Turner 817*47e07394SAndrew Turner mmnext = NULL; 818*47e07394SAndrew Turner for (i = 0; i < VM_MAX_MEMMAPS; i++) { 819*47e07394SAndrew Turner mm = &vm->mem_maps[i]; 820*47e07394SAndrew Turner if (mm->len == 0 || mm->gpa < *gpa) 821*47e07394SAndrew Turner continue; 822*47e07394SAndrew Turner if (mmnext == NULL || mm->gpa < mmnext->gpa) 823*47e07394SAndrew Turner mmnext = mm; 824*47e07394SAndrew Turner } 825*47e07394SAndrew Turner 826*47e07394SAndrew Turner if (mmnext != NULL) { 827*47e07394SAndrew Turner *gpa = mmnext->gpa; 828*47e07394SAndrew Turner if (segid) 829*47e07394SAndrew Turner *segid = mmnext->segid; 830*47e07394SAndrew Turner if (segoff) 831*47e07394SAndrew Turner *segoff = mmnext->segoff; 832*47e07394SAndrew Turner if (len) 833*47e07394SAndrew Turner *len = mmnext->len; 834*47e07394SAndrew Turner if (prot) 835*47e07394SAndrew Turner *prot = mmnext->prot; 836*47e07394SAndrew Turner if (flags) 837*47e07394SAndrew Turner *flags = mmnext->flags; 838*47e07394SAndrew Turner return (0); 839*47e07394SAndrew Turner } else { 840*47e07394SAndrew Turner return (ENOENT); 841*47e07394SAndrew Turner } 842*47e07394SAndrew Turner } 843*47e07394SAndrew Turner 844*47e07394SAndrew Turner static void 845*47e07394SAndrew Turner vm_free_memmap(struct vm *vm, int ident) 846*47e07394SAndrew Turner { 847*47e07394SAndrew Turner struct mem_map *mm; 848*47e07394SAndrew Turner int error __diagused; 849*47e07394SAndrew Turner 850*47e07394SAndrew Turner mm = &vm->mem_maps[ident]; 851*47e07394SAndrew Turner if (mm->len) { 852*47e07394SAndrew Turner error = vm_map_remove(&vm->vmspace->vm_map, mm->gpa, 853*47e07394SAndrew Turner mm->gpa + mm->len); 854*47e07394SAndrew Turner KASSERT(error == KERN_SUCCESS, ("%s: vm_map_remove error %d", 855*47e07394SAndrew Turner __func__, error)); 856*47e07394SAndrew Turner bzero(mm, sizeof(struct mem_map)); 857*47e07394SAndrew Turner } 858*47e07394SAndrew Turner } 859*47e07394SAndrew Turner 860*47e07394SAndrew Turner static __inline bool 861*47e07394SAndrew Turner sysmem_mapping(struct vm *vm, struct mem_map *mm) 862*47e07394SAndrew Turner { 863*47e07394SAndrew Turner 864*47e07394SAndrew Turner if (mm->len != 0 && vm->mem_segs[mm->segid].sysmem) 865*47e07394SAndrew Turner return (true); 866*47e07394SAndrew Turner else 867*47e07394SAndrew Turner return (false); 868*47e07394SAndrew Turner } 869*47e07394SAndrew Turner 870*47e07394SAndrew Turner vm_paddr_t 871*47e07394SAndrew Turner vmm_sysmem_maxaddr(struct vm *vm) 872*47e07394SAndrew Turner { 873*47e07394SAndrew Turner struct mem_map *mm; 874*47e07394SAndrew Turner vm_paddr_t maxaddr; 875*47e07394SAndrew Turner int i; 876*47e07394SAndrew Turner 877*47e07394SAndrew Turner maxaddr = 0; 878*47e07394SAndrew Turner for (i = 0; i < VM_MAX_MEMMAPS; i++) { 879*47e07394SAndrew Turner mm = &vm->mem_maps[i]; 880*47e07394SAndrew Turner if (sysmem_mapping(vm, mm)) { 881*47e07394SAndrew Turner if (maxaddr < mm->gpa + mm->len) 882*47e07394SAndrew Turner maxaddr = mm->gpa + mm->len; 883*47e07394SAndrew Turner } 884*47e07394SAndrew Turner } 885*47e07394SAndrew Turner return (maxaddr); 886*47e07394SAndrew Turner } 887*47e07394SAndrew Turner 888*47e07394SAndrew Turner int 889*47e07394SAndrew Turner vm_gla2gpa_nofault(struct vcpu *vcpu, struct vm_guest_paging *paging, 890*47e07394SAndrew Turner uint64_t gla, int prot, uint64_t *gpa, int *is_fault) 891*47e07394SAndrew Turner { 892*47e07394SAndrew Turner 893*47e07394SAndrew Turner vmmops_gla2gpa(vcpu->cookie, paging, gla, prot, gpa, is_fault); 894*47e07394SAndrew Turner return (0); 895*47e07394SAndrew Turner } 896*47e07394SAndrew Turner 897*47e07394SAndrew Turner static int 898*47e07394SAndrew Turner vmm_reg_raz(struct vcpu *vcpu, uint64_t *rval, void *arg) 899*47e07394SAndrew Turner { 900*47e07394SAndrew Turner *rval = 0; 901*47e07394SAndrew Turner return (0); 902*47e07394SAndrew Turner } 903*47e07394SAndrew Turner 904*47e07394SAndrew Turner static int 905*47e07394SAndrew Turner vmm_reg_read_arg(struct vcpu *vcpu, uint64_t *rval, void *arg) 906*47e07394SAndrew Turner { 907*47e07394SAndrew Turner *rval = *(uint64_t *)arg; 908*47e07394SAndrew Turner return (0); 909*47e07394SAndrew Turner } 910*47e07394SAndrew Turner 911*47e07394SAndrew Turner static int 912*47e07394SAndrew Turner vmm_reg_wi(struct vcpu *vcpu, uint64_t wval, void *arg) 913*47e07394SAndrew Turner { 914*47e07394SAndrew Turner return (0); 915*47e07394SAndrew Turner } 916*47e07394SAndrew Turner 917*47e07394SAndrew Turner static const struct vmm_special_reg vmm_special_regs[] = { 918*47e07394SAndrew Turner #define SPECIAL_REG(_reg, _read, _write) \ 919*47e07394SAndrew Turner { \ 920*47e07394SAndrew Turner .esr_iss = ((_reg ## _op0) << ISS_MSR_OP0_SHIFT) | \ 921*47e07394SAndrew Turner ((_reg ## _op1) << ISS_MSR_OP1_SHIFT) | \ 922*47e07394SAndrew Turner ((_reg ## _CRn) << ISS_MSR_CRn_SHIFT) | \ 923*47e07394SAndrew Turner ((_reg ## _CRm) << ISS_MSR_CRm_SHIFT) | \ 924*47e07394SAndrew Turner ((_reg ## _op2) << ISS_MSR_OP2_SHIFT), \ 925*47e07394SAndrew Turner .esr_mask = ISS_MSR_REG_MASK, \ 926*47e07394SAndrew Turner .reg_read = (_read), \ 927*47e07394SAndrew Turner .reg_write = (_write), \ 928*47e07394SAndrew Turner .arg = NULL, \ 929*47e07394SAndrew Turner } 930*47e07394SAndrew Turner #define ID_SPECIAL_REG(_reg, _name) \ 931*47e07394SAndrew Turner { \ 932*47e07394SAndrew Turner .esr_iss = ((_reg ## _op0) << ISS_MSR_OP0_SHIFT) | \ 933*47e07394SAndrew Turner ((_reg ## _op1) << ISS_MSR_OP1_SHIFT) | \ 934*47e07394SAndrew Turner ((_reg ## _CRn) << ISS_MSR_CRn_SHIFT) | \ 935*47e07394SAndrew Turner ((_reg ## _CRm) << ISS_MSR_CRm_SHIFT) | \ 936*47e07394SAndrew Turner ((_reg ## _op2) << ISS_MSR_OP2_SHIFT), \ 937*47e07394SAndrew Turner .esr_mask = ISS_MSR_REG_MASK, \ 938*47e07394SAndrew Turner .reg_read = vmm_reg_read_arg, \ 939*47e07394SAndrew Turner .reg_write = vmm_reg_wi, \ 940*47e07394SAndrew Turner .arg = &(vmm_arch_regs._name), \ 941*47e07394SAndrew Turner } 942*47e07394SAndrew Turner 943*47e07394SAndrew Turner /* ID registers */ 944*47e07394SAndrew Turner ID_SPECIAL_REG(ID_AA64PFR0_EL1, id_aa64pfr0), 945*47e07394SAndrew Turner ID_SPECIAL_REG(ID_AA64DFR0_EL1, id_aa64dfr0), 946*47e07394SAndrew Turner ID_SPECIAL_REG(ID_AA64ISAR0_EL1, id_aa64isar0), 947*47e07394SAndrew Turner ID_SPECIAL_REG(ID_AA64MMFR0_EL1, id_aa64mmfr0), 948*47e07394SAndrew Turner ID_SPECIAL_REG(ID_AA64MMFR1_EL1, id_aa64mmfr1), 949*47e07394SAndrew Turner 950*47e07394SAndrew Turner /* 951*47e07394SAndrew Turner * All other ID registers are read as zero. 952*47e07394SAndrew Turner * They are all in the op0=3, op1=0, CRn=0, CRm={0..7} space. 953*47e07394SAndrew Turner */ 954*47e07394SAndrew Turner { 955*47e07394SAndrew Turner .esr_iss = (3 << ISS_MSR_OP0_SHIFT) | 956*47e07394SAndrew Turner (0 << ISS_MSR_OP1_SHIFT) | 957*47e07394SAndrew Turner (0 << ISS_MSR_CRn_SHIFT) | 958*47e07394SAndrew Turner (0 << ISS_MSR_CRm_SHIFT), 959*47e07394SAndrew Turner .esr_mask = ISS_MSR_OP0_MASK | ISS_MSR_OP1_MASK | 960*47e07394SAndrew Turner ISS_MSR_CRn_MASK | (0x8 << ISS_MSR_CRm_SHIFT), 961*47e07394SAndrew Turner .reg_read = vmm_reg_raz, 962*47e07394SAndrew Turner .reg_write = vmm_reg_wi, 963*47e07394SAndrew Turner .arg = NULL, 964*47e07394SAndrew Turner }, 965*47e07394SAndrew Turner 966*47e07394SAndrew Turner /* Counter physical registers */ 967*47e07394SAndrew Turner SPECIAL_REG(CNTP_CTL_EL0, vtimer_phys_ctl_read, vtimer_phys_ctl_write), 968*47e07394SAndrew Turner SPECIAL_REG(CNTP_CVAL_EL0, vtimer_phys_cval_read, 969*47e07394SAndrew Turner vtimer_phys_cval_write), 970*47e07394SAndrew Turner SPECIAL_REG(CNTP_TVAL_EL0, vtimer_phys_tval_read, 971*47e07394SAndrew Turner vtimer_phys_tval_write), 972*47e07394SAndrew Turner SPECIAL_REG(CNTPCT_EL0, vtimer_phys_cnt_read, vtimer_phys_cnt_write), 973*47e07394SAndrew Turner #undef SPECIAL_REG 974*47e07394SAndrew Turner }; 975*47e07394SAndrew Turner 976*47e07394SAndrew Turner void 977*47e07394SAndrew Turner vm_register_reg_handler(struct vm *vm, uint64_t iss, uint64_t mask, 978*47e07394SAndrew Turner reg_read_t reg_read, reg_write_t reg_write, void *arg) 979*47e07394SAndrew Turner { 980*47e07394SAndrew Turner int i; 981*47e07394SAndrew Turner 982*47e07394SAndrew Turner for (i = 0; i < nitems(vm->special_reg); i++) { 983*47e07394SAndrew Turner if (vm->special_reg[i].esr_iss == 0 && 984*47e07394SAndrew Turner vm->special_reg[i].esr_mask == 0) { 985*47e07394SAndrew Turner vm->special_reg[i].esr_iss = iss; 986*47e07394SAndrew Turner vm->special_reg[i].esr_mask = mask; 987*47e07394SAndrew Turner vm->special_reg[i].reg_read = reg_read; 988*47e07394SAndrew Turner vm->special_reg[i].reg_write = reg_write; 989*47e07394SAndrew Turner vm->special_reg[i].arg = arg; 990*47e07394SAndrew Turner return; 991*47e07394SAndrew Turner } 992*47e07394SAndrew Turner } 993*47e07394SAndrew Turner 994*47e07394SAndrew Turner panic("%s: No free special register slot", __func__); 995*47e07394SAndrew Turner } 996*47e07394SAndrew Turner 997*47e07394SAndrew Turner void 998*47e07394SAndrew Turner vm_deregister_reg_handler(struct vm *vm, uint64_t iss, uint64_t mask) 999*47e07394SAndrew Turner { 1000*47e07394SAndrew Turner int i; 1001*47e07394SAndrew Turner 1002*47e07394SAndrew Turner for (i = 0; i < nitems(vm->special_reg); i++) { 1003*47e07394SAndrew Turner if (vm->special_reg[i].esr_iss == iss && 1004*47e07394SAndrew Turner vm->special_reg[i].esr_mask == mask) { 1005*47e07394SAndrew Turner memset(&vm->special_reg[i], 0, 1006*47e07394SAndrew Turner sizeof(vm->special_reg[i])); 1007*47e07394SAndrew Turner return; 1008*47e07394SAndrew Turner } 1009*47e07394SAndrew Turner } 1010*47e07394SAndrew Turner 1011*47e07394SAndrew Turner panic("%s: Invalid special register: iss %lx mask %lx", __func__, iss, 1012*47e07394SAndrew Turner mask); 1013*47e07394SAndrew Turner } 1014*47e07394SAndrew Turner 1015*47e07394SAndrew Turner static int 1016*47e07394SAndrew Turner vm_handle_reg_emul(struct vcpu *vcpu, bool *retu) 1017*47e07394SAndrew Turner { 1018*47e07394SAndrew Turner struct vm *vm; 1019*47e07394SAndrew Turner struct vm_exit *vme; 1020*47e07394SAndrew Turner struct vre *vre; 1021*47e07394SAndrew Turner int i, rv; 1022*47e07394SAndrew Turner 1023*47e07394SAndrew Turner vm = vcpu->vm; 1024*47e07394SAndrew Turner vme = &vcpu->exitinfo; 1025*47e07394SAndrew Turner vre = &vme->u.reg_emul.vre; 1026*47e07394SAndrew Turner 1027*47e07394SAndrew Turner for (i = 0; i < nitems(vm->special_reg); i++) { 1028*47e07394SAndrew Turner if (vm->special_reg[i].esr_iss == 0 && 1029*47e07394SAndrew Turner vm->special_reg[i].esr_mask == 0) 1030*47e07394SAndrew Turner continue; 1031*47e07394SAndrew Turner 1032*47e07394SAndrew Turner if ((vre->inst_syndrome & vm->special_reg[i].esr_mask) == 1033*47e07394SAndrew Turner vm->special_reg[i].esr_iss) { 1034*47e07394SAndrew Turner rv = vmm_emulate_register(vcpu, vre, 1035*47e07394SAndrew Turner vm->special_reg[i].reg_read, 1036*47e07394SAndrew Turner vm->special_reg[i].reg_write, 1037*47e07394SAndrew Turner vm->special_reg[i].arg); 1038*47e07394SAndrew Turner if (rv == 0) { 1039*47e07394SAndrew Turner *retu = false; 1040*47e07394SAndrew Turner } 1041*47e07394SAndrew Turner return (rv); 1042*47e07394SAndrew Turner } 1043*47e07394SAndrew Turner } 1044*47e07394SAndrew Turner for (i = 0; i < nitems(vmm_special_regs); i++) { 1045*47e07394SAndrew Turner if ((vre->inst_syndrome & vmm_special_regs[i].esr_mask) == 1046*47e07394SAndrew Turner vmm_special_regs[i].esr_iss) { 1047*47e07394SAndrew Turner rv = vmm_emulate_register(vcpu, vre, 1048*47e07394SAndrew Turner vmm_special_regs[i].reg_read, 1049*47e07394SAndrew Turner vmm_special_regs[i].reg_write, 1050*47e07394SAndrew Turner vmm_special_regs[i].arg); 1051*47e07394SAndrew Turner if (rv == 0) { 1052*47e07394SAndrew Turner *retu = false; 1053*47e07394SAndrew Turner } 1054*47e07394SAndrew Turner return (rv); 1055*47e07394SAndrew Turner } 1056*47e07394SAndrew Turner } 1057*47e07394SAndrew Turner 1058*47e07394SAndrew Turner 1059*47e07394SAndrew Turner *retu = true; 1060*47e07394SAndrew Turner return (0); 1061*47e07394SAndrew Turner } 1062*47e07394SAndrew Turner 1063*47e07394SAndrew Turner void 1064*47e07394SAndrew Turner vm_register_inst_handler(struct vm *vm, uint64_t start, uint64_t size, 1065*47e07394SAndrew Turner mem_region_read_t mmio_read, mem_region_write_t mmio_write) 1066*47e07394SAndrew Turner { 1067*47e07394SAndrew Turner int i; 1068*47e07394SAndrew Turner 1069*47e07394SAndrew Turner for (i = 0; i < nitems(vm->mmio_region); i++) { 1070*47e07394SAndrew Turner if (vm->mmio_region[i].start == 0 && 1071*47e07394SAndrew Turner vm->mmio_region[i].end == 0) { 1072*47e07394SAndrew Turner vm->mmio_region[i].start = start; 1073*47e07394SAndrew Turner vm->mmio_region[i].end = start + size; 1074*47e07394SAndrew Turner vm->mmio_region[i].read = mmio_read; 1075*47e07394SAndrew Turner vm->mmio_region[i].write = mmio_write; 1076*47e07394SAndrew Turner return; 1077*47e07394SAndrew Turner } 1078*47e07394SAndrew Turner } 1079*47e07394SAndrew Turner 1080*47e07394SAndrew Turner panic("%s: No free MMIO region", __func__); 1081*47e07394SAndrew Turner } 1082*47e07394SAndrew Turner 1083*47e07394SAndrew Turner void 1084*47e07394SAndrew Turner vm_deregister_inst_handler(struct vm *vm, uint64_t start, uint64_t size) 1085*47e07394SAndrew Turner { 1086*47e07394SAndrew Turner int i; 1087*47e07394SAndrew Turner 1088*47e07394SAndrew Turner for (i = 0; i < nitems(vm->mmio_region); i++) { 1089*47e07394SAndrew Turner if (vm->mmio_region[i].start == start && 1090*47e07394SAndrew Turner vm->mmio_region[i].end == start + size) { 1091*47e07394SAndrew Turner memset(&vm->mmio_region[i], 0, 1092*47e07394SAndrew Turner sizeof(vm->mmio_region[i])); 1093*47e07394SAndrew Turner return; 1094*47e07394SAndrew Turner } 1095*47e07394SAndrew Turner } 1096*47e07394SAndrew Turner 1097*47e07394SAndrew Turner panic("%s: Invalid MMIO region: %lx - %lx", __func__, start, 1098*47e07394SAndrew Turner start + size); 1099*47e07394SAndrew Turner } 1100*47e07394SAndrew Turner 1101*47e07394SAndrew Turner static int 1102*47e07394SAndrew Turner vm_handle_inst_emul(struct vcpu *vcpu, bool *retu) 1103*47e07394SAndrew Turner { 1104*47e07394SAndrew Turner struct vm *vm; 1105*47e07394SAndrew Turner struct vm_exit *vme; 1106*47e07394SAndrew Turner struct vie *vie; 1107*47e07394SAndrew Turner struct hyp *hyp; 1108*47e07394SAndrew Turner uint64_t fault_ipa; 1109*47e07394SAndrew Turner struct vm_guest_paging *paging; 1110*47e07394SAndrew Turner struct vmm_mmio_region *vmr; 1111*47e07394SAndrew Turner int error, i; 1112*47e07394SAndrew Turner 1113*47e07394SAndrew Turner vm = vcpu->vm; 1114*47e07394SAndrew Turner hyp = vm->cookie; 1115*47e07394SAndrew Turner if (!hyp->vgic_attached) 1116*47e07394SAndrew Turner goto out_user; 1117*47e07394SAndrew Turner 1118*47e07394SAndrew Turner vme = &vcpu->exitinfo; 1119*47e07394SAndrew Turner vie = &vme->u.inst_emul.vie; 1120*47e07394SAndrew Turner paging = &vme->u.inst_emul.paging; 1121*47e07394SAndrew Turner 1122*47e07394SAndrew Turner fault_ipa = vme->u.inst_emul.gpa; 1123*47e07394SAndrew Turner 1124*47e07394SAndrew Turner vmr = NULL; 1125*47e07394SAndrew Turner for (i = 0; i < nitems(vm->mmio_region); i++) { 1126*47e07394SAndrew Turner if (vm->mmio_region[i].start <= fault_ipa && 1127*47e07394SAndrew Turner vm->mmio_region[i].end > fault_ipa) { 1128*47e07394SAndrew Turner vmr = &vm->mmio_region[i]; 1129*47e07394SAndrew Turner break; 1130*47e07394SAndrew Turner } 1131*47e07394SAndrew Turner } 1132*47e07394SAndrew Turner if (vmr == NULL) 1133*47e07394SAndrew Turner goto out_user; 1134*47e07394SAndrew Turner 1135*47e07394SAndrew Turner error = vmm_emulate_instruction(vcpu, fault_ipa, vie, paging, 1136*47e07394SAndrew Turner vmr->read, vmr->write, retu); 1137*47e07394SAndrew Turner return (error); 1138*47e07394SAndrew Turner 1139*47e07394SAndrew Turner out_user: 1140*47e07394SAndrew Turner *retu = true; 1141*47e07394SAndrew Turner return (0); 1142*47e07394SAndrew Turner } 1143*47e07394SAndrew Turner 1144*47e07394SAndrew Turner int 1145*47e07394SAndrew Turner vm_suspend(struct vm *vm, enum vm_suspend_how how) 1146*47e07394SAndrew Turner { 1147*47e07394SAndrew Turner int i; 1148*47e07394SAndrew Turner 1149*47e07394SAndrew Turner if (how <= VM_SUSPEND_NONE || how >= VM_SUSPEND_LAST) 1150*47e07394SAndrew Turner return (EINVAL); 1151*47e07394SAndrew Turner 1152*47e07394SAndrew Turner if (atomic_cmpset_int(&vm->suspend, 0, how) == 0) { 1153*47e07394SAndrew Turner VM_CTR2(vm, "virtual machine already suspended %d/%d", 1154*47e07394SAndrew Turner vm->suspend, how); 1155*47e07394SAndrew Turner return (EALREADY); 1156*47e07394SAndrew Turner } 1157*47e07394SAndrew Turner 1158*47e07394SAndrew Turner VM_CTR1(vm, "virtual machine successfully suspended %d", how); 1159*47e07394SAndrew Turner 1160*47e07394SAndrew Turner /* 1161*47e07394SAndrew Turner * Notify all active vcpus that they are now suspended. 1162*47e07394SAndrew Turner */ 1163*47e07394SAndrew Turner for (i = 0; i < vm->maxcpus; i++) { 1164*47e07394SAndrew Turner if (CPU_ISSET(i, &vm->active_cpus)) 1165*47e07394SAndrew Turner vcpu_notify_event(vm_vcpu(vm, i)); 1166*47e07394SAndrew Turner } 1167*47e07394SAndrew Turner 1168*47e07394SAndrew Turner return (0); 1169*47e07394SAndrew Turner } 1170*47e07394SAndrew Turner 1171*47e07394SAndrew Turner void 1172*47e07394SAndrew Turner vm_exit_suspended(struct vcpu *vcpu, uint64_t pc) 1173*47e07394SAndrew Turner { 1174*47e07394SAndrew Turner struct vm *vm = vcpu->vm; 1175*47e07394SAndrew Turner struct vm_exit *vmexit; 1176*47e07394SAndrew Turner 1177*47e07394SAndrew Turner KASSERT(vm->suspend > VM_SUSPEND_NONE && vm->suspend < VM_SUSPEND_LAST, 1178*47e07394SAndrew Turner ("vm_exit_suspended: invalid suspend type %d", vm->suspend)); 1179*47e07394SAndrew Turner 1180*47e07394SAndrew Turner vmexit = vm_exitinfo(vcpu); 1181*47e07394SAndrew Turner vmexit->pc = pc; 1182*47e07394SAndrew Turner vmexit->inst_length = 4; 1183*47e07394SAndrew Turner vmexit->exitcode = VM_EXITCODE_SUSPENDED; 1184*47e07394SAndrew Turner vmexit->u.suspended.how = vm->suspend; 1185*47e07394SAndrew Turner } 1186*47e07394SAndrew Turner 1187*47e07394SAndrew Turner void 1188*47e07394SAndrew Turner vm_exit_debug(struct vcpu *vcpu, uint64_t pc) 1189*47e07394SAndrew Turner { 1190*47e07394SAndrew Turner struct vm_exit *vmexit; 1191*47e07394SAndrew Turner 1192*47e07394SAndrew Turner vmexit = vm_exitinfo(vcpu); 1193*47e07394SAndrew Turner vmexit->pc = pc; 1194*47e07394SAndrew Turner vmexit->inst_length = 4; 1195*47e07394SAndrew Turner vmexit->exitcode = VM_EXITCODE_DEBUG; 1196*47e07394SAndrew Turner } 1197*47e07394SAndrew Turner 1198*47e07394SAndrew Turner int 1199*47e07394SAndrew Turner vm_activate_cpu(struct vcpu *vcpu) 1200*47e07394SAndrew Turner { 1201*47e07394SAndrew Turner struct vm *vm = vcpu->vm; 1202*47e07394SAndrew Turner 1203*47e07394SAndrew Turner if (CPU_ISSET(vcpu->vcpuid, &vm->active_cpus)) 1204*47e07394SAndrew Turner return (EBUSY); 1205*47e07394SAndrew Turner 1206*47e07394SAndrew Turner CPU_SET_ATOMIC(vcpu->vcpuid, &vm->active_cpus); 1207*47e07394SAndrew Turner return (0); 1208*47e07394SAndrew Turner 1209*47e07394SAndrew Turner } 1210*47e07394SAndrew Turner 1211*47e07394SAndrew Turner int 1212*47e07394SAndrew Turner vm_suspend_cpu(struct vm *vm, struct vcpu *vcpu) 1213*47e07394SAndrew Turner { 1214*47e07394SAndrew Turner if (vcpu == NULL) { 1215*47e07394SAndrew Turner vm->debug_cpus = vm->active_cpus; 1216*47e07394SAndrew Turner for (int i = 0; i < vm->maxcpus; i++) { 1217*47e07394SAndrew Turner if (CPU_ISSET(i, &vm->active_cpus)) 1218*47e07394SAndrew Turner vcpu_notify_event(vm_vcpu(vm, i)); 1219*47e07394SAndrew Turner } 1220*47e07394SAndrew Turner } else { 1221*47e07394SAndrew Turner if (!CPU_ISSET(vcpu->vcpuid, &vm->active_cpus)) 1222*47e07394SAndrew Turner return (EINVAL); 1223*47e07394SAndrew Turner 1224*47e07394SAndrew Turner CPU_SET_ATOMIC(vcpu->vcpuid, &vm->debug_cpus); 1225*47e07394SAndrew Turner vcpu_notify_event(vcpu); 1226*47e07394SAndrew Turner } 1227*47e07394SAndrew Turner return (0); 1228*47e07394SAndrew Turner } 1229*47e07394SAndrew Turner 1230*47e07394SAndrew Turner int 1231*47e07394SAndrew Turner vm_resume_cpu(struct vm *vm, struct vcpu *vcpu) 1232*47e07394SAndrew Turner { 1233*47e07394SAndrew Turner 1234*47e07394SAndrew Turner if (vcpu == NULL) { 1235*47e07394SAndrew Turner CPU_ZERO(&vm->debug_cpus); 1236*47e07394SAndrew Turner } else { 1237*47e07394SAndrew Turner if (!CPU_ISSET(vcpu->vcpuid, &vm->debug_cpus)) 1238*47e07394SAndrew Turner return (EINVAL); 1239*47e07394SAndrew Turner 1240*47e07394SAndrew Turner CPU_CLR_ATOMIC(vcpu->vcpuid, &vm->debug_cpus); 1241*47e07394SAndrew Turner } 1242*47e07394SAndrew Turner return (0); 1243*47e07394SAndrew Turner } 1244*47e07394SAndrew Turner 1245*47e07394SAndrew Turner int 1246*47e07394SAndrew Turner vcpu_debugged(struct vcpu *vcpu) 1247*47e07394SAndrew Turner { 1248*47e07394SAndrew Turner 1249*47e07394SAndrew Turner return (CPU_ISSET(vcpu->vcpuid, &vcpu->vm->debug_cpus)); 1250*47e07394SAndrew Turner } 1251*47e07394SAndrew Turner 1252*47e07394SAndrew Turner cpuset_t 1253*47e07394SAndrew Turner vm_active_cpus(struct vm *vm) 1254*47e07394SAndrew Turner { 1255*47e07394SAndrew Turner 1256*47e07394SAndrew Turner return (vm->active_cpus); 1257*47e07394SAndrew Turner } 1258*47e07394SAndrew Turner 1259*47e07394SAndrew Turner cpuset_t 1260*47e07394SAndrew Turner vm_debug_cpus(struct vm *vm) 1261*47e07394SAndrew Turner { 1262*47e07394SAndrew Turner 1263*47e07394SAndrew Turner return (vm->debug_cpus); 1264*47e07394SAndrew Turner } 1265*47e07394SAndrew Turner 1266*47e07394SAndrew Turner cpuset_t 1267*47e07394SAndrew Turner vm_suspended_cpus(struct vm *vm) 1268*47e07394SAndrew Turner { 1269*47e07394SAndrew Turner 1270*47e07394SAndrew Turner return (vm->suspended_cpus); 1271*47e07394SAndrew Turner } 1272*47e07394SAndrew Turner 1273*47e07394SAndrew Turner 1274*47e07394SAndrew Turner void * 1275*47e07394SAndrew Turner vcpu_stats(struct vcpu *vcpu) 1276*47e07394SAndrew Turner { 1277*47e07394SAndrew Turner 1278*47e07394SAndrew Turner return (vcpu->stats); 1279*47e07394SAndrew Turner } 1280*47e07394SAndrew Turner 1281*47e07394SAndrew Turner /* 1282*47e07394SAndrew Turner * This function is called to ensure that a vcpu "sees" a pending event 1283*47e07394SAndrew Turner * as soon as possible: 1284*47e07394SAndrew Turner * - If the vcpu thread is sleeping then it is woken up. 1285*47e07394SAndrew Turner * - If the vcpu is running on a different host_cpu then an IPI will be directed 1286*47e07394SAndrew Turner * to the host_cpu to cause the vcpu to trap into the hypervisor. 1287*47e07394SAndrew Turner */ 1288*47e07394SAndrew Turner static void 1289*47e07394SAndrew Turner vcpu_notify_event_locked(struct vcpu *vcpu) 1290*47e07394SAndrew Turner { 1291*47e07394SAndrew Turner int hostcpu; 1292*47e07394SAndrew Turner 1293*47e07394SAndrew Turner hostcpu = vcpu->hostcpu; 1294*47e07394SAndrew Turner if (vcpu->state == VCPU_RUNNING) { 1295*47e07394SAndrew Turner KASSERT(hostcpu != NOCPU, ("vcpu running on invalid hostcpu")); 1296*47e07394SAndrew Turner if (hostcpu != curcpu) { 1297*47e07394SAndrew Turner ipi_cpu(hostcpu, vmm_ipinum); 1298*47e07394SAndrew Turner } else { 1299*47e07394SAndrew Turner /* 1300*47e07394SAndrew Turner * If the 'vcpu' is running on 'curcpu' then it must 1301*47e07394SAndrew Turner * be sending a notification to itself (e.g. SELF_IPI). 1302*47e07394SAndrew Turner * The pending event will be picked up when the vcpu 1303*47e07394SAndrew Turner * transitions back to guest context. 1304*47e07394SAndrew Turner */ 1305*47e07394SAndrew Turner } 1306*47e07394SAndrew Turner } else { 1307*47e07394SAndrew Turner KASSERT(hostcpu == NOCPU, ("vcpu state %d not consistent " 1308*47e07394SAndrew Turner "with hostcpu %d", vcpu->state, hostcpu)); 1309*47e07394SAndrew Turner if (vcpu->state == VCPU_SLEEPING) 1310*47e07394SAndrew Turner wakeup_one(vcpu); 1311*47e07394SAndrew Turner } 1312*47e07394SAndrew Turner } 1313*47e07394SAndrew Turner 1314*47e07394SAndrew Turner void 1315*47e07394SAndrew Turner vcpu_notify_event(struct vcpu *vcpu) 1316*47e07394SAndrew Turner { 1317*47e07394SAndrew Turner vcpu_lock(vcpu); 1318*47e07394SAndrew Turner vcpu_notify_event_locked(vcpu); 1319*47e07394SAndrew Turner vcpu_unlock(vcpu); 1320*47e07394SAndrew Turner } 1321*47e07394SAndrew Turner 1322*47e07394SAndrew Turner static void 1323*47e07394SAndrew Turner restore_guest_fpustate(struct vcpu *vcpu) 1324*47e07394SAndrew Turner { 1325*47e07394SAndrew Turner 1326*47e07394SAndrew Turner /* flush host state to the pcb */ 1327*47e07394SAndrew Turner vfp_save_state(curthread, curthread->td_pcb); 1328*47e07394SAndrew Turner /* Ensure the VFP state will be re-loaded when exiting the guest */ 1329*47e07394SAndrew Turner PCPU_SET(fpcurthread, NULL); 1330*47e07394SAndrew Turner 1331*47e07394SAndrew Turner /* restore guest FPU state */ 1332*47e07394SAndrew Turner vfp_enable(); 1333*47e07394SAndrew Turner vfp_restore(vcpu->guestfpu); 1334*47e07394SAndrew Turner 1335*47e07394SAndrew Turner /* 1336*47e07394SAndrew Turner * The FPU is now "dirty" with the guest's state so turn on emulation 1337*47e07394SAndrew Turner * to trap any access to the FPU by the host. 1338*47e07394SAndrew Turner */ 1339*47e07394SAndrew Turner vfp_disable(); 1340*47e07394SAndrew Turner } 1341*47e07394SAndrew Turner 1342*47e07394SAndrew Turner static void 1343*47e07394SAndrew Turner save_guest_fpustate(struct vcpu *vcpu) 1344*47e07394SAndrew Turner { 1345*47e07394SAndrew Turner if ((READ_SPECIALREG(cpacr_el1) & CPACR_FPEN_MASK) != 1346*47e07394SAndrew Turner CPACR_FPEN_TRAP_ALL1) 1347*47e07394SAndrew Turner panic("VFP not enabled in host!"); 1348*47e07394SAndrew Turner 1349*47e07394SAndrew Turner /* save guest FPU state */ 1350*47e07394SAndrew Turner vfp_enable(); 1351*47e07394SAndrew Turner vfp_store(vcpu->guestfpu); 1352*47e07394SAndrew Turner vfp_disable(); 1353*47e07394SAndrew Turner 1354*47e07394SAndrew Turner KASSERT(PCPU_GET(fpcurthread) == NULL, 1355*47e07394SAndrew Turner ("%s: fpcurthread set with guest registers", __func__)); 1356*47e07394SAndrew Turner } 1357*47e07394SAndrew Turner static int 1358*47e07394SAndrew Turner vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, 1359*47e07394SAndrew Turner bool from_idle) 1360*47e07394SAndrew Turner { 1361*47e07394SAndrew Turner int error; 1362*47e07394SAndrew Turner 1363*47e07394SAndrew Turner vcpu_assert_locked(vcpu); 1364*47e07394SAndrew Turner 1365*47e07394SAndrew Turner /* 1366*47e07394SAndrew Turner * State transitions from the vmmdev_ioctl() must always begin from 1367*47e07394SAndrew Turner * the VCPU_IDLE state. This guarantees that there is only a single 1368*47e07394SAndrew Turner * ioctl() operating on a vcpu at any point. 1369*47e07394SAndrew Turner */ 1370*47e07394SAndrew Turner if (from_idle) { 1371*47e07394SAndrew Turner while (vcpu->state != VCPU_IDLE) { 1372*47e07394SAndrew Turner vcpu_notify_event_locked(vcpu); 1373*47e07394SAndrew Turner msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); 1374*47e07394SAndrew Turner } 1375*47e07394SAndrew Turner } else { 1376*47e07394SAndrew Turner KASSERT(vcpu->state != VCPU_IDLE, ("invalid transition from " 1377*47e07394SAndrew Turner "vcpu idle state")); 1378*47e07394SAndrew Turner } 1379*47e07394SAndrew Turner 1380*47e07394SAndrew Turner if (vcpu->state == VCPU_RUNNING) { 1381*47e07394SAndrew Turner KASSERT(vcpu->hostcpu == curcpu, ("curcpu %d and hostcpu %d " 1382*47e07394SAndrew Turner "mismatch for running vcpu", curcpu, vcpu->hostcpu)); 1383*47e07394SAndrew Turner } else { 1384*47e07394SAndrew Turner KASSERT(vcpu->hostcpu == NOCPU, ("Invalid hostcpu %d for a " 1385*47e07394SAndrew Turner "vcpu that is not running", vcpu->hostcpu)); 1386*47e07394SAndrew Turner } 1387*47e07394SAndrew Turner 1388*47e07394SAndrew Turner /* 1389*47e07394SAndrew Turner * The following state transitions are allowed: 1390*47e07394SAndrew Turner * IDLE -> FROZEN -> IDLE 1391*47e07394SAndrew Turner * FROZEN -> RUNNING -> FROZEN 1392*47e07394SAndrew Turner * FROZEN -> SLEEPING -> FROZEN 1393*47e07394SAndrew Turner */ 1394*47e07394SAndrew Turner switch (vcpu->state) { 1395*47e07394SAndrew Turner case VCPU_IDLE: 1396*47e07394SAndrew Turner case VCPU_RUNNING: 1397*47e07394SAndrew Turner case VCPU_SLEEPING: 1398*47e07394SAndrew Turner error = (newstate != VCPU_FROZEN); 1399*47e07394SAndrew Turner break; 1400*47e07394SAndrew Turner case VCPU_FROZEN: 1401*47e07394SAndrew Turner error = (newstate == VCPU_FROZEN); 1402*47e07394SAndrew Turner break; 1403*47e07394SAndrew Turner default: 1404*47e07394SAndrew Turner error = 1; 1405*47e07394SAndrew Turner break; 1406*47e07394SAndrew Turner } 1407*47e07394SAndrew Turner 1408*47e07394SAndrew Turner if (error) 1409*47e07394SAndrew Turner return (EBUSY); 1410*47e07394SAndrew Turner 1411*47e07394SAndrew Turner vcpu->state = newstate; 1412*47e07394SAndrew Turner if (newstate == VCPU_RUNNING) 1413*47e07394SAndrew Turner vcpu->hostcpu = curcpu; 1414*47e07394SAndrew Turner else 1415*47e07394SAndrew Turner vcpu->hostcpu = NOCPU; 1416*47e07394SAndrew Turner 1417*47e07394SAndrew Turner if (newstate == VCPU_IDLE) 1418*47e07394SAndrew Turner wakeup(&vcpu->state); 1419*47e07394SAndrew Turner 1420*47e07394SAndrew Turner return (0); 1421*47e07394SAndrew Turner } 1422*47e07394SAndrew Turner 1423*47e07394SAndrew Turner static void 1424*47e07394SAndrew Turner vcpu_require_state(struct vcpu *vcpu, enum vcpu_state newstate) 1425*47e07394SAndrew Turner { 1426*47e07394SAndrew Turner int error; 1427*47e07394SAndrew Turner 1428*47e07394SAndrew Turner if ((error = vcpu_set_state(vcpu, newstate, false)) != 0) 1429*47e07394SAndrew Turner panic("Error %d setting state to %d\n", error, newstate); 1430*47e07394SAndrew Turner } 1431*47e07394SAndrew Turner 1432*47e07394SAndrew Turner static void 1433*47e07394SAndrew Turner vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) 1434*47e07394SAndrew Turner { 1435*47e07394SAndrew Turner int error; 1436*47e07394SAndrew Turner 1437*47e07394SAndrew Turner if ((error = vcpu_set_state_locked(vcpu, newstate, false)) != 0) 1438*47e07394SAndrew Turner panic("Error %d setting state to %d", error, newstate); 1439*47e07394SAndrew Turner } 1440*47e07394SAndrew Turner 1441*47e07394SAndrew Turner int 1442*47e07394SAndrew Turner vm_get_capability(struct vcpu *vcpu, int type, int *retval) 1443*47e07394SAndrew Turner { 1444*47e07394SAndrew Turner if (type < 0 || type >= VM_CAP_MAX) 1445*47e07394SAndrew Turner return (EINVAL); 1446*47e07394SAndrew Turner 1447*47e07394SAndrew Turner return (vmmops_getcap(vcpu->cookie, type, retval)); 1448*47e07394SAndrew Turner } 1449*47e07394SAndrew Turner 1450*47e07394SAndrew Turner int 1451*47e07394SAndrew Turner vm_set_capability(struct vcpu *vcpu, int type, int val) 1452*47e07394SAndrew Turner { 1453*47e07394SAndrew Turner if (type < 0 || type >= VM_CAP_MAX) 1454*47e07394SAndrew Turner return (EINVAL); 1455*47e07394SAndrew Turner 1456*47e07394SAndrew Turner return (vmmops_setcap(vcpu->cookie, type, val)); 1457*47e07394SAndrew Turner } 1458*47e07394SAndrew Turner 1459*47e07394SAndrew Turner struct vm * 1460*47e07394SAndrew Turner vcpu_vm(struct vcpu *vcpu) 1461*47e07394SAndrew Turner { 1462*47e07394SAndrew Turner return (vcpu->vm); 1463*47e07394SAndrew Turner } 1464*47e07394SAndrew Turner 1465*47e07394SAndrew Turner int 1466*47e07394SAndrew Turner vcpu_vcpuid(struct vcpu *vcpu) 1467*47e07394SAndrew Turner { 1468*47e07394SAndrew Turner return (vcpu->vcpuid); 1469*47e07394SAndrew Turner } 1470*47e07394SAndrew Turner 1471*47e07394SAndrew Turner void * 1472*47e07394SAndrew Turner vcpu_get_cookie(struct vcpu *vcpu) 1473*47e07394SAndrew Turner { 1474*47e07394SAndrew Turner return (vcpu->cookie); 1475*47e07394SAndrew Turner } 1476*47e07394SAndrew Turner 1477*47e07394SAndrew Turner struct vcpu * 1478*47e07394SAndrew Turner vm_vcpu(struct vm *vm, int vcpuid) 1479*47e07394SAndrew Turner { 1480*47e07394SAndrew Turner return (vm->vcpu[vcpuid]); 1481*47e07394SAndrew Turner } 1482*47e07394SAndrew Turner 1483*47e07394SAndrew Turner int 1484*47e07394SAndrew Turner vcpu_set_state(struct vcpu *vcpu, enum vcpu_state newstate, bool from_idle) 1485*47e07394SAndrew Turner { 1486*47e07394SAndrew Turner int error; 1487*47e07394SAndrew Turner 1488*47e07394SAndrew Turner vcpu_lock(vcpu); 1489*47e07394SAndrew Turner error = vcpu_set_state_locked(vcpu, newstate, from_idle); 1490*47e07394SAndrew Turner vcpu_unlock(vcpu); 1491*47e07394SAndrew Turner 1492*47e07394SAndrew Turner return (error); 1493*47e07394SAndrew Turner } 1494*47e07394SAndrew Turner 1495*47e07394SAndrew Turner enum vcpu_state 1496*47e07394SAndrew Turner vcpu_get_state(struct vcpu *vcpu, int *hostcpu) 1497*47e07394SAndrew Turner { 1498*47e07394SAndrew Turner enum vcpu_state state; 1499*47e07394SAndrew Turner 1500*47e07394SAndrew Turner vcpu_lock(vcpu); 1501*47e07394SAndrew Turner state = vcpu->state; 1502*47e07394SAndrew Turner if (hostcpu != NULL) 1503*47e07394SAndrew Turner *hostcpu = vcpu->hostcpu; 1504*47e07394SAndrew Turner vcpu_unlock(vcpu); 1505*47e07394SAndrew Turner 1506*47e07394SAndrew Turner return (state); 1507*47e07394SAndrew Turner } 1508*47e07394SAndrew Turner 1509*47e07394SAndrew Turner static void * 1510*47e07394SAndrew Turner _vm_gpa_hold(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, 1511*47e07394SAndrew Turner void **cookie) 1512*47e07394SAndrew Turner { 1513*47e07394SAndrew Turner int i, count, pageoff; 1514*47e07394SAndrew Turner struct mem_map *mm; 1515*47e07394SAndrew Turner vm_page_t m; 1516*47e07394SAndrew Turner 1517*47e07394SAndrew Turner pageoff = gpa & PAGE_MASK; 1518*47e07394SAndrew Turner if (len > PAGE_SIZE - pageoff) 1519*47e07394SAndrew Turner panic("vm_gpa_hold: invalid gpa/len: 0x%016lx/%lu", gpa, len); 1520*47e07394SAndrew Turner 1521*47e07394SAndrew Turner count = 0; 1522*47e07394SAndrew Turner for (i = 0; i < VM_MAX_MEMMAPS; i++) { 1523*47e07394SAndrew Turner mm = &vm->mem_maps[i]; 1524*47e07394SAndrew Turner if (sysmem_mapping(vm, mm) && gpa >= mm->gpa && 1525*47e07394SAndrew Turner gpa < mm->gpa + mm->len) { 1526*47e07394SAndrew Turner count = vm_fault_quick_hold_pages(&vm->vmspace->vm_map, 1527*47e07394SAndrew Turner trunc_page(gpa), PAGE_SIZE, reqprot, &m, 1); 1528*47e07394SAndrew Turner break; 1529*47e07394SAndrew Turner } 1530*47e07394SAndrew Turner } 1531*47e07394SAndrew Turner 1532*47e07394SAndrew Turner if (count == 1) { 1533*47e07394SAndrew Turner *cookie = m; 1534*47e07394SAndrew Turner return ((void *)(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)) + pageoff)); 1535*47e07394SAndrew Turner } else { 1536*47e07394SAndrew Turner *cookie = NULL; 1537*47e07394SAndrew Turner return (NULL); 1538*47e07394SAndrew Turner } 1539*47e07394SAndrew Turner } 1540*47e07394SAndrew Turner 1541*47e07394SAndrew Turner void * 1542*47e07394SAndrew Turner vm_gpa_hold(struct vcpu *vcpu, vm_paddr_t gpa, size_t len, int reqprot, 1543*47e07394SAndrew Turner void **cookie) 1544*47e07394SAndrew Turner { 1545*47e07394SAndrew Turner #ifdef INVARIANTS 1546*47e07394SAndrew Turner /* 1547*47e07394SAndrew Turner * The current vcpu should be frozen to ensure 'vm_memmap[]' 1548*47e07394SAndrew Turner * stability. 1549*47e07394SAndrew Turner */ 1550*47e07394SAndrew Turner int state = vcpu_get_state(vcpu, NULL); 1551*47e07394SAndrew Turner KASSERT(state == VCPU_FROZEN, ("%s: invalid vcpu state %d", 1552*47e07394SAndrew Turner __func__, state)); 1553*47e07394SAndrew Turner #endif 1554*47e07394SAndrew Turner return (_vm_gpa_hold(vcpu->vm, gpa, len, reqprot, cookie)); 1555*47e07394SAndrew Turner } 1556*47e07394SAndrew Turner 1557*47e07394SAndrew Turner void * 1558*47e07394SAndrew Turner vm_gpa_hold_global(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot, 1559*47e07394SAndrew Turner void **cookie) 1560*47e07394SAndrew Turner { 1561*47e07394SAndrew Turner sx_assert(&vm->mem_segs_lock, SX_LOCKED); 1562*47e07394SAndrew Turner return (_vm_gpa_hold(vm, gpa, len, reqprot, cookie)); 1563*47e07394SAndrew Turner } 1564*47e07394SAndrew Turner 1565*47e07394SAndrew Turner void 1566*47e07394SAndrew Turner vm_gpa_release(void *cookie) 1567*47e07394SAndrew Turner { 1568*47e07394SAndrew Turner vm_page_t m = cookie; 1569*47e07394SAndrew Turner 1570*47e07394SAndrew Turner vm_page_unwire(m, PQ_ACTIVE); 1571*47e07394SAndrew Turner } 1572*47e07394SAndrew Turner 1573*47e07394SAndrew Turner int 1574*47e07394SAndrew Turner vm_get_register(struct vcpu *vcpu, int reg, uint64_t *retval) 1575*47e07394SAndrew Turner { 1576*47e07394SAndrew Turner 1577*47e07394SAndrew Turner if (reg >= VM_REG_LAST) 1578*47e07394SAndrew Turner return (EINVAL); 1579*47e07394SAndrew Turner 1580*47e07394SAndrew Turner return (vmmops_getreg(vcpu->cookie, reg, retval)); 1581*47e07394SAndrew Turner } 1582*47e07394SAndrew Turner 1583*47e07394SAndrew Turner int 1584*47e07394SAndrew Turner vm_set_register(struct vcpu *vcpu, int reg, uint64_t val) 1585*47e07394SAndrew Turner { 1586*47e07394SAndrew Turner int error; 1587*47e07394SAndrew Turner 1588*47e07394SAndrew Turner if (reg >= VM_REG_LAST) 1589*47e07394SAndrew Turner return (EINVAL); 1590*47e07394SAndrew Turner error = vmmops_setreg(vcpu->cookie, reg, val); 1591*47e07394SAndrew Turner if (error || reg != VM_REG_GUEST_PC) 1592*47e07394SAndrew Turner return (error); 1593*47e07394SAndrew Turner 1594*47e07394SAndrew Turner vcpu->nextpc = val; 1595*47e07394SAndrew Turner 1596*47e07394SAndrew Turner return (0); 1597*47e07394SAndrew Turner } 1598*47e07394SAndrew Turner 1599*47e07394SAndrew Turner void * 1600*47e07394SAndrew Turner vm_get_cookie(struct vm *vm) 1601*47e07394SAndrew Turner { 1602*47e07394SAndrew Turner return (vm->cookie); 1603*47e07394SAndrew Turner } 1604*47e07394SAndrew Turner 1605*47e07394SAndrew Turner int 1606*47e07394SAndrew Turner vm_inject_exception(struct vcpu *vcpu, uint64_t esr, uint64_t far) 1607*47e07394SAndrew Turner { 1608*47e07394SAndrew Turner return (vmmops_exception(vcpu->cookie, esr, far)); 1609*47e07394SAndrew Turner } 1610*47e07394SAndrew Turner 1611*47e07394SAndrew Turner int 1612*47e07394SAndrew Turner vm_attach_vgic(struct vm *vm, struct vm_vgic_descr *descr) 1613*47e07394SAndrew Turner { 1614*47e07394SAndrew Turner return (vgic_attach_to_vm(vm->cookie, descr)); 1615*47e07394SAndrew Turner } 1616*47e07394SAndrew Turner 1617*47e07394SAndrew Turner int 1618*47e07394SAndrew Turner vm_assert_irq(struct vm *vm, uint32_t irq) 1619*47e07394SAndrew Turner { 1620*47e07394SAndrew Turner return (vgic_inject_irq(vm->cookie, -1, irq, true)); 1621*47e07394SAndrew Turner } 1622*47e07394SAndrew Turner 1623*47e07394SAndrew Turner int 1624*47e07394SAndrew Turner vm_deassert_irq(struct vm *vm, uint32_t irq) 1625*47e07394SAndrew Turner { 1626*47e07394SAndrew Turner return (vgic_inject_irq(vm->cookie, -1, irq, false)); 1627*47e07394SAndrew Turner } 1628*47e07394SAndrew Turner 1629*47e07394SAndrew Turner int 1630*47e07394SAndrew Turner vm_raise_msi(struct vm *vm, uint64_t msg, uint64_t addr, int bus, int slot, 1631*47e07394SAndrew Turner int func) 1632*47e07394SAndrew Turner { 1633*47e07394SAndrew Turner /* TODO: Should we raise an SError? */ 1634*47e07394SAndrew Turner return (vgic_inject_msi(vm->cookie, msg, addr)); 1635*47e07394SAndrew Turner } 1636*47e07394SAndrew Turner 1637*47e07394SAndrew Turner static int 1638*47e07394SAndrew Turner vm_handle_smccc_call(struct vcpu *vcpu, struct vm_exit *vme, bool *retu) 1639*47e07394SAndrew Turner { 1640*47e07394SAndrew Turner struct hypctx *hypctx; 1641*47e07394SAndrew Turner int i; 1642*47e07394SAndrew Turner 1643*47e07394SAndrew Turner hypctx = vcpu_get_cookie(vcpu); 1644*47e07394SAndrew Turner 1645*47e07394SAndrew Turner if ((hypctx->tf.tf_esr & ESR_ELx_ISS_MASK) != 0) 1646*47e07394SAndrew Turner return (1); 1647*47e07394SAndrew Turner 1648*47e07394SAndrew Turner vme->exitcode = VM_EXITCODE_SMCCC; 1649*47e07394SAndrew Turner vme->u.smccc_call.func_id = hypctx->tf.tf_x[0]; 1650*47e07394SAndrew Turner for (i = 0; i < nitems(vme->u.smccc_call.args); i++) 1651*47e07394SAndrew Turner vme->u.smccc_call.args[i] = hypctx->tf.tf_x[i + 1]; 1652*47e07394SAndrew Turner 1653*47e07394SAndrew Turner *retu = true; 1654*47e07394SAndrew Turner return (0); 1655*47e07394SAndrew Turner } 1656*47e07394SAndrew Turner 1657*47e07394SAndrew Turner static int 1658*47e07394SAndrew Turner vm_handle_wfi(struct vcpu *vcpu, struct vm_exit *vme, bool *retu) 1659*47e07394SAndrew Turner { 1660*47e07394SAndrew Turner vcpu_lock(vcpu); 1661*47e07394SAndrew Turner while (1) { 1662*47e07394SAndrew Turner if (vgic_has_pending_irq(vcpu->cookie)) 1663*47e07394SAndrew Turner break; 1664*47e07394SAndrew Turner 1665*47e07394SAndrew Turner if (vcpu_should_yield(vcpu)) 1666*47e07394SAndrew Turner break; 1667*47e07394SAndrew Turner 1668*47e07394SAndrew Turner vcpu_require_state_locked(vcpu, VCPU_SLEEPING); 1669*47e07394SAndrew Turner /* 1670*47e07394SAndrew Turner * XXX msleep_spin() cannot be interrupted by signals so 1671*47e07394SAndrew Turner * wake up periodically to check pending signals. 1672*47e07394SAndrew Turner */ 1673*47e07394SAndrew Turner msleep_spin(vcpu, &vcpu->mtx, "vmidle", hz); 1674*47e07394SAndrew Turner vcpu_require_state_locked(vcpu, VCPU_FROZEN); 1675*47e07394SAndrew Turner } 1676*47e07394SAndrew Turner vcpu_unlock(vcpu); 1677*47e07394SAndrew Turner 1678*47e07394SAndrew Turner *retu = false; 1679*47e07394SAndrew Turner return (0); 1680*47e07394SAndrew Turner } 1681*47e07394SAndrew Turner 1682*47e07394SAndrew Turner static int 1683*47e07394SAndrew Turner vm_handle_paging(struct vcpu *vcpu, bool *retu) 1684*47e07394SAndrew Turner { 1685*47e07394SAndrew Turner struct vm *vm = vcpu->vm; 1686*47e07394SAndrew Turner struct vm_exit *vme; 1687*47e07394SAndrew Turner struct vm_map *map; 1688*47e07394SAndrew Turner uint64_t addr, esr; 1689*47e07394SAndrew Turner pmap_t pmap; 1690*47e07394SAndrew Turner int ftype, rv; 1691*47e07394SAndrew Turner 1692*47e07394SAndrew Turner vme = &vcpu->exitinfo; 1693*47e07394SAndrew Turner 1694*47e07394SAndrew Turner pmap = vmspace_pmap(vcpu->vm->vmspace); 1695*47e07394SAndrew Turner addr = vme->u.paging.gpa; 1696*47e07394SAndrew Turner esr = vme->u.paging.esr; 1697*47e07394SAndrew Turner 1698*47e07394SAndrew Turner /* The page exists, but the page table needs to be updated. */ 1699*47e07394SAndrew Turner if (pmap_fault(pmap, esr, addr) == KERN_SUCCESS) 1700*47e07394SAndrew Turner return (0); 1701*47e07394SAndrew Turner 1702*47e07394SAndrew Turner switch (ESR_ELx_EXCEPTION(esr)) { 1703*47e07394SAndrew Turner case EXCP_INSN_ABORT_L: 1704*47e07394SAndrew Turner case EXCP_DATA_ABORT_L: 1705*47e07394SAndrew Turner ftype = VM_PROT_EXECUTE | VM_PROT_READ | VM_PROT_WRITE; 1706*47e07394SAndrew Turner break; 1707*47e07394SAndrew Turner default: 1708*47e07394SAndrew Turner panic("%s: Invalid exception (esr = %lx)", __func__, esr); 1709*47e07394SAndrew Turner } 1710*47e07394SAndrew Turner 1711*47e07394SAndrew Turner map = &vm->vmspace->vm_map; 1712*47e07394SAndrew Turner rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL, NULL); 1713*47e07394SAndrew Turner if (rv != KERN_SUCCESS) 1714*47e07394SAndrew Turner return (EFAULT); 1715*47e07394SAndrew Turner 1716*47e07394SAndrew Turner return (0); 1717*47e07394SAndrew Turner } 1718*47e07394SAndrew Turner 1719*47e07394SAndrew Turner int 1720*47e07394SAndrew Turner vm_run(struct vcpu *vcpu) 1721*47e07394SAndrew Turner { 1722*47e07394SAndrew Turner struct vm *vm = vcpu->vm; 1723*47e07394SAndrew Turner struct vm_eventinfo evinfo; 1724*47e07394SAndrew Turner int error, vcpuid; 1725*47e07394SAndrew Turner struct vm_exit *vme; 1726*47e07394SAndrew Turner bool retu; 1727*47e07394SAndrew Turner pmap_t pmap; 1728*47e07394SAndrew Turner 1729*47e07394SAndrew Turner vcpuid = vcpu->vcpuid; 1730*47e07394SAndrew Turner 1731*47e07394SAndrew Turner if (!CPU_ISSET(vcpuid, &vm->active_cpus)) 1732*47e07394SAndrew Turner return (EINVAL); 1733*47e07394SAndrew Turner 1734*47e07394SAndrew Turner if (CPU_ISSET(vcpuid, &vm->suspended_cpus)) 1735*47e07394SAndrew Turner return (EINVAL); 1736*47e07394SAndrew Turner 1737*47e07394SAndrew Turner pmap = vmspace_pmap(vm->vmspace); 1738*47e07394SAndrew Turner vme = &vcpu->exitinfo; 1739*47e07394SAndrew Turner evinfo.rptr = NULL; 1740*47e07394SAndrew Turner evinfo.sptr = &vm->suspend; 1741*47e07394SAndrew Turner evinfo.iptr = NULL; 1742*47e07394SAndrew Turner restart: 1743*47e07394SAndrew Turner critical_enter(); 1744*47e07394SAndrew Turner 1745*47e07394SAndrew Turner restore_guest_fpustate(vcpu); 1746*47e07394SAndrew Turner 1747*47e07394SAndrew Turner vcpu_require_state(vcpu, VCPU_RUNNING); 1748*47e07394SAndrew Turner error = vmmops_run(vcpu->cookie, vcpu->nextpc, pmap, &evinfo); 1749*47e07394SAndrew Turner vcpu_require_state(vcpu, VCPU_FROZEN); 1750*47e07394SAndrew Turner 1751*47e07394SAndrew Turner save_guest_fpustate(vcpu); 1752*47e07394SAndrew Turner 1753*47e07394SAndrew Turner critical_exit(); 1754*47e07394SAndrew Turner 1755*47e07394SAndrew Turner if (error == 0) { 1756*47e07394SAndrew Turner retu = false; 1757*47e07394SAndrew Turner switch (vme->exitcode) { 1758*47e07394SAndrew Turner case VM_EXITCODE_INST_EMUL: 1759*47e07394SAndrew Turner vcpu->nextpc = vme->pc + vme->inst_length; 1760*47e07394SAndrew Turner error = vm_handle_inst_emul(vcpu, &retu); 1761*47e07394SAndrew Turner break; 1762*47e07394SAndrew Turner 1763*47e07394SAndrew Turner case VM_EXITCODE_REG_EMUL: 1764*47e07394SAndrew Turner vcpu->nextpc = vme->pc + vme->inst_length; 1765*47e07394SAndrew Turner error = vm_handle_reg_emul(vcpu, &retu); 1766*47e07394SAndrew Turner break; 1767*47e07394SAndrew Turner 1768*47e07394SAndrew Turner case VM_EXITCODE_HVC: 1769*47e07394SAndrew Turner /* 1770*47e07394SAndrew Turner * The HVC instruction saves the address for the 1771*47e07394SAndrew Turner * next instruction as the return address. 1772*47e07394SAndrew Turner */ 1773*47e07394SAndrew Turner vcpu->nextpc = vme->pc; 1774*47e07394SAndrew Turner /* 1775*47e07394SAndrew Turner * The PSCI call can change the exit information in the 1776*47e07394SAndrew Turner * case of suspend/reset/poweroff/cpu off/cpu on. 1777*47e07394SAndrew Turner */ 1778*47e07394SAndrew Turner error = vm_handle_smccc_call(vcpu, vme, &retu); 1779*47e07394SAndrew Turner break; 1780*47e07394SAndrew Turner 1781*47e07394SAndrew Turner case VM_EXITCODE_WFI: 1782*47e07394SAndrew Turner vcpu->nextpc = vme->pc + vme->inst_length; 1783*47e07394SAndrew Turner error = vm_handle_wfi(vcpu, vme, &retu); 1784*47e07394SAndrew Turner break; 1785*47e07394SAndrew Turner 1786*47e07394SAndrew Turner case VM_EXITCODE_PAGING: 1787*47e07394SAndrew Turner vcpu->nextpc = vme->pc; 1788*47e07394SAndrew Turner error = vm_handle_paging(vcpu, &retu); 1789*47e07394SAndrew Turner break; 1790*47e07394SAndrew Turner 1791*47e07394SAndrew Turner default: 1792*47e07394SAndrew Turner /* Handle in userland */ 1793*47e07394SAndrew Turner vcpu->nextpc = vme->pc; 1794*47e07394SAndrew Turner retu = true; 1795*47e07394SAndrew Turner break; 1796*47e07394SAndrew Turner } 1797*47e07394SAndrew Turner } 1798*47e07394SAndrew Turner 1799*47e07394SAndrew Turner if (error == 0 && retu == false) 1800*47e07394SAndrew Turner goto restart; 1801*47e07394SAndrew Turner 1802*47e07394SAndrew Turner return (error); 1803*47e07394SAndrew Turner } 1804