xref: /freebsd/sys/amd64/amd64/mem.c (revision a163d034fadcfb4a25ca34a2ba5f491c47b6ff69)
15b81b6b3SRodney W. Grimes /*-
25b81b6b3SRodney W. Grimes  * Copyright (c) 1988 University of Utah.
35b81b6b3SRodney W. Grimes  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
45b81b6b3SRodney W. Grimes  * All rights reserved.
55b81b6b3SRodney W. Grimes  *
65b81b6b3SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
75b81b6b3SRodney W. Grimes  * the Systems Programming Group of the University of Utah Computer
85b81b6b3SRodney W. Grimes  * Science Department, and code derived from software contributed to
95b81b6b3SRodney W. Grimes  * Berkeley by William Jolitz.
105b81b6b3SRodney W. Grimes  *
115b81b6b3SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
125b81b6b3SRodney W. Grimes  * modification, are permitted provided that the following conditions
135b81b6b3SRodney W. Grimes  * are met:
145b81b6b3SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
155b81b6b3SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
165b81b6b3SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
175b81b6b3SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
185b81b6b3SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
195b81b6b3SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
205b81b6b3SRodney W. Grimes  *    must display the following acknowledgement:
215b81b6b3SRodney W. Grimes  *	This product includes software developed by the University of
225b81b6b3SRodney W. Grimes  *	California, Berkeley and its contributors.
235b81b6b3SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
245b81b6b3SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
255b81b6b3SRodney W. Grimes  *    without specific prior written permission.
265b81b6b3SRodney W. Grimes  *
275b81b6b3SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
285b81b6b3SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
295b81b6b3SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
305b81b6b3SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
315b81b6b3SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
325b81b6b3SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
335b81b6b3SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
345b81b6b3SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
355b81b6b3SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
365b81b6b3SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
375b81b6b3SRodney W. Grimes  * SUCH DAMAGE.
385b81b6b3SRodney W. Grimes  *
395b81b6b3SRodney W. Grimes  *	from: Utah $Hdr: mem.c 1.13 89/10/08$
4047cacd38SRodney W. Grimes  *	from: @(#)mem.c	7.2 (Berkeley) 5/9/91
41c3aac50fSPeter Wemm  * $FreeBSD$
425b81b6b3SRodney W. Grimes  */
435b81b6b3SRodney W. Grimes 
445b81b6b3SRodney W. Grimes /*
455b81b6b3SRodney W. Grimes  * Memory special file
465b81b6b3SRodney W. Grimes  */
475b81b6b3SRodney W. Grimes 
4826f9a767SRodney W. Grimes #include <sys/param.h>
4926f9a767SRodney W. Grimes #include <sys/conf.h>
50265cdeddSBruce Evans #include <sys/fcntl.h>
514ffd949eSMike Smith #include <sys/ioccom.h>
52d4af7a50SDavid E. O'Brien #include <sys/kernel.h>
5323955314SAlfred Perlstein #include <sys/lock.h>
5426f9a767SRodney W. Grimes #include <sys/malloc.h>
554ffd949eSMike Smith #include <sys/memrange.h>
569dceb26bSJohn Baldwin #include <sys/mutex.h>
5726f9a767SRodney W. Grimes #include <sys/proc.h>
58bb25f0ddSBruce Evans #include <sys/signalvar.h>
59d4af7a50SDavid E. O'Brien #include <sys/systm.h>
60d4af7a50SDavid E. O'Brien #include <sys/uio.h>
615b81b6b3SRodney W. Grimes 
625afffbaaSMark Murray #include <machine/db_machdep.h>
63d1d9d260SBruce Evans #include <machine/frame.h>
6426f9a767SRodney W. Grimes #include <machine/psl.h>
654ffd949eSMike Smith #include <machine/specialreg.h>
665b81b6b3SRodney W. Grimes 
67c87801feSDavid Greenman #include <vm/vm.h>
6826f9a767SRodney W. Grimes #include <vm/pmap.h>
69efeaf95aSDavid Greenman #include <vm/vm_extern.h>
705b81b6b3SRodney W. Grimes 
715afffbaaSMark Murray static dev_t memdev, kmemdev, iodev;
7287f6c662SJulian Elischer 
7387f6c662SJulian Elischer static	d_open_t	mmopen;
7487f6c662SJulian Elischer static	d_close_t	mmclose;
75c73feca0SBruce Evans static	d_read_t	mmrw;
7687f6c662SJulian Elischer static	d_ioctl_t	mmioctl;
7787f6c662SJulian Elischer static	d_mmap_t	memmmap;
7887f6c662SJulian Elischer 
7953ac6efbSJulian Elischer #define CDEV_MAJOR 2
804e2f199eSPoul-Henning Kamp static struct cdevsw mem_cdevsw = {
814e2f199eSPoul-Henning Kamp 	/* open */	mmopen,
824e2f199eSPoul-Henning Kamp 	/* close */	mmclose,
834e2f199eSPoul-Henning Kamp 	/* read */	mmrw,
844e2f199eSPoul-Henning Kamp 	/* write */	mmrw,
854e2f199eSPoul-Henning Kamp 	/* ioctl */	mmioctl,
865afffbaaSMark Murray 	/* poll */	(d_poll_t *)seltrue,
874e2f199eSPoul-Henning Kamp 	/* mmap */	memmmap,
884e2f199eSPoul-Henning Kamp 	/* strategy */	nostrategy,
894e2f199eSPoul-Henning Kamp 	/* name */	"mem",
904e2f199eSPoul-Henning Kamp 	/* maj */	CDEV_MAJOR,
914e2f199eSPoul-Henning Kamp 	/* dump */	nodump,
924e2f199eSPoul-Henning Kamp 	/* psize */	nopsize,
9349c68457SBrian Feldman 	/* flags */	D_MEM,
944e2f199eSPoul-Henning Kamp };
9553ac6efbSJulian Elischer 
964ffd949eSMike Smith MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors");
974ffd949eSMike Smith 
984ffd949eSMike Smith struct mem_range_softc mem_range_softc;
994ffd949eSMike Smith 
10087f6c662SJulian Elischer static int
101b40ce416SJulian Elischer mmclose(dev_t dev, int flags, int fmt, struct thread *td)
10278d172caSRodney W. Grimes {
10378d172caSRodney W. Grimes 	switch (minor(dev)) {
10478d172caSRodney W. Grimes 	case 14:
105b40ce416SJulian Elischer 		td->td_frame->tf_eflags &= ~PSL_IOPL;
10678d172caSRodney W. Grimes 	}
10778d172caSRodney W. Grimes 	return (0);
10878d172caSRodney W. Grimes }
10933f538b9SBruce Evans 
11087f6c662SJulian Elischer static int
111b40ce416SJulian Elischer mmopen(dev_t dev, int flags, int fmt, struct thread *td)
11278d172caSRodney W. Grimes {
113da3df630SBruce Evans 	int error;
11478d172caSRodney W. Grimes 
11578d172caSRodney W. Grimes 	switch (minor(dev)) {
11618284c94SPoul-Henning Kamp 	case 0:
11718284c94SPoul-Henning Kamp 	case 1:
1181851c8fdSRobert Watson 		if (flags & FWRITE) {
119a854ed98SJohn Baldwin 			error = securelevel_gt(td->td_ucred, 0);
1201851c8fdSRobert Watson 			if (error != 0)
1211851c8fdSRobert Watson 				return (error);
1221851c8fdSRobert Watson 		}
12318284c94SPoul-Henning Kamp 		break;
12478d172caSRodney W. Grimes 	case 14:
12544731cabSJohn Baldwin 		error = suser(td);
126da3df630SBruce Evans 		if (error != 0)
127da3df630SBruce Evans 			return (error);
128a854ed98SJohn Baldwin 		error = securelevel_gt(td->td_ucred, 0);
1291851c8fdSRobert Watson 		if (error != 0)
1301851c8fdSRobert Watson 			return (error);
131b40ce416SJulian Elischer 		td->td_frame->tf_eflags |= PSL_IOPL;
13278d172caSRodney W. Grimes 		break;
13378d172caSRodney W. Grimes 	}
13478d172caSRodney W. Grimes 	return (0);
13578d172caSRodney W. Grimes }
13633f538b9SBruce Evans 
1375afffbaaSMark Murray /*ARGSUSED*/
13887f6c662SJulian Elischer static int
1395afffbaaSMark Murray mmrw(dev_t dev, struct uio *uio, int flags)
1405b81b6b3SRodney W. Grimes {
1415afffbaaSMark Murray 	int o;
142493c240cSMark Murray 	u_int c = 0, v;
1435afffbaaSMark Murray 	struct iovec *iov;
1445b81b6b3SRodney W. Grimes 	int error = 0;
1455afffbaaSMark Murray 	vm_offset_t addr, eaddr;
1465b81b6b3SRodney W. Grimes 
1470cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
1480cddd8f0SMatthew Dillon 
1495b81b6b3SRodney W. Grimes 	while (uio->uio_resid > 0 && error == 0) {
1505b81b6b3SRodney W. Grimes 		iov = uio->uio_iov;
1515b81b6b3SRodney W. Grimes 		if (iov->iov_len == 0) {
1525b81b6b3SRodney W. Grimes 			uio->uio_iov++;
1535b81b6b3SRodney W. Grimes 			uio->uio_iovcnt--;
1545b81b6b3SRodney W. Grimes 			if (uio->uio_iovcnt < 0)
1555b81b6b3SRodney W. Grimes 				panic("mmrw");
1565b81b6b3SRodney W. Grimes 			continue;
1575b81b6b3SRodney W. Grimes 		}
1585b81b6b3SRodney W. Grimes 		switch (minor(dev)) {
1595b81b6b3SRodney W. Grimes 
1605b81b6b3SRodney W. Grimes /* minor device 0 is physical memory */
1615b81b6b3SRodney W. Grimes 		case 0:
1625b81b6b3SRodney W. Grimes 			v = uio->uio_offset;
1639f85bc03SPeter Wemm 			v &= ~PAGE_MASK;
1640385347cSPeter Wemm 			pmap_kenter((vm_offset_t)ptvmmap, v);
165f8845af0SPoul-Henning Kamp 			o = (int)uio->uio_offset & PAGE_MASK;
166f8845af0SPoul-Henning Kamp 			c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK));
167f8845af0SPoul-Henning Kamp 			c = min(c, (u_int)(PAGE_SIZE - o));
16826f9a767SRodney W. Grimes 			c = min(c, (u_int)iov->iov_len);
16926f9a767SRodney W. Grimes 			error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
1701af04fadSPeter Wemm 			pmap_qremove((vm_offset_t)ptvmmap, 1);
1715b81b6b3SRodney W. Grimes 			continue;
1725b81b6b3SRodney W. Grimes 
1735b81b6b3SRodney W. Grimes /* minor device 1 is kernel memory */
1745afffbaaSMark Murray 		case 1:
1755b81b6b3SRodney W. Grimes 			c = iov->iov_len;
17697e11262SDavid Greenman 
17797e11262SDavid Greenman 			/*
17897e11262SDavid Greenman 			 * Make sure that all of the pages are currently resident so
17997e11262SDavid Greenman 			 * that we don't create any zero-fill pages.
18097e11262SDavid Greenman 			 */
18197e11262SDavid Greenman 			addr = trunc_page(uio->uio_offset);
1820704324aSDavid Greenman 			eaddr = round_page(uio->uio_offset + c);
183d021fc11SPeter Wemm 
184d021fc11SPeter Wemm 			if (addr < (vm_offset_t)VADDR(PTDPTDI, 0))
185e40ab3e9SMark Murray 				return (EFAULT);
186d021fc11SPeter Wemm 			if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0))
187e40ab3e9SMark Murray 				return (EFAULT);
18897e11262SDavid Greenman 			for (; addr < eaddr; addr += PAGE_SIZE)
189e40ab3e9SMark Murray 				if (pmap_extract(kernel_pmap, addr) == 0)
190e40ab3e9SMark Murray 					return (EFAULT);
19197e11262SDavid Greenman 
19226f9a767SRodney W. Grimes 			if (!kernacc((caddr_t)(int)uio->uio_offset, c,
19302c58685SPoul-Henning Kamp 			    uio->uio_rw == UIO_READ ?
194e40ab3e9SMark Murray 			    VM_PROT_READ : VM_PROT_WRITE))
1955b81b6b3SRodney W. Grimes 				return (EFAULT);
19626f9a767SRodney W. Grimes 			error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
1975b81b6b3SRodney W. Grimes 			continue;
198d9ce8f5cSNate Lawson 
199d9ce8f5cSNate Lawson 		default:
200d9ce8f5cSNate Lawson 			return (ENODEV);
20197e11262SDavid Greenman 		}
2025b81b6b3SRodney W. Grimes 
2035b81b6b3SRodney W. Grimes 		if (error)
2045b81b6b3SRodney W. Grimes 			break;
2052b7f24d2SMike Barcroft 		iov->iov_base = (char *)iov->iov_base + c;
2065b81b6b3SRodney W. Grimes 		iov->iov_len -= c;
2075b81b6b3SRodney W. Grimes 		uio->uio_offset += c;
2085b81b6b3SRodney W. Grimes 		uio->uio_resid -= c;
2095b81b6b3SRodney W. Grimes 	}
2105b81b6b3SRodney W. Grimes 	return (error);
2115b81b6b3SRodney W. Grimes }
212b513c262SDavid Greenman 
213b513c262SDavid Greenman /*******************************************************\
214b513c262SDavid Greenman * allow user processes to MMAP some memory sections	*
215b513c262SDavid Greenman * instead of going through read/write			*
216b513c262SDavid Greenman \*******************************************************/
21787f6c662SJulian Elischer static int
2185afffbaaSMark Murray memmmap(dev_t dev, vm_offset_t offset, int prot)
219b513c262SDavid Greenman {
220b513c262SDavid Greenman 	switch (minor(dev))
221b513c262SDavid Greenman 	{
222b513c262SDavid Greenman 
223b513c262SDavid Greenman 	/* minor device 0 is physical memory */
224b513c262SDavid Greenman 	case 0:
225e40ab3e9SMark Murray         	return (i386_btop(offset));
226b513c262SDavid Greenman 
227b513c262SDavid Greenman 	/* minor device 1 is kernel memory */
228b513c262SDavid Greenman 	case 1:
229e40ab3e9SMark Murray         	return (i386_btop(vtophys(offset)));
230493c240cSMark Murray 
231493c240cSMark Murray 	default:
232e40ab3e9SMark Murray 		return (-1);
233b513c262SDavid Greenman 	}
2348567cb9fSMark Murray }
235b513c262SDavid Greenman 
236316bbd5cSBruce Evans /*
2374ffd949eSMike Smith  * Operations for changing memory attributes.
2384ffd949eSMike Smith  *
2394ffd949eSMike Smith  * This is basically just an ioctl shim for mem_range_attr_get
2404ffd949eSMike Smith  * and mem_range_attr_set.
2414ffd949eSMike Smith  */
2424ffd949eSMike Smith static int
243b40ce416SJulian Elischer mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td)
2444ffd949eSMike Smith {
2454ffd949eSMike Smith 	int nd, error = 0;
2464ffd949eSMike Smith 	struct mem_range_op *mo = (struct mem_range_op *)data;
2474ffd949eSMike Smith 	struct mem_range_desc *md;
2484ffd949eSMike Smith 
2494ffd949eSMike Smith 	/* is this for us? */
2504ffd949eSMike Smith 	if ((cmd != MEMRANGE_GET) &&
2514ffd949eSMike Smith 	    (cmd != MEMRANGE_SET))
2524871de2fSBrian Feldman 		return (ENOTTY);
2534ffd949eSMike Smith 
2544ffd949eSMike Smith 	/* any chance we can handle this? */
2554ffd949eSMike Smith 	if (mem_range_softc.mr_op == NULL)
2564ffd949eSMike Smith 		return (EOPNOTSUPP);
2574ffd949eSMike Smith 
2584ffd949eSMike Smith 	/* do we have any descriptors? */
2594ffd949eSMike Smith 	if (mem_range_softc.mr_ndesc == 0)
2604ffd949eSMike Smith 		return (ENXIO);
2614ffd949eSMike Smith 
2624ffd949eSMike Smith 	switch (cmd) {
2634ffd949eSMike Smith 	case MEMRANGE_GET:
2644ffd949eSMike Smith 		nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc);
2654ffd949eSMike Smith 		if (nd > 0) {
2664ffd949eSMike Smith 			md = (struct mem_range_desc *)
2674ffd949eSMike Smith 				malloc(nd * sizeof(struct mem_range_desc),
268a163d034SWarner Losh 				       M_MEMDESC, M_WAITOK);
269ac3595b0SMike Smith 			error = mem_range_attr_get(md, &nd);
270ac3595b0SMike Smith 			if (!error)
2714ffd949eSMike Smith 				error = copyout(md, mo->mo_desc,
2724ffd949eSMike Smith 					nd * sizeof(struct mem_range_desc));
2734ffd949eSMike Smith 			free(md, M_MEMDESC);
2744ffd949eSMike Smith 		}
275e40ab3e9SMark Murray 		else
276e40ab3e9SMark Murray 			nd = mem_range_softc.mr_ndesc;
2774ffd949eSMike Smith 		mo->mo_arg[0] = nd;
2784ffd949eSMike Smith 		break;
2794ffd949eSMike Smith 
2804ffd949eSMike Smith 	case MEMRANGE_SET:
2814ffd949eSMike Smith 		md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc),
282a163d034SWarner Losh 						    M_MEMDESC, M_WAITOK);
2834ffd949eSMike Smith 		error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc));
2844ffd949eSMike Smith 		/* clamp description string */
2854ffd949eSMike Smith 		md->mr_owner[sizeof(md->mr_owner) - 1] = 0;
2864ffd949eSMike Smith 		if (error == 0)
2874ffd949eSMike Smith 			error = mem_range_attr_set(md, &mo->mo_arg[0]);
2884ffd949eSMike Smith 		free(md, M_MEMDESC);
2894ffd949eSMike Smith 		break;
2904ffd949eSMike Smith 	}
2914ffd949eSMike Smith 	return (error);
2924ffd949eSMike Smith }
2934ffd949eSMike Smith 
2944ffd949eSMike Smith /*
2954ffd949eSMike Smith  * Implementation-neutral, kernel-callable functions for manipulating
2964ffd949eSMike Smith  * memory range attributes.
2974ffd949eSMike Smith  */
298ac3595b0SMike Smith int
2995afffbaaSMark Murray mem_range_attr_get(struct mem_range_desc *mrd, int *arg)
3004ffd949eSMike Smith {
3014af396a5SMike Smith 	/* can we handle this? */
3024af396a5SMike Smith 	if (mem_range_softc.mr_op == NULL)
3034af396a5SMike Smith 		return (EOPNOTSUPP);
3044af396a5SMike Smith 
305e40ab3e9SMark Murray 	if (*arg == 0)
3064ffd949eSMike Smith 		*arg = mem_range_softc.mr_ndesc;
307e40ab3e9SMark Murray 	else
3085afffbaaSMark Murray 		bcopy(mem_range_softc.mr_desc, mrd,
3095afffbaaSMark Murray 			(*arg) * sizeof(struct mem_range_desc));
310ac3595b0SMike Smith 	return (0);
3114ffd949eSMike Smith }
3124ffd949eSMike Smith 
3134ffd949eSMike Smith int
3145afffbaaSMark Murray mem_range_attr_set(struct mem_range_desc *mrd, int *arg)
3154ffd949eSMike Smith {
3164af396a5SMike Smith 	/* can we handle this? */
3174af396a5SMike Smith 	if (mem_range_softc.mr_op == NULL)
3184af396a5SMike Smith 		return (EOPNOTSUPP);
3194af396a5SMike Smith 
3204ffd949eSMike Smith 	return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg));
3214ffd949eSMike Smith }
3224ffd949eSMike Smith 
3239c06a386SPeter Wemm #ifdef SMP
3244a034f21SMike Smith void
3254a034f21SMike Smith mem_range_AP_init(void)
3264a034f21SMike Smith {
327cbdfdcb2SPeter Wemm 	if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
328e40ab3e9SMark Murray 		(mem_range_softc.mr_op->initAP(&mem_range_softc));
3294a034f21SMike Smith }
3309c06a386SPeter Wemm #endif
3314a034f21SMike Smith 
3324ffd949eSMike Smith static int
3335afffbaaSMark Murray mem_modevent(module_t mod, int type, void *data)
3344ffd949eSMike Smith {
3355afffbaaSMark Murray 	switch(type) {
3365afffbaaSMark Murray 	case MOD_LOAD:
3375afffbaaSMark Murray 		if (bootverbose)
3385afffbaaSMark Murray 			printf("mem: <memory & I/O>\n");
3394ffd949eSMike Smith 		/* Initialise memory range handling */
3404ffd949eSMike Smith 		if (mem_range_softc.mr_op != NULL)
3414ffd949eSMike Smith 			mem_range_softc.mr_op->init(&mem_range_softc);
3424ffd949eSMike Smith 
3435afffbaaSMark Murray 		memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM,
3445afffbaaSMark Murray 			0640, "mem");
3455afffbaaSMark Murray 		kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM,
3465afffbaaSMark Murray 			0640, "kmem");
3475afffbaaSMark Murray 		iodev = make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL,
3485afffbaaSMark Murray 			0600, "io");
349e40ab3e9SMark Murray 		return (0);
3505afffbaaSMark Murray 
3515afffbaaSMark Murray 	case MOD_UNLOAD:
3525afffbaaSMark Murray 		destroy_dev(memdev);
3535afffbaaSMark Murray 		destroy_dev(kmemdev);
3545afffbaaSMark Murray 		destroy_dev(iodev);
355e40ab3e9SMark Murray 		return (0);
3565afffbaaSMark Murray 
3575afffbaaSMark Murray 	case MOD_SHUTDOWN:
358e40ab3e9SMark Murray 		return (0);
3595afffbaaSMark Murray 
3605afffbaaSMark Murray 	default:
361e40ab3e9SMark Murray 		return (EOPNOTSUPP);
3625afffbaaSMark Murray 	}
3637198bf47SJulian Elischer }
36453ac6efbSJulian Elischer 
3655afffbaaSMark Murray DEV_MODULE(mem, mem_modevent, NULL);
366