1366f6083SPeter Grehan /*- 25e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 29366f6083SPeter Grehan */ 30366f6083SPeter Grehan 31366f6083SPeter Grehan #include <sys/cdefs.h> 32366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 33366f6083SPeter Grehan 3495ebc360SNeel Natu #include <sys/param.h> 35366f6083SPeter Grehan #include <sys/sysctl.h> 36366f6083SPeter Grehan #include <sys/ioctl.h> 37a71dc724SMarcelo Araujo #include <sys/linker.h> 38366f6083SPeter Grehan #include <sys/mman.h> 39a71dc724SMarcelo Araujo #include <sys/module.h> 406303b65dSNeel Natu #include <sys/_iovec.h> 4195ebc360SNeel Natu #include <sys/cpuset.h> 42366f6083SPeter Grehan 43d665d229SNeel Natu #include <x86/segments.h> 44366f6083SPeter Grehan #include <machine/specialreg.h> 45366f6083SPeter Grehan 469c4d5478SNeel Natu #include <errno.h> 47483d953aSJohn Baldwin #include <stdbool.h> 48366f6083SPeter Grehan #include <stdio.h> 49366f6083SPeter Grehan #include <stdlib.h> 50366f6083SPeter Grehan #include <assert.h> 51366f6083SPeter Grehan #include <string.h> 52366f6083SPeter Grehan #include <fcntl.h> 53366f6083SPeter Grehan #include <unistd.h> 54366f6083SPeter Grehan 55200758f1SNeel Natu #include <libutil.h> 56200758f1SNeel Natu 57483d953aSJohn Baldwin #include <vm/vm.h> 58366f6083SPeter Grehan #include <machine/vmm.h> 59366f6083SPeter Grehan #include <machine/vmm_dev.h> 60483d953aSJohn Baldwin #include <machine/vmm_snapshot.h> 61366f6083SPeter Grehan 62366f6083SPeter Grehan #include "vmmapi.h" 63366f6083SPeter Grehan 64200758f1SNeel Natu #define MB (1024 * 1024UL) 65b060ba50SNeel Natu #define GB (1024 * 1024 * 1024UL) 66b060ba50SNeel Natu 679b1aa8d6SNeel Natu /* 689b1aa8d6SNeel Natu * Size of the guard region before and after the virtual address space 699b1aa8d6SNeel Natu * mapping the guest physical memory. This must be a multiple of the 709b1aa8d6SNeel Natu * superpage size for performance reasons. 719b1aa8d6SNeel Natu */ 729b1aa8d6SNeel Natu #define VM_MMAP_GUARD_SIZE (4 * MB) 739b1aa8d6SNeel Natu 749b1aa8d6SNeel Natu #define PROT_RW (PROT_READ | PROT_WRITE) 759b1aa8d6SNeel Natu #define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC) 769b1aa8d6SNeel Natu 77366f6083SPeter Grehan struct vmctx { 78366f6083SPeter Grehan int fd; 79b060ba50SNeel Natu uint32_t lowmem_limit; 800dd10c00SNeel Natu int memflags; 81b060ba50SNeel Natu size_t lowmem; 82b060ba50SNeel Natu size_t highmem; 839b1aa8d6SNeel Natu char *baseaddr; 84366f6083SPeter Grehan char *name; 85366f6083SPeter Grehan }; 86366f6083SPeter Grehan 87366f6083SPeter Grehan #define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x))) 88366f6083SPeter Grehan #define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x))) 89366f6083SPeter Grehan 90366f6083SPeter Grehan static int 91366f6083SPeter Grehan vm_device_open(const char *name) 92366f6083SPeter Grehan { 93366f6083SPeter Grehan int fd, len; 94366f6083SPeter Grehan char *vmfile; 95366f6083SPeter Grehan 96366f6083SPeter Grehan len = strlen("/dev/vmm/") + strlen(name) + 1; 97366f6083SPeter Grehan vmfile = malloc(len); 98366f6083SPeter Grehan assert(vmfile != NULL); 99366f6083SPeter Grehan snprintf(vmfile, len, "/dev/vmm/%s", name); 100366f6083SPeter Grehan 101366f6083SPeter Grehan /* Open the device file */ 102366f6083SPeter Grehan fd = open(vmfile, O_RDWR, 0); 103366f6083SPeter Grehan 104366f6083SPeter Grehan free(vmfile); 105366f6083SPeter Grehan return (fd); 106366f6083SPeter Grehan } 107366f6083SPeter Grehan 108366f6083SPeter Grehan int 109366f6083SPeter Grehan vm_create(const char *name) 110366f6083SPeter Grehan { 111a71dc724SMarcelo Araujo /* Try to load vmm(4) module before creating a guest. */ 112a71dc724SMarcelo Araujo if (modfind("vmm") < 0) 113a71dc724SMarcelo Araujo kldload("vmm"); 114366f6083SPeter Grehan return (CREATE((char *)name)); 115366f6083SPeter Grehan } 116366f6083SPeter Grehan 117366f6083SPeter Grehan struct vmctx * 118366f6083SPeter Grehan vm_open(const char *name) 119366f6083SPeter Grehan { 120366f6083SPeter Grehan struct vmctx *vm; 121*a7f81b48SRobert Wing int saved_errno; 122366f6083SPeter Grehan 123366f6083SPeter Grehan vm = malloc(sizeof(struct vmctx) + strlen(name) + 1); 124366f6083SPeter Grehan assert(vm != NULL); 125366f6083SPeter Grehan 126366f6083SPeter Grehan vm->fd = -1; 1270dd10c00SNeel Natu vm->memflags = 0; 128b060ba50SNeel Natu vm->lowmem_limit = 3 * GB; 129366f6083SPeter Grehan vm->name = (char *)(vm + 1); 130366f6083SPeter Grehan strcpy(vm->name, name); 131366f6083SPeter Grehan 132366f6083SPeter Grehan if ((vm->fd = vm_device_open(vm->name)) < 0) 133366f6083SPeter Grehan goto err; 134366f6083SPeter Grehan 135366f6083SPeter Grehan return (vm); 136366f6083SPeter Grehan err: 137*a7f81b48SRobert Wing saved_errno = errno; 1386bb140e3SRobert Wing free(vm); 139*a7f81b48SRobert Wing errno = saved_errno; 140366f6083SPeter Grehan return (NULL); 141366f6083SPeter Grehan } 142366f6083SPeter Grehan 143366f6083SPeter Grehan void 144366f6083SPeter Grehan vm_destroy(struct vmctx *vm) 145366f6083SPeter Grehan { 146366f6083SPeter Grehan assert(vm != NULL); 147366f6083SPeter Grehan 148366f6083SPeter Grehan if (vm->fd >= 0) 149366f6083SPeter Grehan close(vm->fd); 150f7d51510SNeel Natu DESTROY(vm->name); 151f7d51510SNeel Natu 152366f6083SPeter Grehan free(vm); 153366f6083SPeter Grehan } 154366f6083SPeter Grehan 155366f6083SPeter Grehan int 156200758f1SNeel Natu vm_parse_memsize(const char *optarg, size_t *ret_memsize) 157200758f1SNeel Natu { 158200758f1SNeel Natu char *endptr; 159200758f1SNeel Natu size_t optval; 160200758f1SNeel Natu int error; 161200758f1SNeel Natu 162200758f1SNeel Natu optval = strtoul(optarg, &endptr, 0); 163200758f1SNeel Natu if (*optarg != '\0' && *endptr == '\0') { 164200758f1SNeel Natu /* 165200758f1SNeel Natu * For the sake of backward compatibility if the memory size 166200758f1SNeel Natu * specified on the command line is less than a megabyte then 167200758f1SNeel Natu * it is interpreted as being in units of MB. 168200758f1SNeel Natu */ 169200758f1SNeel Natu if (optval < MB) 170200758f1SNeel Natu optval *= MB; 171200758f1SNeel Natu *ret_memsize = optval; 172200758f1SNeel Natu error = 0; 173200758f1SNeel Natu } else 174200758f1SNeel Natu error = expand_number(optarg, ret_memsize); 175200758f1SNeel Natu 176200758f1SNeel Natu return (error); 177200758f1SNeel Natu } 178200758f1SNeel Natu 179b060ba50SNeel Natu uint32_t 180b060ba50SNeel Natu vm_get_lowmem_limit(struct vmctx *ctx) 181b060ba50SNeel Natu { 182b060ba50SNeel Natu 183b060ba50SNeel Natu return (ctx->lowmem_limit); 184b060ba50SNeel Natu } 185b060ba50SNeel Natu 186b060ba50SNeel Natu void 187b060ba50SNeel Natu vm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit) 188b060ba50SNeel Natu { 189b060ba50SNeel Natu 190b060ba50SNeel Natu ctx->lowmem_limit = limit; 191b060ba50SNeel Natu } 192b060ba50SNeel Natu 1930dd10c00SNeel Natu void 1940dd10c00SNeel Natu vm_set_memflags(struct vmctx *ctx, int flags) 1950dd10c00SNeel Natu { 1960dd10c00SNeel Natu 1970dd10c00SNeel Natu ctx->memflags = flags; 1980dd10c00SNeel Natu } 1990dd10c00SNeel Natu 2009b1aa8d6SNeel Natu int 2019b1aa8d6SNeel Natu vm_get_memflags(struct vmctx *ctx) 202366f6083SPeter Grehan { 2039b1aa8d6SNeel Natu 2049b1aa8d6SNeel Natu return (ctx->memflags); 2059b1aa8d6SNeel Natu } 206366f6083SPeter Grehan 207366f6083SPeter Grehan /* 2089b1aa8d6SNeel Natu * Map segment 'segid' starting at 'off' into guest address range [gpa,gpa+len). 209366f6083SPeter Grehan */ 2109b1aa8d6SNeel Natu int 2119b1aa8d6SNeel Natu vm_mmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, int segid, vm_ooffset_t off, 2129b1aa8d6SNeel Natu size_t len, int prot) 2139b1aa8d6SNeel Natu { 2149b1aa8d6SNeel Natu struct vm_memmap memmap; 2159b1aa8d6SNeel Natu int error, flags; 2169b1aa8d6SNeel Natu 2179b1aa8d6SNeel Natu memmap.gpa = gpa; 2189b1aa8d6SNeel Natu memmap.segid = segid; 2199b1aa8d6SNeel Natu memmap.segoff = off; 2209b1aa8d6SNeel Natu memmap.len = len; 2219b1aa8d6SNeel Natu memmap.prot = prot; 2229b1aa8d6SNeel Natu memmap.flags = 0; 2239b1aa8d6SNeel Natu 2249b1aa8d6SNeel Natu if (ctx->memflags & VM_MEM_F_WIRED) 2259b1aa8d6SNeel Natu memmap.flags |= VM_MEMMAP_F_WIRED; 2269b1aa8d6SNeel Natu 2279b1aa8d6SNeel Natu /* 2289b1aa8d6SNeel Natu * If this mapping already exists then don't create it again. This 2299b1aa8d6SNeel Natu * is the common case for SYSMEM mappings created by bhyveload(8). 2309b1aa8d6SNeel Natu */ 2319b1aa8d6SNeel Natu error = vm_mmap_getnext(ctx, &gpa, &segid, &off, &len, &prot, &flags); 2329b1aa8d6SNeel Natu if (error == 0 && gpa == memmap.gpa) { 2339b1aa8d6SNeel Natu if (segid != memmap.segid || off != memmap.segoff || 2349b1aa8d6SNeel Natu prot != memmap.prot || flags != memmap.flags) { 2359b1aa8d6SNeel Natu errno = EEXIST; 2369b1aa8d6SNeel Natu return (-1); 2379b1aa8d6SNeel Natu } else { 2389b1aa8d6SNeel Natu return (0); 2399b1aa8d6SNeel Natu } 2409b1aa8d6SNeel Natu } 2419b1aa8d6SNeel Natu 2429b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_MMAP_MEMSEG, &memmap); 2439b1aa8d6SNeel Natu return (error); 2449b1aa8d6SNeel Natu } 2459b1aa8d6SNeel Natu 2469b1aa8d6SNeel Natu int 247483d953aSJohn Baldwin vm_get_guestmem_from_ctx(struct vmctx *ctx, char **guest_baseaddr, 248483d953aSJohn Baldwin size_t *lowmem_size, size_t *highmem_size) 249483d953aSJohn Baldwin { 250483d953aSJohn Baldwin 251483d953aSJohn Baldwin *guest_baseaddr = ctx->baseaddr; 252483d953aSJohn Baldwin *lowmem_size = ctx->lowmem; 253483d953aSJohn Baldwin *highmem_size = ctx->highmem; 254483d953aSJohn Baldwin return (0); 255483d953aSJohn Baldwin } 256483d953aSJohn Baldwin 257483d953aSJohn Baldwin int 258f8a6ec2dSD Scott Phillips vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, size_t len) 259f8a6ec2dSD Scott Phillips { 260f8a6ec2dSD Scott Phillips struct vm_munmap munmap; 261f8a6ec2dSD Scott Phillips int error; 262f8a6ec2dSD Scott Phillips 263f8a6ec2dSD Scott Phillips munmap.gpa = gpa; 264f8a6ec2dSD Scott Phillips munmap.len = len; 265f8a6ec2dSD Scott Phillips 266f8a6ec2dSD Scott Phillips error = ioctl(ctx->fd, VM_MUNMAP_MEMSEG, &munmap); 267f8a6ec2dSD Scott Phillips return (error); 268f8a6ec2dSD Scott Phillips } 269f8a6ec2dSD Scott Phillips 270f8a6ec2dSD Scott Phillips int 2719b1aa8d6SNeel Natu vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid, 2729b1aa8d6SNeel Natu vm_ooffset_t *segoff, size_t *len, int *prot, int *flags) 2739b1aa8d6SNeel Natu { 2749b1aa8d6SNeel Natu struct vm_memmap memmap; 2759b1aa8d6SNeel Natu int error; 2769b1aa8d6SNeel Natu 2779b1aa8d6SNeel Natu bzero(&memmap, sizeof(struct vm_memmap)); 2789b1aa8d6SNeel Natu memmap.gpa = *gpa; 2799b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_MMAP_GETNEXT, &memmap); 2809b1aa8d6SNeel Natu if (error == 0) { 2819b1aa8d6SNeel Natu *gpa = memmap.gpa; 2829b1aa8d6SNeel Natu *segid = memmap.segid; 2839b1aa8d6SNeel Natu *segoff = memmap.segoff; 2849b1aa8d6SNeel Natu *len = memmap.len; 2859b1aa8d6SNeel Natu *prot = memmap.prot; 2869b1aa8d6SNeel Natu *flags = memmap.flags; 287366f6083SPeter Grehan } 288366f6083SPeter Grehan return (error); 289366f6083SPeter Grehan } 290366f6083SPeter Grehan 2919b1aa8d6SNeel Natu /* 2929b1aa8d6SNeel Natu * Return 0 if the segments are identical and non-zero otherwise. 2939b1aa8d6SNeel Natu * 2949b1aa8d6SNeel Natu * This is slightly complicated by the fact that only device memory segments 2959b1aa8d6SNeel Natu * are named. 2969b1aa8d6SNeel Natu */ 2979b1aa8d6SNeel Natu static int 2989b1aa8d6SNeel Natu cmpseg(size_t len, const char *str, size_t len2, const char *str2) 2999b1aa8d6SNeel Natu { 3009b1aa8d6SNeel Natu 3019b1aa8d6SNeel Natu if (len == len2) { 3029b1aa8d6SNeel Natu if ((!str && !str2) || (str && str2 && !strcmp(str, str2))) 3039b1aa8d6SNeel Natu return (0); 3049b1aa8d6SNeel Natu } 3059b1aa8d6SNeel Natu return (-1); 3069b1aa8d6SNeel Natu } 3079b1aa8d6SNeel Natu 3089b1aa8d6SNeel Natu static int 3099b1aa8d6SNeel Natu vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name) 3109b1aa8d6SNeel Natu { 3119b1aa8d6SNeel Natu struct vm_memseg memseg; 3129b1aa8d6SNeel Natu size_t n; 3139b1aa8d6SNeel Natu int error; 3149b1aa8d6SNeel Natu 3159b1aa8d6SNeel Natu /* 3169b1aa8d6SNeel Natu * If the memory segment has already been created then just return. 3179b1aa8d6SNeel Natu * This is the usual case for the SYSMEM segment created by userspace 3189b1aa8d6SNeel Natu * loaders like bhyveload(8). 3199b1aa8d6SNeel Natu */ 3209b1aa8d6SNeel Natu error = vm_get_memseg(ctx, segid, &memseg.len, memseg.name, 3219b1aa8d6SNeel Natu sizeof(memseg.name)); 3229b1aa8d6SNeel Natu if (error) 3239b1aa8d6SNeel Natu return (error); 3249b1aa8d6SNeel Natu 3259b1aa8d6SNeel Natu if (memseg.len != 0) { 3269b1aa8d6SNeel Natu if (cmpseg(len, name, memseg.len, VM_MEMSEG_NAME(&memseg))) { 3279b1aa8d6SNeel Natu errno = EINVAL; 3289b1aa8d6SNeel Natu return (-1); 3299b1aa8d6SNeel Natu } else { 3309b1aa8d6SNeel Natu return (0); 3319b1aa8d6SNeel Natu } 3329b1aa8d6SNeel Natu } 3339b1aa8d6SNeel Natu 3349b1aa8d6SNeel Natu bzero(&memseg, sizeof(struct vm_memseg)); 3359b1aa8d6SNeel Natu memseg.segid = segid; 3369b1aa8d6SNeel Natu memseg.len = len; 3379b1aa8d6SNeel Natu if (name != NULL) { 3389b1aa8d6SNeel Natu n = strlcpy(memseg.name, name, sizeof(memseg.name)); 3399b1aa8d6SNeel Natu if (n >= sizeof(memseg.name)) { 3409b1aa8d6SNeel Natu errno = ENAMETOOLONG; 3419b1aa8d6SNeel Natu return (-1); 3429b1aa8d6SNeel Natu } 3439b1aa8d6SNeel Natu } 3449b1aa8d6SNeel Natu 3459b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_ALLOC_MEMSEG, &memseg); 3469b1aa8d6SNeel Natu return (error); 3479b1aa8d6SNeel Natu } 3489b1aa8d6SNeel Natu 3499b1aa8d6SNeel Natu int 3509b1aa8d6SNeel Natu vm_get_memseg(struct vmctx *ctx, int segid, size_t *lenp, char *namebuf, 3519b1aa8d6SNeel Natu size_t bufsize) 3529b1aa8d6SNeel Natu { 3539b1aa8d6SNeel Natu struct vm_memseg memseg; 3549b1aa8d6SNeel Natu size_t n; 3559b1aa8d6SNeel Natu int error; 3569b1aa8d6SNeel Natu 3579b1aa8d6SNeel Natu memseg.segid = segid; 3589b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_GET_MEMSEG, &memseg); 3599b1aa8d6SNeel Natu if (error == 0) { 3609b1aa8d6SNeel Natu *lenp = memseg.len; 3619b1aa8d6SNeel Natu n = strlcpy(namebuf, memseg.name, bufsize); 3629b1aa8d6SNeel Natu if (n >= bufsize) { 3639b1aa8d6SNeel Natu errno = ENAMETOOLONG; 3649b1aa8d6SNeel Natu error = -1; 3659b1aa8d6SNeel Natu } 3669b1aa8d6SNeel Natu } 3679b1aa8d6SNeel Natu return (error); 3689b1aa8d6SNeel Natu } 3699b1aa8d6SNeel Natu 3709b1aa8d6SNeel Natu static int 3719b1aa8d6SNeel Natu setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base) 3729b1aa8d6SNeel Natu { 3739b1aa8d6SNeel Natu char *ptr; 3749b1aa8d6SNeel Natu int error, flags; 3759b1aa8d6SNeel Natu 3769b1aa8d6SNeel Natu /* Map 'len' bytes starting at 'gpa' in the guest address space */ 3779b1aa8d6SNeel Natu error = vm_mmap_memseg(ctx, gpa, VM_SYSMEM, gpa, len, PROT_ALL); 3789b1aa8d6SNeel Natu if (error) 3799b1aa8d6SNeel Natu return (error); 3809b1aa8d6SNeel Natu 3819b1aa8d6SNeel Natu flags = MAP_SHARED | MAP_FIXED; 3829b1aa8d6SNeel Natu if ((ctx->memflags & VM_MEM_F_INCORE) == 0) 3839b1aa8d6SNeel Natu flags |= MAP_NOCORE; 3849b1aa8d6SNeel Natu 3859b1aa8d6SNeel Natu /* mmap into the process address space on the host */ 3869b1aa8d6SNeel Natu ptr = mmap(base + gpa, len, PROT_RW, flags, ctx->fd, gpa); 3879b1aa8d6SNeel Natu if (ptr == MAP_FAILED) 3889b1aa8d6SNeel Natu return (-1); 3899b1aa8d6SNeel Natu 3909b1aa8d6SNeel Natu return (0); 3919b1aa8d6SNeel Natu } 3929b1aa8d6SNeel Natu 393b060ba50SNeel Natu int 394b060ba50SNeel Natu vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms) 395b060ba50SNeel Natu { 3969b1aa8d6SNeel Natu size_t objsize, len; 3979b1aa8d6SNeel Natu vm_paddr_t gpa; 3989b1aa8d6SNeel Natu char *baseaddr, *ptr; 3996a9648b5SJohn Baldwin int error; 400b060ba50SNeel Natu 4019b1aa8d6SNeel Natu assert(vms == VM_MMAP_ALL); 402b060ba50SNeel Natu 403b060ba50SNeel Natu /* 404b060ba50SNeel Natu * If 'memsize' cannot fit entirely in the 'lowmem' segment then 405b060ba50SNeel Natu * create another 'highmem' segment above 4GB for the remainder. 406b060ba50SNeel Natu */ 407b060ba50SNeel Natu if (memsize > ctx->lowmem_limit) { 408b060ba50SNeel Natu ctx->lowmem = ctx->lowmem_limit; 4099b1aa8d6SNeel Natu ctx->highmem = memsize - ctx->lowmem_limit; 4109b1aa8d6SNeel Natu objsize = 4*GB + ctx->highmem; 411b060ba50SNeel Natu } else { 412b060ba50SNeel Natu ctx->lowmem = memsize; 413b060ba50SNeel Natu ctx->highmem = 0; 4149b1aa8d6SNeel Natu objsize = ctx->lowmem; 4159b1aa8d6SNeel Natu } 4169b1aa8d6SNeel Natu 4179b1aa8d6SNeel Natu error = vm_alloc_memseg(ctx, VM_SYSMEM, objsize, NULL); 4189b1aa8d6SNeel Natu if (error) 4199b1aa8d6SNeel Natu return (error); 4209b1aa8d6SNeel Natu 4219b1aa8d6SNeel Natu /* 4229b1aa8d6SNeel Natu * Stake out a contiguous region covering the guest physical memory 4239b1aa8d6SNeel Natu * and the adjoining guard regions. 4249b1aa8d6SNeel Natu */ 4259b1aa8d6SNeel Natu len = VM_MMAP_GUARD_SIZE + objsize + VM_MMAP_GUARD_SIZE; 4266a9648b5SJohn Baldwin ptr = mmap(NULL, len, PROT_NONE, MAP_GUARD | MAP_ALIGNED_SUPER, -1, 0); 4279b1aa8d6SNeel Natu if (ptr == MAP_FAILED) 4289b1aa8d6SNeel Natu return (-1); 4299b1aa8d6SNeel Natu 4309b1aa8d6SNeel Natu baseaddr = ptr + VM_MMAP_GUARD_SIZE; 4319b1aa8d6SNeel Natu if (ctx->highmem > 0) { 4329b1aa8d6SNeel Natu gpa = 4*GB; 4339b1aa8d6SNeel Natu len = ctx->highmem; 4349b1aa8d6SNeel Natu error = setup_memory_segment(ctx, gpa, len, baseaddr); 4359b1aa8d6SNeel Natu if (error) 4369b1aa8d6SNeel Natu return (error); 437b060ba50SNeel Natu } 438b060ba50SNeel Natu 439b060ba50SNeel Natu if (ctx->lowmem > 0) { 4409b1aa8d6SNeel Natu gpa = 0; 4419b1aa8d6SNeel Natu len = ctx->lowmem; 4429b1aa8d6SNeel Natu error = setup_memory_segment(ctx, gpa, len, baseaddr); 443b060ba50SNeel Natu if (error) 444b060ba50SNeel Natu return (error); 445b060ba50SNeel Natu } 446b060ba50SNeel Natu 4479b1aa8d6SNeel Natu ctx->baseaddr = baseaddr; 448b060ba50SNeel Natu 449b060ba50SNeel Natu return (0); 450b060ba50SNeel Natu } 451b060ba50SNeel Natu 45236e8356eSNeel Natu /* 45336e8356eSNeel Natu * Returns a non-NULL pointer if [gaddr, gaddr+len) is entirely contained in 45436e8356eSNeel Natu * the lowmem or highmem regions. 45536e8356eSNeel Natu * 45636e8356eSNeel Natu * In particular return NULL if [gaddr, gaddr+len) falls in guest MMIO region. 45736e8356eSNeel Natu * The instruction emulation code depends on this behavior. 45836e8356eSNeel Natu */ 459b060ba50SNeel Natu void * 460b060ba50SNeel Natu vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len) 461366f6083SPeter Grehan { 462366f6083SPeter Grehan 46336e8356eSNeel Natu if (ctx->lowmem > 0) { 464edc816d6SGleb Smirnoff if (gaddr < ctx->lowmem && len <= ctx->lowmem && 465edc816d6SGleb Smirnoff gaddr + len <= ctx->lowmem) 46636e8356eSNeel Natu return (ctx->baseaddr + gaddr); 46736e8356eSNeel Natu } 468b060ba50SNeel Natu 46936e8356eSNeel Natu if (ctx->highmem > 0) { 470edc816d6SGleb Smirnoff if (gaddr >= 4*GB) { 471edc816d6SGleb Smirnoff if (gaddr < 4*GB + ctx->highmem && 472edc816d6SGleb Smirnoff len <= ctx->highmem && 473edc816d6SGleb Smirnoff gaddr + len <= 4*GB + ctx->highmem) 47436e8356eSNeel Natu return (ctx->baseaddr + gaddr); 47536e8356eSNeel Natu } 476edc816d6SGleb Smirnoff } 47736e8356eSNeel Natu 478b060ba50SNeel Natu return (NULL); 479366f6083SPeter Grehan } 480366f6083SPeter Grehan 481483d953aSJohn Baldwin vm_paddr_t 482483d953aSJohn Baldwin vm_rev_map_gpa(struct vmctx *ctx, void *addr) 483483d953aSJohn Baldwin { 484483d953aSJohn Baldwin vm_paddr_t offaddr; 485483d953aSJohn Baldwin 486483d953aSJohn Baldwin offaddr = (char *)addr - ctx->baseaddr; 487483d953aSJohn Baldwin 488483d953aSJohn Baldwin if (ctx->lowmem > 0) 489483d953aSJohn Baldwin if (offaddr >= 0 && offaddr <= ctx->lowmem) 490483d953aSJohn Baldwin return (offaddr); 491483d953aSJohn Baldwin 492483d953aSJohn Baldwin if (ctx->highmem > 0) 493483d953aSJohn Baldwin if (offaddr >= 4*GB && offaddr < 4*GB + ctx->highmem) 494483d953aSJohn Baldwin return (offaddr); 495483d953aSJohn Baldwin 496483d953aSJohn Baldwin return ((vm_paddr_t)-1); 497483d953aSJohn Baldwin } 498483d953aSJohn Baldwin 499483d953aSJohn Baldwin /* TODO: maximum size for vmname */ 500483d953aSJohn Baldwin int 501483d953aSJohn Baldwin vm_get_name(struct vmctx *ctx, char *buf, size_t max_len) 502483d953aSJohn Baldwin { 503483d953aSJohn Baldwin 504483d953aSJohn Baldwin if (strlcpy(buf, ctx->name, max_len) >= max_len) 505483d953aSJohn Baldwin return (EINVAL); 506483d953aSJohn Baldwin return (0); 507483d953aSJohn Baldwin } 508483d953aSJohn Baldwin 509be679db4SNeel Natu size_t 510be679db4SNeel Natu vm_get_lowmem_size(struct vmctx *ctx) 511be679db4SNeel Natu { 512be679db4SNeel Natu 513be679db4SNeel Natu return (ctx->lowmem); 514be679db4SNeel Natu } 515be679db4SNeel Natu 516be679db4SNeel Natu size_t 517be679db4SNeel Natu vm_get_highmem_size(struct vmctx *ctx) 518be679db4SNeel Natu { 519be679db4SNeel Natu 520be679db4SNeel Natu return (ctx->highmem); 521be679db4SNeel Natu } 522be679db4SNeel Natu 5239b1aa8d6SNeel Natu void * 5249b1aa8d6SNeel Natu vm_create_devmem(struct vmctx *ctx, int segid, const char *name, size_t len) 5259b1aa8d6SNeel Natu { 5269b1aa8d6SNeel Natu char pathname[MAXPATHLEN]; 5279b1aa8d6SNeel Natu size_t len2; 5289b1aa8d6SNeel Natu char *base, *ptr; 5299b1aa8d6SNeel Natu int fd, error, flags; 5309b1aa8d6SNeel Natu 5319b1aa8d6SNeel Natu fd = -1; 5329b1aa8d6SNeel Natu ptr = MAP_FAILED; 5339b1aa8d6SNeel Natu if (name == NULL || strlen(name) == 0) { 5349b1aa8d6SNeel Natu errno = EINVAL; 5359b1aa8d6SNeel Natu goto done; 5369b1aa8d6SNeel Natu } 5379b1aa8d6SNeel Natu 5389b1aa8d6SNeel Natu error = vm_alloc_memseg(ctx, segid, len, name); 5399b1aa8d6SNeel Natu if (error) 5409b1aa8d6SNeel Natu goto done; 5419b1aa8d6SNeel Natu 5425e4f29c0SNeel Natu strlcpy(pathname, "/dev/vmm.io/", sizeof(pathname)); 5439b1aa8d6SNeel Natu strlcat(pathname, ctx->name, sizeof(pathname)); 5449b1aa8d6SNeel Natu strlcat(pathname, ".", sizeof(pathname)); 5459b1aa8d6SNeel Natu strlcat(pathname, name, sizeof(pathname)); 5469b1aa8d6SNeel Natu 5479b1aa8d6SNeel Natu fd = open(pathname, O_RDWR); 5489b1aa8d6SNeel Natu if (fd < 0) 5499b1aa8d6SNeel Natu goto done; 5509b1aa8d6SNeel Natu 5519b1aa8d6SNeel Natu /* 5529b1aa8d6SNeel Natu * Stake out a contiguous region covering the device memory and the 5539b1aa8d6SNeel Natu * adjoining guard regions. 5549b1aa8d6SNeel Natu */ 5559b1aa8d6SNeel Natu len2 = VM_MMAP_GUARD_SIZE + len + VM_MMAP_GUARD_SIZE; 5566a9648b5SJohn Baldwin base = mmap(NULL, len2, PROT_NONE, MAP_GUARD | MAP_ALIGNED_SUPER, -1, 5576a9648b5SJohn Baldwin 0); 5589b1aa8d6SNeel Natu if (base == MAP_FAILED) 5599b1aa8d6SNeel Natu goto done; 5609b1aa8d6SNeel Natu 5619b1aa8d6SNeel Natu flags = MAP_SHARED | MAP_FIXED; 5629b1aa8d6SNeel Natu if ((ctx->memflags & VM_MEM_F_INCORE) == 0) 5639b1aa8d6SNeel Natu flags |= MAP_NOCORE; 5649b1aa8d6SNeel Natu 5659b1aa8d6SNeel Natu /* mmap the devmem region in the host address space */ 5669b1aa8d6SNeel Natu ptr = mmap(base + VM_MMAP_GUARD_SIZE, len, PROT_RW, flags, fd, 0); 5679b1aa8d6SNeel Natu done: 5689b1aa8d6SNeel Natu if (fd >= 0) 5699b1aa8d6SNeel Natu close(fd); 5709b1aa8d6SNeel Natu return (ptr); 5719b1aa8d6SNeel Natu } 5729b1aa8d6SNeel Natu 573366f6083SPeter Grehan int 574366f6083SPeter Grehan vm_set_desc(struct vmctx *ctx, int vcpu, int reg, 575366f6083SPeter Grehan uint64_t base, uint32_t limit, uint32_t access) 576366f6083SPeter Grehan { 577366f6083SPeter Grehan int error; 578366f6083SPeter Grehan struct vm_seg_desc vmsegdesc; 579366f6083SPeter Grehan 580366f6083SPeter Grehan bzero(&vmsegdesc, sizeof(vmsegdesc)); 581366f6083SPeter Grehan vmsegdesc.cpuid = vcpu; 582366f6083SPeter Grehan vmsegdesc.regnum = reg; 583366f6083SPeter Grehan vmsegdesc.desc.base = base; 584366f6083SPeter Grehan vmsegdesc.desc.limit = limit; 585366f6083SPeter Grehan vmsegdesc.desc.access = access; 586366f6083SPeter Grehan 587366f6083SPeter Grehan error = ioctl(ctx->fd, VM_SET_SEGMENT_DESCRIPTOR, &vmsegdesc); 588366f6083SPeter Grehan return (error); 589366f6083SPeter Grehan } 590366f6083SPeter Grehan 591366f6083SPeter Grehan int 592366f6083SPeter Grehan vm_get_desc(struct vmctx *ctx, int vcpu, int reg, 593366f6083SPeter Grehan uint64_t *base, uint32_t *limit, uint32_t *access) 594366f6083SPeter Grehan { 595366f6083SPeter Grehan int error; 596366f6083SPeter Grehan struct vm_seg_desc vmsegdesc; 597366f6083SPeter Grehan 598366f6083SPeter Grehan bzero(&vmsegdesc, sizeof(vmsegdesc)); 599366f6083SPeter Grehan vmsegdesc.cpuid = vcpu; 600366f6083SPeter Grehan vmsegdesc.regnum = reg; 601366f6083SPeter Grehan 602366f6083SPeter Grehan error = ioctl(ctx->fd, VM_GET_SEGMENT_DESCRIPTOR, &vmsegdesc); 603366f6083SPeter Grehan if (error == 0) { 604366f6083SPeter Grehan *base = vmsegdesc.desc.base; 605366f6083SPeter Grehan *limit = vmsegdesc.desc.limit; 606366f6083SPeter Grehan *access = vmsegdesc.desc.access; 607366f6083SPeter Grehan } 608366f6083SPeter Grehan return (error); 609366f6083SPeter Grehan } 610366f6083SPeter Grehan 611366f6083SPeter Grehan int 612d665d229SNeel Natu vm_get_seg_desc(struct vmctx *ctx, int vcpu, int reg, struct seg_desc *seg_desc) 613d665d229SNeel Natu { 614d665d229SNeel Natu int error; 615d665d229SNeel Natu 616d665d229SNeel Natu error = vm_get_desc(ctx, vcpu, reg, &seg_desc->base, &seg_desc->limit, 617d665d229SNeel Natu &seg_desc->access); 618d665d229SNeel Natu return (error); 619d665d229SNeel Natu } 620d665d229SNeel Natu 621d665d229SNeel Natu int 622366f6083SPeter Grehan vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val) 623366f6083SPeter Grehan { 624366f6083SPeter Grehan int error; 625366f6083SPeter Grehan struct vm_register vmreg; 626366f6083SPeter Grehan 627366f6083SPeter Grehan bzero(&vmreg, sizeof(vmreg)); 628366f6083SPeter Grehan vmreg.cpuid = vcpu; 629366f6083SPeter Grehan vmreg.regnum = reg; 630366f6083SPeter Grehan vmreg.regval = val; 631366f6083SPeter Grehan 632366f6083SPeter Grehan error = ioctl(ctx->fd, VM_SET_REGISTER, &vmreg); 633366f6083SPeter Grehan return (error); 634366f6083SPeter Grehan } 635366f6083SPeter Grehan 636366f6083SPeter Grehan int 637366f6083SPeter Grehan vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *ret_val) 638366f6083SPeter Grehan { 639366f6083SPeter Grehan int error; 640366f6083SPeter Grehan struct vm_register vmreg; 641366f6083SPeter Grehan 642366f6083SPeter Grehan bzero(&vmreg, sizeof(vmreg)); 643366f6083SPeter Grehan vmreg.cpuid = vcpu; 644366f6083SPeter Grehan vmreg.regnum = reg; 645366f6083SPeter Grehan 646366f6083SPeter Grehan error = ioctl(ctx->fd, VM_GET_REGISTER, &vmreg); 647366f6083SPeter Grehan *ret_val = vmreg.regval; 648366f6083SPeter Grehan return (error); 649366f6083SPeter Grehan } 650366f6083SPeter Grehan 651366f6083SPeter Grehan int 6524f866698SJohn Baldwin vm_set_register_set(struct vmctx *ctx, int vcpu, unsigned int count, 6534f866698SJohn Baldwin const int *regnums, uint64_t *regvals) 6544f866698SJohn Baldwin { 6554f866698SJohn Baldwin int error; 6564f866698SJohn Baldwin struct vm_register_set vmregset; 6574f866698SJohn Baldwin 6584f866698SJohn Baldwin bzero(&vmregset, sizeof(vmregset)); 6594f866698SJohn Baldwin vmregset.cpuid = vcpu; 6604f866698SJohn Baldwin vmregset.count = count; 6614f866698SJohn Baldwin vmregset.regnums = regnums; 6624f866698SJohn Baldwin vmregset.regvals = regvals; 6634f866698SJohn Baldwin 6644f866698SJohn Baldwin error = ioctl(ctx->fd, VM_SET_REGISTER_SET, &vmregset); 6654f866698SJohn Baldwin return (error); 6664f866698SJohn Baldwin } 6674f866698SJohn Baldwin 6684f866698SJohn Baldwin int 6694f866698SJohn Baldwin vm_get_register_set(struct vmctx *ctx, int vcpu, unsigned int count, 6704f866698SJohn Baldwin const int *regnums, uint64_t *regvals) 6714f866698SJohn Baldwin { 6724f866698SJohn Baldwin int error; 6734f866698SJohn Baldwin struct vm_register_set vmregset; 6744f866698SJohn Baldwin 6754f866698SJohn Baldwin bzero(&vmregset, sizeof(vmregset)); 6764f866698SJohn Baldwin vmregset.cpuid = vcpu; 6774f866698SJohn Baldwin vmregset.count = count; 6784f866698SJohn Baldwin vmregset.regnums = regnums; 6794f866698SJohn Baldwin vmregset.regvals = regvals; 6804f866698SJohn Baldwin 6814f866698SJohn Baldwin error = ioctl(ctx->fd, VM_GET_REGISTER_SET, &vmregset); 6824f866698SJohn Baldwin return (error); 6834f866698SJohn Baldwin } 6844f866698SJohn Baldwin 6854f866698SJohn Baldwin int 686d087a399SNeel Natu vm_run(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit) 687366f6083SPeter Grehan { 688366f6083SPeter Grehan int error; 689366f6083SPeter Grehan struct vm_run vmrun; 690366f6083SPeter Grehan 691366f6083SPeter Grehan bzero(&vmrun, sizeof(vmrun)); 692366f6083SPeter Grehan vmrun.cpuid = vcpu; 693366f6083SPeter Grehan 694366f6083SPeter Grehan error = ioctl(ctx->fd, VM_RUN, &vmrun); 695366f6083SPeter Grehan bcopy(&vmrun.vm_exit, vmexit, sizeof(struct vm_exit)); 696366f6083SPeter Grehan return (error); 697366f6083SPeter Grehan } 698366f6083SPeter Grehan 699b15a09c0SNeel Natu int 700f0fdcfe2SNeel Natu vm_suspend(struct vmctx *ctx, enum vm_suspend_how how) 701b15a09c0SNeel Natu { 702f0fdcfe2SNeel Natu struct vm_suspend vmsuspend; 703b15a09c0SNeel Natu 704f0fdcfe2SNeel Natu bzero(&vmsuspend, sizeof(vmsuspend)); 705f0fdcfe2SNeel Natu vmsuspend.how = how; 706f0fdcfe2SNeel Natu return (ioctl(ctx->fd, VM_SUSPEND, &vmsuspend)); 707b15a09c0SNeel Natu } 708b15a09c0SNeel Natu 7095fcf252fSNeel Natu int 7105fcf252fSNeel Natu vm_reinit(struct vmctx *ctx) 7115fcf252fSNeel Natu { 7125fcf252fSNeel Natu 7135fcf252fSNeel Natu return (ioctl(ctx->fd, VM_REINIT, 0)); 7145fcf252fSNeel Natu } 7155fcf252fSNeel Natu 716d087a399SNeel Natu int 717d087a399SNeel Natu vm_inject_exception(struct vmctx *ctx, int vcpu, int vector, int errcode_valid, 718d087a399SNeel Natu uint32_t errcode, int restart_instruction) 719366f6083SPeter Grehan { 720dc506506SNeel Natu struct vm_exception exc; 721366f6083SPeter Grehan 722dc506506SNeel Natu exc.cpuid = vcpu; 723dc506506SNeel Natu exc.vector = vector; 724d087a399SNeel Natu exc.error_code = errcode; 725d087a399SNeel Natu exc.error_code_valid = errcode_valid; 726d087a399SNeel Natu exc.restart_instruction = restart_instruction; 727366f6083SPeter Grehan 728dc506506SNeel Natu return (ioctl(ctx->fd, VM_INJECT_EXCEPTION, &exc)); 729366f6083SPeter Grehan } 730366f6083SPeter Grehan 731366f6083SPeter Grehan int 73290d4b48fSNeel Natu vm_apicid2vcpu(struct vmctx *ctx, int apicid) 73390d4b48fSNeel Natu { 73490d4b48fSNeel Natu /* 73590d4b48fSNeel Natu * The apic id associated with the 'vcpu' has the same numerical value 73690d4b48fSNeel Natu * as the 'vcpu' itself. 73790d4b48fSNeel Natu */ 73890d4b48fSNeel Natu return (apicid); 73990d4b48fSNeel Natu } 74090d4b48fSNeel Natu 74190d4b48fSNeel Natu int 742366f6083SPeter Grehan vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector) 743366f6083SPeter Grehan { 744366f6083SPeter Grehan struct vm_lapic_irq vmirq; 745366f6083SPeter Grehan 746366f6083SPeter Grehan bzero(&vmirq, sizeof(vmirq)); 747366f6083SPeter Grehan vmirq.cpuid = vcpu; 748366f6083SPeter Grehan vmirq.vector = vector; 749366f6083SPeter Grehan 750366f6083SPeter Grehan return (ioctl(ctx->fd, VM_LAPIC_IRQ, &vmirq)); 751366f6083SPeter Grehan } 752366f6083SPeter Grehan 753366f6083SPeter Grehan int 754330baf58SJohn Baldwin vm_lapic_local_irq(struct vmctx *ctx, int vcpu, int vector) 755330baf58SJohn Baldwin { 756330baf58SJohn Baldwin struct vm_lapic_irq vmirq; 757330baf58SJohn Baldwin 758330baf58SJohn Baldwin bzero(&vmirq, sizeof(vmirq)); 759330baf58SJohn Baldwin vmirq.cpuid = vcpu; 760330baf58SJohn Baldwin vmirq.vector = vector; 761330baf58SJohn Baldwin 762330baf58SJohn Baldwin return (ioctl(ctx->fd, VM_LAPIC_LOCAL_IRQ, &vmirq)); 763330baf58SJohn Baldwin } 764330baf58SJohn Baldwin 765330baf58SJohn Baldwin int 7664f8be175SNeel Natu vm_lapic_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg) 7674f8be175SNeel Natu { 7684f8be175SNeel Natu struct vm_lapic_msi vmmsi; 7694f8be175SNeel Natu 7704f8be175SNeel Natu bzero(&vmmsi, sizeof(vmmsi)); 7714f8be175SNeel Natu vmmsi.addr = addr; 7724f8be175SNeel Natu vmmsi.msg = msg; 7734f8be175SNeel Natu 7744f8be175SNeel Natu return (ioctl(ctx->fd, VM_LAPIC_MSI, &vmmsi)); 7754f8be175SNeel Natu } 7764f8be175SNeel Natu 7774f8be175SNeel Natu int 778565bbb86SNeel Natu vm_ioapic_assert_irq(struct vmctx *ctx, int irq) 779565bbb86SNeel Natu { 780565bbb86SNeel Natu struct vm_ioapic_irq ioapic_irq; 781565bbb86SNeel Natu 782565bbb86SNeel Natu bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 783565bbb86SNeel Natu ioapic_irq.irq = irq; 784565bbb86SNeel Natu 785565bbb86SNeel Natu return (ioctl(ctx->fd, VM_IOAPIC_ASSERT_IRQ, &ioapic_irq)); 786565bbb86SNeel Natu } 787565bbb86SNeel Natu 788565bbb86SNeel Natu int 789565bbb86SNeel Natu vm_ioapic_deassert_irq(struct vmctx *ctx, int irq) 790565bbb86SNeel Natu { 791565bbb86SNeel Natu struct vm_ioapic_irq ioapic_irq; 792565bbb86SNeel Natu 793565bbb86SNeel Natu bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 794565bbb86SNeel Natu ioapic_irq.irq = irq; 795565bbb86SNeel Natu 796565bbb86SNeel Natu return (ioctl(ctx->fd, VM_IOAPIC_DEASSERT_IRQ, &ioapic_irq)); 797565bbb86SNeel Natu } 798565bbb86SNeel Natu 799565bbb86SNeel Natu int 800ac7304a7SNeel Natu vm_ioapic_pulse_irq(struct vmctx *ctx, int irq) 801ac7304a7SNeel Natu { 802ac7304a7SNeel Natu struct vm_ioapic_irq ioapic_irq; 803ac7304a7SNeel Natu 804ac7304a7SNeel Natu bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 805ac7304a7SNeel Natu ioapic_irq.irq = irq; 806ac7304a7SNeel Natu 807ac7304a7SNeel Natu return (ioctl(ctx->fd, VM_IOAPIC_PULSE_IRQ, &ioapic_irq)); 808ac7304a7SNeel Natu } 809ac7304a7SNeel Natu 810ac7304a7SNeel Natu int 8113cbf3585SJohn Baldwin vm_ioapic_pincount(struct vmctx *ctx, int *pincount) 8123cbf3585SJohn Baldwin { 8133cbf3585SJohn Baldwin 8143cbf3585SJohn Baldwin return (ioctl(ctx->fd, VM_IOAPIC_PINCOUNT, pincount)); 8153cbf3585SJohn Baldwin } 8163cbf3585SJohn Baldwin 8173cbf3585SJohn Baldwin int 8188a68ae80SConrad Meyer vm_readwrite_kernemu_device(struct vmctx *ctx, int vcpu, vm_paddr_t gpa, 8198a68ae80SConrad Meyer bool write, int size, uint64_t *value) 8208a68ae80SConrad Meyer { 8218a68ae80SConrad Meyer struct vm_readwrite_kernemu_device irp = { 8228a68ae80SConrad Meyer .vcpuid = vcpu, 8238a68ae80SConrad Meyer .access_width = fls(size) - 1, 8248a68ae80SConrad Meyer .gpa = gpa, 8258a68ae80SConrad Meyer .value = write ? *value : ~0ul, 8268a68ae80SConrad Meyer }; 8278a68ae80SConrad Meyer long cmd = (write ? VM_SET_KERNEMU_DEV : VM_GET_KERNEMU_DEV); 8288a68ae80SConrad Meyer int rc; 8298a68ae80SConrad Meyer 8308a68ae80SConrad Meyer rc = ioctl(ctx->fd, cmd, &irp); 8318a68ae80SConrad Meyer if (rc == 0 && !write) 8328a68ae80SConrad Meyer *value = irp.value; 8338a68ae80SConrad Meyer return (rc); 8348a68ae80SConrad Meyer } 8358a68ae80SConrad Meyer 8368a68ae80SConrad Meyer int 837762fd208STycho Nightingale vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 838762fd208STycho Nightingale { 839762fd208STycho Nightingale struct vm_isa_irq isa_irq; 840762fd208STycho Nightingale 841762fd208STycho Nightingale bzero(&isa_irq, sizeof(struct vm_isa_irq)); 842762fd208STycho Nightingale isa_irq.atpic_irq = atpic_irq; 843762fd208STycho Nightingale isa_irq.ioapic_irq = ioapic_irq; 844762fd208STycho Nightingale 845762fd208STycho Nightingale return (ioctl(ctx->fd, VM_ISA_ASSERT_IRQ, &isa_irq)); 846762fd208STycho Nightingale } 847762fd208STycho Nightingale 848762fd208STycho Nightingale int 849762fd208STycho Nightingale vm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 850762fd208STycho Nightingale { 851762fd208STycho Nightingale struct vm_isa_irq isa_irq; 852762fd208STycho Nightingale 853762fd208STycho Nightingale bzero(&isa_irq, sizeof(struct vm_isa_irq)); 854762fd208STycho Nightingale isa_irq.atpic_irq = atpic_irq; 855762fd208STycho Nightingale isa_irq.ioapic_irq = ioapic_irq; 856762fd208STycho Nightingale 857762fd208STycho Nightingale return (ioctl(ctx->fd, VM_ISA_DEASSERT_IRQ, &isa_irq)); 858762fd208STycho Nightingale } 859762fd208STycho Nightingale 860762fd208STycho Nightingale int 861762fd208STycho Nightingale vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 862762fd208STycho Nightingale { 863762fd208STycho Nightingale struct vm_isa_irq isa_irq; 864b3e9732aSJohn Baldwin 865762fd208STycho Nightingale bzero(&isa_irq, sizeof(struct vm_isa_irq)); 866762fd208STycho Nightingale isa_irq.atpic_irq = atpic_irq; 867762fd208STycho Nightingale isa_irq.ioapic_irq = ioapic_irq; 868762fd208STycho Nightingale 869762fd208STycho Nightingale return (ioctl(ctx->fd, VM_ISA_PULSE_IRQ, &isa_irq)); 870762fd208STycho Nightingale } 871762fd208STycho Nightingale 872762fd208STycho Nightingale int 873b3e9732aSJohn Baldwin vm_isa_set_irq_trigger(struct vmctx *ctx, int atpic_irq, 874b3e9732aSJohn Baldwin enum vm_intr_trigger trigger) 875b3e9732aSJohn Baldwin { 876b3e9732aSJohn Baldwin struct vm_isa_irq_trigger isa_irq_trigger; 877b3e9732aSJohn Baldwin 878b3e9732aSJohn Baldwin bzero(&isa_irq_trigger, sizeof(struct vm_isa_irq_trigger)); 879b3e9732aSJohn Baldwin isa_irq_trigger.atpic_irq = atpic_irq; 880b3e9732aSJohn Baldwin isa_irq_trigger.trigger = trigger; 881b3e9732aSJohn Baldwin 882b3e9732aSJohn Baldwin return (ioctl(ctx->fd, VM_ISA_SET_IRQ_TRIGGER, &isa_irq_trigger)); 883b3e9732aSJohn Baldwin } 884b3e9732aSJohn Baldwin 885b3e9732aSJohn Baldwin int 886366f6083SPeter Grehan vm_inject_nmi(struct vmctx *ctx, int vcpu) 887366f6083SPeter Grehan { 888366f6083SPeter Grehan struct vm_nmi vmnmi; 889366f6083SPeter Grehan 890366f6083SPeter Grehan bzero(&vmnmi, sizeof(vmnmi)); 891366f6083SPeter Grehan vmnmi.cpuid = vcpu; 892366f6083SPeter Grehan 893366f6083SPeter Grehan return (ioctl(ctx->fd, VM_INJECT_NMI, &vmnmi)); 894366f6083SPeter Grehan } 895366f6083SPeter Grehan 896d000623aSJohn Baldwin static const char *capstrmap[] = { 897d000623aSJohn Baldwin [VM_CAP_HALT_EXIT] = "hlt_exit", 898d000623aSJohn Baldwin [VM_CAP_MTRAP_EXIT] = "mtrap_exit", 899d000623aSJohn Baldwin [VM_CAP_PAUSE_EXIT] = "pause_exit", 900d000623aSJohn Baldwin [VM_CAP_UNRESTRICTED_GUEST] = "unrestricted_guest", 901d000623aSJohn Baldwin [VM_CAP_ENABLE_INVPCID] = "enable_invpcid", 902d000623aSJohn Baldwin [VM_CAP_BPT_EXIT] = "bpt_exit", 903366f6083SPeter Grehan }; 904366f6083SPeter Grehan 90513f4cf6cSNeel Natu int 90613f4cf6cSNeel Natu vm_capability_name2type(const char *capname) 90713f4cf6cSNeel Natu { 90813f4cf6cSNeel Natu int i; 90913f4cf6cSNeel Natu 910d000623aSJohn Baldwin for (i = 0; i < nitems(capstrmap); i++) { 911d000623aSJohn Baldwin if (strcmp(capstrmap[i], capname) == 0) 912d000623aSJohn Baldwin return (i); 913366f6083SPeter Grehan } 914366f6083SPeter Grehan 915366f6083SPeter Grehan return (-1); 916366f6083SPeter Grehan } 917366f6083SPeter Grehan 91813f4cf6cSNeel Natu const char * 91913f4cf6cSNeel Natu vm_capability_type2name(int type) 92013f4cf6cSNeel Natu { 92124c2e17dSJohn Baldwin if (type >= 0 && type < nitems(capstrmap)) 922d000623aSJohn Baldwin return (capstrmap[type]); 92313f4cf6cSNeel Natu 92413f4cf6cSNeel Natu return (NULL); 92513f4cf6cSNeel Natu } 92613f4cf6cSNeel Natu 927366f6083SPeter Grehan int 928366f6083SPeter Grehan vm_get_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, 929366f6083SPeter Grehan int *retval) 930366f6083SPeter Grehan { 931366f6083SPeter Grehan int error; 932366f6083SPeter Grehan struct vm_capability vmcap; 933366f6083SPeter Grehan 934366f6083SPeter Grehan bzero(&vmcap, sizeof(vmcap)); 935366f6083SPeter Grehan vmcap.cpuid = vcpu; 936366f6083SPeter Grehan vmcap.captype = cap; 937366f6083SPeter Grehan 938366f6083SPeter Grehan error = ioctl(ctx->fd, VM_GET_CAPABILITY, &vmcap); 939366f6083SPeter Grehan *retval = vmcap.capval; 940366f6083SPeter Grehan return (error); 941366f6083SPeter Grehan } 942366f6083SPeter Grehan 943366f6083SPeter Grehan int 944366f6083SPeter Grehan vm_set_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, int val) 945366f6083SPeter Grehan { 946366f6083SPeter Grehan struct vm_capability vmcap; 947366f6083SPeter Grehan 948366f6083SPeter Grehan bzero(&vmcap, sizeof(vmcap)); 949366f6083SPeter Grehan vmcap.cpuid = vcpu; 950366f6083SPeter Grehan vmcap.captype = cap; 951366f6083SPeter Grehan vmcap.capval = val; 952366f6083SPeter Grehan 953366f6083SPeter Grehan return (ioctl(ctx->fd, VM_SET_CAPABILITY, &vmcap)); 954366f6083SPeter Grehan } 955366f6083SPeter Grehan 956366f6083SPeter Grehan int 957366f6083SPeter Grehan vm_assign_pptdev(struct vmctx *ctx, int bus, int slot, int func) 958366f6083SPeter Grehan { 959366f6083SPeter Grehan struct vm_pptdev pptdev; 960366f6083SPeter Grehan 961366f6083SPeter Grehan bzero(&pptdev, sizeof(pptdev)); 962366f6083SPeter Grehan pptdev.bus = bus; 963366f6083SPeter Grehan pptdev.slot = slot; 964366f6083SPeter Grehan pptdev.func = func; 965366f6083SPeter Grehan 966366f6083SPeter Grehan return (ioctl(ctx->fd, VM_BIND_PPTDEV, &pptdev)); 967366f6083SPeter Grehan } 968366f6083SPeter Grehan 969366f6083SPeter Grehan int 970366f6083SPeter Grehan vm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func) 971366f6083SPeter Grehan { 972366f6083SPeter Grehan struct vm_pptdev pptdev; 973366f6083SPeter Grehan 974366f6083SPeter Grehan bzero(&pptdev, sizeof(pptdev)); 975366f6083SPeter Grehan pptdev.bus = bus; 976366f6083SPeter Grehan pptdev.slot = slot; 977366f6083SPeter Grehan pptdev.func = func; 978366f6083SPeter Grehan 979366f6083SPeter Grehan return (ioctl(ctx->fd, VM_UNBIND_PPTDEV, &pptdev)); 980366f6083SPeter Grehan } 981366f6083SPeter Grehan 982366f6083SPeter Grehan int 983366f6083SPeter Grehan vm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func, 984366f6083SPeter Grehan vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 985366f6083SPeter Grehan { 986366f6083SPeter Grehan struct vm_pptdev_mmio pptmmio; 987366f6083SPeter Grehan 988366f6083SPeter Grehan bzero(&pptmmio, sizeof(pptmmio)); 989366f6083SPeter Grehan pptmmio.bus = bus; 990366f6083SPeter Grehan pptmmio.slot = slot; 991366f6083SPeter Grehan pptmmio.func = func; 992366f6083SPeter Grehan pptmmio.gpa = gpa; 993366f6083SPeter Grehan pptmmio.len = len; 994366f6083SPeter Grehan pptmmio.hpa = hpa; 995366f6083SPeter Grehan 996366f6083SPeter Grehan return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio)); 997366f6083SPeter Grehan } 998366f6083SPeter Grehan 999366f6083SPeter Grehan int 1000f8a6ec2dSD Scott Phillips vm_unmap_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func, 1001f8a6ec2dSD Scott Phillips vm_paddr_t gpa, size_t len) 1002f8a6ec2dSD Scott Phillips { 1003f8a6ec2dSD Scott Phillips struct vm_pptdev_mmio pptmmio; 1004f8a6ec2dSD Scott Phillips 1005f8a6ec2dSD Scott Phillips bzero(&pptmmio, sizeof(pptmmio)); 1006f8a6ec2dSD Scott Phillips pptmmio.bus = bus; 1007f8a6ec2dSD Scott Phillips pptmmio.slot = slot; 1008f8a6ec2dSD Scott Phillips pptmmio.func = func; 1009f8a6ec2dSD Scott Phillips pptmmio.gpa = gpa; 1010f8a6ec2dSD Scott Phillips pptmmio.len = len; 1011f8a6ec2dSD Scott Phillips 1012f8a6ec2dSD Scott Phillips return (ioctl(ctx->fd, VM_UNMAP_PPTDEV_MMIO, &pptmmio)); 1013f8a6ec2dSD Scott Phillips } 1014f8a6ec2dSD Scott Phillips 1015f8a6ec2dSD Scott Phillips int 101655888cfaSNeel Natu vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func, 10174f8be175SNeel Natu uint64_t addr, uint64_t msg, int numvec) 1018366f6083SPeter Grehan { 1019366f6083SPeter Grehan struct vm_pptdev_msi pptmsi; 1020366f6083SPeter Grehan 1021366f6083SPeter Grehan bzero(&pptmsi, sizeof(pptmsi)); 1022366f6083SPeter Grehan pptmsi.vcpu = vcpu; 1023366f6083SPeter Grehan pptmsi.bus = bus; 1024366f6083SPeter Grehan pptmsi.slot = slot; 1025366f6083SPeter Grehan pptmsi.func = func; 10264f8be175SNeel Natu pptmsi.msg = msg; 10274f8be175SNeel Natu pptmsi.addr = addr; 1028366f6083SPeter Grehan pptmsi.numvec = numvec; 1029366f6083SPeter Grehan 1030366f6083SPeter Grehan return (ioctl(ctx->fd, VM_PPTDEV_MSI, &pptmsi)); 1031366f6083SPeter Grehan } 1032366f6083SPeter Grehan 1033cd942e0fSPeter Grehan int 103455888cfaSNeel Natu vm_setup_pptdev_msix(struct vmctx *ctx, int vcpu, int bus, int slot, int func, 10354f8be175SNeel Natu int idx, uint64_t addr, uint64_t msg, uint32_t vector_control) 1036cd942e0fSPeter Grehan { 1037cd942e0fSPeter Grehan struct vm_pptdev_msix pptmsix; 1038cd942e0fSPeter Grehan 1039cd942e0fSPeter Grehan bzero(&pptmsix, sizeof(pptmsix)); 1040cd942e0fSPeter Grehan pptmsix.vcpu = vcpu; 1041cd942e0fSPeter Grehan pptmsix.bus = bus; 1042cd942e0fSPeter Grehan pptmsix.slot = slot; 1043cd942e0fSPeter Grehan pptmsix.func = func; 1044cd942e0fSPeter Grehan pptmsix.idx = idx; 1045cd942e0fSPeter Grehan pptmsix.msg = msg; 1046cd942e0fSPeter Grehan pptmsix.addr = addr; 1047cd942e0fSPeter Grehan pptmsix.vector_control = vector_control; 1048cd942e0fSPeter Grehan 1049cd942e0fSPeter Grehan return ioctl(ctx->fd, VM_PPTDEV_MSIX, &pptmsix); 1050cd942e0fSPeter Grehan } 1051cd942e0fSPeter Grehan 10521925586eSJohn Baldwin int 10531925586eSJohn Baldwin vm_disable_pptdev_msix(struct vmctx *ctx, int bus, int slot, int func) 10541925586eSJohn Baldwin { 10551925586eSJohn Baldwin struct vm_pptdev ppt; 10561925586eSJohn Baldwin 10571925586eSJohn Baldwin bzero(&ppt, sizeof(ppt)); 10581925586eSJohn Baldwin ppt.bus = bus; 10591925586eSJohn Baldwin ppt.slot = slot; 10601925586eSJohn Baldwin ppt.func = func; 10611925586eSJohn Baldwin 10621925586eSJohn Baldwin return ioctl(ctx->fd, VM_PPTDEV_DISABLE_MSIX, &ppt); 10631925586eSJohn Baldwin } 10641925586eSJohn Baldwin 1065366f6083SPeter Grehan uint64_t * 1066366f6083SPeter Grehan vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv, 1067366f6083SPeter Grehan int *ret_entries) 1068366f6083SPeter Grehan { 1069366f6083SPeter Grehan int error; 1070366f6083SPeter Grehan 1071366f6083SPeter Grehan static struct vm_stats vmstats; 1072366f6083SPeter Grehan 1073366f6083SPeter Grehan vmstats.cpuid = vcpu; 1074366f6083SPeter Grehan 1075366f6083SPeter Grehan error = ioctl(ctx->fd, VM_STATS, &vmstats); 1076366f6083SPeter Grehan if (error == 0) { 1077366f6083SPeter Grehan if (ret_entries) 1078366f6083SPeter Grehan *ret_entries = vmstats.num_entries; 1079366f6083SPeter Grehan if (ret_tv) 1080366f6083SPeter Grehan *ret_tv = vmstats.tv; 1081366f6083SPeter Grehan return (vmstats.statbuf); 1082366f6083SPeter Grehan } else 1083366f6083SPeter Grehan return (NULL); 1084366f6083SPeter Grehan } 1085366f6083SPeter Grehan 1086366f6083SPeter Grehan const char * 1087366f6083SPeter Grehan vm_get_stat_desc(struct vmctx *ctx, int index) 1088366f6083SPeter Grehan { 1089366f6083SPeter Grehan static struct vm_stat_desc statdesc; 1090366f6083SPeter Grehan 1091366f6083SPeter Grehan statdesc.index = index; 1092366f6083SPeter Grehan if (ioctl(ctx->fd, VM_STAT_DESC, &statdesc) == 0) 1093366f6083SPeter Grehan return (statdesc.desc); 1094366f6083SPeter Grehan else 1095366f6083SPeter Grehan return (NULL); 1096366f6083SPeter Grehan } 1097366f6083SPeter Grehan 1098e9027382SNeel Natu int 1099e9027382SNeel Natu vm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *state) 1100e9027382SNeel Natu { 1101e9027382SNeel Natu int error; 1102e9027382SNeel Natu struct vm_x2apic x2apic; 1103e9027382SNeel Natu 1104e9027382SNeel Natu bzero(&x2apic, sizeof(x2apic)); 1105e9027382SNeel Natu x2apic.cpuid = vcpu; 1106e9027382SNeel Natu 1107e9027382SNeel Natu error = ioctl(ctx->fd, VM_GET_X2APIC_STATE, &x2apic); 1108e9027382SNeel Natu *state = x2apic.state; 1109e9027382SNeel Natu return (error); 1110e9027382SNeel Natu } 1111e9027382SNeel Natu 1112e9027382SNeel Natu int 1113e9027382SNeel Natu vm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state state) 1114e9027382SNeel Natu { 1115e9027382SNeel Natu int error; 1116e9027382SNeel Natu struct vm_x2apic x2apic; 1117e9027382SNeel Natu 1118e9027382SNeel Natu bzero(&x2apic, sizeof(x2apic)); 1119e9027382SNeel Natu x2apic.cpuid = vcpu; 1120e9027382SNeel Natu x2apic.state = state; 1121e9027382SNeel Natu 1122e9027382SNeel Natu error = ioctl(ctx->fd, VM_SET_X2APIC_STATE, &x2apic); 1123e9027382SNeel Natu 1124e9027382SNeel Natu return (error); 1125e9027382SNeel Natu } 1126e9027382SNeel Natu 1127366f6083SPeter Grehan /* 1128366f6083SPeter Grehan * From Intel Vol 3a: 1129366f6083SPeter Grehan * Table 9-1. IA-32 Processor States Following Power-up, Reset or INIT 1130366f6083SPeter Grehan */ 1131366f6083SPeter Grehan int 1132366f6083SPeter Grehan vcpu_reset(struct vmctx *vmctx, int vcpu) 1133366f6083SPeter Grehan { 1134366f6083SPeter Grehan int error; 1135366f6083SPeter Grehan uint64_t rflags, rip, cr0, cr4, zero, desc_base, rdx; 1136366f6083SPeter Grehan uint32_t desc_access, desc_limit; 1137366f6083SPeter Grehan uint16_t sel; 1138366f6083SPeter Grehan 1139366f6083SPeter Grehan zero = 0; 1140366f6083SPeter Grehan 1141366f6083SPeter Grehan rflags = 0x2; 1142366f6083SPeter Grehan error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags); 1143366f6083SPeter Grehan if (error) 1144366f6083SPeter Grehan goto done; 1145366f6083SPeter Grehan 1146366f6083SPeter Grehan rip = 0xfff0; 1147366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0) 1148366f6083SPeter Grehan goto done; 1149366f6083SPeter Grehan 1150366f6083SPeter Grehan cr0 = CR0_NE; 1151366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0) 1152366f6083SPeter Grehan goto done; 1153366f6083SPeter Grehan 1154366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, zero)) != 0) 1155366f6083SPeter Grehan goto done; 1156366f6083SPeter Grehan 115732c96bc8SNeel Natu cr4 = 0; 1158366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0) 1159366f6083SPeter Grehan goto done; 1160366f6083SPeter Grehan 1161366f6083SPeter Grehan /* 1162366f6083SPeter Grehan * CS: present, r/w, accessed, 16-bit, byte granularity, usable 1163366f6083SPeter Grehan */ 1164366f6083SPeter Grehan desc_base = 0xffff0000; 1165366f6083SPeter Grehan desc_limit = 0xffff; 1166366f6083SPeter Grehan desc_access = 0x0093; 1167366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS, 1168366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1169366f6083SPeter Grehan if (error) 1170366f6083SPeter Grehan goto done; 1171366f6083SPeter Grehan 1172366f6083SPeter Grehan sel = 0xf000; 1173366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, sel)) != 0) 1174366f6083SPeter Grehan goto done; 1175366f6083SPeter Grehan 1176366f6083SPeter Grehan /* 1177366f6083SPeter Grehan * SS,DS,ES,FS,GS: present, r/w, accessed, 16-bit, byte granularity 1178366f6083SPeter Grehan */ 1179366f6083SPeter Grehan desc_base = 0; 1180366f6083SPeter Grehan desc_limit = 0xffff; 1181366f6083SPeter Grehan desc_access = 0x0093; 1182366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS, 1183366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1184366f6083SPeter Grehan if (error) 1185366f6083SPeter Grehan goto done; 1186366f6083SPeter Grehan 1187366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS, 1188366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1189366f6083SPeter Grehan if (error) 1190366f6083SPeter Grehan goto done; 1191366f6083SPeter Grehan 1192366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES, 1193366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1194366f6083SPeter Grehan if (error) 1195366f6083SPeter Grehan goto done; 1196366f6083SPeter Grehan 1197366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS, 1198366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1199366f6083SPeter Grehan if (error) 1200366f6083SPeter Grehan goto done; 1201366f6083SPeter Grehan 1202366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS, 1203366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1204366f6083SPeter Grehan if (error) 1205366f6083SPeter Grehan goto done; 1206366f6083SPeter Grehan 1207366f6083SPeter Grehan sel = 0; 1208366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, sel)) != 0) 1209366f6083SPeter Grehan goto done; 1210366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, sel)) != 0) 1211366f6083SPeter Grehan goto done; 1212366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, sel)) != 0) 1213366f6083SPeter Grehan goto done; 1214366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, sel)) != 0) 1215366f6083SPeter Grehan goto done; 1216366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, sel)) != 0) 1217366f6083SPeter Grehan goto done; 1218366f6083SPeter Grehan 1219366f6083SPeter Grehan /* General purpose registers */ 1220366f6083SPeter Grehan rdx = 0xf00; 1221366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RAX, zero)) != 0) 1222366f6083SPeter Grehan goto done; 1223366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBX, zero)) != 0) 1224366f6083SPeter Grehan goto done; 1225366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RCX, zero)) != 0) 1226366f6083SPeter Grehan goto done; 1227366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDX, rdx)) != 0) 1228366f6083SPeter Grehan goto done; 1229366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSI, zero)) != 0) 1230366f6083SPeter Grehan goto done; 1231366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDI, zero)) != 0) 1232366f6083SPeter Grehan goto done; 1233366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBP, zero)) != 0) 1234366f6083SPeter Grehan goto done; 1235366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, zero)) != 0) 1236366f6083SPeter Grehan goto done; 1237366f6083SPeter Grehan 1238366f6083SPeter Grehan /* GDTR, IDTR */ 1239366f6083SPeter Grehan desc_base = 0; 1240366f6083SPeter Grehan desc_limit = 0xffff; 1241366f6083SPeter Grehan desc_access = 0; 1242366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR, 1243366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1244366f6083SPeter Grehan if (error != 0) 1245366f6083SPeter Grehan goto done; 1246366f6083SPeter Grehan 1247366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_IDTR, 1248366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1249366f6083SPeter Grehan if (error != 0) 1250366f6083SPeter Grehan goto done; 1251366f6083SPeter Grehan 1252366f6083SPeter Grehan /* TR */ 1253366f6083SPeter Grehan desc_base = 0; 1254366f6083SPeter Grehan desc_limit = 0xffff; 1255366f6083SPeter Grehan desc_access = 0x0000008b; 1256366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access); 1257366f6083SPeter Grehan if (error) 1258366f6083SPeter Grehan goto done; 1259366f6083SPeter Grehan 1260366f6083SPeter Grehan sel = 0; 1261366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, sel)) != 0) 1262366f6083SPeter Grehan goto done; 1263366f6083SPeter Grehan 1264366f6083SPeter Grehan /* LDTR */ 1265366f6083SPeter Grehan desc_base = 0; 1266366f6083SPeter Grehan desc_limit = 0xffff; 1267366f6083SPeter Grehan desc_access = 0x00000082; 1268366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, desc_base, 1269366f6083SPeter Grehan desc_limit, desc_access); 1270366f6083SPeter Grehan if (error) 1271366f6083SPeter Grehan goto done; 1272366f6083SPeter Grehan 1273366f6083SPeter Grehan sel = 0; 1274366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0) 1275366f6083SPeter Grehan goto done; 1276366f6083SPeter Grehan 1277366f6083SPeter Grehan /* XXX cr2, debug registers */ 1278366f6083SPeter Grehan 1279366f6083SPeter Grehan error = 0; 1280366f6083SPeter Grehan done: 1281366f6083SPeter Grehan return (error); 1282366f6083SPeter Grehan } 1283318224bbSNeel Natu 1284318224bbSNeel Natu int 1285318224bbSNeel Natu vm_get_gpa_pmap(struct vmctx *ctx, uint64_t gpa, uint64_t *pte, int *num) 1286318224bbSNeel Natu { 1287318224bbSNeel Natu int error, i; 1288318224bbSNeel Natu struct vm_gpa_pte gpapte; 1289318224bbSNeel Natu 1290318224bbSNeel Natu bzero(&gpapte, sizeof(gpapte)); 1291318224bbSNeel Natu gpapte.gpa = gpa; 1292318224bbSNeel Natu 1293318224bbSNeel Natu error = ioctl(ctx->fd, VM_GET_GPA_PMAP, &gpapte); 1294318224bbSNeel Natu 1295318224bbSNeel Natu if (error == 0) { 1296318224bbSNeel Natu *num = gpapte.ptenum; 1297318224bbSNeel Natu for (i = 0; i < gpapte.ptenum; i++) 1298318224bbSNeel Natu pte[i] = gpapte.pte[i]; 1299318224bbSNeel Natu } 1300318224bbSNeel Natu 1301318224bbSNeel Natu return (error); 1302318224bbSNeel Natu } 130308e3ff32SNeel Natu 130408e3ff32SNeel Natu int 130508e3ff32SNeel Natu vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities) 130608e3ff32SNeel Natu { 130708e3ff32SNeel Natu int error; 130808e3ff32SNeel Natu struct vm_hpet_cap cap; 130908e3ff32SNeel Natu 131008e3ff32SNeel Natu bzero(&cap, sizeof(struct vm_hpet_cap)); 131108e3ff32SNeel Natu error = ioctl(ctx->fd, VM_GET_HPET_CAPABILITIES, &cap); 131208e3ff32SNeel Natu if (capabilities != NULL) 131308e3ff32SNeel Natu *capabilities = cap.capabilities; 131408e3ff32SNeel Natu return (error); 131508e3ff32SNeel Natu } 1316da11f4aaSNeel Natu 13179c4d5478SNeel Natu int 13189c4d5478SNeel Natu vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 13199c4d5478SNeel Natu uint64_t gla, int prot, uint64_t *gpa, int *fault) 1320da11f4aaSNeel Natu { 1321da11f4aaSNeel Natu struct vm_gla2gpa gg; 1322da11f4aaSNeel Natu int error; 1323da11f4aaSNeel Natu 1324da11f4aaSNeel Natu bzero(&gg, sizeof(struct vm_gla2gpa)); 1325da11f4aaSNeel Natu gg.vcpuid = vcpu; 1326da11f4aaSNeel Natu gg.prot = prot; 1327da11f4aaSNeel Natu gg.gla = gla; 1328da11f4aaSNeel Natu gg.paging = *paging; 1329da11f4aaSNeel Natu 1330da11f4aaSNeel Natu error = ioctl(ctx->fd, VM_GLA2GPA, &gg); 1331da11f4aaSNeel Natu if (error == 0) { 1332da11f4aaSNeel Natu *fault = gg.fault; 1333da11f4aaSNeel Natu *gpa = gg.gpa; 1334da11f4aaSNeel Natu } 1335da11f4aaSNeel Natu return (error); 1336da11f4aaSNeel Natu } 1337da11f4aaSNeel Natu 13385f8754c0SJohn Baldwin int 13395f8754c0SJohn Baldwin vm_gla2gpa_nofault(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 13405f8754c0SJohn Baldwin uint64_t gla, int prot, uint64_t *gpa, int *fault) 13415f8754c0SJohn Baldwin { 13425f8754c0SJohn Baldwin struct vm_gla2gpa gg; 13435f8754c0SJohn Baldwin int error; 13445f8754c0SJohn Baldwin 13455f8754c0SJohn Baldwin bzero(&gg, sizeof(struct vm_gla2gpa)); 13465f8754c0SJohn Baldwin gg.vcpuid = vcpu; 13475f8754c0SJohn Baldwin gg.prot = prot; 13485f8754c0SJohn Baldwin gg.gla = gla; 13495f8754c0SJohn Baldwin gg.paging = *paging; 13505f8754c0SJohn Baldwin 13515f8754c0SJohn Baldwin error = ioctl(ctx->fd, VM_GLA2GPA_NOFAULT, &gg); 13525f8754c0SJohn Baldwin if (error == 0) { 13535f8754c0SJohn Baldwin *fault = gg.fault; 13545f8754c0SJohn Baldwin *gpa = gg.gpa; 13555f8754c0SJohn Baldwin } 13565f8754c0SJohn Baldwin return (error); 13575f8754c0SJohn Baldwin } 13585f8754c0SJohn Baldwin 1359da11f4aaSNeel Natu #ifndef min 1360da11f4aaSNeel Natu #define min(a,b) (((a) < (b)) ? (a) : (b)) 1361da11f4aaSNeel Natu #endif 1362da11f4aaSNeel Natu 1363da11f4aaSNeel Natu int 1364d665d229SNeel Natu vm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 13659c4d5478SNeel Natu uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt, 13669c4d5478SNeel Natu int *fault) 1367da11f4aaSNeel Natu { 1368009e2acbSNeel Natu void *va; 1369da11f4aaSNeel Natu uint64_t gpa; 13709c4d5478SNeel Natu int error, i, n, off; 13716303b65dSNeel Natu 13726303b65dSNeel Natu for (i = 0; i < iovcnt; i++) { 13736303b65dSNeel Natu iov[i].iov_base = 0; 13746303b65dSNeel Natu iov[i].iov_len = 0; 13756303b65dSNeel Natu } 13766303b65dSNeel Natu 13776303b65dSNeel Natu while (len) { 13786303b65dSNeel Natu assert(iovcnt > 0); 13799c4d5478SNeel Natu error = vm_gla2gpa(ctx, vcpu, paging, gla, prot, &gpa, fault); 13809c4d5478SNeel Natu if (error || *fault) 13819c4d5478SNeel Natu return (error); 13826303b65dSNeel Natu 13836303b65dSNeel Natu off = gpa & PAGE_MASK; 13846303b65dSNeel Natu n = min(len, PAGE_SIZE - off); 13856303b65dSNeel Natu 1386009e2acbSNeel Natu va = vm_map_gpa(ctx, gpa, n); 1387009e2acbSNeel Natu if (va == NULL) 13889c4d5478SNeel Natu return (EFAULT); 1389009e2acbSNeel Natu 1390009e2acbSNeel Natu iov->iov_base = va; 13916303b65dSNeel Natu iov->iov_len = n; 13926303b65dSNeel Natu iov++; 13936303b65dSNeel Natu iovcnt--; 13946303b65dSNeel Natu 13956303b65dSNeel Natu gla += n; 13966303b65dSNeel Natu len -= n; 13976303b65dSNeel Natu } 13986303b65dSNeel Natu return (0); 13996303b65dSNeel Natu } 14006303b65dSNeel Natu 14016303b65dSNeel Natu void 1402009e2acbSNeel Natu vm_copy_teardown(struct vmctx *ctx, int vcpu, struct iovec *iov, int iovcnt) 1403009e2acbSNeel Natu { 1404009e2acbSNeel Natu 1405009e2acbSNeel Natu return; 1406009e2acbSNeel Natu } 1407009e2acbSNeel Natu 1408009e2acbSNeel Natu void 14096303b65dSNeel Natu vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *iov, void *vp, size_t len) 14106303b65dSNeel Natu { 14116303b65dSNeel Natu const char *src; 14126303b65dSNeel Natu char *dst; 14136303b65dSNeel Natu size_t n; 1414da11f4aaSNeel Natu 1415da11f4aaSNeel Natu dst = vp; 1416da11f4aaSNeel Natu while (len) { 14176303b65dSNeel Natu assert(iov->iov_len); 14186303b65dSNeel Natu n = min(len, iov->iov_len); 1419009e2acbSNeel Natu src = iov->iov_base; 1420da11f4aaSNeel Natu bcopy(src, dst, n); 1421da11f4aaSNeel Natu 14226303b65dSNeel Natu iov++; 1423da11f4aaSNeel Natu dst += n; 1424da11f4aaSNeel Natu len -= n; 1425da11f4aaSNeel Natu } 1426da11f4aaSNeel Natu } 1427da11f4aaSNeel Natu 14286303b65dSNeel Natu void 14296303b65dSNeel Natu vm_copyout(struct vmctx *ctx, int vcpu, const void *vp, struct iovec *iov, 14306303b65dSNeel Natu size_t len) 1431da11f4aaSNeel Natu { 1432da11f4aaSNeel Natu const char *src; 14336303b65dSNeel Natu char *dst; 14346303b65dSNeel Natu size_t n; 1435da11f4aaSNeel Natu 1436da11f4aaSNeel Natu src = vp; 1437da11f4aaSNeel Natu while (len) { 14386303b65dSNeel Natu assert(iov->iov_len); 14396303b65dSNeel Natu n = min(len, iov->iov_len); 1440009e2acbSNeel Natu dst = iov->iov_base; 1441da11f4aaSNeel Natu bcopy(src, dst, n); 1442da11f4aaSNeel Natu 14436303b65dSNeel Natu iov++; 1444da11f4aaSNeel Natu src += n; 1445da11f4aaSNeel Natu len -= n; 1446da11f4aaSNeel Natu } 1447da11f4aaSNeel Natu } 144895ebc360SNeel Natu 144995ebc360SNeel Natu static int 145095ebc360SNeel Natu vm_get_cpus(struct vmctx *ctx, int which, cpuset_t *cpus) 145195ebc360SNeel Natu { 145295ebc360SNeel Natu struct vm_cpuset vm_cpuset; 145395ebc360SNeel Natu int error; 145495ebc360SNeel Natu 145595ebc360SNeel Natu bzero(&vm_cpuset, sizeof(struct vm_cpuset)); 145695ebc360SNeel Natu vm_cpuset.which = which; 145795ebc360SNeel Natu vm_cpuset.cpusetsize = sizeof(cpuset_t); 145895ebc360SNeel Natu vm_cpuset.cpus = cpus; 145995ebc360SNeel Natu 146095ebc360SNeel Natu error = ioctl(ctx->fd, VM_GET_CPUS, &vm_cpuset); 146195ebc360SNeel Natu return (error); 146295ebc360SNeel Natu } 146395ebc360SNeel Natu 146495ebc360SNeel Natu int 146595ebc360SNeel Natu vm_active_cpus(struct vmctx *ctx, cpuset_t *cpus) 146695ebc360SNeel Natu { 146795ebc360SNeel Natu 146895ebc360SNeel Natu return (vm_get_cpus(ctx, VM_ACTIVE_CPUS, cpus)); 146995ebc360SNeel Natu } 147095ebc360SNeel Natu 147195ebc360SNeel Natu int 147295ebc360SNeel Natu vm_suspended_cpus(struct vmctx *ctx, cpuset_t *cpus) 147395ebc360SNeel Natu { 147495ebc360SNeel Natu 147595ebc360SNeel Natu return (vm_get_cpus(ctx, VM_SUSPENDED_CPUS, cpus)); 147695ebc360SNeel Natu } 147795ebc360SNeel Natu 147895ebc360SNeel Natu int 1479fc276d92SJohn Baldwin vm_debug_cpus(struct vmctx *ctx, cpuset_t *cpus) 1480fc276d92SJohn Baldwin { 1481fc276d92SJohn Baldwin 1482fc276d92SJohn Baldwin return (vm_get_cpus(ctx, VM_DEBUG_CPUS, cpus)); 1483fc276d92SJohn Baldwin } 1484fc276d92SJohn Baldwin 1485fc276d92SJohn Baldwin int 148695ebc360SNeel Natu vm_activate_cpu(struct vmctx *ctx, int vcpu) 148795ebc360SNeel Natu { 148895ebc360SNeel Natu struct vm_activate_cpu ac; 148995ebc360SNeel Natu int error; 149095ebc360SNeel Natu 149195ebc360SNeel Natu bzero(&ac, sizeof(struct vm_activate_cpu)); 149295ebc360SNeel Natu ac.vcpuid = vcpu; 149395ebc360SNeel Natu error = ioctl(ctx->fd, VM_ACTIVATE_CPU, &ac); 149495ebc360SNeel Natu return (error); 149595ebc360SNeel Natu } 1496091d4532SNeel Natu 1497091d4532SNeel Natu int 1498fc276d92SJohn Baldwin vm_suspend_cpu(struct vmctx *ctx, int vcpu) 1499fc276d92SJohn Baldwin { 1500fc276d92SJohn Baldwin struct vm_activate_cpu ac; 1501fc276d92SJohn Baldwin int error; 1502fc276d92SJohn Baldwin 1503fc276d92SJohn Baldwin bzero(&ac, sizeof(struct vm_activate_cpu)); 1504fc276d92SJohn Baldwin ac.vcpuid = vcpu; 1505fc276d92SJohn Baldwin error = ioctl(ctx->fd, VM_SUSPEND_CPU, &ac); 1506fc276d92SJohn Baldwin return (error); 1507fc276d92SJohn Baldwin } 1508fc276d92SJohn Baldwin 1509fc276d92SJohn Baldwin int 1510fc276d92SJohn Baldwin vm_resume_cpu(struct vmctx *ctx, int vcpu) 1511fc276d92SJohn Baldwin { 1512fc276d92SJohn Baldwin struct vm_activate_cpu ac; 1513fc276d92SJohn Baldwin int error; 1514fc276d92SJohn Baldwin 1515fc276d92SJohn Baldwin bzero(&ac, sizeof(struct vm_activate_cpu)); 1516fc276d92SJohn Baldwin ac.vcpuid = vcpu; 1517fc276d92SJohn Baldwin error = ioctl(ctx->fd, VM_RESUME_CPU, &ac); 1518fc276d92SJohn Baldwin return (error); 1519fc276d92SJohn Baldwin } 1520fc276d92SJohn Baldwin 1521fc276d92SJohn Baldwin int 1522091d4532SNeel Natu vm_get_intinfo(struct vmctx *ctx, int vcpu, uint64_t *info1, uint64_t *info2) 1523091d4532SNeel Natu { 1524091d4532SNeel Natu struct vm_intinfo vmii; 1525091d4532SNeel Natu int error; 1526091d4532SNeel Natu 1527091d4532SNeel Natu bzero(&vmii, sizeof(struct vm_intinfo)); 1528091d4532SNeel Natu vmii.vcpuid = vcpu; 1529091d4532SNeel Natu error = ioctl(ctx->fd, VM_GET_INTINFO, &vmii); 1530091d4532SNeel Natu if (error == 0) { 1531091d4532SNeel Natu *info1 = vmii.info1; 1532091d4532SNeel Natu *info2 = vmii.info2; 1533091d4532SNeel Natu } 1534091d4532SNeel Natu return (error); 1535091d4532SNeel Natu } 1536091d4532SNeel Natu 1537091d4532SNeel Natu int 1538091d4532SNeel Natu vm_set_intinfo(struct vmctx *ctx, int vcpu, uint64_t info1) 1539091d4532SNeel Natu { 1540091d4532SNeel Natu struct vm_intinfo vmii; 1541091d4532SNeel Natu int error; 1542091d4532SNeel Natu 1543091d4532SNeel Natu bzero(&vmii, sizeof(struct vm_intinfo)); 1544091d4532SNeel Natu vmii.vcpuid = vcpu; 1545091d4532SNeel Natu vmii.info1 = info1; 1546091d4532SNeel Natu error = ioctl(ctx->fd, VM_SET_INTINFO, &vmii); 1547091d4532SNeel Natu return (error); 1548091d4532SNeel Natu } 15490dafa5cdSNeel Natu 15500dafa5cdSNeel Natu int 15510dafa5cdSNeel Natu vm_rtc_write(struct vmctx *ctx, int offset, uint8_t value) 15520dafa5cdSNeel Natu { 15530dafa5cdSNeel Natu struct vm_rtc_data rtcdata; 15540dafa5cdSNeel Natu int error; 15550dafa5cdSNeel Natu 15560dafa5cdSNeel Natu bzero(&rtcdata, sizeof(struct vm_rtc_data)); 15570dafa5cdSNeel Natu rtcdata.offset = offset; 15580dafa5cdSNeel Natu rtcdata.value = value; 15590dafa5cdSNeel Natu error = ioctl(ctx->fd, VM_RTC_WRITE, &rtcdata); 15600dafa5cdSNeel Natu return (error); 15610dafa5cdSNeel Natu } 15620dafa5cdSNeel Natu 15630dafa5cdSNeel Natu int 15640dafa5cdSNeel Natu vm_rtc_read(struct vmctx *ctx, int offset, uint8_t *retval) 15650dafa5cdSNeel Natu { 15660dafa5cdSNeel Natu struct vm_rtc_data rtcdata; 15670dafa5cdSNeel Natu int error; 15680dafa5cdSNeel Natu 15690dafa5cdSNeel Natu bzero(&rtcdata, sizeof(struct vm_rtc_data)); 15700dafa5cdSNeel Natu rtcdata.offset = offset; 15710dafa5cdSNeel Natu error = ioctl(ctx->fd, VM_RTC_READ, &rtcdata); 15720dafa5cdSNeel Natu if (error == 0) 15730dafa5cdSNeel Natu *retval = rtcdata.value; 15740dafa5cdSNeel Natu return (error); 15750dafa5cdSNeel Natu } 15760dafa5cdSNeel Natu 15770dafa5cdSNeel Natu int 15780dafa5cdSNeel Natu vm_rtc_settime(struct vmctx *ctx, time_t secs) 15790dafa5cdSNeel Natu { 15800dafa5cdSNeel Natu struct vm_rtc_time rtctime; 15810dafa5cdSNeel Natu int error; 15820dafa5cdSNeel Natu 15830dafa5cdSNeel Natu bzero(&rtctime, sizeof(struct vm_rtc_time)); 15840dafa5cdSNeel Natu rtctime.secs = secs; 15850dafa5cdSNeel Natu error = ioctl(ctx->fd, VM_RTC_SETTIME, &rtctime); 15860dafa5cdSNeel Natu return (error); 15870dafa5cdSNeel Natu } 15880dafa5cdSNeel Natu 15890dafa5cdSNeel Natu int 15900dafa5cdSNeel Natu vm_rtc_gettime(struct vmctx *ctx, time_t *secs) 15910dafa5cdSNeel Natu { 15920dafa5cdSNeel Natu struct vm_rtc_time rtctime; 15930dafa5cdSNeel Natu int error; 15940dafa5cdSNeel Natu 15950dafa5cdSNeel Natu bzero(&rtctime, sizeof(struct vm_rtc_time)); 15960dafa5cdSNeel Natu error = ioctl(ctx->fd, VM_RTC_GETTIME, &rtctime); 15970dafa5cdSNeel Natu if (error == 0) 15980dafa5cdSNeel Natu *secs = rtctime.secs; 15990dafa5cdSNeel Natu return (error); 16000dafa5cdSNeel Natu } 1601d087a399SNeel Natu 1602d087a399SNeel Natu int 1603d087a399SNeel Natu vm_restart_instruction(void *arg, int vcpu) 1604d087a399SNeel Natu { 1605d087a399SNeel Natu struct vmctx *ctx = arg; 1606d087a399SNeel Natu 1607d087a399SNeel Natu return (ioctl(ctx->fd, VM_RESTART_INSTRUCTION, &vcpu)); 1608d087a399SNeel Natu } 160900ef17beSBartek Rutkowski 161000ef17beSBartek Rutkowski int 1611483d953aSJohn Baldwin vm_snapshot_req(struct vm_snapshot_meta *meta) 1612483d953aSJohn Baldwin { 1613483d953aSJohn Baldwin 1614483d953aSJohn Baldwin if (ioctl(meta->ctx->fd, VM_SNAPSHOT_REQ, meta) == -1) { 1615483d953aSJohn Baldwin #ifdef SNAPSHOT_DEBUG 1616483d953aSJohn Baldwin fprintf(stderr, "%s: snapshot failed for %s: %d\r\n", 1617483d953aSJohn Baldwin __func__, meta->dev_name, errno); 1618483d953aSJohn Baldwin #endif 1619483d953aSJohn Baldwin return (-1); 1620483d953aSJohn Baldwin } 1621483d953aSJohn Baldwin return (0); 1622483d953aSJohn Baldwin } 1623483d953aSJohn Baldwin 1624483d953aSJohn Baldwin int 1625483d953aSJohn Baldwin vm_restore_time(struct vmctx *ctx) 1626483d953aSJohn Baldwin { 1627483d953aSJohn Baldwin int dummy; 1628483d953aSJohn Baldwin 1629483d953aSJohn Baldwin dummy = 0; 1630483d953aSJohn Baldwin return (ioctl(ctx->fd, VM_RESTORE_TIME, &dummy)); 1631483d953aSJohn Baldwin } 1632483d953aSJohn Baldwin 1633483d953aSJohn Baldwin int 163401d822d3SRodney W. Grimes vm_set_topology(struct vmctx *ctx, 163501d822d3SRodney W. Grimes uint16_t sockets, uint16_t cores, uint16_t threads, uint16_t maxcpus) 163601d822d3SRodney W. Grimes { 163701d822d3SRodney W. Grimes struct vm_cpu_topology topology; 163801d822d3SRodney W. Grimes 163901d822d3SRodney W. Grimes bzero(&topology, sizeof (struct vm_cpu_topology)); 164001d822d3SRodney W. Grimes topology.sockets = sockets; 164101d822d3SRodney W. Grimes topology.cores = cores; 164201d822d3SRodney W. Grimes topology.threads = threads; 164301d822d3SRodney W. Grimes topology.maxcpus = maxcpus; 164401d822d3SRodney W. Grimes return (ioctl(ctx->fd, VM_SET_TOPOLOGY, &topology)); 164501d822d3SRodney W. Grimes } 164601d822d3SRodney W. Grimes 164701d822d3SRodney W. Grimes int 164801d822d3SRodney W. Grimes vm_get_topology(struct vmctx *ctx, 164901d822d3SRodney W. Grimes uint16_t *sockets, uint16_t *cores, uint16_t *threads, uint16_t *maxcpus) 165001d822d3SRodney W. Grimes { 165101d822d3SRodney W. Grimes struct vm_cpu_topology topology; 165201d822d3SRodney W. Grimes int error; 165301d822d3SRodney W. Grimes 165401d822d3SRodney W. Grimes bzero(&topology, sizeof (struct vm_cpu_topology)); 165501d822d3SRodney W. Grimes error = ioctl(ctx->fd, VM_GET_TOPOLOGY, &topology); 165601d822d3SRodney W. Grimes if (error == 0) { 165701d822d3SRodney W. Grimes *sockets = topology.sockets; 165801d822d3SRodney W. Grimes *cores = topology.cores; 165901d822d3SRodney W. Grimes *threads = topology.threads; 166001d822d3SRodney W. Grimes *maxcpus = topology.maxcpus; 166101d822d3SRodney W. Grimes } 166201d822d3SRodney W. Grimes return (error); 166301d822d3SRodney W. Grimes } 166401d822d3SRodney W. Grimes 166501d822d3SRodney W. Grimes int 166600ef17beSBartek Rutkowski vm_get_device_fd(struct vmctx *ctx) 166700ef17beSBartek Rutkowski { 166800ef17beSBartek Rutkowski 166900ef17beSBartek Rutkowski return (ctx->fd); 167000ef17beSBartek Rutkowski } 167100ef17beSBartek Rutkowski 167200ef17beSBartek Rutkowski const cap_ioctl_t * 167300ef17beSBartek Rutkowski vm_get_ioctls(size_t *len) 167400ef17beSBartek Rutkowski { 167500ef17beSBartek Rutkowski cap_ioctl_t *cmds; 167600ef17beSBartek Rutkowski /* keep in sync with machine/vmm_dev.h */ 167700ef17beSBartek Rutkowski static const cap_ioctl_t vm_ioctl_cmds[] = { VM_RUN, VM_SUSPEND, VM_REINIT, 167800ef17beSBartek Rutkowski VM_ALLOC_MEMSEG, VM_GET_MEMSEG, VM_MMAP_MEMSEG, VM_MMAP_MEMSEG, 1679f8a6ec2dSD Scott Phillips VM_MMAP_GETNEXT, VM_MUNMAP_MEMSEG, VM_SET_REGISTER, VM_GET_REGISTER, 168000ef17beSBartek Rutkowski VM_SET_SEGMENT_DESCRIPTOR, VM_GET_SEGMENT_DESCRIPTOR, 16814f866698SJohn Baldwin VM_SET_REGISTER_SET, VM_GET_REGISTER_SET, 16828a68ae80SConrad Meyer VM_SET_KERNEMU_DEV, VM_GET_KERNEMU_DEV, 168300ef17beSBartek Rutkowski VM_INJECT_EXCEPTION, VM_LAPIC_IRQ, VM_LAPIC_LOCAL_IRQ, 168400ef17beSBartek Rutkowski VM_LAPIC_MSI, VM_IOAPIC_ASSERT_IRQ, VM_IOAPIC_DEASSERT_IRQ, 168500ef17beSBartek Rutkowski VM_IOAPIC_PULSE_IRQ, VM_IOAPIC_PINCOUNT, VM_ISA_ASSERT_IRQ, 168600ef17beSBartek Rutkowski VM_ISA_DEASSERT_IRQ, VM_ISA_PULSE_IRQ, VM_ISA_SET_IRQ_TRIGGER, 168700ef17beSBartek Rutkowski VM_SET_CAPABILITY, VM_GET_CAPABILITY, VM_BIND_PPTDEV, 168800ef17beSBartek Rutkowski VM_UNBIND_PPTDEV, VM_MAP_PPTDEV_MMIO, VM_PPTDEV_MSI, 1689f8a6ec2dSD Scott Phillips VM_PPTDEV_MSIX, VM_UNMAP_PPTDEV_MMIO, VM_PPTDEV_DISABLE_MSIX, 16901925586eSJohn Baldwin VM_INJECT_NMI, VM_STATS, VM_STAT_DESC, 169100ef17beSBartek Rutkowski VM_SET_X2APIC_STATE, VM_GET_X2APIC_STATE, 169200ef17beSBartek Rutkowski VM_GET_HPET_CAPABILITIES, VM_GET_GPA_PMAP, VM_GLA2GPA, 16935f8754c0SJohn Baldwin VM_GLA2GPA_NOFAULT, 1694fc276d92SJohn Baldwin VM_ACTIVATE_CPU, VM_GET_CPUS, VM_SUSPEND_CPU, VM_RESUME_CPU, 1695fc276d92SJohn Baldwin VM_SET_INTINFO, VM_GET_INTINFO, 169600ef17beSBartek Rutkowski VM_RTC_WRITE, VM_RTC_READ, VM_RTC_SETTIME, VM_RTC_GETTIME, 169701d822d3SRodney W. Grimes VM_RESTART_INSTRUCTION, VM_SET_TOPOLOGY, VM_GET_TOPOLOGY }; 169800ef17beSBartek Rutkowski 169900ef17beSBartek Rutkowski if (len == NULL) { 170000ef17beSBartek Rutkowski cmds = malloc(sizeof(vm_ioctl_cmds)); 170100ef17beSBartek Rutkowski if (cmds == NULL) 170200ef17beSBartek Rutkowski return (NULL); 170300ef17beSBartek Rutkowski bcopy(vm_ioctl_cmds, cmds, sizeof(vm_ioctl_cmds)); 170400ef17beSBartek Rutkowski return (cmds); 170500ef17beSBartek Rutkowski } 170600ef17beSBartek Rutkowski 170700ef17beSBartek Rutkowski *len = nitems(vm_ioctl_cmds); 170800ef17beSBartek Rutkowski return (NULL); 170900ef17beSBartek Rutkowski } 1710