xref: /netbsd-src/lib/libnvmm/libnvmm.c (revision e0d9d410b7a676f4893e55bd6af3f26c867924a9)
1*e0d9d410Sreinoud /*	$NetBSD: libnvmm.c,v 1.20 2021/04/06 08:40:17 reinoud Exp $	*/
22760ca24Smaxv 
32760ca24Smaxv /*
44a2e4dc3Smaxv  * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
52760ca24Smaxv  * All rights reserved.
62760ca24Smaxv  *
74a2e4dc3Smaxv  * This code is part of the NVMM hypervisor.
82760ca24Smaxv  *
92760ca24Smaxv  * Redistribution and use in source and binary forms, with or without
102760ca24Smaxv  * modification, are permitted provided that the following conditions
112760ca24Smaxv  * are met:
122760ca24Smaxv  * 1. Redistributions of source code must retain the above copyright
132760ca24Smaxv  *    notice, this list of conditions and the following disclaimer.
142760ca24Smaxv  * 2. Redistributions in binary form must reproduce the above copyright
152760ca24Smaxv  *    notice, this list of conditions and the following disclaimer in the
162760ca24Smaxv  *    documentation and/or other materials provided with the distribution.
172760ca24Smaxv  *
184a2e4dc3Smaxv  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
194a2e4dc3Smaxv  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
204a2e4dc3Smaxv  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
214a2e4dc3Smaxv  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
224a2e4dc3Smaxv  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
234a2e4dc3Smaxv  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
244a2e4dc3Smaxv  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
254a2e4dc3Smaxv  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
264a2e4dc3Smaxv  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
274a2e4dc3Smaxv  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
284a2e4dc3Smaxv  * SUCH DAMAGE.
292760ca24Smaxv  */
302760ca24Smaxv 
312760ca24Smaxv #include <sys/cdefs.h>
322760ca24Smaxv 
332760ca24Smaxv #include <stdio.h>
342760ca24Smaxv #include <stdlib.h>
352760ca24Smaxv #include <string.h>
362760ca24Smaxv #include <unistd.h>
372760ca24Smaxv #include <fcntl.h>
382760ca24Smaxv #include <errno.h>
392760ca24Smaxv #include <sys/ioctl.h>
402760ca24Smaxv #include <sys/mman.h>
41a026d6cbSmaxv #include <sys/queue.h>
42f9737344Smaxv #include <machine/vmparam.h>
432760ca24Smaxv 
442760ca24Smaxv #include "nvmm.h"
452760ca24Smaxv 
46f9737344Smaxv static struct nvmm_capability __capability;
47f9737344Smaxv 
48f9737344Smaxv #ifdef __x86_64__
49f9737344Smaxv #include "libnvmm_x86.c"
50f9737344Smaxv #endif
5138b2a665Smaxv 
52a026d6cbSmaxv typedef struct __area {
53a026d6cbSmaxv 	LIST_ENTRY(__area) list;
54a026d6cbSmaxv 	gpaddr_t gpa;
55a026d6cbSmaxv 	uintptr_t hva;
56a026d6cbSmaxv 	size_t size;
57e00a8e01Smaxv 	nvmm_prot_t prot;
58a026d6cbSmaxv } area_t;
59a026d6cbSmaxv 
60a026d6cbSmaxv typedef LIST_HEAD(, __area) area_list_t;
61a026d6cbSmaxv 
622760ca24Smaxv static int nvmm_fd = -1;
632760ca24Smaxv 
642760ca24Smaxv /* -------------------------------------------------------------------------- */
652760ca24Smaxv 
666c8db606Smaxv static bool
__area_isvalid(struct nvmm_machine * mach,uintptr_t hva,gpaddr_t gpa,size_t size)676c8db606Smaxv __area_isvalid(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
68a026d6cbSmaxv     size_t size)
69a026d6cbSmaxv {
70a026d6cbSmaxv 	area_list_t *areas = mach->areas;
716c8db606Smaxv 	area_t *ent;
72a026d6cbSmaxv 
736c8db606Smaxv 	LIST_FOREACH(ent, areas, list) {
746c8db606Smaxv 		/* Collision on GPA */
756c8db606Smaxv 		if (gpa >= ent->gpa && gpa < ent->gpa + ent->size) {
766c8db606Smaxv 			return false;
77a026d6cbSmaxv 		}
78506b4248Smaxv 		if (gpa + size > ent->gpa &&
79506b4248Smaxv 		    gpa + size <= ent->gpa + ent->size) {
806c8db606Smaxv 			return false;
81a026d6cbSmaxv 		}
826c8db606Smaxv 		if (gpa <= ent->gpa && gpa + size >= ent->gpa + ent->size) {
836c8db606Smaxv 			return false;
84a026d6cbSmaxv 		}
85a026d6cbSmaxv 	}
86a026d6cbSmaxv 
876c8db606Smaxv 	return true;
88a026d6cbSmaxv }
89a026d6cbSmaxv 
90a026d6cbSmaxv static int
__area_add(struct nvmm_machine * mach,uintptr_t hva,gpaddr_t gpa,size_t size,int prot)91e00a8e01Smaxv __area_add(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size,
92e00a8e01Smaxv     int prot)
93a026d6cbSmaxv {
94a026d6cbSmaxv 	area_list_t *areas = mach->areas;
95e00a8e01Smaxv 	nvmm_prot_t nprot;
96a026d6cbSmaxv 	area_t *area;
976c8db606Smaxv 
98e00a8e01Smaxv 	nprot = 0;
99e00a8e01Smaxv 	if (prot & PROT_READ)
100e00a8e01Smaxv 		nprot |= NVMM_PROT_READ;
101e00a8e01Smaxv 	if (prot & PROT_WRITE)
102e00a8e01Smaxv 		nprot |= NVMM_PROT_WRITE;
103e00a8e01Smaxv 	if (prot & PROT_EXEC)
104e00a8e01Smaxv 		nprot |= NVMM_PROT_EXEC;
105e00a8e01Smaxv 
1066c8db606Smaxv 	if (!__area_isvalid(mach, hva, gpa, size)) {
1076c8db606Smaxv 		errno = EINVAL;
1086c8db606Smaxv 		return -1;
1096c8db606Smaxv 	}
110a026d6cbSmaxv 
111a026d6cbSmaxv 	area = malloc(sizeof(*area));
112a026d6cbSmaxv 	if (area == NULL)
113a026d6cbSmaxv 		return -1;
1142760ca24Smaxv 	area->gpa = gpa;
1152760ca24Smaxv 	area->hva = hva;
1162760ca24Smaxv 	area->size = size;
117e00a8e01Smaxv 	area->prot = nprot;
1182760ca24Smaxv 
1196c8db606Smaxv 	LIST_INSERT_HEAD(areas, area, list);
1206c8db606Smaxv 
1216c8db606Smaxv 	return 0;
1222760ca24Smaxv }
1232760ca24Smaxv 
1246c8db606Smaxv static int
__area_delete(struct nvmm_machine * mach,uintptr_t hva,gpaddr_t gpa,size_t size)1256c8db606Smaxv __area_delete(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
1266c8db606Smaxv     size_t size)
1276c8db606Smaxv {
1286c8db606Smaxv 	area_list_t *areas = mach->areas;
1296c8db606Smaxv 	area_t *ent, *nxt;
1306c8db606Smaxv 
1316c8db606Smaxv 	LIST_FOREACH_SAFE(ent, areas, list, nxt) {
1326c8db606Smaxv 		if (hva == ent->hva && gpa == ent->gpa && size == ent->size) {
1336c8db606Smaxv 			LIST_REMOVE(ent, list);
1346c8db606Smaxv 			free(ent);
135a026d6cbSmaxv 			return 0;
136a026d6cbSmaxv 		}
1376c8db606Smaxv 	}
1386c8db606Smaxv 
1396c8db606Smaxv 	return -1;
1406c8db606Smaxv }
141a026d6cbSmaxv 
142a026d6cbSmaxv static void
__area_remove_all(struct nvmm_machine * mach)143a026d6cbSmaxv __area_remove_all(struct nvmm_machine *mach)
1442760ca24Smaxv {
145a026d6cbSmaxv 	area_list_t *areas = mach->areas;
146a026d6cbSmaxv 	area_t *ent;
1472760ca24Smaxv 
148a026d6cbSmaxv 	while ((ent = LIST_FIRST(areas)) != NULL) {
149a026d6cbSmaxv 		LIST_REMOVE(ent, list);
150a026d6cbSmaxv 		free(ent);
1512760ca24Smaxv 	}
1522760ca24Smaxv 
153a026d6cbSmaxv 	free(areas);
1542760ca24Smaxv }
1552760ca24Smaxv 
1562760ca24Smaxv /* -------------------------------------------------------------------------- */
1572760ca24Smaxv 
158a6418236Smaxv int
nvmm_init(void)1592760ca24Smaxv nvmm_init(void)
1602760ca24Smaxv {
1612760ca24Smaxv 	if (nvmm_fd != -1)
1622760ca24Smaxv 		return 0;
163f9fb7866Smaxv 	nvmm_fd = open("/dev/nvmm", O_RDONLY | O_CLOEXEC);
1642760ca24Smaxv 	if (nvmm_fd == -1)
1652760ca24Smaxv 		return -1;
166f9737344Smaxv 	if (nvmm_capability(&__capability) == -1) {
167f9737344Smaxv 		close(nvmm_fd);
168f9737344Smaxv 		nvmm_fd = -1;
169f9737344Smaxv 		return -1;
170f9737344Smaxv 	}
171f9fb7866Smaxv 	if (__capability.version != NVMM_KERN_VERSION) {
172f9fb7866Smaxv 		close(nvmm_fd);
173f9fb7866Smaxv 		nvmm_fd = -1;
174f9fb7866Smaxv 		errno = EPROGMISMATCH;
175f9fb7866Smaxv 		return -1;
176f9fb7866Smaxv 	}
177f9fb7866Smaxv 
1782760ca24Smaxv 	return 0;
1792760ca24Smaxv }
1802760ca24Smaxv 
1812760ca24Smaxv int
nvmm_root_init(void)182d2ac291eSmaxv nvmm_root_init(void)
183d2ac291eSmaxv {
184d2ac291eSmaxv 	if (nvmm_fd != -1)
185d2ac291eSmaxv 		return 0;
186d2ac291eSmaxv 	nvmm_fd = open("/dev/nvmm", O_WRONLY | O_CLOEXEC);
187d2ac291eSmaxv 	if (nvmm_fd == -1)
188d2ac291eSmaxv 		return -1;
189d2ac291eSmaxv 	if (nvmm_capability(&__capability) == -1) {
190d2ac291eSmaxv 		close(nvmm_fd);
191d2ac291eSmaxv 		nvmm_fd = -1;
192d2ac291eSmaxv 		return -1;
193d2ac291eSmaxv 	}
194d2ac291eSmaxv 	if (__capability.version != NVMM_KERN_VERSION) {
195d2ac291eSmaxv 		close(nvmm_fd);
196d2ac291eSmaxv 		nvmm_fd = -1;
197d2ac291eSmaxv 		errno = EPROGMISMATCH;
198d2ac291eSmaxv 		return -1;
199d2ac291eSmaxv 	}
200d2ac291eSmaxv 
201d2ac291eSmaxv 	return 0;
202d2ac291eSmaxv }
203d2ac291eSmaxv 
204d2ac291eSmaxv int
nvmm_capability(struct nvmm_capability * cap)2052760ca24Smaxv nvmm_capability(struct nvmm_capability *cap)
2062760ca24Smaxv {
2072760ca24Smaxv 	struct nvmm_ioc_capability args;
2082760ca24Smaxv 	int ret;
2092760ca24Smaxv 
2102760ca24Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_CAPABILITY, &args);
2112760ca24Smaxv 	if (ret == -1)
2122760ca24Smaxv 		return -1;
2132760ca24Smaxv 
2142760ca24Smaxv 	memcpy(cap, &args.cap, sizeof(args.cap));
2152760ca24Smaxv 
2162760ca24Smaxv 	return 0;
2172760ca24Smaxv }
2182760ca24Smaxv 
2192760ca24Smaxv int
nvmm_machine_create(struct nvmm_machine * mach)2202760ca24Smaxv nvmm_machine_create(struct nvmm_machine *mach)
2212760ca24Smaxv {
2222760ca24Smaxv 	struct nvmm_ioc_machine_create args;
223f9737344Smaxv 	struct nvmm_comm_page **pages;
224a026d6cbSmaxv 	area_list_t *areas;
2252760ca24Smaxv 	int ret;
2262760ca24Smaxv 
227a026d6cbSmaxv 	areas = calloc(1, sizeof(*areas));
228a026d6cbSmaxv 	if (areas == NULL)
2292760ca24Smaxv 		return -1;
2302760ca24Smaxv 
231f9737344Smaxv 	pages = calloc(__capability.max_vcpus, sizeof(*pages));
232f9737344Smaxv 	if (pages == NULL) {
233f9737344Smaxv 		free(areas);
234f9737344Smaxv 		return -1;
235f9737344Smaxv 	}
236f9737344Smaxv 
237a026d6cbSmaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CREATE, &args);
238a026d6cbSmaxv 	if (ret == -1) {
239a026d6cbSmaxv 		free(areas);
240a026d6cbSmaxv 		return -1;
241a026d6cbSmaxv 	}
242a026d6cbSmaxv 
243a026d6cbSmaxv 	LIST_INIT(areas);
244f9737344Smaxv 
245f9737344Smaxv 	memset(mach, 0, sizeof(*mach));
2462760ca24Smaxv 	mach->machid = args.machid;
247f9737344Smaxv 	mach->pages = pages;
248f9737344Smaxv 	mach->areas = areas;
2492760ca24Smaxv 
2502760ca24Smaxv 	return 0;
2512760ca24Smaxv }
2522760ca24Smaxv 
2532760ca24Smaxv int
nvmm_machine_destroy(struct nvmm_machine * mach)2542760ca24Smaxv nvmm_machine_destroy(struct nvmm_machine *mach)
2552760ca24Smaxv {
2562760ca24Smaxv 	struct nvmm_ioc_machine_destroy args;
2572760ca24Smaxv 	int ret;
2582760ca24Smaxv 
2592760ca24Smaxv 	args.machid = mach->machid;
2602760ca24Smaxv 
2612760ca24Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_DESTROY, &args);
2622760ca24Smaxv 	if (ret == -1)
2632760ca24Smaxv 		return -1;
2642760ca24Smaxv 
265a026d6cbSmaxv 	__area_remove_all(mach);
266f9737344Smaxv 	free(mach->pages);
2672760ca24Smaxv 
2682760ca24Smaxv 	return 0;
2692760ca24Smaxv }
2702760ca24Smaxv 
2712760ca24Smaxv int
nvmm_machine_configure(struct nvmm_machine * mach,uint64_t op,void * conf)2722760ca24Smaxv nvmm_machine_configure(struct nvmm_machine *mach, uint64_t op, void *conf)
2732760ca24Smaxv {
2742760ca24Smaxv 	struct nvmm_ioc_machine_configure args;
2752760ca24Smaxv 	int ret;
2762760ca24Smaxv 
2772760ca24Smaxv 	args.machid = mach->machid;
2782760ca24Smaxv 	args.op = op;
2792760ca24Smaxv 	args.conf = conf;
2802760ca24Smaxv 
2812760ca24Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CONFIGURE, &args);
2822760ca24Smaxv 	if (ret == -1)
2832760ca24Smaxv 		return -1;
2842760ca24Smaxv 
2852760ca24Smaxv 	return 0;
2862760ca24Smaxv }
2872760ca24Smaxv 
2882760ca24Smaxv int
nvmm_vcpu_create(struct nvmm_machine * mach,nvmm_cpuid_t cpuid,struct nvmm_vcpu * vcpu)289d1002cd7Smaxv nvmm_vcpu_create(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
290d1002cd7Smaxv     struct nvmm_vcpu *vcpu)
2912760ca24Smaxv {
2922760ca24Smaxv 	struct nvmm_ioc_vcpu_create args;
293f9737344Smaxv 	struct nvmm_comm_page *comm;
2942760ca24Smaxv 	int ret;
2952760ca24Smaxv 
2962760ca24Smaxv 	args.machid = mach->machid;
2972760ca24Smaxv 	args.cpuid = cpuid;
2982760ca24Smaxv 
2992760ca24Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_CREATE, &args);
3002760ca24Smaxv 	if (ret == -1)
3012760ca24Smaxv 		return -1;
3022760ca24Smaxv 
303f9737344Smaxv 	comm = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FILE,
304f9737344Smaxv 	    nvmm_fd, NVMM_COMM_OFF(mach->machid, cpuid));
305f9737344Smaxv 	if (comm == MAP_FAILED)
306f9737344Smaxv 		return -1;
307f9737344Smaxv 
308f9737344Smaxv 	mach->pages[cpuid] = comm;
309f9737344Smaxv 
310d1002cd7Smaxv 	vcpu->cpuid = cpuid;
311d1002cd7Smaxv 	vcpu->state = &comm->state;
312d1002cd7Smaxv 	vcpu->event = &comm->event;
313*e0d9d410Sreinoud 	vcpu->stop = &comm->stop;
314d1002cd7Smaxv 	vcpu->exit = malloc(sizeof(*vcpu->exit));
315d1002cd7Smaxv 
3162760ca24Smaxv 	return 0;
3172760ca24Smaxv }
3182760ca24Smaxv 
3192760ca24Smaxv int
nvmm_vcpu_destroy(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu)320d1002cd7Smaxv nvmm_vcpu_destroy(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu)
3212760ca24Smaxv {
3222760ca24Smaxv 	struct nvmm_ioc_vcpu_destroy args;
323f9737344Smaxv 	struct nvmm_comm_page *comm;
3242760ca24Smaxv 	int ret;
3252760ca24Smaxv 
3262760ca24Smaxv 	args.machid = mach->machid;
327d1002cd7Smaxv 	args.cpuid = vcpu->cpuid;
3282760ca24Smaxv 
3292760ca24Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_DESTROY, &args);
3302760ca24Smaxv 	if (ret == -1)
3312760ca24Smaxv 		return -1;
3322760ca24Smaxv 
333d1002cd7Smaxv 	comm = mach->pages[vcpu->cpuid];
334f9737344Smaxv 	munmap(comm, PAGE_SIZE);
335d1002cd7Smaxv 	free(vcpu->exit);
336f9737344Smaxv 
3372760ca24Smaxv 	return 0;
3382760ca24Smaxv }
3392760ca24Smaxv 
3402760ca24Smaxv int
nvmm_vcpu_configure(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,uint64_t op,void * conf)341f9fb7866Smaxv nvmm_vcpu_configure(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
342f9fb7866Smaxv     uint64_t op, void *conf)
343f9fb7866Smaxv {
344f9fb7866Smaxv 	struct nvmm_ioc_vcpu_configure args;
345f9fb7866Smaxv 	int ret;
346f9fb7866Smaxv 
347e6f32a58Smaxv 	switch (op) {
348e6f32a58Smaxv 	case NVMM_VCPU_CONF_CALLBACKS:
349e6f32a58Smaxv 		memcpy(&vcpu->cbs, conf, sizeof(vcpu->cbs));
350e6f32a58Smaxv 		return 0;
351e6f32a58Smaxv 	}
352e6f32a58Smaxv 
353f9fb7866Smaxv 	args.machid = mach->machid;
354f9fb7866Smaxv 	args.cpuid = vcpu->cpuid;
355f9fb7866Smaxv 	args.op = op;
356f9fb7866Smaxv 	args.conf = conf;
357f9fb7866Smaxv 
358f9fb7866Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_CONFIGURE, &args);
359f9fb7866Smaxv 	if (ret == -1)
360f9fb7866Smaxv 		return -1;
361f9fb7866Smaxv 
362f9fb7866Smaxv 	return 0;
363f9fb7866Smaxv }
364f9fb7866Smaxv 
365f9fb7866Smaxv int
nvmm_vcpu_setstate(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,uint64_t flags)366d1002cd7Smaxv nvmm_vcpu_setstate(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
367d1002cd7Smaxv     uint64_t flags)
3682760ca24Smaxv {
369f9737344Smaxv 	struct nvmm_comm_page *comm;
3702760ca24Smaxv 
371d1002cd7Smaxv 	comm = mach->pages[vcpu->cpuid];
372f9737344Smaxv 	comm->state_commit |= flags;
373f9737344Smaxv 	comm->state_cached |= flags;
3742760ca24Smaxv 
3752760ca24Smaxv 	return 0;
3762760ca24Smaxv }
3772760ca24Smaxv 
3782760ca24Smaxv int
nvmm_vcpu_getstate(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu,uint64_t flags)379d1002cd7Smaxv nvmm_vcpu_getstate(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu,
380d1002cd7Smaxv     uint64_t flags)
3812760ca24Smaxv {
3822760ca24Smaxv 	struct nvmm_ioc_vcpu_getstate args;
383f9737344Smaxv 	struct nvmm_comm_page *comm;
3842760ca24Smaxv 	int ret;
3852760ca24Smaxv 
386d1002cd7Smaxv 	comm = mach->pages[vcpu->cpuid];
387f9737344Smaxv 
388f9737344Smaxv 	if (__predict_true((flags & ~comm->state_cached) == 0)) {
389d1002cd7Smaxv 		return 0;
390f9737344Smaxv 	}
391f9737344Smaxv 	comm->state_wanted = flags & ~comm->state_cached;
392f9737344Smaxv 
3932760ca24Smaxv 	args.machid = mach->machid;
394d1002cd7Smaxv 	args.cpuid = vcpu->cpuid;
3952760ca24Smaxv 
3962760ca24Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_GETSTATE, &args);
3972760ca24Smaxv 	if (ret == -1)
3982760ca24Smaxv 		return -1;
3992760ca24Smaxv 
4002760ca24Smaxv 	return 0;
4012760ca24Smaxv }
4022760ca24Smaxv 
4032760ca24Smaxv int
nvmm_vcpu_inject(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu)404d1002cd7Smaxv nvmm_vcpu_inject(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu)
4052760ca24Smaxv {
4060d954de6Smaxv 	struct nvmm_comm_page *comm;
4072760ca24Smaxv 
408d1002cd7Smaxv 	comm = mach->pages[vcpu->cpuid];
4090d954de6Smaxv 	comm->event_commit = true;
4102760ca24Smaxv 
4112760ca24Smaxv 	return 0;
4122760ca24Smaxv }
4132760ca24Smaxv 
4142760ca24Smaxv int
nvmm_vcpu_run(struct nvmm_machine * mach,struct nvmm_vcpu * vcpu)415d1002cd7Smaxv nvmm_vcpu_run(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu)
4162760ca24Smaxv {
4172760ca24Smaxv 	struct nvmm_ioc_vcpu_run args;
4182760ca24Smaxv 	int ret;
4192760ca24Smaxv 
4202760ca24Smaxv 	args.machid = mach->machid;
421d1002cd7Smaxv 	args.cpuid = vcpu->cpuid;
4222760ca24Smaxv 	memset(&args.exit, 0, sizeof(args.exit));
4232760ca24Smaxv 
4242760ca24Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_RUN, &args);
4252760ca24Smaxv 	if (ret == -1)
4262760ca24Smaxv 		return -1;
4272760ca24Smaxv 
428d1002cd7Smaxv 	/* No comm support yet, just copy. */
429d1002cd7Smaxv 	memcpy(vcpu->exit, &args.exit, sizeof(args.exit));
4302760ca24Smaxv 
4312760ca24Smaxv 	return 0;
4322760ca24Smaxv }
4332760ca24Smaxv 
4342760ca24Smaxv int
nvmm_gpa_map(struct nvmm_machine * mach,uintptr_t hva,gpaddr_t gpa,size_t size,int prot)4352760ca24Smaxv nvmm_gpa_map(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
436e8b93c69Smaxv     size_t size, int prot)
4372760ca24Smaxv {
4382760ca24Smaxv 	struct nvmm_ioc_gpa_map args;
4392760ca24Smaxv 	int ret;
4402760ca24Smaxv 
441e00a8e01Smaxv 	ret = __area_add(mach, hva, gpa, size, prot);
442a026d6cbSmaxv 	if (ret == -1)
443a026d6cbSmaxv 		return -1;
444a026d6cbSmaxv 
4452760ca24Smaxv 	args.machid = mach->machid;
4462760ca24Smaxv 	args.hva = hva;
4472760ca24Smaxv 	args.gpa = gpa;
4482760ca24Smaxv 	args.size = size;
449e8b93c69Smaxv 	args.prot = prot;
4502760ca24Smaxv 
4512760ca24Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_GPA_MAP, &args);
4522760ca24Smaxv 	if (ret == -1) {
453a026d6cbSmaxv 		/* Can't recover. */
454a026d6cbSmaxv 		abort();
4552760ca24Smaxv 	}
4562760ca24Smaxv 
4572760ca24Smaxv 	return 0;
4582760ca24Smaxv }
4592760ca24Smaxv 
4602760ca24Smaxv int
nvmm_gpa_unmap(struct nvmm_machine * mach,uintptr_t hva,gpaddr_t gpa,size_t size)4612760ca24Smaxv nvmm_gpa_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
4622760ca24Smaxv     size_t size)
4632760ca24Smaxv {
4646c8db606Smaxv 	struct nvmm_ioc_gpa_unmap args;
4656c8db606Smaxv 	int ret;
4666c8db606Smaxv 
4676c8db606Smaxv 	ret = __area_delete(mach, hva, gpa, size);
4686c8db606Smaxv 	if (ret == -1)
4696c8db606Smaxv 		return -1;
4706c8db606Smaxv 
4716c8db606Smaxv 	args.machid = mach->machid;
4726c8db606Smaxv 	args.gpa = gpa;
4736c8db606Smaxv 	args.size = size;
4746c8db606Smaxv 
4756c8db606Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, &args);
476506b4248Smaxv 	if (ret == -1) {
477506b4248Smaxv 		/* Can't recover. */
478506b4248Smaxv 		abort();
479506b4248Smaxv 	}
480506b4248Smaxv 
481506b4248Smaxv 	return 0;
482506b4248Smaxv }
483506b4248Smaxv 
484506b4248Smaxv int
nvmm_hva_map(struct nvmm_machine * mach,uintptr_t hva,size_t size)485506b4248Smaxv nvmm_hva_map(struct nvmm_machine *mach, uintptr_t hva, size_t size)
486506b4248Smaxv {
487506b4248Smaxv 	struct nvmm_ioc_hva_map args;
488506b4248Smaxv 	int ret;
489506b4248Smaxv 
490506b4248Smaxv 	args.machid = mach->machid;
491506b4248Smaxv 	args.hva = hva;
492506b4248Smaxv 	args.size = size;
493506b4248Smaxv 
494506b4248Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_HVA_MAP, &args);
4956c8db606Smaxv 	if (ret == -1)
4966c8db606Smaxv 		return -1;
4976c8db606Smaxv 
498506b4248Smaxv 	return 0;
499506b4248Smaxv }
5006c8db606Smaxv 
501506b4248Smaxv int
nvmm_hva_unmap(struct nvmm_machine * mach,uintptr_t hva,size_t size)502506b4248Smaxv nvmm_hva_unmap(struct nvmm_machine *mach, uintptr_t hva, size_t size)
503506b4248Smaxv {
50438b2a665Smaxv 	struct nvmm_ioc_hva_unmap args;
505506b4248Smaxv 	int ret;
506506b4248Smaxv 
507506b4248Smaxv 	args.machid = mach->machid;
508506b4248Smaxv 	args.hva = hva;
509506b4248Smaxv 	args.size = size;
510506b4248Smaxv 
51138b2a665Smaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_HVA_UNMAP, &args);
512506b4248Smaxv 	if (ret == -1)
513506b4248Smaxv 		return -1;
514506b4248Smaxv 
515506b4248Smaxv 	return 0;
5162760ca24Smaxv }
5172760ca24Smaxv 
5182760ca24Smaxv /*
5192760ca24Smaxv  * nvmm_gva_to_gpa(): architecture-specific.
5202760ca24Smaxv  */
5212760ca24Smaxv 
5222760ca24Smaxv int
nvmm_gpa_to_hva(struct nvmm_machine * mach,gpaddr_t gpa,uintptr_t * hva,nvmm_prot_t * prot)523e00a8e01Smaxv nvmm_gpa_to_hva(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t *hva,
524e00a8e01Smaxv     nvmm_prot_t *prot)
5252760ca24Smaxv {
526a026d6cbSmaxv 	area_list_t *areas = mach->areas;
527a026d6cbSmaxv 	area_t *ent;
5282760ca24Smaxv 
529a026d6cbSmaxv 	LIST_FOREACH(ent, areas, list) {
530506b4248Smaxv 		if (gpa >= ent->gpa && gpa < ent->gpa + ent->size) {
531a026d6cbSmaxv 			*hva = ent->hva + (gpa - ent->gpa);
532e00a8e01Smaxv 			*prot = ent->prot;
5332760ca24Smaxv 			return 0;
5342760ca24Smaxv 		}
535506b4248Smaxv 	}
5362760ca24Smaxv 
5372760ca24Smaxv 	errno = ENOENT;
5382760ca24Smaxv 	return -1;
5392760ca24Smaxv }
5402760ca24Smaxv 
5412760ca24Smaxv /*
5422760ca24Smaxv  * nvmm_assist_io(): architecture-specific.
5432760ca24Smaxv  */
54438b2a665Smaxv 
54538b2a665Smaxv /*
54638b2a665Smaxv  * nvmm_assist_mem(): architecture-specific.
54738b2a665Smaxv  */
54838b2a665Smaxv 
549fbb489fbSmaxv int
nvmm_ctl(int op,void * data,size_t size)550fbb489fbSmaxv nvmm_ctl(int op, void *data, size_t size)
551fbb489fbSmaxv {
552fbb489fbSmaxv 	struct nvmm_ioc_ctl args;
553fbb489fbSmaxv 	int ret;
554fbb489fbSmaxv 
555fbb489fbSmaxv 	args.op = op;
556fbb489fbSmaxv 	args.data = data;
557fbb489fbSmaxv 	args.size = size;
558fbb489fbSmaxv 
559fbb489fbSmaxv 	ret = ioctl(nvmm_fd, NVMM_IOC_CTL, &args);
560fbb489fbSmaxv 	if (ret == -1)
561fbb489fbSmaxv 		return -1;
562fbb489fbSmaxv 
563fbb489fbSmaxv 	return 0;
564fbb489fbSmaxv }
565*e0d9d410Sreinoud 
566*e0d9d410Sreinoud int
nvmm_vcpu_stop(struct nvmm_vcpu * vcpu)567*e0d9d410Sreinoud nvmm_vcpu_stop(struct nvmm_vcpu *vcpu)
568*e0d9d410Sreinoud {
569*e0d9d410Sreinoud 
570*e0d9d410Sreinoud 	*vcpu->stop = 1;
571*e0d9d410Sreinoud 
572*e0d9d410Sreinoud 	return 0;
573*e0d9d410Sreinoud }
574