libnvmm.c revision 1.1 1 1.1 maxv /* $NetBSD: libnvmm.c,v 1.1 2018/11/10 09:28:56 maxv Exp $ */
2 1.1 maxv
3 1.1 maxv /*
4 1.1 maxv * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 1.1 maxv * All rights reserved.
6 1.1 maxv *
7 1.1 maxv * This code is derived from software contributed to The NetBSD Foundation
8 1.1 maxv * by Maxime Villard.
9 1.1 maxv *
10 1.1 maxv * Redistribution and use in source and binary forms, with or without
11 1.1 maxv * modification, are permitted provided that the following conditions
12 1.1 maxv * are met:
13 1.1 maxv * 1. Redistributions of source code must retain the above copyright
14 1.1 maxv * notice, this list of conditions and the following disclaimer.
15 1.1 maxv * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 maxv * notice, this list of conditions and the following disclaimer in the
17 1.1 maxv * documentation and/or other materials provided with the distribution.
18 1.1 maxv *
19 1.1 maxv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 maxv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 maxv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 maxv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 maxv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 maxv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 maxv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 maxv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 maxv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 maxv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 maxv * POSSIBILITY OF SUCH DAMAGE.
30 1.1 maxv */
31 1.1 maxv
32 1.1 maxv #include <sys/cdefs.h>
33 1.1 maxv
34 1.1 maxv #include <stdio.h>
35 1.1 maxv #include <stdlib.h>
36 1.1 maxv #include <string.h>
37 1.1 maxv #include <unistd.h>
38 1.1 maxv #include <fcntl.h>
39 1.1 maxv #include <errno.h>
40 1.1 maxv #include <sys/ioctl.h>
41 1.1 maxv #include <sys/mman.h>
42 1.1 maxv
43 1.1 maxv #include "nvmm.h"
44 1.1 maxv
45 1.1 maxv static int nvmm_fd = -1;
46 1.1 maxv static size_t nvmm_page_size = 0;
47 1.1 maxv
48 1.1 maxv /* -------------------------------------------------------------------------- */
49 1.1 maxv
50 1.1 maxv static int
51 1.1 maxv _nvmm_area_add(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva,
52 1.1 maxv size_t size)
53 1.1 maxv {
54 1.1 maxv struct nvmm_area *area;
55 1.1 maxv void *ptr;
56 1.1 maxv size_t i;
57 1.1 maxv
58 1.1 maxv for (i = 0; i < mach->nareas; i++) {
59 1.1 maxv if (gpa >= mach->areas[i].gpa &&
60 1.1 maxv gpa < mach->areas[i].gpa + mach->areas[i].size) {
61 1.1 maxv goto error;
62 1.1 maxv }
63 1.1 maxv if (gpa + size >= mach->areas[i].gpa &&
64 1.1 maxv gpa + size < mach->areas[i].gpa + mach->areas[i].size) {
65 1.1 maxv goto error;
66 1.1 maxv }
67 1.1 maxv if (gpa < mach->areas[i].gpa &&
68 1.1 maxv gpa + size >= mach->areas[i].gpa + mach->areas[i].size) {
69 1.1 maxv goto error;
70 1.1 maxv }
71 1.1 maxv }
72 1.1 maxv
73 1.1 maxv mach->nareas++;
74 1.1 maxv ptr = realloc(mach->areas, mach->nareas * sizeof(struct nvmm_area));
75 1.1 maxv if (ptr == NULL)
76 1.1 maxv return -1;
77 1.1 maxv mach->areas = ptr;
78 1.1 maxv
79 1.1 maxv area = &mach->areas[mach->nareas-1];
80 1.1 maxv area->gpa = gpa;
81 1.1 maxv area->hva = hva;
82 1.1 maxv area->size = size;
83 1.1 maxv
84 1.1 maxv return 0;
85 1.1 maxv
86 1.1 maxv error:
87 1.1 maxv errno = EEXIST;
88 1.1 maxv return -1;
89 1.1 maxv }
90 1.1 maxv
91 1.1 maxv static int
92 1.1 maxv _nvmm_area_delete(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva,
93 1.1 maxv size_t size)
94 1.1 maxv {
95 1.1 maxv size_t i;
96 1.1 maxv
97 1.1 maxv for (i = 0; i < mach->nareas; i++) {
98 1.1 maxv if (gpa == mach->areas[i].gpa &&
99 1.1 maxv hva == mach->areas[i].hva &&
100 1.1 maxv size == mach->areas[i].size) {
101 1.1 maxv break;
102 1.1 maxv }
103 1.1 maxv }
104 1.1 maxv if (i == mach->nareas) {
105 1.1 maxv errno = ENOENT;
106 1.1 maxv return -1;
107 1.1 maxv }
108 1.1 maxv
109 1.1 maxv memcpy(&mach->areas[i], &mach->areas[i+1],
110 1.1 maxv (mach->nareas - i - 1) * sizeof(struct nvmm_area));
111 1.1 maxv mach->nareas--;
112 1.1 maxv
113 1.1 maxv return 0;
114 1.1 maxv }
115 1.1 maxv
116 1.1 maxv /* -------------------------------------------------------------------------- */
117 1.1 maxv
118 1.1 maxv static int
119 1.1 maxv nvmm_init(void)
120 1.1 maxv {
121 1.1 maxv if (nvmm_fd != -1)
122 1.1 maxv return 0;
123 1.1 maxv nvmm_fd = open("/dev/nvmm", O_RDWR);
124 1.1 maxv if (nvmm_fd == -1)
125 1.1 maxv return -1;
126 1.1 maxv nvmm_page_size = sysconf(_SC_PAGESIZE);
127 1.1 maxv return 0;
128 1.1 maxv }
129 1.1 maxv
130 1.1 maxv int
131 1.1 maxv nvmm_capability(struct nvmm_capability *cap)
132 1.1 maxv {
133 1.1 maxv struct nvmm_ioc_capability args;
134 1.1 maxv int ret;
135 1.1 maxv
136 1.1 maxv if (nvmm_init() == -1) {
137 1.1 maxv return -1;
138 1.1 maxv }
139 1.1 maxv
140 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_CAPABILITY, &args);
141 1.1 maxv if (ret == -1)
142 1.1 maxv return -1;
143 1.1 maxv
144 1.1 maxv memcpy(cap, &args.cap, sizeof(args.cap));
145 1.1 maxv
146 1.1 maxv return 0;
147 1.1 maxv }
148 1.1 maxv
149 1.1 maxv int
150 1.1 maxv nvmm_machine_create(struct nvmm_machine *mach)
151 1.1 maxv {
152 1.1 maxv struct nvmm_ioc_machine_create args;
153 1.1 maxv int ret;
154 1.1 maxv
155 1.1 maxv if (nvmm_init() == -1) {
156 1.1 maxv return -1;
157 1.1 maxv }
158 1.1 maxv
159 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CREATE, &args);
160 1.1 maxv if (ret == -1)
161 1.1 maxv return -1;
162 1.1 maxv
163 1.1 maxv memset(mach, 0, sizeof(*mach));
164 1.1 maxv mach->machid = args.machid;
165 1.1 maxv
166 1.1 maxv return 0;
167 1.1 maxv }
168 1.1 maxv
169 1.1 maxv int
170 1.1 maxv nvmm_machine_destroy(struct nvmm_machine *mach)
171 1.1 maxv {
172 1.1 maxv struct nvmm_ioc_machine_destroy args;
173 1.1 maxv int ret;
174 1.1 maxv
175 1.1 maxv if (nvmm_init() == -1) {
176 1.1 maxv return -1;
177 1.1 maxv }
178 1.1 maxv
179 1.1 maxv args.machid = mach->machid;
180 1.1 maxv
181 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_DESTROY, &args);
182 1.1 maxv if (ret == -1)
183 1.1 maxv return -1;
184 1.1 maxv
185 1.1 maxv free(mach->areas);
186 1.1 maxv
187 1.1 maxv return 0;
188 1.1 maxv }
189 1.1 maxv
190 1.1 maxv int
191 1.1 maxv nvmm_machine_configure(struct nvmm_machine *mach, uint64_t op, void *conf)
192 1.1 maxv {
193 1.1 maxv struct nvmm_ioc_machine_configure args;
194 1.1 maxv int ret;
195 1.1 maxv
196 1.1 maxv if (nvmm_init() == -1) {
197 1.1 maxv return -1;
198 1.1 maxv }
199 1.1 maxv
200 1.1 maxv args.machid = mach->machid;
201 1.1 maxv args.op = op;
202 1.1 maxv args.conf = conf;
203 1.1 maxv
204 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CONFIGURE, &args);
205 1.1 maxv if (ret == -1)
206 1.1 maxv return -1;
207 1.1 maxv
208 1.1 maxv return 0;
209 1.1 maxv }
210 1.1 maxv
211 1.1 maxv int
212 1.1 maxv nvmm_vcpu_create(struct nvmm_machine *mach, nvmm_cpuid_t cpuid)
213 1.1 maxv {
214 1.1 maxv struct nvmm_ioc_vcpu_create args;
215 1.1 maxv int ret;
216 1.1 maxv
217 1.1 maxv if (nvmm_init() == -1) {
218 1.1 maxv return -1;
219 1.1 maxv }
220 1.1 maxv
221 1.1 maxv args.machid = mach->machid;
222 1.1 maxv args.cpuid = cpuid;
223 1.1 maxv
224 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_CREATE, &args);
225 1.1 maxv if (ret == -1)
226 1.1 maxv return -1;
227 1.1 maxv
228 1.1 maxv return 0;
229 1.1 maxv }
230 1.1 maxv
231 1.1 maxv int
232 1.1 maxv nvmm_vcpu_destroy(struct nvmm_machine *mach, nvmm_cpuid_t cpuid)
233 1.1 maxv {
234 1.1 maxv struct nvmm_ioc_vcpu_destroy args;
235 1.1 maxv int ret;
236 1.1 maxv
237 1.1 maxv if (nvmm_init() == -1) {
238 1.1 maxv return -1;
239 1.1 maxv }
240 1.1 maxv
241 1.1 maxv args.machid = mach->machid;
242 1.1 maxv args.cpuid = cpuid;
243 1.1 maxv
244 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_DESTROY, &args);
245 1.1 maxv if (ret == -1)
246 1.1 maxv return -1;
247 1.1 maxv
248 1.1 maxv return 0;
249 1.1 maxv }
250 1.1 maxv
251 1.1 maxv int
252 1.1 maxv nvmm_vcpu_setstate(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
253 1.1 maxv void *state, uint64_t flags)
254 1.1 maxv {
255 1.1 maxv struct nvmm_ioc_vcpu_setstate args;
256 1.1 maxv int ret;
257 1.1 maxv
258 1.1 maxv if (nvmm_init() == -1) {
259 1.1 maxv return -1;
260 1.1 maxv }
261 1.1 maxv
262 1.1 maxv args.machid = mach->machid;
263 1.1 maxv args.cpuid = cpuid;
264 1.1 maxv args.state = state;
265 1.1 maxv args.flags = flags;
266 1.1 maxv
267 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_SETSTATE, &args);
268 1.1 maxv if (ret == -1)
269 1.1 maxv return -1;
270 1.1 maxv
271 1.1 maxv return 0;
272 1.1 maxv }
273 1.1 maxv
274 1.1 maxv int
275 1.1 maxv nvmm_vcpu_getstate(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
276 1.1 maxv void *state, uint64_t flags)
277 1.1 maxv {
278 1.1 maxv struct nvmm_ioc_vcpu_getstate args;
279 1.1 maxv int ret;
280 1.1 maxv
281 1.1 maxv if (nvmm_init() == -1) {
282 1.1 maxv return -1;
283 1.1 maxv }
284 1.1 maxv
285 1.1 maxv args.machid = mach->machid;
286 1.1 maxv args.cpuid = cpuid;
287 1.1 maxv args.state = state;
288 1.1 maxv args.flags = flags;
289 1.1 maxv
290 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_GETSTATE, &args);
291 1.1 maxv if (ret == -1)
292 1.1 maxv return -1;
293 1.1 maxv
294 1.1 maxv return 0;
295 1.1 maxv }
296 1.1 maxv
297 1.1 maxv int
298 1.1 maxv nvmm_vcpu_inject(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
299 1.1 maxv struct nvmm_event *event)
300 1.1 maxv {
301 1.1 maxv struct nvmm_ioc_vcpu_inject args;
302 1.1 maxv int ret;
303 1.1 maxv
304 1.1 maxv if (nvmm_init() == -1) {
305 1.1 maxv return -1;
306 1.1 maxv }
307 1.1 maxv
308 1.1 maxv args.machid = mach->machid;
309 1.1 maxv args.cpuid = cpuid;
310 1.1 maxv memcpy(&args.event, event, sizeof(args.event));
311 1.1 maxv
312 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_INJECT, &args);
313 1.1 maxv if (ret == -1)
314 1.1 maxv return -1;
315 1.1 maxv
316 1.1 maxv return 0;
317 1.1 maxv }
318 1.1 maxv
319 1.1 maxv int
320 1.1 maxv nvmm_vcpu_run(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
321 1.1 maxv struct nvmm_exit *exit)
322 1.1 maxv {
323 1.1 maxv struct nvmm_ioc_vcpu_run args;
324 1.1 maxv int ret;
325 1.1 maxv
326 1.1 maxv if (nvmm_init() == -1) {
327 1.1 maxv return -1;
328 1.1 maxv }
329 1.1 maxv
330 1.1 maxv args.machid = mach->machid;
331 1.1 maxv args.cpuid = cpuid;
332 1.1 maxv memset(&args.exit, 0, sizeof(args.exit));
333 1.1 maxv
334 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_RUN, &args);
335 1.1 maxv if (ret == -1)
336 1.1 maxv return -1;
337 1.1 maxv
338 1.1 maxv memcpy(exit, &args.exit, sizeof(args.exit));
339 1.1 maxv
340 1.1 maxv return 0;
341 1.1 maxv }
342 1.1 maxv
343 1.1 maxv int
344 1.1 maxv nvmm_gpa_map(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
345 1.1 maxv size_t size, int flags)
346 1.1 maxv {
347 1.1 maxv struct nvmm_ioc_gpa_map args;
348 1.1 maxv int ret;
349 1.1 maxv
350 1.1 maxv if (nvmm_init() == -1) {
351 1.1 maxv return -1;
352 1.1 maxv }
353 1.1 maxv
354 1.1 maxv args.machid = mach->machid;
355 1.1 maxv args.hva = hva;
356 1.1 maxv args.gpa = gpa;
357 1.1 maxv args.size = size;
358 1.1 maxv args.flags = flags;
359 1.1 maxv
360 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_GPA_MAP, &args);
361 1.1 maxv if (ret == -1)
362 1.1 maxv return -1;
363 1.1 maxv
364 1.1 maxv ret = _nvmm_area_add(mach, gpa, hva, size);
365 1.1 maxv if (ret == -1) {
366 1.1 maxv nvmm_gpa_unmap(mach, hva, gpa, size);
367 1.1 maxv return -1;
368 1.1 maxv }
369 1.1 maxv
370 1.1 maxv return 0;
371 1.1 maxv }
372 1.1 maxv
373 1.1 maxv int
374 1.1 maxv nvmm_gpa_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
375 1.1 maxv size_t size)
376 1.1 maxv {
377 1.1 maxv struct nvmm_ioc_gpa_unmap args;
378 1.1 maxv int ret;
379 1.1 maxv
380 1.1 maxv if (nvmm_init() == -1) {
381 1.1 maxv return -1;
382 1.1 maxv }
383 1.1 maxv
384 1.1 maxv ret = _nvmm_area_delete(mach, gpa, hva, size);
385 1.1 maxv if (ret == -1)
386 1.1 maxv return -1;
387 1.1 maxv
388 1.1 maxv args.machid = mach->machid;
389 1.1 maxv args.gpa = gpa;
390 1.1 maxv args.size = size;
391 1.1 maxv
392 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, &args);
393 1.1 maxv if (ret == -1)
394 1.1 maxv return -1;
395 1.1 maxv
396 1.1 maxv ret = munmap((void *)hva, size);
397 1.1 maxv
398 1.1 maxv return ret;
399 1.1 maxv }
400 1.1 maxv
401 1.1 maxv /*
402 1.1 maxv * nvmm_gva_to_gpa(): architecture-specific.
403 1.1 maxv */
404 1.1 maxv
405 1.1 maxv int
406 1.1 maxv nvmm_gpa_to_hva(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t *hva)
407 1.1 maxv {
408 1.1 maxv size_t i;
409 1.1 maxv
410 1.1 maxv if (gpa % nvmm_page_size != 0) {
411 1.1 maxv errno = EINVAL;
412 1.1 maxv return -1;
413 1.1 maxv }
414 1.1 maxv
415 1.1 maxv for (i = 0; i < mach->nareas; i++) {
416 1.1 maxv if (gpa < mach->areas[i].gpa) {
417 1.1 maxv continue;
418 1.1 maxv }
419 1.1 maxv if (gpa >= mach->areas[i].gpa + mach->areas[i].size) {
420 1.1 maxv continue;
421 1.1 maxv }
422 1.1 maxv
423 1.1 maxv *hva = mach->areas[i].hva + (gpa - mach->areas[i].gpa);
424 1.1 maxv return 0;
425 1.1 maxv }
426 1.1 maxv
427 1.1 maxv errno = ENOENT;
428 1.1 maxv return -1;
429 1.1 maxv }
430 1.1 maxv
431 1.1 maxv /*
432 1.1 maxv * nvmm_assist_io(): architecture-specific.
433 1.1 maxv */
434