1366f6083SPeter Grehan /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 35e53a4f9SPedro 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 2995ebc360SNeel Natu #include <sys/param.h> 303e9b4532SMark Johnston #include <sys/capsicum.h> 31366f6083SPeter Grehan #include <sys/sysctl.h> 32366f6083SPeter Grehan #include <sys/ioctl.h> 33366f6083SPeter Grehan #include <sys/mman.h> 34967264cfSMark Johnston #include <sys/linker.h> 35a71dc724SMarcelo Araujo #include <sys/module.h> 366303b65dSNeel Natu #include <sys/_iovec.h> 3795ebc360SNeel Natu #include <sys/cpuset.h> 38366f6083SPeter Grehan 393e9b4532SMark Johnston #include <capsicum_helpers.h> 409c4d5478SNeel Natu #include <errno.h> 41483d953aSJohn Baldwin #include <stdbool.h> 42366f6083SPeter Grehan #include <stdio.h> 43366f6083SPeter Grehan #include <stdlib.h> 44366f6083SPeter Grehan #include <assert.h> 45366f6083SPeter Grehan #include <string.h> 46366f6083SPeter Grehan #include <fcntl.h> 47366f6083SPeter Grehan #include <unistd.h> 48366f6083SPeter Grehan 49200758f1SNeel Natu #include <libutil.h> 50200758f1SNeel Natu 51483d953aSJohn Baldwin #include <vm/vm.h> 52366f6083SPeter Grehan #include <machine/vmm.h> 53366f6083SPeter Grehan #include <machine/vmm_dev.h> 54*56a26fc1SMark Johnston #ifdef WITH_VMMAPI_SNAPSHOT 55483d953aSJohn Baldwin #include <machine/vmm_snapshot.h> 56*56a26fc1SMark Johnston #endif 57366f6083SPeter Grehan 58366f6083SPeter Grehan #include "vmmapi.h" 597d9ef309SJohn Baldwin #include "internal.h" 60366f6083SPeter Grehan 61200758f1SNeel Natu #define MB (1024 * 1024UL) 62b060ba50SNeel Natu #define GB (1024 * 1024 * 1024UL) 63b060ba50SNeel Natu 645ec6c300SMark Johnston #ifdef __amd64__ 657e0fa794SMark Johnston #define VM_LOWMEM_LIMIT (3 * GB) 665ec6c300SMark Johnston #else 675ec6c300SMark Johnston #define VM_LOWMEM_LIMIT 0 685ec6c300SMark Johnston #endif 697e0fa794SMark Johnston #define VM_HIGHMEM_BASE (4 * GB) 707e0fa794SMark Johnston 719b1aa8d6SNeel Natu /* 729b1aa8d6SNeel Natu * Size of the guard region before and after the virtual address space 739b1aa8d6SNeel Natu * mapping the guest physical memory. This must be a multiple of the 749b1aa8d6SNeel Natu * superpage size for performance reasons. 759b1aa8d6SNeel Natu */ 769b1aa8d6SNeel Natu #define VM_MMAP_GUARD_SIZE (4 * MB) 779b1aa8d6SNeel Natu 789b1aa8d6SNeel Natu #define PROT_RW (PROT_READ | PROT_WRITE) 799b1aa8d6SNeel Natu #define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC) 809b1aa8d6SNeel Natu 81366f6083SPeter Grehan #define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x))) 82366f6083SPeter Grehan #define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x))) 83366f6083SPeter Grehan 84366f6083SPeter Grehan static int 85366f6083SPeter Grehan vm_device_open(const char *name) 86366f6083SPeter Grehan { 87366f6083SPeter Grehan int fd, len; 88366f6083SPeter Grehan char *vmfile; 89366f6083SPeter Grehan 90366f6083SPeter Grehan len = strlen("/dev/vmm/") + strlen(name) + 1; 91366f6083SPeter Grehan vmfile = malloc(len); 92366f6083SPeter Grehan assert(vmfile != NULL); 93366f6083SPeter Grehan snprintf(vmfile, len, "/dev/vmm/%s", name); 94366f6083SPeter Grehan 95366f6083SPeter Grehan /* Open the device file */ 96366f6083SPeter Grehan fd = open(vmfile, O_RDWR, 0); 97366f6083SPeter Grehan 98366f6083SPeter Grehan free(vmfile); 99366f6083SPeter Grehan return (fd); 100366f6083SPeter Grehan } 101366f6083SPeter Grehan 102366f6083SPeter Grehan int 103366f6083SPeter Grehan vm_create(const char *name) 104366f6083SPeter Grehan { 105a71dc724SMarcelo Araujo /* Try to load vmm(4) module before creating a guest. */ 106a71dc724SMarcelo Araujo if (modfind("vmm") < 0) 107a71dc724SMarcelo Araujo kldload("vmm"); 10845cd18ecSMark Johnston return (CREATE(name)); 109366f6083SPeter Grehan } 110366f6083SPeter Grehan 111366f6083SPeter Grehan struct vmctx * 112366f6083SPeter Grehan vm_open(const char *name) 113366f6083SPeter Grehan { 114366f6083SPeter Grehan struct vmctx *vm; 115a7f81b48SRobert Wing int saved_errno; 116366f6083SPeter Grehan 117366f6083SPeter Grehan vm = malloc(sizeof(struct vmctx) + strlen(name) + 1); 118366f6083SPeter Grehan assert(vm != NULL); 119366f6083SPeter Grehan 120366f6083SPeter Grehan vm->fd = -1; 1210dd10c00SNeel Natu vm->memflags = 0; 122366f6083SPeter Grehan vm->name = (char *)(vm + 1); 123366f6083SPeter Grehan strcpy(vm->name, name); 1247e0fa794SMark Johnston memset(vm->memsegs, 0, sizeof(vm->memsegs)); 125366f6083SPeter Grehan 126366f6083SPeter Grehan if ((vm->fd = vm_device_open(vm->name)) < 0) 127366f6083SPeter Grehan goto err; 128366f6083SPeter Grehan 129366f6083SPeter Grehan return (vm); 130366f6083SPeter Grehan err: 131a7f81b48SRobert Wing saved_errno = errno; 1326bb140e3SRobert Wing free(vm); 133a7f81b48SRobert Wing errno = saved_errno; 134366f6083SPeter Grehan return (NULL); 135366f6083SPeter Grehan } 136366f6083SPeter Grehan 137366f6083SPeter Grehan void 138f0880ab7SVitaliy Gusev vm_close(struct vmctx *vm) 139f0880ab7SVitaliy Gusev { 140f0880ab7SVitaliy Gusev assert(vm != NULL); 141f0880ab7SVitaliy Gusev 142f0880ab7SVitaliy Gusev close(vm->fd); 143f0880ab7SVitaliy Gusev free(vm); 144f0880ab7SVitaliy Gusev } 145f0880ab7SVitaliy Gusev 146f0880ab7SVitaliy Gusev void 147366f6083SPeter Grehan vm_destroy(struct vmctx *vm) 148366f6083SPeter Grehan { 149366f6083SPeter Grehan assert(vm != NULL); 150366f6083SPeter Grehan 151366f6083SPeter Grehan if (vm->fd >= 0) 152366f6083SPeter Grehan close(vm->fd); 153f7d51510SNeel Natu DESTROY(vm->name); 154f7d51510SNeel Natu 155366f6083SPeter Grehan free(vm); 156366f6083SPeter Grehan } 157366f6083SPeter Grehan 1587d9ef309SJohn Baldwin struct vcpu * 1597d9ef309SJohn Baldwin vm_vcpu_open(struct vmctx *ctx, int vcpuid) 1607d9ef309SJohn Baldwin { 1617d9ef309SJohn Baldwin struct vcpu *vcpu; 1627d9ef309SJohn Baldwin 1637d9ef309SJohn Baldwin vcpu = malloc(sizeof(*vcpu)); 1647d9ef309SJohn Baldwin vcpu->ctx = ctx; 1657d9ef309SJohn Baldwin vcpu->vcpuid = vcpuid; 1667d9ef309SJohn Baldwin return (vcpu); 1677d9ef309SJohn Baldwin } 1687d9ef309SJohn Baldwin 1697d9ef309SJohn Baldwin void 1707d9ef309SJohn Baldwin vm_vcpu_close(struct vcpu *vcpu) 1717d9ef309SJohn Baldwin { 1727d9ef309SJohn Baldwin free(vcpu); 1737d9ef309SJohn Baldwin } 1747d9ef309SJohn Baldwin 1757d9ef309SJohn Baldwin int 1767d9ef309SJohn Baldwin vcpu_id(struct vcpu *vcpu) 1777d9ef309SJohn Baldwin { 1787d9ef309SJohn Baldwin return (vcpu->vcpuid); 1797d9ef309SJohn Baldwin } 1807d9ef309SJohn Baldwin 181366f6083SPeter Grehan int 18245cd18ecSMark Johnston vm_parse_memsize(const char *opt, size_t *ret_memsize) 183200758f1SNeel Natu { 184200758f1SNeel Natu char *endptr; 185200758f1SNeel Natu size_t optval; 186200758f1SNeel Natu int error; 187200758f1SNeel Natu 18845cd18ecSMark Johnston optval = strtoul(opt, &endptr, 0); 18945cd18ecSMark Johnston if (*opt != '\0' && *endptr == '\0') { 190200758f1SNeel Natu /* 191200758f1SNeel Natu * For the sake of backward compatibility if the memory size 192200758f1SNeel Natu * specified on the command line is less than a megabyte then 193200758f1SNeel Natu * it is interpreted as being in units of MB. 194200758f1SNeel Natu */ 195200758f1SNeel Natu if (optval < MB) 196200758f1SNeel Natu optval *= MB; 197200758f1SNeel Natu *ret_memsize = optval; 198200758f1SNeel Natu error = 0; 199200758f1SNeel Natu } else 20045cd18ecSMark Johnston error = expand_number(opt, ret_memsize); 201200758f1SNeel Natu 202200758f1SNeel Natu return (error); 203200758f1SNeel Natu } 204200758f1SNeel Natu 205b060ba50SNeel Natu uint32_t 2067e0fa794SMark Johnston vm_get_lowmem_limit(struct vmctx *ctx __unused) 207b060ba50SNeel Natu { 208b060ba50SNeel Natu 2097e0fa794SMark Johnston return (VM_LOWMEM_LIMIT); 210b060ba50SNeel Natu } 211b060ba50SNeel Natu 2120dd10c00SNeel Natu void 2130dd10c00SNeel Natu vm_set_memflags(struct vmctx *ctx, int flags) 2140dd10c00SNeel Natu { 2150dd10c00SNeel Natu 2160dd10c00SNeel Natu ctx->memflags = flags; 2170dd10c00SNeel Natu } 2180dd10c00SNeel Natu 2199b1aa8d6SNeel Natu int 2209b1aa8d6SNeel Natu vm_get_memflags(struct vmctx *ctx) 221366f6083SPeter Grehan { 2229b1aa8d6SNeel Natu 2239b1aa8d6SNeel Natu return (ctx->memflags); 2249b1aa8d6SNeel Natu } 225366f6083SPeter Grehan 226366f6083SPeter Grehan /* 2279b1aa8d6SNeel Natu * Map segment 'segid' starting at 'off' into guest address range [gpa,gpa+len). 228366f6083SPeter Grehan */ 2299b1aa8d6SNeel Natu int 2309b1aa8d6SNeel Natu vm_mmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, int segid, vm_ooffset_t off, 2319b1aa8d6SNeel Natu size_t len, int prot) 2329b1aa8d6SNeel Natu { 2339b1aa8d6SNeel Natu struct vm_memmap memmap; 2349b1aa8d6SNeel Natu int error, flags; 2359b1aa8d6SNeel Natu 2369b1aa8d6SNeel Natu memmap.gpa = gpa; 2379b1aa8d6SNeel Natu memmap.segid = segid; 2389b1aa8d6SNeel Natu memmap.segoff = off; 2399b1aa8d6SNeel Natu memmap.len = len; 2409b1aa8d6SNeel Natu memmap.prot = prot; 2419b1aa8d6SNeel Natu memmap.flags = 0; 2429b1aa8d6SNeel Natu 2439b1aa8d6SNeel Natu if (ctx->memflags & VM_MEM_F_WIRED) 2449b1aa8d6SNeel Natu memmap.flags |= VM_MEMMAP_F_WIRED; 2459b1aa8d6SNeel Natu 2469b1aa8d6SNeel Natu /* 2479b1aa8d6SNeel Natu * If this mapping already exists then don't create it again. This 2489b1aa8d6SNeel Natu * is the common case for SYSMEM mappings created by bhyveload(8). 2499b1aa8d6SNeel Natu */ 2509b1aa8d6SNeel Natu error = vm_mmap_getnext(ctx, &gpa, &segid, &off, &len, &prot, &flags); 2519b1aa8d6SNeel Natu if (error == 0 && gpa == memmap.gpa) { 2529b1aa8d6SNeel Natu if (segid != memmap.segid || off != memmap.segoff || 2539b1aa8d6SNeel Natu prot != memmap.prot || flags != memmap.flags) { 2549b1aa8d6SNeel Natu errno = EEXIST; 2559b1aa8d6SNeel Natu return (-1); 2569b1aa8d6SNeel Natu } else { 2579b1aa8d6SNeel Natu return (0); 2589b1aa8d6SNeel Natu } 2599b1aa8d6SNeel Natu } 2609b1aa8d6SNeel Natu 2619b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_MMAP_MEMSEG, &memmap); 2629b1aa8d6SNeel Natu return (error); 2639b1aa8d6SNeel Natu } 2649b1aa8d6SNeel Natu 2659b1aa8d6SNeel Natu int 266483d953aSJohn Baldwin vm_get_guestmem_from_ctx(struct vmctx *ctx, char **guest_baseaddr, 267483d953aSJohn Baldwin size_t *lowmem_size, size_t *highmem_size) 268483d953aSJohn Baldwin { 269483d953aSJohn Baldwin 270483d953aSJohn Baldwin *guest_baseaddr = ctx->baseaddr; 2717e0fa794SMark Johnston *lowmem_size = ctx->memsegs[VM_MEMSEG_LOW].size; 2727e0fa794SMark Johnston *highmem_size = ctx->memsegs[VM_MEMSEG_HIGH].size; 273483d953aSJohn Baldwin return (0); 274483d953aSJohn Baldwin } 275483d953aSJohn Baldwin 276483d953aSJohn Baldwin int 277f8a6ec2dSD Scott Phillips vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, size_t len) 278f8a6ec2dSD Scott Phillips { 279f8a6ec2dSD Scott Phillips struct vm_munmap munmap; 280f8a6ec2dSD Scott Phillips int error; 281f8a6ec2dSD Scott Phillips 282f8a6ec2dSD Scott Phillips munmap.gpa = gpa; 283f8a6ec2dSD Scott Phillips munmap.len = len; 284f8a6ec2dSD Scott Phillips 285f8a6ec2dSD Scott Phillips error = ioctl(ctx->fd, VM_MUNMAP_MEMSEG, &munmap); 286f8a6ec2dSD Scott Phillips return (error); 287f8a6ec2dSD Scott Phillips } 288f8a6ec2dSD Scott Phillips 289f8a6ec2dSD Scott Phillips int 2909b1aa8d6SNeel Natu vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid, 2919b1aa8d6SNeel Natu vm_ooffset_t *segoff, size_t *len, int *prot, int *flags) 2929b1aa8d6SNeel Natu { 2939b1aa8d6SNeel Natu struct vm_memmap memmap; 2949b1aa8d6SNeel Natu int error; 2959b1aa8d6SNeel Natu 2969b1aa8d6SNeel Natu bzero(&memmap, sizeof(struct vm_memmap)); 2979b1aa8d6SNeel Natu memmap.gpa = *gpa; 2989b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_MMAP_GETNEXT, &memmap); 2999b1aa8d6SNeel Natu if (error == 0) { 3009b1aa8d6SNeel Natu *gpa = memmap.gpa; 3019b1aa8d6SNeel Natu *segid = memmap.segid; 3029b1aa8d6SNeel Natu *segoff = memmap.segoff; 3039b1aa8d6SNeel Natu *len = memmap.len; 3049b1aa8d6SNeel Natu *prot = memmap.prot; 3059b1aa8d6SNeel Natu *flags = memmap.flags; 306366f6083SPeter Grehan } 307366f6083SPeter Grehan return (error); 308366f6083SPeter Grehan } 309366f6083SPeter Grehan 3109b1aa8d6SNeel Natu /* 3119b1aa8d6SNeel Natu * Return 0 if the segments are identical and non-zero otherwise. 3129b1aa8d6SNeel Natu * 3139b1aa8d6SNeel Natu * This is slightly complicated by the fact that only device memory segments 3149b1aa8d6SNeel Natu * are named. 3159b1aa8d6SNeel Natu */ 3169b1aa8d6SNeel Natu static int 3179b1aa8d6SNeel Natu cmpseg(size_t len, const char *str, size_t len2, const char *str2) 3189b1aa8d6SNeel Natu { 3199b1aa8d6SNeel Natu 3209b1aa8d6SNeel Natu if (len == len2) { 3219b1aa8d6SNeel Natu if ((!str && !str2) || (str && str2 && !strcmp(str, str2))) 3229b1aa8d6SNeel Natu return (0); 3239b1aa8d6SNeel Natu } 3249b1aa8d6SNeel Natu return (-1); 3259b1aa8d6SNeel Natu } 3269b1aa8d6SNeel Natu 3279b1aa8d6SNeel Natu static int 3289b1aa8d6SNeel Natu vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name) 3299b1aa8d6SNeel Natu { 3309b1aa8d6SNeel Natu struct vm_memseg memseg; 3319b1aa8d6SNeel Natu size_t n; 3329b1aa8d6SNeel Natu int error; 3339b1aa8d6SNeel Natu 3349b1aa8d6SNeel Natu /* 3359b1aa8d6SNeel Natu * If the memory segment has already been created then just return. 3369b1aa8d6SNeel Natu * This is the usual case for the SYSMEM segment created by userspace 3379b1aa8d6SNeel Natu * loaders like bhyveload(8). 3389b1aa8d6SNeel Natu */ 3399b1aa8d6SNeel Natu error = vm_get_memseg(ctx, segid, &memseg.len, memseg.name, 3409b1aa8d6SNeel Natu sizeof(memseg.name)); 3419b1aa8d6SNeel Natu if (error) 3429b1aa8d6SNeel Natu return (error); 3439b1aa8d6SNeel Natu 3449b1aa8d6SNeel Natu if (memseg.len != 0) { 3459b1aa8d6SNeel Natu if (cmpseg(len, name, memseg.len, VM_MEMSEG_NAME(&memseg))) { 3469b1aa8d6SNeel Natu errno = EINVAL; 3479b1aa8d6SNeel Natu return (-1); 3489b1aa8d6SNeel Natu } else { 3499b1aa8d6SNeel Natu return (0); 3509b1aa8d6SNeel Natu } 3519b1aa8d6SNeel Natu } 3529b1aa8d6SNeel Natu 3539b1aa8d6SNeel Natu bzero(&memseg, sizeof(struct vm_memseg)); 3549b1aa8d6SNeel Natu memseg.segid = segid; 3559b1aa8d6SNeel Natu memseg.len = len; 3569b1aa8d6SNeel Natu if (name != NULL) { 3579b1aa8d6SNeel Natu n = strlcpy(memseg.name, name, sizeof(memseg.name)); 3589b1aa8d6SNeel Natu if (n >= sizeof(memseg.name)) { 3599b1aa8d6SNeel Natu errno = ENAMETOOLONG; 3609b1aa8d6SNeel Natu return (-1); 3619b1aa8d6SNeel Natu } 3629b1aa8d6SNeel Natu } 3639b1aa8d6SNeel Natu 3649b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_ALLOC_MEMSEG, &memseg); 3659b1aa8d6SNeel Natu return (error); 3669b1aa8d6SNeel Natu } 3679b1aa8d6SNeel Natu 3689b1aa8d6SNeel Natu int 3699b1aa8d6SNeel Natu vm_get_memseg(struct vmctx *ctx, int segid, size_t *lenp, char *namebuf, 3709b1aa8d6SNeel Natu size_t bufsize) 3719b1aa8d6SNeel Natu { 3729b1aa8d6SNeel Natu struct vm_memseg memseg; 3739b1aa8d6SNeel Natu size_t n; 3749b1aa8d6SNeel Natu int error; 3759b1aa8d6SNeel Natu 376e499fdcbSMark Johnston bzero(&memseg, sizeof(memseg)); 3779b1aa8d6SNeel Natu memseg.segid = segid; 3789b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_GET_MEMSEG, &memseg); 3799b1aa8d6SNeel Natu if (error == 0) { 3809b1aa8d6SNeel Natu *lenp = memseg.len; 3819b1aa8d6SNeel Natu n = strlcpy(namebuf, memseg.name, bufsize); 3829b1aa8d6SNeel Natu if (n >= bufsize) { 3839b1aa8d6SNeel Natu errno = ENAMETOOLONG; 3849b1aa8d6SNeel Natu error = -1; 3859b1aa8d6SNeel Natu } 3869b1aa8d6SNeel Natu } 3879b1aa8d6SNeel Natu return (error); 3889b1aa8d6SNeel Natu } 3899b1aa8d6SNeel Natu 3909b1aa8d6SNeel Natu static int 3919b1aa8d6SNeel Natu setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base) 3929b1aa8d6SNeel Natu { 3939b1aa8d6SNeel Natu char *ptr; 3949b1aa8d6SNeel Natu int error, flags; 3959b1aa8d6SNeel Natu 3969b1aa8d6SNeel Natu /* Map 'len' bytes starting at 'gpa' in the guest address space */ 3979b1aa8d6SNeel Natu error = vm_mmap_memseg(ctx, gpa, VM_SYSMEM, gpa, len, PROT_ALL); 3989b1aa8d6SNeel Natu if (error) 3999b1aa8d6SNeel Natu return (error); 4009b1aa8d6SNeel Natu 4019b1aa8d6SNeel Natu flags = MAP_SHARED | MAP_FIXED; 4029b1aa8d6SNeel Natu if ((ctx->memflags & VM_MEM_F_INCORE) == 0) 4039b1aa8d6SNeel Natu flags |= MAP_NOCORE; 4049b1aa8d6SNeel Natu 4059b1aa8d6SNeel Natu /* mmap into the process address space on the host */ 4069b1aa8d6SNeel Natu ptr = mmap(base + gpa, len, PROT_RW, flags, ctx->fd, gpa); 4079b1aa8d6SNeel Natu if (ptr == MAP_FAILED) 4089b1aa8d6SNeel Natu return (-1); 4099b1aa8d6SNeel Natu 4109b1aa8d6SNeel Natu return (0); 4119b1aa8d6SNeel Natu } 4129b1aa8d6SNeel Natu 413b060ba50SNeel Natu int 414b060ba50SNeel Natu vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms) 415b060ba50SNeel Natu { 4169b1aa8d6SNeel Natu size_t objsize, len; 4179b1aa8d6SNeel Natu vm_paddr_t gpa; 4189b1aa8d6SNeel Natu char *baseaddr, *ptr; 4196a9648b5SJohn Baldwin int error; 420b060ba50SNeel Natu 4219b1aa8d6SNeel Natu assert(vms == VM_MMAP_ALL); 422b060ba50SNeel Natu 423b060ba50SNeel Natu /* 4247e0fa794SMark Johnston * If 'memsize' cannot fit entirely in the 'lowmem' segment then create 4257e0fa794SMark Johnston * another 'highmem' segment above VM_HIGHMEM_BASE for the remainder. 426b060ba50SNeel Natu */ 4277e0fa794SMark Johnston if (memsize > VM_LOWMEM_LIMIT) { 4287e0fa794SMark Johnston ctx->memsegs[VM_MEMSEG_LOW].size = VM_LOWMEM_LIMIT; 4297e0fa794SMark Johnston ctx->memsegs[VM_MEMSEG_HIGH].size = memsize - VM_LOWMEM_LIMIT; 4307e0fa794SMark Johnston objsize = VM_HIGHMEM_BASE + ctx->memsegs[VM_MEMSEG_HIGH].size; 431b060ba50SNeel Natu } else { 4327e0fa794SMark Johnston ctx->memsegs[VM_MEMSEG_LOW].size = memsize; 4337e0fa794SMark Johnston ctx->memsegs[VM_MEMSEG_HIGH].size = 0; 4347e0fa794SMark Johnston objsize = memsize; 4359b1aa8d6SNeel Natu } 4369b1aa8d6SNeel Natu 4379b1aa8d6SNeel Natu error = vm_alloc_memseg(ctx, VM_SYSMEM, objsize, NULL); 4389b1aa8d6SNeel Natu if (error) 4399b1aa8d6SNeel Natu return (error); 4409b1aa8d6SNeel Natu 4419b1aa8d6SNeel Natu /* 4429b1aa8d6SNeel Natu * Stake out a contiguous region covering the guest physical memory 4439b1aa8d6SNeel Natu * and the adjoining guard regions. 4449b1aa8d6SNeel Natu */ 4459b1aa8d6SNeel Natu len = VM_MMAP_GUARD_SIZE + objsize + VM_MMAP_GUARD_SIZE; 4466a9648b5SJohn Baldwin ptr = mmap(NULL, len, PROT_NONE, MAP_GUARD | MAP_ALIGNED_SUPER, -1, 0); 4479b1aa8d6SNeel Natu if (ptr == MAP_FAILED) 4489b1aa8d6SNeel Natu return (-1); 4499b1aa8d6SNeel Natu 4509b1aa8d6SNeel Natu baseaddr = ptr + VM_MMAP_GUARD_SIZE; 4517e0fa794SMark Johnston if (ctx->memsegs[VM_MEMSEG_HIGH].size > 0) { 4527e0fa794SMark Johnston gpa = VM_HIGHMEM_BASE; 4537e0fa794SMark Johnston len = ctx->memsegs[VM_MEMSEG_HIGH].size; 4549b1aa8d6SNeel Natu error = setup_memory_segment(ctx, gpa, len, baseaddr); 4559b1aa8d6SNeel Natu if (error) 4569b1aa8d6SNeel Natu return (error); 457b060ba50SNeel Natu } 458b060ba50SNeel Natu 4597e0fa794SMark Johnston if (ctx->memsegs[VM_MEMSEG_LOW].size > 0) { 4609b1aa8d6SNeel Natu gpa = 0; 4617e0fa794SMark Johnston len = ctx->memsegs[VM_MEMSEG_LOW].size; 4629b1aa8d6SNeel Natu error = setup_memory_segment(ctx, gpa, len, baseaddr); 463b060ba50SNeel Natu if (error) 464b060ba50SNeel Natu return (error); 465b060ba50SNeel Natu } 466b060ba50SNeel Natu 4679b1aa8d6SNeel Natu ctx->baseaddr = baseaddr; 468b060ba50SNeel Natu 469b060ba50SNeel Natu return (0); 470b060ba50SNeel Natu } 471b060ba50SNeel Natu 47236e8356eSNeel Natu /* 47336e8356eSNeel Natu * Returns a non-NULL pointer if [gaddr, gaddr+len) is entirely contained in 47436e8356eSNeel Natu * the lowmem or highmem regions. 47536e8356eSNeel Natu * 47636e8356eSNeel Natu * In particular return NULL if [gaddr, gaddr+len) falls in guest MMIO region. 47736e8356eSNeel Natu * The instruction emulation code depends on this behavior. 47836e8356eSNeel Natu */ 479b060ba50SNeel Natu void * 480b060ba50SNeel Natu vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len) 481366f6083SPeter Grehan { 4827e0fa794SMark Johnston vm_size_t lowsize, highsize; 483366f6083SPeter Grehan 4847e0fa794SMark Johnston lowsize = ctx->memsegs[VM_MEMSEG_LOW].size; 4857e0fa794SMark Johnston if (lowsize > 0) { 4867e0fa794SMark Johnston if (gaddr < lowsize && len <= lowsize && gaddr + len <= lowsize) 48736e8356eSNeel Natu return (ctx->baseaddr + gaddr); 48836e8356eSNeel Natu } 489b060ba50SNeel Natu 4907e0fa794SMark Johnston highsize = ctx->memsegs[VM_MEMSEG_HIGH].size; 4917e0fa794SMark Johnston if (highsize > 0 && gaddr >= VM_HIGHMEM_BASE) { 4927e0fa794SMark Johnston if (gaddr < VM_HIGHMEM_BASE + highsize && len <= highsize && 4937e0fa794SMark Johnston gaddr + len <= VM_HIGHMEM_BASE + highsize) 49436e8356eSNeel Natu return (ctx->baseaddr + gaddr); 49536e8356eSNeel Natu } 49636e8356eSNeel Natu 497b060ba50SNeel Natu return (NULL); 498366f6083SPeter Grehan } 499366f6083SPeter Grehan 500483d953aSJohn Baldwin vm_paddr_t 501483d953aSJohn Baldwin vm_rev_map_gpa(struct vmctx *ctx, void *addr) 502483d953aSJohn Baldwin { 503483d953aSJohn Baldwin vm_paddr_t offaddr; 5047e0fa794SMark Johnston vm_size_t lowsize, highsize; 505483d953aSJohn Baldwin 506483d953aSJohn Baldwin offaddr = (char *)addr - ctx->baseaddr; 507483d953aSJohn Baldwin 5087e0fa794SMark Johnston lowsize = ctx->memsegs[VM_MEMSEG_LOW].size; 5097e0fa794SMark Johnston if (lowsize > 0) 5107e0fa794SMark Johnston if (offaddr <= lowsize) 511483d953aSJohn Baldwin return (offaddr); 512483d953aSJohn Baldwin 5137e0fa794SMark Johnston highsize = ctx->memsegs[VM_MEMSEG_HIGH].size; 5147e0fa794SMark Johnston if (highsize > 0) 5157e0fa794SMark Johnston if (offaddr >= VM_HIGHMEM_BASE && 5167e0fa794SMark Johnston offaddr < VM_HIGHMEM_BASE + highsize) 517483d953aSJohn Baldwin return (offaddr); 518483d953aSJohn Baldwin 519483d953aSJohn Baldwin return ((vm_paddr_t)-1); 520483d953aSJohn Baldwin } 521483d953aSJohn Baldwin 5223efc45f3SRobert Wing const char * 5233efc45f3SRobert Wing vm_get_name(struct vmctx *ctx) 524483d953aSJohn Baldwin { 525483d953aSJohn Baldwin 5263efc45f3SRobert Wing return (ctx->name); 527483d953aSJohn Baldwin } 528483d953aSJohn Baldwin 529be679db4SNeel Natu size_t 530be679db4SNeel Natu vm_get_lowmem_size(struct vmctx *ctx) 531be679db4SNeel Natu { 532be679db4SNeel Natu 5337e0fa794SMark Johnston return (ctx->memsegs[VM_MEMSEG_LOW].size); 5347e0fa794SMark Johnston } 5357e0fa794SMark Johnston 5367e0fa794SMark Johnston vm_paddr_t 5377e0fa794SMark Johnston vm_get_highmem_base(struct vmctx *ctx __unused) 5387e0fa794SMark Johnston { 5397e0fa794SMark Johnston 5407e0fa794SMark Johnston return (VM_HIGHMEM_BASE); 541be679db4SNeel Natu } 542be679db4SNeel Natu 543be679db4SNeel Natu size_t 544be679db4SNeel Natu vm_get_highmem_size(struct vmctx *ctx) 545be679db4SNeel Natu { 546be679db4SNeel Natu 5477e0fa794SMark Johnston return (ctx->memsegs[VM_MEMSEG_HIGH].size); 548be679db4SNeel Natu } 549be679db4SNeel Natu 5509b1aa8d6SNeel Natu void * 5519b1aa8d6SNeel Natu vm_create_devmem(struct vmctx *ctx, int segid, const char *name, size_t len) 5529b1aa8d6SNeel Natu { 5539b1aa8d6SNeel Natu char pathname[MAXPATHLEN]; 5549b1aa8d6SNeel Natu size_t len2; 5559b1aa8d6SNeel Natu char *base, *ptr; 5569b1aa8d6SNeel Natu int fd, error, flags; 5579b1aa8d6SNeel Natu 5589b1aa8d6SNeel Natu fd = -1; 5599b1aa8d6SNeel Natu ptr = MAP_FAILED; 5609b1aa8d6SNeel Natu if (name == NULL || strlen(name) == 0) { 5619b1aa8d6SNeel Natu errno = EINVAL; 5629b1aa8d6SNeel Natu goto done; 5639b1aa8d6SNeel Natu } 5649b1aa8d6SNeel Natu 5659b1aa8d6SNeel Natu error = vm_alloc_memseg(ctx, segid, len, name); 5669b1aa8d6SNeel Natu if (error) 5679b1aa8d6SNeel Natu goto done; 5689b1aa8d6SNeel Natu 5695e4f29c0SNeel Natu strlcpy(pathname, "/dev/vmm.io/", sizeof(pathname)); 5709b1aa8d6SNeel Natu strlcat(pathname, ctx->name, sizeof(pathname)); 5719b1aa8d6SNeel Natu strlcat(pathname, ".", sizeof(pathname)); 5729b1aa8d6SNeel Natu strlcat(pathname, name, sizeof(pathname)); 5739b1aa8d6SNeel Natu 5749b1aa8d6SNeel Natu fd = open(pathname, O_RDWR); 5759b1aa8d6SNeel Natu if (fd < 0) 5769b1aa8d6SNeel Natu goto done; 5779b1aa8d6SNeel Natu 5789b1aa8d6SNeel Natu /* 5799b1aa8d6SNeel Natu * Stake out a contiguous region covering the device memory and the 5809b1aa8d6SNeel Natu * adjoining guard regions. 5819b1aa8d6SNeel Natu */ 5829b1aa8d6SNeel Natu len2 = VM_MMAP_GUARD_SIZE + len + VM_MMAP_GUARD_SIZE; 5836a9648b5SJohn Baldwin base = mmap(NULL, len2, PROT_NONE, MAP_GUARD | MAP_ALIGNED_SUPER, -1, 5846a9648b5SJohn Baldwin 0); 5859b1aa8d6SNeel Natu if (base == MAP_FAILED) 5869b1aa8d6SNeel Natu goto done; 5879b1aa8d6SNeel Natu 5889b1aa8d6SNeel Natu flags = MAP_SHARED | MAP_FIXED; 5899b1aa8d6SNeel Natu if ((ctx->memflags & VM_MEM_F_INCORE) == 0) 5909b1aa8d6SNeel Natu flags |= MAP_NOCORE; 5919b1aa8d6SNeel Natu 5929b1aa8d6SNeel Natu /* mmap the devmem region in the host address space */ 5939b1aa8d6SNeel Natu ptr = mmap(base + VM_MMAP_GUARD_SIZE, len, PROT_RW, flags, fd, 0); 5949b1aa8d6SNeel Natu done: 5959b1aa8d6SNeel Natu if (fd >= 0) 5969b1aa8d6SNeel Natu close(fd); 5979b1aa8d6SNeel Natu return (ptr); 5989b1aa8d6SNeel Natu } 5999b1aa8d6SNeel Natu 600e4656e10SMark Johnston int 6017d9ef309SJohn Baldwin vcpu_ioctl(struct vcpu *vcpu, u_long cmd, void *arg) 6027d9ef309SJohn Baldwin { 6037d9ef309SJohn Baldwin /* 6047d9ef309SJohn Baldwin * XXX: fragile, handle with care 6057d9ef309SJohn Baldwin * Assumes that the first field of the ioctl data 6067d9ef309SJohn Baldwin * is the vcpuid. 6077d9ef309SJohn Baldwin */ 6087d9ef309SJohn Baldwin *(int *)arg = vcpu->vcpuid; 6097d9ef309SJohn Baldwin return (ioctl(vcpu->ctx->fd, cmd, arg)); 6107d9ef309SJohn Baldwin } 6117d9ef309SJohn Baldwin 612366f6083SPeter Grehan int 6137d9ef309SJohn Baldwin vm_set_register(struct vcpu *vcpu, int reg, uint64_t val) 614366f6083SPeter Grehan { 615366f6083SPeter Grehan int error; 616366f6083SPeter Grehan struct vm_register vmreg; 617366f6083SPeter Grehan 618366f6083SPeter Grehan bzero(&vmreg, sizeof(vmreg)); 619366f6083SPeter Grehan vmreg.regnum = reg; 620366f6083SPeter Grehan vmreg.regval = val; 621366f6083SPeter Grehan 6227d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_SET_REGISTER, &vmreg); 623366f6083SPeter Grehan return (error); 624366f6083SPeter Grehan } 625366f6083SPeter Grehan 626366f6083SPeter Grehan int 6277d9ef309SJohn Baldwin vm_get_register(struct vcpu *vcpu, int reg, uint64_t *ret_val) 628366f6083SPeter Grehan { 629366f6083SPeter Grehan int error; 630366f6083SPeter Grehan struct vm_register vmreg; 631366f6083SPeter Grehan 632366f6083SPeter Grehan bzero(&vmreg, sizeof(vmreg)); 633366f6083SPeter Grehan vmreg.regnum = reg; 634366f6083SPeter Grehan 6357d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_GET_REGISTER, &vmreg); 636366f6083SPeter Grehan *ret_val = vmreg.regval; 637366f6083SPeter Grehan return (error); 638366f6083SPeter Grehan } 639366f6083SPeter Grehan 640366f6083SPeter Grehan int 6417d9ef309SJohn Baldwin vm_set_register_set(struct vcpu *vcpu, unsigned int count, 6424f866698SJohn Baldwin const int *regnums, uint64_t *regvals) 6434f866698SJohn Baldwin { 6444f866698SJohn Baldwin int error; 6454f866698SJohn Baldwin struct vm_register_set vmregset; 6464f866698SJohn Baldwin 6474f866698SJohn Baldwin bzero(&vmregset, sizeof(vmregset)); 6484f866698SJohn Baldwin vmregset.count = count; 6494f866698SJohn Baldwin vmregset.regnums = regnums; 6504f866698SJohn Baldwin vmregset.regvals = regvals; 6514f866698SJohn Baldwin 6527d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_SET_REGISTER_SET, &vmregset); 6534f866698SJohn Baldwin return (error); 6544f866698SJohn Baldwin } 6554f866698SJohn Baldwin 6564f866698SJohn Baldwin int 6577d9ef309SJohn Baldwin vm_get_register_set(struct vcpu *vcpu, unsigned int count, 6584f866698SJohn Baldwin const int *regnums, uint64_t *regvals) 6594f866698SJohn Baldwin { 6604f866698SJohn Baldwin int error; 6614f866698SJohn Baldwin struct vm_register_set vmregset; 6624f866698SJohn Baldwin 6634f866698SJohn Baldwin bzero(&vmregset, sizeof(vmregset)); 6644f866698SJohn Baldwin vmregset.count = count; 6654f866698SJohn Baldwin vmregset.regnums = regnums; 6664f866698SJohn Baldwin vmregset.regvals = regvals; 6674f866698SJohn Baldwin 6687d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_GET_REGISTER_SET, &vmregset); 6694f866698SJohn Baldwin return (error); 6704f866698SJohn Baldwin } 6714f866698SJohn Baldwin 6724f866698SJohn Baldwin int 673e17eca32SMark Johnston vm_run(struct vcpu *vcpu, struct vm_run *vmrun) 674366f6083SPeter Grehan { 675e17eca32SMark Johnston return (vcpu_ioctl(vcpu, VM_RUN, vmrun)); 676366f6083SPeter Grehan } 677366f6083SPeter Grehan 678b15a09c0SNeel Natu int 679f0fdcfe2SNeel Natu vm_suspend(struct vmctx *ctx, enum vm_suspend_how how) 680b15a09c0SNeel Natu { 681f0fdcfe2SNeel Natu struct vm_suspend vmsuspend; 682b15a09c0SNeel Natu 683f0fdcfe2SNeel Natu bzero(&vmsuspend, sizeof(vmsuspend)); 684f0fdcfe2SNeel Natu vmsuspend.how = how; 685f0fdcfe2SNeel Natu return (ioctl(ctx->fd, VM_SUSPEND, &vmsuspend)); 686b15a09c0SNeel Natu } 687b15a09c0SNeel Natu 6885fcf252fSNeel Natu int 6895fcf252fSNeel Natu vm_reinit(struct vmctx *ctx) 6905fcf252fSNeel Natu { 6915fcf252fSNeel Natu 6925fcf252fSNeel Natu return (ioctl(ctx->fd, VM_REINIT, 0)); 6935fcf252fSNeel Natu } 6945fcf252fSNeel Natu 695d087a399SNeel Natu int 69613f4cf6cSNeel Natu vm_capability_name2type(const char *capname) 69713f4cf6cSNeel Natu { 69813f4cf6cSNeel Natu int i; 69913f4cf6cSNeel Natu 70085efb31dSMark Johnston for (i = 0; i < VM_CAP_MAX; i++) { 70185efb31dSMark Johnston if (vm_capstrmap[i] != NULL && 70285efb31dSMark Johnston strcmp(vm_capstrmap[i], capname) == 0) 703d000623aSJohn Baldwin return (i); 704366f6083SPeter Grehan } 705366f6083SPeter Grehan 706366f6083SPeter Grehan return (-1); 707366f6083SPeter Grehan } 708366f6083SPeter Grehan 70913f4cf6cSNeel Natu const char * 71013f4cf6cSNeel Natu vm_capability_type2name(int type) 71113f4cf6cSNeel Natu { 71285efb31dSMark Johnston if (type >= 0 && type < VM_CAP_MAX) 71385efb31dSMark Johnston return (vm_capstrmap[type]); 71413f4cf6cSNeel Natu 71513f4cf6cSNeel Natu return (NULL); 71613f4cf6cSNeel Natu } 71713f4cf6cSNeel Natu 718366f6083SPeter Grehan int 7197d9ef309SJohn Baldwin vm_get_capability(struct vcpu *vcpu, enum vm_cap_type cap, int *retval) 720366f6083SPeter Grehan { 721366f6083SPeter Grehan int error; 722366f6083SPeter Grehan struct vm_capability vmcap; 723366f6083SPeter Grehan 724366f6083SPeter Grehan bzero(&vmcap, sizeof(vmcap)); 725366f6083SPeter Grehan vmcap.captype = cap; 726366f6083SPeter Grehan 7277d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_GET_CAPABILITY, &vmcap); 728366f6083SPeter Grehan *retval = vmcap.capval; 729366f6083SPeter Grehan return (error); 730366f6083SPeter Grehan } 731366f6083SPeter Grehan 732366f6083SPeter Grehan int 7337d9ef309SJohn Baldwin vm_set_capability(struct vcpu *vcpu, enum vm_cap_type cap, int val) 734366f6083SPeter Grehan { 735366f6083SPeter Grehan struct vm_capability vmcap; 736366f6083SPeter Grehan 737366f6083SPeter Grehan bzero(&vmcap, sizeof(vmcap)); 738366f6083SPeter Grehan vmcap.captype = cap; 739366f6083SPeter Grehan vmcap.capval = val; 740366f6083SPeter Grehan 7417d9ef309SJohn Baldwin return (vcpu_ioctl(vcpu, VM_SET_CAPABILITY, &vmcap)); 742366f6083SPeter Grehan } 743366f6083SPeter Grehan 744366f6083SPeter Grehan uint64_t * 7457d9ef309SJohn Baldwin vm_get_stats(struct vcpu *vcpu, struct timeval *ret_tv, 746366f6083SPeter Grehan int *ret_entries) 747366f6083SPeter Grehan { 74864269786SJohn Baldwin static _Thread_local uint64_t *stats_buf; 74964269786SJohn Baldwin static _Thread_local u_int stats_count; 75064269786SJohn Baldwin uint64_t *new_stats; 75164269786SJohn Baldwin struct vm_stats vmstats; 75264269786SJohn Baldwin u_int count, index; 75364269786SJohn Baldwin bool have_stats; 754366f6083SPeter Grehan 75564269786SJohn Baldwin have_stats = false; 75664269786SJohn Baldwin count = 0; 75764269786SJohn Baldwin for (index = 0;; index += nitems(vmstats.statbuf)) { 75864269786SJohn Baldwin vmstats.index = index; 7597d9ef309SJohn Baldwin if (vcpu_ioctl(vcpu, VM_STATS, &vmstats) != 0) 76064269786SJohn Baldwin break; 76164269786SJohn Baldwin if (stats_count < index + vmstats.num_entries) { 76264269786SJohn Baldwin new_stats = realloc(stats_buf, 76364269786SJohn Baldwin (index + vmstats.num_entries) * sizeof(uint64_t)); 76464269786SJohn Baldwin if (new_stats == NULL) { 76564269786SJohn Baldwin errno = ENOMEM; 76664269786SJohn Baldwin return (NULL); 76764269786SJohn Baldwin } 76864269786SJohn Baldwin stats_count = index + vmstats.num_entries; 76964269786SJohn Baldwin stats_buf = new_stats; 77064269786SJohn Baldwin } 77164269786SJohn Baldwin memcpy(stats_buf + index, vmstats.statbuf, 77264269786SJohn Baldwin vmstats.num_entries * sizeof(uint64_t)); 77364269786SJohn Baldwin count += vmstats.num_entries; 77464269786SJohn Baldwin have_stats = true; 775366f6083SPeter Grehan 77664269786SJohn Baldwin if (vmstats.num_entries != nitems(vmstats.statbuf)) 77764269786SJohn Baldwin break; 77864269786SJohn Baldwin } 77964269786SJohn Baldwin if (have_stats) { 780366f6083SPeter Grehan if (ret_entries) 78164269786SJohn Baldwin *ret_entries = count; 782366f6083SPeter Grehan if (ret_tv) 783366f6083SPeter Grehan *ret_tv = vmstats.tv; 78464269786SJohn Baldwin return (stats_buf); 785366f6083SPeter Grehan } else 786366f6083SPeter Grehan return (NULL); 787366f6083SPeter Grehan } 788366f6083SPeter Grehan 789366f6083SPeter Grehan const char * 790366f6083SPeter Grehan vm_get_stat_desc(struct vmctx *ctx, int index) 791366f6083SPeter Grehan { 792366f6083SPeter Grehan static struct vm_stat_desc statdesc; 793366f6083SPeter Grehan 794366f6083SPeter Grehan statdesc.index = index; 795366f6083SPeter Grehan if (ioctl(ctx->fd, VM_STAT_DESC, &statdesc) == 0) 796366f6083SPeter Grehan return (statdesc.desc); 797366f6083SPeter Grehan else 798366f6083SPeter Grehan return (NULL); 799366f6083SPeter Grehan } 800366f6083SPeter Grehan 801*56a26fc1SMark Johnston #ifdef __amd64__ 802e9027382SNeel Natu int 803318224bbSNeel Natu vm_get_gpa_pmap(struct vmctx *ctx, uint64_t gpa, uint64_t *pte, int *num) 804318224bbSNeel Natu { 805318224bbSNeel Natu int error, i; 806318224bbSNeel Natu struct vm_gpa_pte gpapte; 807318224bbSNeel Natu 808318224bbSNeel Natu bzero(&gpapte, sizeof(gpapte)); 809318224bbSNeel Natu gpapte.gpa = gpa; 810318224bbSNeel Natu 811318224bbSNeel Natu error = ioctl(ctx->fd, VM_GET_GPA_PMAP, &gpapte); 812318224bbSNeel Natu 813318224bbSNeel Natu if (error == 0) { 814318224bbSNeel Natu *num = gpapte.ptenum; 815318224bbSNeel Natu for (i = 0; i < gpapte.ptenum; i++) 816318224bbSNeel Natu pte[i] = gpapte.pte[i]; 817318224bbSNeel Natu } 818318224bbSNeel Natu 819318224bbSNeel Natu return (error); 820318224bbSNeel Natu } 82108e3ff32SNeel Natu 82208e3ff32SNeel Natu int 8237d9ef309SJohn Baldwin vm_gla2gpa(struct vcpu *vcpu, struct vm_guest_paging *paging, 8249c4d5478SNeel Natu uint64_t gla, int prot, uint64_t *gpa, int *fault) 825da11f4aaSNeel Natu { 826da11f4aaSNeel Natu struct vm_gla2gpa gg; 827da11f4aaSNeel Natu int error; 828da11f4aaSNeel Natu 829da11f4aaSNeel Natu bzero(&gg, sizeof(struct vm_gla2gpa)); 830da11f4aaSNeel Natu gg.prot = prot; 831da11f4aaSNeel Natu gg.gla = gla; 832da11f4aaSNeel Natu gg.paging = *paging; 833da11f4aaSNeel Natu 8347d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_GLA2GPA, &gg); 835da11f4aaSNeel Natu if (error == 0) { 836da11f4aaSNeel Natu *fault = gg.fault; 837da11f4aaSNeel Natu *gpa = gg.gpa; 838da11f4aaSNeel Natu } 839da11f4aaSNeel Natu return (error); 840da11f4aaSNeel Natu } 841*56a26fc1SMark Johnston #endif 842da11f4aaSNeel Natu 8435f8754c0SJohn Baldwin int 8447d9ef309SJohn Baldwin vm_gla2gpa_nofault(struct vcpu *vcpu, struct vm_guest_paging *paging, 8455f8754c0SJohn Baldwin uint64_t gla, int prot, uint64_t *gpa, int *fault) 8465f8754c0SJohn Baldwin { 8475f8754c0SJohn Baldwin struct vm_gla2gpa gg; 8485f8754c0SJohn Baldwin int error; 8495f8754c0SJohn Baldwin 8505f8754c0SJohn Baldwin bzero(&gg, sizeof(struct vm_gla2gpa)); 8515f8754c0SJohn Baldwin gg.prot = prot; 8525f8754c0SJohn Baldwin gg.gla = gla; 8535f8754c0SJohn Baldwin gg.paging = *paging; 8545f8754c0SJohn Baldwin 8557d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_GLA2GPA_NOFAULT, &gg); 8565f8754c0SJohn Baldwin if (error == 0) { 8575f8754c0SJohn Baldwin *fault = gg.fault; 8585f8754c0SJohn Baldwin *gpa = gg.gpa; 8595f8754c0SJohn Baldwin } 8605f8754c0SJohn Baldwin return (error); 8615f8754c0SJohn Baldwin } 8625f8754c0SJohn Baldwin 863da11f4aaSNeel Natu #ifndef min 864da11f4aaSNeel Natu #define min(a,b) (((a) < (b)) ? (a) : (b)) 865da11f4aaSNeel Natu #endif 866da11f4aaSNeel Natu 867*56a26fc1SMark Johnston #ifdef __amd64__ 868da11f4aaSNeel Natu int 8697d9ef309SJohn Baldwin vm_copy_setup(struct vcpu *vcpu, struct vm_guest_paging *paging, 8709c4d5478SNeel Natu uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt, 8719c4d5478SNeel Natu int *fault) 872da11f4aaSNeel Natu { 873009e2acbSNeel Natu void *va; 87445cd18ecSMark Johnston uint64_t gpa, off; 87545cd18ecSMark Johnston int error, i, n; 8766303b65dSNeel Natu 8776303b65dSNeel Natu for (i = 0; i < iovcnt; i++) { 8786303b65dSNeel Natu iov[i].iov_base = 0; 8796303b65dSNeel Natu iov[i].iov_len = 0; 8806303b65dSNeel Natu } 8816303b65dSNeel Natu 8826303b65dSNeel Natu while (len) { 8836303b65dSNeel Natu assert(iovcnt > 0); 8847d9ef309SJohn Baldwin error = vm_gla2gpa(vcpu, paging, gla, prot, &gpa, fault); 8859c4d5478SNeel Natu if (error || *fault) 8869c4d5478SNeel Natu return (error); 8876303b65dSNeel Natu 8886303b65dSNeel Natu off = gpa & PAGE_MASK; 88945cd18ecSMark Johnston n = MIN(len, PAGE_SIZE - off); 8906303b65dSNeel Natu 8917d9ef309SJohn Baldwin va = vm_map_gpa(vcpu->ctx, gpa, n); 892009e2acbSNeel Natu if (va == NULL) 8939c4d5478SNeel Natu return (EFAULT); 894009e2acbSNeel Natu 895009e2acbSNeel Natu iov->iov_base = va; 8966303b65dSNeel Natu iov->iov_len = n; 8976303b65dSNeel Natu iov++; 8986303b65dSNeel Natu iovcnt--; 8996303b65dSNeel Natu 9006303b65dSNeel Natu gla += n; 9016303b65dSNeel Natu len -= n; 9026303b65dSNeel Natu } 9036303b65dSNeel Natu return (0); 9046303b65dSNeel Natu } 905*56a26fc1SMark Johnston #endif 9066303b65dSNeel Natu 9076303b65dSNeel Natu void 9082b4fe856SJohn Baldwin vm_copy_teardown(struct iovec *iov __unused, int iovcnt __unused) 909009e2acbSNeel Natu { 9102b4fe856SJohn Baldwin /* 9112b4fe856SJohn Baldwin * Intentionally empty. This is used by the instruction 9122b4fe856SJohn Baldwin * emulation code shared with the kernel. The in-kernel 9132b4fe856SJohn Baldwin * version of this is non-empty. 9142b4fe856SJohn Baldwin */ 915009e2acbSNeel Natu } 916009e2acbSNeel Natu 917009e2acbSNeel Natu void 9182b4fe856SJohn Baldwin vm_copyin(struct iovec *iov, void *vp, size_t len) 9196303b65dSNeel Natu { 9206303b65dSNeel Natu const char *src; 9216303b65dSNeel Natu char *dst; 9226303b65dSNeel Natu size_t n; 923da11f4aaSNeel Natu 924da11f4aaSNeel Natu dst = vp; 925da11f4aaSNeel Natu while (len) { 9266303b65dSNeel Natu assert(iov->iov_len); 9276303b65dSNeel Natu n = min(len, iov->iov_len); 928009e2acbSNeel Natu src = iov->iov_base; 929da11f4aaSNeel Natu bcopy(src, dst, n); 930da11f4aaSNeel Natu 9316303b65dSNeel Natu iov++; 932da11f4aaSNeel Natu dst += n; 933da11f4aaSNeel Natu len -= n; 934da11f4aaSNeel Natu } 935da11f4aaSNeel Natu } 936da11f4aaSNeel Natu 9376303b65dSNeel Natu void 9382b4fe856SJohn Baldwin vm_copyout(const void *vp, struct iovec *iov, size_t len) 939da11f4aaSNeel Natu { 940da11f4aaSNeel Natu const char *src; 9416303b65dSNeel Natu char *dst; 9426303b65dSNeel Natu size_t n; 943da11f4aaSNeel Natu 944da11f4aaSNeel Natu src = vp; 945da11f4aaSNeel Natu while (len) { 9466303b65dSNeel Natu assert(iov->iov_len); 9476303b65dSNeel Natu n = min(len, iov->iov_len); 948009e2acbSNeel Natu dst = iov->iov_base; 949da11f4aaSNeel Natu bcopy(src, dst, n); 950da11f4aaSNeel Natu 9516303b65dSNeel Natu iov++; 952da11f4aaSNeel Natu src += n; 953da11f4aaSNeel Natu len -= n; 954da11f4aaSNeel Natu } 955da11f4aaSNeel Natu } 95695ebc360SNeel Natu 95795ebc360SNeel Natu static int 95895ebc360SNeel Natu vm_get_cpus(struct vmctx *ctx, int which, cpuset_t *cpus) 95995ebc360SNeel Natu { 96095ebc360SNeel Natu struct vm_cpuset vm_cpuset; 96195ebc360SNeel Natu int error; 96295ebc360SNeel Natu 96395ebc360SNeel Natu bzero(&vm_cpuset, sizeof(struct vm_cpuset)); 96495ebc360SNeel Natu vm_cpuset.which = which; 96595ebc360SNeel Natu vm_cpuset.cpusetsize = sizeof(cpuset_t); 96695ebc360SNeel Natu vm_cpuset.cpus = cpus; 96795ebc360SNeel Natu 96895ebc360SNeel Natu error = ioctl(ctx->fd, VM_GET_CPUS, &vm_cpuset); 96995ebc360SNeel Natu return (error); 97095ebc360SNeel Natu } 97195ebc360SNeel Natu 97295ebc360SNeel Natu int 97395ebc360SNeel Natu vm_active_cpus(struct vmctx *ctx, cpuset_t *cpus) 97495ebc360SNeel Natu { 97595ebc360SNeel Natu 97695ebc360SNeel Natu return (vm_get_cpus(ctx, VM_ACTIVE_CPUS, cpus)); 97795ebc360SNeel Natu } 97895ebc360SNeel Natu 97995ebc360SNeel Natu int 98095ebc360SNeel Natu vm_suspended_cpus(struct vmctx *ctx, cpuset_t *cpus) 98195ebc360SNeel Natu { 98295ebc360SNeel Natu 98395ebc360SNeel Natu return (vm_get_cpus(ctx, VM_SUSPENDED_CPUS, cpus)); 98495ebc360SNeel Natu } 98595ebc360SNeel Natu 98695ebc360SNeel Natu int 987fc276d92SJohn Baldwin vm_debug_cpus(struct vmctx *ctx, cpuset_t *cpus) 988fc276d92SJohn Baldwin { 989fc276d92SJohn Baldwin 990fc276d92SJohn Baldwin return (vm_get_cpus(ctx, VM_DEBUG_CPUS, cpus)); 991fc276d92SJohn Baldwin } 992fc276d92SJohn Baldwin 993fc276d92SJohn Baldwin int 9947d9ef309SJohn Baldwin vm_activate_cpu(struct vcpu *vcpu) 99595ebc360SNeel Natu { 99695ebc360SNeel Natu struct vm_activate_cpu ac; 99795ebc360SNeel Natu int error; 99895ebc360SNeel Natu 99995ebc360SNeel Natu bzero(&ac, sizeof(struct vm_activate_cpu)); 10007d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_ACTIVATE_CPU, &ac); 100195ebc360SNeel Natu return (error); 100295ebc360SNeel Natu } 1003091d4532SNeel Natu 1004091d4532SNeel Natu int 10057d9ef309SJohn Baldwin vm_suspend_all_cpus(struct vmctx *ctx) 1006fc276d92SJohn Baldwin { 1007fc276d92SJohn Baldwin struct vm_activate_cpu ac; 1008fc276d92SJohn Baldwin int error; 1009fc276d92SJohn Baldwin 1010fc276d92SJohn Baldwin bzero(&ac, sizeof(struct vm_activate_cpu)); 10117d9ef309SJohn Baldwin ac.vcpuid = -1; 1012fc276d92SJohn Baldwin error = ioctl(ctx->fd, VM_SUSPEND_CPU, &ac); 1013fc276d92SJohn Baldwin return (error); 1014fc276d92SJohn Baldwin } 1015fc276d92SJohn Baldwin 1016fc276d92SJohn Baldwin int 10177d9ef309SJohn Baldwin vm_suspend_cpu(struct vcpu *vcpu) 1018fc276d92SJohn Baldwin { 1019fc276d92SJohn Baldwin struct vm_activate_cpu ac; 1020fc276d92SJohn Baldwin int error; 1021fc276d92SJohn Baldwin 1022fc276d92SJohn Baldwin bzero(&ac, sizeof(struct vm_activate_cpu)); 10237d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_SUSPEND_CPU, &ac); 10247d9ef309SJohn Baldwin return (error); 10257d9ef309SJohn Baldwin } 10267d9ef309SJohn Baldwin 10277d9ef309SJohn Baldwin int 10287d9ef309SJohn Baldwin vm_resume_cpu(struct vcpu *vcpu) 10297d9ef309SJohn Baldwin { 10307d9ef309SJohn Baldwin struct vm_activate_cpu ac; 10317d9ef309SJohn Baldwin int error; 10327d9ef309SJohn Baldwin 10337d9ef309SJohn Baldwin bzero(&ac, sizeof(struct vm_activate_cpu)); 10347d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_RESUME_CPU, &ac); 10357d9ef309SJohn Baldwin return (error); 10367d9ef309SJohn Baldwin } 10377d9ef309SJohn Baldwin 10387d9ef309SJohn Baldwin int 10397d9ef309SJohn Baldwin vm_resume_all_cpus(struct vmctx *ctx) 10407d9ef309SJohn Baldwin { 10417d9ef309SJohn Baldwin struct vm_activate_cpu ac; 10427d9ef309SJohn Baldwin int error; 10437d9ef309SJohn Baldwin 10447d9ef309SJohn Baldwin bzero(&ac, sizeof(struct vm_activate_cpu)); 10457d9ef309SJohn Baldwin ac.vcpuid = -1; 1046fc276d92SJohn Baldwin error = ioctl(ctx->fd, VM_RESUME_CPU, &ac); 1047fc276d92SJohn Baldwin return (error); 1048fc276d92SJohn Baldwin } 1049fc276d92SJohn Baldwin 1050*56a26fc1SMark Johnston #ifdef __amd64__ 1051fc276d92SJohn Baldwin int 10527d9ef309SJohn Baldwin vm_get_intinfo(struct vcpu *vcpu, uint64_t *info1, uint64_t *info2) 1053091d4532SNeel Natu { 1054091d4532SNeel Natu struct vm_intinfo vmii; 1055091d4532SNeel Natu int error; 1056091d4532SNeel Natu 1057091d4532SNeel Natu bzero(&vmii, sizeof(struct vm_intinfo)); 10587d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_GET_INTINFO, &vmii); 1059091d4532SNeel Natu if (error == 0) { 1060091d4532SNeel Natu *info1 = vmii.info1; 1061091d4532SNeel Natu *info2 = vmii.info2; 1062091d4532SNeel Natu } 1063091d4532SNeel Natu return (error); 1064091d4532SNeel Natu } 1065091d4532SNeel Natu 1066091d4532SNeel Natu int 10677d9ef309SJohn Baldwin vm_set_intinfo(struct vcpu *vcpu, uint64_t info1) 1068091d4532SNeel Natu { 1069091d4532SNeel Natu struct vm_intinfo vmii; 1070091d4532SNeel Natu int error; 1071091d4532SNeel Natu 1072091d4532SNeel Natu bzero(&vmii, sizeof(struct vm_intinfo)); 1073091d4532SNeel Natu vmii.info1 = info1; 10747d9ef309SJohn Baldwin error = vcpu_ioctl(vcpu, VM_SET_INTINFO, &vmii); 1075091d4532SNeel Natu return (error); 1076091d4532SNeel Natu } 1077*56a26fc1SMark Johnston #endif 10780dafa5cdSNeel Natu 1079*56a26fc1SMark Johnston #ifdef WITH_VMMAPI_SNAPSHOT 10800dafa5cdSNeel Natu int 10817d9ef309SJohn Baldwin vm_restart_instruction(struct vcpu *vcpu) 1082d087a399SNeel Natu { 10837d9ef309SJohn Baldwin int arg; 1084d087a399SNeel Natu 10857d9ef309SJohn Baldwin return (vcpu_ioctl(vcpu, VM_RESTART_INSTRUCTION, &arg)); 1086d087a399SNeel Natu } 108700ef17beSBartek Rutkowski 108800ef17beSBartek Rutkowski int 10890f735657SJohn Baldwin vm_snapshot_req(struct vmctx *ctx, struct vm_snapshot_meta *meta) 1090483d953aSJohn Baldwin { 1091483d953aSJohn Baldwin 10920f735657SJohn Baldwin if (ioctl(ctx->fd, VM_SNAPSHOT_REQ, meta) == -1) { 1093483d953aSJohn Baldwin #ifdef SNAPSHOT_DEBUG 1094483d953aSJohn Baldwin fprintf(stderr, "%s: snapshot failed for %s: %d\r\n", 1095483d953aSJohn Baldwin __func__, meta->dev_name, errno); 1096483d953aSJohn Baldwin #endif 1097483d953aSJohn Baldwin return (-1); 1098483d953aSJohn Baldwin } 1099483d953aSJohn Baldwin return (0); 1100483d953aSJohn Baldwin } 1101483d953aSJohn Baldwin 1102483d953aSJohn Baldwin int 1103483d953aSJohn Baldwin vm_restore_time(struct vmctx *ctx) 1104483d953aSJohn Baldwin { 1105483d953aSJohn Baldwin int dummy; 1106483d953aSJohn Baldwin 1107483d953aSJohn Baldwin dummy = 0; 1108483d953aSJohn Baldwin return (ioctl(ctx->fd, VM_RESTORE_TIME, &dummy)); 1109483d953aSJohn Baldwin } 1110*56a26fc1SMark Johnston #endif 1111483d953aSJohn Baldwin 1112483d953aSJohn Baldwin int 111301d822d3SRodney W. Grimes vm_set_topology(struct vmctx *ctx, 111401d822d3SRodney W. Grimes uint16_t sockets, uint16_t cores, uint16_t threads, uint16_t maxcpus) 111501d822d3SRodney W. Grimes { 111601d822d3SRodney W. Grimes struct vm_cpu_topology topology; 111701d822d3SRodney W. Grimes 111801d822d3SRodney W. Grimes bzero(&topology, sizeof (struct vm_cpu_topology)); 111901d822d3SRodney W. Grimes topology.sockets = sockets; 112001d822d3SRodney W. Grimes topology.cores = cores; 112101d822d3SRodney W. Grimes topology.threads = threads; 112201d822d3SRodney W. Grimes topology.maxcpus = maxcpus; 112301d822d3SRodney W. Grimes return (ioctl(ctx->fd, VM_SET_TOPOLOGY, &topology)); 112401d822d3SRodney W. Grimes } 112501d822d3SRodney W. Grimes 112601d822d3SRodney W. Grimes int 112701d822d3SRodney W. Grimes vm_get_topology(struct vmctx *ctx, 112801d822d3SRodney W. Grimes uint16_t *sockets, uint16_t *cores, uint16_t *threads, uint16_t *maxcpus) 112901d822d3SRodney W. Grimes { 113001d822d3SRodney W. Grimes struct vm_cpu_topology topology; 113101d822d3SRodney W. Grimes int error; 113201d822d3SRodney W. Grimes 113301d822d3SRodney W. Grimes bzero(&topology, sizeof (struct vm_cpu_topology)); 113401d822d3SRodney W. Grimes error = ioctl(ctx->fd, VM_GET_TOPOLOGY, &topology); 113501d822d3SRodney W. Grimes if (error == 0) { 113601d822d3SRodney W. Grimes *sockets = topology.sockets; 113701d822d3SRodney W. Grimes *cores = topology.cores; 113801d822d3SRodney W. Grimes *threads = topology.threads; 113901d822d3SRodney W. Grimes *maxcpus = topology.maxcpus; 114001d822d3SRodney W. Grimes } 114101d822d3SRodney W. Grimes return (error); 114201d822d3SRodney W. Grimes } 114301d822d3SRodney W. Grimes 11443e9b4532SMark Johnston int 11453e9b4532SMark Johnston vm_limit_rights(struct vmctx *ctx) 11463e9b4532SMark Johnston { 11473e9b4532SMark Johnston cap_rights_t rights; 11483e9b4532SMark Johnston 11493e9b4532SMark Johnston cap_rights_init(&rights, CAP_IOCTL, CAP_MMAP_RW); 11503e9b4532SMark Johnston if (caph_rights_limit(ctx->fd, &rights) != 0) 11513e9b4532SMark Johnston return (-1); 11527f00e46bSMark Johnston if (caph_ioctls_limit(ctx->fd, vm_ioctl_cmds, vm_ioctl_ncmds) != 0) 11533e9b4532SMark Johnston return (-1); 11543e9b4532SMark Johnston return (0); 11553e9b4532SMark Johnston } 11563e9b4532SMark Johnston 11573e9b4532SMark Johnston /* 11583e9b4532SMark Johnston * Avoid using in new code. Operations on the fd should be wrapped here so that 11593e9b4532SMark Johnston * capability rights can be kept in sync. 11603e9b4532SMark Johnston */ 11613e9b4532SMark Johnston int 11623e9b4532SMark Johnston vm_get_device_fd(struct vmctx *ctx) 11633e9b4532SMark Johnston { 11643e9b4532SMark Johnston 11653e9b4532SMark Johnston return (ctx->fd); 11663e9b4532SMark Johnston } 11673e9b4532SMark Johnston 11683e9b4532SMark Johnston /* Legacy interface, do not use. */ 11693e9b4532SMark Johnston const cap_ioctl_t * 11703e9b4532SMark Johnston vm_get_ioctls(size_t *len) 11713e9b4532SMark Johnston { 11723e9b4532SMark Johnston cap_ioctl_t *cmds; 11737f00e46bSMark Johnston size_t sz; 117400ef17beSBartek Rutkowski 117500ef17beSBartek Rutkowski if (len == NULL) { 11767f00e46bSMark Johnston sz = vm_ioctl_ncmds * sizeof(vm_ioctl_cmds[0]); 11777f00e46bSMark Johnston cmds = malloc(sz); 117800ef17beSBartek Rutkowski if (cmds == NULL) 117900ef17beSBartek Rutkowski return (NULL); 11807f00e46bSMark Johnston bcopy(vm_ioctl_cmds, cmds, sz); 118100ef17beSBartek Rutkowski return (cmds); 118200ef17beSBartek Rutkowski } 118300ef17beSBartek Rutkowski 11847f00e46bSMark Johnston *len = vm_ioctl_ncmds; 118500ef17beSBartek Rutkowski return (NULL); 118600ef17beSBartek Rutkowski } 1187