Home | History | Annotate | Line # | Download | only in nvmm
nvmm.c revision 1.21.2.3
      1  1.21.2.3    martin /*	$NetBSD: nvmm.c,v 1.21.2.3 2020/04/13 08:04:25 martin Exp $	*/
      2  1.21.2.2  christos 
      3  1.21.2.2  christos /*
      4  1.21.2.2  christos  * Copyright (c) 2018-2019 The NetBSD Foundation, Inc.
      5  1.21.2.2  christos  * All rights reserved.
      6  1.21.2.2  christos  *
      7  1.21.2.2  christos  * This code is derived from software contributed to The NetBSD Foundation
      8  1.21.2.2  christos  * by Maxime Villard.
      9  1.21.2.2  christos  *
     10  1.21.2.2  christos  * Redistribution and use in source and binary forms, with or without
     11  1.21.2.2  christos  * modification, are permitted provided that the following conditions
     12  1.21.2.2  christos  * are met:
     13  1.21.2.2  christos  * 1. Redistributions of source code must retain the above copyright
     14  1.21.2.2  christos  *    notice, this list of conditions and the following disclaimer.
     15  1.21.2.2  christos  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.21.2.2  christos  *    notice, this list of conditions and the following disclaimer in the
     17  1.21.2.2  christos  *    documentation and/or other materials provided with the distribution.
     18  1.21.2.2  christos  *
     19  1.21.2.2  christos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.21.2.2  christos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.21.2.2  christos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.21.2.2  christos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.21.2.2  christos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.21.2.2  christos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.21.2.2  christos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.21.2.2  christos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.21.2.2  christos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.21.2.2  christos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.21.2.2  christos  * POSSIBILITY OF SUCH DAMAGE.
     30  1.21.2.2  christos  */
     31  1.21.2.2  christos 
     32  1.21.2.2  christos #include <sys/cdefs.h>
     33  1.21.2.3    martin __KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.21.2.3 2020/04/13 08:04:25 martin Exp $");
     34  1.21.2.2  christos 
     35  1.21.2.2  christos #include <sys/param.h>
     36  1.21.2.2  christos #include <sys/systm.h>
     37  1.21.2.2  christos #include <sys/kernel.h>
     38  1.21.2.2  christos 
     39  1.21.2.2  christos #include <sys/cpu.h>
     40  1.21.2.2  christos #include <sys/conf.h>
     41  1.21.2.2  christos #include <sys/kmem.h>
     42  1.21.2.2  christos #include <sys/module.h>
     43  1.21.2.2  christos #include <sys/proc.h>
     44  1.21.2.2  christos #include <sys/mman.h>
     45  1.21.2.2  christos #include <sys/file.h>
     46  1.21.2.2  christos #include <sys/filedesc.h>
     47  1.21.2.2  christos #include <sys/kauth.h>
     48  1.21.2.2  christos 
     49  1.21.2.2  christos #include <uvm/uvm.h>
     50  1.21.2.2  christos #include <uvm/uvm_page.h>
     51  1.21.2.2  christos 
     52  1.21.2.2  christos #include "ioconf.h"
     53  1.21.2.2  christos 
     54  1.21.2.2  christos #include <dev/nvmm/nvmm.h>
     55  1.21.2.2  christos #include <dev/nvmm/nvmm_internal.h>
     56  1.21.2.2  christos #include <dev/nvmm/nvmm_ioctl.h>
     57  1.21.2.2  christos 
     58  1.21.2.2  christos static struct nvmm_machine machines[NVMM_MAX_MACHINES];
     59  1.21.2.2  christos static volatile unsigned int nmachines __cacheline_aligned;
     60  1.21.2.2  christos 
     61  1.21.2.2  christos static const struct nvmm_impl *nvmm_impl_list[] = {
     62  1.21.2.2  christos 	&nvmm_x86_svm,	/* x86 AMD SVM */
     63  1.21.2.2  christos 	&nvmm_x86_vmx	/* x86 Intel VMX */
     64  1.21.2.2  christos };
     65  1.21.2.2  christos 
     66  1.21.2.2  christos static const struct nvmm_impl *nvmm_impl = NULL;
     67  1.21.2.2  christos 
     68  1.21.2.2  christos static struct nvmm_owner root_owner;
     69  1.21.2.2  christos 
     70  1.21.2.2  christos /* -------------------------------------------------------------------------- */
     71  1.21.2.2  christos 
     72  1.21.2.2  christos static int
     73  1.21.2.2  christos nvmm_machine_alloc(struct nvmm_machine **ret)
     74  1.21.2.2  christos {
     75  1.21.2.2  christos 	struct nvmm_machine *mach;
     76  1.21.2.2  christos 	size_t i;
     77  1.21.2.2  christos 
     78  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
     79  1.21.2.2  christos 		mach = &machines[i];
     80  1.21.2.2  christos 
     81  1.21.2.2  christos 		rw_enter(&mach->lock, RW_WRITER);
     82  1.21.2.2  christos 		if (mach->present) {
     83  1.21.2.2  christos 			rw_exit(&mach->lock);
     84  1.21.2.2  christos 			continue;
     85  1.21.2.2  christos 		}
     86  1.21.2.2  christos 
     87  1.21.2.2  christos 		mach->present = true;
     88  1.21.2.2  christos 		mach->time = time_second;
     89  1.21.2.2  christos 		*ret = mach;
     90  1.21.2.2  christos 		atomic_inc_uint(&nmachines);
     91  1.21.2.2  christos 		return 0;
     92  1.21.2.2  christos 	}
     93  1.21.2.2  christos 
     94  1.21.2.2  christos 	return ENOBUFS;
     95  1.21.2.2  christos }
     96  1.21.2.2  christos 
     97  1.21.2.2  christos static void
     98  1.21.2.2  christos nvmm_machine_free(struct nvmm_machine *mach)
     99  1.21.2.2  christos {
    100  1.21.2.2  christos 	KASSERT(rw_write_held(&mach->lock));
    101  1.21.2.2  christos 	KASSERT(mach->present);
    102  1.21.2.2  christos 	mach->present = false;
    103  1.21.2.2  christos 	atomic_dec_uint(&nmachines);
    104  1.21.2.2  christos }
    105  1.21.2.2  christos 
    106  1.21.2.2  christos static int
    107  1.21.2.2  christos nvmm_machine_get(struct nvmm_owner *owner, nvmm_machid_t machid,
    108  1.21.2.2  christos     struct nvmm_machine **ret, bool writer)
    109  1.21.2.2  christos {
    110  1.21.2.2  christos 	struct nvmm_machine *mach;
    111  1.21.2.2  christos 	krw_t op = writer ? RW_WRITER : RW_READER;
    112  1.21.2.2  christos 
    113  1.21.2.2  christos 	if (machid >= NVMM_MAX_MACHINES) {
    114  1.21.2.2  christos 		return EINVAL;
    115  1.21.2.2  christos 	}
    116  1.21.2.2  christos 	mach = &machines[machid];
    117  1.21.2.2  christos 
    118  1.21.2.2  christos 	rw_enter(&mach->lock, op);
    119  1.21.2.2  christos 	if (!mach->present) {
    120  1.21.2.2  christos 		rw_exit(&mach->lock);
    121  1.21.2.2  christos 		return ENOENT;
    122  1.21.2.2  christos 	}
    123  1.21.2.2  christos 	if (owner != &root_owner && mach->owner != owner) {
    124  1.21.2.2  christos 		rw_exit(&mach->lock);
    125  1.21.2.2  christos 		return EPERM;
    126  1.21.2.2  christos 	}
    127  1.21.2.2  christos 	*ret = mach;
    128  1.21.2.2  christos 
    129  1.21.2.2  christos 	return 0;
    130  1.21.2.2  christos }
    131  1.21.2.2  christos 
    132  1.21.2.2  christos static void
    133  1.21.2.2  christos nvmm_machine_put(struct nvmm_machine *mach)
    134  1.21.2.2  christos {
    135  1.21.2.2  christos 	rw_exit(&mach->lock);
    136  1.21.2.2  christos }
    137  1.21.2.2  christos 
    138  1.21.2.2  christos /* -------------------------------------------------------------------------- */
    139  1.21.2.2  christos 
    140  1.21.2.2  christos static int
    141  1.21.2.2  christos nvmm_vcpu_alloc(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    142  1.21.2.2  christos     struct nvmm_cpu **ret)
    143  1.21.2.2  christos {
    144  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    145  1.21.2.2  christos 
    146  1.21.2.2  christos 	if (cpuid >= NVMM_MAX_VCPUS) {
    147  1.21.2.2  christos 		return EINVAL;
    148  1.21.2.2  christos 	}
    149  1.21.2.2  christos 	vcpu = &mach->cpus[cpuid];
    150  1.21.2.2  christos 
    151  1.21.2.2  christos 	mutex_enter(&vcpu->lock);
    152  1.21.2.2  christos 	if (vcpu->present) {
    153  1.21.2.2  christos 		mutex_exit(&vcpu->lock);
    154  1.21.2.2  christos 		return EBUSY;
    155  1.21.2.2  christos 	}
    156  1.21.2.2  christos 
    157  1.21.2.2  christos 	vcpu->present = true;
    158  1.21.2.2  christos 	vcpu->comm = NULL;
    159  1.21.2.2  christos 	vcpu->hcpu_last = -1;
    160  1.21.2.2  christos 	*ret = vcpu;
    161  1.21.2.2  christos 	return 0;
    162  1.21.2.2  christos }
    163  1.21.2.2  christos 
    164  1.21.2.2  christos static void
    165  1.21.2.2  christos nvmm_vcpu_free(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
    166  1.21.2.2  christos {
    167  1.21.2.2  christos 	KASSERT(mutex_owned(&vcpu->lock));
    168  1.21.2.2  christos 	vcpu->present = false;
    169  1.21.2.2  christos 	if (vcpu->comm != NULL) {
    170  1.21.2.2  christos 		uvm_deallocate(kernel_map, (vaddr_t)vcpu->comm, PAGE_SIZE);
    171  1.21.2.2  christos 	}
    172  1.21.2.2  christos }
    173  1.21.2.2  christos 
    174  1.21.2.3    martin static int
    175  1.21.2.2  christos nvmm_vcpu_get(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    176  1.21.2.2  christos     struct nvmm_cpu **ret)
    177  1.21.2.2  christos {
    178  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    179  1.21.2.2  christos 
    180  1.21.2.2  christos 	if (cpuid >= NVMM_MAX_VCPUS) {
    181  1.21.2.2  christos 		return EINVAL;
    182  1.21.2.2  christos 	}
    183  1.21.2.2  christos 	vcpu = &mach->cpus[cpuid];
    184  1.21.2.2  christos 
    185  1.21.2.2  christos 	mutex_enter(&vcpu->lock);
    186  1.21.2.2  christos 	if (!vcpu->present) {
    187  1.21.2.2  christos 		mutex_exit(&vcpu->lock);
    188  1.21.2.2  christos 		return ENOENT;
    189  1.21.2.2  christos 	}
    190  1.21.2.2  christos 	*ret = vcpu;
    191  1.21.2.2  christos 
    192  1.21.2.2  christos 	return 0;
    193  1.21.2.2  christos }
    194  1.21.2.2  christos 
    195  1.21.2.3    martin static void
    196  1.21.2.2  christos nvmm_vcpu_put(struct nvmm_cpu *vcpu)
    197  1.21.2.2  christos {
    198  1.21.2.2  christos 	mutex_exit(&vcpu->lock);
    199  1.21.2.2  christos }
    200  1.21.2.2  christos 
    201  1.21.2.2  christos /* -------------------------------------------------------------------------- */
    202  1.21.2.2  christos 
    203  1.21.2.2  christos static void
    204  1.21.2.2  christos nvmm_kill_machines(struct nvmm_owner *owner)
    205  1.21.2.2  christos {
    206  1.21.2.2  christos 	struct nvmm_machine *mach;
    207  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    208  1.21.2.2  christos 	size_t i, j;
    209  1.21.2.2  christos 	int error;
    210  1.21.2.2  christos 
    211  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
    212  1.21.2.2  christos 		mach = &machines[i];
    213  1.21.2.2  christos 
    214  1.21.2.2  christos 		rw_enter(&mach->lock, RW_WRITER);
    215  1.21.2.2  christos 		if (!mach->present || mach->owner != owner) {
    216  1.21.2.2  christos 			rw_exit(&mach->lock);
    217  1.21.2.2  christos 			continue;
    218  1.21.2.2  christos 		}
    219  1.21.2.2  christos 
    220  1.21.2.2  christos 		/* Kill it. */
    221  1.21.2.2  christos 		for (j = 0; j < NVMM_MAX_VCPUS; j++) {
    222  1.21.2.2  christos 			error = nvmm_vcpu_get(mach, j, &vcpu);
    223  1.21.2.2  christos 			if (error)
    224  1.21.2.2  christos 				continue;
    225  1.21.2.2  christos 			(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    226  1.21.2.2  christos 			nvmm_vcpu_free(mach, vcpu);
    227  1.21.2.2  christos 			nvmm_vcpu_put(vcpu);
    228  1.21.2.2  christos 		}
    229  1.21.2.2  christos 		(*nvmm_impl->machine_destroy)(mach);
    230  1.21.2.2  christos 		uvmspace_free(mach->vm);
    231  1.21.2.2  christos 
    232  1.21.2.2  christos 		/* Drop the kernel UOBJ refs. */
    233  1.21.2.2  christos 		for (j = 0; j < NVMM_MAX_HMAPPINGS; j++) {
    234  1.21.2.2  christos 			if (!mach->hmap[j].present)
    235  1.21.2.2  christos 				continue;
    236  1.21.2.2  christos 			uao_detach(mach->hmap[j].uobj);
    237  1.21.2.2  christos 		}
    238  1.21.2.2  christos 
    239  1.21.2.2  christos 		nvmm_machine_free(mach);
    240  1.21.2.2  christos 
    241  1.21.2.2  christos 		rw_exit(&mach->lock);
    242  1.21.2.2  christos 	}
    243  1.21.2.2  christos }
    244  1.21.2.2  christos 
    245  1.21.2.2  christos /* -------------------------------------------------------------------------- */
    246  1.21.2.2  christos 
    247  1.21.2.2  christos static int
    248  1.21.2.2  christos nvmm_capability(struct nvmm_owner *owner, struct nvmm_ioc_capability *args)
    249  1.21.2.2  christos {
    250  1.21.2.3    martin 	args->cap.version = NVMM_KERN_VERSION;
    251  1.21.2.2  christos 	args->cap.state_size = nvmm_impl->state_size;
    252  1.21.2.2  christos 	args->cap.max_machines = NVMM_MAX_MACHINES;
    253  1.21.2.2  christos 	args->cap.max_vcpus = NVMM_MAX_VCPUS;
    254  1.21.2.2  christos 	args->cap.max_ram = NVMM_MAX_RAM;
    255  1.21.2.2  christos 
    256  1.21.2.2  christos 	(*nvmm_impl->capability)(&args->cap);
    257  1.21.2.2  christos 
    258  1.21.2.2  christos 	return 0;
    259  1.21.2.2  christos }
    260  1.21.2.2  christos 
    261  1.21.2.2  christos static int
    262  1.21.2.2  christos nvmm_machine_create(struct nvmm_owner *owner,
    263  1.21.2.2  christos     struct nvmm_ioc_machine_create *args)
    264  1.21.2.2  christos {
    265  1.21.2.2  christos 	struct nvmm_machine *mach;
    266  1.21.2.2  christos 	int error;
    267  1.21.2.2  christos 
    268  1.21.2.2  christos 	error = nvmm_machine_alloc(&mach);
    269  1.21.2.2  christos 	if (error)
    270  1.21.2.2  christos 		return error;
    271  1.21.2.2  christos 
    272  1.21.2.2  christos 	/* Curproc owns the machine. */
    273  1.21.2.2  christos 	mach->owner = owner;
    274  1.21.2.2  christos 
    275  1.21.2.2  christos 	/* Zero out the host mappings. */
    276  1.21.2.2  christos 	memset(&mach->hmap, 0, sizeof(mach->hmap));
    277  1.21.2.2  christos 
    278  1.21.2.2  christos 	/* Create the machine vmspace. */
    279  1.21.2.2  christos 	mach->gpa_begin = 0;
    280  1.21.2.2  christos 	mach->gpa_end = NVMM_MAX_RAM;
    281  1.21.2.2  christos 	mach->vm = uvmspace_alloc(0, mach->gpa_end - mach->gpa_begin, false);
    282  1.21.2.2  christos 
    283  1.21.2.2  christos 	/* Create the comm uobj. */
    284  1.21.2.2  christos 	mach->commuobj = uao_create(NVMM_MAX_VCPUS * PAGE_SIZE, 0);
    285  1.21.2.2  christos 
    286  1.21.2.2  christos 	(*nvmm_impl->machine_create)(mach);
    287  1.21.2.2  christos 
    288  1.21.2.2  christos 	args->machid = mach->machid;
    289  1.21.2.2  christos 	nvmm_machine_put(mach);
    290  1.21.2.2  christos 
    291  1.21.2.2  christos 	return 0;
    292  1.21.2.2  christos }
    293  1.21.2.2  christos 
    294  1.21.2.2  christos static int
    295  1.21.2.2  christos nvmm_machine_destroy(struct nvmm_owner *owner,
    296  1.21.2.2  christos     struct nvmm_ioc_machine_destroy *args)
    297  1.21.2.2  christos {
    298  1.21.2.2  christos 	struct nvmm_machine *mach;
    299  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    300  1.21.2.2  christos 	int error;
    301  1.21.2.2  christos 	size_t i;
    302  1.21.2.2  christos 
    303  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    304  1.21.2.2  christos 	if (error)
    305  1.21.2.2  christos 		return error;
    306  1.21.2.2  christos 
    307  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_VCPUS; i++) {
    308  1.21.2.2  christos 		error = nvmm_vcpu_get(mach, i, &vcpu);
    309  1.21.2.2  christos 		if (error)
    310  1.21.2.2  christos 			continue;
    311  1.21.2.2  christos 
    312  1.21.2.2  christos 		(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    313  1.21.2.2  christos 		nvmm_vcpu_free(mach, vcpu);
    314  1.21.2.2  christos 		nvmm_vcpu_put(vcpu);
    315  1.21.2.2  christos 	}
    316  1.21.2.2  christos 
    317  1.21.2.2  christos 	(*nvmm_impl->machine_destroy)(mach);
    318  1.21.2.2  christos 
    319  1.21.2.2  christos 	/* Free the machine vmspace. */
    320  1.21.2.2  christos 	uvmspace_free(mach->vm);
    321  1.21.2.2  christos 
    322  1.21.2.2  christos 	/* Drop the kernel UOBJ refs. */
    323  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    324  1.21.2.2  christos 		if (!mach->hmap[i].present)
    325  1.21.2.2  christos 			continue;
    326  1.21.2.2  christos 		uao_detach(mach->hmap[i].uobj);
    327  1.21.2.2  christos 	}
    328  1.21.2.2  christos 
    329  1.21.2.2  christos 	nvmm_machine_free(mach);
    330  1.21.2.2  christos 	nvmm_machine_put(mach);
    331  1.21.2.2  christos 
    332  1.21.2.2  christos 	return 0;
    333  1.21.2.2  christos }
    334  1.21.2.2  christos 
    335  1.21.2.2  christos static int
    336  1.21.2.2  christos nvmm_machine_configure(struct nvmm_owner *owner,
    337  1.21.2.2  christos     struct nvmm_ioc_machine_configure *args)
    338  1.21.2.2  christos {
    339  1.21.2.2  christos 	struct nvmm_machine *mach;
    340  1.21.2.2  christos 	size_t allocsz;
    341  1.21.2.2  christos 	uint64_t op;
    342  1.21.2.2  christos 	void *data;
    343  1.21.2.2  christos 	int error;
    344  1.21.2.2  christos 
    345  1.21.2.2  christos 	op = NVMM_MACH_CONF_MD(args->op);
    346  1.21.2.3    martin 	if (__predict_false(op >= nvmm_impl->mach_conf_max)) {
    347  1.21.2.2  christos 		return EINVAL;
    348  1.21.2.2  christos 	}
    349  1.21.2.2  christos 
    350  1.21.2.3    martin 	allocsz = nvmm_impl->mach_conf_sizes[op];
    351  1.21.2.2  christos 	data = kmem_alloc(allocsz, KM_SLEEP);
    352  1.21.2.2  christos 
    353  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    354  1.21.2.2  christos 	if (error) {
    355  1.21.2.2  christos 		kmem_free(data, allocsz);
    356  1.21.2.2  christos 		return error;
    357  1.21.2.2  christos 	}
    358  1.21.2.2  christos 
    359  1.21.2.2  christos 	error = copyin(args->conf, data, allocsz);
    360  1.21.2.2  christos 	if (error) {
    361  1.21.2.2  christos 		goto out;
    362  1.21.2.2  christos 	}
    363  1.21.2.2  christos 
    364  1.21.2.2  christos 	error = (*nvmm_impl->machine_configure)(mach, op, data);
    365  1.21.2.2  christos 
    366  1.21.2.2  christos out:
    367  1.21.2.2  christos 	nvmm_machine_put(mach);
    368  1.21.2.2  christos 	kmem_free(data, allocsz);
    369  1.21.2.2  christos 	return error;
    370  1.21.2.2  christos }
    371  1.21.2.2  christos 
    372  1.21.2.2  christos static int
    373  1.21.2.2  christos nvmm_vcpu_create(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_create *args)
    374  1.21.2.2  christos {
    375  1.21.2.2  christos 	struct nvmm_machine *mach;
    376  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    377  1.21.2.2  christos 	int error;
    378  1.21.2.2  christos 
    379  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    380  1.21.2.2  christos 	if (error)
    381  1.21.2.2  christos 		return error;
    382  1.21.2.2  christos 
    383  1.21.2.2  christos 	error = nvmm_vcpu_alloc(mach, args->cpuid, &vcpu);
    384  1.21.2.2  christos 	if (error)
    385  1.21.2.2  christos 		goto out;
    386  1.21.2.2  christos 
    387  1.21.2.2  christos 	/* Allocate the comm page. */
    388  1.21.2.2  christos 	uao_reference(mach->commuobj);
    389  1.21.2.2  christos 	error = uvm_map(kernel_map, (vaddr_t *)&vcpu->comm, PAGE_SIZE,
    390  1.21.2.2  christos 	    mach->commuobj, args->cpuid * PAGE_SIZE, 0, UVM_MAPFLAG(UVM_PROT_RW,
    391  1.21.2.2  christos 	    UVM_PROT_RW, UVM_INH_SHARE, UVM_ADV_RANDOM, 0));
    392  1.21.2.2  christos 	if (error) {
    393  1.21.2.2  christos 		uao_detach(mach->commuobj);
    394  1.21.2.2  christos 		nvmm_vcpu_free(mach, vcpu);
    395  1.21.2.2  christos 		nvmm_vcpu_put(vcpu);
    396  1.21.2.2  christos 		goto out;
    397  1.21.2.2  christos 	}
    398  1.21.2.2  christos 	error = uvm_map_pageable(kernel_map, (vaddr_t)vcpu->comm,
    399  1.21.2.2  christos 	    (vaddr_t)vcpu->comm + PAGE_SIZE, false, 0);
    400  1.21.2.2  christos 	if (error) {
    401  1.21.2.2  christos 		nvmm_vcpu_free(mach, vcpu);
    402  1.21.2.2  christos 		nvmm_vcpu_put(vcpu);
    403  1.21.2.2  christos 		goto out;
    404  1.21.2.2  christos 	}
    405  1.21.2.2  christos 	memset(vcpu->comm, 0, PAGE_SIZE);
    406  1.21.2.2  christos 
    407  1.21.2.2  christos 	error = (*nvmm_impl->vcpu_create)(mach, vcpu);
    408  1.21.2.2  christos 	if (error) {
    409  1.21.2.2  christos 		nvmm_vcpu_free(mach, vcpu);
    410  1.21.2.2  christos 		nvmm_vcpu_put(vcpu);
    411  1.21.2.2  christos 		goto out;
    412  1.21.2.2  christos 	}
    413  1.21.2.2  christos 
    414  1.21.2.2  christos 	nvmm_vcpu_put(vcpu);
    415  1.21.2.2  christos 
    416  1.21.2.2  christos out:
    417  1.21.2.2  christos 	nvmm_machine_put(mach);
    418  1.21.2.2  christos 	return error;
    419  1.21.2.2  christos }
    420  1.21.2.2  christos 
    421  1.21.2.2  christos static int
    422  1.21.2.2  christos nvmm_vcpu_destroy(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_destroy *args)
    423  1.21.2.2  christos {
    424  1.21.2.2  christos 	struct nvmm_machine *mach;
    425  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    426  1.21.2.2  christos 	int error;
    427  1.21.2.2  christos 
    428  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    429  1.21.2.2  christos 	if (error)
    430  1.21.2.2  christos 		return error;
    431  1.21.2.2  christos 
    432  1.21.2.2  christos 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    433  1.21.2.2  christos 	if (error)
    434  1.21.2.2  christos 		goto out;
    435  1.21.2.2  christos 
    436  1.21.2.2  christos 	(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    437  1.21.2.2  christos 	nvmm_vcpu_free(mach, vcpu);
    438  1.21.2.2  christos 	nvmm_vcpu_put(vcpu);
    439  1.21.2.2  christos 
    440  1.21.2.2  christos out:
    441  1.21.2.2  christos 	nvmm_machine_put(mach);
    442  1.21.2.2  christos 	return error;
    443  1.21.2.2  christos }
    444  1.21.2.2  christos 
    445  1.21.2.2  christos static int
    446  1.21.2.3    martin nvmm_vcpu_configure(struct nvmm_owner *owner,
    447  1.21.2.3    martin     struct nvmm_ioc_vcpu_configure *args)
    448  1.21.2.3    martin {
    449  1.21.2.3    martin 	struct nvmm_machine *mach;
    450  1.21.2.3    martin 	struct nvmm_cpu *vcpu;
    451  1.21.2.3    martin 	size_t allocsz;
    452  1.21.2.3    martin 	uint64_t op;
    453  1.21.2.3    martin 	void *data;
    454  1.21.2.3    martin 	int error;
    455  1.21.2.3    martin 
    456  1.21.2.3    martin 	op = NVMM_VCPU_CONF_MD(args->op);
    457  1.21.2.3    martin 	if (__predict_false(op >= nvmm_impl->vcpu_conf_max))
    458  1.21.2.3    martin 		return EINVAL;
    459  1.21.2.3    martin 
    460  1.21.2.3    martin 	allocsz = nvmm_impl->vcpu_conf_sizes[op];
    461  1.21.2.3    martin 	data = kmem_alloc(allocsz, KM_SLEEP);
    462  1.21.2.3    martin 
    463  1.21.2.3    martin 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    464  1.21.2.3    martin 	if (error) {
    465  1.21.2.3    martin 		kmem_free(data, allocsz);
    466  1.21.2.3    martin 		return error;
    467  1.21.2.3    martin 	}
    468  1.21.2.3    martin 
    469  1.21.2.3    martin 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    470  1.21.2.3    martin 	if (error) {
    471  1.21.2.3    martin 		nvmm_machine_put(mach);
    472  1.21.2.3    martin 		kmem_free(data, allocsz);
    473  1.21.2.3    martin 		return error;
    474  1.21.2.3    martin 	}
    475  1.21.2.3    martin 
    476  1.21.2.3    martin 	error = copyin(args->conf, data, allocsz);
    477  1.21.2.3    martin 	if (error) {
    478  1.21.2.3    martin 		goto out;
    479  1.21.2.3    martin 	}
    480  1.21.2.3    martin 
    481  1.21.2.3    martin 	error = (*nvmm_impl->vcpu_configure)(vcpu, op, data);
    482  1.21.2.3    martin 
    483  1.21.2.3    martin out:
    484  1.21.2.3    martin 	nvmm_vcpu_put(vcpu);
    485  1.21.2.3    martin 	nvmm_machine_put(mach);
    486  1.21.2.3    martin 	kmem_free(data, allocsz);
    487  1.21.2.3    martin 	return error;
    488  1.21.2.3    martin }
    489  1.21.2.3    martin 
    490  1.21.2.3    martin static int
    491  1.21.2.2  christos nvmm_vcpu_setstate(struct nvmm_owner *owner,
    492  1.21.2.2  christos     struct nvmm_ioc_vcpu_setstate *args)
    493  1.21.2.2  christos {
    494  1.21.2.2  christos 	struct nvmm_machine *mach;
    495  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    496  1.21.2.2  christos 	int error;
    497  1.21.2.2  christos 
    498  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    499  1.21.2.2  christos 	if (error)
    500  1.21.2.2  christos 		return error;
    501  1.21.2.2  christos 
    502  1.21.2.2  christos 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    503  1.21.2.2  christos 	if (error)
    504  1.21.2.2  christos 		goto out;
    505  1.21.2.2  christos 
    506  1.21.2.2  christos 	(*nvmm_impl->vcpu_setstate)(vcpu);
    507  1.21.2.2  christos 	nvmm_vcpu_put(vcpu);
    508  1.21.2.2  christos 
    509  1.21.2.2  christos out:
    510  1.21.2.2  christos 	nvmm_machine_put(mach);
    511  1.21.2.2  christos 	return error;
    512  1.21.2.2  christos }
    513  1.21.2.2  christos 
    514  1.21.2.2  christos static int
    515  1.21.2.2  christos nvmm_vcpu_getstate(struct nvmm_owner *owner,
    516  1.21.2.2  christos     struct nvmm_ioc_vcpu_getstate *args)
    517  1.21.2.2  christos {
    518  1.21.2.2  christos 	struct nvmm_machine *mach;
    519  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    520  1.21.2.2  christos 	int error;
    521  1.21.2.2  christos 
    522  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    523  1.21.2.2  christos 	if (error)
    524  1.21.2.2  christos 		return error;
    525  1.21.2.2  christos 
    526  1.21.2.2  christos 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    527  1.21.2.2  christos 	if (error)
    528  1.21.2.2  christos 		goto out;
    529  1.21.2.2  christos 
    530  1.21.2.2  christos 	(*nvmm_impl->vcpu_getstate)(vcpu);
    531  1.21.2.2  christos 	nvmm_vcpu_put(vcpu);
    532  1.21.2.2  christos 
    533  1.21.2.2  christos out:
    534  1.21.2.2  christos 	nvmm_machine_put(mach);
    535  1.21.2.2  christos 	return error;
    536  1.21.2.2  christos }
    537  1.21.2.2  christos 
    538  1.21.2.2  christos static int
    539  1.21.2.2  christos nvmm_vcpu_inject(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_inject *args)
    540  1.21.2.2  christos {
    541  1.21.2.2  christos 	struct nvmm_machine *mach;
    542  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    543  1.21.2.2  christos 	int error;
    544  1.21.2.2  christos 
    545  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    546  1.21.2.2  christos 	if (error)
    547  1.21.2.2  christos 		return error;
    548  1.21.2.2  christos 
    549  1.21.2.2  christos 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    550  1.21.2.2  christos 	if (error)
    551  1.21.2.2  christos 		goto out;
    552  1.21.2.2  christos 
    553  1.21.2.2  christos 	error = (*nvmm_impl->vcpu_inject)(vcpu);
    554  1.21.2.2  christos 	nvmm_vcpu_put(vcpu);
    555  1.21.2.2  christos 
    556  1.21.2.2  christos out:
    557  1.21.2.2  christos 	nvmm_machine_put(mach);
    558  1.21.2.2  christos 	return error;
    559  1.21.2.2  christos }
    560  1.21.2.2  christos 
    561  1.21.2.3    martin static int
    562  1.21.2.2  christos nvmm_do_vcpu_run(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
    563  1.21.2.3    martin     struct nvmm_vcpu_exit *exit)
    564  1.21.2.2  christos {
    565  1.21.2.2  christos 	struct vmspace *vm = mach->vm;
    566  1.21.2.3    martin 	int ret;
    567  1.21.2.2  christos 
    568  1.21.2.2  christos 	while (1) {
    569  1.21.2.3    martin 		ret = (*nvmm_impl->vcpu_run)(mach, vcpu, exit);
    570  1.21.2.3    martin 		if (__predict_false(ret != 0)) {
    571  1.21.2.3    martin 			return ret;
    572  1.21.2.3    martin 		}
    573  1.21.2.2  christos 
    574  1.21.2.3    martin 		if (__predict_true(exit->reason != NVMM_VCPU_EXIT_MEMORY)) {
    575  1.21.2.2  christos 			break;
    576  1.21.2.2  christos 		}
    577  1.21.2.2  christos 		if (exit->u.mem.gpa >= mach->gpa_end) {
    578  1.21.2.2  christos 			break;
    579  1.21.2.2  christos 		}
    580  1.21.2.2  christos 		if (uvm_fault(&vm->vm_map, exit->u.mem.gpa, exit->u.mem.prot)) {
    581  1.21.2.2  christos 			break;
    582  1.21.2.2  christos 		}
    583  1.21.2.2  christos 	}
    584  1.21.2.3    martin 
    585  1.21.2.3    martin 	return 0;
    586  1.21.2.2  christos }
    587  1.21.2.2  christos 
    588  1.21.2.2  christos static int
    589  1.21.2.2  christos nvmm_vcpu_run(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_run *args)
    590  1.21.2.2  christos {
    591  1.21.2.2  christos 	struct nvmm_machine *mach;
    592  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    593  1.21.2.2  christos 	int error;
    594  1.21.2.2  christos 
    595  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    596  1.21.2.2  christos 	if (error)
    597  1.21.2.2  christos 		return error;
    598  1.21.2.2  christos 
    599  1.21.2.2  christos 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    600  1.21.2.2  christos 	if (error)
    601  1.21.2.2  christos 		goto out;
    602  1.21.2.2  christos 
    603  1.21.2.3    martin 	error = nvmm_do_vcpu_run(mach, vcpu, &args->exit);
    604  1.21.2.2  christos 	nvmm_vcpu_put(vcpu);
    605  1.21.2.2  christos 
    606  1.21.2.2  christos out:
    607  1.21.2.2  christos 	nvmm_machine_put(mach);
    608  1.21.2.2  christos 	return error;
    609  1.21.2.2  christos }
    610  1.21.2.2  christos 
    611  1.21.2.2  christos /* -------------------------------------------------------------------------- */
    612  1.21.2.2  christos 
    613  1.21.2.2  christos static struct uvm_object *
    614  1.21.2.2  christos nvmm_hmapping_getuobj(struct nvmm_machine *mach, uintptr_t hva, size_t size,
    615  1.21.2.2  christos    size_t *off)
    616  1.21.2.2  christos {
    617  1.21.2.2  christos 	struct nvmm_hmapping *hmapping;
    618  1.21.2.2  christos 	size_t i;
    619  1.21.2.2  christos 
    620  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    621  1.21.2.2  christos 		hmapping = &mach->hmap[i];
    622  1.21.2.2  christos 		if (!hmapping->present) {
    623  1.21.2.2  christos 			continue;
    624  1.21.2.2  christos 		}
    625  1.21.2.2  christos 		if (hva >= hmapping->hva &&
    626  1.21.2.2  christos 		    hva + size <= hmapping->hva + hmapping->size) {
    627  1.21.2.2  christos 			*off = hva - hmapping->hva;
    628  1.21.2.2  christos 			return hmapping->uobj;
    629  1.21.2.2  christos 		}
    630  1.21.2.2  christos 	}
    631  1.21.2.2  christos 
    632  1.21.2.2  christos 	return NULL;
    633  1.21.2.2  christos }
    634  1.21.2.2  christos 
    635  1.21.2.2  christos static int
    636  1.21.2.2  christos nvmm_hmapping_validate(struct nvmm_machine *mach, uintptr_t hva, size_t size)
    637  1.21.2.2  christos {
    638  1.21.2.2  christos 	struct nvmm_hmapping *hmapping;
    639  1.21.2.2  christos 	size_t i;
    640  1.21.2.2  christos 
    641  1.21.2.2  christos 	if ((hva % PAGE_SIZE) != 0 || (size % PAGE_SIZE) != 0) {
    642  1.21.2.2  christos 		return EINVAL;
    643  1.21.2.2  christos 	}
    644  1.21.2.2  christos 	if (hva == 0) {
    645  1.21.2.2  christos 		return EINVAL;
    646  1.21.2.2  christos 	}
    647  1.21.2.2  christos 
    648  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    649  1.21.2.2  christos 		hmapping = &mach->hmap[i];
    650  1.21.2.2  christos 		if (!hmapping->present) {
    651  1.21.2.2  christos 			continue;
    652  1.21.2.2  christos 		}
    653  1.21.2.2  christos 
    654  1.21.2.2  christos 		if (hva >= hmapping->hva &&
    655  1.21.2.2  christos 		    hva + size <= hmapping->hva + hmapping->size) {
    656  1.21.2.2  christos 			break;
    657  1.21.2.2  christos 		}
    658  1.21.2.2  christos 
    659  1.21.2.2  christos 		if (hva >= hmapping->hva &&
    660  1.21.2.2  christos 		    hva < hmapping->hva + hmapping->size) {
    661  1.21.2.2  christos 			return EEXIST;
    662  1.21.2.2  christos 		}
    663  1.21.2.2  christos 		if (hva + size > hmapping->hva &&
    664  1.21.2.2  christos 		    hva + size <= hmapping->hva + hmapping->size) {
    665  1.21.2.2  christos 			return EEXIST;
    666  1.21.2.2  christos 		}
    667  1.21.2.2  christos 		if (hva <= hmapping->hva &&
    668  1.21.2.2  christos 		    hva + size >= hmapping->hva + hmapping->size) {
    669  1.21.2.2  christos 			return EEXIST;
    670  1.21.2.2  christos 		}
    671  1.21.2.2  christos 	}
    672  1.21.2.2  christos 
    673  1.21.2.2  christos 	return 0;
    674  1.21.2.2  christos }
    675  1.21.2.2  christos 
    676  1.21.2.2  christos static struct nvmm_hmapping *
    677  1.21.2.2  christos nvmm_hmapping_alloc(struct nvmm_machine *mach)
    678  1.21.2.2  christos {
    679  1.21.2.2  christos 	struct nvmm_hmapping *hmapping;
    680  1.21.2.2  christos 	size_t i;
    681  1.21.2.2  christos 
    682  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    683  1.21.2.2  christos 		hmapping = &mach->hmap[i];
    684  1.21.2.2  christos 		if (!hmapping->present) {
    685  1.21.2.2  christos 			hmapping->present = true;
    686  1.21.2.2  christos 			return hmapping;
    687  1.21.2.2  christos 		}
    688  1.21.2.2  christos 	}
    689  1.21.2.2  christos 
    690  1.21.2.2  christos 	return NULL;
    691  1.21.2.2  christos }
    692  1.21.2.2  christos 
    693  1.21.2.2  christos static int
    694  1.21.2.2  christos nvmm_hmapping_free(struct nvmm_machine *mach, uintptr_t hva, size_t size)
    695  1.21.2.2  christos {
    696  1.21.2.2  christos 	struct vmspace *vmspace = curproc->p_vmspace;
    697  1.21.2.2  christos 	struct nvmm_hmapping *hmapping;
    698  1.21.2.2  christos 	size_t i;
    699  1.21.2.2  christos 
    700  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    701  1.21.2.2  christos 		hmapping = &mach->hmap[i];
    702  1.21.2.2  christos 		if (!hmapping->present || hmapping->hva != hva ||
    703  1.21.2.2  christos 		    hmapping->size != size) {
    704  1.21.2.2  christos 			continue;
    705  1.21.2.2  christos 		}
    706  1.21.2.2  christos 
    707  1.21.2.2  christos 		uvm_unmap(&vmspace->vm_map, hmapping->hva,
    708  1.21.2.2  christos 		    hmapping->hva + hmapping->size);
    709  1.21.2.2  christos 		uao_detach(hmapping->uobj);
    710  1.21.2.2  christos 
    711  1.21.2.2  christos 		hmapping->uobj = NULL;
    712  1.21.2.2  christos 		hmapping->present = false;
    713  1.21.2.2  christos 
    714  1.21.2.2  christos 		return 0;
    715  1.21.2.2  christos 	}
    716  1.21.2.2  christos 
    717  1.21.2.2  christos 	return ENOENT;
    718  1.21.2.2  christos }
    719  1.21.2.2  christos 
    720  1.21.2.2  christos static int
    721  1.21.2.2  christos nvmm_hva_map(struct nvmm_owner *owner, struct nvmm_ioc_hva_map *args)
    722  1.21.2.2  christos {
    723  1.21.2.2  christos 	struct vmspace *vmspace = curproc->p_vmspace;
    724  1.21.2.2  christos 	struct nvmm_machine *mach;
    725  1.21.2.2  christos 	struct nvmm_hmapping *hmapping;
    726  1.21.2.2  christos 	vaddr_t uva;
    727  1.21.2.2  christos 	int error;
    728  1.21.2.2  christos 
    729  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    730  1.21.2.2  christos 	if (error)
    731  1.21.2.2  christos 		return error;
    732  1.21.2.2  christos 
    733  1.21.2.2  christos 	error = nvmm_hmapping_validate(mach, args->hva, args->size);
    734  1.21.2.2  christos 	if (error)
    735  1.21.2.2  christos 		goto out;
    736  1.21.2.2  christos 
    737  1.21.2.2  christos 	hmapping = nvmm_hmapping_alloc(mach);
    738  1.21.2.2  christos 	if (hmapping == NULL) {
    739  1.21.2.2  christos 		error = ENOBUFS;
    740  1.21.2.2  christos 		goto out;
    741  1.21.2.2  christos 	}
    742  1.21.2.2  christos 
    743  1.21.2.2  christos 	hmapping->hva = args->hva;
    744  1.21.2.2  christos 	hmapping->size = args->size;
    745  1.21.2.2  christos 	hmapping->uobj = uao_create(hmapping->size, 0);
    746  1.21.2.2  christos 	uva = hmapping->hva;
    747  1.21.2.2  christos 
    748  1.21.2.2  christos 	/* Take a reference for the user. */
    749  1.21.2.2  christos 	uao_reference(hmapping->uobj);
    750  1.21.2.2  christos 
    751  1.21.2.2  christos 	/* Map the uobj into the user address space, as pageable. */
    752  1.21.2.2  christos 	error = uvm_map(&vmspace->vm_map, &uva, hmapping->size, hmapping->uobj,
    753  1.21.2.2  christos 	    0, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_SHARE,
    754  1.21.2.2  christos 	    UVM_ADV_RANDOM, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
    755  1.21.2.2  christos 	if (error) {
    756  1.21.2.2  christos 		uao_detach(hmapping->uobj);
    757  1.21.2.2  christos 	}
    758  1.21.2.2  christos 
    759  1.21.2.2  christos out:
    760  1.21.2.2  christos 	nvmm_machine_put(mach);
    761  1.21.2.2  christos 	return error;
    762  1.21.2.2  christos }
    763  1.21.2.2  christos 
    764  1.21.2.2  christos static int
    765  1.21.2.2  christos nvmm_hva_unmap(struct nvmm_owner *owner, struct nvmm_ioc_hva_unmap *args)
    766  1.21.2.2  christos {
    767  1.21.2.2  christos 	struct nvmm_machine *mach;
    768  1.21.2.2  christos 	int error;
    769  1.21.2.2  christos 
    770  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    771  1.21.2.2  christos 	if (error)
    772  1.21.2.2  christos 		return error;
    773  1.21.2.2  christos 
    774  1.21.2.2  christos 	error = nvmm_hmapping_free(mach, args->hva, args->size);
    775  1.21.2.2  christos 
    776  1.21.2.2  christos 	nvmm_machine_put(mach);
    777  1.21.2.2  christos 	return error;
    778  1.21.2.2  christos }
    779  1.21.2.2  christos 
    780  1.21.2.2  christos /* -------------------------------------------------------------------------- */
    781  1.21.2.2  christos 
    782  1.21.2.2  christos static int
    783  1.21.2.2  christos nvmm_gpa_map(struct nvmm_owner *owner, struct nvmm_ioc_gpa_map *args)
    784  1.21.2.2  christos {
    785  1.21.2.2  christos 	struct nvmm_machine *mach;
    786  1.21.2.2  christos 	struct uvm_object *uobj;
    787  1.21.2.2  christos 	gpaddr_t gpa;
    788  1.21.2.2  christos 	size_t off;
    789  1.21.2.2  christos 	int error;
    790  1.21.2.2  christos 
    791  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    792  1.21.2.2  christos 	if (error)
    793  1.21.2.2  christos 		return error;
    794  1.21.2.2  christos 
    795  1.21.2.2  christos 	if ((args->prot & ~(PROT_READ|PROT_WRITE|PROT_EXEC)) != 0) {
    796  1.21.2.2  christos 		error = EINVAL;
    797  1.21.2.2  christos 		goto out;
    798  1.21.2.2  christos 	}
    799  1.21.2.2  christos 
    800  1.21.2.2  christos 	if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0 ||
    801  1.21.2.2  christos 	    (args->hva % PAGE_SIZE) != 0) {
    802  1.21.2.2  christos 		error = EINVAL;
    803  1.21.2.2  christos 		goto out;
    804  1.21.2.2  christos 	}
    805  1.21.2.2  christos 	if (args->hva == 0) {
    806  1.21.2.2  christos 		error = EINVAL;
    807  1.21.2.2  christos 		goto out;
    808  1.21.2.2  christos 	}
    809  1.21.2.2  christos 	if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
    810  1.21.2.2  christos 		error = EINVAL;
    811  1.21.2.2  christos 		goto out;
    812  1.21.2.2  christos 	}
    813  1.21.2.2  christos 	if (args->gpa + args->size <= args->gpa) {
    814  1.21.2.2  christos 		error = EINVAL;
    815  1.21.2.2  christos 		goto out;
    816  1.21.2.2  christos 	}
    817  1.21.2.2  christos 	if (args->gpa + args->size > mach->gpa_end) {
    818  1.21.2.2  christos 		error = EINVAL;
    819  1.21.2.2  christos 		goto out;
    820  1.21.2.2  christos 	}
    821  1.21.2.2  christos 	gpa = args->gpa;
    822  1.21.2.2  christos 
    823  1.21.2.2  christos 	uobj = nvmm_hmapping_getuobj(mach, args->hva, args->size, &off);
    824  1.21.2.2  christos 	if (uobj == NULL) {
    825  1.21.2.2  christos 		error = EINVAL;
    826  1.21.2.2  christos 		goto out;
    827  1.21.2.2  christos 	}
    828  1.21.2.2  christos 
    829  1.21.2.2  christos 	/* Take a reference for the machine. */
    830  1.21.2.2  christos 	uao_reference(uobj);
    831  1.21.2.2  christos 
    832  1.21.2.2  christos 	/* Map the uobj into the machine address space, as pageable. */
    833  1.21.2.2  christos 	error = uvm_map(&mach->vm->vm_map, &gpa, args->size, uobj, off, 0,
    834  1.21.2.2  christos 	    UVM_MAPFLAG(args->prot, UVM_PROT_RWX, UVM_INH_NONE,
    835  1.21.2.2  christos 	    UVM_ADV_RANDOM, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
    836  1.21.2.2  christos 	if (error) {
    837  1.21.2.2  christos 		uao_detach(uobj);
    838  1.21.2.2  christos 		goto out;
    839  1.21.2.2  christos 	}
    840  1.21.2.2  christos 	if (gpa != args->gpa) {
    841  1.21.2.2  christos 		uao_detach(uobj);
    842  1.21.2.2  christos 		printf("[!] uvm_map problem\n");
    843  1.21.2.2  christos 		error = EINVAL;
    844  1.21.2.2  christos 		goto out;
    845  1.21.2.2  christos 	}
    846  1.21.2.2  christos 
    847  1.21.2.2  christos out:
    848  1.21.2.2  christos 	nvmm_machine_put(mach);
    849  1.21.2.2  christos 	return error;
    850  1.21.2.2  christos }
    851  1.21.2.2  christos 
    852  1.21.2.2  christos static int
    853  1.21.2.2  christos nvmm_gpa_unmap(struct nvmm_owner *owner, struct nvmm_ioc_gpa_unmap *args)
    854  1.21.2.2  christos {
    855  1.21.2.2  christos 	struct nvmm_machine *mach;
    856  1.21.2.2  christos 	gpaddr_t gpa;
    857  1.21.2.2  christos 	int error;
    858  1.21.2.2  christos 
    859  1.21.2.2  christos 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    860  1.21.2.2  christos 	if (error)
    861  1.21.2.2  christos 		return error;
    862  1.21.2.2  christos 
    863  1.21.2.2  christos 	if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0) {
    864  1.21.2.2  christos 		error = EINVAL;
    865  1.21.2.2  christos 		goto out;
    866  1.21.2.2  christos 	}
    867  1.21.2.2  christos 	if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
    868  1.21.2.2  christos 		error = EINVAL;
    869  1.21.2.2  christos 		goto out;
    870  1.21.2.2  christos 	}
    871  1.21.2.2  christos 	if (args->gpa + args->size <= args->gpa) {
    872  1.21.2.2  christos 		error = EINVAL;
    873  1.21.2.2  christos 		goto out;
    874  1.21.2.2  christos 	}
    875  1.21.2.2  christos 	if (args->gpa + args->size >= mach->gpa_end) {
    876  1.21.2.2  christos 		error = EINVAL;
    877  1.21.2.2  christos 		goto out;
    878  1.21.2.2  christos 	}
    879  1.21.2.2  christos 	gpa = args->gpa;
    880  1.21.2.2  christos 
    881  1.21.2.2  christos 	/* Unmap the memory from the machine. */
    882  1.21.2.2  christos 	uvm_unmap(&mach->vm->vm_map, gpa, gpa + args->size);
    883  1.21.2.2  christos 
    884  1.21.2.2  christos out:
    885  1.21.2.2  christos 	nvmm_machine_put(mach);
    886  1.21.2.2  christos 	return error;
    887  1.21.2.2  christos }
    888  1.21.2.2  christos 
    889  1.21.2.2  christos /* -------------------------------------------------------------------------- */
    890  1.21.2.2  christos 
    891  1.21.2.2  christos static int
    892  1.21.2.3    martin nvmm_ctl_mach_info(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args)
    893  1.21.2.2  christos {
    894  1.21.2.2  christos 	struct nvmm_ctl_mach_info ctl;
    895  1.21.2.2  christos 	struct nvmm_machine *mach;
    896  1.21.2.2  christos 	struct nvmm_cpu *vcpu;
    897  1.21.2.2  christos 	int error;
    898  1.21.2.2  christos 	size_t i;
    899  1.21.2.2  christos 
    900  1.21.2.2  christos 	if (args->size != sizeof(ctl))
    901  1.21.2.2  christos 		return EINVAL;
    902  1.21.2.2  christos 	error = copyin(args->data, &ctl, sizeof(ctl));
    903  1.21.2.2  christos 	if (error)
    904  1.21.2.2  christos 		return error;
    905  1.21.2.2  christos 
    906  1.21.2.3    martin 	error = nvmm_machine_get(owner, ctl.machid, &mach, true);
    907  1.21.2.2  christos 	if (error)
    908  1.21.2.2  christos 		return error;
    909  1.21.2.2  christos 
    910  1.21.2.2  christos 	ctl.nvcpus = 0;
    911  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_VCPUS; i++) {
    912  1.21.2.2  christos 		error = nvmm_vcpu_get(mach, i, &vcpu);
    913  1.21.2.2  christos 		if (error)
    914  1.21.2.2  christos 			continue;
    915  1.21.2.2  christos 		ctl.nvcpus++;
    916  1.21.2.2  christos 		nvmm_vcpu_put(vcpu);
    917  1.21.2.2  christos 	}
    918  1.21.2.3    martin 
    919  1.21.2.3    martin 	ctl.nram = 0;
    920  1.21.2.3    martin 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    921  1.21.2.3    martin 		if (!mach->hmap[i].present)
    922  1.21.2.3    martin 			continue;
    923  1.21.2.3    martin 		ctl.nram += mach->hmap[i].size;
    924  1.21.2.3    martin 	}
    925  1.21.2.3    martin 
    926  1.21.2.2  christos 	ctl.pid = mach->owner->pid;
    927  1.21.2.2  christos 	ctl.time = mach->time;
    928  1.21.2.2  christos 
    929  1.21.2.2  christos 	nvmm_machine_put(mach);
    930  1.21.2.2  christos 
    931  1.21.2.2  christos 	error = copyout(&ctl, args->data, sizeof(ctl));
    932  1.21.2.2  christos 	if (error)
    933  1.21.2.2  christos 		return error;
    934  1.21.2.2  christos 
    935  1.21.2.2  christos 	return 0;
    936  1.21.2.2  christos }
    937  1.21.2.2  christos 
    938  1.21.2.2  christos static int
    939  1.21.2.2  christos nvmm_ctl(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args)
    940  1.21.2.2  christos {
    941  1.21.2.2  christos 	switch (args->op) {
    942  1.21.2.2  christos 	case NVMM_CTL_MACH_INFO:
    943  1.21.2.3    martin 		return nvmm_ctl_mach_info(owner, args);
    944  1.21.2.2  christos 	default:
    945  1.21.2.2  christos 		return EINVAL;
    946  1.21.2.2  christos 	}
    947  1.21.2.2  christos }
    948  1.21.2.2  christos 
    949  1.21.2.2  christos /* -------------------------------------------------------------------------- */
    950  1.21.2.2  christos 
    951  1.21.2.2  christos static int
    952  1.21.2.2  christos nvmm_init(void)
    953  1.21.2.2  christos {
    954  1.21.2.2  christos 	size_t i, n;
    955  1.21.2.2  christos 
    956  1.21.2.2  christos 	for (i = 0; i < __arraycount(nvmm_impl_list); i++) {
    957  1.21.2.2  christos 		if (!(*nvmm_impl_list[i]->ident)()) {
    958  1.21.2.2  christos 			continue;
    959  1.21.2.2  christos 		}
    960  1.21.2.2  christos 		nvmm_impl = nvmm_impl_list[i];
    961  1.21.2.2  christos 		break;
    962  1.21.2.2  christos 	}
    963  1.21.2.2  christos 	if (nvmm_impl == NULL) {
    964  1.21.2.2  christos 		printf("[!] No implementation found\n");
    965  1.21.2.2  christos 		return ENOTSUP;
    966  1.21.2.2  christos 	}
    967  1.21.2.2  christos 
    968  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
    969  1.21.2.2  christos 		machines[i].machid = i;
    970  1.21.2.2  christos 		rw_init(&machines[i].lock);
    971  1.21.2.2  christos 		for (n = 0; n < NVMM_MAX_VCPUS; n++) {
    972  1.21.2.2  christos 			machines[i].cpus[n].present = false;
    973  1.21.2.2  christos 			machines[i].cpus[n].cpuid = n;
    974  1.21.2.2  christos 			mutex_init(&machines[i].cpus[n].lock, MUTEX_DEFAULT,
    975  1.21.2.2  christos 			    IPL_NONE);
    976  1.21.2.2  christos 		}
    977  1.21.2.2  christos 	}
    978  1.21.2.2  christos 
    979  1.21.2.2  christos 	(*nvmm_impl->init)();
    980  1.21.2.2  christos 
    981  1.21.2.2  christos 	return 0;
    982  1.21.2.2  christos }
    983  1.21.2.2  christos 
    984  1.21.2.2  christos static void
    985  1.21.2.2  christos nvmm_fini(void)
    986  1.21.2.2  christos {
    987  1.21.2.2  christos 	size_t i, n;
    988  1.21.2.2  christos 
    989  1.21.2.2  christos 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
    990  1.21.2.2  christos 		rw_destroy(&machines[i].lock);
    991  1.21.2.2  christos 		for (n = 0; n < NVMM_MAX_VCPUS; n++) {
    992  1.21.2.2  christos 			mutex_destroy(&machines[i].cpus[n].lock);
    993  1.21.2.2  christos 		}
    994  1.21.2.2  christos 	}
    995  1.21.2.2  christos 
    996  1.21.2.2  christos 	(*nvmm_impl->fini)();
    997  1.21.2.2  christos }
    998  1.21.2.2  christos 
    999  1.21.2.2  christos /* -------------------------------------------------------------------------- */
   1000  1.21.2.2  christos 
   1001  1.21.2.2  christos static dev_type_open(nvmm_open);
   1002  1.21.2.2  christos 
   1003  1.21.2.2  christos const struct cdevsw nvmm_cdevsw = {
   1004  1.21.2.2  christos 	.d_open = nvmm_open,
   1005  1.21.2.2  christos 	.d_close = noclose,
   1006  1.21.2.2  christos 	.d_read = noread,
   1007  1.21.2.2  christos 	.d_write = nowrite,
   1008  1.21.2.2  christos 	.d_ioctl = noioctl,
   1009  1.21.2.2  christos 	.d_stop = nostop,
   1010  1.21.2.2  christos 	.d_tty = notty,
   1011  1.21.2.2  christos 	.d_poll = nopoll,
   1012  1.21.2.2  christos 	.d_mmap = nommap,
   1013  1.21.2.2  christos 	.d_kqfilter = nokqfilter,
   1014  1.21.2.2  christos 	.d_discard = nodiscard,
   1015  1.21.2.2  christos 	.d_flag = D_OTHER | D_MPSAFE
   1016  1.21.2.2  christos };
   1017  1.21.2.2  christos 
   1018  1.21.2.2  christos static int nvmm_ioctl(file_t *, u_long, void *);
   1019  1.21.2.2  christos static int nvmm_close(file_t *);
   1020  1.21.2.2  christos static int nvmm_mmap(file_t *, off_t *, size_t, int, int *, int *,
   1021  1.21.2.2  christos     struct uvm_object **, int *);
   1022  1.21.2.2  christos 
   1023  1.21.2.2  christos const struct fileops nvmm_fileops = {
   1024  1.21.2.2  christos 	.fo_read = fbadop_read,
   1025  1.21.2.2  christos 	.fo_write = fbadop_write,
   1026  1.21.2.2  christos 	.fo_ioctl = nvmm_ioctl,
   1027  1.21.2.2  christos 	.fo_fcntl = fnullop_fcntl,
   1028  1.21.2.2  christos 	.fo_poll = fnullop_poll,
   1029  1.21.2.2  christos 	.fo_stat = fbadop_stat,
   1030  1.21.2.2  christos 	.fo_close = nvmm_close,
   1031  1.21.2.2  christos 	.fo_kqfilter = fnullop_kqfilter,
   1032  1.21.2.2  christos 	.fo_restart = fnullop_restart,
   1033  1.21.2.2  christos 	.fo_mmap = nvmm_mmap,
   1034  1.21.2.2  christos };
   1035  1.21.2.2  christos 
   1036  1.21.2.2  christos static int
   1037  1.21.2.2  christos nvmm_open(dev_t dev, int flags, int type, struct lwp *l)
   1038  1.21.2.2  christos {
   1039  1.21.2.2  christos 	struct nvmm_owner *owner;
   1040  1.21.2.2  christos 	struct file *fp;
   1041  1.21.2.2  christos 	int error, fd;
   1042  1.21.2.2  christos 
   1043  1.21.2.2  christos 	if (minor(dev) != 0)
   1044  1.21.2.2  christos 		return EXDEV;
   1045  1.21.2.3    martin 	if (!(flags & O_CLOEXEC))
   1046  1.21.2.3    martin 		return EINVAL;
   1047  1.21.2.2  christos 	error = fd_allocfile(&fp, &fd);
   1048  1.21.2.2  christos 	if (error)
   1049  1.21.2.2  christos 		return error;
   1050  1.21.2.2  christos 
   1051  1.21.2.3    martin 	if (OFLAGS(flags) & O_WRONLY) {
   1052  1.21.2.3    martin 		owner = &root_owner;
   1053  1.21.2.3    martin 	} else {
   1054  1.21.2.3    martin 		owner = kmem_alloc(sizeof(*owner), KM_SLEEP);
   1055  1.21.2.3    martin 		owner->pid = l->l_proc->p_pid;
   1056  1.21.2.3    martin 	}
   1057  1.21.2.2  christos 
   1058  1.21.2.2  christos 	return fd_clone(fp, fd, flags, &nvmm_fileops, owner);
   1059  1.21.2.2  christos }
   1060  1.21.2.2  christos 
   1061  1.21.2.2  christos static int
   1062  1.21.2.2  christos nvmm_close(file_t *fp)
   1063  1.21.2.2  christos {
   1064  1.21.2.2  christos 	struct nvmm_owner *owner = fp->f_data;
   1065  1.21.2.2  christos 
   1066  1.21.2.2  christos 	KASSERT(owner != NULL);
   1067  1.21.2.2  christos 	nvmm_kill_machines(owner);
   1068  1.21.2.3    martin 	if (owner != &root_owner) {
   1069  1.21.2.3    martin 		kmem_free(owner, sizeof(*owner));
   1070  1.21.2.3    martin 	}
   1071  1.21.2.2  christos 	fp->f_data = NULL;
   1072  1.21.2.2  christos 
   1073  1.21.2.2  christos    	return 0;
   1074  1.21.2.2  christos }
   1075  1.21.2.2  christos 
   1076  1.21.2.2  christos static int
   1077  1.21.2.2  christos nvmm_mmap(file_t *fp, off_t *offp, size_t size, int prot, int *flagsp,
   1078  1.21.2.2  christos     int *advicep, struct uvm_object **uobjp, int *maxprotp)
   1079  1.21.2.2  christos {
   1080  1.21.2.2  christos 	struct nvmm_owner *owner = fp->f_data;
   1081  1.21.2.2  christos 	struct nvmm_machine *mach;
   1082  1.21.2.2  christos 	nvmm_machid_t machid;
   1083  1.21.2.2  christos 	nvmm_cpuid_t cpuid;
   1084  1.21.2.2  christos 	int error;
   1085  1.21.2.2  christos 
   1086  1.21.2.2  christos 	if (prot & PROT_EXEC)
   1087  1.21.2.2  christos 		return EACCES;
   1088  1.21.2.2  christos 	if (size != PAGE_SIZE)
   1089  1.21.2.2  christos 		return EINVAL;
   1090  1.21.2.2  christos 
   1091  1.21.2.2  christos 	cpuid = NVMM_COMM_CPUID(*offp);
   1092  1.21.2.2  christos 	if (__predict_false(cpuid >= NVMM_MAX_VCPUS))
   1093  1.21.2.2  christos 		return EINVAL;
   1094  1.21.2.2  christos 
   1095  1.21.2.2  christos 	machid = NVMM_COMM_MACHID(*offp);
   1096  1.21.2.2  christos 	error = nvmm_machine_get(owner, machid, &mach, false);
   1097  1.21.2.2  christos 	if (error)
   1098  1.21.2.2  christos 		return error;
   1099  1.21.2.2  christos 
   1100  1.21.2.2  christos 	uao_reference(mach->commuobj);
   1101  1.21.2.2  christos 	*uobjp = mach->commuobj;
   1102  1.21.2.2  christos 	*offp = cpuid * PAGE_SIZE;
   1103  1.21.2.2  christos 	*maxprotp = prot;
   1104  1.21.2.2  christos 	*advicep = UVM_ADV_RANDOM;
   1105  1.21.2.2  christos 
   1106  1.21.2.2  christos 	nvmm_machine_put(mach);
   1107  1.21.2.2  christos 	return 0;
   1108  1.21.2.2  christos }
   1109  1.21.2.2  christos 
   1110  1.21.2.2  christos static int
   1111  1.21.2.2  christos nvmm_ioctl(file_t *fp, u_long cmd, void *data)
   1112  1.21.2.2  christos {
   1113  1.21.2.2  christos 	struct nvmm_owner *owner = fp->f_data;
   1114  1.21.2.2  christos 
   1115  1.21.2.2  christos 	KASSERT(owner != NULL);
   1116  1.21.2.2  christos 
   1117  1.21.2.2  christos 	switch (cmd) {
   1118  1.21.2.2  christos 	case NVMM_IOC_CAPABILITY:
   1119  1.21.2.2  christos 		return nvmm_capability(owner, data);
   1120  1.21.2.2  christos 	case NVMM_IOC_MACHINE_CREATE:
   1121  1.21.2.2  christos 		return nvmm_machine_create(owner, data);
   1122  1.21.2.2  christos 	case NVMM_IOC_MACHINE_DESTROY:
   1123  1.21.2.2  christos 		return nvmm_machine_destroy(owner, data);
   1124  1.21.2.2  christos 	case NVMM_IOC_MACHINE_CONFIGURE:
   1125  1.21.2.2  christos 		return nvmm_machine_configure(owner, data);
   1126  1.21.2.2  christos 	case NVMM_IOC_VCPU_CREATE:
   1127  1.21.2.2  christos 		return nvmm_vcpu_create(owner, data);
   1128  1.21.2.2  christos 	case NVMM_IOC_VCPU_DESTROY:
   1129  1.21.2.2  christos 		return nvmm_vcpu_destroy(owner, data);
   1130  1.21.2.3    martin 	case NVMM_IOC_VCPU_CONFIGURE:
   1131  1.21.2.3    martin 		return nvmm_vcpu_configure(owner, data);
   1132  1.21.2.2  christos 	case NVMM_IOC_VCPU_SETSTATE:
   1133  1.21.2.2  christos 		return nvmm_vcpu_setstate(owner, data);
   1134  1.21.2.2  christos 	case NVMM_IOC_VCPU_GETSTATE:
   1135  1.21.2.2  christos 		return nvmm_vcpu_getstate(owner, data);
   1136  1.21.2.2  christos 	case NVMM_IOC_VCPU_INJECT:
   1137  1.21.2.2  christos 		return nvmm_vcpu_inject(owner, data);
   1138  1.21.2.2  christos 	case NVMM_IOC_VCPU_RUN:
   1139  1.21.2.2  christos 		return nvmm_vcpu_run(owner, data);
   1140  1.21.2.2  christos 	case NVMM_IOC_GPA_MAP:
   1141  1.21.2.2  christos 		return nvmm_gpa_map(owner, data);
   1142  1.21.2.2  christos 	case NVMM_IOC_GPA_UNMAP:
   1143  1.21.2.2  christos 		return nvmm_gpa_unmap(owner, data);
   1144  1.21.2.2  christos 	case NVMM_IOC_HVA_MAP:
   1145  1.21.2.2  christos 		return nvmm_hva_map(owner, data);
   1146  1.21.2.2  christos 	case NVMM_IOC_HVA_UNMAP:
   1147  1.21.2.2  christos 		return nvmm_hva_unmap(owner, data);
   1148  1.21.2.2  christos 	case NVMM_IOC_CTL:
   1149  1.21.2.2  christos 		return nvmm_ctl(owner, data);
   1150  1.21.2.2  christos 	default:
   1151  1.21.2.2  christos 		return EINVAL;
   1152  1.21.2.2  christos 	}
   1153  1.21.2.2  christos }
   1154  1.21.2.2  christos 
   1155  1.21.2.2  christos /* -------------------------------------------------------------------------- */
   1156  1.21.2.2  christos 
   1157  1.21.2.2  christos void
   1158  1.21.2.2  christos nvmmattach(int nunits)
   1159  1.21.2.2  christos {
   1160  1.21.2.2  christos 	/* nothing */
   1161  1.21.2.2  christos }
   1162  1.21.2.2  christos 
   1163  1.21.2.2  christos MODULE(MODULE_CLASS_MISC, nvmm, NULL);
   1164  1.21.2.2  christos 
   1165  1.21.2.2  christos static int
   1166  1.21.2.2  christos nvmm_modcmd(modcmd_t cmd, void *arg)
   1167  1.21.2.2  christos {
   1168  1.21.2.2  christos 	int error;
   1169  1.21.2.2  christos 
   1170  1.21.2.2  christos 	switch (cmd) {
   1171  1.21.2.2  christos 	case MODULE_CMD_INIT:
   1172  1.21.2.2  christos 		error = nvmm_init();
   1173  1.21.2.2  christos 		if (error)
   1174  1.21.2.2  christos 			return error;
   1175  1.21.2.2  christos 
   1176  1.21.2.2  christos #if defined(_MODULE)
   1177  1.21.2.2  christos 		{
   1178  1.21.2.2  christos 			devmajor_t bmajor = NODEVMAJOR;
   1179  1.21.2.2  christos 			devmajor_t cmajor = 345;
   1180  1.21.2.2  christos 
   1181  1.21.2.2  christos 			/* mknod /dev/nvmm c 345 0 */
   1182  1.21.2.2  christos 			error = devsw_attach("nvmm", NULL, &bmajor,
   1183  1.21.2.2  christos 			    &nvmm_cdevsw, &cmajor);
   1184  1.21.2.2  christos 			if (error) {
   1185  1.21.2.2  christos 				nvmm_fini();
   1186  1.21.2.2  christos 				return error;
   1187  1.21.2.2  christos 			}
   1188  1.21.2.2  christos 		}
   1189  1.21.2.2  christos #endif
   1190  1.21.2.2  christos 		return 0;
   1191  1.21.2.2  christos 
   1192  1.21.2.2  christos 	case MODULE_CMD_FINI:
   1193  1.21.2.2  christos 		if (nmachines > 0) {
   1194  1.21.2.2  christos 			return EBUSY;
   1195  1.21.2.2  christos 		}
   1196  1.21.2.2  christos #if defined(_MODULE)
   1197  1.21.2.2  christos 		{
   1198  1.21.2.2  christos 			error = devsw_detach(NULL, &nvmm_cdevsw);
   1199  1.21.2.2  christos 			if (error) {
   1200  1.21.2.2  christos 				return error;
   1201  1.21.2.2  christos 			}
   1202  1.21.2.2  christos 		}
   1203  1.21.2.2  christos #endif
   1204  1.21.2.2  christos 		nvmm_fini();
   1205  1.21.2.2  christos 		return 0;
   1206  1.21.2.2  christos 
   1207  1.21.2.2  christos 	case MODULE_CMD_AUTOUNLOAD:
   1208  1.21.2.2  christos 		return EBUSY;
   1209  1.21.2.2  christos 
   1210  1.21.2.2  christos 	default:
   1211  1.21.2.2  christos 		return ENOTTY;
   1212  1.21.2.2  christos 	}
   1213  1.21.2.2  christos }
   1214