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