16d65b43dSAaron LI /*
2bfc69df0SAaron LI * Copyright (c) 2018-2021 Maxime Villard, m00nbsd.net
36d65b43dSAaron LI * All rights reserved.
46d65b43dSAaron LI *
57f0e1ce2SAaron LI * This code is part of the NVMM hypervisor.
66d65b43dSAaron LI *
76d65b43dSAaron LI * Redistribution and use in source and binary forms, with or without
86d65b43dSAaron LI * modification, are permitted provided that the following conditions
96d65b43dSAaron LI * are met:
106d65b43dSAaron LI * 1. Redistributions of source code must retain the above copyright
116d65b43dSAaron LI * notice, this list of conditions and the following disclaimer.
126d65b43dSAaron LI * 2. Redistributions in binary form must reproduce the above copyright
136d65b43dSAaron LI * notice, this list of conditions and the following disclaimer in the
146d65b43dSAaron LI * documentation and/or other materials provided with the distribution.
156d65b43dSAaron LI *
167f0e1ce2SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
177f0e1ce2SAaron LI * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
187f0e1ce2SAaron LI * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
197f0e1ce2SAaron LI * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
207f0e1ce2SAaron LI * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
217f0e1ce2SAaron LI * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
227f0e1ce2SAaron LI * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
237f0e1ce2SAaron LI * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
247f0e1ce2SAaron LI * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257f0e1ce2SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267f0e1ce2SAaron LI * SUCH DAMAGE.
276d65b43dSAaron LI */
286d65b43dSAaron LI
296d65b43dSAaron LI #include <sys/param.h>
306d65b43dSAaron LI #include <sys/systm.h>
316d65b43dSAaron LI
32db2e0557SAaron LI #include <sys/kernel.h>
3342862644SAaron LI #include <sys/mman.h>
346d65b43dSAaron LI
35bfc69df0SAaron LI #include "nvmm.h"
36bfc69df0SAaron LI #include "nvmm_internal.h"
37bfc69df0SAaron LI #include "nvmm_ioctl.h"
386d65b43dSAaron LI
396d65b43dSAaron LI static struct nvmm_machine machines[NVMM_MAX_MACHINES];
40002185e5SAaron LI volatile unsigned int nmachines __cacheline_aligned;
416d65b43dSAaron LI
426d65b43dSAaron LI static const struct nvmm_impl *nvmm_impl_list[] = {
436d65b43dSAaron LI #if defined(__x86_64__)
446d65b43dSAaron LI &nvmm_x86_svm, /* x86 AMD SVM */
456d65b43dSAaron LI &nvmm_x86_vmx /* x86 Intel VMX */
466d65b43dSAaron LI #endif
476d65b43dSAaron LI };
486d65b43dSAaron LI
49002185e5SAaron LI const struct nvmm_impl *nvmm_impl __read_mostly = NULL;
506d65b43dSAaron LI
51002185e5SAaron LI struct nvmm_owner nvmm_root_owner;
526d65b43dSAaron LI
536d65b43dSAaron LI /* -------------------------------------------------------------------------- */
546d65b43dSAaron LI
556d65b43dSAaron LI static int
nvmm_machine_alloc(struct nvmm_machine ** ret)566d65b43dSAaron LI nvmm_machine_alloc(struct nvmm_machine **ret)
576d65b43dSAaron LI {
586d65b43dSAaron LI struct nvmm_machine *mach;
596d65b43dSAaron LI size_t i;
606d65b43dSAaron LI
616d65b43dSAaron LI for (i = 0; i < NVMM_MAX_MACHINES; i++) {
626d65b43dSAaron LI mach = &machines[i];
636d65b43dSAaron LI
6442862644SAaron LI os_rwl_wlock(&mach->lock);
656d65b43dSAaron LI if (mach->present) {
6642862644SAaron LI os_rwl_unlock(&mach->lock);
676d65b43dSAaron LI continue;
686d65b43dSAaron LI }
696d65b43dSAaron LI
706d65b43dSAaron LI mach->present = true;
716d65b43dSAaron LI mach->time = time_second;
726d65b43dSAaron LI *ret = mach;
7342862644SAaron LI os_atomic_inc_uint(&nmachines);
746d65b43dSAaron LI return 0;
756d65b43dSAaron LI }
766d65b43dSAaron LI
776d65b43dSAaron LI return ENOBUFS;
786d65b43dSAaron LI }
796d65b43dSAaron LI
806d65b43dSAaron LI static void
nvmm_machine_free(struct nvmm_machine * mach)816d65b43dSAaron LI nvmm_machine_free(struct nvmm_machine *mach)
826d65b43dSAaron LI {
8342862644SAaron LI OS_ASSERT(os_rwl_wheld(&mach->lock));
8442862644SAaron LI OS_ASSERT(mach->present);
856d65b43dSAaron LI mach->present = false;
8642862644SAaron LI os_atomic_dec_uint(&nmachines);
876d65b43dSAaron LI }
886d65b43dSAaron LI
896d65b43dSAaron LI static int
nvmm_machine_get(struct nvmm_owner * owner,nvmm_machid_t machid,struct nvmm_machine ** ret,bool writer)906d65b43dSAaron LI nvmm_machine_get(struct nvmm_owner *owner, nvmm_machid_t machid,
916d65b43dSAaron LI struct nvmm_machine **ret, bool writer)
926d65b43dSAaron LI {
936d65b43dSAaron LI struct nvmm_machine *mach;
946d65b43dSAaron LI
956d65b43dSAaron LI if (__predict_false(machid >= NVMM_MAX_MACHINES)) {
966d65b43dSAaron LI return EINVAL;
976d65b43dSAaron LI }
986d65b43dSAaron LI mach = &machines[machid];
996d65b43dSAaron LI
10042862644SAaron LI if (__predict_false(writer)) {
10142862644SAaron LI os_rwl_wlock(&mach->lock);
10242862644SAaron LI } else {
10342862644SAaron LI os_rwl_rlock(&mach->lock);
10442862644SAaron LI }
1056d65b43dSAaron LI if (__predict_false(!mach->present)) {
10642862644SAaron LI os_rwl_unlock(&mach->lock);
1076d65b43dSAaron LI return ENOENT;
1086d65b43dSAaron LI }
109002185e5SAaron LI if (__predict_false(mach->owner != owner &&
110002185e5SAaron LI owner != &nvmm_root_owner)) {
11142862644SAaron LI os_rwl_unlock(&mach->lock);
1126d65b43dSAaron LI return EPERM;
1136d65b43dSAaron LI }
1146d65b43dSAaron LI *ret = mach;
1156d65b43dSAaron LI
1166d65b43dSAaron LI return 0;
1176d65b43dSAaron LI }
1186d65b43dSAaron LI
1196d65b43dSAaron LI static void
nvmm_machine_put(struct nvmm_machine * mach)1206d65b43dSAaron LI nvmm_machine_put(struct nvmm_machine *mach)
1216d65b43dSAaron LI {
12242862644SAaron LI os_rwl_unlock(&mach->lock);
1236d65b43dSAaron LI }
1246d65b43dSAaron LI
1256d65b43dSAaron LI /* -------------------------------------------------------------------------- */
1266d65b43dSAaron LI
1276d65b43dSAaron LI static int
nvmm_vcpu_alloc(struct nvmm_machine * mach,nvmm_cpuid_t cpuid,struct nvmm_cpu ** ret)1286d65b43dSAaron LI nvmm_vcpu_alloc(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
1296d65b43dSAaron LI struct nvmm_cpu **ret)
1306d65b43dSAaron LI {
1316d65b43dSAaron LI struct nvmm_cpu *vcpu;
1326d65b43dSAaron LI
1336d65b43dSAaron LI if (cpuid >= NVMM_MAX_VCPUS) {
1346d65b43dSAaron LI return EINVAL;
1356d65b43dSAaron LI }
1366d65b43dSAaron LI vcpu = &mach->cpus[cpuid];
1376d65b43dSAaron LI
13842862644SAaron LI os_mtx_lock(&vcpu->lock);
1396d65b43dSAaron LI if (vcpu->present) {
14042862644SAaron LI os_mtx_unlock(&vcpu->lock);
1416d65b43dSAaron LI return EBUSY;
1426d65b43dSAaron LI }
1436d65b43dSAaron LI
1446d65b43dSAaron LI vcpu->present = true;
1456d65b43dSAaron LI vcpu->comm = NULL;
1466d65b43dSAaron LI vcpu->hcpu_last = -1;
1476d65b43dSAaron LI *ret = vcpu;
1486d65b43dSAaron LI return 0;
1496d65b43dSAaron LI }
1506d65b43dSAaron LI
1516d65b43dSAaron LI static void
nvmm_vcpu_free(struct nvmm_machine * mach,struct nvmm_cpu * vcpu)1526d65b43dSAaron LI nvmm_vcpu_free(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
1536d65b43dSAaron LI {
15442862644SAaron LI OS_ASSERT(os_mtx_owned(&vcpu->lock));
1556d65b43dSAaron LI vcpu->present = false;
1566d65b43dSAaron LI if (vcpu->comm != NULL) {
15742862644SAaron LI os_vmobj_unmap(os_kernel_map, (vaddr_t)vcpu->comm,
158d8a75061SAaron LI (vaddr_t)vcpu->comm + NVMM_COMM_PAGE_SIZE, true);
159*cca384e4SAaron LI /*
160*cca384e4SAaron LI * Require userland to unmap the comm page from its address
161*cca384e4SAaron LI * space, because os_curproc_map at this point (fd close)
162*cca384e4SAaron LI * is not guaranteed to be the correct address space.
163*cca384e4SAaron LI */
1641759ebc3SAaron LI }
1656d65b43dSAaron LI }
1666d65b43dSAaron LI
1676d65b43dSAaron LI static int
nvmm_vcpu_get(struct nvmm_machine * mach,nvmm_cpuid_t cpuid,struct nvmm_cpu ** ret)1686d65b43dSAaron LI nvmm_vcpu_get(struct nvmm_machine *mach, nvmm_cpuid_t cpuid,
1696d65b43dSAaron LI struct nvmm_cpu **ret)
1706d65b43dSAaron LI {
1716d65b43dSAaron LI struct nvmm_cpu *vcpu;
1726d65b43dSAaron LI
1736d65b43dSAaron LI if (__predict_false(cpuid >= NVMM_MAX_VCPUS)) {
1746d65b43dSAaron LI return EINVAL;
1756d65b43dSAaron LI }
1766d65b43dSAaron LI vcpu = &mach->cpus[cpuid];
1776d65b43dSAaron LI
17842862644SAaron LI os_mtx_lock(&vcpu->lock);
1796d65b43dSAaron LI if (__predict_false(!vcpu->present)) {
18042862644SAaron LI os_mtx_unlock(&vcpu->lock);
1816d65b43dSAaron LI return ENOENT;
1826d65b43dSAaron LI }
1836d65b43dSAaron LI *ret = vcpu;
1846d65b43dSAaron LI
1856d65b43dSAaron LI return 0;
1866d65b43dSAaron LI }
1876d65b43dSAaron LI
1886d65b43dSAaron LI static void
nvmm_vcpu_put(struct nvmm_cpu * vcpu)1896d65b43dSAaron LI nvmm_vcpu_put(struct nvmm_cpu *vcpu)
1906d65b43dSAaron LI {
19142862644SAaron LI os_mtx_unlock(&vcpu->lock);
1926d65b43dSAaron LI }
1936d65b43dSAaron LI
1946d65b43dSAaron LI /* -------------------------------------------------------------------------- */
1956d65b43dSAaron LI
196002185e5SAaron LI void
nvmm_kill_machines(struct nvmm_owner * owner)1976d65b43dSAaron LI nvmm_kill_machines(struct nvmm_owner *owner)
1986d65b43dSAaron LI {
1996d65b43dSAaron LI struct nvmm_machine *mach;
2006d65b43dSAaron LI struct nvmm_cpu *vcpu;
2016d65b43dSAaron LI size_t i, j;
2026d65b43dSAaron LI int error;
2036d65b43dSAaron LI
2046d65b43dSAaron LI for (i = 0; i < NVMM_MAX_MACHINES; i++) {
2056d65b43dSAaron LI mach = &machines[i];
2066d65b43dSAaron LI
20742862644SAaron LI os_rwl_wlock(&mach->lock);
2086d65b43dSAaron LI if (!mach->present || mach->owner != owner) {
20942862644SAaron LI os_rwl_unlock(&mach->lock);
2106d65b43dSAaron LI continue;
2116d65b43dSAaron LI }
2126d65b43dSAaron LI
2136d65b43dSAaron LI /* Kill it. */
2146d65b43dSAaron LI for (j = 0; j < NVMM_MAX_VCPUS; j++) {
2156d65b43dSAaron LI error = nvmm_vcpu_get(mach, j, &vcpu);
2166d65b43dSAaron LI if (error)
2176d65b43dSAaron LI continue;
2186d65b43dSAaron LI (*nvmm_impl->vcpu_destroy)(mach, vcpu);
2196d65b43dSAaron LI nvmm_vcpu_free(mach, vcpu);
2206d65b43dSAaron LI nvmm_vcpu_put(vcpu);
22142862644SAaron LI os_atomic_dec_uint(&mach->ncpus);
2226d65b43dSAaron LI }
2236d65b43dSAaron LI (*nvmm_impl->machine_destroy)(mach);
22442862644SAaron LI os_vmspace_destroy(mach->vm);
2256d65b43dSAaron LI
226412bdc0aSAaron LI /* Drop the kernel vmobj refs. */
2276d65b43dSAaron LI for (j = 0; j < NVMM_MAX_HMAPPINGS; j++) {
2286d65b43dSAaron LI if (!mach->hmap[j].present)
2296d65b43dSAaron LI continue;
23042862644SAaron LI os_vmobj_rel(mach->hmap[j].vmobj);
2316d65b43dSAaron LI }
2326d65b43dSAaron LI
2336d65b43dSAaron LI nvmm_machine_free(mach);
2346d65b43dSAaron LI
23542862644SAaron LI os_rwl_unlock(&mach->lock);
2366d65b43dSAaron LI }
2376d65b43dSAaron LI }
2386d65b43dSAaron LI
2396d65b43dSAaron LI /* -------------------------------------------------------------------------- */
2406d65b43dSAaron LI
2416d65b43dSAaron LI static int
nvmm_capability(struct nvmm_owner * owner,struct nvmm_ioc_capability * args)2426d65b43dSAaron LI nvmm_capability(struct nvmm_owner *owner, struct nvmm_ioc_capability *args)
2436d65b43dSAaron LI {
2446d65b43dSAaron LI args->cap.version = NVMM_KERN_VERSION;
2456d65b43dSAaron LI args->cap.state_size = nvmm_impl->state_size;
246*cca384e4SAaron LI args->cap.comm_size = NVMM_COMM_PAGE_SIZE;
2476d65b43dSAaron LI args->cap.max_machines = NVMM_MAX_MACHINES;
2486d65b43dSAaron LI args->cap.max_vcpus = NVMM_MAX_VCPUS;
2496d65b43dSAaron LI args->cap.max_ram = NVMM_MAX_RAM;
2506d65b43dSAaron LI
2516d65b43dSAaron LI (*nvmm_impl->capability)(&args->cap);
2526d65b43dSAaron LI
2536d65b43dSAaron LI return 0;
2546d65b43dSAaron LI }
2556d65b43dSAaron LI
2566d65b43dSAaron LI static int
nvmm_machine_create(struct nvmm_owner * owner,struct nvmm_ioc_machine_create * args)2576d65b43dSAaron LI nvmm_machine_create(struct nvmm_owner *owner,
2586d65b43dSAaron LI struct nvmm_ioc_machine_create *args)
2596d65b43dSAaron LI {
2606d65b43dSAaron LI struct nvmm_machine *mach;
2616d65b43dSAaron LI int error;
2626d65b43dSAaron LI
2636d65b43dSAaron LI error = nvmm_machine_alloc(&mach);
2646d65b43dSAaron LI if (error)
2656d65b43dSAaron LI return error;
2666d65b43dSAaron LI
2676d65b43dSAaron LI /* Curproc owns the machine. */
2686d65b43dSAaron LI mach->owner = owner;
2696d65b43dSAaron LI
2706d65b43dSAaron LI /* Zero out the host mappings. */
2716d65b43dSAaron LI memset(&mach->hmap, 0, sizeof(mach->hmap));
2726d65b43dSAaron LI
2736d65b43dSAaron LI /* Create the machine vmspace. */
2746d65b43dSAaron LI mach->gpa_begin = 0;
2756d65b43dSAaron LI mach->gpa_end = NVMM_MAX_RAM;
27642862644SAaron LI mach->vm = os_vmspace_create(mach->gpa_begin, mach->gpa_end);
2779bbbdb7eSAaron LI
278412bdc0aSAaron LI /* Create the comm vmobj. */
279d8a75061SAaron LI mach->commvmobj = os_vmobj_create(
280d8a75061SAaron LI NVMM_MAX_VCPUS * NVMM_COMM_PAGE_SIZE);
2816d65b43dSAaron LI
2826d65b43dSAaron LI (*nvmm_impl->machine_create)(mach);
2836d65b43dSAaron LI
2846d65b43dSAaron LI args->machid = mach->machid;
2856d65b43dSAaron LI nvmm_machine_put(mach);
2866d65b43dSAaron LI
2876d65b43dSAaron LI return 0;
2886d65b43dSAaron LI }
2896d65b43dSAaron LI
2906d65b43dSAaron LI static int
nvmm_machine_destroy(struct nvmm_owner * owner,struct nvmm_ioc_machine_destroy * args)2916d65b43dSAaron LI nvmm_machine_destroy(struct nvmm_owner *owner,
2926d65b43dSAaron LI struct nvmm_ioc_machine_destroy *args)
2936d65b43dSAaron LI {
2946d65b43dSAaron LI struct nvmm_machine *mach;
2956d65b43dSAaron LI struct nvmm_cpu *vcpu;
2966d65b43dSAaron LI int error;
2976d65b43dSAaron LI size_t i;
2986d65b43dSAaron LI
2996d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, true);
3006d65b43dSAaron LI if (error)
3016d65b43dSAaron LI return error;
3026d65b43dSAaron LI
3036d65b43dSAaron LI for (i = 0; i < NVMM_MAX_VCPUS; i++) {
3046d65b43dSAaron LI error = nvmm_vcpu_get(mach, i, &vcpu);
3056d65b43dSAaron LI if (error)
3066d65b43dSAaron LI continue;
3076d65b43dSAaron LI
3086d65b43dSAaron LI (*nvmm_impl->vcpu_destroy)(mach, vcpu);
3096d65b43dSAaron LI nvmm_vcpu_free(mach, vcpu);
3106d65b43dSAaron LI nvmm_vcpu_put(vcpu);
31142862644SAaron LI os_atomic_dec_uint(&mach->ncpus);
3126d65b43dSAaron LI }
3136d65b43dSAaron LI
3146d65b43dSAaron LI (*nvmm_impl->machine_destroy)(mach);
3156d65b43dSAaron LI
3166d65b43dSAaron LI /* Free the machine vmspace. */
31742862644SAaron LI os_vmspace_destroy(mach->vm);
3186d65b43dSAaron LI
319412bdc0aSAaron LI /* Drop the kernel vmobj refs. */
3206d65b43dSAaron LI for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
3216d65b43dSAaron LI if (!mach->hmap[i].present)
3226d65b43dSAaron LI continue;
32342862644SAaron LI os_vmobj_rel(mach->hmap[i].vmobj);
3246d65b43dSAaron LI }
3256d65b43dSAaron LI
3266d65b43dSAaron LI nvmm_machine_free(mach);
3276d65b43dSAaron LI nvmm_machine_put(mach);
3286d65b43dSAaron LI
3296d65b43dSAaron LI return 0;
3306d65b43dSAaron LI }
3316d65b43dSAaron LI
3326d65b43dSAaron LI static int
nvmm_machine_configure(struct nvmm_owner * owner,struct nvmm_ioc_machine_configure * args)3336d65b43dSAaron LI nvmm_machine_configure(struct nvmm_owner *owner,
3346d65b43dSAaron LI struct nvmm_ioc_machine_configure *args)
3356d65b43dSAaron LI {
3366d65b43dSAaron LI struct nvmm_machine *mach;
3376d65b43dSAaron LI size_t allocsz;
3386d65b43dSAaron LI uint64_t op;
3396d65b43dSAaron LI void *data;
3406d65b43dSAaron LI int error;
3416d65b43dSAaron LI
3426d65b43dSAaron LI op = NVMM_MACH_CONF_MD(args->op);
3436d65b43dSAaron LI if (__predict_false(op >= nvmm_impl->mach_conf_max)) {
3446d65b43dSAaron LI return EINVAL;
3456d65b43dSAaron LI }
3466d65b43dSAaron LI
3476d65b43dSAaron LI allocsz = nvmm_impl->mach_conf_sizes[op];
34842862644SAaron LI data = os_mem_alloc(allocsz);
3496d65b43dSAaron LI
3506d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, true);
3516d65b43dSAaron LI if (error) {
35242862644SAaron LI os_mem_free(data, allocsz);
3536d65b43dSAaron LI return error;
3546d65b43dSAaron LI }
3556d65b43dSAaron LI
3566d65b43dSAaron LI error = copyin(args->conf, data, allocsz);
3576d65b43dSAaron LI if (error) {
3586d65b43dSAaron LI goto out;
3596d65b43dSAaron LI }
3606d65b43dSAaron LI
3616d65b43dSAaron LI error = (*nvmm_impl->machine_configure)(mach, op, data);
3626d65b43dSAaron LI
3636d65b43dSAaron LI out:
3646d65b43dSAaron LI nvmm_machine_put(mach);
36542862644SAaron LI os_mem_free(data, allocsz);
3666d65b43dSAaron LI return error;
3676d65b43dSAaron LI }
3686d65b43dSAaron LI
3696d65b43dSAaron LI static int
nvmm_vcpu_create(struct nvmm_owner * owner,struct nvmm_ioc_vcpu_create * args)3706d65b43dSAaron LI nvmm_vcpu_create(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_create *args)
3716d65b43dSAaron LI {
3726d65b43dSAaron LI struct nvmm_machine *mach;
3736d65b43dSAaron LI struct nvmm_cpu *vcpu;
3746d65b43dSAaron LI int error;
3756d65b43dSAaron LI
3766d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
3776d65b43dSAaron LI if (error)
3786d65b43dSAaron LI return error;
3796d65b43dSAaron LI
3806d65b43dSAaron LI error = nvmm_vcpu_alloc(mach, args->cpuid, &vcpu);
3816d65b43dSAaron LI if (error)
3826d65b43dSAaron LI goto out;
3836d65b43dSAaron LI
384412bdc0aSAaron LI /* Map the comm page on the kernel side, as wired. */
385d8a75061SAaron LI error = os_vmobj_map(os_kernel_map, (vaddr_t *)&vcpu->comm,
386d8a75061SAaron LI NVMM_COMM_PAGE_SIZE, mach->commvmobj,
387d8a75061SAaron LI args->cpuid * NVMM_COMM_PAGE_SIZE, true /* wired */,
38842862644SAaron LI false /* !fixed */, true /* shared */, PROT_READ | PROT_WRITE,
38942862644SAaron LI PROT_READ | PROT_WRITE);
3906d65b43dSAaron LI if (error) {
3916d65b43dSAaron LI nvmm_vcpu_free(mach, vcpu);
3926d65b43dSAaron LI nvmm_vcpu_put(vcpu);
3936d65b43dSAaron LI goto out;
3946d65b43dSAaron LI }
39542862644SAaron LI
396d8a75061SAaron LI memset(vcpu->comm, 0, NVMM_COMM_PAGE_SIZE);
3976d65b43dSAaron LI
3989aa070efSAaron LI /* Map the comm page on the user side, as pageable. */
399*cca384e4SAaron LI error = os_vmobj_map(os_curproc_map, (vaddr_t *)&args->comm,
400d8a75061SAaron LI NVMM_COMM_PAGE_SIZE, mach->commvmobj,
401d8a75061SAaron LI args->cpuid * NVMM_COMM_PAGE_SIZE, false /* !wired */,
40242862644SAaron LI false /* !fixed */, true /* shared */, PROT_READ | PROT_WRITE,
40342862644SAaron LI PROT_READ | PROT_WRITE);
4049aa070efSAaron LI if (error) {
4059aa070efSAaron LI nvmm_vcpu_free(mach, vcpu);
4069aa070efSAaron LI nvmm_vcpu_put(vcpu);
4079aa070efSAaron LI goto out;
4089aa070efSAaron LI }
4099aa070efSAaron LI
4106d65b43dSAaron LI error = (*nvmm_impl->vcpu_create)(mach, vcpu);
4116d65b43dSAaron LI if (error) {
4126d65b43dSAaron LI nvmm_vcpu_free(mach, vcpu);
4136d65b43dSAaron LI nvmm_vcpu_put(vcpu);
4146d65b43dSAaron LI goto out;
4156d65b43dSAaron LI }
4166d65b43dSAaron LI
4176d65b43dSAaron LI nvmm_vcpu_put(vcpu);
41842862644SAaron LI os_atomic_inc_uint(&mach->ncpus);
4196d65b43dSAaron LI
4206d65b43dSAaron LI out:
4216d65b43dSAaron LI nvmm_machine_put(mach);
4226d65b43dSAaron LI return error;
4236d65b43dSAaron LI }
4246d65b43dSAaron LI
4256d65b43dSAaron LI static int
nvmm_vcpu_destroy(struct nvmm_owner * owner,struct nvmm_ioc_vcpu_destroy * args)4266d65b43dSAaron LI nvmm_vcpu_destroy(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_destroy *args)
4276d65b43dSAaron LI {
4286d65b43dSAaron LI struct nvmm_machine *mach;
4296d65b43dSAaron LI struct nvmm_cpu *vcpu;
4306d65b43dSAaron LI int error;
4316d65b43dSAaron LI
4326d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
4336d65b43dSAaron LI if (error)
4346d65b43dSAaron LI return error;
4356d65b43dSAaron LI
4366d65b43dSAaron LI error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
4376d65b43dSAaron LI if (error)
4386d65b43dSAaron LI goto out;
4396d65b43dSAaron LI
4406d65b43dSAaron LI (*nvmm_impl->vcpu_destroy)(mach, vcpu);
4416d65b43dSAaron LI nvmm_vcpu_free(mach, vcpu);
4426d65b43dSAaron LI nvmm_vcpu_put(vcpu);
44342862644SAaron LI os_atomic_dec_uint(&mach->ncpus);
4446d65b43dSAaron LI
4456d65b43dSAaron LI out:
4466d65b43dSAaron LI nvmm_machine_put(mach);
4476d65b43dSAaron LI return error;
4486d65b43dSAaron LI }
4496d65b43dSAaron LI
4506d65b43dSAaron LI static int
nvmm_vcpu_configure(struct nvmm_owner * owner,struct nvmm_ioc_vcpu_configure * args)4516d65b43dSAaron LI nvmm_vcpu_configure(struct nvmm_owner *owner,
4526d65b43dSAaron LI struct nvmm_ioc_vcpu_configure *args)
4536d65b43dSAaron LI {
4546d65b43dSAaron LI struct nvmm_machine *mach;
4556d65b43dSAaron LI struct nvmm_cpu *vcpu;
4566d65b43dSAaron LI size_t allocsz;
4576d65b43dSAaron LI uint64_t op;
4586d65b43dSAaron LI void *data;
4596d65b43dSAaron LI int error;
4606d65b43dSAaron LI
4616d65b43dSAaron LI op = NVMM_VCPU_CONF_MD(args->op);
4626d65b43dSAaron LI if (__predict_false(op >= nvmm_impl->vcpu_conf_max))
4636d65b43dSAaron LI return EINVAL;
4646d65b43dSAaron LI
4656d65b43dSAaron LI allocsz = nvmm_impl->vcpu_conf_sizes[op];
46642862644SAaron LI data = os_mem_alloc(allocsz);
4676d65b43dSAaron LI
4686d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
4696d65b43dSAaron LI if (error) {
47042862644SAaron LI os_mem_free(data, allocsz);
4716d65b43dSAaron LI return error;
4726d65b43dSAaron LI }
4736d65b43dSAaron LI
4746d65b43dSAaron LI error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
4756d65b43dSAaron LI if (error) {
4766d65b43dSAaron LI nvmm_machine_put(mach);
47742862644SAaron LI os_mem_free(data, allocsz);
4786d65b43dSAaron LI return error;
4796d65b43dSAaron LI }
4806d65b43dSAaron LI
4816d65b43dSAaron LI error = copyin(args->conf, data, allocsz);
4826d65b43dSAaron LI if (error) {
4836d65b43dSAaron LI goto out;
4846d65b43dSAaron LI }
4856d65b43dSAaron LI
4866d65b43dSAaron LI error = (*nvmm_impl->vcpu_configure)(vcpu, op, data);
4876d65b43dSAaron LI
4886d65b43dSAaron LI out:
4896d65b43dSAaron LI nvmm_vcpu_put(vcpu);
4906d65b43dSAaron LI nvmm_machine_put(mach);
49142862644SAaron LI os_mem_free(data, allocsz);
4926d65b43dSAaron LI return error;
4936d65b43dSAaron LI }
4946d65b43dSAaron LI
4956d65b43dSAaron LI static int
nvmm_vcpu_setstate(struct nvmm_owner * owner,struct nvmm_ioc_vcpu_setstate * args)4966d65b43dSAaron LI nvmm_vcpu_setstate(struct nvmm_owner *owner,
4976d65b43dSAaron LI struct nvmm_ioc_vcpu_setstate *args)
4986d65b43dSAaron LI {
4996d65b43dSAaron LI struct nvmm_machine *mach;
5006d65b43dSAaron LI struct nvmm_cpu *vcpu;
5016d65b43dSAaron LI int error;
5026d65b43dSAaron LI
5036d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
5046d65b43dSAaron LI if (error)
5056d65b43dSAaron LI return error;
5066d65b43dSAaron LI
5076d65b43dSAaron LI error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
5086d65b43dSAaron LI if (error)
5096d65b43dSAaron LI goto out;
5106d65b43dSAaron LI
5116d65b43dSAaron LI (*nvmm_impl->vcpu_setstate)(vcpu);
5126d65b43dSAaron LI nvmm_vcpu_put(vcpu);
5136d65b43dSAaron LI
5146d65b43dSAaron LI out:
5156d65b43dSAaron LI nvmm_machine_put(mach);
5166d65b43dSAaron LI return error;
5176d65b43dSAaron LI }
5186d65b43dSAaron LI
5196d65b43dSAaron LI static int
nvmm_vcpu_getstate(struct nvmm_owner * owner,struct nvmm_ioc_vcpu_getstate * args)5206d65b43dSAaron LI nvmm_vcpu_getstate(struct nvmm_owner *owner,
5216d65b43dSAaron LI struct nvmm_ioc_vcpu_getstate *args)
5226d65b43dSAaron LI {
5236d65b43dSAaron LI struct nvmm_machine *mach;
5246d65b43dSAaron LI struct nvmm_cpu *vcpu;
5256d65b43dSAaron LI int error;
5266d65b43dSAaron LI
5276d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
5286d65b43dSAaron LI if (error)
5296d65b43dSAaron LI return error;
5306d65b43dSAaron LI
5316d65b43dSAaron LI error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
5326d65b43dSAaron LI if (error)
5336d65b43dSAaron LI goto out;
5346d65b43dSAaron LI
5356d65b43dSAaron LI (*nvmm_impl->vcpu_getstate)(vcpu);
5366d65b43dSAaron LI nvmm_vcpu_put(vcpu);
5376d65b43dSAaron LI
5386d65b43dSAaron LI out:
5396d65b43dSAaron LI nvmm_machine_put(mach);
5406d65b43dSAaron LI return error;
5416d65b43dSAaron LI }
5426d65b43dSAaron LI
5436d65b43dSAaron LI static int
nvmm_vcpu_inject(struct nvmm_owner * owner,struct nvmm_ioc_vcpu_inject * args)5446d65b43dSAaron LI nvmm_vcpu_inject(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_inject *args)
5456d65b43dSAaron LI {
5466d65b43dSAaron LI struct nvmm_machine *mach;
5476d65b43dSAaron LI struct nvmm_cpu *vcpu;
5486d65b43dSAaron LI int error;
5496d65b43dSAaron LI
5506d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
5516d65b43dSAaron LI if (error)
5526d65b43dSAaron LI return error;
5536d65b43dSAaron LI
5546d65b43dSAaron LI error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
5556d65b43dSAaron LI if (error)
5566d65b43dSAaron LI goto out;
5576d65b43dSAaron LI
5586d65b43dSAaron LI error = (*nvmm_impl->vcpu_inject)(vcpu);
5596d65b43dSAaron LI nvmm_vcpu_put(vcpu);
5606d65b43dSAaron LI
5616d65b43dSAaron LI out:
5626d65b43dSAaron LI nvmm_machine_put(mach);
5636d65b43dSAaron LI return error;
5646d65b43dSAaron LI }
5656d65b43dSAaron LI
5666d65b43dSAaron LI static int
nvmm_do_vcpu_run(struct nvmm_machine * mach,struct nvmm_cpu * vcpu,struct nvmm_vcpu_exit * exit)5676d65b43dSAaron LI nvmm_do_vcpu_run(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
5686d65b43dSAaron LI struct nvmm_vcpu_exit *exit)
5696d65b43dSAaron LI {
5706d65b43dSAaron LI struct vmspace *vm = mach->vm;
5716d65b43dSAaron LI int ret;
5726d65b43dSAaron LI
5736d65b43dSAaron LI while (1) {
5746d65b43dSAaron LI /* Got a signal? Or pending resched? Leave. */
57542862644SAaron LI if (__predict_false(os_return_needed())) {
5766d65b43dSAaron LI exit->reason = NVMM_VCPU_EXIT_NONE;
5776d65b43dSAaron LI return 0;
5786d65b43dSAaron LI }
5796d65b43dSAaron LI
5806d65b43dSAaron LI /* Run the VCPU. */
5816d65b43dSAaron LI ret = (*nvmm_impl->vcpu_run)(mach, vcpu, exit);
5826d65b43dSAaron LI if (__predict_false(ret != 0)) {
5836d65b43dSAaron LI return ret;
5846d65b43dSAaron LI }
5856d65b43dSAaron LI
5866d65b43dSAaron LI /* Process nested page faults. */
5876d65b43dSAaron LI if (__predict_true(exit->reason != NVMM_VCPU_EXIT_MEMORY)) {
5886d65b43dSAaron LI break;
5896d65b43dSAaron LI }
5906d65b43dSAaron LI if (exit->u.mem.gpa >= mach->gpa_end) {
5916d65b43dSAaron LI break;
5926d65b43dSAaron LI }
59342862644SAaron LI if (os_vmspace_fault(vm, exit->u.mem.gpa, exit->u.mem.prot)) {
5946d65b43dSAaron LI break;
5956d65b43dSAaron LI }
5966d65b43dSAaron LI }
5976d65b43dSAaron LI
5986d65b43dSAaron LI return 0;
5996d65b43dSAaron LI }
6006d65b43dSAaron LI
6016d65b43dSAaron LI static int
nvmm_vcpu_run(struct nvmm_owner * owner,struct nvmm_ioc_vcpu_run * args)6026d65b43dSAaron LI nvmm_vcpu_run(struct nvmm_owner *owner, struct nvmm_ioc_vcpu_run *args)
6036d65b43dSAaron LI {
6046d65b43dSAaron LI struct nvmm_machine *mach;
6056d65b43dSAaron LI struct nvmm_cpu *vcpu;
6066d65b43dSAaron LI int error;
6076d65b43dSAaron LI
6086d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
6096d65b43dSAaron LI if (error)
6106d65b43dSAaron LI return error;
6116d65b43dSAaron LI
6126d65b43dSAaron LI error = nvmm_vcpu_get(mach, args->cpuid, &vcpu);
6136d65b43dSAaron LI if (error)
6146d65b43dSAaron LI goto out;
6156d65b43dSAaron LI
6166d65b43dSAaron LI error = nvmm_do_vcpu_run(mach, vcpu, &args->exit);
6176d65b43dSAaron LI nvmm_vcpu_put(vcpu);
6186d65b43dSAaron LI
6196d65b43dSAaron LI out:
6206d65b43dSAaron LI nvmm_machine_put(mach);
6216d65b43dSAaron LI return error;
6226d65b43dSAaron LI }
6236d65b43dSAaron LI
6246d65b43dSAaron LI /* -------------------------------------------------------------------------- */
6256d65b43dSAaron LI
62642862644SAaron LI static os_vmobj_t *
nvmm_hmapping_getvmobj(struct nvmm_machine * mach,uintptr_t hva,size_t size,size_t * off)627412bdc0aSAaron LI nvmm_hmapping_getvmobj(struct nvmm_machine *mach, uintptr_t hva, size_t size,
6286d65b43dSAaron LI size_t *off)
6296d65b43dSAaron LI {
6306d65b43dSAaron LI struct nvmm_hmapping *hmapping;
6316d65b43dSAaron LI size_t i;
6326d65b43dSAaron LI
6336d65b43dSAaron LI for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
6346d65b43dSAaron LI hmapping = &mach->hmap[i];
6356d65b43dSAaron LI if (!hmapping->present) {
6366d65b43dSAaron LI continue;
6376d65b43dSAaron LI }
6386d65b43dSAaron LI if (hva >= hmapping->hva &&
6396d65b43dSAaron LI hva + size <= hmapping->hva + hmapping->size) {
6406d65b43dSAaron LI *off = hva - hmapping->hva;
641412bdc0aSAaron LI return hmapping->vmobj;
6426d65b43dSAaron LI }
6436d65b43dSAaron LI }
6446d65b43dSAaron LI
6456d65b43dSAaron LI return NULL;
6466d65b43dSAaron LI }
6476d65b43dSAaron LI
6486d65b43dSAaron LI static int
nvmm_hmapping_validate(struct nvmm_machine * mach,uintptr_t hva,size_t size)6496d65b43dSAaron LI nvmm_hmapping_validate(struct nvmm_machine *mach, uintptr_t hva, size_t size)
6506d65b43dSAaron LI {
6516d65b43dSAaron LI struct nvmm_hmapping *hmapping;
6526d65b43dSAaron LI size_t i;
65360ec4ed4SMatthew Dillon uintptr_t hva_end;
65460ec4ed4SMatthew Dillon uintptr_t hmap_end;
6556d65b43dSAaron LI
6566d65b43dSAaron LI if ((hva % PAGE_SIZE) != 0 || (size % PAGE_SIZE) != 0) {
6576d65b43dSAaron LI return EINVAL;
6586d65b43dSAaron LI }
6596d65b43dSAaron LI if (hva == 0) {
6606d65b43dSAaron LI return EINVAL;
6616d65b43dSAaron LI }
6626d65b43dSAaron LI
66360ec4ed4SMatthew Dillon /*
66460ec4ed4SMatthew Dillon * Overflow tests MUST be done very carefully to avoid compiler
66560ec4ed4SMatthew Dillon * optimizations from effectively deleting the test.
66660ec4ed4SMatthew Dillon */
66760ec4ed4SMatthew Dillon hva_end = hva + size;
66860ec4ed4SMatthew Dillon if (hva_end <= hva)
66960ec4ed4SMatthew Dillon return EINVAL;
67060ec4ed4SMatthew Dillon
67160ec4ed4SMatthew Dillon /*
67260ec4ed4SMatthew Dillon * Overlap tests
67360ec4ed4SMatthew Dillon */
6746d65b43dSAaron LI for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
6756d65b43dSAaron LI hmapping = &mach->hmap[i];
67660ec4ed4SMatthew Dillon
6776d65b43dSAaron LI if (!hmapping->present) {
6786d65b43dSAaron LI continue;
6796d65b43dSAaron LI }
68060ec4ed4SMatthew Dillon hmap_end = hmapping->hva + hmapping->size;
6816d65b43dSAaron LI
68260ec4ed4SMatthew Dillon if (hva >= hmapping->hva && hva_end <= hmap_end)
6836d65b43dSAaron LI break;
68460ec4ed4SMatthew Dillon if (hva >= hmapping->hva && hva < hmap_end)
6856d65b43dSAaron LI return EEXIST;
68660ec4ed4SMatthew Dillon if (hva_end > hmapping->hva && hva_end <= hmap_end)
6876d65b43dSAaron LI return EEXIST;
68860ec4ed4SMatthew Dillon if (hva <= hmapping->hva && hva_end >= hmap_end)
6896d65b43dSAaron LI return EEXIST;
6906d65b43dSAaron LI }
6916d65b43dSAaron LI
6926d65b43dSAaron LI return 0;
6936d65b43dSAaron LI }
6946d65b43dSAaron LI
6956d65b43dSAaron LI static struct nvmm_hmapping *
nvmm_hmapping_alloc(struct nvmm_machine * mach)6966d65b43dSAaron LI nvmm_hmapping_alloc(struct nvmm_machine *mach)
6976d65b43dSAaron LI {
6986d65b43dSAaron LI struct nvmm_hmapping *hmapping;
6996d65b43dSAaron LI size_t i;
7006d65b43dSAaron LI
7016d65b43dSAaron LI for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
7026d65b43dSAaron LI hmapping = &mach->hmap[i];
7036d65b43dSAaron LI if (!hmapping->present) {
7046d65b43dSAaron LI hmapping->present = true;
7056d65b43dSAaron LI return hmapping;
7066d65b43dSAaron LI }
7076d65b43dSAaron LI }
7086d65b43dSAaron LI
7096d65b43dSAaron LI return NULL;
7106d65b43dSAaron LI }
7116d65b43dSAaron LI
7126d65b43dSAaron LI static int
nvmm_hmapping_free(struct nvmm_machine * mach,uintptr_t hva,size_t size)7136d65b43dSAaron LI nvmm_hmapping_free(struct nvmm_machine *mach, uintptr_t hva, size_t size)
7146d65b43dSAaron LI {
7156d65b43dSAaron LI struct nvmm_hmapping *hmapping;
7166d65b43dSAaron LI size_t i;
7176d65b43dSAaron LI
7186d65b43dSAaron LI for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
7196d65b43dSAaron LI hmapping = &mach->hmap[i];
7206d65b43dSAaron LI if (!hmapping->present || hmapping->hva != hva ||
7216d65b43dSAaron LI hmapping->size != size) {
7226d65b43dSAaron LI continue;
7236d65b43dSAaron LI }
7246d65b43dSAaron LI
72542862644SAaron LI os_vmobj_unmap(os_curproc_map, hmapping->hva,
72642862644SAaron LI hmapping->hva + hmapping->size, false);
72742862644SAaron LI os_vmobj_rel(hmapping->vmobj);
7286d65b43dSAaron LI
729412bdc0aSAaron LI hmapping->vmobj = NULL;
7306d65b43dSAaron LI hmapping->present = false;
7316d65b43dSAaron LI
7326d65b43dSAaron LI return 0;
7336d65b43dSAaron LI }
7346d65b43dSAaron LI
7356d65b43dSAaron LI return ENOENT;
7366d65b43dSAaron LI }
7376d65b43dSAaron LI
7386d65b43dSAaron LI static int
nvmm_hva_map(struct nvmm_owner * owner,struct nvmm_ioc_hva_map * args)7396d65b43dSAaron LI nvmm_hva_map(struct nvmm_owner *owner, struct nvmm_ioc_hva_map *args)
7406d65b43dSAaron LI {
7416d65b43dSAaron LI struct nvmm_machine *mach;
7426d65b43dSAaron LI struct nvmm_hmapping *hmapping;
7436d65b43dSAaron LI vaddr_t uva;
7446d65b43dSAaron LI int error;
7456d65b43dSAaron LI
7466d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, true);
7476d65b43dSAaron LI if (error)
7486d65b43dSAaron LI return error;
7496d65b43dSAaron LI
7506d65b43dSAaron LI error = nvmm_hmapping_validate(mach, args->hva, args->size);
7516d65b43dSAaron LI if (error)
7526d65b43dSAaron LI goto out;
7536d65b43dSAaron LI
7546d65b43dSAaron LI hmapping = nvmm_hmapping_alloc(mach);
7556d65b43dSAaron LI if (hmapping == NULL) {
7566d65b43dSAaron LI error = ENOBUFS;
7576d65b43dSAaron LI goto out;
7586d65b43dSAaron LI }
7596d65b43dSAaron LI
7606d65b43dSAaron LI hmapping->hva = args->hva;
7616d65b43dSAaron LI hmapping->size = args->size;
76242862644SAaron LI hmapping->vmobj = os_vmobj_create(hmapping->size);
7636d65b43dSAaron LI uva = hmapping->hva;
7646d65b43dSAaron LI
765412bdc0aSAaron LI /* Map the vmobj into the user address space, as pageable. */
76642862644SAaron LI error = os_vmobj_map(os_curproc_map, &uva, hmapping->size,
76742862644SAaron LI hmapping->vmobj, 0, false /* !wired */, true /* fixed */,
76842862644SAaron LI true /* shared */, PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE);
7696d65b43dSAaron LI
7706d65b43dSAaron LI out:
7716d65b43dSAaron LI nvmm_machine_put(mach);
7726d65b43dSAaron LI return error;
7736d65b43dSAaron LI }
7746d65b43dSAaron LI
7756d65b43dSAaron LI static int
nvmm_hva_unmap(struct nvmm_owner * owner,struct nvmm_ioc_hva_unmap * args)7766d65b43dSAaron LI nvmm_hva_unmap(struct nvmm_owner *owner, struct nvmm_ioc_hva_unmap *args)
7776d65b43dSAaron LI {
7786d65b43dSAaron LI struct nvmm_machine *mach;
7796d65b43dSAaron LI int error;
7806d65b43dSAaron LI
7816d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, true);
7826d65b43dSAaron LI if (error)
7836d65b43dSAaron LI return error;
7846d65b43dSAaron LI
7856d65b43dSAaron LI error = nvmm_hmapping_free(mach, args->hva, args->size);
7866d65b43dSAaron LI
7876d65b43dSAaron LI nvmm_machine_put(mach);
7886d65b43dSAaron LI return error;
7896d65b43dSAaron LI }
7906d65b43dSAaron LI
7916d65b43dSAaron LI /* -------------------------------------------------------------------------- */
7926d65b43dSAaron LI
7936d65b43dSAaron LI static int
nvmm_gpa_map(struct nvmm_owner * owner,struct nvmm_ioc_gpa_map * args)7946d65b43dSAaron LI nvmm_gpa_map(struct nvmm_owner *owner, struct nvmm_ioc_gpa_map *args)
7956d65b43dSAaron LI {
7966d65b43dSAaron LI struct nvmm_machine *mach;
79742862644SAaron LI os_vmobj_t *vmobj;
7986d65b43dSAaron LI gpaddr_t gpa;
79960ec4ed4SMatthew Dillon gpaddr_t gpa_end;
8006d65b43dSAaron LI size_t off;
8016d65b43dSAaron LI int error;
8026d65b43dSAaron LI
8036d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
8046d65b43dSAaron LI if (error)
8056d65b43dSAaron LI return error;
8066d65b43dSAaron LI
8076d65b43dSAaron LI if ((args->prot & ~(PROT_READ|PROT_WRITE|PROT_EXEC)) != 0) {
8086d65b43dSAaron LI error = EINVAL;
8096d65b43dSAaron LI goto out;
8106d65b43dSAaron LI }
8116d65b43dSAaron LI
81260ec4ed4SMatthew Dillon /*
81360ec4ed4SMatthew Dillon * Overflow tests MUST be done very carefully to avoid compiler
81460ec4ed4SMatthew Dillon * optimizations from effectively deleting the test.
81560ec4ed4SMatthew Dillon */
81660ec4ed4SMatthew Dillon gpa = args->gpa;
81760ec4ed4SMatthew Dillon gpa_end = gpa + args->size;
81860ec4ed4SMatthew Dillon if (gpa_end <= gpa) {
81960ec4ed4SMatthew Dillon error = EINVAL;
82060ec4ed4SMatthew Dillon goto out;
82160ec4ed4SMatthew Dillon }
82260ec4ed4SMatthew Dillon
82360ec4ed4SMatthew Dillon if ((gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0 ||
8246d65b43dSAaron LI (args->hva % PAGE_SIZE) != 0) {
8256d65b43dSAaron LI error = EINVAL;
8266d65b43dSAaron LI goto out;
8276d65b43dSAaron LI }
8286d65b43dSAaron LI if (args->hva == 0) {
8296d65b43dSAaron LI error = EINVAL;
8306d65b43dSAaron LI goto out;
8316d65b43dSAaron LI }
83260ec4ed4SMatthew Dillon
83360ec4ed4SMatthew Dillon if (gpa < mach->gpa_begin || gpa >= mach->gpa_end) {
8346d65b43dSAaron LI error = EINVAL;
8356d65b43dSAaron LI goto out;
8366d65b43dSAaron LI }
83760ec4ed4SMatthew Dillon if (gpa_end > mach->gpa_end) {
8386d65b43dSAaron LI error = EINVAL;
8396d65b43dSAaron LI goto out;
8406d65b43dSAaron LI }
8416d65b43dSAaron LI
842412bdc0aSAaron LI vmobj = nvmm_hmapping_getvmobj(mach, args->hva, args->size, &off);
843412bdc0aSAaron LI if (vmobj == NULL) {
8446d65b43dSAaron LI error = EINVAL;
8456d65b43dSAaron LI goto out;
8466d65b43dSAaron LI }
8476d65b43dSAaron LI
848412bdc0aSAaron LI /* Map the vmobj into the machine address space, as pageable. */
84942862644SAaron LI error = os_vmobj_map(&mach->vm->vm_map, &gpa, args->size, vmobj, off,
85042862644SAaron LI false /* !wired */, true /* fixed */, false /* !shared */,
85142862644SAaron LI args->prot, PROT_READ | PROT_WRITE | PROT_EXEC);
8526d65b43dSAaron LI
8536d65b43dSAaron LI out:
8546d65b43dSAaron LI nvmm_machine_put(mach);
8556d65b43dSAaron LI return error;
8566d65b43dSAaron LI }
8576d65b43dSAaron LI
8586d65b43dSAaron LI static int
nvmm_gpa_unmap(struct nvmm_owner * owner,struct nvmm_ioc_gpa_unmap * args)8596d65b43dSAaron LI nvmm_gpa_unmap(struct nvmm_owner *owner, struct nvmm_ioc_gpa_unmap *args)
8606d65b43dSAaron LI {
8616d65b43dSAaron LI struct nvmm_machine *mach;
8626d65b43dSAaron LI gpaddr_t gpa;
86360ec4ed4SMatthew Dillon gpaddr_t gpa_end;
8646d65b43dSAaron LI int error;
8656d65b43dSAaron LI
8666d65b43dSAaron LI error = nvmm_machine_get(owner, args->machid, &mach, false);
8676d65b43dSAaron LI if (error)
8686d65b43dSAaron LI return error;
8696d65b43dSAaron LI
87060ec4ed4SMatthew Dillon /*
87160ec4ed4SMatthew Dillon * Overflow tests MUST be done very carefully to avoid compiler
87260ec4ed4SMatthew Dillon * optimizations from effectively deleting the test.
87360ec4ed4SMatthew Dillon */
8746d65b43dSAaron LI gpa = args->gpa;
87560ec4ed4SMatthew Dillon gpa_end = gpa + args->size;
87660ec4ed4SMatthew Dillon if (gpa_end <= gpa) {
87760ec4ed4SMatthew Dillon error = EINVAL;
87860ec4ed4SMatthew Dillon goto out;
87960ec4ed4SMatthew Dillon }
88060ec4ed4SMatthew Dillon
88160ec4ed4SMatthew Dillon if ((gpa % PAGE_SIZE) != 0 || (args->size % PAGE_SIZE) != 0) {
88260ec4ed4SMatthew Dillon error = EINVAL;
88360ec4ed4SMatthew Dillon goto out;
88460ec4ed4SMatthew Dillon }
88560ec4ed4SMatthew Dillon if (gpa < mach->gpa_begin || gpa >= mach->gpa_end) {
88660ec4ed4SMatthew Dillon error = EINVAL;
88760ec4ed4SMatthew Dillon goto out;
88860ec4ed4SMatthew Dillon }
88960ec4ed4SMatthew Dillon if (gpa_end >= mach->gpa_end) {
89060ec4ed4SMatthew Dillon error = EINVAL;
89160ec4ed4SMatthew Dillon goto out;
89260ec4ed4SMatthew Dillon }
8936d65b43dSAaron LI
8946d65b43dSAaron LI /* Unmap the memory from the machine. */
89542862644SAaron LI os_vmobj_unmap(&mach->vm->vm_map, gpa, gpa + args->size, false);
8966d65b43dSAaron LI
8976d65b43dSAaron LI out:
8986d65b43dSAaron LI nvmm_machine_put(mach);
8996d65b43dSAaron LI return error;
9006d65b43dSAaron LI }
9016d65b43dSAaron LI
9026d65b43dSAaron LI /* -------------------------------------------------------------------------- */
9036d65b43dSAaron LI
9046d65b43dSAaron LI static int
nvmm_ctl_mach_info(struct nvmm_owner * owner,struct nvmm_ioc_ctl * args)9056d65b43dSAaron LI nvmm_ctl_mach_info(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args)
9066d65b43dSAaron LI {
9076d65b43dSAaron LI struct nvmm_ctl_mach_info ctl;
9086d65b43dSAaron LI struct nvmm_machine *mach;
9096d65b43dSAaron LI int error;
9106d65b43dSAaron LI size_t i;
9116d65b43dSAaron LI
9126d65b43dSAaron LI if (args->size != sizeof(ctl))
9136d65b43dSAaron LI return EINVAL;
9146d65b43dSAaron LI error = copyin(args->data, &ctl, sizeof(ctl));
9156d65b43dSAaron LI if (error)
9166d65b43dSAaron LI return error;
9176d65b43dSAaron LI
9186d65b43dSAaron LI error = nvmm_machine_get(owner, ctl.machid, &mach, true);
9196d65b43dSAaron LI if (error)
9206d65b43dSAaron LI return error;
9216d65b43dSAaron LI
9226d65b43dSAaron LI ctl.nvcpus = mach->ncpus;
9236d65b43dSAaron LI
9246d65b43dSAaron LI ctl.nram = 0;
9256d65b43dSAaron LI for (i = 0; i < NVMM_MAX_HMAPPINGS; i++) {
9266d65b43dSAaron LI if (!mach->hmap[i].present)
9276d65b43dSAaron LI continue;
9286d65b43dSAaron LI ctl.nram += mach->hmap[i].size;
9296d65b43dSAaron LI }
9306d65b43dSAaron LI
9316d65b43dSAaron LI ctl.pid = mach->owner->pid;
9326d65b43dSAaron LI ctl.time = mach->time;
9336d65b43dSAaron LI
9346d65b43dSAaron LI nvmm_machine_put(mach);
9356d65b43dSAaron LI
9366d65b43dSAaron LI error = copyout(&ctl, args->data, sizeof(ctl));
9376d65b43dSAaron LI if (error)
9386d65b43dSAaron LI return error;
9396d65b43dSAaron LI
9406d65b43dSAaron LI return 0;
9416d65b43dSAaron LI }
9426d65b43dSAaron LI
9436d65b43dSAaron LI static int
nvmm_ctl(struct nvmm_owner * owner,struct nvmm_ioc_ctl * args)9446d65b43dSAaron LI nvmm_ctl(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args)
9456d65b43dSAaron LI {
9466d65b43dSAaron LI switch (args->op) {
9476d65b43dSAaron LI case NVMM_CTL_MACH_INFO:
9486d65b43dSAaron LI return nvmm_ctl_mach_info(owner, args);
9496d65b43dSAaron LI default:
9506d65b43dSAaron LI return EINVAL;
9516d65b43dSAaron LI }
9526d65b43dSAaron LI }
9536d65b43dSAaron LI
9546d65b43dSAaron LI /* -------------------------------------------------------------------------- */
9556d65b43dSAaron LI
956002185e5SAaron LI const struct nvmm_impl *
nvmm_ident(void)9576d65b43dSAaron LI nvmm_ident(void)
9586d65b43dSAaron LI {
9596d65b43dSAaron LI size_t i;
9606d65b43dSAaron LI
9616d65b43dSAaron LI for (i = 0; i < __arraycount(nvmm_impl_list); i++) {
9626d65b43dSAaron LI if ((*nvmm_impl_list[i]->ident)())
9636d65b43dSAaron LI return nvmm_impl_list[i];
9646d65b43dSAaron LI }
9656d65b43dSAaron LI
9666d65b43dSAaron LI return NULL;
9676d65b43dSAaron LI }
9686d65b43dSAaron LI
969002185e5SAaron LI int
nvmm_init(void)9706d65b43dSAaron LI nvmm_init(void)
9716d65b43dSAaron LI {
9726d65b43dSAaron LI size_t i, n;
9736d65b43dSAaron LI
9746d65b43dSAaron LI nvmm_impl = nvmm_ident();
9756d65b43dSAaron LI if (nvmm_impl == NULL)
9766d65b43dSAaron LI return ENOTSUP;
9776d65b43dSAaron LI
9786d65b43dSAaron LI for (i = 0; i < NVMM_MAX_MACHINES; i++) {
9796d65b43dSAaron LI machines[i].machid = i;
98042862644SAaron LI os_rwl_init(&machines[i].lock);
9816d65b43dSAaron LI for (n = 0; n < NVMM_MAX_VCPUS; n++) {
9826d65b43dSAaron LI machines[i].cpus[n].present = false;
9836d65b43dSAaron LI machines[i].cpus[n].cpuid = n;
98442862644SAaron LI os_mtx_init(&machines[i].cpus[n].lock);
9856d65b43dSAaron LI }
9866d65b43dSAaron LI }
9876d65b43dSAaron LI
9886d65b43dSAaron LI (*nvmm_impl->init)();
9896d65b43dSAaron LI
9906d65b43dSAaron LI return 0;
9916d65b43dSAaron LI }
9926d65b43dSAaron LI
993002185e5SAaron LI void
nvmm_fini(void)9946d65b43dSAaron LI nvmm_fini(void)
9956d65b43dSAaron LI {
9966d65b43dSAaron LI size_t i, n;
9976d65b43dSAaron LI
9986d65b43dSAaron LI for (i = 0; i < NVMM_MAX_MACHINES; i++) {
99942862644SAaron LI os_rwl_destroy(&machines[i].lock);
10006d65b43dSAaron LI for (n = 0; n < NVMM_MAX_VCPUS; n++) {
100142862644SAaron LI os_mtx_destroy(&machines[i].cpus[n].lock);
10026d65b43dSAaron LI }
10036d65b43dSAaron LI }
10046d65b43dSAaron LI
10056d65b43dSAaron LI (*nvmm_impl->fini)();
10066d65b43dSAaron LI nvmm_impl = NULL;
10076d65b43dSAaron LI }
10086d65b43dSAaron LI
10096d65b43dSAaron LI /* -------------------------------------------------------------------------- */
10106d65b43dSAaron LI
1011002185e5SAaron LI int
nvmm_ioctl(struct nvmm_owner * owner,unsigned long cmd,void * data)101242862644SAaron LI nvmm_ioctl(struct nvmm_owner *owner, unsigned long cmd, void *data)
10136d65b43dSAaron LI {
10146d65b43dSAaron LI switch (cmd) {
10156d65b43dSAaron LI case NVMM_IOC_CAPABILITY:
10166d65b43dSAaron LI return nvmm_capability(owner, data);
10176d65b43dSAaron LI case NVMM_IOC_MACHINE_CREATE:
10186d65b43dSAaron LI return nvmm_machine_create(owner, data);
10196d65b43dSAaron LI case NVMM_IOC_MACHINE_DESTROY:
10206d65b43dSAaron LI return nvmm_machine_destroy(owner, data);
10216d65b43dSAaron LI case NVMM_IOC_MACHINE_CONFIGURE:
10226d65b43dSAaron LI return nvmm_machine_configure(owner, data);
10236d65b43dSAaron LI case NVMM_IOC_VCPU_CREATE:
10246d65b43dSAaron LI return nvmm_vcpu_create(owner, data);
10256d65b43dSAaron LI case NVMM_IOC_VCPU_DESTROY:
10266d65b43dSAaron LI return nvmm_vcpu_destroy(owner, data);
10276d65b43dSAaron LI case NVMM_IOC_VCPU_CONFIGURE:
10286d65b43dSAaron LI return nvmm_vcpu_configure(owner, data);
10296d65b43dSAaron LI case NVMM_IOC_VCPU_SETSTATE:
10306d65b43dSAaron LI return nvmm_vcpu_setstate(owner, data);
10316d65b43dSAaron LI case NVMM_IOC_VCPU_GETSTATE:
10326d65b43dSAaron LI return nvmm_vcpu_getstate(owner, data);
10336d65b43dSAaron LI case NVMM_IOC_VCPU_INJECT:
10346d65b43dSAaron LI return nvmm_vcpu_inject(owner, data);
10356d65b43dSAaron LI case NVMM_IOC_VCPU_RUN:
10366d65b43dSAaron LI return nvmm_vcpu_run(owner, data);
10376d65b43dSAaron LI case NVMM_IOC_GPA_MAP:
10386d65b43dSAaron LI return nvmm_gpa_map(owner, data);
10396d65b43dSAaron LI case NVMM_IOC_GPA_UNMAP:
10406d65b43dSAaron LI return nvmm_gpa_unmap(owner, data);
10416d65b43dSAaron LI case NVMM_IOC_HVA_MAP:
10426d65b43dSAaron LI return nvmm_hva_map(owner, data);
10436d65b43dSAaron LI case NVMM_IOC_HVA_UNMAP:
10446d65b43dSAaron LI return nvmm_hva_unmap(owner, data);
10456d65b43dSAaron LI case NVMM_IOC_CTL:
10466d65b43dSAaron LI return nvmm_ctl(owner, data);
10476d65b43dSAaron LI default:
10486d65b43dSAaron LI return EINVAL;
10496d65b43dSAaron LI }
10506d65b43dSAaron LI }
1051