nvmm.c revision 1.6 1 /* $NetBSD: nvmm.c,v 1.6 2019/01/26 15:25:51 maxv Exp $ */
2
3 /*
4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Maxime Villard.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.6 2019/01/26 15:25:51 maxv Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38
39 #include <sys/cpu.h>
40 #include <sys/conf.h>
41 #include <sys/kmem.h>
42 #include <sys/module.h>
43 #include <sys/proc.h>
44
45 #include <uvm/uvm.h>
46 #include <uvm/uvm_page.h>
47
48 #include "ioconf.h"
49
50 #include <dev/nvmm/nvmm.h>
51 #include <dev/nvmm/nvmm_internal.h>
52 #include <dev/nvmm/nvmm_ioctl.h>
53
54 static struct nvmm_machine machines[NVMM_MAX_MACHINES];
55
56 static const struct nvmm_impl *nvmm_impl_list[] = {
57 &nvmm_x86_svm /* x86 AMD SVM */
58 };
59
60 static const struct nvmm_impl *nvmm_impl = NULL;
61
62 /* -------------------------------------------------------------------------- */
63
64 static int
65 nvmm_machine_alloc(struct nvmm_machine **ret)
66 {
67 struct nvmm_machine *mach;
68 size_t i;
69
70 for (i = 0; i < NVMM_MAX_MACHINES; i++) {
71 mach = &machines[i];
72
73 rw_enter(&mach->lock, RW_WRITER);
74 if (mach->present) {
75 rw_exit(&mach->lock);
76 continue;
77 }
78
79 mach->present = true;
80 *ret = mach;
81 return 0;
82 }
83
84 return ENOBUFS;
85 }
86
87 static void
88 nvmm_machine_free(struct nvmm_machine *mach)
89 {
90 KASSERT(rw_write_held(&mach->lock));
91 KASSERT(mach->present);
92 mach->present = false;
93 }
94
95 static int
96 nvmm_machine_get(nvmm_machid_t machid, struct nvmm_machine **ret, bool writer)
97 {
98 struct nvmm_machine *mach;
99 krw_t op = writer ? RW_WRITER : RW_READER;
100
101 if (machid >= NVMM_MAX_MACHINES) {
102 return EINVAL;
103 }
104 mach = &machines[machid];
105
106 rw_enter(&mach->lock, op);
107 if (!mach->present) {
108 rw_exit(&mach->lock);
109 return ENOENT;
110 }
111 if (mach->procid != curproc->p_pid) {
112 rw_exit(&mach->lock);
113 return EPERM;
114 }
115 *ret = mach;
116
117 return 0;
118 }
119
120 static void
121 nvmm_machine_put(struct nvmm_machine *mach)
122 {
123 rw_exit(&mach->lock);
124 }
125
126 /* -------------------------------------------------------------------------- */
127
128 static int
129 nvmm_vcpu_alloc(struct nvmm_machine *mach, struct nvmm_cpu **ret)
130 {
131 struct nvmm_cpu *vcpu;
132 size_t i;
133
134 for (i = 0; i < NVMM_MAX_VCPUS; i++) {
135 vcpu = &mach->cpus[i];
136
137 mutex_enter(&vcpu->lock);
138 if (vcpu->present) {
139 mutex_exit(&vcpu->lock);
140 continue;
141 }
142
143 vcpu->present = true;
144 vcpu->cpuid = i;
145 vcpu->state = kmem_zalloc(nvmm_impl->state_size, KM_SLEEP);
146 *ret = vcpu;
147 return 0;
148 }
149
150 return ENOBUFS;
151 }
152
153 static void
154 nvmm_vcpu_free(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
155 {
156 KASSERT(mutex_owned(&vcpu->lock));
157 vcpu->present = false;
158 kmem_free(vcpu->state, nvmm_impl->state_size);
159 vcpu->hcpu_last = -1;
160 }
161
162 int
163 nvmm_vcpu_get(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
164 struct nvmm_cpu **ret)
165 {
166 struct nvmm_cpu *vcpu;
167
168 if (cpuid >= NVMM_MAX_VCPUS) {
169 return EINVAL;
170 }
171 vcpu = &mach->cpus[cpuid];
172
173 mutex_enter(&vcpu->lock);
174 if (!vcpu->present) {
175 mutex_exit(&vcpu->lock);
176 return ENOENT;
177 }
178 *ret = vcpu;
179
180 return 0;
181 }
182
183 void
184 nvmm_vcpu_put(struct nvmm_cpu *vcpu)
185 {
186 mutex_exit(&vcpu->lock);
187 }
188
189 /* -------------------------------------------------------------------------- */
190
191 static void
192 nvmm_kill_machines(pid_t pid)
193 {
194 struct nvmm_machine *mach;
195 struct nvmm_cpu *vcpu;
196 size_t i, j;
197 int error;
198
199 for (i = 0; i < NVMM_MAX_MACHINES; i++) {
200 mach = &machines[i];
201
202 rw_enter(&mach->lock, RW_WRITER);
203 if (!mach->present || mach->procid != pid) {
204 rw_exit(&mach->lock);
205 continue;
206 }
207
208 /* Kill it. */
209 for (j = 0; j < NVMM_MAX_VCPUS; j++) {
210 error = nvmm_vcpu_get(mach, j, &vcpu);
211 if (error)
212 continue;
213 (*nvmm_impl->vcpu_destroy)(mach, vcpu);
214 nvmm_vcpu_free(mach, vcpu);
215 nvmm_vcpu_put(vcpu);
216 }
217 uvmspace_free(mach->vm);
218
219 /* Drop the kernel UOBJ refs. */
220 for (j = 0; j < NVMM_MAX_SEGS; j++) {
221 if (!mach->segs[j].present)
222 continue;
223 uao_detach(mach->segs[j].uobj);
224 }
225
226 nvmm_machine_free(mach);
227
228 rw_exit(&mach->lock);
229 }
230 }
231
232 /* -------------------------------------------------------------------------- */
233
234 static int
235 nvmm_capability(struct nvmm_ioc_capability *args)
236 {
237 args->cap.version = NVMM_CAPABILITY_VERSION;
238 args->cap.state_size = nvmm_impl->state_size;
239 args->cap.max_machines = NVMM_MAX_MACHINES;
240 args->cap.max_vcpus = NVMM_MAX_VCPUS;
241 args->cap.max_ram = NVMM_MAX_RAM;
242
243 (*nvmm_impl->capability)(&args->cap);
244
245 return 0;
246 }
247
248 static int
249 nvmm_machine_create(struct nvmm_ioc_machine_create *args)
250 {
251 struct nvmm_machine *mach;
252 int error;
253
254 error = nvmm_machine_alloc(&mach);
255 if (error)
256 return error;
257
258 /* Curproc owns the machine. */
259 mach->procid = curproc->p_pid;
260
261 /* Zero out the segments. */
262 memset(&mach->segs, 0, sizeof(mach->segs));
263
264 /* Create the machine vmspace. */
265 mach->gpa_begin = 0;
266 mach->gpa_end = NVMM_MAX_RAM;
267 mach->vm = uvmspace_alloc(0, mach->gpa_end - mach->gpa_begin, false);
268
269 (*nvmm_impl->machine_create)(mach);
270
271 args->machid = mach->machid;
272 nvmm_machine_put(mach);
273
274 return 0;
275 }
276
277 static int
278 nvmm_machine_destroy(struct nvmm_ioc_machine_destroy *args)
279 {
280 struct nvmm_machine *mach;
281 struct nvmm_cpu *vcpu;
282 int error;
283 size_t i;
284
285 error = nvmm_machine_get(args->machid, &mach, true);
286 if (error)
287 return error;
288
289 for (i = 0; i < NVMM_MAX_VCPUS; i++) {
290 error = nvmm_vcpu_get(mach, i, &vcpu);
291 if (error)
292 continue;
293
294 (*nvmm_impl->vcpu_destroy)(mach, vcpu);
295 nvmm_vcpu_free(mach, vcpu);
296 nvmm_vcpu_put(vcpu);
297 }
298
299 (*nvmm_impl->machine_destroy)(mach);
300
301 /* Free the machine vmspace. */
302 uvmspace_free(mach->vm);
303
304 /* Drop the kernel UOBJ refs. */
305 for (i = 0; i < NVMM_MAX_SEGS; i++) {
306 if (!mach->segs[i].present)
307 continue;
308 uao_detach(mach->segs[i].uobj);
309 }
310
311 nvmm_machine_free(mach);
312 nvmm_machine_put(mach);
313
314 return 0;
315 }
316
317 static int
318 nvmm_machine_configure(struct nvmm_ioc_machine_configure *args)
319 {
320 struct nvmm_machine *mach;
321 size_t allocsz;
322 void *data;
323 int error;
324
325 if (__predict_false(args->op >= nvmm_impl->conf_max)) {
326 return EINVAL;
327 }
328
329 allocsz = nvmm_impl->conf_sizes[args->op];
330 data = kmem_alloc(allocsz, KM_SLEEP);
331
332 error = nvmm_machine_get(args->machid, &mach, true);
333 if (error) {
334 kmem_free(data, allocsz);
335 return error;
336 }
337
338 error = copyin(args->conf, data, allocsz);
339 if (error) {
340 goto out;
341 }
342
343 error = (*nvmm_impl->machine_configure)(mach, args->op, data);
344
345 out:
346 nvmm_machine_put(mach);
347 kmem_free(data, allocsz);
348 return error;
349 }
350
351 static int
352 nvmm_vcpu_create(struct nvmm_ioc_vcpu_create *args)
353 {
354 struct nvmm_machine *mach;
355 struct nvmm_cpu *vcpu;
356 int error;
357
358 error = nvmm_machine_get(args->machid, &mach, false);
359 if (error)
360 return error;
361
362 error = nvmm_vcpu_alloc(mach, &vcpu);
363 if (error)
364 goto out;
365
366 error = (*nvmm_impl->vcpu_create)(mach, vcpu);
367 if (error) {
368 nvmm_vcpu_free(mach, vcpu);
369 nvmm_vcpu_put(vcpu);
370 goto out;
371 }
372
373 nvmm_vcpu_put(vcpu);
374
375 out:
376 nvmm_machine_put(mach);
377 return error;
378 }
379
380 static int
381 nvmm_vcpu_destroy(struct nvmm_ioc_vcpu_destroy *args)
382 {
383 struct nvmm_machine *mach;
384 struct nvmm_cpu *vcpu;
385 int error;
386
387 error = nvmm_machine_get(args->machid, &mach, false);
388 if (error)
389 return error;
390
391 error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
392 if (error)
393 goto out;
394
395 (*nvmm_impl->vcpu_destroy)(mach, vcpu);
396 nvmm_vcpu_free(mach, vcpu);
397 nvmm_vcpu_put(vcpu);
398
399 out:
400 nvmm_machine_put(mach);
401 return error;
402 }
403
404 static int
405 nvmm_vcpu_setstate(struct nvmm_ioc_vcpu_setstate *args)
406 {
407 struct nvmm_machine *mach;
408 struct nvmm_cpu *vcpu;
409 int error;
410
411 error = nvmm_machine_get(args->machid, &mach, false);
412 if (error)
413 return error;
414
415 error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
416 if (error)
417 goto out;
418
419 error = copyin(args->state, vcpu->state, nvmm_impl->state_size);
420 if (error) {
421 nvmm_vcpu_put(vcpu);
422 goto out;
423 }
424
425 (*nvmm_impl->vcpu_setstate)(vcpu, vcpu->state, args->flags);
426 nvmm_vcpu_put(vcpu);
427
428 out:
429 nvmm_machine_put(mach);
430 return error;
431 }
432
433 static int
434 nvmm_vcpu_getstate(struct nvmm_ioc_vcpu_getstate *args)
435 {
436 struct nvmm_machine *mach;
437 struct nvmm_cpu *vcpu;
438 int error;
439
440 error = nvmm_machine_get(args->machid, &mach, false);
441 if (error)
442 return error;
443
444 error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
445 if (error)
446 goto out;
447
448 (*nvmm_impl->vcpu_getstate)(vcpu, vcpu->state, args->flags);
449 nvmm_vcpu_put(vcpu);
450 error = copyout(vcpu->state, args->state, nvmm_impl->state_size);
451
452 out:
453 nvmm_machine_put(mach);
454 return error;
455 }
456
457 static int
458 nvmm_vcpu_inject(struct nvmm_ioc_vcpu_inject *args)
459 {
460 struct nvmm_machine *mach;
461 struct nvmm_cpu *vcpu;
462 int error;
463
464 error = nvmm_machine_get(args->machid, &mach, false);
465 if (error)
466 return error;
467
468 error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
469 if (error)
470 goto out;
471
472 error = (*nvmm_impl->vcpu_inject)(mach, vcpu, &args->event);
473 nvmm_vcpu_put(vcpu);
474
475 out:
476 nvmm_machine_put(mach);
477 return error;
478 }
479
480 static int
481 nvmm_vcpu_run(struct nvmm_ioc_vcpu_run *args)
482 {
483 struct nvmm_machine *mach;
484 struct nvmm_cpu *vcpu;
485 int error;
486
487 error = nvmm_machine_get(args->machid, &mach, false);
488 if (error)
489 return error;
490
491 error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
492 if (error)
493 goto out;
494
495 (*nvmm_impl->vcpu_run)(mach, vcpu, &args->exit);
496 nvmm_vcpu_put(vcpu);
497
498 out:
499 nvmm_machine_put(mach);
500 return error;
501 }
502
503 /* -------------------------------------------------------------------------- */
504
505 static struct uvm_object *
506 nvmm_seg_getuobj(struct nvmm_machine *mach, uintptr_t hva, size_t size,
507 size_t *off)
508 {
509 struct nvmm_seg *seg;
510 size_t i;
511
512 for (i = 0; i < NVMM_MAX_SEGS; i++) {
513 seg = &mach->segs[i];
514 if (!seg->present) {
515 continue;
516 }
517 if (hva >= seg->hva && hva + size <= seg->hva + seg->size) {
518 *off = hva - seg->hva;
519 return seg->uobj;
520 }
521 }
522
523 return NULL;
524 }
525
526 static struct nvmm_seg *
527 nvmm_seg_find(struct nvmm_machine *mach, uintptr_t hva, size_t size)
528 {
529 struct nvmm_seg *seg;
530 size_t i;
531
532 for (i = 0; i < NVMM_MAX_SEGS; i++) {
533 seg = &mach->segs[i];
534 if (seg->present && seg->hva == hva && seg->size == size) {
535 return seg;
536 }
537 }
538
539 return NULL;
540 }
541
542 static int
543 nvmm_seg_validate(struct nvmm_machine *mach, uintptr_t hva, size_t size)
544 {
545 struct nvmm_seg *seg;
546 size_t i;
547
548 if ((hva % PAGE_SIZE) != 0 || (size % PAGE_SIZE) != 0) {
549 return EINVAL;
550 }
551 if (hva == 0) {
552 return EINVAL;
553 }
554
555 for (i = 0; i < NVMM_MAX_SEGS; i++) {
556 seg = &mach->segs[i];
557 if (!seg->present) {
558 continue;
559 }
560
561 if (hva >= seg->hva && hva + size <= seg->hva + seg->size) {
562 break;
563 }
564
565 if (hva >= seg->hva && hva < seg->hva + seg->size) {
566 return EEXIST;
567 }
568 if (hva + size > seg->hva &&
569 hva + size <= seg->hva + seg->size) {
570 return EEXIST;
571 }
572 if (hva <= seg->hva && hva + size >= seg->hva + seg->size) {
573 return EEXIST;
574 }
575 }
576
577 return 0;
578 }
579
580 static struct nvmm_seg *
581 nvmm_seg_alloc(struct nvmm_machine *mach)
582 {
583 struct nvmm_seg *seg;
584 size_t i;
585
586 for (i = 0; i < NVMM_MAX_SEGS; i++) {
587 seg = &mach->segs[i];
588 if (!seg->present) {
589 seg->present = true;
590 return seg;
591 }
592 }
593
594 return NULL;
595 }
596
597 static void
598 nvmm_seg_free(struct nvmm_seg *seg)
599 {
600 struct vmspace *vmspace = curproc->p_vmspace;
601
602 uvm_unmap(&vmspace->vm_map, seg->hva, seg->hva + seg->size);
603 uao_detach(seg->uobj);
604
605 seg->uobj = NULL;
606 seg->present = false;
607 }
608
609 static int
610 nvmm_hva_map(struct nvmm_ioc_hva_map *args)
611 {
612 struct vmspace *vmspace = curproc->p_vmspace;
613 struct nvmm_machine *mach;
614 struct nvmm_seg *seg;
615 vaddr_t uva;
616 int error;
617
618 error = nvmm_machine_get(args->machid, &mach, true);
619 if (error)
620 return error;
621
622 error = nvmm_seg_validate(mach, args->hva, args->size);
623 if (error)
624 goto out;
625
626 seg = nvmm_seg_alloc(mach);
627 if (seg == NULL) {
628 error = ENOBUFS;
629 goto out;
630 }
631
632 seg->hva = args->hva;
633 seg->size = args->size;
634 seg->uobj = uao_create(seg->size, 0);
635 uva = seg->hva;
636
637 /* Take a reference for the user. */
638 uao_reference(seg->uobj);
639
640 /* Map the uobj into the user address space, as pageable. */
641 error = uvm_map(&vmspace->vm_map, &uva, seg->size, seg->uobj, 0, 0,
642 UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_SHARE,
643 UVM_ADV_RANDOM, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
644 if (error) {
645 uao_detach(seg->uobj);
646 }
647
648 out:
649 nvmm_machine_put(mach);
650 return error;
651 }
652
653 static int
654 nvmm_hva_unmap(struct nvmm_ioc_hva_unmap *args)
655 {
656 struct nvmm_machine *mach;
657 struct nvmm_seg *seg;
658 int error;
659
660 error = nvmm_machine_get(args->machid, &mach, true);
661 if (error)
662 return error;
663
664 seg = nvmm_seg_find(mach, args->hva, args->size);
665 if (seg == NULL)
666 return ENOENT;
667
668 nvmm_seg_free(seg);
669
670 nvmm_machine_put(mach);
671 return 0;
672 }
673
674 /* -------------------------------------------------------------------------- */
675
676 static int
677 nvmm_gpa_map(struct nvmm_ioc_gpa_map *args)
678 {
679 struct nvmm_machine *mach;
680 struct uvm_object *uobj;
681 gpaddr_t gpa;
682 size_t off;
683 int error;
684
685 error = nvmm_machine_get(args->machid, &mach, false);
686 if (error)
687 return error;
688
689 if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0 ||
690 (args->hva % PAGE_SIZE) != 0) {
691 error = EINVAL;
692 goto out;
693 }
694 if (args->hva == 0) {
695 error = EINVAL;
696 goto out;
697 }
698 if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
699 error = EINVAL;
700 goto out;
701 }
702 if (args->gpa + args->size <= args->gpa) {
703 error = EINVAL;
704 goto out;
705 }
706 if (args->gpa + args->size > mach->gpa_end) {
707 error = EINVAL;
708 goto out;
709 }
710 gpa = args->gpa;
711
712 uobj = nvmm_seg_getuobj(mach, args->hva, args->size, &off);
713 if (uobj == NULL) {
714 error = EINVAL;
715 goto out;
716 }
717
718 /* Take a reference for the machine. */
719 uao_reference(uobj);
720
721 /* Map the uobj into the machine address space, as pageable. */
722 error = uvm_map(&mach->vm->vm_map, &gpa, args->size, uobj, off, 0,
723 UVM_MAPFLAG(UVM_PROT_RWX, UVM_PROT_RWX, UVM_INH_NONE,
724 UVM_ADV_RANDOM, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
725 if (error) {
726 uao_detach(uobj);
727 goto out;
728 }
729 if (gpa != args->gpa) {
730 uao_detach(uobj);
731 printf("[!] uvm_map problem\n");
732 error = EINVAL;
733 goto out;
734 }
735
736 out:
737 nvmm_machine_put(mach);
738 return error;
739 }
740
741 static int
742 nvmm_gpa_unmap(struct nvmm_ioc_gpa_unmap *args)
743 {
744 struct nvmm_machine *mach;
745 gpaddr_t gpa;
746 int error;
747
748 error = nvmm_machine_get(args->machid, &mach, false);
749 if (error)
750 return error;
751
752 if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0) {
753 error = EINVAL;
754 goto out;
755 }
756 if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
757 error = EINVAL;
758 goto out;
759 }
760 if (args->gpa + args->size <= args->gpa) {
761 error = EINVAL;
762 goto out;
763 }
764 if (args->gpa + args->size >= mach->gpa_end) {
765 error = EINVAL;
766 goto out;
767 }
768 gpa = args->gpa;
769
770 /* Unmap the memory from the machine. */
771 uvm_unmap(&mach->vm->vm_map, gpa, gpa + args->size);
772
773 out:
774 nvmm_machine_put(mach);
775 return error;
776 }
777
778 /* -------------------------------------------------------------------------- */
779
780 static int
781 nvmm_init(void)
782 {
783 size_t i, n;
784
785 for (i = 0; i < __arraycount(nvmm_impl_list); i++) {
786 if (!(*nvmm_impl_list[i]->ident)()) {
787 continue;
788 }
789 nvmm_impl = nvmm_impl_list[i];
790 break;
791 }
792 if (nvmm_impl == NULL) {
793 printf("[!] No implementation found\n");
794 return ENOTSUP;
795 }
796
797 for (i = 0; i < NVMM_MAX_MACHINES; i++) {
798 machines[i].machid = i;
799 rw_init(&machines[i].lock);
800 for (n = 0; n < NVMM_MAX_VCPUS; n++) {
801 mutex_init(&machines[i].cpus[n].lock, MUTEX_DEFAULT,
802 IPL_NONE);
803 machines[i].cpus[n].hcpu_last = -1;
804 }
805 }
806
807 (*nvmm_impl->init)();
808
809 return 0;
810 }
811
812 static void
813 nvmm_fini(void)
814 {
815 size_t i, n;
816
817 for (i = 0; i < NVMM_MAX_MACHINES; i++) {
818 rw_destroy(&machines[i].lock);
819 for (n = 0; n < NVMM_MAX_VCPUS; n++) {
820 mutex_destroy(&machines[i].cpus[n].lock);
821 }
822 /* TODO need to free stuff, etc */
823 }
824
825 (*nvmm_impl->fini)();
826 }
827
828 /* -------------------------------------------------------------------------- */
829
830 static int
831 nvmm_open(dev_t dev, int flags, int type, struct lwp *l)
832 {
833 if (minor(dev) != 0) {
834 return EXDEV;
835 }
836
837 return 0;
838 }
839
840 static int
841 nvmm_close(dev_t dev, int flags, int type, struct lwp *l)
842 {
843 KASSERT(minor(dev) == 0);
844
845 nvmm_kill_machines(l->l_proc->p_pid);
846
847 return 0;
848 }
849
850 static int
851 nvmm_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
852 {
853 KASSERT(minor(dev) == 0);
854
855 switch (cmd) {
856 case NVMM_IOC_CAPABILITY:
857 return nvmm_capability(data);
858 case NVMM_IOC_MACHINE_CREATE:
859 return nvmm_machine_create(data);
860 case NVMM_IOC_MACHINE_DESTROY:
861 return nvmm_machine_destroy(data);
862 case NVMM_IOC_MACHINE_CONFIGURE:
863 return nvmm_machine_configure(data);
864 case NVMM_IOC_VCPU_CREATE:
865 return nvmm_vcpu_create(data);
866 case NVMM_IOC_VCPU_DESTROY:
867 return nvmm_vcpu_destroy(data);
868 case NVMM_IOC_VCPU_SETSTATE:
869 return nvmm_vcpu_setstate(data);
870 case NVMM_IOC_VCPU_GETSTATE:
871 return nvmm_vcpu_getstate(data);
872 case NVMM_IOC_VCPU_INJECT:
873 return nvmm_vcpu_inject(data);
874 case NVMM_IOC_VCPU_RUN:
875 return nvmm_vcpu_run(data);
876 case NVMM_IOC_GPA_MAP:
877 return nvmm_gpa_map(data);
878 case NVMM_IOC_GPA_UNMAP:
879 return nvmm_gpa_unmap(data);
880 case NVMM_IOC_HVA_MAP:
881 return nvmm_hva_map(data);
882 case NVMM_IOC_HVA_UNMAP:
883 return nvmm_hva_unmap(data);
884 default:
885 return EINVAL;
886 }
887 }
888
889 const struct cdevsw nvmm_cdevsw = {
890 .d_open = nvmm_open,
891 .d_close = nvmm_close,
892 .d_read = noread,
893 .d_write = nowrite,
894 .d_ioctl = nvmm_ioctl,
895 .d_stop = nostop,
896 .d_tty = notty,
897 .d_poll = nopoll,
898 .d_mmap = nommap,
899 .d_kqfilter = nokqfilter,
900 .d_discard = nodiscard,
901 .d_flag = D_OTHER | D_MPSAFE
902 };
903
904 void
905 nvmmattach(int nunits)
906 {
907 /* nothing */
908 }
909
910 MODULE(MODULE_CLASS_DRIVER, nvmm, NULL);
911
912 static int
913 nvmm_modcmd(modcmd_t cmd, void *arg)
914 {
915 int error;
916
917 switch (cmd) {
918 case MODULE_CMD_INIT:
919 error = nvmm_init();
920 if (error)
921 return error;
922
923 #if defined(_MODULE)
924 {
925 devmajor_t bmajor = NODEVMAJOR;
926 devmajor_t cmajor = 345;
927
928 /* mknod /dev/nvmm c 345 0 */
929 error = devsw_attach("nvmm", NULL, &bmajor,
930 &nvmm_cdevsw, &cmajor);
931 if (error) {
932 nvmm_fini();
933 return error;
934 }
935 }
936 #endif
937 return 0;
938
939 case MODULE_CMD_FINI:
940 #if defined(_MODULE)
941 {
942 error = devsw_detach(NULL, &nvmm_cdevsw);
943 if (error) {
944 return error;
945 }
946 }
947 #endif
948 nvmm_fini();
949 return 0;
950
951 default:
952 return ENOTTY;
953 }
954 }
955