Home | History | Annotate | Line # | Download | only in nvmm
nvmm.c revision 1.41.4.2
      1  1.41.4.2   thorpej /*	$NetBSD: nvmm.c,v 1.41.4.2 2021/04/17 17:26:19 thorpej 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.41.4.2   thorpej __KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.41.4.2 2021/04/17 17:26:19 thorpej 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.1      maxv static const struct nvmm_impl *nvmm_impl_list[] = {
     63      1.33      maxv #if defined(__x86_64__)
     64       1.7      maxv 	&nvmm_x86_svm,	/* x86 AMD SVM */
     65       1.7      maxv 	&nvmm_x86_vmx	/* x86 Intel VMX */
     66      1.33      maxv #endif
     67       1.1      maxv };
     68       1.1      maxv 
     69      1.38      maxv static const struct nvmm_impl *nvmm_impl __read_mostly = NULL;
     70       1.1      maxv 
     71      1.17      maxv static struct nvmm_owner root_owner;
     72      1.17      maxv 
     73       1.1      maxv /* -------------------------------------------------------------------------- */
     74       1.1      maxv 
     75       1.1      maxv static int
     76       1.1      maxv nvmm_machine_alloc(struct nvmm_machine **ret)
     77       1.1      maxv {
     78       1.1      maxv 	struct nvmm_machine *mach;
     79       1.1      maxv 	size_t i;
     80       1.1      maxv 
     81       1.1      maxv 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
     82       1.1      maxv 		mach = &machines[i];
     83       1.1      maxv 
     84       1.1      maxv 		rw_enter(&mach->lock, RW_WRITER);
     85       1.1      maxv 		if (mach->present) {
     86       1.1      maxv 			rw_exit(&mach->lock);
     87       1.1      maxv 			continue;
     88       1.1      maxv 		}
     89       1.1      maxv 
     90       1.1      maxv 		mach->present = true;
     91      1.17      maxv 		mach->time = time_second;
     92       1.1      maxv 		*ret = mach;
     93      1.13      maxv 		atomic_inc_uint(&nmachines);
     94       1.1      maxv 		return 0;
     95       1.1      maxv 	}
     96       1.1      maxv 
     97       1.1      maxv 	return ENOBUFS;
     98       1.1      maxv }
     99       1.1      maxv 
    100       1.1      maxv static void
    101       1.1      maxv nvmm_machine_free(struct nvmm_machine *mach)
    102       1.1      maxv {
    103       1.1      maxv 	KASSERT(rw_write_held(&mach->lock));
    104       1.1      maxv 	KASSERT(mach->present);
    105       1.1      maxv 	mach->present = false;
    106      1.13      maxv 	atomic_dec_uint(&nmachines);
    107       1.1      maxv }
    108       1.1      maxv 
    109       1.1      maxv static int
    110      1.14      maxv nvmm_machine_get(struct nvmm_owner *owner, nvmm_machid_t machid,
    111      1.14      maxv     struct nvmm_machine **ret, bool writer)
    112       1.1      maxv {
    113       1.1      maxv 	struct nvmm_machine *mach;
    114       1.1      maxv 	krw_t op = writer ? RW_WRITER : RW_READER;
    115       1.1      maxv 
    116      1.36      maxv 	if (__predict_false(machid >= NVMM_MAX_MACHINES)) {
    117       1.1      maxv 		return EINVAL;
    118       1.1      maxv 	}
    119       1.1      maxv 	mach = &machines[machid];
    120       1.1      maxv 
    121       1.1      maxv 	rw_enter(&mach->lock, op);
    122      1.36      maxv 	if (__predict_false(!mach->present)) {
    123       1.1      maxv 		rw_exit(&mach->lock);
    124       1.1      maxv 		return ENOENT;
    125       1.1      maxv 	}
    126      1.36      maxv 	if (__predict_false(mach->owner != owner && owner != &root_owner)) {
    127       1.1      maxv 		rw_exit(&mach->lock);
    128       1.1      maxv 		return EPERM;
    129       1.1      maxv 	}
    130       1.1      maxv 	*ret = mach;
    131       1.1      maxv 
    132       1.1      maxv 	return 0;
    133       1.1      maxv }
    134       1.1      maxv 
    135       1.1      maxv static void
    136       1.1      maxv nvmm_machine_put(struct nvmm_machine *mach)
    137       1.1      maxv {
    138       1.1      maxv 	rw_exit(&mach->lock);
    139       1.1      maxv }
    140       1.1      maxv 
    141       1.1      maxv /* -------------------------------------------------------------------------- */
    142       1.1      maxv 
    143       1.1      maxv static int
    144      1.18      maxv nvmm_vcpu_alloc(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    145      1.18      maxv     struct nvmm_cpu **ret)
    146       1.1      maxv {
    147       1.1      maxv 	struct nvmm_cpu *vcpu;
    148       1.1      maxv 
    149      1.18      maxv 	if (cpuid >= NVMM_MAX_VCPUS) {
    150      1.18      maxv 		return EINVAL;
    151      1.18      maxv 	}
    152      1.18      maxv 	vcpu = &mach->cpus[cpuid];
    153       1.1      maxv 
    154      1.18      maxv 	mutex_enter(&vcpu->lock);
    155      1.18      maxv 	if (vcpu->present) {
    156      1.18      maxv 		mutex_exit(&vcpu->lock);
    157      1.18      maxv 		return EBUSY;
    158       1.1      maxv 	}
    159       1.1      maxv 
    160      1.18      maxv 	vcpu->present = true;
    161      1.19      maxv 	vcpu->comm = NULL;
    162      1.18      maxv 	vcpu->hcpu_last = -1;
    163      1.18      maxv 	*ret = vcpu;
    164      1.18      maxv 	return 0;
    165       1.1      maxv }
    166       1.1      maxv 
    167       1.1      maxv static void
    168       1.1      maxv nvmm_vcpu_free(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
    169       1.1      maxv {
    170       1.1      maxv 	KASSERT(mutex_owned(&vcpu->lock));
    171       1.1      maxv 	vcpu->present = false;
    172      1.19      maxv 	if (vcpu->comm != NULL) {
    173      1.19      maxv 		uvm_deallocate(kernel_map, (vaddr_t)vcpu->comm, PAGE_SIZE);
    174      1.19      maxv 	}
    175       1.1      maxv }
    176       1.1      maxv 
    177      1.22      maxv static int
    178       1.1      maxv nvmm_vcpu_get(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
    179       1.1      maxv     struct nvmm_cpu **ret)
    180       1.1      maxv {
    181       1.1      maxv 	struct nvmm_cpu *vcpu;
    182       1.1      maxv 
    183      1.36      maxv 	if (__predict_false(cpuid >= NVMM_MAX_VCPUS)) {
    184       1.1      maxv 		return EINVAL;
    185       1.1      maxv 	}
    186       1.1      maxv 	vcpu = &mach->cpus[cpuid];
    187       1.1      maxv 
    188       1.1      maxv 	mutex_enter(&vcpu->lock);
    189      1.36      maxv 	if (__predict_false(!vcpu->present)) {
    190       1.1      maxv 		mutex_exit(&vcpu->lock);
    191       1.1      maxv 		return ENOENT;
    192       1.1      maxv 	}
    193       1.1      maxv 	*ret = vcpu;
    194       1.1      maxv 
    195       1.1      maxv 	return 0;
    196       1.1      maxv }
    197       1.1      maxv 
    198      1.22      maxv static void
    199       1.1      maxv nvmm_vcpu_put(struct nvmm_cpu *vcpu)
    200       1.1      maxv {
    201       1.1      maxv 	mutex_exit(&vcpu->lock);
    202       1.1      maxv }
    203       1.1      maxv 
    204       1.1      maxv /* -------------------------------------------------------------------------- */
    205       1.1      maxv 
    206       1.1      maxv static void
    207      1.14      maxv nvmm_kill_machines(struct nvmm_owner *owner)
    208       1.1      maxv {
    209       1.1      maxv 	struct nvmm_machine *mach;
    210       1.1      maxv 	struct nvmm_cpu *vcpu;
    211       1.1      maxv 	size_t i, j;
    212       1.1      maxv 	int error;
    213       1.1      maxv 
    214       1.1      maxv 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
    215       1.1      maxv 		mach = &machines[i];
    216       1.1      maxv 
    217       1.1      maxv 		rw_enter(&mach->lock, RW_WRITER);
    218      1.14      maxv 		if (!mach->present || mach->owner != owner) {
    219       1.1      maxv 			rw_exit(&mach->lock);
    220       1.1      maxv 			continue;
    221       1.1      maxv 		}
    222       1.1      maxv 
    223       1.1      maxv 		/* Kill it. */
    224       1.1      maxv 		for (j = 0; j < NVMM_MAX_VCPUS; j++) {
    225       1.1      maxv 			error = nvmm_vcpu_get(mach, j, &vcpu);
    226       1.1      maxv 			if (error)
    227       1.1      maxv 				continue;
    228       1.1      maxv 			(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    229       1.1      maxv 			nvmm_vcpu_free(mach, vcpu);
    230       1.1      maxv 			nvmm_vcpu_put(vcpu);
    231      1.36      maxv 			atomic_dec_uint(&mach->ncpus);
    232       1.1      maxv 		}
    233      1.15      maxv 		(*nvmm_impl->machine_destroy)(mach);
    234       1.1      maxv 		uvmspace_free(mach->vm);
    235       1.4      maxv 
    236       1.4      maxv 		/* Drop the kernel UOBJ refs. */
    237       1.9      maxv 		for (j = 0; j < NVMM_MAX_HMAPPINGS; j++) {
    238       1.9      maxv 			if (!mach->hmap[j].present)
    239       1.4      maxv 				continue;
    240       1.9      maxv 			uao_detach(mach->hmap[j].uobj);
    241       1.4      maxv 		}
    242       1.4      maxv 
    243       1.1      maxv 		nvmm_machine_free(mach);
    244       1.1      maxv 
    245       1.1      maxv 		rw_exit(&mach->lock);
    246       1.1      maxv 	}
    247       1.1      maxv }
    248       1.1      maxv 
    249       1.1      maxv /* -------------------------------------------------------------------------- */
    250       1.1      maxv 
    251       1.1      maxv static int
    252      1.14      maxv nvmm_capability(struct nvmm_owner *owner, struct nvmm_ioc_capability *args)
    253       1.1      maxv {
    254      1.23      maxv 	args->cap.version = NVMM_KERN_VERSION;
    255       1.1      maxv 	args->cap.state_size = nvmm_impl->state_size;
    256       1.1      maxv 	args->cap.max_machines = NVMM_MAX_MACHINES;
    257       1.1      maxv 	args->cap.max_vcpus = NVMM_MAX_VCPUS;
    258       1.1      maxv 	args->cap.max_ram = NVMM_MAX_RAM;
    259       1.1      maxv 
    260       1.1      maxv 	(*nvmm_impl->capability)(&args->cap);
    261       1.1      maxv 
    262       1.1      maxv 	return 0;
    263       1.1      maxv }
    264       1.1      maxv 
    265       1.1      maxv static int
    266      1.14      maxv nvmm_machine_create(struct nvmm_owner *owner,
    267      1.14      maxv     struct nvmm_ioc_machine_create *args)
    268       1.1      maxv {
    269       1.1      maxv 	struct nvmm_machine *mach;
    270       1.1      maxv 	int error;
    271       1.1      maxv 
    272       1.1      maxv 	error = nvmm_machine_alloc(&mach);
    273       1.1      maxv 	if (error)
    274       1.1      maxv 		return error;
    275       1.1      maxv 
    276       1.1      maxv 	/* Curproc owns the machine. */
    277      1.14      maxv 	mach->owner = owner;
    278       1.1      maxv 
    279       1.9      maxv 	/* Zero out the host mappings. */
    280       1.9      maxv 	memset(&mach->hmap, 0, sizeof(mach->hmap));
    281       1.4      maxv 
    282       1.1      maxv 	/* Create the machine vmspace. */
    283       1.1      maxv 	mach->gpa_begin = 0;
    284       1.1      maxv 	mach->gpa_end = NVMM_MAX_RAM;
    285       1.1      maxv 	mach->vm = uvmspace_alloc(0, mach->gpa_end - mach->gpa_begin, false);
    286       1.1      maxv 
    287      1.19      maxv 	/* Create the comm uobj. */
    288      1.19      maxv 	mach->commuobj = uao_create(NVMM_MAX_VCPUS * PAGE_SIZE, 0);
    289      1.19      maxv 
    290       1.1      maxv 	(*nvmm_impl->machine_create)(mach);
    291       1.1      maxv 
    292       1.1      maxv 	args->machid = mach->machid;
    293       1.1      maxv 	nvmm_machine_put(mach);
    294       1.1      maxv 
    295       1.1      maxv 	return 0;
    296       1.1      maxv }
    297       1.1      maxv 
    298       1.1      maxv static int
    299      1.14      maxv nvmm_machine_destroy(struct nvmm_owner *owner,
    300      1.14      maxv     struct nvmm_ioc_machine_destroy *args)
    301       1.1      maxv {
    302       1.1      maxv 	struct nvmm_machine *mach;
    303       1.1      maxv 	struct nvmm_cpu *vcpu;
    304       1.1      maxv 	int error;
    305       1.1      maxv 	size_t i;
    306       1.1      maxv 
    307      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    308       1.1      maxv 	if (error)
    309       1.1      maxv 		return error;
    310       1.1      maxv 
    311       1.1      maxv 	for (i = 0; i < NVMM_MAX_VCPUS; i++) {
    312       1.1      maxv 		error = nvmm_vcpu_get(mach, i, &vcpu);
    313       1.1      maxv 		if (error)
    314       1.1      maxv 			continue;
    315       1.1      maxv 
    316       1.1      maxv 		(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    317       1.1      maxv 		nvmm_vcpu_free(mach, vcpu);
    318       1.1      maxv 		nvmm_vcpu_put(vcpu);
    319      1.36      maxv 		atomic_dec_uint(&mach->ncpus);
    320       1.1      maxv 	}
    321       1.1      maxv 
    322       1.1      maxv 	(*nvmm_impl->machine_destroy)(mach);
    323       1.1      maxv 
    324       1.1      maxv 	/* Free the machine vmspace. */
    325       1.1      maxv 	uvmspace_free(mach->vm);
    326       1.4      maxv 
    327       1.4      maxv 	/* Drop the kernel UOBJ refs. */
    328       1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    329       1.9      maxv 		if (!mach->hmap[i].present)
    330       1.4      maxv 			continue;
    331       1.9      maxv 		uao_detach(mach->hmap[i].uobj);
    332       1.4      maxv 	}
    333       1.1      maxv 
    334       1.1      maxv 	nvmm_machine_free(mach);
    335       1.1      maxv 	nvmm_machine_put(mach);
    336       1.1      maxv 
    337       1.1      maxv 	return 0;
    338       1.1      maxv }
    339       1.1      maxv 
    340       1.1      maxv static int
    341      1.14      maxv nvmm_machine_configure(struct nvmm_owner *owner,
    342      1.14      maxv     struct nvmm_ioc_machine_configure *args)
    343       1.1      maxv {
    344       1.1      maxv 	struct nvmm_machine *mach;
    345       1.1      maxv 	size_t allocsz;
    346      1.21      maxv 	uint64_t op;
    347       1.1      maxv 	void *data;
    348       1.1      maxv 	int error;
    349       1.1      maxv 
    350      1.21      maxv 	op = NVMM_MACH_CONF_MD(args->op);
    351      1.23      maxv 	if (__predict_false(op >= nvmm_impl->mach_conf_max)) {
    352       1.1      maxv 		return EINVAL;
    353       1.1      maxv 	}
    354       1.1      maxv 
    355      1.23      maxv 	allocsz = nvmm_impl->mach_conf_sizes[op];
    356       1.1      maxv 	data = kmem_alloc(allocsz, KM_SLEEP);
    357       1.1      maxv 
    358      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    359       1.1      maxv 	if (error) {
    360       1.1      maxv 		kmem_free(data, allocsz);
    361       1.1      maxv 		return error;
    362       1.1      maxv 	}
    363       1.1      maxv 
    364       1.1      maxv 	error = copyin(args->conf, data, allocsz);
    365       1.1      maxv 	if (error) {
    366       1.1      maxv 		goto out;
    367       1.1      maxv 	}
    368       1.1      maxv 
    369      1.21      maxv 	error = (*nvmm_impl->machine_configure)(mach, op, data);
    370       1.1      maxv 
    371       1.1      maxv out:
    372       1.1      maxv 	nvmm_machine_put(mach);
    373       1.1      maxv 	kmem_free(data, allocsz);
    374       1.1      maxv 	return error;
    375       1.1      maxv }
    376       1.1      maxv 
    377       1.1      maxv static int
    378      1.14      maxv nvmm_vcpu_create(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_create *args)
    379       1.1      maxv {
    380       1.1      maxv 	struct nvmm_machine *mach;
    381       1.1      maxv 	struct nvmm_cpu *vcpu;
    382       1.1      maxv 	int error;
    383       1.1      maxv 
    384      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    385       1.1      maxv 	if (error)
    386       1.1      maxv 		return error;
    387       1.1      maxv 
    388      1.18      maxv 	error = nvmm_vcpu_alloc(mach, args->cpuid, &vcpu);
    389       1.1      maxv 	if (error)
    390       1.1      maxv 		goto out;
    391       1.1      maxv 
    392      1.19      maxv 	/* Allocate the comm page. */
    393      1.19      maxv 	uao_reference(mach->commuobj);
    394      1.19      maxv 	error = uvm_map(kernel_map, (vaddr_t *)&vcpu->comm, PAGE_SIZE,
    395      1.19      maxv 	    mach->commuobj, args->cpuid * PAGE_SIZE, 0, UVM_MAPFLAG(UVM_PROT_RW,
    396      1.19      maxv 	    UVM_PROT_RW, UVM_INH_SHARE, UVM_ADV_RANDOM, 0));
    397      1.19      maxv 	if (error) {
    398      1.19      maxv 		uao_detach(mach->commuobj);
    399      1.19      maxv 		nvmm_vcpu_free(mach, vcpu);
    400      1.19      maxv 		nvmm_vcpu_put(vcpu);
    401      1.19      maxv 		goto out;
    402      1.19      maxv 	}
    403      1.19      maxv 	error = uvm_map_pageable(kernel_map, (vaddr_t)vcpu->comm,
    404      1.19      maxv 	    (vaddr_t)vcpu->comm + PAGE_SIZE, false, 0);
    405      1.19      maxv 	if (error) {
    406      1.19      maxv 		nvmm_vcpu_free(mach, vcpu);
    407      1.19      maxv 		nvmm_vcpu_put(vcpu);
    408      1.19      maxv 		goto out;
    409      1.19      maxv 	}
    410      1.19      maxv 	memset(vcpu->comm, 0, PAGE_SIZE);
    411      1.19      maxv 
    412       1.1      maxv 	error = (*nvmm_impl->vcpu_create)(mach, vcpu);
    413       1.1      maxv 	if (error) {
    414       1.1      maxv 		nvmm_vcpu_free(mach, vcpu);
    415       1.1      maxv 		nvmm_vcpu_put(vcpu);
    416       1.1      maxv 		goto out;
    417       1.1      maxv 	}
    418       1.1      maxv 
    419       1.1      maxv 	nvmm_vcpu_put(vcpu);
    420      1.28      maxv 	atomic_inc_uint(&mach->ncpus);
    421      1.28      maxv 
    422       1.1      maxv out:
    423       1.1      maxv 	nvmm_machine_put(mach);
    424       1.1      maxv 	return error;
    425       1.1      maxv }
    426       1.1      maxv 
    427       1.1      maxv static int
    428      1.14      maxv nvmm_vcpu_destroy(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_destroy *args)
    429       1.1      maxv {
    430       1.1      maxv 	struct nvmm_machine *mach;
    431       1.1      maxv 	struct nvmm_cpu *vcpu;
    432       1.1      maxv 	int error;
    433       1.1      maxv 
    434      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    435       1.1      maxv 	if (error)
    436       1.1      maxv 		return error;
    437       1.1      maxv 
    438       1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    439       1.1      maxv 	if (error)
    440       1.1      maxv 		goto out;
    441       1.1      maxv 
    442       1.1      maxv 	(*nvmm_impl->vcpu_destroy)(mach, vcpu);
    443       1.1      maxv 	nvmm_vcpu_free(mach, vcpu);
    444       1.1      maxv 	nvmm_vcpu_put(vcpu);
    445      1.28      maxv 	atomic_dec_uint(&mach->ncpus);
    446      1.28      maxv 
    447       1.1      maxv out:
    448       1.1      maxv 	nvmm_machine_put(mach);
    449       1.1      maxv 	return error;
    450       1.1      maxv }
    451       1.1      maxv 
    452       1.1      maxv static int
    453      1.23      maxv nvmm_vcpu_configure(struct nvmm_owner *owner,
    454      1.23      maxv     struct nvmm_ioc_vcpu_configure *args)
    455      1.23      maxv {
    456      1.23      maxv 	struct nvmm_machine *mach;
    457      1.23      maxv 	struct nvmm_cpu *vcpu;
    458      1.23      maxv 	size_t allocsz;
    459      1.23      maxv 	uint64_t op;
    460      1.23      maxv 	void *data;
    461      1.23      maxv 	int error;
    462      1.23      maxv 
    463      1.23      maxv 	op = NVMM_VCPU_CONF_MD(args->op);
    464      1.23      maxv 	if (__predict_false(op >= nvmm_impl->vcpu_conf_max))
    465      1.23      maxv 		return EINVAL;
    466      1.23      maxv 
    467      1.23      maxv 	allocsz = nvmm_impl->vcpu_conf_sizes[op];
    468      1.23      maxv 	data = kmem_alloc(allocsz, KM_SLEEP);
    469      1.23      maxv 
    470      1.23      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    471      1.23      maxv 	if (error) {
    472      1.23      maxv 		kmem_free(data, allocsz);
    473      1.23      maxv 		return error;
    474      1.23      maxv 	}
    475      1.23      maxv 
    476      1.23      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    477      1.23      maxv 	if (error) {
    478      1.23      maxv 		nvmm_machine_put(mach);
    479      1.23      maxv 		kmem_free(data, allocsz);
    480      1.23      maxv 		return error;
    481      1.23      maxv 	}
    482      1.23      maxv 
    483      1.23      maxv 	error = copyin(args->conf, data, allocsz);
    484      1.23      maxv 	if (error) {
    485      1.23      maxv 		goto out;
    486      1.23      maxv 	}
    487      1.23      maxv 
    488      1.23      maxv 	error = (*nvmm_impl->vcpu_configure)(vcpu, op, data);
    489      1.23      maxv 
    490      1.23      maxv out:
    491      1.23      maxv 	nvmm_vcpu_put(vcpu);
    492      1.23      maxv 	nvmm_machine_put(mach);
    493      1.23      maxv 	kmem_free(data, allocsz);
    494      1.23      maxv 	return error;
    495      1.23      maxv }
    496      1.23      maxv 
    497      1.23      maxv static int
    498      1.14      maxv nvmm_vcpu_setstate(struct nvmm_owner *owner,
    499      1.14      maxv     struct nvmm_ioc_vcpu_setstate *args)
    500       1.1      maxv {
    501       1.1      maxv 	struct nvmm_machine *mach;
    502       1.1      maxv 	struct nvmm_cpu *vcpu;
    503       1.1      maxv 	int error;
    504       1.1      maxv 
    505      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    506       1.6      maxv 	if (error)
    507       1.1      maxv 		return error;
    508       1.1      maxv 
    509       1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    510       1.1      maxv 	if (error)
    511       1.1      maxv 		goto out;
    512       1.1      maxv 
    513      1.19      maxv 	(*nvmm_impl->vcpu_setstate)(vcpu);
    514       1.1      maxv 	nvmm_vcpu_put(vcpu);
    515       1.1      maxv 
    516       1.1      maxv out:
    517       1.1      maxv 	nvmm_machine_put(mach);
    518       1.1      maxv 	return error;
    519       1.1      maxv }
    520       1.1      maxv 
    521       1.1      maxv static int
    522      1.14      maxv nvmm_vcpu_getstate(struct nvmm_owner *owner,
    523      1.14      maxv     struct nvmm_ioc_vcpu_getstate *args)
    524       1.1      maxv {
    525       1.1      maxv 	struct nvmm_machine *mach;
    526       1.1      maxv 	struct nvmm_cpu *vcpu;
    527       1.1      maxv 	int error;
    528       1.1      maxv 
    529      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    530       1.6      maxv 	if (error)
    531       1.1      maxv 		return error;
    532       1.1      maxv 
    533       1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    534       1.1      maxv 	if (error)
    535       1.1      maxv 		goto out;
    536       1.1      maxv 
    537      1.19      maxv 	(*nvmm_impl->vcpu_getstate)(vcpu);
    538       1.1      maxv 	nvmm_vcpu_put(vcpu);
    539       1.1      maxv 
    540       1.1      maxv out:
    541       1.1      maxv 	nvmm_machine_put(mach);
    542       1.1      maxv 	return error;
    543       1.1      maxv }
    544       1.1      maxv 
    545       1.1      maxv static int
    546      1.14      maxv nvmm_vcpu_inject(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_inject *args)
    547       1.1      maxv {
    548       1.1      maxv 	struct nvmm_machine *mach;
    549       1.1      maxv 	struct nvmm_cpu *vcpu;
    550       1.1      maxv 	int error;
    551       1.1      maxv 
    552      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    553       1.1      maxv 	if (error)
    554       1.1      maxv 		return error;
    555       1.1      maxv 
    556       1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    557       1.1      maxv 	if (error)
    558       1.1      maxv 		goto out;
    559       1.1      maxv 
    560      1.20      maxv 	error = (*nvmm_impl->vcpu_inject)(vcpu);
    561       1.1      maxv 	nvmm_vcpu_put(vcpu);
    562       1.1      maxv 
    563       1.1      maxv out:
    564       1.1      maxv 	nvmm_machine_put(mach);
    565       1.1      maxv 	return error;
    566       1.1      maxv }
    567       1.1      maxv 
    568      1.22      maxv static int
    569       1.8      maxv nvmm_do_vcpu_run(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
    570      1.23      maxv     struct nvmm_vcpu_exit *exit)
    571       1.8      maxv {
    572       1.8      maxv 	struct vmspace *vm = mach->vm;
    573      1.22      maxv 	int ret;
    574       1.8      maxv 
    575       1.8      maxv 	while (1) {
    576      1.30      maxv 		/* Got a signal? Or pending resched? Leave. */
    577  1.41.4.1   thorpej 		if (__predict_false(nvmm_return_needed(vcpu, exit))) {
    578      1.30      maxv 			return 0;
    579      1.30      maxv 		}
    580      1.30      maxv 
    581      1.30      maxv 		/* Run the VCPU. */
    582      1.22      maxv 		ret = (*nvmm_impl->vcpu_run)(mach, vcpu, exit);
    583      1.22      maxv 		if (__predict_false(ret != 0)) {
    584      1.22      maxv 			return ret;
    585      1.22      maxv 		}
    586       1.8      maxv 
    587      1.30      maxv 		/* Process nested page faults. */
    588      1.23      maxv 		if (__predict_true(exit->reason != NVMM_VCPU_EXIT_MEMORY)) {
    589       1.8      maxv 			break;
    590       1.8      maxv 		}
    591      1.10      maxv 		if (exit->u.mem.gpa >= mach->gpa_end) {
    592      1.10      maxv 			break;
    593      1.10      maxv 		}
    594      1.11      maxv 		if (uvm_fault(&vm->vm_map, exit->u.mem.gpa, exit->u.mem.prot)) {
    595       1.8      maxv 			break;
    596       1.8      maxv 		}
    597       1.8      maxv 	}
    598      1.22      maxv 
    599      1.22      maxv 	return 0;
    600       1.8      maxv }
    601       1.8      maxv 
    602       1.1      maxv static int
    603      1.14      maxv nvmm_vcpu_run(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_run *args)
    604       1.1      maxv {
    605       1.1      maxv 	struct nvmm_machine *mach;
    606  1.41.4.2   thorpej 	struct nvmm_cpu *vcpu = NULL;
    607       1.1      maxv 	int error;
    608       1.1      maxv 
    609      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    610       1.1      maxv 	if (error)
    611       1.1      maxv 		return error;
    612       1.1      maxv 
    613       1.1      maxv 	error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
    614       1.1      maxv 	if (error)
    615       1.1      maxv 		goto out;
    616       1.1      maxv 
    617      1.22      maxv 	error = nvmm_do_vcpu_run(mach, vcpu, &args->exit);
    618       1.1      maxv 	nvmm_vcpu_put(vcpu);
    619       1.1      maxv 
    620       1.1      maxv out:
    621       1.1      maxv 	nvmm_machine_put(mach);
    622  1.41.4.2   thorpej 	if (vcpu)
    623  1.41.4.2   thorpej 		vcpu->comm->stop = 0;
    624       1.1      maxv 	return error;
    625       1.1      maxv }
    626       1.1      maxv 
    627       1.1      maxv /* -------------------------------------------------------------------------- */
    628       1.1      maxv 
    629       1.4      maxv static struct uvm_object *
    630       1.9      maxv nvmm_hmapping_getuobj(struct nvmm_machine *mach, uintptr_t hva, size_t size,
    631       1.4      maxv    size_t *off)
    632       1.4      maxv {
    633       1.9      maxv 	struct nvmm_hmapping *hmapping;
    634       1.4      maxv 	size_t i;
    635       1.4      maxv 
    636       1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    637       1.9      maxv 		hmapping = &mach->hmap[i];
    638       1.9      maxv 		if (!hmapping->present) {
    639       1.4      maxv 			continue;
    640       1.4      maxv 		}
    641       1.9      maxv 		if (hva >= hmapping->hva &&
    642       1.9      maxv 		    hva + size <= hmapping->hva + hmapping->size) {
    643       1.9      maxv 			*off = hva - hmapping->hva;
    644       1.9      maxv 			return hmapping->uobj;
    645       1.4      maxv 		}
    646       1.4      maxv 	}
    647       1.4      maxv 
    648       1.4      maxv 	return NULL;
    649       1.4      maxv }
    650       1.4      maxv 
    651       1.4      maxv static int
    652       1.9      maxv nvmm_hmapping_validate(struct nvmm_machine *mach, uintptr_t hva, size_t size)
    653       1.4      maxv {
    654       1.9      maxv 	struct nvmm_hmapping *hmapping;
    655       1.4      maxv 	size_t i;
    656       1.4      maxv 
    657       1.4      maxv 	if ((hva % PAGE_SIZE) != 0 || (size % PAGE_SIZE) != 0) {
    658       1.4      maxv 		return EINVAL;
    659       1.4      maxv 	}
    660       1.4      maxv 	if (hva == 0) {
    661       1.4      maxv 		return EINVAL;
    662       1.4      maxv 	}
    663       1.4      maxv 
    664       1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    665       1.9      maxv 		hmapping = &mach->hmap[i];
    666       1.9      maxv 		if (!hmapping->present) {
    667       1.4      maxv 			continue;
    668       1.4      maxv 		}
    669       1.4      maxv 
    670       1.9      maxv 		if (hva >= hmapping->hva &&
    671       1.9      maxv 		    hva + size <= hmapping->hva + hmapping->size) {
    672       1.4      maxv 			break;
    673       1.4      maxv 		}
    674       1.4      maxv 
    675       1.9      maxv 		if (hva >= hmapping->hva &&
    676       1.9      maxv 		    hva < hmapping->hva + hmapping->size) {
    677       1.4      maxv 			return EEXIST;
    678       1.4      maxv 		}
    679       1.9      maxv 		if (hva + size > hmapping->hva &&
    680       1.9      maxv 		    hva + size <= hmapping->hva + hmapping->size) {
    681       1.4      maxv 			return EEXIST;
    682       1.4      maxv 		}
    683       1.9      maxv 		if (hva <= hmapping->hva &&
    684       1.9      maxv 		    hva + size >= hmapping->hva + hmapping->size) {
    685       1.4      maxv 			return EEXIST;
    686       1.4      maxv 		}
    687       1.4      maxv 	}
    688       1.4      maxv 
    689       1.4      maxv 	return 0;
    690       1.4      maxv }
    691       1.4      maxv 
    692       1.9      maxv static struct nvmm_hmapping *
    693       1.9      maxv nvmm_hmapping_alloc(struct nvmm_machine *mach)
    694       1.4      maxv {
    695       1.9      maxv 	struct nvmm_hmapping *hmapping;
    696       1.4      maxv 	size_t i;
    697       1.4      maxv 
    698       1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    699       1.9      maxv 		hmapping = &mach->hmap[i];
    700       1.9      maxv 		if (!hmapping->present) {
    701       1.9      maxv 			hmapping->present = true;
    702       1.9      maxv 			return hmapping;
    703       1.4      maxv 		}
    704       1.4      maxv 	}
    705       1.4      maxv 
    706       1.4      maxv 	return NULL;
    707       1.4      maxv }
    708       1.4      maxv 
    709       1.9      maxv static int
    710       1.9      maxv nvmm_hmapping_free(struct nvmm_machine *mach, uintptr_t hva, size_t size)
    711       1.4      maxv {
    712       1.4      maxv 	struct vmspace *vmspace = curproc->p_vmspace;
    713       1.9      maxv 	struct nvmm_hmapping *hmapping;
    714       1.9      maxv 	size_t i;
    715       1.4      maxv 
    716       1.9      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    717       1.9      maxv 		hmapping = &mach->hmap[i];
    718       1.9      maxv 		if (!hmapping->present || hmapping->hva != hva ||
    719       1.9      maxv 		    hmapping->size != size) {
    720       1.9      maxv 			continue;
    721       1.9      maxv 		}
    722       1.9      maxv 
    723       1.9      maxv 		uvm_unmap(&vmspace->vm_map, hmapping->hva,
    724       1.9      maxv 		    hmapping->hva + hmapping->size);
    725       1.9      maxv 		uao_detach(hmapping->uobj);
    726       1.4      maxv 
    727       1.9      maxv 		hmapping->uobj = NULL;
    728       1.9      maxv 		hmapping->present = false;
    729       1.9      maxv 
    730       1.9      maxv 		return 0;
    731       1.9      maxv 	}
    732       1.9      maxv 
    733       1.9      maxv 	return ENOENT;
    734       1.4      maxv }
    735       1.4      maxv 
    736       1.4      maxv static int
    737      1.14      maxv nvmm_hva_map(struct nvmm_owner *owner, struct nvmm_ioc_hva_map *args)
    738       1.4      maxv {
    739       1.4      maxv 	struct vmspace *vmspace = curproc->p_vmspace;
    740       1.4      maxv 	struct nvmm_machine *mach;
    741       1.9      maxv 	struct nvmm_hmapping *hmapping;
    742       1.4      maxv 	vaddr_t uva;
    743       1.4      maxv 	int error;
    744       1.4      maxv 
    745      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    746       1.4      maxv 	if (error)
    747       1.4      maxv 		return error;
    748       1.4      maxv 
    749       1.9      maxv 	error = nvmm_hmapping_validate(mach, args->hva, args->size);
    750       1.4      maxv 	if (error)
    751       1.4      maxv 		goto out;
    752       1.4      maxv 
    753       1.9      maxv 	hmapping = nvmm_hmapping_alloc(mach);
    754       1.9      maxv 	if (hmapping == NULL) {
    755       1.4      maxv 		error = ENOBUFS;
    756       1.4      maxv 		goto out;
    757       1.4      maxv 	}
    758       1.4      maxv 
    759       1.9      maxv 	hmapping->hva = args->hva;
    760       1.9      maxv 	hmapping->size = args->size;
    761       1.9      maxv 	hmapping->uobj = uao_create(hmapping->size, 0);
    762       1.9      maxv 	uva = hmapping->hva;
    763       1.4      maxv 
    764       1.4      maxv 	/* Take a reference for the user. */
    765       1.9      maxv 	uao_reference(hmapping->uobj);
    766       1.4      maxv 
    767       1.4      maxv 	/* Map the uobj into the user address space, as pageable. */
    768       1.9      maxv 	error = uvm_map(&vmspace->vm_map, &uva, hmapping->size, hmapping->uobj,
    769       1.9      maxv 	    0, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_SHARE,
    770       1.4      maxv 	    UVM_ADV_RANDOM, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
    771       1.4      maxv 	if (error) {
    772       1.9      maxv 		uao_detach(hmapping->uobj);
    773       1.4      maxv 	}
    774       1.4      maxv 
    775       1.4      maxv out:
    776       1.4      maxv 	nvmm_machine_put(mach);
    777       1.4      maxv 	return error;
    778       1.4      maxv }
    779       1.4      maxv 
    780       1.4      maxv static int
    781      1.14      maxv nvmm_hva_unmap(struct nvmm_owner *owner, struct nvmm_ioc_hva_unmap *args)
    782       1.4      maxv {
    783       1.4      maxv 	struct nvmm_machine *mach;
    784       1.4      maxv 	int error;
    785       1.4      maxv 
    786      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, true);
    787       1.4      maxv 	if (error)
    788       1.4      maxv 		return error;
    789       1.4      maxv 
    790       1.9      maxv 	error = nvmm_hmapping_free(mach, args->hva, args->size);
    791       1.4      maxv 
    792       1.4      maxv 	nvmm_machine_put(mach);
    793       1.9      maxv 	return error;
    794       1.4      maxv }
    795       1.4      maxv 
    796       1.4      maxv /* -------------------------------------------------------------------------- */
    797       1.4      maxv 
    798       1.1      maxv static int
    799      1.14      maxv nvmm_gpa_map(struct nvmm_owner *owner, struct nvmm_ioc_gpa_map *args)
    800       1.1      maxv {
    801       1.1      maxv 	struct nvmm_machine *mach;
    802       1.4      maxv 	struct uvm_object *uobj;
    803       1.1      maxv 	gpaddr_t gpa;
    804       1.4      maxv 	size_t off;
    805       1.1      maxv 	int error;
    806       1.1      maxv 
    807      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    808       1.1      maxv 	if (error)
    809       1.1      maxv 		return error;
    810       1.1      maxv 
    811      1.11      maxv 	if ((args->prot & ~(PROT_READ|PROT_WRITE|PROT_EXEC)) != 0) {
    812      1.11      maxv 		error = EINVAL;
    813      1.11      maxv 		goto out;
    814      1.11      maxv 	}
    815      1.11      maxv 
    816       1.1      maxv 	if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0 ||
    817       1.1      maxv 	    (args->hva % PAGE_SIZE) != 0) {
    818       1.1      maxv 		error = EINVAL;
    819       1.1      maxv 		goto out;
    820       1.1      maxv 	}
    821       1.1      maxv 	if (args->hva == 0) {
    822       1.1      maxv 		error = EINVAL;
    823       1.1      maxv 		goto out;
    824       1.1      maxv 	}
    825       1.1      maxv 	if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
    826       1.1      maxv 		error = EINVAL;
    827       1.1      maxv 		goto out;
    828       1.1      maxv 	}
    829       1.1      maxv 	if (args->gpa + args->size <= args->gpa) {
    830       1.1      maxv 		error = EINVAL;
    831       1.1      maxv 		goto out;
    832       1.1      maxv 	}
    833       1.3      maxv 	if (args->gpa + args->size > mach->gpa_end) {
    834       1.1      maxv 		error = EINVAL;
    835       1.1      maxv 		goto out;
    836       1.1      maxv 	}
    837       1.1      maxv 	gpa = args->gpa;
    838       1.1      maxv 
    839       1.9      maxv 	uobj = nvmm_hmapping_getuobj(mach, args->hva, args->size, &off);
    840       1.4      maxv 	if (uobj == NULL) {
    841       1.4      maxv 		error = EINVAL;
    842       1.4      maxv 		goto out;
    843       1.4      maxv 	}
    844       1.4      maxv 
    845       1.4      maxv 	/* Take a reference for the machine. */
    846       1.4      maxv 	uao_reference(uobj);
    847       1.1      maxv 
    848       1.1      maxv 	/* Map the uobj into the machine address space, as pageable. */
    849       1.4      maxv 	error = uvm_map(&mach->vm->vm_map, &gpa, args->size, uobj, off, 0,
    850      1.11      maxv 	    UVM_MAPFLAG(args->prot, UVM_PROT_RWX, UVM_INH_NONE,
    851       1.4      maxv 	    UVM_ADV_RANDOM, UVM_FLAG_FIXED|UVM_FLAG_UNMAP));
    852       1.1      maxv 	if (error) {
    853       1.4      maxv 		uao_detach(uobj);
    854       1.1      maxv 		goto out;
    855       1.1      maxv 	}
    856       1.1      maxv 	if (gpa != args->gpa) {
    857       1.4      maxv 		uao_detach(uobj);
    858       1.1      maxv 		printf("[!] uvm_map problem\n");
    859       1.1      maxv 		error = EINVAL;
    860       1.1      maxv 		goto out;
    861       1.1      maxv 	}
    862       1.1      maxv 
    863       1.1      maxv out:
    864       1.1      maxv 	nvmm_machine_put(mach);
    865       1.1      maxv 	return error;
    866       1.1      maxv }
    867       1.1      maxv 
    868       1.1      maxv static int
    869      1.14      maxv nvmm_gpa_unmap(struct nvmm_owner *owner, struct nvmm_ioc_gpa_unmap *args)
    870       1.1      maxv {
    871       1.1      maxv 	struct nvmm_machine *mach;
    872       1.1      maxv 	gpaddr_t gpa;
    873       1.1      maxv 	int error;
    874       1.1      maxv 
    875      1.14      maxv 	error = nvmm_machine_get(owner, args->machid, &mach, false);
    876       1.1      maxv 	if (error)
    877       1.1      maxv 		return error;
    878       1.1      maxv 
    879       1.1      maxv 	if ((args->gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0) {
    880       1.1      maxv 		error = EINVAL;
    881       1.1      maxv 		goto out;
    882       1.1      maxv 	}
    883       1.1      maxv 	if (args->gpa < mach->gpa_begin || args->gpa >= mach->gpa_end) {
    884       1.1      maxv 		error = EINVAL;
    885       1.1      maxv 		goto out;
    886       1.1      maxv 	}
    887       1.1      maxv 	if (args->gpa + args->size <= args->gpa) {
    888       1.1      maxv 		error = EINVAL;
    889       1.1      maxv 		goto out;
    890       1.1      maxv 	}
    891       1.1      maxv 	if (args->gpa + args->size >= mach->gpa_end) {
    892       1.1      maxv 		error = EINVAL;
    893       1.1      maxv 		goto out;
    894       1.1      maxv 	}
    895       1.1      maxv 	gpa = args->gpa;
    896       1.1      maxv 
    897       1.1      maxv 	/* Unmap the memory from the machine. */
    898       1.1      maxv 	uvm_unmap(&mach->vm->vm_map, gpa, gpa + args->size);
    899       1.1      maxv 
    900       1.1      maxv out:
    901       1.1      maxv 	nvmm_machine_put(mach);
    902       1.1      maxv 	return error;
    903       1.1      maxv }
    904       1.1      maxv 
    905       1.1      maxv /* -------------------------------------------------------------------------- */
    906       1.1      maxv 
    907       1.1      maxv static int
    908      1.24      maxv nvmm_ctl_mach_info(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args)
    909      1.17      maxv {
    910      1.17      maxv 	struct nvmm_ctl_mach_info ctl;
    911      1.17      maxv 	struct nvmm_machine *mach;
    912      1.17      maxv 	int error;
    913      1.17      maxv 	size_t i;
    914      1.17      maxv 
    915      1.17      maxv 	if (args->size != sizeof(ctl))
    916      1.17      maxv 		return EINVAL;
    917      1.17      maxv 	error = copyin(args->data, &ctl, sizeof(ctl));
    918      1.17      maxv 	if (error)
    919      1.17      maxv 		return error;
    920      1.17      maxv 
    921      1.24      maxv 	error = nvmm_machine_get(owner, ctl.machid, &mach, true);
    922      1.17      maxv 	if (error)
    923      1.17      maxv 		return error;
    924      1.17      maxv 
    925      1.36      maxv 	ctl.nvcpus = mach->ncpus;
    926      1.25      maxv 
    927      1.25      maxv 	ctl.nram = 0;
    928      1.25      maxv 	for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
    929      1.25      maxv 		if (!mach->hmap[i].present)
    930      1.25      maxv 			continue;
    931      1.25      maxv 		ctl.nram += mach->hmap[i].size;
    932      1.25      maxv 	}
    933      1.25      maxv 
    934      1.17      maxv 	ctl.pid = mach->owner->pid;
    935      1.17      maxv 	ctl.time = mach->time;
    936      1.17      maxv 
    937      1.17      maxv 	nvmm_machine_put(mach);
    938      1.17      maxv 
    939      1.17      maxv 	error = copyout(&ctl, args->data, sizeof(ctl));
    940      1.17      maxv 	if (error)
    941      1.17      maxv 		return error;
    942      1.17      maxv 
    943      1.17      maxv 	return 0;
    944      1.17      maxv }
    945      1.17      maxv 
    946      1.17      maxv static int
    947      1.17      maxv nvmm_ctl(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args)
    948      1.17      maxv {
    949      1.17      maxv 	switch (args->op) {
    950      1.17      maxv 	case NVMM_CTL_MACH_INFO:
    951      1.24      maxv 		return nvmm_ctl_mach_info(owner, args);
    952      1.17      maxv 	default:
    953      1.17      maxv 		return EINVAL;
    954      1.17      maxv 	}
    955      1.17      maxv }
    956      1.17      maxv 
    957      1.17      maxv /* -------------------------------------------------------------------------- */
    958      1.17      maxv 
    959      1.31      maxv static const struct nvmm_impl *
    960      1.31      maxv nvmm_ident(void)
    961      1.31      maxv {
    962      1.31      maxv 	size_t i;
    963      1.31      maxv 
    964      1.31      maxv 	for (i = 0; i < __arraycount(nvmm_impl_list); i++) {
    965      1.31      maxv 		if ((*nvmm_impl_list[i]->ident)())
    966      1.31      maxv 			return nvmm_impl_list[i];
    967      1.31      maxv 	}
    968      1.31      maxv 
    969      1.31      maxv 	return NULL;
    970      1.31      maxv }
    971      1.31      maxv 
    972      1.17      maxv static int
    973       1.1      maxv nvmm_init(void)
    974       1.1      maxv {
    975       1.1      maxv 	size_t i, n;
    976       1.1      maxv 
    977      1.31      maxv 	nvmm_impl = nvmm_ident();
    978      1.31      maxv 	if (nvmm_impl == NULL)
    979       1.1      maxv 		return ENOTSUP;
    980       1.1      maxv 
    981       1.1      maxv 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
    982       1.1      maxv 		machines[i].machid = i;
    983       1.1      maxv 		rw_init(&machines[i].lock);
    984       1.1      maxv 		for (n = 0; n < NVMM_MAX_VCPUS; n++) {
    985      1.18      maxv 			machines[i].cpus[n].present = false;
    986      1.18      maxv 			machines[i].cpus[n].cpuid = n;
    987       1.1      maxv 			mutex_init(&machines[i].cpus[n].lock, MUTEX_DEFAULT,
    988       1.1      maxv 			    IPL_NONE);
    989       1.1      maxv 		}
    990       1.1      maxv 	}
    991       1.1      maxv 
    992       1.1      maxv 	(*nvmm_impl->init)();
    993       1.1      maxv 
    994       1.1      maxv 	return 0;
    995       1.1      maxv }
    996       1.1      maxv 
    997       1.1      maxv static void
    998       1.1      maxv nvmm_fini(void)
    999       1.1      maxv {
   1000       1.1      maxv 	size_t i, n;
   1001       1.1      maxv 
   1002       1.1      maxv 	for (i = 0; i < NVMM_MAX_MACHINES; i++) {
   1003       1.1      maxv 		rw_destroy(&machines[i].lock);
   1004       1.1      maxv 		for (n = 0; n < NVMM_MAX_VCPUS; n++) {
   1005       1.1      maxv 			mutex_destroy(&machines[i].cpus[n].lock);
   1006       1.1      maxv 		}
   1007       1.1      maxv 	}
   1008       1.1      maxv 
   1009       1.1      maxv 	(*nvmm_impl->fini)();
   1010      1.29      maxv 	nvmm_impl = NULL;
   1011       1.1      maxv }
   1012       1.1      maxv 
   1013       1.1      maxv /* -------------------------------------------------------------------------- */
   1014       1.1      maxv 
   1015      1.14      maxv static dev_type_open(nvmm_open);
   1016      1.14      maxv 
   1017      1.14      maxv const struct cdevsw nvmm_cdevsw = {
   1018      1.14      maxv 	.d_open = nvmm_open,
   1019      1.14      maxv 	.d_close = noclose,
   1020      1.14      maxv 	.d_read = noread,
   1021      1.14      maxv 	.d_write = nowrite,
   1022      1.14      maxv 	.d_ioctl = noioctl,
   1023      1.14      maxv 	.d_stop = nostop,
   1024      1.14      maxv 	.d_tty = notty,
   1025      1.14      maxv 	.d_poll = nopoll,
   1026      1.14      maxv 	.d_mmap = nommap,
   1027      1.14      maxv 	.d_kqfilter = nokqfilter,
   1028      1.14      maxv 	.d_discard = nodiscard,
   1029      1.14      maxv 	.d_flag = D_OTHER | D_MPSAFE
   1030      1.14      maxv };
   1031      1.14      maxv 
   1032      1.14      maxv static int nvmm_ioctl(file_t *, u_long, void *);
   1033      1.14      maxv static int nvmm_close(file_t *);
   1034      1.19      maxv static int nvmm_mmap(file_t *, off_t *, size_t, int, int *, int *,
   1035      1.19      maxv     struct uvm_object **, int *);
   1036      1.14      maxv 
   1037      1.34      maxv static const struct fileops nvmm_fileops = {
   1038      1.14      maxv 	.fo_read = fbadop_read,
   1039      1.14      maxv 	.fo_write = fbadop_write,
   1040      1.14      maxv 	.fo_ioctl = nvmm_ioctl,
   1041      1.14      maxv 	.fo_fcntl = fnullop_fcntl,
   1042      1.14      maxv 	.fo_poll = fnullop_poll,
   1043      1.14      maxv 	.fo_stat = fbadop_stat,
   1044      1.14      maxv 	.fo_close = nvmm_close,
   1045      1.14      maxv 	.fo_kqfilter = fnullop_kqfilter,
   1046      1.14      maxv 	.fo_restart = fnullop_restart,
   1047      1.19      maxv 	.fo_mmap = nvmm_mmap,
   1048      1.14      maxv };
   1049      1.14      maxv 
   1050       1.1      maxv static int
   1051       1.1      maxv nvmm_open(dev_t dev, int flags, int type, struct lwp *l)
   1052       1.1      maxv {
   1053      1.14      maxv 	struct nvmm_owner *owner;
   1054      1.14      maxv 	struct file *fp;
   1055      1.14      maxv 	int error, fd;
   1056      1.14      maxv 
   1057      1.26      maxv 	if (__predict_false(nvmm_impl == NULL))
   1058      1.26      maxv 		return ENXIO;
   1059      1.14      maxv 	if (minor(dev) != 0)
   1060       1.1      maxv 		return EXDEV;
   1061      1.23      maxv 	if (!(flags & O_CLOEXEC))
   1062      1.23      maxv 		return EINVAL;
   1063      1.14      maxv 	error = fd_allocfile(&fp, &fd);
   1064      1.14      maxv 	if (error)
   1065      1.14      maxv 		return error;
   1066      1.14      maxv 
   1067      1.24      maxv 	if (OFLAGS(flags) & O_WRONLY) {
   1068      1.24      maxv 		owner = &root_owner;
   1069      1.24      maxv 	} else {
   1070      1.24      maxv 		owner = kmem_alloc(sizeof(*owner), KM_SLEEP);
   1071      1.24      maxv 		owner->pid = l->l_proc->p_pid;
   1072      1.24      maxv 	}
   1073       1.1      maxv 
   1074      1.14      maxv 	return fd_clone(fp, fd, flags, &nvmm_fileops, owner);
   1075       1.1      maxv }
   1076       1.1      maxv 
   1077       1.1      maxv static int
   1078      1.14      maxv nvmm_close(file_t *fp)
   1079       1.1      maxv {
   1080      1.14      maxv 	struct nvmm_owner *owner = fp->f_data;
   1081       1.1      maxv 
   1082      1.14      maxv 	KASSERT(owner != NULL);
   1083      1.14      maxv 	nvmm_kill_machines(owner);
   1084      1.24      maxv 	if (owner != &root_owner) {
   1085      1.24      maxv 		kmem_free(owner, sizeof(*owner));
   1086      1.24      maxv 	}
   1087      1.14      maxv 	fp->f_data = NULL;
   1088       1.1      maxv 
   1089      1.41      maxv 	return 0;
   1090       1.1      maxv }
   1091       1.1      maxv 
   1092       1.1      maxv static int
   1093      1.19      maxv nvmm_mmap(file_t *fp, off_t *offp, size_t size, int prot, int *flagsp,
   1094      1.19      maxv     int *advicep, struct uvm_object **uobjp, int *maxprotp)
   1095      1.19      maxv {
   1096      1.19      maxv 	struct nvmm_owner *owner = fp->f_data;
   1097      1.19      maxv 	struct nvmm_machine *mach;
   1098      1.19      maxv 	nvmm_machid_t machid;
   1099      1.19      maxv 	nvmm_cpuid_t cpuid;
   1100      1.19      maxv 	int error;
   1101      1.19      maxv 
   1102      1.19      maxv 	if (prot & PROT_EXEC)
   1103      1.19      maxv 		return EACCES;
   1104      1.19      maxv 	if (size != PAGE_SIZE)
   1105      1.19      maxv 		return EINVAL;
   1106      1.19      maxv 
   1107      1.19      maxv 	cpuid = NVMM_COMM_CPUID(*offp);
   1108      1.19      maxv 	if (__predict_false(cpuid >= NVMM_MAX_VCPUS))
   1109      1.19      maxv 		return EINVAL;
   1110      1.19      maxv 
   1111      1.19      maxv 	machid = NVMM_COMM_MACHID(*offp);
   1112      1.19      maxv 	error = nvmm_machine_get(owner, machid, &mach, false);
   1113      1.19      maxv 	if (error)
   1114      1.19      maxv 		return error;
   1115      1.19      maxv 
   1116      1.19      maxv 	uao_reference(mach->commuobj);
   1117      1.19      maxv 	*uobjp = mach->commuobj;
   1118      1.19      maxv 	*offp = cpuid * PAGE_SIZE;
   1119      1.19      maxv 	*maxprotp = prot;
   1120      1.19      maxv 	*advicep = UVM_ADV_RANDOM;
   1121      1.19      maxv 
   1122      1.19      maxv 	nvmm_machine_put(mach);
   1123      1.19      maxv 	return 0;
   1124      1.19      maxv }
   1125      1.19      maxv 
   1126      1.19      maxv static int
   1127      1.14      maxv nvmm_ioctl(file_t *fp, u_long cmd, void *data)
   1128       1.1      maxv {
   1129      1.14      maxv 	struct nvmm_owner *owner = fp->f_data;
   1130      1.14      maxv 
   1131      1.14      maxv 	KASSERT(owner != NULL);
   1132       1.1      maxv 
   1133       1.1      maxv 	switch (cmd) {
   1134       1.1      maxv 	case NVMM_IOC_CAPABILITY:
   1135      1.14      maxv 		return nvmm_capability(owner, data);
   1136       1.1      maxv 	case NVMM_IOC_MACHINE_CREATE:
   1137      1.14      maxv 		return nvmm_machine_create(owner, data);
   1138       1.1      maxv 	case NVMM_IOC_MACHINE_DESTROY:
   1139      1.14      maxv 		return nvmm_machine_destroy(owner, data);
   1140       1.1      maxv 	case NVMM_IOC_MACHINE_CONFIGURE:
   1141      1.14      maxv 		return nvmm_machine_configure(owner, data);
   1142       1.1      maxv 	case NVMM_IOC_VCPU_CREATE:
   1143      1.14      maxv 		return nvmm_vcpu_create(owner, data);
   1144       1.1      maxv 	case NVMM_IOC_VCPU_DESTROY:
   1145      1.14      maxv 		return nvmm_vcpu_destroy(owner, data);
   1146      1.23      maxv 	case NVMM_IOC_VCPU_CONFIGURE:
   1147      1.23      maxv 		return nvmm_vcpu_configure(owner, data);
   1148       1.1      maxv 	case NVMM_IOC_VCPU_SETSTATE:
   1149      1.14      maxv 		return nvmm_vcpu_setstate(owner, data);
   1150       1.1      maxv 	case NVMM_IOC_VCPU_GETSTATE:
   1151      1.14      maxv 		return nvmm_vcpu_getstate(owner, data);
   1152       1.1      maxv 	case NVMM_IOC_VCPU_INJECT:
   1153      1.14      maxv 		return nvmm_vcpu_inject(owner, data);
   1154       1.1      maxv 	case NVMM_IOC_VCPU_RUN:
   1155      1.14      maxv 		return nvmm_vcpu_run(owner, data);
   1156       1.1      maxv 	case NVMM_IOC_GPA_MAP:
   1157      1.14      maxv 		return nvmm_gpa_map(owner, data);
   1158       1.1      maxv 	case NVMM_IOC_GPA_UNMAP:
   1159      1.14      maxv 		return nvmm_gpa_unmap(owner, data);
   1160       1.4      maxv 	case NVMM_IOC_HVA_MAP:
   1161      1.14      maxv 		return nvmm_hva_map(owner, data);
   1162       1.4      maxv 	case NVMM_IOC_HVA_UNMAP:
   1163      1.14      maxv 		return nvmm_hva_unmap(owner, data);
   1164      1.17      maxv 	case NVMM_IOC_CTL:
   1165      1.17      maxv 		return nvmm_ctl(owner, data);
   1166       1.1      maxv 	default:
   1167       1.1      maxv 		return EINVAL;
   1168       1.1      maxv 	}
   1169       1.1      maxv }
   1170       1.1      maxv 
   1171      1.14      maxv /* -------------------------------------------------------------------------- */
   1172       1.1      maxv 
   1173      1.31      maxv static int nvmm_match(device_t, cfdata_t, void *);
   1174      1.31      maxv static void nvmm_attach(device_t, device_t, void *);
   1175      1.31      maxv static int nvmm_detach(device_t, int);
   1176      1.31      maxv 
   1177      1.31      maxv extern struct cfdriver nvmm_cd;
   1178      1.31      maxv 
   1179      1.31      maxv CFATTACH_DECL_NEW(nvmm, 0, nvmm_match, nvmm_attach, nvmm_detach, NULL);
   1180      1.31      maxv 
   1181      1.31      maxv static struct cfdata nvmm_cfdata[] = {
   1182      1.31      maxv 	{
   1183      1.31      maxv 		.cf_name = "nvmm",
   1184      1.31      maxv 		.cf_atname = "nvmm",
   1185      1.31      maxv 		.cf_unit = 0,
   1186      1.31      maxv 		.cf_fstate = FSTATE_STAR,
   1187      1.31      maxv 		.cf_loc = NULL,
   1188      1.31      maxv 		.cf_flags = 0,
   1189      1.31      maxv 		.cf_pspec = NULL,
   1190      1.31      maxv 	},
   1191      1.31      maxv 	{ NULL, NULL, 0, FSTATE_NOTFOUND, NULL, 0, NULL }
   1192      1.31      maxv };
   1193      1.31      maxv 
   1194      1.31      maxv static int
   1195      1.31      maxv nvmm_match(device_t self, cfdata_t cfdata, void *arg)
   1196      1.31      maxv {
   1197      1.31      maxv 	return 1;
   1198      1.31      maxv }
   1199      1.31      maxv 
   1200      1.31      maxv static void
   1201      1.31      maxv nvmm_attach(device_t parent, device_t self, void *aux)
   1202      1.31      maxv {
   1203      1.31      maxv 	int error;
   1204      1.31      maxv 
   1205      1.31      maxv 	error = nvmm_init();
   1206      1.31      maxv 	if (error)
   1207      1.31      maxv 		panic("%s: impossible", __func__);
   1208      1.32      maxv 	aprint_normal_dev(self, "attached, using backend %s\n",
   1209      1.32      maxv 	    nvmm_impl->name);
   1210      1.31      maxv }
   1211      1.31      maxv 
   1212      1.31      maxv static int
   1213      1.31      maxv nvmm_detach(device_t self, int flags)
   1214      1.31      maxv {
   1215      1.35      maxv 	if (atomic_load_relaxed(&nmachines) > 0)
   1216      1.31      maxv 		return EBUSY;
   1217      1.31      maxv 	nvmm_fini();
   1218      1.31      maxv 	return 0;
   1219      1.31      maxv }
   1220      1.31      maxv 
   1221       1.1      maxv void
   1222       1.1      maxv nvmmattach(int nunits)
   1223       1.1      maxv {
   1224       1.1      maxv 	/* nothing */
   1225       1.1      maxv }
   1226       1.1      maxv 
   1227      1.16      maxv MODULE(MODULE_CLASS_MISC, nvmm, NULL);
   1228       1.1      maxv 
   1229      1.31      maxv #if defined(_MODULE)
   1230      1.31      maxv CFDRIVER_DECL(nvmm, DV_VIRTUAL, NULL);
   1231      1.31      maxv #endif
   1232      1.31      maxv 
   1233       1.1      maxv static int
   1234       1.1      maxv nvmm_modcmd(modcmd_t cmd, void *arg)
   1235       1.1      maxv {
   1236      1.31      maxv #if defined(_MODULE)
   1237      1.31      maxv 	devmajor_t bmajor = NODEVMAJOR;
   1238      1.31      maxv 	devmajor_t cmajor = 345;
   1239      1.31      maxv #endif
   1240       1.1      maxv 	int error;
   1241       1.1      maxv 
   1242       1.1      maxv 	switch (cmd) {
   1243       1.1      maxv 	case MODULE_CMD_INIT:
   1244      1.31      maxv 		if (nvmm_ident() == NULL) {
   1245      1.31      maxv 			aprint_error("%s: cpu not supported\n",
   1246      1.31      maxv 			    nvmm_cd.cd_name);
   1247      1.31      maxv 			return ENOTSUP;
   1248      1.31      maxv 		}
   1249      1.31      maxv #if defined(_MODULE)
   1250      1.31      maxv 		error = config_cfdriver_attach(&nvmm_cd);
   1251       1.1      maxv 		if (error)
   1252       1.1      maxv 			return error;
   1253      1.31      maxv #endif
   1254      1.31      maxv 		error = config_cfattach_attach(nvmm_cd.cd_name, &nvmm_ca);
   1255      1.31      maxv 		if (error) {
   1256      1.31      maxv 			config_cfdriver_detach(&nvmm_cd);
   1257      1.31      maxv 			aprint_error("%s: config_cfattach_attach failed\n",
   1258      1.31      maxv 			    nvmm_cd.cd_name);
   1259      1.31      maxv 			return error;
   1260      1.31      maxv 		}
   1261      1.31      maxv 
   1262      1.31      maxv 		error = config_cfdata_attach(nvmm_cfdata, 1);
   1263      1.31      maxv 		if (error) {
   1264      1.31      maxv 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
   1265      1.31      maxv 			config_cfdriver_detach(&nvmm_cd);
   1266      1.31      maxv 			aprint_error("%s: unable to register cfdata\n",
   1267      1.31      maxv 			    nvmm_cd.cd_name);
   1268      1.31      maxv 			return error;
   1269      1.31      maxv 		}
   1270      1.31      maxv 
   1271      1.31      maxv 		if (config_attach_pseudo(nvmm_cfdata) == NULL) {
   1272      1.31      maxv 			aprint_error("%s: config_attach_pseudo failed\n",
   1273      1.31      maxv 			    nvmm_cd.cd_name);
   1274      1.31      maxv 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
   1275      1.31      maxv 			config_cfdriver_detach(&nvmm_cd);
   1276      1.31      maxv 			return ENXIO;
   1277      1.31      maxv 		}
   1278       1.1      maxv 
   1279       1.1      maxv #if defined(_MODULE)
   1280      1.31      maxv 		/* mknod /dev/nvmm c 345 0 */
   1281      1.31      maxv 		error = devsw_attach(nvmm_cd.cd_name, NULL, &bmajor,
   1282      1.31      maxv 			&nvmm_cdevsw, &cmajor);
   1283      1.31      maxv 		if (error) {
   1284      1.31      maxv 			aprint_error("%s: unable to register devsw\n",
   1285      1.31      maxv 			    nvmm_cd.cd_name);
   1286      1.31      maxv 			config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
   1287      1.31      maxv 			config_cfdriver_detach(&nvmm_cd);
   1288      1.31      maxv 			return error;
   1289       1.1      maxv 		}
   1290       1.1      maxv #endif
   1291       1.1      maxv 		return 0;
   1292       1.1      maxv 	case MODULE_CMD_FINI:
   1293      1.31      maxv 		error = config_cfdata_detach(nvmm_cfdata);
   1294      1.31      maxv 		if (error)
   1295      1.31      maxv 			return error;
   1296      1.31      maxv 		error = config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
   1297      1.31      maxv 		if (error)
   1298      1.31      maxv 			return error;
   1299       1.1      maxv #if defined(_MODULE)
   1300      1.31      maxv 		config_cfdriver_detach(&nvmm_cd);
   1301      1.31      maxv 		devsw_detach(NULL, &nvmm_cdevsw);
   1302       1.1      maxv #endif
   1303       1.1      maxv 		return 0;
   1304      1.13      maxv 	case MODULE_CMD_AUTOUNLOAD:
   1305      1.13      maxv 		return EBUSY;
   1306       1.1      maxv 	default:
   1307       1.1      maxv 		return ENOTTY;
   1308       1.1      maxv 	}
   1309       1.1      maxv }
   1310