xref: /dflybsd-src/sys/dev/virtual/nvmm/nvmm_dragonfly.c (revision 24f14bf420a8b016f2534fd3c7f3b9e45ce582e3)
1df3af4c9SAaron LI /*-
2df3af4c9SAaron LI  * SPDX-License-Identifier: BSD-3-Clause
3df3af4c9SAaron LI  *
4df3af4c9SAaron LI  * Copyright (c) 2021 The DragonFly Project.  All rights reserved.
5df3af4c9SAaron LI  *
6df3af4c9SAaron LI  * This code is derived from software contributed to The DragonFly Project
7df3af4c9SAaron LI  * by Aaron LI <aly@aaronly.me>
8df3af4c9SAaron LI  *
9df3af4c9SAaron LI  * Redistribution and use in source and binary forms, with or without
10df3af4c9SAaron LI  * modification, are permitted provided that the following conditions
11df3af4c9SAaron LI  * are met:
12df3af4c9SAaron LI  *
13df3af4c9SAaron LI  * 1. Redistributions of source code must retain the above copyright
14df3af4c9SAaron LI  *    notice, this list of conditions and the following disclaimer.
15df3af4c9SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
16df3af4c9SAaron LI  *    notice, this list of conditions and the following disclaimer in
17df3af4c9SAaron LI  *    the documentation and/or other materials provided with the
18df3af4c9SAaron LI  *    distribution.
19df3af4c9SAaron LI  * 3. Neither the name of The DragonFly Project nor the names of its
20df3af4c9SAaron LI  *    contributors may be used to endorse or promote products derived
21df3af4c9SAaron LI  *    from this software without specific, prior written permission.
22df3af4c9SAaron LI  *
23df3af4c9SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24df3af4c9SAaron LI  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25df3af4c9SAaron LI  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26df3af4c9SAaron LI  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27df3af4c9SAaron LI  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28df3af4c9SAaron LI  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29df3af4c9SAaron LI  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30df3af4c9SAaron LI  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31df3af4c9SAaron LI  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32df3af4c9SAaron LI  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33df3af4c9SAaron LI  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df3af4c9SAaron LI  * SUCH DAMAGE.
35df3af4c9SAaron LI  */
36df3af4c9SAaron LI 
37df3af4c9SAaron LI #include <sys/param.h>
38df3af4c9SAaron LI #include <sys/systm.h>
39df3af4c9SAaron LI #include <sys/kernel.h>
40df3af4c9SAaron LI #include <sys/mman.h>
41df3af4c9SAaron LI 
42002185e5SAaron LI #include "nvmm.h"
43df3af4c9SAaron LI #include "nvmm_os.h"
44002185e5SAaron LI #include "nvmm_internal.h"
45df3af4c9SAaron LI 
46df3af4c9SAaron LI MALLOC_DEFINE(M_NVMM, "nvmm", "NVMM data");
47df3af4c9SAaron LI 
48df3af4c9SAaron LI /*
49df3af4c9SAaron LI  * NVMM expects VM functions to return 0 on success, but DragonFly's VM
50df3af4c9SAaron LI  * functions return KERN_SUCCESS.  Although it's also defined to be 0,
51df3af4c9SAaron LI  * assert it to be future-proofing.
52df3af4c9SAaron LI  */
53df3af4c9SAaron LI CTASSERT(KERN_SUCCESS == 0);
54df3af4c9SAaron LI 
55df3af4c9SAaron LI os_vmspace_t *
os_vmspace_create(vaddr_t vmin,vaddr_t vmax)56df3af4c9SAaron LI os_vmspace_create(vaddr_t vmin, vaddr_t vmax)
57df3af4c9SAaron LI {
58*24f14bf4SAaron LI 	struct vmspace *vm;
59*24f14bf4SAaron LI 
60*24f14bf4SAaron LI 	vm = vmspace_alloc(vmin, vmax);
61*24f14bf4SAaron LI 
62*24f14bf4SAaron LI 	/*
63*24f14bf4SAaron LI 	 * Set PMAP_MULTI on the backing pmap for the machine.  Only
64*24f14bf4SAaron LI 	 * pmap changes to the backing pmap for the machine affect the
65*24f14bf4SAaron LI 	 * guest.  Changes to the host's pmap do not affect the guest's
66*24f14bf4SAaron LI 	 * backing pmap.
67*24f14bf4SAaron LI 	 */
68*24f14bf4SAaron LI 	pmap_maybethreaded(&vm->vm_pmap);
69*24f14bf4SAaron LI 
70*24f14bf4SAaron LI 	return vm;
71df3af4c9SAaron LI }
72df3af4c9SAaron LI 
73df3af4c9SAaron LI void
os_vmspace_destroy(os_vmspace_t * vm)74df3af4c9SAaron LI os_vmspace_destroy(os_vmspace_t *vm)
75df3af4c9SAaron LI {
76df3af4c9SAaron LI 	pmap_del_all_cpus(vm);
77df3af4c9SAaron LI 	vmspace_rel(vm);
78df3af4c9SAaron LI }
79df3af4c9SAaron LI 
80df3af4c9SAaron LI int
os_vmspace_fault(os_vmspace_t * vm,vaddr_t va,vm_prot_t prot)81df3af4c9SAaron LI os_vmspace_fault(os_vmspace_t *vm, vaddr_t va, vm_prot_t prot)
82df3af4c9SAaron LI {
83df3af4c9SAaron LI 	int fault_flags;
84df3af4c9SAaron LI 
85df3af4c9SAaron LI 	if (prot & VM_PROT_WRITE)
86df3af4c9SAaron LI 		fault_flags = VM_FAULT_DIRTY;
87df3af4c9SAaron LI 	else
88df3af4c9SAaron LI 		fault_flags = VM_FAULT_NORMAL;
89df3af4c9SAaron LI 
90df3af4c9SAaron LI 	return vm_fault(&vm->vm_map, trunc_page(va), prot, fault_flags);
91df3af4c9SAaron LI }
92df3af4c9SAaron LI 
93df3af4c9SAaron LI os_vmobj_t *
os_vmobj_create(voff_t size)94df3af4c9SAaron LI os_vmobj_create(voff_t size)
95df3af4c9SAaron LI {
96df3af4c9SAaron LI 	struct vm_object *object;
97df3af4c9SAaron LI 
98df3af4c9SAaron LI 	object = default_pager_alloc(NULL, size, VM_PROT_DEFAULT, 0);
99df3af4c9SAaron LI 	vm_object_set_flag(object, OBJ_NOSPLIT);
100df3af4c9SAaron LI 
101df3af4c9SAaron LI 	return object;
102df3af4c9SAaron LI }
103df3af4c9SAaron LI 
104df3af4c9SAaron LI void
os_vmobj_ref(os_vmobj_t * vmobj)105df3af4c9SAaron LI os_vmobj_ref(os_vmobj_t *vmobj)
106df3af4c9SAaron LI {
107df3af4c9SAaron LI 	vm_object_hold(vmobj);
108df3af4c9SAaron LI 	vm_object_reference_locked(vmobj);
109df3af4c9SAaron LI 	vm_object_drop(vmobj);
110df3af4c9SAaron LI }
111df3af4c9SAaron LI 
112df3af4c9SAaron LI void
os_vmobj_rel(os_vmobj_t * vmobj)113df3af4c9SAaron LI os_vmobj_rel(os_vmobj_t *vmobj)
114df3af4c9SAaron LI {
115df3af4c9SAaron LI 	vm_object_deallocate(vmobj);
116df3af4c9SAaron LI }
117df3af4c9SAaron LI 
118df3af4c9SAaron LI int
os_vmobj_map(struct vm_map * map,vaddr_t * addr,vsize_t size,os_vmobj_t * vmobj,voff_t offset,bool wired,bool fixed,bool shared,int prot,int maxprot)119df3af4c9SAaron LI os_vmobj_map(struct vm_map *map, vaddr_t *addr, vsize_t size, os_vmobj_t *vmobj,
120df3af4c9SAaron LI     voff_t offset, bool wired, bool fixed, bool shared, int prot, int maxprot)
121df3af4c9SAaron LI {
122df3af4c9SAaron LI 	vm_prot_t vmprot, vmmaxprot;
123df3af4c9SAaron LI 	vm_inherit_t inherit;
124df3af4c9SAaron LI 	vm_offset_t start = *addr;
125df3af4c9SAaron LI 	int rv = KERN_SUCCESS;
126df3af4c9SAaron LI 	int count;
127df3af4c9SAaron LI 
128df3af4c9SAaron LI 	/* Convert prot. */
129df3af4c9SAaron LI 	vmprot = 0;
130df3af4c9SAaron LI 	if (prot & PROT_READ)
131df3af4c9SAaron LI 		vmprot |= VM_PROT_READ;
132df3af4c9SAaron LI 	if (prot & PROT_WRITE)
133df3af4c9SAaron LI 		vmprot |= VM_PROT_WRITE;
134df3af4c9SAaron LI 	if (prot & PROT_EXEC)
135df3af4c9SAaron LI 		vmprot |= VM_PROT_EXECUTE;
136df3af4c9SAaron LI 
137df3af4c9SAaron LI 	/* Convert maxprot. */
138df3af4c9SAaron LI 	vmmaxprot = 0;
139df3af4c9SAaron LI 	if (maxprot & PROT_READ)
140df3af4c9SAaron LI 		vmmaxprot |= VM_PROT_READ;
141df3af4c9SAaron LI 	if (maxprot & PROT_WRITE)
142df3af4c9SAaron LI 		vmmaxprot |= VM_PROT_WRITE;
143df3af4c9SAaron LI 	if (maxprot & PROT_EXEC)
144df3af4c9SAaron LI 		vmmaxprot |= VM_PROT_EXECUTE;
145df3af4c9SAaron LI 
146df3af4c9SAaron LI 	count = vm_map_entry_reserve(MAP_RESERVE_COUNT);
147df3af4c9SAaron LI 	vm_map_lock(map);
148df3af4c9SAaron LI 
149df3af4c9SAaron LI 	if (fixed) {
150df3af4c9SAaron LI 		/*
151df3af4c9SAaron LI 		 * Remove any existing entries in the range, so the new
152df3af4c9SAaron LI 		 * mapping can be created at the requested address.
153df3af4c9SAaron LI 		 */
154df3af4c9SAaron LI 		rv = vm_map_delete(map, start, start + size, &count);
155df3af4c9SAaron LI 	} else {
156df3af4c9SAaron LI 		if (vm_map_findspace(map, start, size, 1, 0, &start))
157df3af4c9SAaron LI 			rv = KERN_NO_SPACE;
158df3af4c9SAaron LI 	}
159df3af4c9SAaron LI 	if (rv != KERN_SUCCESS) {
160df3af4c9SAaron LI 		vm_map_unlock(map);
161df3af4c9SAaron LI 		vm_map_entry_release(count);
162df3af4c9SAaron LI 		return rv;
163df3af4c9SAaron LI 	}
164df3af4c9SAaron LI 
165df3af4c9SAaron LI 	/* Get a reference to the object. */
166df3af4c9SAaron LI 	os_vmobj_ref(vmobj);
167df3af4c9SAaron LI 
168df3af4c9SAaron LI 	/*
169df3af4c9SAaron LI 	 * Map the object. This consumes the reference on success only. On
170df3af4c9SAaron LI 	 * failure we must drop the reference manually.
171df3af4c9SAaron LI 	 */
172df3af4c9SAaron LI 	vm_object_hold(vmobj);
173df3af4c9SAaron LI 	rv = vm_map_insert(map, &count, vmobj, NULL, offset, NULL,
174df3af4c9SAaron LI 	    start, start + size, VM_MAPTYPE_NORMAL, VM_SUBSYS_NVMM,
175df3af4c9SAaron LI 	    vmprot, vmmaxprot, 0);
176df3af4c9SAaron LI 	vm_object_drop(vmobj);
177df3af4c9SAaron LI 	vm_map_unlock(map);
178df3af4c9SAaron LI 	vm_map_entry_release(count);
179df3af4c9SAaron LI 	if (rv != KERN_SUCCESS) {
180df3af4c9SAaron LI 		/* Drop the ref. */
181df3af4c9SAaron LI 		os_vmobj_rel(vmobj);
182df3af4c9SAaron LI 		return rv;
183df3af4c9SAaron LI 	}
184df3af4c9SAaron LI 
185df3af4c9SAaron LI 	inherit = shared ? VM_INHERIT_SHARE : VM_INHERIT_NONE;
186df3af4c9SAaron LI 	rv = vm_map_inherit(map, start, start + size, inherit);
187df3af4c9SAaron LI 	if (rv != KERN_SUCCESS) {
188df3af4c9SAaron LI 		os_vmobj_unmap(map, start, start + size, false);
189df3af4c9SAaron LI 		return rv;
190df3af4c9SAaron LI 	}
191df3af4c9SAaron LI 
192df3af4c9SAaron LI 	if (wired) {
193949c56f8SMatthew Dillon 		rv = vm_map_kernel_wiring(map, start, start + size, 0);
194df3af4c9SAaron LI 		if (rv != KERN_SUCCESS) {
195df3af4c9SAaron LI 			os_vmobj_unmap(map, start, start + size, false);
196df3af4c9SAaron LI 			return rv;
197df3af4c9SAaron LI 		}
198df3af4c9SAaron LI 	}
199df3af4c9SAaron LI 
200df3af4c9SAaron LI 	*addr = start;
201df3af4c9SAaron LI 	return 0;
202df3af4c9SAaron LI }
203df3af4c9SAaron LI 
204df3af4c9SAaron LI void
os_vmobj_unmap(struct vm_map * map,vaddr_t start,vaddr_t end,bool wired)205df3af4c9SAaron LI os_vmobj_unmap(struct vm_map *map, vaddr_t start, vaddr_t end, bool wired)
206df3af4c9SAaron LI {
207df3af4c9SAaron LI 	if (wired) {
208df3af4c9SAaron LI 		/* Unwire kernel mappings before removing. */
209949c56f8SMatthew Dillon 		vm_map_kernel_wiring(map, start, end, KM_PAGEABLE);
210df3af4c9SAaron LI 	}
211df3af4c9SAaron LI 	vm_map_remove(map, start, end);
212df3af4c9SAaron LI }
213df3af4c9SAaron LI 
214df3af4c9SAaron LI void *
os_pagemem_zalloc(size_t size)215df3af4c9SAaron LI os_pagemem_zalloc(size_t size)
216df3af4c9SAaron LI {
217df3af4c9SAaron LI 	void *ret;
218df3af4c9SAaron LI 
219df3af4c9SAaron LI 	/* NOTE: kmem_alloc() may return 0 ! */
220df3af4c9SAaron LI 	ret = (void *)kmem_alloc(kernel_map, roundup(size, PAGE_SIZE),
221df3af4c9SAaron LI 	    VM_SUBSYS_NVMM);
222df3af4c9SAaron LI 
223df3af4c9SAaron LI 	OS_ASSERT((uintptr_t)ret % PAGE_SIZE == 0);
224df3af4c9SAaron LI 
225df3af4c9SAaron LI 	return ret;
226df3af4c9SAaron LI }
227df3af4c9SAaron LI 
228df3af4c9SAaron LI void
os_pagemem_free(void * ptr,size_t size)229df3af4c9SAaron LI os_pagemem_free(void *ptr, size_t size)
230df3af4c9SAaron LI {
231df3af4c9SAaron LI 	kmem_free(kernel_map, (vaddr_t)ptr, roundup(size, PAGE_SIZE));
232df3af4c9SAaron LI }
233df3af4c9SAaron LI 
234df3af4c9SAaron LI paddr_t
os_pa_zalloc(void)235df3af4c9SAaron LI os_pa_zalloc(void)
236df3af4c9SAaron LI {
237df3af4c9SAaron LI 	struct vm_page *pg;
238df3af4c9SAaron LI 
239df3af4c9SAaron LI 	pg = vm_page_alloczwq(0,
240df3af4c9SAaron LI 	    VM_ALLOC_SYSTEM | VM_ALLOC_ZERO | VM_ALLOC_RETRY);
241df3af4c9SAaron LI 
242df3af4c9SAaron LI 	return VM_PAGE_TO_PHYS(pg);
243df3af4c9SAaron LI }
244df3af4c9SAaron LI 
245df3af4c9SAaron LI void
os_pa_free(paddr_t pa)246df3af4c9SAaron LI os_pa_free(paddr_t pa)
247df3af4c9SAaron LI {
248df3af4c9SAaron LI 	vm_page_freezwq(PHYS_TO_VM_PAGE(pa));
249df3af4c9SAaron LI }
250df3af4c9SAaron LI 
251df3af4c9SAaron LI int
os_contigpa_zalloc(paddr_t * pa,vaddr_t * va,size_t npages)252df3af4c9SAaron LI os_contigpa_zalloc(paddr_t *pa, vaddr_t *va, size_t npages)
253df3af4c9SAaron LI {
254df3af4c9SAaron LI 	void *addr;
255df3af4c9SAaron LI 
256df3af4c9SAaron LI 	addr = contigmalloc(npages * PAGE_SIZE, M_NVMM, M_WAITOK | M_ZERO,
257df3af4c9SAaron LI 	    0, ~0UL, PAGE_SIZE, 0);
258df3af4c9SAaron LI 	if (addr == NULL)
259df3af4c9SAaron LI 		return ENOMEM;
260df3af4c9SAaron LI 
261df3af4c9SAaron LI 	*va = (vaddr_t)addr;
262df3af4c9SAaron LI 	*pa = vtophys(addr);
263df3af4c9SAaron LI 	return 0;
264df3af4c9SAaron LI }
265df3af4c9SAaron LI 
266df3af4c9SAaron LI void
os_contigpa_free(paddr_t pa __unused,vaddr_t va,size_t npages)267df3af4c9SAaron LI os_contigpa_free(paddr_t pa __unused, vaddr_t va, size_t npages)
268df3af4c9SAaron LI {
269df3af4c9SAaron LI 	contigfree((void *)va, npages * PAGE_SIZE, M_NVMM);
270df3af4c9SAaron LI }
271002185e5SAaron LI 
272002185e5SAaron LI /* -------------------------------------------------------------------------- */
273002185e5SAaron LI 
274002185e5SAaron LI #include <sys/conf.h>
275002185e5SAaron LI #include <sys/devfs.h>
276002185e5SAaron LI #include <sys/device.h>
277002185e5SAaron LI #include <sys/fcntl.h>
278002185e5SAaron LI #include <sys/module.h>
279002185e5SAaron LI 
280002185e5SAaron LI static d_open_t dfbsd_nvmm_open;
281002185e5SAaron LI static d_ioctl_t dfbsd_nvmm_ioctl;
282002185e5SAaron LI static d_priv_dtor_t dfbsd_nvmm_dtor;
283002185e5SAaron LI 
284002185e5SAaron LI static struct dev_ops nvmm_ops = {
285002185e5SAaron LI 	{ "nvmm", 0, D_MPSAFE },
286002185e5SAaron LI 	.d_open = dfbsd_nvmm_open,
287002185e5SAaron LI 	.d_ioctl = dfbsd_nvmm_ioctl,
288002185e5SAaron LI };
289002185e5SAaron LI 
290002185e5SAaron LI static int
dfbsd_nvmm_open(struct dev_open_args * ap)291002185e5SAaron LI dfbsd_nvmm_open(struct dev_open_args *ap)
292002185e5SAaron LI {
293002185e5SAaron LI 	int flags = ap->a_oflags;
294002185e5SAaron LI 	struct nvmm_owner *owner;
295002185e5SAaron LI 	struct file *fp;
296002185e5SAaron LI 	int error;
297002185e5SAaron LI 
298002185e5SAaron LI 	if (__predict_false(nvmm_impl == NULL))
299002185e5SAaron LI 		return ENXIO;
300002185e5SAaron LI 	if (!(flags & O_CLOEXEC))
301002185e5SAaron LI 		return EINVAL;
302002185e5SAaron LI 
303002185e5SAaron LI 	if (OFLAGS(flags) & O_WRONLY) {
304002185e5SAaron LI 		owner = &nvmm_root_owner;
305002185e5SAaron LI 	} else {
306002185e5SAaron LI 		owner = os_mem_alloc(sizeof(*owner));
307002185e5SAaron LI 		owner->pid = curthread->td_proc->p_pid;
308002185e5SAaron LI 	}
309002185e5SAaron LI 
310002185e5SAaron LI 	fp = ap->a_fpp ? *ap->a_fpp : NULL;
311002185e5SAaron LI 	error = devfs_set_cdevpriv(fp, owner, dfbsd_nvmm_dtor);
312002185e5SAaron LI 	if (error) {
313002185e5SAaron LI 		dfbsd_nvmm_dtor(owner);
314002185e5SAaron LI 		return error;
315002185e5SAaron LI 	}
316002185e5SAaron LI 
317002185e5SAaron LI 	return 0;
318002185e5SAaron LI }
319002185e5SAaron LI 
320002185e5SAaron LI static void
dfbsd_nvmm_dtor(void * arg)321002185e5SAaron LI dfbsd_nvmm_dtor(void *arg)
322002185e5SAaron LI {
323002185e5SAaron LI 	struct nvmm_owner *owner = arg;
324002185e5SAaron LI 
325002185e5SAaron LI 	OS_ASSERT(owner != NULL);
326002185e5SAaron LI 	nvmm_kill_machines(owner);
327002185e5SAaron LI 	if (owner != &nvmm_root_owner) {
328002185e5SAaron LI 		os_mem_free(owner, sizeof(*owner));
329002185e5SAaron LI 	}
330002185e5SAaron LI }
331002185e5SAaron LI 
332002185e5SAaron LI static int
dfbsd_nvmm_ioctl(struct dev_ioctl_args * ap)333002185e5SAaron LI dfbsd_nvmm_ioctl(struct dev_ioctl_args *ap)
334002185e5SAaron LI {
335002185e5SAaron LI 	unsigned long cmd = ap->a_cmd;
336002185e5SAaron LI 	void *data = ap->a_data;
337002185e5SAaron LI 	struct file *fp = ap->a_fp;
338002185e5SAaron LI 	struct nvmm_owner *owner = NULL;
339002185e5SAaron LI 
340002185e5SAaron LI 	devfs_get_cdevpriv(fp, (void **)&owner);
341002185e5SAaron LI 	OS_ASSERT(owner != NULL);
342002185e5SAaron LI 
343002185e5SAaron LI 	return nvmm_ioctl(owner, cmd, data);
344002185e5SAaron LI }
345002185e5SAaron LI 
346002185e5SAaron LI /* -------------------------------------------------------------------------- */
347002185e5SAaron LI 
348002185e5SAaron LI static int
nvmm_attach(void)349002185e5SAaron LI nvmm_attach(void)
350002185e5SAaron LI {
351002185e5SAaron LI 	int error;
352002185e5SAaron LI 
353002185e5SAaron LI 	error = nvmm_init();
354002185e5SAaron LI 	if (error)
355002185e5SAaron LI 		panic("%s: impossible", __func__);
356002185e5SAaron LI 	os_printf("nvmm: attached, using backend %s\n", nvmm_impl->name);
357002185e5SAaron LI 
358002185e5SAaron LI 	return 0;
359002185e5SAaron LI }
360002185e5SAaron LI 
361002185e5SAaron LI static int
nvmm_detach(void)362002185e5SAaron LI nvmm_detach(void)
363002185e5SAaron LI {
364002185e5SAaron LI 	if (os_atomic_load_uint(&nmachines) > 0)
365002185e5SAaron LI 		return EBUSY;
366002185e5SAaron LI 
367002185e5SAaron LI 	nvmm_fini();
368002185e5SAaron LI 	return 0;
369002185e5SAaron LI }
370002185e5SAaron LI 
371002185e5SAaron LI static int
nvmm_modevent(module_t mod __unused,int type,void * data __unused)372002185e5SAaron LI nvmm_modevent(module_t mod __unused, int type, void *data __unused)
373002185e5SAaron LI {
374002185e5SAaron LI 	static cdev_t dev = NULL;
375002185e5SAaron LI 	int error;
376002185e5SAaron LI 
377002185e5SAaron LI 	switch (type) {
378002185e5SAaron LI 	case MOD_LOAD:
379002185e5SAaron LI 		if (nvmm_ident() == NULL) {
380002185e5SAaron LI 			os_printf("nvmm: cpu not supported\n");
381002185e5SAaron LI 			return ENOTSUP;
382002185e5SAaron LI 		}
383002185e5SAaron LI 		error = nvmm_attach();
384002185e5SAaron LI 		if (error)
385002185e5SAaron LI 			return error;
386002185e5SAaron LI 
387002185e5SAaron LI 		dev = make_dev(&nvmm_ops, 0, UID_ROOT, GID_NVMM, 0640, "nvmm");
388002185e5SAaron LI 		if (dev == NULL) {
389002185e5SAaron LI 			os_printf("nvmm: unable to create device\n");
390002185e5SAaron LI 			error = ENOMEM;
391002185e5SAaron LI 		}
392002185e5SAaron LI 		break;
393002185e5SAaron LI 
394002185e5SAaron LI 	case MOD_UNLOAD:
395002185e5SAaron LI 		if (dev == NULL)
396002185e5SAaron LI 			return 0;
397002185e5SAaron LI 		error = nvmm_detach();
398002185e5SAaron LI 		if (error == 0)
399002185e5SAaron LI 			destroy_dev(dev);
400002185e5SAaron LI 		break;
401002185e5SAaron LI 
402002185e5SAaron LI 	case MOD_SHUTDOWN:
403002185e5SAaron LI 		error = 0;
404002185e5SAaron LI 		break;
405002185e5SAaron LI 
406002185e5SAaron LI 	default:
407002185e5SAaron LI 		error = EOPNOTSUPP;
408002185e5SAaron LI 		break;
409002185e5SAaron LI 	}
410002185e5SAaron LI 
411002185e5SAaron LI 	return error;
412002185e5SAaron LI }
413002185e5SAaron LI 
414002185e5SAaron LI static moduledata_t nvmm_moddata = {
415002185e5SAaron LI 	.name = "nvmm",
416002185e5SAaron LI 	.evhand = nvmm_modevent,
417002185e5SAaron LI 	.priv = NULL,
418002185e5SAaron LI };
419002185e5SAaron LI 
420002185e5SAaron LI DECLARE_MODULE(nvmm, nvmm_moddata, SI_SUB_PSEUDO, SI_ORDER_ANY);
421002185e5SAaron LI MODULE_VERSION(nvmm, NVMM_KERN_VERSION);
422