2 * Copyright (c) 2021 Maxime Villard, m00nbsd.net
5 * This code is part of the NVMM hypervisor.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
36 #include "nvmm_internal.h"
39 os_vmspace_create(vaddr_t vmin, vaddr_t vmax)
41 return uvmspace_alloc(vmin, vmax, false);
45 os_vmspace_destroy(os_vmspace_t *vm)
51 os_vmspace_fault(os_vmspace_t *vm, vaddr_t va, vm_prot_t prot)
53 return uvm_fault(&vm->vm_map, va, prot);
57 os_vmobj_create(voff_t size)
59 return uao_create(size, 0);
63 os_vmobj_ref(os_vmobj_t *vmobj)
69 os_vmobj_rel(os_vmobj_t *vmobj)
75 os_vmobj_map(struct vm_map *map, vaddr_t *addr, vsize_t size, os_vmobj_t *vmobj,
76 voff_t offset, bool wired, bool fixed, bool shared, int prot, int maxprot)
78 uvm_flag_t uflags, uprot, umaxprot;
85 if (prot & PROT_WRITE)
90 /* Convert maxprot. */
92 if (maxprot & PROT_READ)
93 umaxprot |= UVM_PROT_R;
94 if (maxprot & PROT_WRITE)
95 umaxprot |= UVM_PROT_W;
96 if (maxprot & PROT_EXEC)
97 umaxprot |= UVM_PROT_X;
99 uflags = UVM_MAPFLAG(uprot, umaxprot,
100 shared ? UVM_INH_SHARE : UVM_INH_NONE, UVM_ADV_RANDOM,
101 fixed ? (UVM_FLAG_FIXED | UVM_FLAG_UNMAP) : 0);
104 /* Need to provide a hint. */
105 if (map == os_curproc_map) {
106 *addr = curproc->p_emul->e_vm_default_addr(curproc,
107 (vaddr_t)curproc->p_vmspace->vm_daddr, size,
108 curproc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN);
114 /* Get a reference to the object. */
118 * Map the object. This consumes the reference on success only. On
119 * failure we must drop the reference manually.
121 error = uvm_map(map, addr, size, vmobj, offset, 0, uflags);
129 error = uvm_map_pageable(map, *addr, *addr + size, false, 0);
131 os_vmobj_unmap(map, *addr, *addr + size, false);
140 os_vmobj_unmap(struct vm_map *map, vaddr_t start, vaddr_t end,
143 uvm_unmap(map, start, end);
147 os_pagemem_zalloc(size_t size)
151 ret = (void *)uvm_km_alloc(kernel_map, roundup(size, PAGE_SIZE), 0,
152 UVM_KMF_WIRED | UVM_KMF_ZERO);
154 OS_ASSERT((uintptr_t)ret % PAGE_SIZE == 0);
160 os_pagemem_free(void *ptr, size_t size)
162 uvm_km_free(kernel_map, (vaddr_t)ptr, roundup(size, PAGE_SIZE),
171 pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
173 return VM_PAGE_TO_PHYS(pg);
177 os_pa_free(paddr_t pa)
179 uvm_pagefree(PHYS_TO_VM_PAGE(pa));
183 os_contigpa_zalloc(paddr_t *pa, vaddr_t *va, size_t npages)
185 struct pglist pglist;
191 ret = uvm_pglistalloc(npages * PAGE_SIZE, 0, ~0UL, PAGE_SIZE, 0,
195 _pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist));
196 _va = uvm_km_alloc(kernel_map, npages * PAGE_SIZE, 0,
197 UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
201 for (i = 0; i < npages; i++) {
202 pmap_kenter_pa(_va + i * PAGE_SIZE, _pa + i * PAGE_SIZE,
203 VM_PROT_READ | VM_PROT_WRITE, PMAP_WRITE_BACK);
205 pmap_update(pmap_kernel());
207 memset((void *)_va, 0, npages * PAGE_SIZE);
214 for (i = 0; i < npages; i++) {
215 uvm_pagefree(PHYS_TO_VM_PAGE(_pa + i * PAGE_SIZE));
221 os_contigpa_free(paddr_t pa, vaddr_t va, size_t npages)
225 pmap_kremove(va, npages * PAGE_SIZE);
226 pmap_update(pmap_kernel());
227 uvm_km_free(kernel_map, va, npages * PAGE_SIZE, UVM_KMF_VAONLY);
228 for (i = 0; i < npages; i++) {
229 uvm_pagefree(PHYS_TO_VM_PAGE(pa + i * PAGE_SIZE));
233 /* -------------------------------------------------------------------------- */
235 #include <sys/conf.h>
236 #include <sys/device.h>
237 #include <sys/file.h>
238 #include <sys/filedesc.h>
239 #include <sys/module.h>
243 static dev_type_open(nbsd_nvmm_open);
244 static int nbsd_nvmm_ioctl(file_t *, u_long, void *);
245 static int nbsd_nvmm_close(file_t *);
247 const struct cdevsw nvmm_cdevsw = {
248 .d_open = nbsd_nvmm_open,
257 .d_kqfilter = nokqfilter,
258 .d_discard = nodiscard,
259 .d_flag = D_OTHER | D_MPSAFE
262 static const struct fileops nvmm_fileops = {
263 .fo_read = fbadop_read,
264 .fo_write = fbadop_write,
265 .fo_ioctl = nbsd_nvmm_ioctl,
266 .fo_fcntl = fnullop_fcntl,
267 .fo_poll = fnullop_poll,
268 .fo_stat = fbadop_stat,
269 .fo_close = nbsd_nvmm_close,
270 .fo_kqfilter = fnullop_kqfilter,
271 .fo_restart = fnullop_restart,
276 nbsd_nvmm_open(dev_t dev, int flags, int type, struct lwp *l)
278 struct nvmm_owner *owner;
282 if (__predict_false(nvmm_impl == NULL))
286 if (!(flags & O_CLOEXEC))
288 error = fd_allocfile(&fp, &fd);
292 if (OFLAGS(flags) & O_WRONLY) {
293 owner = &nvmm_root_owner;
295 owner = os_mem_alloc(sizeof(*owner));
296 owner->pid = l->l_proc->p_pid;
299 return fd_clone(fp, fd, flags, &nvmm_fileops, owner);
303 nbsd_nvmm_ioctl(file_t *fp, u_long cmd, void *data)
305 struct nvmm_owner *owner = fp->f_data;
307 OS_ASSERT(owner != NULL);
309 return nvmm_ioctl(owner, cmd, data);
313 nbsd_nvmm_close(file_t *fp)
315 struct nvmm_owner *owner = fp->f_data;
317 OS_ASSERT(owner != NULL);
318 nvmm_kill_machines(owner);
319 if (owner != &nvmm_root_owner) {
320 os_mem_free(owner, sizeof(*owner));
327 /* -------------------------------------------------------------------------- */
329 static int nvmm_match(device_t, cfdata_t, void *);
330 static void nvmm_attach(device_t, device_t, void *);
331 static int nvmm_detach(device_t, int);
333 extern struct cfdriver nvmm_cd;
335 CFATTACH_DECL_NEW(nvmm, 0, nvmm_match, nvmm_attach, nvmm_detach, NULL);
337 static struct cfdata nvmm_cfdata[] = {
342 .cf_fstate = FSTATE_STAR,
347 { NULL, NULL, 0, FSTATE_NOTFOUND, NULL, 0, NULL }
351 nvmm_match(device_t self, cfdata_t cfdata, void *arg)
357 nvmm_attach(device_t parent, device_t self, void *aux)
363 panic("%s: impossible", __func__);
364 aprint_normal_dev(self, "attached, using backend %s\n",
369 nvmm_detach(device_t self, int flags)
371 if (os_atomic_load_uint(&nmachines) > 0)
378 nvmmattach(int nunits)
383 MODULE(MODULE_CLASS_DRIVER, nvmm, NULL);
386 CFDRIVER_DECL(nvmm, DV_VIRTUAL, NULL);
390 nvmm_modcmd(modcmd_t cmd, void *arg)
393 devmajor_t bmajor = NODEVMAJOR;
394 devmajor_t cmajor = 345;
399 case MODULE_CMD_INIT:
400 if (nvmm_ident() == NULL) {
401 aprint_error("%s: cpu not supported\n",
406 error = config_cfdriver_attach(&nvmm_cd);
410 error = config_cfattach_attach(nvmm_cd.cd_name, &nvmm_ca);
412 config_cfdriver_detach(&nvmm_cd);
413 aprint_error("%s: config_cfattach_attach failed\n",
418 error = config_cfdata_attach(nvmm_cfdata, 1);
420 config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
421 config_cfdriver_detach(&nvmm_cd);
422 aprint_error("%s: unable to register cfdata\n",
427 if (config_attach_pseudo(nvmm_cfdata) == NULL) {
428 aprint_error("%s: config_attach_pseudo failed\n",
430 config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
431 config_cfdriver_detach(&nvmm_cd);
436 /* mknod /dev/nvmm c 345 0 */
437 error = devsw_attach(nvmm_cd.cd_name, NULL, &bmajor,
438 &nvmm_cdevsw, &cmajor);
440 aprint_error("%s: unable to register devsw\n",
442 config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
443 config_cfdriver_detach(&nvmm_cd);
448 case MODULE_CMD_FINI:
449 error = config_cfdata_detach(nvmm_cfdata);
452 error = config_cfattach_detach(nvmm_cd.cd_name, &nvmm_ca);
456 config_cfdriver_detach(&nvmm_cd);
457 devsw_detach(NULL, &nvmm_cdevsw);
460 case MODULE_CMD_AUTOUNLOAD: