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