1366f6083SPeter Grehan /*- 2366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 3366f6083SPeter Grehan * All rights reserved. 4366f6083SPeter Grehan * 5366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 6366f6083SPeter Grehan * modification, are permitted provided that the following conditions 7366f6083SPeter Grehan * are met: 8366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 9366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 10366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 12366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 13366f6083SPeter Grehan * 14366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24366f6083SPeter Grehan * SUCH DAMAGE. 25366f6083SPeter Grehan * 26366f6083SPeter Grehan * $FreeBSD$ 27366f6083SPeter Grehan */ 28366f6083SPeter Grehan 29366f6083SPeter Grehan #include <sys/cdefs.h> 30366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 31366f6083SPeter Grehan 3295ebc360SNeel Natu #include <sys/param.h> 33366f6083SPeter Grehan #include <sys/sysctl.h> 34366f6083SPeter Grehan #include <sys/ioctl.h> 35366f6083SPeter Grehan #include <sys/mman.h> 366303b65dSNeel Natu #include <sys/_iovec.h> 3795ebc360SNeel Natu #include <sys/cpuset.h> 38366f6083SPeter Grehan 39d665d229SNeel Natu #include <x86/segments.h> 40366f6083SPeter Grehan #include <machine/specialreg.h> 41da11f4aaSNeel Natu #include <machine/param.h> 42366f6083SPeter Grehan 439c4d5478SNeel Natu #include <errno.h> 44366f6083SPeter Grehan #include <stdio.h> 45366f6083SPeter Grehan #include <stdlib.h> 46366f6083SPeter Grehan #include <assert.h> 47366f6083SPeter Grehan #include <string.h> 48366f6083SPeter Grehan #include <fcntl.h> 49366f6083SPeter Grehan #include <unistd.h> 50366f6083SPeter Grehan 51200758f1SNeel Natu #include <libutil.h> 52200758f1SNeel Natu 53366f6083SPeter Grehan #include <machine/vmm.h> 54366f6083SPeter Grehan #include <machine/vmm_dev.h> 55366f6083SPeter Grehan 56366f6083SPeter Grehan #include "vmmapi.h" 57366f6083SPeter Grehan 58200758f1SNeel Natu #define MB (1024 * 1024UL) 59b060ba50SNeel Natu #define GB (1024 * 1024 * 1024UL) 60b060ba50SNeel Natu 619b1aa8d6SNeel Natu /* 629b1aa8d6SNeel Natu * Size of the guard region before and after the virtual address space 639b1aa8d6SNeel Natu * mapping the guest physical memory. This must be a multiple of the 649b1aa8d6SNeel Natu * superpage size for performance reasons. 659b1aa8d6SNeel Natu */ 669b1aa8d6SNeel Natu #define VM_MMAP_GUARD_SIZE (4 * MB) 679b1aa8d6SNeel Natu 689b1aa8d6SNeel Natu #define PROT_RW (PROT_READ | PROT_WRITE) 699b1aa8d6SNeel Natu #define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC) 709b1aa8d6SNeel Natu 71366f6083SPeter Grehan struct vmctx { 72366f6083SPeter Grehan int fd; 73b060ba50SNeel Natu uint32_t lowmem_limit; 740dd10c00SNeel Natu int memflags; 75b060ba50SNeel Natu size_t lowmem; 76b060ba50SNeel Natu size_t highmem; 779b1aa8d6SNeel Natu char *baseaddr; 78366f6083SPeter Grehan char *name; 79366f6083SPeter Grehan }; 80366f6083SPeter Grehan 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 { 105366f6083SPeter Grehan 106366f6083SPeter Grehan return (CREATE((char *)name)); 107366f6083SPeter Grehan } 108366f6083SPeter Grehan 109366f6083SPeter Grehan struct vmctx * 110366f6083SPeter Grehan vm_open(const char *name) 111366f6083SPeter Grehan { 112366f6083SPeter Grehan struct vmctx *vm; 113366f6083SPeter Grehan 114366f6083SPeter Grehan vm = malloc(sizeof(struct vmctx) + strlen(name) + 1); 115366f6083SPeter Grehan assert(vm != NULL); 116366f6083SPeter Grehan 117366f6083SPeter Grehan vm->fd = -1; 1180dd10c00SNeel Natu vm->memflags = 0; 119b060ba50SNeel Natu vm->lowmem_limit = 3 * GB; 120366f6083SPeter Grehan vm->name = (char *)(vm + 1); 121366f6083SPeter Grehan strcpy(vm->name, name); 122366f6083SPeter Grehan 123366f6083SPeter Grehan if ((vm->fd = vm_device_open(vm->name)) < 0) 124366f6083SPeter Grehan goto err; 125366f6083SPeter Grehan 126366f6083SPeter Grehan return (vm); 127366f6083SPeter Grehan err: 128366f6083SPeter Grehan vm_destroy(vm); 129366f6083SPeter Grehan return (NULL); 130366f6083SPeter Grehan } 131366f6083SPeter Grehan 132366f6083SPeter Grehan void 133366f6083SPeter Grehan vm_destroy(struct vmctx *vm) 134366f6083SPeter Grehan { 135366f6083SPeter Grehan assert(vm != NULL); 136366f6083SPeter Grehan 137366f6083SPeter Grehan if (vm->fd >= 0) 138366f6083SPeter Grehan close(vm->fd); 139f7d51510SNeel Natu DESTROY(vm->name); 140f7d51510SNeel Natu 141366f6083SPeter Grehan free(vm); 142366f6083SPeter Grehan } 143366f6083SPeter Grehan 144366f6083SPeter Grehan int 145200758f1SNeel Natu vm_parse_memsize(const char *optarg, size_t *ret_memsize) 146200758f1SNeel Natu { 147200758f1SNeel Natu char *endptr; 148200758f1SNeel Natu size_t optval; 149200758f1SNeel Natu int error; 150200758f1SNeel Natu 151200758f1SNeel Natu optval = strtoul(optarg, &endptr, 0); 152200758f1SNeel Natu if (*optarg != '\0' && *endptr == '\0') { 153200758f1SNeel Natu /* 154200758f1SNeel Natu * For the sake of backward compatibility if the memory size 155200758f1SNeel Natu * specified on the command line is less than a megabyte then 156200758f1SNeel Natu * it is interpreted as being in units of MB. 157200758f1SNeel Natu */ 158200758f1SNeel Natu if (optval < MB) 159200758f1SNeel Natu optval *= MB; 160200758f1SNeel Natu *ret_memsize = optval; 161200758f1SNeel Natu error = 0; 162200758f1SNeel Natu } else 163200758f1SNeel Natu error = expand_number(optarg, ret_memsize); 164200758f1SNeel Natu 165200758f1SNeel Natu return (error); 166200758f1SNeel Natu } 167200758f1SNeel Natu 168b060ba50SNeel Natu uint32_t 169b060ba50SNeel Natu vm_get_lowmem_limit(struct vmctx *ctx) 170b060ba50SNeel Natu { 171b060ba50SNeel Natu 172b060ba50SNeel Natu return (ctx->lowmem_limit); 173b060ba50SNeel Natu } 174b060ba50SNeel Natu 175b060ba50SNeel Natu void 176b060ba50SNeel Natu vm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit) 177b060ba50SNeel Natu { 178b060ba50SNeel Natu 179b060ba50SNeel Natu ctx->lowmem_limit = limit; 180b060ba50SNeel Natu } 181b060ba50SNeel Natu 1820dd10c00SNeel Natu void 1830dd10c00SNeel Natu vm_set_memflags(struct vmctx *ctx, int flags) 1840dd10c00SNeel Natu { 1850dd10c00SNeel Natu 1860dd10c00SNeel Natu ctx->memflags = flags; 1870dd10c00SNeel Natu } 1880dd10c00SNeel Natu 1899b1aa8d6SNeel Natu int 1909b1aa8d6SNeel Natu vm_get_memflags(struct vmctx *ctx) 191366f6083SPeter Grehan { 1929b1aa8d6SNeel Natu 1939b1aa8d6SNeel Natu return (ctx->memflags); 1949b1aa8d6SNeel Natu } 195366f6083SPeter Grehan 196366f6083SPeter Grehan /* 1979b1aa8d6SNeel Natu * Map segment 'segid' starting at 'off' into guest address range [gpa,gpa+len). 198366f6083SPeter Grehan */ 1999b1aa8d6SNeel Natu int 2009b1aa8d6SNeel Natu vm_mmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, int segid, vm_ooffset_t off, 2019b1aa8d6SNeel Natu size_t len, int prot) 2029b1aa8d6SNeel Natu { 2039b1aa8d6SNeel Natu struct vm_memmap memmap; 2049b1aa8d6SNeel Natu int error, flags; 2059b1aa8d6SNeel Natu 2069b1aa8d6SNeel Natu memmap.gpa = gpa; 2079b1aa8d6SNeel Natu memmap.segid = segid; 2089b1aa8d6SNeel Natu memmap.segoff = off; 2099b1aa8d6SNeel Natu memmap.len = len; 2109b1aa8d6SNeel Natu memmap.prot = prot; 2119b1aa8d6SNeel Natu memmap.flags = 0; 2129b1aa8d6SNeel Natu 2139b1aa8d6SNeel Natu if (ctx->memflags & VM_MEM_F_WIRED) 2149b1aa8d6SNeel Natu memmap.flags |= VM_MEMMAP_F_WIRED; 2159b1aa8d6SNeel Natu 2169b1aa8d6SNeel Natu /* 2179b1aa8d6SNeel Natu * If this mapping already exists then don't create it again. This 2189b1aa8d6SNeel Natu * is the common case for SYSMEM mappings created by bhyveload(8). 2199b1aa8d6SNeel Natu */ 2209b1aa8d6SNeel Natu error = vm_mmap_getnext(ctx, &gpa, &segid, &off, &len, &prot, &flags); 2219b1aa8d6SNeel Natu if (error == 0 && gpa == memmap.gpa) { 2229b1aa8d6SNeel Natu if (segid != memmap.segid || off != memmap.segoff || 2239b1aa8d6SNeel Natu prot != memmap.prot || flags != memmap.flags) { 2249b1aa8d6SNeel Natu errno = EEXIST; 2259b1aa8d6SNeel Natu return (-1); 2269b1aa8d6SNeel Natu } else { 2279b1aa8d6SNeel Natu return (0); 2289b1aa8d6SNeel Natu } 2299b1aa8d6SNeel Natu } 2309b1aa8d6SNeel Natu 2319b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_MMAP_MEMSEG, &memmap); 2329b1aa8d6SNeel Natu return (error); 2339b1aa8d6SNeel Natu } 2349b1aa8d6SNeel Natu 2359b1aa8d6SNeel Natu int 2369b1aa8d6SNeel Natu vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid, 2379b1aa8d6SNeel Natu vm_ooffset_t *segoff, size_t *len, int *prot, int *flags) 2389b1aa8d6SNeel Natu { 2399b1aa8d6SNeel Natu struct vm_memmap memmap; 2409b1aa8d6SNeel Natu int error; 2419b1aa8d6SNeel Natu 2429b1aa8d6SNeel Natu bzero(&memmap, sizeof(struct vm_memmap)); 2439b1aa8d6SNeel Natu memmap.gpa = *gpa; 2449b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_MMAP_GETNEXT, &memmap); 2459b1aa8d6SNeel Natu if (error == 0) { 2469b1aa8d6SNeel Natu *gpa = memmap.gpa; 2479b1aa8d6SNeel Natu *segid = memmap.segid; 2489b1aa8d6SNeel Natu *segoff = memmap.segoff; 2499b1aa8d6SNeel Natu *len = memmap.len; 2509b1aa8d6SNeel Natu *prot = memmap.prot; 2519b1aa8d6SNeel Natu *flags = memmap.flags; 252366f6083SPeter Grehan } 253366f6083SPeter Grehan return (error); 254366f6083SPeter Grehan } 255366f6083SPeter Grehan 2569b1aa8d6SNeel Natu /* 2579b1aa8d6SNeel Natu * Return 0 if the segments are identical and non-zero otherwise. 2589b1aa8d6SNeel Natu * 2599b1aa8d6SNeel Natu * This is slightly complicated by the fact that only device memory segments 2609b1aa8d6SNeel Natu * are named. 2619b1aa8d6SNeel Natu */ 2629b1aa8d6SNeel Natu static int 2639b1aa8d6SNeel Natu cmpseg(size_t len, const char *str, size_t len2, const char *str2) 2649b1aa8d6SNeel Natu { 2659b1aa8d6SNeel Natu 2669b1aa8d6SNeel Natu if (len == len2) { 2679b1aa8d6SNeel Natu if ((!str && !str2) || (str && str2 && !strcmp(str, str2))) 2689b1aa8d6SNeel Natu return (0); 2699b1aa8d6SNeel Natu } 2709b1aa8d6SNeel Natu return (-1); 2719b1aa8d6SNeel Natu } 2729b1aa8d6SNeel Natu 2739b1aa8d6SNeel Natu static int 2749b1aa8d6SNeel Natu vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name) 2759b1aa8d6SNeel Natu { 2769b1aa8d6SNeel Natu struct vm_memseg memseg; 2779b1aa8d6SNeel Natu size_t n; 2789b1aa8d6SNeel Natu int error; 2799b1aa8d6SNeel Natu 2809b1aa8d6SNeel Natu /* 2819b1aa8d6SNeel Natu * If the memory segment has already been created then just return. 2829b1aa8d6SNeel Natu * This is the usual case for the SYSMEM segment created by userspace 2839b1aa8d6SNeel Natu * loaders like bhyveload(8). 2849b1aa8d6SNeel Natu */ 2859b1aa8d6SNeel Natu error = vm_get_memseg(ctx, segid, &memseg.len, memseg.name, 2869b1aa8d6SNeel Natu sizeof(memseg.name)); 2879b1aa8d6SNeel Natu if (error) 2889b1aa8d6SNeel Natu return (error); 2899b1aa8d6SNeel Natu 2909b1aa8d6SNeel Natu if (memseg.len != 0) { 2919b1aa8d6SNeel Natu if (cmpseg(len, name, memseg.len, VM_MEMSEG_NAME(&memseg))) { 2929b1aa8d6SNeel Natu errno = EINVAL; 2939b1aa8d6SNeel Natu return (-1); 2949b1aa8d6SNeel Natu } else { 2959b1aa8d6SNeel Natu return (0); 2969b1aa8d6SNeel Natu } 2979b1aa8d6SNeel Natu } 2989b1aa8d6SNeel Natu 2999b1aa8d6SNeel Natu bzero(&memseg, sizeof(struct vm_memseg)); 3009b1aa8d6SNeel Natu memseg.segid = segid; 3019b1aa8d6SNeel Natu memseg.len = len; 3029b1aa8d6SNeel Natu if (name != NULL) { 3039b1aa8d6SNeel Natu n = strlcpy(memseg.name, name, sizeof(memseg.name)); 3049b1aa8d6SNeel Natu if (n >= sizeof(memseg.name)) { 3059b1aa8d6SNeel Natu errno = ENAMETOOLONG; 3069b1aa8d6SNeel Natu return (-1); 3079b1aa8d6SNeel Natu } 3089b1aa8d6SNeel Natu } 3099b1aa8d6SNeel Natu 3109b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_ALLOC_MEMSEG, &memseg); 3119b1aa8d6SNeel Natu return (error); 3129b1aa8d6SNeel Natu } 3139b1aa8d6SNeel Natu 3149b1aa8d6SNeel Natu int 3159b1aa8d6SNeel Natu vm_get_memseg(struct vmctx *ctx, int segid, size_t *lenp, char *namebuf, 3169b1aa8d6SNeel Natu size_t bufsize) 3179b1aa8d6SNeel Natu { 3189b1aa8d6SNeel Natu struct vm_memseg memseg; 3199b1aa8d6SNeel Natu size_t n; 3209b1aa8d6SNeel Natu int error; 3219b1aa8d6SNeel Natu 3229b1aa8d6SNeel Natu memseg.segid = segid; 3239b1aa8d6SNeel Natu error = ioctl(ctx->fd, VM_GET_MEMSEG, &memseg); 3249b1aa8d6SNeel Natu if (error == 0) { 3259b1aa8d6SNeel Natu *lenp = memseg.len; 3269b1aa8d6SNeel Natu n = strlcpy(namebuf, memseg.name, bufsize); 3279b1aa8d6SNeel Natu if (n >= bufsize) { 3289b1aa8d6SNeel Natu errno = ENAMETOOLONG; 3299b1aa8d6SNeel Natu error = -1; 3309b1aa8d6SNeel Natu } 3319b1aa8d6SNeel Natu } 3329b1aa8d6SNeel Natu return (error); 3339b1aa8d6SNeel Natu } 3349b1aa8d6SNeel Natu 3359b1aa8d6SNeel Natu static int 3369b1aa8d6SNeel Natu setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base) 3379b1aa8d6SNeel Natu { 3389b1aa8d6SNeel Natu char *ptr; 3399b1aa8d6SNeel Natu int error, flags; 3409b1aa8d6SNeel Natu 3419b1aa8d6SNeel Natu /* Map 'len' bytes starting at 'gpa' in the guest address space */ 3429b1aa8d6SNeel Natu error = vm_mmap_memseg(ctx, gpa, VM_SYSMEM, gpa, len, PROT_ALL); 3439b1aa8d6SNeel Natu if (error) 3449b1aa8d6SNeel Natu return (error); 3459b1aa8d6SNeel Natu 3469b1aa8d6SNeel Natu flags = MAP_SHARED | MAP_FIXED; 3479b1aa8d6SNeel Natu if ((ctx->memflags & VM_MEM_F_INCORE) == 0) 3489b1aa8d6SNeel Natu flags |= MAP_NOCORE; 3499b1aa8d6SNeel Natu 3509b1aa8d6SNeel Natu /* mmap into the process address space on the host */ 3519b1aa8d6SNeel Natu ptr = mmap(base + gpa, len, PROT_RW, flags, ctx->fd, gpa); 3529b1aa8d6SNeel Natu if (ptr == MAP_FAILED) 3539b1aa8d6SNeel Natu return (-1); 3549b1aa8d6SNeel Natu 3559b1aa8d6SNeel Natu return (0); 3569b1aa8d6SNeel Natu } 3579b1aa8d6SNeel Natu 358b060ba50SNeel Natu int 359b060ba50SNeel Natu vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms) 360b060ba50SNeel Natu { 3619b1aa8d6SNeel Natu size_t objsize, len; 3629b1aa8d6SNeel Natu vm_paddr_t gpa; 3639b1aa8d6SNeel Natu char *baseaddr, *ptr; 3649b1aa8d6SNeel Natu int error, flags; 365b060ba50SNeel Natu 3669b1aa8d6SNeel Natu assert(vms == VM_MMAP_ALL); 367b060ba50SNeel Natu 368b060ba50SNeel Natu /* 369b060ba50SNeel Natu * If 'memsize' cannot fit entirely in the 'lowmem' segment then 370b060ba50SNeel Natu * create another 'highmem' segment above 4GB for the remainder. 371b060ba50SNeel Natu */ 372b060ba50SNeel Natu if (memsize > ctx->lowmem_limit) { 373b060ba50SNeel Natu ctx->lowmem = ctx->lowmem_limit; 3749b1aa8d6SNeel Natu ctx->highmem = memsize - ctx->lowmem_limit; 3759b1aa8d6SNeel Natu objsize = 4*GB + ctx->highmem; 376b060ba50SNeel Natu } else { 377b060ba50SNeel Natu ctx->lowmem = memsize; 378b060ba50SNeel Natu ctx->highmem = 0; 3799b1aa8d6SNeel Natu objsize = ctx->lowmem; 3809b1aa8d6SNeel Natu } 3819b1aa8d6SNeel Natu 3829b1aa8d6SNeel Natu error = vm_alloc_memseg(ctx, VM_SYSMEM, objsize, NULL); 3839b1aa8d6SNeel Natu if (error) 3849b1aa8d6SNeel Natu return (error); 3859b1aa8d6SNeel Natu 3869b1aa8d6SNeel Natu /* 3879b1aa8d6SNeel Natu * Stake out a contiguous region covering the guest physical memory 3889b1aa8d6SNeel Natu * and the adjoining guard regions. 3899b1aa8d6SNeel Natu */ 3909b1aa8d6SNeel Natu len = VM_MMAP_GUARD_SIZE + objsize + VM_MMAP_GUARD_SIZE; 3919b1aa8d6SNeel Natu flags = MAP_PRIVATE | MAP_ANON | MAP_NOCORE | MAP_ALIGNED_SUPER; 3929b1aa8d6SNeel Natu ptr = mmap(NULL, len, PROT_NONE, flags, -1, 0); 3939b1aa8d6SNeel Natu if (ptr == MAP_FAILED) 3949b1aa8d6SNeel Natu return (-1); 3959b1aa8d6SNeel Natu 3969b1aa8d6SNeel Natu baseaddr = ptr + VM_MMAP_GUARD_SIZE; 3979b1aa8d6SNeel Natu if (ctx->highmem > 0) { 3989b1aa8d6SNeel Natu gpa = 4*GB; 3999b1aa8d6SNeel Natu len = ctx->highmem; 4009b1aa8d6SNeel Natu error = setup_memory_segment(ctx, gpa, len, baseaddr); 4019b1aa8d6SNeel Natu if (error) 4029b1aa8d6SNeel Natu return (error); 403b060ba50SNeel Natu } 404b060ba50SNeel Natu 405b060ba50SNeel Natu if (ctx->lowmem > 0) { 4069b1aa8d6SNeel Natu gpa = 0; 4079b1aa8d6SNeel Natu len = ctx->lowmem; 4089b1aa8d6SNeel Natu error = setup_memory_segment(ctx, gpa, len, baseaddr); 409b060ba50SNeel Natu if (error) 410b060ba50SNeel Natu return (error); 411b060ba50SNeel Natu } 412b060ba50SNeel Natu 4139b1aa8d6SNeel Natu ctx->baseaddr = baseaddr; 414b060ba50SNeel Natu 415b060ba50SNeel Natu return (0); 416b060ba50SNeel Natu } 417b060ba50SNeel Natu 418*36e8356eSNeel Natu /* 419*36e8356eSNeel Natu * Returns a non-NULL pointer if [gaddr, gaddr+len) is entirely contained in 420*36e8356eSNeel Natu * the lowmem or highmem regions. 421*36e8356eSNeel Natu * 422*36e8356eSNeel Natu * In particular return NULL if [gaddr, gaddr+len) falls in guest MMIO region. 423*36e8356eSNeel Natu * The instruction emulation code depends on this behavior. 424*36e8356eSNeel Natu */ 425b060ba50SNeel Natu void * 426b060ba50SNeel Natu vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len) 427366f6083SPeter Grehan { 428366f6083SPeter Grehan 429*36e8356eSNeel Natu if (ctx->lowmem > 0) { 430*36e8356eSNeel Natu if (gaddr < ctx->lowmem && gaddr + len <= ctx->lowmem) 431*36e8356eSNeel Natu return (ctx->baseaddr + gaddr); 432*36e8356eSNeel Natu } 433b060ba50SNeel Natu 434*36e8356eSNeel Natu if (ctx->highmem > 0) { 435*36e8356eSNeel Natu if (gaddr >= 4*GB && gaddr + len <= 4*GB + ctx->highmem) 436*36e8356eSNeel Natu return (ctx->baseaddr + gaddr); 437*36e8356eSNeel Natu } 438*36e8356eSNeel Natu 439b060ba50SNeel Natu return (NULL); 440366f6083SPeter Grehan } 441366f6083SPeter Grehan 442be679db4SNeel Natu size_t 443be679db4SNeel Natu vm_get_lowmem_size(struct vmctx *ctx) 444be679db4SNeel Natu { 445be679db4SNeel Natu 446be679db4SNeel Natu return (ctx->lowmem); 447be679db4SNeel Natu } 448be679db4SNeel Natu 449be679db4SNeel Natu size_t 450be679db4SNeel Natu vm_get_highmem_size(struct vmctx *ctx) 451be679db4SNeel Natu { 452be679db4SNeel Natu 453be679db4SNeel Natu return (ctx->highmem); 454be679db4SNeel Natu } 455be679db4SNeel Natu 4569b1aa8d6SNeel Natu void * 4579b1aa8d6SNeel Natu vm_create_devmem(struct vmctx *ctx, int segid, const char *name, size_t len) 4589b1aa8d6SNeel Natu { 4599b1aa8d6SNeel Natu char pathname[MAXPATHLEN]; 4609b1aa8d6SNeel Natu size_t len2; 4619b1aa8d6SNeel Natu char *base, *ptr; 4629b1aa8d6SNeel Natu int fd, error, flags; 4639b1aa8d6SNeel Natu 4649b1aa8d6SNeel Natu fd = -1; 4659b1aa8d6SNeel Natu ptr = MAP_FAILED; 4669b1aa8d6SNeel Natu if (name == NULL || strlen(name) == 0) { 4679b1aa8d6SNeel Natu errno = EINVAL; 4689b1aa8d6SNeel Natu goto done; 4699b1aa8d6SNeel Natu } 4709b1aa8d6SNeel Natu 4719b1aa8d6SNeel Natu error = vm_alloc_memseg(ctx, segid, len, name); 4729b1aa8d6SNeel Natu if (error) 4739b1aa8d6SNeel Natu goto done; 4749b1aa8d6SNeel Natu 4759b1aa8d6SNeel Natu strlcpy(pathname, "/dev/vmm/", sizeof(pathname)); 4769b1aa8d6SNeel Natu strlcat(pathname, ctx->name, sizeof(pathname)); 4779b1aa8d6SNeel Natu strlcat(pathname, ".", sizeof(pathname)); 4789b1aa8d6SNeel Natu strlcat(pathname, name, sizeof(pathname)); 4799b1aa8d6SNeel Natu 4809b1aa8d6SNeel Natu fd = open(pathname, O_RDWR); 4819b1aa8d6SNeel Natu if (fd < 0) 4829b1aa8d6SNeel Natu goto done; 4839b1aa8d6SNeel Natu 4849b1aa8d6SNeel Natu /* 4859b1aa8d6SNeel Natu * Stake out a contiguous region covering the device memory and the 4869b1aa8d6SNeel Natu * adjoining guard regions. 4879b1aa8d6SNeel Natu */ 4889b1aa8d6SNeel Natu len2 = VM_MMAP_GUARD_SIZE + len + VM_MMAP_GUARD_SIZE; 4899b1aa8d6SNeel Natu flags = MAP_PRIVATE | MAP_ANON | MAP_NOCORE | MAP_ALIGNED_SUPER; 4909b1aa8d6SNeel Natu base = mmap(NULL, len2, PROT_NONE, flags, -1, 0); 4919b1aa8d6SNeel Natu if (base == MAP_FAILED) 4929b1aa8d6SNeel Natu goto done; 4939b1aa8d6SNeel Natu 4949b1aa8d6SNeel Natu flags = MAP_SHARED | MAP_FIXED; 4959b1aa8d6SNeel Natu if ((ctx->memflags & VM_MEM_F_INCORE) == 0) 4969b1aa8d6SNeel Natu flags |= MAP_NOCORE; 4979b1aa8d6SNeel Natu 4989b1aa8d6SNeel Natu /* mmap the devmem region in the host address space */ 4999b1aa8d6SNeel Natu ptr = mmap(base + VM_MMAP_GUARD_SIZE, len, PROT_RW, flags, fd, 0); 5009b1aa8d6SNeel Natu done: 5019b1aa8d6SNeel Natu if (fd >= 0) 5029b1aa8d6SNeel Natu close(fd); 5039b1aa8d6SNeel Natu return (ptr); 5049b1aa8d6SNeel Natu } 5059b1aa8d6SNeel Natu 506366f6083SPeter Grehan int 507366f6083SPeter Grehan vm_set_desc(struct vmctx *ctx, int vcpu, int reg, 508366f6083SPeter Grehan uint64_t base, uint32_t limit, uint32_t access) 509366f6083SPeter Grehan { 510366f6083SPeter Grehan int error; 511366f6083SPeter Grehan struct vm_seg_desc vmsegdesc; 512366f6083SPeter Grehan 513366f6083SPeter Grehan bzero(&vmsegdesc, sizeof(vmsegdesc)); 514366f6083SPeter Grehan vmsegdesc.cpuid = vcpu; 515366f6083SPeter Grehan vmsegdesc.regnum = reg; 516366f6083SPeter Grehan vmsegdesc.desc.base = base; 517366f6083SPeter Grehan vmsegdesc.desc.limit = limit; 518366f6083SPeter Grehan vmsegdesc.desc.access = access; 519366f6083SPeter Grehan 520366f6083SPeter Grehan error = ioctl(ctx->fd, VM_SET_SEGMENT_DESCRIPTOR, &vmsegdesc); 521366f6083SPeter Grehan return (error); 522366f6083SPeter Grehan } 523366f6083SPeter Grehan 524366f6083SPeter Grehan int 525366f6083SPeter Grehan vm_get_desc(struct vmctx *ctx, int vcpu, int reg, 526366f6083SPeter Grehan uint64_t *base, uint32_t *limit, uint32_t *access) 527366f6083SPeter Grehan { 528366f6083SPeter Grehan int error; 529366f6083SPeter Grehan struct vm_seg_desc vmsegdesc; 530366f6083SPeter Grehan 531366f6083SPeter Grehan bzero(&vmsegdesc, sizeof(vmsegdesc)); 532366f6083SPeter Grehan vmsegdesc.cpuid = vcpu; 533366f6083SPeter Grehan vmsegdesc.regnum = reg; 534366f6083SPeter Grehan 535366f6083SPeter Grehan error = ioctl(ctx->fd, VM_GET_SEGMENT_DESCRIPTOR, &vmsegdesc); 536366f6083SPeter Grehan if (error == 0) { 537366f6083SPeter Grehan *base = vmsegdesc.desc.base; 538366f6083SPeter Grehan *limit = vmsegdesc.desc.limit; 539366f6083SPeter Grehan *access = vmsegdesc.desc.access; 540366f6083SPeter Grehan } 541366f6083SPeter Grehan return (error); 542366f6083SPeter Grehan } 543366f6083SPeter Grehan 544366f6083SPeter Grehan int 545d665d229SNeel Natu vm_get_seg_desc(struct vmctx *ctx, int vcpu, int reg, struct seg_desc *seg_desc) 546d665d229SNeel Natu { 547d665d229SNeel Natu int error; 548d665d229SNeel Natu 549d665d229SNeel Natu error = vm_get_desc(ctx, vcpu, reg, &seg_desc->base, &seg_desc->limit, 550d665d229SNeel Natu &seg_desc->access); 551d665d229SNeel Natu return (error); 552d665d229SNeel Natu } 553d665d229SNeel Natu 554d665d229SNeel Natu int 555366f6083SPeter Grehan vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val) 556366f6083SPeter Grehan { 557366f6083SPeter Grehan int error; 558366f6083SPeter Grehan struct vm_register vmreg; 559366f6083SPeter Grehan 560366f6083SPeter Grehan bzero(&vmreg, sizeof(vmreg)); 561366f6083SPeter Grehan vmreg.cpuid = vcpu; 562366f6083SPeter Grehan vmreg.regnum = reg; 563366f6083SPeter Grehan vmreg.regval = val; 564366f6083SPeter Grehan 565366f6083SPeter Grehan error = ioctl(ctx->fd, VM_SET_REGISTER, &vmreg); 566366f6083SPeter Grehan return (error); 567366f6083SPeter Grehan } 568366f6083SPeter Grehan 569366f6083SPeter Grehan int 570366f6083SPeter Grehan vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *ret_val) 571366f6083SPeter Grehan { 572366f6083SPeter Grehan int error; 573366f6083SPeter Grehan struct vm_register vmreg; 574366f6083SPeter Grehan 575366f6083SPeter Grehan bzero(&vmreg, sizeof(vmreg)); 576366f6083SPeter Grehan vmreg.cpuid = vcpu; 577366f6083SPeter Grehan vmreg.regnum = reg; 578366f6083SPeter Grehan 579366f6083SPeter Grehan error = ioctl(ctx->fd, VM_GET_REGISTER, &vmreg); 580366f6083SPeter Grehan *ret_val = vmreg.regval; 581366f6083SPeter Grehan return (error); 582366f6083SPeter Grehan } 583366f6083SPeter Grehan 584366f6083SPeter Grehan int 585d087a399SNeel Natu vm_run(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit) 586366f6083SPeter Grehan { 587366f6083SPeter Grehan int error; 588366f6083SPeter Grehan struct vm_run vmrun; 589366f6083SPeter Grehan 590366f6083SPeter Grehan bzero(&vmrun, sizeof(vmrun)); 591366f6083SPeter Grehan vmrun.cpuid = vcpu; 592366f6083SPeter Grehan 593366f6083SPeter Grehan error = ioctl(ctx->fd, VM_RUN, &vmrun); 594366f6083SPeter Grehan bcopy(&vmrun.vm_exit, vmexit, sizeof(struct vm_exit)); 595366f6083SPeter Grehan return (error); 596366f6083SPeter Grehan } 597366f6083SPeter Grehan 598b15a09c0SNeel Natu int 599f0fdcfe2SNeel Natu vm_suspend(struct vmctx *ctx, enum vm_suspend_how how) 600b15a09c0SNeel Natu { 601f0fdcfe2SNeel Natu struct vm_suspend vmsuspend; 602b15a09c0SNeel Natu 603f0fdcfe2SNeel Natu bzero(&vmsuspend, sizeof(vmsuspend)); 604f0fdcfe2SNeel Natu vmsuspend.how = how; 605f0fdcfe2SNeel Natu return (ioctl(ctx->fd, VM_SUSPEND, &vmsuspend)); 606b15a09c0SNeel Natu } 607b15a09c0SNeel Natu 6085fcf252fSNeel Natu int 6095fcf252fSNeel Natu vm_reinit(struct vmctx *ctx) 6105fcf252fSNeel Natu { 6115fcf252fSNeel Natu 6125fcf252fSNeel Natu return (ioctl(ctx->fd, VM_REINIT, 0)); 6135fcf252fSNeel Natu } 6145fcf252fSNeel Natu 615d087a399SNeel Natu int 616d087a399SNeel Natu vm_inject_exception(struct vmctx *ctx, int vcpu, int vector, int errcode_valid, 617d087a399SNeel Natu uint32_t errcode, int restart_instruction) 618366f6083SPeter Grehan { 619dc506506SNeel Natu struct vm_exception exc; 620366f6083SPeter Grehan 621dc506506SNeel Natu exc.cpuid = vcpu; 622dc506506SNeel Natu exc.vector = vector; 623d087a399SNeel Natu exc.error_code = errcode; 624d087a399SNeel Natu exc.error_code_valid = errcode_valid; 625d087a399SNeel Natu exc.restart_instruction = restart_instruction; 626366f6083SPeter Grehan 627dc506506SNeel Natu return (ioctl(ctx->fd, VM_INJECT_EXCEPTION, &exc)); 628366f6083SPeter Grehan } 629366f6083SPeter Grehan 630366f6083SPeter Grehan int 63190d4b48fSNeel Natu vm_apicid2vcpu(struct vmctx *ctx, int apicid) 63290d4b48fSNeel Natu { 63390d4b48fSNeel Natu /* 63490d4b48fSNeel Natu * The apic id associated with the 'vcpu' has the same numerical value 63590d4b48fSNeel Natu * as the 'vcpu' itself. 63690d4b48fSNeel Natu */ 63790d4b48fSNeel Natu return (apicid); 63890d4b48fSNeel Natu } 63990d4b48fSNeel Natu 64090d4b48fSNeel Natu int 641366f6083SPeter Grehan vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector) 642366f6083SPeter Grehan { 643366f6083SPeter Grehan struct vm_lapic_irq vmirq; 644366f6083SPeter Grehan 645366f6083SPeter Grehan bzero(&vmirq, sizeof(vmirq)); 646366f6083SPeter Grehan vmirq.cpuid = vcpu; 647366f6083SPeter Grehan vmirq.vector = vector; 648366f6083SPeter Grehan 649366f6083SPeter Grehan return (ioctl(ctx->fd, VM_LAPIC_IRQ, &vmirq)); 650366f6083SPeter Grehan } 651366f6083SPeter Grehan 652366f6083SPeter Grehan int 653330baf58SJohn Baldwin vm_lapic_local_irq(struct vmctx *ctx, int vcpu, int vector) 654330baf58SJohn Baldwin { 655330baf58SJohn Baldwin struct vm_lapic_irq vmirq; 656330baf58SJohn Baldwin 657330baf58SJohn Baldwin bzero(&vmirq, sizeof(vmirq)); 658330baf58SJohn Baldwin vmirq.cpuid = vcpu; 659330baf58SJohn Baldwin vmirq.vector = vector; 660330baf58SJohn Baldwin 661330baf58SJohn Baldwin return (ioctl(ctx->fd, VM_LAPIC_LOCAL_IRQ, &vmirq)); 662330baf58SJohn Baldwin } 663330baf58SJohn Baldwin 664330baf58SJohn Baldwin int 6654f8be175SNeel Natu vm_lapic_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg) 6664f8be175SNeel Natu { 6674f8be175SNeel Natu struct vm_lapic_msi vmmsi; 6684f8be175SNeel Natu 6694f8be175SNeel Natu bzero(&vmmsi, sizeof(vmmsi)); 6704f8be175SNeel Natu vmmsi.addr = addr; 6714f8be175SNeel Natu vmmsi.msg = msg; 6724f8be175SNeel Natu 6734f8be175SNeel Natu return (ioctl(ctx->fd, VM_LAPIC_MSI, &vmmsi)); 6744f8be175SNeel Natu } 6754f8be175SNeel Natu 6764f8be175SNeel Natu int 677565bbb86SNeel Natu vm_ioapic_assert_irq(struct vmctx *ctx, int irq) 678565bbb86SNeel Natu { 679565bbb86SNeel Natu struct vm_ioapic_irq ioapic_irq; 680565bbb86SNeel Natu 681565bbb86SNeel Natu bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 682565bbb86SNeel Natu ioapic_irq.irq = irq; 683565bbb86SNeel Natu 684565bbb86SNeel Natu return (ioctl(ctx->fd, VM_IOAPIC_ASSERT_IRQ, &ioapic_irq)); 685565bbb86SNeel Natu } 686565bbb86SNeel Natu 687565bbb86SNeel Natu int 688565bbb86SNeel Natu vm_ioapic_deassert_irq(struct vmctx *ctx, int irq) 689565bbb86SNeel Natu { 690565bbb86SNeel Natu struct vm_ioapic_irq ioapic_irq; 691565bbb86SNeel Natu 692565bbb86SNeel Natu bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 693565bbb86SNeel Natu ioapic_irq.irq = irq; 694565bbb86SNeel Natu 695565bbb86SNeel Natu return (ioctl(ctx->fd, VM_IOAPIC_DEASSERT_IRQ, &ioapic_irq)); 696565bbb86SNeel Natu } 697565bbb86SNeel Natu 698565bbb86SNeel Natu int 699ac7304a7SNeel Natu vm_ioapic_pulse_irq(struct vmctx *ctx, int irq) 700ac7304a7SNeel Natu { 701ac7304a7SNeel Natu struct vm_ioapic_irq ioapic_irq; 702ac7304a7SNeel Natu 703ac7304a7SNeel Natu bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 704ac7304a7SNeel Natu ioapic_irq.irq = irq; 705ac7304a7SNeel Natu 706ac7304a7SNeel Natu return (ioctl(ctx->fd, VM_IOAPIC_PULSE_IRQ, &ioapic_irq)); 707ac7304a7SNeel Natu } 708ac7304a7SNeel Natu 709ac7304a7SNeel Natu int 7103cbf3585SJohn Baldwin vm_ioapic_pincount(struct vmctx *ctx, int *pincount) 7113cbf3585SJohn Baldwin { 7123cbf3585SJohn Baldwin 7133cbf3585SJohn Baldwin return (ioctl(ctx->fd, VM_IOAPIC_PINCOUNT, pincount)); 7143cbf3585SJohn Baldwin } 7153cbf3585SJohn Baldwin 7163cbf3585SJohn Baldwin int 717762fd208STycho Nightingale vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 718762fd208STycho Nightingale { 719762fd208STycho Nightingale struct vm_isa_irq isa_irq; 720762fd208STycho Nightingale 721762fd208STycho Nightingale bzero(&isa_irq, sizeof(struct vm_isa_irq)); 722762fd208STycho Nightingale isa_irq.atpic_irq = atpic_irq; 723762fd208STycho Nightingale isa_irq.ioapic_irq = ioapic_irq; 724762fd208STycho Nightingale 725762fd208STycho Nightingale return (ioctl(ctx->fd, VM_ISA_ASSERT_IRQ, &isa_irq)); 726762fd208STycho Nightingale } 727762fd208STycho Nightingale 728762fd208STycho Nightingale int 729762fd208STycho Nightingale vm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 730762fd208STycho Nightingale { 731762fd208STycho Nightingale struct vm_isa_irq isa_irq; 732762fd208STycho Nightingale 733762fd208STycho Nightingale bzero(&isa_irq, sizeof(struct vm_isa_irq)); 734762fd208STycho Nightingale isa_irq.atpic_irq = atpic_irq; 735762fd208STycho Nightingale isa_irq.ioapic_irq = ioapic_irq; 736762fd208STycho Nightingale 737762fd208STycho Nightingale return (ioctl(ctx->fd, VM_ISA_DEASSERT_IRQ, &isa_irq)); 738762fd208STycho Nightingale } 739762fd208STycho Nightingale 740762fd208STycho Nightingale int 741762fd208STycho Nightingale vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 742762fd208STycho Nightingale { 743762fd208STycho Nightingale struct vm_isa_irq isa_irq; 744b3e9732aSJohn Baldwin 745762fd208STycho Nightingale bzero(&isa_irq, sizeof(struct vm_isa_irq)); 746762fd208STycho Nightingale isa_irq.atpic_irq = atpic_irq; 747762fd208STycho Nightingale isa_irq.ioapic_irq = ioapic_irq; 748762fd208STycho Nightingale 749762fd208STycho Nightingale return (ioctl(ctx->fd, VM_ISA_PULSE_IRQ, &isa_irq)); 750762fd208STycho Nightingale } 751762fd208STycho Nightingale 752762fd208STycho Nightingale int 753b3e9732aSJohn Baldwin vm_isa_set_irq_trigger(struct vmctx *ctx, int atpic_irq, 754b3e9732aSJohn Baldwin enum vm_intr_trigger trigger) 755b3e9732aSJohn Baldwin { 756b3e9732aSJohn Baldwin struct vm_isa_irq_trigger isa_irq_trigger; 757b3e9732aSJohn Baldwin 758b3e9732aSJohn Baldwin bzero(&isa_irq_trigger, sizeof(struct vm_isa_irq_trigger)); 759b3e9732aSJohn Baldwin isa_irq_trigger.atpic_irq = atpic_irq; 760b3e9732aSJohn Baldwin isa_irq_trigger.trigger = trigger; 761b3e9732aSJohn Baldwin 762b3e9732aSJohn Baldwin return (ioctl(ctx->fd, VM_ISA_SET_IRQ_TRIGGER, &isa_irq_trigger)); 763b3e9732aSJohn Baldwin } 764b3e9732aSJohn Baldwin 765b3e9732aSJohn Baldwin int 766366f6083SPeter Grehan vm_inject_nmi(struct vmctx *ctx, int vcpu) 767366f6083SPeter Grehan { 768366f6083SPeter Grehan struct vm_nmi vmnmi; 769366f6083SPeter Grehan 770366f6083SPeter Grehan bzero(&vmnmi, sizeof(vmnmi)); 771366f6083SPeter Grehan vmnmi.cpuid = vcpu; 772366f6083SPeter Grehan 773366f6083SPeter Grehan return (ioctl(ctx->fd, VM_INJECT_NMI, &vmnmi)); 774366f6083SPeter Grehan } 775366f6083SPeter Grehan 776366f6083SPeter Grehan static struct { 777366f6083SPeter Grehan const char *name; 778366f6083SPeter Grehan int type; 779366f6083SPeter Grehan } capstrmap[] = { 780366f6083SPeter Grehan { "hlt_exit", VM_CAP_HALT_EXIT }, 781366f6083SPeter Grehan { "mtrap_exit", VM_CAP_MTRAP_EXIT }, 782366f6083SPeter Grehan { "pause_exit", VM_CAP_PAUSE_EXIT }, 783366f6083SPeter Grehan { "unrestricted_guest", VM_CAP_UNRESTRICTED_GUEST }, 78449cc03daSNeel Natu { "enable_invpcid", VM_CAP_ENABLE_INVPCID }, 785366f6083SPeter Grehan { 0 } 786366f6083SPeter Grehan }; 787366f6083SPeter Grehan 78813f4cf6cSNeel Natu int 78913f4cf6cSNeel Natu vm_capability_name2type(const char *capname) 79013f4cf6cSNeel Natu { 79113f4cf6cSNeel Natu int i; 79213f4cf6cSNeel Natu 793366f6083SPeter Grehan for (i = 0; capstrmap[i].name != NULL && capname != NULL; i++) { 794366f6083SPeter Grehan if (strcmp(capstrmap[i].name, capname) == 0) 795366f6083SPeter Grehan return (capstrmap[i].type); 796366f6083SPeter Grehan } 797366f6083SPeter Grehan 798366f6083SPeter Grehan return (-1); 799366f6083SPeter Grehan } 800366f6083SPeter Grehan 80113f4cf6cSNeel Natu const char * 80213f4cf6cSNeel Natu vm_capability_type2name(int type) 80313f4cf6cSNeel Natu { 80413f4cf6cSNeel Natu int i; 80513f4cf6cSNeel Natu 80613f4cf6cSNeel Natu for (i = 0; capstrmap[i].name != NULL; i++) { 80713f4cf6cSNeel Natu if (capstrmap[i].type == type) 80813f4cf6cSNeel Natu return (capstrmap[i].name); 80913f4cf6cSNeel Natu } 81013f4cf6cSNeel Natu 81113f4cf6cSNeel Natu return (NULL); 81213f4cf6cSNeel Natu } 81313f4cf6cSNeel Natu 814366f6083SPeter Grehan int 815366f6083SPeter Grehan vm_get_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, 816366f6083SPeter Grehan int *retval) 817366f6083SPeter Grehan { 818366f6083SPeter Grehan int error; 819366f6083SPeter Grehan struct vm_capability vmcap; 820366f6083SPeter Grehan 821366f6083SPeter Grehan bzero(&vmcap, sizeof(vmcap)); 822366f6083SPeter Grehan vmcap.cpuid = vcpu; 823366f6083SPeter Grehan vmcap.captype = cap; 824366f6083SPeter Grehan 825366f6083SPeter Grehan error = ioctl(ctx->fd, VM_GET_CAPABILITY, &vmcap); 826366f6083SPeter Grehan *retval = vmcap.capval; 827366f6083SPeter Grehan return (error); 828366f6083SPeter Grehan } 829366f6083SPeter Grehan 830366f6083SPeter Grehan int 831366f6083SPeter Grehan vm_set_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, int val) 832366f6083SPeter Grehan { 833366f6083SPeter Grehan struct vm_capability vmcap; 834366f6083SPeter Grehan 835366f6083SPeter Grehan bzero(&vmcap, sizeof(vmcap)); 836366f6083SPeter Grehan vmcap.cpuid = vcpu; 837366f6083SPeter Grehan vmcap.captype = cap; 838366f6083SPeter Grehan vmcap.capval = val; 839366f6083SPeter Grehan 840366f6083SPeter Grehan return (ioctl(ctx->fd, VM_SET_CAPABILITY, &vmcap)); 841366f6083SPeter Grehan } 842366f6083SPeter Grehan 843366f6083SPeter Grehan int 844366f6083SPeter Grehan vm_assign_pptdev(struct vmctx *ctx, int bus, int slot, int func) 845366f6083SPeter Grehan { 846366f6083SPeter Grehan struct vm_pptdev pptdev; 847366f6083SPeter Grehan 848366f6083SPeter Grehan bzero(&pptdev, sizeof(pptdev)); 849366f6083SPeter Grehan pptdev.bus = bus; 850366f6083SPeter Grehan pptdev.slot = slot; 851366f6083SPeter Grehan pptdev.func = func; 852366f6083SPeter Grehan 853366f6083SPeter Grehan return (ioctl(ctx->fd, VM_BIND_PPTDEV, &pptdev)); 854366f6083SPeter Grehan } 855366f6083SPeter Grehan 856366f6083SPeter Grehan int 857366f6083SPeter Grehan vm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func) 858366f6083SPeter Grehan { 859366f6083SPeter Grehan struct vm_pptdev pptdev; 860366f6083SPeter Grehan 861366f6083SPeter Grehan bzero(&pptdev, sizeof(pptdev)); 862366f6083SPeter Grehan pptdev.bus = bus; 863366f6083SPeter Grehan pptdev.slot = slot; 864366f6083SPeter Grehan pptdev.func = func; 865366f6083SPeter Grehan 866366f6083SPeter Grehan return (ioctl(ctx->fd, VM_UNBIND_PPTDEV, &pptdev)); 867366f6083SPeter Grehan } 868366f6083SPeter Grehan 869366f6083SPeter Grehan int 870366f6083SPeter Grehan vm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func, 871366f6083SPeter Grehan vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 872366f6083SPeter Grehan { 873366f6083SPeter Grehan struct vm_pptdev_mmio pptmmio; 874366f6083SPeter Grehan 875366f6083SPeter Grehan bzero(&pptmmio, sizeof(pptmmio)); 876366f6083SPeter Grehan pptmmio.bus = bus; 877366f6083SPeter Grehan pptmmio.slot = slot; 878366f6083SPeter Grehan pptmmio.func = func; 879366f6083SPeter Grehan pptmmio.gpa = gpa; 880366f6083SPeter Grehan pptmmio.len = len; 881366f6083SPeter Grehan pptmmio.hpa = hpa; 882366f6083SPeter Grehan 883366f6083SPeter Grehan return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio)); 884366f6083SPeter Grehan } 885366f6083SPeter Grehan 886366f6083SPeter Grehan int 88755888cfaSNeel Natu vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func, 8884f8be175SNeel Natu uint64_t addr, uint64_t msg, int numvec) 889366f6083SPeter Grehan { 890366f6083SPeter Grehan struct vm_pptdev_msi pptmsi; 891366f6083SPeter Grehan 892366f6083SPeter Grehan bzero(&pptmsi, sizeof(pptmsi)); 893366f6083SPeter Grehan pptmsi.vcpu = vcpu; 894366f6083SPeter Grehan pptmsi.bus = bus; 895366f6083SPeter Grehan pptmsi.slot = slot; 896366f6083SPeter Grehan pptmsi.func = func; 8974f8be175SNeel Natu pptmsi.msg = msg; 8984f8be175SNeel Natu pptmsi.addr = addr; 899366f6083SPeter Grehan pptmsi.numvec = numvec; 900366f6083SPeter Grehan 901366f6083SPeter Grehan return (ioctl(ctx->fd, VM_PPTDEV_MSI, &pptmsi)); 902366f6083SPeter Grehan } 903366f6083SPeter Grehan 904cd942e0fSPeter Grehan int 90555888cfaSNeel Natu vm_setup_pptdev_msix(struct vmctx *ctx, int vcpu, int bus, int slot, int func, 9064f8be175SNeel Natu int idx, uint64_t addr, uint64_t msg, uint32_t vector_control) 907cd942e0fSPeter Grehan { 908cd942e0fSPeter Grehan struct vm_pptdev_msix pptmsix; 909cd942e0fSPeter Grehan 910cd942e0fSPeter Grehan bzero(&pptmsix, sizeof(pptmsix)); 911cd942e0fSPeter Grehan pptmsix.vcpu = vcpu; 912cd942e0fSPeter Grehan pptmsix.bus = bus; 913cd942e0fSPeter Grehan pptmsix.slot = slot; 914cd942e0fSPeter Grehan pptmsix.func = func; 915cd942e0fSPeter Grehan pptmsix.idx = idx; 916cd942e0fSPeter Grehan pptmsix.msg = msg; 917cd942e0fSPeter Grehan pptmsix.addr = addr; 918cd942e0fSPeter Grehan pptmsix.vector_control = vector_control; 919cd942e0fSPeter Grehan 920cd942e0fSPeter Grehan return ioctl(ctx->fd, VM_PPTDEV_MSIX, &pptmsix); 921cd942e0fSPeter Grehan } 922cd942e0fSPeter Grehan 923366f6083SPeter Grehan uint64_t * 924366f6083SPeter Grehan vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv, 925366f6083SPeter Grehan int *ret_entries) 926366f6083SPeter Grehan { 927366f6083SPeter Grehan int error; 928366f6083SPeter Grehan 929366f6083SPeter Grehan static struct vm_stats vmstats; 930366f6083SPeter Grehan 931366f6083SPeter Grehan vmstats.cpuid = vcpu; 932366f6083SPeter Grehan 933366f6083SPeter Grehan error = ioctl(ctx->fd, VM_STATS, &vmstats); 934366f6083SPeter Grehan if (error == 0) { 935366f6083SPeter Grehan if (ret_entries) 936366f6083SPeter Grehan *ret_entries = vmstats.num_entries; 937366f6083SPeter Grehan if (ret_tv) 938366f6083SPeter Grehan *ret_tv = vmstats.tv; 939366f6083SPeter Grehan return (vmstats.statbuf); 940366f6083SPeter Grehan } else 941366f6083SPeter Grehan return (NULL); 942366f6083SPeter Grehan } 943366f6083SPeter Grehan 944366f6083SPeter Grehan const char * 945366f6083SPeter Grehan vm_get_stat_desc(struct vmctx *ctx, int index) 946366f6083SPeter Grehan { 947366f6083SPeter Grehan static struct vm_stat_desc statdesc; 948366f6083SPeter Grehan 949366f6083SPeter Grehan statdesc.index = index; 950366f6083SPeter Grehan if (ioctl(ctx->fd, VM_STAT_DESC, &statdesc) == 0) 951366f6083SPeter Grehan return (statdesc.desc); 952366f6083SPeter Grehan else 953366f6083SPeter Grehan return (NULL); 954366f6083SPeter Grehan } 955366f6083SPeter Grehan 956e9027382SNeel Natu int 957e9027382SNeel Natu vm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *state) 958e9027382SNeel Natu { 959e9027382SNeel Natu int error; 960e9027382SNeel Natu struct vm_x2apic x2apic; 961e9027382SNeel Natu 962e9027382SNeel Natu bzero(&x2apic, sizeof(x2apic)); 963e9027382SNeel Natu x2apic.cpuid = vcpu; 964e9027382SNeel Natu 965e9027382SNeel Natu error = ioctl(ctx->fd, VM_GET_X2APIC_STATE, &x2apic); 966e9027382SNeel Natu *state = x2apic.state; 967e9027382SNeel Natu return (error); 968e9027382SNeel Natu } 969e9027382SNeel Natu 970e9027382SNeel Natu int 971e9027382SNeel Natu vm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state state) 972e9027382SNeel Natu { 973e9027382SNeel Natu int error; 974e9027382SNeel Natu struct vm_x2apic x2apic; 975e9027382SNeel Natu 976e9027382SNeel Natu bzero(&x2apic, sizeof(x2apic)); 977e9027382SNeel Natu x2apic.cpuid = vcpu; 978e9027382SNeel Natu x2apic.state = state; 979e9027382SNeel Natu 980e9027382SNeel Natu error = ioctl(ctx->fd, VM_SET_X2APIC_STATE, &x2apic); 981e9027382SNeel Natu 982e9027382SNeel Natu return (error); 983e9027382SNeel Natu } 984e9027382SNeel Natu 985366f6083SPeter Grehan /* 986366f6083SPeter Grehan * From Intel Vol 3a: 987366f6083SPeter Grehan * Table 9-1. IA-32 Processor States Following Power-up, Reset or INIT 988366f6083SPeter Grehan */ 989366f6083SPeter Grehan int 990366f6083SPeter Grehan vcpu_reset(struct vmctx *vmctx, int vcpu) 991366f6083SPeter Grehan { 992366f6083SPeter Grehan int error; 993366f6083SPeter Grehan uint64_t rflags, rip, cr0, cr4, zero, desc_base, rdx; 994366f6083SPeter Grehan uint32_t desc_access, desc_limit; 995366f6083SPeter Grehan uint16_t sel; 996366f6083SPeter Grehan 997366f6083SPeter Grehan zero = 0; 998366f6083SPeter Grehan 999366f6083SPeter Grehan rflags = 0x2; 1000366f6083SPeter Grehan error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags); 1001366f6083SPeter Grehan if (error) 1002366f6083SPeter Grehan goto done; 1003366f6083SPeter Grehan 1004366f6083SPeter Grehan rip = 0xfff0; 1005366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0) 1006366f6083SPeter Grehan goto done; 1007366f6083SPeter Grehan 1008366f6083SPeter Grehan cr0 = CR0_NE; 1009366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0) 1010366f6083SPeter Grehan goto done; 1011366f6083SPeter Grehan 1012366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, zero)) != 0) 1013366f6083SPeter Grehan goto done; 1014366f6083SPeter Grehan 101532c96bc8SNeel Natu cr4 = 0; 1016366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0) 1017366f6083SPeter Grehan goto done; 1018366f6083SPeter Grehan 1019366f6083SPeter Grehan /* 1020366f6083SPeter Grehan * CS: present, r/w, accessed, 16-bit, byte granularity, usable 1021366f6083SPeter Grehan */ 1022366f6083SPeter Grehan desc_base = 0xffff0000; 1023366f6083SPeter Grehan desc_limit = 0xffff; 1024366f6083SPeter Grehan desc_access = 0x0093; 1025366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS, 1026366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1027366f6083SPeter Grehan if (error) 1028366f6083SPeter Grehan goto done; 1029366f6083SPeter Grehan 1030366f6083SPeter Grehan sel = 0xf000; 1031366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, sel)) != 0) 1032366f6083SPeter Grehan goto done; 1033366f6083SPeter Grehan 1034366f6083SPeter Grehan /* 1035366f6083SPeter Grehan * SS,DS,ES,FS,GS: present, r/w, accessed, 16-bit, byte granularity 1036366f6083SPeter Grehan */ 1037366f6083SPeter Grehan desc_base = 0; 1038366f6083SPeter Grehan desc_limit = 0xffff; 1039366f6083SPeter Grehan desc_access = 0x0093; 1040366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS, 1041366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1042366f6083SPeter Grehan if (error) 1043366f6083SPeter Grehan goto done; 1044366f6083SPeter Grehan 1045366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS, 1046366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1047366f6083SPeter Grehan if (error) 1048366f6083SPeter Grehan goto done; 1049366f6083SPeter Grehan 1050366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES, 1051366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1052366f6083SPeter Grehan if (error) 1053366f6083SPeter Grehan goto done; 1054366f6083SPeter Grehan 1055366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS, 1056366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1057366f6083SPeter Grehan if (error) 1058366f6083SPeter Grehan goto done; 1059366f6083SPeter Grehan 1060366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS, 1061366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1062366f6083SPeter Grehan if (error) 1063366f6083SPeter Grehan goto done; 1064366f6083SPeter Grehan 1065366f6083SPeter Grehan sel = 0; 1066366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, sel)) != 0) 1067366f6083SPeter Grehan goto done; 1068366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, sel)) != 0) 1069366f6083SPeter Grehan goto done; 1070366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, sel)) != 0) 1071366f6083SPeter Grehan goto done; 1072366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, sel)) != 0) 1073366f6083SPeter Grehan goto done; 1074366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, sel)) != 0) 1075366f6083SPeter Grehan goto done; 1076366f6083SPeter Grehan 1077366f6083SPeter Grehan /* General purpose registers */ 1078366f6083SPeter Grehan rdx = 0xf00; 1079366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RAX, zero)) != 0) 1080366f6083SPeter Grehan goto done; 1081366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBX, zero)) != 0) 1082366f6083SPeter Grehan goto done; 1083366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RCX, zero)) != 0) 1084366f6083SPeter Grehan goto done; 1085366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDX, rdx)) != 0) 1086366f6083SPeter Grehan goto done; 1087366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSI, zero)) != 0) 1088366f6083SPeter Grehan goto done; 1089366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDI, zero)) != 0) 1090366f6083SPeter Grehan goto done; 1091366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBP, zero)) != 0) 1092366f6083SPeter Grehan goto done; 1093366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, zero)) != 0) 1094366f6083SPeter Grehan goto done; 1095366f6083SPeter Grehan 1096366f6083SPeter Grehan /* GDTR, IDTR */ 1097366f6083SPeter Grehan desc_base = 0; 1098366f6083SPeter Grehan desc_limit = 0xffff; 1099366f6083SPeter Grehan desc_access = 0; 1100366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR, 1101366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1102366f6083SPeter Grehan if (error != 0) 1103366f6083SPeter Grehan goto done; 1104366f6083SPeter Grehan 1105366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_IDTR, 1106366f6083SPeter Grehan desc_base, desc_limit, desc_access); 1107366f6083SPeter Grehan if (error != 0) 1108366f6083SPeter Grehan goto done; 1109366f6083SPeter Grehan 1110366f6083SPeter Grehan /* TR */ 1111366f6083SPeter Grehan desc_base = 0; 1112366f6083SPeter Grehan desc_limit = 0xffff; 1113366f6083SPeter Grehan desc_access = 0x0000008b; 1114366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access); 1115366f6083SPeter Grehan if (error) 1116366f6083SPeter Grehan goto done; 1117366f6083SPeter Grehan 1118366f6083SPeter Grehan sel = 0; 1119366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, sel)) != 0) 1120366f6083SPeter Grehan goto done; 1121366f6083SPeter Grehan 1122366f6083SPeter Grehan /* LDTR */ 1123366f6083SPeter Grehan desc_base = 0; 1124366f6083SPeter Grehan desc_limit = 0xffff; 1125366f6083SPeter Grehan desc_access = 0x00000082; 1126366f6083SPeter Grehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, desc_base, 1127366f6083SPeter Grehan desc_limit, desc_access); 1128366f6083SPeter Grehan if (error) 1129366f6083SPeter Grehan goto done; 1130366f6083SPeter Grehan 1131366f6083SPeter Grehan sel = 0; 1132366f6083SPeter Grehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0) 1133366f6083SPeter Grehan goto done; 1134366f6083SPeter Grehan 1135366f6083SPeter Grehan /* XXX cr2, debug registers */ 1136366f6083SPeter Grehan 1137366f6083SPeter Grehan error = 0; 1138366f6083SPeter Grehan done: 1139366f6083SPeter Grehan return (error); 1140366f6083SPeter Grehan } 1141318224bbSNeel Natu 1142318224bbSNeel Natu int 1143318224bbSNeel Natu vm_get_gpa_pmap(struct vmctx *ctx, uint64_t gpa, uint64_t *pte, int *num) 1144318224bbSNeel Natu { 1145318224bbSNeel Natu int error, i; 1146318224bbSNeel Natu struct vm_gpa_pte gpapte; 1147318224bbSNeel Natu 1148318224bbSNeel Natu bzero(&gpapte, sizeof(gpapte)); 1149318224bbSNeel Natu gpapte.gpa = gpa; 1150318224bbSNeel Natu 1151318224bbSNeel Natu error = ioctl(ctx->fd, VM_GET_GPA_PMAP, &gpapte); 1152318224bbSNeel Natu 1153318224bbSNeel Natu if (error == 0) { 1154318224bbSNeel Natu *num = gpapte.ptenum; 1155318224bbSNeel Natu for (i = 0; i < gpapte.ptenum; i++) 1156318224bbSNeel Natu pte[i] = gpapte.pte[i]; 1157318224bbSNeel Natu } 1158318224bbSNeel Natu 1159318224bbSNeel Natu return (error); 1160318224bbSNeel Natu } 116108e3ff32SNeel Natu 116208e3ff32SNeel Natu int 116308e3ff32SNeel Natu vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities) 116408e3ff32SNeel Natu { 116508e3ff32SNeel Natu int error; 116608e3ff32SNeel Natu struct vm_hpet_cap cap; 116708e3ff32SNeel Natu 116808e3ff32SNeel Natu bzero(&cap, sizeof(struct vm_hpet_cap)); 116908e3ff32SNeel Natu error = ioctl(ctx->fd, VM_GET_HPET_CAPABILITIES, &cap); 117008e3ff32SNeel Natu if (capabilities != NULL) 117108e3ff32SNeel Natu *capabilities = cap.capabilities; 117208e3ff32SNeel Natu return (error); 117308e3ff32SNeel Natu } 1174da11f4aaSNeel Natu 11759c4d5478SNeel Natu int 11769c4d5478SNeel Natu vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 11779c4d5478SNeel Natu uint64_t gla, int prot, uint64_t *gpa, int *fault) 1178da11f4aaSNeel Natu { 1179da11f4aaSNeel Natu struct vm_gla2gpa gg; 1180da11f4aaSNeel Natu int error; 1181da11f4aaSNeel Natu 1182da11f4aaSNeel Natu bzero(&gg, sizeof(struct vm_gla2gpa)); 1183da11f4aaSNeel Natu gg.vcpuid = vcpu; 1184da11f4aaSNeel Natu gg.prot = prot; 1185da11f4aaSNeel Natu gg.gla = gla; 1186da11f4aaSNeel Natu gg.paging = *paging; 1187da11f4aaSNeel Natu 1188da11f4aaSNeel Natu error = ioctl(ctx->fd, VM_GLA2GPA, &gg); 1189da11f4aaSNeel Natu if (error == 0) { 1190da11f4aaSNeel Natu *fault = gg.fault; 1191da11f4aaSNeel Natu *gpa = gg.gpa; 1192da11f4aaSNeel Natu } 1193da11f4aaSNeel Natu return (error); 1194da11f4aaSNeel Natu } 1195da11f4aaSNeel Natu 1196da11f4aaSNeel Natu #ifndef min 1197da11f4aaSNeel Natu #define min(a,b) (((a) < (b)) ? (a) : (b)) 1198da11f4aaSNeel Natu #endif 1199da11f4aaSNeel Natu 1200da11f4aaSNeel Natu int 1201d665d229SNeel Natu vm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 12029c4d5478SNeel Natu uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt, 12039c4d5478SNeel Natu int *fault) 1204da11f4aaSNeel Natu { 1205009e2acbSNeel Natu void *va; 1206da11f4aaSNeel Natu uint64_t gpa; 12079c4d5478SNeel Natu int error, i, n, off; 12086303b65dSNeel Natu 12096303b65dSNeel Natu for (i = 0; i < iovcnt; i++) { 12106303b65dSNeel Natu iov[i].iov_base = 0; 12116303b65dSNeel Natu iov[i].iov_len = 0; 12126303b65dSNeel Natu } 12136303b65dSNeel Natu 12146303b65dSNeel Natu while (len) { 12156303b65dSNeel Natu assert(iovcnt > 0); 12169c4d5478SNeel Natu error = vm_gla2gpa(ctx, vcpu, paging, gla, prot, &gpa, fault); 12179c4d5478SNeel Natu if (error || *fault) 12189c4d5478SNeel Natu return (error); 12196303b65dSNeel Natu 12206303b65dSNeel Natu off = gpa & PAGE_MASK; 12216303b65dSNeel Natu n = min(len, PAGE_SIZE - off); 12226303b65dSNeel Natu 1223009e2acbSNeel Natu va = vm_map_gpa(ctx, gpa, n); 1224009e2acbSNeel Natu if (va == NULL) 12259c4d5478SNeel Natu return (EFAULT); 1226009e2acbSNeel Natu 1227009e2acbSNeel Natu iov->iov_base = va; 12286303b65dSNeel Natu iov->iov_len = n; 12296303b65dSNeel Natu iov++; 12306303b65dSNeel Natu iovcnt--; 12316303b65dSNeel Natu 12326303b65dSNeel Natu gla += n; 12336303b65dSNeel Natu len -= n; 12346303b65dSNeel Natu } 12356303b65dSNeel Natu return (0); 12366303b65dSNeel Natu } 12376303b65dSNeel Natu 12386303b65dSNeel Natu void 1239009e2acbSNeel Natu vm_copy_teardown(struct vmctx *ctx, int vcpu, struct iovec *iov, int iovcnt) 1240009e2acbSNeel Natu { 1241009e2acbSNeel Natu 1242009e2acbSNeel Natu return; 1243009e2acbSNeel Natu } 1244009e2acbSNeel Natu 1245009e2acbSNeel Natu void 12466303b65dSNeel Natu vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *iov, void *vp, size_t len) 12476303b65dSNeel Natu { 12486303b65dSNeel Natu const char *src; 12496303b65dSNeel Natu char *dst; 12506303b65dSNeel Natu size_t n; 1251da11f4aaSNeel Natu 1252da11f4aaSNeel Natu dst = vp; 1253da11f4aaSNeel Natu while (len) { 12546303b65dSNeel Natu assert(iov->iov_len); 12556303b65dSNeel Natu n = min(len, iov->iov_len); 1256009e2acbSNeel Natu src = iov->iov_base; 1257da11f4aaSNeel Natu bcopy(src, dst, n); 1258da11f4aaSNeel Natu 12596303b65dSNeel Natu iov++; 1260da11f4aaSNeel Natu dst += n; 1261da11f4aaSNeel Natu len -= n; 1262da11f4aaSNeel Natu } 1263da11f4aaSNeel Natu } 1264da11f4aaSNeel Natu 12656303b65dSNeel Natu void 12666303b65dSNeel Natu vm_copyout(struct vmctx *ctx, int vcpu, const void *vp, struct iovec *iov, 12676303b65dSNeel Natu size_t len) 1268da11f4aaSNeel Natu { 1269da11f4aaSNeel Natu const char *src; 12706303b65dSNeel Natu char *dst; 12716303b65dSNeel Natu size_t n; 1272da11f4aaSNeel Natu 1273da11f4aaSNeel Natu src = vp; 1274da11f4aaSNeel Natu while (len) { 12756303b65dSNeel Natu assert(iov->iov_len); 12766303b65dSNeel Natu n = min(len, iov->iov_len); 1277009e2acbSNeel Natu dst = iov->iov_base; 1278da11f4aaSNeel Natu bcopy(src, dst, n); 1279da11f4aaSNeel Natu 12806303b65dSNeel Natu iov++; 1281da11f4aaSNeel Natu src += n; 1282da11f4aaSNeel Natu len -= n; 1283da11f4aaSNeel Natu } 1284da11f4aaSNeel Natu } 128595ebc360SNeel Natu 128695ebc360SNeel Natu static int 128795ebc360SNeel Natu vm_get_cpus(struct vmctx *ctx, int which, cpuset_t *cpus) 128895ebc360SNeel Natu { 128995ebc360SNeel Natu struct vm_cpuset vm_cpuset; 129095ebc360SNeel Natu int error; 129195ebc360SNeel Natu 129295ebc360SNeel Natu bzero(&vm_cpuset, sizeof(struct vm_cpuset)); 129395ebc360SNeel Natu vm_cpuset.which = which; 129495ebc360SNeel Natu vm_cpuset.cpusetsize = sizeof(cpuset_t); 129595ebc360SNeel Natu vm_cpuset.cpus = cpus; 129695ebc360SNeel Natu 129795ebc360SNeel Natu error = ioctl(ctx->fd, VM_GET_CPUS, &vm_cpuset); 129895ebc360SNeel Natu return (error); 129995ebc360SNeel Natu } 130095ebc360SNeel Natu 130195ebc360SNeel Natu int 130295ebc360SNeel Natu vm_active_cpus(struct vmctx *ctx, cpuset_t *cpus) 130395ebc360SNeel Natu { 130495ebc360SNeel Natu 130595ebc360SNeel Natu return (vm_get_cpus(ctx, VM_ACTIVE_CPUS, cpus)); 130695ebc360SNeel Natu } 130795ebc360SNeel Natu 130895ebc360SNeel Natu int 130995ebc360SNeel Natu vm_suspended_cpus(struct vmctx *ctx, cpuset_t *cpus) 131095ebc360SNeel Natu { 131195ebc360SNeel Natu 131295ebc360SNeel Natu return (vm_get_cpus(ctx, VM_SUSPENDED_CPUS, cpus)); 131395ebc360SNeel Natu } 131495ebc360SNeel Natu 131595ebc360SNeel Natu int 131695ebc360SNeel Natu vm_activate_cpu(struct vmctx *ctx, int vcpu) 131795ebc360SNeel Natu { 131895ebc360SNeel Natu struct vm_activate_cpu ac; 131995ebc360SNeel Natu int error; 132095ebc360SNeel Natu 132195ebc360SNeel Natu bzero(&ac, sizeof(struct vm_activate_cpu)); 132295ebc360SNeel Natu ac.vcpuid = vcpu; 132395ebc360SNeel Natu error = ioctl(ctx->fd, VM_ACTIVATE_CPU, &ac); 132495ebc360SNeel Natu return (error); 132595ebc360SNeel Natu } 1326091d4532SNeel Natu 1327091d4532SNeel Natu int 1328091d4532SNeel Natu vm_get_intinfo(struct vmctx *ctx, int vcpu, uint64_t *info1, uint64_t *info2) 1329091d4532SNeel Natu { 1330091d4532SNeel Natu struct vm_intinfo vmii; 1331091d4532SNeel Natu int error; 1332091d4532SNeel Natu 1333091d4532SNeel Natu bzero(&vmii, sizeof(struct vm_intinfo)); 1334091d4532SNeel Natu vmii.vcpuid = vcpu; 1335091d4532SNeel Natu error = ioctl(ctx->fd, VM_GET_INTINFO, &vmii); 1336091d4532SNeel Natu if (error == 0) { 1337091d4532SNeel Natu *info1 = vmii.info1; 1338091d4532SNeel Natu *info2 = vmii.info2; 1339091d4532SNeel Natu } 1340091d4532SNeel Natu return (error); 1341091d4532SNeel Natu } 1342091d4532SNeel Natu 1343091d4532SNeel Natu int 1344091d4532SNeel Natu vm_set_intinfo(struct vmctx *ctx, int vcpu, uint64_t info1) 1345091d4532SNeel Natu { 1346091d4532SNeel Natu struct vm_intinfo vmii; 1347091d4532SNeel Natu int error; 1348091d4532SNeel Natu 1349091d4532SNeel Natu bzero(&vmii, sizeof(struct vm_intinfo)); 1350091d4532SNeel Natu vmii.vcpuid = vcpu; 1351091d4532SNeel Natu vmii.info1 = info1; 1352091d4532SNeel Natu error = ioctl(ctx->fd, VM_SET_INTINFO, &vmii); 1353091d4532SNeel Natu return (error); 1354091d4532SNeel Natu } 13550dafa5cdSNeel Natu 13560dafa5cdSNeel Natu int 13570dafa5cdSNeel Natu vm_rtc_write(struct vmctx *ctx, int offset, uint8_t value) 13580dafa5cdSNeel Natu { 13590dafa5cdSNeel Natu struct vm_rtc_data rtcdata; 13600dafa5cdSNeel Natu int error; 13610dafa5cdSNeel Natu 13620dafa5cdSNeel Natu bzero(&rtcdata, sizeof(struct vm_rtc_data)); 13630dafa5cdSNeel Natu rtcdata.offset = offset; 13640dafa5cdSNeel Natu rtcdata.value = value; 13650dafa5cdSNeel Natu error = ioctl(ctx->fd, VM_RTC_WRITE, &rtcdata); 13660dafa5cdSNeel Natu return (error); 13670dafa5cdSNeel Natu } 13680dafa5cdSNeel Natu 13690dafa5cdSNeel Natu int 13700dafa5cdSNeel Natu vm_rtc_read(struct vmctx *ctx, int offset, uint8_t *retval) 13710dafa5cdSNeel Natu { 13720dafa5cdSNeel Natu struct vm_rtc_data rtcdata; 13730dafa5cdSNeel Natu int error; 13740dafa5cdSNeel Natu 13750dafa5cdSNeel Natu bzero(&rtcdata, sizeof(struct vm_rtc_data)); 13760dafa5cdSNeel Natu rtcdata.offset = offset; 13770dafa5cdSNeel Natu error = ioctl(ctx->fd, VM_RTC_READ, &rtcdata); 13780dafa5cdSNeel Natu if (error == 0) 13790dafa5cdSNeel Natu *retval = rtcdata.value; 13800dafa5cdSNeel Natu return (error); 13810dafa5cdSNeel Natu } 13820dafa5cdSNeel Natu 13830dafa5cdSNeel Natu int 13840dafa5cdSNeel Natu vm_rtc_settime(struct vmctx *ctx, time_t secs) 13850dafa5cdSNeel Natu { 13860dafa5cdSNeel Natu struct vm_rtc_time rtctime; 13870dafa5cdSNeel Natu int error; 13880dafa5cdSNeel Natu 13890dafa5cdSNeel Natu bzero(&rtctime, sizeof(struct vm_rtc_time)); 13900dafa5cdSNeel Natu rtctime.secs = secs; 13910dafa5cdSNeel Natu error = ioctl(ctx->fd, VM_RTC_SETTIME, &rtctime); 13920dafa5cdSNeel Natu return (error); 13930dafa5cdSNeel Natu } 13940dafa5cdSNeel Natu 13950dafa5cdSNeel Natu int 13960dafa5cdSNeel Natu vm_rtc_gettime(struct vmctx *ctx, time_t *secs) 13970dafa5cdSNeel Natu { 13980dafa5cdSNeel Natu struct vm_rtc_time rtctime; 13990dafa5cdSNeel Natu int error; 14000dafa5cdSNeel Natu 14010dafa5cdSNeel Natu bzero(&rtctime, sizeof(struct vm_rtc_time)); 14020dafa5cdSNeel Natu error = ioctl(ctx->fd, VM_RTC_GETTIME, &rtctime); 14030dafa5cdSNeel Natu if (error == 0) 14040dafa5cdSNeel Natu *secs = rtctime.secs; 14050dafa5cdSNeel Natu return (error); 14060dafa5cdSNeel Natu } 1407d087a399SNeel Natu 1408d087a399SNeel Natu int 1409d087a399SNeel Natu vm_restart_instruction(void *arg, int vcpu) 1410d087a399SNeel Natu { 1411d087a399SNeel Natu struct vmctx *ctx = arg; 1412d087a399SNeel Natu 1413d087a399SNeel Natu return (ioctl(ctx->fd, VM_RESTART_INSTRUCTION, &vcpu)); 1414d087a399SNeel Natu } 1415