libnvmm.c revision 1.9 1 1.9 maxv /* $NetBSD: libnvmm.c,v 1.9 2019/04/10 18:49:04 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.3 maxv #include <sys/queue.h>
43 1.1 maxv
44 1.1 maxv #include "nvmm.h"
45 1.1 maxv
46 1.6 maxv struct nvmm_callbacks __callbacks;
47 1.6 maxv
48 1.3 maxv typedef struct __area {
49 1.3 maxv LIST_ENTRY(__area) list;
50 1.3 maxv gpaddr_t gpa;
51 1.3 maxv uintptr_t hva;
52 1.3 maxv size_t size;
53 1.8 maxv nvmm_prot_t prot;
54 1.3 maxv } area_t;
55 1.3 maxv
56 1.3 maxv typedef LIST_HEAD(, __area) area_list_t;
57 1.3 maxv
58 1.1 maxv static int nvmm_fd = -1;
59 1.1 maxv
60 1.1 maxv /* -------------------------------------------------------------------------- */
61 1.1 maxv
62 1.4 maxv static bool
63 1.4 maxv __area_isvalid(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
64 1.1 maxv size_t size)
65 1.1 maxv {
66 1.3 maxv area_list_t *areas = mach->areas;
67 1.4 maxv area_t *ent;
68 1.3 maxv
69 1.4 maxv LIST_FOREACH(ent, areas, list) {
70 1.4 maxv /* Collision on GPA */
71 1.4 maxv if (gpa >= ent->gpa && gpa < ent->gpa + ent->size) {
72 1.4 maxv return false;
73 1.1 maxv }
74 1.5 maxv if (gpa + size > ent->gpa &&
75 1.5 maxv gpa + size <= ent->gpa + ent->size) {
76 1.4 maxv return false;
77 1.3 maxv }
78 1.4 maxv if (gpa <= ent->gpa && gpa + size >= ent->gpa + ent->size) {
79 1.4 maxv return false;
80 1.1 maxv }
81 1.1 maxv }
82 1.1 maxv
83 1.4 maxv return true;
84 1.3 maxv }
85 1.3 maxv
86 1.3 maxv static int
87 1.8 maxv __area_add(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size,
88 1.8 maxv int prot)
89 1.3 maxv {
90 1.3 maxv area_list_t *areas = mach->areas;
91 1.8 maxv nvmm_prot_t nprot;
92 1.3 maxv area_t *area;
93 1.4 maxv
94 1.8 maxv nprot = 0;
95 1.8 maxv if (prot & PROT_READ)
96 1.8 maxv nprot |= NVMM_PROT_READ;
97 1.8 maxv if (prot & PROT_WRITE)
98 1.8 maxv nprot |= NVMM_PROT_WRITE;
99 1.8 maxv if (prot & PROT_EXEC)
100 1.8 maxv nprot |= NVMM_PROT_EXEC;
101 1.8 maxv
102 1.4 maxv if (!__area_isvalid(mach, hva, gpa, size)) {
103 1.4 maxv errno = EINVAL;
104 1.4 maxv return -1;
105 1.4 maxv }
106 1.3 maxv
107 1.3 maxv area = malloc(sizeof(*area));
108 1.3 maxv if (area == NULL)
109 1.1 maxv return -1;
110 1.1 maxv area->gpa = gpa;
111 1.1 maxv area->hva = hva;
112 1.1 maxv area->size = size;
113 1.8 maxv area->prot = nprot;
114 1.1 maxv
115 1.4 maxv LIST_INSERT_HEAD(areas, area, list);
116 1.4 maxv
117 1.4 maxv return 0;
118 1.4 maxv }
119 1.4 maxv
120 1.4 maxv static int
121 1.4 maxv __area_delete(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
122 1.4 maxv size_t size)
123 1.4 maxv {
124 1.4 maxv area_list_t *areas = mach->areas;
125 1.4 maxv area_t *ent, *nxt;
126 1.4 maxv
127 1.4 maxv LIST_FOREACH_SAFE(ent, areas, list, nxt) {
128 1.4 maxv if (hva == ent->hva && gpa == ent->gpa && size == ent->size) {
129 1.4 maxv LIST_REMOVE(ent, list);
130 1.4 maxv free(ent);
131 1.4 maxv return 0;
132 1.4 maxv }
133 1.3 maxv }
134 1.3 maxv
135 1.4 maxv return -1;
136 1.1 maxv }
137 1.1 maxv
138 1.3 maxv static void
139 1.3 maxv __area_remove_all(struct nvmm_machine *mach)
140 1.1 maxv {
141 1.3 maxv area_list_t *areas = mach->areas;
142 1.3 maxv area_t *ent;
143 1.1 maxv
144 1.3 maxv while ((ent = LIST_FIRST(areas)) != NULL) {
145 1.3 maxv LIST_REMOVE(ent, list);
146 1.3 maxv free(ent);
147 1.1 maxv }
148 1.1 maxv
149 1.3 maxv free(areas);
150 1.1 maxv }
151 1.1 maxv
152 1.1 maxv /* -------------------------------------------------------------------------- */
153 1.1 maxv
154 1.1 maxv static int
155 1.1 maxv nvmm_init(void)
156 1.1 maxv {
157 1.1 maxv if (nvmm_fd != -1)
158 1.1 maxv return 0;
159 1.1 maxv nvmm_fd = open("/dev/nvmm", O_RDWR);
160 1.1 maxv if (nvmm_fd == -1)
161 1.1 maxv return -1;
162 1.1 maxv return 0;
163 1.1 maxv }
164 1.1 maxv
165 1.1 maxv int
166 1.1 maxv nvmm_capability(struct nvmm_capability *cap)
167 1.1 maxv {
168 1.1 maxv struct nvmm_ioc_capability args;
169 1.1 maxv int ret;
170 1.1 maxv
171 1.1 maxv if (nvmm_init() == -1) {
172 1.1 maxv return -1;
173 1.1 maxv }
174 1.1 maxv
175 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_CAPABILITY, &args);
176 1.1 maxv if (ret == -1)
177 1.1 maxv return -1;
178 1.1 maxv
179 1.1 maxv memcpy(cap, &args.cap, sizeof(args.cap));
180 1.1 maxv
181 1.1 maxv return 0;
182 1.1 maxv }
183 1.1 maxv
184 1.1 maxv int
185 1.1 maxv nvmm_machine_create(struct nvmm_machine *mach)
186 1.1 maxv {
187 1.1 maxv struct nvmm_ioc_machine_create args;
188 1.3 maxv area_list_t *areas;
189 1.1 maxv int ret;
190 1.1 maxv
191 1.1 maxv if (nvmm_init() == -1) {
192 1.1 maxv return -1;
193 1.1 maxv }
194 1.1 maxv
195 1.3 maxv areas = calloc(1, sizeof(*areas));
196 1.3 maxv if (areas == NULL)
197 1.3 maxv return -1;
198 1.3 maxv
199 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CREATE, &args);
200 1.3 maxv if (ret == -1) {
201 1.3 maxv free(areas);
202 1.1 maxv return -1;
203 1.3 maxv }
204 1.1 maxv
205 1.1 maxv memset(mach, 0, sizeof(*mach));
206 1.3 maxv LIST_INIT(areas);
207 1.3 maxv mach->areas = areas;
208 1.1 maxv mach->machid = args.machid;
209 1.1 maxv
210 1.1 maxv return 0;
211 1.1 maxv }
212 1.1 maxv
213 1.1 maxv int
214 1.1 maxv nvmm_machine_destroy(struct nvmm_machine *mach)
215 1.1 maxv {
216 1.1 maxv struct nvmm_ioc_machine_destroy args;
217 1.1 maxv int ret;
218 1.1 maxv
219 1.1 maxv if (nvmm_init() == -1) {
220 1.1 maxv return -1;
221 1.1 maxv }
222 1.1 maxv
223 1.1 maxv args.machid = mach->machid;
224 1.1 maxv
225 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_DESTROY, &args);
226 1.1 maxv if (ret == -1)
227 1.1 maxv return -1;
228 1.1 maxv
229 1.3 maxv __area_remove_all(mach);
230 1.1 maxv
231 1.1 maxv return 0;
232 1.1 maxv }
233 1.1 maxv
234 1.1 maxv int
235 1.1 maxv nvmm_machine_configure(struct nvmm_machine *mach, uint64_t op, void *conf)
236 1.1 maxv {
237 1.1 maxv struct nvmm_ioc_machine_configure args;
238 1.1 maxv int ret;
239 1.1 maxv
240 1.1 maxv if (nvmm_init() == -1) {
241 1.1 maxv return -1;
242 1.1 maxv }
243 1.1 maxv
244 1.1 maxv args.machid = mach->machid;
245 1.1 maxv args.op = op;
246 1.1 maxv args.conf = conf;
247 1.1 maxv
248 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CONFIGURE, &args);
249 1.1 maxv if (ret == -1)
250 1.1 maxv return -1;
251 1.1 maxv
252 1.1 maxv return 0;
253 1.1 maxv }
254 1.1 maxv
255 1.1 maxv int
256 1.1 maxv nvmm_vcpu_create(struct nvmm_machine *mach, nvmm_cpuid_t cpuid)
257 1.1 maxv {
258 1.1 maxv struct nvmm_ioc_vcpu_create args;
259 1.1 maxv int ret;
260 1.1 maxv
261 1.1 maxv if (nvmm_init() == -1) {
262 1.1 maxv return -1;
263 1.1 maxv }
264 1.1 maxv
265 1.1 maxv args.machid = mach->machid;
266 1.1 maxv args.cpuid = cpuid;
267 1.1 maxv
268 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_CREATE, &args);
269 1.1 maxv if (ret == -1)
270 1.1 maxv return -1;
271 1.1 maxv
272 1.1 maxv return 0;
273 1.1 maxv }
274 1.1 maxv
275 1.1 maxv int
276 1.1 maxv nvmm_vcpu_destroy(struct nvmm_machine *mach, nvmm_cpuid_t cpuid)
277 1.1 maxv {
278 1.1 maxv struct nvmm_ioc_vcpu_destroy 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
288 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_DESTROY, &args);
289 1.1 maxv if (ret == -1)
290 1.1 maxv return -1;
291 1.1 maxv
292 1.1 maxv return 0;
293 1.1 maxv }
294 1.1 maxv
295 1.1 maxv int
296 1.1 maxv nvmm_vcpu_setstate(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
297 1.1 maxv void *state, uint64_t flags)
298 1.1 maxv {
299 1.1 maxv struct nvmm_ioc_vcpu_setstate args;
300 1.1 maxv int ret;
301 1.1 maxv
302 1.1 maxv if (nvmm_init() == -1) {
303 1.1 maxv return -1;
304 1.1 maxv }
305 1.1 maxv
306 1.1 maxv args.machid = mach->machid;
307 1.1 maxv args.cpuid = cpuid;
308 1.1 maxv args.state = state;
309 1.1 maxv args.flags = flags;
310 1.1 maxv
311 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_SETSTATE, &args);
312 1.1 maxv if (ret == -1)
313 1.1 maxv return -1;
314 1.1 maxv
315 1.1 maxv return 0;
316 1.1 maxv }
317 1.1 maxv
318 1.1 maxv int
319 1.1 maxv nvmm_vcpu_getstate(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
320 1.1 maxv void *state, uint64_t flags)
321 1.1 maxv {
322 1.1 maxv struct nvmm_ioc_vcpu_getstate args;
323 1.1 maxv int ret;
324 1.1 maxv
325 1.1 maxv if (nvmm_init() == -1) {
326 1.1 maxv return -1;
327 1.1 maxv }
328 1.1 maxv
329 1.1 maxv args.machid = mach->machid;
330 1.1 maxv args.cpuid = cpuid;
331 1.1 maxv args.state = state;
332 1.1 maxv args.flags = flags;
333 1.1 maxv
334 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_GETSTATE, &args);
335 1.1 maxv if (ret == -1)
336 1.1 maxv return -1;
337 1.1 maxv
338 1.1 maxv return 0;
339 1.1 maxv }
340 1.1 maxv
341 1.1 maxv int
342 1.1 maxv nvmm_vcpu_inject(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
343 1.1 maxv struct nvmm_event *event)
344 1.1 maxv {
345 1.1 maxv struct nvmm_ioc_vcpu_inject args;
346 1.1 maxv int ret;
347 1.1 maxv
348 1.1 maxv if (nvmm_init() == -1) {
349 1.1 maxv return -1;
350 1.1 maxv }
351 1.1 maxv
352 1.1 maxv args.machid = mach->machid;
353 1.1 maxv args.cpuid = cpuid;
354 1.1 maxv memcpy(&args.event, event, sizeof(args.event));
355 1.1 maxv
356 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_INJECT, &args);
357 1.1 maxv if (ret == -1)
358 1.1 maxv return -1;
359 1.1 maxv
360 1.1 maxv return 0;
361 1.1 maxv }
362 1.1 maxv
363 1.1 maxv int
364 1.1 maxv nvmm_vcpu_run(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
365 1.1 maxv struct nvmm_exit *exit)
366 1.1 maxv {
367 1.1 maxv struct nvmm_ioc_vcpu_run args;
368 1.1 maxv int ret;
369 1.1 maxv
370 1.1 maxv if (nvmm_init() == -1) {
371 1.1 maxv return -1;
372 1.1 maxv }
373 1.1 maxv
374 1.1 maxv args.machid = mach->machid;
375 1.1 maxv args.cpuid = cpuid;
376 1.1 maxv memset(&args.exit, 0, sizeof(args.exit));
377 1.1 maxv
378 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_VCPU_RUN, &args);
379 1.1 maxv if (ret == -1)
380 1.1 maxv return -1;
381 1.1 maxv
382 1.1 maxv memcpy(exit, &args.exit, sizeof(args.exit));
383 1.1 maxv
384 1.1 maxv return 0;
385 1.1 maxv }
386 1.1 maxv
387 1.1 maxv int
388 1.1 maxv nvmm_gpa_map(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
389 1.7 maxv size_t size, int prot)
390 1.1 maxv {
391 1.1 maxv struct nvmm_ioc_gpa_map args;
392 1.1 maxv int ret;
393 1.1 maxv
394 1.1 maxv if (nvmm_init() == -1) {
395 1.1 maxv return -1;
396 1.1 maxv }
397 1.1 maxv
398 1.8 maxv ret = __area_add(mach, hva, gpa, size, prot);
399 1.3 maxv if (ret == -1)
400 1.3 maxv return -1;
401 1.3 maxv
402 1.1 maxv args.machid = mach->machid;
403 1.1 maxv args.hva = hva;
404 1.1 maxv args.gpa = gpa;
405 1.1 maxv args.size = size;
406 1.7 maxv args.prot = prot;
407 1.1 maxv
408 1.1 maxv ret = ioctl(nvmm_fd, NVMM_IOC_GPA_MAP, &args);
409 1.1 maxv if (ret == -1) {
410 1.3 maxv /* Can't recover. */
411 1.3 maxv abort();
412 1.1 maxv }
413 1.1 maxv
414 1.1 maxv return 0;
415 1.1 maxv }
416 1.1 maxv
417 1.1 maxv int
418 1.1 maxv nvmm_gpa_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
419 1.1 maxv size_t size)
420 1.1 maxv {
421 1.4 maxv struct nvmm_ioc_gpa_unmap args;
422 1.4 maxv int ret;
423 1.4 maxv
424 1.1 maxv if (nvmm_init() == -1) {
425 1.1 maxv return -1;
426 1.1 maxv }
427 1.1 maxv
428 1.4 maxv ret = __area_delete(mach, hva, gpa, size);
429 1.4 maxv if (ret == -1)
430 1.4 maxv return -1;
431 1.4 maxv
432 1.4 maxv args.machid = mach->machid;
433 1.4 maxv args.gpa = gpa;
434 1.4 maxv args.size = size;
435 1.4 maxv
436 1.4 maxv ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, &args);
437 1.5 maxv if (ret == -1) {
438 1.5 maxv /* Can't recover. */
439 1.5 maxv abort();
440 1.5 maxv }
441 1.5 maxv
442 1.5 maxv return 0;
443 1.5 maxv }
444 1.5 maxv
445 1.5 maxv int
446 1.5 maxv nvmm_hva_map(struct nvmm_machine *mach, uintptr_t hva, size_t size)
447 1.5 maxv {
448 1.5 maxv struct nvmm_ioc_hva_map args;
449 1.5 maxv int ret;
450 1.5 maxv
451 1.5 maxv if (nvmm_init() == -1) {
452 1.5 maxv return -1;
453 1.5 maxv }
454 1.5 maxv
455 1.5 maxv args.machid = mach->machid;
456 1.5 maxv args.hva = hva;
457 1.5 maxv args.size = size;
458 1.5 maxv
459 1.5 maxv ret = ioctl(nvmm_fd, NVMM_IOC_HVA_MAP, &args);
460 1.4 maxv if (ret == -1)
461 1.4 maxv return -1;
462 1.4 maxv
463 1.5 maxv return 0;
464 1.5 maxv }
465 1.4 maxv
466 1.5 maxv int
467 1.5 maxv nvmm_hva_unmap(struct nvmm_machine *mach, uintptr_t hva, size_t size)
468 1.5 maxv {
469 1.6 maxv struct nvmm_ioc_hva_unmap args;
470 1.5 maxv int ret;
471 1.5 maxv
472 1.5 maxv if (nvmm_init() == -1) {
473 1.5 maxv return -1;
474 1.5 maxv }
475 1.5 maxv
476 1.5 maxv args.machid = mach->machid;
477 1.5 maxv args.hva = hva;
478 1.5 maxv args.size = size;
479 1.5 maxv
480 1.6 maxv ret = ioctl(nvmm_fd, NVMM_IOC_HVA_UNMAP, &args);
481 1.5 maxv if (ret == -1)
482 1.5 maxv return -1;
483 1.5 maxv
484 1.5 maxv return 0;
485 1.1 maxv }
486 1.1 maxv
487 1.1 maxv /*
488 1.1 maxv * nvmm_gva_to_gpa(): architecture-specific.
489 1.1 maxv */
490 1.1 maxv
491 1.1 maxv int
492 1.8 maxv nvmm_gpa_to_hva(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t *hva,
493 1.8 maxv nvmm_prot_t *prot)
494 1.1 maxv {
495 1.3 maxv area_list_t *areas = mach->areas;
496 1.3 maxv area_t *ent;
497 1.1 maxv
498 1.3 maxv LIST_FOREACH(ent, areas, list) {
499 1.5 maxv if (gpa >= ent->gpa && gpa < ent->gpa + ent->size) {
500 1.5 maxv *hva = ent->hva + (gpa - ent->gpa);
501 1.8 maxv *prot = ent->prot;
502 1.5 maxv return 0;
503 1.1 maxv }
504 1.1 maxv }
505 1.1 maxv
506 1.1 maxv errno = ENOENT;
507 1.1 maxv return -1;
508 1.1 maxv }
509 1.1 maxv
510 1.1 maxv /*
511 1.1 maxv * nvmm_assist_io(): architecture-specific.
512 1.1 maxv */
513 1.6 maxv
514 1.6 maxv /*
515 1.6 maxv * nvmm_assist_mem(): architecture-specific.
516 1.6 maxv */
517 1.6 maxv
518 1.6 maxv void
519 1.6 maxv nvmm_callbacks_register(const struct nvmm_callbacks *cbs)
520 1.6 maxv {
521 1.6 maxv memcpy(&__callbacks, cbs, sizeof(__callbacks));
522 1.6 maxv }
523 1.9 maxv
524 1.9 maxv int
525 1.9 maxv nvmm_ctl(int op, void *data, size_t size)
526 1.9 maxv {
527 1.9 maxv struct nvmm_ioc_ctl args;
528 1.9 maxv int ret;
529 1.9 maxv
530 1.9 maxv if (nvmm_init() == -1) {
531 1.9 maxv return -1;
532 1.9 maxv }
533 1.9 maxv
534 1.9 maxv args.op = op;
535 1.9 maxv args.data = data;
536 1.9 maxv args.size = size;
537 1.9 maxv
538 1.9 maxv ret = ioctl(nvmm_fd, NVMM_IOC_CTL, &args);
539 1.9 maxv if (ret == -1)
540 1.9 maxv return -1;
541 1.9 maxv
542 1.9 maxv return 0;
543 1.9 maxv }
544