Home | History | Annotate | Line # | Download | only in nvmm
      1  1.47  riastrad /*	$NetBSD: nvmm.c,v 1.47 2022/09/13 20:10:04 riastradh Exp $	*/
      2   1.1      maxv 
      3   1.1      maxv /*
      4  1.39      maxv  * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
      5   1.1      maxv  * All rights reserved.
      6   1.1      maxv  *
      7  1.39      maxv  * This code is part of the NVMM hypervisor.
      8   1.1      maxv  *
      9   1.1      maxv  * Redistribution and use in source and binary forms, with or without
     10   1.1      maxv  * modification, are permitted provided that the following conditions
     11   1.1      maxv  * are met:
     12   1.1      maxv  * 1. Redistributions of source code must retain the above copyright
     13   1.1      maxv  *    notice, this list of conditions and the following disclaimer.
     14   1.1      maxv  * 2. Redistributions in binary form must reproduce the above copyright
     15   1.1      maxv  *    notice, this list of conditions and the following disclaimer in the
     16   1.1      maxv  *    documentation and/or other materials provided with the distribution.
     17   1.1      maxv  *
     18  1.39      maxv  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  1.39      maxv  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  1.39      maxv  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  1.39      maxv  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  1.39      maxv  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     23  1.39      maxv  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  1.39      maxv  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     25  1.39      maxv  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     26  1.39      maxv  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  1.39      maxv  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  1.39      maxv  * SUCH DAMAGE.
     29   1.1      maxv  */
     30   1.1      maxv 
     31   1.1      maxv #include <sys/cdefs.h>
     32  1.47  riastrad __KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.47 2022/09/13 20:10:04 riastradh Exp $");
     33   1.1      maxv 
     34   1.1      maxv #include <sys/param.h>
     35   1.1      maxv #include <sys/systm.h>
     36   1.1      maxv #include <sys/kernel.h>
     37   1.1      maxv 
     38  1.37      maxv #include <sys/atomic.h>
     39   1.1      maxv #include <sys/cpu.h>
     40   1.1      maxv #include <sys/conf.h>
     41   1.1      maxv #include <sys/kmem.h>
     42   1.1      maxv #include <sys/module.h>
     43   1.1      maxv #include <sys/proc.h>
     44  1.11      maxv #include <sys/mman.h>
     45  1.14      maxv #include <sys/file.h>
     46  1.14      maxv #include <sys/filedesc.h>
     47  1.31      maxv #include <sys/device.h>
     48   1.1      maxv 
     49  1.40  riastrad #include <uvm/uvm_aobj.h>
     50  1.40  riastrad #include <uvm/uvm_extern.h>
     51   1.1      maxv #include <uvm/uvm_page.h>
     52   1.1      maxv 
     53   1.1      maxv #include "ioconf.h"
     54   1.1      maxv 
     55   1.1      maxv #include <dev/nvmm/nvmm.h>
     56   1.1      maxv #include <dev/nvmm/nvmm_internal.h>
     57   1.1      maxv #include <dev/nvmm/nvmm_ioctl.h>
     58   1.1      maxv 
     59   1.1      maxv static struct nvmm_machine machines[NVMM_MAX_MACHINES];
     60  1.13      maxv static volatile unsigned int nmachines __cacheline_aligned;
     61   1.1      maxv 
     62  1.47  riastrad static struct {
     63  1.47  riastrad 	kmutex_t	lock;
     64  1.47  riastrad 	kcondvar_t	suspendcv;
     65  1.47  riastrad 	kcondvar_t	resumecv;
     66  1.47  riastrad 	unsigned	users;
     67  1.47  riastrad } suspension;
     68  1.47  riastrad 
     69  1.47  riastrad volatile bool nvmm_suspending;
     70  1.47  riastrad 
     71   1.1      maxv static const struct nvmm_impl *nvmm_impl_list[] = {
     72  1.33      maxv #if defined(__x86_64__)
     73   1.7      maxv 	&nvmm_x86_svm,	/* x86 AMD SVM */
     74   1.7      maxv 	&nvmm_x86_vmx	/* x86 Intel VMX */
     75  1.33      maxv #endif
     76   1.1      maxv };
     77   1.1      maxv 
     78  1.38      maxv static const struct nvmm_impl *nvmm_impl __read_mostly = NULL;
     79   1.1      maxv 
     80  1.17      maxv static struct nvmm_owner root_owner;
     81  1.17      maxv 
     82   1.1      maxv /* -------------------------------------------------------------------------- */
     83   1.1      maxv 
     84   1.1      maxv static int
     85  1.47  riastrad nvmm_enter_sig(void)
     86  1.47  riastrad {
     87  1.47  riastrad 	int error;
     88  1.47  riastrad 
     89  1.47  riastrad 	mutex_enter(&suspension.lock);
     90  1.47  riastrad 	while (nvmm_suspending) {
     91  1.47  riastrad 		error = cv_wait_sig(&suspension.resumecv, &suspension.lock);
     92  1.47  riastrad 		if (error)
     93  1.47  riastrad 			goto out;
     94  1.47  riastrad 	}
     95  1.47  riastrad 	KASSERT(suspension.users < UINT_MAX);
     96  1.47  riastrad 	suspension.users++;
     97  1.47  riastrad 	error = 0;
     98  1.47  riastrad out:	mutex_exit(&suspension.lock);
     99  1.47  riastrad 
    100  1.47  riastrad 	return 0;
    101  1.47  riastrad }
    102  1.47  riastrad 
    103  1.47  riastrad static void
    104  1.47  riastrad nvmm_enter(void)
    105  1.47  riastrad {
    106  1.47  riastrad 
    107  1.47  riastrad 	mutex_enter(&suspension.lock);
    108  1.47  riastrad 	while (nvmm_suspending)
    109  1.47  riastrad 		cv_wait(&suspension.resumecv, &suspension.lock);
    110  1.47  riastrad 	KASSERT(suspension.users < UINT_MAX);
    111  1.47  riastrad 	suspension.users++;
    112  1.47  riastrad 	mutex_exit(&suspension.lock);
    113  1.47  riastrad }
    114  1.47  riastrad 
    115  1.47  riastrad static void
    116  1.47  riastrad nvmm_exit(void)
    117  1.47  riastrad {
    118  1.47  riastrad 
    119  1.47  riastrad 	mutex_enter(&suspension.lock);
    120  1.47  riastrad 	KASSERT(suspension.users > 0);
    121  1.47  riastrad 	if (--suspension.users == 0)
    122  1.47  riastrad 		cv_signal(&suspension.suspendcv);
    123  1.47  riastrad 	mutex_exit(&suspension.lock);
    124  1.47  riastrad }
    125  1.47  riastrad 
    126  1.47  riastrad /* -------------------------------------------------------------------------- */
    127  1.47  riastrad 
    128  1.47  riastrad static int
    129   1.1      maxv nvmm_machine_alloc(struct nvmm_machine **ret)
    130   1.1      maxv {
    131   1.1      maxv 	struct nvmm_machine *mach;
    132   1.1      maxv 	size_t i;
    133   1.1      maxv 
    134   1.1      maxv 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
    135   1.1      maxv 		mach = &machines[i];
    136   1.1      maxv 
    137   1.1      maxv 		rw_enter(&mach->lock, RW_WRITER);
    138   1.1      maxv 		if (mach->present) {
    139   1.1      maxv 			rw_exit(&mach->lock);
    140   1.1      maxv 			continue;
    141   1.1      maxv 		}
    142   1.1      maxv 
    143   1.1      maxv 		mach->present = true;
    144  1.17      maxv 		mach->time = time_second;
    145   1.1      maxv 		*ret = mach;
    146  1.13      maxv 		atomic_inc_uint(&nmachines);
    147   1.1      maxv 		return 0;
    148   1.1      maxv 	}
    149   1.1      maxv 
    150   1.1      maxv 	return ENOBUFS;
    151   1.1      maxv }
    152   1.1      maxv 
    153   1.1      maxv static void
    154   1.1      maxv nvmm_machine_free(struct nvmm_machine *mach)
    155   1.1      maxv {
    156   1.1      maxv 	KASSERT(rw_write_held(&mach->lock));
    157   1.1      maxv 	KASSERT(mach->present);
    158   1.1      maxv 	mach->present = false;
    159  1.13      maxv 	atomic_dec_uint(&nmachines);
    160   1.1      maxv }
    161   1.1      maxv 
    162   1.1      maxv static int
    163  1.14      maxv nvmm_machine_get(struct nvmm_owner *owner, nvmm_machid_t machid,
    164  1.14      maxv     struct nvmm_machine **ret, bool writer)
    165   1.1      maxv {
    166   1.1      maxv 	struct nvmm_machine *mach;
    167   1.1      maxv 	krw_t op = writer ? RW_WRITER : RW_READER;
    168   1.1      maxv 
    169  1.36      maxv 	if (__predict_false(machid >= NVMM_MAX_MACHINES)) {
    170   1.1      maxv 		return EINVAL;
    171   1.1      maxv 	}
    172   1.1      maxv 	mach = &machines[machid];
    173   1.1      maxv 
    174   1.1      maxv 	rw_enter(&mach->lock, op);
    175  1.36      maxv 	if (__predict_false(!mach->present)) {
    176   1.1      maxv 		rw_exit(&mach->lock);
    177   1.1      maxv 		return ENOENT;
    178   1.1      maxv 	}
    179  1.36      maxv 	if (__predict_false(mach->owner != owner && owner != &root_owner)) {
    180   1.1      maxv 		rw_exit(&mach->lock);
    181   1.1      maxv 		return EPERM;
    182   1.1      maxv 	}
    183   1.1      maxv 	*ret = mach;
    184   1.1      maxv 
    185   1.1      maxv 	return 0;
    186   1.1      maxv }
    187   1.1      maxv 
    188   1.1      maxv static void
    189   1.1      maxv nvmm_machine_put(struct nvmm_machine *mach)
    190   1.1      maxv {
    191   1.1      maxv 	rw_exit(&mach->lock);
    192   1.1      maxv }
    193   1.1      maxv 
    194   1.1      maxv /* -------------------------------------------------------------------------- */
    195   1.1      maxv 
    196   1.1      maxv static int
    197  1.18      maxv nvmm_vcpu_alloc(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    198  1.18      maxv     struct nvmm_cpu **ret)
    199   1.1      maxv {
    200   1.1      maxv 	struct nvmm_cpu *vcpu;
    201   1.1      maxv 
    202  1.18      maxv 	if (cpuid >= NVMM_MAX_VCPUS) {
    203  1.18      maxv 		return EINVAL;
    204  1.18      maxv 	}
    205  1.18      maxv 	vcpu = &mach->cpus[cpuid];
    206   1.1      maxv 
    207  1.18      maxv 	mutex_enter(&vcpu->lock);
    208  1.18      maxv 	if (vcpu->present) {
    209  1.18      maxv 		mutex_exit(&vcpu->lock);
    210  1.18      maxv 		return EBUSY;
    211   1.1      maxv 	}
    212   1.1      maxv 
    213  1.18      maxv 	vcpu->present = true;
    214  1.19      maxv 	vcpu->comm = NULL;
    215  1.18      maxv 	vcpu->hcpu_last = -1;
    216  1.18      maxv 	*ret = vcpu;
    217  1.18      maxv 	return 0;
    218   1.1      maxv }
    219   1.1      maxv 
    220   1.1      maxv static void
    221   1.1      maxv nvmm_vcpu_free(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
    222   1.1      maxv {
    223   1.1      maxv 	KASSERT(mutex_owned(&vcpu->lock));
    224   1.1      maxv 	vcpu->present = false;
    225  1.19      maxv 	if (vcpu->comm != NULL) {
    226  1.19      maxv 		uvm_deallocate(kernel_map, (vaddr_t)vcpu->comm, PAGE_SIZE);
    227  1.19      maxv 	}
    228   1.1      maxv }
    229   1.1      maxv 
    230  1.22      maxv static int
    231   1.1      maxv nvmm_vcpu_get(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    232   1.1      maxv     struct nvmm_cpu **ret)
    233   1.1      maxv {
    234   1.1      maxv 	struct nvmm_cpu *vcpu;
    235   1.1      maxv 
    236  1.36      maxv 	if (__predict_false(cpuid >= NVMM_MAX_VCPUS)) {
    237   1.1      maxv 		return EINVAL;
    238   1.1      maxv 	}
    239   1.1      maxv 	vcpu = &mach->cpus[cpuid];
    240   1.1      maxv 
    241   1.1      maxv 	mutex_enter(&vcpu->lock);
    242  1.36      maxv 	if (__predict_false(!vcpu->present)) {
    243   1.1      maxv 		mutex_exit(&vcpu->lock);
    244   1.1      maxv 		return ENOENT;
    245   1.1      maxv 	}
    246   1.1      maxv 	*ret = vcpu;
    247   1.1      maxv 
    248   1.1      maxv 	return 0;
    249   1.1      maxv }
    250   1.1      maxv 
    251  1.22      maxv static void
    252   1.1      maxv nvmm_vcpu_put(struct nvmm_cpu *vcpu)
    253   1.1      maxv {
    254   1.1      maxv 	mutex_exit(&vcpu->lock);
    255   1.1      maxv }
    256   1.1      maxv 
    257   1.1      maxv /* -------------------------------------------------------------------------- */
    258   1.1      maxv 
    259   1.1      maxv static void
    260  1.14      maxv nvmm_kill_machines(struct nvmm_owner *owner)
    261   1.1      maxv {
    262   1.1      maxv 	struct nvmm_machine *mach;
    263   1.1      maxv 	struct nvmm_cpu *vcpu;
    264   1.1      maxv 	size_t i, j;
    265   1.1      maxv 	int error;
    266   1.1      maxv 
    267   1.1      maxv 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
    268   1.1      maxv 		mach = &machines[i];
    269   1.1      maxv 
    270   1.1      maxv 		rw_enter(&mach->lock, RW_WRITER);
    271  1.14      maxv 		if (!mach->present || mach->owner != owner) {
    272   1.1      maxv 			rw_exit(&mach->lock);
    273   1.1      maxv 			continue;
    274   1.1      maxv 		}
    275   1.1      maxv 
    276   1.1      maxv 		/* Kill it. */
    277   1.1      maxv 		for (j = 0; j < NVMM_MAX_VCPUS; j++) {
    278   1.1      maxv 			error = nvmm_vcpu_get(mach, j, &vcpu);
    279   1.1      maxv 			if (error)
    280   1.1      maxv 				continue;
    281   1.1      maxv 			(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    282   1.1      maxv 			nvmm_vcpu_free(mach, vcpu);
    283   1.1      maxv 			nvmm_vcpu_put(vcpu);
    284  1.36      maxv 			atomic_dec_uint(&mach->ncpus);
    285   1.1      maxv 		}
    286  1.15      maxv 		(*nvmm_impl->machine_destroy)(mach);
    287   1.1      maxv 		uvmspace_free(mach->vm);
    288   1.4      maxv 
    289   1.4      maxv 		/* Drop the kernel UOBJ refs. */
    290   1.9      maxv 		for (j = 0; j < NVMM_MAX_HMAPPINGS; j++) {
    291   1.9      maxv 			if (!mach->hmap[j].present)
    292   1.4      maxv 				continue;
    293   1.9      maxv 			uao_detach(mach->hmap[j].uobj);
    294   1.4      maxv 		}
    295   1.4      maxv 
    296   1.1      maxv 		nvmm_machine_free(mach);
    297   1.1      maxv 
    298   1.1      maxv 		rw_exit(&mach->lock);
    299   1.1      maxv 	}
    300   1.1      maxv }
    301   1.1      maxv 
    302   1.1      maxv /* -------------------------------------------------------------------------- */
    303   1.1      maxv 
    304   1.1      maxv static int
    305  1.14      maxv nvmm_capability(struct nvmm_owner *owner, struct nvmm_ioc_capability *args)
    306   1.1      maxv {
    307  1.23      maxv 	args->cap.version = NVMM_KERN_VERSION;
    308   1.1      maxv 	args->cap.state_size = nvmm_impl->state_size;
    309   1.1      maxv 	args->cap.max_machines = NVMM_MAX_MACHINES;
    310   1.1      maxv 	args->cap.max_vcpus = NVMM_MAX_VCPUS;
    311   1.1      maxv 	args->cap.max_ram = NVMM_MAX_RAM;
    312   1.1      maxv 
    313   1.1      maxv 	(*nvmm_impl->capability)(&args->cap);
    314   1.1      maxv 
    315   1.1      maxv 	return 0;
    316   1.1      maxv }
    317   1.1      maxv 
    318   1.1      maxv static int
    319  1.14      maxv nvmm_machine_create(struct nvmm_owner *owner,
    320  1.14      maxv     struct nvmm_ioc_machine_create *args)
    321   1.1      maxv {
    322   1.1      maxv 	struct nvmm_machine *mach;
    323   1.1      maxv 	int error;
    324   1.1      maxv 
    325   1.1      maxv 	error = nvmm_machine_alloc(&mach);
    326   1.1      maxv 	if (error)
    327   1.1      maxv 		return error;
    328   1.1      maxv 
    329   1.1      maxv 	/* Curproc owns the machine. */
    330  1.14      maxv 	mach->owner = owner;
    331   1.1      maxv 
    332   1.9      maxv 	/* Zero out the host mappings. */
    333   1.9      maxv 	memset(&mach->hmap, 0, sizeof(mach->hmap));
    334   1.4      maxv 
    335   1.1      maxv 	/* Create the machine vmspace. */
    336   1.1      maxv 	mach->gpa_begin = 0;
    337   1.1      maxv 	mach->gpa_end = NVMM_MAX_RAM;
    338   1.1      maxv 	mach->vm = uvmspace_alloc(0, mach->gpa_end - mach->gpa_begin, false);
    339   1.1      maxv 
    340  1.19      maxv 	/* Create the comm uobj. */
    341  1.19      maxv 	mach->commuobj = uao_create(NVMM_MAX_VCPUS * PAGE_SIZE, 0);
    342  1.19      maxv 
    343   1.1      maxv 	(*nvmm_impl->machine_create)(mach);
    344   1.1      maxv 
    345   1.1      maxv 	args->machid = mach->machid;
    346   1.1      maxv 	nvmm_machine_put(mach);
    347   1.1      maxv 
    348   1.1      maxv 	return 0;
    349   1.1      maxv }
    350   1.1      maxv 
    351   1.1      maxv static int
    352  1.14      maxv nvmm_machine_destroy(struct nvmm_owner *owner,
    353  1.14      maxv     struct nvmm_ioc_machine_destroy *args)
    354   1.1      maxv {
    355   1.1      maxv 	struct nvmm_machine *mach;
    356   1.1      maxv 	struct nvmm_cpu *vcpu;
    357   1.1      maxv 	int error;
    358   1.1      maxv 	size_t i;
    359   1.1      maxv 
    360  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    361   1.1      maxv 	if (error)
    362   1.1      maxv 		return error;
    363   1.1      maxv 
    364   1.1      maxv 	for (i = 0; i < NVMM_MAX_VCPUS; i++) {
    365   1.1      maxv 		error = nvmm_vcpu_get(mach, i, &vcpu);
    366   1.1      maxv 		if (error)
    367   1.1      maxv 			continue;
    368   1.1      maxv 
    369   1.1      maxv 		(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    370   1.1      maxv 		nvmm_vcpu_free(mach, vcpu);
    371   1.1      maxv 		nvmm_vcpu_put(vcpu);
    372  1.36      maxv 		atomic_dec_uint(&mach->ncpus);
    373   1.1      maxv 	}
    374   1.1      maxv 
    375   1.1      maxv 	(*nvmm_impl->machine_destroy)(mach);
    376   1.1      maxv 
    377   1.1      maxv 	/* Free the machine vmspace. */
    378   1.1      maxv 	uvmspace_free(mach->vm);
    379   1.4      maxv 
    380   1.4      maxv 	/* Drop the kernel UOBJ refs. */
    381   1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    382   1.9      maxv 		if (!mach->hmap[i].present)
    383   1.4      maxv 			continue;
    384   1.9      maxv 		uao_detach(mach->hmap[i].uobj);
    385   1.4      maxv 	}
    386   1.1      maxv 
    387   1.1      maxv 	nvmm_machine_free(mach);
    388   1.1      maxv 	nvmm_machine_put(mach);
    389   1.1      maxv 
    390   1.1      maxv 	return 0;
    391   1.1      maxv }
    392   1.1      maxv 
    393   1.1      maxv static int
    394  1.14      maxv nvmm_machine_configure(struct nvmm_owner *owner,
    395  1.14      maxv     struct nvmm_ioc_machine_configure *args)
    396   1.1      maxv {
    397   1.1      maxv 	struct nvmm_machine *mach;
    398   1.1      maxv 	size_t allocsz;
    399  1.21      maxv 	uint64_t op;
    400   1.1      maxv 	void *data;
    401   1.1      maxv 	int error;
    402   1.1      maxv 
    403  1.21      maxv 	op = NVMM_MACH_CONF_MD(args->op);
    404  1.23      maxv 	if (__predict_false(op >= nvmm_impl->mach_conf_max)) {
    405   1.1      maxv 		return EINVAL;
    406   1.1      maxv 	}
    407   1.1      maxv 
    408  1.23      maxv 	allocsz = nvmm_impl->mach_conf_sizes[op];
    409   1.1      maxv 	data = kmem_alloc(allocsz, KM_SLEEP);
    410   1.1      maxv 
    411  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    412   1.1      maxv 	if (error) {
    413   1.1      maxv 		kmem_free(data, allocsz);
    414   1.1      maxv 		return error;
    415   1.1      maxv 	}
    416   1.1      maxv 
    417   1.1      maxv 	error = copyin(args->conf, data, allocsz);
    418   1.1      maxv 	if (error) {
    419   1.1      maxv 		goto out;
    420   1.1      maxv 	}
    421   1.1      maxv 
    422  1.21      maxv 	error = (*nvmm_impl->machine_configure)(mach, op, data);
    423   1.1      maxv 
    424   1.1      maxv out:
    425   1.1      maxv 	nvmm_machine_put(mach);
    426   1.1      maxv 	kmem_free(data, allocsz);
    427   1.1      maxv 	return error;
    428   1.1      maxv }
    429   1.1      maxv 
    430   1.1      maxv static int
    431  1.14      maxv nvmm_vcpu_create(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_create *args)
    432   1.1      maxv {
    433   1.1      maxv 	struct nvmm_machine *mach;
    434   1.1      maxv 	struct nvmm_cpu *vcpu;
    435   1.1      maxv 	int error;
    436   1.1      maxv 
    437  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    438   1.1      maxv 	if (error)
    439   1.1      maxv 		return error;
    440   1.1      maxv 
    441  1.18      maxv 	error = nvmm_vcpu_alloc(mach, args->cpuid, &vcpu);
    442   1.1      maxv 	if (error)
    443   1.1      maxv 		goto out;
    444   1.1      maxv 
    445  1.19      maxv 	/* Allocate the comm page. */
    446  1.19      maxv 	uao_reference(mach->commuobj);
    447  1.19      maxv 	error = uvm_map(kernel_map, (vaddr_t *)&vcpu->comm, PAGE_SIZE,
    448  1.19      maxv 	    mach->commuobj, args->cpuid * PAGE_SIZE, 0, UVM_MAPFLAG(UVM_PROT_RW,
    449  1.19      maxv 	    UVM_PROT_RW, UVM_INH_SHARE, UVM_ADV_RANDOM, 0));
    450  1.19      maxv 	if (error) {
    451  1.19      maxv 		uao_detach(mach->commuobj);
    452  1.19      maxv 		nvmm_vcpu_free(mach, vcpu);
    453  1.19      maxv 		nvmm_vcpu_put(vcpu);
    454  1.19      maxv 		goto out;
    455  1.19      maxv 	}
    456  1.19      maxv 	error = uvm_map_pageable(kernel_map, (vaddr_t)vcpu->comm,
    457  1.19      maxv 	    (vaddr_t)vcpu->comm + PAGE_SIZE, false, 0);
    458  1.19      maxv 	if (error) {
    459  1.19      maxv 		nvmm_vcpu_free(mach, vcpu);
    460  1.19      maxv 		nvmm_vcpu_put(vcpu);
    461  1.19      maxv 		goto out;
    462  1.19      maxv 	}
    463  1.19      maxv 	memset(vcpu->comm, 0, PAGE_SIZE);
    464  1.19      maxv 
    465   1.1      maxv 	error = (*nvmm_impl->vcpu_create)(mach, vcpu);
    466   1.1      maxv 	if (error) {
    467   1.1      maxv 		nvmm_vcpu_free(mach, vcpu);
    468   1.1      maxv 		nvmm_vcpu_put(vcpu);
    469   1.1      maxv 		goto out;
    470   1.1      maxv 	}
    471   1.1      maxv 
    472   1.1      maxv 	nvmm_vcpu_put(vcpu);
    473  1.28      maxv 	atomic_inc_uint(&mach->ncpus);
    474  1.28      maxv 
    475   1.1      maxv out:
    476   1.1      maxv 	nvmm_machine_put(mach);
    477   1.1      maxv 	return error;
    478   1.1      maxv }
    479   1.1      maxv 
    480   1.1      maxv static int
    481  1.14      maxv nvmm_vcpu_destroy(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_destroy *args)
    482   1.1      maxv {
    483   1.1      maxv 	struct nvmm_machine *mach;
    484   1.1      maxv 	struct nvmm_cpu *vcpu;
    485   1.1      maxv 	int error;
    486   1.1      maxv 
    487  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    488   1.1      maxv 	if (error)
    489   1.1      maxv 		return error;
    490   1.1      maxv 
    491   1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    492   1.1      maxv 	if (error)
    493   1.1      maxv 		goto out;
    494   1.1      maxv 
    495   1.1      maxv 	(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    496   1.1      maxv 	nvmm_vcpu_free(mach, vcpu);
    497   1.1      maxv 	nvmm_vcpu_put(vcpu);
    498  1.28      maxv 	atomic_dec_uint(&mach->ncpus);
    499  1.28      maxv 
    500   1.1      maxv out:
    501   1.1      maxv 	nvmm_machine_put(mach);
    502   1.1      maxv 	return error;
    503   1.1      maxv }
    504   1.1      maxv 
    505   1.1      maxv static int
    506  1.23      maxv nvmm_vcpu_configure(struct nvmm_owner *owner,
    507  1.23      maxv     struct nvmm_ioc_vcpu_configure *args)
    508  1.23      maxv {
    509  1.23      maxv 	struct nvmm_machine *mach;
    510  1.23      maxv 	struct nvmm_cpu *vcpu;
    511  1.23      maxv 	size_t allocsz;
    512  1.23      maxv 	uint64_t op;
    513  1.23      maxv 	void *data;
    514  1.23      maxv 	int error;
    515  1.23      maxv 
    516  1.23      maxv 	op = NVMM_VCPU_CONF_MD(args->op);
    517  1.23      maxv 	if (__predict_false(op >= nvmm_impl->vcpu_conf_max))
    518  1.23      maxv 		return EINVAL;
    519  1.23      maxv 
    520  1.23      maxv 	allocsz = nvmm_impl->vcpu_conf_sizes[op];
    521  1.23      maxv 	data = kmem_alloc(allocsz, KM_SLEEP);
    522  1.23      maxv 
    523  1.23      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    524  1.23      maxv 	if (error) {
    525  1.23      maxv 		kmem_free(data, allocsz);
    526  1.23      maxv 		return error;
    527  1.23      maxv 	}
    528  1.23      maxv 
    529  1.23      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    530  1.23      maxv 	if (error) {
    531  1.23      maxv 		nvmm_machine_put(mach);
    532  1.23      maxv 		kmem_free(data, allocsz);
    533  1.23      maxv 		return error;
    534  1.23      maxv 	}
    535  1.23      maxv 
    536  1.23      maxv 	error = copyin(args->conf, data, allocsz);
    537  1.23      maxv 	if (error) {
    538  1.23      maxv 		goto out;
    539  1.23      maxv 	}
    540  1.23      maxv 
    541  1.23      maxv 	error = (*nvmm_impl->vcpu_configure)(vcpu, op, data);
    542  1.23      maxv 
    543  1.23      maxv out:
    544  1.23      maxv 	nvmm_vcpu_put(vcpu);
    545  1.23      maxv 	nvmm_machine_put(mach);
    546  1.23      maxv 	kmem_free(data, allocsz);
    547  1.23      maxv 	return error;
    548  1.23      maxv }
    549  1.23      maxv 
    550  1.23      maxv static int
    551  1.14      maxv nvmm_vcpu_setstate(struct nvmm_owner *owner,
    552  1.14      maxv     struct nvmm_ioc_vcpu_setstate *args)
    553   1.1      maxv {
    554   1.1      maxv 	struct nvmm_machine *mach;
    555   1.1      maxv 	struct nvmm_cpu *vcpu;
    556   1.1      maxv 	int error;
    557   1.1      maxv 
    558  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    559   1.6      maxv 	if (error)
    560   1.1      maxv 		return error;
    561   1.1      maxv 
    562   1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    563   1.1      maxv 	if (error)
    564   1.1      maxv 		goto out;
    565   1.1      maxv 
    566  1.19      maxv 	(*nvmm_impl->vcpu_setstate)(vcpu);
    567   1.1      maxv 	nvmm_vcpu_put(vcpu);
    568   1.1      maxv 
    569   1.1      maxv out:
    570   1.1      maxv 	nvmm_machine_put(mach);
    571   1.1      maxv 	return error;
    572   1.1      maxv }
    573   1.1      maxv 
    574   1.1      maxv static int
    575  1.14      maxv nvmm_vcpu_getstate(struct nvmm_owner *owner,
    576  1.14      maxv     struct nvmm_ioc_vcpu_getstate *args)
    577   1.1      maxv {
    578   1.1      maxv 	struct nvmm_machine *mach;
    579   1.1      maxv 	struct nvmm_cpu *vcpu;
    580   1.1      maxv 	int error;
    581   1.1      maxv 
    582  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    583   1.6      maxv 	if (error)
    584   1.1      maxv 		return error;
    585   1.1      maxv 
    586   1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    587   1.1      maxv 	if (error)
    588   1.1      maxv 		goto out;
    589   1.1      maxv 
    590  1.19      maxv 	(*nvmm_impl->vcpu_getstate)(vcpu);
    591   1.1      maxv 	nvmm_vcpu_put(vcpu);
    592   1.1      maxv 
    593   1.1      maxv out:
    594   1.1      maxv 	nvmm_machine_put(mach);
    595   1.1      maxv 	return error;
    596   1.1      maxv }
    597   1.1      maxv 
    598   1.1      maxv static int
    599  1.14      maxv nvmm_vcpu_inject(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_inject *args)
    600   1.1      maxv {
    601   1.1      maxv 	struct nvmm_machine *mach;
    602   1.1      maxv 	struct nvmm_cpu *vcpu;
    603   1.1      maxv 	int error;
    604   1.1      maxv 
    605  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    606   1.1      maxv 	if (error)
    607   1.1      maxv 		return error;
    608   1.1      maxv 
    609   1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    610   1.1      maxv 	if (error)
    611   1.1      maxv 		goto out;
    612   1.1      maxv 
    613  1.20      maxv 	error = (*nvmm_impl->vcpu_inject)(vcpu);
    614   1.1      maxv 	nvmm_vcpu_put(vcpu);
    615   1.1      maxv 
    616   1.1      maxv out:
    617   1.1      maxv 	nvmm_machine_put(mach);
    618   1.1      maxv 	return error;
    619   1.1      maxv }
    620   1.1      maxv 
    621  1.22      maxv static int
    622   1.8      maxv nvmm_do_vcpu_run(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
    623  1.23      maxv     struct nvmm_vcpu_exit *exit)
    624   1.8      maxv {
    625   1.8      maxv 	struct vmspace *vm = mach->vm;
    626  1.22      maxv 	int ret;
    627   1.8      maxv 
    628   1.8      maxv 	while (1) {
    629  1.30      maxv 		/* Got a signal? Or pending resched? Leave. */
    630  1.42   reinoud 		if (__predict_false(nvmm_return_needed(vcpu, exit))) {
    631  1.30      maxv 			return 0;
    632  1.30      maxv 		}
    633  1.30      maxv 
    634  1.30      maxv 		/* Run the VCPU. */
    635  1.22      maxv 		ret = (*nvmm_impl->vcpu_run)(mach, vcpu, exit);
    636  1.22      maxv 		if (__predict_false(ret != 0)) {
    637  1.22      maxv 			return ret;
    638  1.22      maxv 		}
    639   1.8      maxv 
    640  1.30      maxv 		/* Process nested page faults. */
    641  1.23      maxv 		if (__predict_true(exit->reason != NVMM_VCPU_EXIT_MEMORY)) {
    642   1.8      maxv 			break;
    643   1.8      maxv 		}
    644  1.10      maxv 		if (exit->u.mem.gpa >= mach->gpa_end) {
    645  1.10      maxv 			break;
    646  1.10      maxv 		}
    647  1.11      maxv 		if (uvm_fault(&vm->vm_map, exit->u.mem.gpa, exit->u.mem.prot)) {
    648   1.8      maxv 			break;
    649   1.8      maxv 		}
    650   1.8      maxv 	}
    651  1.22      maxv 
    652  1.22      maxv 	return 0;
    653   1.8      maxv }
    654   1.8      maxv 
    655   1.1      maxv static int
    656  1.14      maxv nvmm_vcpu_run(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_run *args)
    657   1.1      maxv {
    658   1.1      maxv 	struct nvmm_machine *mach;
    659  1.43       mrg 	struct nvmm_cpu *vcpu = NULL;
    660   1.1      maxv 	int error;
    661   1.1      maxv 
    662  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    663   1.1      maxv 	if (error)
    664   1.1      maxv 		return error;
    665   1.1      maxv 
    666   1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    667   1.1      maxv 	if (error)
    668   1.1      maxv 		goto out;
    669   1.1      maxv 
    670  1.22      maxv 	error = nvmm_do_vcpu_run(mach, vcpu, &args->exit);
    671   1.1      maxv 	nvmm_vcpu_put(vcpu);
    672   1.1      maxv 
    673   1.1      maxv out:
    674   1.1      maxv 	nvmm_machine_put(mach);
    675  1.43       mrg 	if (vcpu)
    676  1.43       mrg 		vcpu->comm->stop = 0;
    677   1.1      maxv 	return error;
    678   1.1      maxv }
    679   1.1      maxv 
    680   1.1      maxv /* -------------------------------------------------------------------------- */
    681   1.1      maxv 
    682   1.4      maxv static struct uvm_object *
    683   1.9      maxv nvmm_hmapping_getuobj(struct nvmm_machine *mach, uintptr_t hva, size_t size,
    684   1.4      maxv    size_t *off)
    685   1.4      maxv {
    686   1.9      maxv 	struct nvmm_hmapping *hmapping;
    687   1.4      maxv 	size_t i;
    688   1.4      maxv 
    689   1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    690   1.9      maxv 		hmapping = &mach->hmap[i];
    691   1.9      maxv 		if (!hmapping->present) {
    692   1.4      maxv 			continue;
    693   1.4      maxv 		}
    694   1.9      maxv 		if (hva >= hmapping->hva &&
    695   1.9      maxv 		    hva + size <= hmapping->hva + hmapping->size) {
    696   1.9      maxv 			*off = hva - hmapping->hva;
    697   1.9      maxv 			return hmapping->uobj;
    698   1.4      maxv 		}
    699   1.4      maxv 	}
    700   1.4      maxv 
    701   1.4      maxv 	return NULL;
    702   1.4      maxv }
    703   1.4      maxv 
    704   1.4      maxv static int
    705   1.9      maxv nvmm_hmapping_validate(struct nvmm_machine *mach, uintptr_t hva, size_t size)
    706   1.4      maxv {
    707   1.9      maxv 	struct nvmm_hmapping *hmapping;
    708   1.4      maxv 	size_t i;
    709   1.4      maxv 
    710   1.4      maxv 	if ((hva % PAGE_SIZE) != 0 || (size % PAGE_SIZE) != 0) {
    711   1.4      maxv 		return EINVAL;
    712   1.4      maxv 	}
    713   1.4      maxv 	if (hva == 0) {
    714   1.4      maxv 		return EINVAL;
    715   1.4      maxv 	}
    716   1.4      maxv 
    717   1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    718   1.9      maxv 		hmapping = &mach->hmap[i];
    719   1.9      maxv 		if (!hmapping->present) {
    720   1.4      maxv 			continue;
    721   1.4      maxv 		}
    722   1.4      maxv 
    723   1.9      maxv 		if (hva >= hmapping->hva &&
    724   1.9      maxv 		    hva + size <= hmapping->hva + hmapping->size) {
    725   1.4      maxv 			break;
    726   1.4      maxv 		}
    727   1.4      maxv 
    728   1.9      maxv 		if (hva >= hmapping->hva &&
    729   1.9      maxv 		    hva < hmapping->hva + hmapping->size) {
    730   1.4      maxv 			return EEXIST;
    731   1.4      maxv 		}
    732   1.9      maxv 		if (hva + size > hmapping->hva &&
    733   1.9      maxv 		    hva + size <= hmapping->hva + hmapping->size) {
    734   1.4      maxv 			return EEXIST;
    735   1.4      maxv 		}
    736   1.9      maxv 		if (hva <= hmapping->hva &&
    737   1.9      maxv 		    hva + size >= hmapping->hva + hmapping->size) {
    738   1.4      maxv 			return EEXIST;
    739   1.4      maxv 		}
    740   1.4      maxv 	}
    741   1.4      maxv 
    742   1.4      maxv 	return 0;
    743   1.4      maxv }
    744   1.4      maxv 
    745   1.9      maxv static struct nvmm_hmapping *
    746   1.9      maxv nvmm_hmapping_alloc(struct nvmm_machine *mach)
    747   1.4      maxv {
    748   1.9      maxv 	struct nvmm_hmapping *hmapping;
    749   1.4      maxv 	size_t i;
    750   1.4      maxv 
    751   1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    752   1.9      maxv 		hmapping = &mach->hmap[i];
    753   1.9      maxv 		if (!hmapping->present) {
    754   1.9      maxv 			hmapping->present = true;
    755   1.9      maxv 			return hmapping;
    756   1.4      maxv 		}
    757   1.4      maxv 	}
    758   1.4      maxv 
    759   1.4      maxv 	return NULL;
    760   1.4      maxv }
    761   1.4      maxv 
    762   1.9      maxv static int
    763   1.9      maxv nvmm_hmapping_free(struct nvmm_machine *mach, uintptr_t hva, size_t size)
    764   1.4      maxv {
    765   1.4      maxv 	struct vmspace *vmspace = curproc->p_vmspace;
    766   1.9      maxv 	struct nvmm_hmapping *hmapping;
    767   1.9      maxv 	size_t i;
    768   1.4      maxv 
    769   1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    770   1.9      maxv 		hmapping = &mach->hmap[i];
    771   1.9      maxv 		if (!hmapping->present || hmapping->hva != hva ||
    772   1.9      maxv 		    hmapping->size != size) {
    773   1.9      maxv 			continue;
    774   1.9      maxv 		}
    775   1.9      maxv 
    776   1.9      maxv 		uvm_unmap(&vmspace->vm_map, hmapping->hva,
    777   1.9      maxv 		    hmapping->hva + hmapping->size);
    778   1.9      maxv 		uao_detach(hmapping->uobj);
    779   1.4      maxv 
    780   1.9      maxv 		hmapping->uobj = NULL;
    781   1.9      maxv 		hmapping->present = false;
    782   1.9      maxv 
    783   1.9      maxv 		return 0;
    784   1.9      maxv 	}
    785   1.9      maxv 
    786   1.9      maxv 	return ENOENT;
    787   1.4      maxv }
    788   1.4      maxv 
    789   1.4      maxv static int
    790  1.14      maxv nvmm_hva_map(struct nvmm_owner *owner, struct nvmm_ioc_hva_map *args)
    791   1.4      maxv {
    792   1.4      maxv 	struct vmspace *vmspace = curproc->p_vmspace;
    793   1.4      maxv 	struct nvmm_machine *mach;
    794   1.9      maxv 	struct nvmm_hmapping *hmapping;
    795   1.4      maxv 	vaddr_t uva;
    796   1.4      maxv 	int error;
    797   1.4      maxv 
    798  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    799   1.4      maxv 	if (error)
    800   1.4      maxv 		return error;
    801   1.4      maxv 
    802   1.9      maxv 	error = nvmm_hmapping_validate(mach, args->hva, args->size);
    803   1.4      maxv 	if (error)
    804   1.4      maxv 		goto out;
    805   1.4      maxv 
    806   1.9      maxv 	hmapping = nvmm_hmapping_alloc(mach);
    807   1.9      maxv 	if (hmapping == NULL) {
    808   1.4      maxv 		error = ENOBUFS;
    809   1.4      maxv 		goto out;
    810   1.4      maxv 	}
    811   1.4      maxv 
    812   1.9      maxv 	hmapping->hva = args->hva;
    813   1.9      maxv 	hmapping->size = args->size;
    814   1.9      maxv 	hmapping->uobj = uao_create(hmapping->size, 0);
    815   1.9      maxv 	uva = hmapping->hva;
    816   1.4      maxv 
    817   1.4      maxv 	/* Take a reference for the user. */
    818   1.9      maxv 	uao_reference(hmapping->uobj);
    819   1.4      maxv 
    820   1.4      maxv 	/* Map the uobj into the user address space, as pageable. */
    821   1.9      maxv 	error = uvm_map(&vmspace->vm_map, &uva, hmapping->size, hmapping->uobj,
    822   1.9      maxv 	    0, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_SHARE,
    823   1.4      maxv 	    UVM_ADV_RANDOM, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
    824   1.4      maxv 	if (error) {
    825   1.9      maxv 		uao_detach(hmapping->uobj);
    826   1.4      maxv 	}
    827   1.4      maxv 
    828   1.4      maxv out:
    829   1.4      maxv 	nvmm_machine_put(mach);
    830   1.4      maxv 	return error;
    831   1.4      maxv }
    832   1.4      maxv 
    833   1.4      maxv static int
    834  1.14      maxv nvmm_hva_unmap(struct nvmm_owner *owner, struct nvmm_ioc_hva_unmap *args)
    835   1.4      maxv {
    836   1.4      maxv 	struct nvmm_machine *mach;
    837   1.4      maxv 	int error;
    838   1.4      maxv 
    839  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    840   1.4      maxv 	if (error)
    841   1.4      maxv 		return error;
    842   1.4      maxv 
    843   1.9      maxv 	error = nvmm_hmapping_free(mach, args->hva, args->size);
    844   1.4      maxv 
    845   1.4      maxv 	nvmm_machine_put(mach);
    846   1.9      maxv 	return error;
    847   1.4      maxv }
    848   1.4      maxv 
    849   1.4      maxv /* -------------------------------------------------------------------------- */
    850   1.4      maxv 
    851   1.1      maxv static int
    852  1.14      maxv nvmm_gpa_map(struct nvmm_owner *owner, struct nvmm_ioc_gpa_map *args)
    853   1.1      maxv {
    854   1.1      maxv 	struct nvmm_machine *mach;
    855   1.4      maxv 	struct uvm_object *uobj;
    856   1.1      maxv 	gpaddr_t gpa;
    857   1.4      maxv 	size_t off;
    858   1.1      maxv 	int error;
    859   1.1      maxv 
    860  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    861   1.1      maxv 	if (error)
    862   1.1      maxv 		return error;
    863   1.1      maxv 
    864  1.11      maxv 	if ((args->prot & ~(PROT_READ|PROT_WRITE|PROT_EXEC)) != 0) {
    865  1.11      maxv 		error = EINVAL;
    866  1.11      maxv 		goto out;
    867  1.11      maxv 	}
    868  1.11      maxv 
    869   1.1      maxv 	if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0 ||
    870   1.1      maxv 	    (args->hva % PAGE_SIZE) != 0) {
    871   1.1      maxv 		error = EINVAL;
    872   1.1      maxv 		goto out;
    873   1.1      maxv 	}
    874   1.1      maxv 	if (args->hva == 0) {
    875   1.1      maxv 		error = EINVAL;
    876   1.1      maxv 		goto out;
    877   1.1      maxv 	}
    878   1.1      maxv 	if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
    879   1.1      maxv 		error = EINVAL;
    880   1.1      maxv 		goto out;
    881   1.1      maxv 	}
    882   1.1      maxv 	if (args->gpa + args->size <= args->gpa) {
    883   1.1      maxv 		error = EINVAL;
    884   1.1      maxv 		goto out;
    885   1.1      maxv 	}
    886   1.3      maxv 	if (args->gpa + args->size > mach->gpa_end) {
    887   1.1      maxv 		error = EINVAL;
    888   1.1      maxv 		goto out;
    889   1.1      maxv 	}
    890   1.1      maxv 	gpa = args->gpa;
    891   1.1      maxv 
    892   1.9      maxv 	uobj = nvmm_hmapping_getuobj(mach, args->hva, args->size, &off);
    893   1.4      maxv 	if (uobj == NULL) {
    894   1.4      maxv 		error = EINVAL;
    895   1.4      maxv 		goto out;
    896   1.4      maxv 	}
    897   1.4      maxv 
    898   1.4      maxv 	/* Take a reference for the machine. */
    899   1.4      maxv 	uao_reference(uobj);
    900   1.1      maxv 
    901   1.1      maxv 	/* Map the uobj into the machine address space, as pageable. */
    902   1.4      maxv 	error = uvm_map(&mach->vm->vm_map, &gpa, args->size, uobj, off, 0,
    903  1.11      maxv 	    UVM_MAPFLAG(args->prot, UVM_PROT_RWX, UVM_INH_NONE,
    904   1.4      maxv 	    UVM_ADV_RANDOM, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
    905   1.1      maxv 	if (error) {
    906   1.4      maxv 		uao_detach(uobj);
    907   1.1      maxv 		goto out;
    908   1.1      maxv 	}
    909   1.1      maxv 	if (gpa != args->gpa) {
    910   1.4      maxv 		uao_detach(uobj);
    911   1.1      maxv 		printf("[!] uvm_map problem\n");
    912   1.1      maxv 		error = EINVAL;
    913   1.1      maxv 		goto out;
    914   1.1      maxv 	}
    915   1.1      maxv 
    916   1.1      maxv out:
    917   1.1      maxv 	nvmm_machine_put(mach);
    918   1.1      maxv 	return error;
    919   1.1      maxv }
    920   1.1      maxv 
    921   1.1      maxv static int
    922  1.14      maxv nvmm_gpa_unmap(struct nvmm_owner *owner, struct nvmm_ioc_gpa_unmap *args)
    923   1.1      maxv {
    924   1.1      maxv 	struct nvmm_machine *mach;
    925   1.1      maxv 	gpaddr_t gpa;
    926   1.1      maxv 	int error;
    927   1.1      maxv 
    928  1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    929   1.1      maxv 	if (error)
    930   1.1      maxv 		return error;
    931   1.1      maxv 
    932   1.1      maxv 	if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0) {
    933   1.1      maxv 		error = EINVAL;
    934   1.1      maxv 		goto out;
    935   1.1      maxv 	}
    936   1.1      maxv 	if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
    937   1.1      maxv 		error = EINVAL;
    938   1.1      maxv 		goto out;
    939   1.1      maxv 	}
    940   1.1      maxv 	if (args->gpa + args->size <= args->gpa) {
    941   1.1      maxv 		error = EINVAL;
    942   1.1      maxv 		goto out;
    943   1.1      maxv 	}
    944   1.1      maxv 	if (args->gpa + args->size >= mach->gpa_end) {
    945   1.1      maxv 		error = EINVAL;
    946   1.1      maxv 		goto out;
    947   1.1      maxv 	}
    948   1.1      maxv 	gpa = args->gpa;
    949   1.1      maxv 
    950   1.1      maxv 	/* Unmap the memory from the machine. */
    951   1.1      maxv 	uvm_unmap(&mach->vm->vm_map, gpa, gpa + args->size);
    952   1.1      maxv 
    953   1.1      maxv out:
    954   1.1      maxv 	nvmm_machine_put(mach);
    955   1.1      maxv 	return error;
    956   1.1      maxv }
    957   1.1      maxv 
    958   1.1      maxv /* -------------------------------------------------------------------------- */
    959   1.1      maxv 
    960   1.1      maxv static int
    961  1.24      maxv nvmm_ctl_mach_info(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args)
    962  1.17      maxv {
    963  1.17      maxv 	struct nvmm_ctl_mach_info ctl;
    964  1.17      maxv 	struct nvmm_machine *mach;
    965  1.17      maxv 	int error;
    966  1.17      maxv 	size_t i;
    967  1.17      maxv 
    968  1.17      maxv 	if (args->size != sizeof(ctl))
    969  1.17      maxv 		return EINVAL;
    970  1.17      maxv 	error = copyin(args->data, &ctl, sizeof(ctl));
    971  1.17      maxv 	if (error)
    972  1.17      maxv 		return error;
    973  1.17      maxv 
    974  1.24      maxv 	error = nvmm_machine_get(owner, ctl.machid, &mach, true);
    975  1.17      maxv 	if (error)
    976  1.17      maxv 		return error;
    977  1.17      maxv 
    978  1.36      maxv 	ctl.nvcpus = mach->ncpus;
    979  1.25      maxv 
    980  1.25      maxv 	ctl.nram = 0;
    981  1.25      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    982  1.25      maxv 		if (!mach->hmap[i].present)
    983  1.25      maxv 			continue;
    984  1.25      maxv 		ctl.nram += mach->hmap[i].size;
    985  1.25      maxv 	}
    986  1.25      maxv 
    987  1.17      maxv 	ctl.pid = mach->owner->pid;
    988  1.17      maxv 	ctl.time = mach->time;
    989  1.17      maxv 
    990  1.17      maxv 	nvmm_machine_put(mach);
    991  1.17      maxv 
    992  1.17      maxv 	error = copyout(&ctl, args->data, sizeof(ctl));
    993  1.17      maxv 	if (error)
    994  1.17      maxv 		return error;
    995  1.17      maxv 
    996  1.17      maxv 	return 0;
    997  1.17      maxv }
    998  1.17      maxv 
    999  1.17      maxv static int
   1000  1.17      maxv nvmm_ctl(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args)
   1001  1.17      maxv {
   1002  1.17      maxv 	switch (args->op) {
   1003  1.17      maxv 	case NVMM_CTL_MACH_INFO:
   1004  1.24      maxv 		return nvmm_ctl_mach_info(owner, args);
   1005  1.17      maxv 	default:
   1006  1.17      maxv 		return EINVAL;
   1007  1.17      maxv 	}
   1008  1.17      maxv }
   1009  1.17      maxv 
   1010  1.17      maxv /* -------------------------------------------------------------------------- */
   1011  1.17      maxv 
   1012  1.31      maxv static const struct nvmm_impl *
   1013  1.31      maxv nvmm_ident(void)
   1014  1.31      maxv {
   1015  1.31      maxv 	size_t i;
   1016  1.31      maxv 
   1017  1.31      maxv 	for (i = 0; i < __arraycount(nvmm_impl_list); i++) {
   1018  1.31      maxv 		if ((*nvmm_impl_list[i]->ident)())
   1019  1.31      maxv 			return nvmm_impl_list[i];
   1020  1.31      maxv 	}
   1021  1.31      maxv 
   1022  1.31      maxv 	return NULL;
   1023  1.31      maxv }
   1024  1.31      maxv 
   1025  1.17      maxv static int
   1026   1.1      maxv nvmm_init(void)
   1027   1.1      maxv {
   1028   1.1      maxv 	size_t i, n;
   1029   1.1      maxv 
   1030  1.31      maxv 	nvmm_impl = nvmm_ident();
   1031  1.31      maxv 	if (nvmm_impl == NULL)
   1032   1.1      maxv 		return ENOTSUP;
   1033   1.1      maxv 
   1034   1.1      maxv 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
   1035   1.1      maxv 		machines[i].machid = i;
   1036   1.1      maxv 		rw_init(&machines[i].lock);
   1037   1.1      maxv 		for (n = 0; n < NVMM_MAX_VCPUS; n++) {
   1038  1.18      maxv 			machines[i].cpus[n].present = false;
   1039  1.18      maxv 			machines[i].cpus[n].cpuid = n;
   1040   1.1      maxv 			mutex_init(&machines[i].cpus[n].lock, MUTEX_DEFAULT,
   1041   1.1      maxv 			    IPL_NONE);
   1042   1.1      maxv 		}
   1043   1.1      maxv 	}
   1044   1.1      maxv 
   1045  1.47  riastrad 	mutex_init(&suspension.lock, MUTEX_DEFAULT, IPL_NONE);
   1046  1.47  riastrad 	cv_init(&suspension.suspendcv, "nvmmsus");
   1047  1.47  riastrad 	cv_init(&suspension.resumecv, "nvmmres");
   1048  1.47  riastrad 	suspension.users = 0;
   1049  1.47  riastrad 
   1050   1.1      maxv 	(*nvmm_impl->init)();
   1051   1.1      maxv 
   1052   1.1      maxv 	return 0;
   1053   1.1      maxv }
   1054   1.1      maxv 
   1055   1.1      maxv static void
   1056   1.1      maxv nvmm_fini(void)
   1057   1.1      maxv {
   1058   1.1      maxv 	size_t i, n;
   1059   1.1      maxv 
   1060   1.1      maxv 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
   1061   1.1      maxv 		rw_destroy(&machines[i].lock);
   1062   1.1      maxv 		for (n = 0; n < NVMM_MAX_VCPUS; n++) {
   1063   1.1      maxv 			mutex_destroy(&machines[i].cpus[n].lock);
   1064   1.1      maxv 		}
   1065   1.1      maxv 	}
   1066   1.1      maxv 
   1067   1.1      maxv 	(*nvmm_impl->fini)();
   1068  1.29      maxv 	nvmm_impl = NULL;
   1069   1.1      maxv }
   1070   1.1      maxv 
   1071   1.1      maxv /* -------------------------------------------------------------------------- */
   1072   1.1      maxv 
   1073  1.14      maxv static dev_type_open(nvmm_open);
   1074  1.14      maxv 
   1075  1.14      maxv const struct cdevsw nvmm_cdevsw = {
   1076  1.14      maxv 	.d_open = nvmm_open,
   1077  1.14      maxv 	.d_close = noclose,
   1078  1.14      maxv 	.d_read = noread,
   1079  1.14      maxv 	.d_write = nowrite,
   1080  1.14      maxv 	.d_ioctl = noioctl,
   1081  1.14      maxv 	.d_stop = nostop,
   1082  1.14      maxv 	.d_tty = notty,
   1083  1.14      maxv 	.d_poll = nopoll,
   1084  1.14      maxv 	.d_mmap = nommap,
   1085  1.14      maxv 	.d_kqfilter = nokqfilter,
   1086  1.14      maxv 	.d_discard = nodiscard,
   1087  1.14      maxv 	.d_flag = D_OTHER | D_MPSAFE
   1088  1.14      maxv };
   1089  1.14      maxv 
   1090  1.14      maxv static int nvmm_ioctl(file_t *, u_long, void *);
   1091  1.14      maxv static int nvmm_close(file_t *);
   1092  1.19      maxv static int nvmm_mmap(file_t *, off_t *, size_t, int, int *, int *,
   1093  1.19      maxv     struct uvm_object **, int *);
   1094  1.14      maxv 
   1095  1.34      maxv static const struct fileops nvmm_fileops = {
   1096  1.14      maxv 	.fo_read = fbadop_read,
   1097  1.14      maxv 	.fo_write = fbadop_write,
   1098  1.14      maxv 	.fo_ioctl = nvmm_ioctl,
   1099  1.14      maxv 	.fo_fcntl = fnullop_fcntl,
   1100  1.14      maxv 	.fo_poll = fnullop_poll,
   1101  1.14      maxv 	.fo_stat = fbadop_stat,
   1102  1.14      maxv 	.fo_close = nvmm_close,
   1103  1.14      maxv 	.fo_kqfilter = fnullop_kqfilter,
   1104  1.14      maxv 	.fo_restart = fnullop_restart,
   1105  1.19      maxv 	.fo_mmap = nvmm_mmap,
   1106  1.14      maxv };
   1107  1.14      maxv 
   1108   1.1      maxv static int
   1109   1.1      maxv nvmm_open(dev_t dev, int flags, int type, struct lwp *l)
   1110   1.1      maxv {
   1111  1.14      maxv 	struct nvmm_owner *owner;
   1112  1.14      maxv 	struct file *fp;
   1113  1.14      maxv 	int error, fd;
   1114  1.14      maxv 
   1115  1.26      maxv 	if (__predict_false(nvmm_impl == NULL))
   1116  1.26      maxv 		return ENXIO;
   1117  1.14      maxv 	if (minor(dev) != 0)
   1118   1.1      maxv 		return EXDEV;
   1119  1.23      maxv 	if (!(flags & O_CLOEXEC))
   1120  1.23      maxv 		return EINVAL;
   1121  1.14      maxv 	error = fd_allocfile(&fp, &fd);
   1122  1.14      maxv 	if (error)
   1123  1.14      maxv 		return error;
   1124  1.14      maxv 
   1125  1.24      maxv 	if (OFLAGS(flags) & O_WRONLY) {
   1126  1.24      maxv 		owner = &root_owner;
   1127  1.24      maxv 	} else {
   1128  1.24      maxv 		owner = kmem_alloc(sizeof(*owner), KM_SLEEP);
   1129  1.24      maxv 		owner->pid = l->l_proc->p_pid;
   1130  1.24      maxv 	}
   1131   1.1      maxv 
   1132  1.14      maxv 	return fd_clone(fp, fd, flags, &nvmm_fileops, owner);
   1133   1.1      maxv }
   1134   1.1      maxv 
   1135   1.1      maxv static int
   1136  1.14      maxv nvmm_close(file_t *fp)
   1137   1.1      maxv {
   1138  1.14      maxv 	struct nvmm_owner *owner = fp->f_data;
   1139   1.1      maxv 
   1140  1.14      maxv 	KASSERT(owner != NULL);
   1141  1.47  riastrad 
   1142  1.47  riastrad 	nvmm_enter();
   1143  1.14      maxv 	nvmm_kill_machines(owner);
   1144  1.47  riastrad 	nvmm_exit();
   1145  1.47  riastrad 
   1146  1.24      maxv 	if (owner != &root_owner) {
   1147  1.24      maxv 		kmem_free(owner, sizeof(*owner));
   1148  1.24      maxv 	}
   1149  1.14      maxv 	fp->f_data = NULL;
   1150   1.1      maxv 
   1151  1.41      maxv 	return 0;
   1152   1.1      maxv }
   1153   1.1      maxv 
   1154   1.1      maxv static int
   1155  1.19      maxv nvmm_mmap(file_t *fp, off_t *offp, size_t size, int prot, int *flagsp,
   1156  1.19      maxv     int *advicep, struct uvm_object **uobjp, int *maxprotp)
   1157  1.19      maxv {
   1158  1.19      maxv 	struct nvmm_owner *owner = fp->f_data;
   1159  1.19      maxv 	struct nvmm_machine *mach;
   1160  1.19      maxv 	nvmm_machid_t machid;
   1161  1.19      maxv 	nvmm_cpuid_t cpuid;
   1162  1.19      maxv 	int error;
   1163  1.19      maxv 
   1164  1.45  riastrad 	KASSERT(size > 0);
   1165  1.44  riastrad 
   1166  1.19      maxv 	if (prot & PROT_EXEC)
   1167  1.19      maxv 		return EACCES;
   1168  1.19      maxv 	if (size != PAGE_SIZE)
   1169  1.19      maxv 		return EINVAL;
   1170  1.19      maxv 
   1171  1.19      maxv 	cpuid = NVMM_COMM_CPUID(*offp);
   1172  1.19      maxv 	if (__predict_false(cpuid >= NVMM_MAX_VCPUS))
   1173  1.19      maxv 		return EINVAL;
   1174  1.19      maxv 
   1175  1.19      maxv 	machid = NVMM_COMM_MACHID(*offp);
   1176  1.19      maxv 	error = nvmm_machine_get(owner, machid, &mach, false);
   1177  1.19      maxv 	if (error)
   1178  1.19      maxv 		return error;
   1179  1.19      maxv 
   1180  1.19      maxv 	uao_reference(mach->commuobj);
   1181  1.19      maxv 	*uobjp = mach->commuobj;
   1182  1.19      maxv 	*offp = cpuid * PAGE_SIZE;
   1183  1.19      maxv 	*maxprotp = prot;
   1184  1.19      maxv 	*advicep = UVM_ADV_RANDOM;
   1185  1.19      maxv 
   1186  1.19      maxv 	nvmm_machine_put(mach);
   1187  1.19      maxv 	return 0;
   1188  1.19      maxv }
   1189  1.19      maxv 
   1190  1.19      maxv static int
   1191  1.47  riastrad nvmm_ioctl_internal(file_t *fp, u_long cmd, void *data)
   1192   1.1      maxv {
   1193  1.14      maxv 	struct nvmm_owner *owner = fp->f_data;
   1194  1.14      maxv 
   1195  1.14      maxv 	KASSERT(owner != NULL);
   1196   1.1      maxv 
   1197   1.1      maxv 	switch (cmd) {
   1198   1.1      maxv 	case NVMM_IOC_CAPABILITY:
   1199  1.14      maxv 		return nvmm_capability(owner, data);
   1200   1.1      maxv 	case NVMM_IOC_MACHINE_CREATE:
   1201  1.14      maxv 		return nvmm_machine_create(owner, data);
   1202   1.1      maxv 	case NVMM_IOC_MACHINE_DESTROY:
   1203  1.14      maxv 		return nvmm_machine_destroy(owner, data);
   1204   1.1      maxv 	case NVMM_IOC_MACHINE_CONFIGURE:
   1205  1.14      maxv 		return nvmm_machine_configure(owner, data);
   1206   1.1      maxv 	case NVMM_IOC_VCPU_CREATE:
   1207  1.14      maxv 		return nvmm_vcpu_create(owner, data);
   1208   1.1      maxv 	case NVMM_IOC_VCPU_DESTROY:
   1209  1.14      maxv 		return nvmm_vcpu_destroy(owner, data);
   1210  1.23      maxv 	case NVMM_IOC_VCPU_CONFIGURE:
   1211  1.23      maxv 		return nvmm_vcpu_configure(owner, data);
   1212   1.1      maxv 	case NVMM_IOC_VCPU_SETSTATE:
   1213  1.14      maxv 		return nvmm_vcpu_setstate(owner, data);
   1214   1.1      maxv 	case NVMM_IOC_VCPU_GETSTATE:
   1215  1.14      maxv 		return nvmm_vcpu_getstate(owner, data);
   1216   1.1      maxv 	case NVMM_IOC_VCPU_INJECT:
   1217  1.14      maxv 		return nvmm_vcpu_inject(owner, data);
   1218   1.1      maxv 	case NVMM_IOC_VCPU_RUN:
   1219  1.14      maxv 		return nvmm_vcpu_run(owner, data);
   1220   1.1      maxv 	case NVMM_IOC_GPA_MAP:
   1221  1.14      maxv 		return nvmm_gpa_map(owner, data);
   1222   1.1      maxv 	case NVMM_IOC_GPA_UNMAP:
   1223  1.14      maxv 		return nvmm_gpa_unmap(owner, data);
   1224   1.4      maxv 	case NVMM_IOC_HVA_MAP:
   1225  1.14      maxv 		return nvmm_hva_map(owner, data);
   1226   1.4      maxv 	case NVMM_IOC_HVA_UNMAP:
   1227  1.14      maxv 		return nvmm_hva_unmap(owner, data);
   1228  1.17      maxv 	case NVMM_IOC_CTL:
   1229  1.17      maxv 		return nvmm_ctl(owner, data);
   1230   1.1      maxv 	default:
   1231   1.1      maxv 		return EINVAL;
   1232   1.1      maxv 	}
   1233   1.1      maxv }
   1234   1.1      maxv 
   1235  1.47  riastrad static int
   1236  1.47  riastrad nvmm_ioctl(struct file *fp, u_long cmd, void *data)
   1237  1.47  riastrad {
   1238  1.47  riastrad 	int error;
   1239  1.47  riastrad 
   1240  1.47  riastrad 	error = nvmm_enter_sig();
   1241  1.47  riastrad 	if (error)
   1242  1.47  riastrad 		return error;
   1243  1.47  riastrad 	error = nvmm_ioctl_internal(fp, cmd, data);
   1244  1.47  riastrad 	nvmm_exit();
   1245  1.47  riastrad 
   1246  1.47  riastrad 	return error;
   1247  1.47  riastrad }
   1248  1.47  riastrad 
   1249  1.14      maxv /* -------------------------------------------------------------------------- */
   1250   1.1      maxv 
   1251  1.31      maxv static int nvmm_match(device_t, cfdata_t, void *);
   1252  1.31      maxv static void nvmm_attach(device_t, device_t, void *);
   1253  1.31      maxv static int nvmm_detach(device_t, int);
   1254  1.47  riastrad static bool nvmm_suspend(device_t, const pmf_qual_t *);
   1255  1.47  riastrad static bool nvmm_resume(device_t, const pmf_qual_t *);
   1256  1.31      maxv 
   1257  1.31      maxv extern struct cfdriver nvmm_cd;
   1258  1.31      maxv 
   1259  1.31      maxv CFATTACH_DECL_NEW(nvmm, 0, nvmm_match, nvmm_attach, nvmm_detach, NULL);
   1260  1.31      maxv 
   1261  1.31      maxv static struct cfdata nvmm_cfdata[] = {
   1262  1.31      maxv 	{
   1263  1.31      maxv 		.cf_name = "nvmm",
   1264  1.31      maxv 		.cf_atname = "nvmm",
   1265  1.31      maxv 		.cf_unit = 0,
   1266  1.31      maxv 		.cf_fstate = FSTATE_STAR,
   1267  1.31      maxv 		.cf_loc = NULL,
   1268  1.31      maxv 		.cf_flags = 0,
   1269  1.31      maxv 		.cf_pspec = NULL,
   1270  1.31      maxv 	},
   1271  1.31      maxv 	{ NULL, NULL, 0, FSTATE_NOTFOUND, NULL, 0, NULL }
   1272  1.31      maxv };
   1273  1.31      maxv 
   1274  1.31      maxv static int
   1275  1.31      maxv nvmm_match(device_t self, cfdata_t cfdata, void *arg)
   1276  1.31      maxv {
   1277  1.31      maxv 	return 1;
   1278  1.31      maxv }
   1279  1.31      maxv 
   1280  1.31      maxv static void
   1281  1.31      maxv nvmm_attach(device_t parent, device_t self, void *aux)
   1282  1.31      maxv {
   1283  1.31      maxv 	int error;
   1284  1.31      maxv 
   1285  1.31      maxv 	error = nvmm_init();
   1286  1.31      maxv 	if (error)
   1287  1.31      maxv 		panic("%s: impossible", __func__);
   1288  1.32      maxv 	aprint_normal_dev(self, "attached, using backend %s\n",
   1289  1.32      maxv 	    nvmm_impl->name);
   1290  1.47  riastrad 	if (nvmm_impl->suspend != NULL && nvmm_impl->resume != NULL)
   1291  1.47  riastrad 		pmf_device_register(self, nvmm_suspend, nvmm_resume);
   1292  1.31      maxv }
   1293  1.31      maxv 
   1294  1.31      maxv static int
   1295  1.31      maxv nvmm_detach(device_t self, int flags)
   1296  1.31      maxv {
   1297  1.35      maxv 	if (atomic_load_relaxed(&nmachines) > 0)
   1298  1.31      maxv 		return EBUSY;
   1299  1.47  riastrad 	pmf_device_deregister(self);
   1300  1.31      maxv 	nvmm_fini();
   1301  1.31      maxv 	return 0;
   1302  1.31      maxv }
   1303  1.31      maxv 
   1304  1.47  riastrad static void
   1305  1.47  riastrad nvmm_suspend_vcpu(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
   1306  1.47  riastrad {
   1307  1.47  riastrad 
   1308  1.47  riastrad 	mutex_enter(&vcpu->lock);
   1309  1.47  riastrad 	if (vcpu->present && nvmm_impl->vcpu_suspend)
   1310  1.47  riastrad 		(*nvmm_impl->vcpu_suspend)(mach, vcpu);
   1311  1.47  riastrad 	mutex_exit(&vcpu->lock);
   1312  1.47  riastrad }
   1313  1.47  riastrad 
   1314  1.47  riastrad static void
   1315  1.47  riastrad nvmm_resume_vcpu(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
   1316  1.47  riastrad {
   1317  1.47  riastrad 
   1318  1.47  riastrad 	mutex_enter(&vcpu->lock);
   1319  1.47  riastrad 	if (vcpu->present && nvmm_impl->vcpu_resume)
   1320  1.47  riastrad 		(*nvmm_impl->vcpu_resume)(mach, vcpu);
   1321  1.47  riastrad 	mutex_exit(&vcpu->lock);
   1322  1.47  riastrad }
   1323  1.47  riastrad 
   1324  1.47  riastrad static void
   1325  1.47  riastrad nvmm_suspend_machine(struct nvmm_machine *mach)
   1326  1.47  riastrad {
   1327  1.47  riastrad 
   1328  1.47  riastrad 	rw_enter(&mach->lock, RW_WRITER);
   1329  1.47  riastrad 	if (mach->present) {
   1330  1.47  riastrad 		if (nvmm_impl->vcpu_suspend) {
   1331  1.47  riastrad 			size_t cpuid;
   1332  1.47  riastrad 
   1333  1.47  riastrad 			for (cpuid = 0; cpuid < NVMM_MAX_VCPUS; cpuid++)
   1334  1.47  riastrad 				nvmm_suspend_vcpu(mach, &mach->cpus[cpuid]);
   1335  1.47  riastrad 		}
   1336  1.47  riastrad 		if (nvmm_impl->machine_suspend)
   1337  1.47  riastrad 			(*nvmm_impl->machine_suspend)(mach);
   1338  1.47  riastrad 	}
   1339  1.47  riastrad 	rw_exit(&mach->lock);
   1340  1.47  riastrad }
   1341  1.47  riastrad 
   1342  1.47  riastrad static void
   1343  1.47  riastrad nvmm_resume_machine(struct nvmm_machine *mach)
   1344  1.47  riastrad {
   1345  1.47  riastrad 
   1346  1.47  riastrad 	rw_enter(&mach->lock, RW_WRITER);
   1347  1.47  riastrad 	if (mach->present) {
   1348  1.47  riastrad 		if (nvmm_impl->vcpu_resume) {
   1349  1.47  riastrad 			size_t cpuid;
   1350  1.47  riastrad 
   1351  1.47  riastrad 			for (cpuid = 0; cpuid < NVMM_MAX_VCPUS; cpuid++)
   1352  1.47  riastrad 				nvmm_resume_vcpu(mach, &mach->cpus[cpuid]);
   1353  1.47  riastrad 		}
   1354  1.47  riastrad 		if (nvmm_impl->machine_resume)
   1355  1.47  riastrad 			(*nvmm_impl->machine_resume)(mach);
   1356  1.47  riastrad 	}
   1357  1.47  riastrad 	rw_exit(&mach->lock);
   1358  1.47  riastrad }
   1359  1.47  riastrad 
   1360  1.47  riastrad static bool
   1361  1.47  riastrad nvmm_suspend(device_t self, const pmf_qual_t *qual)
   1362  1.47  riastrad {
   1363  1.47  riastrad 	size_t i;
   1364  1.47  riastrad 
   1365  1.47  riastrad 	/*
   1366  1.47  riastrad 	 * Prevent new users (via ioctl) from starting.
   1367  1.47  riastrad 	 */
   1368  1.47  riastrad 	mutex_enter(&suspension.lock);
   1369  1.47  riastrad 	KASSERT(!nvmm_suspending);
   1370  1.47  riastrad 	atomic_store_relaxed(&nvmm_suspending, true);
   1371  1.47  riastrad 	mutex_exit(&suspension.lock);
   1372  1.47  riastrad 
   1373  1.47  riastrad 	/*
   1374  1.47  riastrad 	 * Interrupt any running VMs so they will break out of run
   1375  1.47  riastrad 	 * loops or anything else and not start up again until we've
   1376  1.47  riastrad 	 * resumed.
   1377  1.47  riastrad 	 */
   1378  1.47  riastrad 	if (nvmm_impl->suspend_interrupt)
   1379  1.47  riastrad 		(*nvmm_impl->suspend_interrupt)();
   1380  1.47  riastrad 
   1381  1.47  riastrad 	/*
   1382  1.47  riastrad 	 * Wait for any running VMs or other ioctls to finish running
   1383  1.47  riastrad 	 * or handling any other ioctls.
   1384  1.47  riastrad 	 */
   1385  1.47  riastrad 	mutex_enter(&suspension.lock);
   1386  1.47  riastrad 	while (suspension.users)
   1387  1.47  riastrad 		cv_wait(&suspension.suspendcv, &suspension.lock);
   1388  1.47  riastrad 	mutex_exit(&suspension.lock);
   1389  1.47  riastrad 
   1390  1.47  riastrad 	/*
   1391  1.47  riastrad 	 * Suspend all the machines.
   1392  1.47  riastrad 	 */
   1393  1.47  riastrad 	if (nvmm_impl->machine_suspend || nvmm_impl->vcpu_suspend) {
   1394  1.47  riastrad 		for (i = 0; i < NVMM_MAX_MACHINES; i++)
   1395  1.47  riastrad 			nvmm_suspend_machine(&machines[i]);
   1396  1.47  riastrad 	}
   1397  1.47  riastrad 
   1398  1.47  riastrad 	/*
   1399  1.47  riastrad 	 * Take any systemwide suspend action.
   1400  1.47  riastrad 	 */
   1401  1.47  riastrad 	if (nvmm_impl->suspend)
   1402  1.47  riastrad 		(*nvmm_impl->suspend)();
   1403  1.47  riastrad 
   1404  1.47  riastrad 	return true;
   1405  1.47  riastrad }
   1406  1.47  riastrad 
   1407  1.47  riastrad static bool
   1408  1.47  riastrad nvmm_resume(device_t self, const pmf_qual_t *qual)
   1409  1.47  riastrad {
   1410  1.47  riastrad 	size_t i;
   1411  1.47  riastrad 
   1412  1.47  riastrad 	KASSERT(atomic_load_relaxed(&nvmm_suspending));
   1413  1.47  riastrad 	KASSERT(suspension.users == 0);
   1414  1.47  riastrad 
   1415  1.47  riastrad 	/*
   1416  1.47  riastrad 	 * Take any systemwide resume action.
   1417  1.47  riastrad 	 */
   1418  1.47  riastrad 	if (nvmm_impl->resume)
   1419  1.47  riastrad 		(*nvmm_impl->resume)();
   1420  1.47  riastrad 
   1421  1.47  riastrad 	/*
   1422  1.47  riastrad 	 * Resume all the machines.
   1423  1.47  riastrad 	 */
   1424  1.47  riastrad 	if (nvmm_impl->machine_resume || nvmm_impl->vcpu_resume) {
   1425  1.47  riastrad 		for (i = 0; i < NVMM_MAX_MACHINES; i++)
   1426  1.47  riastrad 			nvmm_resume_machine(&machines[i]);
   1427  1.47  riastrad 	}
   1428  1.47  riastrad 
   1429  1.47  riastrad 	/*
   1430  1.47  riastrad 	 * Allow new users (via ioctl) to start again.
   1431  1.47  riastrad 	 */
   1432  1.47  riastrad 	mutex_enter(&suspension.lock);
   1433  1.47  riastrad 	atomic_store_relaxed(&nvmm_suspending, false);
   1434  1.47  riastrad 	cv_broadcast(&suspension.resumecv);
   1435  1.47  riastrad 	mutex_exit(&suspension.lock);
   1436  1.47  riastrad 
   1437  1.47  riastrad 	return true;
   1438  1.47  riastrad }
   1439  1.47  riastrad 
   1440   1.1      maxv void
   1441   1.1      maxv nvmmattach(int nunits)
   1442   1.1      maxv {
   1443   1.1      maxv 	/* nothing */
   1444   1.1      maxv }
   1445   1.1      maxv 
   1446  1.16      maxv MODULE(MODULE_CLASS_MISC, nvmm, NULL);
   1447   1.1      maxv 
   1448  1.31      maxv #if defined(_MODULE)
   1449  1.31      maxv CFDRIVER_DECL(nvmm, DV_VIRTUAL, NULL);
   1450  1.31      maxv #endif
   1451  1.31      maxv 
   1452   1.1      maxv static int
   1453   1.1      maxv nvmm_modcmd(modcmd_t cmd, void *arg)
   1454   1.1      maxv {
   1455  1.31      maxv #if defined(_MODULE)
   1456  1.31      maxv 	devmajor_t bmajor = NODEVMAJOR;
   1457  1.31      maxv 	devmajor_t cmajor = 345;
   1458  1.31      maxv #endif
   1459   1.1      maxv 	int error;
   1460   1.1      maxv 
   1461   1.1      maxv 	switch (cmd) {
   1462   1.1      maxv 	case MODULE_CMD_INIT:
   1463  1.31      maxv 		if (nvmm_ident() == NULL) {
   1464  1.31      maxv 			aprint_error("%s: cpu not supported\n",
   1465  1.31      maxv 			    nvmm_cd.cd_name);
   1466  1.31      maxv 			return ENOTSUP;
   1467  1.31      maxv 		}
   1468  1.31      maxv #if defined(_MODULE)
   1469  1.31      maxv 		error = config_cfdriver_attach(&nvmm_cd);
   1470   1.1      maxv 		if (error)
   1471   1.1      maxv 			return error;
   1472  1.31      maxv #endif
   1473  1.31      maxv 		error = config_cfattach_attach(nvmm_cd.cd_name, &nvmm_ca);
   1474  1.31      maxv 		if (error) {
   1475  1.46  pgoyette #if defined(_MODULE)
   1476  1.31      maxv 			config_cfdriver_detach(&nvmm_cd);
   1477  1.46  pgoyette #endif
   1478  1.31      maxv 			aprint_error("%s: config_cfattach_attach failed\n",
   1479  1.31      maxv 			    nvmm_cd.cd_name);
   1480  1.31      maxv 			return error;
   1481  1.31      maxv 		}
   1482  1.31      maxv 
   1483  1.31      maxv 		error = config_cfdata_attach(nvmm_cfdata, 1);
   1484  1.31      maxv 		if (error) {
   1485  1.31      maxv 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
   1486  1.46  pgoyette #if defined(_MODULE)
   1487  1.31      maxv 			config_cfdriver_detach(&nvmm_cd);
   1488  1.46  pgoyette #endif
   1489  1.31      maxv 			aprint_error("%s: unable to register cfdata\n",
   1490  1.31      maxv 			    nvmm_cd.cd_name);
   1491  1.31      maxv 			return error;
   1492  1.31      maxv 		}
   1493  1.31      maxv 
   1494  1.31      maxv 		if (config_attach_pseudo(nvmm_cfdata) == NULL) {
   1495  1.31      maxv 			aprint_error("%s: config_attach_pseudo failed\n",
   1496  1.31      maxv 			    nvmm_cd.cd_name);
   1497  1.31      maxv 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
   1498  1.46  pgoyette #if defined(_MODULE)
   1499  1.31      maxv 			config_cfdriver_detach(&nvmm_cd);
   1500  1.46  pgoyette #endif
   1501  1.31      maxv 			return ENXIO;
   1502  1.31      maxv 		}
   1503   1.1      maxv 
   1504   1.1      maxv #if defined(_MODULE)
   1505  1.31      maxv 		/* mknod /dev/nvmm c 345 0 */
   1506  1.31      maxv 		error = devsw_attach(nvmm_cd.cd_name, NULL, &bmajor,
   1507  1.31      maxv 			&nvmm_cdevsw, &cmajor);
   1508  1.31      maxv 		if (error) {
   1509  1.46  pgoyette 			aprint_error("%s: unable to register devsw, err %d\n",
   1510  1.46  pgoyette 			    nvmm_cd.cd_name, error);
   1511  1.31      maxv 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
   1512  1.31      maxv 			config_cfdriver_detach(&nvmm_cd);
   1513  1.31      maxv 			return error;
   1514   1.1      maxv 		}
   1515   1.1      maxv #endif
   1516   1.1      maxv 		return 0;
   1517   1.1      maxv 	case MODULE_CMD_FINI:
   1518  1.31      maxv 		error = config_cfdata_detach(nvmm_cfdata);
   1519  1.31      maxv 		if (error)
   1520  1.31      maxv 			return error;
   1521  1.31      maxv 		error = config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
   1522  1.31      maxv 		if (error)
   1523  1.31      maxv 			return error;
   1524   1.1      maxv #if defined(_MODULE)
   1525  1.31      maxv 		config_cfdriver_detach(&nvmm_cd);
   1526  1.31      maxv 		devsw_detach(NULL, &nvmm_cdevsw);
   1527   1.1      maxv #endif
   1528   1.1      maxv 		return 0;
   1529  1.13      maxv 	case MODULE_CMD_AUTOUNLOAD:
   1530  1.13      maxv 		return EBUSY;
   1531   1.1      maxv 	default:
   1532   1.1      maxv 		return ENOTTY;
   1533   1.1      maxv 	}
   1534   1.1      maxv }
   1535