Sat Aug 29 07:14:17 2020 UTC ()
nvmm: explicitly include atomic.h


(maxv)
diff -r1.36 -r1.37 src/sys/dev/nvmm/nvmm.c

cvs diff -r1.36 -r1.37 src/sys/dev/nvmm/nvmm.c (switch to unified diff)

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